mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00
tools: update ESLint to v9 and use flat config
Closes: https://github.com/nodejs/node/issues/52567 PR-URL: https://github.com/nodejs/node/pull/52780 Fixes: https://github.com/nodejs/node/issues/52567 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
parent
b9ad94b6da
commit
7e6d92c485
1255 changed files with 16091 additions and 29665 deletions
|
@ -1,15 +0,0 @@
|
|||
node_modules
|
||||
lib/punycode.js
|
||||
test/addons/??_*
|
||||
test/fixtures
|
||||
test/message/esm_display_syntax_error.mjs
|
||||
tools/icu
|
||||
tools/lint-md/lint-md.mjs
|
||||
tools/github_reporter
|
||||
benchmark/tmp
|
||||
benchmark/fixtures
|
||||
doc/**/*.js
|
||||
doc/changelogs/CHANGELOG_v1*.md
|
||||
!doc/changelogs/CHANGELOG_v18.md
|
||||
!doc/api_assets/*.js
|
||||
!.eslintrc.js
|
375
.eslintrc.js
375
.eslintrc.js
|
@ -1,375 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
const Module = require('module');
|
||||
const path = require('path');
|
||||
|
||||
const NodePlugin = require('./tools/node_modules/eslint-plugin-node-core');
|
||||
NodePlugin.RULES_DIR = path.resolve(__dirname, 'tools', 'eslint-rules');
|
||||
|
||||
// The Module._findPath() monkeypatching is to make it so that ESLint will work
|
||||
// if invoked by a globally-installed ESLint or ESLint installed elsewhere
|
||||
// rather than the one we ship. This makes it possible for IDEs to lint files
|
||||
// with our rules while people edit them.
|
||||
const ModuleFindPath = Module._findPath;
|
||||
const hacks = [
|
||||
'eslint-plugin-node-core',
|
||||
'eslint-plugin-jsdoc',
|
||||
'eslint-plugin-markdown',
|
||||
'@babel/eslint-parser',
|
||||
'@babel/plugin-syntax-import-attributes',
|
||||
'@stylistic/eslint-plugin-js',
|
||||
];
|
||||
Module._findPath = (request, paths, isMain) => {
|
||||
const r = ModuleFindPath(request, paths, isMain);
|
||||
if (!r && hacks.includes(request)) {
|
||||
try {
|
||||
return require.resolve(`./tools/node_modules/${request}`);
|
||||
} catch {
|
||||
return require.resolve(
|
||||
`./tools/node_modules/eslint/node_modules/${request}`);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
es2022: true,
|
||||
},
|
||||
extends: ['eslint:recommended', 'plugin:jsdoc/recommended'],
|
||||
plugins: ['jsdoc', 'markdown', 'node-core', '@stylistic/js'],
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
babelOptions: {
|
||||
plugins: [
|
||||
Module._findPath('@babel/plugin-syntax-import-attributes'),
|
||||
],
|
||||
},
|
||||
requireConfigFile: false,
|
||||
sourceType: 'script',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'*.mjs',
|
||||
'test/es-module/test-esm-example-loader.js',
|
||||
'test/es-module/test-esm-type-flag.js',
|
||||
'test/es-module/test-esm-type-flag-alias.js',
|
||||
'test/es-module/test-require-module-detect-entry-point.js',
|
||||
'test/es-module/test-require-module-detect-entry-point-aou.js',
|
||||
],
|
||||
parserOptions: { sourceType: 'module' },
|
||||
},
|
||||
{
|
||||
files: ['**/*.md'],
|
||||
processor: 'markdown/markdown',
|
||||
},
|
||||
{
|
||||
files: ['**/*.md/*.cjs', '**/*.md/*.js'],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
ecmaFeatures: { impliedStrict: true },
|
||||
},
|
||||
rules: { strict: 'off' },
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'**/*.md/*.mjs',
|
||||
'doc/api/esm.md/*.js',
|
||||
'doc/api/packages.md/*.js',
|
||||
],
|
||||
parserOptions: { sourceType: 'module' },
|
||||
rules: { 'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
name: '__filename',
|
||||
message: 'Use import.meta.url instead',
|
||||
},
|
||||
{
|
||||
name: '__dirname',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'exports',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'module',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'require',
|
||||
message: 'Use import instead',
|
||||
},
|
||||
{
|
||||
name: 'Buffer',
|
||||
message: 'Import Buffer instead of using the global',
|
||||
},
|
||||
{
|
||||
name: 'process',
|
||||
message: 'Import process instead of using the global',
|
||||
},
|
||||
] },
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'lib/internal/modules/**/*.js',
|
||||
],
|
||||
rules: {
|
||||
'curly': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'lib/internal/test_runner/**/*.js',
|
||||
],
|
||||
rules: {
|
||||
'node-core/set-proto-to-null-in-object': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
// ESLint built-in rules
|
||||
// https://eslint.org/docs/rules/
|
||||
'accessor-pairs': 'error',
|
||||
'array-callback-return': 'error',
|
||||
'block-scoped-var': 'error',
|
||||
'capitalized-comments': ['error', 'always', {
|
||||
line: {
|
||||
// Ignore all lines that have less characters than 20 and all lines that
|
||||
// start with something that looks like a variable name or code.
|
||||
ignorePattern: '.{0,20}$|[a-z]+ ?[0-9A-Z_.(/=:[#-]|std|http|ssh|ftp',
|
||||
ignoreInlineComments: true,
|
||||
ignoreConsecutiveComments: true,
|
||||
},
|
||||
block: {
|
||||
ignorePattern: '.*',
|
||||
},
|
||||
}],
|
||||
'default-case-last': 'error',
|
||||
'dot-notation': 'error',
|
||||
'eqeqeq': ['error', 'smart'],
|
||||
'func-name-matching': 'error',
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
'no-constant-condition': ['error', { checkLoops: false }],
|
||||
'no-constructor-return': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-else-return': 'error',
|
||||
'no-lonely-if': 'error',
|
||||
'no-mixed-requires': 'error',
|
||||
'no-new-require': 'error',
|
||||
'no-path-concat': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-redeclare': ['error', { 'builtinGlobals': false }],
|
||||
'no-restricted-modules': ['error', 'sys'],
|
||||
'no-restricted-properties': [
|
||||
'error',
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'deepEqual',
|
||||
message: 'Use `assert.deepStrictEqual()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'notDeepEqual',
|
||||
message: 'Use `assert.notDeepStrictEqual()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'equal',
|
||||
message: 'Use `assert.strictEqual()` rather than `assert.equal()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'notEqual',
|
||||
message: 'Use `assert.notStrictEqual()` rather than `assert.notEqual()`.',
|
||||
},
|
||||
{
|
||||
property: '__defineGetter__',
|
||||
message: '__defineGetter__ is deprecated.',
|
||||
},
|
||||
{
|
||||
property: '__defineSetter__',
|
||||
message: '__defineSetter__ is deprecated.',
|
||||
},
|
||||
],
|
||||
// If this list is modified, please copy changes that should apply to ./lib
|
||||
// as well to lib/.eslintrc.yaml.
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]",
|
||||
message: '`setTimeout()` must be invoked with at least two arguments.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='setInterval'][arguments.length<2]",
|
||||
message: '`setInterval()` must be invoked with at least two arguments.',
|
||||
},
|
||||
{
|
||||
selector: 'ThrowStatement > CallExpression[callee.name=/Error$/]',
|
||||
message: 'Use `new` keyword when throwing an `Error`.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.property.name='substr']",
|
||||
message: 'Use String.prototype.slice() or String.prototype.substring() instead of String.prototype.substr()',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='isNaN']",
|
||||
message: 'Use Number.isNaN() instead of the global isNaN() function.',
|
||||
},
|
||||
{
|
||||
// TODO(@panva): move this to no-restricted-properties
|
||||
// when https://github.com/eslint/eslint/issues/16412 is fixed
|
||||
selector: "Identifier[name='webcrypto']",
|
||||
message: 'Use `globalThis.crypto`.',
|
||||
},
|
||||
],
|
||||
'no-self-compare': 'error',
|
||||
'no-template-curly-in-string': 'error',
|
||||
'no-throw-literal': 'error',
|
||||
'no-undef': ['error', { typeof: true }],
|
||||
'no-undef-init': 'error',
|
||||
'no-unused-expressions': ['error', { allowShortCircuit: true }],
|
||||
'no-unused-vars': ['error', { args: 'none', caughtErrors: 'all' }],
|
||||
'no-use-before-define': ['error', {
|
||||
classes: true,
|
||||
functions: false,
|
||||
variables: false,
|
||||
}],
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-useless-constructor': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-var': 'error',
|
||||
'no-void': 'error',
|
||||
'one-var': ['error', { initialized: 'never' }],
|
||||
'prefer-const': ['error', { ignoreReadBeforeAssign: true }],
|
||||
'prefer-object-has-own': 'error',
|
||||
'strict': ['error', 'global'],
|
||||
'symbol-description': 'error',
|
||||
'unicode-bom': 'error',
|
||||
'valid-typeof': ['error', { requireStringLiterals: true }],
|
||||
|
||||
// ESLint recommended rules that we disable
|
||||
'no-inner-declarations': 'off',
|
||||
|
||||
// JSDoc recommended rules that we disable
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
'jsdoc/valid-types': 'off',
|
||||
'jsdoc/no-defaults': 'off',
|
||||
'jsdoc/no-undefined-types': 'off',
|
||||
'jsdoc/require-param': 'off',
|
||||
'jsdoc/check-tag-names': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
|
||||
// Stylistic rules
|
||||
'@stylistic/js/arrow-parens': 'error',
|
||||
'@stylistic/js/arrow-spacing': 'error',
|
||||
'@stylistic/js/block-spacing': 'error',
|
||||
'@stylistic/js/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
||||
'@stylistic/js/comma-dangle': ['error', 'always-multiline'],
|
||||
'@stylistic/js/comma-spacing': 'error',
|
||||
'@stylistic/js/comma-style': 'error',
|
||||
'@stylistic/js/computed-property-spacing': 'error',
|
||||
'@stylistic/js/dot-location': ['error', 'property'],
|
||||
'@stylistic/js/eol-last': 'error',
|
||||
'@stylistic/js/func-call-spacing': 'error',
|
||||
'@stylistic/js/indent': ['error', 2, {
|
||||
ArrayExpression: 'first',
|
||||
CallExpression: { arguments: 'first' },
|
||||
FunctionDeclaration: { parameters: 'first' },
|
||||
FunctionExpression: { parameters: 'first' },
|
||||
MemberExpression: 'off',
|
||||
ObjectExpression: 'first',
|
||||
SwitchCase: 1,
|
||||
}],
|
||||
'@stylistic/js/key-spacing': 'error',
|
||||
'@stylistic/js/keyword-spacing': 'error',
|
||||
'@stylistic/js/linebreak-style': 'error',
|
||||
'@stylistic/js/max-len': ['error', {
|
||||
code: 120,
|
||||
ignorePattern: '^// Flags:',
|
||||
ignoreRegExpLiterals: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
ignoreUrls: true,
|
||||
tabWidth: 2,
|
||||
}],
|
||||
'@stylistic/js/new-parens': 'error',
|
||||
'@stylistic/js/no-confusing-arrow': 'error',
|
||||
'@stylistic/js/no-extra-parens': ['error', 'functions'],
|
||||
'@stylistic/js/no-multi-spaces': ['error', { ignoreEOLComments: true }],
|
||||
'@stylistic/js/no-multiple-empty-lines': ['error', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
||||
'@stylistic/js/no-tabs': 'error',
|
||||
'@stylistic/js/no-trailing-spaces': 'error',
|
||||
'@stylistic/js/no-whitespace-before-property': 'error',
|
||||
'@stylistic/js/object-curly-newline': 'error',
|
||||
'@stylistic/js/object-curly-spacing': ['error', 'always'],
|
||||
'@stylistic/js/one-var-declaration-per-line': 'error',
|
||||
'@stylistic/js/operator-linebreak': ['error', 'after'],
|
||||
'@stylistic/js/padding-line-between-statements': [
|
||||
'error',
|
||||
{ blankLine: 'always', prev: 'function', next: 'function' },
|
||||
],
|
||||
'@stylistic/js/quotes': ['error', 'single', { avoidEscape: true }],
|
||||
'@stylistic/js/quote-props': ['error', 'consistent'],
|
||||
'@stylistic/js/rest-spread-spacing': 'error',
|
||||
'@stylistic/js/semi': 'error',
|
||||
'@stylistic/js/semi-spacing': 'error',
|
||||
'@stylistic/js/space-before-blocks': ['error', 'always'],
|
||||
'@stylistic/js/space-before-function-paren': ['error', {
|
||||
anonymous: 'never',
|
||||
named: 'never',
|
||||
asyncArrow: 'always',
|
||||
}],
|
||||
'@stylistic/js/space-in-parens': 'error',
|
||||
'@stylistic/js/space-infix-ops': 'error',
|
||||
'@stylistic/js/space-unary-ops': 'error',
|
||||
'@stylistic/js/spaced-comment': ['error', 'always', {
|
||||
'block': { 'balanced': true },
|
||||
'exceptions': ['-'],
|
||||
}],
|
||||
'@stylistic/js/template-curly-spacing': 'error',
|
||||
|
||||
// Custom rules from eslint-plugin-node-core
|
||||
'node-core/no-unescaped-regexp-dot': 'error',
|
||||
'node-core/no-duplicate-requires': 'error',
|
||||
'node-core/prefer-proto': 'error',
|
||||
},
|
||||
globals: {
|
||||
ByteLengthQueuingStrategy: 'readable',
|
||||
CompressionStream: 'readable',
|
||||
CountQueuingStrategy: 'readable',
|
||||
CustomEvent: 'readable',
|
||||
crypto: 'readable',
|
||||
Crypto: 'readable',
|
||||
CryptoKey: 'readable',
|
||||
DecompressionStream: 'readable',
|
||||
EventSource: 'readable',
|
||||
fetch: 'readable',
|
||||
FormData: 'readable',
|
||||
navigator: 'readable',
|
||||
ReadableStream: 'readable',
|
||||
ReadableStreamDefaultReader: 'readable',
|
||||
ReadableStreamBYOBReader: 'readable',
|
||||
ReadableStreamBYOBRequest: 'readable',
|
||||
ReadableByteStreamController: 'readable',
|
||||
ReadableStreamDefaultController: 'readable',
|
||||
Response: 'readable',
|
||||
TextDecoderStream: 'readable',
|
||||
TextEncoderStream: 'readable',
|
||||
TransformStream: 'readable',
|
||||
TransformStreamDefaultController: 'readable',
|
||||
ShadowRealm: 'readable',
|
||||
SubtleCrypto: 'readable',
|
||||
WritableStream: 'readable',
|
||||
WritableStreamDefaultWriter: 'readable',
|
||||
WritableStreamDefaultController: 'readable',
|
||||
WebSocket: 'readable',
|
||||
},
|
||||
};
|
2
.github/label-pr-config.yml
vendored
2
.github/label-pr-config.yml
vendored
|
@ -66,7 +66,7 @@ subSystemLabels:
|
|||
/^tools\/build-addons.mjs/: needs-ci
|
||||
# All other tool changes should be marked as such
|
||||
/^tools\//: tools
|
||||
/^\.eslint|\.editorconfig/: tools
|
||||
/^eslint\.config|\.editorconfig/: tools
|
||||
/^typings\//: typings
|
||||
|
||||
## Dependencies
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -13,9 +13,6 @@
|
|||
!.clang-format
|
||||
!.cpplint
|
||||
!.editorconfig
|
||||
!.eslintignore
|
||||
!.eslintrc.js
|
||||
!.eslintrc.yaml
|
||||
!.gitattributes
|
||||
!.github
|
||||
!.gitignore
|
||||
|
|
4
Makefile
4
Makefile
|
@ -1194,7 +1194,7 @@ $(TARBALL): release-only doc-only
|
|||
find $(TARNAME)/deps/v8/test/* -type d ! -regex '.*/test/torque$$' | xargs $(RM) -r
|
||||
find $(TARNAME)/deps/v8/test -type f ! -regex '.*/test/torque/.*' | xargs $(RM)
|
||||
find $(TARNAME)/deps/zlib/contrib/* -type d ! -regex '.*/contrib/optimizations$$' | xargs $(RM) -r
|
||||
find $(TARNAME)/ -name ".eslint*" -maxdepth 2 | xargs $(RM)
|
||||
find $(TARNAME)/ -name "eslint.config*" -maxdepth 2 | xargs $(RM)
|
||||
find $(TARNAME)/ -type l | xargs $(RM)
|
||||
tar -cf $(TARNAME).tar $(TARNAME)
|
||||
$(RM) -r $(TARNAME)
|
||||
|
@ -1372,7 +1372,7 @@ format-md:
|
|||
|
||||
|
||||
|
||||
LINT_JS_TARGETS = .eslintrc.js benchmark doc lib test tools
|
||||
LINT_JS_TARGETS = eslint.config.mjs benchmark doc lib test tools
|
||||
|
||||
run-lint-js = tools/node_modules/eslint/bin/eslint.js --cache \
|
||||
--max-warnings=0 --report-unused-disable-directives $(LINT_JS_TARGETS)
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
## Benchmark-specific linter rules
|
||||
|
||||
env:
|
||||
node: true
|
||||
es6: true
|
||||
|
||||
rules:
|
||||
prefer-arrow-callback: error
|
17
benchmark/eslint.config_partial.mjs
Normal file
17
benchmark/eslint.config_partial.mjs
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { requireEslintTool } from '../tools/eslint.config_utils.mjs';
|
||||
|
||||
const globals = requireEslintTool('globals');
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ['benchmark/**/*.{js,mjs,cjs}'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'prefer-arrow-callback': 'error',
|
||||
},
|
||||
},
|
||||
];
|
|
@ -1,17 +0,0 @@
|
|||
## Docs-specific linter rules
|
||||
|
||||
rules:
|
||||
# Ease some restrictions in doc examples
|
||||
no-restricted-properties: off
|
||||
no-undef: off
|
||||
no-unused-expressions: off
|
||||
no-unused-vars: off
|
||||
symbol-description: off
|
||||
|
||||
# Add new ECMAScript features gradually
|
||||
prefer-const: error
|
||||
prefer-rest-params: error
|
||||
prefer-template: error
|
||||
|
||||
# Stylistic rules
|
||||
'@stylistic/js/no-multiple-empty-lines': [error, {max: 1, maxEOF: 0, maxBOF: 0}]
|
|
@ -855,7 +855,7 @@ might impact an LTS release.
|
|||
| `src/node_api.*` | @nodejs/node-api |
|
||||
| `src/node_crypto.*`, `src/crypto` | @nodejs/crypto |
|
||||
| `test/*` | @nodejs/testing |
|
||||
| `tools/node_modules/eslint`, `.eslintrc` | @nodejs/linting |
|
||||
| `tools/node_modules/eslint`, `eslint.config.mjs` | @nodejs/linting |
|
||||
| build | @nodejs/build |
|
||||
| `src/module_wrap.*`, `lib/internal/modules/*`, `lib/internal/vm/module.js` | @nodejs/modules |
|
||||
| GYP | @nodejs/gyp |
|
||||
|
|
40
doc/eslint.config_partial.mjs
Normal file
40
doc/eslint.config_partial.mjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { requireEslintTool } from '../tools/eslint.config_utils.mjs';
|
||||
|
||||
const globals = requireEslintTool('globals');
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ['doc/**/*.md/*.{js,mjs,cjs}'],
|
||||
rules: {
|
||||
// Ease some restrictions in doc examples.
|
||||
'no-restricted-properties': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-unused-expressions': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'symbol-description': 'off',
|
||||
|
||||
// Add new ECMAScript features gradually.
|
||||
'prefer-const': 'error',
|
||||
'prefer-rest-params': 'error',
|
||||
'prefer-template': 'error',
|
||||
|
||||
// Stylistic rules.
|
||||
'@stylistic/js/no-multiple-empty-lines': [
|
||||
'error',
|
||||
{
|
||||
max: 1,
|
||||
maxEOF: 0,
|
||||
maxBOF: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['doc/api_assets/*.js'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
383
eslint.config.mjs
Normal file
383
eslint.config.mjs
Normal file
|
@ -0,0 +1,383 @@
|
|||
import Module from 'node:module';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
|
||||
import benchmarkConfig from './benchmark/eslint.config_partial.mjs';
|
||||
import docConfig from './doc/eslint.config_partial.mjs';
|
||||
import libConfig from './lib/eslint.config_partial.mjs';
|
||||
import testConfig from './test/eslint.config_partial.mjs';
|
||||
import toolsConfig from './tools/eslint.config_partial.mjs';
|
||||
import {
|
||||
noRestrictedSyntaxCommonAll,
|
||||
noRestrictedSyntaxCommonLib,
|
||||
noRestrictedSyntaxCommonTest,
|
||||
requireEslintTool,
|
||||
resolveEslintTool,
|
||||
} from './tools/eslint.config_utils.mjs';
|
||||
|
||||
const js = requireEslintTool('@eslint/js');
|
||||
const babelEslintParser = requireEslintTool('@babel/eslint-parser');
|
||||
const babelPluginSyntaxImportAttributes = requireEslintTool('@babel/plugin-syntax-import-attributes');
|
||||
const jsdoc = requireEslintTool('eslint-plugin-jsdoc');
|
||||
const markdown = requireEslintTool('eslint-plugin-markdown');
|
||||
const stylisticJs = requireEslintTool('@stylistic/eslint-plugin-js');
|
||||
|
||||
const nodeCore = requireEslintTool('eslint-plugin-node-core');
|
||||
nodeCore.RULES_DIR = fileURLToPath(new URL('./tools/eslint-rules', import.meta.url));
|
||||
|
||||
// The Module._resolveFilename() monkeypatching is to make it so that ESLint is able to
|
||||
// dynamically load extra modules that we install with it.
|
||||
const ModuleResolveFilename = Module._resolveFilename;
|
||||
const hacks = [
|
||||
'eslint-formatter-tap',
|
||||
];
|
||||
Module._resolveFilename = (request, parent, isMain, options) => {
|
||||
if (hacks.includes(request) && parent.id.endsWith('__placeholder__.js')) {
|
||||
return resolveEslintTool(request);
|
||||
}
|
||||
return ModuleResolveFilename(request, parent, isMain, options);
|
||||
};
|
||||
|
||||
export default [
|
||||
// #region ignores
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules/**',
|
||||
'benchmark/fixtures/**',
|
||||
'benchmark/tmp/**',
|
||||
'doc/**/*.js',
|
||||
'doc/changelogs/CHANGELOG_V1*.md',
|
||||
'!doc/api_assets/*.js',
|
||||
'!doc/changelogs/CHANGELOG_V18.md',
|
||||
'lib/punycode.js',
|
||||
'test/.tmp.*/**',
|
||||
'test/addons/??_*',
|
||||
'test/fixtures/**',
|
||||
'test/message/esm_display_syntax_error.mjs',
|
||||
'tools/github_reporter/**',
|
||||
'tools/icu/**',
|
||||
'tools/lint-md/lint-md.mjs',
|
||||
],
|
||||
},
|
||||
// #endregion
|
||||
// #region general config
|
||||
js.configs.recommended,
|
||||
jsdoc.configs['flat/recommended'],
|
||||
{
|
||||
files: ['**/*.{js,cjs}'],
|
||||
languageOptions: {
|
||||
// The default is `commonjs` but it's not supported by the Babel parser.
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
jsdoc,
|
||||
'@stylistic/js': stylisticJs,
|
||||
'node-core': nodeCore,
|
||||
},
|
||||
languageOptions: {
|
||||
parser: babelEslintParser,
|
||||
parserOptions: {
|
||||
babelOptions: {
|
||||
plugins: [
|
||||
babelPluginSyntaxImportAttributes,
|
||||
],
|
||||
},
|
||||
requireConfigFile: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
// #region general globals
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
ByteLengthQueuingStrategy: 'readonly',
|
||||
CompressionStream: 'readonly',
|
||||
CountQueuingStrategy: 'readonly',
|
||||
CustomEvent: 'readonly',
|
||||
crypto: 'readonly',
|
||||
Crypto: 'readonly',
|
||||
CryptoKey: 'readonly',
|
||||
DecompressionStream: 'readonly',
|
||||
EventSource: 'readable',
|
||||
fetch: 'readonly',
|
||||
FormData: 'readonly',
|
||||
navigator: 'readonly',
|
||||
ReadableStream: 'readonly',
|
||||
ReadableStreamDefaultReader: 'readonly',
|
||||
ReadableStreamBYOBReader: 'readonly',
|
||||
ReadableStreamBYOBRequest: 'readonly',
|
||||
ReadableByteStreamController: 'readonly',
|
||||
ReadableStreamDefaultController: 'readonly',
|
||||
Response: 'readonly',
|
||||
TextDecoderStream: 'readonly',
|
||||
TextEncoderStream: 'readonly',
|
||||
TransformStream: 'readonly',
|
||||
TransformStreamDefaultController: 'readonly',
|
||||
ShadowRealm: 'readonly',
|
||||
SubtleCrypto: 'readonly',
|
||||
WritableStream: 'readonly',
|
||||
WritableStreamDefaultWriter: 'readonly',
|
||||
WritableStreamDefaultController: 'readonly',
|
||||
WebSocket: 'readonly',
|
||||
},
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
// #region general rules
|
||||
{
|
||||
rules: {
|
||||
// ESLint built-in rules
|
||||
// https://eslint.org/docs/latest/rules/
|
||||
'accessor-pairs': 'error',
|
||||
'array-callback-return': 'error',
|
||||
'block-scoped-var': 'error',
|
||||
'capitalized-comments': ['error', 'always', {
|
||||
line: {
|
||||
// Ignore all lines that have less characters than 20 and all lines
|
||||
// that start with something that looks like a variable name or code.
|
||||
ignorePattern: '.{0,20}$|[a-z]+ ?[0-9A-Z_.(/=:[#-]|std|http|ssh|ftp',
|
||||
ignoreInlineComments: true,
|
||||
ignoreConsecutiveComments: true,
|
||||
},
|
||||
block: {
|
||||
ignorePattern: '.*',
|
||||
},
|
||||
}],
|
||||
'default-case-last': 'error',
|
||||
'dot-notation': 'error',
|
||||
'eqeqeq': ['error', 'smart'],
|
||||
'func-name-matching': 'error',
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
'no-constant-condition': ['error', { checkLoops: false }],
|
||||
'no-constructor-return': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-else-return': 'error',
|
||||
'no-lonely-if': 'error',
|
||||
'no-mixed-requires': 'error',
|
||||
'no-new-require': 'error',
|
||||
'no-path-concat': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-redeclare': ['error', { builtinGlobals: false }],
|
||||
'no-restricted-modules': ['error', 'sys'],
|
||||
'no-restricted-properties': [
|
||||
'error',
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'deepEqual',
|
||||
message: 'Use `assert.deepStrictEqual()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'notDeepEqual',
|
||||
message: 'Use `assert.notDeepStrictEqual()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'equal',
|
||||
message: 'Use `assert.strictEqual()` rather than `assert.equal()`.',
|
||||
},
|
||||
{
|
||||
object: 'assert',
|
||||
property: 'notEqual',
|
||||
message: 'Use `assert.notStrictEqual()` rather than `assert.notEqual()`.',
|
||||
},
|
||||
{
|
||||
property: '__defineGetter__',
|
||||
message: '__defineGetter__ is deprecated.',
|
||||
},
|
||||
{
|
||||
property: '__defineSetter__',
|
||||
message: '__defineSetter__ is deprecated.',
|
||||
},
|
||||
],
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
...noRestrictedSyntaxCommonAll,
|
||||
...noRestrictedSyntaxCommonLib,
|
||||
...noRestrictedSyntaxCommonTest,
|
||||
],
|
||||
'no-self-compare': 'error',
|
||||
'no-template-curly-in-string': 'error',
|
||||
'no-throw-literal': 'error',
|
||||
'no-undef': ['error', { typeof: true }],
|
||||
'no-undef-init': 'error',
|
||||
'no-unused-expressions': ['error', { allowShortCircuit: true }],
|
||||
'no-unused-vars': ['error', { args: 'none', caughtErrors: 'all' }],
|
||||
'no-use-before-define': ['error', {
|
||||
classes: true,
|
||||
functions: false,
|
||||
variables: false,
|
||||
}],
|
||||
'no-useless-call': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-useless-constructor': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-var': 'error',
|
||||
'no-void': 'error',
|
||||
'one-var': ['error', { initialized: 'never' }],
|
||||
'prefer-const': ['error', { ignoreReadBeforeAssign: true }],
|
||||
'prefer-object-has-own': 'error',
|
||||
'strict': ['error', 'global'],
|
||||
'symbol-description': 'error',
|
||||
'unicode-bom': 'error',
|
||||
'valid-typeof': ['error', { requireStringLiterals: true }],
|
||||
|
||||
// ESLint recommended rules that we disable.
|
||||
'no-inner-declarations': 'off',
|
||||
|
||||
// JSDoc recommended rules that we disable.
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
'jsdoc/valid-types': 'off',
|
||||
'jsdoc/no-defaults': 'off',
|
||||
'jsdoc/no-undefined-types': 'off',
|
||||
'jsdoc/require-param': 'off',
|
||||
'jsdoc/check-tag-names': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
|
||||
// Stylistic rules.
|
||||
'@stylistic/js/arrow-parens': 'error',
|
||||
'@stylistic/js/arrow-spacing': 'error',
|
||||
'@stylistic/js/block-spacing': 'error',
|
||||
'@stylistic/js/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
||||
'@stylistic/js/comma-dangle': ['error', 'always-multiline'],
|
||||
'@stylistic/js/comma-spacing': 'error',
|
||||
'@stylistic/js/comma-style': 'error',
|
||||
'@stylistic/js/computed-property-spacing': 'error',
|
||||
'@stylistic/js/dot-location': ['error', 'property'],
|
||||
'@stylistic/js/eol-last': 'error',
|
||||
'@stylistic/js/func-call-spacing': 'error',
|
||||
'@stylistic/js/indent': ['error', 2, {
|
||||
ArrayExpression: 'first',
|
||||
CallExpression: { arguments: 'first' },
|
||||
FunctionDeclaration: { parameters: 'first' },
|
||||
FunctionExpression: { parameters: 'first' },
|
||||
MemberExpression: 'off',
|
||||
ObjectExpression: 'first',
|
||||
SwitchCase: 1,
|
||||
}],
|
||||
'@stylistic/js/key-spacing': 'error',
|
||||
'@stylistic/js/keyword-spacing': 'error',
|
||||
'@stylistic/js/linebreak-style': 'error',
|
||||
'@stylistic/js/max-len': ['error', {
|
||||
code: 120,
|
||||
ignorePattern: '^// Flags:',
|
||||
ignoreRegExpLiterals: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
ignoreUrls: true,
|
||||
tabWidth: 2,
|
||||
}],
|
||||
'@stylistic/js/new-parens': 'error',
|
||||
'@stylistic/js/no-confusing-arrow': 'error',
|
||||
'@stylistic/js/no-extra-parens': ['error', 'functions'],
|
||||
'@stylistic/js/no-multi-spaces': ['error', { ignoreEOLComments: true }],
|
||||
'@stylistic/js/no-multiple-empty-lines': ['error', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
||||
'@stylistic/js/no-tabs': 'error',
|
||||
'@stylistic/js/no-trailing-spaces': 'error',
|
||||
'@stylistic/js/no-whitespace-before-property': 'error',
|
||||
'@stylistic/js/object-curly-newline': 'error',
|
||||
'@stylistic/js/object-curly-spacing': ['error', 'always'],
|
||||
'@stylistic/js/one-var-declaration-per-line': 'error',
|
||||
'@stylistic/js/operator-linebreak': ['error', 'after'],
|
||||
'@stylistic/js/padding-line-between-statements': [
|
||||
'error',
|
||||
{ blankLine: 'always', prev: 'function', next: 'function' },
|
||||
],
|
||||
'@stylistic/js/quotes': ['error', 'single', { avoidEscape: true }],
|
||||
'@stylistic/js/quote-props': ['error', 'consistent'],
|
||||
'@stylistic/js/rest-spread-spacing': 'error',
|
||||
'@stylistic/js/semi': 'error',
|
||||
'@stylistic/js/semi-spacing': 'error',
|
||||
'@stylistic/js/space-before-blocks': ['error', 'always'],
|
||||
'@stylistic/js/space-before-function-paren': ['error', {
|
||||
anonymous: 'never',
|
||||
named: 'never',
|
||||
asyncArrow: 'always',
|
||||
}],
|
||||
'@stylistic/js/space-in-parens': 'error',
|
||||
'@stylistic/js/space-infix-ops': 'error',
|
||||
'@stylistic/js/space-unary-ops': 'error',
|
||||
'@stylistic/js/spaced-comment': ['error', 'always', {
|
||||
'block': { 'balanced': true },
|
||||
'exceptions': ['-'],
|
||||
}],
|
||||
'@stylistic/js/template-curly-spacing': 'error',
|
||||
|
||||
// Custom rules in tools/eslint-rules.
|
||||
'node-core/no-unescaped-regexp-dot': 'error',
|
||||
'node-core/no-duplicate-requires': 'error',
|
||||
'node-core/prefer-proto': 'error',
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
// #region markdown config
|
||||
{
|
||||
files: ['**/*.md'],
|
||||
plugins: {
|
||||
markdown,
|
||||
},
|
||||
processor: 'markdown/markdown',
|
||||
},
|
||||
{
|
||||
files: ['**/*.md/*.{js,cjs}'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaFeatures: { impliedStrict: true },
|
||||
},
|
||||
},
|
||||
rules: { strict: 'off' },
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'**/*.md/*.mjs',
|
||||
'doc/api/esm.md/*.js',
|
||||
'doc/api/packages.md/*.js',
|
||||
],
|
||||
languageOptions: {
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: { 'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
name: '__filename',
|
||||
message: 'Use import.meta.url instead',
|
||||
},
|
||||
{
|
||||
name: '__dirname',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'exports',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'module',
|
||||
message: 'Not available in ESM',
|
||||
},
|
||||
{
|
||||
name: 'require',
|
||||
message: 'Use import instead',
|
||||
},
|
||||
{
|
||||
name: 'Buffer',
|
||||
message: 'Import Buffer instead of using the global',
|
||||
},
|
||||
{
|
||||
name: 'process',
|
||||
message: 'Import process instead of using the global',
|
||||
},
|
||||
] },
|
||||
},
|
||||
// #endregion
|
||||
// #region partials
|
||||
...benchmarkConfig,
|
||||
...docConfig,
|
||||
...libConfig,
|
||||
...testConfig,
|
||||
...toolsConfig,
|
||||
// #endregion
|
||||
];
|
|
@ -1,276 +0,0 @@
|
|||
env:
|
||||
es6: true
|
||||
|
||||
rules:
|
||||
prefer-object-spread: error
|
||||
no-buffer-constructor: error
|
||||
no-restricted-syntax:
|
||||
# Config copied from .eslintrc.js
|
||||
- error
|
||||
- selector: CallExpression[callee.object.name='assert']:not([callee.property.name='ok']):not([callee.property.name='fail']):not([callee.property.name='ifError'])
|
||||
message: Please only use simple assertions in ./lib
|
||||
- selector: CallExpression[callee.name='setTimeout'][arguments.length<2]
|
||||
message: setTimeout() must be invoked with at least two arguments.
|
||||
- selector: CallExpression[callee.name='setInterval'][arguments.length<2]
|
||||
message: setInterval() must be invoked with at least 2 arguments.
|
||||
- selector: ThrowStatement > CallExpression[callee.name=/Error$/]
|
||||
message: Use new keyword when throwing an Error.
|
||||
# Config specific to lib
|
||||
- selector: NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])
|
||||
message: Use an error exported by the internal/errors module.
|
||||
- selector: CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']
|
||||
message: Please use `require('internal/errors').hideStackFrames()` instead.
|
||||
- selector: AssignmentExpression:matches([left.object.name='Error']):matches([left.name='prepareStackTrace'], [left.property.name='prepareStackTrace'])
|
||||
message: Use 'overrideStackTrace' from 'lib/internal/errors.js' instead of 'Error.prepareStackTrace'.
|
||||
- selector: ThrowStatement > NewExpression[callee.name=/^ERR_[A-Z_]+$/] > ObjectExpression:first-child:not(:has([key.name='message']):has([key.name='code']):has([key.name='syscall']))
|
||||
message: The context passed into SystemError constructor must have .code, .syscall and .message.
|
||||
no-restricted-globals:
|
||||
- error
|
||||
- name: AbortController
|
||||
message: Use `const { AbortController } = require('internal/abort_controller');` instead of the global.
|
||||
- name: AbortSignal
|
||||
message: Use `const { AbortSignal } = require('internal/abort_controller');` instead of the global.
|
||||
- name: Blob
|
||||
message: Use `const { Blob } = require('buffer');` instead of the global.
|
||||
- name: BroadcastChannel
|
||||
message: Use `const { BroadcastChannel } = require('internal/worker/io');` instead of the global.
|
||||
- name: Buffer
|
||||
message: Use `const { Buffer } = require('buffer');` instead of the global.
|
||||
- name: ByteLengthQueuingStrategy
|
||||
message: Use `const { ByteLengthQueuingStrategy } = require('internal/webstreams/queuingstrategies')` instead of the global.
|
||||
- name: CompressionStream
|
||||
message: Use `const { CompressionStream } = require('internal/webstreams/compression')` instead of the global.
|
||||
- name: CountQueuingStrategy
|
||||
message: Use `const { CountQueuingStrategy } = require('internal/webstreams/queuingstrategies')` instead of the global.
|
||||
- name: CustomEvent
|
||||
message: Use `const { CustomEvent } = require('internal/event_target');` instead of the global.
|
||||
- name: DecompressionStream
|
||||
message: Use `const { DecompressionStream } = require('internal/webstreams/compression')` instead of the global.
|
||||
- name: DOMException
|
||||
message: Use lazy function `const { lazyDOMExceptionClass } = require('internal/util');` instead of the global.
|
||||
- name: Event
|
||||
message: Use `const { Event } = require('internal/event_target');` instead of the global.
|
||||
- name: EventTarget
|
||||
message: Use `const { EventTarget } = require('internal/event_target');` instead of the global.
|
||||
- name: File
|
||||
message: Use `const { File } = require('buffer');` instead of the global.
|
||||
- name: FormData
|
||||
message: Use `const { FormData } = require('internal/deps/undici/undici');` instead of the global.
|
||||
- name: Headers
|
||||
message: Use `const { Headers } = require('internal/deps/undici/undici');` instead of the global.
|
||||
# Intl is not available in primordials because it can be
|
||||
# disabled with --without-intl build flag.
|
||||
- name: Intl
|
||||
message: Use `const { Intl } = globalThis;` instead of the global.
|
||||
- name: Iterator
|
||||
message: Use `const { Iterator } = globalThis;` instead of the global.
|
||||
- name: MessageChannel
|
||||
message: Use `const { MessageChannel } = require('internal/worker/io');` instead of the global.
|
||||
- name: MessageEvent
|
||||
message: Use `const { MessageEvent } = require('internal/deps/undici/undici');` instead of the global.
|
||||
- name: MessagePort
|
||||
message: Use `const { MessagePort } = require('internal/worker/io');` instead of the global.
|
||||
- name: Navigator
|
||||
message: Use `const { Navigator } = require('internal/navigator');` instead of the global.
|
||||
- name: navigator
|
||||
message: Use `const { navigator } = require('internal/navigator');` instead of the global.
|
||||
- name: PerformanceEntry
|
||||
message: Use `const { PerformanceEntry } = require('perf_hooks');` instead of the global.
|
||||
- name: PerformanceMark
|
||||
message: Use `const { PerformanceMark } = require('perf_hooks');` instead of the global.
|
||||
- name: PerformanceMeasure
|
||||
message: Use `const { PerformanceMeasure } = require('perf_hooks');` instead of the global.
|
||||
- name: PerformanceObserverEntryList
|
||||
message: Use `const { PerformanceObserverEntryList } = require('perf_hooks');` instead of the global.
|
||||
- name: PerformanceObserver
|
||||
message: Use `const { PerformanceObserver } = require('perf_hooks');` instead of the global.
|
||||
- name: PerformanceResourceTiming
|
||||
message: Use `const { PerformanceResourceTiming } = require('perf_hooks');` instead of the global.
|
||||
- name: ReadableStream
|
||||
message: Use `const { ReadableStream } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: ReadableStreamDefaultReader
|
||||
message: Use `const { ReadableStreamDefaultReader } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: ReadableStreamBYOBReader
|
||||
message: Use `const { ReadableStreamBYOBReader } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: ReadableStreamBYOBRequest
|
||||
message: Use `const { ReadableStreamBYOBRequest } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: ReadableByteStreamController
|
||||
message: Use `const { ReadableByteStreamController } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: ReadableStreamDefaultController
|
||||
message: Use `const { ReadableStreamDefaultController } = require('internal/webstreams/readablestream')` instead of the global.
|
||||
- name: Request
|
||||
message: Use `const { Request } = require('internal/deps/undici/undici');` instead of the global.
|
||||
- name: Response
|
||||
message: Use `const { Response } = require('internal/deps/undici/undici');` instead of the global.
|
||||
# ShadowRealm is not available in primordials because it can be
|
||||
# disabled with --no-harmony-shadow-realm CLI flag.
|
||||
- name: ShadowRealm
|
||||
message: Use `const { ShadowRealm } = globalThis;` instead of the global.
|
||||
# SharedArrayBuffer is not available in primordials because it can be
|
||||
# disabled with --no-harmony-sharedarraybuffer CLI flag.
|
||||
- name: SharedArrayBuffer
|
||||
message: Use `const { SharedArrayBuffer } = globalThis;` instead of the global.
|
||||
- name: TextDecoder
|
||||
message: Use `const { TextDecoder } = require('internal/encoding');` instead of the global.
|
||||
- name: TextDecoderStream
|
||||
message: Use `const { TextDecoderStream } = require('internal/webstreams/encoding')` instead of the global.
|
||||
- name: TextEncoder
|
||||
message: Use `const { TextEncoder } = require('internal/encoding');` instead of the global.
|
||||
- name: TextEncoderStream
|
||||
message: Use `const { TextEncoderStream } = require('internal/webstreams/encoding')` instead of the global.
|
||||
- name: TransformStream
|
||||
message: Use `const { TransformStream } = require('internal/webstreams/transformstream')` instead of the global.
|
||||
- name: TransformStreamDefaultController
|
||||
message: Use `const { TransformStreamDefaultController } = require('internal/webstreams/transformstream')` instead of the global.
|
||||
- name: URL
|
||||
message: Use `const { URL } = require('internal/url');` instead of the global.
|
||||
- name: URLSearchParams
|
||||
message: Use `const { URLSearchParams } = require('internal/url');` instead of the global.
|
||||
# WebAssembly is not available in primordials because it can be
|
||||
# disabled with --jitless CLI flag.
|
||||
- name: WebAssembly
|
||||
message: Use `const { WebAssembly } = globalThis;` instead of the global.
|
||||
- name: WritableStream
|
||||
message: Use `const { WritableStream } = require('internal/webstreams/writablestream')` instead of the global.
|
||||
- name: WritableStreamDefaultWriter
|
||||
message: Use `const { WritableStreamDefaultWriter } = require('internal/webstreams/writablestream')` instead of the global.
|
||||
- name: WritableStreamDefaultController
|
||||
message: Use `const { WritableStreamDefaultController } = require('internal/webstreams/writablestream')` instead of the global.
|
||||
- name: atob
|
||||
message: Use `const { atob } = require('buffer');` instead of the global.
|
||||
- name: btoa
|
||||
message: Use `const { btoa } = require('buffer');` instead of the global.
|
||||
- name: clearImmediate
|
||||
message: Use `const { clearImmediate } = require('timers');` instead of the global.
|
||||
- name: clearInterval
|
||||
message: Use `const { clearInterval } = require('timers');` instead of the global.
|
||||
- name: clearTimeout
|
||||
message: Use `const { clearTimeout } = require('timers');` instead of the global.
|
||||
- name: console
|
||||
message: Use `const console = require('internal/console/global');` instead of the global.
|
||||
- name: crypto
|
||||
message: Use `const { crypto } = require('internal/crypto/webcrypto');` instead of the global.
|
||||
- name: Crypto
|
||||
message: Use `const { Crypto } = require('internal/crypto/webcrypto');` instead of the global.
|
||||
- name: CryptoKey
|
||||
message: Use `const { CryptoKey } = require('internal/crypto/webcrypto');` instead of the global.
|
||||
- name: EventSource
|
||||
message: Use `const { EventSource } = require('internal/deps/undici/undici');` instead of the global.
|
||||
- name: fetch
|
||||
message: Use `const { fetch } = require('internal/deps/undici/undici');` instead of the global.
|
||||
- name: global
|
||||
message: Use `const { globalThis } = primordials;` instead of `global`.
|
||||
- name: globalThis
|
||||
message: Use `const { globalThis } = primordials;` instead of the global.
|
||||
- name: performance
|
||||
message: Use `const { performance } = require('perf_hooks');` instead of the global.
|
||||
- name: queueMicrotask
|
||||
message: Use `const { queueMicrotask } = require('internal/process/task_queues');` instead of the global.
|
||||
- name: setImmediate
|
||||
message: Use `const { setImmediate } = require('timers');` instead of the global.
|
||||
- name: setInterval
|
||||
message: Use `const { setInterval } = require('timers');` instead of the global.
|
||||
- name: setTimeout
|
||||
message: Use `const { setTimeout } = require('timers');` instead of the global.
|
||||
- name: structuredClone
|
||||
message: Use `const { structuredClone } = internalBinding('messaging');` instead of the global.
|
||||
- name: SubtleCrypto
|
||||
message: Use `const { SubtleCrypto } = require('internal/crypto/webcrypto');` instead of the global.
|
||||
no-restricted-modules:
|
||||
- error
|
||||
- name: url
|
||||
message: Require `internal/url` instead of `url`.
|
||||
|
||||
# Stylistic rules
|
||||
'@stylistic/js/no-mixed-operators':
|
||||
- error
|
||||
- groups: [['&&', '||']]
|
||||
|
||||
# Custom rules in tools/eslint-rules
|
||||
node-core/alphabetize-errors: error
|
||||
node-core/alphabetize-primordials: error
|
||||
node-core/avoid-prototype-pollution: error
|
||||
node-core/lowercase-name-for-primitive: error
|
||||
node-core/non-ascii-character: error
|
||||
node-core/no-array-destructuring: error
|
||||
node-core/prefer-primordials:
|
||||
- error
|
||||
- name: AggregateError
|
||||
- name: Array
|
||||
- name: ArrayBuffer
|
||||
- name: Atomics
|
||||
- name: BigInt
|
||||
- name: BigInt64Array
|
||||
- name: BigUint64Array
|
||||
- name: Boolean
|
||||
- name: DataView
|
||||
- name: Date
|
||||
- name: decodeURI
|
||||
- name: decodeURIComponent
|
||||
- name: encodeURI
|
||||
- name: encodeURIComponent
|
||||
- name: escape
|
||||
- name: eval
|
||||
- name: Error
|
||||
ignore:
|
||||
- prepareStackTrace
|
||||
- stackTraceLimit
|
||||
- name: EvalError
|
||||
- name: FinalizationRegistry
|
||||
into: Safe
|
||||
- name: Float32Array
|
||||
- name: Float64Array
|
||||
- name: Function
|
||||
- name: Int16Array
|
||||
- name: Int32Array
|
||||
- name: Int8Array
|
||||
- name: isFinite
|
||||
into: Number
|
||||
- name: isNaN
|
||||
into: Number
|
||||
- name: JSON
|
||||
- name: Map
|
||||
into: Safe
|
||||
- name: Math
|
||||
- name: Number
|
||||
- name: Object
|
||||
- name: parseFloat
|
||||
into: Number
|
||||
- name: parseInt
|
||||
into: Number
|
||||
- name: Proxy
|
||||
- name: Promise
|
||||
- name: RangeError
|
||||
- name: ReferenceError
|
||||
- name: Reflect
|
||||
- name: RegExp
|
||||
- name: Set
|
||||
into: Safe
|
||||
- name: String
|
||||
- name: Symbol
|
||||
- name: SyntaxError
|
||||
- name: TypeError
|
||||
- name: Uint16Array
|
||||
- name: Uint32Array
|
||||
- name: Uint8Array
|
||||
- name: Uint8ClampedArray
|
||||
- name: unescape
|
||||
- name: URIError
|
||||
- name: WeakMap
|
||||
into: Safe
|
||||
- name: WeakRef
|
||||
into: Safe
|
||||
- name: WeakSet
|
||||
into: Safe
|
||||
globals:
|
||||
# Parameters passed to internal modules
|
||||
require: false
|
||||
process: false
|
||||
exports: false
|
||||
module: false
|
||||
internalBinding: false
|
||||
primordials: false
|
||||
overrides:
|
||||
- files: [internal/per_context/primordials.js]
|
||||
rules:
|
||||
node-core/alphabetize-primordials: [error, {enforceTopPosition: false}]
|
486
lib/eslint.config_partial.mjs
Normal file
486
lib/eslint.config_partial.mjs
Normal file
|
@ -0,0 +1,486 @@
|
|||
/* eslint-disable @stylistic/js/max-len */
|
||||
|
||||
import {
|
||||
noRestrictedSyntaxCommonAll,
|
||||
noRestrictedSyntaxCommonLib,
|
||||
} from '../tools/eslint.config_utils.mjs';
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ['lib/**/*.js'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
// Parameters passed to internal modules.
|
||||
require: 'readonly',
|
||||
process: 'readonly',
|
||||
exports: 'readonly',
|
||||
module: 'readonly',
|
||||
internalBinding: 'readonly',
|
||||
primordials: 'readonly',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'prefer-object-spread': 'error',
|
||||
'no-buffer-constructor': 'error',
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
...noRestrictedSyntaxCommonAll,
|
||||
...noRestrictedSyntaxCommonLib,
|
||||
{
|
||||
selector: "CallExpression[callee.object.name='assert']:not([callee.property.name='ok']):not([callee.property.name='fail']):not([callee.property.name='ifError'])",
|
||||
message: 'Please only use simple assertions in ./lib',
|
||||
},
|
||||
{
|
||||
selector: 'NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])',
|
||||
message: 'Use an error exported by the internal/errors module.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']",
|
||||
message: "Please use `require('internal/errors').hideStackFrames()` instead.",
|
||||
},
|
||||
{
|
||||
selector: "AssignmentExpression:matches([left.object.name='Error']):matches([left.name='prepareStackTrace'], [left.property.name='prepareStackTrace'])",
|
||||
message: "Use 'overrideStackTrace' from 'lib/internal/errors.js' instead of 'Error.prepareStackTrace'.",
|
||||
},
|
||||
{
|
||||
selector: "ThrowStatement > NewExpression[callee.name=/^ERR_[A-Z_]+$/] > ObjectExpression:first-child:not(:has([key.name='message']):has([key.name='code']):has([key.name='syscall']))",
|
||||
message: 'The context passed into SystemError constructor must have .code, .syscall and .message.',
|
||||
},
|
||||
],
|
||||
'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
name: 'AbortController',
|
||||
message: "Use `const { AbortController } = require('internal/abort_controller');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'AbortSignal',
|
||||
message: "Use `const { AbortSignal } = require('internal/abort_controller');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Blob',
|
||||
message: "Use `const { Blob } = require('buffer');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'BroadcastChannel',
|
||||
message: "Use `const { BroadcastChannel } = require('internal/worker/io');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Buffer',
|
||||
message: "Use `const { Buffer } = require('buffer');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ByteLengthQueuingStrategy',
|
||||
message: "Use `const { ByteLengthQueuingStrategy } = require('internal/webstreams/queuingstrategies')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'CompressionStream',
|
||||
message: "Use `const { CompressionStream } = require('internal/webstreams/compression')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'CountQueuingStrategy',
|
||||
message: "Use `const { CountQueuingStrategy } = require('internal/webstreams/queuingstrategies')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'CustomEvent',
|
||||
message: "Use `const { CustomEvent } = require('internal/event_target');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'DecompressionStream',
|
||||
message: "Use `const { DecompressionStream } = require('internal/webstreams/compression')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'DOMException',
|
||||
message: "Use lazy function `const { lazyDOMExceptionClass } = require('internal/util');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Event',
|
||||
message: "Use `const { Event } = require('internal/event_target');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'EventTarget',
|
||||
message: "Use `const { EventTarget } = require('internal/event_target');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'File',
|
||||
message: "Use `const { File } = require('buffer');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'FormData',
|
||||
message: "Use `const { FormData } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Headers',
|
||||
message: "Use `const { Headers } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
// Intl is not available in primordials because it can be
|
||||
// disabled with --without-intl build flag.
|
||||
{
|
||||
name: 'Intl',
|
||||
message: 'Use `const { Intl } = globalThis;` instead of the global.',
|
||||
},
|
||||
{
|
||||
name: 'Iterator',
|
||||
message: 'Use `const { Iterator } = globalThis;` instead of the global.',
|
||||
},
|
||||
{
|
||||
name: 'MessageChannel',
|
||||
message: "Use `const { MessageChannel } = require('internal/worker/io');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'MessageEvent',
|
||||
message: "Use `const { MessageEvent } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'MessagePort',
|
||||
message: "Use `const { MessagePort } = require('internal/worker/io');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Navigator',
|
||||
message: "Use `const { Navigator } = require('internal/navigator');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'navigator',
|
||||
message: "Use `const { navigator } = require('internal/navigator');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceEntry',
|
||||
message: "Use `const { PerformanceEntry } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceMark',
|
||||
message: "Use `const { PerformanceMark } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceMeasure',
|
||||
message: "Use `const { PerformanceMeasure } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceObserverEntryList',
|
||||
message: "Use `const { PerformanceObserverEntryList } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceObserver',
|
||||
message: "Use `const { PerformanceObserver } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'PerformanceResourceTiming',
|
||||
message: "Use `const { PerformanceResourceTiming } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableStream',
|
||||
message: "Use `const { ReadableStream } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableStreamDefaultReader',
|
||||
message: "Use `const { ReadableStreamDefaultReader } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableStreamBYOBReader',
|
||||
message: "Use `const { ReadableStreamBYOBReader } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableStreamBYOBRequest',
|
||||
message: "Use `const { ReadableStreamBYOBRequest } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableByteStreamController',
|
||||
message: "Use `const { ReadableByteStreamController } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'ReadableStreamDefaultController',
|
||||
message: "Use `const { ReadableStreamDefaultController } = require('internal/webstreams/readablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Request',
|
||||
message: "Use `const { Request } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Response',
|
||||
message: "Use `const { Response } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
// ShadowRealm is not available in primordials because it can be
|
||||
// disabled with --no-harmony-shadow-realm CLI flag.
|
||||
{
|
||||
name: 'ShadowRealm',
|
||||
message: 'Use `const { ShadowRealm } = globalThis;` instead of the global.',
|
||||
},
|
||||
// SharedArrayBuffer is not available in primordials because it can be
|
||||
// disabled with --no-harmony-sharedarraybuffer CLI flag.
|
||||
{
|
||||
name: 'SharedArrayBuffer',
|
||||
message: 'Use `const { SharedArrayBuffer } = globalThis;` instead of the global.',
|
||||
},
|
||||
{
|
||||
name: 'TextDecoder',
|
||||
message: "Use `const { TextDecoder } = require('internal/encoding');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'TextDecoderStream',
|
||||
message: "Use `const { TextDecoderStream } = require('internal/webstreams/encoding')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'TextEncoder',
|
||||
message: "Use `const { TextEncoder } = require('internal/encoding');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'TextEncoderStream',
|
||||
message: "Use `const { TextEncoderStream } = require('internal/webstreams/encoding')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'TransformStream',
|
||||
message: "Use `const { TransformStream } = require('internal/webstreams/transformstream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'TransformStreamDefaultController',
|
||||
message: "Use `const { TransformStreamDefaultController } = require('internal/webstreams/transformstream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'URL',
|
||||
message: "Use `const { URL } = require('internal/url');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'URLSearchParams',
|
||||
message: "Use `const { URLSearchParams } = require('internal/url');` instead of the global.",
|
||||
},
|
||||
// WebAssembly is not available in primordials because it can be
|
||||
// disabled with --jitless CLI flag.
|
||||
{
|
||||
name: 'WebAssembly',
|
||||
message: 'Use `const { WebAssembly } = globalThis;` instead of the global.',
|
||||
},
|
||||
{
|
||||
name: 'WritableStream',
|
||||
message: "Use `const { WritableStream } = require('internal/webstreams/writablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'WritableStreamDefaultWriter',
|
||||
message: "Use `const { WritableStreamDefaultWriter } = require('internal/webstreams/writablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'WritableStreamDefaultController',
|
||||
message: "Use `const { WritableStreamDefaultController } = require('internal/webstreams/writablestream')` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'atob',
|
||||
message: "Use `const { atob } = require('buffer');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'btoa',
|
||||
message: "Use `const { btoa } = require('buffer');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'clearImmediate',
|
||||
message: "Use `const { clearImmediate } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'clearInterval',
|
||||
message: "Use `const { clearInterval } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'clearTimeout',
|
||||
message: "Use `const { clearTimeout } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'console',
|
||||
message: "Use `const console = require('internal/console/global');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'crypto',
|
||||
message: "Use `const { crypto } = require('internal/crypto/webcrypto');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'Crypto',
|
||||
message: "Use `const { Crypto } = require('internal/crypto/webcrypto');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'CryptoKey',
|
||||
message: "Use `const { CryptoKey } = require('internal/crypto/webcrypto');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'EventSource',
|
||||
message: "Use `const { EventSource } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'fetch',
|
||||
message: "Use `const { fetch } = require('internal/deps/undici/undici');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'global',
|
||||
message: 'Use `const { globalThis } = primordials;` instead of `global`.',
|
||||
},
|
||||
{
|
||||
name: 'globalThis',
|
||||
message: 'Use `const { globalThis } = primordials;` instead of the global.',
|
||||
},
|
||||
{
|
||||
name: 'performance',
|
||||
message: "Use `const { performance } = require('perf_hooks');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'queueMicrotask',
|
||||
message: "Use `const { queueMicrotask } = require('internal/process/task_queues');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'setImmediate',
|
||||
message: "Use `const { setImmediate } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'setInterval',
|
||||
message: "Use `const { setInterval } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'setTimeout',
|
||||
message: "Use `const { setTimeout } = require('timers');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'structuredClone',
|
||||
message: "Use `const { structuredClone } = internalBinding('messaging');` instead of the global.",
|
||||
},
|
||||
{
|
||||
name: 'SubtleCrypto',
|
||||
message: "Use `const { SubtleCrypto } = require('internal/crypto/webcrypto');` instead of the global.",
|
||||
},
|
||||
],
|
||||
'no-restricted-modules': [
|
||||
'error',
|
||||
{
|
||||
name: 'url',
|
||||
message: 'Require `internal/url` instead of `url`.',
|
||||
},
|
||||
],
|
||||
|
||||
// Stylistic rules.
|
||||
'@stylistic/js/no-mixed-operators': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
['&&', '||'],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// Custom rules in tools/eslint-rules.
|
||||
'node-core/alphabetize-errors': 'error',
|
||||
'node-core/alphabetize-primordials': 'error',
|
||||
'node-core/avoid-prototype-pollution': 'error',
|
||||
'node-core/lowercase-name-for-primitive': 'error',
|
||||
'node-core/non-ascii-character': 'error',
|
||||
'node-core/no-array-destructuring': 'error',
|
||||
'node-core/prefer-primordials': [
|
||||
'error',
|
||||
{ name: 'AggregateError' },
|
||||
{ name: 'Array' },
|
||||
{ name: 'ArrayBuffer' },
|
||||
{ name: 'Atomics' },
|
||||
{ name: 'BigInt' },
|
||||
{ name: 'BigInt64Array' },
|
||||
{ name: 'BigUint64Array' },
|
||||
{ name: 'Boolean' },
|
||||
{ name: 'DataView' },
|
||||
{ name: 'Date' },
|
||||
{ name: 'decodeURI' },
|
||||
{ name: 'decodeURIComponent' },
|
||||
{ name: 'encodeURI' },
|
||||
{ name: 'encodeURIComponent' },
|
||||
{ name: 'escape' },
|
||||
{ name: 'eval' },
|
||||
{
|
||||
name: 'Error',
|
||||
ignore: [
|
||||
'prepareStackTrace',
|
||||
'stackTraceLimit',
|
||||
],
|
||||
},
|
||||
{ name: 'EvalError' },
|
||||
{
|
||||
name: 'FinalizationRegistry',
|
||||
into: 'Safe',
|
||||
},
|
||||
{ name: 'Float32Array' },
|
||||
{ name: 'Float64Array' },
|
||||
{ name: 'Function' },
|
||||
{ name: 'Int16Array' },
|
||||
{ name: 'Int32Array' },
|
||||
{ name: 'Int8Array' },
|
||||
{
|
||||
name: 'isFinite',
|
||||
into: 'Number',
|
||||
},
|
||||
{
|
||||
name: 'isNaN',
|
||||
into: 'Number',
|
||||
},
|
||||
{ name: 'JSON' },
|
||||
{
|
||||
name: 'Map',
|
||||
into: 'Safe',
|
||||
},
|
||||
{ name: 'Math' },
|
||||
{ name: 'Number' },
|
||||
{ name: 'Object' },
|
||||
{
|
||||
name: 'parseFloat',
|
||||
into: 'Number',
|
||||
},
|
||||
{
|
||||
name: 'parseInt',
|
||||
into: 'Number',
|
||||
},
|
||||
{ name: 'Proxy' },
|
||||
{ name: 'Promise' },
|
||||
{ name: 'RangeError' },
|
||||
{ name: 'ReferenceError' },
|
||||
{ name: 'Reflect' },
|
||||
{ name: 'RegExp' },
|
||||
{
|
||||
name: 'Set',
|
||||
into: 'Safe',
|
||||
},
|
||||
{ name: 'String' },
|
||||
{ name: 'Symbol' },
|
||||
{ name: 'SyntaxError' },
|
||||
{ name: 'TypeError' },
|
||||
{ name: 'Uint16Array' },
|
||||
{ name: 'Uint32Array' },
|
||||
{ name: 'Uint8Array' },
|
||||
{ name: 'Uint8ClampedArray' },
|
||||
{ name: 'unescape' },
|
||||
{ name: 'URIError' },
|
||||
{
|
||||
name: 'WeakMap',
|
||||
into: 'Safe',
|
||||
},
|
||||
{
|
||||
name: 'WeakRef',
|
||||
into: 'Safe',
|
||||
},
|
||||
{
|
||||
name: 'WeakSet',
|
||||
into: 'Safe',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['lib/internal/modules/**/*.js'],
|
||||
rules: {
|
||||
'curly': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['lib/internal/per_context/primordials.js'],
|
||||
rules: {
|
||||
'node-core/alphabetize-primordials': [
|
||||
'error',
|
||||
{ enforceTopPosition: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['lib/internal/test_runner/**/*.js'],
|
||||
rules: {
|
||||
'node-core/set-proto-to-null-in-object': 'error',
|
||||
},
|
||||
},
|
||||
];
|
|
@ -848,6 +848,7 @@ function guessHandleType(fd) {
|
|||
|
||||
class WeakReference {
|
||||
#weak = null;
|
||||
// eslint-disable-next-line no-unused-private-class-members
|
||||
#strong = null;
|
||||
#refCount = 0;
|
||||
constructor(object) {
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
## Test-specific linter rules
|
||||
|
||||
env:
|
||||
node: true
|
||||
es6: true
|
||||
|
||||
rules:
|
||||
multiline-comment-style: [error, separate-lines]
|
||||
prefer-const: error
|
||||
symbol-description: off
|
||||
|
||||
no-restricted-syntax:
|
||||
# Config copied from .eslintrc.js
|
||||
- error
|
||||
- selector: CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual']):matches([arguments.1.type='Literal']:not([arguments.1.regex]), [arguments.1.type='Identifier'][arguments.1.name='undefined'])
|
||||
message: Use strictEqual instead of deepStrictEqual for literals or undefined.
|
||||
- selector: CallExpression:matches([callee.name='notDeepStrictEqual'], [callee.property.name='notDeepStrictEqual']):matches([arguments.1.type='Literal']:not([arguments.1.regex]), [arguments.1.type='Identifier'][arguments.1.name='undefined'])
|
||||
message: Use notStrictEqual instead of notDeepStrictEqual for literals or undefined.
|
||||
- selector: CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual'])[arguments.2.type='Literal']
|
||||
message: Do not use a literal for the third argument of assert.deepStrictEqual()
|
||||
- selector: CallExpression:matches([callee.name='doesNotThrow'], [callee.property.name='doesNotThrow'])
|
||||
message: Do not use `assert.doesNotThrow()`. Write the code without the wrapper and add a comment instead.
|
||||
- selector: CallExpression:matches([callee.name='doesNotReject'], [callee.property.name='doesNotReject'])
|
||||
message: Do not use `assert.doesNotReject()`. Write the code without the wrapper and add a comment instead.
|
||||
- selector: CallExpression:matches([callee.name='rejects'], [callee.property.name='rejects'])[arguments.length<2]
|
||||
message: '`assert.rejects()` must be invoked with at least two arguments.'
|
||||
- selector: CallExpression[callee.property.name='strictEqual'][arguments.2.type='Literal']
|
||||
message: Do not use a literal for the third argument of assert.strictEqual()
|
||||
- selector: CallExpression:matches([callee.name='throws'], [callee.property.name='throws'])[arguments.1.type='Literal']:not([arguments.1.regex])
|
||||
message: Use an object as second argument of `assert.throws()`.
|
||||
- selector: CallExpression:matches([callee.name='throws'], [callee.property.name='throws'])[arguments.length<2]
|
||||
message: '`assert.throws()` must be invoked with at least two arguments.'
|
||||
- selector: CallExpression[callee.name='setInterval'][arguments.length<2]
|
||||
message: '`setInterval()` must be invoked with at least two arguments.'
|
||||
- selector: ThrowStatement > CallExpression[callee.name=/Error$/]
|
||||
message: Use `new` keyword when throwing an `Error`.
|
||||
- selector: CallExpression:matches([callee.name='notDeepStrictEqual'], [callee.property.name='notDeepStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])
|
||||
message: The first argument should be the `actual`, not the `expected` value.
|
||||
- selector: CallExpression:matches([callee.name='notStrictEqual'], [callee.property.name='notStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])
|
||||
message: The first argument should be the `actual`, not the `expected` value.
|
||||
- selector: CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])
|
||||
message: The first argument should be the `actual`, not the `expected` value.
|
||||
- selector: CallExpression:matches([callee.name='strictEqual'], [callee.property.name='strictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])
|
||||
message: The first argument should be the `actual`, not the `expected` value.
|
||||
- selector: CallExpression[callee.name='isNaN']
|
||||
message: Use Number.isNaN() instead of the global isNaN() function.
|
||||
- selector: VariableDeclarator > CallExpression:matches([callee.name='debuglog'], [callee.property.name='debuglog']):not([arguments.0.value='test'])
|
||||
message: Use 'test' as debuglog value in tests.
|
||||
- selector: CallExpression:matches([callee.object.name="common"][callee.property.name=/^must(Not)?Call/],[callee.name="mustCall"],[callee.name="mustCallAtLeast"],[callee.name="mustNotCall"])>:first-child[type=/FunctionExpression$/][body.body.length=0]
|
||||
message: Do not use an empty function, omit the parameter altogether.
|
||||
- selector: ExpressionStatement>CallExpression:matches([callee.name='rejects'], [callee.object.name='assert'][callee.property.name='rejects'])
|
||||
message: Calling `assert.rejects` without `await` or `.then(common.mustCall())` will not detect never-settling promises.
|
||||
- selector: Identifier[name='webcrypto']
|
||||
message: Use `globalThis.crypto`.
|
||||
|
||||
# Stylistic rules
|
||||
'@stylistic/js/comma-dangle': [error, always-multiline]
|
||||
|
||||
# Custom rules in tools/eslint-rules
|
||||
node-core/prefer-assert-iferror: error
|
||||
node-core/prefer-assert-methods: error
|
||||
node-core/prefer-common-mustnotcall: error
|
||||
node-core/prefer-common-mustsucceed: error
|
||||
node-core/crypto-check: error
|
||||
node-core/eslint-check: error
|
||||
node-core/async-iife-no-unused-result: error
|
||||
node-core/inspector-check: error
|
||||
## common module is mandatory in tests
|
||||
node-core/required-modules:
|
||||
- error
|
||||
- common: common(/index\.(m)?js)?$
|
||||
node-core/require-common-first: error
|
||||
node-core/no-duplicate-requires: off
|
||||
|
||||
# Global scoped methods and vars
|
||||
globals:
|
||||
WebAssembly: false
|
||||
|
||||
overrides:
|
||||
- files:
|
||||
- es-module/*.js
|
||||
- es-module/*.mjs
|
||||
- parallel/*.js
|
||||
- parallel/*.mjs
|
||||
- sequential/*.js
|
||||
- sequential/*.mjs
|
||||
rules:
|
||||
'@stylistic/js/comma-dangle': [error, {
|
||||
arrays: always-multiline,
|
||||
exports: always-multiline,
|
||||
functions: only-multiline,
|
||||
imports: always-multiline,
|
||||
objects: only-multiline,
|
||||
}]
|
|
@ -1,3 +0,0 @@
|
|||
rules:
|
||||
node-core/required-modules: off
|
||||
node-core/require-common-first: off
|
|
@ -189,7 +189,7 @@ if (process.env.NODE_TEST_WITH_ASYNC_HOOKS) {
|
|||
}
|
||||
initHandles[id] = {
|
||||
resource,
|
||||
stack: inspect(new Error()).substr(6),
|
||||
stack: inspect(new Error()).slice(6),
|
||||
};
|
||||
},
|
||||
before() { },
|
||||
|
|
165
test/eslint.config_partial.mjs
Normal file
165
test/eslint.config_partial.mjs
Normal file
|
@ -0,0 +1,165 @@
|
|||
/* eslint-disable @stylistic/js/max-len */
|
||||
|
||||
import {
|
||||
noRestrictedSyntaxCommonAll,
|
||||
noRestrictedSyntaxCommonTest,
|
||||
requireEslintTool,
|
||||
} from '../tools/eslint.config_utils.mjs';
|
||||
|
||||
const globals = requireEslintTool('globals');
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ['test/**/*.{js,mjs,cjs}'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'multiline-comment-style': [
|
||||
'error',
|
||||
'separate-lines',
|
||||
],
|
||||
'prefer-const': 'error',
|
||||
'symbol-description': 'off',
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
...noRestrictedSyntaxCommonAll,
|
||||
...noRestrictedSyntaxCommonTest,
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual']):matches([arguments.1.type='Literal']:not([arguments.1.regex]), [arguments.1.type='Identifier'][arguments.1.name='undefined'])",
|
||||
message: 'Use strictEqual instead of deepStrictEqual for literals or undefined.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='notDeepStrictEqual'], [callee.property.name='notDeepStrictEqual']):matches([arguments.1.type='Literal']:not([arguments.1.regex]), [arguments.1.type='Identifier'][arguments.1.name='undefined'])",
|
||||
message: 'Use notStrictEqual instead of notDeepStrictEqual for literals or undefined.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual'])[arguments.2.type='Literal']",
|
||||
message: 'Do not use a literal for the third argument of assert.deepStrictEqual()',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='doesNotThrow'], [callee.property.name='doesNotThrow'])",
|
||||
message: 'Do not use `assert.doesNotThrow()`. Write the code without the wrapper and add a comment instead.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='doesNotReject'], [callee.property.name='doesNotReject'])",
|
||||
message: 'Do not use `assert.doesNotReject()`. Write the code without the wrapper and add a comment instead.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='rejects'], [callee.property.name='rejects'])[arguments.length<2]",
|
||||
message: '`assert.rejects()` must be invoked with at least two arguments.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.property.name='strictEqual'][arguments.2.type='Literal']",
|
||||
message: 'Do not use a literal for the third argument of assert.strictEqual()',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='throws'], [callee.property.name='throws'])[arguments.1.type='Literal']:not([arguments.1.regex])",
|
||||
message: 'Use an object as second argument of `assert.throws()`.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='throws'], [callee.property.name='throws'])[arguments.length<2]",
|
||||
message: '`assert.throws()` must be invoked with at least two arguments.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='notDeepStrictEqual'], [callee.property.name='notDeepStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
|
||||
message: 'The first argument should be the `actual`, not the `expected` value.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='notStrictEqual'], [callee.property.name='notStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
|
||||
message: 'The first argument should be the `actual`, not the `expected` value.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='deepStrictEqual'], [callee.property.name='deepStrictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
|
||||
message: 'The first argument should be the `actual`, not the `expected` value.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression:matches([callee.name='strictEqual'], [callee.property.name='strictEqual'])[arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
|
||||
message: 'The first argument should be the `actual`, not the `expected` value.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='isNaN']",
|
||||
message: 'Use `Number.isNaN()` instead of the global `isNaN()` function.',
|
||||
},
|
||||
{
|
||||
selector: "VariableDeclarator > CallExpression:matches([callee.name='debuglog'], [callee.property.name='debuglog']):not([arguments.0.value='test'])",
|
||||
message: "Use 'test' as debuglog value in tests.",
|
||||
},
|
||||
{
|
||||
selector: 'CallExpression:matches([callee.object.name="common"][callee.property.name=/^must(Not)?Call/],[callee.name="mustCall"],[callee.name="mustCallAtLeast"],[callee.name="mustNotCall"])>:first-child[type=/FunctionExpression$/][body.body.length=0]',
|
||||
message: 'Do not use an empty function, omit the parameter altogether.',
|
||||
},
|
||||
{
|
||||
selector: "ExpressionStatement>CallExpression:matches([callee.name='rejects'], [callee.object.name='assert'][callee.property.name='rejects'])",
|
||||
message: 'Calling `assert.rejects` without `await` or `.then(common.mustCall())` will not detect never-settling promises.',
|
||||
},
|
||||
],
|
||||
|
||||
// Stylistic rules.
|
||||
'@stylistic/js/comma-dangle': [
|
||||
'error',
|
||||
'always-multiline',
|
||||
],
|
||||
|
||||
// Custom rules in tools/eslint-rules.
|
||||
'node-core/prefer-assert-iferror': 'error',
|
||||
'node-core/prefer-assert-methods': 'error',
|
||||
'node-core/prefer-common-mustnotcall': 'error',
|
||||
'node-core/prefer-common-mustsucceed': 'error',
|
||||
'node-core/crypto-check': 'error',
|
||||
'node-core/eslint-check': 'error',
|
||||
'node-core/async-iife-no-unused-result': 'error',
|
||||
'node-core/inspector-check': 'error',
|
||||
// `common` module is mandatory in tests.
|
||||
'node-core/required-modules': [
|
||||
'error',
|
||||
{ common: 'common(/index\\.(m)?js)?$' },
|
||||
],
|
||||
'node-core/require-common-first': 'error',
|
||||
'node-core/no-duplicate-requires': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'test/es-module/**/*.{js,mjs}',
|
||||
'test/parallel/**/*.{js,mjs}',
|
||||
'test/sequential/**/*.{js,mjs}',
|
||||
],
|
||||
rules: {
|
||||
'@stylistic/js/comma-dangle': [
|
||||
'error',
|
||||
{
|
||||
arrays: 'always-multiline',
|
||||
exports: 'always-multiline',
|
||||
functions: 'only-multiline',
|
||||
imports: 'always-multiline',
|
||||
objects: 'only-multiline',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'test/{common,wpt}/**/*.{js,mjs,cjs}',
|
||||
'test/eslint.config_partial.mjs',
|
||||
],
|
||||
rules: {
|
||||
'node-core/required-modules': 'off',
|
||||
'node-core/require-common-first': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'test/es-module/test-esm-example-loader.js',
|
||||
'test/es-module/test-esm-type-flag.js',
|
||||
'test/es-module/test-esm-type-flag-alias.js',
|
||||
'test/es-module/test-require-module-detect-entry-point.js',
|
||||
'test/es-module/test-require-module-detect-entry-point-aou.js',
|
||||
],
|
||||
languageOptions: {
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
];
|
|
@ -981,6 +981,7 @@ for (const input of inputs) {
|
|||
{
|
||||
|
||||
assert.throws(() => {
|
||||
// eslint-disable-next-line no-constant-binary-expression
|
||||
assert.ok((() => Boolean('' === false))());
|
||||
}, {
|
||||
message: 'The expression evaluated to a falsy value:\n\n' +
|
||||
|
|
|
@ -9,10 +9,7 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/alphabetize-errors');
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 6 },
|
||||
env: { es6: true }
|
||||
}).run('alphabetize-errors', rule, {
|
||||
new RuleTester().run('alphabetize-errors', rule, {
|
||||
valid: [
|
||||
{ code: `
|
||||
E('AAA', 'foo');
|
||||
|
|
|
@ -10,10 +10,7 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/alphabetize-primordials');
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 6 },
|
||||
env: { es6: true }
|
||||
})
|
||||
new RuleTester()
|
||||
.run('alphabetize-primordials', rule, {
|
||||
valid: [
|
||||
'new Array()',
|
||||
|
|
|
@ -11,7 +11,7 @@ const rule = require('../../tools/eslint-rules/async-iife-no-unused-result');
|
|||
const message = 'The result of an immediately-invoked async function needs ' +
|
||||
'to be used (e.g. with `.then(common.mustCall())`)';
|
||||
|
||||
const tester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
|
||||
const tester = new RuleTester();
|
||||
tester.run('async-iife-no-unused-result', rule, {
|
||||
valid: [
|
||||
'(() => {})()',
|
||||
|
@ -27,12 +27,10 @@ tester.run('async-iife-no-unused-result', rule, {
|
|||
{
|
||||
code: '(async () => {})()',
|
||||
errors: [{ message }],
|
||||
output: '(async () => {})()',
|
||||
},
|
||||
{
|
||||
code: '(async function() {})()',
|
||||
errors: [{ message }],
|
||||
output: '(async function() {})()',
|
||||
},
|
||||
{
|
||||
code: "const common = require('../common');(async () => {})()",
|
||||
|
|
|
@ -10,9 +10,7 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/avoid-prototype-pollution');
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 2022 },
|
||||
})
|
||||
new RuleTester()
|
||||
.run('property-descriptor-no-prototype-pollution', rule, {
|
||||
valid: [
|
||||
'ObjectDefineProperties({}, {})',
|
||||
|
@ -125,19 +123,46 @@ new RuleTester({
|
|||
},
|
||||
{
|
||||
code: 'ObjectDefineProperty({}, "key", ObjectGetOwnPropertyDescriptor({}, "key"))',
|
||||
errors: [{ message: /prototype pollution/ }],
|
||||
errors: [{
|
||||
message: /prototype pollution/,
|
||||
suggestions: [{
|
||||
desc: 'Wrap the property descriptor in a null-prototype object',
|
||||
output: 'ObjectDefineProperty({}, "key", { __proto__: null,...ObjectGetOwnPropertyDescriptor({}, "key") })',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
code: 'ReflectDefineProperty({}, "key", ObjectGetOwnPropertyDescriptor({}, "key"))',
|
||||
errors: [{ message: /prototype pollution/ }],
|
||||
errors: [{
|
||||
message: /prototype pollution/,
|
||||
suggestions: [{
|
||||
desc: 'Wrap the property descriptor in a null-prototype object',
|
||||
output:
|
||||
'ReflectDefineProperty({}, "key", { __proto__: null,...ObjectGetOwnPropertyDescriptor({}, "key") })',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
code: 'ObjectDefineProperty({}, "key", ReflectGetOwnPropertyDescriptor({}, "key"))',
|
||||
errors: [{ message: /prototype pollution/ }],
|
||||
errors: [{
|
||||
message: /prototype pollution/,
|
||||
suggestions: [{
|
||||
desc: 'Wrap the property descriptor in a null-prototype object',
|
||||
output:
|
||||
'ObjectDefineProperty({}, "key", { __proto__: null,...ReflectGetOwnPropertyDescriptor({}, "key") })',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
code: 'ReflectDefineProperty({}, "key", ReflectGetOwnPropertyDescriptor({}, "key"))',
|
||||
errors: [{ message: /prototype pollution/ }],
|
||||
errors: [{
|
||||
message: /prototype pollution/,
|
||||
suggestions: [{
|
||||
desc: 'Wrap the property descriptor in a null-prototype object',
|
||||
output:
|
||||
'ReflectDefineProperty({}, "key", { __proto__: null,...ReflectGetOwnPropertyDescriptor({}, "key") })',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
code: 'ObjectDefineProperty({}, "key", { __proto__: Object.prototype })',
|
||||
|
@ -193,7 +218,13 @@ new RuleTester({
|
|||
},
|
||||
{
|
||||
code: 'RegExpPrototypeTest(/some regex/, "some string")',
|
||||
errors: [{ message: /looks up the "exec" property/ }],
|
||||
errors: [{
|
||||
message: /looks up the "exec" property/,
|
||||
suggestions: [{
|
||||
desc: 'Use RegexpPrototypeExec instead',
|
||||
output: 'RegExpPrototypeExec(/some regex/, "some string") !== null',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
code: 'RegExpPrototypeSymbolMatch(/some regex/, "some string")',
|
||||
|
|
|
@ -10,7 +10,11 @@ common.skipIfEslintMissing();
|
|||
const { RuleTester } = require('../../tools/node_modules/eslint');
|
||||
const rule = require('../../tools/eslint-rules/no-duplicate-requires');
|
||||
|
||||
new RuleTester().run('no-duplicate-requires', rule, {
|
||||
new RuleTester({
|
||||
languageOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
}).run('no-duplicate-requires', rule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'require("a"); require("b"); (function() { require("a"); });',
|
||||
|
|
|
@ -15,10 +15,7 @@ const USE_OBJ_DESTRUCTURING =
|
|||
const USE_ARRAY_METHODS =
|
||||
'Use primordials.ArrayPrototypeSlice to avoid unsafe array iteration.';
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 2021 },
|
||||
env: { es6: true }
|
||||
})
|
||||
new RuleTester()
|
||||
.run('no-array-destructuring', rule, {
|
||||
valid: [
|
||||
'const first = [1, 2, 3][0];',
|
||||
|
|
|
@ -15,9 +15,7 @@ const msg1 = 'Please use common.mustSucceed instead of ' +
|
|||
const msg2 = 'Please use common.mustSucceed instead of ' +
|
||||
'common.mustCall with assert.ifError.';
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 2015 }
|
||||
}).run('prefer-common-mustsucceed', rule, {
|
||||
new RuleTester().run('prefer-common-mustsucceed', rule, {
|
||||
valid: [
|
||||
'foo((err) => assert.ifError(err))',
|
||||
'foo(function(err) { assert.ifError(err) })',
|
||||
|
|
|
@ -11,8 +11,9 @@ const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
|||
const rule = require('../../tools/eslint-rules/prefer-primordials');
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 6 },
|
||||
env: { es6: true }
|
||||
languageOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
})
|
||||
.run('prefer-primordials', rule, {
|
||||
valid: [
|
||||
|
|
|
@ -10,9 +10,7 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/prefer-proto');
|
||||
|
||||
new RuleTester({
|
||||
parserOptions: { ecmaVersion: 2022 }
|
||||
}).run('prefer-common-mustsucceed', rule, {
|
||||
new RuleTester().run('prefer-common-mustsucceed', rule, {
|
||||
valid: [
|
||||
'({ __proto__: null })',
|
||||
'const x = { __proto__: null };',
|
||||
|
|
|
@ -12,7 +12,7 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/prefer-util-format-errors');
|
||||
|
||||
new RuleTester({ parserOptions: { ecmaVersion: 6 } })
|
||||
new RuleTester()
|
||||
.run('prefer-util-format-errors', rule, {
|
||||
valid: [
|
||||
'E(\'ABC\', \'abc\');',
|
||||
|
|
|
@ -10,7 +10,11 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/require-common-first');
|
||||
|
||||
new RuleTester().run('require-common-first', rule, {
|
||||
new RuleTester({
|
||||
languageOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
}).run('require-common-first', rule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'require("common")\n' +
|
||||
|
|
|
@ -10,7 +10,11 @@ common.skipIfEslintMissing();
|
|||
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
|
||||
const rule = require('../../tools/eslint-rules/required-modules');
|
||||
|
||||
new RuleTester().run('required-modules', rule, {
|
||||
new RuleTester({
|
||||
languageOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
}).run('required-modules', rule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'require("common")',
|
||||
|
|
|
@ -559,6 +559,7 @@ test('mocks a constructor', (t) => {
|
|||
}
|
||||
|
||||
class MockClazz {
|
||||
// eslint-disable-next-line no-unused-private-class-members
|
||||
#privateValue;
|
||||
|
||||
constructor(z) {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
rules:
|
||||
node-core/required-modules: off
|
||||
node-core/require-common-first: off
|
|
@ -1,14 +0,0 @@
|
|||
env:
|
||||
node: true
|
||||
es6: true
|
||||
|
||||
rules:
|
||||
camelcase:
|
||||
- error
|
||||
- properties: never
|
||||
ignoreDestructuring: true
|
||||
allow: [child_process]
|
||||
no-unused-vars:
|
||||
- error
|
||||
- args: after-used
|
||||
prefer-arrow-callback: error
|
|
@ -43,8 +43,10 @@ rm -rf ../node_modules/eslint
|
|||
"$NODE" "$NPM" uninstall \
|
||||
--install-links=false \
|
||||
--ignore-scripts \
|
||||
eslint-formatter-tap \
|
||||
eslint-plugin-jsdoc \
|
||||
eslint-plugin-markdown \
|
||||
globals \
|
||||
@babel/core \
|
||||
@babel/eslint-parser \
|
||||
@babel/plugin-syntax-import-attributes \
|
||||
|
@ -59,8 +61,10 @@ rm -rf ../node_modules/eslint
|
|||
--no-save \
|
||||
--omit=dev \
|
||||
--omit=peer \
|
||||
eslint-formatter-tap \
|
||||
eslint-plugin-jsdoc \
|
||||
eslint-plugin-markdown \
|
||||
globals \
|
||||
@babel/core \
|
||||
@babel/eslint-parser \
|
||||
@babel/plugin-syntax-import-attributes \
|
||||
|
|
|
@ -148,9 +148,9 @@ module.exports = {
|
|||
suggest: [{
|
||||
desc: 'Use RegexpPrototypeExec instead',
|
||||
fix(fixer) {
|
||||
const testRange = { ...node.range };
|
||||
testRange.start = testRange.start + 'RegexpPrototype'.length;
|
||||
testRange.end = testRange.start + 'Test'.length;
|
||||
const testRange = [ ...node.range ];
|
||||
testRange[0] = testRange[0] + 'RegexpPrototype'.length;
|
||||
testRange[1] = testRange[0] + 'Test'.length;
|
||||
return [
|
||||
fixer.replaceTextRange(testRange, 'Exec'),
|
||||
fixer.insertTextAfter(node, ' !== null'),
|
||||
|
|
|
@ -27,7 +27,7 @@ function isTopLevel(node) {
|
|||
|
||||
module.exports = {
|
||||
create(context) {
|
||||
if (context.parserOptions.sourceType === 'module') {
|
||||
if (context.languageOptions.sourceType === 'module') {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ const { isRequireCall, isString } = require('./rules-utils.js');
|
|||
module.exports = {
|
||||
create(context) {
|
||||
const requiredModule = 'common';
|
||||
const isESM = context.parserOptions.sourceType === 'module';
|
||||
const isESM = context.languageOptions.sourceType === 'module';
|
||||
const foundModules = [];
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = {
|
|||
const requiredModules = options ? Object.keys(options).map((x) => {
|
||||
return [ x, new RegExp(options[x]) ];
|
||||
}) : [];
|
||||
const isESM = context.parserOptions.sourceType === 'module';
|
||||
const isESM = context.languageOptions.sourceType === 'module';
|
||||
|
||||
const foundModules = [];
|
||||
|
||||
|
|
29
tools/eslint.config_partial.mjs
Normal file
29
tools/eslint.config_partial.mjs
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { requireEslintTool } from './eslint.config_utils.mjs';
|
||||
|
||||
const globals = requireEslintTool('globals');
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ['tools/**/*.{js,mjs,cjs}'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'camelcase': [
|
||||
'error',
|
||||
{
|
||||
properties: 'never',
|
||||
ignoreDestructuring: true,
|
||||
allow: ['child_process'],
|
||||
},
|
||||
],
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{ args: 'after-used' },
|
||||
],
|
||||
'prefer-arrow-callback': 'error',
|
||||
},
|
||||
},
|
||||
];
|
35
tools/eslint.config_utils.mjs
Normal file
35
tools/eslint.config_utils.mjs
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { createRequire } from 'node:module';
|
||||
|
||||
export const requireEslintTool = createRequire(new URL('./node_modules/eslint/', import.meta.url));
|
||||
export const resolveEslintTool = (request) => requireEslintTool.resolve(request);
|
||||
|
||||
export const noRestrictedSyntaxCommonAll = [
|
||||
{
|
||||
selector: "CallExpression[callee.name='setInterval'][arguments.length<2]",
|
||||
message: '`setInterval()` must be invoked with at least two arguments.',
|
||||
},
|
||||
{
|
||||
selector: 'ThrowStatement > CallExpression[callee.name=/Error$/]',
|
||||
message: 'Use `new` keyword when throwing an `Error`.',
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.property.name='substr']",
|
||||
message: 'Use String.prototype.slice() or String.prototype.substring() instead of String.prototype.substr()',
|
||||
},
|
||||
];
|
||||
|
||||
export const noRestrictedSyntaxCommonLib = [
|
||||
{
|
||||
selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]",
|
||||
message: '`setTimeout()` must be invoked with at least two arguments.',
|
||||
},
|
||||
];
|
||||
|
||||
export const noRestrictedSyntaxCommonTest = [
|
||||
{
|
||||
// TODO(@panva): move this to no-restricted-properties
|
||||
// when https://github.com/eslint/eslint/issues/16412 is fixed.
|
||||
selector: "Identifier[name='webcrypto']",
|
||||
message: 'Use `globalThis.crypto`.',
|
||||
},
|
||||
];
|
|
@ -928,6 +928,13 @@ int Main(int argc, char* argv[]) {
|
|||
auto mjs_it = file_map.find(".mjs");
|
||||
assert(js_it != file_map.end() && mjs_it != file_map.end());
|
||||
|
||||
auto it = std::find(mjs_it->second.begin(),
|
||||
mjs_it->second.end(),
|
||||
"lib/eslint.config_partial.mjs");
|
||||
if (it != mjs_it->second.end()) {
|
||||
mjs_it->second.erase(it);
|
||||
}
|
||||
|
||||
std::sort(js_it->second.begin(), js_it->second.end());
|
||||
std::sort(mjs_it->second.begin(), mjs_it->second.end());
|
||||
|
||||
|
|
9
tools/node_modules/eslint/bin/eslint.js
generated
vendored
9
tools/node_modules/eslint/bin/eslint.js
generated
vendored
|
@ -64,7 +64,7 @@ function readStdin() {
|
|||
function getErrorMessage(error) {
|
||||
|
||||
// Lazy loading because this is used only if an error happened.
|
||||
const util = require("util");
|
||||
const util = require("node:util");
|
||||
|
||||
// Foolproof -- third-party module might throw non-object.
|
||||
if (typeof error !== "object" || error === null) {
|
||||
|
@ -140,16 +140,17 @@ ${getErrorMessage(error)}`;
|
|||
if (process.argv.includes("--init")) {
|
||||
|
||||
// `eslint --init` has been moved to `@eslint/create-config`
|
||||
console.warn("You can also run this command directly using 'npm init @eslint/config'.");
|
||||
console.warn("You can also run this command directly using 'npm init @eslint/config@latest'.");
|
||||
|
||||
const spawn = require("cross-spawn");
|
||||
|
||||
spawn.sync("npm", ["init", "@eslint/config"], { encoding: "utf8", stdio: "inherit" });
|
||||
spawn.sync("npm", ["init", "@eslint/config@latest"], { encoding: "utf8", stdio: "inherit" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, call the CLI.
|
||||
const exitCode = await require("../lib/cli").execute(
|
||||
const cli = require("../lib/cli");
|
||||
const exitCode = await cli.execute(
|
||||
process.argv,
|
||||
process.argv.includes("--stdin") ? await readStdin() : null,
|
||||
true
|
||||
|
|
93
tools/node_modules/eslint/conf/config-schema.js
generated
vendored
93
tools/node_modules/eslint/conf/config-schema.js
generated
vendored
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* STOP!!! DO NOT MODIFY.
|
||||
*
|
||||
* This file is part of the ongoing work to move the eslintrc-style config
|
||||
* system into the @eslint/eslintrc package. This file needs to remain
|
||||
* unchanged in order for this work to proceed.
|
||||
*
|
||||
* If you think you need to change this file, please contact @nzakas first.
|
||||
*
|
||||
* Thanks in advance for your cooperation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Defines a schema for configs.
|
||||
* @author Sylvan Mably
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const baseConfigProperties = {
|
||||
$schema: { type: "string" },
|
||||
env: { type: "object" },
|
||||
extends: { $ref: "#/definitions/stringOrStrings" },
|
||||
globals: { type: "object" },
|
||||
overrides: {
|
||||
type: "array",
|
||||
items: { $ref: "#/definitions/overrideConfig" },
|
||||
additionalItems: false
|
||||
},
|
||||
parser: { type: ["string", "null"] },
|
||||
parserOptions: { type: "object" },
|
||||
plugins: { type: "array" },
|
||||
processor: { type: "string" },
|
||||
rules: { type: "object" },
|
||||
settings: { type: "object" },
|
||||
noInlineConfig: { type: "boolean" },
|
||||
reportUnusedDisableDirectives: { type: "boolean" },
|
||||
|
||||
ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
|
||||
};
|
||||
|
||||
const configSchema = {
|
||||
definitions: {
|
||||
stringOrStrings: {
|
||||
oneOf: [
|
||||
{ type: "string" },
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
additionalItems: false
|
||||
}
|
||||
]
|
||||
},
|
||||
stringOrStringsRequired: {
|
||||
oneOf: [
|
||||
{ type: "string" },
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
additionalItems: false,
|
||||
minItems: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// Config at top-level.
|
||||
objectConfig: {
|
||||
type: "object",
|
||||
properties: {
|
||||
root: { type: "boolean" },
|
||||
ignorePatterns: { $ref: "#/definitions/stringOrStrings" },
|
||||
...baseConfigProperties
|
||||
},
|
||||
additionalProperties: false
|
||||
},
|
||||
|
||||
// Config in `overrides`.
|
||||
overrideConfig: {
|
||||
type: "object",
|
||||
properties: {
|
||||
excludedFiles: { $ref: "#/definitions/stringOrStrings" },
|
||||
files: { $ref: "#/definitions/stringOrStringsRequired" },
|
||||
...baseConfigProperties
|
||||
},
|
||||
required: ["files"],
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
|
||||
$ref: "#/definitions/objectConfig"
|
||||
};
|
||||
|
||||
module.exports = configSchema;
|
16
tools/node_modules/eslint/conf/ecma-version.js
generated
vendored
Normal file
16
tools/node_modules/eslint/conf/ecma-version.js
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @fileoverview Configuration related to ECMAScript versions
|
||||
* @author Milos Djermanovic
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The latest ECMAScript version supported by ESLint.
|
||||
* @type {number} year-based ECMAScript version
|
||||
*/
|
||||
const LATEST_ECMA_VERSION = 2024;
|
||||
|
||||
module.exports = {
|
||||
LATEST_ECMA_VERSION
|
||||
};
|
1
tools/node_modules/eslint/conf/globals.js
generated
vendored
1
tools/node_modules/eslint/conf/globals.js
generated
vendored
|
@ -70,6 +70,7 @@ const es2015 = {
|
|||
Int16Array: false,
|
||||
Int32Array: false,
|
||||
Int8Array: false,
|
||||
Intl: false,
|
||||
Map: false,
|
||||
Promise: false,
|
||||
Proxy: false,
|
||||
|
|
4
tools/node_modules/eslint/conf/rule-type-list.json
generated
vendored
4
tools/node_modules/eslint/conf/rule-type-list.json
generated
vendored
|
@ -23,6 +23,8 @@
|
|||
{ "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] },
|
||||
{ "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] },
|
||||
{ "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] },
|
||||
{ "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] }
|
||||
{ "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] },
|
||||
{ "removed": "valid-jsdoc", "replacedBy": [] },
|
||||
{ "removed": "require-jsdoc", "replacedBy": [] }
|
||||
]
|
||||
}
|
||||
|
|
18
tools/node_modules/eslint/lib/api.js
generated
vendored
18
tools/node_modules/eslint/lib/api.js
generated
vendored
|
@ -9,8 +9,8 @@
|
|||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { ESLint, FlatESLint } = require("./eslint");
|
||||
const { shouldUseFlatConfig } = require("./eslint/flat-eslint");
|
||||
const { ESLint, shouldUseFlatConfig } = require("./eslint/eslint");
|
||||
const { LegacyESLint } = require("./eslint/legacy-eslint");
|
||||
const { Linter } = require("./linter");
|
||||
const { RuleTester } = require("./rule-tester");
|
||||
const { SourceCode } = require("./source-code");
|
||||
|
@ -23,22 +23,18 @@ const { SourceCode } = require("./source-code");
|
|||
* Loads the correct ESLint constructor given the options.
|
||||
* @param {Object} [options] The options object
|
||||
* @param {boolean} [options.useFlatConfig] Whether or not to use a flat config
|
||||
* @param {string} [options.cwd] The current working directory
|
||||
* @returns {Promise<ESLint|LegacyESLint>} The ESLint constructor
|
||||
*/
|
||||
async function loadESLint({ useFlatConfig, cwd = process.cwd() } = {}) {
|
||||
async function loadESLint({ useFlatConfig } = {}) {
|
||||
|
||||
/*
|
||||
* Note: The v9.x version of this function doesn't have a cwd option
|
||||
* because it's not used. It's only used in the v8.x version of this
|
||||
* function.
|
||||
* Note: The v8.x version of this function also accepted a `cwd` option, but
|
||||
* it is not used in this implementation so we silently ignore it.
|
||||
*/
|
||||
|
||||
const shouldESLintUseFlatConfig = typeof useFlatConfig === "boolean"
|
||||
? useFlatConfig
|
||||
: await shouldUseFlatConfig({ cwd });
|
||||
const shouldESLintUseFlatConfig = useFlatConfig ?? (await shouldUseFlatConfig());
|
||||
|
||||
return shouldESLintUseFlatConfig ? FlatESLint : ESLint;
|
||||
return shouldESLintUseFlatConfig ? ESLint : LegacyESLint;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
21
tools/node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
21
tools/node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
|
@ -15,8 +15,8 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const defaultOptions = require("../../conf/default-cli-options");
|
||||
const pkg = require("../../package.json");
|
||||
|
||||
|
@ -41,6 +41,17 @@ const hash = require("./hash");
|
|||
const LintResultCache = require("./lint-result-cache");
|
||||
|
||||
const debug = require("debug")("eslint:cli-engine");
|
||||
const removedFormatters = new Set([
|
||||
"checkstyle",
|
||||
"codeframe",
|
||||
"compact",
|
||||
"jslint-xml",
|
||||
"junit",
|
||||
"table",
|
||||
"tap",
|
||||
"unix",
|
||||
"visualstudio"
|
||||
]);
|
||||
const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -639,7 +650,7 @@ class CLIEngine {
|
|||
});
|
||||
const lintResultCache =
|
||||
options.cache ? new LintResultCache(cacheFilePath, options.cacheStrategy) : null;
|
||||
const linter = new Linter({ cwd: options.cwd });
|
||||
const linter = new Linter({ cwd: options.cwd, configType: "eslintrc" });
|
||||
|
||||
/** @type {ConfigArray[]} */
|
||||
const lastConfigArrays = [configArrayFactory.getConfigArrayForFile()];
|
||||
|
@ -721,7 +732,7 @@ class CLIEngine {
|
|||
* @returns {void}
|
||||
*/
|
||||
static outputFixes(report) {
|
||||
report.results.filter(result => Object.prototype.hasOwnProperty.call(result, "output")).forEach(result => {
|
||||
report.results.filter(result => Object.hasOwn(result, "output")).forEach(result => {
|
||||
fs.writeFileSync(result.filePath, result.output);
|
||||
});
|
||||
}
|
||||
|
@ -1047,7 +1058,7 @@ class CLIEngine {
|
|||
try {
|
||||
return require(formatterPath);
|
||||
} catch (ex) {
|
||||
if (format === "table" || format === "codeframe") {
|
||||
if (removedFormatters.has(format)) {
|
||||
ex.message = `The ${format} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${format}\``;
|
||||
} else {
|
||||
ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
|
||||
|
|
4
tools/node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
4
tools/node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
|
@ -34,8 +34,8 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const getGlobParent = require("glob-parent");
|
||||
const isGlob = require("is-glob");
|
||||
const escapeRegExp = require("escape-string-regexp");
|
||||
|
|
60
tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js
generated
vendored
60
tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js
generated
vendored
|
@ -1,60 +0,0 @@
|
|||
/**
|
||||
* @fileoverview CheckStyle XML reporter
|
||||
* @author Ian Christian Myers
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const xmlEscape = require("../xml-escape");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the severity of warning or error
|
||||
* @param {Object} message message object to examine
|
||||
* @returns {string} severity level
|
||||
* @private
|
||||
*/
|
||||
function getMessageType(message) {
|
||||
if (message.fatal || message.severity === 2) {
|
||||
return "error";
|
||||
}
|
||||
return "warning";
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "";
|
||||
|
||||
output += "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
||||
output += "<checkstyle version=\"4.3\">";
|
||||
|
||||
results.forEach(result => {
|
||||
const messages = result.messages;
|
||||
|
||||
output += `<file name="${xmlEscape(result.filePath)}">`;
|
||||
|
||||
messages.forEach(message => {
|
||||
output += [
|
||||
`<error line="${xmlEscape(message.line || 0)}"`,
|
||||
`column="${xmlEscape(message.column || 0)}"`,
|
||||
`severity="${xmlEscape(getMessageType(message))}"`,
|
||||
`message="${xmlEscape(message.message)}${message.ruleId ? ` (${message.ruleId})` : ""}"`,
|
||||
`source="${message.ruleId ? xmlEscape(`eslint.rules.${message.ruleId}`) : ""}" />`
|
||||
].join(" ");
|
||||
});
|
||||
|
||||
output += "</file>";
|
||||
|
||||
});
|
||||
|
||||
output += "</checkstyle>";
|
||||
|
||||
return output;
|
||||
};
|
60
tools/node_modules/eslint/lib/cli-engine/formatters/compact.js
generated
vendored
60
tools/node_modules/eslint/lib/cli-engine/formatters/compact.js
generated
vendored
|
@ -1,60 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Compact reporter
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the severity of warning or error
|
||||
* @param {Object} message message object to examine
|
||||
* @returns {string} severity level
|
||||
* @private
|
||||
*/
|
||||
function getMessageType(message) {
|
||||
if (message.fatal || message.severity === 2) {
|
||||
return "Error";
|
||||
}
|
||||
return "Warning";
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "",
|
||||
total = 0;
|
||||
|
||||
results.forEach(result => {
|
||||
|
||||
const messages = result.messages;
|
||||
|
||||
total += messages.length;
|
||||
|
||||
messages.forEach(message => {
|
||||
|
||||
output += `${result.filePath}: `;
|
||||
output += `line ${message.line || 0}`;
|
||||
output += `, col ${message.column || 0}`;
|
||||
output += `, ${getMessageType(message)}`;
|
||||
output += ` - ${message.message}`;
|
||||
output += message.ruleId ? ` (${message.ruleId})` : "";
|
||||
output += "\n";
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if (total > 0) {
|
||||
output += `\n${total} problem${total !== 1 ? "s" : ""}`;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
30
tools/node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
30
tools/node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
|
@ -1,20 +1,8 @@
|
|||
[
|
||||
{
|
||||
"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](../../integrate/nodejs-api) to programmatically use ESLint."
|
||||
|
@ -23,24 +11,8 @@
|
|||
"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](../../integrate/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."
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
41
tools/node_modules/eslint/lib/cli-engine/formatters/jslint-xml.js
generated
vendored
41
tools/node_modules/eslint/lib/cli-engine/formatters/jslint-xml.js
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @fileoverview JSLint XML reporter
|
||||
* @author Ian Christian Myers
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const xmlEscape = require("../xml-escape");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "";
|
||||
|
||||
output += "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
||||
output += "<jslint>";
|
||||
|
||||
results.forEach(result => {
|
||||
const messages = result.messages;
|
||||
|
||||
output += `<file name="${result.filePath}">`;
|
||||
|
||||
messages.forEach(message => {
|
||||
output += [
|
||||
`<issue line="${message.line}"`,
|
||||
`char="${message.column}"`,
|
||||
`evidence="${xmlEscape(message.source || "")}"`,
|
||||
`reason="${xmlEscape(message.message || "")}${message.ruleId ? ` (${message.ruleId})` : ""}" />`
|
||||
].join(" ");
|
||||
});
|
||||
|
||||
output += "</file>";
|
||||
|
||||
});
|
||||
|
||||
output += "</jslint>";
|
||||
|
||||
return output;
|
||||
};
|
82
tools/node_modules/eslint/lib/cli-engine/formatters/junit.js
generated
vendored
82
tools/node_modules/eslint/lib/cli-engine/formatters/junit.js
generated
vendored
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
* @fileoverview jUnit Reporter
|
||||
* @author Jamund Ferguson
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const xmlEscape = require("../xml-escape");
|
||||
const path = require("path");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the severity of warning or error
|
||||
* @param {Object} message message object to examine
|
||||
* @returns {string} severity level
|
||||
* @private
|
||||
*/
|
||||
function getMessageType(message) {
|
||||
if (message.fatal || message.severity === 2) {
|
||||
return "Error";
|
||||
}
|
||||
return "Warning";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full file path without extension
|
||||
* @param {string} filePath input file path
|
||||
* @returns {string} file path without extension
|
||||
* @private
|
||||
*/
|
||||
function pathWithoutExt(filePath) {
|
||||
return path.join(path.dirname(filePath), path.basename(filePath, path.extname(filePath)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "";
|
||||
|
||||
output += "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
|
||||
output += "<testsuites>\n";
|
||||
|
||||
results.forEach(result => {
|
||||
|
||||
const messages = result.messages;
|
||||
const classname = pathWithoutExt(result.filePath);
|
||||
|
||||
if (messages.length > 0) {
|
||||
output += `<testsuite package="org.eslint" time="0" tests="${messages.length}" errors="${messages.length}" name="${result.filePath}">\n`;
|
||||
messages.forEach(message => {
|
||||
const type = message.fatal ? "error" : "failure";
|
||||
|
||||
output += `<testcase time="0" name="org.eslint.${message.ruleId || "unknown"}" classname="${classname}">`;
|
||||
output += `<${type} message="${xmlEscape(message.message || "")}">`;
|
||||
output += "<![CDATA[";
|
||||
output += `line ${message.line || 0}, col `;
|
||||
output += `${message.column || 0}, ${getMessageType(message)}`;
|
||||
output += ` - ${xmlEscape(message.message || "")}`;
|
||||
output += (message.ruleId ? ` (${message.ruleId})` : "");
|
||||
output += "]]>";
|
||||
output += `</${type}>`;
|
||||
output += "</testcase>\n";
|
||||
});
|
||||
output += "</testsuite>\n";
|
||||
} else {
|
||||
output += `<testsuite package="org.eslint" time="0" tests="1" errors="0" name="${result.filePath}">\n`;
|
||||
output += `<testcase time="0" name="${result.filePath}" classname="${classname}" />\n`;
|
||||
output += "</testsuite>\n";
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
output += "</testsuites>\n";
|
||||
|
||||
return output;
|
||||
};
|
58
tools/node_modules/eslint/lib/cli-engine/formatters/unix.js
generated
vendored
58
tools/node_modules/eslint/lib/cli-engine/formatters/unix.js
generated
vendored
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* @fileoverview unix-style formatter.
|
||||
* @author oshi-shinobu
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a canonical error level string based upon the error message passed in.
|
||||
* @param {Object} message Individual error message provided by eslint
|
||||
* @returns {string} Error level string
|
||||
*/
|
||||
function getMessageType(message) {
|
||||
if (message.fatal || message.severity === 2) {
|
||||
return "Error";
|
||||
}
|
||||
return "Warning";
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "",
|
||||
total = 0;
|
||||
|
||||
results.forEach(result => {
|
||||
|
||||
const messages = result.messages;
|
||||
|
||||
total += messages.length;
|
||||
|
||||
messages.forEach(message => {
|
||||
|
||||
output += `${result.filePath}:`;
|
||||
output += `${message.line || 0}:`;
|
||||
output += `${message.column || 0}:`;
|
||||
output += ` ${message.message} `;
|
||||
output += `[${getMessageType(message)}${message.ruleId ? `/${message.ruleId}` : ""}]`;
|
||||
output += "\n";
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if (total > 0) {
|
||||
output += `\n${total} problem${total !== 1 ? "s" : ""}`;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
63
tools/node_modules/eslint/lib/cli-engine/formatters/visualstudio.js
generated
vendored
63
tools/node_modules/eslint/lib/cli-engine/formatters/visualstudio.js
generated
vendored
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Visual Studio compatible formatter
|
||||
* @author Ronald Pijnacker
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the severity of warning or error
|
||||
* @param {Object} message message object to examine
|
||||
* @returns {string} severity level
|
||||
* @private
|
||||
*/
|
||||
function getMessageType(message) {
|
||||
if (message.fatal || message.severity === 2) {
|
||||
return "error";
|
||||
}
|
||||
return "warning";
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
|
||||
let output = "",
|
||||
total = 0;
|
||||
|
||||
results.forEach(result => {
|
||||
|
||||
const messages = result.messages;
|
||||
|
||||
total += messages.length;
|
||||
|
||||
messages.forEach(message => {
|
||||
|
||||
output += result.filePath;
|
||||
output += `(${message.line || 0}`;
|
||||
output += message.column ? `,${message.column}` : "";
|
||||
output += `): ${getMessageType(message)}`;
|
||||
output += message.ruleId ? ` ${message.ruleId}` : "";
|
||||
output += ` : ${message.message}`;
|
||||
output += "\n";
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if (total === 0) {
|
||||
output += "no problems";
|
||||
} else {
|
||||
output += `\n${total} problem${total !== 1 ? "s" : ""}`;
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
8
tools/node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
8
tools/node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
|
@ -8,8 +8,8 @@
|
|||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const fileEntryCache = require("file-entry-cache");
|
||||
const stringify = require("json-stable-stringify-without-jsonify");
|
||||
const pkg = require("../../package.json");
|
||||
|
@ -164,7 +164,7 @@ class LintResultCache {
|
|||
* @returns {void}
|
||||
*/
|
||||
setCachedLintResults(filePath, config, result) {
|
||||
if (result && Object.prototype.hasOwnProperty.call(result, "output")) {
|
||||
if (result && Object.hasOwn(result, "output")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ class LintResultCache {
|
|||
* In `getCachedLintResults`, if source is explicitly null, we will
|
||||
* read the file from the filesystem to set the value again.
|
||||
*/
|
||||
if (Object.prototype.hasOwnProperty.call(resultToSerialize, "source")) {
|
||||
if (Object.hasOwn(resultToSerialize, "source")) {
|
||||
resultToSerialize.source = null;
|
||||
}
|
||||
|
||||
|
|
4
tools/node_modules/eslint/lib/cli-engine/load-rules.js
generated
vendored
4
tools/node_modules/eslint/lib/cli-engine/load-rules.js
generated
vendored
|
@ -9,8 +9,8 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
path = require("path");
|
||||
const fs = require("node:fs"),
|
||||
path = require("node:path");
|
||||
|
||||
const rulesDirCache = {};
|
||||
|
||||
|
|
34
tools/node_modules/eslint/lib/cli-engine/xml-escape.js
generated
vendored
34
tools/node_modules/eslint/lib/cli-engine/xml-escape.js
generated
vendored
|
@ -1,34 +0,0 @@
|
|||
/**
|
||||
* @fileoverview XML character escaper
|
||||
* @author George Chung
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the escaped value for a character
|
||||
* @param {string} s string to examine
|
||||
* @returns {string} severity level
|
||||
* @private
|
||||
*/
|
||||
module.exports = function(s) {
|
||||
return (`${s}`).replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, c => { // eslint-disable-line no-control-regex -- Converting controls to entities
|
||||
switch (c) {
|
||||
case "<":
|
||||
return "<";
|
||||
case ">":
|
||||
return ">";
|
||||
case "&":
|
||||
return "&";
|
||||
case "\"":
|
||||
return """;
|
||||
case "'":
|
||||
return "'";
|
||||
default:
|
||||
return `&#${c.charCodeAt(0)};`;
|
||||
}
|
||||
});
|
||||
};
|
159
tools/node_modules/eslint/lib/cli.js
generated
vendored
159
tools/node_modules/eslint/lib/cli.js
generated
vendored
|
@ -15,11 +15,11 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
path = require("path"),
|
||||
{ promisify } = require("util"),
|
||||
{ ESLint } = require("./eslint"),
|
||||
{ FlatESLint, shouldUseFlatConfig } = require("./eslint/flat-eslint"),
|
||||
const fs = require("node:fs"),
|
||||
path = require("node:path"),
|
||||
{ promisify } = require("node:util"),
|
||||
{ LegacyESLint } = require("./eslint"),
|
||||
{ ESLint, shouldUseFlatConfig, locateConfigFileToUse } = require("./eslint/eslint"),
|
||||
createCLIOptions = require("./options"),
|
||||
log = require("./shared/logging"),
|
||||
RuntimeInfo = require("./shared/runtime-info"),
|
||||
|
@ -37,6 +37,7 @@ const debug = require("debug")("eslint:cli");
|
|||
/** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
|
||||
/** @typedef {import("./eslint/eslint").LintResult} LintResult */
|
||||
/** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
|
||||
/** @typedef {import("./shared/types").Plugin} Plugin */
|
||||
/** @typedef {import("./shared/types").ResultsMeta} ResultsMeta */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -47,6 +48,32 @@ const mkdir = promisify(fs.mkdir);
|
|||
const stat = promisify(fs.stat);
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
/**
|
||||
* Loads plugins with the specified names.
|
||||
* @param {{ "import": (name: string) => Promise<any> }} importer An object with an `import` method called once for each plugin.
|
||||
* @param {string[]} pluginNames The names of the plugins to be loaded, with or without the "eslint-plugin-" prefix.
|
||||
* @returns {Promise<Record<string, Plugin>>} A mapping of plugin short names to implementations.
|
||||
*/
|
||||
async function loadPlugins(importer, pluginNames) {
|
||||
const plugins = {};
|
||||
|
||||
await Promise.all(pluginNames.map(async pluginName => {
|
||||
|
||||
const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
|
||||
const module = await importer.import(longName);
|
||||
|
||||
if (!("default" in module)) {
|
||||
throw new Error(`"${longName}" cannot be used with the \`--plugin\` option because its default module does not provide a \`default\` export`);
|
||||
}
|
||||
|
||||
const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
|
||||
|
||||
plugins[shortName] = module.default;
|
||||
}));
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate function for whether or not to apply fixes in quiet mode.
|
||||
* If a message is a warning, do not apply a fix.
|
||||
|
@ -58,6 +85,16 @@ function quietFixPredicate(message) {
|
|||
return message.severity === 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate function for whether or not to run a rule in quiet mode.
|
||||
* If a rule is set to warning, do not run it.
|
||||
* @param {{ ruleId: string; severity: number; }} rule The rule id and severity.
|
||||
* @returns {boolean} True if the lint rule should run, false otherwise.
|
||||
*/
|
||||
function quietRuleFilter(rule) {
|
||||
return rule.severity === 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the CLI options into the options expected by the ESLint constructor.
|
||||
* @param {ParsedCLIOptions} cliOptions The CLI options to translate.
|
||||
|
@ -94,7 +131,10 @@ async function translateOptions({
|
|||
resolvePluginsRelativeTo,
|
||||
rule,
|
||||
rulesdir,
|
||||
warnIgnored
|
||||
stats,
|
||||
warnIgnored,
|
||||
passOnNoPatterns,
|
||||
maxWarnings
|
||||
}, configType) {
|
||||
|
||||
let overrideConfig, overrideConfigFile;
|
||||
|
@ -140,17 +180,7 @@ async function translateOptions({
|
|||
}
|
||||
|
||||
if (plugin) {
|
||||
const plugins = {};
|
||||
|
||||
for (const pluginName of plugin) {
|
||||
|
||||
const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
|
||||
const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
|
||||
|
||||
plugins[shortName] = await importer.import(longName);
|
||||
}
|
||||
|
||||
overrideConfig[0].plugins = plugins;
|
||||
overrideConfig[0].plugins = await loadPlugins(importer, plugin);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -187,12 +217,20 @@ async function translateOptions({
|
|||
fixTypes: fixType,
|
||||
ignore,
|
||||
overrideConfig,
|
||||
overrideConfigFile
|
||||
overrideConfigFile,
|
||||
passOnNoPatterns
|
||||
};
|
||||
|
||||
if (configType === "flat") {
|
||||
options.ignorePatterns = ignorePattern;
|
||||
options.stats = stats;
|
||||
options.warnIgnored = warnIgnored;
|
||||
|
||||
/*
|
||||
* For performance reasons rules not marked as 'error' are filtered out in quiet mode. As maxWarnings
|
||||
* requires rules set to 'warn' to be run, we only filter out 'warn' rules if maxWarnings is not specified.
|
||||
*/
|
||||
options.ruleFilter = quiet && maxWarnings === -1 ? quietRuleFilter : () => true;
|
||||
} else {
|
||||
options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
|
||||
options.rulePaths = rulesdir;
|
||||
|
@ -266,25 +304,23 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
|
|||
|
||||
const output = await formatter.format(results, resultsMeta);
|
||||
|
||||
if (output) {
|
||||
if (outputFile) {
|
||||
const filePath = path.resolve(process.cwd(), outputFile);
|
||||
if (outputFile) {
|
||||
const filePath = path.resolve(process.cwd(), outputFile);
|
||||
|
||||
if (await isDirectory(filePath)) {
|
||||
log.error("Cannot write to output file path, it is a directory: %s", outputFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await mkdir(path.dirname(filePath), { recursive: true });
|
||||
await writeFile(filePath, output);
|
||||
} catch (ex) {
|
||||
log.error("There was a problem writing the output file:\n%s", ex);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
log.info(output);
|
||||
if (await isDirectory(filePath)) {
|
||||
log.error("Cannot write to output file path, it is a directory: %s", outputFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await mkdir(path.dirname(filePath), { recursive: true });
|
||||
await writeFile(filePath, output);
|
||||
} catch (ex) {
|
||||
log.error("There was a problem writing the output file:\n%s", ex);
|
||||
return false;
|
||||
}
|
||||
} else if (output) {
|
||||
log.info(output);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -300,14 +336,35 @@ async function printResults(engine, results, format, outputFile, resultsMeta) {
|
|||
*/
|
||||
const cli = {
|
||||
|
||||
/**
|
||||
* Calculates the command string for the --inspect-config operation.
|
||||
* @param {string} configFile The path to the config file to inspect.
|
||||
* @returns {Promise<string>} The command string to execute.
|
||||
*/
|
||||
async calculateInspectConfigFlags(configFile) {
|
||||
|
||||
// find the config file
|
||||
const {
|
||||
configFilePath,
|
||||
basePath,
|
||||
error
|
||||
} = await locateConfigFileToUse({ cwd: process.cwd(), configFile });
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return ["--config", configFilePath, "--basePath", basePath];
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the CLI based on an array of arguments that is passed in.
|
||||
* @param {string|Array|Object} args The arguments to process.
|
||||
* @param {string} [text] The text to lint (used for TTY).
|
||||
* @param {boolean} [allowFlatConfig] Whether or not to allow flat config.
|
||||
* @param {boolean} [allowFlatConfig=true] Whether or not to allow flat config.
|
||||
* @returns {Promise<number>} The exit code for the operation.
|
||||
*/
|
||||
async execute(args, text, allowFlatConfig) {
|
||||
async execute(args, text, allowFlatConfig = true) {
|
||||
if (Array.isArray(args)) {
|
||||
debug("CLI args: %o", args.slice(2));
|
||||
}
|
||||
|
@ -323,6 +380,10 @@ const cli = {
|
|||
|
||||
debug("Using flat config?", usingFlatConfig);
|
||||
|
||||
if (allowFlatConfig && !usingFlatConfig) {
|
||||
process.emitWarning("You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details.", "ESLintRCWarning");
|
||||
}
|
||||
|
||||
const CLIOptions = createCLIOptions(usingFlatConfig);
|
||||
|
||||
/** @type {ParsedCLIOptions} */
|
||||
|
@ -376,8 +437,8 @@ const cli = {
|
|||
}
|
||||
|
||||
const engine = usingFlatConfig
|
||||
? new FlatESLint(await translateOptions(options, "flat"))
|
||||
: new ESLint(await translateOptions(options));
|
||||
? new ESLint(await translateOptions(options, "flat"))
|
||||
: new LegacyESLint(await translateOptions(options));
|
||||
const fileConfig =
|
||||
await engine.calculateConfigForFile(options.printConfig);
|
||||
|
||||
|
@ -385,6 +446,24 @@ const cli = {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (options.inspectConfig) {
|
||||
|
||||
log.info("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file.");
|
||||
|
||||
try {
|
||||
const flatOptions = await translateOptions(options, "flat");
|
||||
const spawn = require("cross-spawn");
|
||||
const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile);
|
||||
|
||||
spawn.sync("npx", ["@eslint/config-inspector", ...flags], { encoding: "utf8", stdio: "inherit" });
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug(`Running on ${useStdin ? "text" : "files"}`);
|
||||
|
||||
if (options.fix && options.fixDryRun) {
|
||||
|
@ -405,7 +484,7 @@ const cli = {
|
|||
return 2;
|
||||
}
|
||||
|
||||
const ActiveESLint = usingFlatConfig ? FlatESLint : ESLint;
|
||||
const ActiveESLint = usingFlatConfig ? ESLint : LegacyESLint;
|
||||
|
||||
const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
|
||||
let results;
|
||||
|
|
3
tools/node_modules/eslint/lib/config/default-config.js
generated
vendored
3
tools/node_modules/eslint/lib/config/default-config.js
generated
vendored
|
@ -42,6 +42,9 @@ exports.defaultConfig = [
|
|||
ecmaVersion: "latest",
|
||||
parser: require("espree"),
|
||||
parserOptions: {}
|
||||
},
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 1
|
||||
}
|
||||
},
|
||||
|
||||
|
|
134
tools/node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
134
tools/node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
|
@ -13,12 +13,16 @@ const { ConfigArray, ConfigArraySymbol } = require("@humanwhocodes/config-array"
|
|||
const { flatConfigSchema } = require("./flat-config-schema");
|
||||
const { RuleValidator } = require("./rule-validator");
|
||||
const { defaultConfig } = require("./default-config");
|
||||
const jsPlugin = require("@eslint/js");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fields that are considered metadata and not part of the config object.
|
||||
*/
|
||||
const META_FIELDS = new Set(["name"]);
|
||||
|
||||
const ruleValidator = new RuleValidator();
|
||||
|
||||
/**
|
||||
|
@ -75,7 +79,53 @@ function getObjectId(object) {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a config error with details about where the error occurred.
|
||||
* @param {Error} error The original error.
|
||||
* @param {number} originalLength The original length of the config array.
|
||||
* @param {number} baseLength The length of the base config.
|
||||
* @returns {TypeError} The new error with details.
|
||||
*/
|
||||
function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
|
||||
|
||||
let location = "user-defined";
|
||||
let configIndex = error.index;
|
||||
|
||||
/*
|
||||
* A config array is set up in this order:
|
||||
* 1. Base config
|
||||
* 2. Original configs
|
||||
* 3. User-defined configs
|
||||
* 4. CLI-defined configs
|
||||
*
|
||||
* So we need to adjust the index to account for the base config.
|
||||
*
|
||||
* - If the index is less than the base length, it's in the base config
|
||||
* (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
|
||||
* - If the index is greater than the base length but less than the original
|
||||
* length + base length, it's in the original config. The original config
|
||||
* is passed to the `FlatConfigArray` constructor as the first argument.
|
||||
* - Otherwise, it's in the user-defined config, which is loaded from the
|
||||
* config file and merged with any command-line options.
|
||||
*/
|
||||
if (error.index < baseLength) {
|
||||
location = "base";
|
||||
} else if (error.index < originalLength + baseLength) {
|
||||
location = "original";
|
||||
configIndex = error.index - baseLength;
|
||||
} else {
|
||||
configIndex = error.index - originalLength - baseLength;
|
||||
}
|
||||
|
||||
return new TypeError(
|
||||
`${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
|
||||
{ cause: error }
|
||||
);
|
||||
}
|
||||
|
||||
const originalBaseConfig = Symbol("originalBaseConfig");
|
||||
const originalLength = Symbol("originalLength");
|
||||
const baseLength = Symbol("baseLength");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
|
@ -102,12 +152,24 @@ class FlatConfigArray extends ConfigArray {
|
|||
schema: flatConfigSchema
|
||||
});
|
||||
|
||||
/**
|
||||
* The original length of the array before any modifications.
|
||||
* @type {number}
|
||||
*/
|
||||
this[originalLength] = this.length;
|
||||
|
||||
if (baseConfig[Symbol.iterator]) {
|
||||
this.unshift(...baseConfig);
|
||||
} else {
|
||||
this.unshift(baseConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* The length of the array after applying the base config.
|
||||
* @type {number}
|
||||
*/
|
||||
this[baseLength] = this.length - this[originalLength];
|
||||
|
||||
/**
|
||||
* The base config used to build the config array.
|
||||
* @type {Array<FlatConfig>}
|
||||
|
@ -125,6 +187,49 @@ class FlatConfigArray extends ConfigArray {
|
|||
Object.defineProperty(this, "shouldIgnore", { writable: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the array by calling the superclass method and catching/rethrowing
|
||||
* any ConfigError exceptions with additional details.
|
||||
* @param {any} [context] The context to use to normalize the array.
|
||||
* @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
|
||||
*/
|
||||
normalize(context) {
|
||||
return super.normalize(context)
|
||||
.catch(error => {
|
||||
if (error.name === "ConfigError") {
|
||||
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the array by calling the superclass method and catching/rethrowing
|
||||
* any ConfigError exceptions with additional details.
|
||||
* @param {any} [context] The context to use to normalize the array.
|
||||
* @returns {FlatConfigArray} The current instance.
|
||||
* @throws {TypeError} If the config is invalid.
|
||||
*/
|
||||
normalizeSync(context) {
|
||||
|
||||
try {
|
||||
|
||||
return super.normalizeSync(context);
|
||||
|
||||
} catch (error) {
|
||||
|
||||
if (error.name === "ConfigError") {
|
||||
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* eslint-disable class-methods-use-this -- Desired as instance method */
|
||||
/**
|
||||
* Replaces a config with another config to allow us to put strings
|
||||
|
@ -134,36 +239,17 @@ class FlatConfigArray extends ConfigArray {
|
|||
* @returns {Object} The preprocessed config.
|
||||
*/
|
||||
[ConfigArraySymbol.preprocessConfig](config) {
|
||||
if (config === "eslint:recommended") {
|
||||
|
||||
// if we are in a Node.js environment warn the user
|
||||
if (typeof process !== "undefined" && process.emitWarning) {
|
||||
process.emitWarning("The 'eslint:recommended' string configuration is deprecated and will be replaced by the @eslint/js package's 'recommended' config.");
|
||||
}
|
||||
|
||||
return jsPlugin.configs.recommended;
|
||||
}
|
||||
|
||||
if (config === "eslint:all") {
|
||||
|
||||
// if we are in a Node.js environment warn the user
|
||||
if (typeof process !== "undefined" && process.emitWarning) {
|
||||
process.emitWarning("The 'eslint:all' string configuration is deprecated and will be replaced by the @eslint/js package's 'all' config.");
|
||||
}
|
||||
|
||||
return jsPlugin.configs.all;
|
||||
}
|
||||
|
||||
/*
|
||||
* If `shouldIgnore` is false, we remove any ignore patterns specified
|
||||
* in the config so long as it's not a default config and it doesn't
|
||||
* have a `files` entry.
|
||||
* If a config object has `ignores` and no other non-meta fields, then it's an object
|
||||
* for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
|
||||
* so we'll remove its `ignores`.
|
||||
*/
|
||||
if (
|
||||
!this.shouldIgnore &&
|
||||
!this[originalBaseConfig].includes(config) &&
|
||||
config.ignores &&
|
||||
!config.files
|
||||
Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1
|
||||
) {
|
||||
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
|
||||
const { ignores, ...otherKeys } = config;
|
||||
|
|
61
tools/node_modules/eslint/lib/config/flat-config-helpers.js
generated
vendored
61
tools/node_modules/eslint/lib/config/flat-config-helpers.js
generated
vendored
|
@ -5,6 +5,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../shared/types").Rule} Rule */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Members
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// JSON schema that disallows passing any options
|
||||
const noOptionsSchema = Object.freeze({
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 0
|
||||
});
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -52,32 +69,39 @@ function getRuleFromConfig(ruleId, config) {
|
|||
const { pluginName, ruleName } = parseRuleId(ruleId);
|
||||
|
||||
const plugin = config.plugins && config.plugins[pluginName];
|
||||
let rule = plugin && plugin.rules && plugin.rules[ruleName];
|
||||
|
||||
|
||||
// normalize function rules into objects
|
||||
if (rule && typeof rule === "function") {
|
||||
rule = {
|
||||
create: rule
|
||||
};
|
||||
}
|
||||
const rule = plugin && plugin.rules && plugin.rules[ruleName];
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a complete options schema for a rule.
|
||||
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
|
||||
* @returns {Object} JSON Schema for the rule's options.
|
||||
* @param {Rule} rule A rule object
|
||||
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
|
||||
* @returns {Object|null} JSON Schema for the rule's options. `null` if `meta.schema` is `false`.
|
||||
*/
|
||||
function getRuleOptionsSchema(rule) {
|
||||
|
||||
if (!rule) {
|
||||
if (!rule.meta) {
|
||||
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
||||
}
|
||||
|
||||
const schema = rule.meta.schema;
|
||||
|
||||
if (typeof schema === "undefined") {
|
||||
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
||||
}
|
||||
|
||||
// `schema:false` is an allowed explicit opt-out of options validation for the rule
|
||||
if (schema === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const schema = rule.schema || rule.meta && rule.meta.schema;
|
||||
if (typeof schema !== "object" || schema === null) {
|
||||
throw new TypeError("Rule's `meta.schema` must be an array or object");
|
||||
}
|
||||
|
||||
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
|
||||
if (Array.isArray(schema)) {
|
||||
if (schema.length) {
|
||||
return {
|
||||
|
@ -87,16 +111,13 @@ function getRuleOptionsSchema(rule) {
|
|||
maxItems: schema.length
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 0
|
||||
};
|
||||
|
||||
// `schema:[]` is an explicit way to specify that the rule does not accept any options
|
||||
return { ...noOptionsSchema };
|
||||
}
|
||||
|
||||
// Given a full schema, leave it alone
|
||||
return schema || null;
|
||||
// `schema:<object>` is assumed to be a valid JSON Schema definition
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
|
|
8
tools/node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
8
tools/node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
|
@ -9,11 +9,6 @@
|
|||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Note: This can be removed in ESLint v9 because structuredClone is available globally
|
||||
* starting in Node.js v17.
|
||||
*/
|
||||
const structuredClone = require("@ungap/structured-clone").default;
|
||||
const { normalizeSeverityToNumber } = require("../shared/severity");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -593,6 +588,5 @@ const flatConfigSchema = {
|
|||
|
||||
module.exports = {
|
||||
flatConfigSchema,
|
||||
assertIsRuleSeverity,
|
||||
assertIsRuleOptions
|
||||
assertIsRuleSeverity
|
||||
};
|
||||
|
|
46
tools/node_modules/eslint/lib/config/rule-validator.js
generated
vendored
46
tools/node_modules/eslint/lib/config/rule-validator.js
generated
vendored
|
@ -66,6 +66,25 @@ function throwRuleNotFoundError({ pluginName, ruleName }, config) {
|
|||
throw new TypeError(errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when a rule has an invalid `meta.schema`.
|
||||
*/
|
||||
class InvalidRuleOptionsSchemaError extends Error {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {string} ruleId Id of the rule that has an invalid `meta.schema`.
|
||||
* @param {Error} processingError Error caught while processing the `meta.schema`.
|
||||
*/
|
||||
constructor(ruleId, processingError) {
|
||||
super(
|
||||
`Error while processing options validation schema of rule '${ruleId}': ${processingError.message}`,
|
||||
{ cause: processingError }
|
||||
);
|
||||
this.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -130,10 +149,14 @@ class RuleValidator {
|
|||
|
||||
// Precompile and cache validator the first time
|
||||
if (!this.validators.has(rule)) {
|
||||
const schema = getRuleOptionsSchema(rule);
|
||||
try {
|
||||
const schema = getRuleOptionsSchema(rule);
|
||||
|
||||
if (schema) {
|
||||
this.validators.set(rule, ajv.compile(schema));
|
||||
if (schema) {
|
||||
this.validators.set(rule, ajv.compile(schema));
|
||||
}
|
||||
} catch (err) {
|
||||
throw new InvalidRuleOptionsSchemaError(ruleId, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,9 +167,22 @@ class RuleValidator {
|
|||
validateRule(ruleOptions.slice(1));
|
||||
|
||||
if (validateRule.errors) {
|
||||
throw new Error(`Key "rules": Key "${ruleId}": ${
|
||||
throw new Error(`Key "rules": Key "${ruleId}":\n${
|
||||
validateRule.errors.map(
|
||||
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
|
||||
error => {
|
||||
if (
|
||||
error.keyword === "additionalProperties" &&
|
||||
error.schema === false &&
|
||||
typeof error.parentSchema?.properties === "object" &&
|
||||
typeof error.params?.additionalProperty === "string"
|
||||
) {
|
||||
const expectedProperties = Object.keys(error.parentSchema.properties).map(property => `"${property}"`);
|
||||
|
||||
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n\t\tUnexpected property "${error.params.additionalProperty}". Expected properties: ${expectedProperties.join(", ")}.\n`;
|
||||
}
|
||||
|
||||
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`;
|
||||
}
|
||||
).join("")
|
||||
}`);
|
||||
}
|
||||
|
|
180
tools/node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
180
tools/node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
|
@ -9,13 +9,12 @@
|
|||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs");
|
||||
const fsp = fs.promises;
|
||||
const isGlob = require("is-glob");
|
||||
const hash = require("../cli-engine/hash");
|
||||
const minimatch = require("minimatch");
|
||||
const util = require("util");
|
||||
const fswalk = require("@nodelib/fs.walk");
|
||||
const globParent = require("glob-parent");
|
||||
const isPathInside = require("is-path-inside");
|
||||
|
@ -24,7 +23,6 @@ const isPathInside = require("is-path-inside");
|
|||
// Fixup references
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const doFsWalk = util.promisify(fswalk.walk);
|
||||
const Minimatch = minimatch.Minimatch;
|
||||
const MINIMATCH_OPTIONS = { dot: true };
|
||||
|
||||
|
@ -105,20 +103,30 @@ class AllFilesIgnoredError extends Error {
|
|||
|
||||
/**
|
||||
* Check if a given value is a non-empty string or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is a non-empty string.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is a non-empty string.
|
||||
*/
|
||||
function isNonEmptyString(x) {
|
||||
return typeof x === "string" && x.trim() !== "";
|
||||
function isNonEmptyString(value) {
|
||||
return typeof value === "string" && value.trim() !== "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of non-empty strings or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is an array of non-empty strings.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an array of non-empty strings.
|
||||
*/
|
||||
function isArrayOfNonEmptyString(x) {
|
||||
return Array.isArray(x) && x.every(isNonEmptyString);
|
||||
function isArrayOfNonEmptyString(value) {
|
||||
return Array.isArray(value) && value.length && value.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an empty array or an array of non-empty strings.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an empty array or an array of non-empty
|
||||
* strings.
|
||||
*/
|
||||
function isEmptyArrayOrArrayOfNonEmptyString(value) {
|
||||
return Array.isArray(value) && value.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -270,56 +278,92 @@ async function globSearch({
|
|||
*/
|
||||
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
||||
|
||||
const filePaths = (await doFsWalk(basePath, {
|
||||
const filePaths = (await new Promise((resolve, reject) => {
|
||||
|
||||
deepFilter(entry) {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
||||
let promiseRejected = false;
|
||||
|
||||
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
||||
},
|
||||
entryFilter(entry) {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
/**
|
||||
* Wraps a boolean-returning filter function. The wrapped function will reject the promise if an error occurs.
|
||||
* @param {Function} filter A filter function to wrap.
|
||||
* @returns {Function} A function similar to the wrapped filter that rejects the promise if an error occurs.
|
||||
*/
|
||||
function wrapFilter(filter) {
|
||||
return (...args) => {
|
||||
|
||||
// entries may be directories or files so filter out directories
|
||||
if (entry.dirent.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimization: We need to track when patterns are left unmatched
|
||||
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
||||
* complexity here because the same file can be matched by more than
|
||||
* one pattern. So, when we start, we actually need to test every
|
||||
* pattern against every file. Once we know there are no remaining
|
||||
* unmatched patterns, then we can switch to just looking for the
|
||||
* first matching pattern for improved speed.
|
||||
*/
|
||||
const matchesPattern = unmatchedPatterns.size > 0
|
||||
? matchers.reduce((previousValue, matcher) => {
|
||||
const pathMatches = matcher.match(relativePath);
|
||||
|
||||
/*
|
||||
* We updated the unmatched patterns set only if the path
|
||||
* matches and the file isn't ignored. If the file is
|
||||
* ignored, that means there wasn't a match for the
|
||||
* pattern so it should not be removed.
|
||||
*
|
||||
* Performance note: isFileIgnored() aggressively caches
|
||||
* results so there is no performance penalty for calling
|
||||
* it twice with the same argument.
|
||||
*/
|
||||
if (pathMatches && !configs.isFileIgnored(entry.path)) {
|
||||
unmatchedPatterns.delete(matcher.pattern);
|
||||
// No need to run the filter if an error has been thrown.
|
||||
if (!promiseRejected) {
|
||||
try {
|
||||
return filter(...args);
|
||||
} catch (error) {
|
||||
promiseRejected = true;
|
||||
reject(error);
|
||||
}
|
||||
|
||||
return pathMatches || previousValue;
|
||||
}, false)
|
||||
: matchers.some(matcher => matcher.match(relativePath));
|
||||
|
||||
return matchesPattern && !configs.isFileIgnored(entry.path);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
fswalk.walk(
|
||||
basePath,
|
||||
{
|
||||
deepFilter: wrapFilter(entry => {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
||||
|
||||
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
||||
}),
|
||||
entryFilter: wrapFilter(entry => {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
|
||||
// entries may be directories or files so filter out directories
|
||||
if (entry.dirent.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimization: We need to track when patterns are left unmatched
|
||||
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
||||
* complexity here because the same file can be matched by more than
|
||||
* one pattern. So, when we start, we actually need to test every
|
||||
* pattern against every file. Once we know there are no remaining
|
||||
* unmatched patterns, then we can switch to just looking for the
|
||||
* first matching pattern for improved speed.
|
||||
*/
|
||||
const matchesPattern = unmatchedPatterns.size > 0
|
||||
? matchers.reduce((previousValue, matcher) => {
|
||||
const pathMatches = matcher.match(relativePath);
|
||||
|
||||
/*
|
||||
* We updated the unmatched patterns set only if the path
|
||||
* matches and the file isn't ignored. If the file is
|
||||
* ignored, that means there wasn't a match for the
|
||||
* pattern so it should not be removed.
|
||||
*
|
||||
* Performance note: isFileIgnored() aggressively caches
|
||||
* results so there is no performance penalty for calling
|
||||
* it twice with the same argument.
|
||||
*/
|
||||
if (pathMatches && !configs.isFileIgnored(entry.path)) {
|
||||
unmatchedPatterns.delete(matcher.pattern);
|
||||
}
|
||||
|
||||
return pathMatches || previousValue;
|
||||
}, false)
|
||||
: matchers.some(matcher => matcher.match(relativePath));
|
||||
|
||||
return matchesPattern && !configs.isFileIgnored(entry.path);
|
||||
})
|
||||
},
|
||||
(error, entries) => {
|
||||
|
||||
// If the promise is already rejected, calling `resolve` or `reject` will do nothing.
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(entries);
|
||||
}
|
||||
}
|
||||
);
|
||||
})).map(entry => entry.path);
|
||||
|
||||
// now check to see if we have any unmatched patterns
|
||||
|
@ -655,9 +699,9 @@ class ESLintInvalidOptionsError extends Error {
|
|||
|
||||
/**
|
||||
* Validates and normalizes options for the wrapped CLIEngine instance.
|
||||
* @param {FlatESLintOptions} options The options to process.
|
||||
* @param {ESLintOptions} options The options to process.
|
||||
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
||||
* @returns {FlatESLintOptions} The normalized options.
|
||||
* @returns {ESLintOptions} The normalized options.
|
||||
*/
|
||||
function processOptions({
|
||||
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
||||
|
@ -675,7 +719,10 @@ function processOptions({
|
|||
overrideConfig = null,
|
||||
overrideConfigFile = null,
|
||||
plugins = {},
|
||||
stats = false,
|
||||
warnIgnored = true,
|
||||
passOnNoPatterns = false,
|
||||
ruleFilter = () => true,
|
||||
...unknownOptions
|
||||
}) {
|
||||
const errors = [];
|
||||
|
@ -759,7 +806,7 @@ function processOptions({
|
|||
if (typeof ignore !== "boolean") {
|
||||
errors.push("'ignore' must be a boolean.");
|
||||
}
|
||||
if (!isArrayOfNonEmptyString(ignorePatterns) && ignorePatterns !== null) {
|
||||
if (!isEmptyArrayOrArrayOfNonEmptyString(ignorePatterns) && ignorePatterns !== null) {
|
||||
errors.push("'ignorePatterns' must be an array of non-empty strings or null.");
|
||||
}
|
||||
if (typeof overrideConfig !== "object") {
|
||||
|
@ -768,6 +815,9 @@ function processOptions({
|
|||
if (!isNonEmptyString(overrideConfigFile) && overrideConfigFile !== null && overrideConfigFile !== true) {
|
||||
errors.push("'overrideConfigFile' must be a non-empty string, null, or true.");
|
||||
}
|
||||
if (typeof passOnNoPatterns !== "boolean") {
|
||||
errors.push("'passOnNoPatterns' must be a boolean.");
|
||||
}
|
||||
if (typeof plugins !== "object") {
|
||||
errors.push("'plugins' must be an object or null.");
|
||||
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
||||
|
@ -776,9 +826,15 @@ function processOptions({
|
|||
if (Array.isArray(plugins)) {
|
||||
errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
|
||||
}
|
||||
if (typeof stats !== "boolean") {
|
||||
errors.push("'stats' must be a boolean.");
|
||||
}
|
||||
if (typeof warnIgnored !== "boolean") {
|
||||
errors.push("'warnIgnored' must be a boolean.");
|
||||
}
|
||||
if (typeof ruleFilter !== "function") {
|
||||
errors.push("'ruleFilter' must be a function.");
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
throw new ESLintInvalidOptionsError(errors);
|
||||
}
|
||||
|
@ -800,7 +856,10 @@ function processOptions({
|
|||
globInputPaths,
|
||||
ignore,
|
||||
ignorePatterns,
|
||||
warnIgnored
|
||||
stats,
|
||||
passOnNoPatterns,
|
||||
warnIgnored,
|
||||
ruleFilter
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -887,7 +946,6 @@ function getCacheFile(cacheFile, cwd) {
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
isGlobPattern,
|
||||
findFiles,
|
||||
|
||||
isNonEmptyString,
|
||||
|
|
1281
tools/node_modules/eslint/lib/eslint/eslint.js
generated
vendored
1281
tools/node_modules/eslint/lib/eslint/eslint.js
generated
vendored
File diff suppressed because it is too large
Load diff
1155
tools/node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
1155
tools/node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
File diff suppressed because it is too large
Load diff
4
tools/node_modules/eslint/lib/eslint/index.js
generated
vendored
4
tools/node_modules/eslint/lib/eslint/index.js
generated
vendored
|
@ -1,9 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
const { ESLint } = require("./eslint");
|
||||
const { FlatESLint } = require("./flat-eslint");
|
||||
const { LegacyESLint } = require("./legacy-eslint");
|
||||
|
||||
module.exports = {
|
||||
ESLint,
|
||||
FlatESLint
|
||||
LegacyESLint
|
||||
};
|
||||
|
|
728
tools/node_modules/eslint/lib/eslint/legacy-eslint.js
generated
vendored
Normal file
728
tools/node_modules/eslint/lib/eslint/legacy-eslint.js
generated
vendored
Normal file
|
@ -0,0 +1,728 @@
|
|||
/**
|
||||
* @fileoverview Main API Class
|
||||
* @author Kai Cataldo
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs");
|
||||
const { promisify } = require("node:util");
|
||||
const { CLIEngine, getCLIEngineInternalSlots } = require("../cli-engine/cli-engine");
|
||||
const BuiltinRules = require("../rules");
|
||||
const {
|
||||
Legacy: {
|
||||
ConfigOps: {
|
||||
getRuleSeverity
|
||||
}
|
||||
}
|
||||
} = require("@eslint/eslintrc");
|
||||
const { version } = require("../../package.json");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../cli-engine/cli-engine").LintReport} CLIEngineLintReport */
|
||||
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
|
||||
/** @typedef {import("../shared/types").ConfigData} ConfigData */
|
||||
/** @typedef {import("../shared/types").LintMessage} LintMessage */
|
||||
/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
|
||||
/** @typedef {import("../shared/types").Plugin} Plugin */
|
||||
/** @typedef {import("../shared/types").Rule} Rule */
|
||||
/** @typedef {import("../shared/types").LintResult} LintResult */
|
||||
/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */
|
||||
|
||||
/**
|
||||
* The main formatter object.
|
||||
* @typedef LoadedFormatter
|
||||
* @property {(results: LintResult[], resultsMeta: ResultsMeta) => string | Promise<string>} format format function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The options with which to configure the LegacyESLint instance.
|
||||
* @typedef {Object} LegacyESLintOptions
|
||||
* @property {boolean} [allowInlineConfig] Enable or disable inline configuration comments.
|
||||
* @property {ConfigData} [baseConfig] Base config object, extended by all configs used with this instance
|
||||
* @property {boolean} [cache] Enable result caching.
|
||||
* @property {string} [cacheLocation] The cache file to use instead of .eslintcache.
|
||||
* @property {"metadata" | "content"} [cacheStrategy] The strategy used to detect changed files.
|
||||
* @property {string} [cwd] The value to use for the current working directory.
|
||||
* @property {boolean} [errorOnUnmatchedPattern] If `false` then `ESLint#lintFiles()` doesn't throw even if no target files found. Defaults to `true`.
|
||||
* @property {string[]} [extensions] An array of file extensions to check.
|
||||
* @property {boolean|Function} [fix] Execute in autofix mode. If a function, should return a boolean.
|
||||
* @property {string[]} [fixTypes] Array of rule types to apply fixes for.
|
||||
* @property {boolean} [globInputPaths] Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
|
||||
* @property {boolean} [ignore] False disables use of .eslintignore.
|
||||
* @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
|
||||
* @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
|
||||
* @property {string} [overrideConfigFile] The configuration file to use.
|
||||
* @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
|
||||
* @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
|
||||
* @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
|
||||
* @property {string[]} [rulePaths] An array of directories to load custom rules from.
|
||||
* @property {boolean} [useEslintrc] False disables looking for .eslintrc.* files.
|
||||
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
||||
* the linting operation to short circuit and not report any failures.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A rules metadata object.
|
||||
* @typedef {Object} RulesMeta
|
||||
* @property {string} id The plugin ID.
|
||||
* @property {Object} definition The plugin definition.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Private members for the `ESLint` instance.
|
||||
* @typedef {Object} ESLintPrivateMembers
|
||||
* @property {CLIEngine} cliEngine The wrapped CLIEngine instance.
|
||||
* @property {LegacyESLintOptions} options The options used to instantiate the ESLint instance.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
/**
|
||||
* The map with which to store private class members.
|
||||
* @type {WeakMap<ESLint, ESLintPrivateMembers>}
|
||||
*/
|
||||
const privateMembersMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Check if a given value is a non-empty string or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is a non-empty string.
|
||||
*/
|
||||
function isNonEmptyString(value) {
|
||||
return typeof value === "string" && value.trim() !== "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of non-empty strings or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an array of non-empty strings.
|
||||
*/
|
||||
function isArrayOfNonEmptyString(value) {
|
||||
return Array.isArray(value) && value.length && value.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an empty array or an array of non-empty strings.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an empty array or an array of non-empty
|
||||
* strings.
|
||||
*/
|
||||
function isEmptyArrayOrArrayOfNonEmptyString(value) {
|
||||
return Array.isArray(value) && value.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is a valid fix type or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is valid fix type.
|
||||
*/
|
||||
function isFixType(value) {
|
||||
return value === "directive" || value === "problem" || value === "suggestion" || value === "layout";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of fix types or not.
|
||||
* @param {any} value The value to check.
|
||||
* @returns {boolean} `true` if `value` is an array of fix types.
|
||||
*/
|
||||
function isFixTypeArray(value) {
|
||||
return Array.isArray(value) && value.every(isFixType);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error for invalid options.
|
||||
*/
|
||||
class ESLintInvalidOptionsError extends Error {
|
||||
constructor(messages) {
|
||||
super(`Invalid Options:\n- ${messages.join("\n- ")}`);
|
||||
this.code = "ESLINT_INVALID_OPTIONS";
|
||||
Error.captureStackTrace(this, ESLintInvalidOptionsError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalizes options for the wrapped CLIEngine instance.
|
||||
* @param {LegacyESLintOptions} options The options to process.
|
||||
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
||||
* @returns {LegacyESLintOptions} The normalized options.
|
||||
*/
|
||||
function processOptions({
|
||||
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
||||
baseConfig = null,
|
||||
cache = false,
|
||||
cacheLocation = ".eslintcache",
|
||||
cacheStrategy = "metadata",
|
||||
cwd = process.cwd(),
|
||||
errorOnUnmatchedPattern = true,
|
||||
extensions = null, // ← should be null by default because if it's an array then it suppresses RFC20 feature.
|
||||
fix = false,
|
||||
fixTypes = null, // ← should be null by default because if it's an array then it suppresses rules that don't have the `meta.type` property.
|
||||
globInputPaths = true,
|
||||
ignore = true,
|
||||
ignorePath = null, // ← should be null by default because if it's a string then it may throw ENOENT.
|
||||
overrideConfig = null,
|
||||
overrideConfigFile = null,
|
||||
plugins = {},
|
||||
reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that.
|
||||
resolvePluginsRelativeTo = null, // ← should be null by default because if it's a string then it suppresses RFC47 feature.
|
||||
rulePaths = [],
|
||||
useEslintrc = true,
|
||||
passOnNoPatterns = false,
|
||||
...unknownOptions
|
||||
}) {
|
||||
const errors = [];
|
||||
const unknownOptionKeys = Object.keys(unknownOptions);
|
||||
|
||||
if (unknownOptionKeys.length >= 1) {
|
||||
errors.push(`Unknown options: ${unknownOptionKeys.join(", ")}`);
|
||||
if (unknownOptionKeys.includes("cacheFile")) {
|
||||
errors.push("'cacheFile' has been removed. Please use the 'cacheLocation' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("configFile")) {
|
||||
errors.push("'configFile' has been removed. Please use the 'overrideConfigFile' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("envs")) {
|
||||
errors.push("'envs' has been removed. Please use the 'overrideConfig.env' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("globals")) {
|
||||
errors.push("'globals' has been removed. Please use the 'overrideConfig.globals' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("ignorePattern")) {
|
||||
errors.push("'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("parser")) {
|
||||
errors.push("'parser' has been removed. Please use the 'overrideConfig.parser' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("parserOptions")) {
|
||||
errors.push("'parserOptions' has been removed. Please use the 'overrideConfig.parserOptions' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("rules")) {
|
||||
errors.push("'rules' has been removed. Please use the 'overrideConfig.rules' option instead.");
|
||||
}
|
||||
}
|
||||
if (typeof allowInlineConfig !== "boolean") {
|
||||
errors.push("'allowInlineConfig' must be a boolean.");
|
||||
}
|
||||
if (typeof baseConfig !== "object") {
|
||||
errors.push("'baseConfig' must be an object or null.");
|
||||
}
|
||||
if (typeof cache !== "boolean") {
|
||||
errors.push("'cache' must be a boolean.");
|
||||
}
|
||||
if (!isNonEmptyString(cacheLocation)) {
|
||||
errors.push("'cacheLocation' must be a non-empty string.");
|
||||
}
|
||||
if (
|
||||
cacheStrategy !== "metadata" &&
|
||||
cacheStrategy !== "content"
|
||||
) {
|
||||
errors.push("'cacheStrategy' must be any of \"metadata\", \"content\".");
|
||||
}
|
||||
if (!isNonEmptyString(cwd) || !path.isAbsolute(cwd)) {
|
||||
errors.push("'cwd' must be an absolute path.");
|
||||
}
|
||||
if (typeof errorOnUnmatchedPattern !== "boolean") {
|
||||
errors.push("'errorOnUnmatchedPattern' must be a boolean.");
|
||||
}
|
||||
if (!isEmptyArrayOrArrayOfNonEmptyString(extensions) && extensions !== null) {
|
||||
errors.push("'extensions' must be an array of non-empty strings or null.");
|
||||
}
|
||||
if (typeof fix !== "boolean" && typeof fix !== "function") {
|
||||
errors.push("'fix' must be a boolean or a function.");
|
||||
}
|
||||
if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
|
||||
errors.push("'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".");
|
||||
}
|
||||
if (typeof globInputPaths !== "boolean") {
|
||||
errors.push("'globInputPaths' must be a boolean.");
|
||||
}
|
||||
if (typeof ignore !== "boolean") {
|
||||
errors.push("'ignore' must be a boolean.");
|
||||
}
|
||||
if (!isNonEmptyString(ignorePath) && ignorePath !== null) {
|
||||
errors.push("'ignorePath' must be a non-empty string or null.");
|
||||
}
|
||||
if (typeof overrideConfig !== "object") {
|
||||
errors.push("'overrideConfig' must be an object or null.");
|
||||
}
|
||||
if (!isNonEmptyString(overrideConfigFile) && overrideConfigFile !== null) {
|
||||
errors.push("'overrideConfigFile' must be a non-empty string or null.");
|
||||
}
|
||||
if (typeof plugins !== "object") {
|
||||
errors.push("'plugins' must be an object or null.");
|
||||
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
||||
errors.push("'plugins' must not include an empty string.");
|
||||
}
|
||||
if (Array.isArray(plugins)) {
|
||||
errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
|
||||
}
|
||||
if (
|
||||
reportUnusedDisableDirectives !== "error" &&
|
||||
reportUnusedDisableDirectives !== "warn" &&
|
||||
reportUnusedDisableDirectives !== "off" &&
|
||||
reportUnusedDisableDirectives !== null
|
||||
) {
|
||||
errors.push("'reportUnusedDisableDirectives' must be any of \"error\", \"warn\", \"off\", and null.");
|
||||
}
|
||||
if (
|
||||
!isNonEmptyString(resolvePluginsRelativeTo) &&
|
||||
resolvePluginsRelativeTo !== null
|
||||
) {
|
||||
errors.push("'resolvePluginsRelativeTo' must be a non-empty string or null.");
|
||||
}
|
||||
if (!isEmptyArrayOrArrayOfNonEmptyString(rulePaths)) {
|
||||
errors.push("'rulePaths' must be an array of non-empty strings.");
|
||||
}
|
||||
if (typeof useEslintrc !== "boolean") {
|
||||
errors.push("'useEslintrc' must be a boolean.");
|
||||
}
|
||||
if (typeof passOnNoPatterns !== "boolean") {
|
||||
errors.push("'passOnNoPatterns' must be a boolean.");
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new ESLintInvalidOptionsError(errors);
|
||||
}
|
||||
|
||||
return {
|
||||
allowInlineConfig,
|
||||
baseConfig,
|
||||
cache,
|
||||
cacheLocation,
|
||||
cacheStrategy,
|
||||
configFile: overrideConfigFile,
|
||||
cwd: path.normalize(cwd),
|
||||
errorOnUnmatchedPattern,
|
||||
extensions,
|
||||
fix,
|
||||
fixTypes,
|
||||
globInputPaths,
|
||||
ignore,
|
||||
ignorePath,
|
||||
reportUnusedDisableDirectives,
|
||||
resolvePluginsRelativeTo,
|
||||
rulePaths,
|
||||
useEslintrc,
|
||||
passOnNoPatterns
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value has one or more properties and that value is not undefined.
|
||||
* @param {any} obj The value to check.
|
||||
* @returns {boolean} `true` if `obj` has one or more properties that that value is not undefined.
|
||||
*/
|
||||
function hasDefinedProperty(obj) {
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] !== "undefined") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create rulesMeta object.
|
||||
* @param {Map<string,Rule>} rules a map of rules from which to generate the object.
|
||||
* @returns {Object} metadata for all enabled rules.
|
||||
*/
|
||||
function createRulesMeta(rules) {
|
||||
return Array.from(rules).reduce((retVal, [id, rule]) => {
|
||||
retVal[id] = rule.meta;
|
||||
return retVal;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/** @type {WeakMap<ExtractedConfig, DeprecatedRuleInfo[]>} */
|
||||
const usedDeprecatedRulesCache = new WeakMap();
|
||||
|
||||
/**
|
||||
* Create used deprecated rule list.
|
||||
* @param {CLIEngine} cliEngine The CLIEngine instance.
|
||||
* @param {string} maybeFilePath The absolute path to a lint target file or `"<text>"`.
|
||||
* @returns {DeprecatedRuleInfo[]} The used deprecated rule list.
|
||||
*/
|
||||
function getOrFindUsedDeprecatedRules(cliEngine, maybeFilePath) {
|
||||
const {
|
||||
configArrayFactory,
|
||||
options: { cwd }
|
||||
} = getCLIEngineInternalSlots(cliEngine);
|
||||
const filePath = path.isAbsolute(maybeFilePath)
|
||||
? maybeFilePath
|
||||
: path.join(cwd, "__placeholder__.js");
|
||||
const configArray = configArrayFactory.getConfigArrayForFile(filePath);
|
||||
const config = configArray.extractConfig(filePath);
|
||||
|
||||
// Most files use the same config, so cache it.
|
||||
if (!usedDeprecatedRulesCache.has(config)) {
|
||||
const pluginRules = configArray.pluginRules;
|
||||
const retv = [];
|
||||
|
||||
for (const [ruleId, ruleConf] of Object.entries(config.rules)) {
|
||||
if (getRuleSeverity(ruleConf) === 0) {
|
||||
continue;
|
||||
}
|
||||
const rule = pluginRules.get(ruleId) || BuiltinRules.get(ruleId);
|
||||
const meta = rule && rule.meta;
|
||||
|
||||
if (meta && meta.deprecated) {
|
||||
retv.push({ ruleId, replacedBy: meta.replacedBy || [] });
|
||||
}
|
||||
}
|
||||
|
||||
usedDeprecatedRulesCache.set(config, Object.freeze(retv));
|
||||
}
|
||||
|
||||
return usedDeprecatedRulesCache.get(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the linting results generated by a CLIEngine linting report to
|
||||
* match the ESLint class's API.
|
||||
* @param {CLIEngine} cliEngine The CLIEngine instance.
|
||||
* @param {CLIEngineLintReport} report The CLIEngine linting report to process.
|
||||
* @returns {LintResult[]} The processed linting results.
|
||||
*/
|
||||
function processCLIEngineLintReport(cliEngine, { results }) {
|
||||
const descriptor = {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
return getOrFindUsedDeprecatedRules(cliEngine, this.filePath);
|
||||
}
|
||||
};
|
||||
|
||||
for (const result of results) {
|
||||
Object.defineProperty(result, "usedDeprecatedRules", descriptor);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Array.prototype.sort() compatible compare function to order results by their file path.
|
||||
* @param {LintResult} a The first lint result.
|
||||
* @param {LintResult} b The second lint result.
|
||||
* @returns {number} An integer representing the order in which the two results should occur.
|
||||
*/
|
||||
function compareResultsByFilePath(a, b) {
|
||||
if (a.filePath < b.filePath) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.filePath > b.filePath) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API.
|
||||
*/
|
||||
class LegacyESLint {
|
||||
|
||||
/**
|
||||
* The type of configuration used by this class.
|
||||
* @type {string}
|
||||
*/
|
||||
static configType = "eslintrc";
|
||||
|
||||
/**
|
||||
* Creates a new instance of the main ESLint API.
|
||||
* @param {LegacyESLintOptions} options The options for this instance.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
const processedOptions = processOptions(options);
|
||||
const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins });
|
||||
const {
|
||||
configArrayFactory,
|
||||
lastConfigArrays
|
||||
} = getCLIEngineInternalSlots(cliEngine);
|
||||
let updated = false;
|
||||
|
||||
/*
|
||||
* Address `overrideConfig` to set override config.
|
||||
* Operate the `configArrayFactory` internal slot directly because this
|
||||
* functionality doesn't exist as the public API of CLIEngine.
|
||||
*/
|
||||
if (hasDefinedProperty(options.overrideConfig)) {
|
||||
configArrayFactory.setOverrideConfig(options.overrideConfig);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Update caches.
|
||||
if (updated) {
|
||||
configArrayFactory.clearCache();
|
||||
lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
|
||||
}
|
||||
|
||||
// Initialize private properties.
|
||||
privateMembersMap.set(this, {
|
||||
cliEngine,
|
||||
options: processedOptions
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The version text.
|
||||
* @type {string}
|
||||
*/
|
||||
static get version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs fixes from the given results to files.
|
||||
* @param {LintResult[]} results The lint results.
|
||||
* @returns {Promise<void>} Returns a promise that is used to track side effects.
|
||||
*/
|
||||
static async outputFixes(results) {
|
||||
if (!Array.isArray(results)) {
|
||||
throw new Error("'results' must be an array");
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
results
|
||||
.filter(result => {
|
||||
if (typeof result !== "object" || result === null) {
|
||||
throw new Error("'results' must include only objects");
|
||||
}
|
||||
return (
|
||||
typeof result.output === "string" &&
|
||||
path.isAbsolute(result.filePath)
|
||||
);
|
||||
})
|
||||
.map(r => writeFile(r.filePath, r.output))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns results that only contains errors.
|
||||
* @param {LintResult[]} results The results to filter.
|
||||
* @returns {LintResult[]} The filtered results.
|
||||
*/
|
||||
static getErrorResults(results) {
|
||||
return CLIEngine.getErrorResults(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns meta objects for each rule represented in the lint results.
|
||||
* @param {LintResult[]} results The results to fetch rules meta for.
|
||||
* @returns {Object} A mapping of ruleIds to rule meta objects.
|
||||
*/
|
||||
getRulesMetaForResults(results) {
|
||||
|
||||
const resultRuleIds = new Set();
|
||||
|
||||
// first gather all ruleIds from all results
|
||||
|
||||
for (const result of results) {
|
||||
for (const { ruleId } of result.messages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
for (const { ruleId } of result.suppressedMessages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
// create a map of all rules in the results
|
||||
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
const rules = cliEngine.getRules();
|
||||
const resultRules = new Map();
|
||||
|
||||
for (const [ruleId, rule] of rules) {
|
||||
if (resultRuleIds.has(ruleId)) {
|
||||
resultRules.set(ruleId, rule);
|
||||
}
|
||||
}
|
||||
|
||||
return createRulesMeta(resultRules);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the current configuration on an array of file and directory names.
|
||||
* @param {string[]} patterns An array of file and directory names.
|
||||
* @returns {Promise<LintResult[]>} The results of linting the file patterns given.
|
||||
*/
|
||||
async lintFiles(patterns) {
|
||||
const { cliEngine, options } = privateMembersMap.get(this);
|
||||
|
||||
if (options.passOnNoPatterns && (patterns === "" || (Array.isArray(patterns) && patterns.length === 0))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!isNonEmptyString(patterns) && !isArrayOfNonEmptyString(patterns)) {
|
||||
throw new Error("'patterns' must be a non-empty string or an array of non-empty strings");
|
||||
}
|
||||
|
||||
return processCLIEngineLintReport(
|
||||
cliEngine,
|
||||
cliEngine.executeOnFiles(patterns)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the current configuration on text.
|
||||
* @param {string} code A string of JavaScript code to lint.
|
||||
* @param {Object} [options] The options.
|
||||
* @param {string} [options.filePath] The path to the file of the source code.
|
||||
* @param {boolean} [options.warnIgnored] When set to true, warn if given filePath is an ignored path.
|
||||
* @returns {Promise<LintResult[]>} The results of linting the string of code given.
|
||||
*/
|
||||
async lintText(code, options = {}) {
|
||||
if (typeof code !== "string") {
|
||||
throw new Error("'code' must be a string");
|
||||
}
|
||||
if (typeof options !== "object") {
|
||||
throw new Error("'options' must be an object, null, or undefined");
|
||||
}
|
||||
const {
|
||||
filePath,
|
||||
warnIgnored = false,
|
||||
...unknownOptions
|
||||
} = options || {};
|
||||
|
||||
const unknownOptionKeys = Object.keys(unknownOptions);
|
||||
|
||||
if (unknownOptionKeys.length > 0) {
|
||||
throw new Error(`'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`);
|
||||
}
|
||||
|
||||
if (filePath !== void 0 && !isNonEmptyString(filePath)) {
|
||||
throw new Error("'options.filePath' must be a non-empty string or undefined");
|
||||
}
|
||||
if (typeof warnIgnored !== "boolean") {
|
||||
throw new Error("'options.warnIgnored' must be a boolean or undefined");
|
||||
}
|
||||
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return processCLIEngineLintReport(
|
||||
cliEngine,
|
||||
cliEngine.executeOnText(code, filePath, warnIgnored)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter representing the given formatter name.
|
||||
* @param {string} [name] The name of the formatter to load.
|
||||
* The following values are allowed:
|
||||
* - `undefined` ... Load `stylish` builtin formatter.
|
||||
* - A builtin formatter name ... Load the builtin formatter.
|
||||
* - A third-party formatter name:
|
||||
* - `foo` → `eslint-formatter-foo`
|
||||
* - `@foo` → `@foo/eslint-formatter`
|
||||
* - `@foo/bar` → `@foo/eslint-formatter-bar`
|
||||
* - A file path ... Load the file.
|
||||
* @returns {Promise<LoadedFormatter>} A promise resolving to the formatter object.
|
||||
* This promise will be rejected if the given formatter was not found or not
|
||||
* a function.
|
||||
*/
|
||||
async loadFormatter(name = "stylish") {
|
||||
if (typeof name !== "string") {
|
||||
throw new Error("'name' must be a string");
|
||||
}
|
||||
|
||||
const { cliEngine, options } = privateMembersMap.get(this);
|
||||
const formatter = cliEngine.getFormatter(name);
|
||||
|
||||
if (typeof formatter !== "function") {
|
||||
throw new Error(`Formatter must be a function, but got a ${typeof formatter}.`);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* The main formatter method.
|
||||
* @param {LintResult[]} results The lint results to format.
|
||||
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
||||
* @returns {string | Promise<string>} The formatted lint results.
|
||||
*/
|
||||
format(results, resultsMeta) {
|
||||
let rulesMeta = null;
|
||||
|
||||
results.sort(compareResultsByFilePath);
|
||||
|
||||
return formatter(results, {
|
||||
...resultsMeta,
|
||||
get cwd() {
|
||||
return options.cwd;
|
||||
},
|
||||
get rulesMeta() {
|
||||
if (!rulesMeta) {
|
||||
rulesMeta = createRulesMeta(cliEngine.getRules());
|
||||
}
|
||||
|
||||
return rulesMeta;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} filePath The path of the file to retrieve a config object for.
|
||||
* @returns {Promise<ConfigData>} A configuration object for the file.
|
||||
*/
|
||||
async calculateConfigForFile(filePath) {
|
||||
if (!isNonEmptyString(filePath)) {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return cliEngine.getConfigForFile(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given path is ignored by ESLint.
|
||||
* @param {string} filePath The path of the file to check.
|
||||
* @returns {Promise<boolean>} Whether or not the given path is ignored.
|
||||
*/
|
||||
async isPathIgnored(filePath) {
|
||||
if (!isNonEmptyString(filePath)) {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
|
||||
return cliEngine.isPathIgnored(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
LegacyESLint,
|
||||
|
||||
/**
|
||||
* Get the private class members of a given ESLint instance for tests.
|
||||
* @param {ESLint} instance The ESLint instance to get.
|
||||
* @returns {ESLintPrivateMembers} The instance's private class members.
|
||||
*/
|
||||
getESLintPrivateMembers(instance) {
|
||||
return privateMembersMap.get(instance);
|
||||
}
|
||||
};
|
90
tools/node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
90
tools/node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
|
@ -16,6 +16,11 @@
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
const escapeRegExp = require("escape-string-regexp");
|
||||
const {
|
||||
Legacy: {
|
||||
ConfigOps
|
||||
}
|
||||
} = require("@eslint/eslintrc/universal");
|
||||
|
||||
/**
|
||||
* Compares the locations of two objects in a source file
|
||||
|
@ -33,16 +38,16 @@ function compareLocations(itemA, itemB) {
|
|||
* @param {Iterable<Directive>} directives Unused directives to be removed.
|
||||
* @returns {Directive[][]} Directives grouped by their parent comment.
|
||||
*/
|
||||
function groupByParentComment(directives) {
|
||||
function groupByParentDirective(directives) {
|
||||
const groups = new Map();
|
||||
|
||||
for (const directive of directives) {
|
||||
const { unprocessedDirective: { parentComment } } = directive;
|
||||
const { unprocessedDirective: { parentDirective } } = directive;
|
||||
|
||||
if (groups.has(parentComment)) {
|
||||
groups.get(parentComment).push(directive);
|
||||
if (groups.has(parentDirective)) {
|
||||
groups.get(parentDirective).push(directive);
|
||||
} else {
|
||||
groups.set(parentComment, [directive]);
|
||||
groups.set(parentDirective, [directive]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,19 +57,19 @@ function groupByParentComment(directives) {
|
|||
/**
|
||||
* Creates removal details for a set of directives within the same comment.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {Token} commentToken The backing Comment token.
|
||||
* @param {Token} node The backing Comment token.
|
||||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function createIndividualDirectivesRemoval(directives, commentToken) {
|
||||
function createIndividualDirectivesRemoval(directives, node) {
|
||||
|
||||
/*
|
||||
* `commentToken.value` starts right after `//` or `/*`.
|
||||
* `node.value` starts right after `//` or `/*`.
|
||||
* All calculated offsets will be relative to this index.
|
||||
*/
|
||||
const commentValueStart = commentToken.range[0] + "//".length;
|
||||
const commentValueStart = node.range[0] + "//".length;
|
||||
|
||||
// Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
|
||||
const listStartOffset = /^\s*\S+\s+/u.exec(commentToken.value)[0].length;
|
||||
const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length;
|
||||
|
||||
/*
|
||||
* Get the list text without any surrounding whitespace. In order to preserve the original
|
||||
|
@ -73,7 +78,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
||||
const listText = commentToken.value
|
||||
const listText = node.value
|
||||
.slice(listStartOffset) // remove directive name and all whitespace before the list
|
||||
.split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
|
||||
.trimEnd(); // remove all whitespace after the list
|
||||
|
@ -154,19 +159,19 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a description of deleting an entire unused disable comment.
|
||||
* Creates a description of deleting an entire unused disable directive.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {Token} commentToken The backing Comment token.
|
||||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output Problem.
|
||||
* @param {Token} node The backing Comment token.
|
||||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem.
|
||||
*/
|
||||
function createCommentRemoval(directives, commentToken) {
|
||||
const { range } = commentToken;
|
||||
function createDirectiveRemoval(directives, node) {
|
||||
const { range } = node;
|
||||
const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`);
|
||||
|
||||
return {
|
||||
description: ruleIds.length <= 2
|
||||
? ruleIds.join(" or ")
|
||||
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds[ruleIds.length - 1]}`,
|
||||
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds.at(-1)}`,
|
||||
fix: {
|
||||
range,
|
||||
text: " "
|
||||
|
@ -181,20 +186,20 @@ function createCommentRemoval(directives, commentToken) {
|
|||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function processUnusedDirectives(allDirectives) {
|
||||
const directiveGroups = groupByParentComment(allDirectives);
|
||||
const directiveGroups = groupByParentDirective(allDirectives);
|
||||
|
||||
return directiveGroups.flatMap(
|
||||
directives => {
|
||||
const { parentComment } = directives[0].unprocessedDirective;
|
||||
const remainingRuleIds = new Set(parentComment.ruleIds);
|
||||
const { parentDirective } = directives[0].unprocessedDirective;
|
||||
const remainingRuleIds = new Set(parentDirective.ruleIds);
|
||||
|
||||
for (const directive of directives) {
|
||||
remainingRuleIds.delete(directive.ruleId);
|
||||
}
|
||||
|
||||
return remainingRuleIds.size
|
||||
? createIndividualDirectivesRemoval(directives, parentComment.commentToken)
|
||||
: [createCommentRemoval(directives, parentComment.commentToken)];
|
||||
? createIndividualDirectivesRemoval(directives, parentDirective.node)
|
||||
: [createDirectiveRemoval(directives, parentDirective.node)];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -337,7 +342,7 @@ function applyDirectives(options) {
|
|||
problem.suppressions = problem.suppressions.concat(suppressions);
|
||||
} else {
|
||||
problem.suppressions = suppressions;
|
||||
usedDisableDirectives.add(disableDirectivesForProblem[disableDirectivesForProblem.length - 1]);
|
||||
usedDisableDirectives.add(disableDirectivesForProblem.at(-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,11 +350,11 @@ function applyDirectives(options) {
|
|||
}
|
||||
|
||||
const unusedDisableDirectivesToReport = options.directives
|
||||
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive));
|
||||
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive) && !options.rulesToIgnore.has(directive.ruleId));
|
||||
|
||||
|
||||
const unusedEnableDirectivesToReport = new Set(
|
||||
options.directives.filter(directive => directive.unprocessedDirective.type === "enable")
|
||||
options.directives.filter(directive => directive.unprocessedDirective.type === "enable" && !options.rulesToIgnore.has(directive.ruleId))
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -367,7 +372,7 @@ function applyDirectives(options) {
|
|||
|
||||
const unusedDirectives = processed
|
||||
.map(({ description, fix, unprocessedDirective }) => {
|
||||
const { parentComment, type, line, column } = unprocessedDirective;
|
||||
const { parentDirective, type, line, column } = unprocessedDirective;
|
||||
|
||||
let message;
|
||||
|
||||
|
@ -383,8 +388,8 @@ function applyDirectives(options) {
|
|||
return {
|
||||
ruleId: null,
|
||||
message,
|
||||
line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line,
|
||||
column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column,
|
||||
line: type === "disable-next-line" ? parentDirective.node.loc.start.line : line,
|
||||
column: type === "disable-next-line" ? parentDirective.node.loc.start.column + 1 : column,
|
||||
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
||||
nodeType: null,
|
||||
...options.disableFixes ? {} : { fix }
|
||||
|
@ -410,11 +415,13 @@ function applyDirectives(options) {
|
|||
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
||||
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
||||
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
||||
* @param {Object} options.configuredRules The rules configuration.
|
||||
* @param {Function} options.ruleFilter A predicate function to filter which rules should be executed.
|
||||
* @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
|
||||
* @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
|
||||
* An object with a list of reported problems, the suppressed of which contain the suppression information.
|
||||
*/
|
||||
module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirectives = "off" }) => {
|
||||
module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => {
|
||||
const blockDirectives = directives
|
||||
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
||||
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
||||
|
@ -443,17 +450,38 @@ module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirec
|
|||
}
|
||||
}).sort(compareLocations);
|
||||
|
||||
// This determines a list of rules that are not being run by the given ruleFilter, if present.
|
||||
const rulesToIgnore = configuredRules && ruleFilter
|
||||
? new Set(Object.keys(configuredRules).filter(ruleId => {
|
||||
const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
|
||||
|
||||
// Ignore for disabled rules.
|
||||
if (severity === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !ruleFilter({ severity, ruleId });
|
||||
}))
|
||||
: new Set();
|
||||
|
||||
// If no ruleId is supplied that means this directive is applied to all rules, so we can't determine if it's unused if any rules are filtered out.
|
||||
if (rulesToIgnore.size > 0) {
|
||||
rulesToIgnore.add(null);
|
||||
}
|
||||
|
||||
const blockDirectivesResult = applyDirectives({
|
||||
problems,
|
||||
directives: blockDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives
|
||||
reportUnusedDisableDirectives,
|
||||
rulesToIgnore
|
||||
});
|
||||
const lineDirectivesResult = applyDirectives({
|
||||
problems: blockDirectivesResult.problems,
|
||||
directives: lineDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives
|
||||
reportUnusedDisableDirectives,
|
||||
rulesToIgnore
|
||||
});
|
||||
|
||||
return reportUnusedDisableDirectives !== "off"
|
||||
|
|
3
tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
3
tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
|
@ -9,7 +9,7 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("assert"),
|
||||
const assert = require("node:assert"),
|
||||
{ breakableTypePattern } = require("../../shared/ast-utils"),
|
||||
CodePath = require("./code-path"),
|
||||
CodePathSegment = require("./code-path-segment"),
|
||||
|
@ -222,7 +222,6 @@ function forwardCurrentToHead(analyzer, node) {
|
|||
: "onUnreachableCodePathSegmentStart";
|
||||
|
||||
debug.dump(`${eventName} ${headSegment.id}`);
|
||||
|
||||
CodePathSegment.markUsed(headSegment);
|
||||
analyzer.emitter.emit(
|
||||
eventName,
|
||||
|
|
62
tools/node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
62
tools/node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
|
@ -125,20 +125,6 @@ class CodePath {
|
|||
return this.internal.thrownForkContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the traversal of the code path through each segment. This array
|
||||
* starts empty and segments are added or removed as the code path is
|
||||
* traversed. This array always ends up empty at the end of a code path
|
||||
* traversal. The `CodePathState` uses this to track its progress through
|
||||
* the code path.
|
||||
* This is a passthrough to the underlying `CodePathState`.
|
||||
* @type {CodePathSegment[]}
|
||||
* @deprecated
|
||||
*/
|
||||
get currentSegments() {
|
||||
return this.internal.currentSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses all segments in this code path.
|
||||
*
|
||||
|
@ -180,9 +166,9 @@ class CodePath {
|
|||
const lastSegment = resolvedOptions.last;
|
||||
|
||||
// set up initial location information
|
||||
let record = null;
|
||||
let index = 0;
|
||||
let end = 0;
|
||||
let record;
|
||||
let index;
|
||||
let end;
|
||||
let segment = null;
|
||||
|
||||
// segments that have already been visited during traversal
|
||||
|
@ -191,8 +177,8 @@ class CodePath {
|
|||
// tracks the traversal steps
|
||||
const stack = [[startSegment, 0]];
|
||||
|
||||
// tracks the last skipped segment during traversal
|
||||
let skippedSegment = null;
|
||||
// segments that have been skipped during traversal
|
||||
const skipped = new Set();
|
||||
|
||||
// indicates if we exited early from the traversal
|
||||
let broken = false;
|
||||
|
@ -207,11 +193,7 @@ class CodePath {
|
|||
* @returns {void}
|
||||
*/
|
||||
skip() {
|
||||
if (stack.length <= 1) {
|
||||
broken = true;
|
||||
} else {
|
||||
skippedSegment = stack[stack.length - 2][0];
|
||||
}
|
||||
skipped.add(segment);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -236,6 +218,18 @@ class CodePath {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given previous segment has been skipped.
|
||||
* @param {CodePathSegment} prevSegment A previous segment to check.
|
||||
* @returns {boolean} `true` if the segment has been skipped.
|
||||
*/
|
||||
function isSkipped(prevSegment) {
|
||||
return (
|
||||
skipped.has(prevSegment) ||
|
||||
segment.isLoopedPrevSegment(prevSegment)
|
||||
);
|
||||
}
|
||||
|
||||
// the traversal
|
||||
while (stack.length > 0) {
|
||||
|
||||
|
@ -251,7 +245,7 @@ class CodePath {
|
|||
* Otherwise, we just read the value and sometimes modify the
|
||||
* record as we traverse.
|
||||
*/
|
||||
record = stack[stack.length - 1];
|
||||
record = stack.at(-1);
|
||||
segment = record[0];
|
||||
index = record[1];
|
||||
|
||||
|
@ -272,17 +266,21 @@ class CodePath {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Reset the skipping flag if all branches have been skipped.
|
||||
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
|
||||
skippedSegment = null;
|
||||
}
|
||||
visited.add(segment);
|
||||
|
||||
|
||||
// Skips the segment if all previous segments have been skipped.
|
||||
const shouldSkip = (
|
||||
skipped.size > 0 &&
|
||||
segment.prevSegments.length > 0 &&
|
||||
segment.prevSegments.every(isSkipped)
|
||||
);
|
||||
|
||||
/*
|
||||
* If the most recent segment hasn't been skipped, then we call
|
||||
* the callback, passing in the segment and the controller.
|
||||
*/
|
||||
if (!skippedSegment) {
|
||||
if (!shouldSkip) {
|
||||
resolvedCallback.call(this, segment, controller);
|
||||
|
||||
// exit if we're at the last segment
|
||||
|
@ -298,6 +296,10 @@ class CodePath {
|
|||
if (broken) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
// If the most recent segment has been skipped, then mark it as skipped.
|
||||
skipped.add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
4
tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
4
tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
|
@ -13,7 +13,7 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("assert"),
|
||||
const assert = require("node:assert"),
|
||||
CodePathSegment = require("./code-path-segment");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -207,7 +207,7 @@ class ForkContext {
|
|||
get head() {
|
||||
const list = this.segmentsList;
|
||||
|
||||
return list.length === 0 ? [] : list[list.length - 1];
|
||||
return list.length === 0 ? [] : list.at(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
19
tools/node_modules/eslint/lib/linter/config-comment-parser.js
generated
vendored
19
tools/node_modules/eslint/lib/linter/config-comment-parser.js
generated
vendored
|
@ -40,7 +40,7 @@ module.exports = class ConfigCommentParser {
|
|||
|
||||
/**
|
||||
* Parses a list of "name:string_value" or/and "name" options divided by comma or
|
||||
* whitespace. Used for "global" and "exported" comments.
|
||||
* whitespace. Used for "global" comments.
|
||||
* @param {string} string The string to parse.
|
||||
* @param {Comment} comment The comment node which has the string.
|
||||
* @returns {Object} Result map object of names and string values, or null values if no value was provided
|
||||
|
@ -75,11 +75,9 @@ module.exports = class ConfigCommentParser {
|
|||
parseJsonConfig(string, location) {
|
||||
debug("Parsing JSON config");
|
||||
|
||||
let items = {};
|
||||
|
||||
// Parses a JSON-like comment by the same way as parsing CLI option.
|
||||
try {
|
||||
items = levn.parse("Object", string) || {};
|
||||
const items = levn.parse("Object", string) || {};
|
||||
|
||||
// Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`.
|
||||
// Also, commaless notations have invalid severity:
|
||||
|
@ -102,11 +100,15 @@ module.exports = class ConfigCommentParser {
|
|||
* Optionator cannot parse commaless notations.
|
||||
* But we are supporting that. So this is a fallback for that.
|
||||
*/
|
||||
items = {};
|
||||
const normalizedString = string.replace(/([-a-zA-Z0-9/]+):/gu, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/u, "$1,");
|
||||
|
||||
try {
|
||||
items = JSON.parse(`{${normalizedString}}`);
|
||||
const items = JSON.parse(`{${normalizedString}}`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
config: items
|
||||
};
|
||||
} catch (ex) {
|
||||
debug("Manual parsing failed.");
|
||||
|
||||
|
@ -124,11 +126,6 @@ module.exports = class ConfigCommentParser {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
config: items
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
4
tools/node_modules/eslint/lib/linter/index.js
generated
vendored
4
tools/node_modules/eslint/lib/linter/index.js
generated
vendored
|
@ -1,13 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
const { Linter } = require("./linter");
|
||||
const interpolate = require("./interpolate");
|
||||
const SourceCodeFixer = require("./source-code-fixer");
|
||||
|
||||
module.exports = {
|
||||
Linter,
|
||||
|
||||
// For testers.
|
||||
SourceCodeFixer,
|
||||
interpolate
|
||||
SourceCodeFixer
|
||||
};
|
||||
|
|
26
tools/node_modules/eslint/lib/linter/interpolate.js
generated
vendored
26
tools/node_modules/eslint/lib/linter/interpolate.js
generated
vendored
|
@ -9,13 +9,30 @@
|
|||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = (text, data) => {
|
||||
/**
|
||||
* Returns a global expression matching placeholders in messages.
|
||||
* @returns {RegExp} Global regular expression matching placeholders
|
||||
*/
|
||||
function getPlaceholderMatcher() {
|
||||
return /\{\{([^{}]+?)\}\}/gu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces {{ placeholders }} in the message with the provided data.
|
||||
* Does not replace placeholders not available in the data.
|
||||
* @param {string} text Original message with potential placeholders
|
||||
* @param {Record<string, string>} data Map of placeholder name to its value
|
||||
* @returns {string} Message with replaced placeholders
|
||||
*/
|
||||
function interpolate(text, data) {
|
||||
if (!data) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const matcher = getPlaceholderMatcher();
|
||||
|
||||
// Substitution content for any {{ }} markers.
|
||||
return text.replace(/\{\{([^{}]+?)\}\}/gu, (fullMatch, termWithWhitespace) => {
|
||||
return text.replace(matcher, (fullMatch, termWithWhitespace) => {
|
||||
const term = termWithWhitespace.trim();
|
||||
|
||||
if (term in data) {
|
||||
|
@ -25,4 +42,9 @@ module.exports = (text, data) => {
|
|||
// Preserve old behavior: If parameter name not provided, don't replace it.
|
||||
return fullMatch;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPlaceholderMatcher,
|
||||
interpolate
|
||||
};
|
||||
|
|
633
tools/node_modules/eslint/lib/linter/linter.js
generated
vendored
633
tools/node_modules/eslint/lib/linter/linter.js
generated
vendored
File diff suppressed because it is too large
Load diff
8
tools/node_modules/eslint/lib/linter/report-translator.js
generated
vendored
8
tools/node_modules/eslint/lib/linter/report-translator.js
generated
vendored
|
@ -9,9 +9,9 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("assert");
|
||||
const assert = require("node:assert");
|
||||
const ruleFixer = require("./rule-fixer");
|
||||
const interpolate = require("./interpolate");
|
||||
const { interpolate } = require("./interpolate");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
|
@ -160,7 +160,7 @@ function mergeFixes(fixes, sourceCode) {
|
|||
|
||||
const originalText = sourceCode.text;
|
||||
const start = fixes[0].range[0];
|
||||
const end = fixes[fixes.length - 1].range[1];
|
||||
const end = fixes.at(-1).range[1];
|
||||
let text = "";
|
||||
let lastPos = Number.MIN_SAFE_INTEGER;
|
||||
|
||||
|
@ -343,7 +343,7 @@ module.exports = function createReportTranslator(metadata) {
|
|||
if (descriptor.message) {
|
||||
throw new TypeError("context.report() called with a message and a messageId. Please only pass one.");
|
||||
}
|
||||
if (!messages || !Object.prototype.hasOwnProperty.call(messages, id)) {
|
||||
if (!messages || !Object.hasOwn(messages, id)) {
|
||||
throw new TypeError(`context.report() called with a messageId of '${id}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`);
|
||||
}
|
||||
computedMessage = messages[id];
|
||||
|
|
21
tools/node_modules/eslint/lib/linter/rules.js
generated
vendored
21
tools/node_modules/eslint/lib/linter/rules.js
generated
vendored
|
@ -13,18 +13,10 @@
|
|||
const builtInRules = require("../rules");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Normalizes a rule module to the new-style API
|
||||
* @param {(Function|{create: Function})} rule A rule object, which can either be a function
|
||||
* ("old-style") or an object with a `create` method ("new-style")
|
||||
* @returns {{create: Function}} A new-style rule.
|
||||
*/
|
||||
function normalizeRule(rule) {
|
||||
return typeof rule === "function" ? Object.assign({ create: rule }, rule) : rule;
|
||||
}
|
||||
/** @typedef {import("../shared/types").Rule} Rule */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
|
@ -41,18 +33,17 @@ class Rules {
|
|||
/**
|
||||
* Registers a rule module for rule id in storage.
|
||||
* @param {string} ruleId Rule id (file name).
|
||||
* @param {Function} ruleModule Rule handler.
|
||||
* @param {Rule} rule Rule object.
|
||||
* @returns {void}
|
||||
*/
|
||||
define(ruleId, ruleModule) {
|
||||
this._rules[ruleId] = normalizeRule(ruleModule);
|
||||
define(ruleId, rule) {
|
||||
this._rules[ruleId] = rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access rule handler by id (file name).
|
||||
* @param {string} ruleId Rule id (file name).
|
||||
* @returns {{create: Function, schema: JsonSchema[]}}
|
||||
* A rule. This is normalized to always have the new-style shape with a `create` method.
|
||||
* @returns {Rule} Rule object.
|
||||
*/
|
||||
get(ruleId) {
|
||||
if (typeof this._rules[ruleId] === "string") {
|
||||
|
|
2
tools/node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
2
tools/node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
|
@ -107,7 +107,7 @@ SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {
|
|||
}
|
||||
|
||||
messages.forEach(problem => {
|
||||
if (Object.prototype.hasOwnProperty.call(problem, "fix")) {
|
||||
if (Object.hasOwn(problem, "fix")) {
|
||||
fixes.push(problem);
|
||||
} else {
|
||||
remainingMessages.push(problem);
|
||||
|
|
26
tools/node_modules/eslint/lib/linter/timing.js
generated
vendored
26
tools/node_modules/eslint/lib/linter/timing.js
generated
vendored
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { startTime, endTime } = require("../shared/stats");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -128,21 +130,27 @@ module.exports = (function() {
|
|||
* Time the run
|
||||
* @param {any} key key from the data object
|
||||
* @param {Function} fn function to be called
|
||||
* @param {boolean} stats if 'stats' is true, return the result and the time difference
|
||||
* @returns {Function} function to be executed
|
||||
* @private
|
||||
*/
|
||||
function time(key, fn) {
|
||||
if (typeof data[key] === "undefined") {
|
||||
data[key] = 0;
|
||||
}
|
||||
function time(key, fn, stats) {
|
||||
|
||||
return function(...args) {
|
||||
let t = process.hrtime();
|
||||
const result = fn(...args);
|
||||
|
||||
t = process.hrtime(t);
|
||||
data[key] += t[0] * 1e3 + t[1] / 1e6;
|
||||
return result;
|
||||
const t = startTime();
|
||||
const result = fn(...args);
|
||||
const tdiff = endTime(t);
|
||||
|
||||
if (enabled) {
|
||||
if (typeof data[key] === "undefined") {
|
||||
data[key] = 0;
|
||||
}
|
||||
|
||||
data[key] += tdiff;
|
||||
}
|
||||
|
||||
return stats ? { result, tdiff } : result;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
38
tools/node_modules/eslint/lib/options.js
generated
vendored
38
tools/node_modules/eslint/lib/options.js
generated
vendored
|
@ -38,7 +38,7 @@ const optionator = require("optionator");
|
|||
* @property {boolean} [help] Show help
|
||||
* @property {boolean} ignore Disable use of ignore files and patterns
|
||||
* @property {string} [ignorePath] Specify path of ignore file
|
||||
* @property {string[]} [ignorePattern] Pattern of files to ignore (in addition to those in .eslintignore)
|
||||
* @property {string[]} [ignorePattern] Patterns of files to ignore. In eslintrc mode, these are in addition to `.eslintignore`
|
||||
* @property {boolean} init Run config initialization wizard
|
||||
* @property {boolean} inlineConfig Prevent comments from changing config or rules
|
||||
* @property {number} maxWarnings Number of warnings to trigger nonzero exit code
|
||||
|
@ -57,7 +57,10 @@ const optionator = require("optionator");
|
|||
* @property {boolean} quiet Report errors only
|
||||
* @property {boolean} [version] Output the version number
|
||||
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files
|
||||
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
||||
* the linting operation to short circuit and not report any failures.
|
||||
* @property {string[]} _ Positional filenames or patterns
|
||||
* @property {boolean} [stats] Report additional statistics
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -101,6 +104,16 @@ module.exports = function(usingFlatConfig) {
|
|||
};
|
||||
}
|
||||
|
||||
let inspectConfigFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
inspectConfigFlag = {
|
||||
option: "inspect-config",
|
||||
type: "Boolean",
|
||||
description: "Open the config inspector with the current configuration"
|
||||
};
|
||||
}
|
||||
|
||||
let extFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
|
@ -141,6 +154,17 @@ module.exports = function(usingFlatConfig) {
|
|||
};
|
||||
}
|
||||
|
||||
let statsFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
statsFlag = {
|
||||
option: "stats",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Add statistics to the lint report"
|
||||
};
|
||||
}
|
||||
|
||||
let warnIgnoredFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
|
@ -171,6 +195,7 @@ module.exports = function(usingFlatConfig) {
|
|||
? "Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs"
|
||||
: "Use this configuration, overriding .eslintrc.* config options if present"
|
||||
},
|
||||
inspectConfigFlag,
|
||||
envFlag,
|
||||
extFlag,
|
||||
{
|
||||
|
@ -236,7 +261,7 @@ module.exports = function(usingFlatConfig) {
|
|||
{
|
||||
option: "ignore-pattern",
|
||||
type: "[String]",
|
||||
description: "Pattern of files to ignore (in addition to those in .eslintignore)",
|
||||
description: `Patterns of files to ignore${usingFlatConfig ? "" : " (in addition to those in .eslintignore)"}`,
|
||||
concatRepeatedArrays: [true, {
|
||||
oneValuePerFlag: true
|
||||
}]
|
||||
|
@ -370,6 +395,12 @@ module.exports = function(usingFlatConfig) {
|
|||
description: "Exit with exit code 2 in case of fatal error"
|
||||
},
|
||||
warnIgnoredFlag,
|
||||
{
|
||||
option: "pass-on-no-patterns",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Exit with exit code 0 in case no file patterns are passed"
|
||||
},
|
||||
{
|
||||
option: "debug",
|
||||
type: "Boolean",
|
||||
|
@ -392,7 +423,8 @@ module.exports = function(usingFlatConfig) {
|
|||
option: "print-config",
|
||||
type: "path::String",
|
||||
description: "Print the configuration for the given file"
|
||||
}
|
||||
},
|
||||
statsFlag
|
||||
].filter(value => !!value)
|
||||
});
|
||||
};
|
||||
|
|
1131
tools/node_modules/eslint/lib/rule-tester/flat-rule-tester.js
generated
vendored
1131
tools/node_modules/eslint/lib/rule-tester/flat-rule-tester.js
generated
vendored
File diff suppressed because it is too large
Load diff
4
tools/node_modules/eslint/lib/rule-tester/index.js
generated
vendored
4
tools/node_modules/eslint/lib/rule-tester/index.js
generated
vendored
|
@ -1,5 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
const RuleTester = require("./rule-tester");
|
||||
|
||||
module.exports = {
|
||||
RuleTester: require("./rule-tester")
|
||||
RuleTester
|
||||
};
|
||||
|
|
777
tools/node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
777
tools/node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
File diff suppressed because it is too large
Load diff
2
tools/node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
2
tools/node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
|
@ -74,7 +74,7 @@ module.exports = {
|
|||
function normalizeOptionValue(option) {
|
||||
let consistent = false;
|
||||
let multiline = false;
|
||||
let minItems = 0;
|
||||
let minItems;
|
||||
|
||||
if (option) {
|
||||
if (option === "consistent") {
|
||||
|
|
2
tools/node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
2
tools/node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
|
@ -199,7 +199,7 @@ module.exports = {
|
|||
: sourceCode.getLastToken(node),
|
||||
penultimate = sourceCode.getTokenBefore(last),
|
||||
firstElement = node.elements[0],
|
||||
lastElement = node.elements[node.elements.length - 1];
|
||||
lastElement = node.elements.at(-1);
|
||||
|
||||
const openingBracketMustBeSpaced =
|
||||
options.objectsInArraysException && isObjectType(firstElement) ||
|
||||
|
|
2
tools/node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
2
tools/node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
|
@ -79,7 +79,7 @@ module.exports = {
|
|||
}
|
||||
|
||||
// Defines a predicate to check whether or not a given reference is outside of valid scope.
|
||||
const scopeRange = stack[stack.length - 1];
|
||||
const scopeRange = stack.at(-1);
|
||||
|
||||
/**
|
||||
* Check if a reference is out of scope
|
||||
|
|
4
tools/node_modules/eslint/lib/rules/callback-return.js
generated
vendored
4
tools/node_modules/eslint/lib/rules/callback-return.js
generated
vendored
|
@ -147,7 +147,7 @@ module.exports = {
|
|||
if (closestBlock.type === "BlockStatement") {
|
||||
|
||||
// find the last item in the block
|
||||
const lastItem = closestBlock.body[closestBlock.body.length - 1];
|
||||
const lastItem = closestBlock.body.at(-1);
|
||||
|
||||
// if the callback is the last thing in a block that might be ok
|
||||
if (isCallbackExpression(node, lastItem)) {
|
||||
|
@ -168,7 +168,7 @@ module.exports = {
|
|||
if (lastItem.type === "ReturnStatement") {
|
||||
|
||||
// but only if the callback is immediately before
|
||||
if (isCallbackExpression(node, closestBlock.body[closestBlock.body.length - 2])) {
|
||||
if (isCallbackExpression(node, closestBlock.body.at(-2))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
8
tools/node_modules/eslint/lib/rules/camelcase.js
generated
vendored
8
tools/node_modules/eslint/lib/rules/camelcase.js
generated
vendored
|
@ -47,11 +47,9 @@ module.exports = {
|
|||
},
|
||||
allow: {
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
type: "string"
|
||||
}
|
||||
],
|
||||
items: {
|
||||
type: "string"
|
||||
},
|
||||
minItems: 0,
|
||||
uniqueItems: true
|
||||
}
|
||||
|
|
17
tools/node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
17
tools/node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
|
@ -8,7 +8,6 @@
|
|||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const LETTER_PATTERN = require("./utils/patterns/letters");
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -17,7 +16,8 @@ const astUtils = require("./utils/ast-utils");
|
|||
|
||||
const DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
|
||||
WHITESPACE = /\s/gu,
|
||||
MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u; // TODO: Combine w/ max-len pattern?
|
||||
MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u, // TODO: Combine w/ max-len pattern?
|
||||
LETTER_PATTERN = /\p{L}/u;
|
||||
|
||||
/*
|
||||
* Base schema body for defining the basic capitalization rule, ignorePattern,
|
||||
|
@ -233,7 +233,8 @@ module.exports = {
|
|||
return true;
|
||||
}
|
||||
|
||||
const firstWordChar = commentWordCharsOnly[0];
|
||||
// Get the first Unicode character (1 or 2 code units).
|
||||
const [firstWordChar] = commentWordCharsOnly;
|
||||
|
||||
if (!LETTER_PATTERN.test(firstWordChar)) {
|
||||
return true;
|
||||
|
@ -273,12 +274,14 @@ module.exports = {
|
|||
messageId,
|
||||
fix(fixer) {
|
||||
const match = comment.value.match(LETTER_PATTERN);
|
||||
const char = match[0];
|
||||
|
||||
// Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
|
||||
const charIndex = comment.range[0] + match.index + 2;
|
||||
|
||||
return fixer.replaceTextRange(
|
||||
|
||||
// Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
|
||||
[comment.range[0] + match.index + 2, comment.range[0] + match.index + 3],
|
||||
capitalize === "always" ? match[0].toLocaleUpperCase() : match[0].toLocaleLowerCase()
|
||||
[charIndex, charIndex + char.length],
|
||||
capitalize === "always" ? char.toLocaleUpperCase() : char.toLocaleLowerCase()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
2
tools/node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
2
tools/node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
|
@ -154,7 +154,7 @@ module.exports = {
|
|||
* @returns {any} The last element
|
||||
*/
|
||||
function last(array) {
|
||||
return array[array.length - 1];
|
||||
return array.at(-1);
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
|
|
4
tools/node_modules/eslint/lib/rules/comma-style.js
generated
vendored
4
tools/node_modules/eslint/lib/rules/comma-style.js
generated
vendored
|
@ -66,7 +66,7 @@ module.exports = {
|
|||
NewExpression: true
|
||||
};
|
||||
|
||||
if (context.options.length === 2 && Object.prototype.hasOwnProperty.call(context.options[1], "exceptions")) {
|
||||
if (context.options.length === 2 && Object.hasOwn(context.options[1], "exceptions")) {
|
||||
const keys = Object.keys(context.options[1].exceptions);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
|
@ -218,7 +218,7 @@ module.exports = {
|
|||
|
||||
previousItemToken = tokenAfterItem
|
||||
? sourceCode.getTokenBefore(tokenAfterItem)
|
||||
: sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
|
||||
: sourceCode.ast.tokens.at(-1);
|
||||
} else {
|
||||
previousItemToken = currentItemToken;
|
||||
}
|
||||
|
|
15
tools/node_modules/eslint/lib/rules/complexity.js
generated
vendored
15
tools/node_modules/eslint/lib/rules/complexity.js
generated
vendored
|
@ -64,7 +64,7 @@ module.exports = {
|
|||
|
||||
if (
|
||||
typeof option === "object" &&
|
||||
(Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
|
||||
(Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
|
||||
) {
|
||||
THRESHOLD = option.maximum || option.max;
|
||||
} else if (typeof option === "number") {
|
||||
|
@ -109,6 +109,7 @@ module.exports = {
|
|||
IfStatement: increaseComplexity,
|
||||
WhileStatement: increaseComplexity,
|
||||
DoWhileStatement: increaseComplexity,
|
||||
AssignmentPattern: increaseComplexity,
|
||||
|
||||
// Avoid `default`
|
||||
"SwitchCase[test]": increaseComplexity,
|
||||
|
@ -120,6 +121,18 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
|
||||
MemberExpression(node) {
|
||||
if (node.optional === true) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (node.optional === true) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
onCodePathEnd(codePath, node) {
|
||||
const complexity = complexities.pop();
|
||||
|
||||
|
|
199
tools/node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
199
tools/node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
|
@ -9,22 +9,6 @@
|
|||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks all segments in a set and returns true if any are reachable.
|
||||
* @param {Set<CodePathSegment>} segments The segments to check.
|
||||
* @returns {boolean} True if any segment is reachable; false otherwise.
|
||||
*/
|
||||
function isAnySegmentReachable(segments) {
|
||||
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a constructor.
|
||||
* @param {ASTNode} node A node to check. This node type is one of
|
||||
|
@ -109,7 +93,7 @@ function isPossibleConstructor(node) {
|
|||
);
|
||||
|
||||
case "SequenceExpression": {
|
||||
const lastExpression = node.expressions[node.expressions.length - 1];
|
||||
const lastExpression = node.expressions.at(-1);
|
||||
|
||||
return isPossibleConstructor(lastExpression);
|
||||
}
|
||||
|
@ -119,6 +103,30 @@ function isPossibleConstructor(node) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to store information about a code path segment.
|
||||
*/
|
||||
class SegmentInfo {
|
||||
|
||||
/**
|
||||
* Indicates if super() is called in all code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInEveryPaths = false;
|
||||
|
||||
/**
|
||||
* Indicates if super() is called in any code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInSomePaths = false;
|
||||
|
||||
/**
|
||||
* The nodes which have been validated and don't need to be reconsidered.
|
||||
* @type {ASTNode[]}
|
||||
*/
|
||||
validNodes = [];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -141,8 +149,7 @@ module.exports = {
|
|||
missingAll: "Expected to call 'super()'.",
|
||||
|
||||
duplicate: "Unexpected duplicate 'super()'.",
|
||||
badSuper: "Unexpected 'super()' because 'super' is not a constructor.",
|
||||
unexpected: "Unexpected 'super()'."
|
||||
badSuper: "Unexpected 'super()' because 'super' is not a constructor."
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -159,14 +166,10 @@ module.exports = {
|
|||
*/
|
||||
let funcInfo = null;
|
||||
|
||||
/*
|
||||
* {Map<string, {calledInSomePaths: boolean, calledInEveryPaths: boolean}>}
|
||||
* Information for each code path segment.
|
||||
* - calledInSomePaths: A flag of be called `super()` in some code paths.
|
||||
* - calledInEveryPaths: A flag of be called `super()` in all code paths.
|
||||
* - validNodes:
|
||||
/**
|
||||
* @type {Record<string, SegmentInfo>}
|
||||
*/
|
||||
let segInfoMap = Object.create(null);
|
||||
const segInfoMap = Object.create(null);
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in some paths.
|
||||
|
@ -177,23 +180,21 @@ module.exports = {
|
|||
return segment.reachable && segInfoMap[segment.id].calledInSomePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a segment has been seen in the traversal.
|
||||
* @param {CodePathSegment} segment A code path segment to check.
|
||||
* @returns {boolean} `true` if the segment has been seen.
|
||||
*/
|
||||
function hasSegmentBeenSeen(segment) {
|
||||
return !!segInfoMap[segment.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in all paths.
|
||||
* @param {CodePathSegment} segment A code path segment to get.
|
||||
* @returns {boolean} The flag which shows `super()` is called in all paths.
|
||||
*/
|
||||
function isCalledInEveryPath(segment) {
|
||||
|
||||
/*
|
||||
* If specific segment is the looped segment of the current segment,
|
||||
* skip the segment.
|
||||
* If not skipped, this never becomes true after a loop.
|
||||
*/
|
||||
if (segment.nextSegments.length === 1 &&
|
||||
segment.nextSegments[0].isLoopedPrevSegment(segment)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return segment.reachable && segInfoMap[segment.id].calledInEveryPaths;
|
||||
}
|
||||
|
||||
|
@ -250,9 +251,9 @@ module.exports = {
|
|||
}
|
||||
|
||||
// Reports if `super()` lacked.
|
||||
const segments = codePath.returnedSegments;
|
||||
const calledInEveryPaths = segments.every(isCalledInEveryPath);
|
||||
const calledInSomePaths = segments.some(isCalledInSomePath);
|
||||
const returnedSegments = codePath.returnedSegments;
|
||||
const calledInEveryPaths = returnedSegments.every(isCalledInEveryPath);
|
||||
const calledInSomePaths = returnedSegments.some(isCalledInSomePath);
|
||||
|
||||
if (!calledInEveryPaths) {
|
||||
context.report({
|
||||
|
@ -267,29 +268,37 @@ module.exports = {
|
|||
/**
|
||||
* Initialize information of a given code path segment.
|
||||
* @param {CodePathSegment} segment A code path segment to initialize.
|
||||
* @param {CodePathSegment} node Node that starts the segment.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentStart(segment) {
|
||||
onCodePathSegmentStart(segment, node) {
|
||||
|
||||
funcInfo.currentSegments.add(segment);
|
||||
|
||||
if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize info.
|
||||
const info = segInfoMap[segment.id] = {
|
||||
calledInSomePaths: false,
|
||||
calledInEveryPaths: false,
|
||||
validNodes: []
|
||||
};
|
||||
const info = segInfoMap[segment.id] = new SegmentInfo();
|
||||
|
||||
const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
|
||||
// When there are previous segments, aggregates these.
|
||||
const prevSegments = segment.prevSegments;
|
||||
if (seenPrevSegments.length > 0) {
|
||||
info.calledInSomePaths = seenPrevSegments.some(isCalledInSomePath);
|
||||
info.calledInEveryPaths = seenPrevSegments.every(isCalledInEveryPath);
|
||||
}
|
||||
|
||||
if (prevSegments.length > 0) {
|
||||
info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
|
||||
info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
|
||||
/*
|
||||
* ForStatement > *.update segments are a special case as they are created in advance,
|
||||
* without seen previous segments. Since they logically don't affect `calledInEveryPaths`
|
||||
* calculations, and they can never be a lone previous segment of another one, we'll set
|
||||
* their `calledInEveryPaths` to `true` to effectively ignore them in those calculations.
|
||||
* .
|
||||
*/
|
||||
if (node.parent && node.parent.type === "ForStatement" && node.parent.update === node) {
|
||||
info.calledInEveryPaths = true;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -316,25 +325,30 @@ module.exports = {
|
|||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentLoop(fromSegment, toSegment) {
|
||||
if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update information inside of the loop.
|
||||
const isRealLoop = toSegment.prevSegments.length >= 2;
|
||||
|
||||
funcInfo.codePath.traverseSegments(
|
||||
{ first: toSegment, last: fromSegment },
|
||||
segment => {
|
||||
(segment, controller) => {
|
||||
const info = segInfoMap[segment.id];
|
||||
const prevSegments = segment.prevSegments;
|
||||
|
||||
// Updates flags.
|
||||
info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
|
||||
info.calledInEveryPaths = prevSegments.every(isCalledInEveryPath);
|
||||
// skip segments after the loop
|
||||
if (!info) {
|
||||
controller.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
const calledInSomePreviousPaths = seenPrevSegments.some(isCalledInSomePath);
|
||||
const calledInEveryPreviousPaths = seenPrevSegments.every(isCalledInEveryPath);
|
||||
|
||||
info.calledInSomePaths ||= calledInSomePreviousPaths;
|
||||
info.calledInEveryPaths ||= calledInEveryPreviousPaths;
|
||||
|
||||
// If flags become true anew, reports the valid nodes.
|
||||
if (info.calledInSomePaths || isRealLoop) {
|
||||
if (calledInSomePreviousPaths) {
|
||||
const nodes = info.validNodes;
|
||||
|
||||
info.validNodes = [];
|
||||
|
@ -358,7 +372,7 @@ module.exports = {
|
|||
* @returns {void}
|
||||
*/
|
||||
"CallExpression:exit"(node) {
|
||||
if (!(funcInfo && funcInfo.isConstructor)) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -368,41 +382,34 @@ module.exports = {
|
|||
}
|
||||
|
||||
// Reports if needed.
|
||||
if (funcInfo.hasExtends) {
|
||||
const segments = funcInfo.currentSegments;
|
||||
let duplicate = false;
|
||||
let info = null;
|
||||
const segments = funcInfo.currentSegments;
|
||||
let duplicate = false;
|
||||
let info = null;
|
||||
|
||||
for (const segment of segments) {
|
||||
for (const segment of segments) {
|
||||
|
||||
if (segment.reachable) {
|
||||
info = segInfoMap[segment.id];
|
||||
if (segment.reachable) {
|
||||
info = segInfoMap[segment.id];
|
||||
|
||||
duplicate = duplicate || info.calledInSomePaths;
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
duplicate = duplicate || info.calledInSomePaths;
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (duplicate) {
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node
|
||||
});
|
||||
} else if (!funcInfo.superIsConstructor) {
|
||||
context.report({
|
||||
messageId: "badSuper",
|
||||
node
|
||||
});
|
||||
} else {
|
||||
info.validNodes.push(node);
|
||||
}
|
||||
if (info) {
|
||||
if (duplicate) {
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node
|
||||
});
|
||||
} else if (!funcInfo.superIsConstructor) {
|
||||
context.report({
|
||||
messageId: "badSuper",
|
||||
node
|
||||
});
|
||||
} else {
|
||||
info.validNodes.push(node);
|
||||
}
|
||||
} else if (isAnySegmentReachable(funcInfo.currentSegments)) {
|
||||
context.report({
|
||||
messageId: "unexpected",
|
||||
node
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -412,7 +419,7 @@ module.exports = {
|
|||
* @returns {void}
|
||||
*/
|
||||
ReturnStatement(node) {
|
||||
if (!(funcInfo && funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -432,14 +439,6 @@ module.exports = {
|
|||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets state.
|
||||
* @returns {void}
|
||||
*/
|
||||
"Program:exit"() {
|
||||
segInfoMap = Object.create(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
2
tools/node_modules/eslint/lib/rules/default-case.js
generated
vendored
2
tools/node_modules/eslint/lib/rules/default-case.js
generated
vendored
|
@ -54,7 +54,7 @@ module.exports = {
|
|||
* @returns {any} Last element
|
||||
*/
|
||||
function last(collection) {
|
||||
return collection[collection.length - 1];
|
||||
return collection.at(-1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
|
4
tools/node_modules/eslint/lib/rules/eol-last.js
generated
vendored
4
tools/node_modules/eslint/lib/rules/eol-last.js
generated
vendored
|
@ -45,7 +45,7 @@ module.exports = {
|
|||
Program: function checkBadEOF(node) {
|
||||
const sourceCode = context.sourceCode,
|
||||
src = sourceCode.getText(),
|
||||
lastLine = sourceCode.lines[sourceCode.lines.length - 1],
|
||||
lastLine = sourceCode.lines.at(-1),
|
||||
location = {
|
||||
column: lastLine.length,
|
||||
line: sourceCode.lines.length
|
||||
|
@ -89,7 +89,7 @@ module.exports = {
|
|||
});
|
||||
} else if (mode === "never" && endsWithNewline) {
|
||||
|
||||
const secondLastLine = sourceCode.lines[sourceCode.lines.length - 2];
|
||||
const secondLastLine = sourceCode.lines.at(-2);
|
||||
|
||||
// File is newline-terminated, but shouldn't be
|
||||
context.report({
|
||||
|
|
46
tools/node_modules/eslint/lib/rules/func-style.js
generated
vendored
46
tools/node_modules/eslint/lib/rules/func-style.js
generated
vendored
|
@ -29,6 +29,15 @@ module.exports = {
|
|||
allowArrowFunctions: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
},
|
||||
overrides: {
|
||||
type: "object",
|
||||
properties: {
|
||||
namedExports: {
|
||||
enum: ["declaration", "expression", "ignore"]
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
|
@ -46,13 +55,22 @@ module.exports = {
|
|||
const style = context.options[0],
|
||||
allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions,
|
||||
enforceDeclarations = (style === "declaration"),
|
||||
exportFunctionStyle = context.options[1] && context.options[1].overrides && context.options[1].overrides.namedExports,
|
||||
stack = [];
|
||||
|
||||
const nodesToCheck = {
|
||||
FunctionDeclaration(node) {
|
||||
stack.push(false);
|
||||
|
||||
if (!enforceDeclarations && node.parent.type !== "ExportDefaultDeclaration") {
|
||||
if (
|
||||
!enforceDeclarations &&
|
||||
node.parent.type !== "ExportDefaultDeclaration" &&
|
||||
(typeof exportFunctionStyle === "undefined" || node.parent.type !== "ExportNamedDeclaration")
|
||||
) {
|
||||
context.report({ node, messageId: "expression" });
|
||||
}
|
||||
|
||||
if (node.parent.type === "ExportNamedDeclaration" && exportFunctionStyle === "expression") {
|
||||
context.report({ node, messageId: "expression" });
|
||||
}
|
||||
},
|
||||
|
@ -63,7 +81,18 @@ module.exports = {
|
|||
FunctionExpression(node) {
|
||||
stack.push(false);
|
||||
|
||||
if (enforceDeclarations && node.parent.type === "VariableDeclarator") {
|
||||
if (
|
||||
enforceDeclarations &&
|
||||
node.parent.type === "VariableDeclarator" &&
|
||||
(typeof exportFunctionStyle === "undefined" || node.parent.parent.parent.type !== "ExportNamedDeclaration")
|
||||
) {
|
||||
context.report({ node: node.parent, messageId: "declaration" });
|
||||
}
|
||||
|
||||
if (
|
||||
node.parent.type === "VariableDeclarator" && node.parent.parent.parent.type === "ExportNamedDeclaration" &&
|
||||
exportFunctionStyle === "declaration"
|
||||
) {
|
||||
context.report({ node: node.parent, messageId: "declaration" });
|
||||
}
|
||||
},
|
||||
|
@ -86,8 +115,17 @@ module.exports = {
|
|||
nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
|
||||
const hasThisExpr = stack.pop();
|
||||
|
||||
if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
|
||||
context.report({ node: node.parent, messageId: "declaration" });
|
||||
if (!hasThisExpr && node.parent.type === "VariableDeclarator") {
|
||||
if (
|
||||
enforceDeclarations &&
|
||||
(typeof exportFunctionStyle === "undefined" || node.parent.parent.parent.type !== "ExportNamedDeclaration")
|
||||
) {
|
||||
context.report({ node: node.parent, messageId: "declaration" });
|
||||
}
|
||||
|
||||
if (node.parent.parent.parent.type === "ExportNamedDeclaration" && exportFunctionStyle === "declaration") {
|
||||
context.report({ node: node.parent, messageId: "declaration" });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue