From 3c718983dce640178989cb81407dd29c76ed08e1 Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Mon, 24 Jul 2023 12:58:45 -0700
Subject: [PATCH 1/3] Enable eslint rule @typescript-eslint/no-unused-vars,
 disable compiler rule

---
 .eslintrc.json                     |   7 +-
 package-lock.json                  | 197 +++++++++++++++++++++++++++++
 package.json                       |   1 +
 src/compiler/core.ts               |   6 +-
 src/compiler/emitter.ts            |   1 +
 src/compiler/moduleNameResolver.ts |   2 +-
 src/compiler/watchPublic.ts        |  14 +-
 src/server/editorServices.ts       |   1 +
 src/tsconfig-base.json             |   2 -
 9 files changed, 216 insertions(+), 15 deletions(-)

diff --git a/.eslintrc.json b/.eslintrc.json
index 30e6bb6ef2f65..26ea9ec19f431 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -16,7 +16,7 @@
         "plugin:@typescript-eslint/stylistic"
     ],
     "plugins": [
-        "@typescript-eslint", "no-null", "eslint-plugin-local", "simple-import-sort"
+        "@typescript-eslint", "no-null", "eslint-plugin-local", "simple-import-sort", "jsdoc"
     ],
     "ignorePatterns": [
         "**/node_modules/**",
@@ -70,6 +70,7 @@
             { "selector": "enumMember", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } },
             { "selector": "property", "format": null }
         ],
+        "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
 
         // Rules enabled in typescript-eslint configs that are not applicable here
         "@typescript-eslint/ban-ts-comment": "off",
@@ -80,6 +81,9 @@
         "@typescript-eslint/no-non-null-asserted-optional-chain": "off",
         "@typescript-eslint/no-var-requires": "off",
 
+        // Solely for marking things as used for the purposes of the no-unused-vars rule.
+        "jsdoc/no-undefined-types": ["error", { "disableReporting": true }],
+
         // Todo: For each of these, investigate whether we want to enable them ✨
         "@typescript-eslint/ban-types": "off",
         "no-case-declarations": "off",
@@ -95,7 +99,6 @@
         "@typescript-eslint/no-empty-function": "off",
         "@typescript-eslint/no-empty-interface": "off",
         "@typescript-eslint/no-explicit-any": "off",
-        "@typescript-eslint/no-unused-vars": "off",
 
         // Pending https://github.com/typescript-eslint/typescript-eslint/issues/4820
         "@typescript-eslint/prefer-optional-chain": "off",
diff --git a/package-lock.json b/package-lock.json
index db331ab62fc54..93929a591a3ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,6 +38,7 @@
                 "esbuild": "^0.18.1",
                 "eslint": "^8.22.0",
                 "eslint-formatter-autolinkable-stylish": "^1.2.0",
+                "eslint-plugin-jsdoc": "^46.4.4",
                 "eslint-plugin-local": "^1.0.0",
                 "eslint-plugin-no-null": "^1.0.2",
                 "eslint-plugin-simple-import-sort": "^10.0.0",
@@ -75,6 +76,20 @@
             "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
             "dev": true
         },
+        "node_modules/@es-joy/jsdoccomment": {
+            "version": "0.39.4",
+            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz",
+            "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==",
+            "dev": true,
+            "dependencies": {
+                "comment-parser": "1.3.1",
+                "esquery": "^1.5.0",
+                "jsdoc-type-pratt-parser": "~4.0.0"
+            },
+            "engines": {
+                "node": ">=16"
+            }
+        },
         "node_modules/@esbuild/android-arm": {
             "version": "0.18.16",
             "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.16.tgz",
@@ -1182,6 +1197,15 @@
                 "node": ">= 8"
             }
         },
+        "node_modules/are-docs-informative": {
+            "version": "0.0.2",
+            "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
+            "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
+            "dev": true,
+            "engines": {
+                "node": ">=14"
+            }
+        },
         "node_modules/argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1289,6 +1313,18 @@
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
             "dev": true
         },
+        "node_modules/builtin-modules": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+            "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+            "dev": true,
+            "engines": {
+                "node": ">=6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
         "node_modules/c8": {
             "version": "7.14.0",
             "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz",
@@ -1543,6 +1579,15 @@
                 "node": ">=4"
             }
         },
+        "node_modules/comment-parser": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
+            "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
+            "dev": true,
+            "engines": {
+                "node": ">= 12.0.0"
+            }
+        },
         "node_modules/concat-map": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1835,6 +1880,29 @@
                 "eslint": "^8.3.0"
             }
         },
+        "node_modules/eslint-plugin-jsdoc": {
+            "version": "46.4.4",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.4.tgz",
+            "integrity": "sha512-D8TGPOkq3bnzmYmA7Q6jdsW+Slx7CunhJk1tlouVq6wJjlP1p6eigZPvxFn7aufud/D66xBsNVMhkDQEuqumMg==",
+            "dev": true,
+            "dependencies": {
+                "@es-joy/jsdoccomment": "~0.39.4",
+                "are-docs-informative": "^0.0.2",
+                "comment-parser": "1.3.1",
+                "debug": "^4.3.4",
+                "escape-string-regexp": "^4.0.0",
+                "esquery": "^1.5.0",
+                "is-builtin-module": "^3.2.1",
+                "semver": "^7.5.1",
+                "spdx-expression-parse": "^3.0.1"
+            },
+            "engines": {
+                "node": ">=16"
+            },
+            "peerDependencies": {
+                "eslint": "^7.0.0 || ^8.0.0"
+            }
+        },
         "node_modules/eslint-plugin-local": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz",
@@ -2494,6 +2562,21 @@
                 "node": ">=8"
             }
         },
+        "node_modules/is-builtin-module": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+            "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+            "dev": true,
+            "dependencies": {
+                "builtin-modules": "^3.3.0"
+            },
+            "engines": {
+                "node": ">=6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
         "node_modules/is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2635,6 +2718,15 @@
                 "js-yaml": "bin/js-yaml.js"
             }
         },
+        "node_modules/jsdoc-type-pratt-parser": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
+            "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
         "node_modules/json-schema-traverse": {
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3490,6 +3582,28 @@
                 "source-map": "^0.6.0"
             }
         },
+        "node_modules/spdx-exceptions": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+            "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+            "dev": true
+        },
+        "node_modules/spdx-expression-parse": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+            "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+            "dev": true,
+            "dependencies": {
+                "spdx-exceptions": "^2.1.0",
+                "spdx-license-ids": "^3.0.0"
+            }
+        },
+        "node_modules/spdx-license-ids": {
+            "version": "3.0.13",
+            "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
+            "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
+            "dev": true
+        },
         "node_modules/string-width": {
             "version": "4.2.3",
             "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -3921,6 +4035,17 @@
             "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
             "dev": true
         },
+        "@es-joy/jsdoccomment": {
+            "version": "0.39.4",
+            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz",
+            "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==",
+            "dev": true,
+            "requires": {
+                "comment-parser": "1.3.1",
+                "esquery": "^1.5.0",
+                "jsdoc-type-pratt-parser": "~4.0.0"
+            }
+        },
         "@esbuild/android-arm": {
             "version": "0.18.16",
             "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.16.tgz",
@@ -4626,6 +4751,12 @@
                 "picomatch": "^2.0.4"
             }
         },
+        "are-docs-informative": {
+            "version": "0.0.2",
+            "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
+            "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
+            "dev": true
+        },
         "argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -4715,6 +4846,12 @@
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
             "dev": true
         },
+        "builtin-modules": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+            "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+            "dev": true
+        },
         "c8": {
             "version": "7.14.0",
             "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz",
@@ -4906,6 +5043,12 @@
                 }
             }
         },
+        "comment-parser": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
+            "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
+            "dev": true
+        },
         "concat-map": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -5139,6 +5282,23 @@
                 "plur": "^4.0.0"
             }
         },
+        "eslint-plugin-jsdoc": {
+            "version": "46.4.4",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.4.tgz",
+            "integrity": "sha512-D8TGPOkq3bnzmYmA7Q6jdsW+Slx7CunhJk1tlouVq6wJjlP1p6eigZPvxFn7aufud/D66xBsNVMhkDQEuqumMg==",
+            "dev": true,
+            "requires": {
+                "@es-joy/jsdoccomment": "~0.39.4",
+                "are-docs-informative": "^0.0.2",
+                "comment-parser": "1.3.1",
+                "debug": "^4.3.4",
+                "escape-string-regexp": "^4.0.0",
+                "esquery": "^1.5.0",
+                "is-builtin-module": "^3.2.1",
+                "semver": "^7.5.1",
+                "spdx-expression-parse": "^3.0.1"
+            }
+        },
         "eslint-plugin-local": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz",
@@ -5600,6 +5760,15 @@
                 "binary-extensions": "^2.0.0"
             }
         },
+        "is-builtin-module": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+            "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+            "dev": true,
+            "requires": {
+                "builtin-modules": "^3.3.0"
+            }
+        },
         "is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5699,6 +5868,12 @@
                 "argparse": "^2.0.1"
             }
         },
+        "jsdoc-type-pratt-parser": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
+            "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==",
+            "dev": true
+        },
         "json-schema-traverse": {
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -6290,6 +6465,28 @@
                 "source-map": "^0.6.0"
             }
         },
+        "spdx-exceptions": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+            "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+            "dev": true
+        },
+        "spdx-expression-parse": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+            "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+            "dev": true,
+            "requires": {
+                "spdx-exceptions": "^2.1.0",
+                "spdx-license-ids": "^3.0.0"
+            }
+        },
+        "spdx-license-ids": {
+            "version": "3.0.13",
+            "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
+            "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
+            "dev": true
+        },
         "string-width": {
             "version": "4.2.3",
             "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
diff --git a/package.json b/package.json
index deec92a87bcd7..cdd4e7a84a8cd 100644
--- a/package.json
+++ b/package.json
@@ -64,6 +64,7 @@
         "esbuild": "^0.18.1",
         "eslint": "^8.22.0",
         "eslint-formatter-autolinkable-stylish": "^1.2.0",
+        "eslint-plugin-jsdoc": "^46.4.4",
         "eslint-plugin-local": "^1.0.0",
         "eslint-plugin-no-null": "^1.0.2",
         "eslint-plugin-simple-import-sort": "^10.0.0",
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index 495cc2e3a700c..580215d1ad394 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -288,7 +288,7 @@ export function filter<T>(array: T[], f: (x: T) => boolean): T[];
 /** @internal */
 export function filter<T, U extends T>(array: readonly T[], f: (x: T) => x is U): readonly U[];
 /** @internal */
-export function filter<T, U extends T>(array: readonly T[], f: (x: T) => boolean): readonly T[];
+export function filter<T>(array: readonly T[], f: (x: T) => boolean): readonly T[];
 /** @internal */
 export function filter<T, U extends T>(array: T[] | undefined, f: (x: T) => x is U): U[] | undefined;
 /** @internal */
@@ -296,7 +296,7 @@ export function filter<T>(array: T[] | undefined, f: (x: T) => boolean): T[] | u
 /** @internal */
 export function filter<T, U extends T>(array: readonly T[] | undefined, f: (x: T) => x is U): readonly U[] | undefined;
 /** @internal */
-export function filter<T, U extends T>(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined;
+export function filter<T>(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined;
 /** @internal */
 export function filter<T>(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined {
     if (array) {
@@ -835,7 +835,7 @@ export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Compa
 }
 
 /** @internal */
-export function sortAndDeduplicate<T>(array: readonly string[]): SortedReadonlyArray<string>;
+export function sortAndDeduplicate(array: readonly string[]): SortedReadonlyArray<string>;
 /** @internal */
 export function sortAndDeduplicate<T>(array: readonly T[], comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>): SortedReadonlyArray<T>;
 /** @internal */
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index a58223868f8b0..94d5c1747cdec 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -4083,6 +4083,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
         writeSpace();
         nextPos = emitTokenWithComment(SyntaxKind.AsKeyword, nextPos, writeKeyword, node);
         writeSpace();
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
         nextPos = emitTokenWithComment(SyntaxKind.NamespaceKeyword, nextPos, writeKeyword, node);
         writeSpace();
         emit(node.name);
diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts
index 4538377dafd3d..7598ed836f64e 100644
--- a/src/compiler/moduleNameResolver.ts
+++ b/src/compiler/moduleNameResolver.ts
@@ -331,7 +331,7 @@ interface PackageJson extends PackageJsonPathFields {
     version?: string;
 }
 
-function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
+function readPackageJsonField<K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
 function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
 function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {
     if (!hasProperty(jsonContent, fieldName)) {
diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts
index f5eb07f44dd62..c6ff74e2aafc6 100644
--- a/src/compiler/watchPublic.ts
+++ b/src/compiler/watchPublic.ts
@@ -249,18 +249,18 @@ export interface ProgramHost<T extends BuilderProgram> {
      * Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it
      */
     getModuleResolutionCache?(): ModuleResolutionCache | undefined;
-}
-/**
- * Internal interface used to wire emit through same host
- *
- * @internal
- */
-export interface ProgramHost<T extends BuilderProgram> {
+
+    // Internal interface used to wire emit through same host
+
     // TODO: GH#18217 Optional methods are frequently asserted
+    /** @internal */
     createDirectory?(path: string): void;
+    /** @internal */
     writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
     // For testing
+    /** @internal */
     storeFilesChangingSignatureDuringEmit?: boolean;
+    /** @internal */
     now?(): Date;
 }
 
diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts
index 3c53534bb7594..3e78b22ecede0 100644
--- a/src/server/editorServices.ts
+++ b/src/server/editorServices.ts
@@ -477,6 +477,7 @@ export function convertScriptKindName(scriptKindName: protocol.ScriptKindName) {
 
 /** @internal */
 export function convertUserPreferences(preferences: protocol.UserPreferences): UserPreferences {
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
     const { lazyConfiguredProjectsFromExternalProject, ...userPreferences } = preferences;
     return userPreferences;
 }
diff --git a/src/tsconfig-base.json b/src/tsconfig-base.json
index 3b772f7d33f0f..34c76b9542b13 100644
--- a/src/tsconfig-base.json
+++ b/src/tsconfig-base.json
@@ -21,8 +21,6 @@
         "useUnknownInCatchVariables": false,
         "noImplicitOverride": true,
 
-        "noUnusedLocals": true,
-        "noUnusedParameters": true,
         "allowUnusedLabels": false,
 
         "skipLibCheck": true,

From 00f223742857a239d39c25880ec6585b039c7091 Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Mon, 14 Aug 2023 11:39:53 -0700
Subject: [PATCH 2/3] Attempt to DIY the jsdoc stuff using a local plugin

---
 .eslintrc.json                                |   6 +-
 package-lock.json                             | 197 ------------------
 package.json                                  |   1 -
 .../eslint/rules/mark-jsdoc-types-used.cjs    | 102 +++++++++
 src/compiler/parser.ts                        |   1 +
 5 files changed, 106 insertions(+), 201 deletions(-)
 create mode 100644 scripts/eslint/rules/mark-jsdoc-types-used.cjs

diff --git a/.eslintrc.json b/.eslintrc.json
index dfe38fee99ad8..a9514a1fa389e 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -16,7 +16,7 @@
         "plugin:@typescript-eslint/stylistic"
     ],
     "plugins": [
-        "@typescript-eslint", "no-null", "eslint-plugin-local", "simple-import-sort", "jsdoc"
+        "@typescript-eslint", "no-null", "eslint-plugin-local", "simple-import-sort"
     ],
     "ignorePatterns": [
         "**/node_modules/**",
@@ -90,8 +90,6 @@
         "@typescript-eslint/no-non-null-asserted-optional-chain": "off",
         "@typescript-eslint/no-var-requires": "off",
 
-        // Solely for marking things as used for the purposes of the no-unused-vars rule.
-        "jsdoc/no-undefined-types": ["error", { "disableReporting": true }],
         "@typescript-eslint/no-empty-interface": "off",
         "@typescript-eslint/no-explicit-any": "off",
         "@typescript-eslint/ban-types": [
@@ -123,6 +121,8 @@
         "local/debug-assert": "error",
         "local/no-keywords": "error",
         "local/jsdoc-format": "error",
+        // Solely for marking things as used for the purposes of the no-unused-vars rule.
+        "local/mark-jsdoc-types-used": "error",
 
         // eslint-plugin-no-null
         "no-null/no-null": "error",
diff --git a/package-lock.json b/package-lock.json
index 985c4abe33f57..de3c6fd1e757b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,6 @@
                 "esbuild": "^0.19.0",
                 "eslint": "^8.22.0",
                 "eslint-formatter-autolinkable-stylish": "^1.2.0",
-                "eslint-plugin-jsdoc": "^46.4.4",
                 "eslint-plugin-local": "^1.0.0",
                 "eslint-plugin-no-null": "^1.0.2",
                 "eslint-plugin-simple-import-sort": "^10.0.0",
@@ -76,20 +75,6 @@
             "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
             "dev": true
         },
-        "node_modules/@es-joy/jsdoccomment": {
-            "version": "0.39.4",
-            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz",
-            "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==",
-            "dev": true,
-            "dependencies": {
-                "comment-parser": "1.3.1",
-                "esquery": "^1.5.0",
-                "jsdoc-type-pratt-parser": "~4.0.0"
-            },
-            "engines": {
-                "node": ">=16"
-            }
-        },
         "node_modules/@esbuild/android-arm": {
             "version": "0.19.0",
             "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.0.tgz",
@@ -1197,15 +1182,6 @@
                 "node": ">= 8"
             }
         },
-        "node_modules/are-docs-informative": {
-            "version": "0.0.2",
-            "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
-            "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
-            "dev": true,
-            "engines": {
-                "node": ">=14"
-            }
-        },
         "node_modules/argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1313,18 +1289,6 @@
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
             "dev": true
         },
-        "node_modules/builtin-modules": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
-            "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/c8": {
             "version": "7.14.0",
             "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz",
@@ -1579,15 +1543,6 @@
                 "node": ">=4"
             }
         },
-        "node_modules/comment-parser": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
-            "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
-            "dev": true,
-            "engines": {
-                "node": ">= 12.0.0"
-            }
-        },
         "node_modules/concat-map": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1880,29 +1835,6 @@
                 "eslint": "^8.3.0"
             }
         },
-        "node_modules/eslint-plugin-jsdoc": {
-            "version": "46.4.4",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.4.tgz",
-            "integrity": "sha512-D8TGPOkq3bnzmYmA7Q6jdsW+Slx7CunhJk1tlouVq6wJjlP1p6eigZPvxFn7aufud/D66xBsNVMhkDQEuqumMg==",
-            "dev": true,
-            "dependencies": {
-                "@es-joy/jsdoccomment": "~0.39.4",
-                "are-docs-informative": "^0.0.2",
-                "comment-parser": "1.3.1",
-                "debug": "^4.3.4",
-                "escape-string-regexp": "^4.0.0",
-                "esquery": "^1.5.0",
-                "is-builtin-module": "^3.2.1",
-                "semver": "^7.5.1",
-                "spdx-expression-parse": "^3.0.1"
-            },
-            "engines": {
-                "node": ">=16"
-            },
-            "peerDependencies": {
-                "eslint": "^7.0.0 || ^8.0.0"
-            }
-        },
         "node_modules/eslint-plugin-local": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz",
@@ -2562,21 +2494,6 @@
                 "node": ">=8"
             }
         },
-        "node_modules/is-builtin-module": {
-            "version": "3.2.1",
-            "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
-            "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
-            "dev": true,
-            "dependencies": {
-                "builtin-modules": "^3.3.0"
-            },
-            "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2718,15 +2635,6 @@
                 "js-yaml": "bin/js-yaml.js"
             }
         },
-        "node_modules/jsdoc-type-pratt-parser": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
-            "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=12.0.0"
-            }
-        },
         "node_modules/json-schema-traverse": {
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3573,28 +3481,6 @@
                 "source-map": "^0.6.0"
             }
         },
-        "node_modules/spdx-exceptions": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
-            "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
-            "dev": true
-        },
-        "node_modules/spdx-expression-parse": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
-            "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
-            "dev": true,
-            "dependencies": {
-                "spdx-exceptions": "^2.1.0",
-                "spdx-license-ids": "^3.0.0"
-            }
-        },
-        "node_modules/spdx-license-ids": {
-            "version": "3.0.13",
-            "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
-            "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
-            "dev": true
-        },
         "node_modules/string-width": {
             "version": "4.2.3",
             "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -4026,17 +3912,6 @@
             "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
             "dev": true
         },
-        "@es-joy/jsdoccomment": {
-            "version": "0.39.4",
-            "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz",
-            "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==",
-            "dev": true,
-            "requires": {
-                "comment-parser": "1.3.1",
-                "esquery": "^1.5.0",
-                "jsdoc-type-pratt-parser": "~4.0.0"
-            }
-        },
         "@esbuild/android-arm": {
             "version": "0.19.0",
             "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.0.tgz",
@@ -4742,12 +4617,6 @@
                 "picomatch": "^2.0.4"
             }
         },
-        "are-docs-informative": {
-            "version": "0.0.2",
-            "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
-            "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
-            "dev": true
-        },
         "argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -4837,12 +4706,6 @@
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
             "dev": true
         },
-        "builtin-modules": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
-            "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
-            "dev": true
-        },
         "c8": {
             "version": "7.14.0",
             "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz",
@@ -5034,12 +4897,6 @@
                 }
             }
         },
-        "comment-parser": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz",
-            "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==",
-            "dev": true
-        },
         "concat-map": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -5273,23 +5130,6 @@
                 "plur": "^4.0.0"
             }
         },
-        "eslint-plugin-jsdoc": {
-            "version": "46.4.4",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.4.tgz",
-            "integrity": "sha512-D8TGPOkq3bnzmYmA7Q6jdsW+Slx7CunhJk1tlouVq6wJjlP1p6eigZPvxFn7aufud/D66xBsNVMhkDQEuqumMg==",
-            "dev": true,
-            "requires": {
-                "@es-joy/jsdoccomment": "~0.39.4",
-                "are-docs-informative": "^0.0.2",
-                "comment-parser": "1.3.1",
-                "debug": "^4.3.4",
-                "escape-string-regexp": "^4.0.0",
-                "esquery": "^1.5.0",
-                "is-builtin-module": "^3.2.1",
-                "semver": "^7.5.1",
-                "spdx-expression-parse": "^3.0.1"
-            }
-        },
         "eslint-plugin-local": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz",
@@ -5751,15 +5591,6 @@
                 "binary-extensions": "^2.0.0"
             }
         },
-        "is-builtin-module": {
-            "version": "3.2.1",
-            "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
-            "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
-            "dev": true,
-            "requires": {
-                "builtin-modules": "^3.3.0"
-            }
-        },
         "is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5859,12 +5690,6 @@
                 "argparse": "^2.0.1"
             }
         },
-        "jsdoc-type-pratt-parser": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
-            "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==",
-            "dev": true
-        },
         "json-schema-traverse": {
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -6448,28 +6273,6 @@
                 "source-map": "^0.6.0"
             }
         },
-        "spdx-exceptions": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
-            "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
-            "dev": true
-        },
-        "spdx-expression-parse": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
-            "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
-            "dev": true,
-            "requires": {
-                "spdx-exceptions": "^2.1.0",
-                "spdx-license-ids": "^3.0.0"
-            }
-        },
-        "spdx-license-ids": {
-            "version": "3.0.13",
-            "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
-            "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==",
-            "dev": true
-        },
         "string-width": {
             "version": "4.2.3",
             "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
diff --git a/package.json b/package.json
index a0b8eb36c63f3..cc39f6cba399e 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,6 @@
         "esbuild": "^0.19.0",
         "eslint": "^8.22.0",
         "eslint-formatter-autolinkable-stylish": "^1.2.0",
-        "eslint-plugin-jsdoc": "^46.4.4",
         "eslint-plugin-local": "^1.0.0",
         "eslint-plugin-no-null": "^1.0.2",
         "eslint-plugin-simple-import-sort": "^10.0.0",
diff --git a/scripts/eslint/rules/mark-jsdoc-types-used.cjs b/scripts/eslint/rules/mark-jsdoc-types-used.cjs
new file mode 100644
index 0000000000000..90cb457aa71bc
--- /dev/null
+++ b/scripts/eslint/rules/mark-jsdoc-types-used.cjs
@@ -0,0 +1,102 @@
+const { TSESTree, ESLintUtils } = require("@typescript-eslint/utils");
+const { createRule } = require("./utils.cjs");
+const ts = require("typescript");
+
+/**
+ * @param {ts.Identifier} node
+ */
+function isBareIdentifier(node) {
+    if (ts.isPropertyAccessExpression(node.parent)) {
+        return node.parent.expression === node;
+    }
+
+    if (ts.isQualifiedName(node.parent)) {
+        return node.parent.left === node;
+    }
+
+    // TODO(jakebailey): surely I'm missing something here.
+    // Also, how does eslint deal with type space versus value space? Or does it not?
+
+    return true;
+}
+
+module.exports = createRule({
+    name: "mark-jsdoc-types-used",
+    meta: {
+        docs: {
+            description: ``,
+        },
+        messages: {},
+        schema: [],
+        type: "problem",
+        fixable: "whitespace",
+    },
+    defaultOptions: [],
+
+    create(context) {
+        /** @type {(node: TSESTree.Node) => void} */
+        const checkProgram = (node) => {
+            const parserServices = ESLintUtils.getParserServices(context, /*allowWithoutFullTypeInformation*/ true);
+            const ast = parserServices.esTreeNodeToTSNodeMap.get(node);
+
+            // TODO(jakebailey): I almost guarantee this is overzealous and wrong in some way.
+
+            /**
+             * @param {ts.Node} node
+             */
+            function markIdentifiersUsed(node) {
+                if (ts.isIdentifier(node) && isBareIdentifier(node)) {
+                    context.markVariableAsUsed(node.text);
+                    return;
+                }
+                ts.forEachChild(node, markIdentifiersUsed);
+            }
+
+            /**
+             * @param {ts.Node} node
+             */
+            function visit(node) {
+                const jsDoc = ts.getJSDocTags(node);
+                for (const tag of jsDoc) {
+                    if (ts.isJSDocTypeTag(tag)) {
+                        markIdentifiersUsed(tag.typeExpression);
+                    }
+                    else if (ts.isJSDocTypedefTag(tag) || ts.isJSDocPropertyLikeTag(tag) || ts.isJSDocReturnTag(tag) || ts.isJSDocThrowsTag(tag)) {
+                        if (tag.typeExpression) {
+                            markIdentifiersUsed(tag.typeExpression);
+                        }
+                    }
+                    else if (ts.isJSDocTemplateTag(tag)) {
+                        if (tag.constraint) {
+                            markIdentifiersUsed(tag.constraint);
+                        }
+                        // tag.typeParameters?
+                    }
+                    else if (ts.isJSDocEnumTag(tag)) {
+                        markIdentifiersUsed(tag.typeExpression);
+                    }
+                    else if (ts.isJSDocUnknownTag(tag)) {
+                        // Ignore.
+                        // TODO(jakebailey): Something's wrong here, though, becuase we're getting @parameter tags as unknown. See new code in parser.
+                    }
+                    else if (ts.isJSDocOverrideTag(tag) || ts.isJSDocDeprecatedTag(tag)) {
+                        // Ignore.
+                    }
+                    else if (ts.isJSDocSeeTag(tag)) {
+                        markIdentifiersUsed(tag.tagName);
+                    }
+                    else {
+                        throw new Error(`Unexpected node kind: ${ts.SyntaxKind[tag.kind]} ${tag.getText()}}`);
+                    }
+                }
+                ts.forEachChild(node, visit);
+            }
+
+            visit(ast);
+        };
+
+        return {
+            Program: checkProgram,
+        };
+    },
+});
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index bd8081d1267a1..b19c18e4705ed 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -8973,6 +8973,7 @@ namespace Parser {
                     case "arg":
                     case "argument":
                     case "param":
+                    case "parameter": // TODO(jakebailey): why is this missing?
                         return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin);
                     case "return":
                     case "returns":

From bf6a46bfe7b300c528a822b2440751a367698ce6 Mon Sep 17 00:00:00 2001
From: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
Date: Mon, 22 Jan 2024 12:06:21 -0800
Subject: [PATCH 3/3] fmt

---
 scripts/eslint/rules/mark-jsdoc-types-used.cjs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/eslint/rules/mark-jsdoc-types-used.cjs b/scripts/eslint/rules/mark-jsdoc-types-used.cjs
index 90cb457aa71bc..570c0ff115b5b 100644
--- a/scripts/eslint/rules/mark-jsdoc-types-used.cjs
+++ b/scripts/eslint/rules/mark-jsdoc-types-used.cjs
@@ -35,7 +35,7 @@ module.exports = createRule({
 
     create(context) {
         /** @type {(node: TSESTree.Node) => void} */
-        const checkProgram = (node) => {
+        const checkProgram = node => {
             const parserServices = ESLintUtils.getParserServices(context, /*allowWithoutFullTypeInformation*/ true);
             const ast = parserServices.esTreeNodeToTSNodeMap.get(node);