Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Move parserServices to SourceCode #17311

Merged
merged 1 commit into from Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/src/extend/custom-parsers.md
Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion docs/src/extend/custom-rules.md
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 8 additions & 4 deletions tests/lib/linter/linter.js
Expand Up @@ -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()
});
}
})
Expand All @@ -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()
});
}
})
Expand Down Expand Up @@ -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()
});
}
})
Expand Down Expand Up @@ -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()
});
}
})
Expand Down
4 changes: 3 additions & 1 deletion tests/lib/rule-tester/flat-rule-tester.js
Expand Up @@ -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}'` });
Expand Down
4 changes: 3 additions & 1 deletion tests/lib/rule-tester/rule-tester.js
Expand Up @@ -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}'` });
Expand Down