eslint 9.26.0 → 9.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/bin/eslint.js +7 -11
- package/conf/rule-type-list.json +2 -1
- package/lib/cli-engine/cli-engine.js +7 -7
- package/lib/cli.js +19 -16
- package/lib/config/config-loader.js +42 -39
- package/lib/config/config.js +362 -16
- package/lib/eslint/eslint-helpers.js +3 -1
- package/lib/eslint/eslint.js +31 -13
- package/lib/eslint/legacy-eslint.js +6 -6
- package/lib/languages/js/source-code/source-code.js +40 -6
- package/lib/linter/apply-disable-directives.js +1 -1
- package/lib/linter/file-context.js +11 -0
- package/lib/linter/linter.js +102 -140
- package/lib/linter/report-translator.js +2 -1
- package/lib/linter/{node-event-generator.js → source-code-traverser.js} +143 -87
- package/lib/options.js +7 -0
- package/lib/rule-tester/rule-tester.js +3 -3
- package/lib/rules/func-style.js +57 -7
- package/lib/rules/index.js +1 -0
- package/lib/rules/max-params.js +32 -7
- package/lib/rules/no-array-constructor.js +51 -1
- package/lib/rules/no-implicit-globals.js +31 -15
- package/lib/rules/no-magic-numbers.js +98 -5
- package/lib/rules/no-shadow.js +262 -6
- package/lib/rules/no-unassigned-vars.js +80 -0
- package/lib/rules/no-use-before-define.js +97 -1
- package/lib/rules/no-useless-escape.js +24 -2
- package/lib/rules/prefer-arrow-callback.js +9 -0
- package/lib/rules/prefer-named-capture-group.js +7 -1
- package/lib/services/processor-service.js +1 -1
- package/lib/services/suppressions-service.js +5 -3
- package/lib/services/warning-service.js +85 -0
- package/lib/shared/flags.js +1 -0
- package/lib/types/index.d.ts +132 -9
- package/lib/types/rules.d.ts +66 -3
- package/package.json +11 -11
- package/lib/config/flat-config-helpers.js +0 -128
- package/lib/config/rule-validator.js +0 -199
- package/lib/mcp/mcp-server.js +0 -66
- package/lib/shared/types.js +0 -229
package/lib/types/rules.d.ts
CHANGED
@@ -619,7 +619,7 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
619
619
|
* @see https://eslint.org/docs/latest/rules/curly
|
620
620
|
*/
|
621
621
|
curly: Linter.RuleEntry<
|
622
|
-
["all" | "multi" | "multi-line" | "multi-or-nest"
|
622
|
+
["all"] | ["multi" | "multi-line" | "multi-or-nest", "consistent"?]
|
623
623
|
>;
|
624
624
|
|
625
625
|
/**
|
@@ -807,6 +807,10 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
807
807
|
* @default false
|
808
808
|
*/
|
809
809
|
allowArrowFunctions: boolean;
|
810
|
+
/**
|
811
|
+
* @default false
|
812
|
+
*/
|
813
|
+
allowTypeAnnotation: boolean;
|
810
814
|
overrides: {
|
811
815
|
namedExports: "declaration" | "expression" | "ignore";
|
812
816
|
};
|
@@ -1800,6 +1804,10 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
1800
1804
|
* @default 3
|
1801
1805
|
*/
|
1802
1806
|
max: number;
|
1807
|
+
/**
|
1808
|
+
* @default false
|
1809
|
+
*/
|
1810
|
+
countVoidThis: boolean;
|
1803
1811
|
}>
|
1804
1812
|
| number,
|
1805
1813
|
]
|
@@ -2850,6 +2858,22 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
2850
2858
|
* @default false
|
2851
2859
|
*/
|
2852
2860
|
detectObjects: boolean;
|
2861
|
+
/**
|
2862
|
+
* @default false
|
2863
|
+
*/
|
2864
|
+
ignoreEnums: boolean;
|
2865
|
+
/**
|
2866
|
+
* @default false
|
2867
|
+
*/
|
2868
|
+
ignoreNumericLiteralTypes: boolean;
|
2869
|
+
/**
|
2870
|
+
* @default false
|
2871
|
+
*/
|
2872
|
+
ignoreReadonlyClassProperties: boolean;
|
2873
|
+
/**
|
2874
|
+
* @default false
|
2875
|
+
*/
|
2876
|
+
ignoreTypeIndexes: boolean;
|
2853
2877
|
}>,
|
2854
2878
|
]
|
2855
2879
|
>;
|
@@ -3558,13 +3582,26 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
3558
3582
|
/**
|
3559
3583
|
* @default 'functions'
|
3560
3584
|
*/
|
3561
|
-
hoist:
|
3585
|
+
hoist:
|
3586
|
+
| "functions"
|
3587
|
+
| "all"
|
3588
|
+
| "never"
|
3589
|
+
| "types"
|
3590
|
+
| "functions-and-types";
|
3562
3591
|
allow: string[];
|
3563
3592
|
/**
|
3564
3593
|
* @since 8.10.0
|
3565
3594
|
* @default false
|
3566
3595
|
*/
|
3567
3596
|
ignoreOnInitialization: boolean;
|
3597
|
+
/**
|
3598
|
+
* @default true
|
3599
|
+
*/
|
3600
|
+
ignoreTypeValueShadow: boolean;
|
3601
|
+
/**
|
3602
|
+
* @default true
|
3603
|
+
*/
|
3604
|
+
ignoreFunctionTypeParameterNameValueShadow: boolean;
|
3568
3605
|
}>,
|
3569
3606
|
]
|
3570
3607
|
>;
|
@@ -3710,6 +3747,14 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
3710
3747
|
]
|
3711
3748
|
>;
|
3712
3749
|
|
3750
|
+
/**
|
3751
|
+
* Rule to disallow `let` or `var` variables that are read but never assigned.
|
3752
|
+
*
|
3753
|
+
* @since 9.27.0
|
3754
|
+
* @see https://eslint.org/docs/latest/rules/no-unassigned-vars
|
3755
|
+
*/
|
3756
|
+
"no-unassigned-vars": Linter.RuleEntry<[]>;
|
3757
|
+
|
3713
3758
|
/**
|
3714
3759
|
* Rule to disallow the use of undeclared variables unless mentioned in \/*global *\/ comments.
|
3715
3760
|
*
|
@@ -4045,6 +4090,18 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
4045
4090
|
* @default false
|
4046
4091
|
*/
|
4047
4092
|
allowNamedExports: boolean;
|
4093
|
+
/**
|
4094
|
+
* @default true
|
4095
|
+
*/
|
4096
|
+
enums: boolean;
|
4097
|
+
/**
|
4098
|
+
* @default true
|
4099
|
+
*/
|
4100
|
+
typedefs: boolean;
|
4101
|
+
/**
|
4102
|
+
* @default true
|
4103
|
+
*/
|
4104
|
+
ignoreTypeReferences: boolean;
|
4048
4105
|
}>
|
4049
4106
|
| "nofunc",
|
4050
4107
|
]
|
@@ -4130,7 +4187,13 @@ export interface ESLintRules extends Linter.RulesRecord {
|
|
4130
4187
|
* @since 2.5.0
|
4131
4188
|
* @see https://eslint.org/docs/latest/rules/no-useless-escape
|
4132
4189
|
*/
|
4133
|
-
"no-useless-escape": Linter.RuleEntry<
|
4190
|
+
"no-useless-escape": Linter.RuleEntry<
|
4191
|
+
[
|
4192
|
+
Partial<{
|
4193
|
+
allowRegexCharacters: string[];
|
4194
|
+
}>,
|
4195
|
+
]
|
4196
|
+
>;
|
4134
4197
|
|
4135
4198
|
/**
|
4136
4199
|
* Rule to disallow renaming import, export, and destructured assignments to the same name.
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "9.
|
3
|
+
"version": "9.28.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"type": "commonjs",
|
@@ -108,14 +108,13 @@
|
|
108
108
|
"@eslint-community/regexpp": "^4.12.1",
|
109
109
|
"@eslint/config-array": "^0.20.0",
|
110
110
|
"@eslint/config-helpers": "^0.2.1",
|
111
|
-
"@eslint/core": "^0.
|
111
|
+
"@eslint/core": "^0.14.0",
|
112
112
|
"@eslint/eslintrc": "^3.3.1",
|
113
|
-
"@eslint/js": "9.
|
114
|
-
"@eslint/plugin-kit": "^0.
|
113
|
+
"@eslint/js": "9.28.0",
|
114
|
+
"@eslint/plugin-kit": "^0.3.1",
|
115
115
|
"@humanfs/node": "^0.16.6",
|
116
116
|
"@humanwhocodes/module-importer": "^1.0.1",
|
117
117
|
"@humanwhocodes/retry": "^0.4.2",
|
118
|
-
"@modelcontextprotocol/sdk": "^1.8.0",
|
119
118
|
"@types/estree": "^1.0.6",
|
120
119
|
"@types/json-schema": "^7.0.15",
|
121
120
|
"ajv": "^6.12.4",
|
@@ -139,11 +138,10 @@
|
|
139
138
|
"lodash.merge": "^4.6.2",
|
140
139
|
"minimatch": "^3.1.2",
|
141
140
|
"natural-compare": "^1.4.0",
|
142
|
-
"optionator": "^0.9.3"
|
143
|
-
"zod": "^3.24.2"
|
141
|
+
"optionator": "^0.9.3"
|
144
142
|
},
|
145
143
|
"devDependencies": {
|
146
|
-
"@arethetypeswrong/cli": "^0.
|
144
|
+
"@arethetypeswrong/cli": "^0.18.0",
|
147
145
|
"@babel/core": "^7.4.3",
|
148
146
|
"@babel/preset-env": "^7.4.3",
|
149
147
|
"@cypress/webpack-preprocessor": "^6.0.2",
|
@@ -172,10 +170,12 @@
|
|
172
170
|
"fast-glob": "^3.2.11",
|
173
171
|
"fs-teardown": "^0.1.3",
|
174
172
|
"glob": "^10.0.0",
|
175
|
-
"globals": "^
|
173
|
+
"globals": "^16.2.0",
|
176
174
|
"got": "^11.8.3",
|
177
175
|
"gray-matter": "^4.0.3",
|
178
|
-
"jiti": "^2.
|
176
|
+
"jiti": "^2.2.0",
|
177
|
+
"jiti-v2.0": "npm:jiti@2.0.x",
|
178
|
+
"jiti-v2.1": "npm:jiti@2.1.x",
|
179
179
|
"knip": "^5.32.0",
|
180
180
|
"lint-staged": "^11.0.0",
|
181
181
|
"load-perf": "^0.2.0",
|
@@ -197,7 +197,7 @@
|
|
197
197
|
"recast": "^0.23.0",
|
198
198
|
"regenerator-runtime": "^0.14.0",
|
199
199
|
"semver": "^7.5.3",
|
200
|
-
"shelljs": "^0.
|
200
|
+
"shelljs": "^0.10.0",
|
201
201
|
"sinon": "^11.0.0",
|
202
202
|
"typescript": "^5.3.3",
|
203
203
|
"webpack": "^5.23.0",
|
@@ -1,128 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Shared functions to work with configs.
|
3
|
-
* @author Nicholas C. Zakas
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Typedefs
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
/**
|
13
|
-
* @import { RuleDefinition } from "@eslint/core";
|
14
|
-
* @import { Linter } from "eslint";
|
15
|
-
*/
|
16
|
-
|
17
|
-
//------------------------------------------------------------------------------
|
18
|
-
// Private Members
|
19
|
-
//------------------------------------------------------------------------------
|
20
|
-
|
21
|
-
// JSON schema that disallows passing any options
|
22
|
-
const noOptionsSchema = Object.freeze({
|
23
|
-
type: "array",
|
24
|
-
minItems: 0,
|
25
|
-
maxItems: 0,
|
26
|
-
});
|
27
|
-
|
28
|
-
//-----------------------------------------------------------------------------
|
29
|
-
// Functions
|
30
|
-
//-----------------------------------------------------------------------------
|
31
|
-
|
32
|
-
/**
|
33
|
-
* Parses a ruleId into its plugin and rule parts.
|
34
|
-
* @param {string} ruleId The rule ID to parse.
|
35
|
-
* @returns {{pluginName:string,ruleName:string}} The plugin and rule
|
36
|
-
* parts of the ruleId;
|
37
|
-
*/
|
38
|
-
function parseRuleId(ruleId) {
|
39
|
-
let pluginName, ruleName;
|
40
|
-
|
41
|
-
// distinguish between core rules and plugin rules
|
42
|
-
if (ruleId.includes("/")) {
|
43
|
-
// mimic scoped npm packages
|
44
|
-
if (ruleId.startsWith("@")) {
|
45
|
-
pluginName = ruleId.slice(0, ruleId.lastIndexOf("/"));
|
46
|
-
} else {
|
47
|
-
pluginName = ruleId.slice(0, ruleId.indexOf("/"));
|
48
|
-
}
|
49
|
-
|
50
|
-
ruleName = ruleId.slice(pluginName.length + 1);
|
51
|
-
} else {
|
52
|
-
pluginName = "@";
|
53
|
-
ruleName = ruleId;
|
54
|
-
}
|
55
|
-
|
56
|
-
return {
|
57
|
-
pluginName,
|
58
|
-
ruleName,
|
59
|
-
};
|
60
|
-
}
|
61
|
-
|
62
|
-
/**
|
63
|
-
* Retrieves a rule instance from a given config based on the ruleId.
|
64
|
-
* @param {string} ruleId The rule ID to look for.
|
65
|
-
* @param {Linter.Config} config The config to search.
|
66
|
-
* @returns {RuleDefinition|undefined} The rule if found
|
67
|
-
* or undefined if not.
|
68
|
-
*/
|
69
|
-
function getRuleFromConfig(ruleId, config) {
|
70
|
-
const { pluginName, ruleName } = parseRuleId(ruleId);
|
71
|
-
|
72
|
-
return config.plugins?.[pluginName]?.rules?.[ruleName];
|
73
|
-
}
|
74
|
-
|
75
|
-
/**
|
76
|
-
* Gets a complete options schema for a rule.
|
77
|
-
* @param {RuleDefinition} rule A rule object
|
78
|
-
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
|
79
|
-
* @returns {Object|null} JSON Schema for the rule's options. `null` if `meta.schema` is `false`.
|
80
|
-
*/
|
81
|
-
function getRuleOptionsSchema(rule) {
|
82
|
-
if (!rule.meta) {
|
83
|
-
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
84
|
-
}
|
85
|
-
|
86
|
-
const schema = rule.meta.schema;
|
87
|
-
|
88
|
-
if (typeof schema === "undefined") {
|
89
|
-
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
|
90
|
-
}
|
91
|
-
|
92
|
-
// `schema:false` is an allowed explicit opt-out of options validation for the rule
|
93
|
-
if (schema === false) {
|
94
|
-
return null;
|
95
|
-
}
|
96
|
-
|
97
|
-
if (typeof schema !== "object" || schema === null) {
|
98
|
-
throw new TypeError("Rule's `meta.schema` must be an array or object");
|
99
|
-
}
|
100
|
-
|
101
|
-
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
|
102
|
-
if (Array.isArray(schema)) {
|
103
|
-
if (schema.length) {
|
104
|
-
return {
|
105
|
-
type: "array",
|
106
|
-
items: schema,
|
107
|
-
minItems: 0,
|
108
|
-
maxItems: schema.length,
|
109
|
-
};
|
110
|
-
}
|
111
|
-
|
112
|
-
// `schema:[]` is an explicit way to specify that the rule does not accept any options
|
113
|
-
return { ...noOptionsSchema };
|
114
|
-
}
|
115
|
-
|
116
|
-
// `schema:<object>` is assumed to be a valid JSON Schema definition
|
117
|
-
return schema;
|
118
|
-
}
|
119
|
-
|
120
|
-
//-----------------------------------------------------------------------------
|
121
|
-
// Exports
|
122
|
-
//-----------------------------------------------------------------------------
|
123
|
-
|
124
|
-
module.exports = {
|
125
|
-
parseRuleId,
|
126
|
-
getRuleFromConfig,
|
127
|
-
getRuleOptionsSchema,
|
128
|
-
};
|
@@ -1,199 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Rule Validator
|
3
|
-
* @author Nicholas C. Zakas
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//-----------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//-----------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const ajvImport = require("../shared/ajv");
|
13
|
-
const ajv = ajvImport();
|
14
|
-
const {
|
15
|
-
parseRuleId,
|
16
|
-
getRuleFromConfig,
|
17
|
-
getRuleOptionsSchema,
|
18
|
-
} = require("./flat-config-helpers");
|
19
|
-
const ruleReplacements = require("../../conf/replacements.json");
|
20
|
-
|
21
|
-
//-----------------------------------------------------------------------------
|
22
|
-
// Helpers
|
23
|
-
//-----------------------------------------------------------------------------
|
24
|
-
|
25
|
-
/**
|
26
|
-
* Throws a helpful error when a rule cannot be found.
|
27
|
-
* @param {Object} ruleId The rule identifier.
|
28
|
-
* @param {string} ruleId.pluginName The ID of the rule to find.
|
29
|
-
* @param {string} ruleId.ruleName The ID of the rule to find.
|
30
|
-
* @param {Object} config The config to search in.
|
31
|
-
* @throws {TypeError} For missing plugin or rule.
|
32
|
-
* @returns {void}
|
33
|
-
*/
|
34
|
-
function throwRuleNotFoundError({ pluginName, ruleName }, config) {
|
35
|
-
const ruleId = pluginName === "@" ? ruleName : `${pluginName}/${ruleName}`;
|
36
|
-
|
37
|
-
const errorMessageHeader = `Key "rules": Key "${ruleId}"`;
|
38
|
-
|
39
|
-
let errorMessage = `${errorMessageHeader}: Could not find plugin "${pluginName}" in configuration.`;
|
40
|
-
|
41
|
-
const missingPluginErrorMessage = errorMessage;
|
42
|
-
|
43
|
-
// if the plugin exists then we need to check if the rule exists
|
44
|
-
if (config.plugins && config.plugins[pluginName]) {
|
45
|
-
const replacementRuleName = ruleReplacements.rules[ruleName];
|
46
|
-
|
47
|
-
if (pluginName === "@" && replacementRuleName) {
|
48
|
-
errorMessage = `${errorMessageHeader}: Rule "${ruleName}" was removed and replaced by "${replacementRuleName}".`;
|
49
|
-
} else {
|
50
|
-
errorMessage = `${errorMessageHeader}: Could not find "${ruleName}" in plugin "${pluginName}".`;
|
51
|
-
|
52
|
-
// otherwise, let's see if we can find the rule name elsewhere
|
53
|
-
for (const [otherPluginName, otherPlugin] of Object.entries(
|
54
|
-
config.plugins,
|
55
|
-
)) {
|
56
|
-
if (otherPlugin.rules && otherPlugin.rules[ruleName]) {
|
57
|
-
errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`;
|
58
|
-
break;
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
// falls through to throw error
|
64
|
-
}
|
65
|
-
|
66
|
-
const error = new TypeError(errorMessage);
|
67
|
-
|
68
|
-
if (errorMessage === missingPluginErrorMessage) {
|
69
|
-
error.messageTemplate = "config-plugin-missing";
|
70
|
-
error.messageData = { pluginName, ruleId };
|
71
|
-
}
|
72
|
-
|
73
|
-
throw error;
|
74
|
-
}
|
75
|
-
|
76
|
-
/**
|
77
|
-
* The error type when a rule has an invalid `meta.schema`.
|
78
|
-
*/
|
79
|
-
class InvalidRuleOptionsSchemaError extends Error {
|
80
|
-
/**
|
81
|
-
* Creates a new instance.
|
82
|
-
* @param {string} ruleId Id of the rule that has an invalid `meta.schema`.
|
83
|
-
* @param {Error} processingError Error caught while processing the `meta.schema`.
|
84
|
-
*/
|
85
|
-
constructor(ruleId, processingError) {
|
86
|
-
super(
|
87
|
-
`Error while processing options validation schema of rule '${ruleId}': ${processingError.message}`,
|
88
|
-
{ cause: processingError },
|
89
|
-
);
|
90
|
-
this.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
//-----------------------------------------------------------------------------
|
95
|
-
// Exports
|
96
|
-
//-----------------------------------------------------------------------------
|
97
|
-
|
98
|
-
/**
|
99
|
-
* Implements validation functionality for the rules portion of a config.
|
100
|
-
*/
|
101
|
-
class RuleValidator {
|
102
|
-
/**
|
103
|
-
* Creates a new instance.
|
104
|
-
*/
|
105
|
-
constructor() {
|
106
|
-
/**
|
107
|
-
* A collection of compiled validators for rules that have already
|
108
|
-
* been validated.
|
109
|
-
* @type {WeakMap}
|
110
|
-
*/
|
111
|
-
this.validators = new WeakMap();
|
112
|
-
}
|
113
|
-
|
114
|
-
/**
|
115
|
-
* Validates all of the rule configurations in a config against each
|
116
|
-
* rule's schema.
|
117
|
-
* @param {Object} config The full config to validate. This object must
|
118
|
-
* contain both the rules section and the plugins section.
|
119
|
-
* @returns {void}
|
120
|
-
* @throws {Error} If a rule's configuration does not match its schema.
|
121
|
-
*/
|
122
|
-
validate(config) {
|
123
|
-
if (!config.rules) {
|
124
|
-
return;
|
125
|
-
}
|
126
|
-
|
127
|
-
for (const [ruleId, ruleOptions] of Object.entries(config.rules)) {
|
128
|
-
// check for edge case
|
129
|
-
if (ruleId === "__proto__") {
|
130
|
-
continue;
|
131
|
-
}
|
132
|
-
|
133
|
-
/*
|
134
|
-
* If a rule is disabled, we don't do any validation. This allows
|
135
|
-
* users to safely set any value to 0 or "off" without worrying
|
136
|
-
* that it will cause a validation error.
|
137
|
-
*
|
138
|
-
* Note: ruleOptions is always an array at this point because
|
139
|
-
* this validation occurs after FlatConfigArray has merged and
|
140
|
-
* normalized values.
|
141
|
-
*/
|
142
|
-
if (ruleOptions[0] === 0) {
|
143
|
-
continue;
|
144
|
-
}
|
145
|
-
|
146
|
-
const rule = getRuleFromConfig(ruleId, config);
|
147
|
-
|
148
|
-
if (!rule) {
|
149
|
-
throwRuleNotFoundError(parseRuleId(ruleId), config);
|
150
|
-
}
|
151
|
-
|
152
|
-
// Precompile and cache validator the first time
|
153
|
-
if (!this.validators.has(rule)) {
|
154
|
-
try {
|
155
|
-
const schema = getRuleOptionsSchema(rule);
|
156
|
-
|
157
|
-
if (schema) {
|
158
|
-
this.validators.set(rule, ajv.compile(schema));
|
159
|
-
}
|
160
|
-
} catch (err) {
|
161
|
-
throw new InvalidRuleOptionsSchemaError(ruleId, err);
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
const validateRule = this.validators.get(rule);
|
166
|
-
|
167
|
-
if (validateRule) {
|
168
|
-
validateRule(ruleOptions.slice(1));
|
169
|
-
|
170
|
-
if (validateRule.errors) {
|
171
|
-
throw new Error(
|
172
|
-
`Key "rules": Key "${ruleId}":\n${validateRule.errors
|
173
|
-
.map(error => {
|
174
|
-
if (
|
175
|
-
error.keyword === "additionalProperties" &&
|
176
|
-
error.schema === false &&
|
177
|
-
typeof error.parentSchema?.properties ===
|
178
|
-
"object" &&
|
179
|
-
typeof error.params?.additionalProperty ===
|
180
|
-
"string"
|
181
|
-
) {
|
182
|
-
const expectedProperties = Object.keys(
|
183
|
-
error.parentSchema.properties,
|
184
|
-
).map(property => `"${property}"`);
|
185
|
-
|
186
|
-
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n\t\tUnexpected property "${error.params.additionalProperty}". Expected properties: ${expectedProperties.join(", ")}.\n`;
|
187
|
-
}
|
188
|
-
|
189
|
-
return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`;
|
190
|
-
})
|
191
|
-
.join("")}`,
|
192
|
-
);
|
193
|
-
}
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
}
|
198
|
-
|
199
|
-
exports.RuleValidator = RuleValidator;
|
package/lib/mcp/mcp-server.js
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview MCP Server for handling requests and responses to ESLint.
|
3
|
-
* @author Nicholas C. Zakas
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//-----------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//-----------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
13
|
-
const { z } = require("zod");
|
14
|
-
const { ESLint } = require("../eslint");
|
15
|
-
const pkg = require("../../package.json");
|
16
|
-
|
17
|
-
//-----------------------------------------------------------------------------
|
18
|
-
// Server
|
19
|
-
//-----------------------------------------------------------------------------
|
20
|
-
|
21
|
-
const mcpServer = new McpServer({
|
22
|
-
name: "ESLint",
|
23
|
-
version: pkg.version,
|
24
|
-
});
|
25
|
-
|
26
|
-
// Important: Cursor throws an error when `describe()` is used in the schema.
|
27
|
-
const filePathsSchema = {
|
28
|
-
filePaths: z.array(z.string().min(1)).nonempty(),
|
29
|
-
};
|
30
|
-
|
31
|
-
//-----------------------------------------------------------------------------
|
32
|
-
// Tools
|
33
|
-
//-----------------------------------------------------------------------------
|
34
|
-
|
35
|
-
mcpServer.tool(
|
36
|
-
"lint-files",
|
37
|
-
"Lint files using ESLint. You must provide a list of absolute file paths to the files you want to lint. The absolute file paths should be in the correct format for your operating system (e.g., forward slashes on Unix-like systems, backslashes on Windows).",
|
38
|
-
filePathsSchema,
|
39
|
-
async ({ filePaths }) => {
|
40
|
-
const eslint = new ESLint({
|
41
|
-
// enable lookup from file rather than from cwd
|
42
|
-
flags: ["unstable_config_lookup_from_file"],
|
43
|
-
});
|
44
|
-
|
45
|
-
const results = await eslint.lintFiles(filePaths);
|
46
|
-
const content = results.map(result => ({
|
47
|
-
type: "text",
|
48
|
-
text: JSON.stringify(result),
|
49
|
-
}));
|
50
|
-
|
51
|
-
content.unshift({
|
52
|
-
type: "text",
|
53
|
-
text: "Here are the results of running ESLint on the provided files:",
|
54
|
-
});
|
55
|
-
content.push({
|
56
|
-
type: "text",
|
57
|
-
text: "Do not automatically fix these issues. You must ask the user for confirmation before attempting to fix the issues found.",
|
58
|
-
});
|
59
|
-
|
60
|
-
return {
|
61
|
-
content,
|
62
|
-
};
|
63
|
-
},
|
64
|
-
);
|
65
|
-
|
66
|
-
module.exports = { mcpServer };
|