From f62a75f528f5a9ed885c56c373d641b41ae83f7c Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Fri, 10 Jun 2022 19:23:17 +0530 Subject: [PATCH 1/4] feat: account for rule creation time in performance reports --- lib/linter/linter.js | 2 +- lib/linter/timing.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 5304a612a59..bd1bbb7ca82 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -1101,7 +1101,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO ) ); - const ruleListeners = createRuleListeners(rule, ruleContext); + const ruleListeners = timing.enabled ? timing.time(ruleId, createRuleListeners)(rule, ruleContext) : createRuleListeners(rule, ruleContext); /** * Include `ruleId` in error logs diff --git a/lib/linter/timing.js b/lib/linter/timing.js index c9ab01ec649..914cbf05591 100644 --- a/lib/linter/timing.js +++ b/lib/linter/timing.js @@ -138,10 +138,11 @@ module.exports = (function() { return function(...args) { let t = process.hrtime(); + const result = fn(...args); - fn(...args); t = process.hrtime(t); data[key] += t[0] * 1e3 + t[1] / 1e6; + return result; }; } From 560b2807ff1288167fe89d95713a6e9e1c405498 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sat, 11 Jun 2022 06:48:48 +0530 Subject: [PATCH 2/4] docs: update info about per-rule performance --- .../src/developer-guide/working-with-rules.md | 312 +++++++++--------- 1 file changed, 156 insertions(+), 156 deletions(-) diff --git a/docs/src/developer-guide/working-with-rules.md b/docs/src/developer-guide/working-with-rules.md index d13e921daa8..e5c2fe14187 100644 --- a/docs/src/developer-guide/working-with-rules.md +++ b/docs/src/developer-guide/working-with-rules.md @@ -7,16 +7,15 @@ eleventyNavigation: parent: developer guide title: Working with Rules order: 4 - --- **Note:** This page covers the most recent rule format for ESLint >= 3.0.0. There is also a [deprecated rule format](./working-with-rules-deprecated). Each rule in ESLint has three files named with its identifier (for example, `no-extra-semi`). -* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`) -* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`) -* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`) +* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`) +* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`) +* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`) **Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below. @@ -43,16 +42,16 @@ module.exports = { description: "disallow unnecessary semicolons", category: "Possible Errors", recommended: true, - url: "https://eslint.org/docs/rules/no-extra-semi" + url: "https://eslint.org/docs/rules/no-extra-semi", }, fixable: "code", - schema: [] // no options + schema: [], // no options }, - create: function(context) { + create: function (context) { return { // callback functions }; - } + }, }; ``` @@ -62,39 +61,40 @@ The source file for a rule exports an object with the following properties. `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. +* `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: - * `description` (string) provides the short description of the rule in the [rules index](../rules/) - * `category` (string) specifies the heading under which the rule is listed in the [rules index](../rules/) - * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring/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/) + * `category` (string) specifies the heading under which the rule is listed in the [rules index](../rules/) + * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring/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](../user-guide/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](../user-guide/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. + **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](../user-guide/configuring/rules#configuring-rules) +* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../user-guide/configuring/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: -* 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. @@ -131,33 +131,33 @@ module.exports = { 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](../user-guide/configuring/language-options#specifying-parser-options)). -* `id` - the rule ID. -* `options` - an array of the [configured options](/docs/user-guide/configuring/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions). -* `settings` - the [shared settings](/docs/user-guide/configuring/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](../user-guide/configuring/language-options#specifying-parser-options)). +* `id` - the rule ID. +* `options` - an array of the [configured options](/docs/user-guide/configuring/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions). +* `settings` - the [shared settings](/docs/user-guide/configuring/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](./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. - * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned. - * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned. - * If the node is a `CatchClause`, the variable for the exception is returned. - * 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. -* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint. -* `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)). +* `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](./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. + * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned. + * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned. + * If the node is a `CatchClause`, the variable for the exception is returned. + * 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. +* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint. +* `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)). **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. @@ -166,21 +166,21 @@ Additionally, the `context` object has the following methods: This method returns the scope which has the following types: | 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` | +| `BlockStatement` ※1 | `block` | +| `SwitchStatement` ※1 | `switch` | +| `ForStatement` ※2 | `for` | +| `ForInStatement` ※2 | `for` | +| `ForOfStatement` ※2 | `for` | | `WithStatement` | `with` | | `CatchClause` | `catch` | -| others | ※3 | +| 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;;) {}`).
@@ -188,26 +188,26 @@ This method returns the scope which has the following types: The returned value is a [`Scope` object](scope-manager-interface) defined by the `eslint-scope` package. The `Variable` objects of global variables have some 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. ### context.report() 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: -* `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. @@ -216,7 +216,7 @@ The simplest example is to use just `node` and `message`: ```js context.report({ node: node, - message: "Unexpected identifier" + message: "Unexpected identifier", }); ``` @@ -308,9 +308,9 @@ 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: function (fixer) { return fixer.insertTextAfter(node, ";"); - } + }, }); ``` @@ -320,23 +320,23 @@ 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)` - 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 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. The above methods return a `fixing` object. The `fix()` function can return the following values: -* A `fixing` object. -* An array which includes `fixing` objects. -* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator. +* A `fixing` object. +* An array which includes `fixing` objects. +* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator. If you make a `fix()` function which returns multiple `fixing` objects, those `fixing` objects must not be overlapped. @@ -346,18 +346,19 @@ 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 }) - - // should get fixed to either + ({ foo: 1 }( + // 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`](/docs/rules/quotes) rule. @@ -376,7 +377,7 @@ context.report({ // extend range of the fix to the range of `node.parent` yield fixer.insertTextBefore(node.parent, ""); yield fixer.insertTextAfter(node.parent, ""); - } + }, }); ``` @@ -513,11 +514,11 @@ The `quotes` rule in this example has one option, `"double"` (the `error` is the ```js module.exports = { - create: function(context) { - var isDouble = (context.options[0] === "double"); + create: function (context) { + var isDouble = context.options[0] === "double"; // ... - } + }, }; ``` @@ -531,66 +532,66 @@ The `SourceCode` object is the main object for getting more information about th ```js module.exports = { - create: function(context) { + create: function (context) { var sourceCode = context.getSourceCode(); // ... - } + }, }; ``` 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)` - 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. `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` 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. `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` 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. `rangeOptions` is an object which has 1 property: `includeComments`. -* `includeComments` is a boolean value, the flag to include comment tokens into the result. +* `includeComments` is a boolean value, 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 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. You should use a `SourceCode` object whenever you need to get more information about the code being linted. @@ -598,11 +599,11 @@ You should use a `SourceCode` object whenever you need to get more information a Please note that the following 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 -* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option -* `isSpaceBetweenTokens()` - replaced by `isSpaceBetween()` -* `getJSDocComment()` +* `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()` ### Options Schemas @@ -618,18 +619,18 @@ module.exports = { meta: { schema: [ { - "enum": ["always", "never"] + enum: ["always", "never"], }, { - "type": "object", - "properties": { - "exceptRange": { - "type": "boolean" - } + type: "object", + properties: { + exceptRange: { + type: "boolean", + }, }, - "additionalProperties": false - } - ] + additionalProperties: false, + }, + ], }, }; ``` @@ -645,7 +646,6 @@ To learn more about JSON Schema, we recommend looking at some examples in [websi 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(); @@ -732,7 +732,7 @@ Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms) ### Per-rule Performance -ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time and relative performance impact as a percentage of total rule processing time. +ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time (rule creation + rule execution) and relative performance impact as a percentage of total rule processing time (rule creation + rule execution). ```bash $ TIMING=1 eslint lib @@ -765,9 +765,9 @@ To see a longer list of results (more than 10), set the environment variable to The rule naming conventions for ESLint are fairly simple: -* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. -* If your rule is enforcing the inclusion of something, use a short name without a special prefix. -* Use dashes between words. +* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. +* If your rule is enforcing the inclusion of something, use a short name without a special prefix. +* Use dashes between words. ## Runtime Rules From d4a8e4db44270ba5b35a83700b429274b3d58499 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Tue, 14 Jun 2022 17:42:53 +0530 Subject: [PATCH 3/4] Revert "docs: update info about per-rule performance" This reverts commit 560b2807ff1288167fe89d95713a6e9e1c405498. --- .../src/developer-guide/working-with-rules.md | 312 +++++++++--------- 1 file changed, 156 insertions(+), 156 deletions(-) diff --git a/docs/src/developer-guide/working-with-rules.md b/docs/src/developer-guide/working-with-rules.md index e5c2fe14187..d13e921daa8 100644 --- a/docs/src/developer-guide/working-with-rules.md +++ b/docs/src/developer-guide/working-with-rules.md @@ -7,15 +7,16 @@ eleventyNavigation: parent: developer guide title: Working with Rules order: 4 + --- **Note:** This page covers the most recent rule format for ESLint >= 3.0.0. There is also a [deprecated rule format](./working-with-rules-deprecated). Each rule in ESLint has three files named with its identifier (for example, `no-extra-semi`). -* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`) -* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`) -* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`) +* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`) +* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`) +* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`) **Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below. @@ -42,16 +43,16 @@ module.exports = { description: "disallow unnecessary semicolons", category: "Possible Errors", recommended: true, - url: "https://eslint.org/docs/rules/no-extra-semi", + url: "https://eslint.org/docs/rules/no-extra-semi" }, fixable: "code", - schema: [], // no options + schema: [] // no options }, - create: function (context) { + create: function(context) { return { // callback functions }; - }, + } }; ``` @@ -61,40 +62,39 @@ The source file for a rule exports an object with the following properties. `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. +* `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: - * `description` (string) provides the short description of the rule in the [rules index](../rules/) - * `category` (string) specifies the heading under which the rule is listed in the [rules index](../rules/) - * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring/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/) + * `category` (string) specifies the heading under which the rule is listed in the [rules index](../rules/) + * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring/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](../user-guide/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](../user-guide/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. + **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](../user-guide/configuring/rules#configuring-rules) +* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../user-guide/configuring/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: -* 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. @@ -131,33 +131,33 @@ module.exports = { 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](../user-guide/configuring/language-options#specifying-parser-options)). -* `id` - the rule ID. -* `options` - an array of the [configured options](/docs/user-guide/configuring/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions). -* `settings` - the [shared settings](/docs/user-guide/configuring/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](../user-guide/configuring/language-options#specifying-parser-options)). +* `id` - the rule ID. +* `options` - an array of the [configured options](/docs/user-guide/configuring/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions). +* `settings` - the [shared settings](/docs/user-guide/configuring/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](./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. - * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned. - * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned. - * If the node is a `CatchClause`, the variable for the exception is returned. - * 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. -* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint. -* `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)). +* `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](./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. + * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned. + * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned. + * If the node is a `CatchClause`, the variable for the exception is returned. + * 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. +* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint. +* `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)). **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. @@ -166,21 +166,21 @@ Additionally, the `context` object has the following methods: This method returns the scope which has the following types: | 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` | +| `BlockStatement` ※1 | `block` | +| `SwitchStatement` ※1 | `switch` | +| `ForStatement` ※2 | `for` | +| `ForInStatement` ※2 | `for` | +| `ForOfStatement` ※2 | `for` | | `WithStatement` | `with` | | `CatchClause` | `catch` | -| others | ※3 | +| 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;;) {}`).
@@ -188,26 +188,26 @@ This method returns the scope which has the following types: The returned value is a [`Scope` object](scope-manager-interface) defined by the `eslint-scope` package. The `Variable` objects of global variables have some 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. ### context.report() 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: -* `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. @@ -216,7 +216,7 @@ The simplest example is to use just `node` and `message`: ```js context.report({ node: node, - message: "Unexpected identifier", + message: "Unexpected identifier" }); ``` @@ -308,9 +308,9 @@ 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: function(fixer) { return fixer.insertTextAfter(node, ";"); - }, + } }); ``` @@ -320,23 +320,23 @@ 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)` - 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 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. The above methods return a `fixing` object. The `fix()` function can return the following values: -* A `fixing` object. -* An array which includes `fixing` objects. -* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator. +* A `fixing` object. +* An array which includes `fixing` objects. +* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator. If you make a `fix()` function which returns multiple `fixing` objects, those `fixing` objects must not be overlapped. @@ -346,19 +346,18 @@ 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 }( - // should get fixed to either + ({ foo : 1 }) + + // should get fixed to either - { foo: 1 } - )( - // or + ({ 'foo': 1 }) - { foo: 1 } - )); + // or + + ({ "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`](/docs/rules/quotes) rule. @@ -377,7 +376,7 @@ context.report({ // extend range of the fix to the range of `node.parent` yield fixer.insertTextBefore(node.parent, ""); yield fixer.insertTextAfter(node.parent, ""); - }, + } }); ``` @@ -514,11 +513,11 @@ The `quotes` rule in this example has one option, `"double"` (the `error` is the ```js module.exports = { - create: function (context) { - var isDouble = context.options[0] === "double"; + create: function(context) { + var isDouble = (context.options[0] === "double"); // ... - }, + } }; ``` @@ -532,66 +531,66 @@ The `SourceCode` object is the main object for getting more information about th ```js module.exports = { - create: function (context) { + create: function(context) { var sourceCode = context.getSourceCode(); // ... - }, + } }; ``` 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)` - 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. `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` 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. `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` 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. `rangeOptions` is an object which has 1 property: `includeComments`. -* `includeComments` is a boolean value, the flag to include comment tokens into the result. +* `includeComments` is a boolean value, 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 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. You should use a `SourceCode` object whenever you need to get more information about the code being linted. @@ -599,11 +598,11 @@ You should use a `SourceCode` object whenever you need to get more information a Please note that the following 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 -* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option -* `isSpaceBetweenTokens()` - replaced by `isSpaceBetween()` -* `getJSDocComment()` +* `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()` ### Options Schemas @@ -619,18 +618,18 @@ module.exports = { meta: { schema: [ { - enum: ["always", "never"], + "enum": ["always", "never"] }, { - type: "object", - properties: { - exceptRange: { - type: "boolean", - }, + "type": "object", + "properties": { + "exceptRange": { + "type": "boolean" + } }, - additionalProperties: false, - }, - ], + "additionalProperties": false + } + ] }, }; ``` @@ -646,6 +645,7 @@ To learn more about JSON Schema, we recommend looking at some examples in [websi 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(); @@ -732,7 +732,7 @@ Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms) ### Per-rule Performance -ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time (rule creation + rule execution) and relative performance impact as a percentage of total rule processing time (rule creation + rule execution). +ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time and relative performance impact as a percentage of total rule processing time. ```bash $ TIMING=1 eslint lib @@ -765,9 +765,9 @@ To see a longer list of results (more than 10), set the environment variable to The rule naming conventions for ESLint are fairly simple: -* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. -* If your rule is enforcing the inclusion of something, use a short name without a special prefix. -* Use dashes between words. +* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`. +* If your rule is enforcing the inclusion of something, use a short name without a special prefix. +* Use dashes between words. ## Runtime Rules From c0c379f2bb1f33dcd3479365d7630493163f4816 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Tue, 14 Jun 2022 17:45:26 +0530 Subject: [PATCH 4/4] docs: update info about per-rule performance --- docs/src/developer-guide/working-with-rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/developer-guide/working-with-rules.md b/docs/src/developer-guide/working-with-rules.md index d13e921daa8..248dc960ca7 100644 --- a/docs/src/developer-guide/working-with-rules.md +++ b/docs/src/developer-guide/working-with-rules.md @@ -732,7 +732,7 @@ Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms) ### Per-rule Performance -ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time and relative performance impact as a percentage of total rule processing time. +ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time (rule creation + rule execution) and relative performance impact as a percentage of total rule processing time (rule creation + rule execution). ```bash $ TIMING=1 eslint lib