From 2054b232e4218d7bcfab57269b8c453f1c4cc516 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Mon, 26 Jun 2023 14:53:29 +0200 Subject: [PATCH] feat: Move `parserServices` to `SourceCode` Deprecates `context.parserServices` in favor of `SourceCode#parserServices` Refs #16999 --- docs/src/extend/custom-parsers.md | 4 ++-- docs/src/extend/custom-rules.md | 3 ++- tests/lib/linter/linter.js | 12 ++++++++---- tests/lib/rule-tester/flat-rule-tester.js | 4 +++- tests/lib/rule-tester/rule-tester.js | 4 +++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/src/extend/custom-parsers.md b/docs/src/extend/custom-parsers.md index 388f54b726b..a7327fb91f6 100644 --- a/docs/src/extend/custom-parsers.md +++ b/docs/src/extend/custom-parsers.md @@ -42,7 +42,7 @@ The `parse` method should simply return the [AST](#ast-specification) object. The `parseForESLint` method should return an object that contains the required property `ast` and optional properties `services`, `scopeManager`, and `visitorKeys`. * `ast` should contain the [AST](#ast-specification) object. -* `services` can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.parserServices`. Default is an empty object. +* `services` can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.sourceCode.parserServices`. Default is an empty object. * `scopeManager` can be a [ScopeManager](./scope-manager-interface) object. Custom parsers can use customized scope analysis for experimental/enhancement syntaxes. The default is the `ScopeManager` object which is created by [eslint-scope](https://github.com/eslint/eslint-scope). * Support for `scopeManager` was added in ESLint v4.14.0. ESLint versions that support `scopeManager` will provide an `eslintScopeManager: true` property in `parserOptions`, which can be used for feature detection. * `visitorKeys` can be an object to customize AST traversal. The keys of the object are the type of AST nodes. Each value is an array of the property names which should be traversed. The default is [KEYS of `eslint-visitor-keys`](https://github.com/eslint/eslint-visitor-keys#evkkeys). @@ -120,7 +120,7 @@ To learn more about using ESLint parsers in your project, refer to [Configure a For a complex example of a custom parser, refer to the [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/parser) source code. -A simple custom parser that provides a `context.parserServices.foo()` method to rules. +A simple custom parser that provides a `context.sourceCode.parserServices.foo()` method to rules. ```javascript // awesome-custom-parser.js diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 76c9e88741d..944d334c0f5 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -131,7 +131,7 @@ The `context` object has the following properties: * `sourceCode`: (`object`) A `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)). * `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from the configuration. * `parserPath`: (`string`) The name of the `parser` from the configuration. -* `parserServices`: (`object`) Contains parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.) +* `parserServices`: (**Deprecated:** Use `SourceCode#parserServices` instead.) Contains parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.) * `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). Additionally, the `context` object has the following methods: @@ -575,6 +575,7 @@ There are also some properties you can access: * `ast`: (`object`) `Program` node of the AST for the code being linted. * `scopeManager`: [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code. * `visitorKeys`: (`object`) Visitor keys to traverse this AST. +* `parserServices`: (`object`) Contains parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.) * `lines`: (`array`) Array of lines, split according to the specification's definition of line breaks. You should use a `SourceCode` object whenever you need to get more information about the code being linted. diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index be1380f6880..3a8a8fe7e6c 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -1197,9 +1197,10 @@ describe("Linter", () => { linter.defineRule("test-service-rule", { create: context => ({ Literal(node) { + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); context.report({ node, - message: context.parserServices.test.getMessage() + message: context.sourceCode.parserServices.test.getMessage() }); } }) @@ -1219,9 +1220,10 @@ describe("Linter", () => { linter.defineRule("test-service-rule", { create: context => ({ Literal(node) { + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); context.report({ node, - message: context.parserServices.test.getMessage() + message: context.sourceCode.parserServices.test.getMessage() }); } }) @@ -7956,9 +7958,10 @@ describe("Linter with FlatConfigArray", () => { "test-service-rule": { create: context => ({ Literal(node) { + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); context.report({ node, - message: context.parserServices.test.getMessage() + message: context.sourceCode.parserServices.test.getMessage() }); } }) @@ -7992,9 +7995,10 @@ describe("Linter with FlatConfigArray", () => { "test-service-rule": { create: context => ({ Literal(node) { + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); context.report({ node, - message: context.parserServices.test.getMessage() + message: context.sourceCode.parserServices.test.getMessage() }); } }) diff --git a/tests/lib/rule-tester/flat-rule-tester.js b/tests/lib/rule-tester/flat-rule-tester.js index f65c3bb1913..6c6188aee50 100644 --- a/tests/lib/rule-tester/flat-rule-tester.js +++ b/tests/lib/rule-tester/flat-rule-tester.js @@ -1199,7 +1199,9 @@ describe("FlatRuleTester", () => { const disallowHiRule = { create: context => ({ Literal(node) { - const disallowed = context.parserServices.test.getMessage(); // returns "Hi!" + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); + + const disallowed = context.sourceCode.parserServices.test.getMessage(); // returns "Hi!" if (node.value === disallowed) { context.report({ node, message: `Don't use '${disallowed}'` }); diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js index a36edafd409..cb1cf346f62 100644 --- a/tests/lib/rule-tester/rule-tester.js +++ b/tests/lib/rule-tester/rule-tester.js @@ -1248,7 +1248,9 @@ describe("RuleTester", () => { const disallowHiRule = { create: context => ({ Literal(node) { - const disallowed = context.parserServices.test.getMessage(); // returns "Hi!" + assert.strictEqual(context.parserServices, context.sourceCode.parserServices); + + const disallowed = context.sourceCode.parserServices.test.getMessage(); // returns "Hi!" if (node.value === disallowed) { context.report({ node, message: `Don't use '${disallowed}'` });