From 011b9310b6d050985de3c33f1de73406b0e716c0 Mon Sep 17 00:00:00 2001 From: Nick Wronski Date: Wed, 14 Oct 2015 16:33:46 -0400 Subject: [PATCH 1/7] Added :has() pseudo-selector to grammar. --- esquery.js | 16 +++++++++ grammar.pegjs | 4 ++- parser.js | 88 ++++++++++++++++++++++++++++++++++++++++++++--- tests/queryHas.js | 17 +++++++++ 4 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 tests/queryHas.js diff --git a/esquery.js b/esquery.js index cad6640..887b7de 100644 --- a/esquery.js +++ b/esquery.js @@ -80,6 +80,22 @@ } return true; + case 'has': + var a, collector = []; + for (i = 0, l = selector.selectors.length; i < l; ++i) { + a = []; + estraverse.traverse(node, { + enter: function (node, parent) { + if (parent != null) { a.unshift(parent); } + if (matches(node, selector.selectors[i], a)) { + collector.push(node); + } + }, + leave: function () { a.shift(); } + }); + } + return collector.length !== 0; + case 'child': if (matches(node, selector.right, ancestry)) { return matches(ancestry[0], selector.left, ancestry.slice(1)); diff --git a/grammar.pegjs b/grammar.pegjs index d124c51..34e1c59 100644 --- a/grammar.pegjs +++ b/grammar.pegjs @@ -49,7 +49,7 @@ sequence atom = wildcard / identifier / attr / field / negation / matches - / firstChild / lastChild / nthChild / nthLastChild / class + / has / firstChild / lastChild / nthChild / nthLastChild / class wildcard = a:"*" { return { type: 'wildcard', value: a }; } identifier = "#"? i:identifierName { return { type: 'identifier', value: i }; } @@ -88,12 +88,14 @@ field = "." i:identifierName is:("." identifierName)* { negation = ":not(" _ ss:selectors _ ")" { return { type: 'not', selectors: ss }; } matches = ":matches(" _ ss:selectors _ ")" { return { type: 'matches', selectors: ss }; } +has = ":has(" _ ss:selectors _ ")" { return { type: 'has', selectors: ss }; } firstChild = ":first-child" { return nth(1); } lastChild = ":last-child" { return nthLast(1); } nthChild = ":nth-child(" _ n:[0-9]+ _ ")" { return nth(parseInt(n.join(''), 10)); } nthLastChild = ":nth-last-child(" _ n:[0-9]+ _ ")" { return nthLast(parseInt(n.join(''), 10)); } + class = ":" c:("statement"i / "expression"i / "declaration"i / "function"i / "pattern"i) { return { type: 'class', name: c }; } diff --git a/parser.js b/parser.js index 2ce8134..5e250f7 100644 --- a/parser.js +++ b/parser.js @@ -60,6 +60,7 @@ var result = (function(){ "field": parse_field, "negation": parse_negation, "matches": parse_matches, + "has": parse_has, "firstChild": parse_firstChild, "lastChild": parse_lastChild, "nthChild": parse_nthChild, @@ -700,15 +701,18 @@ var result = (function(){ if (result0 === null) { result0 = parse_matches(); if (result0 === null) { - result0 = parse_firstChild(); + result0 = parse_has(); if (result0 === null) { - result0 = parse_lastChild(); + result0 = parse_firstChild(); if (result0 === null) { - result0 = parse_nthChild(); + result0 = parse_lastChild(); if (result0 === null) { - result0 = parse_nthLastChild(); + result0 = parse_nthChild(); if (result0 === null) { - result0 = parse_class(); + result0 = parse_nthLastChild(); + if (result0 === null) { + result0 = parse_class(); + } } } } @@ -2073,6 +2077,80 @@ var result = (function(){ return result0; } + function parse_has() { + var cacheKey = "has@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5) === ":has(") { + result0 = ":has("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":has(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_selectors(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, ss) { return { type: 'has', selectors: ss }; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + function parse_firstChild() { var cacheKey = "firstChild@" + pos; var cachedResult = cache[cacheKey]; diff --git a/tests/queryHas.js b/tests/queryHas.js new file mode 100644 index 0000000..041f18a --- /dev/null +++ b/tests/queryHas.js @@ -0,0 +1,17 @@ + +define([ + "esquery", + "jstestr/assert", + "jstestr/test", + "./fixtures/conditional" +], function (esquery, assert, test, conditional) { + + test.defineSuite("Parent selector query", { + + "conditional": function () { + var matches = esquery(conditional, 'ExpressionStatement:has([name="foo"][type="Identifier"])'); + assert.isEqual(1, matches.length); + } + + }); +}); From 7d05c2c76033761c43bea6f5af7450be2792eedb Mon Sep 17 00:00:00 2001 From: Nick Wronski Date: Wed, 14 Oct 2015 16:59:31 -0400 Subject: [PATCH 2/7] Latest compatible dependencies. --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b138264..33318c1 100644 --- a/package.json +++ b/package.json @@ -25,16 +25,16 @@ "query" ], "devDependencies": { + "commonjs-everywhere": "~0.9.7", + "esprima": "~2.6.0", "jstestr": ">=0.4", - "pegjs": "~0.7.0", - "commonjs-everywhere": "~0.9.4", - "esprima": "~1.1.1" + "pegjs": "^0.7.0" }, "license": "BSD", "engines": { "node": ">=0.6" }, "dependencies": { - "estraverse": "^4.0.0" + "estraverse": "^4.1.0" } } From 395937882f4cbfe7b180d680342da1d817c71d8b Mon Sep 17 00:00:00 2001 From: Nick Wronski Date: Wed, 14 Oct 2015 17:15:50 -0400 Subject: [PATCH 3/7] Version bump to 0.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33318c1..21aecca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "esquery", "preferGlobal": false, - "version": "0.4.0", + "version": "0.4.1", "author": "Joel Feenstra ", "description": "A query library for ECMAScript AST using a CSS selector like query language.", "main": "esquery.js", From e1da92d78f4790f4560d7d45a75427b9019a48bd Mon Sep 17 00:00:00 2001 From: Kristian Mandrup Date: Mon, 31 Oct 2016 18:12:06 +0100 Subject: [PATCH 4/7] update deps and add API usage doc with examples --- API usage.md | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 +- package.json | 10 +-- 3 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 API usage.md diff --git a/API usage.md b/API usage.md new file mode 100644 index 0000000..e305b8d --- /dev/null +++ b/API usage.md @@ -0,0 +1,241 @@ +## API and usage + +The following examples are taken from the test cases in `/tests` folder. + +### Attribute query + +*for loop* + +`for (i = 0; i < foo.length; i++) { foo[i](); }` + +- `[operator="=\]` - matches `i = 0` +- `[object.name="foo"]` - object named `foo` ie. `foo.length` +- `[name=/i|foo/]` - where name of node matches `i` or `foo` + +*simple function* + +```js +function foo(x, y) { + var z = x + y; + z++; + return z; +} +``` + +- `[kind="var"]` - a `var` +- `[id.name="foo"]` - `foo` declaration, fx a function or variable +- `[left]` - left expression, such as `var z` +- `FunctionDeclaration[params.0.name=x]` - where first argument of function is named `x` + +*simple program* + +```js +var x = 1; +var y = 'y'; +x = x * 2; +if (y) { y += 'z'; } +``` + +- `[body]` - full body, such as function/scope body +- `[body.length<2]` - body has less than 2 nodes +- `[body.length>1]` - body has more than 1 node +- `[body.length<=2]` - body has 2 or less nodes +- `[body.length>=1]` - body has 1 or more nodes +- `[name=/[asdfy]/]` - name matches the characters `asdfy` + +*conditional* + +```js +if (x === 1) { foo(); } else { x = 2; } +if (x == 'test' && true || x) { y = -1; } else if (false) { y = 1; } +``` + +- `[name="x"]` - node named `x` +- `[name!="x"]` - node not named `x` +- `[name=/x|foo/]` - node matches `x` or `foo` +- `[name!=/x|y/]` - node does not match `x` or `y` +- `[callee.name="foo"]` - Where `callee` is named `foo` (ie. function call) +- `[operator]` - That is any type of operator (such as `==`, `||` etc) +- `[prefix=true]` - node that has `prefix` set to true, such as `++c` +- `[test=type(object)]` - where subject of condition is an object, such as `x` in `|| x` +- `[value=type(boolean)]` - where value is a boolean, such +as `&& true` + +Example: `prefix` + +AST node representing unary operators such as `++`, `~`, `typeof` and `delete`" + +`++c` has `prefix: true` and `c++` has `prefix: false` + +```js +interface UnaryExpression <: Expression { + type: "UnaryExpression"; + operator: UnaryOperator; + prefix: boolean; + argument: Expression; +} +``` + +### Classes + +`:statement` - a statement +`:expression` - an expression +`:function` - a function +`:declaration` - a declaration +`:pattern` - a pattern + +Examples: + +`[name="x"]:function` - function named `x` +`[name="foo"]:declaration` - declaration named `foo` + +## Complex + +- descendant selector (` ` space) +- child selector (`>`) +- adjacent sibling selector (`+`) +- general sibling selector (`~`) + +Please see [javascript: expressions-vs-statements](http://www.2ality.com/2012/09/expressions-vs-statements.html) + +`IfStatement > BinaryExpression` - `if` statement followed by a [binary expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators) fx `3+4` or `x*y` + +Valid: `if (2 === 2)` + +`IfStatement > BinaryExpression > Identifier` + +Valid: `if (x === 2)` + +`IfStatement BinaryExpression` + +An `if` statement with any binary expression below it. + +`VariableDeclaration ~ IfStatement` + +`var` declaration with sibling `if` statement + +Valid: siblings of same body +```js +var x = 1; +if (x === 2) +``` + +`VariableDeclaration + ExpressionStatement` + +Valid: variable declaration followed by next sibling which is an expression statement (see [javascript statements and declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements)) + +```js +var y = 'y'; +x = x * 2; +``` + +### Compound + +`[left.name="x"][right.value=1]` - where the left side is a node name `x` and the right has the value `1` + +Valid: `x = 1` + +`[left.name="x"]:matches(*)` any type of node where the left side is named `x` + +### Descendant + +`Program IfStatement` - Any program with an `if` statement + +`Identifier[name=x]` - identified named `x` such as `const x`. Identifiers are used to name variables and functions and to provide labels for certain loops... + +`Identifier [name=x]` - any identifier with named `x`, such as `const x` + +`BinaryExpression [name=x]` a binary expression where one side is named `x`, such as `x !== 3` + +`AssignmentExpression [name=x]` an assignment where one side is named `x`, such as `x = 2` or `y = x` + +### Fields + +You can also query on the [Mozilla Parser API](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API) fields directly + +Example: + +```js +interface IfStatement <: Statement { + type: "IfStatement"; + test: Expression; + consequent: Statement; + alternate: Statement | null; +} +``` + +`.test` - node (object) that has a `test` field set +`.declarations.init` - node that has `.declarations.init` set + +`init` means initialised, such as `var x = 1`, where `x` is initialised to value `1` + +```js +interface VariableDeclaration <: Declaration { + type: "VariableDeclaration"; + declarations: [ VariableDeclarator ]; + kind: "var" | "let" | "const"; +} + +interface VariableDeclarator <: Node { + type: "VariableDeclarator"; + id: Pattern; + init: Expression | null; +} +``` + +### :has + +`ExpressionStatement:has([name="foo"][type="Identifier"])` + +Valid: `const foo = 2` + +### Matches + +`,` means OR (ie. any of) + +- `:matches(IfStatement)` +- `:matches(BinaryExpression, MemberExpression)` +- `:matches([name="foo"], ReturnStatement)` +- `:matches(AssignmentExpression, BinaryExpression)` +- `AssignmentExpression, BinaryExpression, NonExistant` + +### Not + +- `:not(Literal)` not a literal +- `:not([name="x"])` not a node named `x` +- `:not(*)` - not anything! +- `:not(Identifier, IfStatement)` +- `:not([value=1])` not a node set to value of `1` + +### Pseudo child + +`:first-child` - first child node +`:last-child` - last child node +`:nth-child(2)` - 2nd child +`:nth-last-child(2)` - 2nd last child + +### Subject + +`!IfStatement Identifier` - any not an If statement with an Identifier under, such as `const x = 3` but not `if (x == 2)` + +`!* > [name="foo"]` all nodes but those where the immediate child is a node namded `foo` + +More examples: + +- `![test] [name="y"]` +- `![generator=type(boolean)] > BlockStatement` +- `![operator=/=+/] > [name="x"]` +- `!:matches(*) > [name="foo"]` +- `!:not(BlockStatement) > [name="foo"]` +- `![left.name="x"][right.value=1]` +- `* !AssignmentExpression` +- `!VariableDeclaration ~ IfStatement` +- `!VariableDeclaration + !ExpressionStatement` + +### Types + +- `LogicalExpression` +- `ForStatement` +- `FunctionDeclaration` +- `ReturnStatement` +- `AssignmentExpression` diff --git a/README.md b/README.md index a3ee334..a010be0 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,6 @@ The following selectors are supported: * [subject indicator](http://dev.w3.org/csswg/selectors4/#subject): `!IfStatement > [name="foo"]` * class of AST node: `:statement`, `:expression`, `:declaration`, `:function`, or `:pattern` -[![Build Status](https://travis-ci.org/estools/esquery.png?branch=master)](https://travis-ci.org/estools/esquery) +See `API usage.md` document for API usage examples and explanations. + +[![Build Status](https://travis-ci.org/estools/esquery.png?branch=master)](https://travis-ci.org/estools/esquery) \ No newline at end of file diff --git a/package.json b/package.json index 21aecca..bc8ae5f 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,15 @@ ], "devDependencies": { "commonjs-everywhere": "~0.9.7", - "esprima": "~2.6.0", - "jstestr": ">=0.4", - "pegjs": "^0.7.0" + "esprima": "^3.1.0", + "jstestr": "^0.4.2", + "pegjs": "^0.10.0" }, "license": "BSD", "engines": { - "node": ">=0.6" + "node": ">=5.0.0" }, "dependencies": { - "estraverse": "^4.1.0" + "estraverse": "^4.2.0" } } From c29c6224d9e85bff0412af57a7550af2ee7aea34 Mon Sep 17 00:00:00 2001 From: Kristian Mandrup Date: Mon, 31 Oct 2016 18:40:10 +0100 Subject: [PATCH 5/7] add quick start --- API usage.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/API usage.md b/API usage.md index e305b8d..9388404 100644 --- a/API usage.md +++ b/API usage.md @@ -1,5 +1,20 @@ ## API and usage +*Install (via npm for Node.js)* + +`npm i esquery --save` + +*Quick start* + +```js +const esquery = require('esquery'); + +const conditional = "if (x === 1) { foo(); } else { x = 2; }" + +var matches = esquery(conditional, "[name='x']") +console.log(matches); +``` + The following examples are taken from the test cases in `/tests` folder. ### Attribute query @@ -8,7 +23,7 @@ The following examples are taken from the test cases in `/tests` folder. `for (i = 0; i < foo.length; i++) { foo[i](); }` -- `[operator="=\]` - matches `i = 0` +- `[operator="="]` - matches `i = 0` - `[object.name="foo"]` - object named `foo` ie. `foo.length` - `[name=/i|foo/]` - where name of node matches `i` or `foo` From ee41f840d5b1eac71604b252bbe21e947a7696ff Mon Sep 17 00:00:00 2001 From: Kristian Mandrup Date: Tue, 22 Nov 2016 14:36:31 +0100 Subject: [PATCH 6/7] added shorthands --- API usage.md | 49 ++++++ parser.js | 355 ++++++++++++++++++++++++------------------ tests/queryComplex.js | 36 +++++ 3 files changed, 288 insertions(+), 152 deletions(-) diff --git a/API usage.md b/API usage.md index 9388404..d16c291 100644 --- a/API usage.md +++ b/API usage.md @@ -144,6 +144,55 @@ var y = 'y'; x = x * 2; ``` +*Shorthands* + +There are also shorthands such as: + +`@If > @Binary` equivalent to `IfStatement > BinaryExpression` + +See `translateInput` function in `parser.js` for the full list of supported shorthands and translations. + +- `@If`: `IfExpression` +- `@Id`: `Identifier` +- `@Var`: `VariableDeclaration` +- `@Expr` +- `@Member` +- `@Return` +- `@Block` +- `@ForIn` +- `@ForOf` +- `@For` +- `@Empty` +- `@Labeled` +- `@Break` +- `@Continue` +- `@Switch` +- `@Throw` +- `@Try` +- `@While` +- `@DoWhile` +- `@Let` +- `@This` +- `@Array` +- `@Object` +- `@FunDecl` +- `@Fun` +- `@Arrow` +- `@Seq` +- `@Cond` +- `@New` +- `@Member` +- `@Yield` +- `@Gen` +- `@UnaryOp` +- `@Unary` +- `@BinaryOp` +- `@Binary` +- `@LogicalOp` +- `@Logical` +- `@AssignOp` +- `@Assign` + ### Compound `[left.name="x"][right.value=1]` - where the left side is a node name `x` and the right has the value `1` diff --git a/parser.js b/parser.js index 5e250f7..adc99ea 100644 --- a/parser.js +++ b/parser.js @@ -4,7 +4,7 @@ var result = (function(){ * * http://pegjs.majda.cz/ */ - + function quote(s) { /* * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a @@ -27,7 +27,54 @@ var result = (function(){ .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } - + + function translateInput(input) { + input = input.replace(/@If($|[^S])/, 'IfStatement ') + input = input.replace(/@Id($|[^e])/, 'Identifier ') + input = input.replace(/@Var($|[^i])/, 'VariableDeclaration ') + input = input.replace(/@Expr($|[^e])/, 'ExpressionStatement ') + input = input.replace(/@Member($|[^E])/, 'MemberExpression ') + input = input.replace(/@Return($|[^S])/, 'ReturnStatement ') + input = input.replace(/@Block($|[^S])/, 'BlockStatement ') + input = input.replace(/@ForIn($|[^S])/, 'ForInStatement ') + input = input.replace(/@ForOf($|[^S])/, 'ForOfStatement ') + input = input.replace(/@For($|[^S])/, 'ForStatement ') + input = input.replace(/@Empty($|[^S])/, 'EmptyStatement ') + input = input.replace(/@Labeled($|[^S])/, 'LabeledStatement ') + input = input.replace(/@Break($|[^S])/, 'BreakStatement ') + input = input.replace(/@Continue($|[^S])/, 'ContinueStatement ') + input = input.replace(/@With($|[^S])/, 'WithStatement ') + input = input.replace(/@Switch($|[^S])/, 'SwitchStatement ') + input = input.replace(/@Throw($|[^S])/, 'ThrowStatement ') + input = input.replace(/@Try($|[^S])/, 'TryStatement ') + input = input.replace(/@While($|[^S])/, 'WhileStatement ') + input = input.replace(/@DoWhile($|[^S])/, 'DoWhileStatement ') + input = input.replace(/@Let($|[^S])/, 'LetStatement ') + input = input.replace(/@This($|[^S])/, 'ThisExpression ') + input = input.replace(/@Array($|[^S])/, 'ArrayExpression ') + input = input.replace(/@Object($|[^S])/, 'ObjectExpression ') + input = input.replace(/@FunDecl($|[^a])/, 'FunctionDeclaration ') + input = input.replace(/@Fun($|[^c])/, 'FunctionExpression ') + input = input.replace(/@Arrow($|[^E])/, 'ArrowExpression ') + input = input.replace(/@Seq($|[^u])/, 'SequenceExpression ') + input = input.replace(/@Cond($|[^i])/, 'ConditionalExpression ') + input = input.replace(/@New($|[^E])/, 'NewExpression ') + input = input.replace(/@Call($|[^E])/, 'CallExpression ') + input = input.replace(/@Member($|[^E])/, 'MemberExpression ') + input = input.replace(/@Yield($|[^E])/, 'YieldExpression ') + input = input.replace(/@Gen($|[^e])/, 'GeneratorExpression ') + input = input.replace(/@UnaryOp($|[^e])/, 'UnaryOperator ') + input = input.replace(/@Unary($|[^E])/, 'UnaryExpression ') + input = input.replace(/@BinaryOp($|[^e])/, 'BinaryOperator ') + input = input.replace(/@Binary($|[^E])/, 'BinaryExpression ') + input = input.replace(/@LogicalOp($|[^e])/, 'LogicalOperator ') + input = input.replace(/@Logical($|[^E])/, 'LogicalExpression ') + input = input.replace(/@AssignOp($|[^e])/, 'AssignmentOperator ') + input = input.replace(/@Assign($|[^m])/, 'AssignmentExpression ') + + return input + } + var result = { /* * Parses the input with a generated parser. If the parsing is successfull, @@ -36,6 +83,10 @@ var result = (function(){ * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. */ parse: function(input, startRule) { + // console.log('parse', input, startRule) + input = translateInput(input) + // console.log('translated input for parse', input) + var parseFunctions = { "start": parse_start, "_": parse__, @@ -67,7 +118,7 @@ var result = (function(){ "nthLastChild": parse_nthLastChild, "class": parse_class }; - + if (startRule !== undefined) { if (parseFunctions[startRule] === undefined) { throw new Error("Invalid rule name: " + quote(startRule) + "."); @@ -75,29 +126,29 @@ var result = (function(){ } else { startRule = "start"; } - + var pos = 0; var reportFailures = 0; var rightmostFailuresPos = 0; var rightmostFailuresExpected = []; var cache = {}; - + function padLeft(input, padding, length) { var result = input; - + var padLength = length - input.length; for (var i = 0; i < padLength; i++) { result = padding + result; } - + return result; } - + function escape(ch) { var charCode = ch.charCodeAt(0); var escapeChar; var length; - + if (charCode <= 0xFF) { escapeChar = 'x'; length = 2; @@ -105,23 +156,23 @@ var result = (function(){ escapeChar = 'u'; length = 4; } - + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); } - + function matchFailed(failure) { if (pos < rightmostFailuresPos) { return; } - + if (pos > rightmostFailuresPos) { rightmostFailuresPos = pos; rightmostFailuresExpected = []; } - + rightmostFailuresExpected.push(failure); } - + function parse_start() { var cacheKey = "start@" + pos; var cachedResult = cache[cacheKey]; @@ -129,10 +180,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2; var pos0, pos1; - + pos0 = pos; pos1 = pos; result0 = parse__(); @@ -170,14 +221,14 @@ var result = (function(){ pos = pos0; } } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse__() { var cacheKey = "_@" + pos; var cachedResult = cache[cacheKey]; @@ -185,9 +236,9 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1; - + result0 = []; if (input.charCodeAt(pos) === 32) { result1 = " "; @@ -210,14 +261,14 @@ var result = (function(){ } } } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_identifierName() { var cacheKey = "identifierName@" + pos; var cachedResult = cache[cacheKey]; @@ -225,10 +276,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1; var pos0; - + pos0 = pos; if (/^[^ [\],():#!=><~+.]/.test(input.charAt(pos))) { result1 = input.charAt(pos); @@ -262,14 +313,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_binaryOp() { var cacheKey = "binaryOp@" + pos; var cachedResult = cache[cacheKey]; @@ -277,10 +328,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2; var pos0, pos1; - + pos0 = pos; pos1 = pos; result0 = parse__(); @@ -421,14 +472,14 @@ var result = (function(){ } } } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_selectors() { var cacheKey = "selectors@" + pos; var cachedResult = cache[cacheKey]; @@ -436,10 +487,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2, result3, result4, result5; var pos0, pos1, pos2; - + pos0 = pos; pos1 = pos; result0 = parse_selector(); @@ -534,14 +585,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_selector() { var cacheKey = "selector@" + pos; var cachedResult = cache[cacheKey]; @@ -549,10 +600,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2, result3; var pos0, pos1, pos2; - + pos0 = pos; pos1 = pos; result0 = parse_sequence(); @@ -609,14 +660,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_sequence() { var cacheKey = "sequence@" + pos; var cachedResult = cache[cacheKey]; @@ -624,10 +675,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2; var pos0, pos1; - + pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 33) { @@ -671,14 +722,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_atom() { var cacheKey = "atom@" + pos; var cachedResult = cache[cacheKey]; @@ -686,9 +737,9 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0; - + result0 = parse_wildcard(); if (result0 === null) { result0 = parse_identifier(); @@ -723,14 +774,14 @@ var result = (function(){ } } } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_wildcard() { var cacheKey = "wildcard@" + pos; var cachedResult = cache[cacheKey]; @@ -738,10 +789,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0; var pos0; - + pos0 = pos; if (input.charCodeAt(pos) === 42) { result0 = "*"; @@ -758,14 +809,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_identifier() { var cacheKey = "identifier@" + pos; var cachedResult = cache[cacheKey]; @@ -773,10 +824,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1; var pos0, pos1; - + pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 35) { @@ -807,14 +858,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_attr() { var cacheKey = "attr@" + pos; var cachedResult = cache[cacheKey]; @@ -822,10 +873,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1, result2, result3, result4; var pos0, pos1; - + pos0 = pos; pos1 = pos; if (input.charCodeAt(pos) === 91) { @@ -881,14 +932,14 @@ var result = (function(){ if (result0 === null) { pos = pos0; } - + cache[cacheKey] = { nextPos: pos, result: result0 }; return result0; } - + function parse_attrOps() { var cacheKey = "attrOps@" + pos; var cachedResult = cache[cacheKey]; @@ -896,10 +947,10 @@ var result = (function(){ pos = cachedResult.nextPos; return cachedResult.result; } - + var result0, result1; var pos0, pos1; - + pos0 = pos; pos1 = pos; if (/^[> @Binary"); + assert.contains([ + conditional.body[0].test + ], matches); + }, + "three types child": function () { var matches = esquery(conditional, "IfStatement > BinaryExpression > Identifier"); assert.contains([ @@ -26,6 +33,14 @@ define([ ], matches); }, + "three types child (shorthand)": function () { + var matches = esquery(conditional, "@If > @Binary > @Id"); + assert.contains([ + conditional.body[0].test.left + ], matches); + }, + + "two types descendant": function () { var matches = esquery(conditional, "IfStatement BinaryExpression"); assert.contains([ @@ -33,6 +48,13 @@ define([ ], matches); }, + "two types descendant (shorthand)": function () { + var matches = esquery(conditional, "@If @Binary"); + assert.contains([ + conditional.body[0].test + ], matches); + }, + "two types sibling": function () { var matches = esquery(simpleProgram, "VariableDeclaration ~ IfStatement"); assert.contains([ @@ -40,11 +62,25 @@ define([ ], matches); }, + "two types sibling (shorthand)": function () { + var matches = esquery(simpleProgram, "@Var ~ @If"); + assert.contains([ + simpleProgram.body[3] + ], matches); + }, + "two types adjacent": function () { var matches = esquery(simpleProgram, "VariableDeclaration + ExpressionStatement"); assert.contains([ simpleProgram.body[2] ], matches); + }, + + "two types adjacent (shorthand)": function () { + var matches = esquery(simpleProgram, "@Variable + @Expr"); + assert.contains([ + simpleProgram.body[2] + ], matches); } }); }); From 457fa591578ddedec8fc6060c0c009c3e89e7481 Mon Sep 17 00:00:00 2001 From: Kristian Mandrup Date: Wed, 13 Dec 2017 09:23:57 +0700 Subject: [PATCH 7/7] fix API docs as per suggestions by @michaelficarra in PR - simplify regexpr as per @GerHobbelt --- API usage.md | 38 ++-- parser.js | 489 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 340 insertions(+), 187 deletions(-) diff --git a/API usage.md b/API usage.md index d16c291..c95cb43 100644 --- a/API usage.md +++ b/API usage.md @@ -2,16 +2,16 @@ *Install (via npm for Node.js)* -`npm i esquery --save` +`npm install esquery --save` *Quick start* ```js const esquery = require('esquery'); -const conditional = "if (x === 1) { foo(); } else { x = 2; }" +const conditional = 'if (x === 1) { foo(); } else { x = 2; }' -var matches = esquery(conditional, "[name='x']") +var matches = esquery(conditional, '[name='x']') console.log(matches); ``` @@ -73,7 +73,7 @@ if (x == 'test' && true || x) { y = -1; } else if (false) { y = 1; } - `[operator]` - That is any type of operator (such as `==`, `||` etc) - `[prefix=true]` - node that has `prefix` set to true, such as `++c` - `[test=type(object)]` - where subject of condition is an object, such as `x` in `|| x` -- `[value=type(boolean)]` - where value is a boolean, such +- `[value=type(boolean)]` - where value is a boolean, such as `&& true` Example: `prefix` @@ -104,16 +104,18 @@ Examples: `[name="x"]:function` - function named `x` `[name="foo"]:declaration` - declaration named `foo` -## Complex +## Combinators - descendant selector (` ` space) - child selector (`>`) - adjacent sibling selector (`+`) - general sibling selector (`~`) -Please see [javascript: expressions-vs-statements](http://www.2ality.com/2012/09/expressions-vs-statements.html) +Please see [ESTree specification](https://github.com/estree/estree) and [CSS selectors spec](https://www.w3.org/TR/css3-selectors/) -`IfStatement > BinaryExpression` - `if` statement followed by a [binary expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators) fx `3+4` or `x*y` +`IfStatement > BinaryExpression` - [binary expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators) fx `3+4;` or `x*y;` + +A `BinaryExpression` nested directly within an `IfStatement` Valid: `if (2 === 2)` @@ -123,11 +125,11 @@ Valid: `if (x === 2)` `IfStatement BinaryExpression` -An `if` statement with any binary expression below it. +A binary expression nested arbitrarily deeply within an `if` statement. `VariableDeclaration ~ IfStatement` -`var` declaration with sibling `if` statement +`if` statement with sibling `var` declaration. The `if` statement is the target. Valid: siblings of same body ```js @@ -215,7 +217,7 @@ Valid: `x = 1` ### Fields -You can also query on the [Mozilla Parser API](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API) fields directly +You can also query on the [ESTree API](https://github.com/estree/estree) fields directly Example: @@ -280,21 +282,9 @@ Valid: `const foo = 2` ### Subject -`!IfStatement Identifier` - any not an If statement with an Identifier under, such as `const x = 3` but not `if (x == 2)` - -`!* > [name="foo"]` all nodes but those where the immediate child is a node namded `foo` - -More examples: +`!IfStatement Identifier` - any `if` statement with one or more nested `Identifier`, such as `const x = 3` but not `if (x == 2)` -- `![test] [name="y"]` -- `![generator=type(boolean)] > BlockStatement` -- `![operator=/=+/] > [name="x"]` -- `!:matches(*) > [name="foo"]` -- `!:not(BlockStatement) > [name="foo"]` -- `![left.name="x"][right.value=1]` -- `* !AssignmentExpression` -- `!VariableDeclaration ~ IfStatement` -- `!VariableDeclaration + !ExpressionStatement` +`!* > [name="foo"]` all nodes but those where the immediate child is a node named `foo` ### Types diff --git a/parser.js b/parser.js index adc99ea..f4c2532 100644 --- a/parser.js +++ b/parser.js @@ -1,4 +1,4 @@ -var result = (function(){ +var result = (function () { /* * Generated by PEG.js 0.7.0. * @@ -16,61 +16,61 @@ var result = (function(){ * characters. Note that "\0" and "\v" escape sequences are not used * because JSHint does not like the first and IE the second. */ - return '"' + s - .replace(/\\/g, '\\\\') // backslash - .replace(/"/g, '\\"') // closing quote character + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character .replace(/\x08/g, '\\b') // backspace - .replace(/\t/g, '\\t') // horizontal tab - .replace(/\n/g, '\\n') // line feed - .replace(/\f/g, '\\f') // form feed - .replace(/\r/g, '\\r') // carriage return - .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) - + '"'; + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; } function translateInput(input) { - input = input.replace(/@If($|[^S])/, 'IfStatement ') - input = input.replace(/@Id($|[^e])/, 'Identifier ') - input = input.replace(/@Var($|[^i])/, 'VariableDeclaration ') - input = input.replace(/@Expr($|[^e])/, 'ExpressionStatement ') - input = input.replace(/@Member($|[^E])/, 'MemberExpression ') - input = input.replace(/@Return($|[^S])/, 'ReturnStatement ') - input = input.replace(/@Block($|[^S])/, 'BlockStatement ') - input = input.replace(/@ForIn($|[^S])/, 'ForInStatement ') - input = input.replace(/@ForOf($|[^S])/, 'ForOfStatement ') - input = input.replace(/@For($|[^S])/, 'ForStatement ') - input = input.replace(/@Empty($|[^S])/, 'EmptyStatement ') - input = input.replace(/@Labeled($|[^S])/, 'LabeledStatement ') - input = input.replace(/@Break($|[^S])/, 'BreakStatement ') - input = input.replace(/@Continue($|[^S])/, 'ContinueStatement ') - input = input.replace(/@With($|[^S])/, 'WithStatement ') - input = input.replace(/@Switch($|[^S])/, 'SwitchStatement ') - input = input.replace(/@Throw($|[^S])/, 'ThrowStatement ') - input = input.replace(/@Try($|[^S])/, 'TryStatement ') - input = input.replace(/@While($|[^S])/, 'WhileStatement ') - input = input.replace(/@DoWhile($|[^S])/, 'DoWhileStatement ') - input = input.replace(/@Let($|[^S])/, 'LetStatement ') - input = input.replace(/@This($|[^S])/, 'ThisExpression ') - input = input.replace(/@Array($|[^S])/, 'ArrayExpression ') - input = input.replace(/@Object($|[^S])/, 'ObjectExpression ') - input = input.replace(/@FunDecl($|[^a])/, 'FunctionDeclaration ') - input = input.replace(/@Fun($|[^c])/, 'FunctionExpression ') - input = input.replace(/@Arrow($|[^E])/, 'ArrowExpression ') - input = input.replace(/@Seq($|[^u])/, 'SequenceExpression ') - input = input.replace(/@Cond($|[^i])/, 'ConditionalExpression ') - input = input.replace(/@New($|[^E])/, 'NewExpression ') - input = input.replace(/@Call($|[^E])/, 'CallExpression ') - input = input.replace(/@Member($|[^E])/, 'MemberExpression ') - input = input.replace(/@Yield($|[^E])/, 'YieldExpression ') - input = input.replace(/@Gen($|[^e])/, 'GeneratorExpression ') - input = input.replace(/@UnaryOp($|[^e])/, 'UnaryOperator ') - input = input.replace(/@Unary($|[^E])/, 'UnaryExpression ') - input = input.replace(/@BinaryOp($|[^e])/, 'BinaryOperator ') - input = input.replace(/@Binary($|[^E])/, 'BinaryExpression ') - input = input.replace(/@LogicalOp($|[^e])/, 'LogicalOperator ') - input = input.replace(/@Logical($|[^E])/, 'LogicalExpression ') - input = input.replace(/@AssignOp($|[^e])/, 'AssignmentOperator ') - input = input.replace(/@Assign($|[^m])/, 'AssignmentExpression ') + input = input.replace(/@If\b/, 'IfStatement ') + input = input.replace(/@Id\b/, 'Identifier ') + input = input.replace(/@Var\b/, 'VariableDeclaration ') + input = input.replace(/@Expr\b/, 'ExpressionStatement ') + input = input.replace(/@Member\b/, 'MemberExpression ') + input = input.replace(/@Return\b/, 'ReturnStatement ') + input = input.replace(/@Block\b/, 'BlockStatement ') + input = input.replace(/@ForIn\b/, 'ForInStatement ') + input = input.replace(/@ForOf\b/, 'ForOfStatement ') + input = input.replace(/@For\b/, 'ForStatement ') + input = input.replace(/@Empty\b/, 'EmptyStatement ') + input = input.replace(/@Labeled\b/, 'LabeledStatement ') + input = input.replace(/@Break\b/, 'BreakStatement ') + input = input.replace(/@Continue\b/, 'ContinueStatement ') + input = input.replace(/@With\b/, 'WithStatement ') + input = input.replace(/@Switch\b/, 'SwitchStatement ') + input = input.replace(/@Throw\b/, 'ThrowStatement ') + input = input.replace(/@Try\b/, 'TryStatement ') + input = input.replace(/@While\b/, 'WhileStatement ') + input = input.replace(/@DoWhile\b/, 'DoWhileStatement ') + input = input.replace(/@Let\b/, 'LetStatement ') + input = input.replace(/@This\b/, 'ThisExpression ') + input = input.replace(/@Array\b/, 'ArrayExpression ') + input = input.replace(/@Object\b/, 'ObjectExpression ') + input = input.replace(/@FunDecl\b/, 'FunctionDeclaration ') + input = input.replace(/@Fun\b/, 'FunctionExpression ') + input = input.replace(/@Arrow\b/, 'ArrowExpression ') + input = input.replace(/@Seq\b/, 'SequenceExpression ') + input = input.replace(/@Cond\b/, 'ConditionalExpression ') + input = input.replace(/@New\b/, 'NewExpression ') + input = input.replace(/@Call\b/, 'CallExpression ') + input = input.replace(/@Member\b/, 'MemberExpression ') + input = input.replace(/@Yield\b/, 'YieldExpression ') + input = input.replace(/@Gen\b/, 'GeneratorExpression ') + input = input.replace(/@UnaryOp\b/, 'UnaryOperator ') + input = input.replace(/@Unary\b/, 'UnaryExpression ') + input = input.replace(/@BinaryOp\b/, 'BinaryOperator ') + input = input.replace(/@Binary\b/, 'BinaryExpression ') + input = input.replace(/@LogicalOp\b/, 'LogicalOperator ') + input = input.replace(/@Logical\b/, 'LogicalExpression ') + input = input.replace(/@AssignOp\b/, 'AssignmentOperator ') + input = input.replace(/@Assign\b/, 'AssignmentExpression ') return input } @@ -82,7 +82,7 @@ var result = (function(){ * which the parser was generated (see |PEG.buildParser|). If the parsing is * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. */ - parse: function(input, startRule) { + parse: function (input, startRule) { // console.log('parse', input, startRule) input = translateInput(input) // console.log('translated input for parse', input) @@ -206,7 +206,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, ss) { return ss.length === 1 ? ss[0] : { type: 'matches', selectors: ss }; })(pos0, result0[1]); + result0 = (function (offset, ss) { + return ss.length === 1 ? ss[0] : { + type: 'matches', + selectors: ss + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -215,7 +220,9 @@ var result = (function(){ pos0 = pos; result0 = parse__(); if (result0 !== null) { - result0 = (function(offset) { return void 0; })(pos0); + result0 = (function (offset) { + return void 0; + })(pos0); } if (result0 === null) { pos = pos0; @@ -224,7 +231,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -264,7 +271,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -308,7 +315,9 @@ var result = (function(){ result0 = null; } if (result0 !== null) { - result0 = (function(offset, i) { return i.join(''); })(pos0, result0); + result0 = (function (offset, i) { + return i.join(''); + })(pos0, result0); } if (result0 === null) { pos = pos0; @@ -316,7 +325,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -362,7 +371,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset) { return 'child'; })(pos0); + result0 = (function (offset) { + return 'child'; + })(pos0); } if (result0 === null) { pos = pos0; @@ -398,7 +409,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset) { return 'sibling'; })(pos0); + result0 = (function (offset) { + return 'sibling'; + })(pos0); } if (result0 === null) { pos = pos0; @@ -434,7 +447,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset) { return 'adjacent'; })(pos0); + result0 = (function (offset) { + return 'adjacent'; + })(pos0); } if (result0 === null) { pos = pos0; @@ -464,7 +479,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset) { return 'descendant'; })(pos0); + result0 = (function (offset) { + return 'descendant'; + })(pos0); } if (result0 === null) { pos = pos0; @@ -475,7 +492,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -578,9 +595,11 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, s, ss) { - return [s].concat(ss.map(function (s) { return s[3]; })); - })(pos0, result0[0], result0[1]); + result0 = (function (offset, s, ss) { + return [s].concat(ss.map(function (s) { + return s[3]; + })); + })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; @@ -588,7 +607,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -651,9 +670,13 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, a, ops) { + result0 = (function (offset, a, ops) { return ops.reduce(function (memo, rhs) { - return { type: rhs[0], left: memo, right: rhs[1] }; + return { + type: rhs[0], + left: memo, + right: rhs[1] + }; }, a); })(pos0, result0[0], result0[1]); } @@ -663,7 +686,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -713,9 +736,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, subject, as) { - var b = as.length === 1 ? as[0] : { type: 'compound', selectors: as }; - if(subject) b.subject = true; + result0 = (function (offset, subject, as) { + var b = as.length === 1 ? as[0] : { + type: 'compound', + selectors: as + }; + if (subject) b.subject = true; return b; })(pos0, result0[0], result0[1]); } @@ -725,7 +751,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -777,7 +803,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -804,7 +830,12 @@ var result = (function(){ } } if (result0 !== null) { - result0 = (function(offset, a) { return { type: 'wildcard', value: a }; })(pos0, result0); + result0 = (function (offset, a) { + return { + type: 'wildcard', + value: a + }; + })(pos0, result0); } if (result0 === null) { pos = pos0; @@ -812,7 +843,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -853,7 +884,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, i) { return { type: 'identifier', value: i }; })(pos0, result0[1]); + result0 = (function (offset, i) { + return { + type: 'identifier', + value: i + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -861,7 +897,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -927,7 +963,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, v) { return v; })(pos0, result0[2]); + result0 = (function (offset, v) { + return v; + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -935,7 +973,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -984,7 +1022,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, a) { return a + '='; })(pos0, result0[0]); + result0 = (function (offset, a) { + return a + '='; + })(pos0, result0[0]); } if (result0 === null) { pos = pos0; @@ -1003,7 +1043,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1052,7 +1092,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, a) { return a + '='; })(pos0, result0[0]); + result0 = (function (offset, a) { + return a + '='; + })(pos0, result0[0]); } if (result0 === null) { pos = pos0; @@ -1060,7 +1102,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1110,7 +1152,9 @@ var result = (function(){ result0 = null; } if (result0 !== null) { - result0 = (function(offset, i) { return i.join(''); })(pos0, result0); + result0 = (function (offset, i) { + return i.join(''); + })(pos0, result0); } if (result0 === null) { pos = pos0; @@ -1118,7 +1162,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1171,9 +1215,14 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, name, op, value) { - return { type: 'attribute', name: name, operator: op, value: value }; - })(pos0, result0[0], result0[2], result0[4]); + result0 = (function (offset, name, op, value) { + return { + type: 'attribute', + name: name, + operator: op, + value: value + }; + })(pos0, result0[0], result0[2], result0[4]); } if (result0 === null) { pos = pos0; @@ -1219,9 +1268,14 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, name, op, value) { - return { type: 'attribute', name: name, operator: op, value: value }; - })(pos0, result0[0], result0[2], result0[4]); + result0 = (function (offset, name, op, value) { + return { + type: 'attribute', + name: name, + operator: op, + value: value + }; + })(pos0, result0[0], result0[2], result0[4]); } if (result0 === null) { pos = pos0; @@ -1230,7 +1284,12 @@ var result = (function(){ pos0 = pos; result0 = parse_attrName(); if (result0 !== null) { - result0 = (function(offset, name) { return { type: 'attribute', name: name }; })(pos0, result0); + result0 = (function (offset, name) { + return { + type: 'attribute', + name: name + }; + })(pos0, result0); } if (result0 === null) { pos = pos0; @@ -1240,7 +1299,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1311,7 +1370,9 @@ var result = (function(){ pos = pos3; } if (result2 !== null) { - result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + result2 = (function (offset, a, b) { + return a + b; + })(pos2, result2[0], result2[1]); } if (result2 === null) { pos = pos2; @@ -1361,7 +1422,9 @@ var result = (function(){ pos = pos3; } if (result2 !== null) { - result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + result2 = (function (offset, a, b) { + return a + b; + })(pos2, result2[0], result2[1]); } if (result2 === null) { pos = pos2; @@ -1393,9 +1456,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, d) { - return { type: 'literal', value: strUnescape(d.join('')) }; - })(pos0, result0[1]); + result0 = (function (offset, d) { + return { + type: 'literal', + value: strUnescape(d.join('')) + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -1456,7 +1522,9 @@ var result = (function(){ pos = pos3; } if (result2 !== null) { - result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + result2 = (function (offset, a, b) { + return a + b; + })(pos2, result2[0], result2[1]); } if (result2 === null) { pos = pos2; @@ -1506,7 +1574,9 @@ var result = (function(){ pos = pos3; } if (result2 !== null) { - result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + result2 = (function (offset, a, b) { + return a + b; + })(pos2, result2[0], result2[1]); } if (result2 === null) { pos = pos2; @@ -1538,9 +1608,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, d) { - return { type: 'literal', value: strUnescape(d.join('')) }; - })(pos0, result0[1]); + result0 = (function (offset, d) { + return { + type: 'literal', + value: strUnescape(d.join('')) + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -1549,7 +1622,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1649,9 +1722,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, a, b) { - return { type: 'literal', value: parseFloat((a ? a.join('') : '') + b.join('')) }; - })(pos0, result0[0], result0[1]); + result0 = (function (offset, a, b) { + return { + type: 'literal', + value: parseFloat((a ? a.join('') : '') + b.join('')) + }; + })(pos0, result0[0], result0[1]); } if (result0 === null) { pos = pos0; @@ -1659,7 +1735,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1678,7 +1754,12 @@ var result = (function(){ pos0 = pos; result0 = parse_identifierName(); if (result0 !== null) { - result0 = (function(offset, i) { return { type: 'literal', value: i }; })(pos0, result0); + result0 = (function (offset, i) { + return { + type: 'literal', + value: i + }; + })(pos0, result0); } if (result0 === null) { pos = pos0; @@ -1686,7 +1767,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1777,7 +1858,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, t) { return { type: 'type', value: t.join('') }; })(pos0, result0[2]); + result0 = (function (offset, t) { + return { + type: 'type', + value: t.join('') + }; + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -1785,7 +1871,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1864,7 +1950,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, d) { return { type: 'regexp', value: new RegExp(d.join('')) }; })(pos0, result0[1]); + result0 = (function (offset, d) { + return { + type: 'regexp', + value: new RegExp(d.join('')) + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -1872,7 +1963,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -1965,9 +2056,14 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, i, is) { - return { type: 'field', name: is.reduce(function(memo, p){ return memo + p[0] + p[1]; }, i)}; - })(pos0, result0[1], result0[2]); + result0 = (function (offset, i, is) { + return { + type: 'field', + name: is.reduce(function (memo, p) { + return memo + p[0] + p[1]; + }, i) + }; + })(pos0, result0[1], result0[2]); } if (result0 === null) { pos = pos0; @@ -1975,7 +2071,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2041,7 +2137,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, ss) { return { type: 'not', selectors: ss }; })(pos0, result0[2]); + result0 = (function (offset, ss) { + return { + type: 'not', + selectors: ss + }; + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -2049,7 +2150,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2115,7 +2216,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, ss) { return { type: 'matches', selectors: ss }; })(pos0, result0[2]); + result0 = (function (offset, ss) { + return { + type: 'matches', + selectors: ss + }; + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -2123,7 +2229,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2189,7 +2295,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, ss) { return { type: 'has', selectors: ss }; })(pos0, result0[2]); + result0 = (function (offset, ss) { + return { + type: 'has', + selectors: ss + }; + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -2197,7 +2308,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2224,7 +2335,9 @@ var result = (function(){ } } if (result0 !== null) { - result0 = (function(offset) { return nth(1); })(pos0); + result0 = (function (offset) { + return nth(1); + })(pos0); } if (result0 === null) { pos = pos0; @@ -2232,7 +2345,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2259,7 +2372,9 @@ var result = (function(){ } } if (result0 !== null) { - result0 = (function(offset) { return nthLast(1); })(pos0); + result0 = (function (offset) { + return nthLast(1); + })(pos0); } if (result0 === null) { pos = pos0; @@ -2267,7 +2382,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2358,7 +2473,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, n) { return nth(parseInt(n.join(''), 10)); })(pos0, result0[2]); + result0 = (function (offset, n) { + return nth(parseInt(n.join(''), 10)); + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -2366,7 +2483,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2457,7 +2574,9 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, n) { return nthLast(parseInt(n.join(''), 10)); })(pos0, result0[2]); + result0 = (function (offset, n) { + return nthLast(parseInt(n.join(''), 10)); + })(pos0, result0[2]); } if (result0 === null) { pos = pos0; @@ -2465,7 +2584,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2557,9 +2676,12 @@ var result = (function(){ pos = pos1; } if (result0 !== null) { - result0 = (function(offset, c) { - return { type: 'class', name: c }; - })(pos0, result0[1]); + result0 = (function (offset, c) { + return { + type: 'class', + name: c + }; + })(pos0, result0[1]); } if (result0 === null) { pos = pos0; @@ -2567,7 +2689,7 @@ var result = (function(){ cache[cacheKey] = { nextPos: pos, - result: result0 + result: result0 }; return result0; } @@ -2602,7 +2724,9 @@ var result = (function(){ for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { var ch = input.charAt(i); if (ch === "\n") { - if (!seenCR) { line++; } + if (!seenCR) { + line++; + } column = 1; seenCR = false; } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { @@ -2615,26 +2739,55 @@ var result = (function(){ } } - return { line: line, column: column }; + return { + line: line, + column: column + }; } - function nth(n) { return { type: 'nth-child', index: { type: 'literal', value: n } }; } - function nthLast(n) { return { type: 'nth-last-child', index: { type: 'literal', value: n } }; } - function strUnescape(s) { - return s.replace(/\\(.)/g, function(match, ch) { - switch(ch) { - case 'a': return '\a'; - case 'b': return '\b'; - case 'f': return '\f'; - case 'n': return '\n'; - case 'r': return '\r'; - case 't': return '\t'; - case 'v': return '\v'; - default: return ch; - } - }); - } + function nth(n) { + return { + type: 'nth-child', + index: { + type: 'literal', + value: n + } + }; + } + + function nthLast(n) { + return { + type: 'nth-last-child', + index: { + type: 'literal', + value: n + } + }; + } + + function strUnescape(s) { + return s.replace(/\\(.)/g, function (match, ch) { + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + default: + return ch; + } + }); + } var result = parseFunctions[startRule](); @@ -2681,12 +2834,14 @@ var result = (function(){ }, /* Returns the parser source code. */ - toSource: function() { return this._source; } + toSource: function () { + return this._source; + } }; /* Thrown when a parser encounters a syntax error. */ - result.SyntaxError = function(expected, found, offset, line, column) { + result.SyntaxError = function (expected, found, offset, line, column) { function buildMessage(expected, found) { var expectedHumanized, foundHumanized; @@ -2698,9 +2853,9 @@ var result = (function(){ expectedHumanized = expected[0]; break; default: - expectedHumanized = expected.slice(0, expected.length - 1).join(", ") - + " or " - + expected[expected.length - 1]; + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; } foundHumanized = found ? quote(found) : "end of input"; @@ -2721,4 +2876,12 @@ var result = (function(){ return result; })(); -if (typeof define === "function" && define.amd) { define(function(){ return result; }); } else if (typeof module !== "undefined" && module.exports) { module.exports = result; } else { this.esquery = result; } +if (typeof define === "function" && define.amd) { + define(function () { + return result; + }); +} else if (typeof module !== "undefined" && module.exports) { + module.exports = result; +} else { + this.esquery = result; +}