Skip to content

Commit

Permalink
Check if its same buildinfo only for directly referenced projects and…
Browse files Browse the repository at this point in the history
… not recursively

Fixes #50545
  • Loading branch information
sheetalkamat committed Sep 2, 2022
1 parent 856c7c5 commit 83a58b0
Show file tree
Hide file tree
Showing 3 changed files with 337 additions and 19 deletions.
22 changes: 3 additions & 19 deletions src/compiler/tsbuildPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1706,10 +1706,7 @@ namespace ts {
}
}

const seenRefs = buildInfoPath ? new Set<ResolvedConfigFilePath>() : undefined;
const buildInfoCacheEntry = state.buildInfoCache.get(resolvedPath);
seenRefs?.add(resolvedPath);

/** Inputs are up-to-date, just need either timestamp update or bundle prepend manipulation to make it look up-to-date */
let pseudoUpToDate = false;
let usesPrepend = false;
Expand All @@ -1724,7 +1721,7 @@ namespace ts {
}

// Check if tsbuildinfo path is shared, then we need to rebuild
if (buildInfoCacheEntry && hasSameBuildInfo(state, buildInfoCacheEntry, seenRefs!, resolvedConfig, resolvedRefPath)) {
if (buildInfoCacheEntry && hasSameBuildInfo(state, buildInfoCacheEntry, resolvedRefPath)) {
return {
type: UpToDateStatusType.OutOfDateWithUpstream,
outOfDateOutputFileName: buildInfoPath!,
Expand Down Expand Up @@ -1787,22 +1784,9 @@ namespace ts {
};
}

function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, seenRefs: Set<ResolvedConfigFilePath>, resolvedConfig: ParsedCommandLine, resolvedRefPath: ResolvedConfigFilePath) {
if (seenRefs.has(resolvedRefPath)) return false;
seenRefs.add(resolvedRefPath);
function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, resolvedRefPath: ResolvedConfigFilePath) {
const refBuildInfo = state.buildInfoCache.get(resolvedRefPath)!;
if (refBuildInfo.path === buildInfoCacheEntry.path) return true;

if (resolvedConfig.projectReferences) {
// Check references
for (const ref of resolvedConfig.projectReferences) {
const resolvedRef = resolveProjectReferencePath(ref);
const resolvedRefPath = toResolvedConfigFilePath(state, resolvedRef);
const resolvedConfig = parseConfigFile(state, resolvedRef, resolvedRefPath)!;
if (hasSameBuildInfo(state, buildInfoCacheEntry, seenRefs, resolvedConfig, resolvedRefPath)) return true;
}
}
return false;
return refBuildInfo.path === buildInfoCacheEntry.path;
}

function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
Expand Down
31 changes: 31 additions & 0 deletions src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,36 @@ namespace ts {
commandLineArgs: ["--b", "/src", "--verbose"],
edits: noChangeOnlyRuns
});

verifyTscWithEdits({
scenario: "containerOnlyReferenced",
subScenario: "when solution is referenced indirectly",
fs: () => loadProjectFromFiles({
"/src/project1/tsconfig.json": JSON.stringify({
compilerOptions: { composite: true },
references: [],
}),
"/src/project2/tsconfig.json": JSON.stringify({
compilerOptions: { composite: true },
references: [],
}),
"/src/project2/src/b.ts": "export const b = 10;",
"/src/project3/tsconfig.json": JSON.stringify({
compilerOptions: { composite: true },
references: [{ path: "../project1", }, { path: "../project2" }],
}),
"/src/project3/src/c.ts": "export const c = 10;",
"/src/project4/tsconfig.json": JSON.stringify({
compilerOptions: { composite: true },
references: [{ path: "../project3" }]
}),
"/src/project4/src/d.ts": "export const d = 10;",
}),
commandLineArgs: ["--b", "/src/project4", "--verbose", "--explainFiles"],
edits: [{
subScenario: "modify project3 file",
modifyFs: fs => replaceText(fs, "/src/project3/src/c.ts", "c = ", "cc = "),
}],
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
Input::
//// [/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
declare const console: { log(msg: any): void; };

//// [/src/project1/tsconfig.json]
{"compilerOptions":{"composite":true},"references":[]}

//// [/src/project2/src/b.ts]
export const b = 10;

//// [/src/project2/tsconfig.json]
{"compilerOptions":{"composite":true},"references":[]}

//// [/src/project3/src/c.ts]
export const c = 10;

//// [/src/project3/tsconfig.json]
{"compilerOptions":{"composite":true},"references":[{"path":"../project1"},{"path":"../project2"}]}

//// [/src/project4/src/d.ts]
export const d = 10;

//// [/src/project4/tsconfig.json]
{"compilerOptions":{"composite":true},"references":[{"path":"../project3"}]}



Output::
/lib/tsc --b /src/project4 --verbose --explainFiles
[12:00:20 AM] Projects in this build:
* src/project1/tsconfig.json
* src/project2/tsconfig.json
* src/project3/tsconfig.json
* src/project4/tsconfig.json

[12:00:21 AM] Project 'src/project2/tsconfig.json' is out of date because output file 'src/project2/tsconfig.tsbuildinfo' does not exist

[12:00:22 AM] Building project '/src/project2/tsconfig.json'...

lib/lib.d.ts
Default library for target 'es3'
src/project2/src/b.ts
Matched by default include pattern '**/*'
[12:00:28 AM] Project 'src/project3/tsconfig.json' is out of date because output file 'src/project3/tsconfig.tsbuildinfo' does not exist

[12:00:29 AM] Building project '/src/project3/tsconfig.json'...

lib/lib.d.ts
Default library for target 'es3'
src/project3/src/c.ts
Matched by default include pattern '**/*'
[12:00:35 AM] Project 'src/project4/tsconfig.json' is out of date because output file 'src/project4/tsconfig.tsbuildinfo' does not exist
[12:00:36 AM] Building project '/src/project4/tsconfig.json'...
lib/lib.d.ts
Default library for target 'es3'
src/project4/src/d.ts
Matched by default include pattern '**/*'
exitCode:: ExitStatus.Success
//// [/src/project2/src/b.d.ts]
export declare const b = 10;
//// [/src/project2/src/b.js]
"use strict";
exports.__esModule = true;
exports.b = void 0;
exports.b = 10;
//// [/src/project2/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../lib/lib.d.ts","./src/b.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-13368947479-export const b = 10;","signature":"-1807916688-export declare const b = 10;\r\n"}],"options":{"composite":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"./src/b.d.ts"},"version":"FakeTSVersion"}
//// [/src/project2/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../lib/lib.d.ts",
"./src/b.ts"
],
"fileInfos": {
"../../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./src/b.ts": {
"version": "-13368947479-export const b = 10;",
"signature": "-1807916688-export declare const b = 10;\r\n"
}
},
"options": {
"composite": true
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../lib/lib.d.ts",
"./src/b.ts"
],
"latestChangedDtsFile": "./src/b.d.ts"
},
"version": "FakeTSVersion",
"size": 832
}
//// [/src/project3/src/c.d.ts]
export declare const c = 10;
//// [/src/project3/src/c.js]
"use strict";
exports.__esModule = true;
exports.c = void 0;
exports.c = 10;
//// [/src/project3/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../lib/lib.d.ts","./src/c.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-12077479510-export const c = 10;","signature":"-4148571535-export declare const c = 10;\r\n"}],"options":{"composite":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"./src/c.d.ts"},"version":"FakeTSVersion"}
//// [/src/project3/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../lib/lib.d.ts",
"./src/c.ts"
],
"fileInfos": {
"../../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./src/c.ts": {
"version": "-12077479510-export const c = 10;",
"signature": "-4148571535-export declare const c = 10;\r\n"
}
},
"options": {
"composite": true
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../lib/lib.d.ts",
"./src/c.ts"
],
"latestChangedDtsFile": "./src/c.d.ts"
},
"version": "FakeTSVersion",
"size": 832
}
//// [/src/project4/src/d.d.ts]
export declare const d = 10;
//// [/src/project4/src/d.js]
"use strict";
exports.__esModule = true;
exports.d = void 0;
exports.d = 10;
//// [/src/project4/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../lib/lib.d.ts","./src/d.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-10786011541-export const d = 10;","signature":"-6489226382-export declare const d = 10;\r\n"}],"options":{"composite":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"./src/d.d.ts"},"version":"FakeTSVersion"}
//// [/src/project4/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../lib/lib.d.ts",
"./src/d.ts"
],
"fileInfos": {
"../../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./src/d.ts": {
"version": "-10786011541-export const d = 10;",
"signature": "-6489226382-export declare const d = 10;\r\n"
}
},
"options": {
"composite": true
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../lib/lib.d.ts",
"./src/d.ts"
],
"latestChangedDtsFile": "./src/d.d.ts"
},
"version": "FakeTSVersion",
"size": 832
}
Change:: modify project3 file
Input::
//// [/src/project3/src/c.ts]
export const cc = 10;
Output::
/lib/tsc --b /src/project4 --verbose --explainFiles
[12:00:43 AM] Projects in this build:
* src/project1/tsconfig.json
* src/project2/tsconfig.json
* src/project3/tsconfig.json
* src/project4/tsconfig.json
[12:00:44 AM] Project 'src/project2/tsconfig.json' is up to date because newest input 'src/project2/src/b.ts' is older than output 'src/project2/tsconfig.tsbuildinfo'
[12:00:45 AM] Project 'src/project3/tsconfig.json' is out of date because output 'src/project3/tsconfig.tsbuildinfo' is older than input 'src/project3/src/c.ts'
[12:00:46 AM] Building project '/src/project3/tsconfig.json'...
lib/lib.d.ts
Default library for target 'es3'
src/project3/src/c.ts
Matched by default include pattern '**/*'
[12:00:52 AM] Project 'src/project4/tsconfig.json' is out of date because output 'src/project4/tsconfig.tsbuildinfo' is older than input 'src/project3'
[12:00:53 AM] Building project '/src/project4/tsconfig.json'...
[12:00:54 AM] Updating unchanged output timestamps of project '/src/project4/tsconfig.json'...
lib/lib.d.ts
Default library for target 'es3'
src/project4/src/d.ts
Matched by default include pattern '**/*'
exitCode:: ExitStatus.Success


//// [/src/project3/src/c.d.ts]
export declare const cc = 10;


//// [/src/project3/src/c.js]
"use strict";
exports.__esModule = true;
exports.cc = void 0;
exports.cc = 10;


//// [/src/project3/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../lib/lib.d.ts","./src/c.ts"],"fileInfos":[{"version":"3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true},{"version":"-12481904019-export const cc = 10;","signature":"-2519819788-export declare const cc = 10;\r\n"}],"options":{"composite":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"./src/c.d.ts"},"version":"FakeTSVersion"}

//// [/src/project3/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../lib/lib.d.ts",
"./src/c.ts"
],
"fileInfos": {
"../../lib/lib.d.ts": {
"version": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"affectsGlobalScope": true
},
"./src/c.ts": {
"version": "-12481904019-export const cc = 10;",
"signature": "-2519819788-export declare const cc = 10;\r\n"
}
},
"options": {
"composite": true
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../lib/lib.d.ts",
"./src/c.ts"
],
"latestChangedDtsFile": "./src/c.d.ts"
},
"version": "FakeTSVersion",
"size": 834
}

//// [/src/project4/tsconfig.tsbuildinfo] file changed its modified time

0 comments on commit 83a58b0

Please sign in to comment.