Skip to content

Commit 228a885

Browse files
authored
Merge pull request microsoft#19435 from Microsoft/foundWhileSearchingNodeModules
Mark the files found during node_modules search correctly when reusing program structure completely
2 parents 538f1bf + 7828746 commit 228a885

File tree

2 files changed

+95
-11
lines changed

2 files changed

+95
-11
lines changed

src/compiler/program.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,10 @@ namespace ts {
10491049
// update fileName -> file mapping
10501050
for (let i = 0; i < newSourceFiles.length; i++) {
10511051
filesByName.set(filePaths[i], newSourceFiles[i]);
1052+
// Set the file as found during node modules search if it was found that way in old progra,
1053+
if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(filePaths[i]))) {
1054+
sourceFilesFoundSearchingNodeModules.set(filePaths[i], true);
1055+
}
10521056
}
10531057

10541058
files = newSourceFiles;

src/harness/unittests/tscWatchMode.ts

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ namespace ts.tscWatch {
8080
checkOutputDoesNotContain(host, expectedNonAffectedFiles);
8181
}
8282

83-
function checkOutputErrors(host: WatchedSystem, errors?: ReadonlyArray<Diagnostic>, isInitial?: true, skipWaiting?: true) {
83+
function checkOutputErrors(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, isInitial?: true, skipWaiting?: true) {
8484
const outputs = host.getOutput();
85-
const expectedOutputCount = (isInitial ? 0 : 1) + (errors ? errors.length : 0) + (skipWaiting ? 0 : 1);
85+
const expectedOutputCount = (isInitial ? 0 : 1) + errors.length + (skipWaiting ? 0 : 1);
8686
assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString());
8787
let index = 0;
8888
if (!isInitial) {
@@ -339,7 +339,7 @@ namespace ts.tscWatch {
339339
host.runQueuedTimeoutCallbacks();
340340
checkProgramRootFiles(watch(), [file1.path]);
341341
checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]);
342-
checkOutputErrors(host);
342+
checkOutputErrors(host, emptyArray);
343343
});
344344

345345
it("should reflect change in config file", () => {
@@ -792,7 +792,7 @@ namespace ts.tscWatch {
792792
moduleFile.path = moduleFileOldPath;
793793
host.reloadFS([moduleFile, file1, libFile]);
794794
host.runQueuedTimeoutCallbacks();
795-
checkOutputErrors(host);
795+
checkOutputErrors(host, emptyArray);
796796
});
797797

798798
it("rename a module file and rename back should restore the states for configured projects", () => {
@@ -824,7 +824,7 @@ namespace ts.tscWatch {
824824
moduleFile.path = moduleFileOldPath;
825825
host.reloadFS([moduleFile, file1, configFile, libFile]);
826826
host.runQueuedTimeoutCallbacks();
827-
checkOutputErrors(host);
827+
checkOutputErrors(host, emptyArray);
828828
});
829829

830830
it("types should load from config file path if config exists", () => {
@@ -867,7 +867,7 @@ namespace ts.tscWatch {
867867

868868
host.reloadFS([file1, moduleFile, libFile]);
869869
host.runQueuedTimeoutCallbacks();
870-
checkOutputErrors(host);
870+
checkOutputErrors(host, emptyArray);
871871
});
872872

873873
it("Configure file diagnostics events are generated when the config file has errors", () => {
@@ -942,7 +942,7 @@ namespace ts.tscWatch {
942942
}`;
943943
host.reloadFS([file, configFile, libFile]);
944944
host.runQueuedTimeoutCallbacks();
945-
checkOutputErrors(host);
945+
checkOutputErrors(host, emptyArray);
946946
});
947947

948948
it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => {
@@ -1745,7 +1745,7 @@ namespace ts.tscWatch {
17451745

17461746
host.runQueuedTimeoutCallbacks();
17471747
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
1748-
checkOutputErrors(host);
1748+
checkOutputErrors(host, emptyArray);
17491749
});
17501750

17511751
it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => {
@@ -1791,7 +1791,7 @@ namespace ts.tscWatch {
17911791
host.reloadFS(filesWithImported);
17921792
host.checkTimeoutQueueLengthAndRun(1);
17931793
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
1794-
checkOutputErrors(host);
1794+
checkOutputErrors(host, emptyArray);
17951795
});
17961796

17971797
it("works when module resolution changes to ambient module", () => {
@@ -1831,7 +1831,7 @@ declare module "fs" {
18311831

18321832
host.reloadFS(filesWithNodeType);
18331833
host.runQueuedTimeoutCallbacks();
1834-
checkOutputErrors(host);
1834+
checkOutputErrors(host, emptyArray);
18351835
});
18361836

18371837
it("works when included file with ambient module changes", () => {
@@ -1874,7 +1874,87 @@ declare module "fs" {
18741874
file.content += fileContentWithFS;
18751875
host.reloadFS(files);
18761876
host.runQueuedTimeoutCallbacks();
1877-
checkOutputErrors(host);
1877+
checkOutputErrors(host, emptyArray);
1878+
});
1879+
1880+
it("works when reusing program with files from external library", () => {
1881+
interface ExpectedFile { path: string; isExpectedToEmit?: boolean; content?: string; }
1882+
const configDir = "/a/b/projects/myProject/src/";
1883+
const file1: FileOrFolder = {
1884+
path: configDir + "file1.ts",
1885+
content: 'import module1 = require("module1");\nmodule1("hello");'
1886+
};
1887+
const file2: FileOrFolder = {
1888+
path: configDir + "file2.ts",
1889+
content: 'import module11 = require("module1");\nmodule11("hello");'
1890+
};
1891+
const module1: FileOrFolder = {
1892+
path: "/a/b/projects/myProject/node_modules/module1/index.js",
1893+
content: "module.exports = options => { return options.toString(); }"
1894+
};
1895+
const configFile: FileOrFolder = {
1896+
path: configDir + "tsconfig.json",
1897+
content: JSON.stringify({
1898+
compilerOptions: {
1899+
allowJs: true,
1900+
rootDir: ".",
1901+
outDir: "../dist",
1902+
moduleResolution: "node",
1903+
maxNodeModuleJsDepth: 1
1904+
}
1905+
})
1906+
};
1907+
const outDirFolder = "/a/b/projects/myProject/dist/";
1908+
const programFiles = [file1, file2, module1, libFile];
1909+
const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" });
1910+
const watch = createWatchModeWithConfigFile(configFile.path, host);
1911+
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
1912+
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
1913+
const expectedFiles: ExpectedFile[] = [
1914+
createExpectedEmittedFile(file1),
1915+
createExpectedEmittedFile(file2),
1916+
createExpectedToNotEmitFile("index.js"),
1917+
createExpectedToNotEmitFile("src/index.js"),
1918+
createExpectedToNotEmitFile("src/file1.js"),
1919+
createExpectedToNotEmitFile("src/file2.js"),
1920+
createExpectedToNotEmitFile("lib.js"),
1921+
createExpectedToNotEmitFile("lib.d.ts")
1922+
];
1923+
verifyExpectedFiles(expectedFiles);
1924+
1925+
file1.content += "\n;";
1926+
expectedFiles[0].content += ";\n"; // Only emit file1 with this change
1927+
expectedFiles[1].isExpectedToEmit = false;
1928+
host.reloadFS(programFiles.concat(configFile));
1929+
host.runQueuedTimeoutCallbacks();
1930+
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
1931+
checkOutputErrors(host, emptyArray);
1932+
verifyExpectedFiles(expectedFiles);
1933+
1934+
1935+
function verifyExpectedFiles(expectedFiles: ExpectedFile[]) {
1936+
forEach(expectedFiles, f => {
1937+
assert.equal(!!host.fileExists(f.path), f.isExpectedToEmit, "File " + f.path + " is expected to " + (f.isExpectedToEmit ? "emit" : "not emit"));
1938+
if (f.isExpectedToEmit) {
1939+
assert.equal(host.readFile(f.path), f.content, "Expected contents of " + f.path);
1940+
}
1941+
});
1942+
}
1943+
1944+
function createExpectedToNotEmitFile(fileName: string): ExpectedFile {
1945+
return {
1946+
path: outDirFolder + fileName,
1947+
isExpectedToEmit: false
1948+
};
1949+
}
1950+
1951+
function createExpectedEmittedFile(file: FileOrFolder): ExpectedFile {
1952+
return {
1953+
path: removeFileExtension(file.path.replace(configDir, outDirFolder)) + Extension.Js,
1954+
isExpectedToEmit: true,
1955+
content: '"use strict";\nexports.__esModule = true;\n' + file.content.replace("import", "var") + "\n"
1956+
};
1957+
}
18781958
});
18791959
});
18801960

0 commit comments

Comments
 (0)