fix(ivy): use a single constant pool per source file (#25392)
Previously, ngtsc used a new ConstantPool for each decorator compilation. This could result in collisions between constants in the top-level scope. Now, ngtsc uses a single ConstantPool for each source file being compiled, and merges the constant statements into the file after the import section. PR Close #25392
This commit is contained in:

committed by
Ben Lesh

parent
9c92a6fc7a
commit
fba276d3d1
@ -56,6 +56,36 @@ A.decorators = [
|
||||
});
|
||||
|
||||
|
||||
describe('addConstants', () => {
|
||||
it('should insert the given constants after imports in the source file', () => {
|
||||
const PROGRAM = {
|
||||
name: 'some/file.js',
|
||||
contents: `
|
||||
/* A copyright notice */
|
||||
import {Directive} from '@angular/core';
|
||||
export class A {}
|
||||
A.decorators = [
|
||||
{ type: Directive, args: [{ selector: '[a]' }] },
|
||||
{ type: Other }
|
||||
];
|
||||
// Some other content`
|
||||
};
|
||||
const {renderer, program} = setup(PROGRAM);
|
||||
const file = program.getSourceFile('some/file.js');
|
||||
if (file === undefined) {
|
||||
throw new Error(`Could not find source file`);
|
||||
}
|
||||
const output = new MagicString(PROGRAM.contents);
|
||||
renderer.addConstants(output, 'const x = 3;', file);
|
||||
expect(output.toString()).toContain(`
|
||||
import {Directive} from '@angular/core';
|
||||
const x = 3;
|
||||
|
||||
export class A {}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('addDefinitions', () => {
|
||||
it('should insert the definitions directly after the class declaration', () => {
|
||||
const PROGRAM = {
|
||||
|
@ -20,6 +20,9 @@ class TestRenderer extends Renderer {
|
||||
addImports(output: MagicString, imports: {name: string, as: string}[]) {
|
||||
output.prepend('\n// ADD IMPORTS\n');
|
||||
}
|
||||
addConstants(output: MagicString, constants: string, file: ts.SourceFile): void {
|
||||
output.prepend('\n// ADD CONSTANTS\n');
|
||||
}
|
||||
addDefinitions(output: MagicString, analyzedClass: AnalyzedClass, definitions: string) {
|
||||
output.prepend('\n// ADD DEFINITIONS\n');
|
||||
}
|
||||
@ -65,7 +68,8 @@ describe('Renderer', () => {
|
||||
]
|
||||
});
|
||||
const RENDERED_CONTENTS =
|
||||
`\n// REMOVE DECORATORS\n\n// ADD IMPORTS\n\n// ADD DEFINITIONS\n` + INPUT_PROGRAM.contents;
|
||||
`\n// REMOVE DECORATORS\n\n// ADD IMPORTS\n\n// ADD CONSTANTS\n\n// ADD DEFINITIONS\n` +
|
||||
INPUT_PROGRAM.contents;
|
||||
const OUTPUT_PROGRAM_MAP = fromObject({
|
||||
'version': 3,
|
||||
'file': '/output_file.js',
|
||||
@ -74,14 +78,14 @@ describe('Renderer', () => {
|
||||
'import { Directive } from \'@angular/core\';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: \'[a]\' }] }\n];\n'
|
||||
],
|
||||
'names': [],
|
||||
'mappings': ';;;;;;AAAA;;;;;;;;;'
|
||||
'mappings': ';;;;;;;;AAAA;;;;;;;;;'
|
||||
});
|
||||
|
||||
const MERGED_OUTPUT_PROGRAM_MAP = fromObject({
|
||||
'version': 3,
|
||||
'sources': ['/file.ts'],
|
||||
'names': [],
|
||||
'mappings': ';;;;;;AAAA',
|
||||
'mappings': ';;;;;;;;AAAA',
|
||||
'file': '/output_file.js',
|
||||
'sourcesContent': [
|
||||
'import { Directive } from \'@angular/core\';\nexport class A {\n foo(x: string): string {\n return x;\n }\n static decorators = [\n { type: Directive, args: [{ selector: \'[a]\' }] }\n ];\n}'
|
||||
|
Reference in New Issue
Block a user