fix(compiler): reexport less symbols in .ngfactory.ts
files (#19884)
* don't reexport symbols that the user already reexported * never reexport symbols that are part of arguments of non simple function calls Fixes #19883 PR Close #19884
This commit is contained in:

committed by
Matias Niemelä

parent
fd37f3fbab
commit
e3a16ed02d
@ -491,10 +491,11 @@ describe('compiler (unbundled Angular)', () => {
|
||||
const libInput: MockDirectory = {
|
||||
'lib': {
|
||||
'base.ts': `
|
||||
export class AValue {}
|
||||
export type AType = {};
|
||||
|
||||
export class AClass {
|
||||
constructor(a: AType) {}
|
||||
constructor(a: AType, b: AValue) {}
|
||||
}
|
||||
`
|
||||
}
|
||||
@ -502,7 +503,7 @@ describe('compiler (unbundled Angular)', () => {
|
||||
const appInput: MockDirectory = {
|
||||
'app': {
|
||||
'main.ts': `
|
||||
export * from '../lib/base';
|
||||
export {AClass} from '../lib/base';
|
||||
`
|
||||
}
|
||||
};
|
||||
@ -511,7 +512,105 @@ describe('compiler (unbundled Angular)', () => {
|
||||
const {genFiles: appGenFiles} =
|
||||
compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true});
|
||||
const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts');
|
||||
expect(toTypeScript(appNgFactory)).not.toContain('AType');
|
||||
const appNgFactoryTs = toTypeScript(appNgFactory);
|
||||
expect(appNgFactoryTs).not.toContain('AType');
|
||||
expect(appNgFactoryTs).toContain('AValue');
|
||||
});
|
||||
|
||||
it('should not reexport complex function calls', () => {
|
||||
const libInput: MockDirectory = {
|
||||
'lib': {
|
||||
'base.ts': `
|
||||
export class AClass {
|
||||
constructor(arg: any) {}
|
||||
|
||||
static create(arg: any = null): AClass { return new AClass(arg); }
|
||||
|
||||
call(arg: any) {}
|
||||
}
|
||||
|
||||
export function simple(arg: any) { return [arg]; }
|
||||
|
||||
export const ctor_arg = {};
|
||||
export const ctor_call = new AClass(ctor_arg);
|
||||
|
||||
export const static_arg = {};
|
||||
export const static_call = AClass.create(static_arg);
|
||||
|
||||
export const complex_arg = {};
|
||||
export const complex_call = AClass.create().call(complex_arg);
|
||||
|
||||
export const simple_arg = {};
|
||||
export const simple_call = simple(simple_arg);
|
||||
`
|
||||
}
|
||||
};
|
||||
const appInput: MockDirectory = {
|
||||
'app': {
|
||||
'main.ts': `
|
||||
import {ctor_call, static_call, complex_call, simple_call} from '../lib/base';
|
||||
|
||||
export const calls = [ctor_call, static_call, complex_call, simple_call];
|
||||
`,
|
||||
}
|
||||
};
|
||||
|
||||
const {outDir: libOutDir} = compile([libInput, angularSummaryFiles], {useSummaries: true});
|
||||
const {genFiles: appGenFiles} =
|
||||
compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true});
|
||||
const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts');
|
||||
const appNgFactoryTs = toTypeScript(appNgFactory);
|
||||
|
||||
// metadata of ctor calls is preserved, so we reexport the argument
|
||||
expect(appNgFactoryTs).toContain('ctor_arg');
|
||||
expect(appNgFactoryTs).toContain('ctor_call');
|
||||
|
||||
// metadata of static calls is preserved, so we reexport the argument
|
||||
expect(appNgFactoryTs).toContain('static_arg');
|
||||
expect(appNgFactoryTs).toContain('AClass');
|
||||
expect(appNgFactoryTs).toContain('static_call');
|
||||
|
||||
// metadata of complex calls is elided, so we don't reexport the argument
|
||||
expect(appNgFactoryTs).not.toContain('complex_arg');
|
||||
expect(appNgFactoryTs).toContain('complex_call');
|
||||
|
||||
// metadata of simple calls is preserved, so we reexport the argument
|
||||
expect(appNgFactoryTs).toContain('simple_arg');
|
||||
expect(appNgFactoryTs).toContain('simple_call');
|
||||
});
|
||||
|
||||
it('should not reexport already exported symbols except for lowered symbols', () => {
|
||||
const libInput: MockDirectory = {
|
||||
'lib': {
|
||||
'base.ts': `
|
||||
export const exportedVar = 1;
|
||||
|
||||
// A symbol introduced by lowering expressions
|
||||
export const ɵ1 = 'lowered symbol';
|
||||
`
|
||||
}
|
||||
};
|
||||
const appInput: MockDirectory = {
|
||||
'app': {
|
||||
'main.ts': `export * from '../lib/base';`,
|
||||
}
|
||||
};
|
||||
|
||||
const {outDir: libOutDir} = compile([libInput, angularSummaryFiles], {useSummaries: true});
|
||||
const {genFiles: appGenFiles} =
|
||||
compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true});
|
||||
const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts');
|
||||
const appNgFactoryTs = toTypeScript(appNgFactory);
|
||||
|
||||
// we don't need to reexport exported symbols via the .ngfactory
|
||||
// as we can refer to them via the reexport.
|
||||
expect(appNgFactoryTs).not.toContain('exportedVar');
|
||||
|
||||
// although ɵ1 is reexported via `export *`, we still need to reexport it
|
||||
// via the .ngfactory as tsickle expands `export *` into named exports,
|
||||
// and doesn't know about our lowered symbols as we introduce them
|
||||
// after the typecheck phase.
|
||||
expect(appNgFactoryTs).toContain('ɵ1');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -317,37 +317,96 @@ export function main() {
|
||||
expect(summaries[1].metadata).toBe('someString');
|
||||
});
|
||||
|
||||
it('should not create "importAs" names for reexported types in libraries', () => {
|
||||
it('should not create "importAs" names for ctor arguments which are types of reexported classes in libraries',
|
||||
() => {
|
||||
init();
|
||||
const externalSerialized = serializeSummaries(
|
||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver,
|
||||
[
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'type'),
|
||||
metadata: {__symbolic: 'interface'}
|
||||
},
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'value'),
|
||||
metadata: {__symbolic: 'class'}
|
||||
},
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'reexportClass'),
|
||||
metadata: {
|
||||
__symbolic: 'class',
|
||||
'members': {
|
||||
'__ctor__': [{
|
||||
'__symbolic': 'constructor',
|
||||
'parameters': [
|
||||
symbolCache.get('/tmp/external.ts', 'type'),
|
||||
symbolCache.get('/tmp/external.ts', 'value'),
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
],
|
||||
[]);
|
||||
expect(externalSerialized.exportAs).toEqual([]);
|
||||
init({
|
||||
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||
});
|
||||
const serialized = serializeSummaries(
|
||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
|
||||
symbol: symbolCache.get('/tmp/test.ts', 'mainClass'),
|
||||
metadata: symbolCache.get('/tmp/external.d.ts', 'reexportClass'),
|
||||
}],
|
||||
[]);
|
||||
const importAs =
|
||||
deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json)
|
||||
.importAs;
|
||||
expect(importAs).toEqual([
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.d.ts', 'reexportClass'),
|
||||
importAs: symbolCache.get('/tmp/test.d.ts', 'mainClass'),
|
||||
},
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.d.ts', 'value'),
|
||||
importAs: symbolCache.get('someFile.ngfactory.d.ts', 'value_3'),
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should use existing reexports for "importAs" for symbols of libraries', () => {
|
||||
init();
|
||||
const externalSerialized = serializeSummaries(
|
||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver,
|
||||
[
|
||||
{symbol: symbolCache.get('/tmp/external.ts', 'value'), metadata: 'aValue'},
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'type'),
|
||||
metadata: {__symbolic: 'interface'}
|
||||
},
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'reexportType'),
|
||||
metadata: symbolCache.get('/tmp/external.ts', 'type')
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'reexportValue'),
|
||||
metadata: symbolCache.get('/tmp/external.ts', 'value')
|
||||
},
|
||||
],
|
||||
[]);
|
||||
expect(externalSerialized.exportAs).toEqual([]);
|
||||
init({
|
||||
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||
});
|
||||
const serialized = serializeSummaries(
|
||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
|
||||
symbol: symbolCache.get('/tmp/test.ts', 'mainType'),
|
||||
metadata: symbolCache.get('/tmp/external.d.ts', 'reexportType'),
|
||||
symbol: symbolCache.get('/tmp/test.ts', 'mainValue'),
|
||||
metadata: symbolCache.get('/tmp/external.d.ts', 'reexportValue'),
|
||||
}],
|
||||
[]);
|
||||
expect(serialized.exportAs).toEqual([]);
|
||||
const importAs =
|
||||
deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json)
|
||||
.importAs;
|
||||
expect(importAs).toEqual([]);
|
||||
expect(importAs).toEqual([{
|
||||
symbol: symbolCache.get('/tmp/external.d.ts', 'value'),
|
||||
importAs: symbolCache.get('/tmp/test.d.ts', 'mainValue'),
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should create "importAs" names for non source symbols', () => {
|
||||
it('should create reexports in the ngfactory for symbols of libraries', () => {
|
||||
init();
|
||||
const serialized = serializeSummaries(
|
||||
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
|
||||
@ -366,9 +425,10 @@ export function main() {
|
||||
const deserialized =
|
||||
deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json);
|
||||
// Note: no entry for the symbol with members!
|
||||
expect(deserialized.importAs).toEqual([
|
||||
{symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), importAs: 'lib_1'}
|
||||
]);
|
||||
expect(deserialized.importAs).toEqual([{
|
||||
symbol: symbolCache.get('/tmp/external.d.ts', 'lib'),
|
||||
importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1')
|
||||
}]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user