mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(compiler): support generating URL expressions with dynamic imports (#58173)
The compiler's AST factories now support generating a dynamic import call expression with either a string literal or an expression. The later is useful for cases where the URL is dynamically created at runtime. Also, a leading comment can now be added to the URL for cases where bundler behavior needs to be included via special comments. PR Close #58173
This commit is contained in:
parent
c42759b7a0
commit
4a6c6505d9
7 changed files with 72 additions and 15 deletions
|
|
@ -27,7 +27,7 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
|
|||
private sourceUrl: string,
|
||||
) {}
|
||||
|
||||
attachComments(statement: t.Statement, leadingComments: LeadingComment[]): void {
|
||||
attachComments(statement: t.Statement | t.Expression, leadingComments: LeadingComment[]): void {
|
||||
// We must process the comments in reverse because `t.addComment()` will add new ones in front.
|
||||
for (let i = leadingComments.length - 1; i >= 0; i--) {
|
||||
const comment = leadingComments[i];
|
||||
|
|
@ -119,8 +119,12 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
|
|||
|
||||
createIfStatement = t.ifStatement;
|
||||
|
||||
createDynamicImport(url: string): t.Expression {
|
||||
return this.createCallExpression(t.import(), [t.stringLiteral(url)], false /* pure */);
|
||||
createDynamicImport(url: string | t.Expression): t.Expression {
|
||||
return this.createCallExpression(
|
||||
t.import(),
|
||||
[typeof url === 'string' ? t.stringLiteral(url) : url],
|
||||
false /* pure */,
|
||||
);
|
||||
}
|
||||
|
||||
createLiteral(value: string | number | boolean | null | undefined): t.Expression {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,18 @@ describe('BabelAstFactory', () => {
|
|||
|
||||
expect(generate(stmt).code).toEqual(['/* comment 1 */', '//comment 2', 'x = 10;'].join('\n'));
|
||||
});
|
||||
|
||||
it('should add the comments to the given statement', () => {
|
||||
const expr = expression.ast`x + 10`;
|
||||
factory.attachComments(expr, [
|
||||
leadingComment('comment 1', true),
|
||||
leadingComment('comment 2', false),
|
||||
]);
|
||||
|
||||
expect(generate(expr).code).toEqual(
|
||||
['(', '/* comment 1 */', '//comment 2', 'x + 10'].join('\n') + ')',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createArrayLiteral()', () => {
|
||||
|
|
@ -187,11 +199,17 @@ describe('BabelAstFactory', () => {
|
|||
});
|
||||
|
||||
describe('createDynamicImport()', () => {
|
||||
it('should create a dynamic import', () => {
|
||||
it('should create a dynamic import with a string URL', () => {
|
||||
const url = './some/path';
|
||||
const dynamicImport = factory.createDynamicImport(url);
|
||||
expect(generate(dynamicImport).code).toEqual(`import("${url}")`);
|
||||
});
|
||||
|
||||
it('should create a dynamic import with an expression URL', () => {
|
||||
const url = expression.ast`'/' + 'abc' + '/'`;
|
||||
const dynamicImport = factory.createDynamicImport(url);
|
||||
expect(generate(dynamicImport).code).toEqual(`import('/' + 'abc' + '/')`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createIfStatement()', () => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export interface AstFactory<TStatement, TExpression> {
|
|||
* @param statement the statement where the comments are to be attached.
|
||||
* @param leadingComments the comments to attach.
|
||||
*/
|
||||
attachComments(statement: TStatement, leadingComments: LeadingComment[]): void;
|
||||
attachComments(statement: TStatement | TExpression, leadingComments: LeadingComment[]): void;
|
||||
|
||||
/**
|
||||
* Create a literal array expression (e.g. `[expr1, expr2]`).
|
||||
|
|
@ -136,7 +136,7 @@ export interface AstFactory<TStatement, TExpression> {
|
|||
*
|
||||
* @param url the URL that should by used in the dynamic import
|
||||
*/
|
||||
createDynamicImport(url: string): TExpression;
|
||||
createDynamicImport(url: string | TExpression): TExpression;
|
||||
|
||||
/**
|
||||
* Create an identifier.
|
||||
|
|
|
|||
|
|
@ -356,7 +356,15 @@ export class ExpressionTranslatorVisitor<TFile, TStatement, TExpression>
|
|||
}
|
||||
|
||||
visitDynamicImportExpr(ast: o.DynamicImportExpr, context: any) {
|
||||
return this.factory.createDynamicImport(ast.url);
|
||||
const urlExpression =
|
||||
typeof ast.url === 'string'
|
||||
? this.factory.createLiteral(ast.url)
|
||||
: ast.url.visitExpression(this, context);
|
||||
if (ast.urlComment) {
|
||||
this.factory.attachComments(urlExpression, [o.leadingComment(ast.urlComment, true)]);
|
||||
}
|
||||
|
||||
return this.factory.createDynamicImport(urlExpression);
|
||||
}
|
||||
|
||||
visitNotExpr(ast: o.NotExpr, context: Context): TExpression {
|
||||
|
|
|
|||
|
|
@ -126,11 +126,11 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
|
|||
|
||||
createExpressionStatement = ts.factory.createExpressionStatement;
|
||||
|
||||
createDynamicImport(url: string) {
|
||||
createDynamicImport(url: string | ts.Expression) {
|
||||
return ts.factory.createCallExpression(
|
||||
ts.factory.createToken(ts.SyntaxKind.ImportKeyword) as ts.Expression,
|
||||
ts.factory.createToken(ts.SyntaxKind.ImportKeyword) as ts.ImportExpression,
|
||||
/* type */ undefined,
|
||||
[ts.factory.createStringLiteral(url)],
|
||||
[typeof url === 'string' ? ts.factory.createStringLiteral(url) : url],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +352,10 @@ export function createTemplateTail(cooked: string, raw: string): ts.TemplateTail
|
|||
* @param statement The statement that will have comments attached.
|
||||
* @param leadingComments The comments to attach to the statement.
|
||||
*/
|
||||
export function attachComments(statement: ts.Statement, leadingComments: LeadingComment[]): void {
|
||||
export function attachComments(
|
||||
statement: ts.Statement | ts.Expression,
|
||||
leadingComments: LeadingComment[],
|
||||
): void {
|
||||
for (const comment of leadingComments) {
|
||||
const commentKind = comment.multiline
|
||||
? ts.SyntaxKind.MultiLineCommentTrivia
|
||||
|
|
|
|||
|
|
@ -27,6 +27,19 @@ describe('TypeScriptAstFactory', () => {
|
|||
|
||||
expect(generate(stmt)).toEqual(['/* comment 1 */', '//comment 2', 'x = 10;'].join('\n'));
|
||||
});
|
||||
|
||||
it('should add the comments to the given expression', () => {
|
||||
const {
|
||||
items: [expr],
|
||||
generate,
|
||||
} = setupExpressions('x + 10');
|
||||
factory.attachComments(expr, [
|
||||
leadingComment('comment 1', true),
|
||||
leadingComment('comment 2', false),
|
||||
]);
|
||||
|
||||
expect(generate(expr)).toEqual(['/* comment 1 */', '//comment 2', 'x + 10'].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('createArrayLiteral()', () => {
|
||||
|
|
@ -63,12 +76,18 @@ describe('TypeScriptAstFactory', () => {
|
|||
});
|
||||
|
||||
describe('createDynamicImport()', () => {
|
||||
it('should create a dynamic import expression', () => {
|
||||
it('should create a dynamic import expression from a string URL', () => {
|
||||
const {generate} = setupExpressions(``);
|
||||
const url = './some/path';
|
||||
const assignment = factory.createDynamicImport(url);
|
||||
expect(generate(assignment)).toEqual(`import("${url}")`);
|
||||
});
|
||||
|
||||
it('should create a dynamic import expression from an expression URL', () => {
|
||||
const {items, generate} = setupExpressions(`'/' + 'abc' + '/'`);
|
||||
const assignment = factory.createDynamicImport(items[0]);
|
||||
expect(generate(assignment)).toEqual(`import('/' + 'abc' + '/')`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createBlock()', () => {
|
||||
|
|
|
|||
|
|
@ -957,14 +957,15 @@ export class ConditionalExpr extends Expression {
|
|||
|
||||
export class DynamicImportExpr extends Expression {
|
||||
constructor(
|
||||
public url: string,
|
||||
public url: string | Expression,
|
||||
sourceSpan?: ParseSourceSpan | null,
|
||||
public urlComment?: string,
|
||||
) {
|
||||
super(null, sourceSpan);
|
||||
}
|
||||
|
||||
override isEquivalent(e: Expression): boolean {
|
||||
return e instanceof DynamicImportExpr && this.url === e.url;
|
||||
return e instanceof DynamicImportExpr && this.url === e.url && this.urlComment === e.urlComment;
|
||||
}
|
||||
|
||||
override isConstant() {
|
||||
|
|
@ -976,7 +977,11 @@ export class DynamicImportExpr extends Expression {
|
|||
}
|
||||
|
||||
override clone(): DynamicImportExpr {
|
||||
return new DynamicImportExpr(this.url, this.sourceSpan);
|
||||
return new DynamicImportExpr(
|
||||
typeof this.url === 'string' ? this.url : this.url.clone(),
|
||||
this.sourceSpan,
|
||||
this.urlComment,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue