Skip to content

Commit 8626d6c

Browse files
committed
refactor(compiler): Add support for spreaded expressions
Expression that return iterables can now be spreaded if needed.
1 parent d73a374 commit 8626d6c

File tree

8 files changed

+71
-0
lines changed

8 files changed

+71
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ export class BabelAstFactory implements AstFactory<t.Statement, t.Expression> {
160160

161161
createReturnStatement = t.returnStatement;
162162

163+
createSpreadedExpression(expression: t.Expression): t.Expression {
164+
return t.spreadElement(expression) as any;
165+
}
166+
163167
createTaggedTemplate(tag: t.Expression, template: TemplateLiteral<t.Expression>): t.Expression {
164168
const elements = template.elements.map((element, i) =>
165169
this.setSourceMapRange(

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,14 @@ describe('BabelAstFactory', () => {
300300
});
301301
});
302302

303+
describe('createSpreadedExpression()', () => {
304+
it('should create a spreaded expression of an array', () => {
305+
const expr = expression.ast`[3,4,5]`;
306+
const returnStmt = factory.createSpreadedExpression(expr);
307+
expect(generate(returnStmt).code).toEqual('...[3, 4, 5]');
308+
});
309+
});
310+
303311
describe('createTaggedTemplate()', () => {
304312
it('should create a tagged template node from the tag, elements and expressions', () => {
305313
const elements = [

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
@@ -204,6 +204,13 @@ export interface AstFactory<TStatement, TExpression> {
204204
*/
205205
createReturnStatement(expression: TExpression | null): TStatement;
206206

207+
/**
208+
* Create a spreaded express (e.g. `...myIterable`)
209+
*
210+
* @param expression the expression to spread
211+
*/
212+
createSpreadedExpression(expression: TExpression): TExpression;
213+
207214
/**
208215
* Create a tagged template literal string. E.g.
209216
*

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,10 @@ export class ExpressionTranslatorVisitor<TFile, TStatement, TExpression>
402402
);
403403
}
404404

405+
visitSpreadedIterableExpr(ast: o.outputAst.SpreadedIterableExpr, context: any) {
406+
return this.factory.createSpreadedExpression(ast.iterable.visitExpression(this, context));
407+
}
408+
405409
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, context: Context): TExpression {
406410
return this.factory.createArrayLiteral(
407411
ast.entries.map((expr) =>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ class TypeTranslatorVisitor implements o.ExpressionVisitor, o.TypeVisitor {
221221
throw new Error('Method not implemented.');
222222
}
223223

224+
visitSpreadedIterableExpr(ast: o.outputAst.SpreadedIterableExpr, context: any) {
225+
throw new Error('Method not implemented.');
226+
}
227+
224228
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, context: Context): ts.TupleTypeNode {
225229
const values = ast.entries.map((expr) => this.translateExpression(expr, context));
226230
return ts.factory.createTupleTypeNode(values);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ export class TypeScriptAstFactory implements AstFactory<ts.Statement, ts.Express
239239
return ts.factory.createReturnStatement(expression ?? undefined);
240240
}
241241

242+
createSpreadedExpression(expression: ts.Expression): ts.Expression {
243+
return ts.factory.createSpreadElement(expression);
244+
}
245+
242246
createTaggedTemplate(
243247
tag: ts.Expression,
244248
template: TemplateLiteral<ts.Expression>,

packages/compiler/src/output/abstract_emitter.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,11 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
484484
ctx.print(ast, `]`);
485485
return null;
486486
}
487+
visitSpreadedIterableExpr(ast: o.SpreadedIterableExpr, ctx: EmitterVisitorContext): any {
488+
ctx.print(ast, `...`);
489+
ast.iterable.visitExpression(this, ctx);
490+
return null;
491+
}
487492
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: EmitterVisitorContext): any {
488493
ctx.print(ast, `{`);
489494
this.visitAllObjects(

packages/compiler/src/output/output_ast.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,28 @@ export class LiteralArrayExpr extends Expression {
13031303
}
13041304
}
13051305

1306+
export class SpreadedIterableExpr extends Expression {
1307+
public iterable: Expression;
1308+
constructor(iterable: Expression, type?: Type | null, sourceSpan?: ParseSourceSpan | null) {
1309+
super(type, sourceSpan);
1310+
this.iterable = iterable;
1311+
}
1312+
1313+
override isEquivalent(e: Expression): boolean {
1314+
return this.iterable.isEquivalent(e);
1315+
}
1316+
override isConstant(): boolean {
1317+
return false;
1318+
}
1319+
override visitExpression(visitor: ExpressionVisitor, context: any): any {
1320+
return visitor.visitSpreadedIterableExpr(this, context);
1321+
}
1322+
1323+
override clone(): SpreadedIterableExpr {
1324+
return new SpreadedIterableExpr(this.iterable.clone(), this.type, this.sourceSpan);
1325+
}
1326+
}
1327+
13061328
export class LiteralMapEntry {
13071329
constructor(
13081330
public key: string,
@@ -1394,6 +1416,7 @@ export interface ExpressionVisitor {
13941416
visitReadPropExpr(ast: ReadPropExpr, context: any): any;
13951417
visitReadKeyExpr(ast: ReadKeyExpr, context: any): any;
13961418
visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any;
1419+
visitSpreadedIterableExpr(ast: SpreadedIterableExpr, context: any): any;
13971420
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any;
13981421
visitCommaExpr(ast: CommaExpr, context: any): any;
13991422
visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any;
@@ -1698,6 +1721,10 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
16981721
this.visitAllExpressions(ast.entries, context);
16991722
return this.visitExpression(ast, context);
17001723
}
1724+
visitSpreadedIterableExpr(ast: SpreadedIterableExpr, context: any): any {
1725+
this.visitExpression(ast.iterable, context);
1726+
return this.visitExpression(ast, context);
1727+
}
17011728
visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any {
17021729
ast.entries.forEach((entry) => entry.value.visitExpression(this, context));
17031730
return this.visitExpression(ast, context);
@@ -1816,6 +1843,14 @@ export function literalMap(
18161843
);
18171844
}
18181845

1846+
export function spreaded(
1847+
iterable: Expression,
1848+
type?: Type,
1849+
sourceSpan?: ParseSourceSpan | null,
1850+
): SpreadedIterableExpr {
1851+
return new SpreadedIterableExpr(iterable, type, sourceSpan);
1852+
}
1853+
18191854
export function unary(
18201855
operator: UnaryOperator,
18211856
expr: Expression,

0 commit comments

Comments
 (0)