From dbdd9893f54a5a5e3165bc1e21010d9e51740ae8 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Mon, 27 Jun 2016 13:06:40 -0700 Subject: [PATCH] Import completions for require calls --- src/services/services.ts | 26 ++++-- ...etionForStringLiteralNonrelativeImport1.ts | 46 ++++++---- ...etionForStringLiteralNonrelativeImport2.ts | 16 ++-- ...etionForStringLiteralNonrelativeImport3.ts | 17 ++-- ...etionForStringLiteralNonrelativeImport4.ts | 43 +++++---- ...etionForStringLiteralNonrelativeImport5.ts | 29 +++--- ...etionForStringLiteralNonrelativeImport6.ts | 23 +++-- ...mpletionForStringLiteralRelativeImport1.ts | 89 ++++++++++--------- ...mpletionForStringLiteralRelativeImport2.ts | 44 +++++---- ...mpletionForStringLiteralRelativeImport3.ts | 44 +++++---- 10 files changed, 225 insertions(+), 152 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 650d0c4ce1a..04c435f1339 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2775,13 +2775,17 @@ namespace ts { function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { if (node.kind === SyntaxKind.StringLiteral) { - return isNameOfModuleDeclaration(node) || - (isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node); + return isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node); } return false; } + function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) { + return isExternalModuleImportEqualsDeclaration(node.parent.parent) && + getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; + } + /** Returns true if the position is within a comment */ function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean { // The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment @@ -4256,15 +4260,25 @@ namespace ts { const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile); if (argumentInfo) { - // Get string literal completions from specialized signatures of the target - return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo); + // Try to get string literal completions from specialized signatures of the target + const callExpressionCompletionEntries = getStringLiteralCompletionEntriesFromCallExpression(argumentInfo); + if (callExpressionCompletionEntries) { + return callExpressionCompletionEntries; + } + else if (isRequireCall(node.parent, false)) { + // If that failed but this call mataches the signature of a require call, treat the literal as an external module name + return getStringLiteralCompletionEntriesFromModuleNames(node); + } + else { + return undefined; + } } else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) { // Get all names of properties on the expression return getStringLiteralCompletionEntriesFromElementAccess(node.parent); } - else if (node.parent.kind === SyntaxKind.ImportDeclaration) { - // Get all known module names + else if (node.parent.kind === SyntaxKind.ImportDeclaration || isExpressionOfExternalModuleImportEqualsDeclaration(node)) { + // Get all known external module names or complete a path to a module return getStringLiteralCompletionEntriesFromModuleNames(node); } else { diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport1.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport1.ts index 681a6fce03c..5c7b2016a75 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport1.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport1.ts @@ -1,13 +1,17 @@ /// // @Filename: tests/test0.ts -//// import * as foo from "f/*0*/ +//// import * as foo1 from "f/*import_as0*/ +//// import * as foo2 from "fake-module//*import_as1*/ +//// import * as foo3 from "fake-module/*import_as2*/ -// @Filename: tests/test1.ts -//// import * as foo from "fake-module//*1*/ +//// import foo4 = require("f/*import_equals0*/ +//// import foo5 = require("fake-module//*import_equals1*/ +//// import foo6 = require("fake-module/*import_equals2*/ -// @Filename: tests/test2.ts -//// import * as foo from "fake-module/*2*/ +//// var foo7 = require("f/*require0*/ +//// var foo8 = require("fake-module//*require1*/ +//// var foo9 = require("fake-module/*require2*/ // @Filename: package.json //// { "dependencies": { "fake-module": "latest" }, "devDependencies": { "fake-module-dev": "latest" } } @@ -35,19 +39,23 @@ // @Filename: node_modules/unlisted-module/index.ts //// /*unlisted-module*/ -goTo.marker("0"); -verify.completionListContains("fake-module"); -verify.completionListContains("fake-module-dev"); -verify.not.completionListItemsCountIsGreaterThan(2); +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("1"); -verify.completionListContains("index"); -verify.completionListContains("ts"); -verify.completionListContains("dts"); -verify.completionListContains("tsx"); -verify.not.completionListItemsCountIsGreaterThan(4); +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListContains("fake-module"); + verify.completionListContains("fake-module-dev"); + verify.not.completionListItemsCountIsGreaterThan(2); -goTo.marker("2"); -verify.completionListContains("fake-module"); -verify.completionListContains("fake-module-dev"); -verify.not.completionListItemsCountIsGreaterThan(2); \ No newline at end of file + goTo.marker(kind + "1"); + verify.completionListContains("index"); + verify.completionListContains("ts"); + verify.completionListContains("dts"); + verify.completionListContains("tsx"); + verify.not.completionListItemsCountIsGreaterThan(4); + + goTo.marker(kind + "2"); + verify.completionListContains("fake-module"); + verify.completionListContains("fake-module-dev"); + verify.not.completionListItemsCountIsGreaterThan(2); +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport2.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport2.ts index c3e6f2e9062..2b5f57412de 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport2.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport2.ts @@ -1,7 +1,9 @@ /// // @Filename: tests/test0.ts -//// import * as foo from "fake-module//*0*/ +//// import * as foo1 from "fake-module//*import_as0*/ +//// import foo2 = require("fake-module//*import_equals0*/ +//// var foo3 = require("fake-module//*require0*/ // @Filename: package.json //// { "dependencies": { "fake-module": "latest" }, "devDependencies": { "fake-module-dev": "latest" } } @@ -26,7 +28,11 @@ // @Filename: node_modules/@types/unlisted-module/index.d.ts //// /*unlisted-types*/ -goTo.marker("0"); -verify.completionListContains("repeated"); -verify.completionListContains("other"); -verify.not.completionListItemsCountIsGreaterThan(2); +const kinds = ["import_as", "import_equals", "require"]; + +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListContains("repeated"); + verify.completionListContains("other"); + verify.not.completionListItemsCountIsGreaterThan(2); +} diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport3.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport3.ts index 7be26cf76d2..aec9f8411bc 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport3.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport3.ts @@ -2,7 +2,9 @@ // @allowJs: true // @Filename: tests/test0.ts -//// import * as foo from "fake-module//*0*/ +//// import * as foo1 from "fake-module//*import_as0*/ +//// import foo2 = require("fake-module//*import_equals0*/ +//// var foo3 = require("fake-module//*require0*/ // @Filename: package.json //// { "dependencies": { "fake-module": "latest" } } @@ -22,9 +24,12 @@ // @Filename: node_modules/fake-module/repeated.jsx //// /*repeatedjsx*/ -goTo.marker("0"); +const kinds = ["import_as", "import_equals", "require"]; -verify.completionListContains("ts"); -verify.completionListContains("tsx"); -verify.completionListContains("dts"); -verify.not.completionListItemsCountIsGreaterThan(3); +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListContains("ts"); + verify.completionListContains("tsx"); + verify.completionListContains("dts"); + verify.not.completionListItemsCountIsGreaterThan(3); +} diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport4.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport4.ts index baa13638569..64e3cbad48e 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport4.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport4.ts @@ -1,13 +1,17 @@ /// // @Filename: dir1/dir2/dir3/dir4/test0.ts -//// import * as foo from "f/*0*/ +//// import * as foo1 from "f/*import_as0*/ +//// import * as foo2 from "a/*import_as1*/ +//// import * as foo3 from "fake-module/*import_as2*/ -// @Filename: dir1/dir2/dir3/dir4/test1.ts -//// import * as foo from "a/*1*/ +//// import foo4 = require("f/*import_equals0*/ +//// import foo5 = require("a/*import_equals1*/ +//// import foo6 = require("fake-module/*import_equals2*/ -// @Filename: dir1/dir2/dir3/dir4/test2.ts -//// import * as foo from "fake-module/*2*/ +//// var foo7 = require("f/*require0*/ +//// var foo8 = require("a/*require1*/ +//// var foo9 = require("fake-module/*require2*/ // @Filename: package.json //// { "dependencies": { "fake-module": "latest" } } @@ -24,22 +28,25 @@ // @Filename: dir1/dir2/dir3/node_modules/fake-module3/ts.ts //// /*module3*/ +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("0"); +for (const kind of kinds) { + goTo.marker(kind + "0"); -verify.completionListContains("fake-module/"); -verify.completionListContains("fake-module2/"); -verify.completionListContains("fake-module3/"); -verify.not.completionListItemsCountIsGreaterThan(3); + verify.completionListContains("fake-module/"); + verify.completionListContains("fake-module2/"); + verify.completionListContains("fake-module3/"); + verify.not.completionListItemsCountIsGreaterThan(3); -goTo.marker("1"); + goTo.marker(kind + "1"); -verify.completionListContains("ambient-module-test"); -verify.not.completionListItemsCountIsGreaterThan(1); + verify.completionListContains("ambient-module-test"); + verify.not.completionListItemsCountIsGreaterThan(1); -goTo.marker("2"); + goTo.marker(kind + "2"); -verify.completionListContains("fake-module/"); -verify.completionListContains("fake-module2/"); -verify.completionListContains("fake-module3/"); -verify.not.completionListItemsCountIsGreaterThan(3); + verify.completionListContains("fake-module/"); + verify.completionListContains("fake-module2/"); + verify.completionListContains("fake-module3/"); + verify.not.completionListItemsCountIsGreaterThan(3); +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport5.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport5.ts index a5bd602bbbf..4a8b9e2f614 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport5.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport5.ts @@ -1,10 +1,14 @@ /// // @Filename: test0.ts -//// import * as foo from "/*0*/ +//// import * as foo1 from "/*import_as0*/ +//// import * as foo2 from "a/*import_as1*/ -// @Filename: test1.ts -//// import * as foo from "a/*1*/ +//// import foo3 = require("/*import_equals0*/ +//// import foo4 = require("a/*import_equals1*/ + +//// var foo5 = require("/*require0*/ +//// var foo6 = require("a/*require1*/ // @Filename: ambientModules.d.ts //// declare module "ambientModule" {} @@ -13,16 +17,19 @@ // @Filename: ambientModules2.d.ts //// declare module "otherOtherAmbientModule" {} +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("0"); +for (const kind of kinds) { + goTo.marker(kind + "0"); -verify.completionListContains("ambientModule"); -verify.completionListContains("otherAmbientModule"); -verify.completionListContains("otherOtherAmbientModule"); -verify.not.completionListItemsCountIsGreaterThan(3); + verify.completionListContains("ambientModule"); + verify.completionListContains("otherAmbientModule"); + verify.completionListContains("otherOtherAmbientModule"); + verify.not.completionListItemsCountIsGreaterThan(3); -goTo.marker("1"); + goTo.marker(kind + "1"); -verify.completionListContains("ambientModule"); -verify.not.completionListItemsCountIsGreaterThan(1); + verify.completionListContains("ambientModule"); + verify.not.completionListItemsCountIsGreaterThan(1); +} diff --git a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport6.ts b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport6.ts index ed588f35802..bfd0539e149 100644 --- a/tests/cases/fourslash/completionForStringLiteralNonrelativeImport6.ts +++ b/tests/cases/fourslash/completionForStringLiteralNonrelativeImport6.ts @@ -1,7 +1,9 @@ /// // @Filename: tests/test0.ts -//// import * as foo from "module-/*0*/ +//// import * as foo1 from "module-/*import_as0*/ +//// import foo2 = require("module-/*import_equals0*/ +//// var foo3 = require("module-/*require0*/ // @Filename: package.json //// { "dependencies": { @@ -45,13 +47,16 @@ // @Filename: node_modules/module-typings/types.d.ts //// /*module-typings*/ +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("0"); +for (const kind of kinds) { + goTo.marker(kind + "0"); -verify.completionListContains("module-no-main/"); -verify.completionListContains("module-no-main-index-d-ts/"); -verify.completionListContains("module-index-ts"); -verify.completionListContains("module-index-d-ts-explicit-main"); -verify.completionListContains("module-index-d-ts-default-main"); -verify.completionListContains("module-typings"); -verify.not.completionListItemsCountIsGreaterThan(6); + verify.completionListContains("module-no-main/"); + verify.completionListContains("module-no-main-index-d-ts/"); + verify.completionListContains("module-index-ts"); + verify.completionListContains("module-index-d-ts-explicit-main"); + verify.completionListContains("module-index-d-ts-default-main"); + verify.completionListContains("module-typings"); + verify.not.completionListItemsCountIsGreaterThan(6); +} diff --git a/tests/cases/fourslash/completionForStringLiteralRelativeImport1.ts b/tests/cases/fourslash/completionForStringLiteralRelativeImport1.ts index 26a6645b3fa..bb9d6a59c7b 100644 --- a/tests/cases/fourslash/completionForStringLiteralRelativeImport1.ts +++ b/tests/cases/fourslash/completionForStringLiteralRelativeImport1.ts @@ -1,22 +1,30 @@ /// // @Filename: test0.ts -//// import * as foo from "./*0*/ +//// import * as foo1 from "./*import_as0*/ +//// import * as foo2 from ".//*import_as1*/ +//// import * as foo3 from "./f/*import_as2*/ +//// import * as foo4 from "./folder//*import_as3*/ +//// import * as foo5 from "./folder/h/*import_as4*/ -// @Filename: test1.ts -//// import * as foo from ".//*1*/ +//// import foo6 = require("./*import_equals0*/ +//// import foo7 = require(".//*import_equals1*/ +//// import foo8 = require("./f/*import_equals2*/ +//// import foo9 = require("./folder//*import_equals3*/ +//// import foo10 = require("./folder/h/*import_equals4*/ -// @Filename: test2.ts -//// import * as foo from "./f/*2*/ - -// @Filename: test3.ts -//// import * as foo from "./folder//*3*/ - -// @Filename: test4.ts -//// import * as foo from "./folder/h/*4*/ +//// var foo11 = require("./*require0*/ +//// var foo12 = require(".//*require1*/ +//// var foo13 = require("./f/*require2*/ +//// var foo14 = require("./folder//*require3*/ +//// var foo15 = require("./folder/h/*require4*/ // @Filename: parentTest/sub/test5.ts -//// import * as foo from "../g/*5*/ +//// import * as foo16 from "../g/*import_as5*/ + +//// import foo17 = require("../g/*import_equals5*/ + +//// var foo18 = require("../g/*require5*/ // @Filename: f1.ts //// /*f1*/ @@ -40,38 +48,37 @@ //// /*parentf1*/ // @Filename: parentTest/g1.ts //// /*parentg1*/ +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("0"); -verify.completionListIsEmpty(); +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListIsEmpty(); -goTo.marker("1"); -verify.completionListContains("f1"); -verify.completionListContains("f2"); -verify.completionListContains("e1"); -verify.completionListContains("test0"); -verify.completionListContains("test1"); -verify.completionListContains("test2"); -verify.completionListContains("test3"); -verify.completionListContains("test4"); -verify.completionListContains("folder/"); -verify.completionListContains("parentTest/"); -verify.not.completionListItemsCountIsGreaterThan(10); + goTo.marker(kind + "1"); + verify.completionListContains("f1"); + verify.completionListContains("f2"); + verify.completionListContains("e1"); + verify.completionListContains("test0"); + verify.completionListContains("folder/"); + verify.completionListContains("parentTest/"); + verify.not.completionListItemsCountIsGreaterThan(6); -goTo.marker("2"); -verify.completionListContains("f1"); -verify.completionListContains("f2"); -verify.completionListContains("folder/"); -verify.not.completionListItemsCountIsGreaterThan(3); + goTo.marker(kind + "2"); + verify.completionListContains("f1"); + verify.completionListContains("f2"); + verify.completionListContains("folder/"); + verify.not.completionListItemsCountIsGreaterThan(3); -goTo.marker("3"); -verify.completionListContains("f1"); -verify.completionListContains("h1"); -verify.not.completionListItemsCountIsGreaterThan(2); + goTo.marker(kind + "3"); + verify.completionListContains("f1"); + verify.completionListContains("h1"); + verify.not.completionListItemsCountIsGreaterThan(2); -goTo.marker("4"); -verify.completionListContains("h1"); -verify.not.completionListItemsCountIsGreaterThan(1); + goTo.marker(kind + "4"); + verify.completionListContains("h1"); + verify.not.completionListItemsCountIsGreaterThan(1); -goTo.marker("5"); -verify.completionListContains("g1"); -verify.not.completionListItemsCountIsGreaterThan(1); \ No newline at end of file + goTo.marker(kind + "5"); + verify.completionListContains("g1"); + verify.not.completionListItemsCountIsGreaterThan(1); +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionForStringLiteralRelativeImport2.ts b/tests/cases/fourslash/completionForStringLiteralRelativeImport2.ts index 1b4abe79119..4e879148469 100644 --- a/tests/cases/fourslash/completionForStringLiteralRelativeImport2.ts +++ b/tests/cases/fourslash/completionForStringLiteralRelativeImport2.ts @@ -2,10 +2,14 @@ // @allowJs: true // @Filename: test0.ts -//// import * as foo from ".//*0*/ +//// import * as foo1 from ".//*import_as0*/ +//// import * as foo2 from "./f/*import_as1*/ -// @Filename: test1.ts -//// import * as foo from "./f/*1*/ +//// import foo3 = require(".//*import_equals0*/ +//// import foo4 = require("./f/*import_equals1*/ + +//// var foo5 = require(".//*require0*/ +//// var foo6 = require("./f/*require1*/ // @Filename: f1.ts //// /f1*/ @@ -23,21 +27,23 @@ //// /*e1*/ // @Filename: e2.js //// /*e2*/ +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("0"); -verify.completionListContains("f1"); -verify.completionListContains("f2"); -verify.completionListContains("f3"); -verify.completionListContains("f4"); -verify.completionListContains("e1"); -verify.completionListContains("e2"); -verify.completionListContains("test0"); -verify.completionListContains("test1"); -verify.not.completionListItemsCountIsGreaterThan(8); +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListContains("f1"); + verify.completionListContains("f2"); + verify.completionListContains("f3"); + verify.completionListContains("f4"); + verify.completionListContains("e1"); + verify.completionListContains("e2"); + verify.completionListContains("test0"); + verify.not.completionListItemsCountIsGreaterThan(7); -goTo.marker("1"); -verify.completionListContains("f1"); -verify.completionListContains("f2"); -verify.completionListContains("f3"); -verify.completionListContains("f4"); -verify.not.completionListItemsCountIsGreaterThan(4); \ No newline at end of file + goTo.marker(kind + "1"); + verify.completionListContains("f1"); + verify.completionListContains("f2"); + verify.completionListContains("f3"); + verify.completionListContains("f4"); + verify.not.completionListItemsCountIsGreaterThan(4); +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionForStringLiteralRelativeImport3.ts b/tests/cases/fourslash/completionForStringLiteralRelativeImport3.ts index 1b10ffff5b6..426eb3c2318 100644 --- a/tests/cases/fourslash/completionForStringLiteralRelativeImport3.ts +++ b/tests/cases/fourslash/completionForStringLiteralRelativeImport3.ts @@ -1,13 +1,17 @@ /// // @Filename: tests/test0.ts -//// import * as foo from "c:/tests/cases/f/*0*/ +//// import * as foo1 from "c:/tests/cases/f/*import_as0*/ +//// import * as foo2 from "c:/tests/cases/fourslash/*import_as1*/ +//// import * as foo3 from "c:/tests/cases/fourslash//*import_as2*/ -// @Filename: tests/test1.ts -//// import * as foo from "c:/tests/cases/fourslash/*1*/ +//// import foo4 = require("c:/tests/cases/f/*import_equals0*/ +//// import foo5 = require("c:/tests/cases/fourslash/*import_equals1*/ +//// import foo6 = require("c:/tests/cases/fourslash//*import_equals2*/ -// @Filename: tests/test2.ts -//// import * as foo from "c:/tests/cases/fourslash//*2*/ +//// var foo7 = require("c:/tests/cases/f/*require0*/ +//// var foo8 = require("c:/tests/cases/fourslash/*require1*/ +//// var foo9 = require("c:/tests/cases/fourslash//*require2*/ // @Filename: f1.ts //// /*f1*/ @@ -24,18 +28,22 @@ // @Filename: e2.js //// /*e2*/ -goTo.marker("0"); -verify.completionListContains("fourslash/"); -verify.not.completionListItemsCountIsGreaterThan(1); +const kinds = ["import_as", "import_equals", "require"]; -goTo.marker("1"); -verify.completionListContains("fourslash/"); -verify.not.completionListItemsCountIsGreaterThan(1); +for (const kind of kinds) { + goTo.marker(kind + "0"); + verify.completionListContains("fourslash/"); + verify.not.completionListItemsCountIsGreaterThan(1); -goTo.marker("2"); -verify.completionListContains("f1"); -verify.completionListContains("f2"); -verify.completionListContains("e1"); -verify.completionListContains("folder/"); -verify.completionListContains("tests/"); -verify.not.completionListItemsCountIsGreaterThan(5); \ No newline at end of file + goTo.marker(kind + "1"); + verify.completionListContains("fourslash/"); + verify.not.completionListItemsCountIsGreaterThan(1); + + goTo.marker(kind + "2"); + verify.completionListContains("f1"); + verify.completionListContains("f2"); + verify.completionListContains("e1"); + verify.completionListContains("folder/"); + verify.completionListContains("tests/"); + verify.not.completionListItemsCountIsGreaterThan(5); +} \ No newline at end of file