refactor(compiler-cli): allow visiting call expressions without an active linker (#39707)
The compilation result of components may have inserted template functions into the constant pool, which would be inserted into the Babel AST upon program exit. Babel will then proceed with visiting this newly inserted subtree, but we have already cleaned up the linker instance when exiting the program. Any call expressions within the template functions would then fail to be processed, as a file linker would no longer be available. Since the inserted AST subtree is known not to contain yet more partial declarations, it is safe to skip visiting call expressions when no file linker is available. PR Close #39707
This commit is contained in:
parent
8348556b77
commit
e79ce386fc
|
@ -58,9 +58,14 @@ export function createEs2015LinkerPlugin(options: Partial<LinkerOptions> = {}):
|
|||
* with the results of linking the declaration.
|
||||
*/
|
||||
CallExpression(call: NodePath<t.CallExpression>): 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;
|
||||
|
|
|
@ -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']]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue