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`.
This commit is contained in:
Tobias Bosch
2017-08-15 14:41:48 -07:00
committed by Hans
parent 6a1ab61cce
commit 2572bf508f
15 changed files with 149 additions and 53 deletions

View File

@ -42,6 +42,10 @@ export abstract class BaseAotCompilerHost<C extends BaseAotCompilerHostContext>
abstract fileNameToModuleName(importedFile: string, containingFile: string): string|null;
abstract toSummaryFileName(fileName: string, referringSrcFileName: string): string;
abstract fromSummaryFileName(fileName: string, referringLibFileName: string): string;
protected getSourceFile(filePath: string): ts.SourceFile {
const sf = this.program.getSourceFile(filePath);
if (!sf) {
@ -144,10 +148,6 @@ export abstract class BaseAotCompilerHost<C extends BaseAotCompilerHostContext>
return null;
}
getOutputFileName(sourceFilePath: string): string {
return sourceFilePath.replace(EXT, '') + '.d.ts';
}
isSourceFile(filePath: string): boolean {
const excludeRegex =
this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
@ -268,6 +268,12 @@ export class CompilerHost extends BaseAotCompilerHost<CompilerHostContext> {
};
}
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
return fileName.replace(EXT, '') + '.d.ts';
}
fromSummaryFileName(fileName: string, referringLibFileName: string): string { return fileName; }
calculateEmitPath(filePath: string): string {
// Write codegen in a directory structure matching the sources.
let root = this.options.basePath !;

View File

@ -130,6 +130,20 @@ export interface CompilerHost extends ts.CompilerHost {
* See ImportResolver.
*/
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string|null;
/**
* Converts a file name into a representation that should be stored in a summary file.
* This has to include changing the suffix as well.
* E.g.
* `some_file.ts` -> `some_file.d.ts`
*
* @param referringSrcFileName the soure file that refers to fileName
*/
toSummaryFileName(fileName: string, referringSrcFileName: string): string;
/**
* Converts a fileName that was processed by `toSummaryFileName` back into a real fileName
* given the fileName of the library that is referrig to it.
*/
fromSummaryFileName(fileName: string, referringLibFileName: string): string;
/**
* Load a referenced resource either statically or asynchronously. If the host returns a
* `Promise<string>` it is assumed the user of the corresponding `Program` will call

View File

@ -24,6 +24,8 @@ export function createCompilerHost(
host.moduleNameToFileName = mixin.moduleNameToFileName.bind(mixin);
host.fileNameToModuleName = mixin.fileNameToModuleName.bind(mixin);
host.toSummaryFileName = mixin.toSummaryFileName.bind(mixin);
host.fromSummaryFileName = mixin.fromSummaryFileName.bind(mixin);
// Make sure we do not `host.realpath()` from TS as we do not want to resolve symlinks.
// https://github.com/Microsoft/TypeScript/issues/9552
@ -109,9 +111,15 @@ class CompilerHostMixin {
let moduleName: string;
if (importedFilePackagName === containingFilePackageName) {
moduleName = dotRelative(
path.dirname(stripRootDir(this.rootDirs, containingFile)),
stripRootDir(this.rootDirs, importedFile));
const rootedContainingFile = stripRootDir(this.rootDirs, containingFile);
const rootedImportedFile = stripRootDir(this.rootDirs, importedFile);
if (rootedContainingFile !== containingFile && rootedImportedFile !== importedFile) {
// if both files are contained in the `rootDirs`, then strip the rootDirs
containingFile = rootedContainingFile;
importedFile = rootedImportedFile;
}
moduleName = dotRelative(path.dirname(containingFile), importedFile);
} else if (importedFilePackagName) {
moduleName = stripNodeModulesPrefix(importedFile);
} else {
@ -120,6 +128,18 @@ class CompilerHostMixin {
}
return moduleName;
}
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
return this.fileNameToModuleName(fileName, referringSrcFileName);
}
fromSummaryFileName(fileName: string, referringLibFileName: string): string {
const resolved = this.moduleNameToFileName(fileName, referringLibFileName);
if (!resolved) {
throw new Error(`Could not resolve ${fileName} from ${referringLibFileName}`);
}
return resolved;
}
}
interface ModuleFilenameResolutionHost extends ts.ModuleResolutionHost {
@ -189,6 +209,11 @@ function stripNodeModulesPrefix(filePath: string): string {
return filePath.replace(/.*node_modules\//, '');
}
function getNodeModulesPrefix(filePath: string): string|null {
const match = /.*node_modules\//.exec(filePath);
return match ? match[1] : null;
}
function normalizePath(p: string): string {
return path.normalize(path.join(p, '.')).replace(/\\/g, '/');
}

View File

@ -314,6 +314,14 @@ class AotCompilerHostImpl extends BaseAotCompilerHost<CompilerHost> {
fileNameToModuleName(importedFile: string, containingFile: string): string|null {
return this.context.fileNameToModuleName(importedFile, containingFile);
}
toSummaryFileName(fileName: string, referringSrcFileName: string): string {
return this.context.toSummaryFileName(fileName, referringSrcFileName);
}
fromSummaryFileName(fileName: string, referringLibFileName: string): string {
return this.context.fromSummaryFileName(fileName, referringLibFileName);
}
}
export function createProgram(

View File

@ -105,7 +105,8 @@ const summaryResolver = new AotSummaryResolver(
{
loadSummary(filePath: string) { return null; },
isSourceFile(sourceFilePath: string) { return true; },
getOutputFileName(sourceFilePath: string) { return sourceFilePath; }
toSummaryFileName(sourceFilePath: string) { return sourceFilePath; },
fromSummaryFileName(filePath: string): string{return filePath;},
},
staticSymbolCache);

View File

@ -67,8 +67,13 @@ describe('NgCompilerHost', () => {
]
}
});
// both files are in the rootDirs
expect(ngHostWithMultipleRoots.fileNameToModuleName('/tmp/src/b/b.ts', '/tmp/src/a/a.ts'))
.toBe('./b');
// one file is not in the rootDirs
expect(ngHostWithMultipleRoots.fileNameToModuleName('/tmp/src/c/c.ts', '/tmp/src/a/a.ts'))
.toBe('../c/c');
});
it('should error if accessing a source file from a package', () => {