angular-cn/packages/compiler-cli/linker/babel/test/es2015_linker_plugin_spec.ts

336 lines
15 KiB
TypeScript
Raw Normal View History

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* 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 * as o from '@angular/compiler/src/output/output_ast';
import {NodePath, PluginObj, transformSync} from '@babel/core';
import generate from '@babel/generator';
import * as t from '@babel/types';
import {FileLinker} from '../../../linker';
import {MockFileSystemNative} from '../../../src/ngtsc/file_system/testing';
import {MockLogger} from '../../../src/ngtsc/logging/testing';
import {PartialDirectiveLinkerVersion1} from '../../src/file_linker/partial_linkers/partial_directive_linker_1';
import {createEs2015LinkerPlugin} from '../src/es2015_linker_plugin';
describe('createEs2015LinkerPlugin()', () => {
it('should return a Babel plugin visitor that handles Program (enter/exit) and CallExpression nodes',
() => {
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
expect(plugin.visitor).toEqual({
Program: {
enter: jasmine.any(Function),
exit: jasmine.any(Function),
},
CallExpression: jasmine.any(Function),
});
});
it('should return a Babel plugin that calls FileLinker.isPartialDeclaration() on each call expression',
() => {
const isPartialDeclarationSpy = spyOn(FileLinker.prototype, 'isPartialDeclaration');
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
transformSync(
[
'var core;', `fn1()`, 'fn2({prop: () => fn3({})});', `x.method(() => fn4());`,
'spread(...x);'
].join('\n'),
{
plugins: [plugin],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
});
expect(isPartialDeclarationSpy.calls.allArgs()).toEqual([
['fn1'],
['fn2'],
['fn3'],
['method'],
['fn4'],
['spread'],
]);
});
it('should return a Babel plugin that calls FileLinker.linkPartialDeclaration() on each matching declaration',
() => {
const linkSpy = spyOn(FileLinker.prototype, 'linkPartialDeclaration')
.and.returnValue(t.identifier('REPLACEMENT'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
transformSync(
[
'var core;',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 1});`,
`i0.ɵɵngDeclareComponent({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, foo: () => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 2})});`,
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`x.qux(() => ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 3}));`,
'spread(...x);',
`i0['ɵɵngDeclareDirective']({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core, x: 4});`,
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
});
expect(humanizeLinkerCalls(linkSpy.calls)).toEqual([
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
[
'ɵɵngDeclareDirective',
'{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:1}'
],
[
'ɵɵngDeclareComponent',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
'{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,foo:()=>ɵɵngDeclareDirective({minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:2})}'
],
// Note we do not process `x:2` declaration since it is nested within another declaration
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
[
'ɵɵngDeclareDirective',
'{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:3}'
],
[
'ɵɵngDeclareDirective',
'{minVersion:\'0.0.0-PLACEHOLDER\',version:\'0.0.0-PLACEHOLDER\',ngImport:core,x:4}'
],
]);
});
it('should return a Babel plugin that replaces call expressions with the return value from FileLinker.linkPartialDeclaration()',
() => {
let replaceCount = 0;
spyOn(FileLinker.prototype, 'linkPartialDeclaration')
.and.callFake(() => t.identifier('REPLACEMENT_' + ++replaceCount));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'var core;',
'ɵɵngDeclareDirective({version: \'0.0.0-PLACEHOLDER\', ngImport: core});',
'ɵɵngDeclareDirective({version: \'0.0.0-PLACEHOLDER\', ngImport: core, foo: () => bar({})});',
'x.qux();',
'spread(...x);',
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
generatorOpts: {compact: true},
});
expect(result!.code).toEqual('var core;REPLACEMENT_1;REPLACEMENT_2;x.qux();spread(...x);');
});
it('should return a Babel plugin that adds shared statements after any imports', () => {
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'import * as core from \'some-module\';',
'import {id} from \'other-module\';',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
generatorOpts: {compact: true},
});
expect(result!.code)
.toEqual(
'import*as core from\'some-module\';import{id}from\'other-module\';const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";');
});
it('should return a Babel plugin that adds shared statements at the start of the program if it is an ECMAScript Module and there are no imports',
() => {
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'var core;',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
// We declare the file as a module because this cannot be inferred from the source
parserOpts: {sourceType: 'module'},
generatorOpts: {compact: true},
});
expect(result!.code)
.toEqual(
'const _c0=[1];const _c1=[2];const _c2=[3];var core;"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";');
});
it('should return a Babel plugin that adds shared statements at the start of the function body if the ngImport is from a function parameter',
() => {
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'function run(core) {',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
'}'
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
generatorOpts: {compact: true},
});
expect(result!.code)
.toEqual(
'function run(core){const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";}');
});
it('should return a Babel plugin that adds shared statements into an IIFE if no scope could not be derived for the ngImport',
() => {
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'function run() {',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
` ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
'}',
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
filename: '/test.js',
parserOpts: {sourceType: 'unambiguous'},
generatorOpts: {compact: true},
});
expect(result!.code).toEqual([
`function run(){`,
`(function(){const _c0=[1];return"REPLACEMENT";})();`,
`(function(){const _c0=[2];return"REPLACEMENT";})();`,
`(function(){const _c0=[3];return"REPLACEMENT";})();`,
`}`,
].join(''));
});
it('should still execute other plugins that match AST nodes inside the result of the replacement',
() => {
spyOnLinkPartialDeclarationWithConstants(o.fn([], [], null, null, 'FOO'));
const fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core}); FOO;`,
].join('\n'),
{
plugins: [
createEs2015LinkerPlugin({fileSystem, logger}),
createIdentifierMapperPlugin('FOO', 'BAR'),
createIdentifierMapperPlugin('_c0', 'x1'),
],
filename: '/test.js',
parserOpts: {sourceType: 'module'},
generatorOpts: {compact: true},
});
expect(result!.code).toEqual([
`(function(){const x1=[1];return function BAR(){};})();BAR;`,
].join(''));
});
it('should not process call expressions within inserted functions', () => {
spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration')
.and.callFake((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 fileSystem = new MockFileSystemNative();
const logger = new MockLogger();
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
const result = transformSync(
[
'import * as core from \'some-module\';',
refactor(compiler-cli): change how partial-linkers are matched to declaration versions (#41578) Previously, it was not possible to block a partial-linker from trying to process a declaration that was defined in a newer version of Angular than that of the partial-linker. For example, if a partial-linker was published as part of version 12.0.0, there was no way for a partially-compiled declaration compiled via version 13.0.0 to tell the 12.0.0 linker that it would be invalid to attempt to process it. This commit adds a new `minVersion` property to partial-declarations, which is interpreted as the "minimum partial-linker version" that can process this declaration. When selecting a partial-linker for such a declaration, the known linker version ranges are checked to find the most recent linker whose version range has an overlap with the interpreted declaration range. This approach allows us to set a minimum version for a declaration, which can inform an old partial-linker that will it not be able to accurately process the declaration. Note that any pre-release part to versions are ignored in this selection process. The file-linker can be configured, via the `unknownDeclarationVersionHandling` property of `LinkerOptions`, to handle such a situation in one of three ways: - `error` - the version mismatch is a fatal error - `warn` - a warning is sent to the logger but the most recent partial-linker will attempt to process the declaration anyway. - `ignore` - the most recent partial-linker will, silently, attempt to process the declaration. The default is to throw an error. Closes #41497 PR Close #41578
2021-04-12 07:30:20 -04:00
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
].join('\n'),
{
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
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']]);
});
});
/**
* Convert the arguments of the spied-on `calls` into a human readable array.
*/
function humanizeLinkerCalls(
calls: jasmine.Calls<typeof FileLinker.prototype.linkPartialDeclaration>) {
return calls.all().map(({args: [fn, args]}) => [fn, generate(args[0], {compact: true}).code]);
}
/**
* Spy on the `PartialDirectiveLinkerVersion1.linkPartialDeclaration()` method, triggering
* shared constants to be created.
*/
function spyOnLinkPartialDeclarationWithConstants(replacement: o.Expression) {
let callCount = 0;
spyOn(PartialDirectiveLinkerVersion1.prototype, 'linkPartialDeclaration')
.and.callFake((constantPool => {
const constArray = o.literalArr([o.literal(++callCount)]);
// We have to add the constant twice or it will not create a shared statement
constantPool.getConstLiteral(constArray);
constantPool.getConstLiteral(constArray);
return replacement;
}) as typeof PartialDirectiveLinkerVersion1.prototype.linkPartialDeclaration);
}
/**
* A simple Babel plugin that will replace all identifiers that match `<src>` with identifiers
* called `<dest>`.
*/
function createIdentifierMapperPlugin(src: string, dest: string): PluginObj {
return {
visitor: {
Identifier(path: NodePath<t.Identifier>) {
if (path.node.name === src) {
path.replaceWith(t.identifier(dest));
}
}
},
};
}