From de12b266f2aa6f063d0af888b8f0de41d09ec33f Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Thu, 24 Nov 2022 05:12:05 -0500 Subject: [PATCH 01/29] docs: Update configuration file pages (#16509) * docs: update configuration file pages clean up page copy and add small introductions. Part of fix for https://github.com/eslint/eslint/issues/16473 * copy edits * Apply suggestions from code review Co-authored-by: Strek Co-authored-by: Amaresh S M * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Strek * replace html tag w markdown * Apply suggestions from code review Co-authored-by: Milos Djermanovic * add nz clarification Co-authored-by: Strek Co-authored-by: Amaresh S M Co-authored-by: Milos Djermanovic --- .../configuring/configuration-files-new.md | 32 ++++++++++--------- .../configuring/configuration-files.md | 32 ++++++++++--------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/docs/src/user-guide/configuring/configuration-files-new.md b/docs/src/user-guide/configuring/configuration-files-new.md index 2e90595d4e47..72ddc97d405b 100644 --- a/docs/src/user-guide/configuring/configuration-files-new.md +++ b/docs/src/user-guide/configuring/configuration-files-new.md @@ -9,12 +9,14 @@ eleventyNavigation: --- ::: warning -This is an experimental feature. To opt-in, place a `eslint.config.js` file in the root of your project or set the `ESLINT_USE_FLAT_CONFIG` environment variable to `true`. To opt-out, even in the presence of a `eslint.config.js` file, set the environment variable to `false`. If you are using the API, you can use the configuration system described on this page by using the `FlatESLint` class, the `FlatRuleTester` class, or by setting `configType: "flat"` in the `Linter` class. +This is an experimental feature. To opt-in, place an `eslint.config.js` file in the root of your project or set the `ESLINT_USE_FLAT_CONFIG` environment variable to `true`. To opt-out, even in the presence of an `eslint.config.js` file, set the environment variable to `false`. If you are using the API, you can use the configuration system described on this page by using the `FlatESLint` class, the `FlatRuleTester` class, or by setting `configType: "flat"` in the `Linter` class. ::: +You can put your ESLint project configuration in a configuration file. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more. + ## Configuration File -The ESLint configuration file is named `eslint.config.js` and should be placed in the root directory of your project and export an array of configuration objects. Here's an example: +The ESLint configuration file is named `eslint.config.js`. It should be placed in the root directory of your project and export an array of [configuration objects](#configuration-objects). Here's an example: ```js export default [ @@ -27,7 +29,7 @@ export default [ ] ``` -Here, the configuration array contains just one configuration object. The configuration object enables two rules: `semi` and `prefer-const`. These rules will be applied to all of the files ESLint processes using this config file. +In this example, the configuration array contains just one configuration object. The configuration object enables two rules: `semi` and `prefer-const`. These rules are applied to all of the files ESLint processes using this config file. ## Configuration Objects @@ -55,7 +57,7 @@ Each configuration object contains all of the information ESLint needs to execut Patterns specified in `files` and `ignores` use [`minimatch`](https://www.npmjs.com/package/minimatch) syntax and are evaluated relative to the location of the `eslint.config.js` file. ::: -You can use a combination of `files` and `ignores` to determine which files should apply the configuration object and which should not. By default, ESLint matches `**/*.js`, `**/*.cjs`, and `**/*.mjs`. Because config objects that don't specify `files` or `ignores` apply to all files that have been matched by any other configuration object, by default config objects will apply to any JavaScript files passed to ESLint. For example: +You can use a combination of `files` and `ignores` to determine which files should apply the configuration object and which should not. By default, ESLint matches `**/*.js`, `**/*.cjs`, and `**/*.mjs`. Because config objects that don't specify `files` or `ignores` apply to all files that have been matched by any other configuration object, those config objects apply to any JavaScript files passed to ESLint by default. For example: ```js export default [ @@ -67,11 +69,11 @@ export default [ ]; ``` -With this configuration, the `semi` rule is enabled for all files that match the default files in ESLint. So if you pass `example.js` to ESLint, the `semi` rule will be applied. If you pass a non-JavaScript file, like `example.txt`, the `semi` rule will not be applied because there are no other configuration objects that match that filename. (ESLint will output an error message letting you know that the file was ignored due to missing configuration.) +With this configuration, the `semi` rule is enabled for all files that match the default files in ESLint. So if you pass `example.js` to ESLint, the `semi` rule is applied. If you pass a non-JavaScript file, like `example.txt`, the `semi` rule is not applied because there are no other configuration objects that match that filename. (ESLint outputs an error message letting you know that the file was ignored due to missing configuration.) #### Excluding files with `ignores` -You can limit which files a configuration object applies to by specifying a combination of `files` and `ignores` patterns. For example, you may want certain rules to apply only to files in your `src` directory, like this: +You can limit which files a configuration object applies to by specifying a combination of `files` and `ignores` patterns. For example, you may want certain rules to apply only to files in your `src` directory: ```js export default [ @@ -84,7 +86,7 @@ export default [ ]; ``` -Here, only the JavaScript files in the `src` directory will have the `semi` rule applied. If you run ESLint on files in another directory, this configuration object will be skipped. By adding `ignores`, you can also remove some of the files in `src` from this configuration object: +Here, only the JavaScript files in the `src` directory have the `semi` rule applied. If you run ESLint on files in another directory, this configuration object is skipped. By adding `ignores`, you can also remove some of the files in `src` from this configuration object: ```js export default [ @@ -112,7 +114,7 @@ export default [ ]; ``` -Here, the configuration object excludes files ending with `.config.js` except for `eslint.config.js`. That file will still have `semi` applied. +Here, the configuration object excludes files ending with `.config.js` except for `eslint.config.js`. That file still has `semi` applied. If `ignores` is used without `files` and any other setting, then the configuration object applies to all files except the ones specified in `ignores`, for example: @@ -192,7 +194,7 @@ export default [ #### Reporting unused disable directives -Disable directives such as `/*eslint-disable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule will no longer be triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example: +Disable directives such as `/*eslint-disable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule is no longer triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example: ```js export default [ @@ -264,7 +266,7 @@ export default [ ]; ``` -This configuration ensures that the Babel parser, rather than the default, will be used to parse all files ending with `.js` and `.mjs`. +This configuration ensures that the Babel parser, rather than the default Espree parser, is used to parse all files ending with `.js` and `.mjs`. You can also pass options directly to the custom parser by using the `parserOptions` property. This property is an object whose name-value pairs are specific to the parser that you are using. For the Babel parser, you might pass in options like this: @@ -441,7 +443,7 @@ export default [ ]; ``` -This configuration object specifies that there is a processor called `"markdown"` contained in the plugin named `"markdown"` and will apply the processor to all files ending with `.md`. +This configuration object specifies that there is a processor called `"markdown"` contained in the plugin named `"markdown"`. The configuration applies the processor to all files ending with `.md`. Processors may make named code blocks that function as filenames in configuration objects, such as `0.js` and `1.js`. ESLint handles such a named code block as a child of the original file. You can specify additional configuration objects for named code blocks. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files. @@ -503,7 +505,7 @@ Each rule specifies its own options and can be any valid JSON data type. Please There are three possible severities you can specify for a rule * `"error"` (or `2`) - the reported problem should be treated as an error. When using the ESLint CLI, errors cause the CLI to exit with a nonzero code. -* `"warn"` (or `1`) - the reported problem should be treated as a warning. When using the ESLint CLI, warnings are reported but do not change the exit code. If only warnings are reported, the exit code will be 0. +* `"warn"` (or `1`) - the reported problem should be treated as a warning. When using the ESLint CLI, warnings are reported but do not change the exit code. If only warnings are reported, the exit code is 0. * `"off"` (or `0`) - the rule should be turned off completely. #### Rule configuration cascade @@ -546,7 +548,7 @@ Here, the second configuration object only overrides the severity, so the final ### Configuring shared settings -ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify information that should be shared across all of its rules. You can add a `settings` object to a configuration object and it will be supplied to every rule being executed. This may be useful if you are adding custom rules and want them to have access to the same information. Here's an example: +ESLint supports adding shared settings into configuration files. When you add a `settings` object to a configuration object, it is supplied to every rule. By convention, plugins namespace the settings they are interested in to avoid collisions with others. Plugins can use `settings` to specify the information that should be shared across all of their rules. This may be useful if you are adding custom rules and want them to have access to the same information. Here's an example: ```js export default [ @@ -582,7 +584,7 @@ Here, the `eslint:recommended` predefined configuration is applied first and the ## Configuration File Resolution -When ESLint is run on the command line, it first checks the current working directory for `eslint.config.js`, and if not found, will look to the next parent directory for the file. This search continues until either the file is found or the root directory is reached. +When ESLint is run on the command line, it first checks the current working directory for `eslint.config.js`. If the file is not found, it looks to the next parent directory for the file. This search continues until either the file is found or the root directory is reached. You can prevent this search for `eslint.config.js` by setting the `ESLINT_USE_FLAT_CONFIG` environment variable to `true` and using the `-c` or `--config` option on the command line to specify an alternate configuration file, such as: @@ -590,4 +592,4 @@ You can prevent this search for `eslint.config.js` by setting the `ESLINT_USE_FL ESLINT_USE_FLAT_CONFIG=true npx eslint -c some-other-file.js **/*.js ``` -In this case, ESLint will not search for `eslint.config.js` and will instead use `some-other-file.js`. +In this case, ESLint does not search for `eslint.config.js` and instead uses `some-other-file.js`. diff --git a/docs/src/user-guide/configuring/configuration-files.md b/docs/src/user-guide/configuring/configuration-files.md index ed148bfd3c43..bf0534601bc4 100644 --- a/docs/src/user-guide/configuring/configuration-files.md +++ b/docs/src/user-guide/configuring/configuration-files.md @@ -8,6 +8,8 @@ eleventyNavigation: --- +You can put your ESLint project configuration in a configuration file. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more. + ## Configuration File Formats ESLint supports configuration files in several formats: @@ -18,7 +20,7 @@ ESLint supports configuration files in several formats: * **JSON** - use `.eslintrc.json` to define the configuration structure. ESLint's JSON files also allow JavaScript-style comments. * **package.json** - create an `eslintConfig` property in your `package.json` file and define your configuration there. -If there are multiple configuration files in the same directory, ESLint will only use one. The priority order is as follows: +If there are multiple configuration files in the same directory, ESLint only uses one. The priority order is as follows: 1. `.eslintrc.js` 1. `.eslintrc.cjs` @@ -31,7 +33,7 @@ If there are multiple configuration files in the same directory, ESLint will onl There are two ways to use configuration files. -The first way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint will automatically look for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem (`/`), the home directory of the current user (`~/`), or when `root: true` is specified. See [Cascading and Hierarchy](#cascading-and-hierarchy) below for more details on this. Configuration files can be useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file. +The first way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint automatically looks for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem (`/`), the home directory of the current user (`~/`), or when `root: true` is specified. See [Cascading and Hierarchy](#cascading-and-hierarchy) below for more details on this. Configuration files can be useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file. The second way to use configuration files is to save the file wherever you would like and pass its location to the CLI using the `--config` option, such as: @@ -39,7 +41,7 @@ The second way to use configuration files is to save the file wherever you would eslint -c myconfig.json myfiletotest.js ``` -If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](https://eslint.org/docs/user-guide/command-line-interface#--no-eslintrc) along with the [`-c`](https://eslint.org/docs/user-guide/command-line-interface#-c---config) flag. +If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](https://eslint.org/docs/user-guide/command-line-interface#--no-eslintrc) along with the [`--config`](https://eslint.org/docs/user-guide/command-line-interface#-c---config) flag. Here's an example JSON configuration file that uses the `typescript-eslint` parser to support TypeScript syntax: @@ -70,7 +72,7 @@ Here's an example JSON configuration file that uses the `typescript-eslint` pars ### Comments in configuration files -Both the JSON and YAML configuration file formats support comments (package.json files should not include them). You can use JavaScript-style comments for JSON files and YAML-style comments for YAML files. ESLint safely ignores comments in configuration files. This allows your configuration files to be more human-friendly. +Both the JSON and YAML configuration file formats support comments (`package.json` files should not include them). You can use JavaScript-style comments for JSON files and YAML-style comments for YAML files. ESLint safely ignores comments in configuration files. This allows your configuration files to be more human-friendly. For JavaScript-style comments: @@ -100,7 +102,7 @@ rules: ## Adding Shared Settings -ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify information that should be shared across all of its rules. You can add `settings` object to ESLint configuration file and it will be supplied to every rule being executed. This may be useful if you are adding custom rules and want them to have access to the same information and be easily configurable. +ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify the information that should be shared across all of its rules. You can add a `settings` object to the ESLint configuration file and it is supplied to every executed rule. This may be useful if you are adding custom rules and want them to have access to the same information and be easily configurable. In JSON: @@ -122,7 +124,7 @@ And in YAML: ## Cascading and Hierarchy -When using `.eslintrc.*` and `package.json` files for configuration, you can take advantage of configuration cascading. Suppose you have the following structure: +When using `.eslintrc.*` and `package.json` files for configuration, you can take advantage of configuration cascading. Suppose your project has the following structure: ```text your-project @@ -136,7 +138,7 @@ your-project The configuration cascade works based on the location of the file being linted. If there is a `.eslintrc` file in the same directory as the file being linted, then that configuration takes precedence. ESLint then searches up the directory structure, merging any `.eslintrc` files it finds along the way until reaching either a `.eslintrc` file with `root: true` or the root directory. -In the same way, if there is a `package.json` file in the root directory with an `eslintConfig` field, the configuration it describes will apply to all subdirectories beneath it, but the configuration described by the `.eslintrc` file in the `tests/` directory will override it where there are conflicting specifications. +In the same way, if there is a `package.json` file in the root directory with an `eslintConfig` field, the configuration it describes is applied to all subdirectories beneath it. However, the configuration described by the `.eslintrc` file in the `tests/` directory overrides conflicting specifications. ```text your-project @@ -148,9 +150,9 @@ your-project └── test.js ``` -If there is a `.eslintrc` and a `package.json` file found in the same directory, `.eslintrc` will take priority and `package.json` file will not be used. +If there is a `.eslintrc` and a `package.json` file found in the same directory, `.eslintrc` takes priority and the `package.json` file is not used. -By default, ESLint will look for configuration files in all parent folders up to the root directory. This can be useful if you want all of your projects to follow a certain convention, but can sometimes lead to unexpected results. To limit ESLint to a specific project, place `"root": true` inside the `.eslintrc.*` file or `eslintConfig` field of the `package.json` file or in the `.eslintrc.*` file at your project's root level. ESLint will stop looking in parent folders once it finds a configuration with `"root": true`. +By default, ESLint looks for configuration files in all parent folders up to the root directory. This can be useful if you want all of your projects to follow a certain convention, but can sometimes lead to unexpected results. To limit ESLint to a specific project, place `"root": true` inside the `.eslintrc.*` file or `eslintConfig` field of the `package.json` file or in the `.eslintrc.*` file at your project's root level. ESLint stops looking in parent folders once it finds a configuration with `"root": true`. ```js { @@ -165,7 +167,7 @@ And in YAML: root: true ``` -For example, consider `projectA` which has `"root": true` set in the `.eslintrc` file in the `lib/` directory. In this case, while linting `main.js`, the configurations within `lib/` will be used, but the `.eslintrc` file in `projectA/` will not. +For example, consider `projectA` which has `"root": true` set in the `.eslintrc` file in the `lib/` directory. In this case, while linting `main.js`, the configurations within `lib/` are used, but the `.eslintrc` file in `projectA/` is not. ```text home @@ -193,7 +195,7 @@ The complete configuration hierarchy, from highest to lowest precedence, is as f 1. `.eslintrc.*` or `package.json` file in the same directory as the linted file 1. Continue searching for `.eslintrc.*` and `package.json` files in ancestor directories up to and including the root directory or until a config with `"root": true` is found. -Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files will stop there as well. And with the [removal of support for Personal Configuration Files](https://eslint.org/docs/user-guide/configuring/configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory will be ignored. +Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files stops there as well. And with the [removal of support for Personal Configuration Files](https://eslint.org/docs/user-guide/configuring/configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory are ignored. ## Extending Configuration Files @@ -358,7 +360,7 @@ module.exports = { ## Configuration Based on Glob Patterns -v4.1.0+. Sometimes a more fine-controlled configuration is necessary, for example, if the configuration for files within the same directory has to be different. Therefore you can provide configurations under the `overrides` key that will only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., `app/**/*.test.js`). +**v4.1.0+.** Sometimes a more fine-controlled configuration is necessary, like if the configuration for files within the same directory has to be different. In this case, you can provide configurations under the `overrides` key that only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., `app/**/*.test.js`). Glob patterns in overrides use [minimatch syntax](https://github.com/isaacs/minimatch). @@ -388,11 +390,11 @@ In your `.eslintrc.json`: Here is how overrides work in a configuration file: -* The patterns are applied against the file path relative to the directory of the config file. For example, if your config file has the path `/Users/john/workspace/any-project/.eslintrc.js` and the file you want to lint has the path `/Users/john/workspace/any-project/lib/util.js`, then the pattern provided in `.eslintrc.js` will be executed against the relative path `lib/util.js`. +* The patterns are applied against the file path relative to the directory of the config file. For example, if your config file has the path `/Users/john/workspace/any-project/.eslintrc.js` and the file you want to lint has the path `/Users/john/workspace/any-project/lib/util.js`, then the pattern provided in `.eslintrc.js` is executed against the relative path `lib/util.js`. * Glob pattern overrides have higher precedence than the regular configuration in the same config file. Multiple overrides within the same config are applied in order. That is, the last override block in a config file always has the highest precedence. * A glob specific configuration works almost the same as any other ESLint config. Override blocks can contain any configuration options that are valid in a regular config, with the exception of `root` and `ignorePatterns`. * A glob specific configuration can have an `extends` setting, but the `root` property in the extended configs is ignored. The `ignorePatterns` property in the extended configs is used only for the files the glob specific configuration matched. - * Nested `overrides` setting will be applied only if the glob patterns of both of the parent config and the child config matched. This is the same when the extended configs have an `overrides` setting. + * Nested `overrides` settings are applied only if the glob patterns of both the parent config and the child config are matched. This is the same when the extended configs have an `overrides` setting. * Multiple glob patterns can be provided within a single override block. A file must match at least one of the supplied patterns for the configuration to apply. * Override blocks can also specify patterns to exclude from matches. If a file matches any of the excluded patterns, the configuration won't apply. @@ -426,7 +428,7 @@ If you specified the [`--ext`](https://eslint.org/docs/user-guide/command-line-i ## Personal Configuration Files (deprecated) -⚠️ **This feature has been deprecated**. This feature will be removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32). +⚠️ **This feature has been deprecated**. This feature was removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32). `~/` refers to [the home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir). The personal configuration file being referred to here is `~/.eslintrc.*` file, which is currently handled differently than other configuration files. From f89403553b31d24f4fc841424cc7dcb8c3ef689f Mon Sep 17 00:00:00 2001 From: Christian Oliff Date: Fri, 25 Nov 2022 01:23:19 +0900 Subject: [PATCH 02/29] docs: HTTPS link to yeoman.io (#16582) --- docs/src/developer-guide/development-environment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/developer-guide/development-environment.md b/docs/src/developer-guide/development-environment.md index d25b4444910c..f55da6ac8451 100644 --- a/docs/src/developer-guide/development-environment.md +++ b/docs/src/developer-guide/development-environment.md @@ -43,7 +43,7 @@ Now, the remote `upstream` points to the upstream source. ## Step 4: Install the Yeoman Generator -[Yeoman](http://yeoman.io) is a scaffold generator that ESLint uses to help streamline development of new rules. If you don't already have Yeoman installed, you can install it via npm: +[Yeoman](https://yeoman.io) is a scaffold generator that ESLint uses to help streamline development of new rules. If you don't already have Yeoman installed, you can install it via npm: ```shell npm install -g yo From fbcf3abd54dd20aec3c695cacece56493633c97f Mon Sep 17 00:00:00 2001 From: Shanmughapriyan S Date: Sat, 26 Nov 2022 15:15:45 +0530 Subject: [PATCH 03/29] docs: fix searchbar clear button (#16585) --- docs/src/assets/js/search.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/src/assets/js/search.js b/docs/src/assets/js/search.js index 25282bc2d7fd..1de0f475eee2 100644 --- a/docs/src/assets/js/search.js +++ b/docs/src/assets/js/search.js @@ -49,7 +49,6 @@ function clearSearchResults() { resultsElement.removeChild(resultsElement.firstChild); } resultsElement.innerHTML = ""; - searchClearBtn.setAttribute('hidden', ''); } /** @@ -80,13 +79,11 @@ function displaySearchResults(results) { `.trim(); list.append(listItem); } - searchClearBtn.removeAttribute('hidden'); } else { resultsLiveRegion.innerHTML = "No results found."; resultsElement.innerHTML = "No results found."; resultsElement.setAttribute('data-results', 'false'); - searchClearBtn.setAttribute('hidden', ''); } } @@ -151,6 +148,7 @@ if(searchClearBtn) searchInput.value = ''; searchInput.focus(); clearSearchResults(); + searchClearBtn.setAttribute('hidden', ''); }); document.addEventListener('keydown', function (e) { From a91332b8bd9adfa2aa8110071bdf73f56d400050 Mon Sep 17 00:00:00 2001 From: trosos Date: Sun, 27 Nov 2022 01:38:56 +0100 Subject: [PATCH 04/29] feat: In no-invalid-regexp validate flags also for non-literal patterns (#16583) Fixes #16573 --- lib/rules/no-invalid-regexp.js | 58 +++++++++++++++++++--------- tests/lib/rules/no-invalid-regexp.js | 42 ++++++++++++++++++++ 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/lib/rules/no-invalid-regexp.js b/lib/rules/no-invalid-regexp.js index 0f1d9c7bedc6..81b083536d88 100644 --- a/lib/rules/no-invalid-regexp.js +++ b/lib/rules/no-invalid-regexp.js @@ -59,6 +59,20 @@ module.exports = { } } + /** + * Reports error with the provided message. + * @param {ASTNode} node The node holding the invalid RegExp + * @param {string} message The message to report. + * @returns {void} + */ + function report(node, message) { + context.report({ + node, + messageId: "regexMessage", + data: { message } + }); + } + /** * Check if node is a string * @param {ASTNode} node node to evaluate @@ -108,10 +122,13 @@ module.exports = { /** * Check syntax error in a given flags. - * @param {string} flags The RegExp flags to validate. + * @param {string|null} flags The RegExp flags to validate. * @returns {string|null} The syntax error. */ function validateRegExpFlags(flags) { + if (!flags) { + return null; + } try { validator.validateFlags(flags); return null; @@ -122,34 +139,39 @@ module.exports = { return { "CallExpression, NewExpression"(node) { - if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) { + if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp") { return; } - const pattern = node.arguments[0].value; + let flags = getFlags(node); if (flags && allowedFlags) { flags = flags.replace(allowedFlags, ""); } - const message = - ( - flags && validateRegExpFlags(flags) - ) || - ( + let message = validateRegExpFlags(flags); + + if (message) { + report(node, message); + return; + } + + if (!isString(node.arguments[0])) { + return; + } + + const pattern = node.arguments[0].value; + + message = ( - // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag - flags === null - ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false) - : validateRegExpPattern(pattern, flags.includes("u")) - ); + // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag + flags === null + ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false) + : validateRegExpPattern(pattern, flags.includes("u")) + ); if (message) { - context.report({ - node, - messageId: "regexMessage", - data: { message } - }); + report(node, message); } } }; diff --git a/tests/lib/rules/no-invalid-regexp.js b/tests/lib/rules/no-invalid-regexp.js index a34752dcda53..047207b55344 100644 --- a/tests/lib/rules/no-invalid-regexp.js +++ b/tests/lib/rules/no-invalid-regexp.js @@ -57,6 +57,12 @@ ruleTester.run("no-invalid-regexp", rule, { options: [{ allowConstructorFlags: ["a"] }] }, + // unknown pattern + "new RegExp(pattern, 'g')", + "new RegExp('.' + '', 'g')", + "new RegExp(pattern, '')", + "new RegExp(pattern)", + // ES2020 "new RegExp('(?<\\\\ud835\\\\udc9c>.)', 'g')", "new RegExp('(?<\\\\u{1d49c}>.)', 'g')", @@ -87,6 +93,14 @@ ruleTester.run("no-invalid-regexp", rule, { code: "new RegExp('.', 'ga')", options: [{ allowConstructorFlags: ["a"] }] }, + { + code: "new RegExp(pattern, 'ga')", + options: [{ allowConstructorFlags: ["a"] }] + }, + { + code: "new RegExp('.' + '', 'ga')", + options: [{ allowConstructorFlags: ["a"] }] + }, { code: "new RegExp('.', 'a')", options: [{ allowConstructorFlags: ["a", "z"] }] @@ -237,6 +251,34 @@ ruleTester.run("no-invalid-regexp", rule, { data: { message: "Invalid regular expression: /\\/: \\ at end of pattern" }, type: "NewExpression" }] + }, + + // https://github.com/eslint/eslint/issues/16573 + { + code: "RegExp(')' + '', 'a');", + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'a'" }, + type: "CallExpression" + }] + }, + { + code: "new RegExp('.' + '', 'az');", + options: [{ allowConstructorFlags: ["z"] }], + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'a'" }, + type: "NewExpression" + }] + }, + { + code: "new RegExp(pattern, 'az');", + options: [{ allowConstructorFlags: ["a"] }], + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'z'" }, + type: "NewExpression" + }] } ] }); From ade621dd12fcd3b65644bb3468248cc040db756c Mon Sep 17 00:00:00 2001 From: Shanmughapriyan S Date: Sun, 27 Nov 2022 16:57:32 +0530 Subject: [PATCH 05/29] docs: perf debounce the search query (#16586) * perf: debounce search results * fix nits Co-authored-by: Amaresh S M * fix typo Co-authored-by: Amaresh S M * add apply * chore: update the debounce fn parameter * chore: update js doc commments * chore: add punctuation * perf: debounce search results * fix nits Co-authored-by: Amaresh S M * fix typo Co-authored-by: Amaresh S M * add apply * chore: update the debounce fn parameter * chore: update js doc commments * chore: add punctuation Co-authored-by: Amaresh S M --- docs/src/assets/js/search.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/src/assets/js/search.js b/docs/src/assets/js/search.js index 1de0f475eee2..780e3dee1075 100644 --- a/docs/src/assets/js/search.js +++ b/docs/src/assets/js/search.js @@ -111,6 +111,25 @@ function maintainScrollVisibility(activeElement, scrollParent) { } +/** + * Debounces the provided callback with a given delay. + * @param {Function} callback The callback that needs to be debounced. + * @param {Number} delay Time in ms that the timer should wait before the callback is executed. + * @returns {Function} Returns the new debounced function. + */ +function debounce(callback, delay) { + let timer; + return (...args) => { + if (timer) clearTimeout(timer); + timer = setTimeout(() => callback.apply(this, args), delay); + } +} + +const debouncedFetchSearchResults = debounce((query) => { + fetchSearchResults(query) + .then(displaySearchResults) + .catch(clearSearchResults); +}, 300); //----------------------------------------------------------------------------- // Event Handlers @@ -127,9 +146,8 @@ if(searchInput) else searchClearBtn.setAttribute('hidden', ''); if (query.length > 2) { - fetchSearchResults(query) - .then(displaySearchResults) - .catch(clearSearchResults); + + debouncedFetchSearchResults(query); document.addEventListener('click', function(e) { if(e.target !== resultsElement) clearSearchResults(); From e6a865d70aed9e1c07be712e40c38da1a5dda849 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 27 Nov 2022 07:23:15 -0500 Subject: [PATCH 06/29] feat: `prefer-named-capture-group` add suggestions (#16544) * feat: [prefer-named-capture-group] add suggestions * Add test for proper parenthesis matching * fix: only suggest when there are no \s * More granular checking of suggestion viability * Feedback: return null in more cases, no more indexOf, suggestions: null * Account for existing temps --- lib/rules/prefer-named-capture-group.js | 77 +++- tests/lib/rules/prefer-named-capture-group.js | 371 +++++++++++++++++- 2 files changed, 423 insertions(+), 25 deletions(-) diff --git a/lib/rules/prefer-named-capture-group.js b/lib/rules/prefer-named-capture-group.js index 1a13ffa85829..66259fc7beda 100644 --- a/lib/rules/prefer-named-capture-group.js +++ b/lib/rules/prefer-named-capture-group.js @@ -23,6 +23,61 @@ const regexpp = require("regexpp"); const parser = new regexpp.RegExpParser(); +/** + * Creates fixer suggestions for the regex, if statically determinable. + * @param {number} groupStart Starting index of the regex group. + * @param {string} pattern The regular expression pattern to be checked. + * @param {string} rawText Source text of the regexNode. + * @param {ASTNode} regexNode AST node which contains the regular expression. + * @returns {Array} Fixer suggestions for the regex, if statically determinable. + */ +function suggestIfPossible(groupStart, pattern, rawText, regexNode) { + switch (regexNode.type) { + case "Literal": + if (typeof regexNode.value === "string" && rawText.includes("\\")) { + return null; + } + break; + case "TemplateLiteral": + if (regexNode.expressions.length || rawText.slice(1, -1) !== pattern) { + return null; + } + break; + default: + return null; + } + + const start = regexNode.range[0] + groupStart + 2; + + return [ + { + fix(fixer) { + const existingTemps = pattern.match(/temp\d+/gu) || []; + const highestTempCount = existingTemps.reduce( + (previous, next) => + Math.max(previous, Number(next.slice("temp".length))), + 0 + ); + + return fixer.insertTextBeforeRange( + [start, start], + `?` + ); + }, + messageId: "addGroupName" + }, + { + fix(fixer) { + return fixer.insertTextBeforeRange( + [start, start], + "?:" + ); + }, + messageId: "addNonCapture" + } + ]; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -38,23 +93,29 @@ module.exports = { url: "https://eslint.org/docs/rules/prefer-named-capture-group" }, + hasSuggestions: true, + schema: [], messages: { + addGroupName: "Add name to capture group.", + addNonCapture: "Convert group to non-capturing.", required: "Capture group '{{group}}' should be converted to a named or non-capturing group." } }, create(context) { + const sourceCode = context.getSourceCode(); /** * Function to check regular expression. - * @param {string} pattern The regular expression pattern to be check. - * @param {ASTNode} node AST node which contains regular expression. + * @param {string} pattern The regular expression pattern to be checked. + * @param {ASTNode} node AST node which contains the regular expression or a call/new expression. + * @param {ASTNode} regexNode AST node which contains the regular expression. * @param {boolean} uFlag Flag indicates whether unicode mode is enabled or not. * @returns {void} */ - function checkRegex(pattern, node, uFlag) { + function checkRegex(pattern, node, regexNode, uFlag) { let ast; try { @@ -68,12 +129,16 @@ module.exports = { regexpp.visitRegExpAST(ast, { onCapturingGroupEnter(group) { if (!group.name) { + const rawText = sourceCode.getText(regexNode); + const suggest = suggestIfPossible(group.start, pattern, rawText, regexNode); + context.report({ node, messageId: "required", data: { group: group.raw - } + }, + suggest }); } } @@ -83,7 +148,7 @@ module.exports = { return { Literal(node) { if (node.regex) { - checkRegex(node.regex.pattern, node, node.regex.flags.includes("u")); + checkRegex(node.regex.pattern, node, node, node.regex.flags.includes("u")); } }, Program() { @@ -101,7 +166,7 @@ module.exports = { const flags = getStringIfConstant(node.arguments[1]); if (regex) { - checkRegex(regex, node, flags && flags.includes("u")); + checkRegex(regex, node, node.arguments[0], flags && flags.includes("u")); } } } diff --git a/tests/lib/rules/prefer-named-capture-group.js b/tests/lib/rules/prefer-named-capture-group.js index 0faf1d6be65e..dad3d7c02901 100644 --- a/tests/lib/rules/prefer-named-capture-group.js +++ b/tests/lib/rules/prefer-named-capture-group.js @@ -82,7 +82,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 13 + endColumn: 13, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?[0-9]{4})/" + }, + { + messageId: "addNonCapture", + output: "/(?:[0-9]{4})/" + } + ] }] }, { @@ -93,7 +103,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 25 + endColumn: 25, + suggestions: [ + { + messageId: "addGroupName", + output: "new RegExp('(?[0-9]{4})')" + }, + { + messageId: "addNonCapture", + output: "new RegExp('(?:[0-9]{4})')" + } + ] }] }, { @@ -104,7 +124,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 21 + endColumn: 21, + suggestions: [ + { + messageId: "addGroupName", + output: "RegExp('(?[0-9]{4})')" + }, + { + messageId: "addNonCapture", + output: "RegExp('(?:[0-9]{4})')" + } + ] }] }, { @@ -112,7 +142,44 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "NewExpression", - data: { group: "(bc)" } + data: { group: "(bc)" }, + suggestions: [ + { + messageId: "addGroupName", + output: "new RegExp(`a(?bc)d`)" + }, + { + messageId: "addNonCapture", + output: "new RegExp(`a(?:bc)d`)" + } + ] + }] + }, + { + code: "new RegExp('\u1234\u5678(?:a)(b)');", + errors: [{ + messageId: "required", + type: "NewExpression", + data: { group: "(b)" }, + suggestions: [ + { + messageId: "addGroupName", + output: "new RegExp('\u1234\u5678(?:a)(?b)');" + }, + { + messageId: "addNonCapture", + output: "new RegExp('\u1234\u5678(?:a)(?:b)');" + } + ] + }] + }, + { + code: "new RegExp('\\u1234\\u5678(?:a)(b)');", + errors: [{ + messageId: "required", + type: "NewExpression", + data: { group: "(b)" }, + suggestions: null }] }, { @@ -124,7 +191,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 21 + endColumn: 21, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?[0-9]{4})-(\\w{5})/" + }, + { + messageId: "addNonCapture", + output: "/(?:[0-9]{4})-(\\w{5})/" + } + ] }, { messageId: "required", @@ -132,7 +209,173 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "(\\w{5})" }, line: 1, column: 1, - endColumn: 21 + endColumn: 21, + suggestions: [ + { + messageId: "addGroupName", + output: "/([0-9]{4})-(?\\w{5})/" + }, + { + messageId: "addNonCapture", + output: "/([0-9]{4})-(?:\\w{5})/" + } + ] + } + ] + }, + { + code: "/([0-9]{4})-(5)/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "([0-9]{4})" }, + line: 1, + column: 1, + endColumn: 17, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?[0-9]{4})-(5)/" + }, + { + messageId: "addNonCapture", + output: "/(?:[0-9]{4})-(5)/" + } + ] + }, + { + messageId: "required", + type: "Literal", + data: { group: "(5)" }, + line: 1, + column: 1, + endColumn: 17, + suggestions: [ + { + messageId: "addGroupName", + output: "/([0-9]{4})-(?5)/" + }, + { + messageId: "addNonCapture", + output: "/([0-9]{4})-(?:5)/" + } + ] + } + ] + }, + { + code: "/(?(a))/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "(a)" }, + line: 1, + column: 1, + endColumn: 16, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?(?a))/" + }, + { + messageId: "addNonCapture", + output: "/(?(?:a))/" + } + ] + } + ] + }, + { + code: "/(?(a)(?b))/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "(a)" }, + line: 1, + column: 1, + endColumn: 27, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?(?a)(?b))/" + }, + { + messageId: "addNonCapture", + output: "/(?(?:a)(?b))/" + } + ] + } + ] + }, + { + code: "/(?[0-9]{4})-(\\w{5})/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "(\\w{5})" }, + line: 1, + column: 1, + endColumn: 29, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?[0-9]{4})-(?\\w{5})/" + }, + { + messageId: "addNonCapture", + output: "/(?[0-9]{4})-(?:\\w{5})/" + } + ] + } + ] + }, + { + code: "/(?[0-9]{4})-(5)/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "(5)" }, + line: 1, + column: 1, + endColumn: 25, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?[0-9]{4})-(?5)/" + }, + { + messageId: "addNonCapture", + output: "/(?[0-9]{4})-(?:5)/" + } + ] + } + ] + }, + { + code: "/(?a)(?a)(a)(?a)/", + errors: [ + { + messageId: "required", + type: "Literal", + data: { group: "(a)" }, + line: 1, + column: 1, + endColumn: 39, + suggestions: [ + { + messageId: "addGroupName", + output: "/(?a)(?a)(?a)(?a)/" + }, + { + messageId: "addNonCapture", + output: "/(?a)(?a)(?:a)(?a)/" + } + ] } ] }, @@ -141,7 +384,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "NewExpression", - data: { group: "(a)" } + data: { group: "(a)" }, + suggestions: null }] }, { @@ -149,7 +393,34 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "NewExpression", - data: { group: "(bc)" } + data: { group: "(bc)" }, + suggestions: null + }] + }, + { + code: "new RegExp(\"foo\" + \"(a)\" + \"(b)\");", + errors: [ + { + messageId: "required", + type: "NewExpression", + data: { group: "(a)" }, + suggestions: null + }, + { + messageId: "required", + type: "NewExpression", + data: { group: "(b)" }, + suggestions: null + } + ] + }, + { + code: "new RegExp(\"foo\" + \"(?:a)\" + \"(b)\");", + errors: [{ + messageId: "required", + type: "NewExpression", + data: { group: "(b)" }, + suggestions: null }] }, { @@ -157,7 +428,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "CallExpression", - data: { group: "(a)" } + data: { group: "(a)" }, + suggestions: null }] }, { @@ -165,7 +437,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "CallExpression", - data: { group: "(ab)" } + data: { group: "(ab)" }, + suggestions: null }] }, { @@ -173,7 +446,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "NewExpression", - data: { group: "(ab)" } + data: { group: "(ab)" }, + suggestions: null }] }, { @@ -185,7 +459,17 @@ ruleTester.run("prefer-named-capture-group", rule, { line: 1, column: 1, endLine: 2, - endColumn: 3 + endColumn: 3, + suggestions: [ + { + messageId: "addGroupName", + output: "new RegExp(`(?a)\n`)" + }, + { + messageId: "addNonCapture", + output: "new RegExp(`(?:a)\n`)" + } + ] }] }, { @@ -193,7 +477,17 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "CallExpression", - data: { group: "(b\nc)" } + data: { group: "(b\nc)" }, + suggestions: [ + { + messageId: "addGroupName", + output: "RegExp(`a(?b\nc)d`)" + }, + { + messageId: "addNonCapture", + output: "RegExp(`a(?:b\nc)d`)" + } + ] }] }, { @@ -201,7 +495,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "NewExpression", - data: { group: "(b)" } + data: { group: "(b)" }, + suggestions: null }] }, { @@ -209,7 +504,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "CallExpression", - data: { group: "(a)" } + data: { group: "(a)" }, + suggestions: null }] }, { @@ -217,7 +513,8 @@ ruleTester.run("prefer-named-capture-group", rule, { errors: [{ messageId: "required", type: "CallExpression", - data: { group: "(b)" } + data: { group: "(b)" }, + suggestions: null }] }, { @@ -229,7 +526,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 36 + endColumn: 36, + suggestions: [ + { + messageId: "addGroupName", + output: "new globalThis.RegExp('(?[0-9]{4})')" + }, + { + messageId: "addNonCapture", + output: "new globalThis.RegExp('(?:[0-9]{4})')" + } + ] }] }, { @@ -241,7 +548,17 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 1, column: 1, - endColumn: 32 + endColumn: 32, + suggestions: [ + { + messageId: "addGroupName", + output: "globalThis.RegExp('(?[0-9]{4})')" + }, + { + messageId: "addNonCapture", + output: "globalThis.RegExp('(?:[0-9]{4})')" + } + ] }] }, { @@ -256,7 +573,23 @@ ruleTester.run("prefer-named-capture-group", rule, { data: { group: "([0-9]{4})" }, line: 3, column: 17, - endColumn: 52 + endColumn: 52, + suggestions: [ + { + messageId: "addGroupName", + output: ` + function foo() { var globalThis = bar; } + new globalThis.RegExp('(?[0-9]{4})'); + ` + }, + { + messageId: "addNonCapture", + output: ` + function foo() { var globalThis = bar; } + new globalThis.RegExp('(?:[0-9]{4})'); + ` + } + ] }] } ] From 6380c87c563be5dc78ce0ddd5c7409aaf71692bb Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Mon, 28 Nov 2022 06:34:37 +0100 Subject: [PATCH 07/29] docs: fix sitemap and feed (#16592) --- docs/src/static/feed.njk | 1 + docs/src/static/sitemap.njk | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/src/static/feed.njk b/docs/src/static/feed.njk index da59847d097d..d32fb4713ea4 100644 --- a/docs/src/static/feed.njk +++ b/docs/src/static/feed.njk @@ -1,6 +1,7 @@ ---json { "permalink": "feed.xml", + "layout": false, "eleventyExcludeFromCollections": true, "metadata": { "title": "ESLint Blog", diff --git a/docs/src/static/sitemap.njk b/docs/src/static/sitemap.njk index e92a4e568447..47ba2665169d 100644 --- a/docs/src/static/sitemap.njk +++ b/docs/src/static/sitemap.njk @@ -1,5 +1,6 @@ --- permalink: /sitemap.xml +layout: false eleventyExcludeFromCollections: true --- From 49a07c52c5af7e98d161ff4acd44bbbe0aa6383b Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Tue, 29 Nov 2022 17:12:37 +0530 Subject: [PATCH 08/29] feat: add `allowParensAfterCommentPattern` option to no-extra-parens (#16561) * feat: add new `allowParensAfterComment` option (`no-extra-parens`) * feat: add new `allowParensAfterCommentPattern` option to the `no-extra-parens` rule * docs: add new `allowParensAfterCommentPattern` option to the `no-extra-parens` rule * docs: add new `allowParensAfterCommentPattern` option to the `no-extra-parens` rule * docs: add more information for `allowParensAfterCommentPattern` * test: add another invalid case * refactor: remove extra condition Co-authored-by: Milos Djermanovic * test: add more invalid cases Co-authored-by: Milos Djermanovic --- docs/src/rules/no-extra-parens.md | 29 +++++ lib/rules/no-extra-parens.js | 17 ++- tests/lib/rules/no-extra-parens.js | 189 ++++++++++++++++++++++++++++- 3 files changed, 232 insertions(+), 3 deletions(-) diff --git a/docs/src/rules/no-extra-parens.md b/docs/src/rules/no-extra-parens.md index 8e5bb714cbdd..9b1b8df07250 100644 --- a/docs/src/rules/no-extra-parens.md +++ b/docs/src/rules/no-extra-parens.md @@ -38,6 +38,7 @@ This rule has an object option for exceptions to the `"all"` option: * `"enforceForSequenceExpressions": false` allows extra parentheses around sequence expressions * `"enforceForNewInMemberExpressions": false` allows extra parentheses around `new` expressions in member expressions * `"enforceForFunctionPrototypeMethods": false` allows extra parentheses around immediate `.call` and `.apply` method calls on function expressions and around function expressions in the same context. +* `"allowParensAfterCommentPattern": "any-string-pattern"` allows extra parentheses preceded by a comment that matches a regular expression. ### all @@ -322,6 +323,34 @@ const quux = (function () {}.apply()); ::: +### allowParensAfterCommentPattern + +To make this rule allow extra parentheses preceded by specific comments, set this option to a string pattern that will be passed to the [`RegExp` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp). + +Examples of **correct** code for this rule with the `"all"` and `{ "allowParensAfterCommentPattern": "@type" }` options: + +::: correct + +```js +/* eslint no-extra-parens: ["error", "all", { "allowParensAfterCommentPattern": "@type" }] */ + +const span = /**@type {HTMLSpanElement}*/(event.currentTarget); + +if (/** @type {Foo | Bar} */(options).baz) console.log('Lint free'); + +foo(/** @type {Bar} */ (bar), options, { + name: "name", + path: "path", +}); + +if (foo) { + /** @type {Bar} */ + (bar).prop = false; +} +``` + +::: + ### functions Examples of **incorrect** code for this rule with the `"functions"` option: diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js index 246a5a0d5e1e..75ac606ea747 100644 --- a/lib/rules/no-extra-parens.js +++ b/lib/rules/no-extra-parens.js @@ -52,7 +52,8 @@ module.exports = { enforceForArrowConditionals: { type: "boolean" }, enforceForSequenceExpressions: { type: "boolean" }, enforceForNewInMemberExpressions: { type: "boolean" }, - enforceForFunctionPrototypeMethods: { type: "boolean" } + enforceForFunctionPrototypeMethods: { type: "boolean" }, + allowParensAfterCommentPattern: { type: "string" } }, additionalProperties: false } @@ -86,6 +87,7 @@ module.exports = { context.options[1].enforceForNewInMemberExpressions === false; const IGNORE_FUNCTION_PROTOTYPE_METHODS = ALL_NODES && context.options[1] && context.options[1].enforceForFunctionPrototypeMethods === false; + const ALLOW_PARENS_AFTER_COMMENT_PATTERN = ALL_NODES && context.options[1] && context.options[1].allowParensAfterCommentPattern; const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" }); const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" }); @@ -402,6 +404,19 @@ module.exports = { if (isIIFE(node) && !isParenthesised(node.callee)) { return; } + + if (ALLOW_PARENS_AFTER_COMMENT_PATTERN) { + const commentsBeforeLeftParenToken = sourceCode.getCommentsBefore(leftParenToken); + const totalCommentsBeforeLeftParenTokenCount = commentsBeforeLeftParenToken.length; + const ignorePattern = new RegExp(ALLOW_PARENS_AFTER_COMMENT_PATTERN, "u"); + + if ( + totalCommentsBeforeLeftParenTokenCount > 0 && + ignorePattern.test(commentsBeforeLeftParenToken[totalCommentsBeforeLeftParenTokenCount - 1].value) + ) { + return; + } + } } /** diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js index 96ae9f5bddf9..3f57e5b2958b 100644 --- a/tests/lib/rules/no-extra-parens.js +++ b/tests/lib/rules/no-extra-parens.js @@ -738,8 +738,39 @@ ruleTester.run("no-extra-parens", rule, { }, { code: "(Object.prototype.toString.call())", - options: ["functions"], - parserOptions: { ecmaVersion: 2020 } + options: ["functions"] + }, + + // "allowParensAfterCommentPattern" option + { + code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);", + options: ["all", { allowParensAfterCommentPattern: "@type" }] + }, + { + code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');", + options: ["all", { allowParensAfterCommentPattern: "@type" }] + }, + { + code: ` + validate(/** @type {Schema} */ (schema), options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + options: ["all", { allowParensAfterCommentPattern: "@type" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + options: ["all", { allowParensAfterCommentPattern: "@type" }] + }, + { + code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));", + options: ["all", { allowParensAfterCommentPattern: "@type" }] } ], @@ -3192,6 +3223,160 @@ ruleTester.run("no-extra-parens", rule, { errors: [{ messageId: "unexpected" }] }, + // "allowParensAfterCommentPattern" option (off by default) + { + code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);", + output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;", + options: ["all"], + errors: [{ messageId: "unexpected" }] + }, + { + code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');", + output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');", + options: ["all"], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + validate(/** @type {Schema} */ (schema), options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + output: ` + validate(/** @type {Schema} */ schema, options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + options: ["all"], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + options.server.options.requestCert = false; + } + `, + options: ["all"], + errors: [{ messageId: "unexpected" }] + }, + { + code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));", + output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);", + options: ["all"], + errors: [{ messageId: "unexpected" }] + }, + { + code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);", + output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;", + options: ["all", { allowParensAfterCommentPattern: "invalid" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');", + output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');", + options: ["all", { allowParensAfterCommentPattern: "invalid" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + validate(/** @type {Schema} */ (schema), options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + output: ` + validate(/** @type {Schema} */ schema, options, { + name: "Dev Server", + baseDataPath: "options", + }); + `, + options: ["all", { allowParensAfterCommentPattern: "invalid" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + options.server.options.requestCert = false; + } + `, + options: ["all", { allowParensAfterCommentPattern: "invalid" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + /** extra coment */ + (options.server.options).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + /** extra coment */ + options.server.options.requestCert = false; + } + `, + options: ["all", { allowParensAfterCommentPattern: "@type" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + ((options.server.options)).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + (options.server.options).requestCert = false; + } + `, + options: ["all", { allowParensAfterCommentPattern: "@type" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: ` + if (condition) { + /** @type {ServerOptions} */ + let foo = "bar"; + (options.server.options).requestCert = false; + } + `, + output: ` + if (condition) { + /** @type {ServerOptions} */ + let foo = "bar"; + options.server.options.requestCert = false; + } + `, + options: ["all", { allowParensAfterCommentPattern: "@type" }], + errors: [{ messageId: "unexpected" }] + }, + { + code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));", + output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);", + options: ["all", { allowParensAfterCommentPattern: "invalid" }], + errors: [{ messageId: "unexpected" }] + }, + // Optional chaining { code: "var v = (obj?.aaa)?.aaa", From 7628403a57d9d9b4e2cb2b36309170900f58832e Mon Sep 17 00:00:00 2001 From: Amaresh S M Date: Tue, 29 Nov 2022 17:39:35 -0800 Subject: [PATCH 09/29] chore: add discord channel link (#16590) * chore: add discord channel link * Update config.yml * chore: Update .github/ISSUE_TEMPLATE/config.yml Co-authored-by: Nitin Kumar Co-authored-by: Nitin Kumar --- .github/ISSUE_TEMPLATE/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f98389b25f29..46ab7744eeb0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,3 +6,6 @@ contact_links: - name: 📝 Help with VS Code ESLint url: https://github.com/microsoft/vscode-eslint/issues/ about: Bugs and feature requests for the VS Code ESLint plugin + - name: Discord Channel + url: https://eslint.org/chat + about: Get the latest announcements, chat with developers and get help From b6ab030897d2e8b314b33a6502346a4ac45bb8da Mon Sep 17 00:00:00 2001 From: Strek Date: Thu, 1 Dec 2022 02:57:40 +0530 Subject: [PATCH 10/29] docs: add docs codeowners (#16601) * docs: add code owners * chore: update name * chore: update .github/CODEOWNERS Co-authored-by: Nicholas C. Zakas * Update .github/CODEOWNERS Co-authored-by: Nicholas C. Zakas --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000000..5496e79293f0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +/docs/ @eslint/website-team @eslint/eslint-team +* @eslint/eslint-team \ No newline at end of file From 57089b1ede624452bc94404b6e60d01d48cfd468 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Fri, 2 Dec 2022 19:33:41 +0100 Subject: [PATCH 11/29] docs: add a property assignment example for camelcase rule (#16605) --- docs/src/rules/camelcase.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/rules/camelcase.md b/docs/src/rules/camelcase.md index 41f3d65abcd8..46757fd53b06 100644 --- a/docs/src/rules/camelcase.md +++ b/docs/src/rules/camelcase.md @@ -126,6 +126,8 @@ Examples of **correct** code for this rule with the `{ "properties": "never" }` var obj = { my_pref: 1 }; + +obj.foo_bar = "baz"; ``` ::: From 0311d81834d675b8ae7cc92a460b37115edc4018 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Fri, 2 Dec 2022 13:57:35 -0500 Subject: [PATCH 12/29] docs: Configuring Plugins page intro, page tweaks, and rename (#16534) * docs: plugins config intro + tweaks * refactor intro/page name * refactor page to reflect parsers separate from plugins * copy edits * Apply suggestions from code review Co-authored-by: Nitin Kumar * Apply suggestions from code review Co-authored-by: Milos Djermanovic * Update docs/src/user-guide/configuring/plugins.md * change titles to non gerund + inline links * add custom environments bullet point * Apply suggestions from code review Co-authored-by: Milos Djermanovic * update anchor links Co-authored-by: Nitin Kumar Co-authored-by: Milos Djermanovic --- .../developer-guide/working-with-plugins.md | 4 +- .../configuring/configuration-files.md | 2 +- docs/src/user-guide/configuring/index.md | 6 +- docs/src/user-guide/configuring/plugins.md | 175 ++++++++++-------- 4 files changed, 99 insertions(+), 88 deletions(-) diff --git a/docs/src/developer-guide/working-with-plugins.md b/docs/src/developer-guide/working-with-plugins.md index f33cf4b37544..4ce91b22520f 100644 --- a/docs/src/developer-guide/working-with-plugins.md +++ b/docs/src/developer-guide/working-with-plugins.md @@ -144,7 +144,7 @@ overrides: processor: a-plugin/markdown ``` -See [Specifying Processor](../user-guide/configuring/plugins#specifying-processor) for details. +See [Specifying Processor](../user-guide/configuring/plugins#specify-a-processor) for details. #### File Extension-named Processor @@ -205,7 +205,7 @@ If the example plugin above were called `eslint-plugin-myPlugin`, the `myConfig` ``` -**Note:** Please note that configuration will not enable any of the plugin's rules by default, and instead should be treated as a standalone config. This means that you must specify your plugin name in the `plugins` array as well as any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring/plugins#configuring-plugins) for more information. +**Note:** Please note that configuration will not enable any of the plugin's rules by default, and instead should be treated as a standalone config. This means that you must specify your plugin name in the `plugins` array as well as any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring/plugins#configure-plugins) for more information. ### Peer Dependency diff --git a/docs/src/user-guide/configuring/configuration-files.md b/docs/src/user-guide/configuring/configuration-files.md index bf0534601bc4..54dc368ab881 100644 --- a/docs/src/user-guide/configuring/configuration-files.md +++ b/docs/src/user-guide/configuring/configuration-files.md @@ -281,7 +281,7 @@ module.exports = { A [plugin](https://eslint.org/docs/developer-guide/working-with-plugins) is an npm package that can add various extensions to ESLint. A plugin can perform numerous functions, including but not limited to adding new rules and exporting [shareable configurations](https://eslint.org/docs/developer-guide/working-with-plugins#configs-in-plugins). Make sure the package has been installed in a directory where ESLint can require it. -The `plugins` [property value](./plugins#configuring-plugins) can omit the `eslint-plugin-` prefix of the package name. +The `plugins` [property value](./plugins#configure-plugins) can omit the `eslint-plugin-` prefix of the package name. The `extends` property value can consist of: diff --git a/docs/src/user-guide/configuring/index.md b/docs/src/user-guide/configuring/index.md index 116544b69a3d..c71ccbf18b13 100644 --- a/docs/src/user-guide/configuring/index.md +++ b/docs/src/user-guide/configuring/index.md @@ -47,9 +47,9 @@ All of these options give you fine-grained control over how ESLint treats your c [**Plugins**](plugins) -* [Specifying Parser](./plugins#specifying-parser) -* [Specifying Processor](./plugins#specifying-processor) -* [Configuring Plugins](./plugins#configuring-plugins) +* [Configuring Plugins](./plugins#configure-plugins) +* [Specifying Processors](./plugins#specify-a-processor) +* [Configuring Parsers](./plugins#configure-a-parser) [**Ignoring Code**](ignoring-code) diff --git a/docs/src/user-guide/configuring/plugins.md b/docs/src/user-guide/configuring/plugins.md index d355c51200ce..7f3c521a2553 100644 --- a/docs/src/user-guide/configuring/plugins.md +++ b/docs/src/user-guide/configuring/plugins.md @@ -1,93 +1,25 @@ --- -title: Plugins +title: Plugins & Parsers eleventyNavigation: key: configuring plugins parent: configuring - title: Configuring Plugins + title: Configuring Plugins & Parsers order: 4 --- -## Specifying Parser +You can extend ESLint with plugins in a variety of different ways. Plugins can include: -By default, ESLint uses [Espree](https://github.com/eslint/espree) as its parser. You can optionally specify that a different parser should be used in your configuration file so long as the parser meets the following requirements: +* Custom rules to validate if your code meets a certain expectation, and what to do if it does not meet that expectation. +* Custom configurations. +* Custom environments. +* Custom processors to extract JavaScript code from other kinds of files or preprocess code before linting. -1. It must be a Node module loadable from the config file where the parser is used. Usually, this means you should install the parser package separately using npm. -1. It must conform to the [parser interface](../../developer-guide/working-with-custom-parsers). - -Note that even with these compatibilities, there are no guarantees that an external parser will work correctly with ESLint and ESLint will not fix bugs related to incompatibilities with other parsers. - -To indicate the npm module to use as your parser, specify it using the `parser` option in your `.eslintrc` file. For example, the following specifies to use Esprima instead of Espree: - -```json -{ - "parser": "esprima", - "rules": { - "semi": "error" - } -} -``` - -The following parsers are compatible with ESLint: - -* [Esprima](https://www.npmjs.com/package/esprima) -* [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) - A wrapper around the [Babel](https://babeljs.io) parser that makes it compatible with ESLint. -* [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint. - -Note when using a custom parser, the `parserOptions` configuration property is still required for ESLint to work properly with features not in ECMAScript 5 by default. Parsers are all passed `parserOptions` and may or may not use them to determine which features to enable. - -## Specifying Processor - -Plugins may provide processors. Processors can extract JavaScript code from other kinds of files, then let ESLint lint the JavaScript code or processors can convert JavaScript code in preprocessing for some purpose. - -To specify processors in a configuration file, use the `processor` key with the concatenated string of a plugin name and a processor name by a slash. For example, the following enables the processor `a-processor` that the plugin `a-plugin` provided: - -```json -{ - "plugins": ["a-plugin"], - "processor": "a-plugin/a-processor" -} -``` - -To specify processors for specific kinds of files, use the combination of the `overrides` key and the `processor` key. For example, the following uses the processor `a-plugin/markdown` for `*.md` files. - -```json -{ - "plugins": ["a-plugin"], - "overrides": [ - { - "files": ["*.md"], - "processor": "a-plugin/markdown" - } - ] -} -``` +You can also use custom parsers to convert JavaScript code into an abstract syntax tree for ESLint to evaluate. You might want to add a custom parser if your code isn't compatible with ESLint's default parser, Espree. -Processors may make named code blocks such as `0.js` and `1.js`. ESLint handles such a named code block as a child file of the original file. You can specify additional configurations for named code blocks in the `overrides` section of the config. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files. +## Configure Plugins -```json -{ - "plugins": ["a-plugin"], - "overrides": [ - { - "files": ["*.md"], - "processor": "a-plugin/markdown" - }, - { - "files": ["**/*.md/*.js"], - "rules": { - "strict": "off" - } - } - ] -} -``` - -ESLint checks the file path of named code blocks then ignores those if any `overrides` entry didn't match the file path. Be sure to add an `overrides` entry if you want to lint named code blocks other than `*.js`. - -## Configuring Plugins - -ESLint supports the use of third-party plugins. Before using the plugin, you have to install it using npm. +ESLint supports the use of third-party plugins. Before using a plugin, you have to install it using npm. To configure plugins inside of a configuration file, use the `plugins` key, which contains a list of plugin names. The `eslint-plugin-` prefix can be omitted from the plugin name. @@ -111,14 +43,16 @@ And in YAML: **Notes:** -1. Plugins are resolved relative to the config file. In other words, ESLint will load the plugin as a user would obtain by running `require('eslint-plugin-pluginname')` in the config file. +1. Plugins are resolved relative to the config file. In other words, ESLint loads the plugin as a user would obtain by running `require('eslint-plugin-pluginname')` in the config file. 2. Plugins in the base configuration (loaded by `extends` setting) are relative to the derived config file. For example, if `./.eslintrc` has `extends: ["foo"]` and the `eslint-config-foo` has `plugins: ["bar"]`, ESLint finds the `eslint-plugin-bar` from `./node_modules/` (rather than `./node_modules/eslint-config-foo/node_modules/`) or ancestor directories. Thus every plugin in the config file and base configurations is resolved uniquely. ### Naming convention #### Include a plugin -The `eslint-plugin-` prefix can be omitted for non-scoped packages +The `eslint-plugin-` prefix can be omitted for both non-scoped and scoped packages. + +A non-scoped package: ```js { @@ -130,7 +64,7 @@ The `eslint-plugin-` prefix can be omitted for non-scoped packages } ``` -The same rule does apply to scoped packages: +A scoped package: ```js { @@ -145,7 +79,7 @@ The same rule does apply to scoped packages: #### Use a plugin -When using rules, environments or configs defined by plugins, they must be referenced following the convention: +Rules, environments, and configurations defined in plugins must be referenced with the following convention: * `eslint-plugin-foo` → `foo/a-rule` * `@foo/eslint-plugin` → `@foo/a-config` @@ -178,3 +112,80 @@ For example: // ... } ``` + +### Specify a Processor + +Plugins may provide processors. Processors can extract JavaScript code from other kinds of files, then let ESLint lint the JavaScript code. Alternatively, processors can convert JavaScript code during preprocessing. + +To specify processors in a configuration file, use the `processor` key with the concatenated string of a plugin name and a processor name by a slash. For example, the following enables the processor `a-processor` that the plugin `a-plugin` provided: + +```json +{ + "plugins": ["a-plugin"], + "processor": "a-plugin/a-processor" +} +``` + +To specify processors for specific kinds of files, use the combination of the `overrides` key and the `processor` key. For example, the following uses the processor `a-plugin/markdown` for `*.md` files. + +```json +{ + "plugins": ["a-plugin"], + "overrides": [ + { + "files": ["*.md"], + "processor": "a-plugin/markdown" + } + ] +} +``` + +Processors may make named code blocks such as `0.js` and `1.js`. ESLint handles such a named code block as a child file of the original file. You can specify additional configurations for named code blocks in the `overrides` section of the config. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files. + +```json +{ + "plugins": ["a-plugin"], + "overrides": [ + { + "files": ["*.md"], + "processor": "a-plugin/markdown" + }, + { + "files": ["**/*.md/*.js"], + "rules": { + "strict": "off" + } + } + ] +} +``` + +ESLint checks the file path of named code blocks then ignores those if any `overrides` entry didn't match the file path. Be sure to add an `overrides` entry if you want to lint named code blocks other than `*.js`. + +## Configure a Parser + +By default, ESLint uses [Espree](https://github.com/eslint/espree) as its parser. You can optionally specify that a different parser should be used in your configuration file if the parser meets the following requirements: + +1. It must be a Node module loadable from the config file where the parser is used. Usually, this means you should install the parser package separately using npm. +1. It must conform to the [parser interface](../../developer-guide/working-with-custom-parsers). + +Note that even with these compatibilities, there are no guarantees that an external parser works correctly with ESLint. ESLint does not fix bugs related to incompatibilities with other parsers. + +To indicate the npm module to use as your parser, specify it using the `parser` option in your `.eslintrc` file. For example, the following specifies to use Esprima instead of Espree: + +```json +{ + "parser": "esprima", + "rules": { + "semi": "error" + } +} +``` + +The following parsers are compatible with ESLint: + +* [Esprima](https://www.npmjs.com/package/esprima) +* [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) - A wrapper around the [Babel](https://babeljs.io) parser that makes it compatible with ESLint. +* [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint. + +Note that when using a custom parser, the `parserOptions` configuration property is still required for ESLint to work properly with features not in ECMAScript 5 by default. Parsers are all passed `parserOptions` and may or may not use them to determine which features to enable. From 6a5f667378d889726e3289fb3552098da0cbf0bd Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 2 Dec 2022 16:38:01 -0500 Subject: [PATCH 13/29] Build: changelog update for 8.29.0 --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b8ce2a2fbf..f20de753cc1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +v8.29.0 - December 2, 2022 + +* [`0311d81`](https://github.com/eslint/eslint/commit/0311d81834d675b8ae7cc92a460b37115edc4018) docs: Configuring Plugins page intro, page tweaks, and rename (#16534) (Ben Perlmutter) +* [`57089b1`](https://github.com/eslint/eslint/commit/57089b1ede624452bc94404b6e60d01d48cfd468) docs: add a property assignment example for camelcase rule (#16605) (Milos Djermanovic) +* [`b6ab030`](https://github.com/eslint/eslint/commit/b6ab030897d2e8b314b33a6502346a4ac45bb8da) docs: add docs codeowners (#16601) (Strek) +* [`7628403`](https://github.com/eslint/eslint/commit/7628403a57d9d9b4e2cb2b36309170900f58832e) chore: add discord channel link (#16590) (Amaresh S M) +* [`49a07c5`](https://github.com/eslint/eslint/commit/49a07c52c5af7e98d161ff4acd44bbbe0aa6383b) feat: add `allowParensAfterCommentPattern` option to no-extra-parens (#16561) (Nitin Kumar) +* [`6380c87`](https://github.com/eslint/eslint/commit/6380c87c563be5dc78ce0ddd5c7409aaf71692bb) docs: fix sitemap and feed (#16592) (Milos Djermanovic) +* [`e6a865d`](https://github.com/eslint/eslint/commit/e6a865d70aed9e1c07be712e40c38da1a5dda849) feat: `prefer-named-capture-group` add suggestions (#16544) (Josh Goldberg) +* [`ade621d`](https://github.com/eslint/eslint/commit/ade621dd12fcd3b65644bb3468248cc040db756c) docs: perf debounce the search query (#16586) (Shanmughapriyan S) +* [`a91332b`](https://github.com/eslint/eslint/commit/a91332b8bd9adfa2aa8110071bdf73f56d400050) feat: In no-invalid-regexp validate flags also for non-literal patterns (#16583) (trosos) +* [`fbcf3ab`](https://github.com/eslint/eslint/commit/fbcf3abd54dd20aec3c695cacece56493633c97f) docs: fix searchbar clear button (#16585) (Shanmughapriyan S) +* [`f894035`](https://github.com/eslint/eslint/commit/f89403553b31d24f4fc841424cc7dcb8c3ef689f) docs: HTTPS link to yeoman.io (#16582) (Christian Oliff) +* [`de12b26`](https://github.com/eslint/eslint/commit/de12b266f2aa6f063d0af888b8f0de41d09ec33f) docs: Update configuration file pages (#16509) (Ben Perlmutter) +* [`f5808cb`](https://github.com/eslint/eslint/commit/f5808cb51529174a67b4938223f06435ad6d5118) chore: fix rule doc headers check (#16564) (Milos Djermanovic) +* [`1ae9f20`](https://github.com/eslint/eslint/commit/1ae9f2067442434c6ccc6b41703624b302d17c67) docs: update correct code examples for `no-extra-parens` rule (#16560) (Nitin Kumar) + v8.28.0 - November 18, 2022 * [`34c05a7`](https://github.com/eslint/eslint/commit/34c05a779ada3142995392ae12978461900088df) docs: Language Options page intro and tweaks (#16511) (Ben Perlmutter) From d3e4b59f63e53436080b8da827521d6b41a72cea Mon Sep 17 00:00:00 2001 From: ESLint Jenkins Date: Fri, 2 Dec 2022 16:38:01 -0500 Subject: [PATCH 14/29] 8.29.0 --- docs/package.json | 2 +- docs/src/_data/rules.json | 2 +- docs/src/_data/rules_meta.json | 3 ++- docs/src/user-guide/formatters/html-formatter-example.html | 2 +- package.json | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index 1eed49cdc7ad..910566158337 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "docs-eslint", "private": true, - "version": "8.28.0", + "version": "8.29.0", "description": "", "main": "index.js", "keywords": [], diff --git a/docs/src/_data/rules.json b/docs/src/_data/rules.json index 11a3453f59d8..94f3eacaff53 100644 --- a/docs/src/_data/rules.json +++ b/docs/src/_data/rules.json @@ -1298,7 +1298,7 @@ "description": "Enforce using named capture group in regular expression", "recommended": false, "fixable": false, - "hasSuggestions": false + "hasSuggestions": true }, { "name": "prefer-numeric-literals", diff --git a/docs/src/_data/rules_meta.json b/docs/src/_data/rules_meta.json index 5028ea0260d3..08a2e1b75404 100644 --- a/docs/src/_data/rules_meta.json +++ b/docs/src/_data/rules_meta.json @@ -2116,7 +2116,8 @@ "description": "Enforce using named capture group in regular expression", "recommended": false, "url": "https://eslint.org/docs/rules/prefer-named-capture-group" - } + }, + "hasSuggestions": true }, "prefer-numeric-literals": { "type": "suggestion", diff --git a/docs/src/user-guide/formatters/html-formatter-example.html b/docs/src/user-guide/formatters/html-formatter-example.html index 7c90746fc5a4..3023181d00d5 100644 --- a/docs/src/user-guide/formatters/html-formatter-example.html +++ b/docs/src/user-guide/formatters/html-formatter-example.html @@ -118,7 +118,7 @@

ESLint Report

- 9 problems (5 errors, 4 warnings) - Generated on Fri Nov 18 2022 16:27:56 GMT-0500 (Eastern Standard Time) + 9 problems (5 errors, 4 warnings) - Generated on Fri Dec 02 2022 16:38:02 GMT-0500 (Eastern Standard Time)
diff --git a/package.json b/package.json index b29ddd74fbfb..cc50b2ad8361 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint", - "version": "8.28.0", + "version": "8.29.0", "author": "Nicholas C. Zakas ", "description": "An AST-based pattern checker for JavaScript.", "bin": { From e6cb05aa35bafb9e88f161ad1fa6b01942a7c13c Mon Sep 17 00:00:00 2001 From: Sam Chen Date: Sun, 4 Dec 2022 22:24:56 +0800 Subject: [PATCH 15/29] docs: fix css leaking (#16603) --- docs/src/assets/scss/components/rules.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/assets/scss/components/rules.scss b/docs/src/assets/scss/components/rules.scss index 423e0d2fb628..4e0f4619c211 100644 --- a/docs/src/assets/scss/components/rules.scss +++ b/docs/src/assets/scss/components/rules.scss @@ -65,7 +65,7 @@ } } -.rule { +.rule:not(.token) { border-radius: var(--border-radius); background-color: var(--lightest-background-color); display: flex; From 8ba124cfd8aaf01d14ccbcb1654798624948fb0a Mon Sep 17 00:00:00 2001 From: Pavel <104815060+ArdRhena@users.noreply.github.com> Date: Mon, 5 Dec 2022 10:48:37 +0700 Subject: [PATCH 16/29] docs: update the `prefer-const` example (#16607) --- docs/src/rules/prefer-const.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/rules/prefer-const.md b/docs/src/rules/prefer-const.md index 83d29e58273c..19801eb952a2 100644 --- a/docs/src/rules/prefer-const.md +++ b/docs/src/rules/prefer-const.md @@ -105,7 +105,7 @@ for (const a of [1, 2, 3]) { // `end` is never reassigned, but we cannot separate the declarations without modifying the scope. for (let i = 0, end = 10; i < end; ++i) { - console.log(a); + console.log(i); } // `predicate` is only assigned once but cannot be separately declared as `const` From dfc7ec11b11b56daaa10e8e6d08c5cddfc8c2c59 Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Tue, 6 Dec 2022 10:54:56 -0500 Subject: [PATCH 17/29] docs: Formatters page updates (#16566) * docs: Formatters page updates add more information about the built-in formatters Fixes #16476 * add formatter text generation * fix issue and rename manifest * fix manifest formatting issues * restore generated page to state of eslint/eslint:main * rename and refactor as json * fix template spacing * Apply suggestions from code review Co-authored-by: Milos Djermanovic Co-authored-by: Milos Djermanovic --- Makefile.js | 6 ++- .../formatters/formatters-meta.json | 46 +++++++++++++++++++ templates/formatter-examples.md.ejs | 23 +++++++--- 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 lib/cli-engine/formatters/formatters-meta.json diff --git a/Makefile.js b/Makefile.js index e85514db9d90..426dd9b717ad 100644 --- a/Makefile.js +++ b/Makefile.js @@ -447,8 +447,9 @@ function lintMarkdown(files) { */ function getFormatterResults() { const stripAnsi = require("strip-ansi"); + const formattersMetadata = require("./lib/cli-engine/formatters/formatters-meta.json"); - const formatterFiles = fs.readdirSync("./lib/cli-engine/formatters/"), + const formatterFiles = fs.readdirSync("./lib/cli-engine/formatters/").filter(fileName => !fileName.includes("formatters-meta.json")), rules = { "no-else-return": "warn", indent: ["warn", 4], @@ -489,7 +490,8 @@ function getFormatterResults() { ); data.formatterResults[name] = { - result: stripAnsi(formattedOutput) + result: stripAnsi(formattedOutput), + description: formattersMetadata.find(formatter => formatter.name === name).description }; } return data; diff --git a/lib/cli-engine/formatters/formatters-meta.json b/lib/cli-engine/formatters/formatters-meta.json new file mode 100644 index 000000000000..a26ce8d2874f --- /dev/null +++ b/lib/cli-engine/formatters/formatters-meta.json @@ -0,0 +1,46 @@ +[ + { + "name": "checkstyle", + "description": "Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format." + }, + { + "name": "compact", + "description": "Human-readable output format. Mimics the default output of JSHint." + }, + { + "name": "html", + "description": "Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser." + }, + { + "name": "jslint-xml", + "description": "Outputs results to format compatible with the [JSLint Jenkins plugin](https://plugins.jenkins.io/jslint/)." + }, + { + "name": "json-with-metadata", + "description": "Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.\n\nAlternatively, you can use the [ESLint Node.js API](../../developer-guide/nodejs-api) to programmatically use ESLint." + }, + { + "name": "json", + "description": "Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.\n\nAlternatively, you can use the [ESLint Node.js API](../../developer-guide/nodejs-api) to programmatically use ESLint." + }, + { + "name": "junit", + "description": "Outputs results to format compatible with the [JUnit Jenkins plugin](https://plugins.jenkins.io/junit/)." + }, + { + "name": "stylish", + "description": "Human-readable output format. This is the default formatter." + }, + { + "name": "tap", + "description": "Outputs results to the [Test Anything Protocol (TAP)](https://testanything.org/) specification format." + }, + { + "name": "unix", + "description": "Outputs results to a format similar to many commands in UNIX-like systems. Parsable with tools such as [grep](https://www.gnu.org/software/grep/manual/grep.html), [sed](https://www.gnu.org/software/sed/manual/sed.html), and [awk](https://www.gnu.org/software/gawk/manual/gawk.html)." + }, + { + "name": "visualstudio", + "description": "Outputs results to format compatible with the integrated terminal of the [Visual Studio](https://visualstudio.microsoft.com/) IDE. When using Visual Studio, you can click on the linting results in the integrated terminal to go to the issue in the source code." + } +] \ No newline at end of file diff --git a/templates/formatter-examples.md.ejs b/templates/formatter-examples.md.ejs index 218cd8777c36..fb023798a678 100644 --- a/templates/formatter-examples.md.ejs +++ b/templates/formatter-examples.md.ejs @@ -10,7 +10,7 @@ edit_link: https://github.com/eslint/eslint/edit/main/templates/formatter-exampl ESLint comes with several built-in formatters to control the appearance of the linting results, and supports third-party formatters as well. -You can specify a formatter using the `--format` or `-f` flag on the command line. For example, `--format json` uses the `json` formatter. +You can specify a formatter using the `--format` or `-f` flag in the CLI. For example, `--format json` uses the `json` formatter. The built-in formatter options are: @@ -20,9 +20,9 @@ The built-in formatter options are: ## Example Source -Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc` configuration shown below. +Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc.json` configuration shown below. -### `fullOfProblems.js` +`fullOfProblems.js`: ```js function addOne(i) { @@ -34,7 +34,7 @@ function addOne(i) { }; ``` -### `.eslintrc` +`.eslintrc.json`: ```json { @@ -49,17 +49,26 @@ function addOne(i) { } ``` -## Output Examples +Tests the formatters with the CLI: + +```shell +npx eslint --format fullOfProblems.js +``` + +## Built-In Formatter Options <% Object.keys(formatterResults).forEach(function(formatterName) { -%> ### <%= formatterName %> -<% if (formatterName !== "html") { -%> +<%= formatterResults[formatterName].description %> + +Example output: + +<% if (formatterName !== "html") { -%> ```text <%= formatterResults[formatterName].result %> ``` <% } else {-%> - <% } -%> <% }) -%> From 6bef1350e692c818c55c6d2074c12506e98cdf4f Mon Sep 17 00:00:00 2001 From: Tanuj Kanti <86398394+Tanujkanti4441@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:15:09 +0530 Subject: [PATCH 18/29] docs: don't apply layouts to html formatter example (#16591) * fix: font, color and table flow of formatters-example page * fix: add html-formatter-example.json file * fix: table color on theme change * fix: remove additional changes in html-formatter-example.html --- docs/src/user-guide/formatters/html-formatter-example.html | 2 +- docs/src/user-guide/formatters/html-formatter-example.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 docs/src/user-guide/formatters/html-formatter-example.json diff --git a/docs/src/user-guide/formatters/html-formatter-example.html b/docs/src/user-guide/formatters/html-formatter-example.html index 3023181d00d5..b8ef2493d3b2 100644 --- a/docs/src/user-guide/formatters/html-formatter-example.html +++ b/docs/src/user-guide/formatters/html-formatter-example.html @@ -225,4 +225,4 @@

ESLint Report

} - + \ No newline at end of file diff --git a/docs/src/user-guide/formatters/html-formatter-example.json b/docs/src/user-guide/formatters/html-formatter-example.json new file mode 100644 index 000000000000..6070c859e9ef --- /dev/null +++ b/docs/src/user-guide/formatters/html-formatter-example.json @@ -0,0 +1,3 @@ +{ + "layout": false +} \ No newline at end of file From 7276fe5776f03fb90e575ed63a9b1a6766993e42 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Wed, 7 Dec 2022 22:55:28 +0100 Subject: [PATCH 19/29] docs: Fix anchor in URL (#16628) * docs: Fix anchor in URL * Update docs/src/user-guide/configuring/configuration-files.md Co-authored-by: Amaresh S M Co-authored-by: Milos Djermanovic Co-authored-by: Amaresh S M --- docs/src/user-guide/configuring/configuration-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/user-guide/configuring/configuration-files.md b/docs/src/user-guide/configuring/configuration-files.md index 54dc368ab881..8c4f0b19b9ee 100644 --- a/docs/src/user-guide/configuring/configuration-files.md +++ b/docs/src/user-guide/configuring/configuration-files.md @@ -424,7 +424,7 @@ If a config is provided via the `--config` CLI option, the glob patterns in the If you specified directories with CLI (e.g., `eslint lib`), ESLint searches target files in the directory to lint. The target files are `*.js` or the files that match any of `overrides` entries (but exclude entries that are any of `files` end with `*`). -If you specified the [`--ext`](https://eslint.org/docs/user-guide/command-line-interface#ext) command line option along with directories, the target files are only the files that have specified file extensions regardless of `overrides` entries. +If you specified the [`--ext`](../command-line-interface#--ext) command line option along with directories, the target files are only the files that have specified file extensions regardless of `overrides` entries. ## Personal Configuration Files (deprecated) From 75276c9bc7c4bc013fc6bdf277353c979934d73b Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Thu, 8 Dec 2022 19:50:41 +0100 Subject: [PATCH 20/29] docs: reorder options in no-unused-vars (#16625) Refs #16616 --- docs/src/rules/no-unused-vars.md | 120 +++++++++++++++---------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/docs/src/rules/no-unused-vars.md b/docs/src/rules/no-unused-vars.md index 718d3cd4f429..1b3e59ce93b9 100644 --- a/docs/src/rules/no-unused-vars.md +++ b/docs/src/rules/no-unused-vars.md @@ -247,25 +247,6 @@ Examples of **correct** code for the `{ "args": "none" }` option: ::: -### ignoreRestSiblings - -The `ignoreRestSiblings` option is a boolean (default: `false`). Using a [Rest Property](https://github.com/tc39/proposal-object-rest-spread) it is possible to "omit" properties from an object, but by default the sibling properties are marked as "unused". With this option enabled the rest property's siblings are ignored. - -Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option: - -::: correct - -```js -/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/ -// 'foo' and 'bar' were ignored because they have a rest property sibling. -var { foo, ...coords } = data; - -var bar; -({ bar, ...coords } = data); -``` - -::: - ### argsIgnorePattern The `argsIgnorePattern` option specifies exceptions not to check for usage: arguments whose names match a regexp pattern. For example, variables whose names begin with an underscore. @@ -285,47 +266,6 @@ foo(); ::: -### destructuredArrayIgnorePattern - -The `destructuredArrayIgnorePattern` option specifies exceptions not to check for usage: elements of array destructuring patterns whose names match a regexp pattern. For example, variables whose names begin with an underscore. - -Examples of **correct** code for the `{ "destructuredArrayIgnorePattern": "^_" }` option: - -::: correct - -```js -/*eslint no-unused-vars: ["error", { "destructuredArrayIgnorePattern": "^_" }]*/ - -const [a, _b, c] = ["a", "b", "c"]; -console.log(a+c); - -const { x: [_a, foo] } = bar; -console.log(foo); - -function baz([_c, x]) { - x; -} -baz(); - -function test({p: [_q, r]}) { - r; -} -test(); - -let _m, n; -foo.forEach(item => { - [_m, n] = item; - console.log(n); -}); - -let _o, p; -_o = 1; -[_o, p] = foo; -p; -``` - -::: - ### caughtErrors The `caughtErrors` option is used for `catch` block arguments validation. @@ -395,6 +335,66 @@ try { ::: +### destructuredArrayIgnorePattern + +The `destructuredArrayIgnorePattern` option specifies exceptions not to check for usage: elements of array destructuring patterns whose names match a regexp pattern. For example, variables whose names begin with an underscore. + +Examples of **correct** code for the `{ "destructuredArrayIgnorePattern": "^_" }` option: + +::: correct + +```js +/*eslint no-unused-vars: ["error", { "destructuredArrayIgnorePattern": "^_" }]*/ + +const [a, _b, c] = ["a", "b", "c"]; +console.log(a+c); + +const { x: [_a, foo] } = bar; +console.log(foo); + +function baz([_c, x]) { + x; +} +baz(); + +function test({p: [_q, r]}) { + r; +} +test(); + +let _m, n; +foo.forEach(item => { + [_m, n] = item; + console.log(n); +}); + +let _o, p; +_o = 1; +[_o, p] = foo; +p; +``` + +::: + +### ignoreRestSiblings + +The `ignoreRestSiblings` option is a boolean (default: `false`). Using a [Rest Property](https://github.com/tc39/proposal-object-rest-spread) it is possible to "omit" properties from an object, but by default the sibling properties are marked as "unused". With this option enabled the rest property's siblings are ignored. + +Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option: + +::: correct + +```js +/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/ +// 'foo' and 'bar' were ignored because they have a rest property sibling. +var { foo, ...coords } = data; + +var bar; +({ bar, ...coords } = data); +``` + +::: + ## When Not To Use It If you don't want to be notified about unused variables or function arguments, you can safely turn this rule off. From fa2c64be10d5854fb586c20957737d7d2da1975a Mon Sep 17 00:00:00 2001 From: Percy Ma Date: Fri, 9 Dec 2022 02:55:24 +0800 Subject: [PATCH 21/29] docs: use relative links for internal links (#16631) --- docs/src/developer-guide/code-conventions.md | 2 +- .../developer-guide/contributing/new-rules.md | 2 +- .../contributing/reporting-bugs.md | 2 +- .../contributing/rule-changes.md | 2 +- .../contributing/working-on-issues.md | 4 +- docs/src/developer-guide/nodejs-api.md | 8 +- docs/src/developer-guide/selectors.md | 2 +- .../working-with-custom-formatters.md | 2 +- .../developer-guide/working-with-plugins.md | 2 +- .../src/developer-guide/working-with-rules.md | 8 +- docs/src/library/rule-categories.md | 2 +- docs/src/maintainer-guide/governance.md | 8 +- docs/src/rules/id-denylist.md | 2 +- docs/src/rules/indent-legacy.md | 2 +- docs/src/rules/indent.md | 2 +- .../rules/nonblock-statement-body-position.md | 4 +- docs/src/rules/rest-spread-spacing.md | 2 +- docs/src/rules/strict.md | 8 +- .../configuring/configuration-files-new.md | 2 +- .../configuring/configuration-files.md | 18 +-- docs/src/user-guide/getting-started.md | 8 +- docs/src/user-guide/migrating-from-jscs.md | 2 +- docs/src/user-guide/migrating-to-1.0.0.md | 138 +++++++++--------- docs/src/user-guide/migrating-to-2.0.0.md | 32 ++-- docs/src/user-guide/migrating-to-3.0.0.md | 10 +- docs/src/user-guide/migrating-to-4.0.0.md | 16 +- docs/src/user-guide/migrating-to-5.0.0.md | 22 +-- docs/src/user-guide/migrating-to-6.0.0.md | 30 ++-- docs/src/user-guide/migrating-to-7.0.0.md | 50 +++---- docs/src/user-guide/migrating-to-8.0.0.md | 16 +- 30 files changed, 204 insertions(+), 204 deletions(-) diff --git a/docs/src/developer-guide/code-conventions.md b/docs/src/developer-guide/code-conventions.md index e5f5a4482814..089e1247abfd 100644 --- a/docs/src/developer-guide/code-conventions.md +++ b/docs/src/developer-guide/code-conventions.md @@ -7,7 +7,7 @@ Code conventions for ESLint are determined by The rationales for the specific rules in use can be found by looking to the project documentation for any given rule. If the rule is one of our own, see -our own [rule documentation](https://eslint.org/docs/rules/) and otherwise, see +our own [rule documentation](../rules/) and otherwise, see the documentation of the plugin in which the rule can be found. If you need to make changes to a `package.json` file, please see the diff --git a/docs/src/developer-guide/contributing/new-rules.md b/docs/src/developer-guide/contributing/new-rules.md index 0b4cd1bb95a0..28514e85c756 100644 --- a/docs/src/developer-guide/contributing/new-rules.md +++ b/docs/src/developer-guide/contributing/new-rules.md @@ -22,7 +22,7 @@ Even though these are the formal criteria for inclusion, each rule is evaluated ## Proposing a Rule -If you want to propose a new rule, please see how to [create a pull request](/docs/developer-guide/contributing/pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new/choose). +If you want to propose a new rule, please see how to [create a pull request](pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new/choose). We need all of this information in order to determine whether or not the rule is a good core rule candidate. diff --git a/docs/src/developer-guide/contributing/reporting-bugs.md b/docs/src/developer-guide/contributing/reporting-bugs.md index f0ec2fe54e44..09a60ccd83a5 100644 --- a/docs/src/developer-guide/contributing/reporting-bugs.md +++ b/docs/src/developer-guide/contributing/reporting-bugs.md @@ -3,7 +3,7 @@ title: Reporting Bugs --- -If you think you've found a bug in ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) or a [pull request](/docs/developer-guide/contributing/pull-requests) on GitHub. +If you think you've found a bug in ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) or a [pull request](pull-requests) on GitHub. Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that's time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues. diff --git a/docs/src/developer-guide/contributing/rule-changes.md b/docs/src/developer-guide/contributing/rule-changes.md index 7a880e0caca1..14de4495df31 100644 --- a/docs/src/developer-guide/contributing/rule-changes.md +++ b/docs/src/developer-guide/contributing/rule-changes.md @@ -7,7 +7,7 @@ Occasionally, a core ESLint rule needs to be changed. This is not necessarily a ## Proposing a Rule Change -To propose a change to an existing rule, [create a pull request](/docs/developer-guide/contributing/pull-requests) or [new issue](https://github.com/eslint/eslint/issues/new/choose) and fill out the template. +To propose a change to an existing rule, [create a pull request](pull-requests) or [new issue](https://github.com/eslint/eslint/issues/new/choose) and fill out the template. We need all of this information in order to determine whether or not the change is a good candidate for inclusion. diff --git a/docs/src/developer-guide/contributing/working-on-issues.md b/docs/src/developer-guide/contributing/working-on-issues.md index fabb9b1881d3..5c9298448432 100644 --- a/docs/src/developer-guide/contributing/working-on-issues.md +++ b/docs/src/developer-guide/contributing/working-on-issues.md @@ -7,10 +7,10 @@ Our public [issues tracker](https://github.com/eslint/eslint/issues) lists all o ## Issue Labels -We use labels to indicate the status of issues. The most complete documentation on the labels is found in the [Maintainer Guide](https://eslint.org/docs/maintainer-guide/issues.html#when-an-issue-is-opened), but most contributors should find the information on this page sufficient. The most important questions that labels can help you, as a contributor, answer are: +We use labels to indicate the status of issues. The most complete documentation on the labels is found in the [Maintainer Guide](../../maintainer-guide/issues#when-an-issue-is-opened), but most contributors should find the information on this page sufficient. The most important questions that labels can help you, as a contributor, answer are: 1. Is this issue available for me to work on? If you have little or no experience contributing to ESLint, the [`good first issue`](https://github.com/eslint/eslint/labels/good%20first%20issue) label marks appropriate issues. Otherwise, the [`help wanted`](https://github.com/eslint/eslint/labels/help%20wanted) label is an invitation to work on the issue. If you have more experience, you can try working on other issues labeled [`accepted`](https://github.com/eslint/eslint/labels/accepted). Conversely, issues not yet ready to work on are labeled `triage`, `evaluating`, and/or `needs bikeshedding`, and issues that cannot currently be worked on because of something else, such as a bug in a dependency, are labeled `blocked`. -1. What is this issue about? Labels describing the nature of issues include `bug`, `enhancement`, `feature`, `question`, `rule`, `documentation`, `core`, `build`, `cli`, `infrastructure`, `breaking`, and `chore`. These are documented in the [Maintainer Guide](https://eslint.org/docs/maintainer-guide/issues.html#types-of-issues). +1. What is this issue about? Labels describing the nature of issues include `bug`, `enhancement`, `feature`, `question`, `rule`, `documentation`, `core`, `build`, `cli`, `infrastructure`, `breaking`, and `chore`. These are documented in the [Maintainer Guide](../../maintainer-guide/issues#types-of-issues). 1. What is the priority of this issue? Because we have a lot of issues, we prioritize certain issues above others. The following is the list of priorities, from highest to lowest: 1. **Bugs** - problems with the project are actively affecting users. We want to get these resolved as quickly as possible. diff --git a/docs/src/developer-guide/nodejs-api.md b/docs/src/developer-guide/nodejs-api.md index 30b75ccecd98..833a678d7220 100644 --- a/docs/src/developer-guide/nodejs-api.md +++ b/docs/src/developer-guide/nodejs-api.md @@ -489,8 +489,8 @@ The most important method on `Linter` is `verify()`, which initiates linting of * **Note**: If you want to lint text and have your configuration be read and processed, use [`ESLint#lintFiles()`][eslint-lintfiles] or [`ESLint#lintText()`][eslint-linttext] instead. * `options` - (optional) Additional options for this run. * `filename` - (optional) the filename to associate with the source code. - * `preprocess` - (optional) A function that [Processors in Plugins](/docs/developer-guide/working-with-plugins#processors-in-plugins) documentation describes as the `preprocess` method. - * `postprocess` - (optional) A function that [Processors in Plugins](/docs/developer-guide/working-with-plugins#processors-in-plugins) documentation describes as the `postprocess` method. + * `preprocess` - (optional) A function that [Processors in Plugins](working-with-plugins#processors-in-plugins) documentation describes as the `preprocess` method. + * `postprocess` - (optional) A function that [Processors in Plugins](working-with-plugins#processors-in-plugins) documentation describes as the `postprocess` method. * `filterCodeBlock` - (optional) A function that decides which code blocks the linter should adopt. The function receives two arguments. The first argument is the virtual filename of a code block. The second argument is the text of the code block. If the function returned `true` then the linter adopts the code block. If the function was omitted, the linter adopts only `*.js` code blocks. If you provided a `filterCodeBlock` function, it overrides this default behavior, so the linter doesn't adopt `*.js` code blocks automatically. * `disableFixes` - (optional) when set to `true`, the linter doesn't make either the `fix` or `suggestions` property of the lint result. * `allowInlineConfig` - (optional) set to `false` to disable inline comments from changing ESLint rules. @@ -686,7 +686,7 @@ Map { ### Linter#defineParser Each instance of `Linter` holds a map of custom parsers. If you want to define a parser programmatically, you can add this function -with the name of the parser as first argument and the [parser object](/docs/developer-guide/working-with-custom-parsers) as second argument. The default `"espree"` parser will already be loaded for every `Linter` instance. +with the name of the parser as first argument and the [parser object](working-with-custom-parsers) as second argument. The default `"espree"` parser will already be loaded for every `Linter` instance. ```js const Linter = require("eslint").Linter; @@ -918,7 +918,7 @@ ruleTester.run("my-rule", myRule, { --- [configuration object]: ../user-guide/configuring/ -[builtin-formatters]: https://eslint.org/docs/user-guide/formatters/ +[builtin-formatters]: ../user-guide/formatters/ [third-party-formatters]: https://www.npmjs.com/search?q=eslintformatter [eslint-lintfiles]: #-eslintlintfilespatterns [eslint-linttext]: #-eslintlinttextcode-options diff --git a/docs/src/developer-guide/selectors.md b/docs/src/developer-guide/selectors.md index 4be7795d2870..5ea700dead10 100644 --- a/docs/src/developer-guide/selectors.md +++ b/docs/src/developer-guide/selectors.md @@ -93,7 +93,7 @@ If multiple selectors have equal specificity, their listeners will be called in ### Restricting syntax with selectors -With the [no-restricted-syntax](/docs/rules/no-restricted-syntax) rule, you can restrict the usage of particular syntax in your code. For example, you can use the following configuration to disallow using `if` statements that do not have block statements as their body: +With the [no-restricted-syntax](../rules/no-restricted-syntax) rule, you can restrict the usage of particular syntax in your code. For example, you can use the following configuration to disallow using `if` statements that do not have block statements as their body: ```json { diff --git a/docs/src/developer-guide/working-with-custom-formatters.md b/docs/src/developer-guide/working-with-custom-formatters.md index c52d373829d3..78bcb67abb8a 100644 --- a/docs/src/developer-guide/working-with-custom-formatters.md +++ b/docs/src/developer-guide/working-with-custom-formatters.md @@ -376,7 +376,7 @@ error semi ### Complex Argument Passing -If you find the custom formatter pattern doesn't provide enough options for the way you'd like to format ESLint results, the best option is to use ESLint's built-in [JSON formatter](https://eslint.org/docs/user-guide/formatters/) and pipe the output to a second program. For example: +If you find the custom formatter pattern doesn't provide enough options for the way you'd like to format ESLint results, the best option is to use ESLint's built-in [JSON formatter](../user-guide/formatters/) and pipe the output to a second program. For example: ```bash eslint -f json src/ | your-program-that-reads-JSON --option diff --git a/docs/src/developer-guide/working-with-plugins.md b/docs/src/developer-guide/working-with-plugins.md index 4ce91b22520f..dc032922eb35 100644 --- a/docs/src/developer-guide/working-with-plugins.md +++ b/docs/src/developer-guide/working-with-plugins.md @@ -222,7 +222,7 @@ The plugin support was introduced in ESLint version `0.8.0`. Ensure the `peerDep ### Testing -ESLint provides the [`RuleTester`](/docs/developer-guide/nodejs-api#ruletester) utility to make it easy to test the rules of your plugin. +ESLint provides the [`RuleTester`](nodejs-api#ruletester) utility to make it easy to test the rules of your plugin. ### Linting diff --git a/docs/src/developer-guide/working-with-rules.md b/docs/src/developer-guide/working-with-rules.md index a11617239ac6..0e92ccfe748e 100644 --- a/docs/src/developer-guide/working-with-rules.md +++ b/docs/src/developer-guide/working-with-rules.md @@ -129,8 +129,8 @@ The `context` object contains additional functionality that is helpful for rules * `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. +* `options` - an array of the [configured options](../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](../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.) @@ -373,7 +373,7 @@ Best practices for fixes: ({ "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. + * 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. @@ -714,7 +714,7 @@ You can access that code path objects with five events related to code paths. Each bundled rule for ESLint core must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if the rule source file is `lib/rules/foo.js` then the test file should be `tests/lib/rules/foo.js`. -ESLint provides the [`RuleTester`](/docs/developer-guide/nodejs-api#ruletester) utility to make it easy to write tests for rules. +ESLint provides the [`RuleTester`](nodejs-api#ruletester) utility to make it easy to write tests for rules. ## Performance Testing diff --git a/docs/src/library/rule-categories.md b/docs/src/library/rule-categories.md index 9f6688f8a738..8934fe7ecace 100644 --- a/docs/src/library/rule-categories.md +++ b/docs/src/library/rule-categories.md @@ -4,7 +4,7 @@ title: Rule categories ## Rule categories -The rule categories—namely “recommended”, “fixable”, and “hasSuggestions”—are shown in the [rules page](/rules/). They are rendered using the `ruleCategories` macro (imported from `/components/rule-categories.macro.html`). There is also an individual macro for each category type. +The rule categories—namely “recommended”, “fixable”, and “hasSuggestions”—are shown in the [rules page](../rules/). They are rendered using the `ruleCategories` macro (imported from `/components/rule-categories.macro.html`). There is also an individual macro for each category type. ```html { % from 'components/rule-categories.macro.html' import ruleCategories % } diff --git a/docs/src/maintainer-guide/governance.md b/docs/src/maintainer-guide/governance.md index 5bbe24c1f08d..6b77d9f89528 100644 --- a/docs/src/maintainer-guide/governance.md +++ b/docs/src/maintainer-guide/governance.md @@ -36,8 +36,8 @@ Website Team Members are community members who have shown that they are committe * Are expected to delete their public branches when they are no longer necessary. * Must submit pull requests for all changes. * Have their work reviewed by Reviewers and TSC members before acceptance into the repository. -* May label and close website-related issues (see [Managing Issues](issues.html)) -* May merge some pull requests (see [Managing Pull Requests](pullrequests.html)) +* May label and close website-related issues (see [Managing Issues](issues)) +* May merge some pull requests (see [Managing Pull Requests](pullrequests)) To become a Website Team Member: @@ -59,8 +59,8 @@ Committers: * Are expected to delete their public branches when they are no longer necessary. * Must submit pull requests for all changes. * Have their work reviewed by TSC members before acceptance into the repository. -* May label and close issues (see [Managing Issues](issues.html)) -* May merge some pull requests (see [Managing Pull Requests](pullrequests.html)) +* May label and close issues (see [Managing Issues](issues)) +* May merge some pull requests (see [Managing Pull Requests](pullrequests)) To become a Committer: diff --git a/docs/src/rules/id-denylist.md b/docs/src/rules/id-denylist.md index 49a84ce19d4f..d841f37d2dd0 100644 --- a/docs/src/rules/id-denylist.md +++ b/docs/src/rules/id-denylist.md @@ -37,7 +37,7 @@ For example, to restrict the use of common generic identifiers: } ``` -**Note:** The first element of the array is for the rule severity (see [configuring rules](/docs/latest/user-guide/configuring/rules). The other elements in the array are the identifiers that you want to disallow. +**Note:** The first element of the array is for the rule severity (see [configuring rules](../user-guide/configuring/rules). The other elements in the array are the identifiers that you want to disallow. Examples of **incorrect** code for this rule with sample `"data", "callback"` restricted identifiers: diff --git a/docs/src/rules/indent-legacy.md b/docs/src/rules/indent-legacy.md index 051a4c1485ae..97372ebc8ff0 100644 --- a/docs/src/rules/indent-legacy.md +++ b/docs/src/rules/indent-legacy.md @@ -7,7 +7,7 @@ rule_type: layout This rule was **deprecated** in ESLint v4.0.0. -ESLint 4.0.0 introduced a rewrite of the [`indent`](/docs/rules/indent) rule, which now reports more errors than it did in previous versions. To ease the process of migrating to 4.0.0, the `indent-legacy` rule was introduced as a snapshot of the `indent` rule from ESLint 3.x. If your build is failing after the upgrade to 4.0.0, you can disable `indent` and enable `indent-legacy` as a quick fix. Eventually, you should switch back to the `indent` rule to get bugfixes and improvements in future versions. +ESLint 4.0.0 introduced a rewrite of the [`indent`](indent) rule, which now reports more errors than it did in previous versions. To ease the process of migrating to 4.0.0, the `indent-legacy` rule was introduced as a snapshot of the `indent` rule from ESLint 3.x. If your build is failing after the upgrade to 4.0.0, you can disable `indent` and enable `indent-legacy` as a quick fix. Eventually, you should switch back to the `indent` rule to get bugfixes and improvements in future versions. --- diff --git a/docs/src/rules/indent.md b/docs/src/rules/indent.md index 08d10277a37c..d783bf179bd4 100644 --- a/docs/src/rules/indent.md +++ b/docs/src/rules/indent.md @@ -81,7 +81,7 @@ if (a) { This rule has an object option: -* `"ignoredNodes"` can be used to disable indentation checking for any AST node. This accepts an array of [selectors](/docs/developer-guide/selectors). If an AST node is matched by any of the selectors, the indentation of tokens which are direct children of that node will be ignored. This can be used as an escape hatch to relax the rule if you disagree with the indentation that it enforces for a particular syntactic pattern. +* `"ignoredNodes"` can be used to disable indentation checking for any AST node. This accepts an array of [selectors](../developer-guide/selectors). If an AST node is matched by any of the selectors, the indentation of tokens which are direct children of that node will be ignored. This can be used as an escape hatch to relax the rule if you disagree with the indentation that it enforces for a particular syntactic pattern. * `"SwitchCase"` (default: 0) enforces indentation level for `case` clauses in `switch` statements * `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations. It can also be `"first"`, indicating all the declarators should be aligned with the first declarator. * `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs. This can also be set to `"off"` to disable checking for file-level IIFEs. diff --git a/docs/src/rules/nonblock-statement-body-position.md b/docs/src/rules/nonblock-statement-body-position.md index 3fec9fff0777..78d332026e71 100644 --- a/docs/src/rules/nonblock-statement-body-position.md +++ b/docs/src/rules/nonblock-statement-body-position.md @@ -34,7 +34,7 @@ if (foo) bar(); This rule aims to enforce a consistent location for single-line statements. -Note that this rule does not enforce the usage of single-line statements in general. If you would like to disallow single-line statements, use the [`curly`](/docs/rules/curly) rule instead. +Note that this rule does not enforce the usage of single-line statements in general. If you would like to disallow single-line statements, use the [`curly`](curly) rule instead. ### Options @@ -182,4 +182,4 @@ while (foo) ## When Not To Use It -If you're not concerned about consistent locations of single-line statements, you should not turn on this rule. You can also disable this rule if you're using the `"all"` option for the [`curly`](/docs/rules/curly) rule, because this will disallow single-line statements entirely. +If you're not concerned about consistent locations of single-line statements, you should not turn on this rule. You can also disable this rule if you're using the `"all"` option for the [`curly`](curly) rule, because this will disallow single-line statements entirely. diff --git a/docs/src/rules/rest-spread-spacing.md b/docs/src/rules/rest-spread-spacing.md index c661de171ddb..d17c81189fc5 100644 --- a/docs/src/rules/rest-spread-spacing.md +++ b/docs/src/rules/rest-spread-spacing.md @@ -58,7 +58,7 @@ This rule aims to enforce consistent spacing between rest and spread operators a } ``` -Please read the user guide's section on [configuring parser options](/docs/user-guide/configuring#specifying-parser-options) to learn more. +Please read the user guide's section on [configuring parser options](../user-guide/configuring#specifying-parser-options) to learn more. ## Options diff --git a/docs/src/rules/strict.md b/docs/src/rules/strict.md index 7c50c3034113..5a8b1899e6b6 100644 --- a/docs/src/rules/strict.md +++ b/docs/src/rules/strict.md @@ -47,7 +47,7 @@ In **ECMAScript** modules, which always have strict mode semantics, the directiv This rule requires or disallows strict mode directives. -This rule disallows strict mode directives, no matter which option is specified, if ESLint configuration specifies either of the following as [parser options](/docs/user-guide/configuring/language-options#specifying-parser-options): +This rule disallows strict mode directives, no matter which option is specified, if ESLint configuration specifies either of the following as [parser options](../user-guide/configuring/language-options#specifying-parser-options): * `"sourceType": "module"` that is, files are **ECMAScript** modules * `"impliedStrict": true` property in the `ecmaFeatures` object @@ -73,8 +73,8 @@ This rule has a string option: The `"safe"` option corresponds to the `"global"` option if ESLint considers a file to be a **Node.js** or **CommonJS** module because the configuration specifies either of the following: -* `node` or `commonjs` [environments](/docs/user-guide/configuring/language-options#specifying-environments) -* `"globalReturn": true` property in the `ecmaFeatures` object of [parser options](/docs/user-guide/configuring/language-options#specifying-parser-options) +* `node` or `commonjs` [environments](../user-guide/configuring/language-options#specifying-environments) +* `"globalReturn": true` property in the `ecmaFeatures` object of [parser options](../user-guide/configuring/language-options#specifying-parser-options) Otherwise the `"safe"` option corresponds to the `"function"` option. Note that if `"globalReturn": false` is explicitly specified in the configuration, the `"safe"` option will correspond to the `"function"` option regardless of the specified environment. @@ -340,4 +340,4 @@ function foo() { ## When Not To Use It -In a codebase that has both strict and non-strict code, either turn this rule off, or [selectively disable it](/docs/user-guide/configuring/rules#disabling-rules) where necessary. For example, functions referencing `arguments.callee` are invalid in strict mode. A [full list of strict mode differences](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode#Differences_from_non-strict_to_strict) is available on MDN. +In a codebase that has both strict and non-strict code, either turn this rule off, or [selectively disable it](../user-guide/configuring/rules#disabling-rules) where necessary. For example, functions referencing `arguments.callee` are invalid in strict mode. A [full list of strict mode differences](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode#Differences_from_non-strict_to_strict) is available on MDN. diff --git a/docs/src/user-guide/configuring/configuration-files-new.md b/docs/src/user-guide/configuring/configuration-files-new.md index 72ddc97d405b..50737884c1e5 100644 --- a/docs/src/user-guide/configuring/configuration-files-new.md +++ b/docs/src/user-guide/configuring/configuration-files-new.md @@ -486,7 +486,7 @@ export default [ ]; ``` -This configuration object specifies that the [`semi`](/docs/latest/rules/semi) rule should be enabled with a severity of `"error"`. You can also provide options to a rule by specifying an array where the first item is the severity and each item after that is an option for the rule. For example, you can switch the `semi` rule to disallow semicolons by passing `"never"` as an option: +This configuration object specifies that the [`semi`](../../rules/semi) rule should be enabled with a severity of `"error"`. You can also provide options to a rule by specifying an array where the first item is the severity and each item after that is an option for the rule. For example, you can switch the `semi` rule to disallow semicolons by passing `"never"` as an option: ```js export default [ diff --git a/docs/src/user-guide/configuring/configuration-files.md b/docs/src/user-guide/configuring/configuration-files.md index 8c4f0b19b9ee..7c4110db5933 100644 --- a/docs/src/user-guide/configuring/configuration-files.md +++ b/docs/src/user-guide/configuring/configuration-files.md @@ -41,7 +41,7 @@ The second way to use configuration files is to save the file wherever you would eslint -c myconfig.json myfiletotest.js ``` -If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](https://eslint.org/docs/user-guide/command-line-interface#--no-eslintrc) along with the [`--config`](https://eslint.org/docs/user-guide/command-line-interface#-c---config) flag. +If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](../command-line-interface#--no-eslintrc) along with the [`--config`](../../user-guide/command-line-interface#-c---config) flag. Here's an example JSON configuration file that uses the `typescript-eslint` parser to support TypeScript syntax: @@ -195,7 +195,7 @@ The complete configuration hierarchy, from highest to lowest precedence, is as f 1. `.eslintrc.*` or `package.json` file in the same directory as the linted file 1. Continue searching for `.eslintrc.*` and `package.json` files in ancestor directories up to and including the root directory or until a config with `"root": true` is found. -Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files stops there as well. And with the [removal of support for Personal Configuration Files](https://eslint.org/docs/user-guide/configuring/configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory are ignored. +Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files stops there as well. And with the [removal of support for Personal Configuration Files](configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory are ignored. ## Extending Configuration Files @@ -232,7 +232,7 @@ The `rules` property can do any of the following to extend (or override) the set ### Using a shareable configuration package -A [sharable configuration](https://eslint.org/docs/developer-guide/shareable-configs) is an npm package that exports a configuration object. Make sure that you have installed the package in your project root directory, so that ESLint can require it. +A [sharable configuration](../../developer-guide/shareable-configs) is an npm package that exports a configuration object. Make sure that you have installed the package in your project root directory, so that ESLint can require it. The `extends` property value can omit the `eslint-config-` prefix of the package name. @@ -251,7 +251,7 @@ rules: ### Using `eslint:recommended` -Using `"eslint:recommended"` in the `extends` property enables a subset of core rules that report common problems (these rules are identified with a checkmark (recommended) on the [rules page](https://eslint.org/docs/rules/)). +Using `"eslint:recommended"` in the `extends` property enables a subset of core rules that report common problems (these rules are identified with a checkmark (recommended) on the [rules page](../../rules/)). Here's an example of extending `eslint:recommended` and overriding some of the set configuration options: @@ -279,7 +279,7 @@ module.exports = { ### Using a configuration from a plugin -A [plugin](https://eslint.org/docs/developer-guide/working-with-plugins) is an npm package that can add various extensions to ESLint. A plugin can perform numerous functions, including but not limited to adding new rules and exporting [shareable configurations](https://eslint.org/docs/developer-guide/working-with-plugins#configs-in-plugins). Make sure the package has been installed in a directory where ESLint can require it. +A [plugin](../../developer-guide/working-with-plugins) is an npm package that can add various extensions to ESLint. A plugin can perform numerous functions, including but not limited to adding new rules and exporting [shareable configurations](../../developer-guide/working-with-plugins#configs-in-plugins). Make sure the package has been installed in a directory where ESLint can require it. The `plugins` [property value](./plugins#configure-plugins) can omit the `eslint-plugin-` prefix of the package name. @@ -332,9 +332,9 @@ The `extends` property value can be `"eslint:all"` to enable all core rules in t **Important:** This configuration is **not recommended for production use** because it changes with every minor and major version of ESLint. Use it at your own risk. -You might enable all core rules as a shortcut to explore rules and options while you decide on the configuration for a project, especially if you rarely override options or disable rules. The default options for rules are not endorsements by ESLint (for example, the default option for the [`quotes`](https://eslint.org/docs/rules/quotes) rule does not mean double quotes are better than single quotes). +You might enable all core rules as a shortcut to explore rules and options while you decide on the configuration for a project, especially if you rarely override options or disable rules. The default options for rules are not endorsements by ESLint (for example, the default option for the [`quotes`](../../rules/quotes) rule does not mean double quotes are better than single quotes). -If your configuration extends `eslint:all`, after you upgrade to a newer major or minor version of ESLint, review the reported problems before you use the `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#--fix), so you know if a new fixable rule will make changes to the code. +If your configuration extends `eslint:all`, after you upgrade to a newer major or minor version of ESLint, review the reported problems before you use the `--fix` option on the [command line](../command-line-interface#--fix), so you know if a new fixable rule will make changes to the code. Example of a configuration file in JavaScript format: @@ -428,7 +428,7 @@ If you specified the [`--ext`](../command-line-interface#--ext) command line opt ## Personal Configuration Files (deprecated) -⚠️ **This feature has been deprecated**. This feature was removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32). +⚠️ **This feature has been deprecated**. This feature was removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](../command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32). `~/` refers to [the home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir). The personal configuration file being referred to here is `~/.eslintrc.*` file, which is currently handled differently than other configuration files. @@ -444,4 +444,4 @@ If `eslint` could find configuration files in the project, `eslint` ignores `~/. `~/.eslintrc.*` files load shareable configs and custom parsers from `~/node_modules/` – similarly to `require()` – in the user's home directory. Please note that it doesn't load global-installed packages. -`~/.eslintrc.*` files load plugins from `$CWD/node_modules` by default in order to identify plugins uniquely. If you want to use plugins with `~/.eslintrc.*` files, plugins must be installed locally per project. Alternatively, you can use the [`--resolve-plugins-relative-to` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--resolve-plugins-relative-to) to change the location from which ESLint loads plugins. +`~/.eslintrc.*` files load plugins from `$CWD/node_modules` by default in order to identify plugins uniquely. If you want to use plugins with `~/.eslintrc.*` files, plugins must be installed locally per project. Alternatively, you can use the [`--resolve-plugins-relative-to` CLI option](../command-line-interface#--resolve-plugins-relative-to) to change the location from which ESLint loads plugins. diff --git a/docs/src/user-guide/getting-started.md b/docs/src/user-guide/getting-started.md index 0496a156e7b1..655c170bd33c 100644 --- a/docs/src/user-guide/getting-started.md +++ b/docs/src/user-guide/getting-started.md @@ -75,7 +75,7 @@ After running `npm init @eslint/config`, you'll have a `.eslintrc.{js,yml,json}` } ``` -The names `"semi"` and `"quotes"` are the names of [rules](/docs/rules) in ESLint. The first value is the error level of the rule and can be one of these values: +The names `"semi"` and `"quotes"` are the names of [rules](../rules) in ESLint. The first value is the error level of the rule and can be one of these values: * `"off"` or `0` - turn the rule off * `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code) @@ -91,7 +91,7 @@ Your `.eslintrc.{js,yml,json}` configuration file will also include the line: } ``` -Because of this line, all of the rules marked "(recommended)" on the [rules page](/docs/rules) will be turned on. Alternatively, you can use configurations that others have created by searching for "eslint-config" on [npmjs.com](https://www.npmjs.com/search?q=eslint-config). ESLint will not lint your code unless you extend from a shared configuration or explicitly turn rules on in your configuration. +Because of this line, all of the rules marked "(recommended)" on the [rules page](../rules) will be turned on. Alternatively, you can use configurations that others have created by searching for "eslint-config" on [npmjs.com](https://www.npmjs.com/search?q=eslint-config). ESLint will not lint your code unless you extend from a shared configuration or explicitly turn rules on in your configuration. --- @@ -100,5 +100,5 @@ Because of this line, all of the rules marked "(recommended)" on the [rules page * Learn about [advanced configuration](configuring/) of ESLint. * Get familiar with the [command line options](command-line-interface). * Explore [ESLint integrations](integrations) into other tools like editors, build systems, and more. -* Can't find just the right rule? Make your own [custom rule](/docs/developer-guide/working-with-rules). -* Make ESLint even better by [contributing](/docs/developer-guide/contributing/). +* Can't find just the right rule? Make your own [custom rule](../developer-guide/working-with-rules). +* Make ESLint even better by [contributing](../developer-guide/contributing/). diff --git a/docs/src/user-guide/migrating-from-jscs.md b/docs/src/user-guide/migrating-from-jscs.md index ec2fdb01962b..938daf8e2305 100644 --- a/docs/src/user-guide/migrating-from-jscs.md +++ b/docs/src/user-guide/migrating-from-jscs.md @@ -10,7 +10,7 @@ In April 2016, we [announced](https://eslint.org/blog/2016/04/welcoming-jscs-to- Before beginning the process of migrating to ESLint, it's helpful to understand some of the terminology that ESLint uses and how it relates to terminology that JSCS uses. * **Configuration File** - In JSCS, the configuration file is `.jscsrc`, `.jscsrc.json`, `.jscsrc.yaml`, or `.jscsrs.js`. In ESLint, the configuration file can be `.eslintrc.json`, `.eslintrc.yml`, `.eslintrc.yaml`, or `.eslintrc.js` (there is also a deprecated `.eslintrc` file format). -* **Presets** - In JSCS, there were numerous predefined configurations shipped directly within JSCS. ESLint ships with just one predefined configuration (`eslint:recommended`) that has no style rules enabled. However, ESLint does support [shareable configs](https://eslint.org/docs/developer-guide/shareable-configs). Shareable configs are configurations that are published on their own to npm and there are shareable configs available for almost all of the JSCS presets (see [the "Converting Presets" section](#converting-presets) below). Additionally, the `preset` option in a configuration file is the equivalent of the ESLint `extends` option. +* **Presets** - In JSCS, there were numerous predefined configurations shipped directly within JSCS. ESLint ships with just one predefined configuration (`eslint:recommended`) that has no style rules enabled. However, ESLint does support [shareable configs](../developer-guide/shareable-configs). Shareable configs are configurations that are published on their own to npm and there are shareable configs available for almost all of the JSCS presets (see [the "Converting Presets" section](#converting-presets) below). Additionally, the `preset` option in a configuration file is the equivalent of the ESLint `extends` option. ## Convert Configuration Files Using Polyjuice diff --git a/docs/src/user-guide/migrating-to-1.0.0.md b/docs/src/user-guide/migrating-to-1.0.0.md index 8c4628089c38..1ed8496359e6 100644 --- a/docs/src/user-guide/migrating-to-1.0.0.md +++ b/docs/src/user-guide/migrating-to-1.0.0.md @@ -23,62 +23,62 @@ This setting mimics some of the default behavior from 0.x, but not all. If you d The `"eslint:recommended"` configuration contains many of the same default rule settings from 0.x, but not all. These rules are no longer on by default, so you should review your settings to ensure they are still as you expect: -* [no-alert](https://eslint.org/docs/rules/no-alert) -* [no-array-constructor](https://eslint.org/docs/rules/no-array-constructor) -* [no-caller](https://eslint.org/docs/rules/no-caller) -* [no-catch-shadow](https://eslint.org/docs/rules/no-catch-shadow) -* [no-empty-label](https://eslint.org/docs/rules/no-empty-label) -* [no-eval](https://eslint.org/docs/rules/no-eval) -* [no-extend-native](https://eslint.org/docs/rules/no-extend-native) -* [no-extra-bind](https://eslint.org/docs/rules/no-extra-bind) -* [no-extra-strict](https://eslint.org/docs/rules/no-extra-strict) -* [no-implied-eval](https://eslint.org/docs/rules/no-implied-eval) -* [no-iterator](https://eslint.org/docs/rules/no-iterator) -* [no-label-var](https://eslint.org/docs/rules/no-label-var) -* [no-labels](https://eslint.org/docs/rules/no-labels) -* [no-lone-blocks](https://eslint.org/docs/rules/no-lone-blocks) -* [no-loop-func](https://eslint.org/docs/rules/no-loop-func) -* [no-multi-spaces](https://eslint.org/docs/rules/no-multi-spaces) -* [no-multi-str](https://eslint.org/docs/rules/no-multi-str) -* [no-native-reassign](https://eslint.org/docs/rules/no-native-reassign) -* [no-new](https://eslint.org/docs/rules/no-new) -* [no-new-func](https://eslint.org/docs/rules/no-new-func) -* [no-new-object](https://eslint.org/docs/rules/no-new-object) -* [no-new-wrappers](https://eslint.org/docs/rules/no-new-wrappers) -* [no-octal-escape](https://eslint.org/docs/rules/no-octal-escape) -* [no-process-exit](https://eslint.org/docs/rules/no-process-exit) -* [no-proto](https://eslint.org/docs/rules/no-proto) -* [no-return-assign](https://eslint.org/docs/rules/no-return-assign) -* [no-script-url](https://eslint.org/docs/rules/no-script-url) -* [no-sequences](https://eslint.org/docs/rules/no-sequences) -* [no-shadow](https://eslint.org/docs/rules/no-shadow) -* [no-shadow-restricted-names](https://eslint.org/docs/rules/no-shadow-restricted-names) -* [no-spaced-func](https://eslint.org/docs/rules/no-spaced-func) -* [no-trailing-spaces](https://eslint.org/docs/rules/no-trailing-spaces) -* [no-undef-init](https://eslint.org/docs/rules/no-undef-init) -* [no-underscore-dangle](https://eslint.org/docs/rules/no-underscore-dangle) -* [no-unused-expressions](https://eslint.org/docs/rules/no-unused-expressions) -* [no-use-before-define](https://eslint.org/docs/rules/no-use-before-define) -* [no-with](https://eslint.org/docs/rules/no-with) -* [no-wrap-func](https://eslint.org/docs/rules/no-wrap-func) -* [camelcase](https://eslint.org/docs/rules/camelcase) -* [comma-spacing](https://eslint.org/docs/rules/comma-spacing) -* [consistent-return](https://eslint.org/docs/rules/consistent-return) -* [curly](https://eslint.org/docs/rules/curly) -* [dot-notation](https://eslint.org/docs/rules/dot-notation) -* [eol-last](https://eslint.org/docs/rules/eol-last) -* [eqeqeq](https://eslint.org/docs/rules/eqeqeq) -* [key-spacing](https://eslint.org/docs/rules/key-spacing) -* [new-cap](https://eslint.org/docs/rules/new-cap) -* [new-parens](https://eslint.org/docs/rules/new-parens) -* [quotes](https://eslint.org/docs/rules/quotes) -* [semi](https://eslint.org/docs/rules/semi) -* [semi-spacing](https://eslint.org/docs/rules/semi-spacing) -* [space-infix-ops](https://eslint.org/docs/rules/space-infix-ops) -* [space-return-throw-case](https://eslint.org/docs/rules/space-return-throw-case) -* [space-unary-ops](https://eslint.org/docs/rules/space-unary-ops) -* [strict](https://eslint.org/docs/rules/strict) -* [yoda](https://eslint.org/docs/rules/yoda) +* [no-alert](../rules/no-alert) +* [no-array-constructor](../rules/no-array-constructor) +* [no-caller](../rules/no-caller) +* [no-catch-shadow](../rules/no-catch-shadow) +* [no-empty-label](../rules/no-empty-label) +* [no-eval](../rules/no-eval) +* [no-extend-native](../rules/no-extend-native) +* [no-extra-bind](../rules/no-extra-bind) +* [no-extra-strict](../rules/no-extra-strict) +* [no-implied-eval](../rules/no-implied-eval) +* [no-iterator](../rules/no-iterator) +* [no-label-var](../rules/no-label-var) +* [no-labels](../rules/no-labels) +* [no-lone-blocks](../rules/no-lone-blocks) +* [no-loop-func](../rules/no-loop-func) +* [no-multi-spaces](../rules/no-multi-spaces) +* [no-multi-str](../rules/no-multi-str) +* [no-native-reassign](../rules/no-native-reassign) +* [no-new](../rules/no-new) +* [no-new-func](../rules/no-new-func) +* [no-new-object](../rules/no-new-object) +* [no-new-wrappers](../rules/no-new-wrappers) +* [no-octal-escape](../rules/no-octal-escape) +* [no-process-exit](../rules/no-process-exit) +* [no-proto](../rules/no-proto) +* [no-return-assign](../rules/no-return-assign) +* [no-script-url](../rules/no-script-url) +* [no-sequences](../rules/no-sequences) +* [no-shadow](../rules/no-shadow) +* [no-shadow-restricted-names](../rules/no-shadow-restricted-names) +* [no-spaced-func](../rules/no-spaced-func) +* [no-trailing-spaces](../rules/no-trailing-spaces) +* [no-undef-init](../rules/no-undef-init) +* [no-underscore-dangle](../rules/no-underscore-dangle) +* [no-unused-expressions](../rules/no-unused-expressions) +* [no-use-before-define](../rules/no-use-before-define) +* [no-with](../rules/no-with) +* [no-wrap-func](../rules/no-wrap-func) +* [camelcase](../rules/camelcase) +* [comma-spacing](../rules/comma-spacing) +* [consistent-return](../rules/consistent-return) +* [curly](../rules/curly) +* [dot-notation](../rules/dot-notation) +* [eol-last](../rules/eol-last) +* [eqeqeq](../rules/eqeqeq) +* [key-spacing](../rules/key-spacing) +* [new-cap](../rules/new-cap) +* [new-parens](../rules/new-parens) +* [quotes](../rules/quotes) +* [semi](../rules/semi) +* [semi-spacing](../rules/semi-spacing) +* [space-infix-ops](../rules/space-infix-ops) +* [space-return-throw-case](../rules/space-return-throw-case) +* [space-unary-ops](../rules/space-unary-ops) +* [strict](../rules/strict) +* [yoda](../rules/yoda) See also: the [full diff](https://github.com/eslint/eslint/commit/e3e9dbd9876daf4bdeb4e15f8a76a9d5e6e03e39#diff-b01a5cfd9361ca9280a460fd6bb8edbbL1) where the defaults were changed. @@ -151,19 +151,19 @@ Here's a configuration file with the closest equivalent of the old defaults: Over the past several releases, we have been deprecating rules and introducing new rules to take their place. The following is a list of the removed rules and their replacements: -* [generator-star](https://eslint.org/docs/rules/generator-star) is replaced by [generator-star-spacing](https://eslint.org/docs/rules/generator-star-spacing) -* [global-strict](https://eslint.org/docs/rules/global-strict) is replaced by [strict](https://eslint.org/docs/rules/strict) -* [no-comma-dangle](https://eslint.org/docs/rules/no-comma-dangle) is replaced by [comma-dangle](https://eslint.org/docs/rules/comma-dangle) -* [no-empty-class](https://eslint.org/docs/rules/no-empty-class) is replaced by [no-empty-character-class](https://eslint.org/docs/rules/no-empty-character-class) -* [no-extra-strict](https://eslint.org/docs/rules/no-extra-strict) is replaced by [strict](https://eslint.org/docs/rules/strict) -* [no-reserved-keys](https://eslint.org/docs/rules/no-reserved-keys) is replaced by [quote-props](https://eslint.org/docs/rules/quote-props) -* [no-space-before-semi](https://eslint.org/docs/rules/no-space-before-semi) is replaced by [semi-spacing](https://eslint.org/docs/rules/semi-spacing) -* [no-wrap-func](https://eslint.org/docs/rules/no-wrap-func) is replaced by [no-extra-parens](https://eslint.org/docs/rules/no-extra-parens) -* [space-after-function-name](https://eslint.org/docs/rules/space-after-function-name) is replaced by [space-before-function-paren](https://eslint.org/docs/rules/space-before-function-paren) -* [space-before-function-parentheses](https://eslint.org/docs/rules/space-before-function-parentheses) is replaced by [space-before-function-paren](https://eslint.org/docs/rules/space-before-function-paren) -* [space-in-brackets](https://eslint.org/docs/rules/space-in-brackets) is replaced by[object-curly-spacing](https://eslint.org/docs/rules/object-curly-spacing) and [array-bracket-spacing](https://eslint.org/docs/rules/array-bracket-spacing) -* [space-unary-word-ops](https://eslint.org/docs/rules/space-unary-word-ops) is replaced by [space-unary-ops](https://eslint.org/docs/rules/space-unary-ops) -* [spaced-line-comment](https://eslint.org/docs/rules/spaced-line-comment) is replaced by [spaced-comment](https://eslint.org/docs/rules/spaced-comment) +* [generator-star](../rules/generator-star) is replaced by [generator-star-spacing](../rules/generator-star-spacing) +* [global-strict](../rules/global-strict) is replaced by [strict](../rules/strict) +* [no-comma-dangle](../rules/no-comma-dangle) is replaced by [comma-dangle](../rules/comma-dangle) +* [no-empty-class](../rules/no-empty-class) is replaced by [no-empty-character-class](../rules/no-empty-character-class) +* [no-extra-strict](../rules/no-extra-strict) is replaced by [strict](../rules/strict) +* [no-reserved-keys](../rules/no-reserved-keys) is replaced by [quote-props](../rules/quote-props) +* [no-space-before-semi](../rules/no-space-before-semi) is replaced by [semi-spacing](../rules/semi-spacing) +* [no-wrap-func](../rules/no-wrap-func) is replaced by [no-extra-parens](../rules/no-extra-parens) +* [space-after-function-name](../rules/space-after-function-name) is replaced by [space-before-function-paren](../rules/space-before-function-paren) +* [space-before-function-parentheses](../rules/space-before-function-parentheses) is replaced by [space-before-function-paren](../rules/space-before-function-paren) +* [space-in-brackets](../rules/space-in-brackets) is replaced by[object-curly-spacing](../rules/object-curly-spacing) and [array-bracket-spacing](../rules/array-bracket-spacing) +* [space-unary-word-ops](../rules/space-unary-word-ops) is replaced by [space-unary-ops](../rules/space-unary-ops) +* [spaced-line-comment](../rules/spaced-line-comment) is replaced by [spaced-comment](../rules/spaced-comment) **To address:** You'll need to update your rule configurations to use the new rules. ESLint v1.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process. diff --git a/docs/src/user-guide/migrating-to-2.0.0.md b/docs/src/user-guide/migrating-to-2.0.0.md index 6b9ded1f6d17..753fed743a71 100644 --- a/docs/src/user-guide/migrating-to-2.0.0.md +++ b/docs/src/user-guide/migrating-to-2.0.0.md @@ -54,11 +54,11 @@ module.exports = { The following rules have been deprecated with new rules created to take their place. The following is a list of the removed rules and their replacements: -* [no-arrow-condition](https://eslint.org/docs/rules/no-arrow-condition) is replaced by a combination of [no-confusing-arrow](https://eslint.org/docs/rules/no-confusing-arrow) and [no-constant-condition](https://eslint.org/docs/rules/no-constant-condition). Turn on both of these rules to get the same functionality as `no-arrow-condition`. -* [no-empty-label](https://eslint.org/docs/rules/no-empty-label) is replaced by [no-labels](https://eslint.org/docs/rules/no-labels) with `{"allowLoop": true, "allowSwitch": true}` option. -* [space-after-keywords](https://eslint.org/docs/rules/space-after-keywords) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing). -* [space-before-keywords](https://eslint.org/docs/rules/space-before-keywords) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing). -* [space-return-throw-case](https://eslint.org/docs/rules/space-return-throw-case) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing). +* [no-arrow-condition](../rules/no-arrow-condition) is replaced by a combination of [no-confusing-arrow](../rules/no-confusing-arrow) and [no-constant-condition](../rules/no-constant-condition). Turn on both of these rules to get the same functionality as `no-arrow-condition`. +* [no-empty-label](../rules/no-empty-label) is replaced by [no-labels](../rules/no-labels) with `{"allowLoop": true, "allowSwitch": true}` option. +* [space-after-keywords](../rules/space-after-keywords) is replaced by [keyword-spacing](../rules/keyword-spacing). +* [space-before-keywords](../rules/space-before-keywords) is replaced by [keyword-spacing](../rules/keyword-spacing). +* [space-return-throw-case](../rules/space-return-throw-case) is replaced by [keyword-spacing](../rules/keyword-spacing). **To address:** You'll need to update your rule configurations to use the new rules. ESLint v2.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process. @@ -210,17 +210,17 @@ If you're not using `ecmaFeatures` in your configuration or your custom/plugin r In 2.0.0, the following 11 rules were added to `"eslint:recommended"`. -* [constructor-super](https://eslint.org/docs/rules/constructor-super) -* [no-case-declarations](https://eslint.org/docs/rules/no-case-declarations) -* [no-class-assign](https://eslint.org/docs/rules/no-class-assign) -* [no-const-assign](https://eslint.org/docs/rules/no-const-assign) -* [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members) -* [no-empty-pattern](https://eslint.org/docs/rules/no-empty-pattern) -* [no-new-symbol](https://eslint.org/docs/rules/no-new-symbol) -* [no-self-assign](https://eslint.org/docs/rules/no-self-assign) -* [no-this-before-super](https://eslint.org/docs/rules/no-this-before-super) -* [no-unexpected-multiline](https://eslint.org/docs/rules/no-unexpected-multiline) -* [no-unused-labels](https://eslint.org/docs/rules/no-unused-labels) +* [constructor-super](../rules/constructor-super) +* [no-case-declarations](../rules/no-case-declarations) +* [no-class-assign](../rules/no-class-assign) +* [no-const-assign](../rules/no-const-assign) +* [no-dupe-class-members](../rules/no-dupe-class-members) +* [no-empty-pattern](../rules/no-empty-pattern) +* [no-new-symbol](../rules/no-new-symbol) +* [no-self-assign](../rules/no-self-assign) +* [no-this-before-super](../rules/no-this-before-super) +* [no-unexpected-multiline](../rules/no-unexpected-multiline) +* [no-unused-labels](../rules/no-unused-labels) **To address:** If you don't want to be notified by those rules, you can simply disable those rules. diff --git a/docs/src/user-guide/migrating-to-3.0.0.md b/docs/src/user-guide/migrating-to-3.0.0.md index fa93927212d9..b4aa4580e79b 100644 --- a/docs/src/user-guide/migrating-to-3.0.0.md +++ b/docs/src/user-guide/migrating-to-3.0.0.md @@ -38,17 +38,17 @@ To create a new configuration, use `eslint --init`. In 3.0.0, the following rules were added to `"eslint:recommended"`: -* [`no-unsafe-finally`](https://eslint.org/docs/rules/no-unsafe-finally) helps catch `finally` clauses that may not behave as you think. -* [`no-native-reassign`](https://eslint.org/docs/rules/no-native-reassign) was previously part of `no-undef`, but was split out because it didn't make sense as part of another rule. The `no-native-reassign` rule warns whenever you try to overwrite a read-only global variable. -* [`require-yield`](https://eslint.org/docs/rules/require-yield) helps to identify generator functions that do not have the `yield` keyword. +* [`no-unsafe-finally`](../rules/no-unsafe-finally) helps catch `finally` clauses that may not behave as you think. +* [`no-native-reassign`](../rules/no-native-reassign) was previously part of `no-undef`, but was split out because it didn't make sense as part of another rule. The `no-native-reassign` rule warns whenever you try to overwrite a read-only global variable. +* [`require-yield`](../rules/require-yield) helps to identify generator functions that do not have the `yield` keyword. The following rules were removed from `"eslint:recommended"`: -* [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle) used to be recommended because Internet Explorer 8 and earlier threw a syntax error when it found a dangling comma on object literal properties. However, [Internet Explorer 8 was end-of-lifed](https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support) in January 2016 and all other active browsers allow dangling commas. As such, we consider dangling commas to now be a stylistic issue instead of a possible error. +* [`comma-dangle`](../rules/comma-dangle) used to be recommended because Internet Explorer 8 and earlier threw a syntax error when it found a dangling comma on object literal properties. However, [Internet Explorer 8 was end-of-lifed](https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support) in January 2016 and all other active browsers allow dangling commas. As such, we consider dangling commas to now be a stylistic issue instead of a possible error. The following rules were modified: -* [`complexity`](https://eslint.org/docs/rules/complexity) used to have a hardcoded default of 11 in `eslint:recommended` that would be used if you turned the rule on without specifying a maximum. The default is now 20. The rule actually always had a default of 20, but `eslint:recommended` was overriding it by mistake. +* [`complexity`](../rules/complexity) used to have a hardcoded default of 11 in `eslint:recommended` that would be used if you turned the rule on without specifying a maximum. The default is now 20. The rule actually always had a default of 20, but `eslint:recommended` was overriding it by mistake. **To address:** If you want to mimic how `eslint:recommended` worked in v2.x, you can use the following: diff --git a/docs/src/user-guide/migrating-to-4.0.0.md b/docs/src/user-guide/migrating-to-4.0.0.md index e7630a1dc90b..d1267270d431 100644 --- a/docs/src/user-guide/migrating-to-4.0.0.md +++ b/docs/src/user-guide/migrating-to-4.0.0.md @@ -35,10 +35,10 @@ The lists below are ordered roughly by the number of users each change is expect ## `eslint:recommended` changes -Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config: +Two new rules have been added to the [`eslint:recommended`](configuring#using-eslintrecommended) config: -* [`no-compare-neg-zero`](/docs/rules/no-compare-neg-zero) disallows comparisons to `-0` -* [`no-useless-escape`](/docs/rules/no-useless-escape) disallows uselessly-escaped characters in strings and regular expressions +* [`no-compare-neg-zero`](../rules/no-compare-neg-zero) disallows comparisons to `-0` +* [`no-useless-escape`](../rules/no-useless-escape) disallows uselessly-escaped characters in strings and regular expressions **To address:** To mimic the `eslint:recommended` behavior from 3.x, you can disable these rules in a config file: @@ -55,11 +55,11 @@ Two new rules have been added to the [`eslint:recommended`](https://eslint.org/d ## The `indent` rule is more strict -Previously, the [`indent`](/docs/rules/indent) rule was fairly lenient about checking indentation; there were many code patterns where indentation was not validated by the rule. This caused confusion for users, because they were accidentally writing code with incorrect indentation, and they expected ESLint to catch the issues. +Previously, the [`indent`](../rules/indent) rule was fairly lenient about checking indentation; there were many code patterns where indentation was not validated by the rule. This caused confusion for users, because they were accidentally writing code with incorrect indentation, and they expected ESLint to catch the issues. In 4.0.0, the `indent` rule has been rewritten. The new version of the rule will report some indentation errors that the old version of the rule did not catch. Additionally, the indentation of `MemberExpression` nodes, function parameters, and function arguments will now be checked by default (it was previously ignored by default for backwards compatibility). -To make the upgrade process easier, we've introduced the [`indent-legacy`](/docs/rules/indent-legacy) rule as a snapshot of the `indent` rule from 3.x. If you run into issues from the `indent` rule when you upgrade, you should be able to use the `indent-legacy` rule to replicate the 3.x behavior. However, the `indent-legacy` rule is deprecated and will not receive bugfixes or improvements in the future, so you should eventually switch back to the `indent` rule. +To make the upgrade process easier, we've introduced the [`indent-legacy`](../rules/indent-legacy) rule as a snapshot of the `indent` rule from 3.x. If you run into issues from the `indent` rule when you upgrade, you should be able to use the `indent-legacy` rule to replicate the 3.x behavior. However, the `indent-legacy` rule is deprecated and will not receive bugfixes or improvements in the future, so you should eventually switch back to the `indent` rule. **To address:** We recommend upgrading without changing your `indent` configuration, and fixing any new indentation errors that appear in your codebase. However, if you want to mimic how the `indent` rule worked in 3.x, you can update your configuration: @@ -86,13 +86,13 @@ Due to a bug, glob patterns in an `.eslintignore` file were previously resolved ## The `padded-blocks` rule is more strict by default -By default, the [`padded-blocks`](/docs/rules/padded-blocks) rule will now enforce padding in class bodies and switch statements. Previously, the rule would ignore these cases unless the user opted into enforcing them. +By default, the [`padded-blocks`](../rules/padded-blocks) rule will now enforce padding in class bodies and switch statements. Previously, the rule would ignore these cases unless the user opted into enforcing them. **To address:** If this change results in more linting errors in your codebase, you should fix them or reconfigure the rule. ## The `space-before-function-paren` rule is more strict by default -By default, the [`space-before-function-paren`](/docs/rules/space-before-function-paren) rule will now enforce spacing for async arrow functions. Previously, the rule would ignore these cases unless the user opted into enforcing them. +By default, the [`space-before-function-paren`](../rules/space-before-function-paren) rule will now enforce spacing for async arrow functions. Previously, the rule would ignore these cases unless the user opted into enforcing them. **To address:** To mimic the default config from 3.x, you can use: @@ -110,7 +110,7 @@ By default, the [`space-before-function-paren`](/docs/rules/space-before-functio ## The `no-multi-spaces` rule is more strict by default -By default, the [`no-multi-spaces`](/docs/rules/no-multi-spaces) rule will now disallow multiple spaces before comments at the end of a line. Previously, the rule did not check this case. +By default, the [`no-multi-spaces`](../rules/no-multi-spaces) rule will now disallow multiple spaces before comments at the end of a line. Previously, the rule did not check this case. **To address:** To mimic the default config from 3.x, you can use: diff --git a/docs/src/user-guide/migrating-to-5.0.0.md b/docs/src/user-guide/migrating-to-5.0.0.md index 87d19df8dae4..13898eb32687 100644 --- a/docs/src/user-guide/migrating-to-5.0.0.md +++ b/docs/src/user-guide/migrating-to-5.0.0.md @@ -50,10 +50,10 @@ As of April 30th, 2018, Node.js 4 will be at EOL and will no longer be receiving ## `eslint:recommended` changes -Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config: +Two new rules have been added to the [`eslint:recommended`](configuring#using-eslintrecommended) config: -* [`for-direction`](/docs/rules/for-direction) enforces that a `for` loop update clause moves the counter in the right direction. -* [`getter-return`](/docs/rules/getter-return) enforces that a `return` statement is present in property getters. +* [`for-direction`](../rules/for-direction) enforces that a `for` loop update clause moves the counter in the right direction. +* [`getter-return`](../rules/getter-return) enforces that a `return` statement is present in property getters. **To address:** To mimic the `eslint:recommended` behavior from 4.x, you can disable these rules in a config file: @@ -96,7 +96,7 @@ Note that this also enables parsing for other features from ES2018, such as [asy For compatibility, ESLint v5 will treat `ecmaFeatures: { experimentalObjectRestSpread: true }` as an alias for `ecmaVersion: 2018` when the former is found in a config file. As a result, if you use object rest/spread, your code should still parse successfully with ESLint v5. However, note that this alias will be removed in ESLint v6. -**To address:** If you use the `experimentalObjectRestSpread` option, you should be able to upgrade to ESLint v5 without any changes, but you will encounter a deprecation warning. To avoid the warning, use `ecmaVersion: 2018` in your config file rather than `ecmaFeatures: { experimentalObjectRestSpread: true }`. If you would like to disallow the use of other ES2018 features, consider using rules such as [`no-restricted-syntax`](/docs/rules/no-restricted-syntax). +**To address:** If you use the `experimentalObjectRestSpread` option, you should be able to upgrade to ESLint v5 without any changes, but you will encounter a deprecation warning. To avoid the warning, use `ecmaVersion: 2018` in your config file rather than `ecmaFeatures: { experimentalObjectRestSpread: true }`. If you would like to disallow the use of other ES2018 features, consider using rules such as [`no-restricted-syntax`](../rules/no-restricted-syntax). ## Linting nonexistent files from the command line is now a fatal error @@ -113,7 +113,7 @@ ESLint v5 will report a fatal error when either of the following conditions is m * A file provided on the command line does not exist * A glob or folder provided on the command line does not match any lintable files -Note that this also affects the [`CLIEngine.executeOnFiles()`](https://eslint.org/docs/developer-guide/nodejs-api#cliengineexecuteonfiles) API. +Note that this also affects the [`CLIEngine.executeOnFiles()`](../developer-guide/nodejs-api#cliengineexecuteonfiles) API. **To address:** If you encounter an error about missing files after upgrading to ESLint v5, you may want to double-check that there are no typos in the paths you provide to ESLint. To make the error go away, you can simply remove the given files or globs from the list of arguments provided to ESLint on the command line. @@ -121,8 +121,8 @@ If you use a boilerplate generator that relies on this behavior (e.g. to generat ## The default options for some rules have changed -* The default options for the [`object-curly-newline`](/docs/rules/object-curly-newline) rule have changed from `{ multiline: true }` to `{ consistent: true }`. -* The default options object for the [`no-self-assign`](/docs/rules/no-self-assign) rule has changed from `{ props: false }` to `{ props: true }`. +* The default options for the [`object-curly-newline`](../rules/object-curly-newline) rule have changed from `{ multiline: true }` to `{ consistent: true }`. +* The default options object for the [`no-self-assign`](../rules/no-self-assign) rule has changed from `{ props: false }` to `{ props: true }`. **To address:** To restore the rule behavior from ESLint v4, you can update your config file to include the previous options: @@ -137,7 +137,7 @@ If you use a boilerplate generator that relies on this behavior (e.g. to generat ## Deprecated globals have been removed from the `node`, `browser`, and `jest` environments -Some global variables have been deprecated or removed for code running in Node.js, browsers, and Jest. (For example, browsers used to expose an `SVGAltGlyphElement` global variable to JavaScript code, but this global has been removed from web standards and is no longer present in browsers.) As a result, we have removed these globals from the corresponding `eslint` environments, so use of these globals will trigger an error when using rules such as [`no-undef`](/docs/rules/no-undef). +Some global variables have been deprecated or removed for code running in Node.js, browsers, and Jest. (For example, browsers used to expose an `SVGAltGlyphElement` global variable to JavaScript code, but this global has been removed from web standards and is no longer present in browsers.) As a result, we have removed these globals from the corresponding `eslint` environments, so use of these globals will trigger an error when using rules such as [`no-undef`](../rules/no-undef). **To address:** If you use deprecated globals in the `node`, `browser`, or `jest` environments, you can add a `globals` section to your configuration to re-enable any globals you need. For example: @@ -158,7 +158,7 @@ ESLint v4 had a special behavior when linting files that only contain whitespace ESLint v5 treats whitespace-only files the same way as all other files: it parses them and runs enabled rules on them as appropriate. This could lead to additional linting problems if you use a custom rule that reports errors on empty files. -**To address:** If you have an empty file in your project and you don't want it to be linted, consider adding it to an [`.eslintignore` file](/docs/user-guide/configuring#ignoring-files-and-directories). +**To address:** If you have an empty file in your project and you don't want it to be linted, consider adding it to an [`.eslintignore` file](configuring#ignoring-files-and-directories). If you have a custom rule, you should make sure it handles empty files appropriately. (In most cases, no changes should be necessary.) @@ -229,7 +229,7 @@ In ESLint v5, the `context.getScope()` method has the same behavior regardless o Previously, rule context objects had an undocumented `_linter` property, which was used internally within ESLint to process reports from rules. Some rules used this property to achieve functionality that was not intended to be possible for rules. For example, several plugins used the `_linter` property in a rule to monitor reports from other rules, for the purpose of checking for unused `/* eslint-disable */` directive comments. Although this functionality was useful for users, it could also cause stability problems for projects using ESLint. For example, an upgrade to a rule in one plugin could unexpectedly cause a rule in another plugin to start reporting errors. -The `_linter` property has been removed in ESLint v5.0, so it is no longer possible to implement rules with this functionality. However, the [`--report-unused-disable-directives`](/docs/user-guide/command-line-interface#--report-unused-disable-directives) CLI flag can be used to flag unused directive comments. +The `_linter` property has been removed in ESLint v5.0, so it is no longer possible to implement rules with this functionality. However, the [`--report-unused-disable-directives`](command-line-interface#--report-unused-disable-directives) CLI flag can be used to flag unused directive comments. ## `RuleTester` now uses strict equality checks in its assertions @@ -268,6 +268,6 @@ In ESLint v5, an unsuccessful linting run due to a fatal error will result in an ## The `eslint.linter` property is now non-enumerable -When using ESLint's Node.js API, the [`linter`](/docs/developer-guide/nodejs-api#linter-1) property is now non-enumerable. Note that the `linter` property was deprecated in ESLint v4 in favor of the [`Linter`](/docs/developer-guide/nodejs-api#linter) property. +When using ESLint's Node.js API, the [`linter`](../developer-guide/nodejs-api#linter-1) property is now non-enumerable. Note that the `linter` property was deprecated in ESLint v4 in favor of the [`Linter`](../developer-guide/nodejs-api#linter) property. **To address:** If you rely on enumerating all the properties of the `eslint` object, use something like `Object.getOwnPropertyNames` to ensure that non-enumerable keys are captured. diff --git a/docs/src/user-guide/migrating-to-6.0.0.md b/docs/src/user-guide/migrating-to-6.0.0.md index 4173e7deda7a..36f67f16a071 100644 --- a/docs/src/user-guide/migrating-to-6.0.0.md +++ b/docs/src/user-guide/migrating-to-6.0.0.md @@ -51,19 +51,19 @@ As of April 2019, Node.js 6 will be at EOL and will no longer be receiving secur ## `eslint:recommended` has been updated -The following rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config: +The following rules have been added to the [`eslint:recommended`](../user-guide/configuring#using-eslintrecommended) config: -* [`no-async-promise-executor`](https://eslint.org/docs/rules/no-async-promise-executor) disallows using an `async` function as the argument to the `Promise` constructor, which is usually a bug. -* [`no-misleading-character-class`](https://eslint.org/docs/rules/no-misleading-character-class) reports character classes in regular expressions that might not behave as expected. -* [`no-prototype-builtins`](https://eslint.org/docs/rules/no-prototype-builtins) reports method calls like `foo.hasOwnProperty("bar")` (which are a frequent source of bugs), and suggests that they be replaced with `Object.prototype.hasOwnProperty.call(foo, "bar")` instead. -* [`no-shadow-restricted-names`](https://eslint.org/docs/rules/no-shadow-restricted-names) disallows shadowing variables like `undefined` (e.g. with code like `let undefined = 5;`), since is likely to confuse readers. -* [`no-useless-catch`](https://eslint.org/docs/rules/no-useless-catch) reports `catch` clauses that are redundant and can be removed from the code without changing its behavior. -* [`no-with`](https://eslint.org/docs/rules/no-with) disallows use of the [`with` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with), which can make code difficult to understand and cause compatibility problems. -* [`require-atomic-updates`](https://eslint.org/docs/rules/require-atomic-updates) reports race condition bugs that can occur when reassigning variables in async functions. +* [`no-async-promise-executor`](../rules/no-async-promise-executor) disallows using an `async` function as the argument to the `Promise` constructor, which is usually a bug. +* [`no-misleading-character-class`](../rules/no-misleading-character-class) reports character classes in regular expressions that might not behave as expected. +* [`no-prototype-builtins`](../rules/no-prototype-builtins) reports method calls like `foo.hasOwnProperty("bar")` (which are a frequent source of bugs), and suggests that they be replaced with `Object.prototype.hasOwnProperty.call(foo, "bar")` instead. +* [`no-shadow-restricted-names`](../rules/no-shadow-restricted-names) disallows shadowing variables like `undefined` (e.g. with code like `let undefined = 5;`), since is likely to confuse readers. +* [`no-useless-catch`](../rules/no-useless-catch) reports `catch` clauses that are redundant and can be removed from the code without changing its behavior. +* [`no-with`](../rules/no-with) disallows use of the [`with` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with), which can make code difficult to understand and cause compatibility problems. +* [`require-atomic-updates`](../rules/require-atomic-updates) reports race condition bugs that can occur when reassigning variables in async functions. Additionally, the following rule has been *removed* from `eslint:recommended`: -* [`no-console`](https://eslint.org/docs/rules/no-console) disallows calling functions like `console.log`. While this rule is useful in many cases (e.g. to avoid inadvertently leaving debugging statements in production code), it is not as broadly applicable as the other rules in `eslint:recommended`, and it was a source of false positives in cases where `console.log` is acceptable (e.g. in CLI applications). +* [`no-console`](../rules/no-console) disallows calling functions like `console.log`. While this rule is useful in many cases (e.g. to avoid inadvertently leaving debugging statements in production code), it is not as broadly applicable as the other rules in `eslint:recommended`, and it was a source of false positives in cases where `console.log` is acceptable (e.g. in CLI applications). Finally, in ESLint v5 `eslint:recommended` would explicitly disable all core rules that were not considered "recommended". This could cause confusing behavior if `eslint:recommended` was loaded after another config, since `eslint:recommended` would have the effect of turning off some rules. In ESLint v6, `eslint:recommended` has no effect on non-recommended rules. @@ -133,7 +133,7 @@ config | ESLint v5 | ESLint v6 ## The `no-redeclare` rule is now more strict by default -The default options for the [`no-redeclare`](https://eslint.org/docs/rules/no-redeclare) rule have changed from `{ builtinGlobals: false }` to `{ builtinGlobals: true }`. Additionally, the `no-redeclare` rule will now report an error for globals enabled by comments like `/* global foo */` if those globals were already enabled through configuration anyway. +The default options for the [`no-redeclare`](../rules/no-redeclare) rule have changed from `{ builtinGlobals: false }` to `{ builtinGlobals: true }`. Additionally, the `no-redeclare` rule will now report an error for globals enabled by comments like `/* global foo */` if those globals were already enabled through configuration anyway. **To address:** @@ -153,7 +153,7 @@ Additionally, if you see new errors for `global` comments in your code, you shou ## The `comma-dangle` rule is now more strict by default -Previously, the [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle) rule would ignore trailing function arguments and parameters, unless explicitly configured to check for function commas. In ESLint v6, function commas are treated the same way as other types of trailing commas. +Previously, the [`comma-dangle`](../rules/comma-dangle) rule would ignore trailing function arguments and parameters, unless explicitly configured to check for function commas. In ESLint v6, function commas are treated the same way as other types of trailing commas. **To address:** You can restore the previous default behavior of the rule with: @@ -177,7 +177,7 @@ To restore the previous behavior of a string option like `"always-multiline"`, r ## The `no-confusing-arrow` rule is now more lenient by default -The default options for the [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow) rule have changed from `{ allowParens: false }` to `{ allowParens: true }`. +The default options for the [`no-confusing-arrow`](../rules/no-confusing-arrow) rule have changed from `{ allowParens: false }` to `{ allowParens: true }`. **To address:** You can restore the previous default behavior of the rule with: @@ -195,7 +195,7 @@ The default options for the [`no-confusing-arrow`](https://eslint.org/docs/rules Due to a bug, the glob patterns in a `files` list in an `overrides` section of a config file would never match dotfiles, making it impossible to have overrides apply to files starting with a dot. This bug has been fixed in ESLint v6. -**To address:** If you don't want dotfiles to be matched by an override, consider adding something like `excludedFiles: [".*"]` to that `overrides` section. See the [documentation](https://eslint.org/docs/user-guide/configuring#configuration-based-on-glob-patterns) for more details. +**To address:** If you don't want dotfiles to be matched by an override, consider adding something like `excludedFiles: [".*"]` to that `overrides` section. See the [documentation](../user-guide/configuring#configuration-based-on-glob-patterns) for more details. **Related issue(s):** [eslint/eslint#11201](https://github.com/eslint/eslint/issues/11201) @@ -282,7 +282,7 @@ If you're not sure which config file needs to be updated, it may be useful to ru ## User-provided regular expressions in rule options are parsed with the unicode flag -Rules like [`max-len`](/docs/rules/max-len) accept a string option which is interpreted as a regular expression. In ESLint v6.0.0, these regular expressions are interpreted with the [unicode flag](https://mathiasbynens.be/notes/es6-unicode-regex), which should exhibit more reasonable behavior when matching characters like astral symbols. Unicode regexes also validate escape sequences more strictly than non-unicode regexes. +Rules like [`max-len`](../rules/max-len) accept a string option which is interpreted as a regular expression. In ESLint v6.0.0, these regular expressions are interpreted with the [unicode flag](https://mathiasbynens.be/notes/es6-unicode-regex), which should exhibit more reasonable behavior when matching characters like astral symbols. Unicode regexes also validate escape sequences more strictly than non-unicode regexes. **To address:** If you get rule option validation errors after upgrading, ensure that any regular expressions in your rule options have no invalid escape sequences. @@ -328,6 +328,6 @@ Previously, when linting code with a parser that had not been previously defined In ESLint v6, `Linter` will no longer perform any filesystem operations, including loading parsers. -**To address:** If you're using `Linter` with a custom parser, use [`Linter#defineParser`](https://eslint.org/docs/developer-guide/nodejs-api#linterdefineparser) to explicitly define the parser before linting any code. +**To address:** If you're using `Linter` with a custom parser, use [`Linter#defineParser`](../developer-guide/nodejs-api#linterdefineparser) to explicitly define the parser before linting any code. **Related issue(s):** [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7) diff --git a/docs/src/user-guide/migrating-to-7.0.0.md b/docs/src/user-guide/migrating-to-7.0.0.md index f8c6d7969ffe..ecb959bb5873 100644 --- a/docs/src/user-guide/migrating-to-7.0.0.md +++ b/docs/src/user-guide/migrating-to-7.0.0.md @@ -147,20 +147,20 @@ To allow for the colocation of comments that provide context with the directive, The ten Node.js/CommonJS rules in core have been deprecated and moved to the [eslint-plugin-node](https://github.com/mysticatea/eslint-plugin-node) plugin. -**To address:** As per [our deprecation policy](https://eslint.org/docs/user-guide/rule-deprecation), the deprecated rules will remain in core for the foreseeable future and are still available for use. However, we will no longer be updating or fixing any bugs in those rules. To use a supported version of the rules, we recommend using the corresponding rules in the plugin instead. +**To address:** As per [our deprecation policy](../user-guide/rule-deprecation), the deprecated rules will remain in core for the foreseeable future and are still available for use. However, we will no longer be updating or fixing any bugs in those rules. To use a supported version of the rules, we recommend using the corresponding rules in the plugin instead. | Deprecated Rules | Replacement | | :--------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------ | -| [callback-return](https://eslint.org/docs/rules/callback-return) | [node/callback-return](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md) | -| [global-require](https://eslint.org/docs/rules/global-require) | [node/global-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/global-require.md) | -| [handle-callback-err](https://eslint.org/docs/rules/handle-callback-err) | [node/handle-callback-err](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/handle-callback-err.md) | -| [no-mixed-requires](https://eslint.org/docs/rules/no-mixed-requires) | [node/no-mixed-requires](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-mixed-requires.md) | -| [no-new-require](https://eslint.org/docs/rules/no-new-require) | [node/no-new-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-new-require.md) | -| [no-path-concat](https://eslint.org/docs/rules/no-path-concat) | [node/no-path-concat](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-path-concat.md) | -| [no-process-env](https://eslint.org/docs/rules/no-process-env) | [node/no-process-env](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-env.md) | -| [no-process-exit](https://eslint.org/docs/rules/no-process-exit) | [node/no-process-exit](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-exit.md) | -| [no-restricted-modules](https://eslint.org/docs/rules/no-restricted-modules) | [node/no-restricted-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-require.md) | -| [no-sync](https://eslint.org/docs/rules/no-sync) | [node/no-sync](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-sync.md) | +| [callback-return](../rules/callback-return) | [node/callback-return](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md) | +| [global-require](../rules/global-require) | [node/global-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/global-require.md) | +| [handle-callback-err](../rules/handle-callback-err) | [node/handle-callback-err](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/handle-callback-err.md) | +| [no-mixed-requires](../rules/no-mixed-requires) | [node/no-mixed-requires](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-mixed-requires.md) | +| [no-new-require](../rules/no-new-require) | [node/no-new-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-new-require.md) | +| [no-path-concat](../rules/no-path-concat) | [node/no-path-concat](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-path-concat.md) | +| [no-process-env](../rules/no-process-env) | [node/no-process-env](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-env.md) | +| [no-process-exit](../rules/no-process-exit) | [node/no-process-exit](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-exit.md) | +| [no-restricted-modules](../rules/no-restricted-modules) | [node/no-restricted-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-require.md) | +| [no-sync](../rules/no-sync) | [node/no-sync](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-sync.md) | **Related issue(s):** [#12898](https://github.com/eslint/eslint/pull/12898) @@ -168,16 +168,16 @@ The ten Node.js/CommonJS rules in core have been deprecated and moved to the [es Several rules have been enhanced and now report additional errors: -* [accessor-pairs](https://eslint.org/docs/rules/accessor-pairs) rule now recognizes class members by default. -* [array-callback-return](https://eslint.org/docs/rules/array-callback-return) rule now recognizes `flatMap` method. -* [computed-property-spacing](https://eslint.org/docs/rules/computed-property-spacing) rule now recognizes class members by default. -* [func-names](https://eslint.org/docs/rules/func-names) rule now recognizes function declarations in default exports. -* [no-extra-parens](https://eslint.org/docs/rules/no-extra-parens) rule now recognizes parentheses in assignment targets. -* [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members) rule now recognizes computed keys for static class members. -* [no-magic-numbers](https://eslint.org/docs/rules/no-magic-numbers) rule now recognizes bigint literals. -* [radix](https://eslint.org/docs/rules/radix) rule now recognizes invalid numbers for the second parameter of `parseInt()`. -* [use-isnan](https://eslint.org/docs/rules/use-isnan) rule now recognizes class members by default. -* [yoda](https://eslint.org/docs/rules/yoda) rule now recognizes bigint literals. +* [accessor-pairs](../rules/accessor-pairs) rule now recognizes class members by default. +* [array-callback-return](../rules/array-callback-return) rule now recognizes `flatMap` method. +* [computed-property-spacing](../rules/computed-property-spacing) rule now recognizes class members by default. +* [func-names](../rules/func-names) rule now recognizes function declarations in default exports. +* [no-extra-parens](../rules/no-extra-parens) rule now recognizes parentheses in assignment targets. +* [no-dupe-class-members](../rules/no-dupe-class-members) rule now recognizes computed keys for static class members. +* [no-magic-numbers](../rules/no-magic-numbers) rule now recognizes bigint literals. +* [radix](../rules/radix) rule now recognizes invalid numbers for the second parameter of `parseInt()`. +* [use-isnan](../rules/use-isnan) rule now recognizes class members by default. +* [yoda](../rules/yoda) rule now recognizes bigint literals. **To address:** Fix errors or disable these rules. @@ -187,9 +187,9 @@ Several rules have been enhanced and now report additional errors: Three new rules have been enabled in the `eslint:recommended` preset. -* [no-dupe-else-if](https://eslint.org/docs/rules/no-dupe-else-if) -* [no-import-assign](https://eslint.org/docs/rules/no-import-assign) -* [no-setter-return](https://eslint.org/docs/rules/no-setter-return) +* [no-dupe-else-if](../rules/no-dupe-else-if) +* [no-import-assign](../rules/no-import-assign) +* [no-setter-return](../rules/no-setter-return) **To address:** Fix errors or disable these rules. @@ -209,7 +209,7 @@ The `RuleTester` now validates the following: ## The `CLIEngine` class has been deprecated -The [`CLIEngine` class](https://eslint.org/docs/developer-guide/nodejs-api#cliengine) has been deprecated and replaced by the new [`ESLint` class](https://eslint.org/docs/developer-guide/nodejs-api#eslint-class). +The [`CLIEngine` class](../developer-guide/nodejs-api#cliengine) has been deprecated and replaced by the new [`ESLint` class](../developer-guide/nodejs-api#eslint-class). The `CLIEngine` class provides a synchronous API that is blocking the implementation of features such as parallel linting, supporting ES modules in shareable configs/parsers/plugins/formatters, and adding the ability to visually display the progress of linting runs. The new `ESLint` class provides an asynchronous API that ESLint core will now using going forward. `CLIEngine` will remain in core for the foreseeable future but may be removed in a future major version. diff --git a/docs/src/user-guide/migrating-to-8.0.0.md b/docs/src/user-guide/migrating-to-8.0.0.md index 43f54b4b027e..f28f15ccbd1c 100644 --- a/docs/src/user-guide/migrating-to-8.0.0.md +++ b/docs/src/user-guide/migrating-to-8.0.0.md @@ -109,10 +109,10 @@ In ESLint v7.0.0, using both `--report-unused-disable-directives` and `--fix` on Four new rules have been enabled in the `eslint:recommended` preset. -* [`no-loss-of-precision`](https://eslint.org/docs/rules/no-loss-of-precision) -* [`no-nonoctal-decimal-escape`](https://eslint.org/docs/rules/no-nonoctal-decimal-escape) -* [`no-unsafe-optional-chaining`](https://eslint.org/docs/rules/no-unsafe-optional-chaining) -* [`no-useless-backreference`](https://eslint.org/docs/rules/no-useless-backreference) +* [`no-loss-of-precision`](../rules/no-loss-of-precision) +* [`no-nonoctal-decimal-escape`](../rules/no-nonoctal-decimal-escape) +* [`no-unsafe-optional-chaining`](../rules/no-unsafe-optional-chaining) +* [`no-useless-backreference`](../rules/no-useless-backreference) **To address:** Fix errors or disable these rules. @@ -120,7 +120,7 @@ Four new rules have been enabled in the `eslint:recommended` preset. ## Rules require `meta.hasSuggestions` to provide suggestions -In ESLint v7.0.0, rules that [provided suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions) did not need to let ESLint know. In v8.0.0, rules providing suggestions need to set their `meta.hasSuggestions` to `true`. This informs ESLint that the rule intends to provide suggestions. Without this property, any attempt to provide a suggestion will result in an error. +In ESLint v7.0.0, rules that [provided suggestions](../developer-guide/working-with-rules#providing-suggestions) did not need to let ESLint know. In v8.0.0, rules providing suggestions need to set their `meta.hasSuggestions` to `true`. This informs ESLint that the rule intends to provide suggestions. Without this property, any attempt to provide a suggestion will result in an error. **To address:** If your rule provides suggestions, add `meta.hasSuggestions` to the object, such as: @@ -168,7 +168,7 @@ The [eslint-plugin/require-meta-fixable](https://github.com/not-an-aardvark/esli The [eslint-plugin/prefer-object-rule](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-object-rule.md) rule can automatically fix and enforce that your rules are written with the object format instead of the deprecated function format. -See the [rule documentation](https://eslint.org/docs/developer-guide/working-with-rules) for more information on writing rules. +See the [rule documentation](../developer-guide/working-with-rules) for more information on writing rules. **Related issue(s):** [#13349](https://github.com/eslint/eslint/issues/13349) @@ -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()`](https://eslint.org/docs/developer-guide/working-with-rules#sourcecodegetcommentsbefore-sourcecodegetcommentsafter-and-sourcecodegetcommentsinside). +**To address:** If your rule uses `SourceCode#getComments()`, please use [`SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, or `SourceCode#getCommentsInside()`](../developer-guide/working-with-rules#sourcecodegetcommentsbefore-sourcecodegetcommentsafter-and-sourcecodegetcommentsinside). **Related issue(s):** [#14744](https://github.com/eslint/eslint/issues/14744) @@ -233,7 +233,7 @@ In ESLint v8.0.0 (via Acorn v8.0.0), the key and value are now separate objects ## The `CLIEngine` class has been removed -The `CLIEngine` class has been removed and replaced by the [`ESLint` class](https://eslint.org/docs/developer-guide/nodejs-api#eslint-class). +The `CLIEngine` class has been removed and replaced by the [`ESLint` class](../developer-guide/nodejs-api#eslint-class). **To address:** Update your code to use the new `ESLint` class if you are currently using `CLIEngine`. The following table maps the existing `CLIEngine` methods to their `ESLint` counterparts: From 293573eb530d161d2a5b01efd9d3de49dadea022 Mon Sep 17 00:00:00 2001 From: Sam Chen Date: Fri, 9 Dec 2022 02:58:29 +0800 Subject: [PATCH 22/29] docs: fix broken line numbers (#16606) * docs: fix broken line numbers * docs: fix scss styles * docs: fix lint errors * Update docs/src/assets/scss/syntax-highlighter.scss Co-authored-by: Strek * docs: fix scss * docs: move file and add license * add aria-hidden * add license to file header Co-authored-by: Strek --- docs/.eleventy.js | 53 ++++----- docs/package.json | 1 + docs/src/_plugins/md-syntax-highlighter.js | 107 +++++++++++++++++++ docs/src/assets/scss/syntax-highlighter.scss | 45 ++++---- 4 files changed, 162 insertions(+), 44 deletions(-) create mode 100644 docs/src/_plugins/md-syntax-highlighter.js diff --git a/docs/.eleventy.js b/docs/.eleventy.js index 8ad469cc7360..32666ec624d3 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -10,7 +10,7 @@ const Image = require("@11ty/eleventy-img"); const path = require("path"); const { slug } = require("github-slugger"); const yaml = require("js-yaml"); - +const { highlighter, preWrapperPlugin, lineNumberPlugin } = require("./src/_plugins/md-syntax-highlighter"); const { DateTime } = require("luxon"); @@ -145,7 +145,8 @@ module.exports = function(eleventyConfig) { eleventyConfig.addPlugin(eleventyNavigationPlugin); eleventyConfig.addPlugin(syntaxHighlight, { - alwaysWrapLineHighlights: true + alwaysWrapLineHighlights: true, + templateFormats: ["liquid", "njk"] }); eleventyConfig.addPlugin(pluginRss); eleventyConfig.addPlugin(pluginTOC, { @@ -186,30 +187,32 @@ module.exports = function(eleventyConfig) { } const markdownIt = require("markdown-it"); + const md = markdownIt({ html: true, linkify: true, typographer: true, highlight: (str, lang) => highlighter(md, str, lang) }) + .use(markdownItAnchor, { + slugify + }) + .use(markdownItContainer, "correct", {}) + .use(markdownItContainer, "incorrect", {}) + .use(markdownItContainer, "warning", { + render(tokens, idx) { + return generateAlertMarkup("warning", tokens, idx); + } + }) + .use(markdownItContainer, "tip", { + render(tokens, idx) { + return generateAlertMarkup("tip", tokens, idx); + } + }) + .use(markdownItContainer, "important", { + render(tokens, idx) { + return generateAlertMarkup("important", tokens, idx); + } + }) + .use(preWrapperPlugin) + .use(lineNumberPlugin) + .disable("code"); - eleventyConfig.setLibrary("md", - markdownIt({ html: true, linkify: true, typographer: true }) - .use(markdownItAnchor, { - slugify - }) - .use(markdownItContainer, "correct", {}) - .use(markdownItContainer, "incorrect", {}) - .use(markdownItContainer, "warning", { - render(tokens, idx) { - return generateAlertMarkup("warning", tokens, idx); - } - }) - .use(markdownItContainer, "tip", { - render(tokens, idx) { - return generateAlertMarkup("tip", tokens, idx); - } - }) - .use(markdownItContainer, "important", { - render(tokens, idx) { - return generateAlertMarkup("important", tokens, idx); - } - }) - .disable("code")); + eleventyConfig.setLibrary("md", md); //------------------------------------------------------------------------------ // Shortcodes diff --git a/docs/package.json b/docs/package.json index 910566158337..c9935e99321b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -42,6 +42,7 @@ "netlify-cli": "^10.3.1", "npm-run-all": "^4.1.5", "postcss-html": "^1.5.0", + "prismjs": "^1.29.0", "rimraf": "^3.0.2", "sass": "^1.52.1", "stylelint": "^14.13.0", diff --git a/docs/src/_plugins/md-syntax-highlighter.js b/docs/src/_plugins/md-syntax-highlighter.js new file mode 100644 index 000000000000..c886043821b8 --- /dev/null +++ b/docs/src/_plugins/md-syntax-highlighter.js @@ -0,0 +1,107 @@ +/** + * MIT License + +Copyright (c) 2019-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +/** @typedef {import("markdown-it")} MarkdownIt */ + +const Prism = require("prismjs"); +const loadLanguages = require("prismjs/components/"); + +/** + * + * @param {MarkdownIt} md markdown-it + * @param {string} str code + * @param {string} lang code language + * @returns + */ +const highlighter = function (md, str, lang) { + let result = ""; + if (lang) { + try { + loadLanguages([lang]); + result = Prism.highlight(str, Prism.languages[lang], lang); + } catch (err) { + console.log(err); + } + } else { + result = md.utils.escapeHtml(str); + } + + return `
${result}
`; +}; + +/** + * + * modified from https://github.com/vuejs/vitepress/blob/main/src/node/markdown/plugins/preWrapper.ts + * @param {MarkdownIt} md + * @license MIT License. See file header. + */ +const preWrapperPlugin = (md) => { + const fence = md.renderer.rules.fence; + md.renderer.rules.fence = (...args) => { + const [tokens, idx] = args; + const lang = tokens[idx].info.trim(); + const rawCode = fence(...args); + return `
${rawCode}
`; + }; +}; + +/** + * + * modified from https://github.com/vuejs/vitepress/blob/main/src/node/markdown/plugins/lineNumbers.ts + * @param {MarkdownIt} md + * @license MIT License. See file header. + */ +const lineNumberPlugin = (md) => { + const fence = md.renderer.rules.fence; + md.renderer.rules.fence = (...args) => { + const [tokens, idx] = args; + const lang = tokens[idx].info.trim(); + const rawCode = fence(...args); + const code = rawCode.slice( + rawCode.indexOf(""), + rawCode.indexOf("") + ); + const lines = code.split("\n"); + const lineNumbersCode = [...Array(lines.length - 1)] + .map( + (line, index) => + `${index + 1}
` + ) + .join(""); + + const lineNumbersWrapperCode = ``; + + const finalCode = rawCode + .replace(/<\/div>$/, `${lineNumbersWrapperCode}`) + .replace(/"(language-\S*?)"/, '"$1 line-numbers-mode"') + .replace(//, ``) + .replace(/
/, `
`);
+
+        return finalCode;
+    };
+};
+
+module.exports.highlighter = highlighter;
+module.exports.preWrapperPlugin = preWrapperPlugin;
+module.exports.lineNumberPlugin = lineNumberPlugin;
diff --git a/docs/src/assets/scss/syntax-highlighter.scss b/docs/src/assets/scss/syntax-highlighter.scss
index cb26ac75af42..18269425cb19 100644
--- a/docs/src/assets/scss/syntax-highlighter.scss
+++ b/docs/src/assets/scss/syntax-highlighter.scss
@@ -32,7 +32,7 @@ pre[class*="language-"] {
 }
 
 /* Code blocks */
-pre[class*="language-"] {
+div[class*="language-"] {
     padding: 1.5rem;
     margin: 1.5rem 0;
     overflow: auto;
@@ -52,8 +52,8 @@ pre[class*="language-"] {
 
 /* Inline code */
 :not(pre) > code[class*="language-"] {
-    padding: .1em;
-    border-radius: .3em;
+    padding: 0.1em;
+    border-radius: 0.3em;
     white-space: normal;
 }
 
@@ -69,7 +69,7 @@ pre[class*="language-"] {
 }
 
 .token.namespace {
-    opacity: .7;
+    opacity: 0.7;
 }
 
 .token.selector,
@@ -100,25 +100,32 @@ pre[class*="language-"] {
     cursor: help;
 }
 
-pre {
-    counter-reset: lineNumber;
-}
-
-code .highlight-line {
-    font-variant-ligatures: none;
+.line-numbers-wrapper {
+    position: absolute;
+    top: 0;
+    text-align: right;
+    padding-top: 1.5rem;
+    font-size: 1em;
+    font-family: var(--mono-font), Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+    line-height: 1.5;
+    color: var(--icon-color);
 }
 
-code .highlight-line::before {
-    -webkit-user-select: none;
+.line-number {
+    user-select: none;
     color: var(--icon-color);
-    content: counter(lineNumber);
-    counter-increment: lineNumber;
     display: inline-block;
     font-variant-numeric: tabular-nums;
-    margin-right: 1.2em;
-    padding-right: 1.2em;
-    margin-inline-end: 1.2em;
-    padding-inline-end: 1.2em;
     text-align: right;
-    width: 2.4em;
+    width: 1.2em;
+}
+
+div[class*="language-"].line-numbers-mode {
+    position: relative;
+
+    pre[class*="language-"] {
+        padding-left: calc(2.4em + 1.2rem);
+        margin-top: 0;
+        margin-bottom: 0;
+    }
 }

From 9b8bb72c49a453086954b06a5d7dd390731b1975 Mon Sep 17 00:00:00 2001
From: Milos Djermanovic 
Date: Thu, 8 Dec 2022 20:17:06 +0100
Subject: [PATCH 23/29] fix: autofix recursive functions in no-var (#16611)

Fixes #16610
---
 lib/rules/no-var.js       |  2 +-
 tests/lib/rules/no-var.js | 68 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/lib/rules/no-var.js b/lib/rules/no-var.js
index cfb64efafcce..80ff8f1a027d 100644
--- a/lib/rules/no-var.js
+++ b/lib/rules/no-var.js
@@ -159,7 +159,7 @@ function hasReferenceInTDZ(node) {
             return !reference.init && (
                 start < idStart ||
                 (defaultValue !== null && start >= defaultStart && end <= defaultEnd) ||
-                (start >= initStart && end <= initEnd)
+                (!astUtils.isFunction(node) && start >= initStart && end <= initEnd)
             );
         });
     };
diff --git a/tests/lib/rules/no-var.js b/tests/lib/rules/no-var.js
index 84e14ae19c90..26b0a8464f4d 100644
--- a/tests/lib/rules/no-var.js
+++ b/tests/lib/rules/no-var.js
@@ -319,6 +319,74 @@ ruleTester.run("no-var", rule, {
             code: "function foo() { var { let } = {}; }",
             output: null,
             errors: [{ messageId: "unexpectedVar" }]
+        },
+
+        // https://github.com/eslint/eslint/issues/16610
+        {
+            code: "var fx = function (i = 0) { if (i < 5) { return fx(i + 1); } console.log(i); }; fx();",
+            output: "let fx = function (i = 0) { if (i < 5) { return fx(i + 1); } console.log(i); }; fx();",
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var foo = function () { foo() };",
+            output: "let foo = function () { foo() };",
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var foo = () => foo();",
+            output: "let foo = () => foo();",
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var foo = (function () { foo(); })();",
+            output: null,
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var foo = bar(function () { foo(); });",
+            output: null,
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var bar = foo, foo = function () { foo(); };",
+            output: null,
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var bar = foo; var foo = function () { foo(); };",
+            output: "let bar = foo; var foo = function () { foo(); };",
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                { messageId: "unexpectedVar" },
+                { messageId: "unexpectedVar" }
+            ]
+        },
+        {
+            code: "var { foo = foo } = function () { foo(); };",
+            output: null,
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var { bar = foo, foo } = function () { foo(); };",
+            output: null,
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [{ messageId: "unexpectedVar" }]
+        },
+        {
+            code: "var bar = function () { foo(); }; var foo = function() {};",
+            output: "let bar = function () { foo(); }; var foo = function() {};",
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                { messageId: "unexpectedVar" },
+                { messageId: "unexpectedVar" }
+            ]
         }
     ]
 });

From 90c9219181e0aadcae7224602d2988186d457113 Mon Sep 17 00:00:00 2001
From: Bryan Mishkin <698306+bmish@users.noreply.github.com>
Date: Thu, 8 Dec 2022 12:05:04 -0800
Subject: [PATCH 24/29] refactor: migrate off deprecated function-style rules
 in all tests (#16618)

* refactor: migrate off deprecated function-style rules in all tests

Preparing for RFC-85.

* chore: enable object-shorthand rule always avoidExplicitReturnArrows
---
 docs/.eleventy.js                             |    2 +-
 lib/rule-tester/flat-rule-tester.js           |   20 +-
 lib/rule-tester/rule-tester.js                |   18 +-
 lib/rules/comma-dangle.js                     |    2 +-
 lib/rules/multiline-ternary.js                |    4 +-
 lib/rules/no-else-return.js                   |    2 +-
 lib/rules/no-unneeded-ternary.js              |    2 +-
 packages/eslint-config-eslint/default.yml     |    2 +-
 tests/fixtures/rules/custom-rule.js           |   24 +-
 tests/lib/cli-engine/cli-engine.js            |    4 +-
 tests/lib/config/flat-config-array.js         |   42 +-
 .../code-path-analysis/code-path-analyzer.js  |  416 +--
 .../linter/code-path-analysis/code-path.js    |   12 +-
 tests/lib/linter/linter.js                    | 2804 +++++++++--------
 tests/lib/rules/no-unused-vars.js             |   28 +-
 tests/lib/rules/prefer-const.js               |   12 +-
 tests/lib/rules/utils/ast-utils.js            |  144 +-
 tests/lib/shared/config-validator.js          |   85 +-
 tests/lib/source-code/source-code.js          |  846 +++--
 tests/tools/eslint-fuzzer.js                  |  141 +-
 tools/fuzzer-runner.js                        |    4 +-
 21 files changed, 2645 insertions(+), 1969 deletions(-)

diff --git a/docs/.eleventy.js b/docs/.eleventy.js
index 32666ec624d3..87dc13b5faf3 100644
--- a/docs/.eleventy.js
+++ b/docs/.eleventy.js
@@ -455,7 +455,7 @@ module.exports = function(eleventyConfig) {
      * URLs with a file extension, like main.css, main.js, sitemap.xml, etc. should not be rewritten
      */
     eleventyConfig.setBrowserSyncConfig({
-        middleware: (req, res, next) => {
+        middleware(req, res, next) {
             if (!/(?:\.[a-zA-Z][^/]*|\/)$/u.test(req.url)) {
                 req.url += ".html";
             }
diff --git a/lib/rule-tester/flat-rule-tester.js b/lib/rule-tester/flat-rule-tester.js
index f915924c78b6..b45b5d3c3dbd 100644
--- a/lib/rule-tester/flat-rule-tester.js
+++ b/lib/rule-tester/flat-rule-tester.js
@@ -619,15 +619,17 @@ class FlatRuleTester {
                 plugins: {
                     "rule-tester": {
                         rules: {
-                            "validate-ast"() {
-                                return {
-                                    Program(node) {
-                                        beforeAST = cloneDeeplyExcludesParent(node);
-                                    },
-                                    "Program:exit"(node) {
-                                        afterAST = node;
-                                    }
-                                };
+                            "validate-ast": {
+                                create() {
+                                    return {
+                                        Program(node) {
+                                            beforeAST = cloneDeeplyExcludesParent(node);
+                                        },
+                                        "Program:exit"(node) {
+                                            afterAST = node;
+                                        }
+                                    };
+                                }
                             }
                         }
                     }
diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js
index 2af272bd25b3..62fd467e0b07 100644
--- a/lib/rule-tester/rule-tester.js
+++ b/lib/rule-tester/rule-tester.js
@@ -632,14 +632,18 @@ class RuleTester {
              * The goal is to check whether or not AST was modified when
              * running the rule under test.
              */
-            linter.defineRule("rule-tester/validate-ast", () => ({
-                Program(node) {
-                    beforeAST = cloneDeeplyExcludesParent(node);
-                },
-                "Program:exit"(node) {
-                    afterAST = node;
+            linter.defineRule("rule-tester/validate-ast", {
+                create() {
+                    return {
+                        Program(node) {
+                            beforeAST = cloneDeeplyExcludesParent(node);
+                        },
+                        "Program:exit"(node) {
+                            afterAST = node;
+                        }
+                    };
                 }
-            }));
+            });
 
             if (typeof config.parser === "string") {
                 assert(path.isAbsolute(config.parser), "Parsers provided as strings to RuleTester must be absolute paths");
diff --git a/lib/rules/comma-dangle.js b/lib/rules/comma-dangle.js
index 89d8cabcc372..09fecd5a448f 100644
--- a/lib/rules/comma-dangle.js
+++ b/lib/rules/comma-dangle.js
@@ -346,7 +346,7 @@ module.exports = {
             "always-multiline": forceTrailingCommaIfMultiline,
             "only-multiline": allowTrailingCommaIfMultiline,
             never: forbidTrailingComma,
-            ignore: () => {}
+            ignore() {}
         };
 
         return {
diff --git a/lib/rules/multiline-ternary.js b/lib/rules/multiline-ternary.js
index 62c84bbfed85..d8fe0b161c9e 100644
--- a/lib/rules/multiline-ternary.js
+++ b/lib/rules/multiline-ternary.js
@@ -73,7 +73,7 @@ module.exports = {
                                 end: lastTokenOfTest.loc.end
                             },
                             messageId: "unexpectedTestCons",
-                            fix: fixer => {
+                            fix(fixer) {
                                 if (hasComments) {
                                     return null;
                                 }
@@ -101,7 +101,7 @@ module.exports = {
                                 end: lastTokenOfConsequent.loc.end
                             },
                             messageId: "unexpectedConsAlt",
-                            fix: fixer => {
+                            fix(fixer) {
                                 if (hasComments) {
                                     return null;
                                 }
diff --git a/lib/rules/no-else-return.js b/lib/rules/no-else-return.js
index d1da3aa49cb4..f3ceedb4cd7f 100644
--- a/lib/rules/no-else-return.js
+++ b/lib/rules/no-else-return.js
@@ -178,7 +178,7 @@ module.exports = {
             context.report({
                 node,
                 messageId: "unexpected",
-                fix: fixer => {
+                fix(fixer) {
 
                     if (!isSafeFromNameCollisions(node, currentScope)) {
                         return null;
diff --git a/lib/rules/no-unneeded-ternary.js b/lib/rules/no-unneeded-ternary.js
index c193282fa703..80b83ac9ded3 100644
--- a/lib/rules/no-unneeded-ternary.js
+++ b/lib/rules/no-unneeded-ternary.js
@@ -144,7 +144,7 @@ module.exports = {
                     context.report({
                         node,
                         messageId: "unnecessaryConditionalAssignment",
-                        fix: fixer => {
+                        fix(fixer) {
                             const shouldParenthesizeAlternate =
                                 (
                                     astUtils.getPrecedence(node.alternate) < OR_PRECEDENCE ||
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index e233e8b01cc3..afaabe4f7ab5 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -275,7 +275,7 @@ rules:
     object-curly-newline: ["error", { "consistent": true, "multiline": true }]
     object-curly-spacing: ["error", "always"]
     object-property-newline: ["error", { "allowAllPropertiesOnSameLine": true }]
-    object-shorthand: "error"
+    object-shorthand: ["error", "always", { "avoidExplicitReturnArrows": true }]
     one-var-declaration-per-line: "error"
     operator-assignment: "error"
     operator-linebreak: "error"
diff --git a/tests/fixtures/rules/custom-rule.js b/tests/fixtures/rules/custom-rule.js
index 6d8b662ba398..8b1cce10dbc3 100644
--- a/tests/fixtures/rules/custom-rule.js
+++ b/tests/fixtures/rules/custom-rule.js
@@ -1,15 +1,17 @@
-module.exports = function(context) {
+module.exports = {
+    meta: {
+        schema: []
+    },
+    create(context) {
 
-    "use strict";
+        "use strict";
 
-    return {
-        "Identifier": function(node) {
-            if (node.name === "foo") {
-                context.report(node, "Identifier cannot be named 'foo'.");
+        return {
+            "Identifier": function(node) {
+                if (node.name === "foo") {
+                    context.report(node, "Identifier cannot be named 'foo'.");
+                }
             }
-        }
-    };
-
+        };
+    }
 };
-
-module.exports.schema = [];
diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js
index 9cd5593c8b3e..df3b6719f4c5 100644
--- a/tests/lib/cli-engine/cli-engine.js
+++ b/tests/lib/cli-engine/cli-engine.js
@@ -5018,7 +5018,7 @@ describe("CLIEngine", () => {
 
         it("should call fs.writeFileSync() for each result with output", () => {
             const fakeFS = {
-                    writeFileSync: () => {}
+                    writeFileSync() {}
                 },
                 localCLIEngine = proxyquire("../../../lib/cli-engine/cli-engine", {
                     fs: fakeFS
@@ -5048,7 +5048,7 @@ describe("CLIEngine", () => {
 
         it("should call fs.writeFileSync() for each result with output and not at all for a result without output", () => {
             const fakeFS = {
-                    writeFileSync: () => {}
+                    writeFileSync() {}
                 },
                 localCLIEngine = proxyquire("../../../lib/cli-engine/cli-engine", {
                     fs: fakeFS
diff --git a/tests/lib/config/flat-config-array.js b/tests/lib/config/flat-config-array.js
index 675257ee8ec8..0b284f61f072 100644
--- a/tests/lib/config/flat-config-array.js
+++ b/tests/lib/config/flat-config-array.js
@@ -25,15 +25,17 @@ const baseConfig = {
         "@": {
             rules: {
                 foo: {
-                    schema: {
-                        type: "array",
-                        items: [
-                            {
-                                enum: ["always", "never"]
-                            }
-                        ],
-                        minItems: 0,
-                        maxItems: 1
+                    meta: {
+                        schema: {
+                            type: "array",
+                            items: [
+                                {
+                                    enum: ["always", "never"]
+                                }
+                            ],
+                            minItems: 0,
+                            maxItems: 1
+                        }
                     }
 
                 },
@@ -48,13 +50,15 @@ const baseConfig = {
                 boom() {},
 
                 foo2: {
-                    schema: {
-                        type: "array",
-                        items: {
-                            type: "string"
-                        },
-                        uniqueItems: true,
-                        minItems: 1
+                    meta: {
+                        schema: {
+                            type: "array",
+                            items: {
+                                type: "string"
+                            },
+                            uniqueItems: true,
+                            minItems: 1
+                        }
                     }
                 }
             }
@@ -1505,20 +1509,20 @@ describe("FlatConfigArray", () => {
                 {
                     rules: {
                         foo: 1,
-                        bar: "error"
+                        foo2: "error"
                     }
                 },
                 {
                     rules: {
                         foo: ["error", "never"],
-                        bar: ["warn", "foo"]
+                        foo2: ["warn", "foo"]
                     }
                 }
             ], {
                 plugins: baseConfig.plugins,
                 rules: {
                     foo: [2, "never"],
-                    bar: [1, "foo"]
+                    foo2: [1, "foo"]
                 }
             }));
 
diff --git a/tests/lib/linter/code-path-analysis/code-path-analyzer.js b/tests/lib/linter/code-path-analysis/code-path-analyzer.js
index 0b5dd33aab80..cc2717a7ff8a 100644
--- a/tests/lib/linter/code-path-analysis/code-path-analyzer.js
+++ b/tests/lib/linter/code-path-analysis/code-path-analyzer.js
@@ -66,11 +66,13 @@ describe("CodePathAnalyzer", () => {
 
         beforeEach(() => {
             actual = [];
-            linter.defineRule("test", () => ({
-                onCodePathStart(codePath) {
-                    actual.push(codePath);
-                }
-            }));
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathStart(codePath) {
+                        actual.push(codePath);
+                    }
+                })
+            });
             linter.verify(
                 "function foo(a) { if (a) return 0; else throw new Error(); }",
                 { rules: { test: 2 } }
@@ -142,22 +144,24 @@ describe("CodePathAnalyzer", () => {
             assert(actual[1].currentSegments.length === 0);
 
             // there is the current segment in progress.
-            linter.defineRule("test", () => {
-                let codePath = null;
-
-                return {
-                    onCodePathStart(cp) {
-                        codePath = cp;
-                    },
-                    ReturnStatement() {
-                        assert(codePath.currentSegments.length === 1);
-                        assert(codePath.currentSegments[0] instanceof CodePathSegment);
-                    },
-                    ThrowStatement() {
-                        assert(codePath.currentSegments.length === 1);
-                        assert(codePath.currentSegments[0] instanceof CodePathSegment);
-                    }
-                };
+            linter.defineRule("test", {
+                create() {
+                    let codePath = null;
+
+                    return {
+                        onCodePathStart(cp) {
+                            codePath = cp;
+                        },
+                        ReturnStatement() {
+                            assert(codePath.currentSegments.length === 1);
+                            assert(codePath.currentSegments[0] instanceof CodePathSegment);
+                        },
+                        ThrowStatement() {
+                            assert(codePath.currentSegments.length === 1);
+                            assert(codePath.currentSegments[0] instanceof CodePathSegment);
+                        }
+                    };
+                }
             });
             linter.verify(
                 "function foo(a) { if (a) return 0; else throw new Error(); }",
@@ -171,11 +175,13 @@ describe("CodePathAnalyzer", () => {
 
         beforeEach(() => {
             actual = [];
-            linter.defineRule("test", () => ({
-                onCodePathSegmentStart(segment) {
-                    actual.push(segment);
-                }
-            }));
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentStart(segment) {
+                        actual.push(segment);
+                    }
+                })
+            });
             linter.verify(
                 "function foo(a) { if (a) return 0; else throw new Error(); }",
                 { rules: { test: 2 } }
@@ -258,35 +264,37 @@ describe("CodePathAnalyzer", () => {
             let count = 0;
             let lastCodePathNodeType = null;
 
-            linter.defineRule("test", () => ({
-                onCodePathStart(cp, node) {
-                    count += 1;
-                    lastCodePathNodeType = node.type;
-
-                    assert(cp instanceof CodePath);
-                    if (count === 1) {
-                        assert(node.type === "Program");
-                    } else if (count === 2) {
-                        assert(node.type === "FunctionDeclaration");
-                    } else if (count === 3) {
-                        assert(node.type === "FunctionExpression");
-                    } else if (count === 4) {
-                        assert(node.type === "ArrowFunctionExpression");
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathStart(cp, node) {
+                        count += 1;
+                        lastCodePathNodeType = node.type;
+
+                        assert(cp instanceof CodePath);
+                        if (count === 1) {
+                            assert(node.type === "Program");
+                        } else if (count === 2) {
+                            assert(node.type === "FunctionDeclaration");
+                        } else if (count === 3) {
+                            assert(node.type === "FunctionExpression");
+                        } else if (count === 4) {
+                            assert(node.type === "ArrowFunctionExpression");
+                        }
+                    },
+                    Program() {
+                        assert(lastCodePathNodeType === "Program");
+                    },
+                    FunctionDeclaration() {
+                        assert(lastCodePathNodeType === "FunctionDeclaration");
+                    },
+                    FunctionExpression() {
+                        assert(lastCodePathNodeType === "FunctionExpression");
+                    },
+                    ArrowFunctionExpression() {
+                        assert(lastCodePathNodeType === "ArrowFunctionExpression");
                     }
-                },
-                Program() {
-                    assert(lastCodePathNodeType === "Program");
-                },
-                FunctionDeclaration() {
-                    assert(lastCodePathNodeType === "FunctionDeclaration");
-                },
-                FunctionExpression() {
-                    assert(lastCodePathNodeType === "FunctionExpression");
-                },
-                ArrowFunctionExpression() {
-                    assert(lastCodePathNodeType === "ArrowFunctionExpression");
-                }
-            }));
+                })
+            });
             linter.verify(
                 "foo(); function foo() {} var foo = function() {}; var foo = () => {};",
                 { rules: { test: 2 }, env: { es6: true } }
@@ -301,35 +309,37 @@ describe("CodePathAnalyzer", () => {
             let count = 0;
             let lastNodeType = null;
 
-            linter.defineRule("test", () => ({
-                onCodePathEnd(cp, node) {
-                    count += 1;
-
-                    assert(cp instanceof CodePath);
-                    if (count === 4) {
-                        assert(node.type === "Program");
-                    } else if (count === 1) {
-                        assert(node.type === "FunctionDeclaration");
-                    } else if (count === 2) {
-                        assert(node.type === "FunctionExpression");
-                    } else if (count === 3) {
-                        assert(node.type === "ArrowFunctionExpression");
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathEnd(cp, node) {
+                        count += 1;
+
+                        assert(cp instanceof CodePath);
+                        if (count === 4) {
+                            assert(node.type === "Program");
+                        } else if (count === 1) {
+                            assert(node.type === "FunctionDeclaration");
+                        } else if (count === 2) {
+                            assert(node.type === "FunctionExpression");
+                        } else if (count === 3) {
+                            assert(node.type === "ArrowFunctionExpression");
+                        }
+                        assert(node.type === lastNodeType);
+                    },
+                    "Program:exit"() {
+                        lastNodeType = "Program";
+                    },
+                    "FunctionDeclaration:exit"() {
+                        lastNodeType = "FunctionDeclaration";
+                    },
+                    "FunctionExpression:exit"() {
+                        lastNodeType = "FunctionExpression";
+                    },
+                    "ArrowFunctionExpression:exit"() {
+                        lastNodeType = "ArrowFunctionExpression";
                     }
-                    assert(node.type === lastNodeType);
-                },
-                "Program:exit"() {
-                    lastNodeType = "Program";
-                },
-                "FunctionDeclaration:exit"() {
-                    lastNodeType = "FunctionDeclaration";
-                },
-                "FunctionExpression:exit"() {
-                    lastNodeType = "FunctionExpression";
-                },
-                "ArrowFunctionExpression:exit"() {
-                    lastNodeType = "ArrowFunctionExpression";
-                }
-            }));
+                })
+            });
             linter.verify(
                 "foo(); function foo() {} var foo = function() {}; var foo = () => {};",
                 { rules: { test: 2 }, env: { es6: true } }
@@ -344,35 +354,37 @@ describe("CodePathAnalyzer", () => {
             let count = 0;
             let lastCodePathNodeType = null;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentStart(segment, node) {
-                    count += 1;
-                    lastCodePathNodeType = node.type;
-
-                    assert(segment instanceof CodePathSegment);
-                    if (count === 1) {
-                        assert(node.type === "Program");
-                    } else if (count === 2) {
-                        assert(node.type === "FunctionDeclaration");
-                    } else if (count === 3) {
-                        assert(node.type === "FunctionExpression");
-                    } else if (count === 4) {
-                        assert(node.type === "ArrowFunctionExpression");
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentStart(segment, node) {
+                        count += 1;
+                        lastCodePathNodeType = node.type;
+
+                        assert(segment instanceof CodePathSegment);
+                        if (count === 1) {
+                            assert(node.type === "Program");
+                        } else if (count === 2) {
+                            assert(node.type === "FunctionDeclaration");
+                        } else if (count === 3) {
+                            assert(node.type === "FunctionExpression");
+                        } else if (count === 4) {
+                            assert(node.type === "ArrowFunctionExpression");
+                        }
+                    },
+                    Program() {
+                        assert(lastCodePathNodeType === "Program");
+                    },
+                    FunctionDeclaration() {
+                        assert(lastCodePathNodeType === "FunctionDeclaration");
+                    },
+                    FunctionExpression() {
+                        assert(lastCodePathNodeType === "FunctionExpression");
+                    },
+                    ArrowFunctionExpression() {
+                        assert(lastCodePathNodeType === "ArrowFunctionExpression");
                     }
-                },
-                Program() {
-                    assert(lastCodePathNodeType === "Program");
-                },
-                FunctionDeclaration() {
-                    assert(lastCodePathNodeType === "FunctionDeclaration");
-                },
-                FunctionExpression() {
-                    assert(lastCodePathNodeType === "FunctionExpression");
-                },
-                ArrowFunctionExpression() {
-                    assert(lastCodePathNodeType === "ArrowFunctionExpression");
-                }
-            }));
+                })
+            });
             linter.verify(
                 "foo(); function foo() {} var foo = function() {}; var foo = () => {};",
                 { rules: { test: 2 }, env: { es6: true } }
@@ -387,35 +399,37 @@ describe("CodePathAnalyzer", () => {
             let count = 0;
             let lastNodeType = null;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentEnd(cp, node) {
-                    count += 1;
-
-                    assert(cp instanceof CodePathSegment);
-                    if (count === 4) {
-                        assert(node.type === "Program");
-                    } else if (count === 1) {
-                        assert(node.type === "FunctionDeclaration");
-                    } else if (count === 2) {
-                        assert(node.type === "FunctionExpression");
-                    } else if (count === 3) {
-                        assert(node.type === "ArrowFunctionExpression");
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentEnd(cp, node) {
+                        count += 1;
+
+                        assert(cp instanceof CodePathSegment);
+                        if (count === 4) {
+                            assert(node.type === "Program");
+                        } else if (count === 1) {
+                            assert(node.type === "FunctionDeclaration");
+                        } else if (count === 2) {
+                            assert(node.type === "FunctionExpression");
+                        } else if (count === 3) {
+                            assert(node.type === "ArrowFunctionExpression");
+                        }
+                        assert(node.type === lastNodeType);
+                    },
+                    "Program:exit"() {
+                        lastNodeType = "Program";
+                    },
+                    "FunctionDeclaration:exit"() {
+                        lastNodeType = "FunctionDeclaration";
+                    },
+                    "FunctionExpression:exit"() {
+                        lastNodeType = "FunctionExpression";
+                    },
+                    "ArrowFunctionExpression:exit"() {
+                        lastNodeType = "ArrowFunctionExpression";
                     }
-                    assert(node.type === lastNodeType);
-                },
-                "Program:exit"() {
-                    lastNodeType = "Program";
-                },
-                "FunctionDeclaration:exit"() {
-                    lastNodeType = "FunctionDeclaration";
-                },
-                "FunctionExpression:exit"() {
-                    lastNodeType = "FunctionExpression";
-                },
-                "ArrowFunctionExpression:exit"() {
-                    lastNodeType = "ArrowFunctionExpression";
-                }
-            }));
+                })
+            });
             linter.verify(
                 "foo(); function foo() {} var foo = function() {}; var foo = () => {};",
                 { rules: { test: 2 }, env: { es6: true } }
@@ -429,14 +443,16 @@ describe("CodePathAnalyzer", () => {
         it("should be fired in `while` loops", () => {
             let count = 0;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentLoop(fromSegment, toSegment, node) {
-                    count += 1;
-                    assert(fromSegment instanceof CodePathSegment);
-                    assert(toSegment instanceof CodePathSegment);
-                    assert(node.type === "WhileStatement");
-                }
-            }));
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentLoop(fromSegment, toSegment, node) {
+                        count += 1;
+                        assert(fromSegment instanceof CodePathSegment);
+                        assert(toSegment instanceof CodePathSegment);
+                        assert(node.type === "WhileStatement");
+                    }
+                })
+            });
             linter.verify(
                 "while (a) { foo(); }",
                 { rules: { test: 2 } }
@@ -448,14 +464,16 @@ describe("CodePathAnalyzer", () => {
         it("should be fired in `do-while` loops", () => {
             let count = 0;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentLoop(fromSegment, toSegment, node) {
-                    count += 1;
-                    assert(fromSegment instanceof CodePathSegment);
-                    assert(toSegment instanceof CodePathSegment);
-                    assert(node.type === "DoWhileStatement");
-                }
-            }));
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentLoop(fromSegment, toSegment, node) {
+                        count += 1;
+                        assert(fromSegment instanceof CodePathSegment);
+                        assert(toSegment instanceof CodePathSegment);
+                        assert(node.type === "DoWhileStatement");
+                    }
+                })
+            });
             linter.verify(
                 "do { foo(); } while (a);",
                 { rules: { test: 2 } }
@@ -467,21 +485,23 @@ describe("CodePathAnalyzer", () => {
         it("should be fired in `for` loops", () => {
             let count = 0;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentLoop(fromSegment, toSegment, node) {
-                    count += 1;
-                    assert(fromSegment instanceof CodePathSegment);
-                    assert(toSegment instanceof CodePathSegment);
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentLoop(fromSegment, toSegment, node) {
+                        count += 1;
+                        assert(fromSegment instanceof CodePathSegment);
+                        assert(toSegment instanceof CodePathSegment);
 
-                    if (count === 1) {
+                        if (count === 1) {
 
-                        // connect path: "update" -> "test"
-                        assert(node.parent.type === "ForStatement");
-                    } else if (count === 2) {
-                        assert(node.type === "ForStatement");
+                            // connect path: "update" -> "test"
+                            assert(node.parent.type === "ForStatement");
+                        } else if (count === 2) {
+                            assert(node.type === "ForStatement");
+                        }
                     }
-                }
-            }));
+                })
+            });
             linter.verify(
                 "for (var i = 0; i < 10; ++i) { foo(); }",
                 { rules: { test: 2 } }
@@ -493,21 +513,23 @@ describe("CodePathAnalyzer", () => {
         it("should be fired in `for-in` loops", () => {
             let count = 0;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentLoop(fromSegment, toSegment, node) {
-                    count += 1;
-                    assert(fromSegment instanceof CodePathSegment);
-                    assert(toSegment instanceof CodePathSegment);
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentLoop(fromSegment, toSegment, node) {
+                        count += 1;
+                        assert(fromSegment instanceof CodePathSegment);
+                        assert(toSegment instanceof CodePathSegment);
 
-                    if (count === 1) {
+                        if (count === 1) {
 
-                        // connect path: "right" -> "left"
-                        assert(node.parent.type === "ForInStatement");
-                    } else if (count === 2) {
-                        assert(node.type === "ForInStatement");
+                            // connect path: "right" -> "left"
+                            assert(node.parent.type === "ForInStatement");
+                        } else if (count === 2) {
+                            assert(node.type === "ForInStatement");
+                        }
                     }
-                }
-            }));
+                })
+            });
             linter.verify(
                 "for (var k in obj) { foo(); }",
                 { rules: { test: 2 } }
@@ -519,21 +541,23 @@ describe("CodePathAnalyzer", () => {
         it("should be fired in `for-of` loops", () => {
             let count = 0;
 
-            linter.defineRule("test", () => ({
-                onCodePathSegmentLoop(fromSegment, toSegment, node) {
-                    count += 1;
-                    assert(fromSegment instanceof CodePathSegment);
-                    assert(toSegment instanceof CodePathSegment);
+            linter.defineRule("test", {
+                create: () => ({
+                    onCodePathSegmentLoop(fromSegment, toSegment, node) {
+                        count += 1;
+                        assert(fromSegment instanceof CodePathSegment);
+                        assert(toSegment instanceof CodePathSegment);
 
-                    if (count === 1) {
+                        if (count === 1) {
 
-                        // connect path: "right" -> "left"
-                        assert(node.parent.type === "ForOfStatement");
-                    } else if (count === 2) {
-                        assert(node.type === "ForOfStatement");
+                            // connect path: "right" -> "left"
+                            assert(node.parent.type === "ForOfStatement");
+                        } else if (count === 2) {
+                            assert(node.type === "ForOfStatement");
+                        }
                     }
-                }
-            }));
+                })
+            });
             linter.verify(
                 "for (var x of xs) { foo(); }",
                 { rules: { test: 2 }, env: { es6: true } }
@@ -555,11 +579,13 @@ describe("CodePathAnalyzer", () => {
 
                 assert(expected.length > 0, "/*expected */ comments not found.");
 
-                linter.defineRule("test", () => ({
-                    onCodePathEnd(codePath) {
-                        actual.push(debug.makeDotArrows(codePath));
-                    }
-                }));
+                linter.defineRule("test", {
+                    create: () => ({
+                        onCodePathEnd(codePath) {
+                            actual.push(debug.makeDotArrows(codePath));
+                        }
+                    })
+                });
                 const messages = linter.verify(source, {
                     parserOptions: { ecmaVersion: 2022 },
                     rules: { test: 2 }
diff --git a/tests/lib/linter/code-path-analysis/code-path.js b/tests/lib/linter/code-path-analysis/code-path.js
index 40fb017ed7b3..7f1d738f6e96 100644
--- a/tests/lib/linter/code-path-analysis/code-path.js
+++ b/tests/lib/linter/code-path-analysis/code-path.js
@@ -25,11 +25,13 @@ const linter = new Linter();
 function parseCodePaths(code) {
     const retv = [];
 
-    linter.defineRule("test", () => ({
-        onCodePathStart(codePath) {
-            retv.push(codePath);
-        }
-    }));
+    linter.defineRule("test", {
+        create: () => ({
+            onCodePathStart(codePath) {
+                retv.push(codePath);
+            }
+        })
+    });
 
     linter.verify(code, {
         rules: { test: 2 },
diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js
index 407194d47e70..549969cc165e 100644
--- a/tests/lib/linter/linter.js
+++ b/tests/lib/linter/linter.js
@@ -80,11 +80,13 @@ describe("Linter", () => {
         it("an error should be thrown when an error occurs inside of an event handler", () => {
             const config = { rules: { checker: "error" } };
 
-            linter.defineRule("checker", () => ({
-                Program() {
-                    throw new Error("Intentional error.");
-                }
-            }));
+            linter.defineRule("checker", {
+                create: () => ({
+                    Program() {
+                        throw new Error("Intentional error.");
+                    }
+                })
+            });
 
             assert.throws(() => {
                 linter.verify(code, config, filename);
@@ -94,7 +96,9 @@ describe("Linter", () => {
         it("does not call rule listeners with a `this` value", () => {
             const spy = sinon.spy();
 
-            linter.defineRule("checker", () => ({ Program: spy }));
+            linter.defineRule("checker", {
+                create: () => ({ Program: spy })
+            });
             linter.verify("foo", { rules: { checker: "error" } });
             assert(spy.calledOnce, "Rule should have been called");
             assert.strictEqual(spy.firstCall.thisValue, void 0, "this value should be undefined");
@@ -103,7 +107,9 @@ describe("Linter", () => {
         it("does not allow listeners to use special EventEmitter values", () => {
             const spy = sinon.spy();
 
-            linter.defineRule("checker", () => ({ newListener: spy }));
+            linter.defineRule("checker", {
+                create: () => ({ newListener: spy })
+            });
             linter.verify("foo", { rules: { checker: "error", "no-undef": "error" } });
             assert(spy.notCalled);
         });
@@ -120,7 +126,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
 
             linter.verify("foo + bar", { rules: { checker: "error" } });
             assert(spy.calledOnce);
@@ -136,7 +142,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, { rules: { checker: "error" } });
             assert(spy.calledOnce);
         });
@@ -148,7 +154,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, { rules: { checker: "error" } });
             assert(spy.calledOnce);
         });
@@ -160,7 +166,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, { rules: { checker: "error" } });
             assert(spy.calledOnce);
         });
@@ -172,7 +178,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, { rules: { checker: "error" } });
             assert(spy.calledOnce);
         });
@@ -184,7 +190,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, { rules: { checker: "error" } });
             assert(spy.calledOnce);
         });
@@ -350,11 +356,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    assert.strictEqual(context.getSource(), TEST_CODE);
-                });
-                return { Program: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        assert.strictEqual(context.getSource(), TEST_CODE);
+                    });
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -365,11 +373,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node), TEST_CODE);
-                });
-                return { Program: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node), TEST_CODE);
+                    });
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -380,11 +390,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
-                });
-                return { Program: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
+                    });
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -395,11 +407,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node), "6 * 7");
-                });
-                return { BinaryExpression: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node), "6 * 7");
+                    });
+                    return { BinaryExpression: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -410,11 +424,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
-                });
-                return { BinaryExpression: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
+                    });
+                    return { BinaryExpression: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -425,11 +441,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
-                });
-                return { BinaryExpression: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
+                    });
+                    return { BinaryExpression: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -440,11 +458,13 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
-                });
-                return { BinaryExpression: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
+                    });
+                    return { BinaryExpression: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -461,13 +481,15 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const ancestors = context.getAncestors();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const ancestors = context.getAncestors();
 
-                    assert.strictEqual(ancestors.length, 3);
-                });
-                return { BinaryExpression: spy };
+                        assert.strictEqual(ancestors.length, 3);
+                    });
+                    return { BinaryExpression: spy };
+                }
             });
 
             linter.verify(code, config, filename, true);
@@ -478,14 +500,16 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const ancestors = context.getAncestors();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const ancestors = context.getAncestors();
 
-                    assert.strictEqual(ancestors.length, 0);
-                });
+                        assert.strictEqual(ancestors.length, 0);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -503,7 +527,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -515,7 +539,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -530,7 +554,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -542,7 +566,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -560,7 +584,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -578,7 +602,7 @@ describe("Linter", () => {
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -592,13 +616,15 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "global");
-                });
-                return { Program: spy };
+                        assert.strictEqual(scope.type, "global");
+                    });
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -609,13 +635,15 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                });
-                return { FunctionDeclaration: spy };
+                        assert.strictEqual(scope.type, "function");
+                    });
+                    return { FunctionDeclaration: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -626,14 +654,16 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                    assert.strictEqual(scope.block.id.name, "foo");
-                });
-                return { LabeledStatement: spy };
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block.id.name, "foo");
+                    });
+                    return { LabeledStatement: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -644,15 +674,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                    assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
-                });
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
+                    });
 
-                return { ReturnStatement: spy };
+                    return { ReturnStatement: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -663,15 +695,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "switch");
-                    assert.strictEqual(scope.block.type, "SwitchStatement");
-                });
+                        assert.strictEqual(scope.type, "switch");
+                        assert.strictEqual(scope.block.type, "SwitchStatement");
+                    });
 
-                return { SwitchStatement: spy };
+                    return { SwitchStatement: spy };
+                }
             });
 
             linter.verify("switch(foo){ case 'a': var b = 'foo'; }", config);
@@ -682,15 +716,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "block");
-                    assert.strictEqual(scope.block.type, "BlockStatement");
-                });
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.block.type, "BlockStatement");
+                    });
 
-                return { BlockStatement: spy };
+                    return { BlockStatement: spy };
+                }
             });
 
             linter.verify("var x; {let y = 1}", config);
@@ -701,15 +737,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "block");
-                    assert.strictEqual(scope.block.type, "BlockStatement");
-                });
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.block.type, "BlockStatement");
+                    });
 
-                return { BlockStatement: spy };
+                    return { BlockStatement: spy };
+                }
             });
 
             linter.verify("if (true) { let x = 1 }", config);
@@ -720,15 +758,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                    assert.strictEqual(scope.block.type, "FunctionDeclaration");
-                });
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block.type, "FunctionDeclaration");
+                    });
 
-                return { FunctionDeclaration: spy };
+                    return { FunctionDeclaration: spy };
+                }
             });
 
             linter.verify("function foo() {}", config);
@@ -739,15 +779,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                    assert.strictEqual(scope.block.type, "FunctionExpression");
-                });
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block.type, "FunctionExpression");
+                    });
 
-                return { FunctionExpression: spy };
+                    return { FunctionExpression: spy };
+                }
             });
 
             linter.verify("(function foo() {})();", config);
@@ -758,15 +800,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "catch");
-                    assert.strictEqual(scope.block.type, "CatchClause");
-                });
+                        assert.strictEqual(scope.type, "catch");
+                        assert.strictEqual(scope.block.type, "CatchClause");
+                    });
 
-                return { CatchClause: spy };
+                    return { CatchClause: spy };
+                }
             });
 
             linter.verify("try {} catch (err) {}", config);
@@ -777,14 +821,16 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "module");
-                });
+                        assert.strictEqual(scope.type, "module");
+                    });
 
-                return { AssignmentExpression: spy };
+                    return { AssignmentExpression: spy };
+                }
             });
 
             linter.verify("var foo = {}; foo.bar = 1;", config);
@@ -795,14 +841,16 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, ecmaFeatures: { globalReturn: true } } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(scope.type, "function");
-                });
+                        assert.strictEqual(scope.type, "function");
+                    });
 
-                return { AssignmentExpression: spy };
+                    return { AssignmentExpression: spy };
+                }
             });
 
             linter.verify("var foo = {}; foo.bar = 1;", config);
@@ -815,17 +863,19 @@ describe("Linter", () => {
             const code = "var a = 1, b = 2;";
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    assert.isTrue(context.markVariableAsUsed("a"));
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        assert.isTrue(context.markVariableAsUsed("a"));
 
-                    const scope = context.getScope();
+                        const scope = context.getScope();
 
-                    assert.isTrue(getVariable(scope, "a").eslintUsed);
-                    assert.notOk(getVariable(scope, "b").eslintUsed);
-                });
+                        assert.isTrue(getVariable(scope, "a").eslintUsed);
+                        assert.notOk(getVariable(scope, "b").eslintUsed);
+                    });
 
-                return { "Program:exit": spy };
+                    return { "Program:exit": spy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" } });
@@ -835,17 +885,19 @@ describe("Linter", () => {
             const code = "function abc(a, b) { return 1; }";
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    assert.isTrue(context.markVariableAsUsed("a"));
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        assert.isTrue(context.markVariableAsUsed("a"));
 
-                    const scope = context.getScope();
+                        const scope = context.getScope();
 
-                    assert.isTrue(getVariable(scope, "a").eslintUsed);
-                    assert.notOk(getVariable(scope, "b").eslintUsed);
-                });
+                        assert.isTrue(getVariable(scope, "a").eslintUsed);
+                        assert.notOk(getVariable(scope, "b").eslintUsed);
+                    });
 
-                return { ReturnStatement: spy };
+                    return { ReturnStatement: spy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" } });
@@ -855,18 +907,20 @@ describe("Linter", () => {
             const code = "var a, b; function abc() { return 1; }";
             let returnSpy, exitSpy;
 
-            linter.defineRule("checker", context => {
-                returnSpy = sinon.spy(() => {
-                    assert.isTrue(context.markVariableAsUsed("a"));
-                });
-                exitSpy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    returnSpy = sinon.spy(() => {
+                        assert.isTrue(context.markVariableAsUsed("a"));
+                    });
+                    exitSpy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.isTrue(getVariable(scope, "a").eslintUsed);
-                    assert.notOk(getVariable(scope, "b").eslintUsed);
-                });
+                        assert.isTrue(getVariable(scope, "a").eslintUsed);
+                        assert.notOk(getVariable(scope, "b").eslintUsed);
+                    });
 
-                return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+                    return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" } });
@@ -878,18 +932,20 @@ describe("Linter", () => {
             const code = "var a = 1, b = 2;";
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const globalScope = context.getScope(),
-                        childScope = globalScope.childScopes[0];
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const globalScope = context.getScope(),
+                            childScope = globalScope.childScopes[0];
 
-                    assert.isTrue(context.markVariableAsUsed("a"));
+                        assert.isTrue(context.markVariableAsUsed("a"));
 
-                    assert.isTrue(getVariable(childScope, "a").eslintUsed);
-                    assert.isUndefined(getVariable(childScope, "b").eslintUsed);
-                });
+                        assert.isTrue(getVariable(childScope, "a").eslintUsed);
+                        assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+                    });
 
-                return { "Program:exit": spy };
+                    return { "Program:exit": spy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" }, env: { node: true } });
@@ -900,18 +956,20 @@ describe("Linter", () => {
             const code = "var a = 1, b = 2;";
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const globalScope = context.getScope(),
-                        childScope = globalScope.childScopes[0];
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const globalScope = context.getScope(),
+                            childScope = globalScope.childScopes[0];
 
-                    assert.isTrue(context.markVariableAsUsed("a"));
+                        assert.isTrue(context.markVariableAsUsed("a"));
 
-                    assert.isTrue(getVariable(childScope, "a").eslintUsed);
-                    assert.isUndefined(getVariable(childScope, "b").eslintUsed);
-                });
+                        assert.isTrue(getVariable(childScope, "a").eslintUsed);
+                        assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+                    });
 
-                return { "Program:exit": spy };
+                    return { "Program:exit": spy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }, filename, true);
@@ -922,12 +980,14 @@ describe("Linter", () => {
             const code = "var a = 1, b = 2;";
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    assert.isFalse(context.markVariableAsUsed("c"));
-                });
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        assert.isFalse(context.markVariableAsUsed("c"));
+                    });
 
-                return { "Program:exit": spy };
+                    return { "Program:exit": spy };
+                }
             });
 
             linter.verify(code, { rules: { checker: "error" } });
@@ -948,13 +1008,15 @@ describe("Linter", () => {
                 spyIdentifier = sinon.spy(),
                 spyBinaryExpression = sinon.spy();
 
-            linter.defineRule("checker", () => ({
-                Literal: spyLiteral,
-                VariableDeclarator: spyVariableDeclarator,
-                VariableDeclaration: spyVariableDeclaration,
-                Identifier: spyIdentifier,
-                BinaryExpression: spyBinaryExpression
-            }));
+            linter.defineRule("checker", {
+                create: () => ({
+                    Literal: spyLiteral,
+                    VariableDeclarator: spyVariableDeclarator,
+                    VariableDeclaration: spyVariableDeclaration,
+                    Identifier: spyIdentifier,
+                    BinaryExpression: spyBinaryExpression
+                })
+            });
 
             const messages = linter.verify(code, config, filename, true);
             const suppressedMessages = linter.getSuppressedMessages();
@@ -969,11 +1031,13 @@ describe("Linter", () => {
         });
 
         it("should throw an error if a rule reports a problem without a message", () => {
-            linter.defineRule("invalid-report", context => ({
-                Program(node) {
-                    context.report({ node });
-                }
-            }));
+            linter.defineRule("invalid-report", {
+                create: context => ({
+                    Program(node) {
+                        context.report({ node });
+                    }
+                })
+            });
 
             assert.throws(
                 () => linter.verify("foo", { rules: { "invalid-report": "error" } }),
@@ -987,11 +1051,13 @@ describe("Linter", () => {
         const code = "test-rule";
 
         it("should pass settings to all rules", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    context.report(node, context.settings.info);
-                }
-            }));
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        context.report(node, context.settings.info);
+                    }
+                })
+            });
 
             const config = { rules: {}, settings: { info: "Hello" } };
 
@@ -1006,13 +1072,15 @@ describe("Linter", () => {
         });
 
         it("should not have any settings if they were not passed in", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    if (Object.getOwnPropertyNames(context.settings).length !== 0) {
-                        context.report(node, "Settings should be empty");
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        if (Object.getOwnPropertyNames(context.settings).length !== 0) {
+                            context.report(node, "Settings should be empty");
+                        }
                     }
-                }
-            }));
+                })
+            });
 
             const config = { rules: {} };
 
@@ -1037,9 +1105,11 @@ describe("Linter", () => {
                 }
             };
 
-            linter.defineRule("test-rule", sinon.mock().withArgs(
-                sinon.match({ parserOptions })
-            ).returns({}));
+            linter.defineRule("test-rule", {
+                create: sinon.mock().withArgs(
+                    sinon.match({ parserOptions })
+                ).returns({})
+            });
 
             const config = { rules: { "test-rule": 2 }, parserOptions };
 
@@ -1050,9 +1120,11 @@ describe("Linter", () => {
 
             const parserOptions = {};
 
-            linter.defineRule("test-rule", sinon.mock().withArgs(
-                sinon.match({ parserOptions })
-            ).returns({}));
+            linter.defineRule("test-rule", {
+                create: sinon.mock().withArgs(
+                    sinon.match({ parserOptions })
+                ).returns({})
+            });
 
             const config = { rules: { "test-rule": 2 } };
 
@@ -1097,9 +1169,11 @@ describe("Linter", () => {
             const alternateParser = "esprima";
 
             linter.defineParser("esprima", esprima);
-            linter.defineRule("test-rule", sinon.mock().withArgs(
-                sinon.match({ parserPath: alternateParser })
-            ).returns({}));
+            linter.defineRule("test-rule", {
+                create: sinon.mock().withArgs(
+                    sinon.match({ parserPath: alternateParser })
+                ).returns({})
+            });
 
             const config = { rules: { "test-rule": 2 }, parser: alternateParser };
 
@@ -1119,14 +1193,16 @@ describe("Linter", () => {
 
         it("should expose parser services when using parseForESLint() and services are specified", () => {
             linter.defineParser("enhanced-parser", testParsers.enhancedParser);
-            linter.defineRule("test-service-rule", context => ({
-                Literal(node) {
-                    context.report({
-                        node,
-                        message: context.parserServices.test.getMessage()
-                    });
-                }
-            }));
+            linter.defineRule("test-service-rule", {
+                create: context => ({
+                    Literal(node) {
+                        context.report({
+                            node,
+                            message: context.parserServices.test.getMessage()
+                        });
+                    }
+                })
+            });
 
             const config = { rules: { "test-service-rule": 2 }, parser: "enhanced-parser" };
             const messages = linter.verify("0", config, filename);
@@ -1139,14 +1215,16 @@ describe("Linter", () => {
 
         it("should use the same parserServices if source code object is reused", () => {
             linter.defineParser("enhanced-parser", testParsers.enhancedParser);
-            linter.defineRule("test-service-rule", context => ({
-                Literal(node) {
-                    context.report({
-                        node,
-                        message: context.parserServices.test.getMessage()
-                    });
-                }
-            }));
+            linter.defineRule("test-service-rule", {
+                create: context => ({
+                    Literal(node) {
+                        context.report({
+                            node,
+                            message: context.parserServices.test.getMessage()
+                        });
+                    }
+                })
+            });
 
             const config = { rules: { "test-service-rule": 2 }, parser: "enhanced-parser" };
             const messages = linter.verify("0", config, filename);
@@ -1165,9 +1243,11 @@ describe("Linter", () => {
         });
 
         it("should pass parser as parserPath to all rules when default parser is used", () => {
-            linter.defineRule("test-rule", sinon.mock().withArgs(
-                sinon.match({ parserPath: "espree" })
-            ).returns({}));
+            linter.defineRule("test-rule", {
+                create: sinon.mock().withArgs(
+                    sinon.match({ parserPath: "espree" })
+                ).returns({})
+            });
 
             const config = { rules: { "test-rule": 2 } };
 
@@ -1277,38 +1357,40 @@ describe("Linter", () => {
             `;
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
-                    const a = getVariable(scope, "a"),
-                        b = getVariable(scope, "b"),
-                        c = getVariable(scope, "c"),
-                        d = getVariable(scope, "d"),
-                        e = getVariable(scope, "e"),
-                        f = getVariable(scope, "f"),
-                        mathGlobal = getVariable(scope, "Math"),
-                        arrayGlobal = getVariable(scope, "Array"),
-                        configGlobal = getVariable(scope, "ConfigGlobal");
-
-                    assert.strictEqual(a.name, "a");
-                    assert.strictEqual(a.writeable, false);
-                    assert.strictEqual(b.name, "b");
-                    assert.strictEqual(b.writeable, true);
-                    assert.strictEqual(c.name, "c");
-                    assert.strictEqual(c.writeable, false);
-                    assert.strictEqual(d.name, "d");
-                    assert.strictEqual(d.writeable, false);
-                    assert.strictEqual(e.name, "e");
-                    assert.strictEqual(e.writeable, true);
-                    assert.strictEqual(f.name, "f");
-                    assert.strictEqual(f.writeable, true);
-                    assert.strictEqual(mathGlobal, null);
-                    assert.strictEqual(arrayGlobal, null);
-                    assert.strictEqual(configGlobal.name, "ConfigGlobal");
-                    assert.strictEqual(configGlobal.writeable, false);
-                });
-
-                return { Program: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
+                        const a = getVariable(scope, "a"),
+                            b = getVariable(scope, "b"),
+                            c = getVariable(scope, "c"),
+                            d = getVariable(scope, "d"),
+                            e = getVariable(scope, "e"),
+                            f = getVariable(scope, "f"),
+                            mathGlobal = getVariable(scope, "Math"),
+                            arrayGlobal = getVariable(scope, "Array"),
+                            configGlobal = getVariable(scope, "ConfigGlobal");
+
+                        assert.strictEqual(a.name, "a");
+                        assert.strictEqual(a.writeable, false);
+                        assert.strictEqual(b.name, "b");
+                        assert.strictEqual(b.writeable, true);
+                        assert.strictEqual(c.name, "c");
+                        assert.strictEqual(c.writeable, false);
+                        assert.strictEqual(d.name, "d");
+                        assert.strictEqual(d.writeable, false);
+                        assert.strictEqual(e.name, "e");
+                        assert.strictEqual(e.writeable, true);
+                        assert.strictEqual(f.name, "f");
+                        assert.strictEqual(f.writeable, true);
+                        assert.strictEqual(mathGlobal, null);
+                        assert.strictEqual(arrayGlobal, null);
+                        assert.strictEqual(configGlobal.name, "ConfigGlobal");
+                        assert.strictEqual(configGlobal.writeable, false);
+                    });
+
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1323,22 +1405,24 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        a = getVariable(scope, "a"),
-                        b = getVariable(scope, "b"),
-                        c = getVariable(scope, "c");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            a = getVariable(scope, "a"),
+                            b = getVariable(scope, "b"),
+                            c = getVariable(scope, "c");
 
-                    assert.strictEqual(a.name, "a");
-                    assert.strictEqual(a.writeable, false);
-                    assert.strictEqual(b.name, "b");
-                    assert.strictEqual(b.writeable, true);
-                    assert.strictEqual(c.name, "c");
-                    assert.strictEqual(c.writeable, false);
-                });
+                        assert.strictEqual(a.name, "a");
+                        assert.strictEqual(a.writeable, false);
+                        assert.strictEqual(b.name, "b");
+                        assert.strictEqual(b.writeable, true);
+                        assert.strictEqual(c.name, "c");
+                        assert.strictEqual(c.writeable, false);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1362,17 +1446,19 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        exports = getVariable(scope, "exports"),
-                        window = getVariable(scope, "window");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            exports = getVariable(scope, "exports"),
+                            window = getVariable(scope, "window");
 
-                    assert.strictEqual(exports.writeable, true);
-                    assert.strictEqual(window.writeable, false);
-                });
+                        assert.strictEqual(exports.writeable, true);
+                        assert.strictEqual(window.writeable, false);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1387,17 +1473,19 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        exports = getVariable(scope, "exports"),
-                        window = getVariable(scope, "window");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            exports = getVariable(scope, "exports"),
+                            window = getVariable(scope, "window");
 
-                    assert.strictEqual(exports.writeable, true);
-                    assert.strictEqual(window, null);
-                });
+                        assert.strictEqual(exports.writeable, true);
+                        assert.strictEqual(window, null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1419,15 +1507,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        horse = getVariable(scope, "horse");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            horse = getVariable(scope, "horse");
 
-                    assert.strictEqual(horse.eslintUsed, true);
-                });
+                        assert.strictEqual(horse.eslintUsed, true);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1439,15 +1529,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        horse = getVariable(scope, "horse");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            horse = getVariable(scope, "horse");
 
-                    assert.strictEqual(horse, null);
-                });
+                        assert.strictEqual(horse, null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1459,15 +1551,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        horse = getVariable(scope, "horse");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            horse = getVariable(scope, "horse");
 
-                    assert.strictEqual(horse.eslintUsed, true);
-                });
+                        assert.strictEqual(horse.eslintUsed, true);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1479,15 +1573,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        horse = getVariable(scope, "horse");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            horse = getVariable(scope, "horse");
 
-                    assert.strictEqual(horse, null); // there is no global scope at all
-                });
+                        assert.strictEqual(horse, null); // there is no global scope at all
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1499,15 +1595,17 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, env: { node: true } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope(),
-                        horse = getVariable(scope, "horse");
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope(),
+                            horse = getVariable(scope, "horse");
 
-                    assert.strictEqual(horse, null); // there is no global scope at all
-                });
+                        assert.strictEqual(horse, null); // there is no global scope at all
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1522,14 +1620,16 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(getVariable(scope, "a"), null);
-                });
+                        assert.strictEqual(getVariable(scope, "a"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1544,17 +1644,19 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(getVariable(scope, "a"), null);
-                    assert.strictEqual(getVariable(scope, "b"), null);
-                    assert.strictEqual(getVariable(scope, "foo"), null);
-                    assert.strictEqual(getVariable(scope, "c"), null);
-                });
+                        assert.strictEqual(getVariable(scope, "a"), null);
+                        assert.strictEqual(getVariable(scope, "b"), null);
+                        assert.strictEqual(getVariable(scope, "foo"), null);
+                        assert.strictEqual(getVariable(scope, "c"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1569,16 +1671,18 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.notStrictEqual(getVariable(scope, "Object"), null);
-                    assert.notStrictEqual(getVariable(scope, "Array"), null);
-                    assert.notStrictEqual(getVariable(scope, "undefined"), null);
-                });
+                        assert.notStrictEqual(getVariable(scope, "Object"), null);
+                        assert.notStrictEqual(getVariable(scope, "Array"), null);
+                        assert.notStrictEqual(getVariable(scope, "undefined"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1589,16 +1693,18 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(getVariable(scope, "Promise"), null);
-                    assert.strictEqual(getVariable(scope, "Symbol"), null);
-                    assert.strictEqual(getVariable(scope, "WeakMap"), null);
-                });
+                        assert.strictEqual(getVariable(scope, "Promise"), null);
+                        assert.strictEqual(getVariable(scope, "Symbol"), null);
+                        assert.strictEqual(getVariable(scope, "WeakMap"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1609,16 +1715,18 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, env: { es6: true } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.notStrictEqual(getVariable(scope, "Promise"), null);
-                    assert.notStrictEqual(getVariable(scope, "Symbol"), null);
-                    assert.notStrictEqual(getVariable(scope, "WeakMap"), null);
-                });
+                        assert.notStrictEqual(getVariable(scope, "Promise"), null);
+                        assert.notStrictEqual(getVariable(scope, "Symbol"), null);
+                        assert.notStrictEqual(getVariable(scope, "WeakMap"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1629,16 +1737,18 @@ describe("Linter", () => {
             const config = { rules: { checker: "error" }, globals: { Promise: "off", Symbol: "off", WeakMap: "off" }, env: { es6: true } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    const scope = context.getScope();
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        const scope = context.getScope();
 
-                    assert.strictEqual(getVariable(scope, "Promise"), null);
-                    assert.strictEqual(getVariable(scope, "Symbol"), null);
-                    assert.strictEqual(getVariable(scope, "WeakMap"), null);
-                });
+                        assert.strictEqual(getVariable(scope, "Promise"), null);
+                        assert.strictEqual(getVariable(scope, "Symbol"), null);
+                        assert.strictEqual(getVariable(scope, "WeakMap"), null);
+                    });
 
-                return { Program: spy };
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -1650,11 +1760,13 @@ describe("Linter", () => {
         const code = "new-rule";
 
         it("can add a rule dynamically", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    context.report(node, "message");
-                }
-            }));
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        context.report(node, "message");
+                    }
+                })
+            });
 
             const config = { rules: {} };
 
@@ -1680,12 +1792,14 @@ describe("Linter", () => {
 
             code.forEach(item => {
                 config.rules[item] = 1;
-                newRules[item] = function(context) {
-                    return {
-                        Literal(node) {
-                            context.report(node, "message");
-                        }
-                    };
+                newRules[item] = {
+                    create(context) {
+                        return {
+                            Literal(node) {
+                                context.report(node, "message");
+                            }
+                        };
+                    }
                 };
             });
             linter.defineRules(newRules);
@@ -1709,11 +1823,13 @@ describe("Linter", () => {
         const code = "filename-rule";
 
         it("has access to the filename", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    context.report(node, context.getFilename());
-                }
-            }));
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        context.report(node, context.getFilename());
+                    }
+                })
+            });
 
             const config = { rules: {} };
 
@@ -1727,11 +1843,13 @@ describe("Linter", () => {
         });
 
         it("has access to the physicalFilename", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    context.report(node, context.getPhysicalFilename());
-                }
-            }));
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        context.report(node, context.getPhysicalFilename());
+                    }
+                })
+            });
 
             const config = { rules: {} };
 
@@ -1745,11 +1863,13 @@ describe("Linter", () => {
         });
 
         it("defaults filename to ''", () => {
-            linter.defineRule(code, context => ({
-                Literal(node) {
-                    context.report(node, context.getFilename());
-                }
-            }));
+            linter.defineRule(code, {
+                create: context => ({
+                    Literal(node) {
+                        context.report(node, context.getFilename());
+                    }
+                })
+            });
 
             const config = { rules: {} };
 
@@ -2011,13 +2131,17 @@ describe("Linter", () => {
     describe("when evaluating code with comments to disable and enable configurable rule as part of plugin", () => {
 
         beforeEach(() => {
-            linter.defineRule("test-plugin/test-rule", context => ({
-                Literal(node) {
-                    if (node.value === "trigger violation") {
-                        context.report(node, "Reporting violation.");
-                    }
+            linter.defineRule("test-plugin/test-rule", {
+                create(context) {
+                    return {
+                        Literal(node) {
+                            if (node.value === "trigger violation") {
+                                context.report(node, "Reporting violation.");
+                            }
+                        }
+                    };
                 }
-            }));
+            });
         });
 
         it("should not report a violation when inline comment enables plugin rule and there's no violation", () => {
@@ -2045,11 +2169,13 @@ describe("Linter", () => {
         it("should report a violation when the report is right before the comment", () => {
             const code = " /* eslint-disable */ ";
 
-            linter.defineRule("checker", context => ({
-                Program() {
-                    context.report({ loc: { line: 1, column: 0 }, message: "foo" });
-                }
-            }));
+            linter.defineRule("checker", {
+                create: context => ({
+                    Program() {
+                        context.report({ loc: { line: 1, column: 0 }, message: "foo" });
+                    }
+                })
+            });
             const problems = linter.verify(code, { rules: { checker: "error" } });
             const suppressedMessages = linter.getSuppressedMessages();
 
@@ -2061,11 +2187,13 @@ describe("Linter", () => {
         it("should not report a violation when the report is right at the start of the comment", () => {
             const code = " /* eslint-disable */ ";
 
-            linter.defineRule("checker", context => ({
-                Program() {
-                    context.report({ loc: { line: 1, column: 1 }, message: "foo" });
-                }
-            }));
+            linter.defineRule("checker", {
+                create: context => ({
+                    Program() {
+                        context.report({ loc: { line: 1, column: 1 }, message: "foo" });
+                    }
+                })
+            });
             const problems = linter.verify(code, { rules: { checker: "error" } });
             const suppressedMessages = linter.getSuppressedMessages();
 
@@ -3279,7 +3407,7 @@ var a = "test2";
                 return {};
             });
 
-            linter.defineRule("checker", spy);
+            linter.defineRule("checker", { create: spy });
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
@@ -3289,11 +3417,13 @@ var a = "test2";
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node), "'123';");
-                });
-                return { ExpressionStatement: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node), "'123';");
+                    });
+                    return { ExpressionStatement: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -3431,11 +3561,13 @@ var a = "test2";
 
     describe("when evaluating an empty string", () => {
         it("runs rules", () => {
-            linter.defineRule("no-programs", context => ({
-                Program(node) {
-                    context.report({ node, message: "No programs allowed." });
-                }
-            }));
+            linter.defineRule("no-programs", {
+                create: context => ({
+                    Program(node) {
+                        context.report({ node, message: "No programs allowed." });
+                    }
+                })
+            });
 
             assert.strictEqual(
                 linter.verify("", { rules: { "no-programs": "error" } }).length,
@@ -3638,8 +3770,8 @@ var a = "test2";
             let ok = false;
 
             linter.defineRules({
-                test(context) {
-                    return {
+                test: {
+                    create: context => ({
                         Program() {
                             const scope = context.getScope();
                             const sourceCode = context.getSourceCode();
@@ -3653,7 +3785,7 @@ var a = "test2";
 
                             ok = true;
                         }
-                    };
+                    })
                 }
             });
 
@@ -3810,11 +3942,13 @@ var a = "test2";
             const linterWithOption = new Linter({ cwd });
             let spy;
 
-            linterWithOption.defineRule("checker", context => {
-                spy = sinon.spy(() => {
-                    assert.strictEqual(context.getCwd(), cwd);
-                });
-                return { Program: spy };
+            linterWithOption.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(() => {
+                        assert.strictEqual(context.getCwd(), cwd);
+                    });
+                    return { Program: spy };
+                }
             });
 
             linterWithOption.verify(code, config);
@@ -3825,12 +3959,14 @@ var a = "test2";
             let spy;
             const linterWithOption = new Linter({ });
 
-            linterWithOption.defineRule("checker", context => {
+            linterWithOption.defineRule("checker", {
+                create(context) {
 
-                spy = sinon.spy(() => {
-                    assert.strictEqual(context.getCwd(), process.cwd());
-                });
-                return { Program: spy };
+                    spy = sinon.spy(() => {
+                        assert.strictEqual(context.getCwd(), process.cwd());
+                    });
+                    return { Program: spy };
+                }
             });
 
             linterWithOption.verify(code, config);
@@ -3840,12 +3976,14 @@ var a = "test2";
         it("should assign process.cwd() to it if the option is undefined", () => {
             let spy;
 
-            linter.defineRule("checker", context => {
+            linter.defineRule("checker", {
+                create(context) {
 
-                spy = sinon.spy(() => {
-                    assert.strictEqual(context.getCwd(), process.cwd());
-                });
-                return { Program: spy };
+                    spy = sinon.spy(() => {
+                        assert.strictEqual(context.getCwd(), process.cwd());
+                    });
+                    return { Program: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -4640,11 +4778,13 @@ var a = "test2";
             const config = { rules: { checker: "error" } };
             let spy;
 
-            linter.defineRule("checker", context => {
-                spy = sinon.spy(node => {
-                    assert.strictEqual(context.getSource(node), "'123';");
-                });
-                return { ExpressionStatement: spy };
+            linter.defineRule("checker", {
+                create(context) {
+                    spy = sinon.spy(node => {
+                        assert.strictEqual(context.getSource(node), "'123';");
+                    });
+                    return { ExpressionStatement: spy };
+                }
             });
 
             linter.verify(code, config);
@@ -4660,7 +4800,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", filenameChecker);
+                linter.defineRule("checker", { create: filenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } }, { filename: "foo.js" });
                 assert(filenameChecker.calledOnce);
             });
@@ -4671,7 +4811,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", filenameChecker);
+                linter.defineRule("checker", { create: filenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } }, "bar.js");
                 assert(filenameChecker.calledOnce);
             });
@@ -4682,7 +4822,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", filenameChecker);
+                linter.defineRule("checker", { create: filenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } }, {});
                 assert(filenameChecker.calledOnce);
             });
@@ -4693,7 +4833,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", filenameChecker);
+                linter.defineRule("checker", { create: filenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } });
                 assert(filenameChecker.calledOnce);
             });
@@ -4706,7 +4846,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", physicalFilenameChecker);
+                linter.defineRule("checker", { create: physicalFilenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } }, { filename: "foo.js" });
                 assert(physicalFilenameChecker.calledOnce);
             });
@@ -4717,7 +4857,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", physicalFilenameChecker);
+                linter.defineRule("checker", { create: physicalFilenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } }, {});
                 assert(physicalFilenameChecker.calledOnce);
             });
@@ -4728,7 +4868,7 @@ var a = "test2";
                     return {};
                 });
 
-                linter.defineRule("checker", physicalFilenameChecker);
+                linter.defineRule("checker", { create: physicalFilenameChecker });
                 linter.verify("foo;", { rules: { checker: "error" } });
                 assert(physicalFilenameChecker.calledOnce);
             });
@@ -4777,11 +4917,13 @@ var a = "test2";
                 let ecmaVersion = null;
                 const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
 
-                linter.defineRule("ecma-version", context => ({
-                    Program() {
-                        ecmaVersion = context.parserOptions.ecmaVersion;
-                    }
-                }));
+                linter.defineRule("ecma-version", {
+                    create: context => ({
+                        Program() {
+                            ecmaVersion = context.parserOptions.ecmaVersion;
+                        }
+                    })
+                });
                 linter.verify("", config);
                 assert.strictEqual(ecmaVersion, espree.latestEcmaVersion, "ecmaVersion should be 13");
             });
@@ -4791,11 +4933,13 @@ var a = "test2";
                 const config = { rules: { "ecma-version": 2 }, parser: "custom-parser", parserOptions: { ecmaVersion: "latest" } };
 
                 linter.defineParser("custom-parser", testParsers.enhancedParser);
-                linter.defineRule("ecma-version", context => ({
-                    Program() {
-                        ecmaVersion = context.parserOptions.ecmaVersion;
-                    }
-                }));
+                linter.defineRule("ecma-version", {
+                    create: context => ({
+                        Program() {
+                            ecmaVersion = context.parserOptions.ecmaVersion;
+                        }
+                    })
+                });
                 linter.verify("", config);
                 assert.strictEqual(ecmaVersion, "latest", "ecmaVersion should be latest");
             });
@@ -4804,11 +4948,13 @@ var a = "test2";
                 let ecmaVersion = null;
                 const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
 
-                linter.defineRule("ecma-version", context => ({
-                    Program() {
-                        ecmaVersion = context.languageOptions.ecmaVersion;
-                    }
-                }));
+                linter.defineRule("ecma-version", {
+                    create: context => ({
+                        Program() {
+                            ecmaVersion = context.languageOptions.ecmaVersion;
+                        }
+                    })
+                });
                 linter.verify("", config);
                 assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
             });
@@ -4818,11 +4964,13 @@ var a = "test2";
                 const config = { rules: { "ecma-version": 2 }, parser: "custom-parser", parserOptions: { ecmaVersion: "next" } };
 
                 linter.defineParser("custom-parser", testParsers.stubParser);
-                linter.defineRule("ecma-version", context => ({
-                    Program() {
-                        ecmaVersion = context.languageOptions.ecmaVersion;
-                    }
-                }));
+                linter.defineRule("ecma-version", {
+                    create: context => ({
+                        Program() {
+                            ecmaVersion = context.languageOptions.ecmaVersion;
+                        }
+                    })
+                });
                 linter.verify("", config);
                 assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
             });
@@ -4832,11 +4980,13 @@ var a = "test2";
                 const config = { rules: { "ecma-version": 2 }, parser: "custom-parser" };
 
                 linter.defineParser("custom-parser", testParsers.enhancedParser);
-                linter.defineRule("ecma-version", context => ({
-                    Program() {
-                        ecmaVersion = context.languageOptions.ecmaVersion;
-                    }
-                }));
+                linter.defineRule("ecma-version", {
+                    create: context => ({
+                        Program() {
+                            ecmaVersion = context.languageOptions.ecmaVersion;
+                        }
+                    })
+                });
                 linter.verify("", config);
                 assert.strictEqual(ecmaVersion, 5, "ecmaVersion should be 5");
             });
@@ -4844,11 +4994,13 @@ var a = "test2";
             it("should pass normalized ecmaVersion to eslint-scope", () => {
                 let blockScope = null;
 
-                linter.defineRule("block-scope", context => ({
-                    BlockStatement() {
-                        blockScope = context.getScope();
-                    }
-                }));
+                linter.defineRule("block-scope", {
+                    create: context => ({
+                        BlockStatement() {
+                            blockScope = context.getScope();
+                        }
+                    })
+                });
                 linter.defineParser("custom-parser", {
                     parse: (...args) => espree.parse(...args)
                 });
@@ -5247,8 +5399,8 @@ var a = "test2";
             let ok = false;
 
             linter.defineRules({
-                test(context) {
-                    return {
+                test: {
+                    create: context => ({
                         Program() {
                             const scope = context.getScope();
                             const sourceCode = context.getSourceCode();
@@ -5273,7 +5425,7 @@ var a = "test2";
 
                             ok = true;
                         }
-                    };
+                    })
                 }
             });
 
@@ -5321,16 +5473,20 @@ var a = "test2";
             let ast1 = null,
                 ast2 = null;
 
-            linter.defineRule("save-ast1", () => ({
-                Program(node) {
-                    ast1 = node;
-                }
-            }));
-            linter.defineRule("save-ast2", () => ({
-                Program(node) {
-                    ast2 = node;
-                }
-            }));
+            linter.defineRule("save-ast1", {
+                create: () => ({
+                    Program(node) {
+                        ast1 = node;
+                    }
+                })
+            });
+            linter.defineRule("save-ast2", {
+                create: () => ({
+                    Program(node) {
+                        ast2 = node;
+                    }
+                })
+            });
 
             linter.verify("function render() { return 
{hello}
}", { parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } }, rules: { "save-ast1": 2 } }); linter.verify(linter.getSourceCode(), { parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } }, rules: { "save-ast2": 2 } }); @@ -5365,7 +5521,7 @@ var a = "test2"; return {}; }); - linter.defineRule("foo-bar-baz", spy); + linter.defineRule("foo-bar-baz", { create: spy }); linter.verify("x", { rules: { "foo-bar-baz": "error" } }); assert(spy.calledOnce); }); @@ -5827,12 +5983,14 @@ var a = "test2"; function getScope(code, astSelector, ecmaVersion = 5) { let node, scope; - linter.defineRule("get-scope", context => ({ - [astSelector](node0) { - node = node0; - scope = context.getScope(); - } - })); + linter.defineRule("get-scope", { + create: context => ({ + [astSelector](node0) { + node = node0; + scope = context.getScope(); + } + }) + }); linter.verify( code, { @@ -6084,13 +6242,13 @@ var a = "test2"; let ok = false; linter.defineRules({ - test(context) { - return { + test: { + create: context => ({ Program() { scope = context.getScope(); ok = true; } - }; + }) } }); linter.verify(code, { rules: { test: 2 }, globals: { e: true, f: false } }); @@ -6177,78 +6335,80 @@ var a = "test2"; */ function verify(code, type, expectedNamesList) { linter.defineRules({ - test(context) { + test: { + create(context) { - /** - * Assert `context.getDeclaredVariables(node)` is empty. - * @param {ASTNode} node A node to check. - * @returns {void} - */ - function checkEmpty(node) { - assert.strictEqual(0, context.getDeclaredVariables(node).length); - } - const rule = { - Program: checkEmpty, - EmptyStatement: checkEmpty, - BlockStatement: checkEmpty, - ExpressionStatement: checkEmpty, - LabeledStatement: checkEmpty, - BreakStatement: checkEmpty, - ContinueStatement: checkEmpty, - WithStatement: checkEmpty, - SwitchStatement: checkEmpty, - ReturnStatement: checkEmpty, - ThrowStatement: checkEmpty, - TryStatement: checkEmpty, - WhileStatement: checkEmpty, - DoWhileStatement: checkEmpty, - ForStatement: checkEmpty, - ForInStatement: checkEmpty, - DebuggerStatement: checkEmpty, - ThisExpression: checkEmpty, - ArrayExpression: checkEmpty, - ObjectExpression: checkEmpty, - Property: checkEmpty, - SequenceExpression: checkEmpty, - UnaryExpression: checkEmpty, - BinaryExpression: checkEmpty, - AssignmentExpression: checkEmpty, - UpdateExpression: checkEmpty, - LogicalExpression: checkEmpty, - ConditionalExpression: checkEmpty, - CallExpression: checkEmpty, - NewExpression: checkEmpty, - MemberExpression: checkEmpty, - SwitchCase: checkEmpty, - Identifier: checkEmpty, - Literal: checkEmpty, - ForOfStatement: checkEmpty, - ArrowFunctionExpression: checkEmpty, - YieldExpression: checkEmpty, - TemplateLiteral: checkEmpty, - TaggedTemplateExpression: checkEmpty, - TemplateElement: checkEmpty, - ObjectPattern: checkEmpty, - ArrayPattern: checkEmpty, - RestElement: checkEmpty, - AssignmentPattern: checkEmpty, - ClassBody: checkEmpty, - MethodDefinition: checkEmpty, - MetaProperty: checkEmpty - }; + /** + * Assert `context.getDeclaredVariables(node)` is empty. + * @param {ASTNode} node A node to check. + * @returns {void} + */ + function checkEmpty(node) { + assert.strictEqual(0, context.getDeclaredVariables(node).length); + } + const rule = { + Program: checkEmpty, + EmptyStatement: checkEmpty, + BlockStatement: checkEmpty, + ExpressionStatement: checkEmpty, + LabeledStatement: checkEmpty, + BreakStatement: checkEmpty, + ContinueStatement: checkEmpty, + WithStatement: checkEmpty, + SwitchStatement: checkEmpty, + ReturnStatement: checkEmpty, + ThrowStatement: checkEmpty, + TryStatement: checkEmpty, + WhileStatement: checkEmpty, + DoWhileStatement: checkEmpty, + ForStatement: checkEmpty, + ForInStatement: checkEmpty, + DebuggerStatement: checkEmpty, + ThisExpression: checkEmpty, + ArrayExpression: checkEmpty, + ObjectExpression: checkEmpty, + Property: checkEmpty, + SequenceExpression: checkEmpty, + UnaryExpression: checkEmpty, + BinaryExpression: checkEmpty, + AssignmentExpression: checkEmpty, + UpdateExpression: checkEmpty, + LogicalExpression: checkEmpty, + ConditionalExpression: checkEmpty, + CallExpression: checkEmpty, + NewExpression: checkEmpty, + MemberExpression: checkEmpty, + SwitchCase: checkEmpty, + Identifier: checkEmpty, + Literal: checkEmpty, + ForOfStatement: checkEmpty, + ArrowFunctionExpression: checkEmpty, + YieldExpression: checkEmpty, + TemplateLiteral: checkEmpty, + TaggedTemplateExpression: checkEmpty, + TemplateElement: checkEmpty, + ObjectPattern: checkEmpty, + ArrayPattern: checkEmpty, + RestElement: checkEmpty, + AssignmentPattern: checkEmpty, + ClassBody: checkEmpty, + MethodDefinition: checkEmpty, + MetaProperty: checkEmpty + }; - rule[type] = function(node) { - const expectedNames = expectedNamesList.shift(); - const variables = context.getDeclaredVariables(node); + rule[type] = function(node) { + const expectedNames = expectedNamesList.shift(); + const variables = context.getDeclaredVariables(node); - assert(Array.isArray(expectedNames)); - assert(Array.isArray(variables)); - assert.strictEqual(expectedNames.length, variables.length); - for (let i = variables.length - 1; i >= 0; i--) { - assert.strictEqual(expectedNames[i], variables[i].name); - } - }; - return rule; + assert(Array.isArray(expectedNames)); + assert(Array.isArray(variables)); + assert.strictEqual(expectedNames.length, variables.length); + for (let i = variables.length - 1; i >= 0; i--) { + assert.strictEqual(expectedNames[i], variables[i].name); + } + }; + return rule; + } } }); linter.verify(code, { @@ -6548,7 +6708,9 @@ var a = "test2"; }); it("loading rule in one doesn't change the other", () => { - linter1.defineRule("mock-rule", () => ({})); + linter1.defineRule("mock-rule", { + create: () => ({}) + }); assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present"); assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present"); @@ -6565,13 +6727,15 @@ var a = "test2"; receivedPhysicalFilenames = []; // A rule that always reports the AST with a message equal to the source text - linter.defineRule("report-original-text", context => ({ - Program(ast) { - receivedFilenames.push(context.getFilename()); - receivedPhysicalFilenames.push(context.getPhysicalFilename()); - context.report({ node: ast, message: context.getSourceCode().text }); - } - })); + linter.defineRule("report-original-text", { + create: context => ({ + Program(ast) { + receivedFilenames.push(context.getFilename()); + receivedPhysicalFilenames.push(context.getPhysicalFilename()); + context.report({ node: ast, message: context.getSourceCode().text }); + } + }) + }); }); describe("preprocessors", () => { @@ -6907,11 +7071,13 @@ var a = "test2"; }); it("should throw an error if fix is passed from a legacy-format rule", () => { - linter.defineRule("test-rule", context => ({ - Program(node) { - context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" })); - } - })); + linter.defineRule("test-rule", { + create: context => ({ + Program(node) { + context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" })); + } + }) + }); assert.throws(() => { linter.verify("0", { rules: { "test-rule": "error" } }); @@ -7000,7 +7166,9 @@ var a = "test2"; * This test focuses on the instance of https://github.com/eslint/eslint/blob/v2.0.0-alpha-2/conf/environments.js#L26-L28 * This `verify()` takes the instance and runs https://github.com/eslint/eslint/blob/v2.0.0-alpha-2/lib/eslint.js#L416 */ - linter.defineRule("test", () => ({})); + linter.defineRule("test", { + create: () => ({}) + }); linter.verify("var a = 0;", { env: { node: true }, parserOptions: { ecmaVersion: 6, sourceType: "module" }, @@ -7010,13 +7178,15 @@ var a = "test2"; // This `verify()` takes the instance and tests that the instance was not modified. let ok = false; - linter.defineRule("test", context => { - assert( - context.parserOptions.ecmaFeatures.globalReturn, - "`ecmaFeatures.globalReturn` of the node environment should not be modified." - ); - ok = true; - return {}; + linter.defineRule("test", { + create(context) { + assert( + context.parserOptions.ecmaFeatures.globalReturn, + "`ecmaFeatures.globalReturn` of the node environment should not be modified." + ); + ok = true; + return {}; + } }); linter.verify("var a = 0;", { env: { node: true }, @@ -7029,13 +7199,17 @@ var a = "test2"; it("should throw when rule's create() function does not return an object", () => { const config = { rules: { checker: "error" } }; - linter.defineRule("checker", () => null); // returns null + linter.defineRule("checker", { + create: () => null + }); // returns null assert.throws(() => { linter.verify("abc", config, filename); }, "The create() function for rule 'checker' did not return an object."); - linter.defineRule("checker", () => {}); // returns undefined + linter.defineRule("checker", { + create() {} + }); // returns undefined assert.throws(() => { linter.verify("abc", config, filename); @@ -7111,11 +7285,13 @@ var a = "test2"; const nodes = []; - linter.defineRule("collect-node-types", () => ({ - "*"(node) { - nodes.push(node.type); - } - })); + linter.defineRule("collect-node-types", { + create: () => ({ + "*"(node) { + nodes.push(node.type); + } + }) + }); linter.defineParser("non-js-parser", testParsers.nonJSParser); @@ -7166,21 +7342,27 @@ var a = "test2"; beforeEach(() => { types = []; firstChildNodes = []; - linter.defineRule("collect-node-types", () => ({ - "*"(node) { - types.push(node.type); - } - })); - linter.defineRule("save-scope-manager", context => { - scopeManager = context.getSourceCode().scopeManager; - - return {}; + linter.defineRule("collect-node-types", { + create: () => ({ + "*"(node) { + types.push(node.type); + } + }) }); - linter.defineRule("esquery-option", () => ({ - ":first-child"(node) { - firstChildNodes.push(node); + linter.defineRule("save-scope-manager", { + create(context) { + scopeManager = context.getSourceCode().scopeManager; + + return {}; } - })); + }); + linter.defineRule("esquery-option", { + create: () => ({ + ":first-child"(node) { + firstChildNodes.push(node); + } + }) + }); linter.defineParser("enhanced-parser2", testParsers.enhancedParser2); linter.verify("@foo class A {}", { parser: "enhanced-parser2", @@ -7210,12 +7392,14 @@ var a = "test2"; it("should use the same visitorKeys if the source code object is reused", () => { const types2 = []; - - linter.defineRule("collect-node-types", () => ({ - "*"(node) { - types2.push(node.type); - } - })); + + linter.defineRule("collect-node-types", { + create: () => ({ + "*"(node) { + types2.push(node.type); + } + }) + }); linter.verify(sourceCode, { rules: { "collect-node-types": "error" @@ -7242,11 +7426,13 @@ var a = "test2"; beforeEach(() => { linter.defineParser("enhanced-parser3", testParsers.enhancedParser3); - linter.defineRule("save-scope1", context => ({ - Program() { - scope = context.getScope(); - } - })); + linter.defineRule("save-scope1", { + create: context => ({ + Program() { + scope = context.getScope(); + } + }) + }); linter.verify("@foo class A {}", { parser: "enhanced-parser3", rules: { "save-scope1": 2 } }); sourceCode = linter.getSourceCode(); @@ -7263,11 +7449,13 @@ var a = "test2"; it("should use the same scope if the source code object is reused", () => { let scope2 = null; - linter.defineRule("save-scope2", context => ({ - Program() { - scope2 = context.getScope(); - } - })); + linter.defineRule("save-scope2", { + create: context => ({ + Program() { + scope2 = context.getScope(); + } + }) + }); linter.verify(sourceCode, { rules: { "save-scope2": 2 } }, "test.js"); assert(scope2 !== null); @@ -7410,12 +7598,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.ecmaVersion, 2015); } - }; + }) } } } @@ -7434,12 +7622,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009); } - }; + }) } } } @@ -7455,12 +7643,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.ecmaVersion, 5); } - }; + }) } } } @@ -7479,12 +7667,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009); } - }; + }) } } } @@ -7508,12 +7696,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.sourceType, "module"); } - }; + }) } } } @@ -7529,12 +7717,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker(context) { - return { + checker: { + create: context => ({ Program() { assert.strictEqual(context.languageOptions.sourceType, "commonjs"); } - }; + }) } } } @@ -7695,9 +7883,11 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "test-rule": sinon.mock().withArgs( - sinon.match({ languageOptions: { parser: esprima } }) - ).returns({}) + "test-rule": { + create: sinon.mock().withArgs( + sinon.match({ languageOptions: { parser: esprima } }) + ).returns({}) + } } } }, @@ -7742,14 +7932,16 @@ describe("Linter with FlatConfigArray", () => { "enhanced-parser": testParsers.enhancedParser }, rules: { - "test-service-rule": context => ({ - Literal(node) { - context.report({ - node, - message: context.parserServices.test.getMessage() - }); - } - }) + "test-service-rule": { + create: context => ({ + Literal(node) { + context.report({ + node, + message: context.parserServices.test.getMessage() + }); + } + }) + } } } }, @@ -7779,14 +7971,16 @@ describe("Linter with FlatConfigArray", () => { "enhanced-parser": testParsers.enhancedParser }, rules: { - "test-service-rule": context => ({ - Literal(node) { - context.report({ - node, - message: context.parserServices.test.getMessage() - }); - } - }) + "test-service-rule": { + create: context => ({ + Literal(node) { + context.report({ + node, + message: context.parserServices.test.getMessage() + }); + } + }) + } } } }, @@ -7829,7 +8023,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "test-rule": spy + "test-rule": { create: spy } } } }, @@ -7921,11 +8115,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "collect-node-types": () => ({ - "*"(node) { - nodes.push(node.type); - } - }) + "collect-node-types": { + create: () => ({ + "*"(node) { + nodes.push(node.type); + } + }) + } } } }, @@ -7988,21 +8184,27 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "collect-node-types": () => ({ - "*"(node) { - types.push(node.type); - } - }), - "save-scope-manager": context => { - scopeManager = context.getSourceCode().scopeManager; - - return {}; + "collect-node-types": { + create: () => ({ + "*"(node) { + types.push(node.type); + } + }) }, - "esquery-option": () => ({ - ":first-child"(node) { - firstChildNodes.push(node); + "save-scope-manager": { + create(context) { + scopeManager = context.getSourceCode().scopeManager; + + return {}; } - }) + }, + "esquery-option": { + create: () => ({ + ":first-child"(node) { + firstChildNodes.push(node); + } + }) + } } } }, @@ -8041,11 +8243,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "collect-node-types": () => ({ - "*"(node) { - types2.push(node.type); - } - }) + "collect-node-types": { + create: () => ({ + "*"(node) { + types2.push(node.type); + } + }) + } } } }, @@ -8079,11 +8283,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "save-scope1": context => ({ - Program() { - scope = context.getScope(); - } - }) + "save-scope1": { + create: context => ({ + Program() { + scope = context.getScope(); + } + }) + } } } }, @@ -8114,11 +8320,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "save-scope2": context => ({ - Program() { - scope2 = context.getScope(); - } - }) + "save-scope2": { + create: context => ({ + Program() { + scope2 = context.getScope(); + } + }) + } } } }, @@ -8170,9 +8378,11 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "test-rule": sinon.mock().withArgs( - sinon.match({ languageOptions: { parserOptions } }) - ).returns({}) + "test-rule": { + create: sinon.mock().withArgs( + sinon.match({ languageOptions: { parserOptions } }) + ).returns({}) + } } } }, @@ -8193,17 +8403,19 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "test-rule": sinon.mock().withArgs( - sinon.match({ - languageOptions: { - parserOptions: { - ecmaFeatures: { - globalReturn: false + "test-rule": { + create: sinon.mock().withArgs( + sinon.match({ + languageOptions: { + parserOptions: { + ecmaFeatures: { + globalReturn: false + } } } - } - }) - ).returns({}) + }) + ).returns({}) + } } } }, @@ -8392,7 +8604,7 @@ describe("Linter with FlatConfigArray", () => { const code = "var enum;"; const messages = linter.verify(code, { languageOptions: { - ...ecmaVersion ? { ecmaVersion } : {}, + ...(ecmaVersion ? { ecmaVersion } : {}), sourceType: "script" } }, filename); @@ -8411,7 +8623,7 @@ describe("Linter with FlatConfigArray", () => { const code = "obj.enum; obj.function; var obj = { enum: 1, function: 2 };"; const messages = linter.verify(code, { languageOptions: { - ...ecmaVersion ? { ecmaVersion } : {}, + ...(ecmaVersion ? { ecmaVersion } : {}), sourceType: "script" } }, filename); @@ -8427,7 +8639,7 @@ describe("Linter with FlatConfigArray", () => { const code = ""; const messages = linter.verify(code, { languageOptions: { - ...ecmaVersion ? { ecmaVersion } : {}, + ...(ecmaVersion ? { ecmaVersion } : {}), sourceType: "script", parserOptions: { allowReserved: true @@ -8453,11 +8665,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - [ruleId]: context => ({ - Literal(node) { - context.report(node, context.settings.info); - } - }) + [ruleId]: { + create: context => ({ + Literal(node) { + context.report(node, context.settings.info); + } + }) + } } } }, @@ -8484,13 +8698,15 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - [ruleId]: context => ({ - Literal(node) { - if (Object.getOwnPropertyNames(context.settings).length !== 0) { - context.report(node, "Settings should be empty"); + [ruleId]: { + create: context => ({ + Literal(node) { + if (Object.getOwnPropertyNames(context.settings).length !== 0) { + context.report(node, "Settings should be empty"); + } } - } - }) + }) + } } } }, @@ -8645,7 +8861,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } } @@ -8665,11 +8881,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: () => ({ - Program() { - throw new Error("Intentional error."); - } - }) + checker: { + create: () => ({ + Program() { + throw new Error("Intentional error."); + } + + }) + } } } }, @@ -8687,9 +8906,11 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: () => ({ - Program: spy - }) + checker: { + create: () => ({ + Program: spy + }) + } } } }, @@ -8707,9 +8928,11 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: () => ({ - newListener: spy - }) + checker: { + create: () => ({ + newListener: spy + }) + } } } }, @@ -8739,7 +8962,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -8763,14 +8986,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker() { - return { - Literal: spyLiteral, - VariableDeclarator: spyVariableDeclarator, - VariableDeclaration: spyVariableDeclaration, - Identifier: spyIdentifier, - BinaryExpression: spyBinaryExpression - }; + checker: { + create() { + return { + Literal: spyLiteral, + VariableDeclarator: spyVariableDeclarator, + VariableDeclaration: spyVariableDeclaration, + Identifier: spyIdentifier, + BinaryExpression: spyBinaryExpression + }; + } } } } @@ -8797,12 +9022,12 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "invalid-report"(context) { - return { + "invalid-report": { + create: context => ({ Program(node) { context.report({ node }); } - }; + }) } } } @@ -8831,11 +9056,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - [ruleId]: context => ({ - Literal(node) { - context.report(node, context.getFilename()); - } - }) + [ruleId]: { + create: context => ({ + Literal(node) { + context.report(node, context.getFilename()); + } + }) + } } } }, @@ -8857,11 +9084,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - [ruleId]: context => ({ - Literal(node) { - context.report(node, context.getFilename()); - } - }) + [ruleId]: { + create: context => ({ + Literal(node) { + context.report(node, context.getFilename()); + } + }) + } } } }, @@ -8889,11 +9118,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - [ruleId]: context => ({ - Literal(node) { - context.report(node, context.getPhysicalFilename()); - } - }) + [ruleId]: { + create: context => ({ + Literal(node) { + context.report(node, context.getPhysicalFilename()); + } + }) + } } } }, @@ -8924,7 +9155,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -8946,7 +9177,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -8968,7 +9199,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -8990,7 +9221,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9012,7 +9243,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9036,11 +9267,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - assert.strictEqual(context.getSource(), TEST_CODE); - }); - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(() => { + assert.strictEqual(context.getSource(), TEST_CODE); + }); + return { Program: spy }; + } } } } @@ -9060,11 +9293,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node), TEST_CODE); - }); - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node), TEST_CODE); + }); + return { Program: spy }; + } } } } @@ -9083,11 +9318,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE); - }); - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE); + }); + return { Program: spy }; + } } } } @@ -9106,11 +9343,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node), "6 * 7"); - }); - return { BinaryExpression: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node), "6 * 7"); + }); + return { BinaryExpression: spy }; + } } } } @@ -9129,11 +9368,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node, 2), "= 6 * 7"); - }); - return { BinaryExpression: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node, 2), "= 6 * 7"); + }); + return { BinaryExpression: spy }; + } } } } @@ -9152,11 +9393,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;"); - }); - return { BinaryExpression: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;"); + }); + return { BinaryExpression: spy }; + } } } } @@ -9175,11 +9418,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(node => { - assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;"); - }); - return { BinaryExpression: spy }; + checker: { + create(context) { + spy = sinon.spy(node => { + assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;"); + }); + return { BinaryExpression: spy }; + } } } } @@ -9204,13 +9449,15 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const ancestors = context.getAncestors(); + checker: { + create(context) { + spy = sinon.spy(() => { + const ancestors = context.getAncestors(); - assert.strictEqual(ancestors.length, 3); - }); - return { BinaryExpression: spy }; + assert.strictEqual(ancestors.length, 3); + }); + return { BinaryExpression: spy }; + } } } } @@ -9229,14 +9476,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const ancestors = context.getAncestors(); + checker: { + create(context) { + spy = sinon.spy(() => { + const ancestors = context.getAncestors(); - assert.strictEqual(ancestors.length, 0); - }); + assert.strictEqual(ancestors.length, 0); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -9262,7 +9511,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9283,7 +9532,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9307,7 +9556,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9328,7 +9577,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9355,7 +9604,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9382,7 +9631,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -9404,13 +9653,15 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "global"); - }); - return { Program: spy }; + assert.strictEqual(scope.type, "global"); + }); + return { Program: spy }; + } } } } @@ -9432,13 +9683,15 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - }); - return { FunctionDeclaration: spy }; + assert.strictEqual(scope.type, "function"); + }); + return { FunctionDeclaration: spy }; + } } } } @@ -9460,14 +9713,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - assert.strictEqual(scope.block.id.name, "foo"); - }); - return { LabeledStatement: spy }; + assert.strictEqual(scope.type, "function"); + assert.strictEqual(scope.block.id.name, "foo"); + }); + return { LabeledStatement: spy }; + } } } } @@ -9490,15 +9745,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - assert.strictEqual(scope.block.type, "ArrowFunctionExpression"); - }); + assert.strictEqual(scope.type, "function"); + assert.strictEqual(scope.block.type, "ArrowFunctionExpression"); + }); - return { ReturnStatement: spy }; + return { ReturnStatement: spy }; + } } } } @@ -9521,15 +9778,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "switch"); - assert.strictEqual(scope.block.type, "SwitchStatement"); - }); + assert.strictEqual(scope.type, "switch"); + assert.strictEqual(scope.block.type, "SwitchStatement"); + }); - return { SwitchStatement: spy }; + return { SwitchStatement: spy }; + } } } } @@ -9551,15 +9810,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "block"); - assert.strictEqual(scope.block.type, "BlockStatement"); - }); + assert.strictEqual(scope.type, "block"); + assert.strictEqual(scope.block.type, "BlockStatement"); + }); - return { BlockStatement: spy }; + return { BlockStatement: spy }; + } } } } @@ -9582,15 +9843,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "block"); - assert.strictEqual(scope.block.type, "BlockStatement"); - }); + assert.strictEqual(scope.type, "block"); + assert.strictEqual(scope.block.type, "BlockStatement"); + }); - return { BlockStatement: spy }; + return { BlockStatement: spy }; + } } } } @@ -9613,15 +9876,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - assert.strictEqual(scope.block.type, "FunctionDeclaration"); - }); + assert.strictEqual(scope.type, "function"); + assert.strictEqual(scope.block.type, "FunctionDeclaration"); + }); - return { FunctionDeclaration: spy }; + return { FunctionDeclaration: spy }; + } } } } @@ -9644,15 +9909,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - assert.strictEqual(scope.block.type, "FunctionExpression"); - }); + assert.strictEqual(scope.type, "function"); + assert.strictEqual(scope.block.type, "FunctionExpression"); + }); - return { FunctionExpression: spy }; + return { FunctionExpression: spy }; + } } } } @@ -9675,15 +9942,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "catch"); - assert.strictEqual(scope.block.type, "CatchClause"); - }); + assert.strictEqual(scope.type, "catch"); + assert.strictEqual(scope.block.type, "CatchClause"); + }); - return { CatchClause: spy }; + return { CatchClause: spy }; + } } } } @@ -9705,14 +9974,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "module"); - }); + assert.strictEqual(scope.type, "module"); + }); - return { AssignmentExpression: spy }; + return { AssignmentExpression: spy }; + } } } } @@ -9736,14 +10007,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(scope.type, "function"); - }); + assert.strictEqual(scope.type, "function"); + }); - return { AssignmentExpression: spy }; + return { AssignmentExpression: spy }; + } } } } @@ -9775,12 +10048,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - "get-scope": context => ({ - [astSelector](node0) { - node = node0; - scope = context.getScope(); - } - }) + "get-scope": { + create: context => ({ + [astSelector](node0) { + node = node0; + scope = context.getScope(); + } + }) + } } } }, @@ -10042,13 +10317,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - test(context) { - return { + test: { + create: context => ({ Program() { scope = context.getScope(); ok = true; } - }; + }) } } } @@ -10152,78 +10427,81 @@ describe("Linter with FlatConfigArray", () => { test: { rules: { - test(context) { - - /** - * Assert `context.getDeclaredVariables(node)` is empty. - * @param {ASTNode} node A node to check. - * @returns {void} - */ - function checkEmpty(node) { - assert.strictEqual(0, context.getDeclaredVariables(node).length); - } - const rule = { - Program: checkEmpty, - EmptyStatement: checkEmpty, - BlockStatement: checkEmpty, - ExpressionStatement: checkEmpty, - LabeledStatement: checkEmpty, - BreakStatement: checkEmpty, - ContinueStatement: checkEmpty, - WithStatement: checkEmpty, - SwitchStatement: checkEmpty, - ReturnStatement: checkEmpty, - ThrowStatement: checkEmpty, - TryStatement: checkEmpty, - WhileStatement: checkEmpty, - DoWhileStatement: checkEmpty, - ForStatement: checkEmpty, - ForInStatement: checkEmpty, - DebuggerStatement: checkEmpty, - ThisExpression: checkEmpty, - ArrayExpression: checkEmpty, - ObjectExpression: checkEmpty, - Property: checkEmpty, - SequenceExpression: checkEmpty, - UnaryExpression: checkEmpty, - BinaryExpression: checkEmpty, - AssignmentExpression: checkEmpty, - UpdateExpression: checkEmpty, - LogicalExpression: checkEmpty, - ConditionalExpression: checkEmpty, - CallExpression: checkEmpty, - NewExpression: checkEmpty, - MemberExpression: checkEmpty, - SwitchCase: checkEmpty, - Identifier: checkEmpty, - Literal: checkEmpty, - ForOfStatement: checkEmpty, - ArrowFunctionExpression: checkEmpty, - YieldExpression: checkEmpty, - TemplateLiteral: checkEmpty, - TaggedTemplateExpression: checkEmpty, - TemplateElement: checkEmpty, - ObjectPattern: checkEmpty, - ArrayPattern: checkEmpty, - RestElement: checkEmpty, - AssignmentPattern: checkEmpty, - ClassBody: checkEmpty, - MethodDefinition: checkEmpty, - MetaProperty: checkEmpty - }; - - rule[type] = function(node) { - const expectedNames = expectedNamesList.shift(); - const variables = context.getDeclaredVariables(node); + test: { + create(context) { - assert(Array.isArray(expectedNames)); - assert(Array.isArray(variables)); - assert.strictEqual(expectedNames.length, variables.length); - for (let i = variables.length - 1; i >= 0; i--) { - assert.strictEqual(expectedNames[i], variables[i].name); + /** + * Assert `context.getDeclaredVariables(node)` is empty. + * @param {ASTNode} node A node to check. + * @returns {void} + */ + function checkEmpty(node) { + assert.strictEqual(0, context.getDeclaredVariables(node).length); } - }; - return rule; + const rule = { + Program: checkEmpty, + EmptyStatement: checkEmpty, + BlockStatement: checkEmpty, + ExpressionStatement: checkEmpty, + LabeledStatement: checkEmpty, + BreakStatement: checkEmpty, + ContinueStatement: checkEmpty, + WithStatement: checkEmpty, + SwitchStatement: checkEmpty, + ReturnStatement: checkEmpty, + ThrowStatement: checkEmpty, + TryStatement: checkEmpty, + WhileStatement: checkEmpty, + DoWhileStatement: checkEmpty, + ForStatement: checkEmpty, + ForInStatement: checkEmpty, + DebuggerStatement: checkEmpty, + ThisExpression: checkEmpty, + ArrayExpression: checkEmpty, + ObjectExpression: checkEmpty, + Property: checkEmpty, + SequenceExpression: checkEmpty, + UnaryExpression: checkEmpty, + BinaryExpression: checkEmpty, + AssignmentExpression: checkEmpty, + UpdateExpression: checkEmpty, + LogicalExpression: checkEmpty, + ConditionalExpression: checkEmpty, + CallExpression: checkEmpty, + NewExpression: checkEmpty, + MemberExpression: checkEmpty, + SwitchCase: checkEmpty, + Identifier: checkEmpty, + Literal: checkEmpty, + ForOfStatement: checkEmpty, + ArrowFunctionExpression: checkEmpty, + YieldExpression: checkEmpty, + TemplateLiteral: checkEmpty, + TaggedTemplateExpression: checkEmpty, + TemplateElement: checkEmpty, + ObjectPattern: checkEmpty, + ArrayPattern: checkEmpty, + RestElement: checkEmpty, + AssignmentPattern: checkEmpty, + ClassBody: checkEmpty, + MethodDefinition: checkEmpty, + MetaProperty: checkEmpty + }; + + rule[type] = function(node) { + const expectedNames = expectedNamesList.shift(); + const variables = context.getDeclaredVariables(node); + + assert(Array.isArray(expectedNames)); + assert(Array.isArray(variables)); + assert.strictEqual(expectedNames.length, variables.length); + for (let i = variables.length - 1; i >= 0; i--) { + assert.strictEqual(expectedNames[i], variables[i].name); + } + }; + return rule; + } + } } @@ -10396,17 +10674,19 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - assert.isTrue(context.markVariableAsUsed("a")); + checker: { + create(context) { + spy = sinon.spy(() => { + assert.isTrue(context.markVariableAsUsed("a")); - const scope = context.getScope(); + const scope = context.getScope(); - assert.isTrue(getVariable(scope, "a").eslintUsed); - assert.notOk(getVariable(scope, "b").eslintUsed); - }); + assert.isTrue(getVariable(scope, "a").eslintUsed); + assert.notOk(getVariable(scope, "b").eslintUsed); + }); - return { "Program:exit": spy }; + return { "Program:exit": spy }; + } } } } @@ -10429,17 +10709,19 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - assert.isTrue(context.markVariableAsUsed("a")); + checker: { + create(context) { + spy = sinon.spy(() => { + assert.isTrue(context.markVariableAsUsed("a")); - const scope = context.getScope(); + const scope = context.getScope(); - assert.isTrue(getVariable(scope, "a").eslintUsed); - assert.notOk(getVariable(scope, "b").eslintUsed); - }); + assert.isTrue(getVariable(scope, "a").eslintUsed); + assert.notOk(getVariable(scope, "b").eslintUsed); + }); - return { ReturnStatement: spy }; + return { ReturnStatement: spy }; + } } } } @@ -10459,18 +10741,20 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - returnSpy = sinon.spy(() => { - assert.isTrue(context.markVariableAsUsed("a")); - }); - exitSpy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + returnSpy = sinon.spy(() => { + assert.isTrue(context.markVariableAsUsed("a")); + }); + exitSpy = sinon.spy(() => { + const scope = context.getScope(); - assert.isTrue(getVariable(scope, "a").eslintUsed); - assert.notOk(getVariable(scope, "b").eslintUsed); - }); + assert.isTrue(getVariable(scope, "a").eslintUsed); + assert.notOk(getVariable(scope, "b").eslintUsed); + }); - return { ReturnStatement: returnSpy, "Program:exit": exitSpy }; + return { ReturnStatement: returnSpy, "Program:exit": exitSpy }; + } } } } @@ -10494,18 +10778,20 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const globalScope = context.getScope(), - childScope = globalScope.childScopes[0]; + checker: { + create(context) { + spy = sinon.spy(() => { + const globalScope = context.getScope(), + childScope = globalScope.childScopes[0]; - assert.isTrue(context.markVariableAsUsed("a"), "Call to markVariableAsUsed should return true"); + assert.isTrue(context.markVariableAsUsed("a"), "Call to markVariableAsUsed should return true"); - assert.isTrue(getVariable(childScope, "a").eslintUsed, "'a' should be marked as used."); - assert.isUndefined(getVariable(childScope, "b").eslintUsed, "'b' should be marked as used."); - }); + assert.isTrue(getVariable(childScope, "a").eslintUsed, "'a' should be marked as used."); + assert.isUndefined(getVariable(childScope, "b").eslintUsed, "'b' should be marked as used."); + }); - return { "Program:exit": spy }; + return { "Program:exit": spy }; + } } } } @@ -10528,18 +10814,20 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const globalScope = context.getScope(), - childScope = globalScope.childScopes[0]; + checker: { + create(context) { + spy = sinon.spy(() => { + const globalScope = context.getScope(), + childScope = globalScope.childScopes[0]; - assert.isTrue(context.markVariableAsUsed("a")); + assert.isTrue(context.markVariableAsUsed("a")); - assert.isTrue(getVariable(childScope, "a").eslintUsed); - assert.isUndefined(getVariable(childScope, "b").eslintUsed); - }); + assert.isTrue(getVariable(childScope, "a").eslintUsed); + assert.isUndefined(getVariable(childScope, "b").eslintUsed); + }); - return { "Program:exit": spy }; + return { "Program:exit": spy }; + } } } } @@ -10563,12 +10851,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - assert.isFalse(context.markVariableAsUsed("c")); - }); + checker: { + create(context) { + spy = sinon.spy(() => { + assert.isFalse(context.markVariableAsUsed("c")); + }); - return { "Program:exit": spy }; + return { "Program:exit": spy }; + } } } } @@ -10593,11 +10883,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - assert.strictEqual(context.getCwd(), cwd); - }); - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(() => { + assert.strictEqual(context.getCwd(), cwd); + }); + return { Program: spy }; + } } } } @@ -10617,12 +10909,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { + checker: { + create(context) { - spy = sinon.spy(() => { - assert.strictEqual(context.getCwd(), process.cwd()); - }); - return { Program: spy }; + spy = sinon.spy(() => { + assert.strictEqual(context.getCwd(), process.cwd()); + }); + return { Program: spy }; + } } } } @@ -10640,12 +10934,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { + checker: { + create(context) { - spy = sinon.spy(() => { - assert.strictEqual(context.getCwd(), process.cwd()); - }); - return { Program: spy }; + spy = sinon.spy(() => { + assert.strictEqual(context.getCwd(), process.cwd()); + }); + return { Program: spy }; + } } } } @@ -10747,7 +11043,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: spy + checker: { create: spy } } } }, @@ -10774,7 +11070,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: filenameChecker + checker: { create: filenameChecker } } } }, @@ -10797,7 +11093,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: filenameChecker + checker: { create: filenameChecker } } } }, @@ -10820,7 +11116,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: filenameChecker + checker: { create: filenameChecker } } } }, @@ -10843,7 +11139,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: filenameChecker + checker: { create: filenameChecker } } } }, @@ -10868,7 +11164,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: physicalFilenameChecker + checker: { create: physicalFilenameChecker } } } }, @@ -10891,7 +11187,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: physicalFilenameChecker + checker: { create: physicalFilenameChecker } } } }, @@ -10914,7 +11210,7 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: physicalFilenameChecker + checker: { create: physicalFilenameChecker } } } }, @@ -10949,38 +11245,40 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); - const a = getVariable(scope, "a"), - b = getVariable(scope, "b"), - c = getVariable(scope, "c"), - d = getVariable(scope, "d"), - e = getVariable(scope, "e"), - f = getVariable(scope, "f"), - mathGlobal = getVariable(scope, "Math"), - arrayGlobal = getVariable(scope, "Array"), - configGlobal = getVariable(scope, "ConfigGlobal"); - - assert.strictEqual(a.name, "a"); - assert.strictEqual(a.writeable, false); - assert.strictEqual(b.name, "b"); - assert.strictEqual(b.writeable, true); - assert.strictEqual(c.name, "c"); - assert.strictEqual(c.writeable, false); - assert.strictEqual(d.name, "d"); - assert.strictEqual(d.writeable, false); - assert.strictEqual(e.name, "e"); - assert.strictEqual(e.writeable, true); - assert.strictEqual(f.name, "f"); - assert.strictEqual(f.writeable, true); - assert.strictEqual(mathGlobal, null); - assert.strictEqual(arrayGlobal, null); - assert.strictEqual(configGlobal.name, "ConfigGlobal"); - assert.strictEqual(configGlobal.writeable, false); - }); - - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); + const a = getVariable(scope, "a"), + b = getVariable(scope, "b"), + c = getVariable(scope, "c"), + d = getVariable(scope, "d"), + e = getVariable(scope, "e"), + f = getVariable(scope, "f"), + mathGlobal = getVariable(scope, "Math"), + arrayGlobal = getVariable(scope, "Array"), + configGlobal = getVariable(scope, "ConfigGlobal"); + + assert.strictEqual(a.name, "a"); + assert.strictEqual(a.writeable, false); + assert.strictEqual(b.name, "b"); + assert.strictEqual(b.writeable, true); + assert.strictEqual(c.name, "c"); + assert.strictEqual(c.writeable, false); + assert.strictEqual(d.name, "d"); + assert.strictEqual(d.writeable, false); + assert.strictEqual(e.name, "e"); + assert.strictEqual(e.writeable, true); + assert.strictEqual(f.name, "f"); + assert.strictEqual(f.writeable, true); + assert.strictEqual(mathGlobal, null); + assert.strictEqual(arrayGlobal, null); + assert.strictEqual(configGlobal.name, "ConfigGlobal"); + assert.strictEqual(configGlobal.writeable, false); + }); + + return { Program: spy }; + } } } } @@ -11006,22 +11304,24 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - a = getVariable(scope, "a"), - b = getVariable(scope, "b"), - c = getVariable(scope, "c"); - - assert.strictEqual(a.name, "a"); - assert.strictEqual(a.writeable, false); - assert.strictEqual(b.name, "b"); - assert.strictEqual(b.writeable, true); - assert.strictEqual(c.name, "c"); - assert.strictEqual(c.writeable, false); - }); - - return { Program: spy }; + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + a = getVariable(scope, "a"), + b = getVariable(scope, "b"), + c = getVariable(scope, "c"); + + assert.strictEqual(a.name, "a"); + assert.strictEqual(a.writeable, false); + assert.strictEqual(b.name, "b"); + assert.strictEqual(b.writeable, true); + assert.strictEqual(c.name, "c"); + assert.strictEqual(c.writeable, false); + }); + + return { Program: spy }; + } } } } @@ -11044,14 +11344,16 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(getVariable(scope, "a"), null); - }); + assert.strictEqual(getVariable(scope, "a"), null); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11075,17 +11377,19 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.strictEqual(getVariable(scope, "a"), null); - assert.strictEqual(getVariable(scope, "b"), null); - assert.strictEqual(getVariable(scope, "foo"), null); - assert.strictEqual(getVariable(scope, "c"), null); - }); + assert.strictEqual(getVariable(scope, "a"), null); + assert.strictEqual(getVariable(scope, "b"), null); + assert.strictEqual(getVariable(scope, "foo"), null); + assert.strictEqual(getVariable(scope, "c"), null); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11106,8 +11410,8 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - test(context) { - return { + test: { + create: context => ({ Program() { const scope = context.getScope(); const sourceCode = context.getSourceCode(); @@ -11132,7 +11436,7 @@ describe("Linter with FlatConfigArray", () => { ok = true; } - }; + }) } } } @@ -11195,15 +11499,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - horse = getVariable(scope, "horse"); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + horse = getVariable(scope, "horse"); - assert.strictEqual(horse.eslintUsed, true); - }); + assert.strictEqual(horse.eslintUsed, true); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11225,15 +11531,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - horse = getVariable(scope, "horse"); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + horse = getVariable(scope, "horse"); - assert.strictEqual(horse, null); - }); + assert.strictEqual(horse, null); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11255,15 +11563,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - horse = getVariable(scope, "horse"); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + horse = getVariable(scope, "horse"); - assert.strictEqual(horse.eslintUsed, true); - }); + assert.strictEqual(horse.eslintUsed, true); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11285,15 +11595,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - horse = getVariable(scope, "horse"); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + horse = getVariable(scope, "horse"); - assert.strictEqual(horse, null); // there is no global scope at all - }); + assert.strictEqual(horse, null); // there is no global scope at all + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11316,15 +11628,17 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(), - horse = getVariable(scope, "horse"); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(), + horse = getVariable(scope, "horse"); - assert.strictEqual(horse, null); // there is no global scope at all - }); + assert.strictEqual(horse, null); // there is no global scope at all + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -11598,14 +11912,14 @@ describe("Linter with FlatConfigArray", () => { plugins: { "test-plugin": { rules: { - "test-rule"(context) { - return { + "test-rule": { + create: context => ({ Literal(node) { if (node.value === "trigger violation") { context.report(node, "Reporting violation."); } } - }; + }) } } } @@ -11643,11 +11957,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => ({ - Program() { - context.report({ loc: { line: 1, column: 0 }, message: "foo" }); - } - }) + checker: { + create: context => ({ + Program() { + context.report({ loc: { line: 1, column: 0 }, message: "foo" }); + } + }) + } } } }, @@ -11672,11 +11988,13 @@ describe("Linter with FlatConfigArray", () => { plugins: { test: { rules: { - checker: context => ({ - Program() { - context.report({ loc: { line: 1, column: 1 }, message: "foo" }); - } - }) + checker: { + create: context => ({ + Program() { + context.report({ loc: { line: 1, column: 1 }, message: "foo" }); + } + }) + } } } }, @@ -13374,8 +13692,8 @@ var a = "test2"; plugins: { test: { rules: { - test(context) { - return { + test: { + create: context => ({ Program() { const scope = context.getScope(); const sourceCode = context.getSourceCode(); @@ -13389,7 +13707,7 @@ var a = "test2"; ok = true; } - }; + }) } } } @@ -14413,16 +14731,18 @@ var a = "test2"; plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.notStrictEqual(getVariable(scope, "Object"), null); - assert.notStrictEqual(getVariable(scope, "Array"), null); - assert.notStrictEqual(getVariable(scope, "undefined"), null); - }); + assert.notStrictEqual(getVariable(scope, "Object"), null); + assert.notStrictEqual(getVariable(scope, "Array"), null); + assert.notStrictEqual(getVariable(scope, "undefined"), null); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -14446,16 +14766,18 @@ var a = "test2"; plugins: { test: { rules: { - checker: context => { - spy = sinon.spy(() => { - const scope = context.getScope(); + checker: { + create(context) { + spy = sinon.spy(() => { + const scope = context.getScope(); - assert.notStrictEqual(getVariable(scope, "Promise"), null); - assert.notStrictEqual(getVariable(scope, "Symbol"), null); - assert.notStrictEqual(getVariable(scope, "WeakMap"), null); - }); + assert.notStrictEqual(getVariable(scope, "Promise"), null); + assert.notStrictEqual(getVariable(scope, "Symbol"), null); + assert.notStrictEqual(getVariable(scope, "WeakMap"), null); + }); - return { Program: spy }; + return { Program: spy }; + } } } } @@ -14781,7 +15103,9 @@ var a = "test2"; describe("defineRule()", () => { it("should throw an error when called in flat config mode", () => { assert.throws(() => { - linter.defineRule("foo", () => {}); + linter.defineRule("foo", { + create() {} + }); }, /This method cannot be used with flat config/u); }); }); @@ -14982,11 +15306,13 @@ var a = "test2"; plugins: { test: { rules: { - "test-rule": context => ({ - Program(node) { - context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" })); - } - }) + "test-rule": { + create: context => ({ + Program(node) { + context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" })); + } + }) + } } } }, @@ -15017,7 +15343,9 @@ var a = "test2"; }); it("loading rule in one doesn't change the other", () => { - linter1.defineRule("mock-rule", () => ({})); + linter1.defineRule("mock-rule", { + create: () => ({}) + }); assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present"); assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present"); @@ -15480,17 +15808,21 @@ var a = "test2"; plugins: { test: { rules: { - "save-ast1": () => ({ - Program(node) { - ast1 = node; - } - }), + "save-ast1": { + create: () => ({ + Program(node) { + ast1 = node; + } + }) + }, - "save-ast2": () => ({ - Program(node) { - ast2 = node; - } - }) + "save-ast2": { + create: () => ({ + Program(node) { + ast2 = node; + } + }) + } } } @@ -15530,7 +15862,7 @@ var a = "test2"; plugins: { test: { rules: { - "foo-bar-baz": spy + "foo-bar-baz": { create: spy } } } }, @@ -15552,11 +15884,15 @@ var a = "test2"; plugins: { test: { rules: { - "no-programs": context => ({ - Program(node) { - context.report({ node, message: "No programs allowed." }); + "no-programs": { + create(context) { + return { + Program(node) { + context.report({ node, message: "No programs allowed." }); + } + }; } - }) + } } } }, diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index b723a29abcf3..2f145fa418f3 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -18,20 +18,22 @@ const rule = require("../../../lib/rules/no-unused-vars"), const ruleTester = new RuleTester(); -ruleTester.defineRule("use-every-a", context => { - - /** - * Mark a variable as used - * @returns {void} - * @private - */ - function useA() { - context.markVariableAsUsed("a"); +ruleTester.defineRule("use-every-a", { + create(context) { + + /** + * Mark a variable as used + * @returns {void} + * @private + */ + function useA() { + context.markVariableAsUsed("a"); + } + return { + VariableDeclaration: useA, + ReturnStatement: useA + }; } - return { - VariableDeclaration: useA, - ReturnStatement: useA - }; }); /** diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js index c65252cb0bf1..b4c185f12a72 100644 --- a/tests/lib/rules/prefer-const.js +++ b/tests/lib/rules/prefer-const.js @@ -19,11 +19,13 @@ const rule = require("../../../lib/rules/prefer-const"), const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); -ruleTester.defineRule("use-x", context => ({ - VariableDeclaration() { - context.markVariableAsUsed("x"); - } -})); +ruleTester.defineRule("use-x", { + create: context => ({ + VariableDeclaration() { + context.markVariableAsUsed("x"); + } + }) +}); ruleTester.run("prefer-const", rule, { valid: [ diff --git a/tests/lib/rules/utils/ast-utils.js b/tests/lib/rules/utils/ast-utils.js index c36a9ac0e252..3f9da7316763 100644 --- a/tests/lib/rules/utils/ast-utils.js +++ b/tests/lib/rules/utils/ast-utils.js @@ -61,22 +61,26 @@ describe("ast-utils", () => { describe("isTokenOnSameLine", () => { it("should return false if the tokens are not on the same line", () => { - linter.defineRule("checker", mustCall(context => ({ - BlockStatement: mustCall(node => { - assert.isFalse(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node)); - }) - }))); + linter.defineRule("checker", { + create: mustCall(context => ({ + BlockStatement: mustCall(node => { + assert.isFalse(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node)); + }) + })) + }); linter.verify("if(a)\n{}", { rules: { checker: "error" } }); }); it("should return true if the tokens are on the same line", () => { - linter.defineRule("checker", mustCall(context => ({ - BlockStatement: mustCall(node => { - assert.isTrue(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node)); - }) - }))); + linter.defineRule("checker", { + create: mustCall(context => ({ + BlockStatement: mustCall(node => { + assert.isTrue(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node)); + }) + })) + }); linter.verify("if(a){}", { rules: { checker: "error" } }); }); @@ -116,64 +120,74 @@ describe("ast-utils", () => { // catch it("should return true if reference is assigned for catch", () => { - linter.defineRule("checker", mustCall(context => ({ - CatchClause: mustCall(node => { - const variables = context.getDeclaredVariables(node); + linter.defineRule("checker", { + create: mustCall(context => ({ + CatchClause: mustCall(node => { + const variables = context.getDeclaredVariables(node); - assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); - }) - }))); + assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); + }) + })) + }); linter.verify("try { } catch (e) { e = 10; }", { rules: { checker: "error" } }); }); // const it("should return true if reference is assigned for const", () => { - linter.defineRule("checker", mustCall(context => ({ - VariableDeclaration: mustCall(node => { - const variables = context.getDeclaredVariables(node); + linter.defineRule("checker", { + create: mustCall(context => ({ + VariableDeclaration: mustCall(node => { + const variables = context.getDeclaredVariables(node); - assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); - }) - }))); + assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); + }) + })) + }); linter.verify("const a = 1; a = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); }); it("should return false if reference is not assigned for const", () => { - linter.defineRule("checker", mustCall(context => ({ - VariableDeclaration: mustCall(node => { - const variables = context.getDeclaredVariables(node); + linter.defineRule("checker", { + create: mustCall(context => ({ + VariableDeclaration: mustCall(node => { + const variables = context.getDeclaredVariables(node); - assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0); - }) - }))); + assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0); + }) + })) + }); linter.verify("const a = 1; c = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); }); // class it("should return true if reference is assigned for class", () => { - linter.defineRule("checker", mustCall(context => ({ - ClassDeclaration: mustCall(node => { - const variables = context.getDeclaredVariables(node); + linter.defineRule("checker", { + create: mustCall(context => ({ + ClassDeclaration: mustCall(node => { + const variables = context.getDeclaredVariables(node); - assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); - assert.lengthOf(astUtils.getModifyingReferences(variables[1].references), 0); - }) - }))); + assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1); + assert.lengthOf(astUtils.getModifyingReferences(variables[1].references), 0); + }) + })) + }); linter.verify("class A { }\n A = 1;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); }); it("should return false if reference is not assigned for class", () => { - linter.defineRule("checker", mustCall(context => ({ - ClassDeclaration: mustCall(node => { - const variables = context.getDeclaredVariables(node); + linter.defineRule("checker", { + create: mustCall(context => ({ + ClassDeclaration: mustCall(node => { + const variables = context.getDeclaredVariables(node); - assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0); - }) - }))); + assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0); + }) + })) + }); linter.verify("class A { } foo(A);", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); }); @@ -372,11 +386,13 @@ describe("ast-utils", () => { function assertNodeTypeInLoop(code, nodeType, expectedInLoop) { const results = []; - linter.defineRule("checker", mustCall(() => ({ - [nodeType]: mustCall(node => { - results.push(astUtils.isInLoop(node)); - }) - }))); + linter.defineRule("checker", { + create: mustCall(() => ({ + [nodeType]: mustCall(node => { + results.push(astUtils.isInLoop(node)); + }) + })) + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.lengthOf(results, 1); @@ -897,14 +913,16 @@ describe("ast-utils", () => { Object.keys(expectedResults).forEach(key => { it(`should return "${expectedResults[key]}" for "${key}".`, () => { - linter.defineRule("checker", mustCall(() => ({ - ":function": mustCall(node => { - assert.strictEqual( - astUtils.getFunctionNameWithKind(node), - expectedResults[key] - ); - }) - }))); + linter.defineRule("checker", { + create: mustCall(() => ({ + ":function": mustCall(node => { + assert.strictEqual( + astUtils.getFunctionNameWithKind(node), + expectedResults[key] + ); + }) + })) + }); linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 13 } }); }); @@ -975,14 +993,16 @@ describe("ast-utils", () => { }; it(`should return "${JSON.stringify(expectedLoc)}" for "${key}".`, () => { - linter.defineRule("checker", mustCall(() => ({ - ":function": mustCall(node => { - assert.deepStrictEqual( - astUtils.getFunctionHeadLoc(node, linter.getSourceCode()), - expectedLoc - ); - }) - }))); + linter.defineRule("checker", { + create: mustCall(() => ({ + ":function": mustCall(node => { + assert.deepStrictEqual( + astUtils.getFunctionHeadLoc(node, linter.getSourceCode()), + expectedLoc + ); + }) + })) + }); linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 13 } }, "test.js", true); }); diff --git a/tests/lib/shared/config-validator.js b/tests/lib/shared/config-validator.js index 61d616b3ae01..d54d26e360d7 100644 --- a/tests/lib/shared/config-validator.js +++ b/tests/lib/shared/config-validator.js @@ -32,59 +32,48 @@ const assert = require("chai").assert, const linter = new Linter(); -/** - * Fake a rule object - * @param {Object} context context passed to the rules by eslint - * @returns {Object} mocked rule listeners - * @private - */ -function mockRule(context) { - return { - Program(node) { - context.report(node, "Expected a validation error."); - } - }; -} - -mockRule.schema = [ - { - enum: ["first", "second"] +const mockRule = { + meta: { + schema: [{ + enum: ["first", "second"] + }] + }, + create(context) { + return { + Program(node) { + context.report(node, "Expected a validation error."); + } + }; } -]; - -/** - * Fake a rule object - * @param {Object} context context passed to the rules by eslint - * @returns {Object} mocked rule listeners - * @private - */ -function mockObjectRule(context) { - return { - Program(node) { - context.report(node, "Expected a validation error."); - } - }; -} - -mockObjectRule.schema = { - enum: ["first", "second"] }; -/** - * Fake a rule with no options - * @param {Object} context context passed to the rules by eslint - * @returns {Object} mocked rule listeners - * @private - */ -function mockNoOptionsRule(context) { - return { - Program(node) { - context.report(node, "Expected a validation error."); +const mockObjectRule = { + meta: { + schema: { + enum: ["first", "second"] } - }; -} + }, + create(context) { + return { + Program(node) { + context.report(node, "Expected a validation error."); + } + }; + } +}; -mockNoOptionsRule.schema = []; +const mockNoOptionsRule = { + meta: { + schema: [] + }, + create(context) { + return { + Program(node) { + context.report(node, "Expected a validation error."); + } + }; + } +}; const mockRequiredOptionsRule = { meta: { diff --git a/tests/lib/source-code/source-code.js b/tests/lib/source-code/source-code.js index c44d4a2e434f..7bfbd5ea09fd 100644 --- a/tests/lib/source-code/source-code.js +++ b/tests/lib/source-code/source-code.js @@ -253,7 +253,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -281,7 +287,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -311,7 +323,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledTwice, "Event handler should be called twice."); @@ -343,7 +361,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -371,7 +395,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -400,7 +430,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -431,7 +467,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -462,7 +504,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -492,7 +540,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); @@ -524,7 +578,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -555,7 +615,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -586,7 +652,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ ArrowFunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + ArrowFunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -615,7 +687,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -648,7 +726,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledTwice, "Event handler should be called."); }); @@ -680,7 +764,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledTwice, "Event handler should be called."); }); @@ -710,7 +800,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -748,7 +844,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" } }); assert.isTrue(spy.calledTwice, "Event handler should be called."); }); @@ -777,7 +879,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ ClassExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + ClassExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -806,7 +914,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ ClassDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + ClassDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -835,7 +949,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -868,7 +988,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionExpression: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionExpression: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -899,7 +1025,13 @@ describe("SourceCode", () => { const spy = sinon.spy(assertJSDoc); - linter.defineRule("checker", () => ({ FunctionDeclaration: spy })); + linter.defineRule("checker", { + create() { + return ({ + FunctionDeclaration: spy + }); + } + }); linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } }); assert.isTrue(spy.calledOnce, "Event handler should be called."); }); @@ -956,13 +1088,17 @@ describe("SourceCode", () => { "/* Trailing comment for VariableDeclaration */" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(1, 1), - VariableDeclarator: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(1, 1), + VariableDeclarator: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -975,13 +1111,17 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 1), - CallExpression: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 1), + CallExpression: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -992,12 +1132,16 @@ describe("SourceCode", () => { "if (/* Leading comment for Identifier */ a) {}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - IfStatement: assertCommentCount(1, 0), - Identifier: assertCommentCount(1, 0), - BlockStatement: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + IfStatement: assertCommentCount(1, 0), + Identifier: assertCommentCount(1, 0), + BlockStatement: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1012,15 +1156,19 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(0, 0), - VariableDeclarator: assertCommentCount(0, 0), - ObjectExpression: assertCommentCount(0, 1), - ReturnStatement: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(0, 0), + VariableDeclarator: assertCommentCount(0, 0), + ObjectExpression: assertCommentCount(0, 1), + ReturnStatement: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1034,15 +1182,19 @@ describe("SourceCode", () => { "var baz;" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(0, 0), - VariableDeclarator: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - ObjectExpression: assertCommentCount(0, 0), - Property: assertCommentCount(0, 1), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(0, 0), + VariableDeclarator: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + ObjectExpression: assertCommentCount(0, 0), + Property: assertCommentCount(0, 1), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1061,16 +1213,20 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ExportDefaultDeclaration: assertCommentCount(1, 0), - ClassDeclaration: assertCommentCount(0, 0), - ClassBody: assertCommentCount(0, 0), - MethodDefinition: assertCommentCount(1, 0), - Identifier: assertCommentCount(0, 0), - FunctionExpression: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ExportDefaultDeclaration: assertCommentCount(1, 0), + ClassDeclaration: assertCommentCount(0, 0), + ClassBody: assertCommentCount(0, 0), + MethodDefinition: assertCommentCount(1, 0), + Identifier: assertCommentCount(0, 0), + FunctionExpression: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1084,19 +1240,25 @@ describe("SourceCode", () => { ].join("\n"); let varDeclCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration(node) { - if (varDeclCount === 0) { - assertCommentCount(1, 1)(node); - } else { - assertCommentCount(1, 0)(node); - } - varDeclCount++; - }, - VariableDeclarator: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + + VariableDeclaration(node) { + if (varDeclCount === 0) { + assertCommentCount(1, 1)(node); + } else { + assertCommentCount(1, 0)(node); + } + varDeclCount++; + }, + + VariableDeclarator: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1110,18 +1272,24 @@ describe("SourceCode", () => { ].join("\n"); let varDeclCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration(node) { - if (varDeclCount === 0) { - assertCommentCount(1, 1)(node); - } else { - assertCommentCount(1, 0)(node); - } - varDeclCount++; - }, - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + + VariableDeclaration(node) { + if (varDeclCount === 0) { + assertCommentCount(1, 1)(node); + } else { + assertCommentCount(1, 0)(node); + } + varDeclCount++; + }, + + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1129,7 +1297,13 @@ describe("SourceCode", () => { it("should include shebang comment when program only contains shebang", () => { const code = "#!/usr/bin/env node"; - linter.defineRule("checker", () => ({ Program: assertCommentCount(1, 0) })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(1, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1141,13 +1315,17 @@ describe("SourceCode", () => { "// Trailing comment for VariableDeclaration" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(1, 1), - VariableDeclarator: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 1), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(1, 1), + VariableDeclarator: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 1), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1161,14 +1339,18 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(1, 1), - CallExpression: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(1, 1), + CallExpression: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1182,13 +1364,17 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - DebuggerStatement: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + DebuggerStatement: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1202,13 +1388,17 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - ReturnStatement: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + ReturnStatement: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1222,13 +1412,17 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - ThrowStatement: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + ThrowStatement: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1243,16 +1437,20 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - WhileStatement: assertCommentCount(1, 1), - Literal: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(1, 0), - VariableDeclarator: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + WhileStatement: assertCommentCount(1, 1), + Literal: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(1, 0), + VariableDeclarator: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1271,24 +1469,30 @@ describe("SourceCode", () => { ].join("\n"); let switchCaseCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 0), - SwitchCase: node => { - if (switchCaseCount === 0) { - assertCommentCount(1, 1)(node); - } else { - assertCommentCount(1, 0)(node); - } - switchCaseCount++; - }, - Literal: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 0), - CallExpression: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 0), + + SwitchCase(node) { + if (switchCaseCount === 0) { + assertCommentCount(1, 1)(node); + } else { + assertCommentCount(1, 0)(node); + } + switchCaseCount++; + }, + + Literal: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 0), + CallExpression: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1305,21 +1509,27 @@ describe("SourceCode", () => { ].join("\n"); let switchCaseCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 0), - SwitchCase: node => { - if (switchCaseCount === 0) { - assertCommentCount(1, 1)(node); - } else { - assertCommentCount(1, 0)(node); - } - switchCaseCount++; - }, - Literal: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 0), - CallExpression: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 0), + + SwitchCase(node) { + if (switchCaseCount === 0) { + assertCommentCount(1, 1)(node); + } else { + assertCommentCount(1, 0)(node); + } + switchCaseCount++; + }, + + Literal: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 0), + CallExpression: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1338,23 +1548,29 @@ describe("SourceCode", () => { ].join("\n"); let breakStatementCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 0), - SwitchCase: node => { - if (breakStatementCount === 0) { - assertCommentCount(0, 0)(node); - } else { - assertCommentCount(0, 1)(node); - } - breakStatementCount++; - }, - BreakStatement: assertCommentCount(0, 0), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 0), + + SwitchCase(node) { + if (breakStatementCount === 0) { + assertCommentCount(0, 0)(node); + } else { + assertCommentCount(0, 1)(node); + } + breakStatementCount++; + }, + + BreakStatement: assertCommentCount(0, 0), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1368,14 +1584,18 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - SwitchCase: assertCommentCount(0, 1), - BreakStatement: assertCommentCount(0, 0), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + SwitchCase: assertCommentCount(0, 1), + BreakStatement: assertCommentCount(0, 0), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1394,22 +1614,26 @@ describe("SourceCode", () => { "};" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 0), - AssignmentExpression: assertCommentCount(0, 0), - MemberExpression: assertCommentCount(0, 0), - Identifier: assertCommentCount(0, 0), - FunctionExpression: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 0), - SwitchCase: assertCommentCount(0, 1), - ReturnStatement: assertCommentCount(0, 0), - CallExpression: assertCommentCount(0, 0), - BinaryExpression: assertCommentCount(0, 0), - Literal: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 0), + AssignmentExpression: assertCommentCount(0, 0), + MemberExpression: assertCommentCount(0, 0), + Identifier: assertCommentCount(0, 0), + FunctionExpression: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 0), + SwitchCase: assertCommentCount(0, 1), + ReturnStatement: assertCommentCount(0, 0), + CallExpression: assertCommentCount(0, 0), + BinaryExpression: assertCommentCount(0, 0), + Literal: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1420,7 +1644,13 @@ describe("SourceCode", () => { "/*another comment*/" ].join("\n"); - linter.defineRule("checker", () => ({ Program: assertCommentCount(2, 0) })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(2, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1433,10 +1663,14 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - BlockStatement: assertCommentCount(0, 2) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + BlockStatement: assertCommentCount(0, 2) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1449,11 +1683,15 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ClassDeclaration: assertCommentCount(0, 0), - ClassBody: assertCommentCount(0, 2) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ClassDeclaration: assertCommentCount(0, 0), + ClassBody: assertCommentCount(0, 2) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1466,11 +1704,15 @@ describe("SourceCode", () => { "})" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 0), - ObjectExpression: assertCommentCount(0, 2) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 0), + ObjectExpression: assertCommentCount(0, 2) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1483,11 +1725,15 @@ describe("SourceCode", () => { "]" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ExpressionStatement: assertCommentCount(0, 0), - ArrayExpression: assertCommentCount(0, 2) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ExpressionStatement: assertCommentCount(0, 0), + ArrayExpression: assertCommentCount(0, 2) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1500,11 +1746,15 @@ describe("SourceCode", () => { "}" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(0, 2), - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(0, 2), + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1519,21 +1769,27 @@ describe("SourceCode", () => { ].join("\n"); let varDeclCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(1, 2), - VariableDeclarator: node => { - if (varDeclCount === 0) { - assertCommentCount(0, 0)(node); - } else if (varDeclCount === 1) { - assertCommentCount(1, 0)(node); - } else { - assertCommentCount(1, 0)(node); - } - varDeclCount++; - }, - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(1, 2), + + VariableDeclarator(node) { + if (varDeclCount === 0) { + assertCommentCount(0, 0)(node); + } else if (varDeclCount === 1) { + assertCommentCount(1, 0)(node); + } else { + assertCommentCount(1, 0)(node); + } + varDeclCount++; + }, + + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1545,12 +1801,16 @@ describe("SourceCode", () => { " a;" ].join("\n"); - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - VariableDeclaration: assertCommentCount(0, 0), - VariableDeclarator: assertCommentCount(2, 0), - Identifier: assertCommentCount(0, 0) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + VariableDeclaration: assertCommentCount(0, 0), + VariableDeclarator: assertCommentCount(2, 0), + Identifier: assertCommentCount(0, 0) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1558,12 +1818,16 @@ describe("SourceCode", () => { it("should return attached comments between tokens to the correct nodes for empty function declarations", () => { const code = "/* 1 */ function /* 2 */ foo(/* 3 */) /* 4 */ { /* 5 */ } /* 6 */"; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - FunctionDeclaration: assertCommentCount(1, 1), - Identifier: assertCommentCount(1, 0), - BlockStatement: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + FunctionDeclaration: assertCommentCount(1, 1), + Identifier: assertCommentCount(1, 0), + BlockStatement: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1572,19 +1836,25 @@ describe("SourceCode", () => { const code = "/* 1 */ class /* 2 */ Foo /* 3 */ extends /* 4 */ Bar /* 5 */ { /* 6 */ } /* 7 */"; let idCount = 0; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - ClassDeclaration: assertCommentCount(1, 1), - Identifier: node => { - if (idCount === 0) { - assertCommentCount(1, 1)(node); - } else { - assertCommentCount(1, 1)(node); - } - idCount++; - }, - ClassBody: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + ClassDeclaration: assertCommentCount(1, 1), + + Identifier(node) { + if (idCount === 0) { + assertCommentCount(1, 1)(node); + } else { + assertCommentCount(1, 1)(node); + } + idCount++; + }, + + ClassBody: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); @@ -1592,11 +1862,15 @@ describe("SourceCode", () => { it("should return attached comments between tokens to the correct nodes for empty switch statements", () => { const code = "/* 1 */ switch /* 2 */ (/* 3 */ foo /* 4 */) /* 5 */ { /* 6 */ } /* 7 */"; - linter.defineRule("checker", () => ({ - Program: assertCommentCount(0, 0), - SwitchStatement: assertCommentCount(1, 6), - Identifier: assertCommentCount(1, 1) - })); + linter.defineRule("checker", { + create() { + return ({ + Program: assertCommentCount(0, 0), + SwitchStatement: assertCommentCount(1, 6), + Identifier: assertCommentCount(1, 1) + }); + } + }); assert.isEmpty(linter.verify(code, config)); }); diff --git a/tests/tools/eslint-fuzzer.js b/tests/tools/eslint-fuzzer.js index 1c894b99595b..da267de24c1d 100644 --- a/tests/tools/eslint-fuzzer.js +++ b/tests/tools/eslint-fuzzer.js @@ -15,7 +15,7 @@ const configRule = require("../../tools/config-rule"); //------------------------------------------------------------------------------ describe("eslint-fuzzer", function() { - let fakeRule, fuzz; + let fuzz; /* * These tests take awhile because isolating which rule caused an error requires running eslint up to hundreds of @@ -39,9 +39,6 @@ describe("eslint-fuzzer", function() { // Make sure the config generator generates a config for "test-fuzzer-rule" sinon.stub(configRule, "createCoreRuleConfigs").returns(Object.assign(realCoreRuleConfigs, { "test-fuzzer-rule": [2] })); - // Create a closure around `fakeRule` so that tests can reassign it and have the changes take effect. - linter.defineRule("test-fuzzer-rule", Object.assign(context => fakeRule(context), { meta: { fixable: "code" } })); - fuzz = require("../../tools/eslint-fuzzer"); }); @@ -52,12 +49,14 @@ describe("eslint-fuzzer", function() { describe("when running in crash-only mode", () => { describe("when a rule crashes on the given input", () => { it("should report the crash with a minimal config", () => { - fakeRule = context => ({ - Program() { - if (context.getSourceCode().text === "foo") { - throw CRASH_BUG; + linter.defineRule("test-fuzzer-rule", { + create: context => ({ + Program() { + if (context.getSourceCode().text === "foo") { + throw CRASH_BUG; + } } - } + }) }); const results = fuzz({ count: 1, codeGenerator: () => "foo", checkAutofixes: false, linter }); @@ -72,7 +71,7 @@ describe("eslint-fuzzer", function() { describe("when no rules crash", () => { it("should return an empty array", () => { - fakeRule = () => ({}); + linter.defineRule("test-fuzzer-rule", { create: () => ({}) }); assert.deepStrictEqual(fuzz({ count: 1, codeGenerator: () => "foo", checkAutofixes: false, linter }), []); }); @@ -91,12 +90,14 @@ describe("eslint-fuzzer", function() { describe("when a rule crashes on the given input", () => { it("should report the crash with a minimal config", () => { - fakeRule = context => ({ - Program() { - if (context.getSourceCode().text === "foo") { - throw CRASH_BUG; + linter.defineRule("test-fuzzer-rule", { + create: context => ({ + Program() { + if (context.getSourceCode().text === "foo") { + throw CRASH_BUG; + } } - } + }) }); const results = fuzz({ count: 1, codeGenerator: () => "foo", checkAutofixes: false, linter }); @@ -113,16 +114,19 @@ describe("eslint-fuzzer", function() { it("does not report any errors", () => { // Replaces programs that start with "foo" with "bar" - fakeRule = context => ({ - Program(node) { - if (context.getSourceCode().text === `foo ${disableFixableRulesComment}`) { - context.report({ - node, - message: "no foos allowed", - fix: fixer => fixer.replaceText(node, `bar ${disableFixableRulesComment}`) - }); + linter.defineRule("test-fuzzer-rule", { + meta: { fixable: "code" }, + create: context => ({ + Program(node) { + if (context.getSourceCode().text === `foo ${disableFixableRulesComment}`) { + context.report({ + node, + message: "no foos allowed", + fix: fixer => fixer.replaceText(node, `bar ${disableFixableRulesComment}`) + }); + } } - } + }) }); const results = fuzz({ @@ -145,18 +149,21 @@ describe("eslint-fuzzer", function() { it("reports an autofix error with a minimal config", () => { // Replaces programs that start with "foo" with invalid syntax - fakeRule = context => ({ - Program(node) { - const sourceCode = context.getSourceCode(); - - if (sourceCode.text === `foo ${disableFixableRulesComment}`) { - context.report({ - node, - message: "no foos allowed", - fix: fixer => fixer.replaceTextRange([0, sourceCode.text.length], INVALID_SYNTAX) - }); + linter.defineRule("test-fuzzer-rule", { + meta: { fixable: "code" }, + create: context => ({ + Program(node) { + const sourceCode = context.getSourceCode(); + + if (sourceCode.text === `foo ${disableFixableRulesComment}`) { + context.report({ + node, + message: "no foos allowed", + fix: fixer => fixer.replaceTextRange([0, sourceCode.text.length], INVALID_SYNTAX) + }); + } } - } + }) }); const results = fuzz({ @@ -186,23 +193,26 @@ describe("eslint-fuzzer", function() { const intermediateCode = `bar ${disableFixableRulesComment}`; // Replaces programs that start with "foo" with invalid syntax - fakeRule = context => ({ - Program(node) { - const sourceCode = context.getSourceCode(); - - if (sourceCode.text.startsWith("foo") || sourceCode.text === intermediateCode) { - context.report({ - node, - message: "no foos allowed", - fix(fixer) { - return fixer.replaceTextRange( - [0, sourceCode.text.length], - sourceCode.text === intermediateCode ? INVALID_SYNTAX : intermediateCode - ); - } - }); + linter.defineRule("test-fuzzer-rule", { + meta: { fixable: "code" }, + create: context => ({ + Program(node) { + const sourceCode = context.getSourceCode(); + + if (sourceCode.text.startsWith("foo") || sourceCode.text === intermediateCode) { + context.report({ + node, + message: "no foos allowed", + fix(fixer) { + return fixer.replaceTextRange( + [0, sourceCode.text.length], + sourceCode.text === intermediateCode ? INVALID_SYNTAX : intermediateCode + ); + } + }); + } } - } + }) }); const results = fuzz({ @@ -231,20 +241,23 @@ describe("eslint-fuzzer", function() { it("reports a crash error with a minimal config", () => { // Replaces programs that start with "foo" with invalid syntax - fakeRule = context => ({ - Program(node) { - const sourceCode = context.getSourceCode(); - - if (sourceCode.text.startsWith("foo")) { - context.report({ - node, - message: "no foos allowed", - fix: fixer => fixer.replaceText(node, "bar") - }); - } else if (sourceCode.text === `bar ${disableFixableRulesComment}`) { - throw CRASH_BUG; + linter.defineRule("test-fuzzer-rule", { + meta: { fixable: "code" }, + create: context => ({ + Program(node) { + const sourceCode = context.getSourceCode(); + + if (sourceCode.text.startsWith("foo")) { + context.report({ + node, + message: "no foos allowed", + fix: fixer => fixer.replaceText(node, "bar") + }); + } else if (sourceCode.text === `bar ${disableFixableRulesComment}`) { + throw CRASH_BUG; + } } - } + }) }); const results = fuzz({ diff --git a/tools/fuzzer-runner.js b/tools/fuzzer-runner.js index b056c701f9eb..805cc0252584 100644 --- a/tools/fuzzer-runner.js +++ b/tools/fuzzer-runner.js @@ -58,7 +58,7 @@ function run({ amount = 300, fuzzBrokenAutofixes = true } = {}) { linter, count: crashTestCount, checkAutofixes: false, - progressCallback: elapsedErrors => { + progressCallback(elapsedErrors) { progressBar.tick(1, { elapsedErrors }); progressBar.render(); } @@ -68,7 +68,7 @@ function run({ amount = 300, fuzzBrokenAutofixes = true } = {}) { linter, count: autofixTestCount, checkAutofixes: true, - progressCallback: elapsedErrors => { + progressCallback(elapsedErrors) { progressBar.tick(ESTIMATED_CRASH_AUTOFIX_PERFORMANCE_RATIO, { elapsedErrors: crashTestResults.length + elapsedErrors }); progressBar.render(); } From ad44344ef6fdeac7217eb83bc54a230382c0da5e Mon Sep 17 00:00:00 2001 From: Ben Perlmutter <57849986+bpmutter@users.noreply.github.com> Date: Fri, 9 Dec 2022 14:16:54 -0500 Subject: [PATCH 25/29] docs: CLI documentation standardization (#16563) * docs: CLI intro + copy tweaks * docs: CLI docs standardization Fixes #16475 * continue on standardization * finish first pass of formatting * finish adding examples * fixes * copy edits * Apply suggestions from code review Co-authored-by: Milos Djermanovic Co-authored-by: Amaresh S M * put aliases in the headers * fix --ext description * update --rulesdir docs per feedback * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas Co-authored-by: Milos Djermanovic * update help text * readd cli help output * clarify --ext description * clarify using --rule w --no-eslintrc * implement MD and NZ feedback * Apply suggestions from code review Co-authored-by: Milos Djermanovic Co-authored-by: Nicholas C. Zakas * clarify formatter example comments * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas * standardize all headings to Title Case * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas Co-authored-by: Milos Djermanovic Co-authored-by: Amaresh S M Co-authored-by: Nicholas C. Zakas --- docs/src/_data/links.json | 2 +- docs/src/user-guide/command-line-interface.md | 481 ++++++++++++------ lib/options.js | 10 +- 3 files changed, 333 insertions(+), 160 deletions(-) diff --git a/docs/src/_data/links.json b/docs/src/_data/links.json index d9b297332167..870744392e73 100644 --- a/docs/src/_data/links.json +++ b/docs/src/_data/links.json @@ -14,7 +14,7 @@ "team": "/team", "configuring": "https://eslint.org/docs/user-guide/configuring/", - "fixProblems": "https://eslint.org/docs/user-guide/command-line-interface#fixing-problems", + "fixProblems": "https://eslint.org/docs/user-guide/command-line-interface#fix-problems", "donate": "/donate", "openCollective": "https://opencollective.com/eslint", diff --git a/docs/src/user-guide/command-line-interface.md b/docs/src/user-guide/command-line-interface.md index 8668fa813073..fa0ae714c6c0 100644 --- a/docs/src/user-guide/command-line-interface.md +++ b/docs/src/user-guide/command-line-interface.md @@ -38,11 +38,23 @@ npx eslint "lib/**" **Note:** You can also use alternative package managers such as [Yarn](https://yarnpkg.com/) or [pnpm](https://pnpm.io/) to run ESLint. Please refer to your package manager's documentation for the correct syntax. +## Pass Multiple Values to an Option + +Options that accept multiple values can be specified by repeating the option or with a comma-delimited list (other than [`--ignore-pattern`](#--ignore-pattern), which does not allow the second style). + +Examples of options that accept multiple values: + +```shell +npx eslint --ext .jsx --ext .js lib/ +# OR +npx eslint --ext .jsx,.js lib/ +``` + ## Options -The command line utility has several options. You can view the options by running `npx eslint -h`. +You can view all the CLI options by running `npx eslint -h`. -```text +```txt eslint [options] file.js [file.js] [dir] Basic configuration: @@ -55,26 +67,26 @@ Basic configuration: --parser-options Object Specify parser options --resolve-plugins-relative-to path::String A folder where plugins should be resolved from, CWD by default -Specifying rules and plugins: +Specify rules and plugins: --plugin [String] Specify plugins --rule Object Specify rules --rulesdir [path::String] Load additional rules from this directory. Deprecated: Use rules from plugins -Fixing problems: +Fix problems: --fix Automatically fix problems --fix-dry-run Automatically fix problems without saving the changes to the file system --fix-type Array Specify the types of fixes to apply (directive, problem, suggestion, layout) -Ignoring files: +Ignore files: --ignore-path path::String Specify path of ignore file --no-ignore Disable use of ignore files and patterns --ignore-pattern [String] Pattern of files to ignore (in addition to those in .eslintignore) -Using stdin: +Use stdin: --stdin Lint code provided on - default: false --stdin-filename String Specify filename to process STDIN as -Handling warnings: +Handle warnings: --quiet Report errors only - default: false --max-warnings Int Number of warnings to trigger nonzero exit code - default: -1 @@ -104,23 +116,15 @@ Miscellaneous: --print-config path::String Print the configuration for the given file ``` -Options that accept array values can be specified by repeating the option or with a comma-delimited list (other than `--ignore-pattern` which does not allow the second style). - -Example: - -```shell -npx eslint --ext .jsx --ext .js lib/ -# OR -npx eslint --ext .jsx,.js lib/ -``` - -### Basic configuration +### Basic Configuration #### `--no-eslintrc` Disables use of configuration from `.eslintrc.*` and `package.json` files. -Example: +* **Argument Type**: No argument. + +##### `--no-eslintrc` example ```shell npx eslint --no-eslintrc file.js @@ -130,7 +134,10 @@ npx eslint --no-eslintrc file.js This option allows you to specify an additional configuration file for ESLint (see [Configuring ESLint](configuring/) for more). -Example: +* **Argument Type**: String. Path to file. +* **Multiple Arguments**: No + +##### `-c`, `--config` example ```shell npx eslint -c ~/my-eslint.json file.js @@ -142,9 +149,14 @@ If `.eslintrc.*` and/or `package.json` files are also used for configuration (i. #### `--env` -This option enables specific environments. Details about the global variables defined by each environment are available on the [Specifying Environments](configuring/language-options#specifying-environments) documentation. This option only enables environments; it does not disable environments set in other configuration files. To specify multiple environments, separate them using commas, or use the option multiple times. +This option enables specific environments. + +* **Argument Type**: String. One of the available environments. +* **Multiple Arguments**: Yes + +Details about the global variables defined by each environment are available in the [Specifying Environments](configuring/language-options#specifying-environments) documentation. This option only enables environments. It does not disable environments set in other configuration files. To specify multiple environments, separate them using commas, or use the option multiple times. -Examples: +##### `--env` example ```shell npx eslint --env browser,node file.js @@ -154,9 +166,14 @@ npx eslint --env browser --env node file.js #### `--ext` This option allows you to specify which file extensions ESLint uses when searching for target files in the directories you specify. -By default, ESLint lints `*.js` files and the files that match the `overrides` entries of your configuration. -Examples: +* **Argument Type**: String. File extension. +* **Multiple Arguments**: Yes +* **Default Value**: `.js` and the files that match the `overrides` entries of your configuration. + +`--ext` is only used when the the patterns to lint are directories. If you use glob patterns or file names, then `--ext` is ignored. For example, `npx eslint "lib/*" --ext .js` matches all files within the `lib/` directory, regardless of extension. + +##### `--ext` example ```shell # Use only .ts extension @@ -169,15 +186,14 @@ npx eslint . --ext .js --ext .ts npx eslint . --ext .js,.ts ``` -**Note:** `--ext` is only used when the arguments are directories. If you use glob patterns or file names, then `--ext` is ignored. - -For example, `npx eslint lib/* --ext .js` matches all files within the `lib/` directory, regardless of extension. - #### `--global` -This option defines global variables so that they are not flagged as `undefined` by the `no-undef` rule. Any specified global variables are assumed to be read-only by default, but appending `:true` to a variable's name ensures that `no-undef` also allows writes. To specify multiple global variables, separate them using commas, or use the option multiple times. +This option defines global variables so that they are not flagged as undefined by the [`no-undef`](../rules/no-undef) rule. -Examples: +* **Argument Type**: String. Name of the global variable. Any specified global variables are assumed to be read-only by default, but appending `:true` to a variable's name ensures that `no-undef` also allows writes. +* **Multiple Arguments**: Yes + +##### `--global` example ```shell npx eslint --global require,exports:true file.js @@ -186,35 +202,67 @@ npx eslint --global require --global exports:true #### `--parser` -This option allows you to specify a parser to be used by ESLint. By default, `espree` is used. +This option allows you to specify a parser to be used by ESLint. + +* **Argument Type**: String. Parser to be used by ESLint. +* **Multiple Arguments**: No +* **Default Value**: `espree` + +##### `--parser` example + +```shell +# Use TypeScript ESLint parser +npx eslint --parser @typescript-eslint/parser file.ts +``` #### `--parser-options` -This option allows you to specify parser options to be used by ESLint. Note that the available parser options are determined by the parser being used. +This option allows you to specify parser options to be used by ESLint. The available parser options are determined by the parser being used. + +* **Argument Type**: Key/value pair separated by colon (`:`). +* **Multiple Arguments**: Yes -Examples: +##### `--parser-options` example ```shell -echo '3 ** 4' | npx eslint --stdin --parser-options=ecmaVersion:6 # fails with a parsing error -echo '3 ** 4' | npx eslint --stdin --parser-options=ecmaVersion:7 # succeeds, yay! +echo '3 ** 4' | npx eslint --stdin --parser-options ecmaVersion:6 # fails with a parsing error +echo '3 ** 4' | npx eslint --stdin --parser-options ecmaVersion:7 # succeeds, yay! ``` #### `--resolve-plugins-relative-to` -Changes the folder where plugins are resolved from. By default, plugins are resolved from the current working directory. This option should be used when plugins were installed by someone other than the end user. It should be set to the project directory of the project that has a dependency on the necessary plugins. For example: +Changes the directory where plugins are resolved from. + +* **Argument Type**: String. Path to directory. +* **Multiple Arguments**: No +* **Default Value**: By default, plugins are resolved from the directory in which your configuration file is found. + +This option should be used when plugins were installed by someone other than the end user. It should be set to the project directory of the project that has a dependency on the necessary plugins. + +For example: * When using a config file that is located outside of the current project (with the `--config` flag), if the config uses plugins which are installed locally to itself, `--resolve-plugins-relative-to` should be set to the directory containing the config file. * If an integration has dependencies on ESLint and a set of plugins, and the tool invokes ESLint on behalf of the user with a preset configuration, the tool should set `--resolve-plugins-relative-to` to the top-level directory of the tool. -### Specifying rules and plugins +##### `--resolve-plugins-relative-to` example + +```shell +npx eslint --config ~/personal-eslintrc.js \ +--resolve-plugins-relative-to /usr/local/lib/ +``` + +### Specify Rules and Plugins #### `--plugin` -This option specifies a plugin to load. You can omit the prefix `eslint-plugin-` from the plugin name. +This option specifies a plugin to load. + +* **Argument Type**: String. Plugin name. You can optionally omit the prefix `eslint-plugin-` from the plugin name. +* **Multiple Arguments**: Yes Before using the plugin, you have to install it using npm. -Examples: +##### `--plugin` example ```shell npx eslint --plugin jquery file.js @@ -223,16 +271,26 @@ npx eslint --plugin eslint-plugin-mocha file.js #### `--rule` -This option specifies the rules to be used. These rules are merged with any rules specified with configuration files. (You can use `--no-eslintrc` to change that behavior.) To define multiple rules, separate them using commas, or use the option multiple times. The [levn](https://github.com/gkz/levn#levn--) format is used for specifying the rules. +This option specifies the rules to be used. + +* **Argument Type**: Rules and their configuration specified with [levn](https://github.com/gkz/levn#levn--) format. +* **Multiple Arguments**: Yes -If the rule is defined within a plugin, you have to prefix the rule ID with the plugin name and a `/`. +These rules are merged with any rules specified with configuration files. If the rule is defined in a plugin, you have to prefix the rule ID with the plugin name and a `/`. -Examples: +To ignore rules in `.eslintrc` configuration files and only run rules specified in the command line, use the `--rules` flag in combination with the [`--no-eslintrc`](#--no-eslintrc) flag. + +##### `--rule` example ```shell +# Apply single rule npx eslint --rule 'quotes: [error, double]' +# Apply multiple rules npx eslint --rule 'guard-for-in: error' --rule 'brace-style: [error, 1tbs]' +# Apply rule from jquery plugin npx eslint --rule 'jquery/dollar-sign: error' +# Only apply rule from the command line +npx eslint --rule 'quotes: [error, double]' --no-eslintrc ``` #### `--rulesdir` @@ -241,53 +299,69 @@ npx eslint --rule 'jquery/dollar-sign: error' This option allows you to specify another directory from which to load rules files. This allows you to dynamically load new rules at run time. This is useful when you have custom rules that aren't suitable for being bundled with ESLint. -Example: +* **Argument Type**: String. Path to directory. The rules in your custom rules directory must follow the same format as bundled rules to work properly. +* **Multiple Arguments**: Yes. -```shell -npx eslint --rulesdir my-rules/ file.js -``` +Note that, as with core rules and plugin rules, you still need to enable the rules in configuration or via the `--rule` CLI option in order to actually run those rules during linting. Specifying a rules directory with `--rulesdir` does not automatically enable the rules within that directory. -The rules in your custom rules directory must follow the same format as bundled rules to work properly. You can also specify multiple locations for custom rules by including multiple `--rulesdir` options: +##### `--rulesdir` example ```shell +npx eslint --rulesdir my-rules/ file.js npx eslint --rulesdir my-rules/ --rulesdir my-other-rules/ file.js ``` -Note that, as with core rules and plugin rules, you still need to enable the rules in configuration or via the `--rule` CLI option in order to actually run those rules during linting. Specifying a rules directory with `--rulesdir` does not automatically enable the rules within that directory. - -### Fixing problems +### Fix Problems #### `--fix` -This option instructs ESLint to try to fix as many issues as possible. The fixes are made to the actual files themselves and only the remaining unfixed issues are output. Not all problems are fixable using this option, and the option does not work in these situations: +This option instructs ESLint to try to fix as many issues as possible. The fixes are made to the actual files themselves and only the remaining unfixed issues are output. + +* **Argument Type**: No argument. + +Not all problems are fixable using this option, and the option does not work in these situations: 1. This option throws an error when code is piped to ESLint. 1. This option has no effect on code that uses a processor, unless the processor opts into allowing autofixes. If you want to fix code from `stdin` or otherwise want to get the fixes without actually writing them to the file, use the [`--fix-dry-run`](#--fix-dry-run) option. +##### `--fix` example + +```shell +npx eslint --fix file.js +``` + #### `--fix-dry-run` -This option has the same effect as `--fix` with one difference: the fixes are not saved to the file system. This makes it possible to fix code from `stdin` (when used with the `--stdin` flag). +This option has the same effect as `--fix` with the difference that the fixes are not saved to the file system. Because the default formatter does not output the fixed code, you'll have to use another formatter (e.g. `--format json`) to get the fixes. -Because the default formatter does not output the fixed code, you'll have to use another one (e.g. `json`) to get the fixes. Here's an example of this pattern: +* **Argument Type**: No argument. -```shell -getSomeText | npx eslint --stdin --fix-dry-run --format=json -``` +This makes it possible to fix code from `stdin` when used with the `--stdin` flag. This flag can be useful for integrations (e.g. editor plugins) which need to autofix text from the command line without saving it to the filesystem. +##### `--fix-dry-run` example + +```shell +getSomeText | npx eslint --stdin --fix-dry-run --format json +``` + #### `--fix-type` -This option allows you to specify the type of fixes to apply when using either `--fix` or `--fix-dry-run`. The four types of fixes are: +This option allows you to specify the type of fixes to apply when using either `--fix` or `--fix-dry-run`. -1. `problem` - fix potential errors in the code -1. `suggestion` - apply fixes to the code that improve it -1. `layout` - apply fixes that do not change the program structure (AST) -1. `directive` - apply fixes to inline directives such as `// eslint-disable` +* **Argument Type**: String. One of the following fix types: + 1. `problem` - fix potential errors in the code + 1. `suggestion` - apply fixes to the code that improve it + 1. `layout` - apply fixes that do not change the program structure (AST) + 1. `directive` - apply fixes to inline directives such as `// eslint-disable` +* **Multiple Arguments**: Yes -You can specify one or more fix type on the command line. Here are some examples: +This option is helpful if you are using another program to format your code, but you would still like ESLint to apply other types of fixes. + +##### `--fix-type` example ```shell npx eslint --fix --fix-type suggestion . @@ -295,17 +369,19 @@ npx eslint --fix --fix-type suggestion --fix-type problem . npx eslint --fix --fix-type suggestion,layout . ``` -This option is helpful if you are using another program to format your code but you would still like ESLint to apply other types of fixes. - -### Ignoring files +### Ignore Files #### `--ignore-path` -**Note:** `--ignore-path` is not supported when using flat config (`eslint.config.js`). +This option allows you to specify the file to use as your `.eslintignore`. -This option allows you to specify the file to use as your `.eslintignore`. By default, ESLint looks in the current working directory for `.eslintignore`. You can override this behavior by providing a path to a different file. +* **Argument Type**: String. Path to file. +* **Multiple Arguments**: No +* **Default Value**: By default, ESLint looks for `.eslintignore` in the current working directory. -Example: +**Note:** `--ignore-path` is not supported when using [flat configuration](./configuring/configuration-files-new) (`eslint.config.js`). + +##### `--ignore-path` example ```shell npx eslint --ignore-path tmp/.eslintignore file.js @@ -314,9 +390,11 @@ npx eslint --ignore-path .gitignore file.js #### `--no-ignore` -Disables excluding of files from `.eslintignore`, `--ignore-path`, `--ignore-pattern`, and `ignorePatterns` property in config files. +Disables excluding of files from `.eslintignore` files, `--ignore-path` flags, `--ignore-pattern` flags, and the `ignorePatterns` property in config files. + +* **Argument Type**: No argument. -Example: +##### `--no-ignore` example ```shell npx eslint --no-ignore file.js @@ -324,21 +402,26 @@ npx eslint --no-ignore file.js #### `--ignore-pattern` -This option allows you to specify patterns of files to ignore (in addition to those in `.eslintignore`). You can repeat the option to provide multiple patterns. The supported syntax is the same as for `.eslintignore` [files](configuring/ignoring-code#the-eslintignore-file), which use the same patterns as the `.gitignore` [specification](https://git-scm.com/docs/gitignore). You should quote your patterns in order to avoid shell interpretation of glob patterns. +This option allows you to specify patterns of files to ignore (in addition to those in `.eslintignore`). + +* **Argument Type**: String. The supported syntax is the same as for [`.eslintignore` files](configuring/ignoring-code#the-eslintignore-file), which use the same patterns as the [`.gitignore` specification](https://git-scm.com/docs/gitignore). You should quote your patterns in order to avoid shell interpretation of glob patterns. +* **Multiple Arguments**: Yes -Example: +##### `--ignore-pattern` example ```shell -npx eslint --ignore-pattern '/lib/' --ignore-pattern '/src/vendor/*' . +npx eslint --ignore-pattern "/lib/" --ignore-pattern "/src/vendor/*" . ``` -### Using stdin +### Use stdin #### `--stdin` This option tells ESLint to read and lint source code from STDIN instead of from files. You can use this to pipe code to ESLint. -Example: +* **Argument Type**: No argument. + +##### `--stdin` example ```shell cat myfile.js | npx eslint --stdin @@ -346,21 +429,28 @@ cat myfile.js | npx eslint --stdin #### `--stdin-filename` -This option allows you to specify a filename to process STDIN as. This is useful when processing files from STDIN and you have rules which depend on the filename. +This option allows you to specify a filename to process STDIN as. + +* **Argument Type**: String. Path to file. +* **Multiple Arguments**: No -Example +This is useful when processing files from STDIN and you have rules which depend on the filename. + +##### `--stdin-filename` example ```shell -cat myfile.js | npx eslint --stdin --stdin-filename=myfile.js +cat myfile.js | npx eslint --stdin --stdin-filename myfile.js ``` -### Handling warnings +### Handle Warnings #### `--quiet` This option allows you to disable reporting on warnings. If you enable this option, only errors are reported by ESLint. -Example: +* **Argument Type**: No argument. + +##### `--quiet` example ```shell npx eslint --quiet file.js @@ -370,9 +460,12 @@ npx eslint --quiet file.js This option allows you to specify a warning threshold, which can be used to force ESLint to exit with an error status if there are too many warning-level rule violations in your project. -Normally, if ESLint runs and finds no errors (only warnings), it exits with a success exit status. However, if `--max-warnings` is specified and the total warning count is greater than the specified threshold, ESLint exits with an error status. To prevent this behavior, omit this option or specify a threshold of `-1`. +* **Argument Type**: Integer. The maximum number of warnings to allow. To prevent this behavior, do not use this option or specify `-1` as the argument. +* **Multiple Arguments**: No -Example: +Normally, if ESLint runs and finds no errors (only warnings), it exits with a success exit status. However, if `--max-warnings` is specified and the total warning count is greater than the specified threshold, ESLint exits with an error status. + +##### `--max-warnings` example ```shell npx eslint --max-warnings 10 file.js @@ -382,84 +475,86 @@ npx eslint --max-warnings 10 file.js #### `-o`, `--output-file` -Enable report to be written to a file. +Write the output of linting results to a specified file. + +* **Argument Type**: String. Path to file. +* **Multiple Arguments**: No -Example: +##### `-o`, `--output-file` example ```shell npx eslint -o ./test/test.html ``` -When specified, the given format is output into the provided file name. - #### `-f`, `--format` -This option specifies the output format for the console. Possible formats are: +This option specifies the output format for the console. + +* **Argument Type**: String. One of the [built-in formatters](formatters/) or a custom formatter. +* **Multiple Arguments**: No +* **Default Value**: [`stylish`](formatters/#stylish) -* [checkstyle](formatters/#checkstyle) -* [compact](formatters/#compact) -* [html](formatters/#html) -* [jslint-xml](formatters/#jslint-xml) -* [json](formatters/#json) -* [junit](formatters/#junit) -* [stylish](formatters/#stylish) (the default) -* [tap](formatters/#tap) -* [unix](formatters/#unix) -* [visualstudio](formatters/#visualstudio) +If you are using a custom formatter defined in a local file, you can specify the path to the custom formatter file. -Example: +An npm-installed formatter is resolved with or without `eslint-formatter-` prefix. + +When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so: ```shell -npx eslint -f compact file.js +# Saves the output into the `results.txt` file. +npx eslint -f compact file.js > results.txt ``` -You can also use a custom formatter from the command line by specifying a path to the custom formatter file. +##### `-f`, `--format` example -Example: +Use the built-in `compact` formatter: ```shell -npx eslint -f ./customformat.js file.js +npx eslint --format compact file.js ``` -An npm-installed formatter is resolved with or without `eslint-formatter-` prefix. +Use a local custom formatter: + +```shell +npx eslint -f ./customformat.js file.js +``` -Example: +Use an npm-installed formatter: ```shell npm install eslint-formatter-pretty +# Then run one of the following commands npx eslint -f pretty file.js - -// equivalent: +# or alternatively npx eslint -f eslint-formatter-pretty file.js ``` -When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so: - -```shell -npx eslint -f compact file.js > results.txt -``` +#### `--color` and `--no-color` -This saves the output into the `results.txt` file. +These options force the enabling/disabling of colorized output. -#### `--color`, `--no-color` +* **Argument Type**: No argument. -This option forces the enabling/disabling of colorized output. You can use this to override the default behavior, which is to enable colorized output unless no TTY is detected, such as when piping `eslint` through `cat` or `less`. +You can use these options to override the default behavior, which is to enable colorized output unless no TTY is detected, such as when piping `eslint` through `cat` or `less`. -Examples: +##### `--color` and `--no-color` example ```shell npx eslint --color file.js | cat npx eslint --no-color file.js ``` -### Inline configuration comments +### Inline Configuration Comments #### `--no-inline-config` This option prevents inline comments like `/*eslint-disable*/` or -`/*global foo*/` from having any effect. This allows you to set an ESLint -config without files modifying it. All inline config comments are ignored, e.g.: +`/*global foo*/` from having any effect. + +* **Argument Type**: No argument. + +This allows you to set an ESLint config without files modifying it. All inline config comments are ignored, such as: * `/*eslint-disable*/` * `/*eslint-enable*/` @@ -469,7 +564,7 @@ config without files modifying it. All inline config comments are ignored, e.g.: * `// eslint-disable-line` * `// eslint-disable-next-line` -Example: +##### `--no-inline-config` example ```shell npx eslint --no-inline-config file.js @@ -477,11 +572,19 @@ npx eslint --no-inline-config file.js #### `--report-unused-disable-directives` -This option causes ESLint to report directive comments like `// eslint-disable-line` when no errors would have been reported on that line anyway. This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` comments which are no longer applicable. +This option causes ESLint to report directive comments like `// eslint-disable-line` when no errors would have been reported on that line anyway. + +* **Argument Type**: No argument. + +This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` comments which are no longer applicable. + +::: warning +When using this option, it is possible that new errors start being reported whenever ESLint or custom rules are upgraded. -**Warning**: When using this option, it is possible that new errors start being reported whenever ESLint or custom rules are upgraded. For example, suppose a rule has a bug that causes it to report a false positive, and an `eslint-disable` comment is added to suppress the incorrect report. If the bug is then fixed in a patch release of ESLint, the `eslint-disable` comment becomes unused since ESLint is no longer generating an incorrect report. This results in a new reported error for the unused directive if the `report-unused-disable-directives` option is used. +For example, suppose a rule has a bug that causes it to report a false positive, and an `eslint-disable` comment is added to suppress the incorrect report. If the bug is then fixed in a patch release of ESLint, the `eslint-disable` comment becomes unused since ESLint is no longer generating an incorrect report. This results in a new reported error for the unused directive if the `report-unused-disable-directives` option is used. +::: -Example: +##### `--report-unused-disable-directives` example ```shell npx eslint --report-unused-disable-directives file.js @@ -491,25 +594,38 @@ npx eslint --report-unused-disable-directives file.js #### `--cache` -Store the info about processed files in order to only operate on the changed ones. The cache is stored in `.eslintcache` by default. Enabling this option can dramatically improve ESLint's running time by ensuring that only changed files are linted. +Store the info about processed files in order to only operate on the changed ones. Enabling this option can dramatically improve ESLint's run time performance by ensuring that only changed files are linted. +The cache is stored in `.eslintcache` by default. -**Note:** If you run ESLint with `--cache` and then run ESLint without `--cache`, the `.eslintcache` file will be deleted. This is necessary because the results of the lint might change and make `.eslintcache` invalid. If you want to control when the cache file is deleted, then use `--cache-location` to specify an alternate location for the cache file. +* **Argument Type**: No argument. -**Note:** Autofixed files are not placed in the cache. Subsequent linting that does not trigger an autofix will place it in the cache. +If you run ESLint with `--cache` and then run ESLint without `--cache`, the `.eslintcache` file will be deleted. This is necessary because the results of the lint might change and make `.eslintcache` invalid. If you want to control when the cache file is deleted, then use `--cache-location` to specify an alternate location for the cache file. + +Autofixed files are not placed in the cache. Subsequent linting that does not trigger an autofix will place it in the cache. + +##### `--cache` example + +```shell +npx eslint --cache file.js +``` #### `--cache-file` -Path to the cache file. If no file is specified, `.eslintcache` is used. The file is created in the directory where the `eslint` command is executed. **Deprecated**: Use `--cache-location` instead. +**Deprecated**: Use `--cache-location` instead. + +Path to the cache file. If none specified `.eslintcache` is used. The file is created in the directory where the `eslint` command is executed. #### `--cache-location` -Path to the cache location. Can be a file or a directory. If no location is specified, `.eslintcache` is used. In that case, the file is created in the directory where the `eslint` command is executed. +Specify the path to the cache location. Can be a file or a directory. -If a directory is specified, a cache file is created inside the specified folder. The name of the file is based on the hash of the current working directory (CWD). e.g.: `.cache_hashOfCWD` +* **Argument Type**: String. Path to file or directory. If a directory is specified, a cache file is created inside the specified folder. The name of the file is based on the hash of the current working directory, e.g.: `.cache_hashOfCWD`. +* **Multiple Arguments**: No +* **Default Value**: If no location is specified, `.eslintcache` is used. The file is created in the directory where the `eslint` command is executed. -**Important note:** If the directory for the cache does not exist make sure you add a trailing `/` on \*nix systems or `\` in windows. Otherwise the path is assumed to be a file. +If the directory for the cache does not exist make sure you add a trailing `/` on \*nix systems or `\` on Windows. Otherwise, the path is assumed to be a file. -Example: +##### `--cache-location` example ```shell npx eslint "src/**/*.js" --cache --cache-location "/Users/user/.eslintcache/" @@ -517,11 +633,17 @@ npx eslint "src/**/*.js" --cache --cache-location "/Users/user/.eslintcache/" #### `--cache-strategy` -Strategy for the cache to use for detecting changed files. Can be either `metadata` or `content`. If no strategy is specified, `metadata` is used. +Strategy for the cache to use for detecting changed files. + +* **Argument Type**: String. One of the following values: + 1. `metadata` + 1. `content` +* **Multiple Arguments**: No +* **Default Value**: `metadata` -The `content` strategy can be useful in cases where the modification time of your files changes even if their contents have not. For example, this can happen during git operations like git clone because git does not track file modification time. +The `content` strategy can be useful in cases where the modification time of your files changes even if their contents have not. For example, this can happen during git operations like `git clone` because git does not track file modification time. -Example: +##### `--cache-strategy` example ```shell npx eslint "src/**/*.js" --cache --cache-strategy content @@ -531,60 +653,111 @@ npx eslint "src/**/*.js" --cache --cache-strategy content #### `--init` -This option runs `npm init @eslint/config` to start the config initialization wizard. It's designed to help new users quickly create an `.eslintrc.js` file by answering a few questions and choosing a popular style guide. +This option runs `npm init @eslint/config` to start the config initialization wizard. It's designed to help new users quickly create an `.eslintrc` file by answering a few questions. When you use this flag, the CLI does not perform linting. + +* **Argument Type**: No argument. The resulting configuration file is created in the current directory. +##### `--init` example + +```shell +npx eslint --init +``` + #### `--env-info` -This option outputs information about the execution environment, including the version of Node, npm, and local and global installations of ESLint. The ESLint team may ask for this information to help solve bugs. +This option outputs information about the execution environment, including the version of Node.js, npm, and local and global installations of ESLint. + +* **Argument Type**: No argument. + +The ESLint team may ask for this information to help solve bugs. When you use this flag, the CLI does not perform linting. + +##### `--env-info` example + +```shell +npx eslint --env-info +``` #### `--no-error-on-unmatched-pattern` This option prevents errors when a quoted glob pattern or `--ext` is unmatched. This does not prevent errors when your shell can't match a glob. +* **Argument Type**: No argument. + +##### `--no-error-on-unmatched-pattern` example + +```shell +npx eslint --no-error-on-unmatched-pattern --ext .ts "lib/*" +``` + #### `--exit-on-fatal-error` -This option causes ESLint to exit with exit code 2 if one or more fatal parsing errors occur. Without this option, fatal parsing errors are reported as rule violations. +This option causes ESLint to exit with exit code 2 if one or more fatal parsing errors occur. Without this option, ESLint reports fatal parsing errors as rule violations. + +* **Argument Type**: No argument. + +##### `--exit-on-fatal-error` example + +```shell +npx eslint --exit-on-fatal-error file.js +``` #### `--debug` -This option outputs debugging information to the console. This information is useful when you're seeing a problem and having a hard time pinpointing it. The ESLint team may ask for this debugging information to help solve bugs. -Add this flag to an ESLint command line invocation in order to get extra debug information as the command is run (e.g. `npx eslint --debug test.js` and `npx eslint test.js --debug` are equivalent) +This option outputs debugging information to the console. Add this flag to an ESLint command line invocation in order to get extra debugging information while the command runs. -#### `-h`, `--help` +* **Argument Type**: No argument. -This option outputs the help menu, displaying all of the available options. All other options are ignored when this is present. +This information is useful when you're seeing a problem and having a hard time pinpointing it. The ESLint team may ask for this debugging information to help solve bugs. -#### `-v`, `--version` +##### `--debug` example -This option outputs the current ESLint version onto the console. All other options are ignored when this is present. +```shell +npx eslint --debug test.js +``` -#### `--print-config` +#### `-h`, `--help` -This option outputs the configuration to be used for the file passed. When present, no linting is performed and only config-related options are valid. +This option outputs the help menu, displaying all of the available options. All other options are ignored when this is present. When you use this flag, the CLI does not perform linting. -Example: +* **Argument Type**: No argument. + +##### `-h`, `--help` example ```shell -npx eslint --print-config file.js +npx eslint --help ``` -## Ignoring files from linting +#### `-v`, `--version` + +This option outputs the current ESLint version onto the console. All other options are ignored when this is present. When you use this flag, the CLI does not perform linting. -ESLint supports `.eslintignore` files to exclude files from the linting process when ESLint operates on a directory. Files given as individual CLI arguments are exempt from exclusion. The `.eslintignore` file is a plain text file containing one pattern per line. It can be located in any of the target directory's ancestors; it affects files in its containing directory as well as all sub-directories. Here's a simple example of a `.eslintignore` file: +* **Argument Type**: No argument. -```text -temp.js -**/vendor/*.js +##### `-v`, `--version` example + +```shell +npx eslint --version ``` -A more detailed breakdown of supported patterns and directories ESLint ignores by default can be found in [Ignoring Code](configuring/ignoring-code). +#### `--print-config` + +This option outputs the configuration to be used for the file passed. When present, no linting is performed and only config-related options are valid. When you use this flag, the CLI does not perform linting. + +* **Argument Type**: String. Path to file. +* **Multiple Arguments**: No + +##### `--print-config` example + +```shell +npx eslint --print-config file.js +``` -## Exit codes +## Exit Codes When linting files, ESLint exits with one of the following exit codes: -* `0`: Linting was successful and there are no linting errors. If the `--max-warnings` flag is set to `n`, the number of linting warnings is at most `n`. +* `0`: Linting was successful and there are no linting errors. If the [`--max-warnings`](#--max-warnings) flag is set to `n`, the number of linting warnings is at most `n`. * `1`: Linting was successful and there is at least one linting error, or there are more linting warnings than allowed by the `--max-warnings` option. * `2`: Linting was unsuccessful due to a configuration problem or an internal error. diff --git a/lib/options.js b/lib/options.js index c43aad93276a..2bc4018afb5d 100644 --- a/lib/options.js +++ b/lib/options.js @@ -177,7 +177,7 @@ module.exports = function(usingFlatConfig) { }, resolvePluginsFlag, { - heading: "Specifying rules and plugins" + heading: "Specify Rules and Plugins" }, { option: "plugin", @@ -191,7 +191,7 @@ module.exports = function(usingFlatConfig) { }, rulesDirFlag, { - heading: "Fixing problems" + heading: "Fix Problems" }, { option: "fix", @@ -211,7 +211,7 @@ module.exports = function(usingFlatConfig) { description: "Specify the types of fixes to apply (directive, problem, suggestion, layout)" }, { - heading: "Ignoring files" + heading: "Ignore Files" }, ignorePathFlag, { @@ -229,7 +229,7 @@ module.exports = function(usingFlatConfig) { }] }, { - heading: "Using stdin" + heading: "Use stdin" }, { option: "stdin", @@ -243,7 +243,7 @@ module.exports = function(usingFlatConfig) { description: "Specify filename to process STDIN as" }, { - heading: "Handling warnings" + heading: "Handle Warnings" }, { option: "quiet", From 7190d98ff40023f24b0c6a98319ae8a82c99ff5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20R=C3=A8gne?= Date: Mon, 12 Dec 2022 13:26:43 +0100 Subject: [PATCH 26/29] feat: update globals (#16654) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc50b2ad8361..679d0b4eb455 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", From 0d9af4c5674809be993439c766dcd9d7f65fcec9 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Thu, 15 Dec 2022 00:05:56 +0100 Subject: [PATCH 27/29] ci: fix npm v9 problem with `file:` (#16664) * ci: fix npm v9 problem with `file:` * pin config-array --- .npmrc | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.npmrc b/.npmrc index c1ca392feaa4..8783d627dc54 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ package-lock = false +install-links = false diff --git a/package.json b/package.json index 679d0b4eb455..f3f679cdd418 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "bugs": "https://github.com/eslint/eslint/issues/", "dependencies": { "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/config-array": "0.11.7", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", From 6a8cd94ed08983c70ca7d72dc6e360770a743405 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 14 Dec 2022 15:40:39 -0800 Subject: [PATCH 28/29] docs: Clarify Discord info in issue template config (#16663) --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 46ab7744eeb0..1e20844c21fe 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,6 +6,6 @@ contact_links: - name: 📝 Help with VS Code ESLint url: https://github.com/microsoft/vscode-eslint/issues/ about: Bugs and feature requests for the VS Code ESLint plugin - - name: Discord Channel + - name: Discord Server url: https://eslint.org/chat - about: Get the latest announcements, chat with developers and get help + about: Talk with the team From ba74253e8bd63e9e163bbee0540031be77e39253 Mon Sep 17 00:00:00 2001 From: Patrick McElhaney Date: Wed, 14 Dec 2022 18:53:53 -0500 Subject: [PATCH 29/29] chore: standardize npm script names per #14827 (#16315) * chore: standardize npm script names per #14827 * put lint:fix right after lint * chore: fix ordering of :fix Co-authored-by: Milos Djermanovic * chore: change release scripts to have "release:" prefix Co-authored-by: Milos Djermanovic * docs: update package.json naming to include 'release' * docs: add css so abnf code formats okay * chore: exclude linting from npm test * docs: remove counter-reset. I guess that was a merge error Co-authored-by: Milos Djermanovic --- Makefile.js | 1 - .../package-json-conventions.md | 30 +++++++++---------- package.json | 28 ++++++++--------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/Makefile.js b/Makefile.js index 426dd9b717ad..14d2bac003a6 100644 --- a/Makefile.js +++ b/Makefile.js @@ -632,7 +632,6 @@ target.karma = () => { }; target.test = function() { - target.lint(); target.checkRuleFiles(); target.mocha(); target.karma(); diff --git a/docs/src/developer-guide/package-json-conventions.md b/docs/src/developer-guide/package-json-conventions.md index 654b9d7ad0db..3d38adecd2b2 100644 --- a/docs/src/developer-guide/package-json-conventions.md +++ b/docs/src/developer-guide/package-json-conventions.md @@ -9,22 +9,16 @@ The following applies to the "scripts" section of `package.json` files. npm script names MUST contain only lower case letters, `:` to separate parts, `-` to separate words, and `+` to separate file extensions. Each part name SHOULD be either a full English word (e.g. `coverage` not `cov`) or a well-known initialism in all lowercase (e.g. `wasm`). -Here is a summary of the proposal in EBNF. - -```ebnf -name = life-cycle | main ":fix"? target? option* ":watch"? - -life-cycle = prepare | preinstall | install | postinstall | prepublish | preprepare | prepare | postprepare | prepack | postpack | prepublishOnly; - -main = "build" | "lint" | "start" | "test"; - -target = ":" word ("-" word)* | extension ("+" extension)*; - -option = ":" word ("-" word)*; - -word = [a-z]+; - -extension = [a-z0-9]+; +Here is a summary of the proposal in ABNF. + +```abnf +name = life-cycle / main target? option* ":watch"? +life-cycle = "prepare" / "preinstall" / "install" / "postinstall" / "prepublish" / "preprepare" / "prepare" / "postprepare" / "prepack" / "postpack" / "prepublishOnly" +main = "build" / "lint" ":fix"? / "release" / "start" / "test" +target = ":" word ("-" word)* / extension ("+" extension)* +option = ":" word ("-" word)* +word = ALPHA + +extension = ( ALPHA / DIGIT )+ ``` ## Order @@ -41,6 +35,10 @@ Scripts that generate a set of files from source code and / or data MUST have na If a package contains any `build:*` scripts, there MAY be a script named `build`. If so, SHOULD produce the same output as running each of the `build` scripts individually. It MUST produce a subset of the output from running those scripts. +### Release + +Scripts that have public side effects (publishing the web site, committing to Git, etc.) MUST begin with `release`. + ### Lint Scripts that statically analyze files (mostly, but not limited to running `eslint` itself) MUST have names that begin with `lint`. diff --git a/package.json b/package.json index f3f679cdd418..6fddc975cd58 100644 --- a/package.json +++ b/package.json @@ -13,22 +13,22 @@ "./use-at-your-own-risk": "./lib/unsupported-api.js" }, "scripts": { + "build:docs:update-links": "node tools/fetch-docs-links.js", + "release:generate:latest": "node Makefile.js generateRelease", + "release:generate:alpha": "node Makefile.js generatePrerelease -- alpha", + "release:generate:beta": "node Makefile.js generatePrerelease -- beta", + "release:publish": "node Makefile.js publishRelease", + "release:generate:rc": "node Makefile.js generatePrerelease -- rc", + "build:site": "node Makefile.js gensite", + "build:webpack": "node Makefile.js webpack", + "lint": "node Makefile.js lint", + "lint:fix": "node Makefile.js lint -- fix", + "lint:docs:js": "node Makefile.js lintDocsJS", + "lint:fix:docs:js": "node Makefile.js lintDocsJS -- fix", "test": "node Makefile.js test", "test:cli": "mocha", - "lint": "node Makefile.js lint", - "lint:docsjs": "node Makefile.js lintDocsJS", - "fix": "node Makefile.js lint -- fix", - "fix:docsjs": "node Makefile.js lintDocsJS -- fix", - "fuzz": "node Makefile.js fuzz", - "generate-release": "node Makefile.js generateRelease", - "generate-alpharelease": "node Makefile.js generatePrerelease -- alpha", - "generate-betarelease": "node Makefile.js generatePrerelease -- beta", - "generate-rcrelease": "node Makefile.js generatePrerelease -- rc", - "publish-release": "node Makefile.js publishRelease", - "gensite": "node Makefile.js gensite", - "webpack": "node Makefile.js webpack", - "perf": "node Makefile.js perf", - "docs:update-links": "node tools/fetch-docs-links.js" + "test:fuzz": "node Makefile.js fuzz", + "test:performance": "node Makefile.js perf" }, "gitHooks": { "pre-commit": "lint-staged"