@eslint/json 0.4.0 → 0.5.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 +99 -0
- package/dist/cjs/index.cjs +142 -112
- package/dist/cjs/index.d.cts +35 -76
- package/dist/esm/index.d.ts +35 -76
- package/dist/esm/index.js +142 -112
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -75,6 +75,47 @@ export default [
|
|
|
75
75
|
];
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
In CommonJS format:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const json = require("@eslint/json").default;
|
|
82
|
+
|
|
83
|
+
module.exports = [
|
|
84
|
+
{
|
|
85
|
+
plugins: {
|
|
86
|
+
json,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// lint JSON files
|
|
91
|
+
{
|
|
92
|
+
files: ["**/*.json"],
|
|
93
|
+
language: "json/json",
|
|
94
|
+
rules: {
|
|
95
|
+
"json/no-duplicate-keys": "error",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// lint JSONC files
|
|
100
|
+
{
|
|
101
|
+
files: ["**/*.jsonc", ".vscode/*.json"],
|
|
102
|
+
language: "json/jsonc",
|
|
103
|
+
rules: {
|
|
104
|
+
"json/no-duplicate-keys": "error",
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// lint JSON5 files
|
|
109
|
+
{
|
|
110
|
+
files: ["**/*.json5"],
|
|
111
|
+
language: "json/json5",
|
|
112
|
+
rules: {
|
|
113
|
+
"json/no-duplicate-keys": "error",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
```
|
|
118
|
+
|
|
78
119
|
## Recommended Configuration
|
|
79
120
|
|
|
80
121
|
To use the recommended configuration for this plugin, specify your matching `files` and then use the `json.configs.recommended` object, like this:
|
|
@@ -114,6 +155,64 @@ export default [
|
|
|
114
155
|
- `no-duplicate-keys` - warns when there are two keys in an object with the same text.
|
|
115
156
|
- `no-empty-keys` - warns when there is a key in an object that is an empty string or contains only whitespace (note: `package-lock.json` uses empty keys intentionally)
|
|
116
157
|
|
|
158
|
+
## Configuration Comments
|
|
159
|
+
|
|
160
|
+
In JSONC and JSON5 files, you can also use [rule configurations comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments) and [disable directives](https://eslint.org/docs/latest/use/configure/rules#disabling-rules).
|
|
161
|
+
|
|
162
|
+
```jsonc
|
|
163
|
+
/* eslint json/no-empty-keys: "error" */
|
|
164
|
+
|
|
165
|
+
{
|
|
166
|
+
"foo": {
|
|
167
|
+
"": 1, // eslint-disable-line json/no-empty-keys -- We want an empty key here
|
|
168
|
+
},
|
|
169
|
+
"bar": {
|
|
170
|
+
// eslint-disable-next-line json/no-empty-keys -- We want an empty key here too
|
|
171
|
+
"": 2,
|
|
172
|
+
},
|
|
173
|
+
/* eslint-disable json/no-empty-keys -- Empty keys are allowed in the following code as well */
|
|
174
|
+
"baz": [
|
|
175
|
+
{
|
|
176
|
+
"": 3,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"": 4,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
/* eslint-enable json/no-empty-keys -- re-enable now */
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Both line and block comments can be used for all kinds of configuration comments.
|
|
187
|
+
|
|
188
|
+
## Frequently Asked Questions
|
|
189
|
+
|
|
190
|
+
### How does this relate to `eslint-plugin-json` and `eslint-plugin-jsonc`?
|
|
191
|
+
|
|
192
|
+
This plugin implements JSON parsing for ESLint using the language plugins API, which is the official way of supporting non-JavaScript languages in ESLint. This differs from the other plugins:
|
|
193
|
+
|
|
194
|
+
- `eslint-plugin-json` uses a processor to parse the JSON, meaning it doesn't create an AST and you can't write custom rules for it.
|
|
195
|
+
- `eslint-plugin-jsonc` uses a parser that still goes through the JavaScript linting functionality and requires several rules to disallow valid JavaScript syntax that is invalid in JSON.
|
|
196
|
+
|
|
197
|
+
As such, this plugin is more robust and faster than the others. You can write your own custom rules when using the languages in this plugin, too.
|
|
198
|
+
|
|
199
|
+
### What about missing rules that are available in `eslint-plugin-json` and `eslint-plugin-jsonc`?
|
|
200
|
+
|
|
201
|
+
Most of the rules in `eslint-plugin-json` are actually syntax errors that are caught automatically by the parser used in this plugin.
|
|
202
|
+
|
|
203
|
+
Similarly, many of the rules in `eslint-plugin-jsonc` specifically disallow valid JavaScript syntax that is invalid in the context of JSON. These are also automatically caught by the parser in this plugin.
|
|
204
|
+
|
|
205
|
+
Any other rules that catch potential problems in JSON are welcome to be implemented. You can [open an issue](https://github.com/eslint/json/issues/new/choose) to propose a new rule.
|
|
206
|
+
|
|
117
207
|
## License
|
|
118
208
|
|
|
119
209
|
Apache 2.0
|
|
210
|
+
|
|
211
|
+
## Sponsors
|
|
212
|
+
|
|
213
|
+
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
|
|
214
|
+
<!--sponsorsstart-->
|
|
215
|
+
<!--sponsorsend-->
|
|
216
|
+
|
|
217
|
+
<!--techsponsorsstart-->
|
|
218
|
+
<!--techsponsorsend-->
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var momoa = require('@humanwhocodes/momoa');
|
|
6
|
+
var pluginKit = require('@eslint/plugin-kit');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @fileoverview The JSONSourceCode class.
|
|
@@ -23,48 +24,28 @@ var momoa = require('@humanwhocodes/momoa');
|
|
|
23
24
|
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
24
25
|
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
25
26
|
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
27
|
+
/** @typedef {import("@eslint/core").FileProblem} FileProblem */
|
|
28
|
+
/** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
|
|
29
|
+
/** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
|
|
26
30
|
|
|
27
31
|
//-----------------------------------------------------------------------------
|
|
28
32
|
// Helpers
|
|
29
33
|
//-----------------------------------------------------------------------------
|
|
30
34
|
|
|
35
|
+
const commentParser = new pluginKit.ConfigCommentParser();
|
|
36
|
+
|
|
37
|
+
const INLINE_CONFIG =
|
|
38
|
+
/^\s*(?:eslint(?:-enable|-disable(?:(?:-next)?-line)?)?)(?:\s|$)/u;
|
|
39
|
+
|
|
31
40
|
/**
|
|
32
41
|
* A class to represent a step in the traversal process.
|
|
33
|
-
* @implements {VisitTraversalStep}
|
|
34
42
|
*/
|
|
35
|
-
class JSONTraversalStep {
|
|
36
|
-
/**
|
|
37
|
-
* The type of the step.
|
|
38
|
-
* @type {"visit"}
|
|
39
|
-
* @readonly
|
|
40
|
-
*/
|
|
41
|
-
type = "visit";
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The kind of the step. Represents the same data as the `type` property
|
|
45
|
-
* but it's a number for performance.
|
|
46
|
-
* @type {1}
|
|
47
|
-
* @readonly
|
|
48
|
-
*/
|
|
49
|
-
kind = 1;
|
|
50
|
-
|
|
43
|
+
class JSONTraversalStep extends pluginKit.VisitNodeStep {
|
|
51
44
|
/**
|
|
52
45
|
* The target of the step.
|
|
53
46
|
* @type {JSONNode}
|
|
54
47
|
*/
|
|
55
|
-
target;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The phase of the step.
|
|
59
|
-
* @type {1|2}
|
|
60
|
-
*/
|
|
61
|
-
phase;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* The arguments of the step.
|
|
65
|
-
* @type {Array<any>}
|
|
66
|
-
*/
|
|
67
|
-
args;
|
|
48
|
+
target = undefined;
|
|
68
49
|
|
|
69
50
|
/**
|
|
70
51
|
* Creates a new instance.
|
|
@@ -74,9 +55,9 @@ class JSONTraversalStep {
|
|
|
74
55
|
* @param {Array<any>} options.args The arguments of the step.
|
|
75
56
|
*/
|
|
76
57
|
constructor({ target, phase, args }) {
|
|
58
|
+
super({ target, phase, args });
|
|
59
|
+
|
|
77
60
|
this.target = target;
|
|
78
|
-
this.phase = phase;
|
|
79
|
-
this.args = args;
|
|
80
61
|
}
|
|
81
62
|
}
|
|
82
63
|
|
|
@@ -86,9 +67,8 @@ class JSONTraversalStep {
|
|
|
86
67
|
|
|
87
68
|
/**
|
|
88
69
|
* JSON Source Code Object
|
|
89
|
-
* @implements {TextSourceCode}
|
|
90
70
|
*/
|
|
91
|
-
class JSONSourceCode {
|
|
71
|
+
class JSONSourceCode extends pluginKit.TextSourceCodeBase {
|
|
92
72
|
/**
|
|
93
73
|
* Cached traversal steps.
|
|
94
74
|
* @type {Array<JSONTraversalStep>|undefined}
|
|
@@ -102,22 +82,16 @@ class JSONSourceCode {
|
|
|
102
82
|
#parents = new WeakMap();
|
|
103
83
|
|
|
104
84
|
/**
|
|
105
|
-
*
|
|
106
|
-
* @type {Array<
|
|
85
|
+
* Collection of inline configuration comments.
|
|
86
|
+
* @type {Array<JSONToken>}
|
|
107
87
|
*/
|
|
108
|
-
#
|
|
88
|
+
#inlineConfigComments;
|
|
109
89
|
|
|
110
90
|
/**
|
|
111
91
|
* The AST of the source code.
|
|
112
92
|
* @type {DocumentNode}
|
|
113
93
|
*/
|
|
114
|
-
ast;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* The text of the source code.
|
|
118
|
-
* @type {string}
|
|
119
|
-
*/
|
|
120
|
-
text;
|
|
94
|
+
ast = undefined;
|
|
121
95
|
|
|
122
96
|
/**
|
|
123
97
|
* The comment node in the source code.
|
|
@@ -132,97 +106,150 @@ class JSONSourceCode {
|
|
|
132
106
|
* @param {DocumentNode} options.ast The root AST node.
|
|
133
107
|
*/
|
|
134
108
|
constructor({ text, ast }) {
|
|
109
|
+
super({ text, ast });
|
|
135
110
|
this.ast = ast;
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
);
|
|
111
|
+
this.comments = ast.tokens
|
|
112
|
+
? ast.tokens.filter(token => token.type.endsWith("Comment"))
|
|
113
|
+
: [];
|
|
140
114
|
}
|
|
141
115
|
|
|
142
|
-
/* eslint-disable class-methods-use-this -- Required to complete interface. */
|
|
143
|
-
|
|
144
116
|
/**
|
|
145
|
-
* Returns the
|
|
146
|
-
* @param {
|
|
147
|
-
* @returns {
|
|
117
|
+
* Returns the value of the given comment.
|
|
118
|
+
* @param {JSONToken} comment The comment to get the value of.
|
|
119
|
+
* @returns {string} The value of the comment.
|
|
120
|
+
* @throws {Error} When an unexpected comment type is passed.
|
|
148
121
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
122
|
+
#getCommentValue(comment) {
|
|
123
|
+
if (comment.type === "LineComment") {
|
|
124
|
+
return this.getText(comment).slice(2); // strip leading `//`
|
|
125
|
+
}
|
|
152
126
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* @returns {SourceRange} The range information for the node or token.
|
|
157
|
-
*/
|
|
158
|
-
getRange(nodeOrToken) {
|
|
159
|
-
return nodeOrToken.range;
|
|
160
|
-
}
|
|
127
|
+
if (comment.type === "BlockComment") {
|
|
128
|
+
return this.getText(comment).slice(2, -2); // strip leading `/*` and trailing `*/`
|
|
129
|
+
}
|
|
161
130
|
|
|
162
|
-
|
|
131
|
+
throw new Error(`Unexpected comment type '${comment.type}'`);
|
|
132
|
+
}
|
|
163
133
|
|
|
164
134
|
/**
|
|
165
|
-
* Returns
|
|
166
|
-
*
|
|
167
|
-
* @returns {
|
|
135
|
+
* Returns an array of all inline configuration nodes found in the
|
|
136
|
+
* source code.
|
|
137
|
+
* @returns {Array<JSONToken>} An array of all inline configuration nodes.
|
|
168
138
|
*/
|
|
169
|
-
|
|
170
|
-
|
|
139
|
+
getInlineConfigNodes() {
|
|
140
|
+
if (!this.#inlineConfigComments) {
|
|
141
|
+
this.#inlineConfigComments = this.comments.filter(comment =>
|
|
142
|
+
INLINE_CONFIG.test(this.#getCommentValue(comment)),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return this.#inlineConfigComments;
|
|
171
147
|
}
|
|
172
148
|
|
|
173
149
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* @returns {Array<
|
|
177
|
-
*
|
|
178
|
-
* @throws {TypeError} When `node` is missing.
|
|
150
|
+
* Returns directives that enable or disable rules along with any problems
|
|
151
|
+
* encountered while parsing the directives.
|
|
152
|
+
* @returns {{problems:Array<FileProblem>,directives:Array<Directive>}} Information
|
|
153
|
+
* that ESLint needs to further process the directives.
|
|
179
154
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
155
|
+
getDisableDirectives() {
|
|
156
|
+
const problems = [];
|
|
157
|
+
const directives = [];
|
|
158
|
+
|
|
159
|
+
this.getInlineConfigNodes().forEach(comment => {
|
|
160
|
+
const { label, value, justification } =
|
|
161
|
+
commentParser.parseDirective(this.#getCommentValue(comment));
|
|
162
|
+
|
|
163
|
+
// `eslint-disable-line` directives are not allowed to span multiple lines as it would be confusing to which lines they apply
|
|
164
|
+
if (
|
|
165
|
+
label === "eslint-disable-line" &&
|
|
166
|
+
comment.loc.start.line !== comment.loc.end.line
|
|
167
|
+
) {
|
|
168
|
+
const message = `${label} comment should not span multiple lines.`;
|
|
169
|
+
|
|
170
|
+
problems.push({
|
|
171
|
+
ruleId: null,
|
|
172
|
+
message,
|
|
173
|
+
loc: comment.loc,
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
switch (label) {
|
|
179
|
+
case "eslint-disable":
|
|
180
|
+
case "eslint-enable":
|
|
181
|
+
case "eslint-disable-next-line":
|
|
182
|
+
case "eslint-disable-line": {
|
|
183
|
+
const directiveType = label.slice("eslint-".length);
|
|
184
|
+
|
|
185
|
+
directives.push(
|
|
186
|
+
new pluginKit.Directive({
|
|
187
|
+
type: /** @type {DirectiveType} */ (directiveType),
|
|
188
|
+
node: comment,
|
|
189
|
+
value,
|
|
190
|
+
justification,
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
186
194
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
ancestor = this.#parents.get(ancestor)
|
|
191
|
-
) {
|
|
192
|
-
ancestorsStartingAtParent.push(ancestor);
|
|
193
|
-
}
|
|
195
|
+
// no default
|
|
196
|
+
}
|
|
197
|
+
});
|
|
194
198
|
|
|
195
|
-
return
|
|
199
|
+
return { problems, directives };
|
|
196
200
|
}
|
|
197
201
|
|
|
198
202
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* @
|
|
202
|
-
*
|
|
203
|
-
* @returns {string} The text representing the AST node.
|
|
204
|
-
* @public
|
|
203
|
+
* Returns inline rule configurations along with any problems
|
|
204
|
+
* encountered while parsing the configurations.
|
|
205
|
+
* @returns {{problems:Array<FileProblem>,configs:Array<{config:{rules:RulesConfig},loc:SourceLocation}>}} Information
|
|
206
|
+
* that ESLint needs to further process the rule configurations.
|
|
205
207
|
*/
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
applyInlineConfig() {
|
|
209
|
+
const problems = [];
|
|
210
|
+
const configs = [];
|
|
211
|
+
|
|
212
|
+
this.getInlineConfigNodes().forEach(comment => {
|
|
213
|
+
const { label, value } = commentParser.parseDirective(
|
|
214
|
+
this.#getCommentValue(comment),
|
|
211
215
|
);
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
|
|
217
|
+
if (label === "eslint") {
|
|
218
|
+
const parseResult = commentParser.parseJSONLikeConfig(value);
|
|
219
|
+
|
|
220
|
+
if (parseResult.ok) {
|
|
221
|
+
configs.push({
|
|
222
|
+
config: {
|
|
223
|
+
rules: parseResult.config,
|
|
224
|
+
},
|
|
225
|
+
loc: comment.loc,
|
|
226
|
+
});
|
|
227
|
+
} else {
|
|
228
|
+
problems.push({
|
|
229
|
+
ruleId: null,
|
|
230
|
+
message:
|
|
231
|
+
/** @type {{ok: false, error: { message: string }}} */ (
|
|
232
|
+
parseResult
|
|
233
|
+
).error.message,
|
|
234
|
+
loc: comment.loc,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
configs,
|
|
242
|
+
problems,
|
|
243
|
+
};
|
|
214
244
|
}
|
|
215
245
|
|
|
216
246
|
/**
|
|
217
|
-
*
|
|
218
|
-
* @
|
|
219
|
-
* @
|
|
247
|
+
* Returns the parent of the given node.
|
|
248
|
+
* @param {JSONNode} node The node to get the parent of.
|
|
249
|
+
* @returns {JSONNode|undefined} The parent of the node.
|
|
220
250
|
*/
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.#lines = this.text.split(/\r?\n/gu);
|
|
224
|
-
}
|
|
225
|
-
return this.#lines;
|
|
251
|
+
getParent(node) {
|
|
252
|
+
return this.#parents.get(node);
|
|
226
253
|
}
|
|
227
254
|
|
|
228
255
|
/**
|
|
@@ -239,7 +266,10 @@ class JSONSourceCode {
|
|
|
239
266
|
const steps = (this.#steps = []);
|
|
240
267
|
|
|
241
268
|
for (const { node, parent, phase } of momoa.iterator(this.ast)) {
|
|
242
|
-
|
|
269
|
+
if (parent) {
|
|
270
|
+
this.#parents.set(node, parent);
|
|
271
|
+
}
|
|
272
|
+
|
|
243
273
|
steps.push(
|
|
244
274
|
new JSONTraversalStep({
|
|
245
275
|
target: node,
|
|
@@ -500,7 +530,7 @@ var noEmptyKeys = {
|
|
|
500
530
|
const plugin = {
|
|
501
531
|
meta: {
|
|
502
532
|
name: "@eslint/json",
|
|
503
|
-
version: "0.
|
|
533
|
+
version: "0.5.0", // x-release-please-version
|
|
504
534
|
},
|
|
505
535
|
languages: {
|
|
506
536
|
json: new JSONLanguage({ mode: "json" }),
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -7,6 +7,9 @@ export type File = import("@eslint/core").File;
|
|
|
7
7
|
export type TraversalStep = import("@eslint/core").TraversalStep;
|
|
8
8
|
export type TextSourceCode = import("@eslint/core").TextSourceCode;
|
|
9
9
|
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
10
|
+
export type FileProblem = import("@eslint/core").FileProblem;
|
|
11
|
+
export type DirectiveType = import("@eslint/core").DirectiveType;
|
|
12
|
+
export type RulesConfig = import("@eslint/core").RulesConfig;
|
|
10
13
|
export type Language = import("@eslint/core").Language;
|
|
11
14
|
export type OkParseResult = import("@eslint/core").OkParseResult<DocumentNode>;
|
|
12
15
|
export type ParseResult = import("@eslint/core").ParseResult<DocumentNode>;
|
|
@@ -79,9 +82,8 @@ export class JSONLanguage implements Language {
|
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
81
84
|
* JSON Source Code Object
|
|
82
|
-
* @implements {TextSourceCode}
|
|
83
85
|
*/
|
|
84
|
-
export class JSONSourceCode
|
|
86
|
+
export class JSONSourceCode extends TextSourceCodeBase {
|
|
85
87
|
/**
|
|
86
88
|
* Creates a new instance.
|
|
87
89
|
* @param {Object} options The options for the instance.
|
|
@@ -97,57 +99,48 @@ export class JSONSourceCode implements TextSourceCode {
|
|
|
97
99
|
* @type {DocumentNode}
|
|
98
100
|
*/
|
|
99
101
|
ast: DocumentNode;
|
|
100
|
-
/**
|
|
101
|
-
* The text of the source code.
|
|
102
|
-
* @type {string}
|
|
103
|
-
*/
|
|
104
|
-
text: string;
|
|
105
102
|
/**
|
|
106
103
|
* The comment node in the source code.
|
|
107
104
|
* @type {Array<JSONToken>|undefined}
|
|
108
105
|
*/
|
|
109
106
|
comments: Array<JSONToken> | undefined;
|
|
110
107
|
/**
|
|
111
|
-
* Returns
|
|
112
|
-
*
|
|
113
|
-
* @returns {
|
|
108
|
+
* Returns an array of all inline configuration nodes found in the
|
|
109
|
+
* source code.
|
|
110
|
+
* @returns {Array<JSONToken>} An array of all inline configuration nodes.
|
|
114
111
|
*/
|
|
115
|
-
|
|
112
|
+
getInlineConfigNodes(): Array<JSONToken>;
|
|
116
113
|
/**
|
|
117
|
-
* Returns
|
|
118
|
-
*
|
|
119
|
-
* @returns {
|
|
114
|
+
* Returns directives that enable or disable rules along with any problems
|
|
115
|
+
* encountered while parsing the directives.
|
|
116
|
+
* @returns {{problems:Array<FileProblem>,directives:Array<Directive>}} Information
|
|
117
|
+
* that ESLint needs to further process the directives.
|
|
120
118
|
*/
|
|
121
|
-
|
|
119
|
+
getDisableDirectives(): {
|
|
120
|
+
problems: Array<FileProblem>;
|
|
121
|
+
directives: Array<Directive>;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Returns inline rule configurations along with any problems
|
|
125
|
+
* encountered while parsing the configurations.
|
|
126
|
+
* @returns {{problems:Array<FileProblem>,configs:Array<{config:{rules:RulesConfig},loc:SourceLocation}>}} Information
|
|
127
|
+
* that ESLint needs to further process the rule configurations.
|
|
128
|
+
*/
|
|
129
|
+
applyInlineConfig(): {
|
|
130
|
+
problems: Array<FileProblem>;
|
|
131
|
+
configs: Array<{
|
|
132
|
+
config: {
|
|
133
|
+
rules: RulesConfig;
|
|
134
|
+
};
|
|
135
|
+
loc: SourceLocation;
|
|
136
|
+
}>;
|
|
137
|
+
};
|
|
122
138
|
/**
|
|
123
139
|
* Returns the parent of the given node.
|
|
124
140
|
* @param {JSONNode} node The node to get the parent of.
|
|
125
141
|
* @returns {JSONNode|undefined} The parent of the node.
|
|
126
142
|
*/
|
|
127
143
|
getParent(node: JSONNode): JSONNode | undefined;
|
|
128
|
-
/**
|
|
129
|
-
* Gets all the ancestors of a given node
|
|
130
|
-
* @param {JSONNode} node The node
|
|
131
|
-
* @returns {Array<JSONNode>} All the ancestor nodes in the AST, not including the provided node, starting
|
|
132
|
-
* from the root node at index 0 and going inwards to the parent node.
|
|
133
|
-
* @throws {TypeError} When `node` is missing.
|
|
134
|
-
*/
|
|
135
|
-
getAncestors(node: JSONNode): Array<JSONNode>;
|
|
136
|
-
/**
|
|
137
|
-
* Gets the source code for the given node.
|
|
138
|
-
* @param {JSONNode} [node] The AST node to get the text for.
|
|
139
|
-
* @param {number} [beforeCount] The number of characters before the node to retrieve.
|
|
140
|
-
* @param {number} [afterCount] The number of characters after the node to retrieve.
|
|
141
|
-
* @returns {string} The text representing the AST node.
|
|
142
|
-
* @public
|
|
143
|
-
*/
|
|
144
|
-
public getText(node?: JSONNode, beforeCount?: number, afterCount?: number): string;
|
|
145
|
-
/**
|
|
146
|
-
* Gets the entire source text split into an array of lines.
|
|
147
|
-
* @returns {Array} The source text as an array of lines.
|
|
148
|
-
* @public
|
|
149
|
-
*/
|
|
150
|
-
public get lines(): any[];
|
|
151
144
|
/**
|
|
152
145
|
* Traverse the source code and return the steps that were taken.
|
|
153
146
|
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
@@ -199,24 +192,12 @@ declare namespace plugin {
|
|
|
199
192
|
};
|
|
200
193
|
let configs: {};
|
|
201
194
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
* @author Nicholas C. Zakas
|
|
205
|
-
*/
|
|
206
|
-
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
207
|
-
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
208
|
-
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
209
|
-
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
210
|
-
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
211
|
-
/** @typedef {import("@eslint/core").File} File */
|
|
212
|
-
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
213
|
-
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
214
|
-
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
195
|
+
import { TextSourceCodeBase } from '@eslint/plugin-kit';
|
|
196
|
+
import { Directive } from '@eslint/plugin-kit';
|
|
215
197
|
/**
|
|
216
198
|
* A class to represent a step in the traversal process.
|
|
217
|
-
* @implements {VisitTraversalStep}
|
|
218
199
|
*/
|
|
219
|
-
declare class JSONTraversalStep
|
|
200
|
+
declare class JSONTraversalStep extends VisitNodeStep {
|
|
220
201
|
/**
|
|
221
202
|
* Creates a new instance.
|
|
222
203
|
* @param {Object} options The options for the step.
|
|
@@ -229,33 +210,11 @@ declare class JSONTraversalStep implements VisitTraversalStep {
|
|
|
229
210
|
phase: 1 | 2;
|
|
230
211
|
args: Array<any>;
|
|
231
212
|
});
|
|
232
|
-
/**
|
|
233
|
-
* The type of the step.
|
|
234
|
-
* @type {"visit"}
|
|
235
|
-
* @readonly
|
|
236
|
-
*/
|
|
237
|
-
readonly type: "visit";
|
|
238
|
-
/**
|
|
239
|
-
* The kind of the step. Represents the same data as the `type` property
|
|
240
|
-
* but it's a number for performance.
|
|
241
|
-
* @type {1}
|
|
242
|
-
* @readonly
|
|
243
|
-
*/
|
|
244
|
-
readonly kind: 1;
|
|
245
213
|
/**
|
|
246
214
|
* The target of the step.
|
|
247
215
|
* @type {JSONNode}
|
|
248
216
|
*/
|
|
249
217
|
target: JSONNode;
|
|
250
|
-
/**
|
|
251
|
-
* The phase of the step.
|
|
252
|
-
* @type {1|2}
|
|
253
|
-
*/
|
|
254
|
-
phase: 1 | 2;
|
|
255
|
-
/**
|
|
256
|
-
* The arguments of the step.
|
|
257
|
-
* @type {Array<any>}
|
|
258
|
-
*/
|
|
259
|
-
args: Array<any>;
|
|
260
218
|
}
|
|
219
|
+
import { VisitNodeStep } from '@eslint/plugin-kit';
|
|
261
220
|
export { plugin as default };
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export type File = import("@eslint/core").File;
|
|
|
7
7
|
export type TraversalStep = import("@eslint/core").TraversalStep;
|
|
8
8
|
export type TextSourceCode = import("@eslint/core").TextSourceCode;
|
|
9
9
|
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
10
|
+
export type FileProblem = import("@eslint/core").FileProblem;
|
|
11
|
+
export type DirectiveType = import("@eslint/core").DirectiveType;
|
|
12
|
+
export type RulesConfig = import("@eslint/core").RulesConfig;
|
|
10
13
|
export type Language = import("@eslint/core").Language;
|
|
11
14
|
export type OkParseResult = import("@eslint/core").OkParseResult<DocumentNode>;
|
|
12
15
|
export type ParseResult = import("@eslint/core").ParseResult<DocumentNode>;
|
|
@@ -79,9 +82,8 @@ export class JSONLanguage implements Language {
|
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
81
84
|
* JSON Source Code Object
|
|
82
|
-
* @implements {TextSourceCode}
|
|
83
85
|
*/
|
|
84
|
-
export class JSONSourceCode
|
|
86
|
+
export class JSONSourceCode extends TextSourceCodeBase {
|
|
85
87
|
/**
|
|
86
88
|
* Creates a new instance.
|
|
87
89
|
* @param {Object} options The options for the instance.
|
|
@@ -97,57 +99,48 @@ export class JSONSourceCode implements TextSourceCode {
|
|
|
97
99
|
* @type {DocumentNode}
|
|
98
100
|
*/
|
|
99
101
|
ast: DocumentNode;
|
|
100
|
-
/**
|
|
101
|
-
* The text of the source code.
|
|
102
|
-
* @type {string}
|
|
103
|
-
*/
|
|
104
|
-
text: string;
|
|
105
102
|
/**
|
|
106
103
|
* The comment node in the source code.
|
|
107
104
|
* @type {Array<JSONToken>|undefined}
|
|
108
105
|
*/
|
|
109
106
|
comments: Array<JSONToken> | undefined;
|
|
110
107
|
/**
|
|
111
|
-
* Returns
|
|
112
|
-
*
|
|
113
|
-
* @returns {
|
|
108
|
+
* Returns an array of all inline configuration nodes found in the
|
|
109
|
+
* source code.
|
|
110
|
+
* @returns {Array<JSONToken>} An array of all inline configuration nodes.
|
|
114
111
|
*/
|
|
115
|
-
|
|
112
|
+
getInlineConfigNodes(): Array<JSONToken>;
|
|
116
113
|
/**
|
|
117
|
-
* Returns
|
|
118
|
-
*
|
|
119
|
-
* @returns {
|
|
114
|
+
* Returns directives that enable or disable rules along with any problems
|
|
115
|
+
* encountered while parsing the directives.
|
|
116
|
+
* @returns {{problems:Array<FileProblem>,directives:Array<Directive>}} Information
|
|
117
|
+
* that ESLint needs to further process the directives.
|
|
120
118
|
*/
|
|
121
|
-
|
|
119
|
+
getDisableDirectives(): {
|
|
120
|
+
problems: Array<FileProblem>;
|
|
121
|
+
directives: Array<Directive>;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Returns inline rule configurations along with any problems
|
|
125
|
+
* encountered while parsing the configurations.
|
|
126
|
+
* @returns {{problems:Array<FileProblem>,configs:Array<{config:{rules:RulesConfig},loc:SourceLocation}>}} Information
|
|
127
|
+
* that ESLint needs to further process the rule configurations.
|
|
128
|
+
*/
|
|
129
|
+
applyInlineConfig(): {
|
|
130
|
+
problems: Array<FileProblem>;
|
|
131
|
+
configs: Array<{
|
|
132
|
+
config: {
|
|
133
|
+
rules: RulesConfig;
|
|
134
|
+
};
|
|
135
|
+
loc: SourceLocation;
|
|
136
|
+
}>;
|
|
137
|
+
};
|
|
122
138
|
/**
|
|
123
139
|
* Returns the parent of the given node.
|
|
124
140
|
* @param {JSONNode} node The node to get the parent of.
|
|
125
141
|
* @returns {JSONNode|undefined} The parent of the node.
|
|
126
142
|
*/
|
|
127
143
|
getParent(node: JSONNode): JSONNode | undefined;
|
|
128
|
-
/**
|
|
129
|
-
* Gets all the ancestors of a given node
|
|
130
|
-
* @param {JSONNode} node The node
|
|
131
|
-
* @returns {Array<JSONNode>} All the ancestor nodes in the AST, not including the provided node, starting
|
|
132
|
-
* from the root node at index 0 and going inwards to the parent node.
|
|
133
|
-
* @throws {TypeError} When `node` is missing.
|
|
134
|
-
*/
|
|
135
|
-
getAncestors(node: JSONNode): Array<JSONNode>;
|
|
136
|
-
/**
|
|
137
|
-
* Gets the source code for the given node.
|
|
138
|
-
* @param {JSONNode} [node] The AST node to get the text for.
|
|
139
|
-
* @param {number} [beforeCount] The number of characters before the node to retrieve.
|
|
140
|
-
* @param {number} [afterCount] The number of characters after the node to retrieve.
|
|
141
|
-
* @returns {string} The text representing the AST node.
|
|
142
|
-
* @public
|
|
143
|
-
*/
|
|
144
|
-
public getText(node?: JSONNode, beforeCount?: number, afterCount?: number): string;
|
|
145
|
-
/**
|
|
146
|
-
* Gets the entire source text split into an array of lines.
|
|
147
|
-
* @returns {Array} The source text as an array of lines.
|
|
148
|
-
* @public
|
|
149
|
-
*/
|
|
150
|
-
public get lines(): any[];
|
|
151
144
|
/**
|
|
152
145
|
* Traverse the source code and return the steps that were taken.
|
|
153
146
|
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
@@ -199,24 +192,12 @@ declare namespace plugin {
|
|
|
199
192
|
};
|
|
200
193
|
let configs: {};
|
|
201
194
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
* @author Nicholas C. Zakas
|
|
205
|
-
*/
|
|
206
|
-
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
207
|
-
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
208
|
-
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
209
|
-
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
210
|
-
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
211
|
-
/** @typedef {import("@eslint/core").File} File */
|
|
212
|
-
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
213
|
-
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
214
|
-
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
195
|
+
import { TextSourceCodeBase } from '@eslint/plugin-kit';
|
|
196
|
+
import { Directive } from '@eslint/plugin-kit';
|
|
215
197
|
/**
|
|
216
198
|
* A class to represent a step in the traversal process.
|
|
217
|
-
* @implements {VisitTraversalStep}
|
|
218
199
|
*/
|
|
219
|
-
declare class JSONTraversalStep
|
|
200
|
+
declare class JSONTraversalStep extends VisitNodeStep {
|
|
220
201
|
/**
|
|
221
202
|
* Creates a new instance.
|
|
222
203
|
* @param {Object} options The options for the step.
|
|
@@ -229,33 +210,11 @@ declare class JSONTraversalStep implements VisitTraversalStep {
|
|
|
229
210
|
phase: 1 | 2;
|
|
230
211
|
args: Array<any>;
|
|
231
212
|
});
|
|
232
|
-
/**
|
|
233
|
-
* The type of the step.
|
|
234
|
-
* @type {"visit"}
|
|
235
|
-
* @readonly
|
|
236
|
-
*/
|
|
237
|
-
readonly type: "visit";
|
|
238
|
-
/**
|
|
239
|
-
* The kind of the step. Represents the same data as the `type` property
|
|
240
|
-
* but it's a number for performance.
|
|
241
|
-
* @type {1}
|
|
242
|
-
* @readonly
|
|
243
|
-
*/
|
|
244
|
-
readonly kind: 1;
|
|
245
213
|
/**
|
|
246
214
|
* The target of the step.
|
|
247
215
|
* @type {JSONNode}
|
|
248
216
|
*/
|
|
249
217
|
target: JSONNode;
|
|
250
|
-
/**
|
|
251
|
-
* The phase of the step.
|
|
252
|
-
* @type {1|2}
|
|
253
|
-
*/
|
|
254
|
-
phase: 1 | 2;
|
|
255
|
-
/**
|
|
256
|
-
* The arguments of the step.
|
|
257
|
-
* @type {Array<any>}
|
|
258
|
-
*/
|
|
259
|
-
args: Array<any>;
|
|
260
218
|
}
|
|
219
|
+
import { VisitNodeStep } from '@eslint/plugin-kit';
|
|
261
220
|
export { plugin as default };
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-self-types="./index.d.ts"
|
|
2
2
|
import { iterator, visitorKeys, parse } from '@humanwhocodes/momoa';
|
|
3
|
+
import { ConfigCommentParser, TextSourceCodeBase, Directive, VisitNodeStep } from '@eslint/plugin-kit';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @fileoverview The JSONSourceCode class.
|
|
@@ -20,48 +21,28 @@ import { iterator, visitorKeys, parse } from '@humanwhocodes/momoa';
|
|
|
20
21
|
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
21
22
|
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
22
23
|
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
24
|
+
/** @typedef {import("@eslint/core").FileProblem} FileProblem */
|
|
25
|
+
/** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
|
|
26
|
+
/** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
|
|
23
27
|
|
|
24
28
|
//-----------------------------------------------------------------------------
|
|
25
29
|
// Helpers
|
|
26
30
|
//-----------------------------------------------------------------------------
|
|
27
31
|
|
|
32
|
+
const commentParser = new ConfigCommentParser();
|
|
33
|
+
|
|
34
|
+
const INLINE_CONFIG =
|
|
35
|
+
/^\s*(?:eslint(?:-enable|-disable(?:(?:-next)?-line)?)?)(?:\s|$)/u;
|
|
36
|
+
|
|
28
37
|
/**
|
|
29
38
|
* A class to represent a step in the traversal process.
|
|
30
|
-
* @implements {VisitTraversalStep}
|
|
31
39
|
*/
|
|
32
|
-
class JSONTraversalStep {
|
|
33
|
-
/**
|
|
34
|
-
* The type of the step.
|
|
35
|
-
* @type {"visit"}
|
|
36
|
-
* @readonly
|
|
37
|
-
*/
|
|
38
|
-
type = "visit";
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* The kind of the step. Represents the same data as the `type` property
|
|
42
|
-
* but it's a number for performance.
|
|
43
|
-
* @type {1}
|
|
44
|
-
* @readonly
|
|
45
|
-
*/
|
|
46
|
-
kind = 1;
|
|
47
|
-
|
|
40
|
+
class JSONTraversalStep extends VisitNodeStep {
|
|
48
41
|
/**
|
|
49
42
|
* The target of the step.
|
|
50
43
|
* @type {JSONNode}
|
|
51
44
|
*/
|
|
52
|
-
target;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* The phase of the step.
|
|
56
|
-
* @type {1|2}
|
|
57
|
-
*/
|
|
58
|
-
phase;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The arguments of the step.
|
|
62
|
-
* @type {Array<any>}
|
|
63
|
-
*/
|
|
64
|
-
args;
|
|
45
|
+
target = undefined;
|
|
65
46
|
|
|
66
47
|
/**
|
|
67
48
|
* Creates a new instance.
|
|
@@ -71,9 +52,9 @@ class JSONTraversalStep {
|
|
|
71
52
|
* @param {Array<any>} options.args The arguments of the step.
|
|
72
53
|
*/
|
|
73
54
|
constructor({ target, phase, args }) {
|
|
55
|
+
super({ target, phase, args });
|
|
56
|
+
|
|
74
57
|
this.target = target;
|
|
75
|
-
this.phase = phase;
|
|
76
|
-
this.args = args;
|
|
77
58
|
}
|
|
78
59
|
}
|
|
79
60
|
|
|
@@ -83,9 +64,8 @@ class JSONTraversalStep {
|
|
|
83
64
|
|
|
84
65
|
/**
|
|
85
66
|
* JSON Source Code Object
|
|
86
|
-
* @implements {TextSourceCode}
|
|
87
67
|
*/
|
|
88
|
-
class JSONSourceCode {
|
|
68
|
+
class JSONSourceCode extends TextSourceCodeBase {
|
|
89
69
|
/**
|
|
90
70
|
* Cached traversal steps.
|
|
91
71
|
* @type {Array<JSONTraversalStep>|undefined}
|
|
@@ -99,22 +79,16 @@ class JSONSourceCode {
|
|
|
99
79
|
#parents = new WeakMap();
|
|
100
80
|
|
|
101
81
|
/**
|
|
102
|
-
*
|
|
103
|
-
* @type {Array<
|
|
82
|
+
* Collection of inline configuration comments.
|
|
83
|
+
* @type {Array<JSONToken>}
|
|
104
84
|
*/
|
|
105
|
-
#
|
|
85
|
+
#inlineConfigComments;
|
|
106
86
|
|
|
107
87
|
/**
|
|
108
88
|
* The AST of the source code.
|
|
109
89
|
* @type {DocumentNode}
|
|
110
90
|
*/
|
|
111
|
-
ast;
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* The text of the source code.
|
|
115
|
-
* @type {string}
|
|
116
|
-
*/
|
|
117
|
-
text;
|
|
91
|
+
ast = undefined;
|
|
118
92
|
|
|
119
93
|
/**
|
|
120
94
|
* The comment node in the source code.
|
|
@@ -129,97 +103,150 @@ class JSONSourceCode {
|
|
|
129
103
|
* @param {DocumentNode} options.ast The root AST node.
|
|
130
104
|
*/
|
|
131
105
|
constructor({ text, ast }) {
|
|
106
|
+
super({ text, ast });
|
|
132
107
|
this.ast = ast;
|
|
133
|
-
this.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
);
|
|
108
|
+
this.comments = ast.tokens
|
|
109
|
+
? ast.tokens.filter(token => token.type.endsWith("Comment"))
|
|
110
|
+
: [];
|
|
137
111
|
}
|
|
138
112
|
|
|
139
|
-
/* eslint-disable class-methods-use-this -- Required to complete interface. */
|
|
140
|
-
|
|
141
113
|
/**
|
|
142
|
-
* Returns the
|
|
143
|
-
* @param {
|
|
144
|
-
* @returns {
|
|
114
|
+
* Returns the value of the given comment.
|
|
115
|
+
* @param {JSONToken} comment The comment to get the value of.
|
|
116
|
+
* @returns {string} The value of the comment.
|
|
117
|
+
* @throws {Error} When an unexpected comment type is passed.
|
|
145
118
|
*/
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
119
|
+
#getCommentValue(comment) {
|
|
120
|
+
if (comment.type === "LineComment") {
|
|
121
|
+
return this.getText(comment).slice(2); // strip leading `//`
|
|
122
|
+
}
|
|
149
123
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
* @returns {SourceRange} The range information for the node or token.
|
|
154
|
-
*/
|
|
155
|
-
getRange(nodeOrToken) {
|
|
156
|
-
return nodeOrToken.range;
|
|
157
|
-
}
|
|
124
|
+
if (comment.type === "BlockComment") {
|
|
125
|
+
return this.getText(comment).slice(2, -2); // strip leading `/*` and trailing `*/`
|
|
126
|
+
}
|
|
158
127
|
|
|
159
|
-
|
|
128
|
+
throw new Error(`Unexpected comment type '${comment.type}'`);
|
|
129
|
+
}
|
|
160
130
|
|
|
161
131
|
/**
|
|
162
|
-
* Returns
|
|
163
|
-
*
|
|
164
|
-
* @returns {
|
|
132
|
+
* Returns an array of all inline configuration nodes found in the
|
|
133
|
+
* source code.
|
|
134
|
+
* @returns {Array<JSONToken>} An array of all inline configuration nodes.
|
|
165
135
|
*/
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
getInlineConfigNodes() {
|
|
137
|
+
if (!this.#inlineConfigComments) {
|
|
138
|
+
this.#inlineConfigComments = this.comments.filter(comment =>
|
|
139
|
+
INLINE_CONFIG.test(this.#getCommentValue(comment)),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return this.#inlineConfigComments;
|
|
168
144
|
}
|
|
169
145
|
|
|
170
146
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* @returns {Array<
|
|
174
|
-
*
|
|
175
|
-
* @throws {TypeError} When `node` is missing.
|
|
147
|
+
* Returns directives that enable or disable rules along with any problems
|
|
148
|
+
* encountered while parsing the directives.
|
|
149
|
+
* @returns {{problems:Array<FileProblem>,directives:Array<Directive>}} Information
|
|
150
|
+
* that ESLint needs to further process the directives.
|
|
176
151
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
152
|
+
getDisableDirectives() {
|
|
153
|
+
const problems = [];
|
|
154
|
+
const directives = [];
|
|
155
|
+
|
|
156
|
+
this.getInlineConfigNodes().forEach(comment => {
|
|
157
|
+
const { label, value, justification } =
|
|
158
|
+
commentParser.parseDirective(this.#getCommentValue(comment));
|
|
159
|
+
|
|
160
|
+
// `eslint-disable-line` directives are not allowed to span multiple lines as it would be confusing to which lines they apply
|
|
161
|
+
if (
|
|
162
|
+
label === "eslint-disable-line" &&
|
|
163
|
+
comment.loc.start.line !== comment.loc.end.line
|
|
164
|
+
) {
|
|
165
|
+
const message = `${label} comment should not span multiple lines.`;
|
|
166
|
+
|
|
167
|
+
problems.push({
|
|
168
|
+
ruleId: null,
|
|
169
|
+
message,
|
|
170
|
+
loc: comment.loc,
|
|
171
|
+
});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
switch (label) {
|
|
176
|
+
case "eslint-disable":
|
|
177
|
+
case "eslint-enable":
|
|
178
|
+
case "eslint-disable-next-line":
|
|
179
|
+
case "eslint-disable-line": {
|
|
180
|
+
const directiveType = label.slice("eslint-".length);
|
|
181
|
+
|
|
182
|
+
directives.push(
|
|
183
|
+
new Directive({
|
|
184
|
+
type: /** @type {DirectiveType} */ (directiveType),
|
|
185
|
+
node: comment,
|
|
186
|
+
value,
|
|
187
|
+
justification,
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
183
191
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
ancestor = this.#parents.get(ancestor)
|
|
188
|
-
) {
|
|
189
|
-
ancestorsStartingAtParent.push(ancestor);
|
|
190
|
-
}
|
|
192
|
+
// no default
|
|
193
|
+
}
|
|
194
|
+
});
|
|
191
195
|
|
|
192
|
-
return
|
|
196
|
+
return { problems, directives };
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* @
|
|
199
|
-
*
|
|
200
|
-
* @returns {string} The text representing the AST node.
|
|
201
|
-
* @public
|
|
200
|
+
* Returns inline rule configurations along with any problems
|
|
201
|
+
* encountered while parsing the configurations.
|
|
202
|
+
* @returns {{problems:Array<FileProblem>,configs:Array<{config:{rules:RulesConfig},loc:SourceLocation}>}} Information
|
|
203
|
+
* that ESLint needs to further process the rule configurations.
|
|
202
204
|
*/
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
applyInlineConfig() {
|
|
206
|
+
const problems = [];
|
|
207
|
+
const configs = [];
|
|
208
|
+
|
|
209
|
+
this.getInlineConfigNodes().forEach(comment => {
|
|
210
|
+
const { label, value } = commentParser.parseDirective(
|
|
211
|
+
this.#getCommentValue(comment),
|
|
208
212
|
);
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
|
|
214
|
+
if (label === "eslint") {
|
|
215
|
+
const parseResult = commentParser.parseJSONLikeConfig(value);
|
|
216
|
+
|
|
217
|
+
if (parseResult.ok) {
|
|
218
|
+
configs.push({
|
|
219
|
+
config: {
|
|
220
|
+
rules: parseResult.config,
|
|
221
|
+
},
|
|
222
|
+
loc: comment.loc,
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
problems.push({
|
|
226
|
+
ruleId: null,
|
|
227
|
+
message:
|
|
228
|
+
/** @type {{ok: false, error: { message: string }}} */ (
|
|
229
|
+
parseResult
|
|
230
|
+
).error.message,
|
|
231
|
+
loc: comment.loc,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
configs,
|
|
239
|
+
problems,
|
|
240
|
+
};
|
|
211
241
|
}
|
|
212
242
|
|
|
213
243
|
/**
|
|
214
|
-
*
|
|
215
|
-
* @
|
|
216
|
-
* @
|
|
244
|
+
* Returns the parent of the given node.
|
|
245
|
+
* @param {JSONNode} node The node to get the parent of.
|
|
246
|
+
* @returns {JSONNode|undefined} The parent of the node.
|
|
217
247
|
*/
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
this.#lines = this.text.split(/\r?\n/gu);
|
|
221
|
-
}
|
|
222
|
-
return this.#lines;
|
|
248
|
+
getParent(node) {
|
|
249
|
+
return this.#parents.get(node);
|
|
223
250
|
}
|
|
224
251
|
|
|
225
252
|
/**
|
|
@@ -236,7 +263,10 @@ class JSONSourceCode {
|
|
|
236
263
|
const steps = (this.#steps = []);
|
|
237
264
|
|
|
238
265
|
for (const { node, parent, phase } of iterator(this.ast)) {
|
|
239
|
-
|
|
266
|
+
if (parent) {
|
|
267
|
+
this.#parents.set(node, parent);
|
|
268
|
+
}
|
|
269
|
+
|
|
240
270
|
steps.push(
|
|
241
271
|
new JSONTraversalStep({
|
|
242
272
|
target: node,
|
|
@@ -497,7 +527,7 @@ var noEmptyKeys = {
|
|
|
497
527
|
const plugin = {
|
|
498
528
|
meta: {
|
|
499
529
|
name: "@eslint/json",
|
|
500
|
-
version: "0.
|
|
530
|
+
version: "0.5.0", // x-release-please-version
|
|
501
531
|
},
|
|
502
532
|
languages: {
|
|
503
533
|
json: new JSONLanguage({ mode: "json" }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint/json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "JSON linting plugin for ESLint",
|
|
5
5
|
"author": "Nicholas C. Zakas",
|
|
6
6
|
"type": "module",
|
|
@@ -61,13 +61,15 @@
|
|
|
61
61
|
],
|
|
62
62
|
"license": "Apache-2.0",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@
|
|
64
|
+
"@eslint/plugin-kit": "^0.2.0",
|
|
65
|
+
"@humanwhocodes/momoa": "^3.2.1"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
|
-
"@eslint/core": "^0.
|
|
68
|
+
"@eslint/core": "^0.6.0",
|
|
68
69
|
"@types/eslint": "^8.56.10",
|
|
69
70
|
"c8": "^9.1.0",
|
|
70
|
-
"
|
|
71
|
+
"dedent": "^1.5.3",
|
|
72
|
+
"eslint": "^9.11.1",
|
|
71
73
|
"eslint-config-eslint": "^11.0.0",
|
|
72
74
|
"lint-staged": "^15.2.7",
|
|
73
75
|
"mocha": "^10.4.0",
|
|
@@ -79,8 +81,5 @@
|
|
|
79
81
|
},
|
|
80
82
|
"engines": {
|
|
81
83
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
82
|
-
},
|
|
83
|
-
"peerDependencies": {
|
|
84
|
-
"eslint": "^9.6.0"
|
|
85
84
|
}
|
|
86
85
|
}
|