Skip to content

Commit b6129b4

Browse files
committed
Fix the project reference verification to include json source file version check
1 parent aac961e commit b6129b4

File tree

4 files changed

+56
-14
lines changed

4 files changed

+56
-14
lines changed

src/compiler/core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ namespace ts {
842842
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
843843
}
844844

845-
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
845+
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
846846
if (!array1 || !array2) {
847847
return array1 === array2;
848848
}
@@ -852,7 +852,7 @@ namespace ts {
852852
}
853853

854854
for (let i = 0; i < array1.length; i++) {
855-
if (!equalityComparer(array1[i], array2[i])) {
855+
if (!equalityComparer(array1[i], array2[i], i)) {
856856
return false;
857857
}
858858
}

src/compiler/program.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ namespace ts {
455455
}
456456

457457
// If project references dont match
458-
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences)) {
458+
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) {
459459
return false;
460460
}
461461

@@ -483,9 +483,27 @@ namespace ts {
483483

484484
return true;
485485

486-
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
487-
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
488-
hasInvalidatedResolution(sourceFile.path);
486+
function sourceFileNotUptoDate(sourceFile: SourceFile) {
487+
return !sourceFileVersionUptoDate(sourceFile) ||
488+
hasInvalidatedResolution(sourceFile.resolvedPath || sourceFile.path);
489+
}
490+
491+
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
492+
return sourceFile.version === getSourceVersion(sourceFile.resolvedPath || sourceFile.path);
493+
}
494+
495+
function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
496+
if (!projectReferenceIsEqualTo(oldRef, newRef)) {
497+
return false;
498+
}
499+
const oldResolvedRef = program!.getResolvedProjectReferences()![index];
500+
if (oldResolvedRef) {
501+
// If sourceFile for the oldResolvedRef existed, check the version for uptodate
502+
return sourceFileVersionUptoDate(oldResolvedRef.sourceFile);
503+
}
504+
// In old program, not able to resolve project reference path,
505+
// so if config file doesnt exist, it is uptodate.
506+
return !fileExists(resolveProjectReferencePath(oldRef));
489507
}
490508
}
491509

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,10 @@ interface Array<T> {}`
187187
}
188188

189189
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
190+
checkMapKeys(caption, arrayToMap(actual, identity), expected);
190191
assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`);
191192
for (const f of expected) {
192-
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
193+
assert.isTrue(contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
193194
}
194195
}
195196

src/testRunner/unittests/tsbuildWatchMode.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ namespace ts.tscWatch {
3434
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
3535
}
3636

37+
function projectFileName(subProject: SubProject, baseFileName: string) {
38+
return `${projectPath(subProject)}/${baseFileName}`;
39+
}
40+
3741
function projectFile(subProject: SubProject, baseFileName: string): File {
3842
return {
3943
path: projectFilePath(subProject, baseFileName),
@@ -391,10 +395,10 @@ let x: string = 10;`);
391395
});
392396

393397
describe("tsc-watch works with project references", () => {
394-
const coreIndexDts = projectFilePath(SubProject.core, "index.d.ts");
395-
const coreAnotherModuleDts = projectFilePath(SubProject.core, "anotherModule.d.ts");
396-
const logicIndexDts = projectFilePath(SubProject.logic, "index.d.ts");
397-
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat(coreIndexDts, coreAnotherModuleDts, logicIndexDts);
398+
const coreIndexDts = projectFileName(SubProject.core, "index.d.ts");
399+
const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts");
400+
const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts");
401+
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
398402
const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests));
399403

400404
function createSolution() {
@@ -432,7 +436,7 @@ let x: string = 10;`);
432436
}
433437

434438
function verifyDependencies(watch: () => BuilderProgram, filePath: string, expected: ReadonlyArray<string>) {
435-
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!).map(f => f.toLocaleLowerCase()), expected);
439+
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!), expected);
436440
}
437441

438442
describe("invoking when references are already built", () => {
@@ -447,7 +451,7 @@ let x: string = 10;`);
447451
});
448452

449453
it("local edit in ts file, result in watch compilation because logic.d.ts is written", () => {
450-
const { host, solutionBuilder } = createSolutionAndWatchMode();
454+
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
451455
host.writeFile(logic[1].path, `${logic[1].content}
452456
function foo() {
453457
}`);
@@ -456,10 +460,11 @@ function foo() {
456460

457461
host.checkTimeoutQueueLengthAndRun(1); // not ideal, but currently because of d.ts but no new file is written
458462
checkOutputErrorsIncremental(host, emptyArray);
463+
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
459464
});
460465

461466
it("non local edit in ts file, rebuilds in watch compilation", () => {
462-
const { host, solutionBuilder } = createSolutionAndWatchMode();
467+
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
463468
host.writeFile(logic[1].path, `${logic[1].content}
464469
export function gfoo() {
465470
}`);
@@ -468,8 +473,26 @@ export function gfoo() {
468473

469474
host.checkTimeoutQueueLengthAndRun(1);
470475
checkOutputErrorsIncremental(host, emptyArray);
476+
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
471477
});
472478

479+
it("change in project reference config file builds correctly", () => {
480+
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
481+
host.writeFile(logic[0].path, JSON.stringify({
482+
compilerOptions: { composite: true, declaration: true, declarationDir: "decls" },
483+
references: [{ path: "../core" }]
484+
}));
485+
solutionBuilder.invalidateProject(logic[0].path, ConfigFileProgramReloadLevel.Full);
486+
solutionBuilder.buildInvalidatedProject();
487+
488+
host.checkTimeoutQueueLengthAndRun(1);
489+
checkOutputErrorsIncremental(host, [
490+
// TODO: #26036
491+
// The error is reported in d.ts file because it isnt resolved from ts file path, but is resolved from .d.ts file
492+
"sample1/logic/decls/index.d.ts(2,22): error TS2307: Cannot find module '../core/anotherModule'.\n"
493+
]);
494+
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
495+
});
473496
});
474497
});
475498
});

0 commit comments

Comments
 (0)