-
-
Notifications
You must be signed in to change notification settings - Fork 11
Allow AST plugins to manipulate Javascript scope #5
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
Merged
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
aec31f3
Allow AST plugins to manipulate Javascript scope
ef4 a85d49a
Merge branch 'main' into jsutils
ef4 d140e53
add failing tests for hbs scope collision
ef4 ac77392
handle HBS scope collision
ef4 c219c93
renaming bindValue->bindExpression
ef4 7f4eb94
documenting some gnarlier bits
ef4 bfd5900
update readme
ef4 01e628a
adding docs
ef4 3828958
extending API to cover more side-effectful cases
ef4 10c1d8f
un-nesting function
ef4 44867df
reving caniuse
ef4 dc058a8
refactoring to take the whole template compiler
ef4 352e1d1
progress on source-to-source mode
ef4 d03774c
implementing swapping between forms
ef4 c140edb
progress on removal
ef4 bcb1bfe
improving tests
ef4 3186af3
finish import pruning
ef4 c49eaf2
don't snapshot the wire format
ef4 691ea9d
Merge remote-tracking branch 'origin/main' into source-to-source
ef4 e4cafda
exporting types and making base plugin easier to use directly
ef4 d846415
Merge pull request #9 from emberjs/source-to-source
ef4 3b49509
Avoid reusing identifiers for bound expressions
dfreeman 43b6bff
Reuse (or don't) imported identifiers as appropriate
dfreeman 9a2a7cf
post-merge test adjustments
ef4 d87621b
publishing 2.0.0-alpha.1
ef4 204bb41
resolve config relative to process.cwd
ef4 8d4570b
releasing 2.0.0-alpha.2
ef4 8c13b22
provide env.filename
ef4 0dafb5b
upgrade babel-import-util
ef4 3e0f874
Provide a nicer-looking order
ef4 1c6cbb1
support options when loading transform plugins on node, and clarify t…
ef4 aeb2746
releasing alpha.3
ef4 a07b538
support both cjs and transpiled esm
ef4 73b7789
releasing alpha.4
ef4 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import type { types as t } from '@babel/core'; | ||
| import type * as Babel from '@babel/core'; | ||
| import type { NodePath } from '@babel/traverse'; | ||
| import type { ImportUtil } from 'babel-import-util'; | ||
|
|
||
| // This exists to give AST plugins a controlled interface for influencing the | ||
| // surrounding Javascript scope | ||
| export class JSUtils { | ||
| #babel: typeof Babel; | ||
| #program: NodePath<t.Program>; | ||
| #template: NodePath<t.Expression>; | ||
| #locals: string[]; | ||
| #importer: ImportUtil; | ||
|
|
||
| constructor( | ||
| babel: typeof Babel, | ||
| program: NodePath<t.Program>, | ||
| template: NodePath<t.Expression>, | ||
| locals: string[], | ||
| importer: ImportUtil | ||
| ) { | ||
| this.#babel = babel; | ||
| this.#program = program; | ||
| this.#template = template; | ||
| this.#locals = locals; | ||
| this.#importer = importer; | ||
| } | ||
|
|
||
| bindValue(expression: string, opts?: { nameHint?: string }): string { | ||
| let name = this.#unusedNameLike(opts?.nameHint ?? 'a'); | ||
| let t = this.#babel.types; | ||
| this.#program.unshiftContainer( | ||
| 'body', | ||
| t.variableDeclaration('let', [ | ||
| t.variableDeclarator(t.identifier(name), this.#parseExpression(expression)), | ||
| ]) | ||
| ); | ||
| this.#locals.push(name); | ||
| return name; | ||
| } | ||
|
|
||
| bindImport(moduleSpecifier: string, exportedName: string, opts?: { nameHint?: string }): string { | ||
| let identifier = this.#importer.import( | ||
| this.#template, | ||
| moduleSpecifier, | ||
| exportedName, | ||
| opts?.nameHint | ||
| ); | ||
| this.#locals.push(identifier.name); | ||
| return identifier.name; | ||
| } | ||
|
|
||
| #parseExpression(expressionString: string): t.Expression { | ||
| let parsed = this.#babel.parse(expressionString); | ||
| if (!parsed) { | ||
| throw new Error(`JSUtils.bindValue could not understand the expression: ${expressionString}`); | ||
| } | ||
| let statements = body(parsed); | ||
| if (statements.length !== 1) { | ||
| throw new Error( | ||
| `JSUtils.bindValue expected to find exactly one expression but found ${statements.length} in: ${expressionString}` | ||
| ); | ||
| } | ||
| let statement = statements[0]; | ||
| if (statement.type !== 'ExpressionStatement') { | ||
| throw new Error( | ||
| `JSUtils.bindValue expected to find an expression but found ${statement.type} in: ${expressionString}` | ||
| ); | ||
| } | ||
| return statement.expression; | ||
| } | ||
|
|
||
| #unusedNameLike(desiredName: string): string { | ||
| let candidate = desiredName; | ||
| let counter = 0; | ||
| while (this.#template.scope.hasBinding(candidate)) { | ||
| candidate = `${desiredName}${counter++}`; | ||
| } | ||
| return candidate; | ||
| } | ||
| } | ||
|
|
||
| // This extends Glimmer's ASTPluginEnvironment type to put our jsutils into | ||
| // meta. | ||
| export type WithJSUtils<T extends { meta?: object }> = { | ||
| meta: T['meta'] & { jsutils: JSUtils }; | ||
| } & T; | ||
|
|
||
| function body(node: t.Program | t.File) { | ||
| if (node.type === 'File') { | ||
| return node.program.body; | ||
| } else { | ||
| return node.body; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.