-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(ast-spec): add fixture test framework and some initial fixtures #3258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for the PR, @bradzacher! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitors per day. |
0a510a2
to
52fb374
Compare
3f04cd5
to
a5f8933
Compare
63f5b1a
to
9edbb00
Compare
|
||
range: [46, 48], | ||
loc: { | ||
start: { column: 46, line: 1 }, | ||
end: { column: 48, line: 1 }, | ||
}, | ||
}, | ||
id: Identifier { | ||
type: 'Identifier', | ||
name: 'Foo', | ||
|
||
range: [6, 9], | ||
loc: { | ||
start: { column: 6, line: 1 }, | ||
end: { column: 9, line: 1 }, | ||
}, | ||
}, | ||
implements: Array [ | ||
- TSClassImplements { | ||
- type: 'TSClassImplements', | ||
+ TSExpressionWithTypeArguments { | ||
+ type: 'TSExpressionWithTypeArguments', | ||
expression: Identifier { | ||
type: 'Identifier', | ||
name: 'Object', | ||
|
||
range: [21, 27], | ||
loc: { | ||
start: { column: 21, line: 1 }, | ||
end: { column: 27, line: 1 }, | ||
}, | ||
}, | ||
|
||
range: [21, 27], | ||
loc: { | ||
start: { column: 21, line: 1 }, | ||
end: { column: 27, line: 1 }, | ||
}, | ||
}, | ||
- TSClassImplements { | ||
- type: 'TSClassImplements', | ||
+ TSExpressionWithTypeArguments { | ||
+ type: 'TSExpressionWithTypeArguments', | ||
expression: Identifier { | ||
type: 'Identifier', | ||
name: 'Function', | ||
|
||
range: [29, 37], | ||
loc: { | ||
start: { column: 29, line: 1 }, | ||
end: { column: 37, line: 1 }, | ||
}, | ||
}, | ||
|
||
range: [29, 37], | ||
loc: { | ||
start: { column: 29, line: 1 }, | ||
end: { column: 37, line: 1 }, | ||
}, | ||
}, | ||
- TSClassImplements { | ||
- type: 'TSClassImplements', | ||
+ TSExpressionWithTypeArguments { | ||
+ type: 'TSExpressionWithTypeArguments', | ||
expression: Identifier { | ||
type: 'Identifier', | ||
name: 'RegExp', | ||
|
||
range: [39, 45], | ||
loc: { | ||
start: { column: 39, line: 1 }, | ||
end: { column: 45, line: 1 }, | ||
}, | ||
}, | ||
|
||
range: [39, 45], | ||
loc: { | ||
start: { column: 39, line: 1 }, | ||
end: { column: 45, line: 1 }, | ||
}, | ||
}, | ||
], | ||
superClass: null, | ||
|
||
range: [0, 48], | ||
loc: { | ||
start: { column: 0, line: 1 }, | ||
end: { column: 48, line: 1 }, | ||
}, | ||
}, | ||
], | ||
sourceType: 'script', | ||
|
||
range: [0, 49], | ||
loc: { | ||
start: { column: 0, line: 1 }, | ||
end: { column: 0, line: 2 }, | ||
}, | ||
}" | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example of an AST misalignment.
range: [0, 5], | ||
loc: { | ||
start: { column: 0, line: 1 }, | ||
end: { column: 5, line: 1 }, | ||
}, | ||
}, | ||
Identifier { | ||
type: 'Identifier', | ||
value: 'Foo', | ||
|
||
range: [6, 9], | ||
loc: { | ||
start: { column: 6, line: 1 }, | ||
end: { column: 9, line: 1 }, | ||
}, | ||
}, | ||
- Keyword { | ||
- type: 'Keyword', | ||
+ Identifier { | ||
+ type: 'Identifier', | ||
value: 'implements', | ||
|
||
range: [10, 20], | ||
loc: { | ||
start: { column: 10, line: 1 }, | ||
end: { column: 20, line: 1 }, | ||
}, | ||
}, | ||
Identifier { | ||
type: 'Identifier', | ||
value: 'Object', | ||
|
||
range: [21, 27], | ||
loc: { | ||
start: { column: 21, line: 1 }, | ||
end: { column: 27, line: 1 }, | ||
}, | ||
}, | ||
Punctuator { | ||
type: 'Punctuator', | ||
value: ',', | ||
|
||
range: [27, 28], | ||
loc: { | ||
start: { column: 27, line: 1 }, | ||
end: { column: 28, line: 1 }, | ||
}, | ||
}, | ||
Identifier { | ||
type: 'Identifier', | ||
value: 'Function', | ||
|
||
range: [29, 37], | ||
loc: { | ||
start: { column: 29, line: 1 }, | ||
end: { column: 37, line: 1 }, | ||
}, | ||
}, | ||
Punctuator { | ||
type: 'Punctuator', | ||
value: ',', | ||
|
||
range: [37, 38], | ||
loc: { | ||
start: { column: 37, line: 1 }, | ||
end: { column: 38, line: 1 }, | ||
}, | ||
}, | ||
Identifier { | ||
type: 'Identifier', | ||
value: 'RegExp', | ||
|
||
range: [39, 45], | ||
loc: { | ||
start: { column: 39, line: 1 }, | ||
end: { column: 45, line: 1 }, | ||
}, | ||
}, | ||
Punctuator { | ||
type: 'Punctuator', | ||
value: '{', | ||
|
||
range: [46, 47], | ||
loc: { | ||
start: { column: 46, line: 1 }, | ||
end: { column: 47, line: 1 }, | ||
}, | ||
}, | ||
Punctuator { | ||
type: 'Punctuator', | ||
value: '}', | ||
|
||
range: [47, 48], | ||
loc: { | ||
start: { column: 47, line: 1 }, | ||
end: { column: 48, line: 1 }, | ||
}, | ||
}, | ||
]" | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example of an token misalignment.
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`AST Fixtures List fixtures with AST differences 1`] = ` | ||
Set { | ||
"src/declaration/ClassDeclaration/fixtures/implementsMany/fixture.ts", | ||
"src/declaration/ClassDeclaration/fixtures/implementsOne/fixture.ts", | ||
"src/declaration/ClassDeclaration/fixtures/typeParameters/fixture.ts", | ||
"src/declaration/ClassDeclaration/fixtures/typeParametersExtendsTypeParameters/fixture.ts", | ||
} | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snapshot which provides a centralised list of fixtures with AST differences
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`AST Fixtures List fixtures with Token differences 1`] = ` | ||
Set { | ||
"src/declaration/ClassDeclaration/fixtures/implementsMany/fixture.ts", | ||
"src/declaration/ClassDeclaration/fixtures/implementsOne/fixture.ts", | ||
} | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snapshot which provides a centralised list of fixtures with Token differences
9edbb00
to
e0572c1
Compare
0b491e8
to
1e4b373
Compare
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`AST Fixtures List fixtures with Error differences 1`] = ` | ||
Object { | ||
"Babel errored but TSESTree didn't": Set { | ||
"declaration/ClassDeclaration/fixtures/_error_/implements-non-identifier/fixture.ts", | ||
"declaration/ExportAllDeclaration/fixtures/_error_/non-string-source/fixture.ts", | ||
"declaration/ExportAllDeclaration/fixtures/_error_/type-kind/fixture.ts", | ||
"declaration/ExportNamedDeclaration/fixtures/_error_/anonymous-class/fixture.ts", | ||
}, | ||
"TSESTree errored but Babel didn't": Set { | ||
"declaration/ExportAllDeclaration/fixtures/_error_/named-non-identifier/fixture.ts", | ||
"declaration/ExportNamedDeclaration/fixtures/_error_/aliased-literal/fixture.ts", | ||
}, | ||
} | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snapshot which provides a centralised list of fixtures with error differences (not error messages, just existence of errors)
274305a
to
7d7e545
Compare
7d7e545
to
cab0fd7
Compare
@JoshuaKGoldberg - wanna take a look? Got any opinions about this broken-up style of things vs the gigantic bag of fixtures that we have currently? |
Sure! I'll try to find time Soon™️. |
31f3341
to
376997f
Compare
The core of this is done - all that's left is creating fixtures for each and every case. That way we can make all new AST changes add fixtures here, and migrate the old fixtures piece-by-piece - we can distribute the work so I'm not the blocker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔥. Just a few small code nitpicks from me on re-review, nothing close to blocking. Awesome!!
I'd want to hear from @JamesHenry on the Nx shenanigans, if James has time.
characters.push("'"); | ||
|
||
return characters.join(''); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This functionally behaves about the same as str::replaceAll("'", '\\')
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could technically write this as
str.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
Though that would be slower because you'd need to do it in two passes over the string.
I haven't perf tested it, but given that there are going to be hundreds of these strings - each with a few hundred characters, I think that double handling will add up.
* - Removing @typescript-eslint/typescript-estree as an explicit devDependency in the package.json | ||
* - Add an `.nxignore` file at the root of the monorepo which ignores this file (which we then in turn | ||
* ensure is the only place we directly import from the @typescript-eslint/typescript-estree package). | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like something we (@JamesHenry 😄) should feature request into Nx: the ability to have technical circular dependencies only in tests...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't remember the exact history of this but I'm pretty sure I provided this breakdown and created this solution to the problem.
As it turns out on this PR right now the @typescript-eslint/typescript-estree
package is not in the package.json of ast-spec, so we could simplify things to:
The specifying of the package in the package.json was the real issue, and is the thing that causes the rigid circular dependency to exist between the nodes on the graph - there would be no way to know that the package was only used in certain situations when that is the way the relationship is defined. As part of the Nx updates I'm doing we'll be moving entirely to source to source relationships between packages/graph nodes (as is far more common) and we won't need to worry about this in that situation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I didn't include it in the screenshot but feel free to move some of the commentary around why we don't want to include the package in the package.json to make that lint rule happy and that's why we are disabling it inline)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there an update to nx to allow this? I swear there was a reason we went with using an .nxignore
file.
Or did we used to rely on implicit dependency graph and now we have an explicit one configured it doesn't matter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid I don't 100% remember 😬
@JoshuaKGoldberg @bradzacher I’ve set aside some time tomorrow 👍 |
packages/ast-spec/src/declaration/ClassDeclaration/fixtures/extends-literal/README.md
Show resolved
Hide resolved
addressed comments. side note: I was thinking that this could be a platform for us to work on #1852. we also could be running alignment tests against |
376997f
to
7d44794
Compare
Great work, @bradzacher! |
7d44794
to
d699cbf
Compare
Codecov Report
@@ Coverage Diff @@
## main #3258 +/- ##
=======================================
Coverage 94.23% 94.24%
=======================================
Files 152 152
Lines 8281 8283 +2
Branches 2694 2696 +2
=======================================
+ Hits 7804 7806 +2
Misses 263 263
Partials 214 214
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Add fixture tests for each and every AST node. To make things more readable I: - separated the AST from the tokens - this stops the individual snapshot from being so long it's impossible to understand - if there are changes to tokens - then they should be more obvious now. Before you had to expand the snapshot in github to understand that the token was part of the tokens array. - always write error snapshot, and always write AST/token snapshots - This is just for consistency and to make it easier whilst you're developing. - It will prevent us from accidentally leaving behind error snapshots if they weren't supposed to be there. - added a custom snapshot serializer - Having learned how useful they are with scope manager - I created a new one to improve the look of the snapshots. - Instead of sorting alphabetically, I place `type` at the top, and `range`/`loc` at the end. - Instead of outputting `Object` ahead of every node, instead it outputs the node `type`. - I adjusted the output `range`/`loc` so they take up fewer lines and are more compact. I prefixed the snapshot names with numbers just so we can control the sorting of them. No other reason.
d699cbf
to
fb13fb5
Compare
// the promisify util will eat the stderr logs | ||
async function execAsync( | ||
command: string, | ||
args: ReadonlyArray<string>, | ||
options: childProcess.SpawnOptions, | ||
): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
const child = childProcess.spawn(command, args, { | ||
...options, | ||
stdio: 'inherit', | ||
}); | ||
|
||
child.on('error', e => reject(e)); | ||
child.on('exit', () => resolve()); | ||
child.on('close', () => resolve()); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bradzacher this seem to not be working on windows machines
Error: spawn yarn ENOENT
at Process.ChildProcess._handle.onexit (node:internal/child_process:283:19)
at onErrorNT (node:internal/child_process:478:16)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -4058,
code: 'ENOENT',
syscall: 'spawn yarn',
path: 'yarn',
spawnargs: [ 'build' ]
}
and rolling this code back to const execAsync = promisify(childProcess.exec);
seem to be fixing it, not sure what is actually causing this issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can figure out how to make it work on Windows and display the error logs - happy to accept a PR!
I'd assume the path isn't properly set so the binary can't be found? That's generally what ENONET means I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from my understunding of the issue, its related to /
and \
beeing incorrectly used, i did my tests on 2 env win 11 (stable) and win 11 eac (preview), with both node 16 and 18, i was able to reproduce this in all those cases
as for linux subsystem (ubuntu) (linux "vm" in windows) i was unable to reproduce this
edit:
shell, spawn option is required to correctly execute yarn instance (yarn.bat) on windows machines
see: https://stackoverflow.com/questions/37459717/error-spawn-enoent-on-windows
yarn isn't recognized in the console as a program but as a command.
Add fixture tests for each and every AST node.
To make things more readable I:
type
at the top, andrange
/loc
at the end.Object
ahead of every node, instead it outputs the nodetype
.range
/loc
so they take up fewer lines and are more compact.I prefixed the snapshot names with numbers just so we can control the sorting of them. No other reason.
Work In Progress
I wanted to get some early feedback on things like the folder structure and the snapshot representation before I go too far down this rabbit hole.
TODO: