Skip to content

Commit 63b0ad7

Browse files
crisbetokirjs
authored andcommitted
refactor(compiler-cli): account for spread elements in translator
Adds the ability to generate spread elements in the linker.
1 parent e407280 commit 63b0ad7

6 files changed

Lines changed: 71 additions & 13 deletions

File tree

packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
/**
2222
* A Babel flavored implementation of the AstFactory.
2323
*/
24-
export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
24+
export class BabelAstFactory implements AstFactory<t.Statement, t.Expression | t.SpreadElement> {
2525
constructor(
2626
/** The absolute path to the source file being compiled. */
2727
private sourceUrl: string,
@@ -74,7 +74,11 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
7474

7575
createBlock = t.blockStatement;
7676

77-
createCallExpression(callee: t.Expression, args: t.Expression[], pure: boolean): t.Expression {
77+
createCallExpression(
78+
callee: t.Expression,
79+
args: (t.Expression | t.SpreadElement)[],
80+
pure: boolean,
81+
): t.Expression {
7882
const call = t.callExpression(callee, args);
7983
if (pure) {
8084
t.addComment(call, 'leading', ' @__PURE__ ', /* line */ false);
@@ -90,6 +94,10 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
9094

9195
createExpressionStatement = t.expressionStatement;
9296

97+
createSpreadElement(expression: t.Expression): t.SpreadElement {
98+
return t.spreadElement(expression);
99+
}
100+
93101
createFunctionDeclaration(
94102
functionName: string,
95103
parameters: string[],
@@ -158,7 +166,9 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
158166
}
159167
}
160168

161-
createNewExpression = t.newExpression;
169+
createNewExpression(expression: t.Expression, args: t.Expression[]): t.Expression {
170+
return t.newExpression(expression, args);
171+
}
162172

163173
createObjectLiteral(properties: ObjectLiteralProperty<t.Expression>[]): t.Expression {
164174
return t.objectExpression(
@@ -181,7 +191,9 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
181191
return t.memberExpression(expression, t.identifier(propertyName), /* computed */ false);
182192
}
183193

184-
createReturnStatement = t.returnStatement;
194+
createReturnStatement(expression: t.Expression | null): t.Statement {
195+
return t.returnStatement(expression);
196+
}
185197

186198
createTaggedTemplate(tag: t.Expression, template: TemplateLiteral<t.Expression>): t.Expression {
187199
return t.taggedTemplateExpression(tag, this.createTemplateLiteral(template));
@@ -223,7 +235,7 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
223235
return t.regExpLiteral(body, flags ?? undefined);
224236
}
225237

226-
setSourceMapRange<T extends t.Statement | t.Expression | t.TemplateElement>(
238+
setSourceMapRange<T extends t.Statement | t.Expression | t.TemplateElement | t.SpreadElement>(
227239
node: T,
228240
sourceMapRange: SourceMapRange | null,
229241
): T {

packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export function createEs2015LinkerPlugin({
2626
logger,
2727
...options
2828
}: LinkerPluginOptions): PluginObj {
29-
let fileLinker: FileLinker<ConstantScopePath, t.Statement, t.Expression> | null = null;
29+
let fileLinker: FileLinker<
30+
ConstantScopePath,
31+
t.Statement,
32+
t.Expression | t.SpreadElement
33+
> | null = null;
3034

3135
return {
3236
visitor: {
@@ -47,13 +51,10 @@ export function createEs2015LinkerPlugin({
4751
}
4852
const sourceUrl = fileSystem.resolve(file.opts.cwd ?? '.', filename);
4953

50-
const linkerEnvironment = LinkerEnvironment.create<t.Statement, t.Expression>(
51-
fileSystem,
52-
logger,
53-
new BabelAstHost(),
54-
new BabelAstFactory(sourceUrl),
55-
options,
56-
);
54+
const linkerEnvironment = LinkerEnvironment.create<
55+
t.Statement,
56+
t.Expression | t.SpreadElement
57+
>(fileSystem, logger, new BabelAstHost(), new BabelAstFactory(sourceUrl), options);
5758
fileLinker = new FileLinker(linkerEnvironment, sourceUrl, file.code);
5859
},
5960

packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,23 @@ describe('BabelAstFactory', () => {
412412
});
413413
});
414414

415+
describe('createSpreadElement()', () => {
416+
it('should create a spread element in an array', () => {
417+
const before = factory.createIdentifier('a');
418+
const spread = factory.createSpreadElement(factory.createIdentifier('b'));
419+
const array = factory.createArrayLiteral([before, spread]);
420+
expect(generate(array).code).toEqual('[a, ...b]');
421+
});
422+
423+
it('should create a spread in a call expression', () => {
424+
const fn = factory.createIdentifier('fn');
425+
const before = factory.createIdentifier('a');
426+
const spread = factory.createSpreadElement(factory.createIdentifier('b'));
427+
const call = factory.createCallExpression(fn, [before, spread], false);
428+
expect(generate(call).code).toEqual('fn(a, ...b)');
429+
});
430+
});
431+
415432
describe('setSourceMapRange()', () => {
416433
it('should attach the `sourceMapRange` to the given `node`', () => {
417434
const expr = expression.ast`42`;

packages/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ export interface AstFactory<TStatement, TExpression> {
280280
*/
281281
createRegularExpressionLiteral(body: string, flags: string | null): TExpression;
282282

283+
/**
284+
* Create a spread element, typically in an array or function call. E.g. `[...a]` or `fn(...b)`.
285+
*
286+
* @param target Expression of the spread element.
287+
*/
288+
createSpreadElement(expression: TExpression): TExpression;
289+
283290
/**
284291
* Attach a source map range to the given node.
285292
*

packages/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
262262

263263
createPropertyAccess = ts.factory.createPropertyAccessExpression;
264264

265+
createSpreadElement = ts.factory.createSpreadElement;
266+
265267
createReturnStatement(expression: ts.Expression | null): ts.Statement {
266268
return ts.factory.createReturnStatement(expression ?? undefined);
267269
}

packages/compiler-cli/src/ngtsc/translator/test/typescript_ast_factory_spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,25 @@ describe('TypeScriptAstFactory', () => {
490490
});
491491
});
492492

493+
describe('createSpreadElement()', () => {
494+
it('should create a spread element in an array', () => {
495+
const {generate} = setupStatements();
496+
const before = factory.createIdentifier('a');
497+
const spread = factory.createSpreadElement(factory.createIdentifier('b'));
498+
const array = factory.createArrayLiteral([before, spread]);
499+
expect(generate(array)).toEqual('[a, ...b]');
500+
});
501+
502+
it('should create a spread in a call expression', () => {
503+
const {generate} = setupStatements();
504+
const fn = factory.createIdentifier('fn');
505+
const before = factory.createIdentifier('a');
506+
const spread = factory.createSpreadElement(factory.createIdentifier('b'));
507+
const call = factory.createCallExpression(fn, [before, spread], false);
508+
expect(generate(call)).toEqual('fn(a, ...b)');
509+
});
510+
});
511+
493512
describe('setSourceMapRange()', () => {
494513
it('should attach the `sourceMapRange` to the given `node`', () => {
495514
const {

0 commit comments

Comments
 (0)