Repository navigation
Fix eslint-parser AST definition of AccessorProperty - #18257
Conversation
Thanks for opening this pull request! 馃帀We really appreciate you taking the time to contribute, @jpradelle. A maintainer will take a look as soon as they can. In the meantime, please make sure that:
If anything needs adjusting we'll leave comments here. Thanks again! |
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/62196 |
| // AST Types that are not presented in Babel AST | ||
| const newTypes = { | ||
| AccessorProperty: ["decorators", "typeAnnotation"].concat( | ||
| ESLINT_VISITOR_KEYS.PropertyDefinition, |
There was a problem hiding this comment.
| ESLINT_VISITOR_KEYS.PropertyDefinition, | |
| ESLINT_VISITOR_KEYS.AccessorProperty, |
There is no guarantee that the shape of these two AST types will always be exactly the same.
There was a problem hiding this comment.
There is nothing in ESLINT_VISITOR_KEYS that looks like to be something for AccessorProperty.
I can replace with (which is the computed values of PropertyDefinition)
AccessorProperty: ["decorators", "typeAnnotation", "value", "key"],I kept typeAnnotation copied from PropertyDefinition, but I'm not sure about the use, and I don't get why this was added here https://github.com/babel/babel/pull/13752/changes#diff-76e55da3b712c3967c9951e46430e7c52680d3de9baf60f803c742233b181b2dR16
decorators I found it in node when parsing this code
class T { @foo() accessor a; }For the fix of this issue specifically, only this is needed.
AccessorProperty: ["value"],I'm not completely sure of the impact of the rest.
I think we should go with at least
AccessorProperty: ["decorators", "value", "key"],There was a problem hiding this comment.
Fair enough. The accessor is still stage 2.7 so espree does not support this syntax. In that case the AccessorProperty basically follows what Babel defines ClassAccessorProperty, in that case we can just pull the visitor keys from types.VISITOR_KEYS.ClassAccessorProperty.
Update: never mind, the ClassAccessorProperty will not have value anyway. At this point I agree with you and we can just put AccessorProperty: ["decorators", "typeAnnotation", "value", "key"], here.
| const ast = parseForESLint("class T { accessor a = `x${y}z`; }", { | ||
| eslintVisitorKeys: true, | ||
| eslintScopeManager: true, | ||
| babelOptions: BABEL_OPTIONS, | ||
| }).ast; | ||
|
|
||
| const accessor = ast.body[0].body.body[0]; | ||
| expect(accessor.type).toBe("AccessorProperty"); | ||
|
|
||
| const quasis = accessor.value.quasis; | ||
| expect(quasis.map(q => q.range)).toEqual([ | ||
| [23, 27], // `x${ | ||
| [28, 31], // }z` | ||
| ]); | ||
| }); |
There was a problem hiding this comment.
| const ast = parseForESLint("class T { accessor a = `x${y}z`; }", { | |
| eslintVisitorKeys: true, | |
| eslintScopeManager: true, | |
| babelOptions: BABEL_OPTIONS, | |
| }).ast; | |
| const accessor = ast.body[0].body.body[0]; | |
| expect(accessor.type).toBe("AccessorProperty"); | |
| const quasis = accessor.value.quasis; | |
| expect(quasis.map(q => q.range)).toEqual([ | |
| [23, 27], // `x${ | |
| [28, 31], // }z` | |
| ]); | |
| }); | |
| parseAndAssertSame("class T { accessor a = `x${y}z`; }"); |
parseAndAssertSame would have caught the quasis mismatches.
There was a problem hiding this comment.
Doing so throws an exception
Babel and Espree > templates > template element ranges inside accessor property #18230
SyntaxError: Unexpected token a
at Espree.raise (/home/jpradelle/workspace/babel/node_modules/espree/dist/espree.cjs:892:6)
at Espree.unexpected (/home/jpradelle/workspace/babel/node_modules/espree/dist/espree.cjs:942:10)
at Espree.pp$9.semicolon (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:776:68)
at Espree.pp$8.parseClassField (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:1680:10)
at Espree.pp$8.parseClassElement (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:1612:12)
at Espree.pp$8.parseClass (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:1528:26)
at Espree.pp$8.parseStatement (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:989:19)
at Espree.pp$8.parseTopLevel (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:856:23)
at Espree.parseTopLevel (/home/jpradelle/workspace/babel/node_modules/espree/dist/espree.cjs:879:18)
at Espree.parse (/home/jpradelle/workspace/babel/node_modules/acorn/dist/acorn.js:611:17)
accessor keyword is not parsed properly by Espree
I didn't commit this test I firstly used, that's more in the spirit of comparing things like that, but I didn't find it relevant
it("accessor property template ranges match property template ranges #18230", () => {
const collectQuasiRanges = ast => {
const ranges = [];
const walk = node => {
if (!node || typeof node !== "object") return;
if (node.type === "TemplateElement") {
ranges.push([node.range[0], node.range[1]]);
}
for (const key of Object.keys(node)) {
const value = node[key];
if (Array.isArray(value)) {
value.forEach(walk);
} else if (value && typeof value === "object" && value.type) {
walk(value);
}
}
};
walk(ast);
return ranges;
};
const options = {
eslintVisitorKeys: true,
eslintScopeManager: true,
babelOptions: BABEL_OPTIONS,
};
const withAccessor = parseForESLint(
`class Test {
/**/accessor foo = \`\${' '}\`;
}`,
options,
).ast;
const withoutAccessor = parseForESLint(
`class Test {
/*accessor*/ foo = \`\${' '}\`;
}`,
options,
).ast;
expect(collectQuasiRanges(withAccessor)).toEqual(
collectQuasiRanges(withoutAccessor),
);
});There was a problem hiding this comment.
I am glad that you have not committed that test, which is too complex for merely AST comparision. Could you move the parseAndAssertSame test to the typescript-estree.test.js? I believe typescript-estree should support parsing accessor property very well.
There was a problem hiding this comment.
Working as expected in typescript-estree.test.js, thanks 馃憤
|
commit: |
Fixes template quasis parsing for AccessorProperty. For example this was wrongly parsed:
See ticket #18230 for more details and samples.