Skip to content

Commit 5869662

Browse files
authored
Merge pull request microsoft#30721 from Microsoft/amdOut
Do not create multiple sourceFile to single outputFile with project redirect as the output file is included by default
2 parents 78b0956 + 602aec2 commit 5869662

File tree

8 files changed

+684
-27
lines changed

8 files changed

+684
-27
lines changed

src/compiler/program.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,8 +2266,13 @@ namespace ts {
22662266

22672267
let redirectedPath: Path | undefined;
22682268
if (refFile) {
2269-
const redirect = getProjectReferenceRedirect(fileName);
2270-
if (redirect) {
2269+
const redirectProject = getProjectReferenceRedirectProject(fileName);
2270+
if (redirectProject) {
2271+
if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) {
2272+
// Shouldnt create many to 1 mapping file in --out scenario
2273+
return undefined;
2274+
}
2275+
const redirect = getProjectReferenceOutputName(redirectProject, fileName);
22712276
fileName = redirect;
22722277
// Once we start redirecting to a file, we can potentially come back to it
22732278
// via a back-reference from another file in the .d.ts folder. If that happens we'll
@@ -2364,17 +2369,23 @@ namespace ts {
23642369
}
23652370

23662371
function getProjectReferenceRedirect(fileName: string): string | undefined {
2372+
const referencedProject = getProjectReferenceRedirectProject(fileName);
2373+
return referencedProject && getProjectReferenceOutputName(referencedProject, fileName);
2374+
}
2375+
2376+
function getProjectReferenceRedirectProject(fileName: string) {
23672377
// Ignore dts or any of the non ts files
23682378
if (!resolvedProjectReferences || !resolvedProjectReferences.length || fileExtensionIs(fileName, Extension.Dts) || !fileExtensionIsOneOf(fileName, supportedTSExtensions)) {
23692379
return undefined;
23702380
}
23712381

23722382
// If this file is produced by a referenced project, we need to rewrite it to
23732383
// look in the output folder of the referenced project rather than the input
2374-
const referencedProject = getResolvedProjectReferenceToRedirect(fileName);
2375-
if (!referencedProject) {
2376-
return undefined;
2377-
}
2384+
return getResolvedProjectReferenceToRedirect(fileName);
2385+
}
2386+
2387+
2388+
function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) {
23782389
const out = referencedProject.commandLine.options.outFile || referencedProject.commandLine.options.out;
23792390
return out ?
23802391
changeExtension(out, Extension.Dts) :

src/compiler/tsbuild.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ namespace ts {
394394
const projectStatus = createFileMap<UpToDateStatus>(toPath);
395395
const missingRoots = createMap<true>();
396396
let globalDependencyGraph: DependencyGraph | undefined;
397-
const writeFileName = (s: string) => host.trace && host.trace(s);
397+
const writeFileName = host.trace ? (s: string) => host.trace!(s) : undefined;
398398
let readFileWithCache = (f: string) => host.readFile(f);
399399
let projectCompilerOptions = baseCompilerOptions;
400400
const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions);
@@ -1129,7 +1129,7 @@ namespace ts {
11291129
let declDiagnostics: Diagnostic[] | undefined;
11301130
const reportDeclarationDiagnostics = (d: Diagnostic) => (declDiagnostics || (declDiagnostics = [])).push(d);
11311131
const outputFiles: OutputFile[] = [];
1132-
emitFilesAndReportErrors(program, reportDeclarationDiagnostics, writeFileName, /*reportSummary*/ undefined, (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }));
1132+
emitFilesAndReportErrors(program, reportDeclarationDiagnostics, /*writeFileName*/ undefined, /*reportSummary*/ undefined, (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }));
11331133
// Don't emit .d.ts if there are decl file errors
11341134
if (declDiagnostics) {
11351135
program.restoreState();
@@ -1138,7 +1138,7 @@ namespace ts {
11381138

11391139
// Actual Emit
11401140
const emitterDiagnostics = createDiagnosticCollection();
1141-
const emittedOutputs = createFileMap<true>(toPath as ToPath);
1141+
const emittedOutputs = createFileMap<string>(toPath as ToPath);
11421142
outputFiles.forEach(({ name, text, writeByteOrderMark }) => {
11431143
let priorChangeTime: Date | undefined;
11441144
if (!anyDtsChanged && isDeclarationFile(name)) {
@@ -1152,7 +1152,7 @@ namespace ts {
11521152
}
11531153
}
11541154

1155-
emittedOutputs.setValue(name, true);
1155+
emittedOutputs.setValue(name, name);
11561156
writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark);
11571157
if (priorChangeTime !== undefined) {
11581158
newestDeclarationFileContentChangedTime = newer(priorChangeTime, newestDeclarationFileContentChangedTime);
@@ -1165,6 +1165,11 @@ namespace ts {
11651165
return buildErrors(emitDiagnostics, BuildResultFlags.EmitErrors, "Emit");
11661166
}
11671167

1168+
if (writeFileName) {
1169+
emittedOutputs.forEach(name => listEmittedFile(configFile, name));
1170+
listFiles(program, writeFileName);
1171+
}
1172+
11681173
// Update time stamps for rest of the outputs
11691174
newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(configFile, newestDeclarationFileContentChangedTime, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs);
11701175

@@ -1182,13 +1187,21 @@ namespace ts {
11821187
function buildErrors(diagnostics: ReadonlyArray<Diagnostic>, errorFlags: BuildResultFlags, errorType: string) {
11831188
resultFlags |= errorFlags;
11841189
reportAndStoreErrors(proj, diagnostics);
1190+
// List files if any other build error using program (emit errors already report files)
1191+
if (writeFileName) listFiles(program, writeFileName);
11851192
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` });
11861193
afterProgramCreate(proj, program);
11871194
projectCompilerOptions = baseCompilerOptions;
11881195
return resultFlags;
11891196
}
11901197
}
11911198

1199+
function listEmittedFile(proj: ParsedCommandLine, file: string) {
1200+
if (writeFileName && proj.options.listEmittedFiles) {
1201+
writeFileName(`TSFILE: ${file}`);
1202+
}
1203+
}
1204+
11921205
function afterProgramCreate(proj: ResolvedConfigFileName, program: T) {
11931206
if (host.afterProgramEmitAndDiagnostics) {
11941207
host.afterProgramEmitAndDiagnostics(program);
@@ -1229,9 +1242,9 @@ namespace ts {
12291242
// Actual Emit
12301243
Debug.assert(!!outputFiles.length);
12311244
const emitterDiagnostics = createDiagnosticCollection();
1232-
const emittedOutputs = createFileMap<true>(toPath as ToPath);
1245+
const emittedOutputs = createFileMap<string>(toPath as ToPath);
12331246
outputFiles.forEach(({ name, text, writeByteOrderMark }) => {
1234-
emittedOutputs.setValue(name, true);
1247+
emittedOutputs.setValue(name, name);
12351248
writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark);
12361249
});
12371250
const emitDiagnostics = emitterDiagnostics.getDiagnostics();
@@ -1242,6 +1255,10 @@ namespace ts {
12421255
return BuildResultFlags.DeclarationOutputUnchanged | BuildResultFlags.EmitErrors;
12431256
}
12441257

1258+
if (writeFileName) {
1259+
emittedOutputs.forEach(name => listEmittedFile(config, name));
1260+
}
1261+
12451262
// Update timestamps for dts
12461263
const newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(config, minimumDate, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs);
12471264

@@ -1270,7 +1287,7 @@ namespace ts {
12701287
projectStatus.setValue(proj.options.configFilePath as ResolvedConfigFilePath, status);
12711288
}
12721289

1273-
function updateOutputTimestampsWorker(proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap<true>) {
1290+
function updateOutputTimestampsWorker(proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap<string>) {
12741291
const outputs = getAllProjectOutputs(proj, !host.useCaseSensitiveFileNames());
12751292
if (!skipOutputs || outputs.length !== skipOutputs.getSize()) {
12761293
if (options.verbose) {
@@ -1287,9 +1304,7 @@ namespace ts {
12871304
}
12881305

12891306
host.setModifiedTime(file, now);
1290-
if (proj.options.listEmittedFiles) {
1291-
writeFileName(`TSFILE: ${file}`);
1292-
}
1307+
listEmittedFile(proj, file);
12931308
}
12941309
}
12951310

src/compiler/watch.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ namespace ts {
121121
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
122122
}
123123

124+
export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) {
125+
if (program.getCompilerOptions().listFiles) {
126+
forEach(program.getSourceFiles(), file => {
127+
writeFileName(file.fileName);
128+
});
129+
}
130+
}
131+
124132
/**
125133
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
126134
*/
@@ -152,12 +160,7 @@ namespace ts {
152160
const filepath = getNormalizedAbsolutePath(file, currentDir);
153161
writeFileName(`TSFILE: ${filepath}`);
154162
});
155-
156-
if (program.getCompilerOptions().listFiles) {
157-
forEach(program.getSourceFiles(), file => {
158-
writeFileName(file.fileName);
159-
});
160-
}
163+
listFiles(program, writeFileName);
161164
}
162165

163166
if (reportSummary) {

src/testRunner/unittests/tsbuild/amdModulesWithOut.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,58 @@ ${internal} export enum internalEnum { a, b, c }`);
198198
modifyAgainFs: fs => replaceText(fs, sources[project.lib][source.ts][1], `export const`, `/*@internal*/ export const`),
199199
});
200200
});
201+
202+
describe("when the module resolution finds original source file", () => {
203+
function modifyFs(fs: vfs.FileSystem) {
204+
// Make lib to output to parent dir
205+
replaceText(fs, sources[project.lib][source.config], `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`);
206+
// Change reference to file1 module to resolve to lib/file1
207+
replaceText(fs, sources[project.app][source.ts][0], "file1", "lib/file1");
208+
}
209+
210+
const libOutputFile: OutputFile = [
211+
"/src/lib/module.js",
212+
"/src/lib/module.js.map",
213+
"/src/lib/module.d.ts",
214+
"/src/lib/module.d.ts.map",
215+
"/src/lib/module.tsbuildinfo"
216+
];
217+
verifyTsbuildOutput({
218+
scenario: "when the module resolution finds original source file",
219+
projFs: () => outFileFs,
220+
time,
221+
tick,
222+
proj: "amdModulesWithOut",
223+
rootNames: ["/src/app"],
224+
expectedMapFileNames: [
225+
libOutputFile[ext.jsmap],
226+
libOutputFile[ext.dtsmap],
227+
outputFiles[project.app][ext.jsmap],
228+
outputFiles[project.app][ext.dtsmap],
229+
],
230+
expectedBuildInfoFilesForSectionBaselines: [
231+
[libOutputFile[ext.buildinfo], libOutputFile[ext.js], libOutputFile[ext.dts]],
232+
[outputFiles[project.app][ext.buildinfo], outputFiles[project.app][ext.js], outputFiles[project.app][ext.dts]]
233+
],
234+
lastProjectOutputJs: outputFiles[project.app][ext.js],
235+
initialBuild: {
236+
modifyFs,
237+
expectedDiagnostics: [
238+
getExpectedDiagnosticForProjectsInBuild("src/lib/tsconfig.json", "src/app/tsconfig.json"),
239+
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/lib/tsconfig.json", "src/module.js"],
240+
[Diagnostics.Building_project_0, sources[project.lib][source.config]],
241+
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/app/tsconfig.json", "src/app/module.js"],
242+
[Diagnostics.Building_project_0, sources[project.app][source.config]],
243+
]
244+
},
245+
outputFiles: [
246+
...libOutputFile,
247+
...outputFiles[project.app]
248+
],
249+
baselineOnly: true,
250+
verifyDiagnostics: true
251+
});
252+
});
201253
});
202254
});
203255
}

src/testRunner/unittests/tsbuild/helpers.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,11 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
234234
incrementalDtsUnchangedBuild?: BuildState;
235235
incrementalHeaderChangedBuild?: BuildState;
236236
baselineOnly?: true;
237+
verifyDiagnostics?: true;
237238
}
238239

239240
export function verifyTsbuildOutput({
240-
scenario, projFs, time, tick, proj, rootNames, outputFiles, baselineOnly,
241+
scenario, projFs, time, tick, proj, rootNames, outputFiles, baselineOnly, verifyDiagnostics,
241242
expectedMapFileNames, expectedBuildInfoFilesForSectionBaselines, lastProjectOutputJs,
242243
initialBuild, incrementalDtsChangedBuild, incrementalDtsUnchangedBuild, incrementalHeaderChangedBuild
243244
}: VerifyTsBuildInput) {
@@ -264,7 +265,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
264265
host = undefined!;
265266
});
266267
describe("initialBuild", () => {
267-
if (!baselineOnly) {
268+
if (!baselineOnly || verifyDiagnostics) {
268269
it(`verify diagnostics`, () => {
269270
host.assertDiagnosticMessages(...(initialBuild.expectedDiagnostics || emptyArray));
270271
});

src/testRunner/unittests/tsbuild/sample.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,14 @@ export class cNew {}`);
427427
builder.buildAllProjects();
428428
assert.deepEqual(host.traces, [
429429
"TSFILE: /src/core/anotherModule.js",
430-
"TSFILE: /src/core/anotherModule.d.ts",
431430
"TSFILE: /src/core/anotherModule.d.ts.map",
431+
"TSFILE: /src/core/anotherModule.d.ts",
432432
"TSFILE: /src/core/index.js",
433-
"TSFILE: /src/core/index.d.ts",
434433
"TSFILE: /src/core/index.d.ts.map",
434+
"TSFILE: /src/core/index.d.ts",
435435
"TSFILE: /src/core/tsconfig.tsbuildinfo",
436-
"TSFILE: /src/logic/index.js",
437436
"TSFILE: /src/logic/index.js.map",
437+
"TSFILE: /src/logic/index.js",
438438
"TSFILE: /src/logic/index.d.ts",
439439
"TSFILE: /src/logic/tsconfig.tsbuildinfo",
440440
"TSFILE: /src/tests/index.js",

src/testRunner/unittests/tsbuild/transitiveReferences.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export const b = new A();`);
6565
const expectedFileTraces = [
6666
...getLibs(),
6767
"/src/a.ts",
68+
...getLibs(),
69+
"/src/b.ts"
6870
];
6971
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "node"),
7072
allExpectedOutputs,

0 commit comments

Comments
 (0)