diff --git a/.ng-dev/format.mts b/.ng-dev/format.mts
index 8cd63a8b67659..61b26a7c1917b 100644
--- a/.ng-dev/format.mts
+++ b/.ng-dev/format.mts
@@ -18,6 +18,7 @@ export const format: FormatConfig = {
'packages/benchpress/**/*.{js,ts}',
'packages/common/**/*.{js,ts}',
'packages/compiler/**/*.{js,ts}',
+ 'packages/compiler-cli/**/*.{js,ts}',
'packages/core/**/*.{js,ts}',
'packages/docs/**/*.{js,ts}',
'packages/elements/**/*.{js,ts}',
@@ -35,6 +36,8 @@ export const format: FormatConfig = {
'packages/upgrade/**/*.{js,ts}',
'packages/zone.js/**/*.{js,ts}',
+ // Test cases contain non valid code.
+ '!packages/compiler-cli/test/compliance/test_cases/**/*.{js,ts}',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
// Both third_party and .yarn are directories containing copied code which should
@@ -83,6 +86,7 @@ export const format: FormatConfig = {
'!packages/benchpress/**/*.{js,ts}',
'!packages/common/**/*.{js,ts}',
'!packages/compiler/**/*.{js,ts}',
+ '!packages/compiler-cli/**/*.{js,ts}',
'!packages/core/**/*.{js,ts}',
'!packages/docs/**/*.{js,ts}',
'!packages/elements/**/*.{js,ts}',
diff --git a/packages/compiler-cli/esbuild.config.js b/packages/compiler-cli/esbuild.config.js
index d34723a0b4d9b..d5ed1080fd29e 100644
--- a/packages/compiler-cli/esbuild.config.js
+++ b/packages/compiler-cli/esbuild.config.js
@@ -7,12 +7,12 @@
*/
module.exports = {
- resolveExtensions : ['.mjs', '.js'],
+ resolveExtensions: ['.mjs', '.js'],
// Note: `@bazel/esbuild` has a bug and does not pass-through the format from Starlark.
- format : 'esm',
- banner : {
+ format: 'esm',
+ banner: {
// Workaround for: https://github.com/evanw/esbuild/issues/946
- js : `
+ js: `
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
`,
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/basic.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/basic.ts
index e065134e45374..4ddce090fabbe 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/basic.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/basic.ts
@@ -15,17 +15,11 @@ import {Lib2Module} from 'lib2_built/module';
selector: 'id-app',
template: '',
})
-export class AppComponent {
-}
+export class AppComponent {}
@NgModule({
- imports: [
- Lib2Module,
- BrowserModule,
- ServerModule,
- ],
+ imports: [Lib2Module, BrowserModule, ServerModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
-export class BasicAppModule {
-}
+export class BasicAppModule {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts
index 7f8e7dedb3c65..e479dc84ef9c7 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts
@@ -11,8 +11,7 @@ import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
@Injectable()
-export class NormalService {
-}
+export class NormalService {}
@Component({
selector: 'dep-app',
@@ -26,16 +25,12 @@ export class AppComponent {
}
@NgModule({
- imports: [
- BrowserModule,
- ServerModule,
- ],
+ imports: [BrowserModule, ServerModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [NormalService],
})
-export class DepAppModule {
-}
+export class DepAppModule {}
@Injectable({providedIn: DepAppModule})
export class ShakeableService {
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts
index 2a4c73a53b376..a5b71e7b4b95a 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts
@@ -11,16 +11,14 @@ import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
@Injectable()
-export class Service {
-}
+export class Service {}
@Component({
selector: 'hierarchy-app',
template: '',
providers: [Service],
})
-export class AppComponent {
-}
+export class AppComponent {}
@Component({
selector: 'child-cmp',
@@ -29,18 +27,14 @@ export class AppComponent {
export class ChildComponent {
found: boolean;
- constructor(@Optional() @Self() service: Service|null) {
+ constructor(@Optional() @Self() service: Service | null) {
this.found = !!service;
}
}
@NgModule({
- imports: [
- BrowserModule,
- ServerModule,
- ],
+ imports: [BrowserModule, ServerModule],
declarations: [AppComponent, ChildComponent],
bootstrap: [AppComponent],
})
-export class HierarchyAppModule {
-}
+export class HierarchyAppModule {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root.ts
index 8af32cb960d02..7b64c6ff4e6d8 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root.ts
@@ -17,27 +17,22 @@ import {LazyModule} from './root_lazy';
selector: 'root-app',
template: '',
})
-export class AppComponent {
-}
+export class AppComponent {}
export function children(): any {
console.error('children', LazyModule);
return LazyModule;
}
-
@NgModule({
imports: [
BrowserModule,
ServerModule,
- RouterModule.forRoot(
- [
- {path: '', pathMatch: 'prefix', loadChildren: children},
- ],
- {initialNavigation: 'enabledBlocking'}),
+ RouterModule.forRoot([{path: '', pathMatch: 'prefix', loadChildren: children}], {
+ initialNavigation: 'enabledBlocking',
+ }),
],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
-export class RootAppModule {
-}
+export class RootAppModule {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_lazy.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_lazy.ts
index d62b6b0e40ee5..40aa38ab26eca 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_lazy.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_lazy.ts
@@ -25,11 +25,6 @@ export class RouteComponent {
@NgModule({
declarations: [RouteComponent],
- imports: [
- RouterModule.forChild([
- {path: '', pathMatch: 'prefix', component: RouteComponent},
- ]),
- ],
+ imports: [RouterModule.forChild([{path: '', pathMatch: 'prefix', component: RouteComponent}])],
})
-export class LazyModule {
-}
+export class LazyModule {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_service.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_service.ts
index 8cd0dd1beb4b0..582ca36929f81 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_service.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/root_service.ts
@@ -11,5 +11,4 @@ import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root',
})
-export class Service {
-}
+export class Service {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts
index f606f6cf28542..f17e22d0693dc 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts
@@ -12,7 +12,7 @@ import {ServerModule} from '@angular/platform-server';
@Injectable()
export class NormalService {
- constructor(@Optional() @Self() readonly shakeable: ShakeableService|null) {}
+ constructor(@Optional() @Self() readonly shakeable: ShakeableService | null) {}
}
@Component({
@@ -27,17 +27,12 @@ export class AppComponent {
}
@NgModule({
- imports: [
- BrowserModule,
- ServerModule,
- ],
+ imports: [BrowserModule, ServerModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [NormalService],
})
-export class SelfAppModule {
-}
+export class SelfAppModule {}
@Injectable({providedIn: SelfAppModule})
-export class ShakeableService {
-}
+export class ShakeableService {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts
index 2ffdf243aee00..e474377e8bb96 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts
@@ -10,7 +10,6 @@ import {Component, Inject, Injectable, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
-
@Component({
selector: 'string-app',
template: '{{data}}',
@@ -23,16 +22,12 @@ export class AppComponent {
}
@NgModule({
- imports: [
- BrowserModule,
- ServerModule,
- ],
+ imports: [BrowserModule, ServerModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [{provide: 'someStringToken', useValue: 'works'}],
})
-export class StringAppModule {
-}
+export class StringAppModule {}
@Injectable({providedIn: StringAppModule})
export class Service {
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts
index e61b70b819197..a8d83f63fc86e 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts
@@ -6,24 +6,30 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {Component, forwardRef, Inject, inject, Injectable, InjectionToken, NgModule} from '@angular/core';
+import {
+ Component,
+ forwardRef,
+ Inject,
+ inject,
+ Injectable,
+ InjectionToken,
+ NgModule,
+} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ServerModule} from '@angular/platform-server';
export interface IService {
- readonly dep: {readonly data: string;};
+ readonly dep: {readonly data: string};
}
@NgModule({})
-export class TokenModule {
-}
+export class TokenModule {}
export const TOKEN = new InjectionToken('test', {
providedIn: TokenModule,
factory: () => new Service(inject(Dep)),
});
-
@Component({
selector: 'token-app',
template: '{{data}}',
@@ -36,17 +42,12 @@ export class AppComponent {
}
@NgModule({
- imports: [
- BrowserModule,
- ServerModule,
- TokenModule,
- ],
+ imports: [BrowserModule, ServerModule, TokenModule],
providers: [forwardRef(() => Dep)],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
-export class TokenAppModule {
-}
+export class TokenAppModule {}
@Injectable()
export class Dep {
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts
index 213cd829e42e0..155176deb3d34 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts
@@ -18,71 +18,71 @@ import {StringAppModule} from 'app_built/src/string';
import {TokenAppModule} from 'app_built/src/token';
describe('ngInjectableDef Bazel Integration', () => {
- it('works in AOT', done => {
+ it('works in AOT', (done) => {
renderModule(BasicAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>0:0<\//);
done();
});
});
- it('@Self() works in component hierarchies', done => {
+ it('@Self() works in component hierarchies', (done) => {
renderModule(HierarchyAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>false<\//);
done();
});
});
- it('@Optional() Self() resolves to @Injectable() scoped service', done => {
+ it('@Optional() Self() resolves to @Injectable() scoped service', (done) => {
renderModule(SelfAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>true<\//);
done();
});
});
- it('InjectionToken ngInjectableDef works', done => {
+ it('InjectionToken ngInjectableDef works', (done) => {
renderModule(TokenAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>fromToken<\//);
done();
});
});
- it('APP_ROOT_SCOPE works', done => {
+ it('APP_ROOT_SCOPE works', (done) => {
renderModule(RootAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>true:false<\//);
done();
});
});
- it('can inject dependencies', done => {
+ it('can inject dependencies', (done) => {
renderModule(DepAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>true<\//);
done();
});
});
- it('string tokens work', done => {
+ it('string tokens work', (done) => {
renderModule(StringAppModule, {
document: '',
url: '/',
- }).then(html => {
+ }).then((html) => {
expect(html).toMatch(/>works<\//);
done();
});
@@ -105,8 +105,7 @@ describe('ngInjectableDef Bazel Integration', () => {
it('allows provider override in JIT for module-scoped @Injectables', () => {
@NgModule()
- class Module {
- }
+ class Module {}
@Injectable({
providedIn: Module,
@@ -159,33 +158,32 @@ describe('ngInjectableDef Bazel Integration', () => {
expect(() => TestBed.inject(ChildService).value).toThrowError(/ChildService/);
});
- it('uses legacy `ngInjectable` property even if it inherits from a class that has `ɵprov` property',
- () => {
- @Injectable({
- providedIn: 'root',
- useValue: new ParentService('parent'),
- })
- class ParentService {
- constructor(public value: string) {}
- }
-
- // ChildServices extends ParentService but does not have @Injectable
- class ChildService extends ParentService {
- constructor(value: string) {
- super(value);
- }
- static ngInjectableDef = {
- providedIn: 'root',
- factory: () => new ChildService('child'),
- token: ChildService,
- };
- }
-
- TestBed.configureTestingModule({});
- // We are asserting that system throws an error, rather than taking the inherited
- // annotation.
- expect(TestBed.inject(ChildService).value).toEqual('child');
- });
+ it('uses legacy `ngInjectable` property even if it inherits from a class that has `ɵprov` property', () => {
+ @Injectable({
+ providedIn: 'root',
+ useValue: new ParentService('parent'),
+ })
+ class ParentService {
+ constructor(public value: string) {}
+ }
+
+ // ChildServices extends ParentService but does not have @Injectable
+ class ChildService extends ParentService {
+ constructor(value: string) {
+ super(value);
+ }
+ static ngInjectableDef = {
+ providedIn: 'root',
+ factory: () => new ChildService('child'),
+ token: ChildService,
+ };
+ }
+
+ TestBed.configureTestingModule({});
+ // We are asserting that system throws an error, rather than taking the inherited
+ // annotation.
+ expect(TestBed.inject(ChildService).value).toEqual('child');
+ });
it('NgModule injector understands requests for INJECTABLE', () => {
TestBed.configureTestingModule({
@@ -200,8 +198,7 @@ describe('ngInjectableDef Bazel Integration', () => {
template: 'test',
providers: [{provide: 'foo', useValue: 'bar'}],
})
- class TestCmp {
- }
+ class TestCmp {}
TestBed.configureTestingModule({
declarations: [TestCmp],
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/lib1/module.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/lib1/module.ts
index b0db0bd4ded03..029b47da70dda 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/lib1/module.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/lib1/module.ts
@@ -9,8 +9,7 @@
import {Injectable, NgModule} from '@angular/core';
@NgModule({})
-export class Lib1Module {
-}
+export class Lib1Module {}
@Injectable({
providedIn: Lib1Module,
diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/lib2/module.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/lib2/module.ts
index 625363165b6ae..e0393c99aacc4 100644
--- a/packages/compiler-cli/integrationtest/bazel/injectable_def/lib2/module.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/lib2/module.ts
@@ -28,5 +28,4 @@ export class Lib2Cmp {
exports: [Lib2Cmp],
imports: [Lib1Module],
})
-export class Lib2Module {
-}
+export class Lib2Module {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/src/module.ts b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/src/module.ts
index a649a7462886a..3dbcc575c53d5 100644
--- a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/src/module.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/src/module.ts
@@ -11,30 +11,25 @@ import {Injectable, InjectionToken, NgModule} from '@angular/core';
export const AOT_TOKEN = new InjectionToken('TOKEN');
@Injectable()
-export class AotService {
-}
+export class AotService {}
@NgModule({
providers: [AotService],
})
-export class AotServiceModule {
-}
+export class AotServiceModule {}
@NgModule({
providers: [{provide: AOT_TOKEN, useValue: 'imports'}],
})
-export class AotImportedModule {
-}
+export class AotImportedModule {}
@NgModule({
providers: [{provide: AOT_TOKEN, useValue: 'exports'}],
})
-export class AotExportedModule {
-}
+export class AotExportedModule {}
@NgModule({
imports: [AotServiceModule, AotImportedModule],
exports: [AotExportedModule],
})
-export class AotModule {
-}
+export class AotModule {}
diff --git a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts
index c05950ee1b25c..f769e97dd68c0 100644
--- a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts
+++ b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts
@@ -6,7 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {forwardRef, Injectable, InjectionToken, Injector, NgModule, ɵcreateInjector as createInjector} from '@angular/core';
+import {
+ forwardRef,
+ Injectable,
+ InjectionToken,
+ Injector,
+ NgModule,
+ ɵcreateInjector as createInjector,
+} from '@angular/core';
import {AOT_TOKEN, AotModule, AotService} from 'app_built/src/module';
describe('NgModule', () => {
@@ -25,24 +32,19 @@ describe('NgModule', () => {
});
});
-
-
describe('JIT', () => {
@Injectable({providedIn: null})
- class Service {
- }
+ class Service {}
@NgModule({
providers: [Service],
})
- class JitModule {
- }
+ class JitModule {}
@NgModule({
imports: [JitModule],
})
- class JitAppModule {
- }
+ class JitAppModule {}
it('works', () => {
createInjector(JitAppModule);
@@ -52,20 +54,18 @@ describe('NgModule', () => {
@NgModule({
imports: [forwardRef(() => BModule)],
})
- class AModule {
- }
+ class AModule {}
@NgModule({
imports: [AModule],
})
- class BModule {
- }
+ class BModule {}
- expect(() => createInjector(AModule))
- .toThrowError(
- 'NG0200: Circular dependency in DI detected for AModule. ' +
- 'Dependency path: AModule > BModule > AModule. ' +
- 'Find more at https://angular.io/errors/NG0200');
+ expect(() => createInjector(AModule)).toThrowError(
+ 'NG0200: Circular dependency in DI detected for AModule. ' +
+ 'Dependency path: AModule > BModule > AModule. ' +
+ 'Find more at https://angular.io/errors/NG0200',
+ );
});
it('merges imports and exports', () => {
@@ -73,20 +73,17 @@ describe('NgModule', () => {
@NgModule({
providers: [{provide: TOKEN, useValue: 'provided from A'}],
})
- class AModule {
- }
+ class AModule {}
@NgModule({
providers: [{provide: TOKEN, useValue: 'provided from B'}],
})
- class BModule {
- }
+ class BModule {}
@NgModule({
imports: [AModule],
exports: [BModule],
})
- class CModule {
- }
+ class CModule {}
const injector = createInjector(CModule);
expect(injector.get(TOKEN)).toEqual('provided from B');
diff --git a/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts b/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts
index 108c44486c27b..00047cff09321 100644
--- a/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts
+++ b/packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts
@@ -8,15 +8,24 @@
import {types as t} from '@babel/core';
import {assert} from '../../../../linker';
-import {AstFactory, BinaryOperator, LeadingComment, ObjectLiteralProperty, SourceMapRange, TemplateLiteral, VariableDeclarationType} from '../../../../src/ngtsc/translator';
+import {
+ AstFactory,
+ BinaryOperator,
+ LeadingComment,
+ ObjectLiteralProperty,
+ SourceMapRange,
+ TemplateLiteral,
+ VariableDeclarationType,
+} from '../../../../src/ngtsc/translator';
/**
* A Babel flavored implementation of the AstFactory.
*/
export class BabelAstFactory implements AstFactory {
constructor(
- /** The absolute path to the source file being compiled. */
- private sourceUrl: string) {}
+ /** The absolute path to the source file being compiled. */
+ private sourceUrl: string,
+ ) {}
attachComments(statement: t.Statement, leadingComments: LeadingComment[]): void {
// We must process the comments in reverse because `t.addComment()` will add new ones in front.
@@ -34,8 +43,10 @@ export class BabelAstFactory implements AstFactory {
}
createBinaryExpression(
- leftOperand: t.Expression, operator: BinaryOperator,
- rightOperand: t.Expression): t.Expression {
+ leftOperand: t.Expression,
+ operator: BinaryOperator,
+ rightOperand: t.Expression,
+ ): t.Expression {
switch (operator) {
case '&&':
case '||':
@@ -64,26 +75,44 @@ export class BabelAstFactory implements AstFactory {
createExpressionStatement = t.expressionStatement;
- createFunctionDeclaration(functionName: string, parameters: string[], body: t.Statement):
- t.Statement {
+ createFunctionDeclaration(
+ functionName: string,
+ parameters: string[],
+ body: t.Statement,
+ ): t.Statement {
assert(body, t.isBlockStatement, 'a block');
return t.functionDeclaration(
- t.identifier(functionName), parameters.map(param => t.identifier(param)), body);
+ t.identifier(functionName),
+ parameters.map((param) => t.identifier(param)),
+ body,
+ );
}
- createArrowFunctionExpression(parameters: string[], body: t.Statement|t.Expression):
- t.Expression {
+ createArrowFunctionExpression(
+ parameters: string[],
+ body: t.Statement | t.Expression,
+ ): t.Expression {
if (t.isStatement(body)) {
assert(body, t.isBlockStatement, 'a block');
}
- return t.arrowFunctionExpression(parameters.map(param => t.identifier(param)), body);
+ return t.arrowFunctionExpression(
+ parameters.map((param) => t.identifier(param)),
+ body,
+ );
}
- createFunctionExpression(functionName: string|null, parameters: string[], body: t.Statement):
- t.Expression {
+ createFunctionExpression(
+ functionName: string | null,
+ parameters: string[],
+ body: t.Statement,
+ ): t.Expression {
assert(body, t.isBlockStatement, 'a block');
const name = functionName !== null ? t.identifier(functionName) : null;
- return t.functionExpression(name, parameters.map(param => t.identifier(param)), body);
+ return t.functionExpression(
+ name,
+ parameters.map((param) => t.identifier(param)),
+ body,
+ );
}
createIdentifier = t.identifier;
@@ -94,7 +123,7 @@ export class BabelAstFactory implements AstFactory {
return this.createCallExpression(t.import(), [t.stringLiteral(url)], false /* pure */);
}
- createLiteral(value: string|number|boolean|null|undefined): t.Expression {
+ createLiteral(value: string | number | boolean | null | undefined): t.Expression {
if (typeof value === 'string') {
return t.stringLiteral(value);
} else if (typeof value === 'number') {
@@ -113,11 +142,14 @@ export class BabelAstFactory implements AstFactory {
createNewExpression = t.newExpression;
createObjectLiteral(properties: ObjectLiteralProperty[]): t.Expression {
- return t.objectExpression(properties.map(prop => {
- const key =
- prop.quoted ? t.stringLiteral(prop.propertyName) : t.identifier(prop.propertyName);
- return t.objectProperty(key, prop.value);
- }));
+ return t.objectExpression(
+ properties.map((prop) => {
+ const key = prop.quoted
+ ? t.stringLiteral(prop.propertyName)
+ : t.identifier(prop.propertyName);
+ return t.objectProperty(key, prop.value);
+ }),
+ );
}
createParenthesizedExpression = t.parenthesizedExpression;
@@ -129,9 +161,12 @@ export class BabelAstFactory implements AstFactory {
createReturnStatement = t.returnStatement;
createTaggedTemplate(tag: t.Expression, template: TemplateLiteral): t.Expression {
- const elements = template.elements.map(
- (element, i) => this.setSourceMapRange(
- t.templateElement(element, i === template.elements.length - 1), element.range));
+ const elements = template.elements.map((element, i) =>
+ this.setSourceMapRange(
+ t.templateElement(element, i === template.elements.length - 1),
+ element.range,
+ ),
+ );
return t.taggedTemplateExpression(tag, t.templateLiteral(elements, template.expressions));
}
@@ -144,14 +179,19 @@ export class BabelAstFactory implements AstFactory {
createUnaryExpression = t.unaryExpression;
createVariableDeclaration(
- variableName: string, initializer: t.Expression|null,
- type: VariableDeclarationType): t.Statement {
- return t.variableDeclaration(
- type, [t.variableDeclarator(t.identifier(variableName), initializer)]);
- }
-
- setSourceMapRange(
- node: T, sourceMapRange: SourceMapRange|null): T {
+ variableName: string,
+ initializer: t.Expression | null,
+ type: VariableDeclarationType,
+ ): t.Statement {
+ return t.variableDeclaration(type, [
+ t.variableDeclarator(t.identifier(variableName), initializer),
+ ]);
+ }
+
+ setSourceMapRange(
+ node: T,
+ sourceMapRange: SourceMapRange | null,
+ ): T {
if (sourceMapRange === null) {
return node;
}
@@ -161,14 +201,14 @@ export class BabelAstFactory implements AstFactory {
// file. This happens when the template is inline, in which case just use `undefined`.
filename: sourceMapRange.url !== this.sourceUrl ? sourceMapRange.url : undefined,
start: {
- line: sourceMapRange.start.line + 1, // lines are 1-based in Babel.
+ line: sourceMapRange.start.line + 1, // lines are 1-based in Babel.
column: sourceMapRange.start.column,
},
end: {
- line: sourceMapRange.end.line + 1, // lines are 1-based in Babel.
+ line: sourceMapRange.end.line + 1, // lines are 1-based in Babel.
column: sourceMapRange.end.column,
},
- } as any; // Needed because the Babel typings for `loc` don't include `filename`.
+ } as any; // Needed because the Babel typings for `loc` don't include `filename`.
node.start = sourceMapRange.start.offset;
node.end = sourceMapRange.end.offset;
diff --git a/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts b/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts
index 918dce7412c57..e40919b2d4715 100644
--- a/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts
+++ b/packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts
@@ -14,7 +14,7 @@ import {assert, AstHost, FatalLinkerError, Range} from '../../../../linker';
* This implementation of `AstHost` is able to get information from Babel AST nodes.
*/
export class BabelAstHost implements AstHost {
- getSymbolName(node: t.Expression): string|null {
+ getSymbolName(node: t.Expression): string | null {
if (t.isIdentifier(node)) {
return node.name;
} else if (t.isMemberExpression(node) && t.isIdentifier(node.property)) {
@@ -60,7 +60,7 @@ export class BabelAstHost implements AstHost {
parseArrayLiteral(array: t.Expression): t.Expression[] {
assert(array, t.isArrayExpression, 'an array literal');
- return array.elements.map(element => {
+ return array.elements.map((element) => {
assert(element, isNotEmptyElement, 'element in array not to be empty');
assert(element, isNotSpreadElement, 'element in array not to use spread syntax');
return element;
@@ -84,8 +84,9 @@ export class BabelAstHost implements AstHost {
return result;
}
- isFunctionExpression(node: t.Expression):
- node is Extract {
+ isFunctionExpression(
+ node: t.Expression,
+ ): node is Extract {
return t.isFunction(node) || t.isArrowFunctionExpression(node);
}
@@ -102,7 +103,9 @@ export class BabelAstHost implements AstHost {
if (fn.body.body.length !== 1) {
throw new FatalLinkerError(
- fn.body, 'Unsupported syntax, expected a function body with a single return statement.');
+ fn.body,
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
}
const stmt = fn.body.body[0];
assert(stmt, t.isReturnStatement, 'a function body with a single return statement');
@@ -117,7 +120,7 @@ export class BabelAstHost implements AstHost {
parseParameters(fn: t.Expression): t.Expression[] {
assert(fn, this.isFunctionExpression, 'a function');
- return fn.params.map(param => {
+ return fn.params.map((param) => {
assert(param, t.isIdentifier, 'an identifier');
return param;
});
@@ -131,7 +134,7 @@ export class BabelAstHost implements AstHost {
}
parseArguments(call: t.Expression): t.Expression[] {
assert(call, t.isCallExpression, 'a call expression');
- return call.arguments.map(arg => {
+ return call.arguments.map((arg) => {
assert(arg, isNotSpreadArgument, 'argument not to use spread syntax');
assert(arg, t.isExpression, 'argument to be an expression');
return arg;
@@ -141,10 +144,12 @@ export class BabelAstHost implements AstHost {
getRange(node: t.Expression): Range {
if (node.loc == null || node.start == null || node.end == null) {
throw new FatalLinkerError(
- node, 'Unable to read range for node - it is missing location information.');
+ node,
+ 'Unable to read range for node - it is missing location information.',
+ );
}
return {
- startLine: node.loc.start.line - 1, // Babel lines are 1-based
+ startLine: node.loc.start.line - 1, // Babel lines are 1-based
startCol: node.loc.start.column,
startPos: node.start,
endPos: node.end,
@@ -156,8 +161,9 @@ export class BabelAstHost implements AstHost {
* Return true if the expression does not represent an empty element in an array literal.
* For example in `[,foo]` the first element is "empty".
*/
-function isNotEmptyElement(e: t.Expression|t.SpreadElement|null): e is t.Expression|
- t.SpreadElement {
+function isNotEmptyElement(
+ e: t.Expression | t.SpreadElement | null,
+): e is t.Expression | t.SpreadElement {
return e !== null;
}
@@ -165,11 +171,10 @@ function isNotEmptyElement(e: t.Expression|t.SpreadElement|null): e is t.Express
* Return true if the expression is not a spread element of an array literal.
* For example in `[x, ...rest]` the `...rest` expression is a spread element.
*/
-function isNotSpreadElement(e: t.Expression|t.SpreadElement): e is t.Expression {
+function isNotSpreadElement(e: t.Expression | t.SpreadElement): e is t.Expression {
return !t.isSpreadElement(e);
}
-
/**
* Return true if the node can be considered a text based property name for an
* object expression.
@@ -177,8 +182,9 @@ function isNotSpreadElement(e: t.Expression|t.SpreadElement): e is t.Expression
* Notably in the Babel AST, object patterns (for destructuring) could be of type
* `t.PrivateName` so we need a distinction between object expressions and patterns.
*/
-function isObjectExpressionPropertyName(n: t.Node): n is t.Identifier|t.StringLiteral|
- t.NumericLiteral {
+function isObjectExpressionPropertyName(
+ n: t.Node,
+): n is t.Identifier | t.StringLiteral | t.NumericLiteral {
return t.isIdentifier(n) || t.isStringLiteral(n) || t.isNumericLiteral(n);
}
@@ -194,12 +200,17 @@ function isNotSpreadArgument(arg: ArgumentType): arg is Exclude|NodePath|NodePath;
+ | NodePath
+ | NodePath
+ | NodePath;
/**
* This class represents the lexical scope of a partial declaration in Babel source code.
@@ -36,7 +38,7 @@ export class BabelDeclarationScope implements DeclarationScope|null = null;
+export function createEs2015LinkerPlugin({
+ fileSystem,
+ logger,
+ ...options
+}: LinkerPluginOptions): PluginObj {
+ let fileLinker: FileLinker | null = null;
return {
visitor: {
Program: {
-
/**
* Create a new `FileLinker` as we enter each file (`t.Program` in Babel).
*/
@@ -40,12 +42,18 @@ export function createEs2015LinkerPlugin({fileSystem, logger, ...options}: Linke
const filename = file.opts.filename ?? file.opts.filenameRelative;
if (!filename) {
throw new Error(
- 'No filename (nor filenameRelative) provided by Babel. This is required for the linking of partially compiled directives and components.');
+ 'No filename (nor filenameRelative) provided by Babel. This is required for the linking of partially compiled directives and components.',
+ );
}
const sourceUrl = fileSystem.resolve(file.opts.cwd ?? '.', filename);
const linkerEnvironment = LinkerEnvironment.create(
- fileSystem, logger, new BabelAstHost(), new BabelAstFactory(sourceUrl), options);
+ fileSystem,
+ logger,
+ new BabelAstHost(),
+ new BabelAstFactory(sourceUrl),
+ options,
+ );
fileLinker = new FileLinker(linkerEnvironment, sourceUrl, file.code);
},
@@ -59,7 +67,7 @@ export function createEs2015LinkerPlugin({fileSystem, logger, ...options}: Linke
insertStatements(constantScope, statements);
}
fileLinker = null;
- }
+ },
},
/**
@@ -89,11 +97,11 @@ export function createEs2015LinkerPlugin({fileSystem, logger, ...options}: Linke
call.replaceWith(replacement);
} catch (e) {
- const node = isFatalLinkerError(e) ? e.node as t.Node : call.node;
+ const node = isFatalLinkerError(e) ? (e.node as t.Node) : call.node;
throw buildCodeFrameError(state.file, (e as Error).message, node);
}
- }
- }
+ },
+ },
};
}
@@ -114,7 +122,9 @@ function insertStatements(path: ConstantScopePath, statements: t.Statement[]): v
* Insert the `statements` at the top of the body of the `fn` function.
*/
function insertIntoFunction(
- fn: NodePath, statements: t.Statement[]): void {
+ fn: NodePath,
+ statements: t.Statement[],
+): void {
const body = fn.get('body');
body.unshiftContainer('body', statements);
}
@@ -124,7 +134,7 @@ function insertIntoFunction(
*/
function insertIntoProgram(program: NodePath, statements: t.Statement[]): void {
const body = program.get('body');
- const importStatements = body.filter(statement => statement.isImportDeclaration());
+ const importStatements = body.filter((statement) => statement.isImportDeclaration());
if (importStatements.length === 0) {
program.unshiftContainer('body', statements);
} else {
@@ -132,7 +142,7 @@ function insertIntoProgram(program: NodePath, statements: t.Statement
}
}
-function getCalleeName(call: NodePath): string|null {
+function getCalleeName(call: NodePath): string | null {
const callee = call.node.callee;
if (t.isIdentifier(callee)) {
return callee.name;
@@ -149,13 +159,13 @@ function getCalleeName(call: NodePath): string|null {
* Return true if all the `nodes` are Babel expressions.
*/
function isExpressionArray(nodes: t.Node[]): nodes is t.Expression[] {
- return nodes.every(node => t.isExpression(node));
+ return nodes.every((node) => t.isExpression(node));
}
/**
* Assert that the given `obj` is `null`.
*/
-function assertNull(obj: T|null): asserts obj is null {
+function assertNull(obj: T | null): asserts obj is null {
if (obj !== null) {
throw new Error('BUG - expected `obj` to be null');
}
@@ -164,7 +174,7 @@ function assertNull(obj: T|null): asserts obj is null {
/**
* Assert that the given `obj` is not `null`.
*/
-function assertNotNull(obj: T|null): asserts obj is T {
+function assertNotNull(obj: T | null): asserts obj is T {
if (obj === null) {
throw new Error('BUG - expected `obj` not to be null');
}
diff --git a/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts b/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts
index ecf317aae9127..43d6785a330a7 100644
--- a/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts
+++ b/packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts
@@ -22,19 +22,17 @@ const statement = template.statement;
describe('BabelAstFactory', () => {
let factory: BabelAstFactory;
- beforeEach(() => factory = new BabelAstFactory('/original.ts'));
+ beforeEach(() => (factory = new BabelAstFactory('/original.ts')));
describe('attachComments()', () => {
it('should add the comments to the given statement', () => {
const stmt = statement.ast`x = 10;`;
- factory.attachComments(
- stmt, [leadingComment('comment 1', true), leadingComment('comment 2', false)]);
+ factory.attachComments(stmt, [
+ leadingComment('comment 1', true),
+ leadingComment('comment 2', false),
+ ]);
- expect(generate(stmt).code).toEqual([
- '/* comment 1 */',
- '//comment 2',
- 'x = 10;',
- ].join('\n'));
+ expect(generate(stmt).code).toEqual(['/* comment 1 */', '//comment 2', 'x = 10;'].join('\n'));
});
});
@@ -79,12 +77,7 @@ describe('BabelAstFactory', () => {
const stmt1 = statement.ast`x = 10`;
const stmt2 = statement.ast`y = 20`;
const block = factory.createBlock([stmt1, stmt2]);
- expect(generate(block).code).toEqual([
- '{',
- ' x = 10;',
- ' y = 20;',
- '}',
- ].join('\n'));
+ expect(generate(block).code).toEqual(['{', ' x = 10;', ' y = 20;', '}'].join('\n'));
});
});
@@ -135,76 +128,54 @@ describe('BabelAstFactory', () => {
});
describe('createFunctionDeclaration()', () => {
- it('should create a function declaration node with the given name, parameters and body statements',
- () => {
- const stmts = statement.ast`{x = 10; y = 20;}`;
- const fn = factory.createFunctionDeclaration('foo', ['arg1', 'arg2'], stmts);
- expect(generate(fn).code).toEqual([
- 'function foo(arg1, arg2) {',
- ' x = 10;',
- ' y = 20;',
- '}',
- ].join('\n'));
- });
+ it('should create a function declaration node with the given name, parameters and body statements', () => {
+ const stmts = statement.ast`{x = 10; y = 20;}`;
+ const fn = factory.createFunctionDeclaration('foo', ['arg1', 'arg2'], stmts);
+ expect(generate(fn).code).toEqual(
+ ['function foo(arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
+ );
+ });
});
describe('createFunctionExpression()', () => {
- it('should create a function expression node with the given name, parameters and body statements',
- () => {
- const stmts = statement.ast`{x = 10; y = 20;}`;
- const fn = factory.createFunctionExpression('foo', ['arg1', 'arg2'], stmts);
- expect(t.isStatement(fn)).toBe(false);
- expect(generate(fn).code).toEqual([
- 'function foo(arg1, arg2) {',
- ' x = 10;',
- ' y = 20;',
- '}',
- ].join('\n'));
- });
+ it('should create a function expression node with the given name, parameters and body statements', () => {
+ const stmts = statement.ast`{x = 10; y = 20;}`;
+ const fn = factory.createFunctionExpression('foo', ['arg1', 'arg2'], stmts);
+ expect(t.isStatement(fn)).toBe(false);
+ expect(generate(fn).code).toEqual(
+ ['function foo(arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
+ );
+ });
it('should create an anonymous function expression node if the name is null', () => {
const stmts = statement.ast`{x = 10; y = 20;}`;
const fn = factory.createFunctionExpression(null, ['arg1', 'arg2'], stmts);
- expect(generate(fn).code).toEqual([
- 'function (arg1, arg2) {',
- ' x = 10;',
- ' y = 20;',
- '}',
- ].join('\n'));
+ expect(generate(fn).code).toEqual(
+ ['function (arg1, arg2) {', ' x = 10;', ' y = 20;', '}'].join('\n'),
+ );
});
});
describe('createArrowFunctionExpression()', () => {
- it('should create an arrow function with an implicit return if a single statement is provided',
- () => {
- const expr = expression.ast`arg2 + arg1`;
- const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], expr);
- expect(generate(fn).code).toEqual('(arg1, arg2) => arg2 + arg1');
- });
+ it('should create an arrow function with an implicit return if a single statement is provided', () => {
+ const expr = expression.ast`arg2 + arg1`;
+ const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], expr);
+ expect(generate(fn).code).toEqual('(arg1, arg2) => arg2 + arg1');
+ });
it('should create an arrow function with an implicit return object literal', () => {
const expr = expression.ast`{a: 1, b: 2}`;
const fn = factory.createArrowFunctionExpression([], expr);
- expect(generate(fn).code).toEqual([
- '() => ({',
- ' a: 1,',
- ' b: 2',
- '})',
- ].join('\n'));
- });
-
- it('should create an arrow function with a body when an array of statements is provided',
- () => {
- const stmts = statement.ast`{x = 10; y = 20; return x + y;}`;
- const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], stmts);
- expect(generate(fn).code).toEqual([
- '(arg1, arg2) => {',
- ' x = 10;',
- ' y = 20;',
- ' return x + y;',
- '}',
- ].join('\n'));
- });
+ expect(generate(fn).code).toEqual(['() => ({', ' a: 1,', ' b: 2', '})'].join('\n'));
+ });
+
+ it('should create an arrow function with a body when an array of statements is provided', () => {
+ const stmts = statement.ast`{x = 10; y = 20; return x + y;}`;
+ const fn = factory.createArrowFunctionExpression(['arg1', 'arg2'], stmts);
+ expect(generate(fn).code).toEqual(
+ ['(arg1, arg2) => {', ' x = 10;', ' y = 20;', ' return x + y;', '}'].join('\n'),
+ );
+ });
});
describe('createIdentifier()', () => {
@@ -279,14 +250,13 @@ describe('BabelAstFactory', () => {
});
describe('createNewExpression()', () => {
- it('should create a `new` operation on the constructor `expression` with the given `args`',
- () => {
- const expr = expression.ast`Foo`;
- const arg1 = expression.ast`42`;
- const arg2 = expression.ast`"moo"`;
- const call = factory.createNewExpression(expr, [arg1, arg2]);
- expect(generate(call).code).toEqual('new Foo(42, "moo")');
- });
+ it('should create a `new` operation on the constructor `expression` with the given `args`', () => {
+ const expr = expression.ast`Foo`;
+ const arg1 = expression.ast`42`;
+ const arg2 = expression.ast`"moo"`;
+ const call = factory.createNewExpression(expr, [arg1, arg2]);
+ expect(generate(call).code).toEqual('new Foo(42, "moo")');
+ });
});
describe('createObjectLiteral()', () => {
@@ -297,12 +267,7 @@ describe('BabelAstFactory', () => {
{propertyName: 'prop1', value: prop1, quoted: false},
{propertyName: 'prop2', value: prop2, quoted: true},
]);
- expect(generate(obj).code).toEqual([
- '{',
- ' prop1: 42,',
- ' "prop2": "moo"',
- '}',
- ].join('\n'));
+ expect(generate(obj).code).toEqual(['{', ' prop1: 42,', ' "prop2": "moo"', '}'].join('\n'));
});
});
@@ -342,10 +307,7 @@ describe('BabelAstFactory', () => {
{raw: 'raw2', cooked: 'cooked2', range: null},
{raw: 'raw3', cooked: 'cooked3', range: null},
];
- const expressions = [
- expression.ast`42`,
- expression.ast`"moo"`,
- ];
+ const expressions = [expression.ast`42`, expression.ast`"moo"`];
const tag = expression.ast`tagFn`;
const template = factory.createTaggedTemplate(tag, {elements, expressions});
expect(generate(template).code).toEqual('tagFn`raw1${42}raw2${"moo"}raw3`');
@@ -377,32 +339,28 @@ describe('BabelAstFactory', () => {
});
describe('createVariableDeclaration()', () => {
- it('should create a variable declaration statement node for the given variable name and initializer',
- () => {
- const initializer = expression.ast`42`;
- const varDecl = factory.createVariableDeclaration('foo', initializer, 'let');
- expect(generate(varDecl).code).toEqual('let foo = 42;');
- });
-
- it('should create a constant declaration statement node for the given variable name and initializer',
- () => {
- const initializer = expression.ast`42`;
- const varDecl = factory.createVariableDeclaration('foo', initializer, 'const');
- expect(generate(varDecl).code).toEqual('const foo = 42;');
- });
-
- it('should create a downleveled variable declaration statement node for the given variable name and initializer',
- () => {
- const initializer = expression.ast`42`;
- const varDecl = factory.createVariableDeclaration('foo', initializer, 'var');
- expect(generate(varDecl).code).toEqual('var foo = 42;');
- });
-
- it('should create an uninitialized variable declaration statement node for the given variable name and a null initializer',
- () => {
- const varDecl = factory.createVariableDeclaration('foo', null, 'let');
- expect(generate(varDecl).code).toEqual('let foo;');
- });
+ it('should create a variable declaration statement node for the given variable name and initializer', () => {
+ const initializer = expression.ast`42`;
+ const varDecl = factory.createVariableDeclaration('foo', initializer, 'let');
+ expect(generate(varDecl).code).toEqual('let foo = 42;');
+ });
+
+ it('should create a constant declaration statement node for the given variable name and initializer', () => {
+ const initializer = expression.ast`42`;
+ const varDecl = factory.createVariableDeclaration('foo', initializer, 'const');
+ expect(generate(varDecl).code).toEqual('const foo = 42;');
+ });
+
+ it('should create a downleveled variable declaration statement node for the given variable name and initializer', () => {
+ const initializer = expression.ast`42`;
+ const varDecl = factory.createVariableDeclaration('foo', initializer, 'var');
+ expect(generate(varDecl).code).toEqual('var foo = 42;');
+ });
+
+ it('should create an uninitialized variable declaration statement node for the given variable name and a null initializer', () => {
+ const varDecl = factory.createVariableDeclaration('foo', null, 'let');
+ expect(generate(varDecl).code).toEqual('let foo;');
+ });
});
describe('setSourceMapRange()', () => {
@@ -416,7 +374,7 @@ describe('BabelAstFactory', () => {
start: {line: 0, column: 1, offset: 1},
end: {line: 2, column: 3, offset: 15},
content: '-****\n*****\n****',
- url: 'other.ts'
+ url: 'other.ts',
});
// Lines are 1-based in Babel.
@@ -424,7 +382,7 @@ describe('BabelAstFactory', () => {
filename: 'other.ts',
start: {line: 1, column: 1},
end: {line: 3, column: 3},
- } as any); // The typings for `loc` do not include `filename`.
+ } as any); // The typings for `loc` do not include `filename`.
expect(expr.start).toEqual(1);
expect(expr.end).toEqual(15);
});
@@ -435,7 +393,7 @@ describe('BabelAstFactory', () => {
start: {line: 0, column: 1, offset: 1},
end: {line: 2, column: 3, offset: 15},
content: '-****\n*****\n****',
- url: '/original.ts'
+ url: '/original.ts',
});
// Lines are 1-based in Babel.
@@ -443,7 +401,7 @@ describe('BabelAstFactory', () => {
filename: undefined,
start: {line: 1, column: 1},
end: {line: 3, column: 3},
- } as any); // The typings for `loc` do not include `filename`.
+ } as any); // The typings for `loc` do not include `filename`.
});
});
});
diff --git a/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts b/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts
index 81e84f81e3ad5..eac2587dea95e 100644
--- a/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts
+++ b/packages/compiler-cli/linker/babel/test/ast/babel_ast_host_spec.ts
@@ -11,7 +11,7 @@ import {BabelAstHost} from '../../src/ast/babel_ast_host';
describe('BabelAstHost', () => {
let host: BabelAstHost;
- beforeEach(() => host = new BabelAstHost());
+ beforeEach(() => (host = new BabelAstHost()));
describe('getSymbolName()', () => {
it('should return the name of an identifier', () => {
@@ -30,7 +30,7 @@ describe('BabelAstHost', () => {
describe('isStringLiteral()', () => {
it('should return true if the expression is a string literal', () => {
expect(host.isStringLiteral(expr('"moo"'))).toBe(true);
- expect(host.isStringLiteral(expr('\'moo\''))).toBe(true);
+ expect(host.isStringLiteral(expr("'moo'"))).toBe(true);
});
it('should return false if the expression is not a string literal', () => {
@@ -40,23 +40,24 @@ describe('BabelAstHost', () => {
expect(host.isStringLiteral(expr('{}'))).toBe(false);
expect(host.isStringLiteral(expr('[]'))).toBe(false);
expect(host.isStringLiteral(expr('null'))).toBe(false);
- expect(host.isStringLiteral(expr('\'a\' + \'b\''))).toBe(false);
+ expect(host.isStringLiteral(expr("'a' + 'b'"))).toBe(false);
});
it('should return false if the expression is a template string', () => {
- expect(host.isStringLiteral(expr('\`moo\`'))).toBe(false);
+ expect(host.isStringLiteral(expr('`moo`'))).toBe(false);
});
});
describe('parseStringLiteral()', () => {
it('should extract the string value', () => {
expect(host.parseStringLiteral(expr('"moo"'))).toEqual('moo');
- expect(host.parseStringLiteral(expr('\'moo\''))).toEqual('moo');
+ expect(host.parseStringLiteral(expr("'moo'"))).toEqual('moo');
});
it('should error if the value is not a string literal', () => {
- expect(() => host.parseStringLiteral(expr('42')))
- .toThrowError('Unsupported syntax, expected a string literal.');
+ expect(() => host.parseStringLiteral(expr('42'))).toThrowError(
+ 'Unsupported syntax, expected a string literal.',
+ );
});
});
@@ -68,13 +69,13 @@ describe('BabelAstHost', () => {
it('should return false if the expression is not a number literal', () => {
expect(host.isStringLiteral(expr('true'))).toBe(false);
expect(host.isNumericLiteral(expr('"moo"'))).toBe(false);
- expect(host.isNumericLiteral(expr('\'moo\''))).toBe(false);
+ expect(host.isNumericLiteral(expr("'moo'"))).toBe(false);
expect(host.isNumericLiteral(expr('someIdentifier'))).toBe(false);
expect(host.isNumericLiteral(expr('{}'))).toBe(false);
expect(host.isNumericLiteral(expr('[]'))).toBe(false);
expect(host.isNumericLiteral(expr('null'))).toBe(false);
- expect(host.isNumericLiteral(expr('\'a\' + \'b\''))).toBe(false);
- expect(host.isNumericLiteral(expr('\`moo\`'))).toBe(false);
+ expect(host.isNumericLiteral(expr("'a' + 'b'"))).toBe(false);
+ expect(host.isNumericLiteral(expr('`moo`'))).toBe(false);
});
});
@@ -84,8 +85,9 @@ describe('BabelAstHost', () => {
});
it('should error if the value is not a numeric literal', () => {
- expect(() => host.parseNumericLiteral(expr('"moo"')))
- .toThrowError('Unsupported syntax, expected a numeric literal.');
+ expect(() => host.parseNumericLiteral(expr('"moo"'))).toThrowError(
+ 'Unsupported syntax, expected a numeric literal.',
+ );
});
});
@@ -102,14 +104,14 @@ describe('BabelAstHost', () => {
it('should return false if the expression is not a boolean literal', () => {
expect(host.isBooleanLiteral(expr('"moo"'))).toBe(false);
- expect(host.isBooleanLiteral(expr('\'moo\''))).toBe(false);
+ expect(host.isBooleanLiteral(expr("'moo'"))).toBe(false);
expect(host.isBooleanLiteral(expr('someIdentifier'))).toBe(false);
expect(host.isBooleanLiteral(expr('42'))).toBe(false);
expect(host.isBooleanLiteral(expr('{}'))).toBe(false);
expect(host.isBooleanLiteral(expr('[]'))).toBe(false);
expect(host.isBooleanLiteral(expr('null'))).toBe(false);
- expect(host.isBooleanLiteral(expr('\'a\' + \'b\''))).toBe(false);
- expect(host.isBooleanLiteral(expr('\`moo\`'))).toBe(false);
+ expect(host.isBooleanLiteral(expr("'a' + 'b'"))).toBe(false);
+ expect(host.isBooleanLiteral(expr('`moo`'))).toBe(false);
expect(host.isBooleanLiteral(expr('!2'))).toBe(false);
expect(host.isBooleanLiteral(expr('~1'))).toBe(false);
});
@@ -127,8 +129,9 @@ describe('BabelAstHost', () => {
});
it('should error if the value is not a boolean literal', () => {
- expect(() => host.parseBooleanLiteral(expr('"moo"')))
- .toThrowError('Unsupported syntax, expected a boolean literal.');
+ expect(() => host.parseBooleanLiteral(expr('"moo"'))).toThrowError(
+ 'Unsupported syntax, expected a boolean literal.',
+ );
});
});
@@ -141,67 +144,71 @@ describe('BabelAstHost', () => {
it('should return false if the expression is not an array literal', () => {
expect(host.isArrayLiteral(expr('"moo"'))).toBe(false);
- expect(host.isArrayLiteral(expr('\'moo\''))).toBe(false);
+ expect(host.isArrayLiteral(expr("'moo'"))).toBe(false);
expect(host.isArrayLiteral(expr('someIdentifier'))).toBe(false);
expect(host.isArrayLiteral(expr('42'))).toBe(false);
expect(host.isArrayLiteral(expr('{}'))).toBe(false);
expect(host.isArrayLiteral(expr('null'))).toBe(false);
- expect(host.isArrayLiteral(expr('\'a\' + \'b\''))).toBe(false);
- expect(host.isArrayLiteral(expr('\`moo\`'))).toBe(false);
+ expect(host.isArrayLiteral(expr("'a' + 'b'"))).toBe(false);
+ expect(host.isArrayLiteral(expr('`moo`'))).toBe(false);
});
});
describe('parseArrayLiteral()', () => {
it('should extract the expressions in the array', () => {
- const moo = expr('\'moo\'');
+ const moo = expr("'moo'");
expect(host.parseArrayLiteral(expr('[]'))).toEqual([]);
- expect(host.parseArrayLiteral(expr('[\'moo\']'))).toEqual([moo]);
+ expect(host.parseArrayLiteral(expr("['moo']"))).toEqual([moo]);
});
it('should error if there is an empty item', () => {
- expect(() => host.parseArrayLiteral(expr('[,]')))
- .toThrowError('Unsupported syntax, expected element in array not to be empty.');
+ expect(() => host.parseArrayLiteral(expr('[,]'))).toThrowError(
+ 'Unsupported syntax, expected element in array not to be empty.',
+ );
});
it('should error if there is a spread element', () => {
- expect(() => host.parseArrayLiteral(expr('[...[0,1]]')))
- .toThrowError('Unsupported syntax, expected element in array not to use spread syntax.');
+ expect(() => host.parseArrayLiteral(expr('[...[0,1]]'))).toThrowError(
+ 'Unsupported syntax, expected element in array not to use spread syntax.',
+ );
});
});
describe('isObjectLiteral()', () => {
it('should return true if the expression is an object literal', () => {
expect(host.isObjectLiteral(rhs('x = {}'))).toBe(true);
- expect(host.isObjectLiteral(rhs('x = { foo: \'bar\' }'))).toBe(true);
+ expect(host.isObjectLiteral(rhs("x = { foo: 'bar' }"))).toBe(true);
});
it('should return false if the expression is not an object literal', () => {
expect(host.isObjectLiteral(rhs('x = "moo"'))).toBe(false);
- expect(host.isObjectLiteral(rhs('x = \'moo\''))).toBe(false);
+ expect(host.isObjectLiteral(rhs("x = 'moo'"))).toBe(false);
expect(host.isObjectLiteral(rhs('x = someIdentifier'))).toBe(false);
expect(host.isObjectLiteral(rhs('x = 42'))).toBe(false);
expect(host.isObjectLiteral(rhs('x = []'))).toBe(false);
expect(host.isObjectLiteral(rhs('x = null'))).toBe(false);
- expect(host.isObjectLiteral(rhs('x = \'a\' + \'b\''))).toBe(false);
- expect(host.isObjectLiteral(rhs('x = \`moo\`'))).toBe(false);
+ expect(host.isObjectLiteral(rhs("x = 'a' + 'b'"))).toBe(false);
+ expect(host.isObjectLiteral(rhs('x = `moo`'))).toBe(false);
});
});
describe('parseObjectLiteral()', () => {
it('should extract the properties from the object', () => {
- const moo = expr('\'moo\'');
+ const moo = expr("'moo'");
expect(host.parseObjectLiteral(rhs('x = {}'))).toEqual(new Map());
- expect(host.parseObjectLiteral(rhs('x = {a: \'moo\'}'))).toEqual(new Map([['a', moo]]));
+ expect(host.parseObjectLiteral(rhs("x = {a: 'moo'}"))).toEqual(new Map([['a', moo]]));
});
it('should error if there is a method', () => {
- expect(() => host.parseObjectLiteral(rhs('x = { foo() {} }')))
- .toThrowError('Unsupported syntax, expected a property assignment.');
+ expect(() => host.parseObjectLiteral(rhs('x = { foo() {} }'))).toThrowError(
+ 'Unsupported syntax, expected a property assignment.',
+ );
});
it('should error if there is a spread element', () => {
- expect(() => host.parseObjectLiteral(rhs('x = {...{a:\'moo\'}}')))
- .toThrowError('Unsupported syntax, expected a property assignment.');
+ expect(() => host.parseObjectLiteral(rhs("x = {...{a:'moo'}}"))).toThrowError(
+ 'Unsupported syntax, expected a property assignment.',
+ );
});
});
@@ -220,57 +227,61 @@ describe('BabelAstHost', () => {
it('should return false if the expression is not a function expression', () => {
expect(host.isFunctionExpression(expr('[]'))).toBe(false);
expect(host.isFunctionExpression(expr('"moo"'))).toBe(false);
- expect(host.isFunctionExpression(expr('\'moo\''))).toBe(false);
+ expect(host.isFunctionExpression(expr("'moo'"))).toBe(false);
expect(host.isFunctionExpression(expr('someIdentifier'))).toBe(false);
expect(host.isFunctionExpression(expr('42'))).toBe(false);
expect(host.isFunctionExpression(expr('{}'))).toBe(false);
expect(host.isFunctionExpression(expr('null'))).toBe(false);
- expect(host.isFunctionExpression(expr('\'a\' + \'b\''))).toBe(false);
- expect(host.isFunctionExpression(expr('\`moo\`'))).toBe(false);
+ expect(host.isFunctionExpression(expr("'a' + 'b'"))).toBe(false);
+ expect(host.isFunctionExpression(expr('`moo`'))).toBe(false);
});
});
describe('parseReturnValue()', () => {
it('should extract the return value of a function', () => {
- const moo = expr('\'moo\'');
- expect(host.parseReturnValue(rhs('x = function() { return \'moo\'; }'))).toEqual(moo);
+ const moo = expr("'moo'");
+ expect(host.parseReturnValue(rhs("x = function() { return 'moo'; }"))).toEqual(moo);
});
it('should extract the value of a simple arrow function', () => {
- const moo = expr('\'moo\'');
- expect(host.parseReturnValue(rhs('x = () => \'moo\''))).toEqual(moo);
+ const moo = expr("'moo'");
+ expect(host.parseReturnValue(rhs("x = () => 'moo'"))).toEqual(moo);
});
it('should extract the return value of an arrow function', () => {
- const moo = expr('\'moo\'');
- expect(host.parseReturnValue(rhs('x = () => { return \'moo\' }'))).toEqual(moo);
+ const moo = expr("'moo'");
+ expect(host.parseReturnValue(rhs("x = () => { return 'moo' }"))).toEqual(moo);
});
it('should error if the body has 0 statements', () => {
- expect(() => host.parseReturnValue(rhs('x = function () { }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
- expect(() => host.parseReturnValue(rhs('x = () => { }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
+ expect(() => host.parseReturnValue(rhs('x = function () { }'))).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
+ expect(() => host.parseReturnValue(rhs('x = () => { }'))).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
});
it('should error if the body has more than 1 statement', () => {
- expect(() => host.parseReturnValue(rhs('x = function () { const x = 10; return x; }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
- expect(() => host.parseReturnValue(rhs('x = () => { const x = 10; return x; }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
+ expect(() =>
+ host.parseReturnValue(rhs('x = function () { const x = 10; return x; }')),
+ ).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
+ expect(() =>
+ host.parseReturnValue(rhs('x = () => { const x = 10; return x; }')),
+ ).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
});
it('should error if the single statement is not a return statement', () => {
- expect(() => host.parseReturnValue(rhs('x = function () { const x = 10; }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
- expect(() => host.parseReturnValue(rhs('x = () => { const x = 10; }')))
- .toThrowError(
- 'Unsupported syntax, expected a function body with a single return statement.');
+ expect(() => host.parseReturnValue(rhs('x = function () { const x = 10; }'))).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
+ expect(() => host.parseReturnValue(rhs('x = () => { const x = 10; }'))).toThrowError(
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
});
});
@@ -281,13 +292,15 @@ describe('BabelAstHost', () => {
});
it('should error if the node is not a function declaration or arrow function', () => {
- expect(() => host.parseParameters(expr('[]')))
- .toThrowError('Unsupported syntax, expected a function.');
+ expect(() => host.parseParameters(expr('[]'))).toThrowError(
+ 'Unsupported syntax, expected a function.',
+ );
});
it('should error if a parameter uses spread syntax', () => {
- expect(() => host.parseParameters(rhs('x = function(a, ...other) {}')))
- .toThrowError('Unsupported syntax, expected an identifier.');
+ expect(() => host.parseParameters(rhs('x = function(a, ...other) {}'))).toThrowError(
+ 'Unsupported syntax, expected an identifier.',
+ );
});
});
@@ -301,13 +314,13 @@ describe('BabelAstHost', () => {
it('should return false if the expression is not a call expression', () => {
expect(host.isCallExpression(expr('[]'))).toBe(false);
expect(host.isCallExpression(expr('"moo"'))).toBe(false);
- expect(host.isCallExpression(expr('\'moo\''))).toBe(false);
+ expect(host.isCallExpression(expr("'moo'"))).toBe(false);
expect(host.isCallExpression(expr('someIdentifier'))).toBe(false);
expect(host.isCallExpression(expr('42'))).toBe(false);
expect(host.isCallExpression(expr('{}'))).toBe(false);
expect(host.isCallExpression(expr('null'))).toBe(false);
- expect(host.isCallExpression(expr('\'a\' + \'b\''))).toBe(false);
- expect(host.isCallExpression(expr('\`moo\`'))).toBe(false);
+ expect(host.isCallExpression(expr("'a' + 'b'"))).toBe(false);
+ expect(host.isCallExpression(expr('`moo`'))).toBe(false);
});
});
@@ -318,8 +331,9 @@ describe('BabelAstHost', () => {
});
it('should error if the node is not a call expression', () => {
- expect(() => host.parseCallee(expr('[]')))
- .toThrowError('Unsupported syntax, expected a call expression.');
+ expect(() => host.parseCallee(expr('[]'))).toThrowError(
+ 'Unsupported syntax, expected a call expression.',
+ );
});
});
@@ -330,30 +344,37 @@ describe('BabelAstHost', () => {
});
it('should error if the node is not a call expression', () => {
- expect(() => host.parseArguments(expr('[]')))
- .toThrowError('Unsupported syntax, expected a call expression.');
+ expect(() => host.parseArguments(expr('[]'))).toThrowError(
+ 'Unsupported syntax, expected a call expression.',
+ );
});
it('should error if an argument uses spread syntax', () => {
- expect(() => host.parseArguments(expr('foo(1, ...[])')))
- .toThrowError('Unsupported syntax, expected argument not to use spread syntax.');
+ expect(() => host.parseArguments(expr('foo(1, ...[])'))).toThrowError(
+ 'Unsupported syntax, expected argument not to use spread syntax.',
+ );
});
});
describe('getRange()', () => {
it('should extract the range from the expression', () => {
- const file = parse('// preamble\nx = \'moo\';');
+ const file = parse("// preamble\nx = 'moo';");
const stmt = file!.program.body[0] as t.Statement;
assertExpressionStatement(stmt);
assertAssignmentExpression(stmt.expression);
- expect(host.getRange(stmt.expression.right))
- .toEqual({startLine: 1, startCol: 4, startPos: 16, endPos: 21});
+ expect(host.getRange(stmt.expression.right)).toEqual({
+ startLine: 1,
+ startCol: 4,
+ startPos: 16,
+ endPos: 21,
+ });
});
it('should error if there is no range information', () => {
- const moo = rhs('// preamble\nx = \'moo\';');
- expect(() => host.getRange(moo))
- .toThrowError('Unable to read range for node - it is missing location information.');
+ const moo = rhs("// preamble\nx = 'moo';");
+ expect(() => host.getRange(moo)).toThrowError(
+ 'Unable to read range for node - it is missing location information.',
+ );
});
});
});
diff --git a/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts b/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts
index 2b30d53d874ac..535ba50213354 100644
--- a/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts
+++ b/packages/compiler-cli/linker/babel/test/babel_declaration_scope_spec.ts
@@ -14,13 +14,14 @@ describe('BabelDeclarationScope', () => {
describe('getConstantScopeRef()', () => {
it('should return a path to the ES module where the expression was imported', () => {
const ast = parse(
- [
- 'import * as core from \'@angular/core\';',
- 'function foo() {',
- ' var TEST = core;',
- '}',
- ].join('\n'),
- {sourceType: 'module'}) as t.File;
+ [
+ "import * as core from '@angular/core';",
+ 'function foo() {',
+ ' var TEST = core;',
+ '}',
+ ].join('\n'),
+ {sourceType: 'module'},
+ ) as t.File;
const nodePath = findVarDeclaration(ast, 'TEST');
const scope = new BabelDeclarationScope(nodePath.scope);
const constantScope = scope.getConstantScopeRef(nodePath.get('init').node);
@@ -30,13 +31,9 @@ describe('BabelDeclarationScope', () => {
it('should return a path to the ES Module where the expression is declared', () => {
const ast = parse(
- [
- 'var core;',
- 'export function foo() {',
- ' var TEST = core;',
- '}',
- ].join('\n'),
- {sourceType: 'module'}) as t.File;
+ ['var core;', 'export function foo() {', ' var TEST = core;', '}'].join('\n'),
+ {sourceType: 'module'},
+ ) as t.File;
const nodePath = findVarDeclaration(ast, 'TEST');
const scope = new BabelDeclarationScope(nodePath.scope);
const constantScope = scope.getConstantScopeRef(nodePath.get('init').node);
@@ -45,14 +42,9 @@ describe('BabelDeclarationScope', () => {
});
it('should return null if the file is not an ES module', () => {
- const ast = parse(
- [
- 'var core;',
- 'function foo() {',
- ' var TEST = core;',
- '}',
- ].join('\n'),
- {sourceType: 'script'}) as t.File;
+ const ast = parse(['var core;', 'function foo() {', ' var TEST = core;', '}'].join('\n'), {
+ sourceType: 'script',
+ }) as t.File;
const nodePath = findVarDeclaration(ast, 'TEST');
const scope = new BabelDeclarationScope(nodePath.scope);
const constantScope = scope.getConstantScopeRef(nodePath.get('init').node);
@@ -61,16 +53,17 @@ describe('BabelDeclarationScope', () => {
it('should return the IIFE factory function where the expression is a parameter', () => {
const ast = parse(
- [
- 'var core;',
- '(function(core) {',
- ' var BLOCK = \'block\';',
- ' function foo() {',
- ' var TEST = core;',
- ' }',
- '})(core);',
- ].join('\n'),
- {sourceType: 'script'}) as t.File;
+ [
+ 'var core;',
+ '(function(core) {',
+ " var BLOCK = 'block';",
+ ' function foo() {',
+ ' var TEST = core;',
+ ' }',
+ '})(core);',
+ ].join('\n'),
+ {sourceType: 'script'},
+ ) as t.File;
const nodePath = findVarDeclaration(ast, 'TEST');
const fnPath = findFirstFunction(ast);
const scope = new BabelDeclarationScope(nodePath.scope);
@@ -88,11 +81,13 @@ describe('BabelDeclarationScope', () => {
* Note: the `init` property is explicitly omitted to workaround a performance cliff in the
* TypeScript type checker.
*/
-type InitializedVariableDeclarator = Omit&{init: t.Expression};
+type InitializedVariableDeclarator = Omit & {init: t.Expression};
function findVarDeclaration(
- file: t.File, varName: string): NodePath {
- let varDecl: NodePath|undefined = undefined;
+ file: t.File,
+ varName: string,
+): NodePath {
+ let varDecl: NodePath | undefined = undefined;
traverse(file, {
VariableDeclarator: (path: NodePath) => {
const id = path.get('id');
@@ -100,7 +95,7 @@ function findVarDeclaration(
varDecl = path;
path.stop();
}
- }
+ },
});
if (varDecl === undefined) {
throw new Error(`TEST BUG: expected to find variable declaration for ${varName}.`);
@@ -109,12 +104,12 @@ function findVarDeclaration(
}
function findFirstFunction(file: t.File): NodePath {
- let fn: NodePath|undefined = undefined;
+ let fn: NodePath | undefined = undefined;
traverse(file, {
Function: (path) => {
fn = path;
path.stop();
- }
+ },
});
if (fn === undefined) {
throw new Error(`TEST BUG: expected to find a function.`);
diff --git a/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts b/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts
index 1c74ad1e518c4..9711e53c030cd 100644
--- a/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts
+++ b/packages/compiler-cli/linker/babel/test/babel_plugin_spec.ts
@@ -10,7 +10,7 @@ import babel from '@babel/core';
describe('default babel plugin entry-point', () => {
it('should work as a Babel plugin using the module specifier', async () => {
const result = (await babel.transformAsync(
- `
+ `
import * as i0 from "@angular/core";
export class MyMod {}
@@ -18,12 +18,11 @@ describe('default babel plugin entry-point', () => {
MyMod.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyMod, declarations: [MyComponent] });
`,
- {
- plugins: [
- '@angular/compiler-cli/linker/babel/index.mjs',
- ],
- filename: 'test.js',
- }))!;
+ {
+ plugins: ['@angular/compiler-cli/linker/babel/index.mjs'],
+ filename: 'test.js',
+ },
+ ))!;
expect(result).not.toBeNull();
expect(result.code).not.toContain('ɵɵngDeclareNgModule');
@@ -33,7 +32,7 @@ describe('default babel plugin entry-point', () => {
it('should be configurable', async () => {
const result = (await babel.transformAsync(
- `
+ `
import * as i0 from "@angular/core";
export class MyMod {}
@@ -41,12 +40,11 @@ describe('default babel plugin entry-point', () => {
MyMod.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyMod, declarations: [MyComponent] });
`,
- {
- plugins: [
- ['@angular/compiler-cli/linker/babel/index.mjs', {linkerJitMode: true}],
- ],
- filename: 'test.js',
- }))!;
+ {
+ plugins: [['@angular/compiler-cli/linker/babel/index.mjs', {linkerJitMode: true}]],
+ filename: 'test.js',
+ },
+ ))!;
expect(result).not.toBeNull();
expect(result.code).not.toContain('ɵɵngDeclareNgModule');
diff --git a/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts b/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts
index a2d803b852b96..e1734320ac1da 100644
--- a/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts
+++ b/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts
@@ -20,115 +20,119 @@ import {PartialDirectiveLinkerVersion1} from '../../src/file_linker/partial_link
import {createEs2015LinkerPlugin} from '../src/es2015_linker_plugin';
describe('createEs2015LinkerPlugin()', () => {
- it('should return a Babel plugin visitor that handles Program (enter/exit) and CallExpression nodes',
- () => {
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- expect(plugin.visitor).toEqual({
- Program: {
- enter: jasmine.any(Function),
- exit: jasmine.any(Function),
- },
- CallExpression: jasmine.any(Function),
- });
- });
+ it('should return a Babel plugin visitor that handles Program (enter/exit) and CallExpression nodes', () => {
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ expect(plugin.visitor).toEqual({
+ Program: {
+ enter: jasmine.any(Function),
+ exit: jasmine.any(Function),
+ },
+ CallExpression: jasmine.any(Function),
+ });
+ });
- it('should return a Babel plugin that calls FileLinker.isPartialDeclaration() on each call expression',
- () => {
- const isPartialDeclarationSpy = spyOn(FileLinker.prototype, 'isPartialDeclaration');
+ it('should return a Babel plugin that calls FileLinker.isPartialDeclaration() on each call expression', () => {
+ const isPartialDeclarationSpy = spyOn(FileLinker.prototype, 'isPartialDeclaration');
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- babel.transformSync(
- [
- 'var core;', `fn1()`, 'fn2({prop: () => fn3({})});', `x.method(() => fn4());`,
- 'spread(...x);'
- ].join('\n'),
- {
- plugins: [plugin],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- });
- expect(isPartialDeclarationSpy.calls.allArgs()).toEqual([
- ['fn1'],
- ['fn2'],
- ['fn3'],
- ['method'],
- ['fn4'],
- ['spread'],
- ]);
- });
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ babel.transformSync(
+ [
+ 'var core;',
+ `fn1()`,
+ 'fn2({prop: () => fn3({})});',
+ `x.method(() => fn4());`,
+ 'spread(...x);',
+ ].join('\n'),
+ {
+ plugins: [plugin],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ },
+ );
+ expect(isPartialDeclarationSpy.calls.allArgs()).toEqual([
+ ['fn1'],
+ ['fn2'],
+ ['fn3'],
+ ['method'],
+ ['fn4'],
+ ['spread'],
+ ]);
+ });
- it('should return a Babel plugin that calls FileLinker.linkPartialDeclaration() on each matching declaration',
- () => {
- const linkSpy = spyOn(FileLinker.prototype, 'linkPartialDeclaration')
- .and.returnValue(t.identifier('REPLACEMENT'));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ it('should return a Babel plugin that calls FileLinker.linkPartialDeclaration() on each matching declaration', () => {
+ const linkSpy = spyOn(FileLinker.prototype, 'linkPartialDeclaration').and.returnValue(
+ t.identifier('REPLACEMENT'),
+ );
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- babel.transformSync(
- [
- 'var core;',
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 1});`,
- `i0.ɵɵngDeclareComponent({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, foo: () => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 2})});`,
- `x.qux(() => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 3}));`,
- 'spread(...x);',
- `i0['ɵɵngDeclareDirective']({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 4});`,
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- });
+ babel.transformSync(
+ [
+ 'var core;',
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 1});`,
+ `i0.ɵɵngDeclareComponent({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, foo: () => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 2})});`,
+ `x.qux(() => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 3}));`,
+ 'spread(...x);',
+ `i0['ɵɵngDeclareDirective']({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 4});`,
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ },
+ );
- expect(humanizeLinkerCalls(linkSpy.calls)).toEqual([
- [
- 'ɵɵngDeclareDirective',
- '{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:1}'
- ],
- [
- 'ɵɵngDeclareComponent',
- '{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,foo:()=>ɵɵngDeclareDirective({minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:2})}'
- ],
- // Note we do not process `x:2` declaration since it is nested within another declaration
- [
- 'ɵɵngDeclareDirective',
- '{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:3}'
- ],
- [
- 'ɵɵngDeclareDirective',
- '{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:4}'
- ],
- ]);
- });
+ expect(humanizeLinkerCalls(linkSpy.calls)).toEqual([
+ [
+ 'ɵɵngDeclareDirective',
+ "{minVersion:'0.0.0-PLACEHOLDER',version:'0.0.0-PLACEHOLDER',ngImport:core,x:1}",
+ ],
+ [
+ 'ɵɵngDeclareComponent',
+ "{minVersion:'0.0.0-PLACEHOLDER',version:'0.0.0-PLACEHOLDER',ngImport:core,foo:()=>ɵɵngDeclareDirective({minVersion:'0.0.0-PLACEHOLDER',version:'0.0.0-PLACEHOLDER',ngImport:core,x:2})}",
+ ],
+ // Note we do not process `x:2` declaration since it is nested within another declaration
+ [
+ 'ɵɵngDeclareDirective',
+ "{minVersion:'0.0.0-PLACEHOLDER',version:'0.0.0-PLACEHOLDER',ngImport:core,x:3}",
+ ],
+ [
+ 'ɵɵngDeclareDirective',
+ "{minVersion:'0.0.0-PLACEHOLDER',version:'0.0.0-PLACEHOLDER',ngImport:core,x:4}",
+ ],
+ ]);
+ });
- it('should return a Babel plugin that replaces call expressions with the return value from FileLinker.linkPartialDeclaration()',
- () => {
- let replaceCount = 0;
- spyOn(FileLinker.prototype, 'linkPartialDeclaration')
- .and.callFake(() => t.identifier('REPLACEMENT_' + ++replaceCount));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- const result = babel.transformSync(
- [
- 'var core;',
- 'ɵɵngDeclareDirective({version: \'0.0.0-PLACEHOLDER\', ngImport: core});',
- 'ɵɵngDeclareDirective({version: \'0.0.0-PLACEHOLDER\', ngImport: core, foo: () => bar({})});',
- 'x.qux();',
- 'spread(...x);',
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- generatorOpts: {compact: true},
- });
- expect(result!.code).toEqual('var core;REPLACEMENT_1;REPLACEMENT_2;x.qux();spread(...x);');
- });
+ it('should return a Babel plugin that replaces call expressions with the return value from FileLinker.linkPartialDeclaration()', () => {
+ let replaceCount = 0;
+ spyOn(FileLinker.prototype, 'linkPartialDeclaration').and.callFake(() =>
+ t.identifier('REPLACEMENT_' + ++replaceCount),
+ );
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ const result = babel.transformSync(
+ [
+ 'var core;',
+ "ɵɵngDeclareDirective({version: '0.0.0-PLACEHOLDER', ngImport: core});",
+ "ɵɵngDeclareDirective({version: '0.0.0-PLACEHOLDER', ngImport: core, foo: () => bar({})});",
+ 'x.qux();',
+ 'spread(...x);',
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual('var core;REPLACEMENT_1;REPLACEMENT_2;x.qux();spread(...x);');
+ });
it('should return a Babel plugin that adds shared statements after any imports', () => {
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
@@ -136,165 +140,180 @@ describe('createEs2015LinkerPlugin()', () => {
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = babel.transformSync(
- [
- 'import * as core from \'some-module\';',
- 'import {id} from \'other-module\';',
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- generatorOpts: {compact: true},
- });
- expect(result!.code)
- .toEqual(
- 'import*as core from\'some-module\';import{id}from\'other-module\';const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";');
+ [
+ "import * as core from 'some-module';",
+ "import {id} from 'other-module';",
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ 'import*as core from\'some-module\';import{id}from\'other-module\';const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";',
+ );
});
- it('should return a Babel plugin that adds shared statements at the start of the program if it is an ECMAScript Module and there are no imports',
- () => {
- spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- const result = babel.transformSync(
- [
- 'var core;',
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- // We declare the file as a module because this cannot be inferred from the source
- parserOpts: {sourceType: 'module'},
- generatorOpts: {compact: true},
- });
- expect(result!.code)
- .toEqual(
- 'const _c0=[1];const _c1=[2];const _c2=[3];var core;"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";');
- });
+ it('should return a Babel plugin that adds shared statements at the start of the program if it is an ECMAScript Module and there are no imports', () => {
+ spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ const result = babel.transformSync(
+ [
+ 'var core;',
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ // We declare the file as a module because this cannot be inferred from the source
+ parserOpts: {sourceType: 'module'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ 'const _c0=[1];const _c1=[2];const _c2=[3];var core;"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";',
+ );
+ });
- it('should return a Babel plugin that adds shared statements at the start of the function body if the ngImport is from a function parameter',
- () => {
- spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- const result = babel.transformSync(
- [
- 'function run(core) {',
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- '}'
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- generatorOpts: {compact: true},
- });
- expect(result!.code)
- .toEqual(
- 'function run(core){const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";}');
- });
+ it('should return a Babel plugin that adds shared statements at the start of the function body if the ngImport is from a function parameter', () => {
+ spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ const result = babel.transformSync(
+ [
+ 'function run(core) {',
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ '}',
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ 'function run(core){const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";}',
+ );
+ });
- it('should return a Babel plugin that adds shared statements into an IIFE if no scope could not be derived for the ngImport',
- () => {
- spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- const result = babel.transformSync(
- [
- 'function run() {',
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- '}',
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- generatorOpts: {compact: true},
- });
- expect(result!.code).toEqual([
- `function run(){`,
- `(function(){const _c0=[1];return"REPLACEMENT";})();`,
- `(function(){const _c0=[2];return"REPLACEMENT";})();`,
- `(function(){const _c0=[3];return"REPLACEMENT";})();`,
- `}`,
- ].join(''));
- });
+ it('should return a Babel plugin that adds shared statements into an IIFE if no scope could not be derived for the ngImport', () => {
+ spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ const result = babel.transformSync(
+ [
+ 'function run() {',
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ '}',
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ [
+ `function run(){`,
+ `(function(){const _c0=[1];return"REPLACEMENT";})();`,
+ `(function(){const _c0=[2];return"REPLACEMENT";})();`,
+ `(function(){const _c0=[3];return"REPLACEMENT";})();`,
+ `}`,
+ ].join(''),
+ );
+ });
- it('should still execute other plugins that match AST nodes inside the result of the replacement',
- () => {
- spyOnLinkPartialDeclarationWithConstants(o.fn([], [], null, null, 'FOO'));
- const fileSystem = new MockFileSystemNative();
- const logger = new MockLogger();
- const plugin = createEs2015LinkerPlugin({fileSystem, logger});
- const result = babel.transformSync(
- [
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core}); FOO;`,
- ].join('\n'),
- {
- plugins: [
- createEs2015LinkerPlugin({fileSystem, logger}),
- createIdentifierMapperPlugin('FOO', 'BAR'),
- createIdentifierMapperPlugin('_c0', 'x1'),
- ],
- filename: '/test.js',
- parserOpts: {sourceType: 'module'},
- generatorOpts: {compact: true},
- });
- expect(result!.code).toEqual([
- `(function(){const x1=[1];return function BAR(){};})();BAR;`,
- ].join(''));
- });
+ it('should still execute other plugins that match AST nodes inside the result of the replacement', () => {
+ spyOnLinkPartialDeclarationWithConstants(o.fn([], [], null, null, 'FOO'));
+ const fileSystem = new MockFileSystemNative();
+ const logger = new MockLogger();
+ const plugin = createEs2015LinkerPlugin({fileSystem, logger});
+ const result = babel.transformSync(
+ [
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core}); FOO;`,
+ ].join('\n'),
+ {
+ plugins: [
+ createEs2015LinkerPlugin({fileSystem, logger}),
+ createIdentifierMapperPlugin('FOO', 'BAR'),
+ createIdentifierMapperPlugin('_c0', 'x1'),
+ ],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'module'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ [`(function(){const x1=[1];return function BAR(){};})();BAR;`].join(''),
+ );
+ });
it('should not process call expressions within inserted functions', () => {
- spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration')
- .and.callFake((constantPool => {
- // Insert a call expression into the constant pool. This is inserted into
- // Babel's AST upon program exit, and will therefore be visited by Babel
- // outside of an active linker context.
- constantPool.statements.push(
- o.fn(/* params */[], /* body */[], /* type */ undefined,
- /* sourceSpan */ undefined, /* name */ 'inserted')
- .callFn([])
- .toStmt());
+ spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration').and.callFake(((
+ constantPool,
+ ) => {
+ // Insert a call expression into the constant pool. This is inserted into
+ // Babel's AST upon program exit, and will therefore be visited by Babel
+ // outside of an active linker context.
+ constantPool.statements.push(
+ o
+ .fn(
+ /* params */ [],
+ /* body */ [],
+ /* type */ undefined,
+ /* sourceSpan */ undefined,
+ /* name */ 'inserted',
+ )
+ .callFn([])
+ .toStmt(),
+ );
- return {
- expression: o.literal('REPLACEMENT'),
- statements: [],
- };
- }) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration);
+ return {
+ expression: o.literal('REPLACEMENT'),
+ statements: [],
+ };
+ }) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration);
- const isPartialDeclarationSpy =
- spyOn(FileLinker.prototype, 'isPartialDeclaration').and.callThrough();
+ const isPartialDeclarationSpy = spyOn(
+ FileLinker.prototype,
+ 'isPartialDeclaration',
+ ).and.callThrough();
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = babel.transformSync(
- [
- 'import * as core from \'some-module\';',
- `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
- ].join('\n'),
- {
- plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
- filename: '/test.js',
- parserOpts: {sourceType: 'unambiguous'},
- generatorOpts: {compact: true},
- });
- expect(result!.code)
- .toEqual('import*as core from\'some-module\';(function inserted(){})();"REPLACEMENT";');
+ [
+ "import * as core from 'some-module';",
+ `ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
+ ].join('\n'),
+ {
+ plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
+ filename: '/test.js',
+ parserOpts: {sourceType: 'unambiguous'},
+ generatorOpts: {compact: true},
+ },
+ );
+ expect(result!.code).toEqual(
+ 'import*as core from\'some-module\';(function inserted(){})();"REPLACEMENT";',
+ );
expect(isPartialDeclarationSpy.calls.allArgs()).toEqual([['ɵɵngDeclareDirective']]);
});
@@ -304,7 +323,8 @@ describe('createEs2015LinkerPlugin()', () => {
* Convert the arguments of the spied-on `calls` into a human readable array.
*/
function humanizeLinkerCalls(
- calls: jasmine.Calls) {
+ calls: jasmine.Calls,
+) {
return calls.all().map(({args: [fn, args]}) => [fn, generate(args[0], {compact: true}).code]);
}
@@ -314,17 +334,18 @@ function humanizeLinkerCalls(
*/
function spyOnLinkPartialDeclarationWithConstants(replacement: o.Expression) {
let callCount = 0;
- spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration')
- .and.callFake((constantPool => {
- const constArray = o.literalArr([o.literal(++callCount)]);
- // We have to add the constant twice or it will not create a shared statement
- constantPool.getConstLiteral(constArray);
- constantPool.getConstLiteral(constArray);
- return {
- expression: replacement,
- statements: [],
- };
- }) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration);
+ spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration').and.callFake(((
+ constantPool,
+ ) => {
+ const constArray = o.literalArr([o.literal(++callCount)]);
+ // We have to add the constant twice or it will not create a shared statement
+ constantPool.getConstLiteral(constArray);
+ constantPool.getConstLiteral(constArray);
+ return {
+ expression: replacement,
+ statements: [],
+ };
+ }) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration);
}
/**
@@ -338,7 +359,7 @@ function createIdentifierMapperPlugin(src: string, dest: string): PluginObj {
if (path.node.name === src) {
path.replaceWith(t.identifier(dest));
}
- }
+ },
},
};
}
diff --git a/packages/compiler-cli/linker/src/ast/ast_host.ts b/packages/compiler-cli/linker/src/ast/ast_host.ts
index 1a7cdde4f4402..31fc7f3316317 100644
--- a/packages/compiler-cli/linker/src/ast/ast_host.ts
+++ b/packages/compiler-cli/linker/src/ast/ast_host.ts
@@ -15,7 +15,7 @@ export interface AstHost {
* Get the name of the symbol represented by the given expression node, or `null` if it is not a
* symbol.
*/
- getSymbolName(node: TExpression): string|null;
+ getSymbolName(node: TExpression): string | null;
/**
* Return `true` if the given expression is a string literal, or false otherwise.
diff --git a/packages/compiler-cli/linker/src/ast/ast_value.ts b/packages/compiler-cli/linker/src/ast/ast_value.ts
index 81cd052af8e47..77adf75d53444 100644
--- a/packages/compiler-cli/linker/src/ast/ast_value.ts
+++ b/packages/compiler-cli/linker/src/ast/ast_value.ts
@@ -17,17 +17,17 @@ import {AstHost, Range} from './ast_host';
* Note: Excluding `Array` types as we consider object literals are "objects"
* in the AST.
*/
-type ObjectType = T extends Array? never : T extends Record? T : never;
+type ObjectType = T extends Array ? never : T extends Record ? T : never;
/**
* Represents the value type of an object literal.
*/
-type ObjectValueType = T extends Record? R : never;
+type ObjectValueType = T extends Record ? R : never;
/**
* Represents the value type of an array literal.
*/
-type ArrayValueType = T extends Array? R : never;
+type ArrayValueType = T extends Array ? R : never;
/**
* Ensures that `This` has its generic type `Actual` conform to the expected generic type in
@@ -38,7 +38,7 @@ type ConformsTo = Actual extends Expected ? This : never
/**
* Represents only the string keys of type `T`.
*/
-type PropertyKey = keyof T&string;
+type PropertyKey = keyof T & string;
/**
* This helper class wraps an object expression along with an `AstHost` object, exposing helper
@@ -57,15 +57,19 @@ export class AstObject {
/**
* Create a new `AstObject` from the given `expression` and `host`.
*/
- static parse(expression: TExpression, host: AstHost):
- AstObject {
+ static parse(
+ expression: TExpression,
+ host: AstHost,
+ ): AstObject {
const obj = host.parseObjectLiteral(expression);
return new AstObject(expression, obj, host);
}
private constructor(
- readonly expression: TExpression, private obj: Map,
- private host: AstHost) {}
+ readonly expression: TExpression,
+ private obj: Map,
+ private host: AstHost,
+ ) {}
/**
* Returns true if the object has a property called `propertyName`.
@@ -79,8 +83,10 @@ export class AstObject {
*
* Throws an error if there is no such property or the property is not a number.
*/
- getNumber>(this: ConformsTo, propertyName: K):
- number {
+ getNumber>(
+ this: ConformsTo,
+ propertyName: K,
+ ): number {
return this.host.parseNumericLiteral(this.getRequiredProperty(propertyName));
}
@@ -89,8 +95,10 @@ export class AstObject {
*
* Throws an error if there is no such property or the property is not a string.
*/
- getString>(this: ConformsTo, propertyName: K):
- string {
+ getString>(
+ this: ConformsTo,
+ propertyName: K,
+ ): string {
return this.host.parseStringLiteral(this.getRequiredProperty(propertyName));
}
@@ -99,8 +107,10 @@ export class AstObject {
*
* Throws an error if there is no such property or the property is not a boolean.
*/
- getBoolean>(this: ConformsTo, propertyName: K):
- boolean {
+ getBoolean>(
+ this: ConformsTo,
+ propertyName: K,
+ ): boolean {
return this.host.parseBooleanLiteral(this.getRequiredProperty(propertyName)) as any;
}
@@ -109,8 +119,10 @@ export class AstObject {
*
* Throws an error if there is no such property or the property is not an object.
*/
- getObject>(this: ConformsTo, propertyName: K):
- AstObject, TExpression> {
+ getObject>(
+ this: ConformsTo,
+ propertyName: K,
+ ): AstObject, TExpression> {
const expr = this.getRequiredProperty(propertyName);
const obj = this.host.parseObjectLiteral(expr);
return new AstObject, TExpression>(expr, obj, this.host);
@@ -121,10 +133,12 @@ export class AstObject {
*
* Throws an error if there is no such property or the property is not an array.
*/
- getArray>(this: ConformsTo, propertyName: K):
- AstValue, TExpression>[] {
+ getArray>(
+ this: ConformsTo,
+ propertyName: K,
+ ): AstValue, TExpression>[] {
const arr = this.host.parseArrayLiteral(this.getRequiredProperty(propertyName));
- return arr.map(entry => new AstValue, TExpression>(entry, this.host));
+ return arr.map((entry) => new AstValue, TExpression>(entry, this.host));
}
/**
@@ -159,12 +173,15 @@ export class AstObject {
* Converts the AstObject to a raw JavaScript object, mapping each property value (as an
* `AstValue`) to the generic type (`T`) via the `mapper` function.
*/
- toLiteral(mapper: (value: AstValue, TExpression>, key: string) => V):
- Record {
+ toLiteral(
+ mapper: (value: AstValue, TExpression>, key: string) => V,
+ ): Record {
const result: Record = {};
for (const [key, expression] of this.obj) {
- result[key] =
- mapper(new AstValue, TExpression>(expression, this.host), key);
+ result[key] = mapper(
+ new AstValue, TExpression>(expression, this.host),
+ key,
+ );
}
return result;
}
@@ -184,7 +201,9 @@ export class AstObject {
private getRequiredProperty(propertyName: PropertyKey): TExpression {
if (!this.obj.has(propertyName)) {
throw new FatalLinkerError(
- this.expression, `Expected property '${propertyName}' to be present.`);
+ this.expression,
+ `Expected property '${propertyName}' to be present.`,
+ );
}
return this.obj.get(propertyName)!;
}
@@ -202,13 +221,16 @@ export class AstValue {
/** Type brand that ensures that the `T` type is respected for assignability. */
ɵtypeBrand: T = null!;
- constructor(readonly expression: TExpression, private host: AstHost) {}
+ constructor(
+ readonly expression: TExpression,
+ private host: AstHost,
+ ) {}
/**
* Get the name of the symbol represented by the given expression node, or `null` if it is not a
* symbol.
*/
- getSymbolName(): string|null {
+ getSymbolName(): string | null {
return this.host.getSymbolName(this.expression);
}
@@ -285,7 +307,7 @@ export class AstValue {
*/
getArray(this: ConformsTo): AstValue, TExpression>[] {
const arr = this.host.parseArrayLiteral(this.expression);
- return arr.map(entry => new AstValue, TExpression>(entry, this.host));
+ return arr.map((entry) => new AstValue, TExpression>(entry, this.host));
}
/**
@@ -308,7 +330,9 @@ export class AstValue {
* function expression.
*/
getFunctionParameters(this: ConformsTo): AstValue[] {
- return this.host.parseParameters(this.expression).map(param => new AstValue(param, this.host));
+ return this.host
+ .parseParameters(this.expression)
+ .map((param) => new AstValue(param, this.host));
}
isCallExpression(): boolean {
@@ -321,7 +345,7 @@ export class AstValue {
getArguments(): AstValue[] {
const args = this.host.parseArguments(this.expression);
- return args.map(arg => new AstValue(arg, this.host));
+ return args.map((arg) => new AstValue(arg, this.host));
}
/**
diff --git a/packages/compiler-cli/linker/src/ast/typescript/typescript_ast_host.ts b/packages/compiler-cli/linker/src/ast/typescript/typescript_ast_host.ts
index f08fcb1549726..8a118a4238c5c 100644
--- a/packages/compiler-cli/linker/src/ast/typescript/typescript_ast_host.ts
+++ b/packages/compiler-cli/linker/src/ast/typescript/typescript_ast_host.ts
@@ -12,7 +12,6 @@ import {FatalLinkerError} from '../../fatal_linker_error';
import {AstHost, Range} from '../ast_host';
import {assert} from '../utils';
-
/**
* This implementation of `AstHost` is able to get information from TypeScript AST nodes.
*
@@ -23,7 +22,7 @@ import {assert} from '../utils';
* do linking in the future.
*/
export class TypeScriptAstHost implements AstHost {
- getSymbolName(node: ts.Expression): string|null {
+ getSymbolName(node: ts.Expression): string | null {
if (ts.isIdentifier(node)) {
return node.text;
} else if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name)) {
@@ -59,7 +58,7 @@ export class TypeScriptAstHost implements AstHost {
if (isBooleanLiteral(bool)) {
return bool.kind === ts.SyntaxKind.TrueKeyword;
} else if (isMinifiedBooleanLiteral(bool)) {
- return !(+bool.operand.text);
+ return !+bool.operand.text;
} else {
throw new FatalLinkerError(bool, 'Unsupported syntax, expected a boolean literal.');
}
@@ -69,7 +68,7 @@ export class TypeScriptAstHost implements AstHost {
parseArrayLiteral(array: ts.Expression): ts.Expression[] {
assert(array, this.isArrayLiteral, 'an array literal');
- return array.elements.map(element => {
+ return array.elements.map((element) => {
assert(element, isNotEmptyElement, 'element in array not to be empty');
assert(element, isNotSpreadElement, 'element in array not to use spread syntax');
return element;
@@ -90,7 +89,7 @@ export class TypeScriptAstHost implements AstHost {
return result;
}
- isFunctionExpression(node: ts.Expression): node is ts.FunctionExpression|ts.ArrowFunction {
+ isFunctionExpression(node: ts.Expression): node is ts.FunctionExpression | ts.ArrowFunction {
return ts.isFunctionExpression(node) || ts.isArrowFunction(node);
}
@@ -107,7 +106,9 @@ export class TypeScriptAstHost implements AstHost {
if (fn.body.statements.length !== 1) {
throw new FatalLinkerError(
- fn.body, 'Unsupported syntax, expected a function body with a single return statement.');
+ fn.body,
+ 'Unsupported syntax, expected a function body with a single return statement.',
+ );
}
const stmt = fn.body.statements[0];
assert(stmt, ts.isReturnStatement, 'a function body with a single return statement');
@@ -120,7 +121,7 @@ export class TypeScriptAstHost implements AstHost {
parseParameters(fn: ts.Expression): ts.Expression[] {
assert(fn, this.isFunctionExpression, 'a function');
- return fn.parameters.map(param => {
+ return fn.parameters.map((param) => {
assert(param.name, ts.isIdentifier, 'an identifier');
if (param.dotDotDotToken) {
throw new FatalLinkerError(fn.body, 'Unsupported syntax, expected an identifier.');
@@ -138,7 +139,7 @@ export class TypeScriptAstHost implements AstHost {
parseArguments(call: ts.Expression): ts.Expression[] {
assert(call, ts.isCallExpression, 'a call expression');
- return call.arguments.map(arg => {
+ return call.arguments.map((arg) => {
assert(arg, isNotSpreadElement, 'argument not to use spread syntax');
return arg;
});
@@ -148,7 +149,9 @@ export class TypeScriptAstHost implements AstHost {
const file = node.getSourceFile();
if (file === undefined) {
throw new FatalLinkerError(
- node, 'Unable to read range for node - it is missing parent information.');
+ node,
+ 'Unable to read range for node - it is missing parent information.',
+ );
}
const startPos = node.getStart();
const endPos = node.getEnd();
@@ -161,8 +164,9 @@ export class TypeScriptAstHost implements AstHost {
* Return true if the expression does not represent an empty element in an array literal.
* For example in `[,foo]` the first element is "empty".
*/
-function isNotEmptyElement(e: ts.Expression|ts.SpreadElement|
- ts.OmittedExpression): e is ts.Expression|ts.SpreadElement {
+function isNotEmptyElement(
+ e: ts.Expression | ts.SpreadElement | ts.OmittedExpression,
+): e is ts.Expression | ts.SpreadElement {
return !ts.isOmittedExpression(e);
}
@@ -170,30 +174,36 @@ function isNotEmptyElement(e: ts.Expression|ts.SpreadElement|
* Return true if the expression is not a spread element of an array literal.
* For example in `[x, ...rest]` the `...rest` expression is a spread element.
*/
-function isNotSpreadElement(e: ts.Expression|ts.SpreadElement): e is ts.Expression {
+function isNotSpreadElement(e: ts.Expression | ts.SpreadElement): e is ts.Expression {
return !ts.isSpreadElement(e);
}
/**
* Return true if the expression can be considered a text based property name.
*/
-function isPropertyName(e: ts.PropertyName): e is ts.Identifier|ts.StringLiteral|ts.NumericLiteral {
+function isPropertyName(
+ e: ts.PropertyName,
+): e is ts.Identifier | ts.StringLiteral | ts.NumericLiteral {
return ts.isIdentifier(e) || ts.isStringLiteral(e) || ts.isNumericLiteral(e);
}
/**
* Return true if the node is either `true` or `false` literals.
*/
-function isBooleanLiteral(node: ts.Expression): node is ts.TrueLiteral|ts.FalseLiteral {
+function isBooleanLiteral(node: ts.Expression): node is ts.TrueLiteral | ts.FalseLiteral {
return node.kind === ts.SyntaxKind.TrueKeyword || node.kind === ts.SyntaxKind.FalseKeyword;
}
-type MinifiedBooleanLiteral = ts.PrefixUnaryExpression&{operand: ts.NumericLiteral};
+type MinifiedBooleanLiteral = ts.PrefixUnaryExpression & {operand: ts.NumericLiteral};
/**
* Return true if the node is either `!0` or `!1`.
*/
function isMinifiedBooleanLiteral(node: ts.Expression): node is MinifiedBooleanLiteral {
- return ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken &&
- ts.isNumericLiteral(node.operand) && (node.operand.text === '0' || node.operand.text === '1');
+ return (
+ ts.isPrefixUnaryExpression(node) &&
+ node.operator === ts.SyntaxKind.ExclamationToken &&
+ ts.isNumericLiteral(node.operand) &&
+ (node.operand.text === '0' || node.operand.text === '1')
+ );
}
diff --git a/packages/compiler-cli/linker/src/ast/utils.ts b/packages/compiler-cli/linker/src/ast/utils.ts
index 2aa9437361f5c..2803ebfd44bf0 100644
--- a/packages/compiler-cli/linker/src/ast/utils.ts
+++ b/packages/compiler-cli/linker/src/ast/utils.ts
@@ -11,7 +11,10 @@ import {FatalLinkerError} from '../fatal_linker_error';
* Assert that the given `node` is of the type guarded by the `predicate` function.
*/
export function assert(
- node: T, predicate: (node: T) => node is K, expected: string): asserts node is K {
+ node: T,
+ predicate: (node: T) => node is K,
+ expected: string,
+): asserts node is K {
if (!predicate(node)) {
throw new FatalLinkerError(node, `Unsupported syntax, expected ${expected}.`);
}
diff --git a/packages/compiler-cli/linker/src/fatal_linker_error.ts b/packages/compiler-cli/linker/src/fatal_linker_error.ts
index 49bf52f3f3576..aa23ead610a07 100644
--- a/packages/compiler-cli/linker/src/fatal_linker_error.ts
+++ b/packages/compiler-cli/linker/src/fatal_linker_error.ts
@@ -18,7 +18,10 @@ export class FatalLinkerError extends Error {
* @param node The AST node where the error occurred.
* @param message A description of the error.
*/
- constructor(public node: unknown, message: string) {
+ constructor(
+ public node: unknown,
+ message: string,
+ ) {
super(message);
}
}
diff --git a/packages/compiler-cli/linker/src/file_linker/declaration_scope.ts b/packages/compiler-cli/linker/src/file_linker/declaration_scope.ts
index 320a269a26c23..269f44df33218 100644
--- a/packages/compiler-cli/linker/src/file_linker/declaration_scope.ts
+++ b/packages/compiler-cli/linker/src/file_linker/declaration_scope.ts
@@ -41,5 +41,5 @@ export interface DeclarationScope {
* @returns a reference to a reference object for where the shared constant statements will be
* inserted, or `null` if it is not possible to have a shared scope.
*/
- getConstantScopeRef(expression: TExpression): TSharedConstantScope|null;
+ getConstantScopeRef(expression: TExpression): TSharedConstantScope | null;
}
diff --git a/packages/compiler-cli/linker/src/file_linker/emit_scopes/emit_scope.ts b/packages/compiler-cli/linker/src/file_linker/emit_scopes/emit_scope.ts
index dd22af73defed..073e4b308ac6c 100644
--- a/packages/compiler-cli/linker/src/file_linker/emit_scopes/emit_scope.ts
+++ b/packages/compiler-cli/linker/src/file_linker/emit_scopes/emit_scope.ts
@@ -25,9 +25,10 @@ export class EmitScope {
readonly constantPool = new ConstantPool();
constructor(
- protected readonly ngImport: TExpression,
- protected readonly translator: Translator,
- private readonly factory: AstFactory) {}
+ protected readonly ngImport: TExpression,
+ protected readonly translator: Translator,
+ private readonly factory: AstFactory,
+ ) {}
/**
* Translate the given Output AST definition expression into a generic `TExpression`.
@@ -36,7 +37,9 @@ export class EmitScope {
*/
translateDefinition(definition: LinkedDefinition): TExpression {
const expression = this.translator.translateExpression(
- definition.expression, new LinkerImportGenerator(this.factory, this.ngImport));
+ definition.expression,
+ new LinkerImportGenerator(this.factory, this.ngImport),
+ );
if (definition.statements.length > 0) {
// Definition statements must be emitted "after" the declaration for which the definition is
@@ -46,9 +49,11 @@ export class EmitScope {
// definition expression.
const importGenerator = new LinkerImportGenerator(this.factory, this.ngImport);
return this.wrapInIifeWithStatements(
- expression,
- definition.statements.map(
- statement => this.translator.translateStatement(statement, importGenerator)));
+ expression,
+ definition.statements.map((statement) =>
+ this.translator.translateStatement(statement, importGenerator),
+ ),
+ );
} else {
// Since there are no definition statements, just return the definition expression directly.
return expression;
@@ -60,14 +65,15 @@ export class EmitScope {
*/
getConstantStatements(): TStatement[] {
const importGenerator = new LinkerImportGenerator(this.factory, this.ngImport);
- return this.constantPool.statements.map(
- statement => this.translator.translateStatement(statement, importGenerator));
+ return this.constantPool.statements.map((statement) =>
+ this.translator.translateStatement(statement, importGenerator),
+ );
}
private wrapInIifeWithStatements(expression: TExpression, statements: TStatement[]): TExpression {
const returnStatement = this.factory.createReturnStatement(expression);
const body = this.factory.createBlock([...statements, returnStatement]);
- const fn = this.factory.createFunctionExpression(/* name */ null, /* args */[], body);
- return this.factory.createCallExpression(fn, /* args */[], /* pure */ false);
+ const fn = this.factory.createFunctionExpression(/* name */ null, /* args */ [], body);
+ return this.factory.createCallExpression(fn, /* args */ [], /* pure */ false);
}
}
diff --git a/packages/compiler-cli/linker/src/file_linker/file_linker.ts b/packages/compiler-cli/linker/src/file_linker/file_linker.ts
index 14c55d41e9371..0240c16bd7bc2 100644
--- a/packages/compiler-cli/linker/src/file_linker/file_linker.ts
+++ b/packages/compiler-cli/linker/src/file_linker/file_linker.ts
@@ -26,11 +26,15 @@ export class FileLinker {
private emitScopes = new Map>();
constructor(
- private linkerEnvironment: LinkerEnvironment,
- sourceUrl: AbsoluteFsPath, code: string) {
+ private linkerEnvironment: LinkerEnvironment,
+ sourceUrl: AbsoluteFsPath,
+ code: string,
+ ) {
this.linkerSelector = new PartialLinkerSelector(
- createLinkerMap(this.linkerEnvironment, sourceUrl, code), this.linkerEnvironment.logger,
- this.linkerEnvironment.options.unknownDeclarationVersionHandling);
+ createLinkerMap(this.linkerEnvironment, sourceUrl, code),
+ this.linkerEnvironment.logger,
+ this.linkerEnvironment.options.unknownDeclarationVersionHandling,
+ );
}
/**
@@ -53,16 +57,20 @@ export class FileLinker {
* @param declarationScope the scope that contains this call to the declaration function.
*/
linkPartialDeclaration(
- declarationFn: string, args: TExpression[],
- declarationScope: DeclarationScope): TExpression {
+ declarationFn: string,
+ args: TExpression[],
+ declarationScope: DeclarationScope,
+ ): TExpression {
if (args.length !== 1) {
throw new Error(
- `Invalid function call: It should have only a single object literal argument, but contained ${
- args.length}.`);
+ `Invalid function call: It should have only a single object literal argument, but contained ${args.length}.`,
+ );
}
- const metaObj =
- AstObject.parse(args[0], this.linkerEnvironment.host);
+ const metaObj = AstObject.parse(
+ args[0],
+ this.linkerEnvironment.host,
+ );
const ngImport = metaObj.getNode('ngImport');
const emitScope = this.getEmitScope(ngImport, declarationScope);
@@ -78,8 +86,8 @@ export class FileLinker {
* Return all the shared constant statements and their associated constant scope references, so
* that they can be inserted into the source code.
*/
- getConstantStatements(): {constantScope: TConstantScope, statements: TStatement[]}[] {
- const results: {constantScope: TConstantScope, statements: TStatement[]}[] = [];
+ getConstantStatements(): {constantScope: TConstantScope; statements: TStatement[]}[] {
+ const results: {constantScope: TConstantScope; statements: TStatement[]}[] = [];
for (const [constantScope, emitScope] of this.emitScopes.entries()) {
const statements = emitScope.getConstantStatements();
results.push({constantScope, statements});
@@ -88,20 +96,24 @@ export class FileLinker {
}
private getEmitScope(
- ngImport: TExpression, declarationScope: DeclarationScope):
- EmitScope {
+ ngImport: TExpression,
+ declarationScope: DeclarationScope,
+ ): EmitScope {
const constantScope = declarationScope.getConstantScopeRef(ngImport);
if (constantScope === null) {
// There is no constant scope so we will emit extra statements into the definition IIFE.
return new LocalEmitScope(
- ngImport, this.linkerEnvironment.translator, this.linkerEnvironment.factory);
+ ngImport,
+ this.linkerEnvironment.translator,
+ this.linkerEnvironment.factory,
+ );
}
if (!this.emitScopes.has(constantScope)) {
this.emitScopes.set(
- constantScope,
- new EmitScope(
- ngImport, this.linkerEnvironment.translator, this.linkerEnvironment.factory));
+ constantScope,
+ new EmitScope(ngImport, this.linkerEnvironment.translator, this.linkerEnvironment.factory),
+ );
}
return this.emitScopes.get(constantScope)!;
}
diff --git a/packages/compiler-cli/linker/src/file_linker/get_source_file.ts b/packages/compiler-cli/linker/src/file_linker/get_source_file.ts
index f7764e2c86e40..928f99d477c86 100644
--- a/packages/compiler-cli/linker/src/file_linker/get_source_file.ts
+++ b/packages/compiler-cli/linker/src/file_linker/get_source_file.ts
@@ -12,20 +12,23 @@ import {SourceFile, SourceFileLoader} from '../../../src/ngtsc/sourcemaps';
/**
* A function that will return a `SourceFile` object (or null) for the current file being linked.
*/
-export type GetSourceFileFn = () => SourceFile|null;
+export type GetSourceFileFn = () => SourceFile | null;
/**
* Create a `GetSourceFileFn` that will return the `SourceFile` being linked or `null`, if not
* available.
*/
export function createGetSourceFile(
- sourceUrl: AbsoluteFsPath, code: string, loader: SourceFileLoader|null): GetSourceFileFn {
+ sourceUrl: AbsoluteFsPath,
+ code: string,
+ loader: SourceFileLoader | null,
+): GetSourceFileFn {
if (loader === null) {
// No source-mapping so just return a function that always returns `null`.
return () => null;
} else {
// Source-mapping is available so return a function that will load (and cache) the `SourceFile`.
- let sourceFile: SourceFile|null|undefined = undefined;
+ let sourceFile: SourceFile | null | undefined = undefined;
return () => {
if (sourceFile === undefined) {
sourceFile = loader.loadSourceFile(sourceUrl, code);
diff --git a/packages/compiler-cli/linker/src/file_linker/linker_environment.ts b/packages/compiler-cli/linker/src/file_linker/linker_environment.ts
index c3477f3b7a8a9..f0c6e8f83d52f 100644
--- a/packages/compiler-cli/linker/src/file_linker/linker_environment.ts
+++ b/packages/compiler-cli/linker/src/file_linker/linker_environment.ts
@@ -16,23 +16,31 @@ import {Translator} from './translator';
export class LinkerEnvironment {
readonly translator = new Translator(this.factory);
- readonly sourceFileLoader =
- this.options.sourceMapping ? new SourceFileLoader(this.fileSystem, this.logger, {}) : null;
+ readonly sourceFileLoader = this.options.sourceMapping
+ ? new SourceFileLoader(this.fileSystem, this.logger, {})
+ : null;
private constructor(
- readonly fileSystem: ReadonlyFileSystem, readonly logger: Logger,
- readonly host: AstHost, readonly factory: AstFactory,
- readonly options: LinkerOptions) {}
+ readonly fileSystem: ReadonlyFileSystem,
+ readonly logger: Logger,
+ readonly host: AstHost,
+ readonly factory: AstFactory,
+ readonly options: LinkerOptions,
+ ) {}
static create(
- fileSystem: ReadonlyFileSystem, logger: Logger, host: AstHost,
- factory: AstFactory,
- options: Partial): LinkerEnvironment {
+ fileSystem: ReadonlyFileSystem,
+ logger: Logger,
+ host: AstHost,
+ factory: AstFactory,
+ options: Partial,
+ ): LinkerEnvironment {
return new LinkerEnvironment(fileSystem, logger, host, factory, {
sourceMapping: options.sourceMapping ?? DEFAULT_LINKER_OPTIONS.sourceMapping,
linkerJitMode: options.linkerJitMode ?? DEFAULT_LINKER_OPTIONS.linkerJitMode,
- unknownDeclarationVersionHandling: options.unknownDeclarationVersionHandling ??
- DEFAULT_LINKER_OPTIONS.unknownDeclarationVersionHandling,
+ unknownDeclarationVersionHandling:
+ options.unknownDeclarationVersionHandling ??
+ DEFAULT_LINKER_OPTIONS.unknownDeclarationVersionHandling,
});
}
}
diff --git a/packages/compiler-cli/linker/src/file_linker/linker_options.ts b/packages/compiler-cli/linker/src/file_linker/linker_options.ts
index 85945e00e5145..3442d298d3fae 100644
--- a/packages/compiler-cli/linker/src/file_linker/linker_options.ts
+++ b/packages/compiler-cli/linker/src/file_linker/linker_options.ts
@@ -36,7 +36,7 @@ export interface LinkerOptions {
*
* The default is `error`.
*/
- unknownDeclarationVersionHandling: 'ignore'|'warn'|'error';
+ unknownDeclarationVersionHandling: 'ignore' | 'warn' | 'error';
}
/**
diff --git a/packages/compiler-cli/linker/src/file_linker/needs_linking.ts b/packages/compiler-cli/linker/src/file_linker/needs_linking.ts
index 1a0901e519461..3f0972cbea2bc 100644
--- a/packages/compiler-cli/linker/src/file_linker/needs_linking.ts
+++ b/packages/compiler-cli/linker/src/file_linker/needs_linking.ts
@@ -24,5 +24,5 @@ import {declarationFunctions} from './partial_linkers/partial_linker_selector';
* @returns whether the source file may contain declarations that need to be linked.
*/
export function needsLinking(path: string, source: string): boolean {
- return declarationFunctions.some(fn => source.includes(fn));
+ return declarationFunctions.some((fn) => source.includes(fn));
}
diff --git a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_async_linker_1.ts b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_async_linker_1.ts
index 0effd02c9ba20..442bba029f84a 100644
--- a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_async_linker_1.ts
+++ b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_async_linker_1.ts
@@ -5,7 +5,12 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {compileOpaqueAsyncClassMetadata, ConstantPool, R3ClassMetadata, R3DeclareClassMetadataAsync} from '@angular/compiler';
+import {
+ compileOpaqueAsyncClassMetadata,
+ ConstantPool,
+ R3ClassMetadata,
+ R3DeclareClassMetadataAsync,
+} from '@angular/compiler';
import {AstObject, AstValue} from '../../ast/ast_value';
import {FatalLinkerError} from '../../fatal_linker_error';
@@ -15,23 +20,30 @@ import {LinkedDefinition, PartialLinker} from './partial_linker';
/**
* A `PartialLinker` that is designed to process `ɵɵngDeclareClassMetadataAsync()` call expressions.
*/
-export class PartialClassMetadataAsyncLinkerVersion1 implements
- PartialLinker {
+export class PartialClassMetadataAsyncLinkerVersion1
+ implements PartialLinker
+{
linkPartialDeclaration(
- constantPool: ConstantPool,
- metaObj: AstObject): LinkedDefinition {
+ constantPool: ConstantPool,
+ metaObj: AstObject,
+ ): LinkedDefinition {
const resolveMetadataKey = 'resolveMetadata';
- const resolveMetadata =
- metaObj.getValue(resolveMetadataKey) as unknown as AstValue;
+ const resolveMetadata = metaObj.getValue(resolveMetadataKey) as unknown as AstValue<
+ Function,
+ TExpression
+ >;
if (!resolveMetadata.isFunction()) {
throw new FatalLinkerError(
- resolveMetadata, `Unsupported \`${resolveMetadataKey}\` value. Expected a function.`);
+ resolveMetadata,
+ `Unsupported \`${resolveMetadataKey}\` value. Expected a function.`,
+ );
}
const dependencyResolverFunction = metaObj.getOpaque('resolveDeferredDeps');
- const deferredSymbolNames =
- resolveMetadata.getFunctionParameters().map(p => p.getSymbolName()!);
+ const deferredSymbolNames = resolveMetadata
+ .getFunctionParameters()
+ .map((p) => p.getSymbolName()!);
const returnValue = resolveMetadata.getFunctionReturnValue().getObject();
const metadata: R3ClassMetadata = {
type: metaObj.getOpaque('type'),
@@ -42,7 +54,10 @@ export class PartialClassMetadataAsyncLinkerVersion1 implements
return {
expression: compileOpaqueAsyncClassMetadata(
- metadata, dependencyResolverFunction, deferredSymbolNames),
+ metadata,
+ dependencyResolverFunction,
+ deferredSymbolNames,
+ ),
statements: [],
};
}
diff --git a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_linker_1.ts b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_linker_1.ts
index 75d64eed72966..10c4adcf04781 100644
--- a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_linker_1.ts
+++ b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_class_metadata_linker_1.ts
@@ -5,7 +5,14 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {compileClassMetadata, ConstantPool, outputAst as o, R3ClassMetadata, R3DeclareClassMetadata, R3PartialDeclaration} from '@angular/compiler';
+import {
+ compileClassMetadata,
+ ConstantPool,
+ outputAst as o,
+ R3ClassMetadata,
+ R3DeclareClassMetadata,
+ R3PartialDeclaration,
+} from '@angular/compiler';
import {AstObject} from '../../ast/ast_value';
@@ -16,8 +23,9 @@ import {LinkedDefinition, PartialLinker} from './partial_linker';
*/
export class PartialClassMetadataLinkerVersion1 implements PartialLinker {
linkPartialDeclaration(
- constantPool: ConstantPool,
- metaObj: AstObject): LinkedDefinition {
+ constantPool: ConstantPool,
+ metaObj: AstObject,
+ ): LinkedDefinition {
const meta = toR3ClassMetadata(metaObj);
return {
expression: compileClassMetadata(meta),
@@ -30,7 +38,8 @@ export class PartialClassMetadataLinkerVersion1 implements PartialL
* Derives the `R3ClassMetadata` structure from the AST object.
*/
export function toR3ClassMetadata(
- metaObj: AstObject): R3ClassMetadata {
+ metaObj: AstObject,
+): R3ClassMetadata {
return {
type: metaObj.getOpaque('type'),
decorators: metaObj.getOpaque('decorators'),
diff --git a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts
index 85e154be47bac..0e50779a3b81d 100644
--- a/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts
+++ b/packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts
@@ -5,7 +5,33 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {BoundTarget, ChangeDetectionStrategy, compileComponentFromMetadata, ConstantPool, DeclarationListEmitMode, DEFAULT_INTERPOLATION_CONFIG, DeferBlockDepsEmitMode, ForwardRefHandling, InterpolationConfig, makeBindingParser, outputAst as o, parseTemplate, R3ComponentDeferMetadata, R3ComponentMetadata, R3DeclareComponentMetadata, R3DeclareDirectiveDependencyMetadata, R3DeclarePipeDependencyMetadata, R3DirectiveDependencyMetadata, R3PartialDeclaration, R3TargetBinder, R3TemplateDependencyKind, R3TemplateDependencyMetadata, SelectorMatcher, TmplAstDeferredBlock, ViewEncapsulation} from '@angular/compiler';
+import {
+ BoundTarget,
+ ChangeDetectionStrategy,
+ compileComponentFromMetadata,
+ ConstantPool,
+ DeclarationListEmitMode,
+ DEFAULT_INTERPOLATION_CONFIG,
+ DeferBlockDepsEmitMode,
+ ForwardRefHandling,
+ InterpolationConfig,
+ makeBindingParser,
+ outputAst as o,
+ parseTemplate,
+ R3ComponentDeferMetadata,
+ R3ComponentMetadata,
+ R3DeclareComponentMetadata,
+ R3DeclareDirectiveDependencyMetadata,
+ R3DeclarePipeDependencyMetadata,
+ R3DirectiveDependencyMetadata,
+ R3PartialDeclaration,
+ R3TargetBinder,
+ R3TemplateDependencyKind,
+ R3TemplateDependencyMetadata,
+ SelectorMatcher,
+ TmplAstDeferredBlock,
+ ViewEncapsulation,
+} from '@angular/compiler';
import semver from 'semver';
import {AbsoluteFsPath} from '../../../../src/ngtsc/file_system';
@@ -19,39 +45,46 @@ import {LinkedDefinition, PartialLinker} from './partial_linker';
import {extractForwardRef, PLACEHOLDER_VERSION} from './util';
function makeDirectiveMetadata(
- directiveExpr: AstObject,
- typeExpr: o.WrappedNodeExpr,
- isComponentByDefault: true|null = null): R3DirectiveDependencyMetadata {
+ directiveExpr: AstObject,
+ typeExpr: o.WrappedNodeExpr,
+ isComponentByDefault: true | null = null,
+): R3DirectiveDependencyMetadata {
return {
kind: R3TemplateDependencyKind.Directive,
- isComponent: isComponentByDefault ||
- (directiveExpr.has('kind') && directiveExpr.getString('kind') === 'component'),
+ isComponent:
+ isComponentByDefault ||
+ (directiveExpr.has('kind') && directiveExpr.getString('kind') === 'component'),
type: typeExpr,
selector: directiveExpr.getString('selector'),
- inputs: directiveExpr.has('inputs') ?
- directiveExpr.getArray('inputs').map(input => input.getString()) :
- [],
- outputs: directiveExpr.has('outputs') ?
- directiveExpr.getArray('outputs').map(input => input.getString()) :
- [],
- exportAs: directiveExpr.has('exportAs') ?
- directiveExpr.getArray('exportAs').map(exportAs => exportAs.getString()) :
- null,
+ inputs: directiveExpr.has('inputs')
+ ? directiveExpr.getArray('inputs').map((input) => input.getString())
+ : [],
+ outputs: directiveExpr.has('outputs')
+ ? directiveExpr.getArray('outputs').map((input) => input.getString())
+ : [],
+ exportAs: directiveExpr.has('exportAs')
+ ? directiveExpr.getArray('exportAs').map((exportAs) => exportAs.getString())
+ : null,
};
}
/**
* A `PartialLinker` that is designed to process `ɵɵngDeclareComponent()` call expressions.
*/
-export class PartialComponentLinkerVersion1 implements
- PartialLinker {
+export class PartialComponentLinkerVersion1
+ implements PartialLinker
+{
constructor(
- private readonly getSourceFile: GetSourceFileFn, private sourceUrl: AbsoluteFsPath,
- private code: string) {}
+ private readonly getSourceFile: GetSourceFileFn,
+ private sourceUrl: AbsoluteFsPath,
+ private code: string,
+ ) {}
linkPartialDeclaration(
- constantPool: ConstantPool, metaObj: AstObject,
- version: string): LinkedDefinition {
+ constantPool: ConstantPool,
+ metaObj: AstObject,
+ version: string,
+ ): LinkedDefinition {
const meta = this.toR3ComponentMeta(metaObj, version);
return compileComponentFromMetadata(meta, constantPool, makeBindingParser());
}
@@ -60,8 +93,9 @@ export class PartialComponentLinkerVersion1 implements
* This function derives the `R3ComponentMetadata` from the provided AST object.
*/
private toR3ComponentMeta(
- metaObj: AstObject,
- version: string): R3ComponentMetadata {
+ metaObj: AstObject,
+ version: string,
+ ): R3ComponentMetadata {
const interpolation = parseInterpolationConfig(metaObj);
const templateSource = metaObj.getValue('template');
const isInline = metaObj.has('isInline') ? metaObj.getBoolean('isInline') : false;
@@ -76,30 +110,34 @@ export class PartialComponentLinkerVersion1 implements
interpolationConfig: interpolation,
range: templateInfo.range,
enableI18nLegacyMessageIdFormat: false,
- preserveWhitespaces:
- metaObj.has('preserveWhitespaces') ? metaObj.getBoolean('preserveWhitespaces') : false,
+ preserveWhitespaces: metaObj.has('preserveWhitespaces')
+ ? metaObj.getBoolean('preserveWhitespaces')
+ : false,
// We normalize line endings if the template is was inline.
i18nNormalizeLineEndingsInICUs: isInline,
enableBlockSyntax,
});
if (template.errors !== null) {
- const errors = template.errors.map(err => err.toString()).join('\n');
+ const errors = template.errors.map((err) => err.toString()).join('\n');
throw new FatalLinkerError(
- templateSource.expression, `Errors found in the template:\n${errors}`);
+ templateSource.expression,
+ `Errors found in the template:\n${errors}`,
+ );
}
const binder = new R3TargetBinder(new SelectorMatcher());
const boundTarget = binder.bind({template: template.nodes});
let declarationListEmitMode = DeclarationListEmitMode.Direct;
- const extractDeclarationTypeExpr =
- (type: AstValue o.Expression), TExpression>) => {
- const {expression, forwardRef} = extractForwardRef(type);
- if (forwardRef === ForwardRefHandling.Unwrapped) {
- declarationListEmitMode = DeclarationListEmitMode.Closure;
- }
- return expression;
- };
+ const extractDeclarationTypeExpr = (
+ type: AstValue o.Expression), TExpression>,
+ ) => {
+ const {expression, forwardRef} = extractForwardRef(type);
+ if (forwardRef === ForwardRefHandling.Unwrapped) {
+ declarationListEmitMode = DeclarationListEmitMode.Closure;
+ }
+ return expression;
+ };
let declarations: R3TemplateDependencyMetadata[] = [];
@@ -110,21 +148,25 @@ export class PartialComponentLinkerVersion1 implements
// Process the old style fields:
if (metaObj.has('components')) {
- declarations.push(...metaObj.getArray('components').map(dir => {
- const dirExpr = dir.getObject();
- const typeExpr = extractDeclarationTypeExpr(dirExpr.getValue('type'));
- return makeDirectiveMetadata(dirExpr, typeExpr, /* isComponentByDefault */ true);
- }));
+ declarations.push(
+ ...metaObj.getArray('components').map((dir) => {
+ const dirExpr = dir.getObject();
+ const typeExpr = extractDeclarationTypeExpr(dirExpr.getValue('type'));
+ return makeDirectiveMetadata(dirExpr, typeExpr, /* isComponentByDefault */ true);
+ }),
+ );
}
if (metaObj.has('directives')) {
- declarations.push(...metaObj.getArray('directives').map(dir => {
- const dirExpr = dir.getObject();
- const typeExpr = extractDeclarationTypeExpr(dirExpr.getValue('type'));
- return makeDirectiveMetadata(dirExpr, typeExpr);
- }));
+ declarations.push(
+ ...metaObj.getArray('directives').map((dir) => {
+ const dirExpr = dir.getObject();
+ const typeExpr = extractDeclarationTypeExpr(dirExpr.getValue('type'));
+ return makeDirectiveMetadata(dirExpr, typeExpr);
+ }),
+ );
}
if (metaObj.has('pipes')) {
- const pipes = metaObj.getObject('pipes').toMap(pipe => pipe);
+ const pipes = metaObj.getObject('pipes').toMap((pipe) => pipe);
for (const [name, type] of pipes) {
const typeExpr = extractDeclarationTypeExpr(type);
declarations.push({
@@ -147,8 +189,10 @@ export class PartialComponentLinkerVersion1 implements
declarations.push(makeDirectiveMetadata(depObj, typeExpr));
break;
case 'pipe':
- const pipeObj =
- depObj as AstObject;
+ const pipeObj = depObj as AstObject<
+ R3DeclarePipeDependencyMetadata & {kind: 'pipe'},
+ TExpression
+ >;
declarations.push({
kind: R3TemplateDependencyKind.Pipe,
name: pipeObj.getString('name'),
@@ -176,16 +220,17 @@ export class PartialComponentLinkerVersion1 implements
ngContentSelectors: template.ngContentSelectors,
},
declarationListEmitMode,
- styles: metaObj.has('styles') ? metaObj.getArray('styles').map(entry => entry.getString()) :
- [],
+ styles: metaObj.has('styles')
+ ? metaObj.getArray('styles').map((entry) => entry.getString())
+ : [],
defer: this.createR3ComponentDeferMetadata(metaObj, boundTarget),
- encapsulation: metaObj.has('encapsulation') ?
- parseEncapsulation(metaObj.getValue('encapsulation')) :
- ViewEncapsulation.Emulated,
+ encapsulation: metaObj.has('encapsulation')
+ ? parseEncapsulation(metaObj.getValue('encapsulation'))
+ : ViewEncapsulation.Emulated,
interpolation,
- changeDetection: metaObj.has('changeDetection') ?
- parseChangeDetectionStrategy(metaObj.getValue('changeDetection')) :
- ChangeDetectionStrategy.Default,
+ changeDetection: metaObj.has('changeDetection')
+ ? parseChangeDetectionStrategy(metaObj.getValue('changeDetection'))
+ : ChangeDetectionStrategy.Default,
animations: metaObj.has('animations') ? metaObj.getOpaque('animations') : null,
relativeContextFilePath: this.sourceUrl,
i18nUseExternalIds: false,
@@ -196,8 +241,10 @@ export class PartialComponentLinkerVersion1 implements
/**
* Update the range to remove the start and end chars, which should be quotes around the template.
*/
- private getTemplateInfo(templateNode: AstValue, isInline: boolean):
- TemplateInfo {
+ private getTemplateInfo(
+ templateNode: AstValue,
+ isInline: boolean,
+ ): TemplateInfo {
const range = templateNode.getRange();
if (!isInline) {
@@ -214,7 +261,7 @@ export class PartialComponentLinkerVersion1 implements
return this.templateFromPartialCode(templateNode, range);
}
- private tryExternalTemplate(range: Range): TemplateInfo|null {
+ private tryExternalTemplate(range: Range): TemplateInfo | null {
const sourceFile = this.getSourceFile();
if (sourceFile === null) {
return null;
@@ -225,12 +272,19 @@ export class PartialComponentLinkerVersion1 implements
// * the file is different to the current file
// * the file does not end in `.js` or `.ts` (we expect it to be something like `.html`).
// * the range starts at the beginning of the file
- if (pos === null || pos.file === this.sourceUrl || /\.[jt]s$/.test(pos.file) ||
- pos.line !== 0 || pos.column !== 0) {
+ if (
+ pos === null ||
+ pos.file === this.sourceUrl ||
+ /\.[jt]s$/.test(pos.file) ||
+ pos.line !== 0 ||
+ pos.column !== 0
+ ) {
return null;
}
- const templateContents = sourceFile.sources.find(src => src?.sourcePath === pos.file)!.contents;
+ const templateContents = sourceFile.sources.find(
+ (src) => src?.sourcePath === pos.file,
+ )!.contents;
return {
code: templateContents,
@@ -241,13 +295,17 @@ export class PartialComponentLinkerVersion1 implements
}
private templateFromPartialCode(
- templateNode: AstValue,
- {startPos, endPos, startLine, startCol}: Range): TemplateInfo {
+ templateNode: AstValue,
+ {startPos, endPos, startLine, startCol}: Range,
+ ): TemplateInfo {
if (!/["'`]/.test(this.code[startPos]) || this.code[startPos] !== this.code[endPos - 1]) {
throw new FatalLinkerError(
- templateNode.expression,
- `Expected the template string to be wrapped in quotes but got: ${
- this.code.substring(startPos, endPos)}`);
+ templateNode.expression,
+ `Expected the template string to be wrapped in quotes but got: ${this.code.substring(
+ startPos,
+ endPos,
+ )}`,
+ );
}
return {
code: this.code,
@@ -258,12 +316,14 @@ export class PartialComponentLinkerVersion1 implements
}
private createR3ComponentDeferMetadata(
- metaObj: AstObject,
- boundTarget: BoundTarget): R3ComponentDeferMetadata {
+ metaObj: AstObject,
+ boundTarget: BoundTarget,
+ ): R3ComponentDeferMetadata {
const deferredBlocks = boundTarget.getDeferBlocks();
- const blocks = new Map();
- const dependencies =
- metaObj.has('deferBlockDependencies') ? metaObj.getArray('deferBlockDependencies') : null;
+ const blocks = new Map();
+ const dependencies = metaObj.has('deferBlockDependencies')
+ ? metaObj.getArray('deferBlockDependencies')
+ : null;
for (let i = 0; i < deferredBlocks.length; i++) {
const matchingDependencyFn = dependencies?.[i];
@@ -272,8 +332,9 @@ export class PartialComponentLinkerVersion1 implements
blocks.set(deferredBlocks[i], null);
} else {
blocks.set(
- deferredBlocks[i],
- matchingDependencyFn.isNull() ? null : matchingDependencyFn.getOpaque());
+ deferredBlocks[i],
+ matchingDependencyFn.isNull() ? null : matchingDependencyFn.getOpaque(),
+ );
}
}
@@ -292,17 +353,19 @@ interface TemplateInfo {
* Extract an `InterpolationConfig` from the component declaration.
*/
function parseInterpolationConfig(
- metaObj: AstObject): InterpolationConfig {
+ metaObj: AstObject,
+): InterpolationConfig {
if (!metaObj.has('interpolation')) {
return DEFAULT_INTERPOLATION_CONFIG;
}
const interpolationExpr = metaObj.getValue('interpolation');
- const values = interpolationExpr.getArray().map(entry => entry.getString());
+ const values = interpolationExpr.getArray().map((entry) => entry.getString());
if (values.length !== 2) {
throw new FatalLinkerError(
- interpolationExpr.expression,
- 'Unsupported interpolation config, expected an array containing exactly two strings');
+ interpolationExpr.expression,
+ 'Unsupported interpolation config, expected an array containing exactly two strings',
+ );
}
return InterpolationConfig.fromArray(values as [string, string]);
}
@@ -311,11 +374,14 @@ function parseInterpolationConfig(
* Determines the `ViewEncapsulation` mode from the AST value's symbol name.
*/
function parseEncapsulation