Skip to content

Commit

Permalink
Merge pull request #31820 from microsoft/nodeModules
Browse files Browse the repository at this point in the history
  When resolving from typings cache, handle node code modules
  • Loading branch information
sheetalkamat committed Jun 12, 2019
2 parents 520f7e8 + 2fd80b3 commit a0d164f
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
8 changes: 7 additions & 1 deletion src/compiler/resolutionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ namespace ts {
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost | undefined;
projectName?: string;
getGlobalCache?(): string | undefined;
globalCacheResolutionModuleName?(externalModuleName: string): string;
writeLog(s: string): void;
maxNumberOfFilesToIterateForInvalidation?: number;
getCurrentProgram(): Program | undefined;
Expand Down Expand Up @@ -270,7 +271,12 @@ namespace ts {
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
// create different collection of failed lookup locations for second pass
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(
Debug.assertDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName),
resolutionHost.projectName,
compilerOptions,
host,
globalCache);
if (resolvedModule) {
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as string[], failedLookupLocations) };
}
Expand Down
6 changes: 5 additions & 1 deletion src/jsTyping/jsTyping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ namespace ts.JsTyping {

export const nodeCoreModules = arrayToSet(nodeCoreModuleList);

export function nonRelativeModuleNameForTypingCache(moduleName: string) {
return nodeCoreModules.has(moduleName) ? "node" : moduleName;
}

/**
* A map of loose file names to library names that we are confident require typings
*/
Expand Down Expand Up @@ -150,7 +154,7 @@ namespace ts.JsTyping {
// add typings for unresolved imports
if (unresolvedImports) {
const module = deduplicate<string>(
unresolvedImports.map(moduleId => nodeCoreModules.has(moduleId) ? "node" : moduleId),
unresolvedImports.map(nonRelativeModuleNameForTypingCache),
equateStringsCaseSensitive,
compareStringsCaseSensitive);
addInferredTypings(module, "Inferred typings from unresolved imports");
Expand Down
3 changes: 3 additions & 0 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ namespace ts.server {
return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined;
}

/*@internal*/
globalCacheResolutionModuleName = JsTyping.nonRelativeModuleNameForTypingCache;

/*@internal*/
fileIsOpen(filePath: Path) {
return this.projectService.openFiles.has(filePath);
Expand Down
64 changes: 64 additions & 0 deletions src/testRunner/unittests/tsserver/typingsInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,70 @@ namespace ts.projectSystem {
import * as c from "foo/a/c";
`, ["foo"], [fooAA, fooAB, fooAC]);
});

it("should handle node core modules", () => {
const file: TestFSWithWatch.File = {
path: "/a/b/app.js",
content: `// @ts-check
const net = require("net");
const stream = require("stream");`
};
const nodeTyping: TestFSWithWatch.File = {
path: `${globalTypingsCacheLocation}/node_modules/node/index.d.ts`,
content: `
declare module "net" {
export type n = number;
}
declare module "stream" {
export type s = string;
}`,
};

const host = createServerHost([file, libFile]);
const installer = new (class extends Installer {
constructor() {
super(host, { globalTypingsCacheLocation, typesRegistry: createTypesRegistry("node") });
}
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) {
executeCommand(this, host, ["node"], [nodeTyping], cb);
}
})();
const projectService = createProjectService(host, { typingsInstaller: installer });
projectService.openClientFile(file.path);
projectService.checkNumberOfProjects({ inferredProjects: 1 });

const proj = projectService.inferredProjects[0];
checkProjectActualFiles(proj, [file.path, libFile.path]);
installer.installAll(/*expectedCount*/ 1);
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);
projectService.applyChangesInOpenFiles(
/*openFiles*/ undefined,
arrayIterator([{
fileName: file.path,
changes: arrayIterator([{
span: {
start: file.content.indexOf(`"stream"`) + 2,
length: 0
},
newText: " "
}])
}]),
/*closedFiles*/ undefined
);
// Below timeout Updates the typings to empty array because of "s tream" as unsresolved import
// and schedules the update graph because of this.
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);

// Here, since typings doesnt contain node typings and resolution fails and
// node typings go out of project,
// but because we handle core node modules when resolving from typings cache
// node typings are included in the project
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(proj, [file.path, libFile.path, nodeTyping.path]);
});
});

describe("unittests:: tsserver:: typingsInstaller:: tsserver:: with inferred Project", () => {
Expand Down

0 comments on commit a0d164f

Please sign in to comment.