Fix the project reference verification to include json source file version check

This commit is contained in:
Sheetal Nandi 2018-09-14 17:12:22 -07:00
parent aac961e60d
commit b6129b452f
4 changed files with 56 additions and 14 deletions

View File

@ -842,7 +842,7 @@ namespace ts {
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
}
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
if (!array1 || !array2) {
return array1 === array2;
}
@ -852,7 +852,7 @@ namespace ts {
}
for (let i = 0; i < array1.length; i++) {
if (!equalityComparer(array1[i], array2[i])) {
if (!equalityComparer(array1[i], array2[i], i)) {
return false;
}
}

View File

@ -455,7 +455,7 @@ namespace ts {
}
// If project references dont match
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences)) {
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) {
return false;
}
@ -483,9 +483,27 @@ namespace ts {
return true;
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
hasInvalidatedResolution(sourceFile.path);
function sourceFileNotUptoDate(sourceFile: SourceFile) {
return !sourceFileVersionUptoDate(sourceFile) ||
hasInvalidatedResolution(sourceFile.resolvedPath || sourceFile.path);
}
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
return sourceFile.version === getSourceVersion(sourceFile.resolvedPath || sourceFile.path);
}
function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
if (!projectReferenceIsEqualTo(oldRef, newRef)) {
return false;
}
const oldResolvedRef = program!.getResolvedProjectReferences()![index];
if (oldResolvedRef) {
// If sourceFile for the oldResolvedRef existed, check the version for uptodate
return sourceFileVersionUptoDate(oldResolvedRef.sourceFile);
}
// In old program, not able to resolve project reference path,
// so if config file doesnt exist, it is uptodate.
return !fileExists(resolveProjectReferencePath(oldRef));
}
}

View File

@ -187,9 +187,10 @@ interface Array<T> {}`
}
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
checkMapKeys(caption, arrayToMap(actual, identity), expected);
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")}`);
for (const f of expected) {
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
assert.isTrue(contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
}
}

View File

@ -34,6 +34,10 @@ namespace ts.tscWatch {
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
}
function projectFileName(subProject: SubProject, baseFileName: string) {
return `${projectPath(subProject)}/${baseFileName}`;
}
function projectFile(subProject: SubProject, baseFileName: string): File {
return {
path: projectFilePath(subProject, baseFileName),
@ -391,10 +395,10 @@ let x: string = 10;`);
});
describe("tsc-watch works with project references", () => {
const coreIndexDts = projectFilePath(SubProject.core, "index.d.ts");
const coreAnotherModuleDts = projectFilePath(SubProject.core, "anotherModule.d.ts");
const logicIndexDts = projectFilePath(SubProject.logic, "index.d.ts");
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat(coreIndexDts, coreAnotherModuleDts, logicIndexDts);
const coreIndexDts = projectFileName(SubProject.core, "index.d.ts");
const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts");
const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts");
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests));
function createSolution() {
@ -432,7 +436,7 @@ let x: string = 10;`);
}
function verifyDependencies(watch: () => BuilderProgram, filePath: string, expected: ReadonlyArray<string>) {
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!).map(f => f.toLocaleLowerCase()), expected);
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!), expected);
}
describe("invoking when references are already built", () => {
@ -447,7 +451,7 @@ let x: string = 10;`);
});
it("local edit in ts file, result in watch compilation because logic.d.ts is written", () => {
const { host, solutionBuilder } = createSolutionAndWatchMode();
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[1].path, `${logic[1].content}
function foo() {
}`);
@ -456,10 +460,11 @@ function foo() {
host.checkTimeoutQueueLengthAndRun(1); // not ideal, but currently because of d.ts but no new file is written
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
});
it("non local edit in ts file, rebuilds in watch compilation", () => {
const { host, solutionBuilder } = createSolutionAndWatchMode();
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[1].path, `${logic[1].content}
export function gfoo() {
}`);
@ -468,8 +473,26 @@ export function gfoo() {
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
});
it("change in project reference config file builds correctly", () => {
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[0].path, JSON.stringify({
compilerOptions: { composite: true, declaration: true, declarationDir: "decls" },
references: [{ path: "../core" }]
}));
solutionBuilder.invalidateProject(logic[0].path, ConfigFileProgramReloadLevel.Full);
solutionBuilder.buildInvalidatedProject();
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, [
// TODO: #26036
// The error is reported in d.ts file because it isnt resolved from ts file path, but is resolved from .d.ts file
"sample1/logic/decls/index.d.ts(2,22): error TS2307: Cannot find module '../core/anotherModule'.\n"
]);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
});
});
});
});