feat(compiler): generate proper reexports in .ngfactory.ts
files to not need transitive deps for compiling .ngfactory.ts
files. (#13524)
Note: This checks the constructors of `@Injectable` classes more strictly. E.g this will fail now as the constructor argument has no `@Inject` nor is the type of the argument a DI token. ``` @Injectable() class MyService { constructor(dep: string) {} } ``` Last part of #12787 Closes #12787
This commit is contained in:
@ -487,6 +487,8 @@ describe('StaticReflector', () => {
|
||||
export class Child extends Parent {}
|
||||
|
||||
export class ChildNoDecorators extends Parent {}
|
||||
|
||||
export class ChildInvalidParent extends a.InvalidParent {}
|
||||
`
|
||||
});
|
||||
|
||||
@ -500,6 +502,10 @@ describe('StaticReflector', () => {
|
||||
expect(
|
||||
reflector.annotations(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildNoDecorators')))
|
||||
.toEqual([new ClassDecorator('parent')]);
|
||||
|
||||
expect(reflector.annotations(
|
||||
reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||
.toEqual([]);
|
||||
});
|
||||
|
||||
it('should inherit parameters', () => {
|
||||
@ -520,6 +526,8 @@ describe('StaticReflector', () => {
|
||||
export class ChildWithCtor extends Parent {
|
||||
constructor(@ParamDecorator('c') c: C) {}
|
||||
}
|
||||
|
||||
export class ChildInvalidParent extends a.InvalidParent {}
|
||||
`
|
||||
});
|
||||
|
||||
@ -537,6 +545,10 @@ describe('StaticReflector', () => {
|
||||
|
||||
expect(reflector.parameters(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildWithCtor')))
|
||||
.toEqual([[reflector.getStaticSymbol('/tmp/src/main.ts', 'C'), new ParamDecorator('c')]]);
|
||||
|
||||
expect(
|
||||
reflector.parameters(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||
.toEqual([]);
|
||||
});
|
||||
|
||||
it('should inherit property metadata', () => {
|
||||
@ -561,6 +573,8 @@ describe('StaticReflector', () => {
|
||||
@PropDecorator('c')
|
||||
c: C;
|
||||
}
|
||||
|
||||
export class ChildInvalidParent extends a.InvalidParent {}
|
||||
`
|
||||
});
|
||||
|
||||
@ -577,6 +591,10 @@ describe('StaticReflector', () => {
|
||||
'b': [new PropDecorator('b1'), new PropDecorator('b2')],
|
||||
'c': [new PropDecorator('c')]
|
||||
});
|
||||
|
||||
expect(reflector.propMetadata(
|
||||
reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent')))
|
||||
.toEqual({});
|
||||
});
|
||||
|
||||
it('should inherit lifecycle hooks', () => {
|
||||
@ -591,6 +609,8 @@ describe('StaticReflector', () => {
|
||||
hook2() {}
|
||||
hook3() {}
|
||||
}
|
||||
|
||||
export class ChildInvalidParent extends a.InvalidParent {}
|
||||
`
|
||||
});
|
||||
|
||||
@ -606,6 +626,10 @@ describe('StaticReflector', () => {
|
||||
expect(hooks(reflector.getStaticSymbol('/tmp/src/main.ts', 'Child'), [
|
||||
'hook1', 'hook2', 'hook3'
|
||||
])).toEqual([true, true, true]);
|
||||
|
||||
expect(hooks(reflector.getStaticSymbol('/tmp/src/main.ts', 'ChildInvalidParent'), [
|
||||
'hook1', 'hook2', 'hook3'
|
||||
])).toEqual([false, false, false]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -16,7 +16,7 @@ import * as ts from 'typescript';
|
||||
const TS_EXT = /(^.|(?!\.d)..)\.ts$/;
|
||||
|
||||
describe('StaticSymbolResolver', () => {
|
||||
const noContext = new StaticSymbol('', '');
|
||||
const noContext = new StaticSymbol('', '', []);
|
||||
let host: StaticSymbolResolverHost;
|
||||
let symbolResolver: StaticSymbolResolver;
|
||||
let symbolCache: StaticSymbolCache;
|
||||
@ -24,10 +24,11 @@ describe('StaticSymbolResolver', () => {
|
||||
beforeEach(() => { symbolCache = new StaticSymbolCache(); });
|
||||
|
||||
function init(
|
||||
testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = []) {
|
||||
testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = [],
|
||||
summaryImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = []) {
|
||||
host = new MockStaticSymbolResolverHost(testData);
|
||||
symbolResolver =
|
||||
new StaticSymbolResolver(host, symbolCache, new MockSummaryResolver(summaries));
|
||||
symbolResolver = new StaticSymbolResolver(
|
||||
host, symbolCache, new MockSummaryResolver(summaries, summaryImportAs));
|
||||
}
|
||||
|
||||
beforeEach(() => init());
|
||||
@ -137,6 +138,73 @@ describe('StaticSymbolResolver', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
describe('importAs', () => {
|
||||
|
||||
it('should calculate importAs relationship for non source files without summaries', () => {
|
||||
init(
|
||||
{
|
||||
'/test.d.ts': [{
|
||||
'__symbolic': 'module',
|
||||
'version': 3,
|
||||
'metadata': {
|
||||
'a': {'__symbolic': 'reference', 'name': 'b', 'module': './test2'},
|
||||
}
|
||||
}],
|
||||
'/test2.d.ts': [{
|
||||
'__symbolic': 'module',
|
||||
'version': 3,
|
||||
'metadata': {
|
||||
'b': {'__symbolic': 'reference', 'name': 'c', 'module': './test3'},
|
||||
}
|
||||
}]
|
||||
},
|
||||
[]);
|
||||
symbolResolver.getSymbolsOf('/test.d.ts');
|
||||
symbolResolver.getSymbolsOf('/test2.d.ts');
|
||||
|
||||
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'b')))
|
||||
.toBe(symbolCache.get('/test.d.ts', 'a'));
|
||||
expect(symbolResolver.getImportAs(symbolCache.get('/test3.d.ts', 'c')))
|
||||
.toBe(symbolCache.get('/test.d.ts', 'a'));
|
||||
});
|
||||
|
||||
it('should calculate importAs relationship for non source files with summaries', () => {
|
||||
init(
|
||||
{
|
||||
'/test.ts': `
|
||||
export {a} from './test2';
|
||||
`
|
||||
},
|
||||
[], [{
|
||||
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||
}]);
|
||||
symbolResolver.getSymbolsOf('/test.ts');
|
||||
|
||||
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a')))
|
||||
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
||||
});
|
||||
|
||||
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
||||
() => {
|
||||
init(
|
||||
{
|
||||
'/test.ts': `
|
||||
export {a} from './test2';
|
||||
`
|
||||
},
|
||||
[], [{
|
||||
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||
}]);
|
||||
symbolResolver.getSymbolsOf('/test.ts');
|
||||
|
||||
expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a', ['someMember'])))
|
||||
.toBe(symbolCache.get('/test3.d.ts', 'b', ['someMember']));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should replace references by StaticSymbols', () => {
|
||||
init({
|
||||
'/test.ts': `
|
||||
@ -180,6 +248,42 @@ describe('StaticSymbolResolver', () => {
|
||||
.toBeFalsy();
|
||||
});
|
||||
|
||||
it('should fill references to ambient symbols with undefined', () => {
|
||||
init({
|
||||
'/test.ts': `
|
||||
export var y = 1;
|
||||
export var z = [window, z];
|
||||
`
|
||||
});
|
||||
|
||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'z')).metadata).toEqual([
|
||||
undefined, symbolCache.get('/test.ts', 'z')
|
||||
]);
|
||||
});
|
||||
|
||||
it('should allow to use symbols with __', () => {
|
||||
init({
|
||||
'/test.ts': `
|
||||
export {__a__ as __b__} from './test2';
|
||||
import {__c__} from './test2';
|
||||
|
||||
export var __x__ = 1;
|
||||
export var __y__ = __c__;
|
||||
`
|
||||
});
|
||||
|
||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__x__')).metadata).toBe(1);
|
||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__y__')).metadata)
|
||||
.toBe(symbolCache.get('/test2.d.ts', '__c__'));
|
||||
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', '__b__')).metadata)
|
||||
.toBe(symbolCache.get('/test2.d.ts', '__a__'));
|
||||
|
||||
expect(symbolResolver.getSymbolsOf('/test.ts')).toEqual([
|
||||
symbolCache.get('/test.ts', '__x__'), symbolCache.get('/test.ts', '__y__'),
|
||||
symbolCache.get('/test.ts', '__b__')
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be able to trace a named export', () => {
|
||||
const symbol = symbolResolver
|
||||
.resolveSymbol(symbolResolver.getSymbolByModule(
|
||||
@ -240,7 +344,10 @@ describe('StaticSymbolResolver', () => {
|
||||
});
|
||||
|
||||
export class MockSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||
constructor(private summaries: Summary<StaticSymbol>[] = []) {}
|
||||
constructor(private summaries: Summary<StaticSymbol>[] = [], private importAs: {
|
||||
symbol: StaticSymbol,
|
||||
importAs: StaticSymbol
|
||||
}[] = []) {}
|
||||
|
||||
resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> {
|
||||
return this.summaries.find(summary => summary.symbol === reference);
|
||||
@ -249,6 +356,13 @@ export class MockSummaryResolver implements SummaryResolver<StaticSymbol> {
|
||||
return this.summaries.filter(summary => summary.symbol.filePath === filePath)
|
||||
.map(summary => summary.symbol);
|
||||
}
|
||||
getImportAs(symbol: StaticSymbol): StaticSymbol {
|
||||
const entry = this.importAs.find(entry => entry.symbol === symbol);
|
||||
return entry ? entry.importAs : undefined;
|
||||
}
|
||||
|
||||
isLibraryFile(filePath: string): boolean { return filePath.endsWith('.d.ts'); }
|
||||
getLibraryFileName(filePath: string): string { return filePath.replace(/(\.d)?\.ts$/, '.d.ts'); }
|
||||
}
|
||||
|
||||
export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost {
|
||||
|
@ -7,12 +7,12 @@
|
||||
*/
|
||||
|
||||
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, CompileTypeSummary, ResolvedStaticSymbol, StaticSymbol, StaticSymbolCache, StaticSymbolResolver} from '@angular/compiler';
|
||||
import {AotSummarySerializerHost, deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||
import * as path from 'path';
|
||||
|
||||
import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec';
|
||||
|
||||
const EXT = /\.ts$|.d.ts$/;
|
||||
const EXT = /(\.d)?\.ts$/;
|
||||
|
||||
export function main() {
|
||||
describe('AotSummaryResolver', () => {
|
||||
@ -32,8 +32,7 @@ export function main() {
|
||||
const mockSummaryResolver = new MockSummaryResolver([]);
|
||||
const symbolResolver = new StaticSymbolResolver(
|
||||
new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver);
|
||||
return serializeSummaries(
|
||||
new MockAotSummarySerializerHost(), mockSummaryResolver, symbolResolver, symbols, types);
|
||||
return serializeSummaries(mockSummaryResolver, symbolResolver, symbols, types).json;
|
||||
}
|
||||
|
||||
it('should load serialized summary files', () => {
|
||||
@ -56,17 +55,48 @@ export function main() {
|
||||
expect(summaryResolver.resolveSummary(asymbol)).toBe(summaryResolver.resolveSummary(asymbol));
|
||||
});
|
||||
|
||||
it('should return all sumbols in a summary', () => {
|
||||
it('should return all symbols in a summary', () => {
|
||||
const asymbol = symbolCache.get('/a.d.ts', 'a');
|
||||
init({'/a.ngsummary.json': serialize([{symbol: asymbol, metadata: 1}], [])});
|
||||
expect(summaryResolver.getSymbolsOf('/a.d.ts')).toEqual([asymbol]);
|
||||
});
|
||||
|
||||
it('should fill importAs for deep symbols', () => {
|
||||
const libSymbol = symbolCache.get('/lib.d.ts', 'Lib');
|
||||
const srcSymbol = symbolCache.get('/src.ts', 'Src');
|
||||
init({
|
||||
'/src.ngsummary.json':
|
||||
serialize([{symbol: srcSymbol, metadata: 1}, {symbol: libSymbol, metadata: 2}], [])
|
||||
});
|
||||
summaryResolver.getSymbolsOf('/src.d.ts');
|
||||
|
||||
expect(summaryResolver.getImportAs(symbolCache.get('/src.d.ts', 'Src'))).toBeFalsy();
|
||||
expect(summaryResolver.getImportAs(libSymbol))
|
||||
.toBe(symbolCache.get('/src.ngfactory.ts', 'Lib_1'));
|
||||
});
|
||||
|
||||
describe('isLibraryFile', () => {
|
||||
it('should use host.isSourceFile to calculate the result', () => {
|
||||
init();
|
||||
expect(summaryResolver.isLibraryFile('someFile.ts')).toBe(false);
|
||||
expect(summaryResolver.isLibraryFile('someFile.d.ts')).toBe(true);
|
||||
});
|
||||
|
||||
it('should calculate the result for generated files based on the result for non generated files',
|
||||
() => {
|
||||
init();
|
||||
spyOn(host, 'isSourceFile').and.callThrough();
|
||||
expect(summaryResolver.isLibraryFile('someFile.ngfactory.ts')).toBe(false);
|
||||
expect(host.isSourceFile).toHaveBeenCalledWith('someFile.ts');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export class MockAotSummarySerializerHost implements AotSummarySerializerHost {
|
||||
export class MockAotSummaryResolverHost implements AotSummaryResolverHost {
|
||||
constructor(private summaries: {[fileName: string]: string}) {}
|
||||
|
||||
fileNameToModuleName(fileName: string): string {
|
||||
return './' + path.basename(fileName).replace(EXT, '');
|
||||
}
|
||||
@ -76,11 +106,6 @@ export class MockAotSummarySerializerHost implements AotSummarySerializerHost {
|
||||
}
|
||||
|
||||
isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); }
|
||||
}
|
||||
|
||||
export class MockAotSummaryResolverHost extends MockAotSummarySerializerHost implements
|
||||
AotSummaryResolverHost {
|
||||
constructor(private summaries: {[fileName: string]: string}) { super(); }
|
||||
|
||||
loadSummary(filePath: string): string { return this.summaries[filePath]; }
|
||||
}
|
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
import {AotSummaryResolver, AotSummaryResolverHost, CompileSummaryKind, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost} from '@angular/compiler';
|
||||
import {AotSummarySerializerHost, deserializeSummaries, serializeSummaries, summaryFileName} from '@angular/compiler/src/aot/summary_serializer';
|
||||
import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/aot/summary_serializer';
|
||||
import {summaryFileName} from '@angular/compiler/src/aot/util';
|
||||
|
||||
import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec';
|
||||
import {MockAotSummaryResolverHost} from './summary_resolver_spec';
|
||||
@ -42,7 +43,7 @@ export function main() {
|
||||
it('should serialize various data correctly', () => {
|
||||
init();
|
||||
const serializedData = serializeSummaries(
|
||||
host, summaryResolver, symbolResolver,
|
||||
summaryResolver, symbolResolver,
|
||||
[
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/some_values.ts', 'Values'),
|
||||
@ -50,7 +51,9 @@ export function main() {
|
||||
aNumber: 1,
|
||||
aString: 'hello',
|
||||
anArray: [1, 2],
|
||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.ts', 'someName')
|
||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.ts', 'someName'),
|
||||
aStaticSymbolWithMembers:
|
||||
symbolCache.get('/tmp/some_symbol.ts', 'someName', ['someMember']),
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -66,11 +69,11 @@ export function main() {
|
||||
summaryKind: CompileSummaryKind.Injectable,
|
||||
type: {
|
||||
reference: symbolCache.get('/tmp/some_service.ts', 'SomeService'),
|
||||
},
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
const summaries = deserializeSummaries(symbolCache, serializedData);
|
||||
const summaries = deserializeSummaries(symbolCache, serializedData.json).summaries;
|
||||
expect(summaries.length).toBe(2);
|
||||
|
||||
// Note: change from .ts to .d.ts is expected
|
||||
@ -79,7 +82,9 @@ export function main() {
|
||||
aNumber: 1,
|
||||
aString: 'hello',
|
||||
anArray: [1, 2],
|
||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.d.ts', 'someName')
|
||||
aStaticSymbol: symbolCache.get('/tmp/some_symbol.d.ts', 'someName'),
|
||||
aStaticSymbolWithMembers:
|
||||
symbolCache.get('/tmp/some_symbol.d.ts', 'someName', ['someMember'])
|
||||
});
|
||||
|
||||
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService'));
|
||||
@ -91,8 +96,8 @@ export function main() {
|
||||
|
||||
it('should automatically add exported directives / pipes of NgModules that are not source files',
|
||||
() => {
|
||||
init({});
|
||||
const externalSerialized = serializeSummaries(host, summaryResolver, symbolResolver, [], [
|
||||
init();
|
||||
const externalSerialized = serializeSummaries(summaryResolver, symbolResolver, [], [
|
||||
<any>{
|
||||
summaryKind: CompileSummaryKind.Pipe,
|
||||
type: {
|
||||
@ -107,11 +112,11 @@ export function main() {
|
||||
}
|
||||
]);
|
||||
init({
|
||||
'/tmp/external.ngsummary.json': externalSerialized,
|
||||
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||
});
|
||||
|
||||
const serialized = serializeSummaries(
|
||||
host, summaryResolver, symbolResolver, [], [<any>{
|
||||
summaryResolver, symbolResolver, [], [<any>{
|
||||
summaryKind: CompileSummaryKind.NgModule,
|
||||
type: {reference: symbolCache.get('/tmp/some_module.ts', 'SomeModule')},
|
||||
exportedPipes: [
|
||||
@ -124,7 +129,7 @@ export function main() {
|
||||
]
|
||||
}]);
|
||||
|
||||
const summaries = deserializeSummaries(symbolCache, serialized);
|
||||
const summaries = deserializeSummaries(symbolCache, serialized.json).summaries;
|
||||
expect(summaries.length).toBe(3);
|
||||
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/some_module.d.ts', 'SomeModule'));
|
||||
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/external.d.ts', 'SomeExternalDir'));
|
||||
@ -134,8 +139,9 @@ export function main() {
|
||||
|
||||
it('should automatically add the metadata of referenced symbols that are not in the soure files',
|
||||
() => {
|
||||
init();
|
||||
const externalSerialized = serializeSummaries(
|
||||
host, summaryResolver, symbolResolver,
|
||||
summaryResolver, symbolResolver,
|
||||
[
|
||||
{
|
||||
symbol: symbolCache.get('/tmp/external.ts', 'PROVIDERS'),
|
||||
@ -154,7 +160,7 @@ export function main() {
|
||||
}]);
|
||||
init(
|
||||
{
|
||||
'/tmp/external.ngsummary.json': externalSerialized,
|
||||
'/tmp/external.ngsummary.json': externalSerialized.json,
|
||||
},
|
||||
{
|
||||
'/tmp/local.ts': `
|
||||
@ -164,7 +170,7 @@ export function main() {
|
||||
{__symbolic: 'module', version: 3, metadata: {'external': 'b'}}
|
||||
});
|
||||
const serialized = serializeSummaries(
|
||||
host, summaryResolver, symbolResolver, [{
|
||||
summaryResolver, symbolResolver, [{
|
||||
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
||||
metadata: {
|
||||
local: symbolCache.get('/tmp/local.ts', 'local'),
|
||||
@ -174,7 +180,7 @@ export function main() {
|
||||
}],
|
||||
[]);
|
||||
|
||||
const summaries = deserializeSummaries(symbolCache, serialized);
|
||||
const summaries = deserializeSummaries(symbolCache, serialized.json).summaries;
|
||||
// Note: local should not show up!
|
||||
expect(summaries.length).toBe(4);
|
||||
expect(summaries[0].symbol).toBe(symbolCache.get('/tmp/test.d.ts', 'main'));
|
||||
@ -195,5 +201,28 @@ export function main() {
|
||||
expect(summaries[3].type.type.reference)
|
||||
.toBe(symbolCache.get('/tmp/external_svc.d.ts', 'SomeService'));
|
||||
});
|
||||
|
||||
it('should create "importAs" names for non source symbols', () => {
|
||||
init();
|
||||
const serialized = serializeSummaries(
|
||||
summaryResolver, symbolResolver, [{
|
||||
symbol: symbolCache.get('/tmp/test.ts', 'main'),
|
||||
metadata: [
|
||||
symbolCache.get('/tmp/external.d.ts', 'lib'),
|
||||
symbolCache.get('/tmp/external.d.ts', 'lib', ['someMember']),
|
||||
]
|
||||
}],
|
||||
[]);
|
||||
// Note: no entry for the symbol with members!
|
||||
expect(serialized.exportAs).toEqual([
|
||||
{symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), exportAs: 'lib_1'}
|
||||
]);
|
||||
|
||||
const deserialized = deserializeSummaries(symbolCache, 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'}
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
@ -15,16 +16,17 @@ const someModuleUrl = 'somePackage/somePath';
|
||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
|
||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: {name: 'someLocalId', filePath: someModuleUrl}
|
||||
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||
};
|
||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: {name: 'someExternalId', filePath: anotherModuleUrl}
|
||||
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
|
||||
};
|
||||
|
||||
class SimpleJsImportGenerator implements ImportResolver {
|
||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||
return importedUrlStr;
|
||||
}
|
||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||
}
|
||||
|
||||
export function main() {
|
||||
@ -33,11 +35,13 @@ export function main() {
|
||||
// - declaring fields
|
||||
|
||||
describe('JavaScriptEmitter', () => {
|
||||
let importResolver: ImportResolver;
|
||||
let emitter: JavaScriptEmitter;
|
||||
let someVar: o.ReadVarExpr;
|
||||
|
||||
beforeEach(() => {
|
||||
emitter = new JavaScriptEmitter(new SimpleJsImportGenerator());
|
||||
importResolver = new SimpleJsImportGenerator();
|
||||
emitter = new JavaScriptEmitter(importResolver);
|
||||
someVar = o.variable('someVar');
|
||||
});
|
||||
|
||||
@ -124,6 +128,16 @@ export function main() {
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support `importAs` for external identifiers', () => {
|
||||
spyOn(importResolver, 'getImportAs')
|
||||
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
|
||||
`var import0 = re` +
|
||||
`quire('somePackage/importAsModule');`,
|
||||
`import0.importAsName;`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support operators', () => {
|
||||
const lhs = o.variable('lhs');
|
||||
const rhs = o.variable('rhs');
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {assetUrl, createIdentifier} from '@angular/compiler/src/identifiers';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
@ -262,4 +263,5 @@ export class SimpleJsImportGenerator implements ImportResolver {
|
||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||
return importedUrlStr;
|
||||
}
|
||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||
}
|
||||
|
@ -74,4 +74,5 @@ class StubReflectorHost implements StaticSymbolResolverHost {
|
||||
|
||||
class StubImportResolver extends ImportResolver {
|
||||
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string { return ''; }
|
||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from '@angular/compiler/src/aot/static_symbol';
|
||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import * as o from '@angular/compiler/src/output/output_ast';
|
||||
import {ImportResolver} from '@angular/compiler/src/output/path_util';
|
||||
@ -15,38 +16,42 @@ const someModuleUrl = 'somePackage/somePath';
|
||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
|
||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: {name: 'someLocalId', filePath: someModuleUrl}
|
||||
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||
};
|
||||
|
||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: {name: 'someExternalId', filePath: anotherModuleUrl}
|
||||
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
|
||||
};
|
||||
|
||||
class SimpleJsImportGenerator implements ImportResolver {
|
||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||
return importedUrlStr;
|
||||
}
|
||||
getImportAs(symbol: StaticSymbol): StaticSymbol { return null; }
|
||||
}
|
||||
|
||||
export function main() {
|
||||
// Note supported features of our OutputAsti n TS:
|
||||
// Not supported features of our OutputAst in TS:
|
||||
// - real `const` like in Dart
|
||||
// - final fields
|
||||
|
||||
describe('TypeScriptEmitter', () => {
|
||||
let importResolver: ImportResolver;
|
||||
let emitter: TypeScriptEmitter;
|
||||
let someVar: o.ReadVarExpr;
|
||||
|
||||
beforeEach(() => {
|
||||
emitter = new TypeScriptEmitter(new SimpleJsImportGenerator());
|
||||
importResolver = new SimpleJsImportGenerator();
|
||||
emitter = new TypeScriptEmitter(importResolver);
|
||||
someVar = o.variable('someVar');
|
||||
});
|
||||
|
||||
function emitStmt(stmt: o.Statement, exportedVars: string[] = null): string {
|
||||
function emitStmt(stmt: o.Statement | o.Statement[], exportedVars: string[] = null): string {
|
||||
if (!exportedVars) {
|
||||
exportedVars = [];
|
||||
}
|
||||
return emitter.emitStatements(someModuleUrl, [stmt], exportedVars);
|
||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||
return emitter.emitStatements(someModuleUrl, stmts, exportedVars);
|
||||
}
|
||||
|
||||
it('should declare variables', () => {
|
||||
@ -59,6 +64,79 @@ export function main() {
|
||||
.toEqual(`var someVar:number = 1;`);
|
||||
});
|
||||
|
||||
describe('declare variables with ExternExpressions as values', () => {
|
||||
it('should create no reexport if the identifier is in the same module', () => {
|
||||
// identifier is in the same module -> no reexport
|
||||
expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||
.toEqual('export var someVar:any = someLocalId;');
|
||||
});
|
||||
|
||||
it('should create no reexport if the variable is not exported', () => {
|
||||
expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt())).toEqual([
|
||||
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||
`var someVar:any = import0.someExternalId;`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should create no reexport if the variable is typed', () => {
|
||||
expect(emitStmt(
|
||||
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(o.DYNAMIC_TYPE),
|
||||
['someVar']))
|
||||
.toEqual([
|
||||
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||
`export var someVar:any = import0.someExternalId;`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should create no reexport if the identifier has members', () => {
|
||||
const externalModuleIdentifierWithMembers: CompileIdentifierMetadata = {
|
||||
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', ['a'])
|
||||
};
|
||||
expect(emitStmt(
|
||||
someVar.set(o.importExpr(externalModuleIdentifierWithMembers)).toDeclStmt(),
|
||||
['someVar']))
|
||||
.toEqual([
|
||||
`import * as import0 from 'somePackage/someOtherPath';`,
|
||||
`export var someVar:any = import0.someExternalId.a;`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should create a reexport', () => {
|
||||
expect(
|
||||
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||
.toEqual([
|
||||
`export {someExternalId as someVar} from 'somePackage/someOtherPath';`, ``
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should create multiple reexports from the same file', () => {
|
||||
const someVar2 = o.variable('someVar2');
|
||||
const externalModuleIdentifier2: CompileIdentifierMetadata = {
|
||||
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId2', [])
|
||||
};
|
||||
expect(emitStmt(
|
||||
[
|
||||
someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(),
|
||||
someVar2.set(o.importExpr(externalModuleIdentifier2)).toDeclStmt()
|
||||
],
|
||||
['someVar', 'someVar2']))
|
||||
.toEqual([
|
||||
`export {someExternalId as someVar,someExternalId2 as someVar2} from 'somePackage/someOtherPath';`,
|
||||
``
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should use `importAs` for reexports', () => {
|
||||
spyOn(importResolver, 'getImportAs')
|
||||
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||
expect(
|
||||
emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt(), ['someVar']))
|
||||
.toEqual([
|
||||
`export {importAsName as someVar} from 'somePackage/importAsModule';`, ``
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
it('should read and write variables', () => {
|
||||
expect(emitStmt(someVar.toStmt())).toEqual(`someVar;`);
|
||||
expect(emitStmt(someVar.set(o.literal(1)).toStmt())).toEqual(`someVar = 1;`);
|
||||
@ -134,6 +212,14 @@ export function main() {
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support `importAs` for external identifiers', () => {
|
||||
spyOn(importResolver, 'getImportAs')
|
||||
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||
expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())).toEqual([
|
||||
`import * as import0 from 'somePackage/importAsModule';`, `import0.importAsName;`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support operators', () => {
|
||||
const lhs = o.variable('lhs');
|
||||
const rhs = o.variable('rhs');
|
||||
@ -332,6 +418,16 @@ export function main() {
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support `importAs` for external types', () => {
|
||||
spyOn(importResolver, 'getImportAs')
|
||||
.and.returnValue(new StaticSymbol('somePackage/importAsModule', 'importAsName', []));
|
||||
const writeVarExpr = o.variable('a').set(o.NULL_EXPR);
|
||||
expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(externalModuleIdentifier)))).toEqual([
|
||||
`import * as import0 from 'somePackage/importAsModule';`,
|
||||
`var a:import0.importAsName = (null as any);`
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should support expression types', () => {
|
||||
expect(emitStmt(o.variable('a')
|
||||
.set(o.NULL_EXPR)
|
||||
|
Reference in New Issue
Block a user