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:

committed by
Kara Erickson

parent
21bd8c9a2e
commit
06e36e5972
@ -5,8 +5,11 @@
|
||||
* 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 {Statement} from '@angular/compiler';
|
||||
import MagicString from 'magic-string';
|
||||
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 {getIifeBody} from '../host/esm5_host';
|
||||
import {EsmRenderingFormatter} from './esm_rendering_formatter';
|
||||
@ -35,4 +38,22 @@ export class Esm5RenderingFormatter extends EsmRenderingFormatter {
|
||||
const insertionPoint = returnStatement.getFullStart();
|
||||
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
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {Statement} from '@angular/compiler';
|
||||
import MagicString from 'magic-string';
|
||||
import * as ts from 'typescript';
|
||||
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 {CompiledClass} from '../analysis/types';
|
||||
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 {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
||||
import {stripExtension} from './utils';
|
||||
import {Reexport} from '../../../src/ngtsc/imports';
|
||||
import {isAssignment} from '../host/esm2015_host';
|
||||
|
||||
/**
|
||||
* A RenderingFormatter that works with ECMAScript Module import and export statements.
|
||||
*/
|
||||
export class EsmRenderingFormatter implements RenderingFormatter {
|
||||
protected printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
|
||||
|
||||
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 {
|
||||
for (const stmt of sf.statements) {
|
||||
if (!ts.isImportDeclaration(stmt) && !ts.isImportEqualsDeclaration(stmt) &&
|
||||
|
@ -8,19 +8,18 @@
|
||||
import {ConstantPool, Expression, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler';
|
||||
import MagicString from 'magic-string';
|
||||
import * as ts from 'typescript';
|
||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../../src/ngtsc/imports';
|
||||
import {translateStatement, ImportManager} from '../../../src/ngtsc/translator';
|
||||
import {ImportManager} from '../../../src/ngtsc/translator';
|
||||
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/types';
|
||||
import {PrivateDeclarationsAnalyses} from '../analysis/private_declarations_analyzer';
|
||||
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
|
||||
import {IMPORT_PREFIX} from '../constants';
|
||||
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 {FileToWrite, getImportRewriter, stripExtension} from './utils';
|
||||
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
||||
import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter';
|
||||
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`.
|
||||
@ -98,7 +97,8 @@ export class Renderer {
|
||||
|
||||
this.srcFormatter.addConstants(
|
||||
outputText,
|
||||
renderConstantPool(compiledFile.sourceFile, compiledFile.constantPool, importManager),
|
||||
renderConstantPool(
|
||||
this.srcFormatter, compiledFile.sourceFile, compiledFile.constantPool, importManager),
|
||||
compiledFile.sourceFile);
|
||||
}
|
||||
|
||||
@ -185,12 +185,9 @@ export class Renderer {
|
||||
|
||||
private renderStatements(
|
||||
sourceFile: ts.SourceFile, statements: Statement[], imports: ImportManager): string {
|
||||
const printer = createPrinter();
|
||||
const translate = (stmt: Statement) =>
|
||||
translateStatement(stmt, imports, NOOP_DEFAULT_IMPORT_RECORDER);
|
||||
const print = (stmt: Statement) =>
|
||||
printer.printNode(ts.EmitHint.Unspecified, translate(stmt), sourceFile);
|
||||
return statements.map(print).join('\n');
|
||||
const printStatement = (stmt: Statement) =>
|
||||
this.srcFormatter.printStatement(stmt, sourceFile, imports);
|
||||
return statements.map(printStatement).join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,12 +195,10 @@ export class Renderer {
|
||||
* Render the constant pool as source code for the given class.
|
||||
*/
|
||||
export function renderConstantPool(
|
||||
sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: ImportManager): string {
|
||||
const printer = createPrinter();
|
||||
return constantPool.statements
|
||||
.map(stmt => translateStatement(stmt, imports, NOOP_DEFAULT_IMPORT_RECORDER))
|
||||
.map(stmt => printer.printNode(ts.EmitHint.Unspecified, stmt, sourceFile))
|
||||
.join('\n');
|
||||
formatter: RenderingFormatter, sourceFile: ts.SourceFile, constantPool: ConstantPool,
|
||||
imports: ImportManager): string {
|
||||
const printStatement = (stmt: Statement) => formatter.printStatement(stmt, sourceFile, imports);
|
||||
return constantPool.statements.map(printStatement).join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,7 +211,3 @@ function createAssignmentStatement(
|
||||
const receiver = new WrappedNodeExpr(receiverName);
|
||||
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
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {Statement} from '@angular/compiler';
|
||||
import MagicString from 'magic-string';
|
||||
import * as ts from 'typescript';
|
||||
import {Reexport} from '../../../src/ngtsc/imports';
|
||||
@ -45,4 +46,5 @@ export interface RenderingFormatter {
|
||||
addModuleWithProvidersParams(
|
||||
outputText: MagicString, moduleWithProviders: ModuleWithProvidersInfo[],
|
||||
importManager: ImportManager): void;
|
||||
printStatement(stmt: Statement, sourceFile: ts.SourceFile, importManager: ImportManager): string;
|
||||
}
|
||||
|
Reference in New Issue
Block a user