fix(compiler): make sure our out path calculation is correct

This commit is contained in:
Tobias Bosch 2017-09-28 11:42:58 -07:00 committed by Victor Berchet
parent ec2be5dccb
commit 2f6ae527d1
2 changed files with 67 additions and 29 deletions

View File

@ -210,7 +210,15 @@ class AngularCompilerProgram implements Program {
return emitResult;
}
const srcToOutPath = this.createSrcToOutPathMapper(outSrcMapping);
let sampleSrcFileName: string|undefined;
let sampleOutFileName: string|undefined;
if (outSrcMapping.length) {
sampleSrcFileName = outSrcMapping[0].sourceFile.fileName;
sampleOutFileName = outSrcMapping[0].outFileName;
}
const srcToOutPath =
createSrcToOutPathMapper(this.options.outDir, sampleSrcFileName, sampleOutFileName);
if (emitFlags & EmitFlags.Codegen) {
genFiles.forEach(gf => {
if (gf.source) {
@ -287,29 +295,6 @@ class AngularCompilerProgram implements Program {
return {before: beforeTs, after: afterTs};
}
private createSrcToOutPathMapper(outSrcMappings:
Array<{sourceFile: ts.SourceFile, outFileName: string}>):
(srcFileName: string) => string {
let srcToOutPath: (srcFileName: string) => string;
if (this.options.outDir) {
// TODO(tbosch): talk to TypeScript team to expose their logic for calculating the `rootDir`
// if none was specified.
if (outSrcMappings.length === 0) {
throw new Error(`Can't calculate the rootDir without at least one outSrcMapping. `);
}
const firstEntry = outSrcMappings[0];
const entrySrcDir = path.dirname(firstEntry.sourceFile.fileName);
const entryOutDir = path.dirname(firstEntry.outFileName);
const commonSuffix = longestCommonSuffix(entrySrcDir, entryOutDir);
const rootDir = entrySrcDir.substring(0, entrySrcDir.length - commonSuffix.length);
srcToOutPath = (srcFileName) =>
path.resolve(this.options.outDir, path.relative(rootDir, srcFileName));
} else {
srcToOutPath = (srcFileName) => srcFileName;
}
return srcToOutPath;
}
private initSync() {
if (this._analyzedModules) {
return;
@ -567,12 +552,42 @@ function getNgOptionDiagnostics(options: CompilerOptions): Diagnostic[] {
return [];
}
function longestCommonSuffix(a: string, b: string): string {
let len = 0;
while (a.charCodeAt(a.length - 1 - len) === b.charCodeAt(b.length - 1 - len)) {
len++;
/**
* Returns a function that can adjust a path from source path to out path,
* based on an existing mapping from source to out path.
*
* TODO(tbosch): talk to the TypeScript team to expose their logic for calculating the `rootDir`
* if none was specified.
*
* @param outDir
* @param outSrcMappings
*/
export function createSrcToOutPathMapper(
outDir: string | undefined, sampleSrcFileName: string | undefined,
sampleOutFileName: string | undefined): (srcFileName: string) => string {
let srcToOutPath: (srcFileName: string) => string;
if (outDir) {
if (sampleSrcFileName == null || sampleOutFileName == null) {
throw new Error(`Can't calculate the rootDir without a sample srcFileName / outFileName. `);
}
const srcFileDir = path.dirname(sampleSrcFileName);
const outFileDir = path.dirname(sampleOutFileName);
if (srcFileDir === outFileDir) {
return (srcFileName) => srcFileName;
}
const srcDirParts = srcFileDir.split(path.sep);
const outDirParts = outFileDir.split(path.sep);
// calculate the common suffix
let i = 0;
while (i < Math.min(srcDirParts.length, outDirParts.length) &&
srcDirParts[srcDirParts.length - 1 - i] === outDirParts[outDirParts.length - 1 - i])
i++;
const rootDir = srcDirParts.slice(0, srcDirParts.length - i).join(path.sep);
srcToOutPath = (srcFileName) => path.resolve(outDir, path.relative(rootDir, srcFileName));
} else {
srcToOutPath = (srcFileName) => srcFileName;
}
return a.substring(a.length - len);
return srcToOutPath;
}
export function i18nExtract(

View File

@ -12,6 +12,7 @@ import * as path from 'path';
import * as ts from 'typescript';
import {CompilerHost} from '../../src/transformers/api';
import {createSrcToOutPathMapper} from '../../src/transformers/program';
import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util';
import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support';
@ -361,4 +362,26 @@ describe('ng program', () => {
testSupport.shouldNotExist('build/node_modules/lib/index.ngfactory.d.ts');
testSupport.shouldNotExist('build/node_modules/lib/index.ngsummary.json');
});
describe('createSrcToOutPathMapper', () => {
it('should return identity mapping if no outDir is present', () => {
const mapper = createSrcToOutPathMapper(undefined, undefined, undefined);
expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js');
});
it('should return identity mapping if first src and out fileName have same dir', () => {
const mapper = createSrcToOutPathMapper('/tmp', '/tmp/a/x.ts', '/tmp/a/x.js');
expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js');
});
it('should adjust the filename if the outDir is inside of the rootDir', () => {
const mapper = createSrcToOutPathMapper('/tmp/out', '/tmp/a/x.ts', '/tmp/out/a/x.js');
expect(mapper('/tmp/b/y.js')).toBe('/tmp/out/b/y.js');
});
it('should adjust the filename if the outDir is outside of the rootDir', () => {
const mapper = createSrcToOutPathMapper('/out', '/tmp/a/x.ts', '/a/x.js');
expect(mapper('/tmp/b/y.js')).toBe('/out/b/y.js');
});
});
});