Skip to content

Commit 779e13e

Browse files
authored
fix: default to parse all JSDoc and provide options to configure it (typescript-eslint#7999)
1 parent 39c437a commit 779e13e

File tree

13 files changed

+112
-11
lines changed

13 files changed

+112
-11
lines changed

docs/packages/Parser.mdx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ interface ParserOptions {
4040
ecmaVersion?: number | 'latest';
4141
emitDecoratorMetadata?: boolean;
4242
extraFileExtensions?: string[];
43+
jsDocParsingMode?: 'all' | 'none' | 'type-info';
4344
jsxFragmentName?: string | null;
4445
jsxPragma?: string | null;
4546
lib?: string[];
46-
program?: import('typescript').Program;
47+
programs?: import('typescript').Program;
4748
project?: string | string[] | true;
4849
projectFolderIgnoreList?: string[];
4950
tsconfigRootDir?: string;
@@ -118,6 +119,21 @@ This option allows you to provide one or more additional file extensions which s
118119
The default extensions are `['.js', '.mjs', '.cjs', '.jsx', '.ts', '.mts', '.cts', '.tsx']`.
119120
Add extensions starting with `.`, followed by the file extension. E.g. for a `.vue` file use `"extraFileExtensions": [".vue"]`.
120121

122+
### `jsDocParsingMode`
123+
124+
> Default if `parserOptions.project` is set, then `'all'`, otherwise `'none'`
125+
126+
When TS parses a file it will also parse JSDoc comments into the AST - which can then be consumed by lint rules.
127+
If you are using TypeScript version >=5.3 then this option can be used as a performance optimization.
128+
129+
The valid values for this rule are:
130+
131+
- `'all'` - parse all JSDoc comments, always.
132+
- `'none'` - parse no JSDoc comments, ever.
133+
- `'type-info'` - parse just JSDoc comments that are required to provide correct type-info. TS will always parse JSDoc in non-TS files, but never in TS files.
134+
135+
If you do not use lint rules like `eslint-plugin-deprecation` that rely on TS's JSDoc tag representation, then you can set this to `'none'` to improve parser performance.
136+
121137
### `jsxFragmentName`
122138

123139
> Default `null`
@@ -149,7 +165,7 @@ Specifies the TypeScript `lib`s that are available. This is used by the scope an
149165

150166
If you provide `parserOptions.project`, you do not need to set this, as it will automatically detected from the compiler.
151167

152-
### `program`
168+
### `programs`
153169

154170
> Default `undefined`.
155171

docs/packages/TypeScript_ESTree.mdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ interface ParseOptions {
7070
*/
7171
filePath?: string;
7272

73+
/**
74+
* If you are using TypeScript version >=5.3 then this option can be used as a performance optimization.
75+
*
76+
* The valid values for this rule are:
77+
* - `'all'` - parse all JSDoc comments, always.
78+
* - `'none'` - parse no JSDoc comments, ever.
79+
* - `'type-info'` - parse just JSDoc comments that are required to provide correct type-info. TS will always parse JSDoc in non-TS files, but never in TS files.
80+
*
81+
* If you do not rely on JSDoc tags from the TypeScript AST, then you can safely set this to `'none'` to improve performance.
82+
*/
83+
jsDocParsingMode?: JSDocParsingMode;
84+
7385
/**
7486
* Enable parsing of JSX.
7587
* For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
@@ -111,6 +123,7 @@ interface ParseOptions {
111123
const PARSE_DEFAULT_OPTIONS: ParseOptions = {
112124
comment: false,
113125
filePath: 'estree.ts', // or 'estree.tsx', if you pass jsx: true
126+
jsDocParsingMode: 'all',
114127
jsx: false,
115128
loc: false,
116129
loggerFn: undefined,

packages/types/src/parser-options.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ type EcmaVersion =
3232
type SourceTypeClassic = 'module' | 'script';
3333
type SourceType = SourceTypeClassic | 'commonjs';
3434

35+
type JSDocParsingMode = 'all' | 'none' | 'type-info';
36+
37+
// If you add publicly visible options here, make sure they're also documented in `docs/packages/Parser.mdx`
3538
interface ParserOptions {
3639
ecmaFeatures?: {
3740
globalReturn?: boolean;
@@ -57,8 +60,9 @@ interface ParserOptions {
5760
EXPERIMENTAL_useSourceOfProjectReferenceRedirect?: boolean; // purposely undocumented for now
5861
extraFileExtensions?: string[];
5962
filePath?: string;
63+
jsDocParsingMode?: JSDocParsingMode;
6064
loc?: boolean;
61-
program?: Program | null;
65+
programs?: Program | null;
6266
project?: string[] | string | true | null;
6367
projectFolderIgnoreList?: (RegExp | string)[];
6468
range?: boolean;
@@ -77,6 +81,7 @@ export {
7781
CacheDurationSeconds,
7882
DebugLevel,
7983
EcmaVersion,
84+
JSDocParsingMode,
8085
ParserOptions,
8186
SourceType,
8287
};

packages/typescript-estree/src/create-program/createDefaultProgram.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function createDefaultProgram(
5959
[parseSettings.filePath],
6060
{
6161
...commandLine.options,
62-
jsDocParsingMode: ts.JSDocParsingMode?.ParseForTypeInfo,
62+
jsDocParsingMode: parseSettings.jsDocParsingMode,
6363
},
6464
compilerHost,
6565
);

packages/typescript-estree/src/create-program/createIsolatedProgram.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function createIsolatedProgram(
6565
const program = ts.createProgram(
6666
[parseSettings.filePath],
6767
{
68-
jsDocParsingMode: ts.JSDocParsingMode?.ParseForTypeInfo,
68+
jsDocParsingMode: parseSettings.jsDocParsingMode,
6969
noResolve: true,
7070
target: ts.ScriptTarget.Latest,
7171
jsx: parseSettings.jsx ? ts.JsxEmit.Preserve : undefined,

packages/typescript-estree/src/create-program/createProjectService.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ const createStubFileWatcher = (): ts.FileWatcher => ({
99

1010
export type TypeScriptProjectService = ts.server.ProjectService;
1111

12-
export function createProjectService(): TypeScriptProjectService {
12+
export function createProjectService(
13+
jsDocParsingMode?: ts.JSDocParsingMode,
14+
): TypeScriptProjectService {
1315
// We import this lazily to avoid its cost for users who don't use the service
1416
// TODO: Once we drop support for TS<5.3 we can import from "typescript" directly
1517
const tsserver = require('typescript/lib/tsserverlibrary') as typeof ts;
@@ -45,6 +47,6 @@ export function createProjectService(): TypeScriptProjectService {
4547
startGroup: doNothing,
4648
},
4749
session: undefined,
48-
jsDocParsingMode: tsserver.JSDocParsingMode?.ParseForTypeInfo,
50+
jsDocParsingMode,
4951
});
5052
}

packages/typescript-estree/src/create-program/createSourceFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function createSourceFile(parseSettings: ParseSettings): ts.SourceFile {
2222
parseSettings.codeFullText,
2323
{
2424
languageVersion: ts.ScriptTarget.Latest,
25-
jsDocParsingMode: ts.JSDocParsingMode?.ParseNone,
25+
jsDocParsingMode: parseSettings.jsDocParsingMode,
2626
},
2727
/* setParentNodes */ true,
2828
getScriptKind(parseSettings.filePath, parseSettings.jsx),

packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ function createWatchProgram(
267267
// eslint-disable-next-line @typescript-eslint/no-empty-function
268268
/*reportWatchStatus*/ () => {},
269269
) as WatchCompilerHostOfConfigFile<ts.BuilderProgram>;
270-
watchCompilerHost.jsDocParsingMode = ts.JSDocParsingMode?.ParseForTypeInfo;
270+
watchCompilerHost.jsDocParsingMode = parseSettings.jsDocParsingMode;
271271

272272
// ensure readFile reads the code being linted instead of the copy on disk
273273
const oldReadFile = watchCompilerHost.readFile;

packages/typescript-estree/src/parseSettings/createParseSettings.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import debug from 'debug';
2-
import type * as ts from 'typescript';
2+
import * as ts from 'typescript';
33

44
import type { TypeScriptProjectService } from '../create-program/createProjectService';
55
import { createProjectService } from '../create-program/createProjectService';
@@ -23,6 +23,15 @@ const log = debug(
2323
let TSCONFIG_MATCH_CACHE: ExpiringCache<string, string> | null;
2424
let TSSERVER_PROJECT_SERVICE: TypeScriptProjectService | null = null;
2525

26+
// NOTE - we intentionally use "unnecessary" `?.` here because in TS<5.3 this enum doesn't exist
27+
// This object exists so we can centralize these for tracking and so we don't proliferate these across the file
28+
const JSDocParsingMode = {
29+
ParseAll: ts.JSDocParsingMode?.ParseAll,
30+
ParseNone: ts.JSDocParsingMode?.ParseNone,
31+
ParseForTypeErrors: ts.JSDocParsingMode?.ParseForTypeErrors,
32+
ParseForTypeInfo: ts.JSDocParsingMode?.ParseForTypeInfo,
33+
} as const;
34+
2635
export function createParseSettings(
2736
code: ts.SourceFile | string,
2837
options: Partial<TSESTreeOptions> = {},
@@ -34,6 +43,22 @@ export function createParseSettings(
3443
? options.tsconfigRootDir
3544
: process.cwd();
3645
const passedLoggerFn = typeof options.loggerFn === 'function';
46+
const jsDocParsingMode = ((): ts.JSDocParsingMode => {
47+
switch (options.jsDocParsingMode) {
48+
case 'all':
49+
return JSDocParsingMode.ParseAll;
50+
51+
case 'none':
52+
return JSDocParsingMode.ParseNone;
53+
54+
case 'type-info':
55+
return JSDocParsingMode.ParseForTypeInfo;
56+
57+
default:
58+
return JSDocParsingMode.ParseAll;
59+
}
60+
})();
61+
3762
const parseSettings: MutableParseSettings = {
3863
allowInvalidAST: options.allowInvalidAST === true,
3964
code,
@@ -56,7 +81,7 @@ export function createParseSettings(
5681
process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER !== 'false') ||
5782
(process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER === 'true' &&
5883
options.EXPERIMENTAL_useProjectService !== false)
59-
? (TSSERVER_PROJECT_SERVICE ??= createProjectService())
84+
? (TSSERVER_PROJECT_SERVICE ??= createProjectService(jsDocParsingMode))
6085
: undefined,
6186
EXPERIMENTAL_useSourceOfProjectReferenceRedirect:
6287
options.EXPERIMENTAL_useSourceOfProjectReferenceRedirect === true,
@@ -71,6 +96,7 @@ export function createParseSettings(
7196
: getFileName(options.jsx),
7297
tsconfigRootDir,
7398
),
99+
jsDocParsingMode,
74100
jsx: options.jsx === true,
75101
loc: options.loc === true,
76102
log:
@@ -136,6 +162,17 @@ export function createParseSettings(
136162
});
137163
}
138164

165+
// No type-aware linting which means that cross-file (or even same-file) JSDoc is useless
166+
// So in this specific case we default to 'none' if no value was provided
167+
if (
168+
options.jsDocParsingMode == null &&
169+
parseSettings.projects.length === 0 &&
170+
parseSettings.programs == null &&
171+
parseSettings.EXPERIMENTAL_projectService == null
172+
) {
173+
parseSettings.jsDocParsingMode = JSDocParsingMode.ParseNone;
174+
}
175+
139176
warnAboutTSVersion(parseSettings, passedLoggerFn);
140177

141178
return parseSettings;

packages/typescript-estree/src/parseSettings/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import type { CacheLike } from './ExpiringCache';
77

88
type DebugModule = 'eslint' | 'typescript-eslint' | 'typescript';
99

10+
// Workaround to support new TS version features for consumers on old TS versions
11+
declare module 'typescript' {
12+
// Added in TypeScript 5.3
13+
enum JSDocParsingMode {}
14+
}
15+
1016
/**
1117
* Internal settings used by the parser to run on a file.
1218
*/
@@ -84,6 +90,11 @@ export interface MutableParseSettings {
8490
*/
8591
filePath: string;
8692

93+
/**
94+
* JSDoc parsing style to pass through to TypeScript
95+
*/
96+
jsDocParsingMode: ts.JSDocParsingMode;
97+
8798
/**
8899
* Whether parsing of JSX is enabled.
89100
*

packages/typescript-estree/src/parser-options.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
CacheDurationSeconds,
33
DebugLevel,
4+
JSDocParsingMode,
45
} from '@typescript-eslint/types';
56
import type * as ts from 'typescript';
67

@@ -45,6 +46,18 @@ interface ParseOptions {
4546
*/
4647
filePath?: string;
4748

49+
/**
50+
* If you are using TypeScript version >=5.3 then this option can be used as a performance optimization.
51+
*
52+
* The valid values for this rule are:
53+
* - `'all'` - parse all JSDoc comments, always.
54+
* - `'none'` - parse no JSDoc comments, ever.
55+
* - `'type-info'` - parse just JSDoc comments that are required to provide correct type-info. TS will always parse JSDoc in non-TS files, but never in TS files.
56+
*
57+
* If you do not rely on JSDoc tags from the TypeScript AST, then you can safely set this to `'none'` to improve performance.
58+
*/
59+
jsDocParsingMode?: JSDocParsingMode;
60+
4861
/**
4962
* Enable parsing of JSX.
5063
* For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html

packages/website-eslint/build.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ async function buildPackage(name: string, file: string): Promise<void> {
8080
assert: requireResolved('./src/mock/assert.js'),
8181
path: requireResolved('./src/mock/path.js'),
8282
typescript: requireResolved('./src/mock/typescript.js'),
83+
'typescript/lib/tsserverlibrary': requireResolved(
84+
'./src/mock/typescript.js',
85+
),
8386
'lru-cache': requireResolved('./src/mock/lru-cache.js'),
8487
},
8588
plugins: [

packages/website/src/components/linter/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const defaultParseSettings: ParseSettings = {
1717
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: false,
1818
extraFileExtensions: [],
1919
filePath: '',
20+
jsDocParsingMode: window.ts?.JSDocParsingMode?.ParseAll,
2021
jsx: true,
2122
loc: true,
2223
log: console.log,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy