-
Notifications
You must be signed in to change notification settings - Fork 962
Description
Context: typescript-eslint/typescript-eslint#1686
cc @kaicataldo
When parsing an assignment within an object pattern, acorn reuses the identifier object for both the Property.key
, and the AssignmentPattern.left
. Best shown by the example below.
This is a problem because it means that any mutations applied to one node also apply to the other node.
For example, ESLint adds a parent
property as it traverses the AST. This node reuse means that the parent
will be wrong for one of the two locations (whichever one is traversed first).
It has exposed a subtle bug in ESLint's camelcase rule.
When the code is parsed by espree (and thus acorn), the rule does not fire an error, because it does not detect the correct lineage for the node.
However, when the code is parsed by a parser that does not reuse objects (like typescript-estree), the rule fires an error, because the parent pointers are correct.
Is this intentional? To me it seems like a bug in acorn, as I would assume that every AST node is a brand new object, no matter how similar to an existing node they might be. It seems like ESLint makes the same assumption as well.
const acorn = require('acorn');
const ast = acorn.parse("const {foo=1} = {};");
/*
{
"type": "Property",
"start": 7,
"end": 12,
"method": false,
"shorthand": true,
"computed": false,
"key": {
"type": "Identifier",
"start": 7,
"end": 10,
"name": "foo"
},
"kind": "init",
"value": {
"type": "AssignmentPattern",
"start": 7,
"end": 12,
"left": {
"type": "Identifier",
"start": 7,
"end": 10,
"name": "foo"
},
"right": {
"type": "Literal",
"start": 11,
"end": 12,
"value": 1,
"raw": "1"
}
}
}
*/
const node = ast.body[0].declarations[0].id.properties[0];
console.log(node.key === node.value.left) // true