diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 5c94dde5cc5..96c6e08f0f5 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -1191,10 +1191,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
case SyntaxKind.JSDocEnumTag:
bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
break;
- // In source files and blocks, bind functions first to match hoisting that occurs at runtime
case SyntaxKind.JSDocImportTag:
bindJSDocImportTag(node as JSDocImportTag);
break;
+ // In source files and blocks, bind functions first to match hoisting that occurs at runtime
case SyntaxKind.SourceFile: {
bindEachFunctionsFirst((node as SourceFile).statements);
bind((node as SourceFile).endOfFileToken);
@@ -2105,7 +2105,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
}
function bindJSDocImportTag(node: JSDocImportTag) {
+ // don't bind the importClause yet; that's delayed until bindJSDocImports
bind(node.tagName);
+ bind(node.moduleSpecifier);
+ bind(node.attributes);
if (typeof node.comment !== "string") {
bindEach(node.comment);
diff --git a/tests/cases/fourslash/completionsImportDeclarationAttributesEmptyModuleSpecifier1.ts b/tests/cases/fourslash/completionsImportDeclarationAttributesEmptyModuleSpecifier1.ts
new file mode 100644
index 00000000000..f083815dfcb
--- /dev/null
+++ b/tests/cases/fourslash/completionsImportDeclarationAttributesEmptyModuleSpecifier1.ts
@@ -0,0 +1,17 @@
+///
+
+// @strict: true
+
+// @filename: global.d.ts
+//// interface ImportAttributes {
+//// type: "json";
+//// }
+
+// @filename: index.ts
+//// import * as ns from "" with { type: "/**/" };
+
+verify.completions({
+ marker: "",
+ exact: ["json"],
+ isNewIdentifierLocation: false,
+});
diff --git a/tests/cases/fourslash/completionsImportDeclarationAttributesErrorModuleSpecifier1.ts b/tests/cases/fourslash/completionsImportDeclarationAttributesErrorModuleSpecifier1.ts
new file mode 100644
index 00000000000..bbad49da515
--- /dev/null
+++ b/tests/cases/fourslash/completionsImportDeclarationAttributesErrorModuleSpecifier1.ts
@@ -0,0 +1,17 @@
+///
+
+// @strict: true
+
+// @filename: global.d.ts
+//// interface ImportAttributes {
+//// type: "json";
+//// }
+
+// @filename: index.ts
+//// import * as ns from () with { type: "/**/" };
+
+verify.completions({
+ marker: "",
+ exact: ["json"],
+ isNewIdentifierLocation: false,
+});
diff --git a/tests/cases/fourslash/completionsJSDocImportTagAttributesEmptyModuleSpecifier1.ts b/tests/cases/fourslash/completionsJSDocImportTagAttributesEmptyModuleSpecifier1.ts
new file mode 100644
index 00000000000..ad23ca3b933
--- /dev/null
+++ b/tests/cases/fourslash/completionsJSDocImportTagAttributesEmptyModuleSpecifier1.ts
@@ -0,0 +1,19 @@
+///
+
+// @strict: true
+// @checkJs: true
+// @allowJs: true
+
+// @filename: global.d.ts
+//// interface ImportAttributes {
+//// type: "json";
+//// }
+
+// @filename: index.js
+//// /** @import * as ns from "" with { type: "/**/" } */
+
+verify.completions({
+ marker: "",
+ exact: ["json"],
+ isNewIdentifierLocation: false,
+});
diff --git a/tests/cases/fourslash/completionsJSDocImportTagAttributesErrorModuleSpecifier1.ts b/tests/cases/fourslash/completionsJSDocImportTagAttributesErrorModuleSpecifier1.ts
new file mode 100644
index 00000000000..56825e73e3f
--- /dev/null
+++ b/tests/cases/fourslash/completionsJSDocImportTagAttributesErrorModuleSpecifier1.ts
@@ -0,0 +1,19 @@
+///
+
+// @strict: true
+// @checkJs: true
+// @allowJs: true
+
+// @filename: global.d.ts
+//// interface ImportAttributes {
+//// type: "json";
+//// }
+
+// @filename: index.js
+//// /** @import * as ns from () with { type: "/**/" } */
+
+verify.completions({
+ marker: "",
+ exact: ["json"],
+ isNewIdentifierLocation: false,
+});
diff --git a/tests/cases/fourslash/completionsJSDocImportTagEmptyModuleSpecifier1.ts b/tests/cases/fourslash/completionsJSDocImportTagEmptyModuleSpecifier1.ts
new file mode 100644
index 00000000000..ccbe067406e
--- /dev/null
+++ b/tests/cases/fourslash/completionsJSDocImportTagEmptyModuleSpecifier1.ts
@@ -0,0 +1,18 @@
+///
+
+// @strict: true
+// @checkJs: true
+// @allowJs: true
+// @moduleResolution: nodenext
+
+// @filename: node_modules/pkg/index.d.ts
+//// export type MyUnion = string | number;
+
+// @filename: index.js
+//// /** @import { MyUnion } from "/**/" */
+
+verify.completions({
+ marker: "",
+ exact: ["pkg"],
+ isNewIdentifierLocation: true,
+});
diff --git a/tests/cases/fourslash/completionsJSDocNoCrash1.ts b/tests/cases/fourslash/completionsJSDocNoCrash1.ts
new file mode 100644
index 00000000000..a5aa659a9e0
--- /dev/null
+++ b/tests/cases/fourslash/completionsJSDocNoCrash1.ts
@@ -0,0 +1,31 @@
+///
+
+// @strict: true
+// @checkJs: true
+// @allowJs: true
+
+// @filename: index.js
+//// /**
+//// * @example
+////
+//// @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
+////
+////
+////
+//// .animate-show.ng-hide-add.ng-hide-add-active,
+//// .animate-show.ng-hide-remove.ng-hide-remove-active {
+//// transition:all linear 0./**/5s;
+//// }
+////
+////
+//// */
+//// var ngShowDirective = ['$animate', function($animate) {}];
+
+verify.completions({
+ marker: "",
+ includes: ["url"],
+ isNewIdentifierLocation: true,
+ preferences: {
+ includeCompletionsWithInsertText: true
+ }
+});
diff --git a/tests/cases/fourslash/completionsJSDocNoCrash2.ts b/tests/cases/fourslash/completionsJSDocNoCrash2.ts
new file mode 100644
index 00000000000..e37d4452245
--- /dev/null
+++ b/tests/cases/fourslash/completionsJSDocNoCrash2.ts
@@ -0,0 +1,29 @@
+///
+
+// @strict: true
+
+// @filename: index.ts
+//// /**
+//// * @example
+////
+//// @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
+////
+////
+////
+//// .animate-show.ng-hide-add.ng-hide-add-active,
+//// .animate-show.ng-hide-remove.ng-hide-remove-active {
+//// transition:all linear 0./**/5s;
+//// }
+////
+////
+//// */
+//// var ngShowDirective = ['$animate', function($animate) {}];
+
+verify.completions({
+ marker: "",
+ exact: completion.globalTypes,
+ isNewIdentifierLocation: false,
+ preferences: {
+ includeCompletionsWithInsertText: true
+ }
+});