From c9a6dd9f3df4e3c2bfcc5dceb770b021709152ae Mon Sep 17 00:00:00 2001 From: Fotis Papadogeorgopoulos Date: Thu, 6 Jun 2024 03:29:58 +0300 Subject: [PATCH] feat(parser, typescript-estree): export withoutProjectParserOptions utility (#9233) * feat(typescript-estree): add function to remove parser options that prompt typechecking * feat(parser): re-export removeParserOptionsThatPromptTypechecking * chore: fix lint rule about importing types * refactor: prefer rest/spread over delete * refactor: rename to withoutProjectParserOptions * refactor: rename withoutProjectParserOptions file as well * test: add unit test for withoutProjectParserOptions * docs: add withoutProjectParserOptions * refactor: use single unit test for withoutProjectParserOptions * chore: fix no-unused-vars lint error * chore: avoid wrapping lines in Parser.mdx * fix: update test with toEqual assertion --- docs/packages/Parser.mdx | 28 +++++++++++++++++++ packages/parser/src/index.ts | 1 + packages/typescript-estree/src/index.ts | 1 + .../src/withoutProjectParserOptions.ts | 18 ++++++++++++ .../lib/withoutProjectParserOptions.test.ts | 14 ++++++++++ 5 files changed, 62 insertions(+) create mode 100644 packages/typescript-estree/src/withoutProjectParserOptions.ts create mode 100644 packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx index 110a0f116872..d9f46936de12 100644 --- a/docs/packages/Parser.mdx +++ b/docs/packages/Parser.mdx @@ -402,3 +402,31 @@ module.exports = { + +### `withoutProjectParserOptions(parserOptions)` + +Removes options that prompt the parser to parse the project with type information. +In other words, you can use this if you are invoking the parser directly, to ensure that one file will be parsed in isolation, which is much faster. + +This is useful in cases where you invoke the parser directly, such as in an ESLint plugin context. + +```ts +declare function withoutProjectParserOptions( + options: TSESTreeOptions, +): TSESTreeOptions; +``` + +Example usage: + +```js title="somePlugin.js" +const parser = require('@typescript-eslint/parser'); + +function parse(path, content, context) { + const contextParserOptions = context.languageOptions?.parserOptions ?? {}; + const parserOptions = + parser.withoutProjectParserOptions(contextParserOptions); + + // Do something with the cleaned-up options eventually, such as invoking the parser + parser.parseForESLint(content, parserOptions); +} +``` diff --git a/packages/parser/src/index.ts b/packages/parser/src/index.ts index 9ccf6b17ed8f..9799bc982d07 100644 --- a/packages/parser/src/index.ts +++ b/packages/parser/src/index.ts @@ -5,6 +5,7 @@ export { ParserServicesWithoutTypeInformation, clearCaches, createProgram, + withoutProjectParserOptions, } from '@typescript-eslint/typescript-estree'; // note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder diff --git a/packages/typescript-estree/src/index.ts b/packages/typescript-estree/src/index.ts index c86262b7cd9d..5f6e8768d0c4 100644 --- a/packages/typescript-estree/src/index.ts +++ b/packages/typescript-estree/src/index.ts @@ -19,6 +19,7 @@ export { typescriptVersionIsAtLeast } from './version-check'; export * from './getModifiers'; export { TSError } from './node-utils'; export * from './clear-caches'; +export { withoutProjectParserOptions } from './withoutProjectParserOptions'; // note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access diff --git a/packages/typescript-estree/src/withoutProjectParserOptions.ts b/packages/typescript-estree/src/withoutProjectParserOptions.ts new file mode 100644 index 000000000000..f911bee1dcf4 --- /dev/null +++ b/packages/typescript-estree/src/withoutProjectParserOptions.ts @@ -0,0 +1,18 @@ +import type { TSESTreeOptions } from './parser-options'; + +/** + * Removes options that prompt the parser to parse the project with type + * information. In other words, you can use this if you are invoking the parser + * directly, to ensure that one file will be parsed in isolation, which is much, + * much faster. + * + * @see https://github.com/typescript-eslint/typescript-eslint/issues/8428 + */ +export function withoutProjectParserOptions( + opts: TSESTreeOptions, +): TSESTreeOptions { + // eslint-disable-next-line @typescript-eslint/no-unused-vars -- The variables are meant to be omitted + const { EXPERIMENTAL_useProjectService, project, ...rest } = opts; + + return rest; +} diff --git a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts new file mode 100644 index 000000000000..56a96ca2bd91 --- /dev/null +++ b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts @@ -0,0 +1,14 @@ +import { withoutProjectParserOptions } from '../../src'; + +describe('withoutProjectParserOptions', () => { + it('removes only project parser options', () => { + const without = withoutProjectParserOptions({ + comment: true, + EXPERIMENTAL_useProjectService: true, + project: true, + }); + expect(without).toEqual({ + comment: true, + }); + }); +});