estools/esquery

Attribute regex test converts undefined attributes to strings

Closed this issue · 1 comments

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)

IHTFY commented

esquery still regex matches against the string 'undefined' for nodes that don't have the specified attribute.

For example:
In the demo, using the default code:

  • * --> 44 nodes (all nodes)
  • [name] --> 14 nodes (14 nodes have a 'name' property)
  • [name=undefined] --> 30 nodes (14 nodes do not have a 'name' property)

Therefore,

  • [name=/f/] --> 31 nodes (30 undefined + foo)

And if you actually just want to match any node that has a 'name' containing 'f', you use:

  • [name=/f/][name!=undefined] --> 1 node (foo)

This holds true for any attribute name ('value', 'raw', 'operator', 'id', 'parms', etc.).

Even invalid attributes such as 'abc123{}^%$' or 'fakeAttr' will match against 'undefined'.

  • [fakeAttr=/u/] --> 44 nodes (no node has a 'fakeAttr' property, so they all match against 'undefined')