From 4171833b3a7c29b160bc484d1a256a848dd6e138 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Sat, 18 Feb 2023 13:32:29 -0500 Subject: [PATCH 01/16] Start copy edits --- docs/src/extend/custom-rules.md | 72 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index cbb9be2d175..6c89ffefa52 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -36,30 +36,29 @@ module.exports = { ## Rule Basics -The source file for a rule exports an object with the following properties. +The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format. `meta` (object) contains metadata for the rule: * `type` (string) indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: + * `"problem"` means the rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve. * `"suggestion"` means the rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. * `"layout"` means the rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. -* `docs` (object) is required for core rules of ESLint: +* `docs` (object) is required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. * `description` (string) provides the short description of the rule in the [rules index](../rules/) - * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule + * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../use configure/configuration-files#extending-configuration-files) enables the rule * `url` (string) specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations) - In a custom rule or plugin, you can omit `docs` or include any properties that you need in it. - -* `fixable` (string) is either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule +* `fixable` (string) is either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. - **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable. + **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable. * `hasSuggestions` (boolean) specifies whether rules can return suggestions (defaults to `false` if omitted) - **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. + **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. * `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules) @@ -221,7 +220,6 @@ The node contains all of the information necessary to figure out the line and co You can also use placeholders in the message and provide `data`: ```js -{% raw %} context.report({ node: node, message: "Unexpected identifier: {{ identifier }}", @@ -229,12 +227,11 @@ context.report({ identifier: node.name } }); -{% endraw %} ``` Note that leading and trailing whitespace is optional in message parameters. -The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node. +The node contains all the information necessary to figure out the line and column number of the offending text as well the source text representing the node. ### `messageId`s @@ -242,9 +239,11 @@ Instead of typing out messages in both the `context.report()` call and your test This allows you to avoid retyping error messages. It also prevents errors reported in different sections of your rule from having out-of-date messages. +Rule file: + ```js -{% raw %} -// in your rule +// avoidName.js + module.exports = { meta: { messages: { @@ -267,13 +266,22 @@ module.exports = { }; } }; +``` -// in the file to lint: +In the file to lint: + +```javascript +// someFile.js var foo = 2; // ^ error: Avoid using variables named 'foo' +``` + +In your tests: + +```javascript +// avoidName.test.js -// In your tests: var rule = require("../../../lib/rules/my-rule"); var RuleTester = require("eslint").RuleTester; @@ -291,7 +299,6 @@ ruleTester.run("my-rule", rule, { } ] }); -{% endraw %} ``` ### Applying Fixes @@ -308,7 +315,7 @@ context.report({ }); ``` -Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all of the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterwards, any remaining problems will be reported as usual. +Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterwards, any remaining problems will be reported as usual. **Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-basics) the `meta.fixable` property. @@ -323,7 +330,7 @@ The `fixer` object has the following methods: * `replaceText(nodeOrToken, text)` - replaces the text in the given node or token * `replaceTextRange(range, text)` - replaces the text in the given range -A range is a two-item array containing character indices inside of the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent. +A range is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent. The above methods return a `fixing` object. The `fix()` function can return the following values: @@ -340,21 +347,22 @@ Best practices for fixes: 1. Make fixes as small as possible. Fixes that are unnecessarily large could conflict with other fixes, and prevent them from being applied. 1. Only make one fix per message. This is enforced because you must return the result of the fixer operation from `fix()`. 1. Since all rules are run again after the initial round of fixes is applied, it's not necessary for a rule to check whether the code style of a fix will cause errors to be reported by another rule. - * For example, suppose a fixer would like to surround an object key with quotes, but it's not sure whether the user would prefer single or double quotes. - ```js - ({ foo : 1 }) +* For example, suppose a fixer would like to surround an object key with quotes, but it's not sure whether the user would prefer single or double quotes. + + ```js + ({ foo : 1 }) - // should get fixed to either + // should get fixed to either - ({ 'foo': 1 }) + ({ 'foo': 1 }) - // or + // or - ({ "foo": 1 }) - ``` + ({ "foo": 1 }) + ``` - * This fixer can just select a quote type arbitrarily. If it guesses wrong, the resulting code will be automatically reported and fixed by the [`quotes`](../rules/quotes) rule. +* This fixer can just select a quote type arbitrarily. If it guesses wrong, the resulting code will be automatically reported and fixed by the [`quotes`](../rules/quotes) rule. Note: Making fixes as small as possible is a best practice, but in some cases it may be correct to extend the range of the fix in order to intentionally prevent other rules from making fixes in a surrounding range in the same pass. For instance, if replacement text declares a new variable, it can be useful to prevent other changes in the scope of the variable as they might cause name collisions. @@ -385,10 +393,9 @@ For example, if two fixes want to modify characters 0 through 5, only one is app In some cases fixes aren't appropriate to be automatically applied, for example, if a fix potentially changes functionality or if there are multiple valid ways to fix a rule depending on the implementation intent (see the best practices for [applying fixes](#applying-fixes) listed above). In these cases, there is an alternative `suggest` option on `context.report()` that allows other tools, such as editors, to expose helpers for users to manually apply a suggestion. -In order to provide suggestions, use the `suggest` key in the report argument with an array of suggestion objects. The suggestion objects represent individual suggestions that could be applied and require either a `desc` key string that describes what applying the suggestion would do or a `messageId` key (see [below](#suggestion-messageids)), and a `fix` key that is a function defining the suggestion result. This `fix` function follows the same API as regular fixes (described above in [applying fixes](#applying-fixes)). +To provide suggestions, use the `suggest` key in the report argument with an array of suggestion objects. The suggestion objects represent individual suggestions that could be applied and require either a `desc` key string that describes what applying the suggestion would do or a `messageId` key (see [below](#suggestion-messageids)), and a `fix` key that is a function defining the suggestion result. This `fix` function follows the same API as regular fixes (described above in [applying fixes](#applying-fixes)). ```js -{% raw %} context.report({ node: node, message: "Unnecessary escape character: \\{{character}}.", @@ -408,7 +415,6 @@ context.report({ } ] }); -{% endraw %} ``` **Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-basics) this property. @@ -427,7 +433,6 @@ Suggestions are intended to provide fixes. ESLint will automatically remove the Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use it in a rule: ```js -{% raw %} module.exports = { meta: { messages: { @@ -460,7 +465,6 @@ module.exports = { }); } }; -{% endraw %} ``` #### Placeholders in suggestion messages @@ -470,7 +474,6 @@ You can also use placeholders in the suggestion message. This works the same way Please note that you have to provide `data` on the suggestion's object. Suggestion messages cannot use properties from the overall error's `data`. ```js -{% raw %} module.exports = { meta: { messages: { @@ -497,7 +500,6 @@ module.exports = { }); } }; -{% endraw %} ``` ### context.options @@ -597,7 +599,7 @@ You should use a `SourceCode` object whenever you need to get more information a #### Deprecated -Please note that the following methods have been deprecated and will be removed in a future version of ESLint: +Please note that the following `context` methods have been deprecated and will be removed in a future version of ESLint: * `getComments()` - replaced by `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()` * `getTokenOrCommentBefore()` - replaced by `getTokenBefore()` with the `{ includeComments: true }` option From 3549f6e331b926295ca1abeef6645e24d833d871 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Sat, 18 Feb 2023 14:03:54 -0500 Subject: [PATCH 02/16] redo page IA --- docs/src/extend/custom-rules.md | 130 +++++++++++++++++--------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 6c89ffefa52..210e13605f8 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -34,7 +34,7 @@ module.exports = { }; ``` -## Rule Basics +## Rule Structure The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format. @@ -68,9 +68,9 @@ The source file for a rule exports an object with the following properties. Both `create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: -* if a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree -* if a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree -* if a key is an event name, ESLint calls that **handler** function for [code path analysis](code-path-analysis) +* If a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree. +* If a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree. +* If a key is an event name, ESLint calls that **handler** function for [code path analysis](code-path-analysis). A rule can use the current node and its surrounding tree to report or fix problems. @@ -105,11 +105,15 @@ module.exports = { ## The Context Object -The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties: +TODO: contextualize where the context object is used in a sentence + +The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. + +The `context` object has the following properties: * `parserOptions` - the parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). * `id` - the rule ID. -* `options` - an array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions). +* `options` - an array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#contextoptions)). * `settings` - the [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. * `parserPath` - the name of the `parser` from configuration. * `parserServices` - an object containing 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.) @@ -130,8 +134,8 @@ Additionally, the `context` object has the following methods: * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()` - returns the filename associated with the source. * `getPhysicalFilename()` - when linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()` - returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables. -* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint. +* `getScope()` - returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see the [dedicated section](#contextgetscope)). +* `getSourceCode()` - returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see the [dedicated section](#contextgetsourcecode)). * `markVariableAsUsed(name)` - marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. * `report(descriptor)` - reports a problem in the code (see the [dedicated section](#contextreport)). @@ -215,7 +219,7 @@ context.report({ The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node. -### Using message placeholders +#### Using message placeholders You can also use placeholders in the message and provide `data`: @@ -233,7 +237,7 @@ Note that leading and trailing whitespace is optional in message parameters. The node contains all the information necessary to figure out the line and column number of the offending text as well the source text representing the node. -### `messageId`s +#### `messageId`s Instead of typing out messages in both the `context.report()` call and your tests, you can use `messageId`s instead. @@ -301,7 +305,7 @@ ruleTester.run("my-rule", rule, { }); ``` -### Applying Fixes +#### Applying Fixes If you'd like ESLint to attempt to fix the problem you're reporting, you can do so by specifying the `fix` function when using `context.report()`. The `fix` function receives a single argument, a `fixer` object, that you can use to apply a fix. For example: @@ -317,7 +321,7 @@ context.report({ Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterwards, any remaining problems will be reported as usual. -**Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-basics) the `meta.fixable` property. +**Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-structure) the `meta.fixable` property. The `fixer` object has the following methods: @@ -389,7 +393,7 @@ There is no way to specify which of the conflicting fixes is applied. For example, if two fixes want to modify characters 0 through 5, only one is applied. -### Providing Suggestions +#### Providing Suggestions In some cases fixes aren't appropriate to be automatically applied, for example, if a fix potentially changes functionality or if there are multiple valid ways to fix a rule depending on the implementation intent (see the best practices for [applying fixes](#applying-fixes) listed above). In these cases, there is an alternative `suggest` option on `context.report()` that allows other tools, such as editors, to expose helpers for users to manually apply a suggestion. @@ -417,7 +421,7 @@ context.report({ }); ``` -**Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-basics) this property. +**Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-structure) this property. Note: Suggestions will be applied as a stand-alone change, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or conform to user preferences on presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it. @@ -428,7 +432,7 @@ Best practices for suggestions: Suggestions are intended to provide fixes. ESLint will automatically remove the whole suggestion from the linting output if the suggestion's `fix` function returned `null` or an empty array/sequence. -#### Suggestion `messageId`s +##### Suggestion `messageId`s Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use it in a rule: @@ -597,15 +601,48 @@ There are also some properties you can access: You should use a `SourceCode` object whenever you need to get more information about the code being linted. -#### Deprecated +#### Getting the Source Text -Please note that the following `context` methods have been deprecated and will be removed in a future version of ESLint: +TODO: contextualize where sourceCode object comes from -* `getComments()` - replaced by `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()` -* `getTokenOrCommentBefore()` - replaced by `getTokenBefore()` with the `{ includeComments: true }` option -* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option -* `isSpaceBetweenTokens()` - replaced by `isSpaceBetween()` -* `getJSDocComment()` +If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows: + +```js + +// get all source +var source = sourceCode.getText(); + +// get source for just this AST node +var nodeSource = sourceCode.getText(node); + +// get source for AST node plus previous two characters +var nodeSourceWithPrev = sourceCode.getText(node, 2); + +// get source for AST node plus following two characters +var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2); +``` + +In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.). + +#### Accessing Comments + +While comments are not technically part of the AST, ESLint provides a few ways for rules to access them: + +#### sourceCode.getAllComments() + +This method returns an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location. + +#### sourceCode.getCommentsBefore(), sourceCode.getCommentsAfter(), and sourceCode.getCommentsInside() + +These methods return an array of comments that appear directly before, directly after, and inside nodes, respectively. They are useful for rules that need to check comments in relation to a given node or token. + +Keep in mind that the results of this method are calculated on demand. + +#### Token traversal methods + +Finally, comments can be accessed through many of `sourceCode`'s methods using the `includeComments` option. + +TODO: see if can link to above ### Options Schemas @@ -643,44 +680,7 @@ To learn more about JSON Schema, we recommend looking at some examples in [websi **Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored). -### Getting the Source - -If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows: - -```js - -// get all source -var source = sourceCode.getText(); - -// get source for just this AST node -var nodeSource = sourceCode.getText(node); - -// get source for AST node plus previous two characters -var nodeSourceWithPrev = sourceCode.getText(node, 2); - -// get source for AST node plus following two characters -var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2); -``` - -In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.). - -### Accessing Comments - -While comments are not technically part of the AST, ESLint provides a few ways for rules to access them: - -#### sourceCode.getAllComments() - -This method returns an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location. - -#### sourceCode.getCommentsBefore(), sourceCode.getCommentsAfter(), and sourceCode.getCommentsInside() - -These methods return an array of comments that appear directly before, directly after, and inside nodes, respectively. They are useful for rules that need to check comments in relation to a given node or token. - -Keep in mind that the results of this method are calculated on demand. - -#### Token traversal methods - -Finally, comments can be accessed through many of `sourceCode`'s methods using the `includeComments` option. +TODO: see if can link to above. ### Accessing Shebangs @@ -693,6 +693,16 @@ You can access that code path objects with five events related to code paths. [details here](code-path-analysis) +### Deprecated `context` Methods + +Please note that the following `context` methods have been deprecated and will be removed in a future version of ESLint: + +* `getComments()` - replaced by `SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, and `SourceCode#getCommentsInside()` +* `getTokenOrCommentBefore()` - replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option +* `getTokenOrCommentAfter()` - replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option +* `isSpaceBetweenTokens()` - replaced by `SourceCode#isSpaceBetween()` +* `getJSDocComment()` + ## Rule Unit Tests ESLint provides the [`RuleTester`](../integrate/nodejs-api#ruletester) utility to make it easy to write tests for rules. From 01eb3e4b46852064bc3cbdce1c0a57754bbcd9b9 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Wed, 22 Feb 2023 21:30:45 -0500 Subject: [PATCH 03/16] copy edits --- docs/src/extend/custom-rules.md | 262 +++++++++++++++-------------- docs/src/use/migrating-to-5.0.0.md | 2 +- 2 files changed, 134 insertions(+), 130 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 210e13605f8..dbb7e56dfa5 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -38,35 +38,35 @@ module.exports = { The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format. -`meta` (object) contains metadata for the rule: +`meta` (object) Contains metadata for the rule: -* `type` (string) indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: +* `type`: (string) indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: - * `"problem"` means the rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve. - * `"suggestion"` means the rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. - * `"layout"` means the rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. + * `"problem"`: The rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve. + * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. + * `"layout"`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. -* `docs` (object) is required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. +* `docs`: (object) Required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. - * `description` (string) provides the short description of the rule in the [rules index](../rules/) - * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../use configure/configuration-files#extending-configuration-files) enables the rule - * `url` (string) specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations) + * `description`: (string) Provides the short description of the rule in the [rules index](../rules/). + * `recommended`: (boolean) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use configure/configuration-files#extending-configuration-files) enables the rule. + * `url`: (string) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations). -* `fixable` (string) is either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. +* `fixable`: (string) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable. -* `hasSuggestions` (boolean) specifies whether rules can return suggestions (defaults to `false` if omitted) +* `hasSuggestions`: (boolean) Specifies whether rules can return suggestions (defaults to `false` if omitted). **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. -* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules) +* `schema`: (array) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules). -* `deprecated` (boolean) indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. +* `deprecated`: (boolean) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. -* `replacedBy` (array) in the case of a deprecated rule, specifies replacement rule(s) +* `replacedBy`: (array) In the case of a deprecated rule, specifies replacement rule(s). -`create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: +`create`: (function) Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: * If a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree. * If a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree. @@ -105,24 +105,36 @@ module.exports = { ## The Context Object -TODO: contextualize where the context object is used in a sentence +The `context` object is the argument of the callback function in the `create` property of a custom rule. For example: + +```js +// customRule.js + +module.exports = { + meta: { ... }, + // `context` object is the argument + create: function(context) { + // ... + } +}; +``` The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties: -* `parserOptions` - the parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). -* `id` - the rule ID. -* `options` - an array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#contextoptions)). -* `settings` - the [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. -* `parserPath` - the name of the `parser` from configuration. -* `parserServices` - an object containing 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)). +* `id`: The rule ID. +* `options`: An array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). +* `settings`: The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. +* `parserPath`: The name of the `parser` from configuration. +* `parserServices`: An object containing 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.) Additionally, the `context` object has the following methods: -* `getAncestors()` - returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. -* `getCwd()` - returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered as the current working directory. -* `getDeclaredVariables(node)` - returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables. +* `getAncestors()`: Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. +* `getCwd()`: Returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered as the current working directory. +* `getDeclaredVariables(node)`: Returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables. * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned. * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned. * If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned, in addition to variables for the function parameters. @@ -132,20 +144,20 @@ Additionally, the `context` object has the following methods: * If the node is an `ImportDeclaration`, variables for all of its specifiers are returned. * If the node is an `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`, the declared variable is returned. * Otherwise, if the node does not declare any variables, an empty array is returned. -* `getFilename()` - returns the filename associated with the source. -* `getPhysicalFilename()` - when linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()` - returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see the [dedicated section](#contextgetscope)). -* `getSourceCode()` - returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see the [dedicated section](#contextgetsourcecode)). -* `markVariableAsUsed(name)` - marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. -* `report(descriptor)` - reports a problem in the code (see the [dedicated section](#contextreport)). +* `getFilename()`: Returns the filename associated with the source. +* `getPhysicalFilename()`: When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. +* `getScope()`: Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see the [dedicated section](#accessing-scope-of-a-node)). +* `getSourceCode()`: Returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see the [dedicated section](#accessing-the-source-code)). +* `markVariableAsUsed(name)`: Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. +* `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)). **Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon. -### context.getScope() +### Accessing Scope of a Node -This method returns the scope of the current node. It is a useful method for finding information about the variables in a given scope, and how they are used in other scopes. +The `context.getScope()` method returns the scope of the current node. It is a useful method for finding information about the variables in a given scope, and how they are used in other scopes. -#### Scope types +#### Scope Types The following table contains a list of AST node types and the scope type that they correspond to. For more information about the scope types, refer to the [`Scope` object documentation](./scope-manager-interface#scope-interface). @@ -180,31 +192,31 @@ Also inside of each `Variable`, the `Variable#defs` property contains an array o Global variables have the following additional properties: -* `Variable#writeable` (`boolean | undefined`) ... If `true`, this global variable can be assigned arbitrary value. If `false`, this global variable is read-only. -* `Variable#eslintExplicitGlobal` (`boolean | undefined`) ... If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file. -* `Variable#eslintExplicitGlobalComments` (`Comment[] | undefined`) ... The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments. -* `Variable#eslintImplicitGlobalSetting` (`"readonly" | "writable" | undefined`) ... The configured value in config files. This can be different from `variable.writeable` if there are `/* globals */` directive comments. +* `Variable#writeable`: (`boolean | undefined`) If `true`, this global variable can be assigned arbitrary value. If `false`, this global variable is read-only. +* `Variable#eslintExplicitGlobal`: (`boolean | undefined`) If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file. +* `Variable#eslintExplicitGlobalComments`: (`Comment[] | undefined`) The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments. +* `Variable#eslintImplicitGlobalSetting`: (`"readonly" | "writable" | undefined`) The configured value in config files. This can be different from `variable.writeable` if there are `/* globals */` directive comments. For examples of using `context.getScope()` to track variables, refer to the source code for the following built-in rules: * [no-shadow](https://github.com/eslint/eslint/blob/main/lib/rules/no-shadow.js): Calls `context.getScopes()` at the global scope and parses all child scopes to make sure a variable name is not reused at a lower scope. ([no-shadow](../rules/no-shadow) documentation) * [no-redeclare](https://github.com/eslint/eslint/blob/main/lib/rules/no-redeclare.js): Calls `context.getScope()` at each scope to make sure that a variable is not declared twice at that scope. ([no-redeclare](../rules/no-redeclare) documentation) -### context.report() +### Reporting Problems -The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties: +The main method you'll use when writing custom rules is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties: -* `message` - the problem message. -* `node` - (optional) the AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. -* `loc` - (optional) an object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. - * `start` - An object of the start location. - * `line` - the 1-based line number at which the problem occurred. - * `column` - the 0-based column number at which the problem occurred. - * `end` - An object of the end location. - * `line` - the 1-based line number at which the problem occurred. - * `column` - the 0-based column number at which the problem occurred. -* `data` - (optional) [placeholder](#using-message-placeholders) data for `message`. -* `fix` - (optional) a function that applies a [fix](#applying-fixes) to resolve the problem. +* `message`: The problem message. +* `node`: (optional) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. +* `loc`: (optional) An object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. + * `start`: An object of the start location. + * `line`: The 1-based line number at which the problem occurred. + * `column` The 0-based column number at which the problem occurred. + * `end`: An object of the end location. + * `line`: The 1-based line number at which the problem occurred. + * `column`: The 0-based column number at which the problem occurred. +* `data`:(optional) [Placeholder](#using-message-placeholders) data for `message`. +* `fix`: (optional) A function that applies a [fix](#applying-fixes) to resolve the problem. Note that at least one of `node` or `loc` is required. @@ -217,9 +229,9 @@ context.report({ }); ``` -The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node. +The node contains all the information necessary to figure out the line and column number of the offending text as well the source text representing the node. -#### Using message placeholders +#### Using Message Placeholders You can also use placeholders in the message and provide `data`: @@ -325,14 +337,14 @@ Here, the `fix()` function is used to insert a semicolon after the node. Note th The `fixer` object has the following methods: -* `insertTextAfter(nodeOrToken, text)` - inserts text after the given node or token -* `insertTextAfterRange(range, text)` - inserts text after the given range -* `insertTextBefore(nodeOrToken, text)` - inserts text before the given node or token -* `insertTextBeforeRange(range, text)` - inserts text before the given range -* `remove(nodeOrToken)` - removes the given node or token -* `removeRange(range)` - removes text in the given range -* `replaceText(nodeOrToken, text)` - replaces the text in the given node or token -* `replaceTextRange(range, text)` - replaces the text in the given range +* `insertTextAfter(nodeOrToken, text)`: Insert text after the given node or token. +* `insertTextAfterRange(range, text)`: Insert text after the given range +* `insertTextBefore(nodeOrToken, text)`: Insert text before the given node or token +* `insertTextBeforeRange(range, text)`: Insert text before the given range +* `remove(nodeOrToken)`: Remove the given node or token +* `removeRange(range)`: Remove text in the given range +* `replaceText(nodeOrToken, text)`: Replace the text in the given node or token +* `replaceTextRange(range, text)`: Replace the text in the given range A range is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent. @@ -432,7 +444,7 @@ Best practices for suggestions: Suggestions are intended to provide fixes. ESLint will automatically remove the whole suggestion from the linting output if the suggestion's `fix` function returned `null` or an empty array/sequence. -##### Suggestion `messageId`s +#### Suggestion `messageId`s Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use it in a rule: @@ -471,7 +483,7 @@ module.exports = { }; ``` -#### Placeholders in suggestion messages +#### Placeholders in Suggestion Messages You can also use placeholders in the suggestion message. This works the same way as placeholders for the overall error (see [using message placeholders](#using-message-placeholders)). @@ -506,7 +518,7 @@ module.exports = { }; ``` -### context.options +### Accessing Options Passed to a Rule Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line, or in comments). For example: @@ -532,9 +544,11 @@ Since `context.options` is just an array, you can use it to determine how many o When using options, make sure that your rule has some logical defaults in case the options are not provided. -### context.getSourceCode() +TODO: change title + +### Accessing the Source Code -The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `getSourceCode()` method: +The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `context.getSourceCode()` method: ```js module.exports = { @@ -548,63 +562,61 @@ module.exports = { Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code: -* `getText(node)` - returns the source code for the given node. Omit `node` to get the whole source. -* `getAllComments()` - returns an array of all comments in the source. -* `getCommentsBefore(nodeOrToken)` - returns an array of comment tokens that occur directly before the given node or token. -* `getCommentsAfter(nodeOrToken)` - returns an array of comment tokens that occur directly after the given node or token. -* `getCommentsInside(node)` - returns an array of all comment tokens inside a given node. -* `isSpaceBetween(nodeOrToken, nodeOrToken)` - returns true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node. -* `getFirstToken(node, skipOptions)` - returns the first token representing the given node. -* `getFirstTokens(node, countOptions)` - returns the first `count` tokens representing the given node. -* `getLastToken(node, skipOptions)` - returns the last token representing the given node. -* `getLastTokens(node, countOptions)` - returns the last `count` tokens representing the given node. -* `getTokenAfter(nodeOrToken, skipOptions)` - returns the first token after the given node or token. -* `getTokensAfter(nodeOrToken, countOptions)` - returns `count` tokens after the given node or token. -* `getTokenBefore(nodeOrToken, skipOptions)` - returns the first token before the given node or token. -* `getTokensBefore(nodeOrToken, countOptions)` - returns `count` tokens before the given node or token. -* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)` - returns the first token between two nodes or tokens. -* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)` - returns the first `count` tokens between two nodes or tokens. -* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)` - returns the last token between two nodes or tokens. -* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)` - returns the last `count` tokens between two nodes or tokens. -* `getTokens(node)` - returns all tokens for the given node. -* `getTokensBetween(nodeOrToken1, nodeOrToken2)` - returns all tokens between two nodes. -* `getTokenByRangeStart(index, rangeOptions)` - returns the token whose range starts at the given index in the source. -* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index. -* `getLocFromIndex(index)` - returns an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based. -* `getIndexFromLoc(loc)` - returns the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key. -* `commentsExistBetween(nodeOrToken1, nodeOrToken2)` - returns `true` if comments exist between two nodes. +* `getText(node)`: Return the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#getting-the-source-text)). +* `getAllComments()`: Return an array of all comments in the source. +* `getCommentsBefore(nodeOrToken)`: Return an array of comment tokens that occur directly before the given node or token. +* `getCommentsAfter(nodeOrToken)`: Return an array of comment tokens that occur directly after the given node or token. +* `getCommentsInside(node)`: Return an array of all comment tokens inside a given node. +* `isSpaceBetween(nodeOrToken, nodeOrToken)`: Return true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node. +* `getFirstToken(node, skipOptions)`: Return the first token representing the given node. +* `getFirstTokens(node, countOptions)`: Return the first `count` tokens representing the given node. +* `getLastToken(node, skipOptions)`: Return the last token representing the given node. +* `getLastTokens(node, countOptions)`: Return the last `count` tokens representing the given node. +* `getTokenAfter(nodeOrToken, skipOptions)`: Return the first token after the given node or token. +* `getTokensAfter(nodeOrToken, countOptions)`: Return `count` tokens after the given node or token. +* `getTokenBefore(nodeOrToken, skipOptions)`: Return the first token before the given node or token. +* `getTokensBefore(nodeOrToken, countOptions)`: Return `count` tokens before the given node or token. +* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Return the first token between two nodes or tokens. +* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Return the first `count` tokens between two nodes or tokens. +* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Return the last token between two nodes or tokens. +* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Return the last `count` tokens between two nodes or tokens. +* `getTokens(node)`: Return all tokens for the given node. +* `getTokensBetween(nodeOrToken1, nodeOrToken2)`: Return all tokens between two nodes. +* `getTokenByRangeStart(index, rangeOptions)`: Return the token whose range starts at the given index in the source. +* `getNodeByRangeIndex(index)`: Return the deepest node in the AST containing the given source index. +* `getLocFromIndex(index)`: Return an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based. +* `getIndexFromLoc(loc)`: Return the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key. +* `commentsExistBetween(nodeOrToken1, nodeOrToken2)`: Return `true` if comments exist between two nodes. `skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`. -* `skip` is a positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. -* `includeComments` is a boolean value, the flag to include comment tokens into the result. -* `filter` is a function which gets a token as the first argument, if the function returns `false` then the result excludes the token. +* `skip`: Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. +* `includeComments`: Boolean, the flag to include comment tokens into the result. +* `filter`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. `countOptions` is an object which has 3 properties; `count`, `includeComments`, and `filter`. Default is `{count: 0, includeComments: false, filter: null}`. -* `count` is a positive integer, the maximum number of returning tokens. -* `includeComments` is a boolean value, the flag to include comment tokens into the result. -* `filter` is a function which gets a token as the first argument, if the function returns `false` then the result excludes the token. +* `count`: Positive integer, the maximum number of returning tokens. +* `includeComments`: Boolean, the flag to include comment tokens into the result. +* `filter` Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. `rangeOptions` is an object which has 1 property: `includeComments`. -* `includeComments` is a boolean value, the flag to include comment tokens into the result. +* `includeComments`: Boolean, the flag to include comment tokens into the result. There are also some properties you can access: -* `hasBOM` - the flag to indicate whether or not the source code has Unicode BOM. -* `text` - the full text of the code being linted. Unicode BOM has been stripped from this text. -* `ast` - the `Program` node of the AST for the code being linted. -* `scopeManager` - the [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code. -* `visitorKeys` - the visitor keys to traverse this AST. -* `lines` - an array of lines, split according to the specification's definition of line breaks. +* `hasBOM`: The flag to indicate whether the source code has Unicode BOM. +* `text`: The full text of the code being linted. Unicode BOM has been stripped from this text. +* `ast`: `Program` node of the AST for the code being linted. +* `scopeManager`: [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code. +* `visitorKeys`: Visitor keys to traverse this AST. +* `lines`: 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. #### Getting the Source Text -TODO: contextualize where sourceCode object comes from - If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows: ```js @@ -628,21 +640,16 @@ In this way, you can look for patterns in the JavaScript text itself when the AS While comments are not technically part of the AST, ESLint provides a few ways for rules to access them: -#### sourceCode.getAllComments() - -This method returns an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location. - -#### sourceCode.getCommentsBefore(), sourceCode.getCommentsAfter(), and sourceCode.getCommentsInside() +* `sourceCode.getAllComments()`: Return an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location. +* `sourceCode.getCommentsBefore()`: Return an array of comments that appear directly before nodes. +* `sourceCode.getCommentsAfter()`: Return an array of comments that appear directly after nodes. +* `sourceCode.getCommentsInside()` Return an array of comments that appear inside nodes. -These methods return an array of comments that appear directly before, directly after, and inside nodes, respectively. They are useful for rules that need to check comments in relation to a given node or token. +`sourceCode.getCommentsBefore()`, `sourceCode.getCommentsAfter()`, and `sourceCode.getCommentsInside()` are useful for rules that need to check comments in relation to a given node or token. -Keep in mind that the results of this method are calculated on demand. +Keep in mind that the results of these methods are calculated on demand. -#### Token traversal methods - -Finally, comments can be accessed through many of `sourceCode`'s methods using the `includeComments` option. - -TODO: see if can link to above +You can also access comments through many of `sourceCode`'s methods using the `includeComments` option. ### Options Schemas @@ -680,28 +687,25 @@ To learn more about JSON Schema, we recommend looking at some examples in [websi **Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored). -TODO: see if can link to above. - ### Accessing Shebangs +TODO: which methods to access shebang? also would be helpful to have a small example here. + Shebangs are represented by tokens of type `"Shebang"`. They are treated as comments and can be accessed by the methods outlined above. ### Accessing Code Paths -ESLint analyzes code paths while traversing AST. -You can access that code path objects with five events related to code paths. - -[details here](code-path-analysis) +ESLint analyzes code paths while traversing AST. You can access that code path objects with five events related to code paths. For more information, refer to [Code Path Analysis](code-path-analysis). ### Deprecated `context` Methods Please note that the following `context` methods have been deprecated and will be removed in a future version of ESLint: -* `getComments()` - replaced by `SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, and `SourceCode#getCommentsInside()` -* `getTokenOrCommentBefore()` - replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option -* `getTokenOrCommentAfter()` - replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option -* `isSpaceBetweenTokens()` - replaced by `SourceCode#isSpaceBetween()` -* `getJSDocComment()` +* `getComments()`: Replaced by `SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, and `SourceCode#getCommentsInside()`. +* `getTokenOrCommentBefore()`: Replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option. +* `getTokenOrCommentAfter()`: Replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option. +* `isSpaceBetweenTokens()`: Replaced by `SourceCode#isSpaceBetween()` +* `getJSDocComment()`. ## Rule Unit Tests diff --git a/docs/src/use/migrating-to-5.0.0.md b/docs/src/use/migrating-to-5.0.0.md index 5eb4ec7ad1a..d5507b3a711 100644 --- a/docs/src/use/migrating-to-5.0.0.md +++ b/docs/src/use/migrating-to-5.0.0.md @@ -221,7 +221,7 @@ Previously, the `context.getScope()` method changed its behavior based on the `p Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes. -In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/custom-rules#contextgetscope) for more details on which scopes are returned. +In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/custom-rules#accessing-scope-of-a-node) for more details on which scopes are returned. **To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information. From 64d3c064bf1239ad615e6d76779950e49daecfda Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Thu, 23 Feb 2023 21:32:26 -0500 Subject: [PATCH 04/16] copy edits --- docs/src/extend/custom-rules.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index dbb7e56dfa5..3a846e9cf0d 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -46,10 +46,10 @@ The source file for a rule exports an object with the following properties. Both * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. * `"layout"`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. -* `docs`: (object) Required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. +* `docs`: (object) Required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. The following properties are only relevant when working on core rules. * `description`: (string) Provides the short description of the rule in the [rules index](../rules/). - * `recommended`: (boolean) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use configure/configuration-files#extending-configuration-files) enables the rule. + * `recommended`: (boolean) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. * `url`: (string) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations). * `fixable`: (string) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. @@ -346,7 +346,7 @@ The `fixer` object has the following methods: * `replaceText(nodeOrToken, text)`: Replace the text in the given node or token * `replaceTextRange(range, text)`: Replace the text in the given range -A range is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent. +A `range` is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent. The above methods return a `fixing` object. The `fix()` function can return the following values: @@ -435,7 +435,7 @@ context.report({ **Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-structure) this property. -Note: Suggestions will be applied as a stand-alone change, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or conform to user preferences on presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it. +**Note:** Suggestions are applied as stand-alone changes, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or conform to user preferences on presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it. Best practices for suggestions: @@ -446,7 +446,7 @@ Suggestions are intended to provide fixes. ESLint will automatically remove the #### Suggestion `messageId`s -Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use it in a rule: +Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use a suggestion `messageId` in a rule: ```js module.exports = { @@ -466,13 +466,13 @@ module.exports = { data: { character }, suggest: [ { - messageId: "removeEscape", + messageId: "removeEscape", // suggestion messageId fix: function(fixer) { return fixer.removeRange(range); } }, { - messageId: "escapeBackslash", + messageId: "escapeBackslash", // suggestion messageId fix: function(fixer) { return fixer.insertTextBeforeRange(range, "\\"); } @@ -520,7 +520,7 @@ module.exports = { ### Accessing Options Passed to a Rule -Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line, or in comments). For example: +Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line interface, or comments). For example: ```json { @@ -544,8 +544,6 @@ Since `context.options` is just an array, you can use it to determine how many o When using options, make sure that your rule has some logical defaults in case the options are not provided. -TODO: change title - ### Accessing the Source Code The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `context.getSourceCode()` method: @@ -653,7 +651,7 @@ You can also access comments through many of `sourceCode`'s methods using the `i ### Options Schemas -Rules may export a `schema` property, which is a [JSON schema](https://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`. +Rules may export a `schema` property, which is a [JSON Schema](https://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`. There are two formats for a rule's exported `schema`. The first is a full JSON Schema object describing all possible options the rule accepts, including the rule's error level as the first argument and any optional arguments thereafter. @@ -681,10 +679,12 @@ module.exports = { }; ``` -In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a Boolean property named `exceptRange`. +In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a boolean property named `exceptRange`. To learn more about JSON Schema, we recommend looking at some examples in [website](https://json-schema.org/learn/) to start, and also reading [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) (a free ebook). +TODO: i don't understand what this note is saying. could someone clarify? + **Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored). ### Accessing Shebangs @@ -695,7 +695,7 @@ Shebangs are represented by tokens of type `"Shebang"`. They are treated as comm ### Accessing Code Paths -ESLint analyzes code paths while traversing AST. You can access that code path objects with five events related to code paths. For more information, refer to [Code Path Analysis](code-path-analysis). +ESLint analyzes code paths while traversing AST. You can access code path objects with five events related to code paths. For more information, refer to [Code Path Analysis](code-path-analysis). ### Deprecated `context` Methods @@ -713,11 +713,11 @@ ESLint provides the [`RuleTester`](../integrate/nodejs-api#ruletester) utility t ## Rule Naming Conventions -While you can give a custom rule any name you'd like, the core rules have naming conventions that it could be clearer to apply to your custom rule. To learn more, refer to the [Core Rule Naming Conventions](../contribute/core-rules#rule-naming-conventions) documentation. +While you can give a custom rule any name you'd like, the core rules have naming conventions. It could be clearer to apply these same naming conventions to your custom rule. To learn more, refer to the [Core Rule Naming Conventions](../contribute/core-rules#rule-naming-conventions) documentation. ## Runtime Rules -The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with. With runtime rules, you don't have to wait for the next version of ESLint or be disappointed that your rule isn't general enough to apply to the larger JavaScript community, just write your rules and include them at runtime. +The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with or be included in a plugin. Just write your rules and include them at runtime. Runtime rules are written in the same format as all other rules. Create your rule as you would any other and then follow these steps: From 5b6d50a73e0d0061e6deb829071de85de4d4c4f0 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Tue, 28 Feb 2023 21:47:32 -0500 Subject: [PATCH 05/16] Apply suggestions from code review Co-authored-by: Nicholas C. Zakas Co-authored-by: Nitin Kumar --- docs/src/extend/custom-rules.md | 47 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index dbf23e6236f..ba27feed60d 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -46,7 +46,7 @@ The source file for a rule exports an object with the following properties. Both * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. * `"layout"`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. -* `docs`: (object) Required for **core rules** of ESLint. If you are creating a custom rule, you **do not** need to include the `docs` object or can include any properties that you need in it. The following properties are only relevant when working on core rules. +* `docs`: (object) Required for core rules and optional for custom rules. Core rules have specific entries inside of `docs` while custom rules can include any properties that you need. The following properties are only relevant when working on core rules. * `description`: (string) Provides the short description of the rule in the [rules index](../rules/). * `recommended`: (boolean) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. @@ -64,7 +64,7 @@ The source file for a rule exports an object with the following properties. Both * `deprecated`: (boolean) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. -* `replacedBy`: (array) In the case of a deprecated rule, specifies replacement rule(s). +* `replacedBy`: (array) In the case of a deprecated rule, specify replacement rule(s). `create`: (function) Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: @@ -105,7 +105,7 @@ module.exports = { ## The Context Object -The `context` object is the argument of the callback function in the `create` property of a custom rule. For example: +The `context` object is the only argument of the `create` method in a rule. For example: ```js // customRule.js @@ -113,13 +113,13 @@ The `context` object is the argument of the callback function in the `create` pr module.exports = { meta: { ... }, // `context` object is the argument - create: function(context) { + create(context) { // ... } }; ``` -The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. +As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties: @@ -127,13 +127,13 @@ The `context` object has the following properties: * `id`: The rule ID. * `options`: An array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). * `settings`: The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. -* `parserPath`: The name of the `parser` from configuration. +* `parserPath`: The name of the `parser` from the configuration. * `parserServices`: An object containing 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.) Additionally, the `context` object has the following methods: * `getAncestors()`: Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. -* `getCwd()`: Returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered as the current working directory. +* `getCwd()`: Returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory. * `getDeclaredVariables(node)`: Returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables. * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned. * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned. @@ -146,14 +146,14 @@ Additionally, the `context` object has the following methods: * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: Returns the filename associated with the source. * `getPhysicalFilename()`: When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()`: Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see the [dedicated section](#accessing-scope-of-a-node)). -* `getSourceCode()`: Returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see the [dedicated section](#accessing-the-source-code)). +* `getScope()`: Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-scope-of-a-node)). +* `getSourceCode()`: Returns 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)). * `markVariableAsUsed(name)`: Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. * `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)). **Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon. -### Accessing Scope of a Node +### Accessing the Scope of a Node The `context.getScope()` method returns the scope of the current node. It is a useful method for finding information about the variables in a given scope, and how they are used in other scopes. @@ -192,10 +192,10 @@ Also inside of each `Variable`, the `Variable#defs` property contains an array o Global variables have the following additional properties: -* `Variable#writeable`: (`boolean | undefined`) If `true`, this global variable can be assigned arbitrary value. If `false`, this global variable is read-only. +* `Variable#writeable`: (`boolean | undefined`) If `true`, this global variable can be assigned an arbitrary value. If `false`, this global variable is read-only. * `Variable#eslintExplicitGlobal`: (`boolean | undefined`) If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file. * `Variable#eslintExplicitGlobalComments`: (`Comment[] | undefined`) The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments. -* `Variable#eslintImplicitGlobalSetting`: (`"readonly" | "writable" | undefined`) The configured value in config files. This can be different from `variable.writeable` if there are `/* globals */` directive comments. +* `Variable#eslintImplicitGlobalSetting`: (`"readonly" | "writable" | undefined`) The configured value in config files. This can differ from `variable.writeable` if there are `/* globals */` directive comments. For examples of using `context.getScope()` to track variables, refer to the source code for the following built-in rules: @@ -229,7 +229,7 @@ context.report({ }); ``` -The node contains all the information necessary to figure out the line and column number of the offending text as well the source text representing the node. +The node contains all the information necessary to figure out the line and column number of the offending text as well as the source text representing the node. #### Using Message Placeholders @@ -247,7 +247,7 @@ context.report({ Note that leading and trailing whitespace is optional in message parameters. -The node contains all the information necessary to figure out the line and column number of the offending text as well the source text representing the node. +The node contains all the information necessary to figure out the line and column number of the offending text as well as the source text representing the node. #### `messageId`s @@ -258,7 +258,7 @@ This allows you to avoid retyping error messages. It also prevents errors report Rule file: ```js -// avoidName.js +// avoid-name.js module.exports = { meta: { @@ -296,7 +296,7 @@ var foo = 2; In your tests: ```javascript -// avoidName.test.js +// avoid-name.test.js var rule = require("../../../lib/rules/my-rule"); var RuleTester = require("eslint").RuleTester; @@ -331,7 +331,7 @@ context.report({ }); ``` -Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterwards, any remaining problems will be reported as usual. +Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterward, any remaining problems will be reported as usual. **Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-structure) the `meta.fixable` property. @@ -435,7 +435,7 @@ context.report({ **Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-structure) this property. -**Note:** Suggestions are applied as stand-alone changes, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or conform to user preferences on presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it. +**Note:** Suggestions are applied as stand-alone changes, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user-defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation or conform to user preferences on the presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it. Best practices for suggestions: @@ -588,7 +588,7 @@ Once you have an instance of `SourceCode`, you can use the following methods on `skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`. -* `skip`: Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. +* `skip`: Positive integer, the number of skipping tokens. If the `filter` option is given at the same time, it doesn't count filtered tokens as skipped. * `includeComments`: Boolean, the flag to include comment tokens into the result. * `filter`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. @@ -613,7 +613,7 @@ There are also some properties you can access: You should use a `SourceCode` object whenever you need to get more information about the code being linted. -#### Getting the Source Text +#### Accessing the Source Text If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows: @@ -632,7 +632,7 @@ var nodeSourceWithPrev = sourceCode.getText(node, 2); var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2); ``` -In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.). +In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as the location of commas, semicolons, parentheses, etc.). #### Accessing Comments @@ -679,13 +679,12 @@ module.exports = { }; ``` -In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a boolean property named `exceptRange`. +In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string that may be either `"always"` or `"never"`. The final optional argument is an object, which may have a boolean property named `exceptRange`. To learn more about JSON Schema, we recommend looking at some examples in [website](https://json-schema.org/learn/) to start, and also reading [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) (a free ebook). -TODO: i don't understand what this note is saying. could someone clarify? -**Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored). +**Note:** Currently you need to use a full JSON Schema object rather than an array in case your schema has references ($ref), because, in the case of array format, ESLint transforms this array into a single schema without updating references that make them incorrect (they are ignored). ### Accessing Shebangs From a424e335cf6fa7037469044c47c6740c9f44ea74 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Sun, 5 Mar 2023 14:44:04 -0500 Subject: [PATCH 06/16] shebang guidance --- docs/src/extend/custom-rules.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index ba27feed60d..c3d6da12066 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -655,7 +655,7 @@ Rules may export a `schema` property, which is a [JSON Schema](https://json-sche There are two formats for a rule's exported `schema`. The first is a full JSON Schema object describing all possible options the rule accepts, including the rule's error level as the first argument and any optional arguments thereafter. -However, to simplify schema creation, rules may also export an array of schemas for each optional positional argument, and ESLint will automatically validate the required error level first. For example, the `yoda` rule accepts a primary mode argument, as well as an extra options object with named properties. +However, to simplify schema creation, rules may also export an array of schemas for each optional positional argument. ESLint automatically validates the required error level first. For example, the `yoda` rule accepts a primary mode argument, as well as an extra options object with named properties. ```js // "yoda": [2, "never", { "exceptRange": true }] @@ -683,14 +683,11 @@ In the preceding example, the error level is assumed to be the first argument. I To learn more about JSON Schema, we recommend looking at some examples in [website](https://json-schema.org/learn/) to start, and also reading [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) (a free ebook). - -**Note:** Currently you need to use a full JSON Schema object rather than an array in case your schema has references ($ref), because, in the case of array format, ESLint transforms this array into a single schema without updating references that make them incorrect (they are ignored). +**Note:** If your rule schema uses JSON schema [`$ref`](https://json-schema.org/understanding-json-schema/structuring.html#ref) properties, you must use the full JSON Schema object rather than the array of positional property schemas. This is because ESLint transforms the array shorthand into a single schema without updating references that makes them incorrect (they are ignored). ### Accessing Shebangs -TODO: which methods to access shebang? also would be helpful to have a small example here. - -Shebangs are represented by tokens of type `"Shebang"`. They are treated as comments and can be accessed by the methods outlined above. +[Shebangs (#!)](https://en.wikipedia.org/wiki/Shebang_(Unix)) are represented by the unique tokens of type `"Shebang"`. They are treated as comments and can be accessed by the methods outlined in the [Accessing Comments](#accessing-comments) section, such as `sourceCode.getAllComments()`. ### Accessing Code Paths From c09af26472f98ab68c74ff07a6ff68f309e0af8b Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Sun, 5 Mar 2023 14:46:00 -0500 Subject: [PATCH 07/16] reconcile changeS --- docs/src/extend/custom-rules.md | 66 ++++++++++++++++---------------- docs/src/use/migrate-to-8.0.0.md | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index c3d6da12066..521b54e92bd 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -38,9 +38,9 @@ module.exports = { The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format. -`meta` (object) Contains metadata for the rule: +`meta`: (object) Contains metadata for the rule: -* `type`: (string) indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: +* `type`: (string) Indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: * `"problem"`: The rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve. * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. @@ -66,7 +66,7 @@ The source file for a rule exports an object with the following properties. Both * `replacedBy`: (array) In the case of a deprecated rule, specify replacement rule(s). -`create`: (function) Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: +`create()`: Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: * If a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree. * If a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree. @@ -123,12 +123,11 @@ As the name implies, the `context` object contains information that is relevant The `context` object has the following properties: -* `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). -* `id`: The rule ID. -* `options`: An array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). -* `settings`: The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. -* `parserPath`: The name of the `parser` from the configuration. -* `parserServices`: An object containing 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.) +* `id`: (string) The rule ID. +* `options`: (array) An array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). +* `settings`: (object) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. +* `parserPath`: (string) The name of the `parser` from 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.) Additionally, the `context` object has the following methods: @@ -206,17 +205,17 @@ For examples of using `context.getScope()` to track variables, refer to the sour The main method you'll use when writing custom rules is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties: -* `message`: The problem message. -* `node`: (optional) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. -* `loc`: (optional) An object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. +* `message`: (string) The problem message. +* `node`: (optional object) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. +* `loc`: (optional object) Specifies the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. * `start`: An object of the start location. - * `line`: The 1-based line number at which the problem occurred. - * `column` The 0-based column number at which the problem occurred. + * `line`: (number) The 1-based line number at which the problem occurred. + * `column` (number) The 0-based column number at which the problem occurred. * `end`: An object of the end location. - * `line`: The 1-based line number at which the problem occurred. - * `column`: The 0-based column number at which the problem occurred. -* `data`:(optional) [Placeholder](#using-message-placeholders) data for `message`. -* `fix`: (optional) A function that applies a [fix](#applying-fixes) to resolve the problem. + * `line`: (number) The 1-based line number at which the problem occurred. + * `column`: (number) The 0-based column number at which the problem occurred. +* `data`:(optional object) [Placeholder](#using-message-placeholders) data for `message`. +* `fix(fixer)`: (optional function) Applies a [fix](#applying-fixes) to resolve the problem. Note that at least one of `node` or `loc` is required. @@ -325,7 +324,7 @@ If you'd like ESLint to attempt to fix the problem you're reporting, you can do context.report({ node: node, message: "Missing semicolon", - fix: function(fixer) { + fix(fixer) { return fixer.insertTextAfter(node, ";"); } }); @@ -588,28 +587,28 @@ Once you have an instance of `SourceCode`, you can use the following methods on `skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`. -* `skip`: Positive integer, the number of skipping tokens. If the `filter` option is given at the same time, it doesn't count filtered tokens as skipped. -* `includeComments`: Boolean, the flag to include comment tokens into the result. -* `filter`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. +* `skip`: (number) Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. +* `includeComments`: (boolean) The flag to include comment tokens into the result. +* `filter(token)`: Function which gets a token as the first argument. If the function returns `false` then the result excludes the token. `countOptions` is an object which has 3 properties; `count`, `includeComments`, and `filter`. Default is `{count: 0, includeComments: false, filter: null}`. -* `count`: Positive integer, the maximum number of returning tokens. -* `includeComments`: Boolean, the flag to include comment tokens into the result. -* `filter` Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. +* `count`: (number) Positive integer, the maximum number of returning tokens. +* `includeComments`: (boolean) The flag to include comment tokens into the result. +* `filter(token)`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. -`rangeOptions` is an object which has 1 property: `includeComments`. +`rangeOptions`: (object) Has 1 property: `includeComments`. -* `includeComments`: Boolean, the flag to include comment tokens into the result. +* `includeComments`: (boolean) The flag to include comment tokens into the result. There are also some properties you can access: -* `hasBOM`: The flag to indicate whether the source code has Unicode BOM. -* `text`: The full text of the code being linted. Unicode BOM has been stripped from this text. -* `ast`: `Program` node of the AST for the code being linted. +* `hasBOM`: (boolean) The flag to indicate whether the source code has Unicode BOM. +* `text`: (string) The full text of the code being linted. Unicode BOM has been stripped from this text. +* `ast`: (object) `Program` node of the AST for the code being linted. * `scopeManager`: [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code. -* `visitorKeys`: Visitor keys to traverse this AST. -* `lines`: Array of lines, split according to the specification's definition of line breaks. +* `visitorKeys`: (object) Visitor keys to traverse this AST. +* `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. @@ -701,7 +700,8 @@ Please note that the following `context` methods have been deprecated and will b * `getTokenOrCommentBefore()`: Replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option. * `getTokenOrCommentAfter()`: Replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option. * `isSpaceBetweenTokens()`: Replaced by `SourceCode#isSpaceBetween()` -* `getJSDocComment()`. +* `getJSDocComment()` +* `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). ## Rule Unit Tests diff --git a/docs/src/use/migrate-to-8.0.0.md b/docs/src/use/migrate-to-8.0.0.md index 71d92c52087..2eaa942b91b 100644 --- a/docs/src/use/migrate-to-8.0.0.md +++ b/docs/src/use/migrate-to-8.0.0.md @@ -178,7 +178,7 @@ Back in ESLint v4.0.0, we deprecated `SourceCode#getComments()`, but we neglecte The `SourceCode#getComments()` method will be removed in v9.0.0. -**To address:** If your rule uses `SourceCode#getComments()`, please use [`SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, or `SourceCode#getCommentsInside()`](../extend/custom-rules#sourcecodegetcommentsbefore-sourcecodegetcommentsafter-and-sourcecodegetcommentsinside). +**To address:** If your rule uses `SourceCode#getComments()`, please use [`SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, or `SourceCode#getCommentsInside()`](../extend/custom-rules#accessing-comments). **Related issue(s):** [#14744](https://github.com/eslint/eslint/issues/14744) From aba4e505c6cba8234eebbed84b5fffcf4fc8ee6b Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:38:21 -0500 Subject: [PATCH 08/16] Apply suggestions from code review Co-authored-by: Nitin Kumar --- docs/src/extend/custom-rules.md | 2 +- docs/src/use/migrating-to-5.0.0.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 521b54e92bd..1a3a60471f6 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -145,7 +145,7 @@ Additionally, the `context` object has the following methods: * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: Returns the filename associated with the source. * `getPhysicalFilename()`: When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()`: Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-scope-of-a-node)). +* `getScope()`: Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-the-scope-of-a-node)). * `getSourceCode()`: Returns 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)). * `markVariableAsUsed(name)`: Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. * `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)). diff --git a/docs/src/use/migrating-to-5.0.0.md b/docs/src/use/migrating-to-5.0.0.md index d5507b3a711..1f65fe5cfe1 100644 --- a/docs/src/use/migrating-to-5.0.0.md +++ b/docs/src/use/migrating-to-5.0.0.md @@ -221,7 +221,7 @@ Previously, the `context.getScope()` method changed its behavior based on the `p Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes. -In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/custom-rules#accessing-scope-of-a-node) for more details on which scopes are returned. +In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/custom-rules#accessing-the-scope-of-a-node) for more details on which scopes are returned. **To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information. From 19cb887e92b79ace96dff704a7485e44fe015fcc Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Thu, 9 Mar 2023 20:44:38 -0500 Subject: [PATCH 09/16] Apply suggestions from code review --- docs/src/extend/custom-rules.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 1a3a60471f6..47feb3a4db0 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -235,6 +235,7 @@ The node contains all the information necessary to figure out the line and colum You can also use placeholders in the message and provide `data`: ```js +{% raw %} context.report({ node: node, message: "Unexpected identifier: {{ identifier }}", @@ -242,6 +243,7 @@ context.report({ identifier: node.name } }); +{% endraw %} ``` Note that leading and trailing whitespace is optional in message parameters. @@ -257,6 +259,7 @@ This allows you to avoid retyping error messages. It also prevents errors report Rule file: ```js +{% raw %} // avoid-name.js module.exports = { @@ -281,6 +284,7 @@ module.exports = { }; } }; +{% endraw %} ``` In the file to lint: @@ -411,6 +415,7 @@ In some cases fixes aren't appropriate to be automatically applied, for example, To provide suggestions, use the `suggest` key in the report argument with an array of suggestion objects. The suggestion objects represent individual suggestions that could be applied and require either a `desc` key string that describes what applying the suggestion would do or a `messageId` key (see [below](#suggestion-messageids)), and a `fix` key that is a function defining the suggestion result. This `fix` function follows the same API as regular fixes (described above in [applying fixes](#applying-fixes)). ```js +{% raw %} context.report({ node: node, message: "Unnecessary escape character: \\{{character}}.", @@ -430,6 +435,7 @@ context.report({ } ] }); +{% endraw %} ``` **Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-structure) this property. @@ -448,6 +454,7 @@ Suggestions are intended to provide fixes. ESLint will automatically remove the Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use a suggestion `messageId` in a rule: ```js +{% raw %} module.exports = { meta: { messages: { @@ -480,6 +487,7 @@ module.exports = { }); } }; +{% endraw %} ``` #### Placeholders in Suggestion Messages @@ -489,6 +497,7 @@ You can also use placeholders in the suggestion message. This works the same way Please note that you have to provide `data` on the suggestion's object. Suggestion messages cannot use properties from the overall error's `data`. ```js +{% raw %} module.exports = { meta: { messages: { @@ -515,6 +524,7 @@ module.exports = { }); } }; +{% endraw %} ``` ### Accessing Options Passed to a Rule From da74fdd02b565e0a23276ed37c3edd6cac87919a Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Thu, 9 Mar 2023 21:01:38 -0500 Subject: [PATCH 10/16] fix broken inline links --- docs/src/extend/custom-rules.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 47feb3a4db0..f2a28c56be7 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -60,7 +60,7 @@ The source file for a rule exports an object with the following properties. Both **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. -* `schema`: (array) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules). +* `schema`: (array) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules). * `deprecated`: (boolean) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. @@ -124,7 +124,7 @@ As the name implies, the `context` object contains information that is relevant The `context` object has the following properties: * `id`: (string) The rule ID. -* `options`: (array) An array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). +* `options`: (array) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). * `settings`: (object) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. * `parserPath`: (string) The name of the `parser` from 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.) @@ -569,7 +569,7 @@ module.exports = { Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code: -* `getText(node)`: Return the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#getting-the-source-text)). +* `getText(node)`: Return the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)). * `getAllComments()`: Return an array of all comments in the source. * `getCommentsBefore(nodeOrToken)`: Return an array of comment tokens that occur directly before the given node or token. * `getCommentsAfter(nodeOrToken)`: Return an array of comment tokens that occur directly after the given node or token. From fe7b1cf6573ccdb5438d060c47a9474e319233b5 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Sat, 11 Mar 2023 15:27:42 -0500 Subject: [PATCH 11/16] highlighting for types --- docs/src/extend/custom-rules.md | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index f2a28c56be7..184eeed9e91 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -38,33 +38,33 @@ module.exports = { The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format. -`meta`: (object) Contains metadata for the rule: +`meta`: (`object`) Contains metadata for the rule: -* `type`: (string) Indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: +* `type`: (`string`) Indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`: * `"problem"`: The rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve. * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed. * `"layout"`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST. -* `docs`: (object) Required for core rules and optional for custom rules. Core rules have specific entries inside of `docs` while custom rules can include any properties that you need. The following properties are only relevant when working on core rules. +* `docs`: (`object`) Required for core rules and optional for custom rules. Core rules have specific entries inside of `docs` while custom rules can include any properties that you need. The following properties are only relevant when working on core rules. - * `description`: (string) Provides the short description of the rule in the [rules index](../rules/). - * `recommended`: (boolean) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. - * `url`: (string) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations). + * `description`: (`string`) Provides the short description of the rule in the [rules index](../rules/). + * `recommended`: (`boolean`) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. + * `url`: (`string`) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations). -* `fixable`: (string) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. +* `fixable`: (`string`) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable. -* `hasSuggestions`: (boolean) Specifies whether rules can return suggestions (defaults to `false` if omitted). +* `hasSuggestions`: (`boolean`) Specifies whether rules can return suggestions (defaults to `false` if omitted). **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. * `schema`: (array) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules). -* `deprecated`: (boolean) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. +* `deprecated`: (`boolean`) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. -* `replacedBy`: (array) In the case of a deprecated rule, specify replacement rule(s). +* `replacedBy`: (`array`) In the case of a deprecated rule, specify replacement rule(s). `create()`: Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code: @@ -123,11 +123,11 @@ As the name implies, the `context` object contains information that is relevant The `context` object has the following properties: -* `id`: (string) The rule ID. -* `options`: (array) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). -* `settings`: (object) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. -* `parserPath`: (string) The name of the `parser` from 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.) +* `id`: (`string`) The rule ID. +* `options`: (`array`) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). +* `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. +* `parserPath`: (`string`) The name of the `parser` from 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.) Additionally, the `context` object has the following methods: @@ -205,17 +205,17 @@ For examples of using `context.getScope()` to track variables, refer to the sour The main method you'll use when writing custom rules is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties: -* `message`: (string) The problem message. -* `node`: (optional object) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. -* `loc`: (optional object) Specifies the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. +* `message`: (`string`) The problem message. +* `node`: (optional `object`) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem. +* `loc`: (optional `object`) Specifies the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. * `start`: An object of the start location. - * `line`: (number) The 1-based line number at which the problem occurred. - * `column` (number) The 0-based column number at which the problem occurred. + * `line`: (`number`) The 1-based line number at which the problem occurred. + * `column` (`number`) The 0-based column number at which the problem occurred. * `end`: An object of the end location. - * `line`: (number) The 1-based line number at which the problem occurred. - * `column`: (number) The 0-based column number at which the problem occurred. -* `data`:(optional object) [Placeholder](#using-message-placeholders) data for `message`. -* `fix(fixer)`: (optional function) Applies a [fix](#applying-fixes) to resolve the problem. + * `line`: (`number`) The 1-based line number at which the problem occurred. + * `column`: (`number`) The 0-based column number at which the problem occurred. +* `data`:(optional `object`) [Placeholder](#using-message-placeholders) data for `message`. +* `fix(fixer)`: (optional `function`) Applies a [fix](#applying-fixes) to resolve the problem. Note that at least one of `node` or `loc` is required. @@ -597,28 +597,28 @@ Once you have an instance of `SourceCode`, you can use the following methods on `skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`. -* `skip`: (number) Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. -* `includeComments`: (boolean) The flag to include comment tokens into the result. +* `skip`: (`number`) Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped. +* `includeComments`: (`boolean`) The flag to include comment tokens into the result. * `filter(token)`: Function which gets a token as the first argument. If the function returns `false` then the result excludes the token. `countOptions` is an object which has 3 properties; `count`, `includeComments`, and `filter`. Default is `{count: 0, includeComments: false, filter: null}`. -* `count`: (number) Positive integer, the maximum number of returning tokens. -* `includeComments`: (boolean) The flag to include comment tokens into the result. +* `count`: (`number`) Positive integer, the maximum number of returning tokens. +* `includeComments`: (`boolean`) The flag to include comment tokens into the result. * `filter(token)`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. `rangeOptions`: (object) Has 1 property: `includeComments`. -* `includeComments`: (boolean) The flag to include comment tokens into the result. +* `includeComments`: (`boolean`) The flag to include comment tokens into the result. There are also some properties you can access: -* `hasBOM`: (boolean) The flag to indicate whether the source code has Unicode BOM. -* `text`: (string) The full text of the code being linted. Unicode BOM has been stripped from this text. -* `ast`: (object) `Program` node of the AST for the code being linted. +* `hasBOM`: (`boolean`) The flag to indicate whether the source code has Unicode BOM. +* `text`: (`string`) The full text of the code being linted. Unicode BOM has been stripped from this text. +* `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. -* `lines`: (array) Array of lines, split according to the specification's definition of line breaks. +* `visitorKeys`: (`object`) Visitor keys to traverse this AST. +* `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. From 4d8cac8e94da8e87052fb690abd06fe0e368a6bf Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Tue, 14 Mar 2023 20:29:24 -0400 Subject: [PATCH 12/16] Apply suggestions from code review Co-authored-by: Milos Djermanovic Co-authored-by: Nitin Kumar --- docs/src/extend/custom-rules.md | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 184eeed9e91..7edf842a34f 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -49,7 +49,7 @@ The source file for a rule exports an object with the following properties. Both * `docs`: (`object`) Required for core rules and optional for custom rules. Core rules have specific entries inside of `docs` while custom rules can include any properties that you need. The following properties are only relevant when working on core rules. * `description`: (`string`) Provides the short description of the rule in the [rules index](../rules/). - * `recommended`: (`boolean`) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. + * `recommended`: (`boolean`) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule. * `url`: (`string`) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations). * `fixable`: (`string`) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule. @@ -60,7 +60,7 @@ The source file for a rule exports an object with the following properties. Both **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions. -* `schema`: (array) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules). +* `schema`: (`object | array`) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules). * `deprecated`: (`boolean`) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated. @@ -125,14 +125,14 @@ The `context` object has the following properties: * `id`: (`string`) The rule ID. * `options`: (`array`) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)). -* `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration. -* `parserPath`: (`string`) The name of the `parser` from configuration. +* `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.) Additionally, the `context` object has the following methods: * `getAncestors()`: Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself. -* `getCwd()`: Returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory. +* `getCwd()`: Returns the `cwd` option passed to the [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory. * `getDeclaredVariables(node)`: Returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables. * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned. * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned. @@ -210,11 +210,11 @@ The main method you'll use when writing custom rules is `context.report()`, whic * `loc`: (optional `object`) Specifies the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`. * `start`: An object of the start location. * `line`: (`number`) The 1-based line number at which the problem occurred. - * `column` (`number`) The 0-based column number at which the problem occurred. + * `column`: (`number`) The 0-based column number at which the problem occurred. * `end`: An object of the end location. * `line`: (`number`) The 1-based line number at which the problem occurred. * `column`: (`number`) The 0-based column number at which the problem occurred. -* `data`:(optional `object`) [Placeholder](#using-message-placeholders) data for `message`. +* `data`: (optional `object`) [Placeholder](#using-message-placeholders) data for `message`. * `fix(fixer)`: (optional `function`) Applies a [fix](#applying-fixes) to resolve the problem. Note that at least one of `node` or `loc` is required. @@ -301,7 +301,7 @@ In your tests: ```javascript // avoid-name.test.js -var rule = require("../../../lib/rules/my-rule"); +var rule = require("../../../lib/rules/avoid-name"); var RuleTester = require("eslint").RuleTester; var ruleTester = new RuleTester(); @@ -569,31 +569,31 @@ module.exports = { Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code: -* `getText(node)`: Return the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)). -* `getAllComments()`: Return an array of all comments in the source. -* `getCommentsBefore(nodeOrToken)`: Return an array of comment tokens that occur directly before the given node or token. -* `getCommentsAfter(nodeOrToken)`: Return an array of comment tokens that occur directly after the given node or token. -* `getCommentsInside(node)`: Return an array of all comment tokens inside a given node. -* `isSpaceBetween(nodeOrToken, nodeOrToken)`: Return true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node. -* `getFirstToken(node, skipOptions)`: Return the first token representing the given node. -* `getFirstTokens(node, countOptions)`: Return the first `count` tokens representing the given node. -* `getLastToken(node, skipOptions)`: Return the last token representing the given node. -* `getLastTokens(node, countOptions)`: Return the last `count` tokens representing the given node. -* `getTokenAfter(nodeOrToken, skipOptions)`: Return the first token after the given node or token. -* `getTokensAfter(nodeOrToken, countOptions)`: Return `count` tokens after the given node or token. -* `getTokenBefore(nodeOrToken, skipOptions)`: Return the first token before the given node or token. -* `getTokensBefore(nodeOrToken, countOptions)`: Return `count` tokens before the given node or token. -* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Return the first token between two nodes or tokens. -* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Return the first `count` tokens between two nodes or tokens. -* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Return the last token between two nodes or tokens. -* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Return the last `count` tokens between two nodes or tokens. -* `getTokens(node)`: Return all tokens for the given node. -* `getTokensBetween(nodeOrToken1, nodeOrToken2)`: Return all tokens between two nodes. -* `getTokenByRangeStart(index, rangeOptions)`: Return the token whose range starts at the given index in the source. -* `getNodeByRangeIndex(index)`: Return the deepest node in the AST containing the given source index. -* `getLocFromIndex(index)`: Return an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based. -* `getIndexFromLoc(loc)`: Return the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key. -* `commentsExistBetween(nodeOrToken1, nodeOrToken2)`: Return `true` if comments exist between two nodes. +* `getText(node)`: Returns the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)). +* `getAllComments()`: Returns an array of all comments in the source. +* `getCommentsBefore(nodeOrToken)`: Returns an array of comment tokens that occur directly before the given node or token. +* `getCommentsAfter(nodeOrToken)`: Returns an array of comment tokens that occur directly after the given node or token. +* `getCommentsInside(node)`: Returns an array of all comment tokens inside a given node. +* `isSpaceBetween(nodeOrToken, nodeOrToken)`: Returns true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node. +* `getFirstToken(node, skipOptions)`: Returns the first token representing the given node. +* `getFirstTokens(node, countOptions)`: Returns the first `count` tokens representing the given node. +* `getLastToken(node, skipOptions)`: Returns the last token representing the given node. +* `getLastTokens(node, countOptions)`: Returns the last `count` tokens representing the given node. +* `getTokenAfter(nodeOrToken, skipOptions)`: Returns the first token after the given node or token. +* `getTokensAfter(nodeOrToken, countOptions)`: Returns `count` tokens after the given node or token. +* `getTokenBefore(nodeOrToken, skipOptions)`: Returns the first token before the given node or token. +* `getTokensBefore(nodeOrToken, countOptions)`: Returns `count` tokens before the given node or token. +* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Returns the first token between two nodes or tokens. +* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Returns the first `count` tokens between two nodes or tokens. +* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Returns the last token between two nodes or tokens. +* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Returns the last `count` tokens between two nodes or tokens. +* `getTokens(node)`: Returns all tokens for the given node. +* `getTokensBetween(nodeOrToken1, nodeOrToken2)`: Returns all tokens between two nodes. +* `getTokenByRangeStart(index, rangeOptions)`: Returns the token whose range starts at the given index in the source. +* `getNodeByRangeIndex(index)`: Returns the deepest node in the AST containing the given source index. +* `getLocFromIndex(index)`: Returns an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based. +* `getIndexFromLoc(loc)`: Returns the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key. +* `commentsExistBetween(nodeOrToken1, nodeOrToken2)`: Returns `true` if comments exist between two nodes. `skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`. @@ -607,7 +607,7 @@ Once you have an instance of `SourceCode`, you can use the following methods on * `includeComments`: (`boolean`) The flag to include comment tokens into the result. * `filter(token)`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token. -`rangeOptions`: (object) Has 1 property: `includeComments`. +`rangeOptions` is an object that has 1 property, `includeComments`. Default is `{includeComments: false}`. * `includeComments`: (`boolean`) The flag to include comment tokens into the result. From e74487320b6bf4ed5108cf2bdbfe4ea7e379599c Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Mon, 20 Mar 2023 21:47:22 -0400 Subject: [PATCH 13/16] implement MD feedback --- docs/src/extend/custom-rules.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 7edf842a34f..5814923f5a6 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -570,10 +570,10 @@ module.exports = { Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code: * `getText(node)`: Returns the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)). -* `getAllComments()`: Returns an array of all comments in the source. -* `getCommentsBefore(nodeOrToken)`: Returns an array of comment tokens that occur directly before the given node or token. -* `getCommentsAfter(nodeOrToken)`: Returns an array of comment tokens that occur directly after the given node or token. -* `getCommentsInside(node)`: Returns an array of all comment tokens inside a given node. +* `getAllComments()`: Returns an array of all comments in the source (see the [dedicated section](#accessing-comments)). +* `getCommentsBefore(nodeOrToken)`: Returns an array of comment tokens that occur directly before the given node or token (see the [dedicated section](#accessing-comments)). +* `getCommentsAfter(nodeOrToken)`: Returns an array of comment tokens that occur directly after the given node or token (see the [dedicated section](#accessing-comments)). +* `getCommentsInside(node)`: Returns an array of all comment tokens inside a given node (see the [dedicated section](#accessing-comments)). * `isSpaceBetween(nodeOrToken, nodeOrToken)`: Returns true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node. * `getFirstToken(node, skipOptions)`: Returns the first token representing the given node. * `getFirstTokens(node, countOptions)`: Returns the first `count` tokens representing the given node. @@ -645,12 +645,7 @@ In this way, you can look for patterns in the JavaScript text itself when the AS #### Accessing Comments -While comments are not technically part of the AST, ESLint provides a few ways for rules to access them: - -* `sourceCode.getAllComments()`: Return an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location. -* `sourceCode.getCommentsBefore()`: Return an array of comments that appear directly before nodes. -* `sourceCode.getCommentsAfter()`: Return an array of comments that appear directly after nodes. -* `sourceCode.getCommentsInside()` Return an array of comments that appear inside nodes. +While comments are not technically part of the AST, ESLint provides the `sourceCode.getAllComments()`, `sourceCode.getCommentsBefore()`, `sourceCode.getCommentsAfter()`, and `sourceCode.getCommentsInside()` to access them. `sourceCode.getCommentsBefore()`, `sourceCode.getCommentsAfter()`, and `sourceCode.getCommentsInside()` are useful for rules that need to check comments in relation to a given node or token. @@ -702,9 +697,9 @@ To learn more about JSON Schema, we recommend looking at some examples in [websi ESLint analyzes code paths while traversing AST. You can access code path objects with five events related to code paths. For more information, refer to [Code Path Analysis](code-path-analysis). -### Deprecated `context` Methods +### Deprecated `SourceCode` Methods -Please note that the following `context` methods have been deprecated and will be removed in a future version of ESLint: +Please note that the following `SourceCode` methods have been deprecated and will be removed in a future version of ESLint: * `getComments()`: Replaced by `SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, and `SourceCode#getCommentsInside()`. * `getTokenOrCommentBefore()`: Replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option. From e2926aaa763ee9df7afee1a48f63e366fbfac8ab Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Thu, 6 Apr 2023 21:37:11 -0400 Subject: [PATCH 14/16] Apply suggestions from code review Co-authored-by: Nicholas C. Zakas --- docs/src/extend/custom-rules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index b1e0c7acabf..94c9648d02c 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -128,6 +128,7 @@ The `context` object has the following properties: * `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.) +* `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: @@ -145,7 +146,7 @@ Additionally, the `context` object has the following methods: * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: Returns the filename associated with the source. * `getPhysicalFilename()`: When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()`: (**Deprecated: Use `SourceCode.getScope(node)` instead.**) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-the-scope-of-a-node)). +* `getScope()`: (**Deprecated:** Use `SourceCode.getScope(node)` instead.) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-the-scope-of-a-node)). * `getSourceCode()`: Returns 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)). * `markVariableAsUsed(name)`: Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. * `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)). @@ -757,7 +758,6 @@ Please note that the following `SourceCode` methods have been deprecated and wil * `getTokenOrCommentAfter()`: Replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option. * `isSpaceBetweenTokens()`: Replaced by `SourceCode#isSpaceBetween()` * `getJSDocComment()` -* `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)). ## Rule Unit Tests From 03d8b7cd5851e4565a9a802f4cdcb7c7ef75b7cf Mon Sep 17 00:00:00 2001 From: Ben Perlmutter Date: Thu, 6 Apr 2023 21:48:12 -0400 Subject: [PATCH 15/16] implement MD feedback --- docs/src/extend/custom-rules.md | 65 ++++-------------------------- docs/src/use/migrating-to-5.0.0.md | 2 +- 2 files changed, 9 insertions(+), 58 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index 94c9648d02c..d887558fe9b 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -146,62 +146,13 @@ Additionally, the `context` object has the following methods: * Otherwise, if the node does not declare any variables, an empty array is returned. * `getFilename()`: Returns the filename associated with the source. * `getPhysicalFilename()`: When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `` if not specified. -* `getScope()`: (**Deprecated:** Use `SourceCode.getScope(node)` instead.) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables (see [Accessing the Scope of a Node](#accessing-the-scope-of-a-node)). +* `getScope()`: (**Deprecated:** Use `SourceCode.getScope(node)` instead.) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables. * `getSourceCode()`: Returns 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)). * `markVariableAsUsed(name)`: Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`. * `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)). **Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon. -### Accessing the Scope of a Node - -The `context.getScope()` method returns the scope of the current node. It is a useful method for finding information about the variables in a given scope, and how they are used in other scopes. - -#### Scope Types - -The following table contains a list of AST node types and the scope type that they correspond to. For more information about the scope types, refer to the [`Scope` object documentation](./scope-manager-interface#scope-interface). - -| AST Node Type | Scope Type | -|:--------------------------|:-----------| -| `Program` | `global` | -| `FunctionDeclaration` | `function` | -| `FunctionExpression` | `function` | -| `ArrowFunctionExpression` | `function` | -| `ClassDeclaration` | `class` | -| `ClassExpression` | `class` | -| `BlockStatement` ※1 | `block` | -| `SwitchStatement` ※1 | `switch` | -| `ForStatement` ※2 | `for` | -| `ForInStatement` ※2 | `for` | -| `ForOfStatement` ※2 | `for` | -| `WithStatement` | `with` | -| `CatchClause` | `catch` | -| others | ※3 | - -**※1** Only if the configured parser provided the block-scope feature. The default parser provides the block-scope feature if `parserOptions.ecmaVersion` is not less than `6`.
-**※2** Only if the `for` statement defines the iteration variable as a block-scoped variable (E.g., `for (let i = 0;;) {}`).
-**※3** The scope of the closest ancestor node which has own scope. If the closest ancestor node has multiple scopes then it chooses the innermost scope (E.g., the `Program` node has a `global` scope and a `module` scope if `Program#sourceType` is `"module"`. The innermost scope is the `module` scope.). - -#### Scope Variables - -The `Scope#variables` property contains an array of [`Variable` objects](./scope-manager-interface#variable-interface). These are the variables declared in current scope. You can use these `Variable` objects to track references to a variable throughout the entire module. - -Inside of each `Variable`, the `Variable#references` property contains an array of [`Reference` objects](./scope-manager-interface#reference-interface). The `Reference` array contains all the locations where the variable is referenced in the module's source code. - -Also inside of each `Variable`, the `Variable#defs` property contains an array of [`Definition` objects](./scope-manager-interface#definition-interface). You can use the `Definitions` to find where the variable was defined. - -Global variables have the following additional properties: - -* `Variable#writeable`: (`boolean | undefined`) If `true`, this global variable can be assigned an arbitrary value. If `false`, this global variable is read-only. -* `Variable#eslintExplicitGlobal`: (`boolean | undefined`) If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file. -* `Variable#eslintExplicitGlobalComments`: (`Comment[] | undefined`) The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments. -* `Variable#eslintImplicitGlobalSetting`: (`"readonly" | "writable" | undefined`) The configured value in config files. This can differ from `variable.writeable` if there are `/* globals */` directive comments. - -For examples of using `context.getScope()` to track variables, refer to the source code for the following built-in rules: - -* [no-shadow](https://github.com/eslint/eslint/blob/main/lib/rules/no-shadow.js): Calls `context.getScopes()` at the global scope and parses all child scopes to make sure a variable name is not reused at a lower scope. ([no-shadow](../rules/no-shadow) documentation) -* [no-redeclare](https://github.com/eslint/eslint/blob/main/lib/rules/no-redeclare.js): Calls `context.getScope()` at each scope to make sure that a variable is not declared twice at that scope. ([no-redeclare](../rules/no-redeclare) documentation) - ### Reporting Problems The main method you'll use when writing custom rules is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties: @@ -370,17 +321,17 @@ Best practices for fixes: * For example, suppose a fixer would like to surround an object key with quotes, but it's not sure whether the user would prefer single or double quotes. - ```js - ({ foo : 1 }) + ```js + ({ foo : 1 }) - // should get fixed to either + // should get fixed to either - ({ 'foo': 1 }) + ({ 'foo': 1 }) - // or + // or - ({ "foo": 1 }) - ``` + ({ "foo": 1 }) + ``` * This fixer can just select a quote type arbitrarily. If it guesses wrong, the resulting code will be automatically reported and fixed by the [`quotes`](../rules/quotes) rule. diff --git a/docs/src/use/migrating-to-5.0.0.md b/docs/src/use/migrating-to-5.0.0.md index 1f65fe5cfe1..96c54ec5dee 100644 --- a/docs/src/use/migrating-to-5.0.0.md +++ b/docs/src/use/migrating-to-5.0.0.md @@ -221,7 +221,7 @@ Previously, the `context.getScope()` method changed its behavior based on the `p Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes. -In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/custom-rules#accessing-the-scope-of-a-node) for more details on which scopes are returned. +In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/scope-manager-interface) for more details on which scopes are returned. **To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information. From 6a4fa11d03d08860fe1751db991ed254d6e14036 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 20 Apr 2023 11:31:37 -0700 Subject: [PATCH 16/16] Update docs/src/extend/custom-rules.md Co-authored-by: Nitin Kumar --- docs/src/extend/custom-rules.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/src/extend/custom-rules.md b/docs/src/extend/custom-rules.md index d887558fe9b..165b0695aff 100644 --- a/docs/src/extend/custom-rules.md +++ b/docs/src/extend/custom-rules.md @@ -293,13 +293,13 @@ Here, the `fix()` function is used to insert a semicolon after the node. Note th The `fixer` object has the following methods: * `insertTextAfter(nodeOrToken, text)`: Insert text after the given node or token. -* `insertTextAfterRange(range, text)`: Insert text after the given range -* `insertTextBefore(nodeOrToken, text)`: Insert text before the given node or token -* `insertTextBeforeRange(range, text)`: Insert text before the given range -* `remove(nodeOrToken)`: Remove the given node or token -* `removeRange(range)`: Remove text in the given range -* `replaceText(nodeOrToken, text)`: Replace the text in the given node or token -* `replaceTextRange(range, text)`: Replace the text in the given range +* `insertTextAfterRange(range, text)`: Insert text after the given range. +* `insertTextBefore(nodeOrToken, text)`: Insert text before the given node or token. +* `insertTextBeforeRange(range, text)`: Insert text before the given range. +* `remove(nodeOrToken)`: Remove the given node or token. +* `removeRange(range)`: Remove text in the given range. +* `replaceText(nodeOrToken, text)`: Replace the text in the given node or token. +* `replaceTextRange(range, text)`: Replace the text in the given range. A `range` is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent.