Skip to content

Commit 2572bf5

Browse files
tboschhansl
authored andcommitted
feat(compiler): make .ngsummary.json files portable
This also allows to customize the filePaths in `.ngsummary.json` file via the new methods `toSummaryFileName` and `fromSummaryFileName` on the `CompilerHost`.
1 parent 6a1ab61 commit 2572bf5

File tree

15 files changed

+149
-53
lines changed

15 files changed

+149
-53
lines changed

packages/compiler-cli/src/compiler_host.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export abstract class BaseAotCompilerHost<C extends BaseAotCompilerHostContext>
4242

4343
abstract fileNameToModuleName(importedFile: string, containingFile: string): string|null;
4444

45+
abstract toSummaryFileName(fileName: string, referringSrcFileName: string): string;
46+
47+
abstract fromSummaryFileName(fileName: string, referringLibFileName: string): string;
48+
4549
protected getSourceFile(filePath: string): ts.SourceFile {
4650
const sf = this.program.getSourceFile(filePath);
4751
if (!sf) {
@@ -144,10 +148,6 @@ export abstract class BaseAotCompilerHost<C extends BaseAotCompilerHostContext>
144148
return null;
145149
}
146150

147-
getOutputFileName(sourceFilePath: string): string {
148-
return sourceFilePath.replace(EXT, '') + '.d.ts';
149-
}
150-
151151
isSourceFile(filePath: string): boolean {
152152
const excludeRegex =
153153
this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
@@ -268,6 +268,12 @@ export class CompilerHost extends BaseAotCompilerHost<CompilerHostContext> {
268268
};
269269
}
270270

271+
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
272+
return fileName.replace(EXT, '') + '.d.ts';
273+
}
274+
275+
fromSummaryFileName(fileName: string, referringLibFileName: string): string { return fileName; }
276+
271277
calculateEmitPath(filePath: string): string {
272278
// Write codegen in a directory structure matching the sources.
273279
let root = this.options.basePath !;

packages/compiler-cli/src/transformers/api.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ export interface CompilerHost extends ts.CompilerHost {
130130
* See ImportResolver.
131131
*/
132132
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string|null;
133+
/**
134+
* Converts a file name into a representation that should be stored in a summary file.
135+
* This has to include changing the suffix as well.
136+
* E.g.
137+
* `some_file.ts` -> `some_file.d.ts`
138+
*
139+
* @param referringSrcFileName the soure file that refers to fileName
140+
*/
141+
toSummaryFileName(fileName: string, referringSrcFileName: string): string;
142+
/**
143+
* Converts a fileName that was processed by `toSummaryFileName` back into a real fileName
144+
* given the fileName of the library that is referrig to it.
145+
*/
146+
fromSummaryFileName(fileName: string, referringLibFileName: string): string;
133147
/**
134148
* Load a referenced resource either statically or asynchronously. If the host returns a
135149
* `Promise<string>` it is assumed the user of the corresponding `Program` will call

packages/compiler-cli/src/transformers/compiler_host.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export function createCompilerHost(
2424

2525
host.moduleNameToFileName = mixin.moduleNameToFileName.bind(mixin);
2626
host.fileNameToModuleName = mixin.fileNameToModuleName.bind(mixin);
27+
host.toSummaryFileName = mixin.toSummaryFileName.bind(mixin);
28+
host.fromSummaryFileName = mixin.fromSummaryFileName.bind(mixin);
2729

2830
// Make sure we do not `host.realpath()` from TS as we do not want to resolve symlinks.
2931
// https://github.com/Microsoft/TypeScript/issues/9552
@@ -109,9 +111,15 @@ class CompilerHostMixin {
109111

110112
let moduleName: string;
111113
if (importedFilePackagName === containingFilePackageName) {
112-
moduleName = dotRelative(
113-
path.dirname(stripRootDir(this.rootDirs, containingFile)),
114-
stripRootDir(this.rootDirs, importedFile));
114+
const rootedContainingFile = stripRootDir(this.rootDirs, containingFile);
115+
const rootedImportedFile = stripRootDir(this.rootDirs, importedFile);
116+
117+
if (rootedContainingFile !== containingFile && rootedImportedFile !== importedFile) {
118+
// if both files are contained in the `rootDirs`, then strip the rootDirs
119+
containingFile = rootedContainingFile;
120+
importedFile = rootedImportedFile;
121+
}
122+
moduleName = dotRelative(path.dirname(containingFile), importedFile);
115123
} else if (importedFilePackagName) {
116124
moduleName = stripNodeModulesPrefix(importedFile);
117125
} else {
@@ -120,6 +128,18 @@ class CompilerHostMixin {
120128
}
121129
return moduleName;
122130
}
131+
132+
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
133+
return this.fileNameToModuleName(fileName, referringSrcFileName);
134+
}
135+
136+
fromSummaryFileName(fileName: string, referringLibFileName: string): string {
137+
const resolved = this.moduleNameToFileName(fileName, referringLibFileName);
138+
if (!resolved) {
139+
throw new Error(`Could not resolve ${fileName} from ${referringLibFileName}`);
140+
}
141+
return resolved;
142+
}
123143
}
124144

125145
interface ModuleFilenameResolutionHost extends ts.ModuleResolutionHost {
@@ -189,6 +209,11 @@ function stripNodeModulesPrefix(filePath: string): string {
189209
return filePath.replace(/.*node_modules\//, '');
190210
}
191211

212+
function getNodeModulesPrefix(filePath: string): string|null {
213+
const match = /.*node_modules\//.exec(filePath);
214+
return match ? match[1] : null;
215+
}
216+
192217
function normalizePath(p: string): string {
193218
return path.normalize(path.join(p, '.')).replace(/\\/g, '/');
194219
}

packages/compiler-cli/src/transformers/program.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,14 @@ class AotCompilerHostImpl extends BaseAotCompilerHost<CompilerHost> {
314314
fileNameToModuleName(importedFile: string, containingFile: string): string|null {
315315
return this.context.fileNameToModuleName(importedFile, containingFile);
316316
}
317+
318+
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
319+
return this.context.toSummaryFileName(fileName, referringSrcFileName);
320+
}
321+
322+
fromSummaryFileName(fileName: string, referringLibFileName: string): string {
323+
return this.context.fromSummaryFileName(fileName, referringLibFileName);
324+
}
317325
}
318326

319327
export function createProgram(

packages/compiler-cli/test/diagnostics/mocks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ const summaryResolver = new AotSummaryResolver(
105105
{
106106
loadSummary(filePath: string) { return null; },
107107
isSourceFile(sourceFilePath: string) { return true; },
108-
getOutputFileName(sourceFilePath: string) { return sourceFilePath; }
108+
toSummaryFileName(sourceFilePath: string) { return sourceFilePath; },
109+
fromSummaryFileName(filePath: string): string{return filePath;},
109110
},
110111
staticSymbolCache);
111112

packages/compiler-cli/test/transformers/compiler_host_spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,13 @@ describe('NgCompilerHost', () => {
6767
]
6868
}
6969
});
70+
// both files are in the rootDirs
7071
expect(ngHostWithMultipleRoots.fileNameToModuleName('/tmp/src/b/b.ts', '/tmp/src/a/a.ts'))
7172
.toBe('./b');
73+
74+
// one file is not in the rootDirs
75+
expect(ngHostWithMultipleRoots.fileNameToModuleName('/tmp/src/c/c.ts', '/tmp/src/a/a.ts'))
76+
.toBe('../c/c');
7277
});
7378

7479
it('should error if accessing a source file from a package', () => {

packages/compiler/src/aot/compiler.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ export class AotCompiler {
207207
}
208208

209209
private _createSummary(
210-
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
210+
srcFileName: string, directives: StaticSymbol[], pipes: StaticSymbol[],
211211
ngModules: StaticSymbol[], injectables: StaticSymbol[],
212212
ngFactoryCtx: OutputContext): GeneratedFile[] {
213-
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
213+
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileName)
214214
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
215215
const typeData: {
216216
summary: CompileTypeSummary,
@@ -235,18 +235,19 @@ export class AotCompiler {
235235
metadata: this._metadataResolver.getInjectableSummary(ref) !.type
236236
}))
237237
];
238-
const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
238+
const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileName, true));
239239
const {json, exportAs} = serializeSummaries(
240-
forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
240+
srcFileName, forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries,
241+
typeData);
241242
exportAs.forEach((entry) => {
242243
ngFactoryCtx.statements.push(
243244
o.variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [
244245
o.StmtModifier.Exported
245246
]));
246247
});
247-
const summaryJson = new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
248+
const summaryJson = new GeneratedFile(srcFileName, summaryFileName(srcFileName), json);
248249
if (this._enableSummariesForJit) {
249-
return [summaryJson, this._codegenSourceModule(srcFileUrl, forJitOutputCtx)];
250+
return [summaryJson, this._codegenSourceModule(srcFileName, forJitOutputCtx)];
250251
};
251252

252253
return [summaryJson];

packages/compiler/src/aot/summary_resolver.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,20 @@ export interface AotSummaryResolverHost {
2323
*/
2424
isSourceFile(sourceFilePath: string): boolean;
2525
/**
26-
* Returns the output file path of a source file.
26+
* Converts a file name into a representation that should be stored in a summary file.
27+
* This has to include changing the suffix as well.
2728
* E.g.
2829
* `some_file.ts` -> `some_file.d.ts`
30+
*
31+
* @param referringSrcFileName the soure file that refers to fileName
2932
*/
30-
getOutputFileName(sourceFilePath: string): string;
33+
toSummaryFileName(fileName: string, referringSrcFileName: string): string;
34+
35+
/**
36+
* Converts a fileName that was processed by `toSummaryFileName` back into a real fileName
37+
* given the fileName of the library that is referrig to it.
38+
*/
39+
fromSummaryFileName(fileName: string, referringLibFileName: string): string;
3140
}
3241

3342
export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
@@ -46,7 +55,13 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
4655
return !this.host.isSourceFile(stripGeneratedFileSuffix(filePath));
4756
}
4857

49-
getLibraryFileName(filePath: string) { return this.host.getOutputFileName(filePath); }
58+
toSummaryFileName(filePath: string, referringSrcFileName: string) {
59+
return this.host.toSummaryFileName(filePath, referringSrcFileName);
60+
}
61+
62+
fromSummaryFileName(fileName: string, referringLibFileName: string) {
63+
return this.host.fromSummaryFileName(fileName, referringLibFileName);
64+
}
5065

5166
resolveSummary(staticSymbol: StaticSymbol): Summary<StaticSymbol> {
5267
staticSymbol.assertNoMembers();
@@ -85,7 +100,8 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> {
85100
throw e;
86101
}
87102
if (json) {
88-
const {summaries, importAs} = deserializeSummaries(this.staticSymbolCache, json);
103+
const {summaries, importAs} =
104+
deserializeSummaries(this.staticSymbolCache, this, filePath, json);
89105
summaries.forEach((summary) => this.summaryCache.set(summary.symbol, summary));
90106
importAs.forEach((importAs) => {
91107
this.importAs.set(

packages/compiler/src/aot/summary_serializer.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolv
1515
import {summaryForJitFileName, summaryForJitName} from './util';
1616

1717
export function serializeSummaries(
18-
forJitCtx: OutputContext, summaryResolver: SummaryResolver<StaticSymbol>,
18+
srcFileName: string, forJitCtx: OutputContext, summaryResolver: SummaryResolver<StaticSymbol>,
1919
symbolResolver: StaticSymbolResolver, symbols: ResolvedStaticSymbol[], types: {
2020
summary: CompileTypeSummary,
2121
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
@@ -76,15 +76,17 @@ export function serializeSummaries(
7676
});
7777
}
7878
});
79-
const {json, exportAs} = toJsonSerializer.serialize();
79+
const {json, exportAs} = toJsonSerializer.serialize(srcFileName);
8080
forJitSerializer.serialize(exportAs);
8181
return {json, exportAs};
8282
}
8383

84-
export function deserializeSummaries(symbolCache: StaticSymbolCache, json: string):
84+
export function deserializeSummaries(
85+
symbolCache: StaticSymbolCache, summaryResolver: SummaryResolver<StaticSymbol>,
86+
libraryFileName: string, json: string):
8587
{summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: string}[]} {
86-
const deserializer = new FromJsonDeserializer(symbolCache);
87-
return deserializer.deserialize(json);
88+
const deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
89+
return deserializer.deserialize(libraryFileName, json);
8890
}
8991

9092
export function createForJitStub(outputCtx: OutputContext, reference: StaticSymbol) {
@@ -151,7 +153,8 @@ class ToJsonSerializer extends ValueTransformer {
151153
}
152154
}
153155

154-
serialize(): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
156+
serialize(srcFileName: string):
157+
{json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
155158
const exportAs: {symbol: StaticSymbol, exportAs: string}[] = [];
156159
const json = JSON.stringify({
157160
summaries: this.processedSummaries,
@@ -165,10 +168,7 @@ class ToJsonSerializer extends ValueTransformer {
165168
return {
166169
__symbol: index,
167170
name: symbol.name,
168-
// We convert the source filenames tinto output filenames,
169-
// as the generated summary file will be used when the current
170-
// compilation unit is used as a library
171-
filePath: this.summaryResolver.getLibraryFileName(symbol.filePath),
171+
filePath: this.summaryResolver.toSummaryFileName(symbol.filePath, srcFileName),
172172
importAs: importAs
173173
};
174174
})
@@ -317,15 +317,21 @@ class ForJitSerializer {
317317
class FromJsonDeserializer extends ValueTransformer {
318318
private symbols: StaticSymbol[];
319319

320-
constructor(private symbolCache: StaticSymbolCache) { super(); }
320+
constructor(
321+
private symbolCache: StaticSymbolCache,
322+
private summaryResolver: SummaryResolver<StaticSymbol>) {
323+
super();
324+
}
321325

322-
deserialize(json: string):
326+
deserialize(libraryFileName: string, json: string):
323327
{summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: string}[]} {
324328
const data: {summaries: any[], symbols: any[]} = JSON.parse(json);
325329
const importAs: {symbol: StaticSymbol, importAs: string}[] = [];
326330
this.symbols = [];
327331
data.symbols.forEach((serializedSymbol) => {
328-
const symbol = this.symbolCache.get(serializedSymbol.filePath, serializedSymbol.name);
332+
const symbol = this.symbolCache.get(
333+
this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName),
334+
serializedSymbol.name);
329335
this.symbols.push(symbol);
330336
if (serializedSymbol.importAs) {
331337
importAs.push({symbol: symbol, importAs: serializedSymbol.importAs});

packages/compiler/src/summary_resolver.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export interface Summary<T> {
1717

1818
export abstract class SummaryResolver<T> {
1919
abstract isLibraryFile(fileName: string): boolean;
20-
abstract getLibraryFileName(fileName: string): string|null;
20+
abstract toSummaryFileName(fileName: string, referringSrcFileName: string): string;
21+
abstract fromSummaryFileName(fileName: string, referringLibFileName: string): string;
2122
abstract resolveSummary(reference: T): Summary<T>|null;
2223
abstract getSymbolsOf(filePath: string): T[];
2324
abstract getImportAs(reference: T): T;
@@ -28,12 +29,13 @@ export abstract class SummaryResolver<T> {
2829
export class JitSummaryResolver implements SummaryResolver<Type<any>> {
2930
private _summaries = new Map<Type<any>, Summary<Type<any>>>();
3031

31-
isLibraryFile(fileName: string): boolean { return false; };
32-
getLibraryFileName(fileName: string): string|null { return null; }
32+
isLibraryFile(): boolean { return false; };
33+
toSummaryFileName(fileName: string): string { return fileName; }
34+
fromSummaryFileName(fileName: string): string { return fileName; }
3335
resolveSummary(reference: Type<any>): Summary<Type<any>>|null {
3436
return this._summaries.get(reference) || null;
3537
};
36-
getSymbolsOf(filePath: string): Type<any>[] { return []; }
38+
getSymbolsOf(): Type<any>[] { return []; }
3739
getImportAs(reference: Type<any>): Type<any> { return reference; }
3840
addSummary(summary: Summary<Type<any>>) { this._summaries.set(summary.symbol, summary); };
3941
}

0 commit comments

Comments
 (0)