@eslint/json 0.1.0 → 0.3.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 +27 -7
- package/dist/cjs/index.cjs +54 -20
- package/dist/cjs/index.d.cts +95 -14
- package/dist/esm/index.d.ts +95 -14
- package/dist/esm/index.js +54 -20
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,12 +28,13 @@ deno add @eslint/json
|
|
|
28
28
|
|
|
29
29
|
## Usage
|
|
30
30
|
|
|
31
|
-
This package exports
|
|
31
|
+
This package exports these languages:
|
|
32
32
|
|
|
33
33
|
- `"json/json"` is for regular JSON files
|
|
34
|
-
- `"json/jsonc"` is for JSON files that support comments (
|
|
34
|
+
- `"json/jsonc"` is for JSON files that support comments ([JSONC](https://github.com/microsoft/node-jsonc-parser)) such as those used for Visual Studio Code configuration files
|
|
35
|
+
- `"json/json5"` is for [JSON5](https://json5.org) files
|
|
35
36
|
|
|
36
|
-
Depending on which types of JSON files you'd like to lint, you can set up your `eslint.config.js` file to include just the files you'd like. Here's an example that lints
|
|
37
|
+
Depending on which types of JSON files you'd like to lint, you can set up your `eslint.config.js` file to include just the files you'd like. Here's an example that lints JSON, JSONC, and JSON5 files:
|
|
37
38
|
|
|
38
39
|
```js
|
|
39
40
|
import json from "@eslint/json";
|
|
@@ -54,14 +55,23 @@ export default [
|
|
|
54
55
|
},
|
|
55
56
|
},
|
|
56
57
|
|
|
57
|
-
// lint
|
|
58
|
+
// lint JSONC files
|
|
58
59
|
{
|
|
59
|
-
files: ["**/*.jsonc"],
|
|
60
|
+
files: ["**/*.jsonc", ".vscode/*.json"],
|
|
60
61
|
language: "json/jsonc",
|
|
61
62
|
rules: {
|
|
62
63
|
"json/no-duplicate-keys": "error",
|
|
63
64
|
},
|
|
64
65
|
},
|
|
66
|
+
|
|
67
|
+
// lint JSON5 files
|
|
68
|
+
{
|
|
69
|
+
files: ["**/*.json5"],
|
|
70
|
+
language: "json/json5",
|
|
71
|
+
rules: {
|
|
72
|
+
"json/no-duplicate-keys": "error",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
65
75
|
];
|
|
66
76
|
```
|
|
67
77
|
|
|
@@ -76,23 +86,33 @@ export default [
|
|
|
76
86
|
// lint JSON files
|
|
77
87
|
{
|
|
78
88
|
files: ["**/*.json"],
|
|
89
|
+
ignores: ["package-lock.json"],
|
|
79
90
|
language: "json/json",
|
|
80
91
|
...json.configs.recommended,
|
|
81
92
|
},
|
|
82
93
|
|
|
83
|
-
// lint
|
|
94
|
+
// lint JSONC files
|
|
84
95
|
{
|
|
85
96
|
files: ["**/*.jsonc"],
|
|
86
97
|
language: "json/jsonc",
|
|
87
98
|
...json.configs.recommended,
|
|
88
99
|
},
|
|
100
|
+
|
|
101
|
+
// lint JSON5 files
|
|
102
|
+
{
|
|
103
|
+
files: ["**/*.json5"],
|
|
104
|
+
language: "json/json5",
|
|
105
|
+
...json.configs.recommended,
|
|
106
|
+
},
|
|
89
107
|
];
|
|
90
108
|
```
|
|
91
109
|
|
|
110
|
+
**Note:** You generally want to ignore `package-lock.json` because it is auto-generated and you typically will not want to manually make changes to it.
|
|
111
|
+
|
|
92
112
|
## Rules
|
|
93
113
|
|
|
94
114
|
- `no-duplicate-keys` - warns when there are two keys in an object with the same text.
|
|
95
|
-
- `no-empty-keys` - warns when there is a key in an object that is an empty string or contains only whitespace
|
|
115
|
+
- `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)
|
|
96
116
|
|
|
97
117
|
## License
|
|
98
118
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -15,13 +15,12 @@ var momoa = require('@humanwhocodes/momoa');
|
|
|
15
15
|
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
16
16
|
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
17
17
|
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
18
|
-
/** @typedef {import("@eslint/core").
|
|
19
|
-
/** @typedef {import("@eslint/core").
|
|
18
|
+
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
19
|
+
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
20
20
|
/** @typedef {import("@eslint/core").File} File */
|
|
21
21
|
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
22
|
-
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
23
22
|
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
24
|
-
/** @typedef {import("@eslint/core").
|
|
23
|
+
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
25
24
|
|
|
26
25
|
//-----------------------------------------------------------------------------
|
|
27
26
|
// Helpers
|
|
@@ -49,7 +48,7 @@ class JSONTraversalStep {
|
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
50
|
* The target of the step.
|
|
52
|
-
* @type {JSONNode
|
|
51
|
+
* @type {JSONNode}
|
|
53
52
|
*/
|
|
54
53
|
target;
|
|
55
54
|
|
|
@@ -68,7 +67,7 @@ class JSONTraversalStep {
|
|
|
68
67
|
/**
|
|
69
68
|
* Creates a new instance.
|
|
70
69
|
* @param {Object} options The options for the step.
|
|
71
|
-
* @param {JSONNode
|
|
70
|
+
* @param {JSONNode} options.target The target of the step.
|
|
72
71
|
* @param {1|2} options.phase The phase of the step.
|
|
73
72
|
* @param {Array<any>} options.args The arguments of the step.
|
|
74
73
|
*/
|
|
@@ -108,7 +107,7 @@ class JSONSourceCode {
|
|
|
108
107
|
|
|
109
108
|
/**
|
|
110
109
|
* The AST of the source code.
|
|
111
|
-
* @type {DocumentNode
|
|
110
|
+
* @type {DocumentNode}
|
|
112
111
|
*/
|
|
113
112
|
ast;
|
|
114
113
|
|
|
@@ -128,7 +127,7 @@ class JSONSourceCode {
|
|
|
128
127
|
* Creates a new instance.
|
|
129
128
|
* @param {Object} options The options for the instance.
|
|
130
129
|
* @param {string} options.text The source code text.
|
|
131
|
-
* @param {DocumentNode
|
|
130
|
+
* @param {DocumentNode} options.ast The root AST node.
|
|
132
131
|
*/
|
|
133
132
|
constructor({ text, ast }) {
|
|
134
133
|
this.ast = ast;
|
|
@@ -138,6 +137,28 @@ class JSONSourceCode {
|
|
|
138
137
|
);
|
|
139
138
|
}
|
|
140
139
|
|
|
140
|
+
/* eslint-disable class-methods-use-this -- Required to complete interface. */
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Returns the loc information for the given node or token.
|
|
144
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the loc information for.
|
|
145
|
+
* @returns {SourceLocation} The loc information for the node or token.
|
|
146
|
+
*/
|
|
147
|
+
getLoc(nodeOrToken) {
|
|
148
|
+
return nodeOrToken.loc;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Returns the range information for the given node or token.
|
|
153
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the range information for.
|
|
154
|
+
* @returns {SourceRange} The range information for the node or token.
|
|
155
|
+
*/
|
|
156
|
+
getRange(nodeOrToken) {
|
|
157
|
+
return nodeOrToken.range;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* eslint-enable class-methods-use-this -- Required to complete interface. */
|
|
161
|
+
|
|
141
162
|
/**
|
|
142
163
|
* Returns the parent of the given node.
|
|
143
164
|
* @param {JSONNode} node The node to get the parent of.
|
|
@@ -204,7 +225,7 @@ class JSONSourceCode {
|
|
|
204
225
|
|
|
205
226
|
/**
|
|
206
227
|
* Traverse the source code and return the steps that were taken.
|
|
207
|
-
* @returns {Iterable<
|
|
228
|
+
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
208
229
|
*/
|
|
209
230
|
traverse() {
|
|
210
231
|
// Because the AST doesn't mutate, we can cache the steps
|
|
@@ -212,15 +233,14 @@ class JSONSourceCode {
|
|
|
212
233
|
return this.#steps.values();
|
|
213
234
|
}
|
|
214
235
|
|
|
236
|
+
/** @type {Array<JSONTraversalStep>} */
|
|
215
237
|
const steps = (this.#steps = []);
|
|
216
238
|
|
|
217
|
-
for (const { node, parent, phase } of momoa.iterator(
|
|
218
|
-
/** @type {DocumentNode} */ (this.ast),
|
|
219
|
-
)) {
|
|
239
|
+
for (const { node, parent, phase } of momoa.iterator(this.ast)) {
|
|
220
240
|
this.#parents.set(node, parent);
|
|
221
241
|
steps.push(
|
|
222
242
|
new JSONTraversalStep({
|
|
223
|
-
target:
|
|
243
|
+
target: node,
|
|
224
244
|
phase: phase === "enter" ? 1 : 2,
|
|
225
245
|
args: [node, parent],
|
|
226
246
|
}),
|
|
@@ -241,6 +261,9 @@ class JSONSourceCode {
|
|
|
241
261
|
// Types
|
|
242
262
|
//-----------------------------------------------------------------------------
|
|
243
263
|
|
|
264
|
+
/** @typedef {import("@eslint/core").Language} Language */
|
|
265
|
+
/** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
|
|
266
|
+
/** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
|
|
244
267
|
|
|
245
268
|
//-----------------------------------------------------------------------------
|
|
246
269
|
// Exports
|
|
@@ -277,7 +300,7 @@ class JSONLanguage {
|
|
|
277
300
|
|
|
278
301
|
/**
|
|
279
302
|
* The parser mode.
|
|
280
|
-
* @type {"json"|"jsonc"}
|
|
303
|
+
* @type {"json"|"jsonc"|"json5"}
|
|
281
304
|
*/
|
|
282
305
|
#mode = "json";
|
|
283
306
|
|
|
@@ -290,7 +313,7 @@ class JSONLanguage {
|
|
|
290
313
|
/**
|
|
291
314
|
* Creates a new instance.
|
|
292
315
|
* @param {Object} options The options to use for this instance.
|
|
293
|
-
* @param {"json"|"jsonc"} options.mode The parser mode to use.
|
|
316
|
+
* @param {"json"|"jsonc"|"json5"} options.mode The parser mode to use.
|
|
294
317
|
*/
|
|
295
318
|
constructor({ mode }) {
|
|
296
319
|
this.#mode = mode;
|
|
@@ -332,7 +355,7 @@ class JSONLanguage {
|
|
|
332
355
|
|
|
333
356
|
return {
|
|
334
357
|
ok: true,
|
|
335
|
-
ast:
|
|
358
|
+
ast: root,
|
|
336
359
|
};
|
|
337
360
|
} catch (ex) {
|
|
338
361
|
// error messages end with (line:column) so we strip that off for ESLint
|
|
@@ -356,7 +379,7 @@ class JSONLanguage {
|
|
|
356
379
|
/**
|
|
357
380
|
* Creates a new `JSONSourceCode` object from the given information.
|
|
358
381
|
* @param {File} file The virtual file to create a `JSONSourceCode` object from.
|
|
359
|
-
* @param {
|
|
382
|
+
* @param {OkParseResult} parseResult The result returned from `parse()`.
|
|
360
383
|
* @returns {JSONSourceCode} The new `JSONSourceCode` object.
|
|
361
384
|
*/
|
|
362
385
|
createSourceCode(file, parseResult) {
|
|
@@ -374,7 +397,7 @@ class JSONLanguage {
|
|
|
374
397
|
*/
|
|
375
398
|
|
|
376
399
|
//-----------------------------------------------------------------------------
|
|
377
|
-
//
|
|
400
|
+
// Rule Definition
|
|
378
401
|
//-----------------------------------------------------------------------------
|
|
379
402
|
|
|
380
403
|
var noDuplicateKeys = {
|
|
@@ -401,7 +424,10 @@ var noDuplicateKeys = {
|
|
|
401
424
|
},
|
|
402
425
|
|
|
403
426
|
Member(node) {
|
|
404
|
-
const key =
|
|
427
|
+
const key =
|
|
428
|
+
node.name.type === "String"
|
|
429
|
+
? node.name.value
|
|
430
|
+
: node.name.name;
|
|
405
431
|
|
|
406
432
|
if (keys.has(key)) {
|
|
407
433
|
context.report({
|
|
@@ -443,7 +469,10 @@ var noEmptyKeys = {
|
|
|
443
469
|
create(context) {
|
|
444
470
|
return {
|
|
445
471
|
Member(node) {
|
|
446
|
-
const key =
|
|
472
|
+
const key =
|
|
473
|
+
node.name.type === "String"
|
|
474
|
+
? node.name.value
|
|
475
|
+
: node.name.name;
|
|
447
476
|
|
|
448
477
|
if (key.trim() === "") {
|
|
449
478
|
context.report({
|
|
@@ -467,9 +496,14 @@ var noEmptyKeys = {
|
|
|
467
496
|
//-----------------------------------------------------------------------------
|
|
468
497
|
|
|
469
498
|
const plugin = {
|
|
499
|
+
meta: {
|
|
500
|
+
name: "@eslint/json",
|
|
501
|
+
version: "0.3.0", // x-release-please-version
|
|
502
|
+
},
|
|
470
503
|
languages: {
|
|
471
504
|
json: new JSONLanguage({ mode: "json" }),
|
|
472
505
|
jsonc: new JSONLanguage({ mode: "jsonc" }),
|
|
506
|
+
json5: new JSONLanguage({ mode: "json5" }),
|
|
473
507
|
},
|
|
474
508
|
rules: {
|
|
475
509
|
"no-duplicate-keys": noDuplicateKeys,
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -2,17 +2,24 @@ export { plugin as default };
|
|
|
2
2
|
export type DocumentNode = import("@humanwhocodes/momoa").DocumentNode;
|
|
3
3
|
export type JSONNode = import("@humanwhocodes/momoa").Node;
|
|
4
4
|
export type JSONToken = import("@humanwhocodes/momoa").Token;
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
5
|
+
export type SourceRange = import("@eslint/core").SourceRange;
|
|
6
|
+
export type SourceLocation = import("@eslint/core").SourceLocation;
|
|
7
7
|
export type File = import("@eslint/core").File;
|
|
8
8
|
export type TraversalStep = import("@eslint/core").TraversalStep;
|
|
9
|
-
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
10
9
|
export type TextSourceCode = import("@eslint/core").TextSourceCode;
|
|
11
|
-
export type
|
|
10
|
+
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
11
|
+
export type Language = import("@eslint/core").Language;
|
|
12
|
+
export type OkParseResult = import("@eslint/core").OkParseResult<DocumentNode>;
|
|
13
|
+
export type ParseResult = import("@eslint/core").ParseResult<DocumentNode>;
|
|
12
14
|
declare namespace plugin {
|
|
15
|
+
namespace meta {
|
|
16
|
+
let name: string;
|
|
17
|
+
let version: string;
|
|
18
|
+
}
|
|
13
19
|
namespace languages {
|
|
14
20
|
let json: JSONLanguage;
|
|
15
21
|
let jsonc: JSONLanguage;
|
|
22
|
+
let json5: JSONLanguage;
|
|
16
23
|
}
|
|
17
24
|
let rules: {
|
|
18
25
|
"no-duplicate-keys": {
|
|
@@ -52,6 +59,9 @@ declare namespace plugin {
|
|
|
52
59
|
* @filedescription Functions to fix up rules to provide missing methods on the `context` object.
|
|
53
60
|
* @author Nicholas C. Zakas
|
|
54
61
|
*/
|
|
62
|
+
/** @typedef {import("@eslint/core").Language} Language */
|
|
63
|
+
/** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
|
|
64
|
+
/** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
|
|
55
65
|
/**
|
|
56
66
|
* JSON Language Object
|
|
57
67
|
* @implements {Language}
|
|
@@ -60,10 +70,10 @@ declare class JSONLanguage implements Language {
|
|
|
60
70
|
/**
|
|
61
71
|
* Creates a new instance.
|
|
62
72
|
* @param {Object} options The options to use for this instance.
|
|
63
|
-
* @param {"json"|"jsonc"} options.mode The parser mode to use.
|
|
73
|
+
* @param {"json"|"jsonc"|"json5"} options.mode The parser mode to use.
|
|
64
74
|
*/
|
|
65
75
|
constructor({ mode }: {
|
|
66
|
-
mode: "json" | "jsonc";
|
|
76
|
+
mode: "json" | "jsonc" | "json5";
|
|
67
77
|
});
|
|
68
78
|
/**
|
|
69
79
|
* The type of file to read.
|
|
@@ -106,10 +116,10 @@ declare class JSONLanguage implements Language {
|
|
|
106
116
|
/**
|
|
107
117
|
* Creates a new `JSONSourceCode` object from the given information.
|
|
108
118
|
* @param {File} file The virtual file to create a `JSONSourceCode` object from.
|
|
109
|
-
* @param {
|
|
119
|
+
* @param {OkParseResult} parseResult The result returned from `parse()`.
|
|
110
120
|
* @returns {JSONSourceCode} The new `JSONSourceCode` object.
|
|
111
121
|
*/
|
|
112
|
-
createSourceCode(file: File, parseResult:
|
|
122
|
+
createSourceCode(file: File, parseResult: OkParseResult): JSONSourceCode;
|
|
113
123
|
#private;
|
|
114
124
|
}
|
|
115
125
|
/**
|
|
@@ -121,17 +131,17 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
121
131
|
* Creates a new instance.
|
|
122
132
|
* @param {Object} options The options for the instance.
|
|
123
133
|
* @param {string} options.text The source code text.
|
|
124
|
-
* @param {DocumentNode
|
|
134
|
+
* @param {DocumentNode} options.ast The root AST node.
|
|
125
135
|
*/
|
|
126
136
|
constructor({ text, ast }: {
|
|
127
137
|
text: string;
|
|
128
|
-
ast: DocumentNode
|
|
138
|
+
ast: DocumentNode;
|
|
129
139
|
});
|
|
130
140
|
/**
|
|
131
141
|
* The AST of the source code.
|
|
132
|
-
* @type {DocumentNode
|
|
142
|
+
* @type {DocumentNode}
|
|
133
143
|
*/
|
|
134
|
-
ast: DocumentNode
|
|
144
|
+
ast: DocumentNode;
|
|
135
145
|
/**
|
|
136
146
|
* The text of the source code.
|
|
137
147
|
* @type {string}
|
|
@@ -142,6 +152,18 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
142
152
|
* @type {Array<JSONToken>|undefined}
|
|
143
153
|
*/
|
|
144
154
|
comments: Array<JSONToken> | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Returns the loc information for the given node or token.
|
|
157
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the loc information for.
|
|
158
|
+
* @returns {SourceLocation} The loc information for the node or token.
|
|
159
|
+
*/
|
|
160
|
+
getLoc(nodeOrToken: JSONNode | JSONToken): SourceLocation;
|
|
161
|
+
/**
|
|
162
|
+
* Returns the range information for the given node or token.
|
|
163
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the range information for.
|
|
164
|
+
* @returns {SourceRange} The range information for the node or token.
|
|
165
|
+
*/
|
|
166
|
+
getRange(nodeOrToken: JSONNode | JSONToken): SourceRange;
|
|
145
167
|
/**
|
|
146
168
|
* Returns the parent of the given node.
|
|
147
169
|
* @param {JSONNode} node The node to get the parent of.
|
|
@@ -173,8 +195,67 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
173
195
|
public get lines(): any[];
|
|
174
196
|
/**
|
|
175
197
|
* Traverse the source code and return the steps that were taken.
|
|
176
|
-
* @returns {Iterable<
|
|
198
|
+
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
177
199
|
*/
|
|
178
|
-
traverse(): Iterable<
|
|
200
|
+
traverse(): Iterable<JSONTraversalStep>;
|
|
179
201
|
#private;
|
|
180
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* @fileoverview The JSONSourceCode class.
|
|
205
|
+
* @author Nicholas C. Zakas
|
|
206
|
+
*/
|
|
207
|
+
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
208
|
+
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
209
|
+
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
210
|
+
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
211
|
+
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
212
|
+
/** @typedef {import("@eslint/core").File} File */
|
|
213
|
+
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
214
|
+
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
215
|
+
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
216
|
+
/**
|
|
217
|
+
* A class to represent a step in the traversal process.
|
|
218
|
+
* @implements {VisitTraversalStep}
|
|
219
|
+
*/
|
|
220
|
+
declare class JSONTraversalStep implements VisitTraversalStep {
|
|
221
|
+
/**
|
|
222
|
+
* Creates a new instance.
|
|
223
|
+
* @param {Object} options The options for the step.
|
|
224
|
+
* @param {JSONNode} options.target The target of the step.
|
|
225
|
+
* @param {1|2} options.phase The phase of the step.
|
|
226
|
+
* @param {Array<any>} options.args The arguments of the step.
|
|
227
|
+
*/
|
|
228
|
+
constructor({ target, phase, args }: {
|
|
229
|
+
target: JSONNode;
|
|
230
|
+
phase: 1 | 2;
|
|
231
|
+
args: Array<any>;
|
|
232
|
+
});
|
|
233
|
+
/**
|
|
234
|
+
* The type of the step.
|
|
235
|
+
* @type {"visit"}
|
|
236
|
+
* @readonly
|
|
237
|
+
*/
|
|
238
|
+
readonly type: "visit";
|
|
239
|
+
/**
|
|
240
|
+
* The kind of the step. Represents the same data as the `type` property
|
|
241
|
+
* but it's a number for performance.
|
|
242
|
+
* @type {1}
|
|
243
|
+
* @readonly
|
|
244
|
+
*/
|
|
245
|
+
readonly kind: 1;
|
|
246
|
+
/**
|
|
247
|
+
* The target of the step.
|
|
248
|
+
* @type {JSONNode}
|
|
249
|
+
*/
|
|
250
|
+
target: JSONNode;
|
|
251
|
+
/**
|
|
252
|
+
* The phase of the step.
|
|
253
|
+
* @type {1|2}
|
|
254
|
+
*/
|
|
255
|
+
phase: 1 | 2;
|
|
256
|
+
/**
|
|
257
|
+
* The arguments of the step.
|
|
258
|
+
* @type {Array<any>}
|
|
259
|
+
*/
|
|
260
|
+
args: Array<any>;
|
|
261
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -2,17 +2,24 @@ export { plugin as default };
|
|
|
2
2
|
export type DocumentNode = import("@humanwhocodes/momoa").DocumentNode;
|
|
3
3
|
export type JSONNode = import("@humanwhocodes/momoa").Node;
|
|
4
4
|
export type JSONToken = import("@humanwhocodes/momoa").Token;
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
5
|
+
export type SourceRange = import("@eslint/core").SourceRange;
|
|
6
|
+
export type SourceLocation = import("@eslint/core").SourceLocation;
|
|
7
7
|
export type File = import("@eslint/core").File;
|
|
8
8
|
export type TraversalStep = import("@eslint/core").TraversalStep;
|
|
9
|
-
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
10
9
|
export type TextSourceCode = import("@eslint/core").TextSourceCode;
|
|
11
|
-
export type
|
|
10
|
+
export type VisitTraversalStep = import("@eslint/core").VisitTraversalStep;
|
|
11
|
+
export type Language = import("@eslint/core").Language;
|
|
12
|
+
export type OkParseResult = import("@eslint/core").OkParseResult<DocumentNode>;
|
|
13
|
+
export type ParseResult = import("@eslint/core").ParseResult<DocumentNode>;
|
|
12
14
|
declare namespace plugin {
|
|
15
|
+
namespace meta {
|
|
16
|
+
let name: string;
|
|
17
|
+
let version: string;
|
|
18
|
+
}
|
|
13
19
|
namespace languages {
|
|
14
20
|
let json: JSONLanguage;
|
|
15
21
|
let jsonc: JSONLanguage;
|
|
22
|
+
let json5: JSONLanguage;
|
|
16
23
|
}
|
|
17
24
|
let rules: {
|
|
18
25
|
"no-duplicate-keys": {
|
|
@@ -52,6 +59,9 @@ declare namespace plugin {
|
|
|
52
59
|
* @filedescription Functions to fix up rules to provide missing methods on the `context` object.
|
|
53
60
|
* @author Nicholas C. Zakas
|
|
54
61
|
*/
|
|
62
|
+
/** @typedef {import("@eslint/core").Language} Language */
|
|
63
|
+
/** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
|
|
64
|
+
/** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
|
|
55
65
|
/**
|
|
56
66
|
* JSON Language Object
|
|
57
67
|
* @implements {Language}
|
|
@@ -60,10 +70,10 @@ declare class JSONLanguage implements Language {
|
|
|
60
70
|
/**
|
|
61
71
|
* Creates a new instance.
|
|
62
72
|
* @param {Object} options The options to use for this instance.
|
|
63
|
-
* @param {"json"|"jsonc"} options.mode The parser mode to use.
|
|
73
|
+
* @param {"json"|"jsonc"|"json5"} options.mode The parser mode to use.
|
|
64
74
|
*/
|
|
65
75
|
constructor({ mode }: {
|
|
66
|
-
mode: "json" | "jsonc";
|
|
76
|
+
mode: "json" | "jsonc" | "json5";
|
|
67
77
|
});
|
|
68
78
|
/**
|
|
69
79
|
* The type of file to read.
|
|
@@ -106,10 +116,10 @@ declare class JSONLanguage implements Language {
|
|
|
106
116
|
/**
|
|
107
117
|
* Creates a new `JSONSourceCode` object from the given information.
|
|
108
118
|
* @param {File} file The virtual file to create a `JSONSourceCode` object from.
|
|
109
|
-
* @param {
|
|
119
|
+
* @param {OkParseResult} parseResult The result returned from `parse()`.
|
|
110
120
|
* @returns {JSONSourceCode} The new `JSONSourceCode` object.
|
|
111
121
|
*/
|
|
112
|
-
createSourceCode(file: File, parseResult:
|
|
122
|
+
createSourceCode(file: File, parseResult: OkParseResult): JSONSourceCode;
|
|
113
123
|
#private;
|
|
114
124
|
}
|
|
115
125
|
/**
|
|
@@ -121,17 +131,17 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
121
131
|
* Creates a new instance.
|
|
122
132
|
* @param {Object} options The options for the instance.
|
|
123
133
|
* @param {string} options.text The source code text.
|
|
124
|
-
* @param {DocumentNode
|
|
134
|
+
* @param {DocumentNode} options.ast The root AST node.
|
|
125
135
|
*/
|
|
126
136
|
constructor({ text, ast }: {
|
|
127
137
|
text: string;
|
|
128
|
-
ast: DocumentNode
|
|
138
|
+
ast: DocumentNode;
|
|
129
139
|
});
|
|
130
140
|
/**
|
|
131
141
|
* The AST of the source code.
|
|
132
|
-
* @type {DocumentNode
|
|
142
|
+
* @type {DocumentNode}
|
|
133
143
|
*/
|
|
134
|
-
ast: DocumentNode
|
|
144
|
+
ast: DocumentNode;
|
|
135
145
|
/**
|
|
136
146
|
* The text of the source code.
|
|
137
147
|
* @type {string}
|
|
@@ -142,6 +152,18 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
142
152
|
* @type {Array<JSONToken>|undefined}
|
|
143
153
|
*/
|
|
144
154
|
comments: Array<JSONToken> | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Returns the loc information for the given node or token.
|
|
157
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the loc information for.
|
|
158
|
+
* @returns {SourceLocation} The loc information for the node or token.
|
|
159
|
+
*/
|
|
160
|
+
getLoc(nodeOrToken: JSONNode | JSONToken): SourceLocation;
|
|
161
|
+
/**
|
|
162
|
+
* Returns the range information for the given node or token.
|
|
163
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the range information for.
|
|
164
|
+
* @returns {SourceRange} The range information for the node or token.
|
|
165
|
+
*/
|
|
166
|
+
getRange(nodeOrToken: JSONNode | JSONToken): SourceRange;
|
|
145
167
|
/**
|
|
146
168
|
* Returns the parent of the given node.
|
|
147
169
|
* @param {JSONNode} node The node to get the parent of.
|
|
@@ -173,8 +195,67 @@ declare class JSONSourceCode implements TextSourceCode {
|
|
|
173
195
|
public get lines(): any[];
|
|
174
196
|
/**
|
|
175
197
|
* Traverse the source code and return the steps that were taken.
|
|
176
|
-
* @returns {Iterable<
|
|
198
|
+
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
177
199
|
*/
|
|
178
|
-
traverse(): Iterable<
|
|
200
|
+
traverse(): Iterable<JSONTraversalStep>;
|
|
179
201
|
#private;
|
|
180
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* @fileoverview The JSONSourceCode class.
|
|
205
|
+
* @author Nicholas C. Zakas
|
|
206
|
+
*/
|
|
207
|
+
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
208
|
+
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
209
|
+
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
210
|
+
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
211
|
+
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
212
|
+
/** @typedef {import("@eslint/core").File} File */
|
|
213
|
+
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
214
|
+
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
215
|
+
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
216
|
+
/**
|
|
217
|
+
* A class to represent a step in the traversal process.
|
|
218
|
+
* @implements {VisitTraversalStep}
|
|
219
|
+
*/
|
|
220
|
+
declare class JSONTraversalStep implements VisitTraversalStep {
|
|
221
|
+
/**
|
|
222
|
+
* Creates a new instance.
|
|
223
|
+
* @param {Object} options The options for the step.
|
|
224
|
+
* @param {JSONNode} options.target The target of the step.
|
|
225
|
+
* @param {1|2} options.phase The phase of the step.
|
|
226
|
+
* @param {Array<any>} options.args The arguments of the step.
|
|
227
|
+
*/
|
|
228
|
+
constructor({ target, phase, args }: {
|
|
229
|
+
target: JSONNode;
|
|
230
|
+
phase: 1 | 2;
|
|
231
|
+
args: Array<any>;
|
|
232
|
+
});
|
|
233
|
+
/**
|
|
234
|
+
* The type of the step.
|
|
235
|
+
* @type {"visit"}
|
|
236
|
+
* @readonly
|
|
237
|
+
*/
|
|
238
|
+
readonly type: "visit";
|
|
239
|
+
/**
|
|
240
|
+
* The kind of the step. Represents the same data as the `type` property
|
|
241
|
+
* but it's a number for performance.
|
|
242
|
+
* @type {1}
|
|
243
|
+
* @readonly
|
|
244
|
+
*/
|
|
245
|
+
readonly kind: 1;
|
|
246
|
+
/**
|
|
247
|
+
* The target of the step.
|
|
248
|
+
* @type {JSONNode}
|
|
249
|
+
*/
|
|
250
|
+
target: JSONNode;
|
|
251
|
+
/**
|
|
252
|
+
* The phase of the step.
|
|
253
|
+
* @type {1|2}
|
|
254
|
+
*/
|
|
255
|
+
phase: 1 | 2;
|
|
256
|
+
/**
|
|
257
|
+
* The arguments of the step.
|
|
258
|
+
* @type {Array<any>}
|
|
259
|
+
*/
|
|
260
|
+
args: Array<any>;
|
|
261
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -14,13 +14,12 @@ import { iterator, visitorKeys, parse } from '@humanwhocodes/momoa';
|
|
|
14
14
|
/** @typedef {import("@humanwhocodes/momoa").DocumentNode} DocumentNode */
|
|
15
15
|
/** @typedef {import("@humanwhocodes/momoa").Node} JSONNode */
|
|
16
16
|
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
17
|
-
/** @typedef {import("@eslint/core").
|
|
18
|
-
/** @typedef {import("@eslint/core").
|
|
17
|
+
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
18
|
+
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
19
19
|
/** @typedef {import("@eslint/core").File} File */
|
|
20
20
|
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
21
|
-
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
22
21
|
/** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
|
|
23
|
-
/** @typedef {import("@eslint/core").
|
|
22
|
+
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
|
|
24
23
|
|
|
25
24
|
//-----------------------------------------------------------------------------
|
|
26
25
|
// Helpers
|
|
@@ -48,7 +47,7 @@ class JSONTraversalStep {
|
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
49
|
* The target of the step.
|
|
51
|
-
* @type {JSONNode
|
|
50
|
+
* @type {JSONNode}
|
|
52
51
|
*/
|
|
53
52
|
target;
|
|
54
53
|
|
|
@@ -67,7 +66,7 @@ class JSONTraversalStep {
|
|
|
67
66
|
/**
|
|
68
67
|
* Creates a new instance.
|
|
69
68
|
* @param {Object} options The options for the step.
|
|
70
|
-
* @param {JSONNode
|
|
69
|
+
* @param {JSONNode} options.target The target of the step.
|
|
71
70
|
* @param {1|2} options.phase The phase of the step.
|
|
72
71
|
* @param {Array<any>} options.args The arguments of the step.
|
|
73
72
|
*/
|
|
@@ -107,7 +106,7 @@ class JSONSourceCode {
|
|
|
107
106
|
|
|
108
107
|
/**
|
|
109
108
|
* The AST of the source code.
|
|
110
|
-
* @type {DocumentNode
|
|
109
|
+
* @type {DocumentNode}
|
|
111
110
|
*/
|
|
112
111
|
ast;
|
|
113
112
|
|
|
@@ -127,7 +126,7 @@ class JSONSourceCode {
|
|
|
127
126
|
* Creates a new instance.
|
|
128
127
|
* @param {Object} options The options for the instance.
|
|
129
128
|
* @param {string} options.text The source code text.
|
|
130
|
-
* @param {DocumentNode
|
|
129
|
+
* @param {DocumentNode} options.ast The root AST node.
|
|
131
130
|
*/
|
|
132
131
|
constructor({ text, ast }) {
|
|
133
132
|
this.ast = ast;
|
|
@@ -137,6 +136,28 @@ class JSONSourceCode {
|
|
|
137
136
|
);
|
|
138
137
|
}
|
|
139
138
|
|
|
139
|
+
/* eslint-disable class-methods-use-this -- Required to complete interface. */
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Returns the loc information for the given node or token.
|
|
143
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the loc information for.
|
|
144
|
+
* @returns {SourceLocation} The loc information for the node or token.
|
|
145
|
+
*/
|
|
146
|
+
getLoc(nodeOrToken) {
|
|
147
|
+
return nodeOrToken.loc;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Returns the range information for the given node or token.
|
|
152
|
+
* @param {JSONNode|JSONToken} nodeOrToken The node or token to get the range information for.
|
|
153
|
+
* @returns {SourceRange} The range information for the node or token.
|
|
154
|
+
*/
|
|
155
|
+
getRange(nodeOrToken) {
|
|
156
|
+
return nodeOrToken.range;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* eslint-enable class-methods-use-this -- Required to complete interface. */
|
|
160
|
+
|
|
140
161
|
/**
|
|
141
162
|
* Returns the parent of the given node.
|
|
142
163
|
* @param {JSONNode} node The node to get the parent of.
|
|
@@ -203,7 +224,7 @@ class JSONSourceCode {
|
|
|
203
224
|
|
|
204
225
|
/**
|
|
205
226
|
* Traverse the source code and return the steps that were taken.
|
|
206
|
-
* @returns {Iterable<
|
|
227
|
+
* @returns {Iterable<JSONTraversalStep>} The steps that were taken while traversing the source code.
|
|
207
228
|
*/
|
|
208
229
|
traverse() {
|
|
209
230
|
// Because the AST doesn't mutate, we can cache the steps
|
|
@@ -211,15 +232,14 @@ class JSONSourceCode {
|
|
|
211
232
|
return this.#steps.values();
|
|
212
233
|
}
|
|
213
234
|
|
|
235
|
+
/** @type {Array<JSONTraversalStep>} */
|
|
214
236
|
const steps = (this.#steps = []);
|
|
215
237
|
|
|
216
|
-
for (const { node, parent, phase } of iterator(
|
|
217
|
-
/** @type {DocumentNode} */ (this.ast),
|
|
218
|
-
)) {
|
|
238
|
+
for (const { node, parent, phase } of iterator(this.ast)) {
|
|
219
239
|
this.#parents.set(node, parent);
|
|
220
240
|
steps.push(
|
|
221
241
|
new JSONTraversalStep({
|
|
222
|
-
target:
|
|
242
|
+
target: node,
|
|
223
243
|
phase: phase === "enter" ? 1 : 2,
|
|
224
244
|
args: [node, parent],
|
|
225
245
|
}),
|
|
@@ -240,6 +260,9 @@ class JSONSourceCode {
|
|
|
240
260
|
// Types
|
|
241
261
|
//-----------------------------------------------------------------------------
|
|
242
262
|
|
|
263
|
+
/** @typedef {import("@eslint/core").Language} Language */
|
|
264
|
+
/** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
|
|
265
|
+
/** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
|
|
243
266
|
|
|
244
267
|
//-----------------------------------------------------------------------------
|
|
245
268
|
// Exports
|
|
@@ -276,7 +299,7 @@ class JSONLanguage {
|
|
|
276
299
|
|
|
277
300
|
/**
|
|
278
301
|
* The parser mode.
|
|
279
|
-
* @type {"json"|"jsonc"}
|
|
302
|
+
* @type {"json"|"jsonc"|"json5"}
|
|
280
303
|
*/
|
|
281
304
|
#mode = "json";
|
|
282
305
|
|
|
@@ -289,7 +312,7 @@ class JSONLanguage {
|
|
|
289
312
|
/**
|
|
290
313
|
* Creates a new instance.
|
|
291
314
|
* @param {Object} options The options to use for this instance.
|
|
292
|
-
* @param {"json"|"jsonc"} options.mode The parser mode to use.
|
|
315
|
+
* @param {"json"|"jsonc"|"json5"} options.mode The parser mode to use.
|
|
293
316
|
*/
|
|
294
317
|
constructor({ mode }) {
|
|
295
318
|
this.#mode = mode;
|
|
@@ -331,7 +354,7 @@ class JSONLanguage {
|
|
|
331
354
|
|
|
332
355
|
return {
|
|
333
356
|
ok: true,
|
|
334
|
-
ast:
|
|
357
|
+
ast: root,
|
|
335
358
|
};
|
|
336
359
|
} catch (ex) {
|
|
337
360
|
// error messages end with (line:column) so we strip that off for ESLint
|
|
@@ -355,7 +378,7 @@ class JSONLanguage {
|
|
|
355
378
|
/**
|
|
356
379
|
* Creates a new `JSONSourceCode` object from the given information.
|
|
357
380
|
* @param {File} file The virtual file to create a `JSONSourceCode` object from.
|
|
358
|
-
* @param {
|
|
381
|
+
* @param {OkParseResult} parseResult The result returned from `parse()`.
|
|
359
382
|
* @returns {JSONSourceCode} The new `JSONSourceCode` object.
|
|
360
383
|
*/
|
|
361
384
|
createSourceCode(file, parseResult) {
|
|
@@ -373,7 +396,7 @@ class JSONLanguage {
|
|
|
373
396
|
*/
|
|
374
397
|
|
|
375
398
|
//-----------------------------------------------------------------------------
|
|
376
|
-
//
|
|
399
|
+
// Rule Definition
|
|
377
400
|
//-----------------------------------------------------------------------------
|
|
378
401
|
|
|
379
402
|
var noDuplicateKeys = {
|
|
@@ -400,7 +423,10 @@ var noDuplicateKeys = {
|
|
|
400
423
|
},
|
|
401
424
|
|
|
402
425
|
Member(node) {
|
|
403
|
-
const key =
|
|
426
|
+
const key =
|
|
427
|
+
node.name.type === "String"
|
|
428
|
+
? node.name.value
|
|
429
|
+
: node.name.name;
|
|
404
430
|
|
|
405
431
|
if (keys.has(key)) {
|
|
406
432
|
context.report({
|
|
@@ -442,7 +468,10 @@ var noEmptyKeys = {
|
|
|
442
468
|
create(context) {
|
|
443
469
|
return {
|
|
444
470
|
Member(node) {
|
|
445
|
-
const key =
|
|
471
|
+
const key =
|
|
472
|
+
node.name.type === "String"
|
|
473
|
+
? node.name.value
|
|
474
|
+
: node.name.name;
|
|
446
475
|
|
|
447
476
|
if (key.trim() === "") {
|
|
448
477
|
context.report({
|
|
@@ -466,9 +495,14 @@ var noEmptyKeys = {
|
|
|
466
495
|
//-----------------------------------------------------------------------------
|
|
467
496
|
|
|
468
497
|
const plugin = {
|
|
498
|
+
meta: {
|
|
499
|
+
name: "@eslint/json",
|
|
500
|
+
version: "0.3.0", // x-release-please-version
|
|
501
|
+
},
|
|
469
502
|
languages: {
|
|
470
503
|
json: new JSONLanguage({ mode: "json" }),
|
|
471
504
|
jsonc: new JSONLanguage({ mode: "jsonc" }),
|
|
505
|
+
json5: new JSONLanguage({ mode: "json5" }),
|
|
472
506
|
},
|
|
473
507
|
rules: {
|
|
474
508
|
"no-duplicate-keys": noDuplicateKeys,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint/json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "JSON linting plugin for ESLint",
|
|
5
5
|
"author": "Nicholas C. Zakas",
|
|
6
6
|
"type": "module",
|
|
@@ -61,10 +61,10 @@
|
|
|
61
61
|
],
|
|
62
62
|
"license": "Apache-2.0",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@humanwhocodes/momoa": "^3.
|
|
64
|
+
"@humanwhocodes/momoa": "^3.2.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@eslint/core": "^0.
|
|
67
|
+
"@eslint/core": "^0.3.0",
|
|
68
68
|
"@types/eslint": "^8.56.10",
|
|
69
69
|
"c8": "^9.1.0",
|
|
70
70
|
"eslint": "^9.6.0",
|