fix(ngcc): do not emit ES2015 code in ES5 files (#33514)
Previously, ngcc's `Renderer` would add some constants in the processed files which were emitted as ES2015 code (e.g. `const` declarations). This would result in invalid ES5 generated code that would break when run on browsers that do not support the emitted format. This commit fixes it by adding a `printStatement()` method to `RenderingFormatter`, which can convert statements to JavaScript code in a suitable format for the corresponding `RenderingFormatter`. Additionally, the `translateExpression()` and `translateStatement()` ngtsc helper methods are augmented to accept an extra hint to know whether the code needs to be translated to ES5 format or not. Fixes #32665 PR Close #33514
This commit is contained in:
parent
704775168d
commit
033aba9351
|
@ -95,7 +95,7 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'."
|
||||||
grep "const ɵMatTable_BaseFactory = ɵngcc0.ɵɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm2015/table.js
|
grep "const ɵMatTable_BaseFactory = ɵngcc0.ɵɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm2015/table.js
|
||||||
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm2015)."
|
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm2015)."
|
||||||
|
|
||||||
grep "const ɵMatTable_BaseFactory = ɵngcc0.ɵɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm5/table.es5.js
|
grep "var ɵMatTable_BaseFactory = ɵngcc0.ɵɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm5/table.es5.js
|
||||||
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm5)."
|
assertSucceeded "Expected 'ngcc' to generate a base factory for 'MatTable' in '@angular/material' (esm5)."
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {Statement} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../../src/ngtsc/imports';
|
||||||
|
import {ImportManager, translateStatement} from '../../../src/ngtsc/translator';
|
||||||
import {CompiledClass} from '../analysis/types';
|
import {CompiledClass} from '../analysis/types';
|
||||||
import {getIifeBody} from '../host/esm5_host';
|
import {getIifeBody} from '../host/esm5_host';
|
||||||
import {EsmRenderingFormatter} from './esm_rendering_formatter';
|
import {EsmRenderingFormatter} from './esm_rendering_formatter';
|
||||||
|
@ -35,4 +38,22 @@ export class Esm5RenderingFormatter extends EsmRenderingFormatter {
|
||||||
const insertionPoint = returnStatement.getFullStart();
|
const insertionPoint = returnStatement.getFullStart();
|
||||||
output.appendLeft(insertionPoint, '\n' + definitions);
|
output.appendLeft(insertionPoint, '\n' + definitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a `Statement` to JavaScript code in a format suitable for rendering by this formatter.
|
||||||
|
*
|
||||||
|
* @param stmt The `Statement` to print.
|
||||||
|
* @param sourceFile A `ts.SourceFile` that provides context for the statement. See
|
||||||
|
* `ts.Printer#printNode()` for more info.
|
||||||
|
* @param importManager The `ImportManager` to use for managing imports.
|
||||||
|
*
|
||||||
|
* @return The JavaScript code corresponding to `stmt` (in the appropriate format).
|
||||||
|
*/
|
||||||
|
printStatement(stmt: Statement, sourceFile: ts.SourceFile, importManager: ImportManager): string {
|
||||||
|
const node =
|
||||||
|
translateStatement(stmt, importManager, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES5);
|
||||||
|
const code = this.printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {Statement} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {relative, dirname, AbsoluteFsPath, absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
|
import {relative, dirname, AbsoluteFsPath, absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
|
||||||
import {Import, ImportManager} from '../../../src/ngtsc/translator';
|
import {NOOP_DEFAULT_IMPORT_RECORDER, Reexport} from '../../../src/ngtsc/imports';
|
||||||
|
import {Import, ImportManager, translateStatement} from '../../../src/ngtsc/translator';
|
||||||
import {isDtsPath} from '../../../src/ngtsc/util/src/typescript';
|
import {isDtsPath} from '../../../src/ngtsc/util/src/typescript';
|
||||||
import {CompiledClass} from '../analysis/types';
|
import {CompiledClass} from '../analysis/types';
|
||||||
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
|
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
|
||||||
|
@ -16,13 +18,14 @@ import {ModuleWithProvidersInfo} from '../analysis/module_with_providers_analyze
|
||||||
import {ExportInfo} from '../analysis/private_declarations_analyzer';
|
import {ExportInfo} from '../analysis/private_declarations_analyzer';
|
||||||
import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
||||||
import {stripExtension} from './utils';
|
import {stripExtension} from './utils';
|
||||||
import {Reexport} from '../../../src/ngtsc/imports';
|
|
||||||
import {isAssignment} from '../host/esm2015_host';
|
import {isAssignment} from '../host/esm2015_host';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A RenderingFormatter that works with ECMAScript Module import and export statements.
|
* A RenderingFormatter that works with ECMAScript Module import and export statements.
|
||||||
*/
|
*/
|
||||||
export class EsmRenderingFormatter implements RenderingFormatter {
|
export class EsmRenderingFormatter implements RenderingFormatter {
|
||||||
|
protected printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
|
||||||
|
|
||||||
constructor(protected host: NgccReflectionHost, protected isCore: boolean) {}
|
constructor(protected host: NgccReflectionHost, protected isCore: boolean) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -225,6 +228,24 @@ export class EsmRenderingFormatter implements RenderingFormatter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a `Statement` to JavaScript code in a format suitable for rendering by this formatter.
|
||||||
|
*
|
||||||
|
* @param stmt The `Statement` to print.
|
||||||
|
* @param sourceFile A `ts.SourceFile` that provides context for the statement. See
|
||||||
|
* `ts.Printer#printNode()` for more info.
|
||||||
|
* @param importManager The `ImportManager` to use for managing imports.
|
||||||
|
*
|
||||||
|
* @return The JavaScript code corresponding to `stmt` (in the appropriate format).
|
||||||
|
*/
|
||||||
|
printStatement(stmt: Statement, sourceFile: ts.SourceFile, importManager: ImportManager): string {
|
||||||
|
const node = translateStatement(
|
||||||
|
stmt, importManager, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
|
||||||
|
const code = this.printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
protected findEndOfImports(sf: ts.SourceFile): number {
|
protected findEndOfImports(sf: ts.SourceFile): number {
|
||||||
for (const stmt of sf.statements) {
|
for (const stmt of sf.statements) {
|
||||||
if (!ts.isImportDeclaration(stmt) && !ts.isImportEqualsDeclaration(stmt) &&
|
if (!ts.isImportDeclaration(stmt) && !ts.isImportEqualsDeclaration(stmt) &&
|
||||||
|
|
|
@ -8,19 +8,18 @@
|
||||||
import {ConstantPool, Expression, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler';
|
import {ConstantPool, Expression, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../../src/ngtsc/imports';
|
import {ImportManager} from '../../../src/ngtsc/translator';
|
||||||
import {translateStatement, ImportManager} from '../../../src/ngtsc/translator';
|
|
||||||
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/types';
|
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/types';
|
||||||
import {PrivateDeclarationsAnalyses} from '../analysis/private_declarations_analyzer';
|
import {PrivateDeclarationsAnalyses} from '../analysis/private_declarations_analyzer';
|
||||||
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
|
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
|
||||||
import {IMPORT_PREFIX} from '../constants';
|
import {IMPORT_PREFIX} from '../constants';
|
||||||
import {FileSystem} from '../../../src/ngtsc/file_system';
|
import {FileSystem} from '../../../src/ngtsc/file_system';
|
||||||
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {Logger} from '../logging/logger';
|
import {Logger} from '../logging/logger';
|
||||||
import {FileToWrite, getImportRewriter, stripExtension} from './utils';
|
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
||||||
import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
||||||
import {extractSourceMap, renderSourceAndMap} from './source_maps';
|
import {extractSourceMap, renderSourceAndMap} from './source_maps';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {FileToWrite, getImportRewriter, stripExtension} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base-class for rendering an `AnalyzedFile`.
|
* A base-class for rendering an `AnalyzedFile`.
|
||||||
|
@ -98,7 +97,8 @@ export class Renderer {
|
||||||
|
|
||||||
this.srcFormatter.addConstants(
|
this.srcFormatter.addConstants(
|
||||||
outputText,
|
outputText,
|
||||||
renderConstantPool(compiledFile.sourceFile, compiledFile.constantPool, importManager),
|
renderConstantPool(
|
||||||
|
this.srcFormatter, compiledFile.sourceFile, compiledFile.constantPool, importManager),
|
||||||
compiledFile.sourceFile);
|
compiledFile.sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,12 +185,9 @@ export class Renderer {
|
||||||
|
|
||||||
private renderStatements(
|
private renderStatements(
|
||||||
sourceFile: ts.SourceFile, statements: Statement[], imports: ImportManager): string {
|
sourceFile: ts.SourceFile, statements: Statement[], imports: ImportManager): string {
|
||||||
const printer = createPrinter();
|
const printStatement = (stmt: Statement) =>
|
||||||
const translate = (stmt: Statement) =>
|
this.srcFormatter.printStatement(stmt, sourceFile, imports);
|
||||||
translateStatement(stmt, imports, NOOP_DEFAULT_IMPORT_RECORDER);
|
return statements.map(printStatement).join('\n');
|
||||||
const print = (stmt: Statement) =>
|
|
||||||
printer.printNode(ts.EmitHint.Unspecified, translate(stmt), sourceFile);
|
|
||||||
return statements.map(print).join('\n');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,12 +195,10 @@ export class Renderer {
|
||||||
* Render the constant pool as source code for the given class.
|
* Render the constant pool as source code for the given class.
|
||||||
*/
|
*/
|
||||||
export function renderConstantPool(
|
export function renderConstantPool(
|
||||||
sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: ImportManager): string {
|
formatter: RenderingFormatter, sourceFile: ts.SourceFile, constantPool: ConstantPool,
|
||||||
const printer = createPrinter();
|
imports: ImportManager): string {
|
||||||
return constantPool.statements
|
const printStatement = (stmt: Statement) => formatter.printStatement(stmt, sourceFile, imports);
|
||||||
.map(stmt => translateStatement(stmt, imports, NOOP_DEFAULT_IMPORT_RECORDER))
|
return constantPool.statements.map(printStatement).join('\n');
|
||||||
.map(stmt => printer.printNode(ts.EmitHint.Unspecified, stmt, sourceFile))
|
|
||||||
.join('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -216,7 +211,3 @@ function createAssignmentStatement(
|
||||||
const receiver = new WrappedNodeExpr(receiverName);
|
const receiver = new WrappedNodeExpr(receiverName);
|
||||||
return new WritePropExpr(receiver, propName, initializer).toStmt();
|
return new WritePropExpr(receiver, propName, initializer).toStmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPrinter(): ts.Printer {
|
|
||||||
return ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {Statement} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {Reexport} from '../../../src/ngtsc/imports';
|
import {Reexport} from '../../../src/ngtsc/imports';
|
||||||
|
@ -45,4 +46,5 @@ export interface RenderingFormatter {
|
||||||
addModuleWithProvidersParams(
|
addModuleWithProvidersParams(
|
||||||
outputText: MagicString, moduleWithProviders: ModuleWithProvidersInfo[],
|
outputText: MagicString, moduleWithProviders: ModuleWithProvidersInfo[],
|
||||||
importManager: ImportManager): void;
|
importManager: ImportManager): void;
|
||||||
|
printStatement(stmt: Statement, sourceFile: ts.SourceFile, importManager: ImportManager): string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ ts_library(
|
||||||
exclude = ["integration/**/*.ts"],
|
exclude = ["integration/**/*.ts"],
|
||||||
),
|
),
|
||||||
deps = [
|
deps = [
|
||||||
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli/ngcc",
|
"//packages/compiler-cli/ngcc",
|
||||||
"//packages/compiler-cli/ngcc/test/helpers",
|
"//packages/compiler-cli/ngcc/test/helpers",
|
||||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||||
|
|
|
@ -147,6 +147,38 @@ runInEachFileSystem(() => {
|
||||||
'{ bar: [{ type: Input }] });');
|
'{ bar: [{ type: Input }] });');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not add `const` in ES5 generated code', () => {
|
||||||
|
genNodeModules({
|
||||||
|
'test-package': {
|
||||||
|
'/index.ts': `
|
||||||
|
import {Directive, Input, NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[foo]',
|
||||||
|
host: {bar: ''},
|
||||||
|
})
|
||||||
|
export class FooDirective {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [FooDirective],
|
||||||
|
})
|
||||||
|
export class FooModule {}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
mainNgcc({
|
||||||
|
basePath: '/node_modules',
|
||||||
|
targetEntryPointPath: 'test-package',
|
||||||
|
propertiesToConsider: ['main'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
|
||||||
|
expect(jsContents).not.toMatch(/\bconst \w+\s*=/);
|
||||||
|
expect(jsContents).toMatch(/\bvar _c0 =/);
|
||||||
|
});
|
||||||
|
|
||||||
describe('in async mode', () => {
|
describe('in async mode', () => {
|
||||||
it('should run ngcc without errors for fesm2015', async() => {
|
it('should run ngcc without errors for fesm2015', async() => {
|
||||||
const promise = mainNgcc({
|
const promise = mainNgcc({
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
||||||
|
@ -518,5 +519,19 @@ SOME DEFINITION TEXT
|
||||||
expect(output.toString()).toContain(`function C() {\n }\n return C;`);
|
expect(output.toString()).toContain(`function C() {\n }\n return C;`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('printStatement', () => {
|
||||||
|
it('should transpile code to ES5', () => {
|
||||||
|
const {renderer, sourceFile, importManager} = setup(PROGRAM);
|
||||||
|
|
||||||
|
const stmt1 = new DeclareVarStmt('foo', new LiteralExpr(42), null, [StmtModifier.Static]);
|
||||||
|
const stmt2 = new DeclareVarStmt('bar', new LiteralExpr(true));
|
||||||
|
const stmt3 = new DeclareVarStmt('baz', new LiteralExpr('qux'), undefined, []);
|
||||||
|
|
||||||
|
expect(renderer.printStatement(stmt1, sourceFile, importManager)).toBe('var foo = 42;');
|
||||||
|
expect(renderer.printStatement(stmt2, sourceFile, importManager)).toBe('var bar = true;');
|
||||||
|
expect(renderer.printStatement(stmt3, sourceFile, importManager)).toBe('var baz = "qux";');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,6 +53,7 @@ class TestRenderingFormatter implements RenderingFormatter {
|
||||||
importManager: ImportManager): void {
|
importManager: ImportManager): void {
|
||||||
output.prepend('\n// ADD MODUlE WITH PROVIDERS PARAMS\n');
|
output.prepend('\n// ADD MODUlE WITH PROVIDERS PARAMS\n');
|
||||||
}
|
}
|
||||||
|
printStatement(): string { return 'IGNORED'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTestRenderer(
|
function createTestRenderer(
|
||||||
|
@ -87,6 +88,7 @@ function createTestRenderer(
|
||||||
spyOn(testFormatter, 'removeDecorators').and.callThrough();
|
spyOn(testFormatter, 'removeDecorators').and.callThrough();
|
||||||
spyOn(testFormatter, 'rewriteSwitchableDeclarations').and.callThrough();
|
spyOn(testFormatter, 'rewriteSwitchableDeclarations').and.callThrough();
|
||||||
spyOn(testFormatter, 'addModuleWithProvidersParams').and.callThrough();
|
spyOn(testFormatter, 'addModuleWithProvidersParams').and.callThrough();
|
||||||
|
spyOn(testFormatter, 'printStatement').and.callThrough();
|
||||||
|
|
||||||
const renderer = new DtsRenderer(testFormatter, fs, logger, host, bundle);
|
const renderer = new DtsRenderer(testFormatter, fs, logger, host, bundle);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
||||||
|
@ -545,5 +546,19 @@ SOME DEFINITION TEXT
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('printStatement', () => {
|
||||||
|
it('should transpile code to ES5', () => {
|
||||||
|
const {renderer, sourceFile, importManager} = setup(PROGRAM);
|
||||||
|
|
||||||
|
const stmt1 = new DeclareVarStmt('foo', new LiteralExpr(42), null, [StmtModifier.Static]);
|
||||||
|
const stmt2 = new DeclareVarStmt('bar', new LiteralExpr(true));
|
||||||
|
const stmt3 = new DeclareVarStmt('baz', new LiteralExpr('qux'), undefined, []);
|
||||||
|
|
||||||
|
expect(renderer.printStatement(stmt1, sourceFile, importManager)).toBe('var foo = 42;');
|
||||||
|
expect(renderer.printStatement(stmt2, sourceFile, importManager)).toBe('var bar = true;');
|
||||||
|
expect(renderer.printStatement(stmt3, sourceFile, importManager)).toBe('var baz = "qux";');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
||||||
|
@ -623,5 +624,19 @@ export { D };
|
||||||
static withProviders2(): (ModuleWithProviders)&{ngModule:ExternalModule};`);
|
static withProviders2(): (ModuleWithProviders)&{ngModule:ExternalModule};`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('printStatement', () => {
|
||||||
|
it('should transpile code to ES2015', () => {
|
||||||
|
const {renderer, sourceFile, importManager} = setup([PROGRAM]);
|
||||||
|
|
||||||
|
const stmt1 = new DeclareVarStmt('foo', new LiteralExpr(42), null, [StmtModifier.Final]);
|
||||||
|
const stmt2 = new DeclareVarStmt('bar', new LiteralExpr(true));
|
||||||
|
const stmt3 = new DeclareVarStmt('baz', new LiteralExpr('qux'), undefined, []);
|
||||||
|
|
||||||
|
expect(renderer.printStatement(stmt1, sourceFile, importManager)).toBe('const foo = 42;');
|
||||||
|
expect(renderer.printStatement(stmt2, sourceFile, importManager)).toBe('var bar = true;');
|
||||||
|
expect(renderer.printStatement(stmt3, sourceFile, importManager)).toBe('var baz = "qux";');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {Statement} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {fromObject, generateMapFileComment, SourceMapConverter} from 'convert-source-map';
|
import {fromObject, generateMapFileComment, SourceMapConverter} from 'convert-source-map';
|
||||||
import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system';
|
import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system';
|
||||||
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||||
import {Reexport} from '../../../src/ngtsc/imports';
|
import {NOOP_DEFAULT_IMPORT_RECORDER, Reexport} from '../../../src/ngtsc/imports';
|
||||||
import {loadTestFiles} from '../../../test/helpers';
|
import {loadTestFiles} from '../../../test/helpers';
|
||||||
import {Import, ImportManager} from '../../../src/ngtsc/translator';
|
import {Import, ImportManager, translateStatement} from '../../../src/ngtsc/translator';
|
||||||
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
||||||
import {CompiledClass} from '../../src/analysis/types';
|
import {CompiledClass} from '../../src/analysis/types';
|
||||||
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
|
||||||
|
@ -27,6 +28,8 @@ import {RenderingFormatter, RedundantDecoratorMap} from '../../src/rendering/ren
|
||||||
import {makeTestEntryPointBundle, getRootFiles} from '../helpers/utils';
|
import {makeTestEntryPointBundle, getRootFiles} from '../helpers/utils';
|
||||||
|
|
||||||
class TestRenderingFormatter implements RenderingFormatter {
|
class TestRenderingFormatter implements RenderingFormatter {
|
||||||
|
private printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
|
||||||
|
|
||||||
addImports(output: MagicString, imports: Import[], sf: ts.SourceFile) {
|
addImports(output: MagicString, imports: Import[], sf: ts.SourceFile) {
|
||||||
output.prepend('\n// ADD IMPORTS\n');
|
output.prepend('\n// ADD IMPORTS\n');
|
||||||
}
|
}
|
||||||
|
@ -56,6 +59,13 @@ class TestRenderingFormatter implements RenderingFormatter {
|
||||||
importManager: ImportManager): void {
|
importManager: ImportManager): void {
|
||||||
output.prepend('\n// ADD MODUlE WITH PROVIDERS PARAMS\n');
|
output.prepend('\n// ADD MODUlE WITH PROVIDERS PARAMS\n');
|
||||||
}
|
}
|
||||||
|
printStatement(stmt: Statement, sourceFile: ts.SourceFile, importManager: ImportManager): string {
|
||||||
|
const node = translateStatement(
|
||||||
|
stmt, importManager, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
|
||||||
|
const code = this.printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
|
||||||
|
|
||||||
|
return `// TRANSPILED\n${code}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTestRenderer(
|
function createTestRenderer(
|
||||||
|
@ -92,6 +102,7 @@ function createTestRenderer(
|
||||||
spyOn(testFormatter, 'removeDecorators').and.callThrough();
|
spyOn(testFormatter, 'removeDecorators').and.callThrough();
|
||||||
spyOn(testFormatter, 'rewriteSwitchableDeclarations').and.callThrough();
|
spyOn(testFormatter, 'rewriteSwitchableDeclarations').and.callThrough();
|
||||||
spyOn(testFormatter, 'addModuleWithProvidersParams').and.callThrough();
|
spyOn(testFormatter, 'addModuleWithProvidersParams').and.callThrough();
|
||||||
|
spyOn(testFormatter, 'printStatement').and.callThrough();
|
||||||
|
|
||||||
const renderer = new Renderer(host, testFormatter, fs, logger, bundle);
|
const renderer = new Renderer(host, testFormatter, fs, logger, bundle);
|
||||||
|
|
||||||
|
@ -200,8 +211,9 @@ runInEachFileSystem(() => {
|
||||||
renderer.renderProgram(
|
renderer.renderProgram(
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
||||||
expect(addDefinitionsSpy.calls.first().args[2])
|
expect(addDefinitionsSpy.calls.first().args[2]).toEqual(`// TRANSPILED
|
||||||
.toEqual(`A.ɵfac = function A_Factory(t) { return new (t || A)(); };
|
A.ɵfac = function A_Factory(t) { return new (t || A)(); };
|
||||||
|
// TRANSPILED
|
||||||
A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) {
|
A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) {
|
||||||
ɵngcc0.ɵɵtext(0);
|
ɵngcc0.ɵɵtext(0);
|
||||||
} if (rf & 2) {
|
} if (rf & 2) {
|
||||||
|
@ -209,8 +221,8 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v
|
||||||
} }, encapsulation: 2 });`);
|
} }, encapsulation: 2 });`);
|
||||||
|
|
||||||
const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy;
|
const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy;
|
||||||
expect(addAdjacentStatementsSpy.calls.first().args[2])
|
expect(addAdjacentStatementsSpy.calls.first().args[2]).toEqual(`// TRANSPILED
|
||||||
.toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||||
type: Component,
|
type: Component,
|
||||||
args: [{ selector: 'a', template: '{{ person!.name }}' }]
|
args: [{ selector: 'a', template: '{{ person!.name }}' }]
|
||||||
}], null, null);`);
|
}], null, null);`);
|
||||||
|
@ -243,8 +255,9 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v
|
||||||
name: 'A',
|
name: 'A',
|
||||||
decorators: [jasmine.objectContaining({name: 'Directive'})]
|
decorators: [jasmine.objectContaining({name: 'Directive'})]
|
||||||
}));
|
}));
|
||||||
expect(addDefinitionsSpy.calls.first().args[2])
|
expect(addDefinitionsSpy.calls.first().args[2]).toEqual(`// TRANSPILED
|
||||||
.toEqual(`A.ɵfac = function A_Factory(t) { return new (t || A)(); };
|
A.ɵfac = function A_Factory(t) { return new (t || A)(); };
|
||||||
|
// TRANSPILED
|
||||||
A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });`);
|
A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -260,8 +273,8 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });`
|
||||||
expect(addAdjacentStatementsSpy.calls.first().args[1])
|
expect(addAdjacentStatementsSpy.calls.first().args[1])
|
||||||
.toEqual(jasmine.objectContaining(
|
.toEqual(jasmine.objectContaining(
|
||||||
{name: 'A', decorators: [jasmine.objectContaining({name: 'Directive'})]}));
|
{name: 'A', decorators: [jasmine.objectContaining({name: 'Directive'})]}));
|
||||||
expect(addAdjacentStatementsSpy.calls.first().args[2])
|
expect(addAdjacentStatementsSpy.calls.first().args[2]).toEqual(`// TRANSPILED
|
||||||
.toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||||
type: Directive,
|
type: Directive,
|
||||||
args: [{ selector: '[a]' }]
|
args: [{ selector: '[a]' }]
|
||||||
}], null, null);`);
|
}], null, null);`);
|
||||||
|
@ -271,7 +284,7 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });`
|
||||||
() => {
|
() => {
|
||||||
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
||||||
testFormatter} = createTestRenderer('test-package', [INPUT_PROGRAM]);
|
testFormatter} = createTestRenderer('test-package', [INPUT_PROGRAM]);
|
||||||
const result = renderer.renderProgram(
|
renderer.renderProgram(
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
const removeDecoratorsSpy = testFormatter.removeDecorators as jasmine.Spy;
|
const removeDecoratorsSpy = testFormatter.removeDecorators as jasmine.Spy;
|
||||||
expect(removeDecoratorsSpy.calls.first().args[0].toString())
|
expect(removeDecoratorsSpy.calls.first().args[0].toString())
|
||||||
|
@ -467,9 +480,9 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });`
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
|
|
||||||
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
|
||||||
expect(addDefinitionsSpy.calls.first().args[2])
|
expect(addDefinitionsSpy.calls.first().args[2]).toEqual(`// TRANSPILED
|
||||||
.toEqual(
|
UndecoratedBase.ɵfac = function UndecoratedBase_Factory(t) { return new (t || UndecoratedBase)(); };
|
||||||
`UndecoratedBase.ɵfac = function UndecoratedBase_Factory(t) { return new (t || UndecoratedBase)(); };
|
// TRANSPILED
|
||||||
UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, viewQuery: function UndecoratedBase_Query(rf, ctx) { if (rf & 1) {
|
UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, viewQuery: function UndecoratedBase_Query(rf, ctx) { if (rf & 1) {
|
||||||
ɵngcc0.ɵɵstaticViewQuery(_c0, true);
|
ɵngcc0.ɵɵstaticViewQuery(_c0, true);
|
||||||
} if (rf & 2) {
|
} if (rf & 2) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler';
|
||||||
import MagicString from 'magic-string';
|
import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
||||||
|
@ -592,5 +593,19 @@ SOME DEFINITION TEXT
|
||||||
expect(output.toString()).toContain(`function C() {\n }\n return C;`);
|
expect(output.toString()).toContain(`function C() {\n }\n return C;`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('printStatement', () => {
|
||||||
|
it('should transpile code to ES5', () => {
|
||||||
|
const {renderer, sourceFile, importManager} = setup(PROGRAM);
|
||||||
|
|
||||||
|
const stmt1 = new DeclareVarStmt('foo', new LiteralExpr(42), null, [StmtModifier.Static]);
|
||||||
|
const stmt2 = new DeclareVarStmt('bar', new LiteralExpr(true));
|
||||||
|
const stmt3 = new DeclareVarStmt('baz', new LiteralExpr('qux'), undefined, []);
|
||||||
|
|
||||||
|
expect(renderer.printStatement(stmt1, sourceFile, importManager)).toBe('var foo = 42;');
|
||||||
|
expect(renderer.printStatement(stmt2, sourceFile, importManager)).toBe('var bar = true;');
|
||||||
|
expect(renderer.printStatement(stmt3, sourceFile, importManager)).toBe('var baz = "qux";');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -119,7 +119,8 @@ runInEachFileSystem(() => {
|
||||||
}
|
}
|
||||||
const sf = getSourceFileOrError(program, _('/index.ts'));
|
const sf = getSourceFileOrError(program, _('/index.ts'));
|
||||||
const im = new ImportManager(new NoopImportRewriter(), 'i');
|
const im = new ImportManager(new NoopImportRewriter(), 'i');
|
||||||
const tsStatement = translateStatement(call, im, NOOP_DEFAULT_IMPORT_RECORDER);
|
const tsStatement =
|
||||||
|
translateStatement(call, im, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
|
||||||
const res = ts.createPrinter().printNode(ts.EmitHint.Unspecified, tsStatement, sf);
|
const res = ts.createPrinter().printNode(ts.EmitHint.Unspecified, tsStatement, sf);
|
||||||
return res.replace(/\s+/g, ' ');
|
return res.replace(/\s+/g, ' ');
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,9 @@ class IvyVisitor extends Visitor {
|
||||||
|
|
||||||
res.forEach(field => {
|
res.forEach(field => {
|
||||||
// Translate the initializer for the field into TS nodes.
|
// Translate the initializer for the field into TS nodes.
|
||||||
const exprNode =
|
const exprNode = translateExpression(
|
||||||
translateExpression(field.initializer, this.importManager, this.defaultImportRecorder);
|
field.initializer, this.importManager, this.defaultImportRecorder,
|
||||||
|
ts.ScriptTarget.ES2015);
|
||||||
|
|
||||||
// Create a static property declaration for the new field.
|
// Create a static property declaration for the new field.
|
||||||
const property = ts.createProperty(
|
const property = ts.createProperty(
|
||||||
|
@ -73,7 +74,9 @@ class IvyVisitor extends Visitor {
|
||||||
undefined, exprNode);
|
undefined, exprNode);
|
||||||
|
|
||||||
field.statements
|
field.statements
|
||||||
.map(stmt => translateStatement(stmt, this.importManager, this.defaultImportRecorder))
|
.map(
|
||||||
|
stmt => translateStatement(
|
||||||
|
stmt, this.importManager, this.defaultImportRecorder, ts.ScriptTarget.ES2015))
|
||||||
.forEach(stmt => statements.push(stmt));
|
.forEach(stmt => statements.push(stmt));
|
||||||
|
|
||||||
members.push(property);
|
members.push(property);
|
||||||
|
@ -218,7 +221,8 @@ function transformIvySourceFile(
|
||||||
// Generate the constant statements first, as they may involve adding additional imports
|
// Generate the constant statements first, as they may involve adding additional imports
|
||||||
// to the ImportManager.
|
// to the ImportManager.
|
||||||
const constants = constantPool.statements.map(
|
const constants = constantPool.statements.map(
|
||||||
stmt => translateStatement(stmt, importManager, defaultImportRecorder));
|
stmt =>
|
||||||
|
translateStatement(stmt, importManager, defaultImportRecorder, ts.ScriptTarget.ES2015));
|
||||||
|
|
||||||
// Preserve @fileoverview comments required by Closure, since the location might change as a
|
// Preserve @fileoverview comments required by Closure, since the location might change as a
|
||||||
// result of adding extra imports and constant pool statements.
|
// result of adding extra imports and constant pool statements.
|
||||||
|
|
|
@ -100,17 +100,19 @@ export class ImportManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function translateExpression(
|
export function translateExpression(
|
||||||
expression: Expression, imports: ImportManager,
|
expression: Expression, imports: ImportManager, defaultImportRecorder: DefaultImportRecorder,
|
||||||
defaultImportRecorder: DefaultImportRecorder): ts.Expression {
|
scriptTarget: Exclude<ts.ScriptTarget, ts.ScriptTarget.JSON>): ts.Expression {
|
||||||
return expression.visitExpression(
|
return expression.visitExpression(
|
||||||
new ExpressionTranslatorVisitor(imports, defaultImportRecorder), new Context(false));
|
new ExpressionTranslatorVisitor(imports, defaultImportRecorder, scriptTarget),
|
||||||
|
new Context(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function translateStatement(
|
export function translateStatement(
|
||||||
statement: Statement, imports: ImportManager,
|
statement: Statement, imports: ImportManager, defaultImportRecorder: DefaultImportRecorder,
|
||||||
defaultImportRecorder: DefaultImportRecorder): ts.Statement {
|
scriptTarget: Exclude<ts.ScriptTarget, ts.ScriptTarget.JSON>): ts.Statement {
|
||||||
return statement.visitStatement(
|
return statement.visitStatement(
|
||||||
new ExpressionTranslatorVisitor(imports, defaultImportRecorder), new Context(true));
|
new ExpressionTranslatorVisitor(imports, defaultImportRecorder, scriptTarget),
|
||||||
|
new Context(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function translateType(type: Type, imports: ImportManager): ts.TypeNode {
|
export function translateType(type: Type, imports: ImportManager): ts.TypeNode {
|
||||||
|
@ -120,10 +122,14 @@ export function translateType(type: Type, imports: ImportManager): ts.TypeNode {
|
||||||
class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor {
|
class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor {
|
||||||
private externalSourceFiles = new Map<string, ts.SourceMapSource>();
|
private externalSourceFiles = new Map<string, ts.SourceMapSource>();
|
||||||
constructor(
|
constructor(
|
||||||
private imports: ImportManager, private defaultImportRecorder: DefaultImportRecorder) {}
|
private imports: ImportManager, private defaultImportRecorder: DefaultImportRecorder,
|
||||||
|
private scriptTarget: Exclude<ts.ScriptTarget, ts.ScriptTarget.JSON>) {}
|
||||||
|
|
||||||
visitDeclareVarStmt(stmt: DeclareVarStmt, context: Context): ts.VariableStatement {
|
visitDeclareVarStmt(stmt: DeclareVarStmt, context: Context): ts.VariableStatement {
|
||||||
const nodeFlags = stmt.hasModifier(StmtModifier.Final) ? ts.NodeFlags.Const : ts.NodeFlags.None;
|
const nodeFlags =
|
||||||
|
((this.scriptTarget >= ts.ScriptTarget.ES2015) && stmt.hasModifier(StmtModifier.Final)) ?
|
||||||
|
ts.NodeFlags.Const :
|
||||||
|
ts.NodeFlags.None;
|
||||||
return ts.createVariableStatement(
|
return ts.createVariableStatement(
|
||||||
undefined, ts.createVariableDeclarationList(
|
undefined, ts.createVariableDeclarationList(
|
||||||
[ts.createVariableDeclaration(
|
[ts.createVariableDeclaration(
|
||||||
|
@ -149,6 +155,11 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
visitDeclareClassStmt(stmt: ClassStmt, context: Context) {
|
visitDeclareClassStmt(stmt: ClassStmt, context: Context) {
|
||||||
|
if (this.scriptTarget < ts.ScriptTarget.ES2015) {
|
||||||
|
throw new Error(
|
||||||
|
`Unsupported mode: Visiting a "declare class" statement (class ${stmt.name}) while ` +
|
||||||
|
`targeting ${ts.ScriptTarget[this.scriptTarget]}.`);
|
||||||
|
}
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +211,7 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor
|
||||||
const exprContext = context.withExpressionMode;
|
const exprContext = context.withExpressionMode;
|
||||||
const lhs = ts.createElementAccess(
|
const lhs = ts.createElementAccess(
|
||||||
expr.receiver.visitExpression(this, exprContext),
|
expr.receiver.visitExpression(this, exprContext),
|
||||||
expr.index.visitExpression(this, exprContext), );
|
expr.index.visitExpression(this, exprContext));
|
||||||
const rhs = expr.value.visitExpression(this, exprContext);
|
const rhs = expr.value.visitExpression(this, exprContext);
|
||||||
const result: ts.Expression = ts.createBinary(lhs, ts.SyntaxKind.EqualsToken, rhs);
|
const result: ts.Expression = ts.createBinary(lhs, ts.SyntaxKind.EqualsToken, rhs);
|
||||||
return context.isStatement ? result : ts.createParen(result);
|
return context.isStatement ? result : ts.createParen(result);
|
||||||
|
@ -252,6 +263,12 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLocalizedString(ast: LocalizedString, context: Context): ts.Expression {
|
visitLocalizedString(ast: LocalizedString, context: Context): ts.Expression {
|
||||||
|
if (this.scriptTarget < ts.ScriptTarget.ES2015) {
|
||||||
|
// This should never happen.
|
||||||
|
throw new Error(
|
||||||
|
'Unsupported mode: Visiting a localized string (which produces a tagged template ' +
|
||||||
|
`literal) ' while targeting ${ts.ScriptTarget[this.scriptTarget]}.`);
|
||||||
|
}
|
||||||
return visitLocalizedString(ast, context, this);
|
return visitLocalizedString(ast, context, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +535,8 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
visitTypeofExpr(ast: TypeofExpr, context: Context): ts.TypeQueryNode {
|
visitTypeofExpr(ast: TypeofExpr, context: Context): ts.TypeQueryNode {
|
||||||
let expr = translateExpression(ast.expr, this.imports, NOOP_DEFAULT_IMPORT_RECORDER);
|
let expr = translateExpression(
|
||||||
|
ast.expr, this.imports, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
|
||||||
return ts.createTypeQueryNode(expr as ts.Identifier);
|
return ts.createTypeQueryNode(expr as ts.Identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,8 @@ export class Environment {
|
||||||
const ngExpr = this.refEmitter.emit(ref, this.contextFile);
|
const ngExpr = this.refEmitter.emit(ref, this.contextFile);
|
||||||
|
|
||||||
// Use `translateExpression` to convert the `Expression` into a `ts.Expression`.
|
// Use `translateExpression` to convert the `Expression` into a `ts.Expression`.
|
||||||
return translateExpression(ngExpr, this.importManager, NOOP_DEFAULT_IMPORT_RECORDER);
|
return translateExpression(
|
||||||
|
ngExpr, this.importManager, NOOP_DEFAULT_IMPORT_RECORDER, ts.ScriptTarget.ES2015);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue