diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index 12e62aaa7b9ab..d6f8a2d01fcee 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -692,7 +692,54 @@ namespace ts.projectSystem { checkProjectActualFiles(p, [app.path, jqueryDTS.path]); }); - it("configured projects discover from bower.josn", () => { + it("configured projects discover from bower_components", () => { + const app = { + path: "/app.js", + content: "" + }; + const jsconfig = { + path: "/jsconfig.json", + content: JSON.stringify({}) + }; + const jquery = { + path: "/bower_components/jquery/index.js", + content: "" + }; + const jqueryPackage = { + path: "/bower_components/jquery/package.json", + content: JSON.stringify({ name: "jquery" }) + }; + const jqueryDTS = { + path: "/tmp/node_modules/@types/jquery/index.d.ts", + content: "" + }; + const host = createServerHost([app, jsconfig, jquery, jqueryPackage]); + const installer = new (class extends Installer { + constructor() { + super(host, { globalTypingsCacheLocation: "/tmp", typesRegistry: createTypesRegistry("jquery") }); + } + installWorker(_requestId: number, _args: string[], _cwd: string, cb: server.typingsInstaller.RequestCompletedAction) { + const installedTypings = ["@types/jquery"]; + const typingFiles = [jqueryDTS]; + executeCommand(this, host, installedTypings, typingFiles, cb); + } + })(); + + const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer }); + projectService.openClientFile(app.path); + + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + const p = projectService.configuredProjects[0]; + checkProjectActualFiles(p, [app.path]); + checkWatchedFiles(host, [jsconfig.path, "/bower_components", "/node_modules"]); + + installer.installAll(/*expectedCount*/ 1); + + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(p, [app.path, jqueryDTS.path]); + }); + + it("configured projects discover from bower.json", () => { const app = { path: "/app.js", content: "" @@ -975,7 +1022,7 @@ namespace ts.projectSystem { } }); - it("should use cached locaitons", () => { + it("should use cached locations", () => { const f = { path: "/a/b/app.js", content: "" diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index e7196e8f491c5..c11f6e67a71a6 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -99,8 +99,11 @@ namespace ts.JsTyping { const bowerJsonPath = combinePaths(searchDir, "bower.json"); getTypingNamesFromJson(bowerJsonPath, filesToWatch); + const bowerComponentsPath = combinePaths(searchDir, "bower_components"); + getTypingNamesFromPackagesFolder(bowerComponentsPath); + const nodeModulesPath = combinePaths(searchDir, "node_modules"); - getTypingNamesFromNodeModuleFolder(nodeModulesPath); + getTypingNamesFromPackagesFolder(nodeModulesPath); } getTypingNamesFromSourceFileNames(fileNames); @@ -199,20 +202,24 @@ namespace ts.JsTyping { } /** - * Infer typing names from node_module folder - * @param nodeModulesPath is the path to the "node_modules" folder + * Infer typing names from packages folder (ex: node_module, bower_components) + * @param packagesFolderPath is the path to the packages folder + */ - function getTypingNamesFromNodeModuleFolder(nodeModulesPath: string) { + function getTypingNamesFromPackagesFolder(packagesFolderPath: string) { + filesToWatch.push(packagesFolderPath); + // Todo: add support for ModuleResolutionHost too - if (!host.directoryExists(nodeModulesPath)) { + if (!host.directoryExists(packagesFolderPath)) { return; } const typingNames: string[] = []; - const fileNames = host.readDirectory(nodeModulesPath, [".json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2); + const fileNames = host.readDirectory(packagesFolderPath, [".json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2); for (const fileName of fileNames) { const normalizedFileName = normalizePath(fileName); - if (getBaseFileName(normalizedFileName) !== "package.json") { + const baseFileName = getBaseFileName(normalizedFileName); + if (baseFileName !== "package.json" && baseFileName !== "bower.json") { continue; } const result = readConfigFile(normalizedFileName, (path: string) => host.readFile(path)); @@ -224,7 +231,7 @@ namespace ts.JsTyping { // npm 3's package.json contains a "_requiredBy" field // we should include all the top level module names for npm 2, and only module names whose // "_requiredBy" field starts with "#" or equals "/" for npm 3. - if (packageJson._requiredBy && + if (baseFileName === "package.json" && packageJson._requiredBy && filter(packageJson._requiredBy, (r: string) => r[0] === "#" || r === "/").length === 0) { continue; }