Skip to content

Commit 76d2ba6

Browse files
committed
Testing WIP
1 parent 6d04378 commit 76d2ba6

File tree

9 files changed

+101
-30
lines changed

9 files changed

+101
-30
lines changed

src/compiler/tsbuild.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -317,16 +317,12 @@ namespace ts {
317317
return date2 > date1 ? date2 : date1;
318318
}
319319

320-
function older(date1: Date, date2: Date): Date {
321-
return date2 < date1 ? date2 : date1;
322-
}
323-
324320
function isDeclarationFile(fileName: string) {
325321
return fileExtensionIs(fileName, ".d.ts");
326322
}
327323

328-
export function createBuildContext(options: BuildOptions): BuildContext {
329-
const verboseDiag = options.verbose && createDiagnosticReporter(sys, /*pretty*/ false);
324+
export function createBuildContext(options: BuildOptions, reportDiagnostic: DiagnosticReporter): BuildContext {
325+
const verboseDiag = options.verbose && reportDiagnostic;
330326
return {
331327
options,
332328
projectStatus: createFileMap(),
@@ -371,8 +367,7 @@ namespace ts {
371367
addProject(".");
372368
}
373369

374-
const context = createBuildContext({ verbose, dry, force });
375-
const builder = createSolutionBuilder(host, reportDiagnostic, context);
370+
const builder = createSolutionBuilder(host, reportDiagnostic, { verbose, dry, force });
376371
if (clean) {
377372
builder.cleanProjects(projects);
378373
}
@@ -391,8 +386,9 @@ namespace ts {
391386
}
392387
}
393388

394-
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, context: BuildContext) {
389+
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, options: BuildOptions) {
395390
const configFileCache = createConfigFileCache(host);
391+
let context: BuildContext = undefined!;
396392

397393
return {
398394
getUpToDateStatus,
@@ -473,7 +469,7 @@ namespace ts {
473469
oldestOutputFileTime = outputTime;
474470
oldestOutputFileName = output;
475471
}
476-
newestOutputFileTime = older(newestOutputFileTime, outputTime);
472+
newestOutputFileTime = newer(newestOutputFileTime, outputTime);
477473

478474
// Keep track of when the most recent time a .d.ts file was changed.
479475
// In addition to file timestamps, we also keep track of when a .d.ts file
@@ -709,6 +705,8 @@ namespace ts {
709705
}
710706

711707
function cleanProjects(configFileNames: string[]) {
708+
context = createBuildContext(options, reportDiagnostic);
709+
712710
// Get the same graph for cleaning we'd use for building
713711
const graph = createDependencyGraph(configFileNames);
714712

@@ -736,6 +734,8 @@ namespace ts {
736734
}
737735

738736
function buildProjects(configFileNames: string[]) {
737+
context = createBuildContext(options, reportDiagnostic);
738+
739739
const resolvedNames: string[] = [];
740740
for (const name of configFileNames) {
741741
let fullPath = resolvePath(host.getCurrentDirectory(), name);
@@ -823,7 +823,7 @@ namespace ts {
823823
context.verbose(Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, configFileName, status.missingOutputFileName);
824824
return;
825825
case UpToDateStatusType.UpToDate:
826-
context.verbose(Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFileName, status.newestDeclarationFileContentChangedTime as any, status.newestOutputFileTime);
826+
context.verbose(Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFileName, status.newestInputFileTime, status.newestOutputFileTime);
827827
return;
828828
case UpToDateStatusType.UpToDateWithUpstreamTypes:
829829
context.verbose(Diagnostics.Project_0_is_up_to_date_with_its_upstream_types, configFileName);

src/harness/unittests/tsbuild.ts

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace ts {
44
let currentTime = 100;
55
const bfs = new vfs.FileSystem(/*ignoreCase*/ false, { time });
6-
const lastDiagnostics: Diagnostic[] = [];
6+
let lastDiagnostics: Diagnostic[] = [];
77
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
88

99
const sampleRoot = resolvePath(__dirname, "../../tests/projects/sample1");
@@ -12,47 +12,109 @@ namespace ts {
1212
bfs.writeFileSync("/lib/lib.d.ts", Harness.IO.readFile(combinePaths(Harness.libFolder, "lib.d.ts")));
1313
bfs.meta.set("defaultLibLocation", "/lib");
1414
bfs.makeReadonly();
15+
tick();
1516

1617
describe("tsbuild tests", () => {
17-
it("builds the referenced project", () => {
18+
it("can build the sample project 'tests' without error", () => {
1819
const fs = bfs.shadow();
1920
const host = new fakes.CompilerHost(fs);
20-
const builder = createSolutionBuilder(host, reportDiagnostic, createBuildContext({ dry: false, force: false, verbose: false }));
21+
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: false });
2122

2223
fs.chdir("/src/tests");
23-
fs.debugPrint();
2424
builder.buildProjects(["."]);
25-
printDiagnostics();
26-
fs.debugPrint();
27-
assertDiagnosticMessages(Diagnostics.File_0_does_not_exist);
25+
assertDiagnosticMessages(/*empty*/);
26+
});
27+
28+
it("can detect when and what to rebuild", () => {
29+
const fs = bfs.shadow();
30+
const host = new fakes.CompilerHost(fs);
31+
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: true });
32+
33+
fs.chdir("/src/tests");
34+
builder.buildProjects(["."]);
35+
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
36+
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
37+
Diagnostics.Building_project_0,
38+
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
39+
Diagnostics.Building_project_0,
40+
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
41+
Diagnostics.Building_project_0);
42+
tick();
43+
44+
// All three projects are up to date
45+
clearDiagnostics();
46+
builder.buildProjects(["."]);
47+
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
48+
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
49+
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
50+
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
51+
tick();
2852

53+
// Update a file in the leaf node (tests), only it should rebuild the last one
54+
clearDiagnostics();
55+
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
56+
builder.buildProjects(["."]);
57+
58+
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
59+
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
60+
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
61+
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
62+
Diagnostics.Building_project_0);
2963
tick();
64+
65+
// Update a file in the parent (without affecting types), should get fast downstream builds
66+
clearDiagnostics();
67+
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
68+
builder.buildProjects(["."]);
69+
70+
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
71+
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
72+
Diagnostics.Building_project_0,
73+
Diagnostics.Project_0_is_up_to_date_with_its_upstream_types,
74+
Diagnostics.Updating_output_timestamps_of_project_0,
75+
Diagnostics.Project_0_is_up_to_date_with_its_upstream_types,
76+
Diagnostics.Updating_output_timestamps_of_project_0);
3077
});
3178
});
3279

80+
function replaceText(fs: vfs.FileSystem, path: string, oldText: string, newText: string) {
81+
if (!fs.statSync(path).isFile()) {
82+
throw new Error(`File ${path} does not exist`);
83+
}
84+
const old = fs.readFileSync(path, 'utf-8');
85+
if (old.indexOf(oldText) < 0) {
86+
throw new Error(`Text "${oldText}" does not exist in file ${path}`);
87+
}
88+
const newContent = old.replace(oldText, newText);
89+
fs.writeFileSync(path, newContent, 'utf-8');
90+
}
91+
3392
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
3493
const actual = lastDiagnostics.slice();
35-
actual.sort((a, b) => b.code - a.code);
36-
expected.sort((a, b) => b.code - a.code);
3794
if (actual.length !== expected.length) {
38-
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected ${actual.join(",")}, got ${expected.join(",")}`);
95+
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\ngot\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
3996
}
4097
for (let i = 0; i < actual.length; i++) {
4198
if (actual[i].code !== expected[i].code) {
42-
assert.fail(actual[i].messageText, expected[i].message, "Mismatched error code");
99+
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
43100
}
44101
}
45102
}
46103

47-
export function printDiagnostics() {
104+
function clearDiagnostics() {
105+
lastDiagnostics = [];
106+
}
107+
108+
export function printDiagnostics(header = "== Diagnostics ==") {
48109
const out = createDiagnosticReporter(sys);
110+
sys.write(header + "\r\n");
49111
for (const d of lastDiagnostics) {
50112
out(d);
51113
}
52114
}
53115

54116
function tick() {
55-
currentTime += 10;
117+
currentTime += 100000;
56118
}
57119
function time() {
58120
return currentTime;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export const someString: string = "HELLO WORLD";
12
export function leftPad(s: string, n: number) { return s + n; }
23
export function multiply(a: number, b: number) { return a * b; }
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2-
2+
"compilerOptions": {
3+
"composite": true,
4+
"declaration": true
5+
}
36
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as c from '../core';
1+
import * as c from '../core/index';
22
export function getSecondsInDay() {
33
return c.multiply(10, 15);
44
}

tests/projects/sample1/logic/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"compilerOptions": {
3+
"composite": true,
4+
"declaration": true
5+
},
26
"references": [
37
{ "path": "../core" }
48
]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as c from '../core';
2-
import * as logic from '../logic';
1+
import * as c from '../core/index';
2+
import * as logic from '../logic/index';
33

44
c.leftPad("", 10);
55
logic.getSecondsInDay();

tests/projects/sample1/tests/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
"references": [
33
{ "path": "../core" },
44
{ "path": "../logic" }
5-
]
5+
],
6+
"files": ["index.ts"]
67
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"references": [
3-
{ "path": "../logic" }
3+
{ "path": "../logic/index" }
44
]
55
}

0 commit comments

Comments
 (0)