diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index 5a14f1cd5f860..58bbdff8e5203 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -344,10 +344,18 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N return superDeclaration; } - /** Gets all decorators of the given class symbol. */ + /** + * Gets all decorators of the given class symbol. Any decorator that have been synthetically + * injected by a migration will not be present in the returned collection. + */ getDecoratorsOfSymbol(symbol: NgccClassSymbol): Decorator[]|null { const {classDecorators} = this.acquireDecoratorInfo(symbol); - return classDecorators; + if (classDecorators === null) { + return null; + } + + // Return a clone of the array to prevent consumers from mutating the cache. + return Array.from(classDecorators); } /** diff --git a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts index d85f29e9beec7..c29afece754e9 100644 --- a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts @@ -1931,6 +1931,20 @@ runInEachFileSystem(() => { expect(classDecoratorsSecondary.length).toEqual(1); expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); }); + + it('should return a cloned array on each invocation', () => { + loadTestFiles(DECORATED_FILES); + const {program} = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); + const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker()); + const classDecl = + getDeclaration(program, DECORATED_FILES[0].name, 'A', ts.isClassDeclaration) !; + const classSymbol = host.getClassSymbol(classDecl) !; + + const firstResult = host.getDecoratorsOfSymbol(classSymbol); + const secondResult = host.getDecoratorsOfSymbol(classSymbol); + + expect(firstResult).not.toBe(secondResult); + }); }); describe('getDtsDeclarationsOfClass()', () => {