Skip to content

Commit 7f004ad

Browse files
authored
Merge pull request #33380 from microsoft/isolatedModules
With --isolatedModules, --declaration emit is now allowed and builder handles it for incremental compilation
2 parents e60d28e + 0019cee commit 7f004ad

File tree

9 files changed

+442
-47
lines changed

9 files changed

+442
-47
lines changed

Diff for: src/compiler/builder.ts

+29-3
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,7 @@ namespace ts {
173173
const compilerOptions = newProgram.getCompilerOptions();
174174
state.compilerOptions = compilerOptions;
175175
// With --out or --outFile, any change affects all semantic diagnostics so no need to cache them
176-
// With --isolatedModules, emitting changed file doesnt emit dependent files so we cant know of dependent files to retrieve errors so dont cache the errors
177-
if (!compilerOptions.outFile && !compilerOptions.out && !compilerOptions.isolatedModules) {
176+
if (!compilerOptions.outFile && !compilerOptions.out) {
178177
state.semanticDiagnosticsPerFile = createMap<readonly Diagnostic[]>();
179178
}
180179
state.changedFilesSet = createMap<true>();
@@ -483,16 +482,43 @@ namespace ts {
483482
return !state.semanticDiagnosticsFromOldState.size;
484483
}
485484

485+
function isChangedSignagure(state: BuilderProgramState, path: Path) {
486+
const newSignature = Debug.assertDefined(state.currentAffectedFilesSignatures).get(path);
487+
const oldSignagure = Debug.assertDefined(state.fileInfos.get(path)).signature;
488+
return newSignature !== oldSignagure;
489+
}
490+
486491
/**
487492
* Iterate on referencing modules that export entities from affected file
488493
*/
489494
function forEachReferencingModulesOfExportOfAffectedFile(state: BuilderProgramState, affectedFile: SourceFile, fn: (state: BuilderProgramState, filePath: Path) => boolean) {
490495
// If there was change in signature (dts output) for the changed file,
491496
// then only we need to handle pending file emit
492-
if (!state.exportedModulesMap || state.affectedFiles!.length === 1 || !state.changedFilesSet.has(affectedFile.path)) {
497+
if (!state.exportedModulesMap || !state.changedFilesSet.has(affectedFile.path)) {
493498
return;
494499
}
495500

501+
if (!isChangedSignagure(state, affectedFile.path)) return;
502+
503+
// Since isolated modules dont change js files, files affected by change in signature is itself
504+
// But we need to cleanup semantic diagnostics and queue dts emit for affected files
505+
if (state.compilerOptions.isolatedModules) {
506+
const seenFileNamesMap = createMap<true>();
507+
seenFileNamesMap.set(affectedFile.path, true);
508+
const queue = BuilderState.getReferencedByPaths(state, affectedFile.resolvedPath);
509+
while (queue.length > 0) {
510+
const currentPath = queue.pop()!;
511+
if (!seenFileNamesMap.has(currentPath)) {
512+
seenFileNamesMap.set(currentPath, true);
513+
const result = fn(state, currentPath);
514+
if (result && isChangedSignagure(state, currentPath)) {
515+
const currentSourceFile = Debug.assertDefined(state.program).getSourceFileByPath(currentPath)!;
516+
queue.push(...BuilderState.getReferencedByPaths(state, currentSourceFile.resolvedPath));
517+
}
518+
}
519+
}
520+
}
521+
496522
Debug.assert(!!state.currentAffectedFilesExportedModulesMap);
497523
const seenFileAndExportsOfFile = createMap<true>();
498524
// Go through exported modules from cache first

Diff for: src/compiler/builderState.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ namespace ts.BuilderState {
466466
/**
467467
* Gets the files referenced by the the file path
468468
*/
469-
function getReferencedByPaths(state: Readonly<BuilderState>, referencedFilePath: Path) {
469+
export function getReferencedByPaths(state: Readonly<BuilderState>, referencedFilePath: Path) {
470470
return arrayFrom(mapDefinedIterator(state.referencedMap!.entries(), ([filePath, referencesInFile]) =>
471471
referencesInFile.has(referencedFilePath) ? filePath as Path : undefined
472472
));

Diff for: src/compiler/program.ts

-4
Original file line numberDiff line numberDiff line change
@@ -2807,10 +2807,6 @@ namespace ts {
28072807
}
28082808

28092809
if (options.isolatedModules) {
2810-
if (getEmitDeclarations(options)) {
2811-
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, getEmitDeclarationOptionName(options), "isolatedModules");
2812-
}
2813-
28142810
if (options.out) {
28152811
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules");
28162812
}

Diff for: src/testRunner/unittests/tsbuild/helpers.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ interface Symbol {
230230
}
231231
}
232232

233-
interface BuildInput {
233+
export interface BuildInput {
234234
fs: vfs.FileSystem;
235235
tick: () => void;
236236
rootNames: readonly string[];
@@ -239,7 +239,7 @@ interface Symbol {
239239
baselineBuildInfo?: true;
240240
}
241241

242-
function build({ fs, tick, rootNames, modifyFs, baselineSourceMap, baselineBuildInfo }: BuildInput) {
242+
export function tscBuild({ fs, tick, rootNames, modifyFs, baselineSourceMap, baselineBuildInfo }: BuildInput) {
243243
const actualReadFileMap = createMap<number>();
244244
modifyFs(fs);
245245
tick();
@@ -344,7 +344,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
344344
let host: fakes.SolutionBuilderHost;
345345
let initialWrittenFiles: Map<true>;
346346
before(() => {
347-
const result = build({
347+
const result = tscBuild({
348348
fs: projFs().shadow(),
349349
tick,
350350
rootNames,
@@ -390,7 +390,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
390390
tick();
391391
newFs = fs.shadow();
392392
tick();
393-
({ actualReadFileMap, host } = build({
393+
({ actualReadFileMap, host } = tscBuild({
394394
fs: newFs,
395395
tick,
396396
rootNames,
@@ -429,7 +429,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
429429
});
430430
}
431431
it(`Verify emit output file text is same when built clean`, () => {
432-
const { fs, writtenFiles } = build({
432+
const { fs, writtenFiles } = tscBuild({
433433
fs: newFs.shadow(),
434434
tick,
435435
rootNames,

Diff for: src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts

+51-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace ts {
2525
]
2626
},
2727
incrementalDtsChangedBuild: {
28-
modifyFs: fs => replaceText(fs, "/src/bar.ts", "param: string", ""),
28+
modifyFs: changeBarParam,
2929
expectedDiagnostics: [
3030
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
3131
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/tsconfig.json", "src/obj/bar.js", "src/bar.ts"],
@@ -36,5 +36,55 @@ namespace ts {
3636
baselineOnly: true,
3737
verifyDiagnostics: true
3838
});
39+
40+
verifyTsbuildOutput({
41+
scenario: "inferred type from transitive module with isolatedModules",
42+
projFs: () => projFs,
43+
time,
44+
tick,
45+
proj: "inferredTypeFromTransitiveModule",
46+
rootNames: ["/src"],
47+
initialBuild: { modifyFs: changeToIsolatedModules },
48+
incrementalDtsChangedBuild: { modifyFs: changeBarParam },
49+
baselineOnly: true,
50+
});
51+
52+
it("reports errors in files affected by change in signature", () => {
53+
const { fs, host } = tscBuild({
54+
fs: projFs.shadow(),
55+
tick,
56+
rootNames: ["/src"],
57+
modifyFs: fs => {
58+
changeToIsolatedModules(fs);
59+
appendText(fs, "/src/lazyIndex.ts", `
60+
import { default as bar } from './bar';
61+
bar("hello");`);
62+
}
63+
});
64+
host.assertErrors(/*empty*/);
65+
66+
tick();
67+
const { fs: newFs, host: newHost, writtenFiles } = tscBuild({
68+
fs: fs.shadow(),
69+
tick,
70+
rootNames: ["/src"],
71+
modifyFs: changeBarParam
72+
});
73+
// Has errors
74+
newHost.assertErrors({
75+
message: [Diagnostics.Expected_0_arguments_but_got_1, 0, 1],
76+
location: expectedLocationIndexOf(newFs, "/src/lazyIndex.ts", `"hello"`)
77+
});
78+
// No written files
79+
assert.equal(writtenFiles.size, 0);
80+
});
3981
});
82+
83+
function changeToIsolatedModules(fs: vfs.FileSystem) {
84+
replaceText(fs, "/src/tsconfig.json", `"incremental": true`, `"incremental": true, "isolatedModules": true`);
85+
}
86+
87+
function changeBarParam(fs: vfs.FileSystem) {
88+
replaceText(fs, "/src/bar.ts", "param: string", "");
89+
}
4090
}

0 commit comments

Comments
 (0)