Comparing version 1.5.0 to 1.5.1
{ | ||
"name": "astq", | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"description": "Abstract Syntax Tree (AST) Query Engine", | ||
@@ -5,0 +5,0 @@ "main": "lib/astq.browser.js", |
{ | ||
"name": "astq", | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"description": "Abstract Syntax Tree (AST) Query Engine", | ||
@@ -5,0 +5,0 @@ "keywords": [ "abstract", "syntax", "tree", "query", "engine", "adaptable" ], |
@@ -186,3 +186,3 @@ | ||
arithmethical ::= expr ("+" | "-" | "*" | "/" | "%" | "**") expr | ||
function-call ::= id "(" (param ("," param)*)? ")" | ||
function-call ::= id "(" (expr ("," expr)*)? ")" | ||
attribute-ref ::= "@" id | ||
@@ -199,2 +199,63 @@ query-parameter ::= "{" id "}" | ||
Notice that the function call parameters can be full expressions theirself, | ||
including (through the recursion over `sub-query` above) full query paths. | ||
The available pre-defined standard functions are: | ||
- `type(): String`:<br/> | ||
Return type of current node. | ||
Example: `type() === "foo"` | ||
- `depth(): Number`:<br/> | ||
Return depth in AST of current node (counting from 1 for the root node). | ||
Example: `depth() <= 3` | ||
- `pos(): Number`:<br/> | ||
Return position of current node among sibling (counting from 1 first the first sibling). | ||
Example: `pos() === 2` | ||
- `nth(pos: Number): Boolean`:<br/> | ||
Check whether position of current node among sibling is `pos` (counting from 1 fir | ||
the first sibling). Negative values for `pos` count from the last sibling backward, | ||
i.e., `-1` is the last sibling. | ||
Example: `nth(3)` | ||
- `first(): Boolean`:<br/> | ||
Shorthand for `nth(1)`. | ||
- `last(): Boolean`:<br/> | ||
Shorthand for `nth(-1)`. | ||
- `count(array: Object[]): Number`:<br/> | ||
Return the number of elements in `array`. | ||
The `array` usually is either an externally passed-in parameter or a sub-query. | ||
Example: `count({nodes}) <= count(// *)` | ||
- `below(node: Node): Boolean`:<br/> | ||
Checks whether current node is somewhere below `node`, i.e., | ||
whether current node is a child or descendant of `node`. | ||
Example: `below({node})`. | ||
- `follows(node: Node): Boolean`:<br/> | ||
Checks whether current node is following `node`, i.e., | ||
whether current node comes after `node` in a standard | ||
depth-first tree visit (where parents are visited before childs). | ||
Example: `follows({node})`. | ||
- `in(nodes: Node[]): Number`:<br/> | ||
Checks whether current node is in `nodes`. | ||
The `nodes` usually is either an externally passed-in parameter or a sub-query. | ||
Example: `in({nodes})` | ||
- `substr(str: String, pos: Number, len: Number): String`:<br/> | ||
Returns the sub-string of `str`, starting at `pos` with length `len`. | ||
Example: `substr(@foo, 0, 1) == "A"` | ||
- `lc(str: String): String`:<br/> | ||
Returns the lower-case variant of `str`. | ||
Example: `lc(@foo) == "a"` | ||
- `uc(str: String): String`:<br/> | ||
Returns the upper-case variant of `str`. | ||
Example: `uc(@foo) == "A"` | ||
Application Programming Interface (API) | ||
@@ -201,0 +262,0 @@ --------------------------------------- |
@@ -25,2 +25,23 @@ /* | ||
/* internal helper function: find position between siblings */ | ||
let pos = (A, T) => { | ||
let parent = A.getParentNode(T, "*") | ||
if (parent === null) | ||
return 1 | ||
let pchilds = A.getChildNodes(parent, "*") | ||
for (let i = 0; i < pchilds.length; i++) | ||
if (pchilds[i] === T) | ||
return (i + 1) | ||
throw new Error("cannot find myself") | ||
} | ||
/* internal helper function: find parent nodes */ | ||
let parents = (A, T) => { | ||
let parents = [] | ||
while ((T = A.getParentNode(T, "*")) !== null) | ||
parents.push(T) | ||
return parents | ||
} | ||
/* the exported standard functions */ | ||
let stdfuncs = { | ||
@@ -43,10 +64,3 @@ /* type name of node */ | ||
"pos": (A, T) => { | ||
let parent = A.getParentNode(T, "*") | ||
if (parent === null) | ||
return 1 | ||
let pchilds = A.getChildNodes(parent, "*") | ||
for (let i = 0; i < pchilds.length; i++) | ||
if (pchilds[i] === T) | ||
return (i + 1) | ||
throw new Error("cannot find myself") | ||
return pos(A, T) | ||
}, | ||
@@ -61,3 +75,3 @@ | ||
if (num < 0) | ||
num = pchilds - (num + 1) | ||
num = pchilds.length - (num + 1) | ||
for (let i = 0; i < pchilds.length; i++) | ||
@@ -96,2 +110,48 @@ if (pchilds[i] === T) | ||
/* check whether node is below another */ | ||
"below": (A, T, other) => { | ||
if (!A.taste(other)) | ||
throw new Error("invalid argument to function \"below\" (node expected)") | ||
let node = T | ||
while ((node = A.getParentNode(node, "*")) !== null) | ||
if (node === other) | ||
return true | ||
return false | ||
}, | ||
/* check whether node follows another */ | ||
"follows": (A, T, other) => { | ||
if (!A.taste(other)) | ||
throw new Error("invalid argument to function \"follows\" (node expected)") | ||
if (T === other) | ||
return false | ||
let pathOfT = [ T ].concat(parents(A, T )).reverse() | ||
let pathOfOther = [ other ].concat(parents(A, other)).reverse() | ||
let len = Math.min(pathOfT.length, pathOfOther.length) | ||
let i | ||
for (i = 0; i < len; i++) | ||
if (pathOfT[i] !== pathOfOther[i]) | ||
break | ||
if (i === 0) | ||
throw new Error("internal error: root nodes have to be same same") | ||
else if (i === len) { | ||
if (pathOfOther.length < pathOfT.length) | ||
return true | ||
else | ||
return false | ||
} | ||
else | ||
return pos(A, pathOfT[i]) > pos(A, pathOfOther[i]) | ||
}, | ||
/* check whether node is in a list of nodes */ | ||
"in": (A, T, val) => { | ||
if (!(typeof val === "object" && val instanceof Array)) | ||
throw new Error("invalid argument to function \"in\" (array expected)") | ||
for (let i = 0; i < val.length; i++) | ||
if (val[i] === T) | ||
return true | ||
return false | ||
}, | ||
/* retrieve a sub-string */ | ||
@@ -98,0 +158,0 @@ "substr": (A, T, str, pos, len) => { |
@@ -37,4 +37,5 @@ /* | ||
describe("ASTq Library", function () { | ||
it("basic functionality", function () { | ||
var astq = new ASTQ() | ||
var astq = new ASTQ() | ||
it("API availability", function () { | ||
expect(astq).to.respondTo("version") | ||
@@ -47,3 +48,2 @@ expect(astq).to.respondTo("adapter") | ||
expect(astq).to.respondTo("query") | ||
expect(astq.version()).to.have.property("major") | ||
@@ -53,37 +53,70 @@ expect(astq.version()).to.have.property("minor") | ||
expect(astq.version()).to.have.property("date") | ||
}) | ||
astq.func("add", function (a, b) { return a + b }) | ||
astq.func("add", function (a, b) { return a + b }) | ||
var ASTY = require("asty") | ||
var asty = new ASTY() | ||
var node1 = asty.create("node1") | ||
var node2 = asty.create("node2") | ||
var node3 = asty.create("node3") | ||
var node4 = asty.create("node4") | ||
var node5 = asty.create("node5") | ||
var node6 = asty.create("node6").set("foo", "bar") | ||
var node7 = asty.create("node7").set("quux", "baz") | ||
var node8 = asty.create("node8") | ||
var node9 = asty.create("node9") | ||
node1.add(node2) | ||
node1.add(node3) | ||
node1.add(node4) | ||
node3.add(node5) | ||
node3.add(node6) | ||
node3.add(node7) | ||
node6.add(node8) | ||
node6.add(node9) | ||
var ASTY = require("asty") | ||
var asty = new ASTY() | ||
var node1 = asty.create("node1") | ||
var node2 = asty.create("node2") | ||
var node3 = asty.create("node3") | ||
var node4 = asty.create("node4") | ||
var node5 = asty.create("node5") | ||
var node6 = asty.create("node6").set("foo", "bar") | ||
var node7 = asty.create("node7").set("quux", "baz") | ||
var node8 = asty.create("node8") | ||
var node9 = asty.create("node9") | ||
node1.add(node2) | ||
node1.add(node3) | ||
node1.add(node4) | ||
node3.add(node5) | ||
node3.add(node6) | ||
node3.add(node7) | ||
node6.add(node8) | ||
node6.add(node9) | ||
it("simple queries", function () { | ||
expect(astq.query(node1, "node1")).to.have.members([ node1 ]) | ||
expect(astq.query(node1, "badNodeName")).to.be.empty | ||
expect(astq.query(node1, "*")).to.have.members([ node1 ]) | ||
expect(astq.query(node1, "* [ * [ * [ node1 ]]]")).to.have.members([ node1 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' ]")).to.have.members([ node6 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' ] +// * [ @quux == 'baz' ]")).to.have.members([ node7 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' && +// * [ @quux == 'baz' ] ]")).to.have.members([ node6 ]) | ||
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 ]) | ||
}) | ||
it("filter functions", function () { | ||
expect(astq.query(node1, "// * [ type() == 'node3' ]")) | ||
.to.have.members([ node3 ]) | ||
expect(astq.query(node1, "// * [ depth() == 3 ]")) | ||
.to.have.members([ node5, node6, node7 ]) | ||
expect(astq.query(node1, "// * [ pos() <= 1 ]")) | ||
.to.have.members([ node2, node5, node8 ]) | ||
expect(astq.query(node1, "// * [ nth(2) ]")) | ||
.to.have.members([ node3, node6, node9 ]) | ||
expect(astq.query(node1, "// * [ first() ]")) | ||
.to.have.members([ node2, node5, node8 ]) | ||
expect(astq.query(node1, "// * [ last() ]")) | ||
.to.have.members([ node4, node7, node9 ]) | ||
expect(astq.query(node1, "// * [ count(/*) == 3 ]")) | ||
.to.have.members([ node3 ]) | ||
expect(astq.query(node1, "// * [ below({node}) ]", { node: node3 })) | ||
.to.have.members([ node5, node6, node7, node8, node9 ]) | ||
expect(astq.query(node1, "// * [ follows({node}) ]", { node: node6 })) | ||
.to.be.deep.equal([ node8, node9, node7, node4 ]) | ||
expect(astq.query(node1, "// * [ in({nodes}) ]", { nodes: [ node3, node6 ] })) | ||
.to.have.members([ node3, node6 ]) | ||
expect(astq.query(node1, "// * [ in( * [ @foo == 'bar' || @quux == 'baz' ]) ]")) | ||
.to.have.members([ node6, node7 ]) | ||
}) | ||
it("complex queries", function () { | ||
expect(astq.query(node1, "* [ * [ * [ node1 ]]]")) | ||
.to.have.members([ node1 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' ]")) | ||
.to.have.members([ node6 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' ] +// * [ @quux == 'baz' ]")) | ||
.to.have.members([ node7 ]) | ||
expect(astq.query(node1, "// * [ @foo == 'bar' && +// * [ @quux == 'baz' ] ]")) | ||
.to.have.members([ node6 ]) | ||
expect(astq.query(node1, "/ node2 ../ node1 / node2")) | ||
.to.have.members([ node2 ]) | ||
}) | ||
it("subset queries", function () { | ||
expect(astq.query(node1, "*, // *")) | ||
@@ -90,0 +123,0 @@ .to.have.members([ node1, node2, node3, node5, node6, 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
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
534861
7166
430