estools / esquery Goto Github PK
View Code? Open in Web Editor NEWECMAScript AST query library.
Home Page: http://estools.github.io/esquery/
License: Other
ECMAScript AST query library.
Home Page: http://estools.github.io/esquery/
License: Other
Comments in the AST are stored separately (if at all). They will have to be associated with the nodes somehow, perhaps range would work. The use case is for things like overriding rules in esquery or searching for the doc of a particular statement.
I'd like to use the newly exposed matches
function in one of my projects.
I had to look at the tests to figure out the expected behaviour.
Queries with subject indicators match more nodes than they should, and also match the same node multiple times. E.g.:
esquery(esprima.parse('foo = bar = baz'),
'!AssignmentExpression > AssignmentExpression > Identifier');
...returns the following:
[ AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: Identifier { type: 'Identifier', name: 'bar' },
right: Identifier { type: 'Identifier', name: 'baz' } },
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: Identifier { type: 'Identifier', name: 'foo' },
right:
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: [Object],
right: [Object] } },
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: Identifier { type: 'Identifier', name: 'bar' },
right: Identifier { type: 'Identifier', name: 'baz' } },
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: Identifier { type: 'Identifier', name: 'foo' },
right:
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: [Object],
right: [Object] } } ]
As far as I can tell, it should return only this:
[ AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: Identifier { type: 'Identifier', name: 'foo' },
right:
AssignmentExpression {
type: 'AssignmentExpression',
operator: '=',
left: [Object],
right: [Object] } } ]
a[b="c"][d="e"]
parses as
{
"type": "compound",
"selectors": [
{
"type": "identifier",
"value": "a"
},
{
"type": "attribute",
"name": "b",
"operator": "=",
"value": {
"type": "literal",
"value": "c\"][d=\"e"
}
}
]
}
I expected
{
"type": "compound",
"selectors": [
{
"type": "identifier",
"value": "a"
},
{
"type": "attribute",
"name": "b",
"operator": "=",
"value": {
"type": "literal",
"value": "c"
}
},
{
"type": "attribute",
"name": "d",
"operator": "=",
"value": {
"type": "literal",
"value": "e"
}
}
]
}
... which is how the above selector parses when then the value is unquoted.
The demo page give an error 404
I’ve found that each time I use esquery I have a question how to use it? Is it conventional, like other estools: var query = require('esquery').query
or is it plain function var query = require('esquery')
? API is also not clear at first.
Examples could be found in tests, of course, but is there a sense to add short description to the readme, to give new users answer to such questions?
Added in #19, but not properly documented.
:root would be the same as in the css spec. :relative would allow for an optimization of :matches and :not. It would also allow for a couple other searches.
With the most recent release of this package, I'm no longer able to run eslint
for my project without it failing. This is tough, because my team runs it on build as part of our CI tooling (currently using node version 5.12.0
). Doesn't seem like NPM tries to resolve packages based on engine versions, either.
It looks like this was intentional– but I'm curious why there wasn't a major version increment for it?
As an aside: this particular package is one that we should be updating to used fix versions but haven't yet.
Thanks for maintaining this project! Would be glad to help out with any potential solutions you all would be interested in.
Like CSS tag selectors, I think the node type should be a case-insensitive match.
ex. you can't do /foobar/i to get a case insensitive match for a regex, or put the "i" flag at the end of an attribute match like you could with CSS.
https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors#case-insensitive
It outputs an error saying esquery can't be found.
When matching an attribute regex for an attribute that does not exist, esquery appears to test the regex on the string 'null'
. This can result in confusing false positives.
For example, I would expect the following selector to match any unicode regex literal:
Literal[regex.flags=/u/]
But it also matches all non-regex literals. This is because non-regex literals don't have a regex.flags
property, so the regex /u/
gets matched against null
, resulting in a successful match.
const esquery = require('esquery');
const espree = require('espree');
const selector = esquery.parse('Literal[regex.flags=/u/]');
const expressionStatement = espree.parse('1').body[0].expression;
esquery.matches(expressionStatement, selector) // => true
(Originally reported in eslint/eslint#8733)
I'd like to suggest creating another rollup artifact without the bundled estraverse.
This would have a few advantages:
estraverse.VisitorKeys
, which would allow using esquery with things like TypeScript and JSX (and be a sensible workaround for #57)If this works, I can prepare a small PR over the next few days. To keep backwards compatibility, I can set it up as a new output artifact that wouldn't impact anything - would that work?
I tried searching for UpdateExpression[prefix=true]
today, but true
is being interpreted as a string. Should it also match a prefix
property with the Boolean value true
? Should it only match that value since it was specified without quotes?
I'm trying to use grasp with squery which I think uses esquery under the hood?
How do I match an import with a given specifier:
I can't do import-dec[specifiers=x]
since specifiers
is a list of nodes, such as import {x, y z} from 'v'
const find = 'import-dec[specifiers=x] ~ class-dec[id=#CoolGang]'
const replace = `class {{.id}} {{.body}}`
const replacer = grasp.replace('squery', find, replace)
And release it to npm.
thank you.
Hopefully people will understand the performance consequences of calling these interfaces repeatedly with a string as selector.
esquery.min.js
in the gh-pages
branch is an old version and needs to be updated. Specifically, the demo page still expects a postfix subject indicator. PR to follow shortly.
Safari (at least as of 6.1) doesn't expose a global called performance
so the demo just stops where you call performance.now()
.
Safari doesn't appear to implement the performance
object behind a prefix, either, the way Chrome used to have webkitPerformance
. So you're stuck with millisecond resolution in Safari, but I note that the initial demo takes 7ms in Chrome on my machine.
I'm not sure if you want to go all the way and use a performance.now()
polyfill or not, and if so, which one, so I'll refrain from issuing a PR.
https://www.npmjs.com/package/esquery
is out of date
e.g.: missing the 'class' type selector
here's the changes since last publish e81ac46...master
Showing 38 changed files with 1,665 additions and 2,290 deletions.
Using Identifier [name=x]
produces identical results to Identifier[name=x]
in the demo, even though it should produce no results. The "descendant" selector should require that the RHS be one or more steps below the LHS in the tree, not zero or more.
Using the following snippet in the ESQuery demo:
var f = "foo/bar";
None of these queries is parsed correctly and all fail with an error:
[value=/foo\/bar/]
Invalid regular expression: /foo/: \ at end of pattern
[value=/foo\\/bar/]
Expected " " or "]" but "b" found.
[value=/foo\\\\/bar/]
Expected " " or "]" but "b" found.
I'm using tsquery
to write an import-location-specific TSLint rule for RxJS and the RegExp issue appears to be an upstream problem with this package.
I love love love PEGjs: http://pegjs.majda.cz/
Adding token matching is useful for a few cases where things like whitespace are important but not represented in the AST.
Possible pseudo selectors:
[a</b/]
, [a>=/b/]
, etc. Only [a=/b/]
and possibly [a!=/b/]
should be allowed.
Could you update gh-pages so that https://estools.github.io/esquery/ is against the current version, or, better yet, use Github's ability under Settings to have the github.io URL point to master
so it is always up to date?
Thanks!
I'm looking at using esquery in ESLint, and it looks very close to what I need for the implementation I have in mind. The one thing that is missing is a way to figure out the target node type of a given selector. Basically, something that can take the selector AST and returns:
"*" => "*"
"FunctionDeclaration > VariableDeclarator" => "VariableDeclarator"
":not(FunctionDeclaration)" => "*"
Basically, my implementation will look like:
var queryAST = esquery.parse(key);
var targetType = esquery.getTargetType(queryAST);
eslint.on(targetType, function(node) {
If (esquery.matches(node, queryAST, parents)) {
// apply rule
}
}
It'd be great if there was release notes for this project.
As a user, it's hard to parse all of the commit messages in the history to determine what's actually changed from version to version.
A markdown file in the repo root is one way people do this.
Another way is via the github releases UI.
The following-sibling combinator is made of the "tilde" (U+007E, ~) character that separates two compound selectors. The elements represented by the two compound selectors share the same parent in the document tree and the element represented by the first compound selector precedes (not necessarily immediately) the element represented by the second one.
See http://dev.w3.org/csswg/selectors4/#general-sibling-combinators.
Minimal reproduceable example:
The :nth-child
selector throws an error if object spread syntax (type
of ExperimentalSpreadSyntax
) is encountered.
Stack trace:
> eslint .
Cannot read property 'length' of undefined
TypeError: Cannot read property 'length' of undefined
at nthChild (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/esquery/esquery.js:256:34)
at matches (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/esquery/esquery.js:158:25)
at Function.matches (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/esquery/esquery.js:103:25)
at NodeEventGenerator.applySelector (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/util/node-event-generator.js:250:21)
at NodeEventGenerator.applySelectors (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/util/node-event-generator.js:278:22)
at NodeEventGenerator.enterNode (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/util/node-event-generator.js:294:14)
at CodePathAnalyzer.enterNode (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:608:23)
at Traverser.enter [as _enter] (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/linter.js:1006:32)
at Traverser._traverse (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/util/traverser.js:132:14)
at Traverser._traverse (/Users/andrew/Documents/Code/vvv/www/editor/htdocs/wp-content/plugins/gutenberg/node_modules/eslint/lib/util/traverser.js:147:30)
Throwing line:
Line 204 in 1853a6f
Real-world use-case:
I am trying to create a no-restricted-syntax
ESLint rule for forbidding all but ArrayExpression
as the second argument of Lodash methods which accept path
argument:
CallExpression[callee.name=/^(invokeMap|get|has|hasIn|invoke|result|set|setWith|unset|update|updateWith)$/] > :not(ArrayExpression):nth-child(2)
This works in isolated usage:
...but with above error, fails with the object spread syntax.
Fails on 0.3.0
, but works on gh-pages
esquery.parse(':function')
Error is
"Expected "#", "*", ".", ":first-child", ":last-child", ":matches(", ":not(", ":nth-child(", ":nth-last-child(", "[" or [^ [\],():#!=><~+.] but ":" found."
Result on gh-pages is
{
"type": "class",
"name": "function"
}
var esprima = require('esprima');
var esquery = require('esquery');
var ast = esprima.parse('a + !b');
var query = esquery.parse('BinaryExpression! > UnaryExpression.right');
// should be true (does not work)
console.log(esquery.matches(ast.body[0].expression, query, [ast.body[0], ast]));
// should be false (does not work)
console.log(esquery.matches(ast.body[0].expression.right, query, [ast.body[0].expression, ast.body[0], ast]));
// should include only the BinaryExpression (works)
console.log(JSON.stringify(esquery.match(ast, query, []), null, 4));
We'll need to add esprima as a dev dependency to parse these programs.
CSS4 defines something called a reference combinator which allows for matching attributes between nodes. It would be a very expensive combinator but could be very useful for things like checking for identifiers which have not been declared earlier. I think it would need to be more generic than the one defined in CSS4 to be very useful.
Hi,
I'm trying to run the tests with the command:
npm test
results in error for me:
Error: Tried loading "fixtures/conditional" at ./fixtures/conditional.js then tried...
But when I run with the command below, the tests run ok:
node node_modules/jstestr/bin/jstestr.js module=tests/queryAttribute
node node_modules/jstestr/bin/jstestr.js module=tests/queryField
etc...
Is there some other command I have to use?
I´m running with:
Thank you.
Hi, I'm thinking about using esquery for matching some pretty deeply nested constructs. I need to differentiate between eg. the object
and property
of a MemberExpression
, so I cannot use the child selector, as it will match a child in either position:
const q = esquery.parse('MemberExpression > Identifier[name=foo]');
const ast = require('acorn').parse("foo.foo()")
console.log(esquery.match(ast, q));
[ Node { type: 'Identifier', start: 0, end: 3, name: 'foo' },
Node { type: 'Identifier', start: 4, end: 7, name: 'foo' } ]
I know that I drop into "attribute mode" and achieve what I need using a query like:
MemberExpression[property.name=foo]
... but since the asts I need to match are much deeper than that, it would be really awkward to have to spell out the rest of the subtree like that with lots of repeated [property.foo.bar=123][property.foo.quux=abc]
. It would be much nicer if I could use something like the >
selector to cover the nesting aspects.
Am I overlooking a nice way to achieve that?
The closest I could find is discusssed here but the pull request is not merged.
#45
In dom, once I get a node via css selector, I always have a parentNode
property to trace up to the root of the tree.
Hey team!
I've been using ESQuery for several years and I love the API, so thank you for your efforts. I've been writing a lot of TypeScript lately, and I've had a go at a project using the ESQuery API for querying TypeScript ASTs. I'm planning on open-sourcing it, but I checked out your licence and saw the following point:
Neither the name of the ESQuery nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
I'm hoping it will be okay to mention that the API is taken from ESQuery (and that it uses your selector parser internally)? Assuming that falls within the realm of that particular licence term, I'd like to request permission to use the name ESQuery.
Thanks!
Various types can be classified and group together. Things like statements and expressions. Possible pseudo selectors:
I use ESLint with babel-eslint parser to check my code. There has a loop when query unknown key JSXOpeningElement.
I made a pr in estraverse. But esquery resolve this issue maybe better.
It seems an npm release was made without tagging it here in git.
Please tag it - that eases tracking for other distributors - e.g. Debian where I have recently included this module. :-)
npm ERR! Error: No compatible version found: bn.js@'^0.15.0'
npm ERR! Valid install targets:
npm ERR! ["0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.1.6","0.1.7","0.2.0","0.2.1","0.2.2","0.3.0","0.3.1","0.4.0","0.4.1","0.4.2","0.4.3","0.4.4","0.5.0","0.5.1","0.5.2","0.5.3","0.5.4","0.6.0","0.7.0","0.7.1","0.8.0","0.8.1","0.9.0","0.10.0","0.10.1","0.11.0","0.11.1","0.11.2","0.11.3","0.11.4","0.11.5","0.11.6","0.11.7","0.12.0","0.13.0","0.13.1","0.13.2","0.13.3","0.14.0","0.14.1","0.14.2","0.15.0","0.15.1","0.15.2","0.16.0"]
npm ERR! at installTargetsError (/home/travis/.nvm/v0.8.28/lib/node_modules/npm/lib/cache.js:719:10)
npm ERR! at /home/travis/.nvm/v0.8.28/lib/node_modules/npm/lib/cache.js:641:10
I say we drop them from the CI process. Nobody is seriously using them anyway (or at least shouldn't be due to security concerns).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.