Skip to content

Commit 17ee923

Browse files
committed
Write first test with --build and --watch
1 parent 13bd478 commit 17ee923

File tree

8 files changed

+123
-46
lines changed

8 files changed

+123
-46
lines changed

src/compiler/program.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,20 @@ namespace ts {
6666
mtime: Date;
6767
}
6868

69-
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
69+
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
7070
const existingDirectories = createMap<boolean>();
7171

7272
function getCanonicalFileName(fileName: string): string {
7373
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
7474
// otherwise use toLowerCase as a canonical form.
75-
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
75+
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
7676
}
7777

7878
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
7979
let text: string | undefined;
8080
try {
8181
performance.mark("beforeIORead");
82-
text = sys.readFile(fileName, options.charset);
82+
text = system.readFile(fileName, options.charset);
8383
performance.mark("afterIORead");
8484
performance.measure("I/O Read", "beforeIORead", "afterIORead");
8585
}
@@ -97,7 +97,7 @@ namespace ts {
9797
if (existingDirectories.has(directoryPath)) {
9898
return true;
9999
}
100-
if (sys.directoryExists(directoryPath)) {
100+
if (system.directoryExists(directoryPath)) {
101101
existingDirectories.set(directoryPath, true);
102102
return true;
103103
}
@@ -108,7 +108,7 @@ namespace ts {
108108
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
109109
const parentDirectory = getDirectoryPath(directoryPath);
110110
ensureDirectoriesExist(parentDirectory);
111-
sys.createDirectory(directoryPath);
111+
system.createDirectory(directoryPath);
112112
}
113113
}
114114

@@ -119,8 +119,8 @@ namespace ts {
119119
outputFingerprints = createMap<OutputFingerprint>();
120120
}
121121

122-
const hash = sys.createHash!(data); // TODO: GH#18217
123-
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
122+
const hash = system.createHash!(data); // TODO: GH#18217
123+
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
124124

125125
if (mtimeBefore) {
126126
const fingerprint = outputFingerprints.get(fileName);
@@ -133,9 +133,9 @@ namespace ts {
133133
}
134134
}
135135

136-
sys.writeFile(fileName, data, writeByteOrderMark);
136+
system.writeFile(fileName, data, writeByteOrderMark);
137137

138-
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
138+
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
139139

140140
outputFingerprints.set(fileName, {
141141
hash,
@@ -149,11 +149,11 @@ namespace ts {
149149
performance.mark("beforeIOWrite");
150150
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
151151

152-
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
152+
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
153153
writeFileIfUpdated(fileName, data, writeByteOrderMark);
154154
}
155155
else {
156-
sys.writeFile(fileName, data, writeByteOrderMark);
156+
system.writeFile(fileName, data, writeByteOrderMark);
157157
}
158158

159159
performance.mark("afterIOWrite");
@@ -167,32 +167,32 @@ namespace ts {
167167
}
168168

169169
function getDefaultLibLocation(): string {
170-
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
170+
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
171171
}
172172

173173
const newLine = getNewLineCharacter(options);
174-
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
174+
const realpath = system.realpath && ((path: string) => system.realpath!(path));
175175

176176
return {
177177
getSourceFile,
178178
getDefaultLibLocation,
179179
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
180180
writeFile,
181-
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
182-
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
181+
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
182+
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
183183
getCanonicalFileName,
184184
getNewLine: () => newLine,
185-
fileExists: fileName => sys.fileExists(fileName),
186-
readFile: fileName => sys.readFile(fileName),
187-
trace: (s: string) => sys.write(s + newLine),
188-
directoryExists: directoryName => sys.directoryExists(directoryName),
189-
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
190-
getDirectories: (path: string) => sys.getDirectories(path),
185+
fileExists: fileName => system.fileExists(fileName),
186+
readFile: fileName => system.readFile(fileName),
187+
trace: (s: string) => system.write(s + newLine),
188+
directoryExists: directoryName => system.directoryExists(directoryName),
189+
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
190+
getDirectories: (path: string) => system.getDirectories(path),
191191
realpath,
192-
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
193-
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
194-
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
195-
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
192+
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
193+
getModifiedTime: system.getModifiedTime && (path => system.getModifiedTime!(path)),
194+
setModifiedTime: system.setModifiedTime && ((path, date) => system.setModifiedTime!(path, date)),
195+
deleteFile: system.deleteFile && (path => system.deleteFile!(path))
196196
};
197197
}
198198

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,22 +620,22 @@ interface Array<T> {}`
620620
}
621621
}
622622

623-
removeFile(filePath: string) {
623+
deleteFile(filePath: string) {
624624
const path = this.toFullPath(filePath);
625625
const currentEntry = this.fs.get(path) as FsFile;
626626
Debug.assert(isFsFile(currentEntry));
627627
this.removeFileOrFolder(currentEntry, returnFalse);
628628
}
629629

630-
removeFolder(folderPath: string, recursive?: boolean) {
630+
deleteFolder(folderPath: string, recursive?: boolean) {
631631
const path = this.toFullPath(folderPath);
632632
const currentEntry = this.fs.get(path) as FsFolder;
633633
Debug.assert(isFsFolder(currentEntry));
634634
if (recursive && currentEntry.entries.length) {
635635
const subEntries = currentEntry.entries.slice();
636636
subEntries.forEach(fsEntry => {
637637
if (isFsFolder(fsEntry)) {
638-
this.removeFolder(fsEntry.fullPath, recursive);
638+
this.deleteFolder(fsEntry.fullPath, recursive);
639639
}
640640
else {
641641
this.removeFileOrFolder(fsEntry, returnFalse);
@@ -766,6 +766,14 @@ interface Array<T> {}`
766766
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
767767
}
768768

769+
setModifiedTime(s: string, date: Date) {
770+
const path = this.toFullPath(s);
771+
const fsEntry = this.fs.get(path);
772+
if (fsEntry) {
773+
fsEntry.modifiedTime = date;
774+
}
775+
}
776+
769777
readFile(s: string): string | undefined {
770778
const fsEntry = this.getRealFile(this.toFullPath(s));
771779
return fsEntry ? fsEntry.content : undefined;

src/testRunner/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"unittests/transform.ts",
8181
"unittests/transpile.ts",
8282
"unittests/tsbuild.ts",
83+
"unittests/tsbuildWatchMode.ts",
8384
"unittests/tsconfigParsing.ts",
8485
"unittests/tscWatchMode.ts",
8586
"unittests/versionCache.ts",
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace ts.tscWatch {
2+
export import libFile = TestFSWithWatch.libFile;
3+
function createSolutionBuilder(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
4+
const compilerHost = createCompilerHost({}, /*setParentNodes*/ undefined, host);
5+
const reportDiag = createDiagnosticReporter(host);
6+
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
7+
const buildHost: BuildHost = {
8+
error: report,
9+
verbose: report,
10+
message: report,
11+
errorDiagnostic: d => reportDiag(d)
12+
};
13+
return ts.createSolutionBuilder(compilerHost, buildHost, rootNames, defaultOptions || { dry: false, force: false, verbose: false }, host);
14+
}
15+
16+
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
17+
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
18+
solutionBuilder.buildAllProjects();
19+
solutionBuilder.startWatching();
20+
return solutionBuilder;
21+
}
22+
23+
describe("tsbuild-watch program updates", () => {
24+
const projectsLocation = "/user/username/projects";
25+
const project = "sample1";
26+
const enum SubProject {
27+
core = "core",
28+
logic = "logic",
29+
tests = "tests",
30+
ui = "ui"
31+
}
32+
type ReadonlyFile = Readonly<File>;
33+
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
34+
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
35+
const root = Harness.IO.getWorkspaceRoot();
36+
function projectFile(subProject: SubProject, baseFileName: string): File {
37+
return {
38+
path: `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`,
39+
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
40+
};
41+
}
42+
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
43+
const tsconfig = projectFile(subProject, "tsconfig.json");
44+
const index = projectFile(subProject, "index.ts");
45+
if (!anotherModuleAndSomeDecl) {
46+
return [tsconfig, index];
47+
}
48+
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
49+
const someDecl = projectFile(SubProject.core, "some_decl.ts");
50+
return [tsconfig, index, anotherModule, someDecl];
51+
}
52+
53+
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
54+
const logic = subProjectFiles(SubProject.logic);
55+
const tests = subProjectFiles(SubProject.tests);
56+
const ui = subProjectFiles(SubProject.ui);
57+
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
58+
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
59+
it("creates solution in watch mode", () => {
60+
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
61+
const originalWrite = host.write;
62+
host.write = s => { console.log(s); originalWrite.call(host, s); };
63+
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
64+
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
65+
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
66+
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
67+
});
68+
});
69+
}

src/testRunner/unittests/tscWatchMode.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
namespace ts.tscWatch {
2-
import WatchedSystem = TestFSWithWatch.TestServerHost;
3-
type File = TestFSWithWatch.File;
4-
type SymLink = TestFSWithWatch.SymLink;
5-
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
6-
import checkArray = TestFSWithWatch.checkArray;
7-
import libFile = TestFSWithWatch.libFile;
8-
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
9-
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
10-
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
11-
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
12-
import checkOutputContains = TestFSWithWatch.checkOutputContains;
13-
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
14-
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
2+
export import WatchedSystem = TestFSWithWatch.TestServerHost;
3+
export type File = TestFSWithWatch.File;
4+
export type SymLink = TestFSWithWatch.SymLink;
5+
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
6+
export import checkArray = TestFSWithWatch.checkArray;
7+
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
8+
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
9+
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
10+
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
11+
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
12+
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
13+
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
1514

1615
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
1716
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8257,7 +8257,7 @@ new C();`
82578257

82588258
verifyProjectWithResolvedModule(session);
82598259

8260-
host.removeFolder(recognizersTextDist, /*recursive*/ true);
8260+
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
82618261
host.runQueuedTimeoutCallbacks();
82628262

82638263
verifyProjectWithUnresolvedModule(session);
@@ -9173,7 +9173,7 @@ describe("Test Suite 1", () => {
91739173
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
91749174

91759175
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
9176-
host.removeFile(unitTest1.path);
9176+
host.deleteFile(unitTest1.path);
91779177
host.checkTimeoutQueueLengthAndRun(2);
91789178
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
91799179

@@ -9297,7 +9297,7 @@ export function Test2() {
92979297
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
92989298

92999299
// Testing what happens if we delete the original sources.
9300-
host.removeFile(bTs.path);
9300+
host.deleteFile(bTs.path);
93019301

93029302
openFilesForSession([userTs], session);
93039303
const service = session.getProjectService();

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4125,7 +4125,7 @@ declare namespace ts {
41254125
declare namespace ts {
41264126
function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName?: string): string | undefined;
41274127
function resolveTripleslashReference(moduleName: string, containingFile: string): string;
4128-
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost;
4128+
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system?: System): CompilerHost;
41294129
function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
41304130
interface FormatDiagnosticsHost {
41314131
getCurrentDirectory(): string;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4125,7 +4125,7 @@ declare namespace ts {
41254125
declare namespace ts {
41264126
function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName?: string): string | undefined;
41274127
function resolveTripleslashReference(moduleName: string, containingFile: string): string;
4128-
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost;
4128+
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system?: System): CompilerHost;
41294129
function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
41304130
interface FormatDiagnosticsHost {
41314131
getCurrentDirectory(): string;

0 commit comments

Comments
 (0)