Comparing version 1.4.8 to 1.5.0
{ | ||
"name": "astq", | ||
"version": "1.4.8", | ||
"version": "1.5.0", | ||
"description": "Abstract Syntax Tree (AST) Query Engine", | ||
@@ -5,0 +5,0 @@ "main": "lib/astq.browser.js", |
@@ -25,3 +25,3 @@ { | ||
"maxdepth": 7, | ||
"maxstatements": 150, | ||
"maxstatements": 200, | ||
"maxlen": 200, | ||
@@ -28,0 +28,0 @@ "loopfunc": true, |
{ | ||
"name": "astq", | ||
"version": "1.4.8", | ||
"version": "1.5.0", | ||
"description": "Abstract Syntax Tree (AST) Query Engine", | ||
@@ -23,3 +23,3 @@ "keywords": [ "abstract", "syntax", "tree", "query", "engine", "adaptable" ], | ||
"pegjs-util": "~1.0.6", | ||
"asty": "~1.2.1", | ||
"asty": "~1.2.2", | ||
"cache-lru": "~1.0.7" | ||
@@ -33,10 +33,10 @@ }, | ||
"grunt-browserify": "~4.0.0", | ||
"grunt-jscs": "~2.0.0", | ||
"grunt-jscs": "~2.1.0", | ||
"grunt-mocha-test": "~0.12.7", | ||
"grunt-eslint": "~17.0.0", | ||
"babel-eslint": "~4.0.5", | ||
"grunt-eslint": "~17.1.0", | ||
"babel-eslint": "~4.0.10", | ||
"mocha": "~2.2.5", | ||
"chai": "~3.2.0", | ||
"babelify": "~6.1.3", | ||
"minifyify": "~7.0.3", | ||
"minifyify": "~7.0.5", | ||
"browserify-header": "~0.9.2", | ||
@@ -43,0 +43,0 @@ "browserify-derequire": "~0.9.4", |
@@ -67,7 +67,10 @@ | ||
separated by comma. A path consists of a mandatory initial query step | ||
and optionally zero or more subsequent query steps. The difference | ||
between initial and subsequent query steps is | ||
that an initial query step does not need an axis while all subsequent | ||
query steps require it. | ||
and optionally zero or more subsequent query steps. | ||
The difference between initial and subsequent query steps is that an | ||
initial query step does not need an axis while all subsequent query | ||
steps require it. A query step consists of an (optional) AST node search | ||
axis, a (mandatory) AST node type match and an (optional) AST node | ||
filter expression: | ||
query ::= path (, path)* | ||
@@ -78,10 +81,62 @@ path ::= step-initial step-subsequent* | ||
A query step consists of an (optional) AST node search axis (direct/any child, | ||
direct/any left/right sibling or direct/any parent), a (mandatory) AST node type | ||
match and an (optional) AST node filter expression: | ||
The search axis can be either for direct (`/`) or any (`//`) child | ||
nodes, for direct (`-/`) or any (`-//`) left sibling node(s), for direct | ||
(`+/`) or any (`+//`) right sibling node(s), for direct (`../`) or any | ||
(`..//`) parent node(s), for any preceding nodes (`<//`), or for any | ||
following nodes (`>//`). | ||
axis ::= ("//" | "/" | "+//" | "+/" | "-//" | "-/" | "../" | "..//") (":" id)? | ||
match ::= id | "*" | ||
filter ::= "[" expr "]" | ||
As an illustrating example: given an AST of the following particular | ||
nodes... | ||
A | ||
| | ||
+-+-+-+-+ | ||
/ / | \ \ | ||
B C D E F | ||
| | ||
+--+--+ | ||
/ | \ | ||
G H I | ||
| | ||
+-+-+ | ||
/ \ | ||
J K | ||
...the following queries and their result exist: | ||
Start Node | Query | Result Node(s) | ||
-----------|----------|---------------- | ||
`D` | `/ *` | `G, H, I` | ||
`D` | `// *` | `G, H, J, K, I` | ||
`D` | `-/ *` | `C` | ||
`D` | `-// *` | `C, B` | ||
`D` | `+/ *` | `E` | ||
`D` | `+// *` | `E, F` | ||
`H` | `../ *` | `D` | ||
`H` | `..// *` | `D, A` | ||
`H` | `<// *` | `G, D, C B A` | ||
`H` | `>// *` | `J, K, I, E, F` | ||
A search axis usually walks along the references between nodes (at least | ||
in case of ASTy based AST). But in case the underlying AST and its | ||
adapter uses typed references, you can optionally constrain the search | ||
axis to take only references matching the type `id` into account. | ||
axis ::= axis-direction axis-type? | ||
axis-direction ::= axis-child | ||
| axis-sibling-left | ||
| axis-sibling-right | ||
| axis-parent | ||
| axis-preceding | ||
| axis-following | ||
axis-child ::= ("/" | "//") | ||
axis-sibling-left ::= ("-/" | "-//") | ||
axis-sibling-right ::= ("+/" | "+//") | ||
axis-parent ::= ("../" | "..//") | ||
axis-preceding ::= "<//" | ||
axis-following ::= ">//" | ||
axis-type ::= ":" id | ||
match ::= id | "*" | ||
filter ::= "[" expr "]" | ||
The real power comes through the optional filter expression: it can be | ||
@@ -95,3 +150,3 @@ applied to each query step and it recursively(!) can contain sub-queries | ||
+------------------------------------------------+ +-----+ path | ||
+---------------------+ +-----+ path | ||
+---------------------+ +-----+ path | ||
+----+ +-----------------------------------------+ +-----+ step | ||
@@ -164,2 +219,3 @@ ++ + + + ++ axis | ||
Calling `adapter()` causes these three to be replaced with a single custom adapter. | ||
Returns the API itself. | ||
@@ -182,3 +238,3 @@ /* the built-in implementation for supporting ASTy */ | ||
to return an arbitrary value and optionally can access the current `node` with | ||
the help of the selected `adapter`. | ||
the help of the selected `adapter`. Returns the API itself. | ||
@@ -196,3 +252,3 @@ /* the built-in implementation for "depth" */ | ||
up to `num` ASTs of parsed queries will be cached. Set `num` to | ||
`0` to disable the cache at all. | ||
`0` to disable the cache at all. Returns the API itself. | ||
@@ -203,2 +259,3 @@ - `ASTQ#compile(selector: String, trace?: Boolean): ASTQQuery { | ||
If `trace` is `true` the compiling is dumped to the console. | ||
Returns the query object. | ||
@@ -209,2 +266,3 @@ - `ASTQ#execute(node: Object, query: ASTQQuery, params, trace?: Boolean): Object[]`:<br/> | ||
If `trace` is `true` the execution is dumped to the console. | ||
Returns an array of zero or more matching AST nodes. | ||
@@ -217,2 +275,3 @@ - `ASTQ#query(node: Object, selector: String, params?: Object, trace: Boolean): Object[]`: <br/> | ||
If `trace` is `true` the compiling and execution is dumped to the console. | ||
Returns an array of zero or more matching AST nodes. | ||
@@ -219,0 +278,0 @@ ### ASTQAdapter API |
@@ -122,3 +122,4 @@ /* | ||
} | ||
matchAndTake(leftSibling) | ||
if (leftSibling !== null) | ||
matchAndTake(leftSibling) | ||
} | ||
@@ -131,7 +132,8 @@ } | ||
let pchilds = this.adapter.getChildNodes(parent, t) | ||
for (let i = 0; i < pchilds.length; i++) { | ||
let i = 0 | ||
for (; i < pchilds.length; i++) | ||
if (pchilds[i] === T) | ||
break | ||
for (i--; i >= 0; i--) | ||
matchAndTake(pchilds[i]) | ||
} | ||
} | ||
@@ -148,6 +150,4 @@ } | ||
break | ||
if (i < pchilds.length) { | ||
i++ | ||
matchAndTake(pchilds[i]) | ||
} | ||
if (i < pchilds.length) | ||
matchAndTake(pchilds[++i]) | ||
} | ||
@@ -164,7 +164,5 @@ } | ||
break | ||
if (i < pchilds.length) { | ||
i++ | ||
while (i < pchilds.length) | ||
matchAndTake(pchilds[i++]) | ||
} | ||
if (i < pchilds.length) | ||
for (i++; i < pchilds.length; i++) | ||
matchAndTake(pchilds[i]) | ||
} | ||
@@ -189,2 +187,43 @@ } | ||
} | ||
else if (op === "<//") { | ||
/* transitive preceding nodes */ | ||
let ctx = { sentinel: T, take: true } | ||
for (;;) { | ||
let parent = this.adapter.getParentNode(T, "*") | ||
if (parent === null) | ||
break | ||
T = parent | ||
} | ||
let walk = (T) => { | ||
if (T === ctx.sentinel) | ||
ctx.take = false | ||
if (ctx.take) | ||
matchAndTake(T) | ||
if (ctx.take) | ||
this.adapter.getChildNodes(T, t).forEach((T) => walk(T)) /* RECURSION */ | ||
} | ||
if (T !== ctx.sentinel) { | ||
matchAndTake(T) | ||
this.adapter.getChildNodes(T, t).forEach((T) => walk(T)) | ||
} | ||
nodes = nodes.reverse() | ||
} | ||
else if (op === ">//") { | ||
/* transitive following nodes */ | ||
let ctx = { sentinel: T, take: false } | ||
for (;;) { | ||
let parent = this.adapter.getParentNode(T, "*") | ||
if (parent === null) | ||
break | ||
T = parent | ||
} | ||
let walk = (T) => { | ||
if (ctx.take) | ||
matchAndTake(T) | ||
if (T === ctx.sentinel) | ||
ctx.take = true | ||
this.adapter.getChildNodes(T, t).forEach((T) => walk(T)) /* RECURSION */ | ||
} | ||
this.adapter.getChildNodes(T, t).forEach((T) => walk(T)) | ||
} | ||
} | ||
@@ -191,0 +230,0 @@ else |
@@ -63,2 +63,4 @@ /* | ||
var node7 = asty.create("node7").set("quux", "baz") | ||
var node8 = asty.create("node8") | ||
var node9 = asty.create("node9") | ||
node1.add(node2) | ||
@@ -70,2 +72,4 @@ node1.add(node3) | ||
node3.add(node7) | ||
node6.add(node8) | ||
node6.add(node9) | ||
@@ -79,8 +83,13 @@ expect(astq.query(node1, "node1")).to.have.members([ node1 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' && +// * [ @quux == 'baz' ] ]")).to.have.members([ node6 ]) | ||
expect(astq.query(node1, "// * [ pos() <= 1 ]")).to.have.members([ node2, node5 ]) | ||
expect(astq.query(node1, "// * [ pos() <= 1 ]")).to.have.members([ node2, node5, node8 ]) | ||
expect(astq.query(node1, "// * [ count(/*) == 3 ]")).to.have.members([ node3 ]) | ||
expect(astq.query(node1, "// * [ depth() == 3 ]", {}, true)).to.have.members([ node5, node6, node7 ]) | ||
expect(astq.query(node1, "/ node2 ../ node1 / node2")).to.have.members([ node2 ]) | ||
expect(astq.query(node1, "*, // *")) | ||
.to.have.members([ node1, node2, node3, node5, node6, node8, node9, node7, node4 ]) | ||
expect(astq.query(node6, "<// *")).to.be.deep.equal([ node5, node3, node2, node1 ]) | ||
expect(astq.query(node6, ">// *")).to.be.deep.equal([ node8, node9, node7, node4 ]) | ||
}) | ||
}) | ||
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
521328
7038
369
Updatedasty@~1.2.2