aboutsummaryrefslogtreecommitdiff
path: root/node_modules/braces/lib/parsers.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/braces/lib/parsers.js')
-rw-r--r--node_modules/braces/lib/parsers.js360
1 files changed, 360 insertions, 0 deletions
diff --git a/node_modules/braces/lib/parsers.js b/node_modules/braces/lib/parsers.js
new file mode 100644
index 0000000..8bf3e92
--- /dev/null
+++ b/node_modules/braces/lib/parsers.js
@@ -0,0 +1,360 @@
+'use strict';
+
+var Node = require('snapdragon-node');
+var utils = require('./utils');
+
+/**
+ * Braces parsers
+ */
+
+module.exports = function(braces, options) {
+ braces.parser
+ .set('bos', function() {
+ if (!this.parsed) {
+ this.ast = this.nodes[0] = new Node(this.ast);
+ }
+ })
+
+ /**
+ * Character parsers
+ */
+
+ .set('escape', function() {
+ var pos = this.position();
+ var m = this.match(/^(?:\\(.)|\$\{)/);
+ if (!m) return;
+
+ var prev = this.prev();
+ var last = utils.last(prev.nodes);
+
+ var node = pos(new Node({
+ type: 'text',
+ multiplier: 1,
+ val: m[0]
+ }));
+
+ if (node.val === '\\\\') {
+ return node;
+ }
+
+ if (node.val === '${') {
+ var str = this.input;
+ var idx = -1;
+ var ch;
+
+ while ((ch = str[++idx])) {
+ this.consume(1);
+ node.val += ch;
+ if (ch === '\\') {
+ node.val += str[++idx];
+ continue;
+ }
+ if (ch === '}') {
+ break;
+ }
+ }
+ }
+
+ if (this.options.unescape !== false) {
+ node.val = node.val.replace(/\\([{}])/g, '$1');
+ }
+
+ if (last.val === '"' && this.input.charAt(0) === '"') {
+ last.val = node.val;
+ this.consume(1);
+ return;
+ }
+
+ return concatNodes.call(this, pos, node, prev, options);
+ })
+
+ /**
+ * Brackets: "[...]" (basic, this is overridden by
+ * other parsers in more advanced implementations)
+ */
+
+ .set('bracket', function() {
+ var isInside = this.isInside('brace');
+ var pos = this.position();
+ var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/);
+ if (!m) return;
+
+ var prev = this.prev();
+ var val = m[0];
+ var negated = m[1] ? '^' : '';
+ var inner = m[2] || '';
+ var close = m[3] || '';
+
+ if (isInside && prev.type === 'brace') {
+ prev.text = prev.text || '';
+ prev.text += val;
+ }
+
+ var esc = this.input.slice(0, 2);
+ if (inner === '' && esc === '\\]') {
+ inner += esc;
+ this.consume(2);
+
+ var str = this.input;
+ var idx = -1;
+ var ch;
+
+ while ((ch = str[++idx])) {
+ this.consume(1);
+ if (ch === ']') {
+ close = ch;
+ break;
+ }
+ inner += ch;
+ }
+ }
+
+ return pos(new Node({
+ type: 'bracket',
+ val: val,
+ escaped: close !== ']',
+ negated: negated,
+ inner: inner,
+ close: close
+ }));
+ })
+
+ /**
+ * Empty braces (we capture these early to
+ * speed up processing in the compiler)
+ */
+
+ .set('multiplier', function() {
+ var isInside = this.isInside('brace');
+ var pos = this.position();
+ var m = this.match(/^\{((?:,|\{,+\})+)\}/);
+ if (!m) return;
+
+ this.multiplier = true;
+ var prev = this.prev();
+ var val = m[0];
+
+ if (isInside && prev.type === 'brace') {
+ prev.text = prev.text || '';
+ prev.text += val;
+ }
+
+ var node = pos(new Node({
+ type: 'text',
+ multiplier: 1,
+ match: m,
+ val: val
+ }));
+
+ return concatNodes.call(this, pos, node, prev, options);
+ })
+
+ /**
+ * Open
+ */
+
+ .set('brace.open', function() {
+ var pos = this.position();
+ var m = this.match(/^\{(?!(?:[^\\}]?|,+)\})/);
+ if (!m) return;
+
+ var prev = this.prev();
+ var last = utils.last(prev.nodes);
+
+ // if the last parsed character was an extglob character
+ // we need to _not optimize_ the brace pattern because
+ // it might be mistaken for an extglob by a downstream parser
+ if (last && last.val && isExtglobChar(last.val.slice(-1))) {
+ last.optimize = false;
+ }
+
+ var open = pos(new Node({
+ type: 'brace.open',
+ val: m[0]
+ }));
+
+ var node = pos(new Node({
+ type: 'brace',
+ nodes: []
+ }));
+
+ node.push(open);
+ prev.push(node);
+ this.push('brace', node);
+ })
+
+ /**
+ * Close
+ */
+
+ .set('brace.close', function() {
+ var pos = this.position();
+ var m = this.match(/^\}/);
+ if (!m || !m[0]) return;
+
+ var brace = this.pop('brace');
+ var node = pos(new Node({
+ type: 'brace.close',
+ val: m[0]
+ }));
+
+ if (!this.isType(brace, 'brace')) {
+ if (this.options.strict) {
+ throw new Error('missing opening "{"');
+ }
+ node.type = 'text';
+ node.multiplier = 0;
+ node.escaped = true;
+ return node;
+ }
+
+ var prev = this.prev();
+ var last = utils.last(prev.nodes);
+ if (last.text) {
+ var lastNode = utils.last(last.nodes);
+ if (lastNode.val === ')' && /[!@*?+]\(/.test(last.text)) {
+ var open = last.nodes[0];
+ var text = last.nodes[1];
+ if (open.type === 'brace.open' && text && text.type === 'text') {
+ text.optimize = false;
+ }
+ }
+ }
+
+ if (brace.nodes.length > 2) {
+ var first = brace.nodes[1];
+ if (first.type === 'text' && first.val === ',') {
+ brace.nodes.splice(1, 1);
+ brace.nodes.push(first);
+ }
+ }
+
+ brace.push(node);
+ })
+
+ /**
+ * Capture boundary characters
+ */
+
+ .set('boundary', function() {
+ var pos = this.position();
+ var m = this.match(/^[$^](?!\{)/);
+ if (!m) return;
+ return pos(new Node({
+ type: 'text',
+ val: m[0]
+ }));
+ })
+
+ /**
+ * One or zero, non-comma characters wrapped in braces
+ */
+
+ .set('nobrace', function() {
+ var isInside = this.isInside('brace');
+ var pos = this.position();
+ var m = this.match(/^\{[^,]?\}/);
+ if (!m) return;
+
+ var prev = this.prev();
+ var val = m[0];
+
+ if (isInside && prev.type === 'brace') {
+ prev.text = prev.text || '';
+ prev.text += val;
+ }
+
+ return pos(new Node({
+ type: 'text',
+ multiplier: 0,
+ val: val
+ }));
+ })
+
+ /**
+ * Text
+ */
+
+ .set('text', function() {
+ var isInside = this.isInside('brace');
+ var pos = this.position();
+ var m = this.match(/^((?!\\)[^${}[\]])+/);
+ if (!m) return;
+
+ var prev = this.prev();
+ var val = m[0];
+
+ if (isInside && prev.type === 'brace') {
+ prev.text = prev.text || '';
+ prev.text += val;
+ }
+
+ var node = pos(new Node({
+ type: 'text',
+ multiplier: 1,
+ val: val
+ }));
+
+ return concatNodes.call(this, pos, node, prev, options);
+ });
+};
+
+/**
+ * Returns true if the character is an extglob character.
+ */
+
+function isExtglobChar(ch) {
+ return ch === '!' || ch === '@' || ch === '*' || ch === '?' || ch === '+';
+}
+
+/**
+ * Combine text nodes, and calculate empty sets (`{,,}`)
+ * @param {Function} `pos` Function to calculate node position
+ * @param {Object} `node` AST node
+ * @return {Object}
+ */
+
+function concatNodes(pos, node, parent, options) {
+ node.orig = node.val;
+ var prev = this.prev();
+ var last = utils.last(prev.nodes);
+ var isEscaped = false;
+
+ if (node.val.length > 1) {
+ var a = node.val.charAt(0);
+ var b = node.val.slice(-1);
+
+ isEscaped = (a === '"' && b === '"')
+ || (a === "'" && b === "'")
+ || (a === '`' && b === '`');
+ }
+
+ if (isEscaped && options.unescape !== false) {
+ node.val = node.val.slice(1, node.val.length - 1);
+ node.escaped = true;
+ }
+
+ if (node.match) {
+ var match = node.match[1];
+ if (!match || match.indexOf('}') === -1) {
+ match = node.match[0];
+ }
+
+ // replace each set with a single ","
+ var val = match.replace(/\{/g, ',').replace(/\}/g, '');
+ node.multiplier *= val.length;
+ node.val = '';
+ }
+
+ var simpleText = last.type === 'text'
+ && last.multiplier === 1
+ && node.multiplier === 1
+ && node.val;
+
+ if (simpleText) {
+ last.val += node.val;
+ return;
+ }
+
+ prev.push(node);
+}