diff --git a/packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts b/packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts index 578641c36a..9bb8165a11 100644 --- a/packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts +++ b/packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts @@ -10,8 +10,7 @@ import MagicString from 'magic-string'; import * as ts from 'typescript'; import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {CompiledClass} from '../analysis/decoration_analyzer'; -import {ExportInfo} from '../analysis/private_declarations_analyzer'; -import {Renderer, stripExtension} from './renderer'; +import {RedundantDecoratorMap, Renderer, stripExtension} from './renderer'; import {EntryPointBundle} from '../packages/entry_point_bundle'; export class EsmRenderer extends Renderer { @@ -71,7 +70,7 @@ export class EsmRenderer extends Renderer { /** * Remove static decorator properties from classes */ - removeDecorators(output: MagicString, decoratorsToRemove: Map): void { + removeDecorators(output: MagicString, decoratorsToRemove: RedundantDecoratorMap): void { decoratorsToRemove.forEach((nodesToRemove, containerNode) => { if (ts.isArrayLiteralExpression(containerNode)) { const items = containerNode.elements; diff --git a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts index 71e851d44f..26bb1ebfa8 100644 --- a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts +++ b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts @@ -49,6 +49,14 @@ interface DtsClassInfo { compilation: CompileResult[]; } +/** + * The collected decorators that have become redundant after the compilation + * of Ivy static fields. The map is keyed by the container node, such that we + * can tell if we should remove the entire decorator property + */ +export type RedundantDecoratorMap = Map; +export const RedundantDecoratorMap = Map; + /** * A base-class for rendering an `AnalyzedFile`. * @@ -113,12 +121,15 @@ export abstract class Renderer { if (compiledFile) { const importManager = new NgccImportManager(this.bundle.isFlat, this.isCore, IMPORT_PREFIX); - const decoratorsToRemove = new Map(); + + // TODO: remove constructor param metadata and property decorators (we need info from the + // handlers to do this) + const decoratorsToRemove = this.computeDecoratorsToRemove(compiledFile.compiledClasses); + this.removeDecorators(outputText, decoratorsToRemove); compiledFile.compiledClasses.forEach(clazz => { const renderedDefinition = renderDefinitions(compiledFile.sourceFile, clazz, importManager); this.addDefinitions(outputText, clazz, renderedDefinition); - this.trackDecorators(clazz.decorators, decoratorsToRemove); }); this.addConstants( @@ -129,10 +140,6 @@ export abstract class Renderer { this.addImports( outputText, importManager.getAllImports( compiledFile.sourceFile.fileName, this.bundle.src.r3SymbolsFile)); - - // TODO: remove constructor param metadata and property decorators (we need info from the - // handlers to do this) - this.removeDecorators(outputText, decoratorsToRemove); } // Add exports to the entry-point file @@ -190,25 +197,31 @@ export abstract class Renderer { protected abstract addDefinitions( output: MagicString, compiledClass: CompiledClass, definitions: string): void; protected abstract removeDecorators( - output: MagicString, decoratorsToRemove: Map): void; + output: MagicString, decoratorsToRemove: RedundantDecoratorMap): void; protected abstract rewriteSwitchableDeclarations( outputText: MagicString, sourceFile: ts.SourceFile, declarations: SwitchableVariableDeclaration[]): void; /** - * Add the decorator nodes that are to be removed to a map - * So that we can tell if we should remove the entire decorator property + * From the given list of classes, computes a map of decorators that should be removed. + * The decorators to remove are keyed by their container node, such that we can tell if + * we should remove the entire decorator property. + * @param classes The list of classes that may have decorators to remove. + * @returns A map of decorators to remove, keyed by their container node. */ - protected trackDecorators(decorators: Decorator[], decoratorsToRemove: Map): - void { - decorators.forEach(dec => { - const decoratorArray = dec.node.parent !; - if (!decoratorsToRemove.has(decoratorArray)) { - decoratorsToRemove.set(decoratorArray, [dec.node]); - } else { - decoratorsToRemove.get(decoratorArray) !.push(dec.node); - } + protected computeDecoratorsToRemove(classes: CompiledClass[]): RedundantDecoratorMap { + const decoratorsToRemove = new RedundantDecoratorMap(); + classes.forEach(clazz => { + clazz.decorators.forEach(dec => { + const decoratorArray = dec.node.parent !; + if (!decoratorsToRemove.has(decoratorArray)) { + decoratorsToRemove.set(decoratorArray, [dec.node]); + } else { + decoratorsToRemove.get(decoratorArray) !.push(dec.node); + } + }); }); + return decoratorsToRemove; } /** diff --git a/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts index 24e8db34ac..2642653f62 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts @@ -315,10 +315,12 @@ SOME DEFINITION TEXT const decoratorsToRemove = new Map(); decoratorsToRemove.set(decorator.node.parent !, [decorator.node]); renderer.removeDecorators(output, decoratorsToRemove); + renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); expect(output.toString()).toContain(`{ type: OtherA }`); expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[b]' }] }`); expect(output.toString()).toContain(`{ type: OtherB }`); + expect(output.toString()).toContain(`function C() {}\nSOME DEFINITION TEXT\n return C;`); expect(output.toString()).not.toContain(`C.decorators = [ { type: Directive, args: [{ selector: '[c]' }] }, ];`); diff --git a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts index c00b85bef3..af391eff71 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts @@ -14,7 +14,7 @@ import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registr import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; -import {Renderer} from '../../src/rendering/renderer'; +import {RedundantDecoratorMap, Renderer} from '../../src/rendering/renderer'; import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; import {makeTestEntryPointBundle} from '../helpers/utils'; @@ -37,7 +37,7 @@ class TestRenderer extends Renderer { addDefinitions(output: MagicString, compiledClass: CompiledClass, definitions: string) { output.prepend('\n// ADD DEFINITIONS\n'); } - removeDecorators(output: MagicString, decoratorsToRemove: Map) { + removeDecorators(output: MagicString, decoratorsToRemove: RedundantDecoratorMap) { output.prepend('\n// REMOVE DECORATORS\n'); } rewriteSwitchableDeclarations(output: MagicString, sourceFile: ts.SourceFile): void { @@ -97,7 +97,7 @@ describe('Renderer', () => { }); const RENDERED_CONTENTS = - `\n// ADD EXPORTS\n\n// REMOVE DECORATORS\n\n// ADD IMPORTS\n\n// ADD CONSTANTS\n\n// ADD DEFINITIONS\n` + + `\n// ADD EXPORTS\n\n// ADD IMPORTS\n\n// ADD CONSTANTS\n\n// ADD DEFINITIONS\n\n// REMOVE DECORATORS\n` + INPUT_PROGRAM.contents; const OUTPUT_PROGRAM_MAP = fromObject({