Skip to content

Commit cb7aca3

Browse files
committed
Do project reference errors before doing input/output file checks
1 parent 7817fbf commit cb7aca3

11 files changed

+88
-135
lines changed

src/compiler/tsbuildPublic.ts

+80-90
Original file line numberDiff line numberDiff line change
@@ -1346,14 +1346,52 @@ namespace ts {
13461346
}
13471347

13481348
function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
1349-
// Container if no files are specified in the project
1350-
if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) {
1349+
// Container if no files are specified in the project
1350+
if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) {
13511351
return {
13521352
type: UpToDateStatusType.ContainerOnly
13531353
};
13541354
}
13551355

1356+
// Fast check to see if reference projects are buildable
1357+
let referenceStatuses;
13561358
const force = !!state.options.force;
1359+
if (project.projectReferences) {
1360+
state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.ComputingUpstream });
1361+
for (const ref of project.projectReferences) {
1362+
const resolvedRef = resolveProjectReferencePath(ref);
1363+
const resolvedRefPath = toResolvedConfigFilePath(state, resolvedRef);
1364+
const refStatus = getUpToDateStatus(state, parseConfigFile(state, resolvedRef, resolvedRefPath), resolvedRefPath);
1365+
1366+
// Its a circular reference ignore the status of this project
1367+
if (refStatus.type === UpToDateStatusType.ComputingUpstream ||
1368+
refStatus.type === UpToDateStatusType.ContainerOnly) { // Container only ignore this project
1369+
continue;
1370+
}
1371+
1372+
// An upstream project is blocked
1373+
if (refStatus.type === UpToDateStatusType.Unbuildable ||
1374+
refStatus.type === UpToDateStatusType.UpstreamBlocked) {
1375+
return {
1376+
type: UpToDateStatusType.UpstreamBlocked,
1377+
upstreamProjectName: ref.path,
1378+
upstreamProjectBlocked: refStatus.type === UpToDateStatusType.UpstreamBlocked
1379+
};
1380+
}
1381+
1382+
// If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
1383+
if (refStatus.type !== UpToDateStatusType.UpToDate) {
1384+
return {
1385+
type: UpToDateStatusType.UpstreamOutOfDate,
1386+
upstreamProjectName: ref.path
1387+
};
1388+
}
1389+
1390+
if (!force) (referenceStatuses ||= []).push({ ref, refStatus });
1391+
}
1392+
}
1393+
1394+
// Check output files
13571395
let newestInputFileName: string = undefined!;
13581396
let newestInputFileTime = minimumDate;
13591397
const { host } = state;
@@ -1381,17 +1419,16 @@ namespace ts {
13811419
// Now see if all outputs are newer than the newest input
13821420
let oldestOutputFileName = "(none)";
13831421
let oldestOutputFileTime = maximumDate;
1384-
let missingOutputFileName: string | undefined;
13851422
let newestDeclarationFileContentChangedTime = minimumDate;
1386-
let isOutOfDateWithInputs = false;
13871423
if (!force) {
13881424
for (const output of outputs) {
13891425
// Output is missing; can stop checking
1390-
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
13911426
const outputTime = getModifiedTime(host, output);
13921427
if (outputTime === missingFileModifiedTime) {
1393-
missingOutputFileName = output;
1394-
break;
1428+
return {
1429+
type: UpToDateStatusType.OutputMissing,
1430+
missingOutputFileName: output
1431+
};
13951432
}
13961433

13971434
if (outputTime < oldestOutputFileTime) {
@@ -1400,10 +1437,12 @@ namespace ts {
14001437
}
14011438

14021439
// If an output is older than the newest input, we can stop checking
1403-
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
14041440
if (outputTime < newestInputFileTime) {
1405-
isOutOfDateWithInputs = true;
1406-
break;
1441+
return {
1442+
type: UpToDateStatusType.OutOfDateWithSelf,
1443+
outOfDateOutputFileName: oldestOutputFileName,
1444+
newerInputFileName: newestInputFileName
1445+
};
14071446
}
14081447

14091448
// Keep track of when the most recent time a .d.ts file was changed.
@@ -1419,96 +1458,47 @@ namespace ts {
14191458
let pseudoUpToDate = false;
14201459
let usesPrepend = false;
14211460
let upstreamChangedProject: string | undefined;
1422-
if (project.projectReferences) {
1423-
state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.ComputingUpstream });
1424-
for (const ref of project.projectReferences) {
1461+
if (referenceStatuses) {
1462+
for (const { ref, refStatus } of referenceStatuses) {
14251463
usesPrepend = usesPrepend || !!(ref.prepend);
1426-
const resolvedRef = resolveProjectReferencePath(ref);
1427-
const resolvedRefPath = toResolvedConfigFilePath(state, resolvedRef);
1428-
const refStatus = getUpToDateStatus(state, parseConfigFile(state, resolvedRef, resolvedRefPath), resolvedRefPath);
1429-
1430-
// Its a circular reference ignore the status of this project
1431-
if (refStatus.type === UpToDateStatusType.ComputingUpstream ||
1432-
refStatus.type === UpToDateStatusType.ContainerOnly) { // Container only ignore this project
1464+
// If the upstream project's newest file is older than our oldest output, we
1465+
// can't be out of date because of it
1466+
if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) {
14331467
continue;
14341468
}
14351469

1436-
// An upstream project is blocked
1437-
if (refStatus.type === UpToDateStatusType.Unbuildable ||
1438-
refStatus.type === UpToDateStatusType.UpstreamBlocked) {
1439-
return {
1440-
type: UpToDateStatusType.UpstreamBlocked,
1441-
upstreamProjectName: ref.path,
1442-
upstreamProjectBlocked: refStatus.type === UpToDateStatusType.UpstreamBlocked
1443-
};
1444-
}
1445-
1446-
// If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
1447-
if (refStatus.type !== UpToDateStatusType.UpToDate) {
1448-
return {
1449-
type: UpToDateStatusType.UpstreamOutOfDate,
1450-
upstreamProjectName: ref.path
1451-
};
1470+
// If the upstream project has only change .d.ts files, and we've built
1471+
// *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
1472+
if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) {
1473+
pseudoUpToDate = true;
1474+
upstreamChangedProject = ref.path;
1475+
continue;
14521476
}
14531477

1454-
// Check oldest output file name only if there is no missing output file name
1455-
// (a check we will have skipped if this is a forced build)
1456-
if (!force && !missingOutputFileName) {
1457-
// If the upstream project's newest file is older than our oldest output, we
1458-
// can't be out of date because of it
1459-
if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) {
1460-
continue;
1461-
}
1462-
1463-
// If the upstream project has only change .d.ts files, and we've built
1464-
// *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
1465-
if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) {
1466-
pseudoUpToDate = true;
1467-
upstreamChangedProject = ref.path;
1468-
continue;
1469-
}
1470-
1471-
// We have an output older than an upstream output - we are out of date
1472-
Debug.assert(oldestOutputFileName !== undefined, "Should have an oldest output filename here");
1473-
return {
1474-
type: UpToDateStatusType.OutOfDateWithUpstream,
1475-
outOfDateOutputFileName: oldestOutputFileName,
1476-
newerProjectName: ref.path
1477-
};
1478-
}
1478+
// We have an output older than an upstream output - we are out of date
1479+
Debug.assert(oldestOutputFileName !== undefined, "Should have an oldest output filename here");
1480+
return {
1481+
type: UpToDateStatusType.OutOfDateWithUpstream,
1482+
outOfDateOutputFileName: oldestOutputFileName,
1483+
newerProjectName: ref.path
1484+
};
14791485
}
14801486
}
14811487

1482-
if (missingOutputFileName !== undefined) {
1483-
return {
1484-
type: UpToDateStatusType.OutputMissing,
1485-
missingOutputFileName
1486-
};
1487-
}
1488+
// Check tsconfig time
1489+
const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName);
1490+
if (configStatus) return configStatus;
14881491

1489-
if (isOutOfDateWithInputs) {
1490-
return {
1491-
type: UpToDateStatusType.OutOfDateWithSelf,
1492-
outOfDateOutputFileName: oldestOutputFileName,
1493-
newerInputFileName: newestInputFileName
1494-
};
1495-
}
1496-
else {
1497-
// Check tsconfig time
1498-
const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName);
1499-
if (configStatus) return configStatus;
1500-
1501-
// Check extended config time
1502-
const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName));
1503-
if (extendedConfigStatus) return extendedConfigStatus;
1504-
1505-
// Check package file time
1506-
const dependentPackageFileStatus = forEach(
1507-
state.lastCachedPackageJsonLookups.get(resolvedPath) || emptyArray,
1508-
([path]) => checkConfigFileUpToDateStatus(state, path, oldestOutputFileTime, oldestOutputFileName)
1509-
);
1510-
if (dependentPackageFileStatus) return dependentPackageFileStatus;
1511-
}
1492+
// Check extended config time
1493+
const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName));
1494+
if (extendedConfigStatus) return extendedConfigStatus;
1495+
1496+
// Check package file time
1497+
const dependentPackageFileStatus = forEach(
1498+
state.lastCachedPackageJsonLookups.get(resolvedPath) || emptyArray,
1499+
([path]) => checkConfigFileUpToDateStatus(state, path, oldestOutputFileTime, oldestOutputFileName)
1500+
);
1501+
if (dependentPackageFileStatus) return dependentPackageFileStatus;
15121502

15131503
if (!force && !state.buildInfoChecked.has(resolvedPath)) {
15141504
state.buildInfoChecked.set(resolvedPath, true);

tests/baselines/reference/tsbuild/demo/in-bad-ref-branch-reports-the-error-about-files-not-in-rootDir-at-the-import-location.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,7 @@ exitCode:: ExitStatus.DiagnosticsPresent_OutputsSkipped
222222

223223
getModifiedTime:: {
224224
"/src/core/utilities.ts": 1,
225-
"/src/lib/core/utilities.js": 1,
226-
"/src/animals/animal.ts": 1,
227-
"/src/animals/dog.ts": 1,
228-
"/src/animals/index.ts": 1,
229-
"/src/lib/animals/animal.js": 1,
230-
"/src/zoo/zoo.ts": 1,
231-
"/src/lib/zoo/zoo.js": 1
225+
"/src/lib/core/utilities.js": 1
232226
}
233227

234228
setModifiedTime:: {}

tests/baselines/reference/tsbuild/sample1/does-not-build-downstream-projects-if-upstream-projects-have-errors.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@ getModifiedTime:: {
144144
"/src/core/some_decl.d.ts": 1,
145145
"/src/core/anotherModule.js": 1,
146146
"/src/logic/index.ts": 1,
147-
"/src/logic/index.js": 1,
148-
"/src/tests/index.ts": 1,
149-
"/src/tests/index.js": 1
147+
"/src/logic/index.js": 1
150148
}
151149

152150
setModifiedTime:: {}

tests/baselines/reference/tsbuild/sample1/does-not-write-any-files-in-a-dry-build.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,7 @@ getModifiedTime:: {
123123
"/src/core/anotherModule.ts": 1,
124124
"/src/core/index.ts": 1,
125125
"/src/core/some_decl.d.ts": 1,
126-
"/src/core/anotherModule.js": 1,
127-
"/src/logic/index.ts": 1,
128-
"/src/logic/index.js": 1,
129-
"/src/tests/index.ts": 1,
130-
"/src/tests/index.js": 1
126+
"/src/core/anotherModule.js": 1
131127
}
132128

133129
setModifiedTime:: {}

tests/baselines/reference/tsbuild/transitiveReferences/reports-error-about-module-not-found-with-node-resolution-with-external-module-name.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ getModifiedTime:: {
7575
"/src/a.ts": 1,
7676
"/src/a.js": 1,
7777
"/src/b.ts": 1,
78-
"/src/b.js": 1,
79-
"/src/c.ts": 1,
80-
"/src/c.js": 1
78+
"/src/b.js": 1
8179
}
8280

8381
setModifiedTime:: {}

tests/baselines/reference/tsbuildWatch/demo/updates-with-bad-reference.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -449,13 +449,7 @@ directoryExists:: {
449449

450450
getModifiedTimes:: {
451451
"/user/username/projects/demo/core/utilities.ts": 1,
452-
"/user/username/projects/demo/lib/core/utilities.js": 1,
453-
"/user/username/projects/demo/animals/animal.ts": 1,
454-
"/user/username/projects/demo/animals/dog.ts": 1,
455-
"/user/username/projects/demo/animals/index.ts": 1,
456-
"/user/username/projects/demo/lib/animals/animal.js": 1,
457-
"/user/username/projects/demo/zoo/zoo.ts": 1,
458-
"/user/username/projects/demo/lib/zoo/zoo.js": 1
452+
"/user/username/projects/demo/lib/core/utilities.js": 1
459453
}
460454

461455
setModifiedTimes:: {}

tests/baselines/reference/tsbuildWatch/programUpdates/incremental-updates-in-verbose-mode.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ Output::
549549
>> Screen clear
550550
[12:01:31 AM] File change detected. Starting incremental compilation...
551551

552-
[[90m12:01:32 AM[0m] Project 'sample1/logic/tsconfig.json' is out of date because oldest output 'sample1/logic/index.js' is older than newest input 'sample1/core'
552+
[[90m12:01:32 AM[0m] Project 'sample1/logic/tsconfig.json' is out of date because oldest output 'sample1/logic/index.js' is older than newest input 'sample1/logic/index.ts'
553553

554554
[12:01:33 AM] Building project '/user/username/projects/sample1/logic/tsconfig.json'...
555555

@@ -746,7 +746,7 @@ Output::
746746
>> Screen clear
747747
[12:01:56 AM] File change detected. Starting incremental compilation...
748748

749-
[[90m12:01:57 AM[0m] Project 'sample1/logic/tsconfig.json' is out of date because oldest output 'sample1/logic/index.js' is older than newest input 'sample1/core'
749+
[[90m12:01:57 AM[0m] Project 'sample1/logic/tsconfig.json' is out of date because oldest output 'sample1/logic/index.js' is older than newest input 'sample1/logic/index.ts'
750750

751751
[12:01:58 AM] Building project '/user/username/projects/sample1/logic/tsconfig.json'...
752752

tests/baselines/reference/tsbuildWatch/programUpdates/watches-config-files-that-are-not-present.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,7 @@ directoryExists:: {
220220
getModifiedTimes:: {
221221
"/user/username/projects/sample1/core/anothermodule.ts": 1,
222222
"/user/username/projects/sample1/core/index.ts": 1,
223-
"/user/username/projects/sample1/core/anothermodule.js": 1,
224-
"/user/username/projects/sample1/tests/index.ts": 1,
225-
"/user/username/projects/sample1/tests/index.js": 1
223+
"/user/username/projects/sample1/core/anothermodule.js": 1
226224
}
227225

228226
setModifiedTimes:: {}

tests/baselines/reference/tsbuildWatch/programUpdates/with-circular-project-reference/builds-when-new-file-is-added,-and-its-subsequent-updates.js

-5
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,6 @@ directoryExists:: {
461461
}
462462

463463
getModifiedTimes:: {
464-
"/user/username/projects/sample1/core/anothermodule.ts": 1,
465-
"/user/username/projects/sample1/core/index.ts": 1,
466-
"/user/username/projects/sample1/core/anothermodule.js": 1,
467-
"/user/username/projects/sample1/tests/index.ts": 1,
468-
"/user/username/projects/sample1/tests/index.js": 1,
469464
"/user/username/projects/sample1/logic/index.ts": 1,
470465
"/user/username/projects/sample1/logic/index.js": 1
471466
}

tests/baselines/reference/tsbuildWatch/programUpdates/with-circular-project-reference/change-builds-changes-and-reports-found-errors-message.js

-5
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,6 @@ directoryExists:: {
461461
}
462462

463463
getModifiedTimes:: {
464-
"/user/username/projects/sample1/core/anothermodule.ts": 1,
465-
"/user/username/projects/sample1/core/index.ts": 1,
466-
"/user/username/projects/sample1/core/anothermodule.js": 1,
467-
"/user/username/projects/sample1/tests/index.ts": 1,
468-
"/user/username/projects/sample1/tests/index.js": 1,
469464
"/user/username/projects/sample1/logic/index.ts": 1,
470465
"/user/username/projects/sample1/logic/index.js": 1
471466
}

tests/baselines/reference/tsbuildWatch/programUpdates/with-circular-project-reference/non-local-change-does-not-start-build-of-referencing-projects.js

-5
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,6 @@ directoryExists:: {
461461
}
462462

463463
getModifiedTimes:: {
464-
"/user/username/projects/sample1/core/anothermodule.ts": 1,
465-
"/user/username/projects/sample1/core/index.ts": 1,
466-
"/user/username/projects/sample1/core/anothermodule.js": 1,
467-
"/user/username/projects/sample1/tests/index.ts": 1,
468-
"/user/username/projects/sample1/tests/index.js": 1,
469464
"/user/username/projects/sample1/logic/index.ts": 1,
470465
"/user/username/projects/sample1/logic/index.js": 1
471466
}

0 commit comments

Comments
 (0)