diff --git a/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts b/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts index b13be8e407..0ebe7b5db5 100644 --- a/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts +++ b/packages/compiler-cli/linker/babel/src/es2015_linker_plugin.ts @@ -58,9 +58,14 @@ export function createEs2015LinkerPlugin(options: Partial = {}): * with the results of linking the declaration. */ CallExpression(call: NodePath): void { - try { - assertNotNull(fileLinker); + if (fileLinker === null) { + // Any statements that are inserted upon program exit will be visited outside of an active + // linker context. These call expressions are known not to contain partial declarations, + // so it's safe to skip visiting those call expressions. + return; + } + try { const callee = call.node.callee; if (!t.isExpression(callee)) { return; 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 556010a192..da4b2bc8b8 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 @@ -213,6 +213,41 @@ describe('createEs2015LinkerPlugin()', () => { `(function(){const x1=[1];return function BAR(){};})();BAR;`, ].join('')); }); + + it('should not process call expressions within inserted functions', () => { + spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration') + .and.callFake(((sourceUrl, code, 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 o.literal('REPLACEMENT'); + }) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration); + + const isPartialDeclarationSpy = + spyOn(FileLinker.prototype, 'isPartialDeclaration').and.callThrough(); + + const result = transformSync( + [ + 'import * as core from \'some-module\';', + `ɵɵngDeclareDirective({version: 1, ngImport: core})`, + ].join('\n'), + { + plugins: [createEs2015LinkerPlugin()], + 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']]); + }); }); /**