-
Notifications
You must be signed in to change notification settings - Fork 15
fix: credit destructured dynamic import() bindings as exports consumers #1921
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
Changes from all commits
2b6a00d
b28051a
17fbcba
26918bb
be6432c
4ead840
f6326bf
590f560
d3ea4a4
c306812
8bb5893
46037b1
6a84cf9
8d936d1
11c84be
963301a
3e8035d
879635e
0fe9fc3
ccf3c19
d5b1162
8971017
056c5e4
0738171
6f2423c
4c02378
0698e16
4ac3b99
6767f09
5f6f30a
b479318
c39ac40
067674f
f6807b4
1c07a54
bf82aa2
cd02d27
980b5dc
4a873a3
8f3348a
acf804c
986c851
71e9174
d2935cc
6515186
30c491a
9db911b
70559fc
822e0eb
fcdfe7d
ee6362c
d4e6212
aec5d2b
d250f8d
82caa41
ad1396e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4051,22 +4051,44 @@ function extractImportNames( | |||||||||||||||||||||||
| return names; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Wrapper node types that can sit between a dynamic `import()` call and its | ||||||||||||||||||||||||
| * enclosing `variable_declarator` without changing which value gets bound — | ||||||||||||||||||||||||
| * `await`, redundant parentheses, and TypeScript `as`/`satisfies` casts. | ||||||||||||||||||||||||
| * Real-world dynamic-import call sites often combine several of these, e.g. | ||||||||||||||||||||||||
| * `const { X } = (await import('./mod.js')) as { X: Fn }` nests | ||||||||||||||||||||||||
| * await_expression → parenthesized_expression → as_expression before | ||||||||||||||||||||||||
| * reaching the declarator (#1781). `satisfies_expression` (TS 4.9+ | ||||||||||||||||||||||||
| * `... satisfies { X: Fn }`) is structurally identical to `as_expression` | ||||||||||||||||||||||||
| * here — same Greptile follow-up as the native mirror. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| const DYNAMIC_IMPORT_WRAPPER_TYPES = new Set([ | ||||||||||||||||||||||||
| 'await_expression', | ||||||||||||||||||||||||
| 'parenthesized_expression', | ||||||||||||||||||||||||
| 'as_expression', | ||||||||||||||||||||||||
| 'satisfies_expression', | ||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||
|
Comment on lines
+4065
to
+4070
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Extract destructured names from a dynamic import() call expression. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * Handles: | ||||||||||||||||||||||||
| * const { a, b } = await import('./foo.js') → ['a', 'b'] | ||||||||||||||||||||||||
| * const mod = await import('./foo.js') → ['mod'] | ||||||||||||||||||||||||
| * import('./foo.js') → [] (no names extractable) | ||||||||||||||||||||||||
| * const { a, b } = await import('./foo.js') → ['a', 'b'] | ||||||||||||||||||||||||
| * const mod = await import('./foo.js') → ['mod'] | ||||||||||||||||||||||||
| * const { a } = (await import('./foo.js')) as { a: Fn } → ['a'] | ||||||||||||||||||||||||
| * import('./foo.js') → [] (no names extractable) | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * Walks up the AST from the call_expression to find the enclosing | ||||||||||||||||||||||||
| * Walks up the AST from the call_expression — through any nesting of | ||||||||||||||||||||||||
| * await/parenthesized/as-cast wrappers — to find the enclosing | ||||||||||||||||||||||||
| * variable_declarator and reads the name/object_pattern. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| function extractDynamicImportNames(callNode: TreeSitterNode): string[] { | ||||||||||||||||||||||||
| // Walk up: call_expression → await_expression → variable_declarator | ||||||||||||||||||||||||
| // Walk up through await_expression / parenthesized_expression / as_expression | ||||||||||||||||||||||||
| // wrappers, in any combination or order, to reach the variable_declarator. | ||||||||||||||||||||||||
| let current = callNode.parent; | ||||||||||||||||||||||||
| // Skip await_expression wrapper if present | ||||||||||||||||||||||||
| if (current && current.type === 'await_expression') current = current.parent; | ||||||||||||||||||||||||
| while (current && DYNAMIC_IMPORT_WRAPPER_TYPES.has(current.type)) { | ||||||||||||||||||||||||
| current = current.parent; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| // We should now be at a variable_declarator (or not, if standalone import()) | ||||||||||||||||||||||||
| if (current?.type !== 'variable_declarator') return []; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
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.
satisfies_expressionnot included in the wrapper setTypeScript 4.9+ allows
const { X } = (await import('./mod.js')) satisfies { X: Fn }. tree-sitter-typescript parses that as asatisfies_expressionwrapper, which is not inDYNAMIC_IMPORT_WRAPPER_TYPES(or the Rust equivalent), so the walk-up would bail out and return[]— the same symptom as the bug being fixed. The pattern is rare in practice but structurally identical to theas_expressioncase already handled. Worth adding now that the set is being explicitly maintained.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.
Fixed — added
satisfies_expressionto the wrapper set in both engines (verified it's a real tree-sitter-typescript node type first), plus a regression test in each inad1396ed.