Skip to content

Commit 45899ad

Browse files
authored
Merge pull request #29569 from Microsoft/inputFiles
Make getters for js, sourcemap, dts and dts map text for prepend nodes so as to avoid unnecessary multiple file reads
2 parents 0ddcab3 + 1b12a85 commit 45899ad

File tree

9 files changed

+142
-38
lines changed

9 files changed

+142
-38
lines changed

src/compiler/emitter.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,22 @@ namespace ts {
3838
}
3939
}
4040

41+
/*@internal*/
42+
export function getOutputPathsForBundle(options: CompilerOptions, forceDtsPaths: boolean): EmitFileNames {
43+
const outPath = options.outFile || options.out!;
44+
const jsFilePath = options.emitDeclarationOnly ? undefined : outPath;
45+
const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options);
46+
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined;
47+
const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
48+
const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined;
49+
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath };
50+
}
51+
4152
/*@internal*/
4253
export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames {
4354
const options = host.getCompilerOptions();
4455
if (sourceFile.kind === SyntaxKind.Bundle) {
45-
const outPath = options.outFile || options.out!;
46-
const jsFilePath = options.emitDeclarationOnly ? undefined : outPath;
47-
const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options);
48-
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined;
49-
const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
50-
const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined;
51-
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath };
56+
return getOutputPathsForBundle(options, forceDtsPaths);
5257
}
5358
else {
5459
const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options));

src/compiler/factory.ts

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,41 +2630,88 @@ namespace ts {
26302630
}
26312631

26322632
export function createUnparsedSourceFile(text: string): UnparsedSource;
2633+
export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts"): UnparsedSource;
26332634
export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
2634-
export function createUnparsedSourceFile(text: string, mapPath?: string, map?: string): UnparsedSource {
2635+
export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, map?: string): UnparsedSource {
26352636
const node = <UnparsedSource>createNode(SyntaxKind.UnparsedSource);
2636-
node.text = text;
2637-
node.sourceMapPath = mapPath;
2638-
node.sourceMapText = map;
2637+
if (!isString(textOrInputFiles)) {
2638+
Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts");
2639+
node.fileName = mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath;
2640+
node.sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath;
2641+
Object.defineProperties(node, {
2642+
text: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; } },
2643+
sourceMapText: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; } },
2644+
});
2645+
}
2646+
else {
2647+
node.text = textOrInputFiles;
2648+
node.sourceMapPath = mapPathOrType;
2649+
node.sourceMapText = map;
2650+
}
26392651
return node;
26402652
}
26412653
export function createInputFiles(
2642-
javascript: string,
2643-
declaration: string
2654+
javascriptText: string,
2655+
declarationText: string
2656+
): InputFiles;
2657+
export function createInputFiles(
2658+
readFileText: (path: string) => string | undefined,
2659+
javascriptPath: string,
2660+
javascriptMapPath: string | undefined,
2661+
declarationPath: string,
2662+
declarationMapPath: string | undefined,
26442663
): InputFiles;
26452664
export function createInputFiles(
2646-
javascript: string,
2647-
declaration: string,
2665+
javascriptText: string,
2666+
declarationText: string,
26482667
javascriptMapPath: string | undefined,
26492668
javascriptMapText: string | undefined,
26502669
declarationMapPath: string | undefined,
26512670
declarationMapText: string | undefined
26522671
): InputFiles;
26532672
export function createInputFiles(
2654-
javascript: string,
2655-
declaration: string,
2673+
javascriptTextOrReadFileText: string | ((path: string) => string | undefined),
2674+
declarationTextOrJavascriptPath: string,
26562675
javascriptMapPath?: string,
2657-
javascriptMapText?: string,
2676+
javascriptMapTextOrDeclarationPath?: string,
26582677
declarationMapPath?: string,
26592678
declarationMapText?: string
26602679
): InputFiles {
26612680
const node = <InputFiles>createNode(SyntaxKind.InputFiles);
2662-
node.javascriptText = javascript;
2663-
node.javascriptMapPath = javascriptMapPath;
2664-
node.javascriptMapText = javascriptMapText;
2665-
node.declarationText = declaration;
2666-
node.declarationMapPath = declarationMapPath;
2667-
node.declarationMapText = declarationMapText;
2681+
if (!isString(javascriptTextOrReadFileText)) {
2682+
const cache = createMap<string | false>();
2683+
const textGetter = (path: string | undefined) => {
2684+
if (path === undefined) return undefined;
2685+
let value = cache.get(path);
2686+
if (value === undefined) {
2687+
value = javascriptTextOrReadFileText(path);
2688+
cache.set(path, value !== undefined ? value : false);
2689+
}
2690+
return value !== false ? value as string : undefined;
2691+
};
2692+
const definedTextGetter = (path: string) => {
2693+
const result = textGetter(path);
2694+
return result !== undefined ? result : `/* Input file ${path} was missing */\r\n`;
2695+
};
2696+
node.javascriptPath = declarationTextOrJavascriptPath;
2697+
node.javascriptMapPath = javascriptMapPath;
2698+
node.declarationPath = Debug.assertDefined(javascriptMapTextOrDeclarationPath);
2699+
node.declarationMapPath = declarationMapPath;
2700+
Object.defineProperties(node, {
2701+
javascriptText: { get() { return definedTextGetter(declarationTextOrJavascriptPath); } },
2702+
javascriptMapText: { get() { return textGetter(javascriptMapPath); } }, // TODO:: if there is inline sourceMap in jsFile, use that
2703+
declarationText: { get() { return definedTextGetter(Debug.assertDefined(javascriptMapTextOrDeclarationPath)); } },
2704+
declarationMapText: { get() { return textGetter(declarationMapPath); } } // TODO:: if there is inline sourceMap in dtsFile, use that
2705+
});
2706+
}
2707+
else {
2708+
node.javascriptText = javascriptTextOrReadFileText;
2709+
node.javascriptMapPath = javascriptMapPath;
2710+
node.javascriptMapText = javascriptMapTextOrDeclarationPath;
2711+
node.declarationText = declarationTextOrJavascriptPath;
2712+
node.declarationMapPath = declarationMapPath;
2713+
node.declarationMapText = declarationMapText;
2714+
}
26682715
return node;
26692716
}
26702717

src/compiler/program.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,14 +1456,12 @@ namespace ts {
14561456
// Upstream project didn't have outFile set -- skip (error will have been issued earlier)
14571457
if (!out) continue;
14581458

1459-
const dtsFilename = changeExtension(out, ".d.ts");
1460-
const js = host.readFile(out) || `/* Input file ${out} was missing */\r\n`;
1461-
const jsMapPath = out + ".map"; // TODO: try to read sourceMappingUrl comment from the file
1462-
const jsMap = host.readFile(jsMapPath);
1463-
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
1464-
const dtsMapPath = dtsFilename + ".map";
1465-
const dtsMap = host.readFile(dtsMapPath);
1466-
const node = createInputFiles(js, dts, jsMap && jsMapPath, jsMap, dtsMap && dtsMapPath, dtsMap);
1459+
const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true);
1460+
const node = createInputFiles(fileName => {
1461+
const path = toPath(fileName);
1462+
const sourceFile = getSourceFileByPath(path);
1463+
return sourceFile ? sourceFile.text : filesByName.has(path) ? undefined : host.readFile(path);
1464+
}, jsFilePath! , sourceMapFilePath, declarationFilePath! , declarationMapPath);
14671465
nodes.push(node);
14681466
}
14691467
}

src/compiler/transformers/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ namespace ts {
207207
}
208208
), mapDefined(node.prepends, prepend => {
209209
if (prepend.kind === SyntaxKind.InputFiles) {
210-
return createUnparsedSourceFile(prepend.declarationText, prepend.declarationMapPath, prepend.declarationMapText);
210+
return createUnparsedSourceFile(prepend, "dts");
211211
}
212212
}));
213213
bundle.syntheticFileReferences = [];

src/compiler/transformers/ts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ namespace ts {
101101
function transformBundle(node: Bundle) {
102102
return createBundle(node.sourceFiles.map(transformSourceFile), mapDefined(node.prepends, prepend => {
103103
if (prepend.kind === SyntaxKind.InputFiles) {
104-
return createUnparsedSourceFile(prepend.javascriptText, prepend.javascriptMapPath, prepend.javascriptMapText);
104+
return createUnparsedSourceFile(prepend, "js");
105105
}
106106
return prepend;
107107
}));

src/compiler/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,16 +2761,19 @@ namespace ts {
27612761

27622762
export interface InputFiles extends Node {
27632763
kind: SyntaxKind.InputFiles;
2764+
javascriptPath?: string;
27642765
javascriptText: string;
27652766
javascriptMapPath?: string;
27662767
javascriptMapText?: string;
2768+
declarationPath?: string;
27672769
declarationText: string;
27682770
declarationMapPath?: string;
27692771
declarationMapText?: string;
27702772
}
27712773

27722774
export interface UnparsedSource extends Node {
27732775
kind: SyntaxKind.UnparsedSource;
2776+
fileName?: string;
27742777
text: string;
27752778
sourceMapPath?: string;
27762779
sourceMapText?: string;

src/testRunner/unittests/tsbuild.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,11 +469,20 @@ export const b = new A();`);
469469

470470
describe("unittests:: tsbuild - baseline sectioned sourcemaps", () => {
471471
let fs: vfs.FileSystem | undefined;
472+
const actualReadFileMap = createMap<number>();
472473
before(() => {
473474
fs = outFileFs.shadow();
474475
const host = new fakes.SolutionBuilderHost(fs);
475476
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
476477
host.clearDiagnostics();
478+
const originalReadFile = host.readFile;
479+
host.readFile = path => {
480+
// Dont record libs
481+
if (path.startsWith("/src/")) {
482+
actualReadFileMap.set(path, (actualReadFileMap.get(path) || 0) + 1);
483+
}
484+
return originalReadFile.call(host, path);
485+
};
477486
builder.buildAllProjects();
478487
host.assertDiagnosticMessages(/*none*/);
479488
});
@@ -485,6 +494,38 @@ export const b = new A();`);
485494
// tslint:disable-next-line:no-null-keyword
486495
Harness.Baseline.runBaseline("outfile-concat.js", patch ? vfs.formatPatch(patch) : null);
487496
});
497+
it("verify readFile calls", () => {
498+
const expected = [
499+
// Configs
500+
"/src/third/tsconfig.json",
501+
"/src/second/tsconfig.json",
502+
"/src/first/tsconfig.json",
503+
504+
// Source files
505+
"/src/third/third_part1.ts",
506+
"/src/second/second_part1.ts",
507+
"/src/second/second_part2.ts",
508+
"/src/first/first_PART1.ts",
509+
"/src/first/first_part2.ts",
510+
"/src/first/first_part3.ts",
511+
512+
// outputs
513+
"/src/first/bin/first-output.js",
514+
"/src/first/bin/first-output.js.map",
515+
"/src/first/bin/first-output.d.ts",
516+
"/src/first/bin/first-output.d.ts.map",
517+
"/src/2/second-output.js",
518+
"/src/2/second-output.js.map",
519+
"/src/2/second-output.d.ts",
520+
"/src/2/second-output.d.ts.map"
521+
];
522+
523+
assert.equal(actualReadFileMap.size, expected.length, `Expected: ${JSON.stringify(expected)} \nActual: ${JSON.stringify(arrayFrom(actualReadFileMap.entries()))}`);
524+
expected.forEach(expectedValue => {
525+
const actual = actualReadFileMap.get(expectedValue);
526+
assert.equal(actual, 1, `Mismatch in read file call number for: ${expectedValue}\nExpected: ${JSON.stringify(expected)} \nActual: ${JSON.stringify(arrayFrom(actualReadFileMap.entries()))}`);
527+
});
528+
});
488529
});
489530

490531
describe("unittests:: tsbuild - downstream prepend projects always get rebuilt", () => {

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,15 +1726,18 @@ declare namespace ts {
17261726
}
17271727
interface InputFiles extends Node {
17281728
kind: SyntaxKind.InputFiles;
1729+
javascriptPath?: string;
17291730
javascriptText: string;
17301731
javascriptMapPath?: string;
17311732
javascriptMapText?: string;
1733+
declarationPath?: string;
17321734
declarationText: string;
17331735
declarationMapPath?: string;
17341736
declarationMapText?: string;
17351737
}
17361738
interface UnparsedSource extends Node {
17371739
kind: SyntaxKind.UnparsedSource;
1740+
fileName?: string;
17381741
text: string;
17391742
sourceMapPath?: string;
17401743
sourceMapText?: string;
@@ -3979,9 +3982,11 @@ declare namespace ts {
39793982
function updateCommaList(node: CommaListExpression, elements: ReadonlyArray<Expression>): CommaListExpression;
39803983
function createBundle(sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource | InputFiles>): Bundle;
39813984
function createUnparsedSourceFile(text: string): UnparsedSource;
3985+
function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts"): UnparsedSource;
39823986
function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
3983-
function createInputFiles(javascript: string, declaration: string): InputFiles;
3984-
function createInputFiles(javascript: string, declaration: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
3987+
function createInputFiles(javascriptText: string, declarationText: string): InputFiles;
3988+
function createInputFiles(readFileText: (path: string) => string | undefined, javascriptPath: string, javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined): InputFiles;
3989+
function createInputFiles(javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
39853990
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource>): Bundle;
39863991
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>): CallExpression;
39873992
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>, param: ParameterDeclaration, paramValue: Expression): CallExpression;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,15 +1726,18 @@ declare namespace ts {
17261726
}
17271727
interface InputFiles extends Node {
17281728
kind: SyntaxKind.InputFiles;
1729+
javascriptPath?: string;
17291730
javascriptText: string;
17301731
javascriptMapPath?: string;
17311732
javascriptMapText?: string;
1733+
declarationPath?: string;
17321734
declarationText: string;
17331735
declarationMapPath?: string;
17341736
declarationMapText?: string;
17351737
}
17361738
interface UnparsedSource extends Node {
17371739
kind: SyntaxKind.UnparsedSource;
1740+
fileName?: string;
17381741
text: string;
17391742
sourceMapPath?: string;
17401743
sourceMapText?: string;
@@ -3979,9 +3982,11 @@ declare namespace ts {
39793982
function updateCommaList(node: CommaListExpression, elements: ReadonlyArray<Expression>): CommaListExpression;
39803983
function createBundle(sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource | InputFiles>): Bundle;
39813984
function createUnparsedSourceFile(text: string): UnparsedSource;
3985+
function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts"): UnparsedSource;
39823986
function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
3983-
function createInputFiles(javascript: string, declaration: string): InputFiles;
3984-
function createInputFiles(javascript: string, declaration: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
3987+
function createInputFiles(javascriptText: string, declarationText: string): InputFiles;
3988+
function createInputFiles(readFileText: (path: string) => string | undefined, javascriptPath: string, javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined): InputFiles;
3989+
function createInputFiles(javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
39853990
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource>): Bundle;
39863991
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>): CallExpression;
39873992
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>, param: ParameterDeclaration, paramValue: Expression): CallExpression;

0 commit comments

Comments
 (0)