@eslint/json 0.11.0 → 0.13.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 +72 -33
- package/dist/cjs/index.cjs +295 -139
- package/dist/cjs/index.d.cts +117 -77
- package/dist/cjs/types.cts +22 -68
- package/dist/esm/index.d.ts +117 -77
- package/dist/esm/index.js +295 -139
- package/dist/esm/types.d.ts +11 -49
- package/dist/esm/types.ts +22 -68
- package/package.json +23 -11
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @import { DocumentNode, AnyNode, Token, MemberNode } from "@humanwhocodes/momoa"
|
|
4
|
+
* @import { SourceLocation, FileProblem, DirectiveType, RulesConfig, Language, OkParseResult, ParseResult, File } from "@eslint/core"
|
|
5
|
+
* @import { JSONSyntaxElement, JSONRuleDefinition } from "./types.ts"
|
|
6
|
+
*/
|
|
1
7
|
// @ts-self-types="./index.d.ts"
|
|
2
8
|
import { iterator, visitorKeys, parse } from '@humanwhocodes/momoa';
|
|
3
9
|
import { ConfigCommentParser, TextSourceCodeBase, Directive, VisitNodeStep } from '@eslint/plugin-kit';
|
|
@@ -13,19 +19,8 @@ import naturalCompare from 'natural-compare';
|
|
|
13
19
|
// Types
|
|
14
20
|
//-----------------------------------------------------------------------------
|
|
15
21
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
/** @typedef {import("@humanwhocodes/momoa").Token} JSONToken */
|
|
19
|
-
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
|
|
20
|
-
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
|
|
21
|
-
/** @typedef {import("@eslint/core").File} File */
|
|
22
|
-
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
|
|
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 */
|
|
27
|
-
/** @typedef {import("./types.ts").IJSONSourceCode} IJSONSourceCode */
|
|
28
|
-
/** @typedef {import("./types.ts").JSONSyntaxElement} JSONSyntaxElement */
|
|
22
|
+
/**
|
|
23
|
+
*/
|
|
29
24
|
|
|
30
25
|
//-----------------------------------------------------------------------------
|
|
31
26
|
// Helpers
|
|
@@ -42,14 +37,14 @@ const INLINE_CONFIG =
|
|
|
42
37
|
class JSONTraversalStep extends VisitNodeStep {
|
|
43
38
|
/**
|
|
44
39
|
* The target of the step.
|
|
45
|
-
* @type {
|
|
40
|
+
* @type {AnyNode}
|
|
46
41
|
*/
|
|
47
42
|
target = undefined;
|
|
48
43
|
|
|
49
44
|
/**
|
|
50
45
|
* Creates a new instance.
|
|
51
46
|
* @param {Object} options The options for the step.
|
|
52
|
-
* @param {
|
|
47
|
+
* @param {AnyNode} options.target The target of the step.
|
|
53
48
|
* @param {1|2} options.phase The phase of the step.
|
|
54
49
|
* @param {Array<any>} options.args The arguments of the step.
|
|
55
50
|
*/
|
|
@@ -60,13 +55,44 @@ class JSONTraversalStep extends VisitNodeStep {
|
|
|
60
55
|
}
|
|
61
56
|
}
|
|
62
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Processes tokens to extract comments and their starting tokens.
|
|
60
|
+
* @param {Array<Token>} tokens The tokens to process.
|
|
61
|
+
* @returns {{ comments: Array<Token>, starts: Map<number, number>, ends: Map<number, number>}}
|
|
62
|
+
* An object containing an array of comments, a map of starting token range to token index, and
|
|
63
|
+
* a map of ending token range to token index.
|
|
64
|
+
*/
|
|
65
|
+
function processTokens(tokens) {
|
|
66
|
+
/** @type {Array<Token>} */
|
|
67
|
+
const comments = [];
|
|
68
|
+
|
|
69
|
+
/** @type {Map<number, number>} */
|
|
70
|
+
const starts = new Map();
|
|
71
|
+
|
|
72
|
+
/** @type {Map<number, number>} */
|
|
73
|
+
const ends = new Map();
|
|
74
|
+
|
|
75
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
76
|
+
const token = tokens[i];
|
|
77
|
+
|
|
78
|
+
if (token.type.endsWith("Comment")) {
|
|
79
|
+
comments.push(token);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
starts.set(token.range[0], i);
|
|
83
|
+
ends.set(token.range[1], i);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { comments, starts, ends };
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
//-----------------------------------------------------------------------------
|
|
64
90
|
// Exports
|
|
65
91
|
//-----------------------------------------------------------------------------
|
|
66
92
|
|
|
67
93
|
/**
|
|
68
94
|
* JSON Source Code Object
|
|
69
|
-
* @
|
|
95
|
+
* @extends {TextSourceCodeBase<{LangOptions: JSONLanguageOptions, RootNode: DocumentNode, SyntaxElementWithLoc: JSONSyntaxElement, ConfigNode: Token}>}
|
|
70
96
|
*/
|
|
71
97
|
class JSONSourceCode extends TextSourceCodeBase {
|
|
72
98
|
/**
|
|
@@ -77,13 +103,13 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
77
103
|
|
|
78
104
|
/**
|
|
79
105
|
* Cache of parent nodes.
|
|
80
|
-
* @type {WeakMap<
|
|
106
|
+
* @type {WeakMap<AnyNode, AnyNode>}
|
|
81
107
|
*/
|
|
82
108
|
#parents = new WeakMap();
|
|
83
109
|
|
|
84
110
|
/**
|
|
85
111
|
* Collection of inline configuration comments.
|
|
86
|
-
* @type {Array<
|
|
112
|
+
* @type {Array<Token>}
|
|
87
113
|
*/
|
|
88
114
|
#inlineConfigComments;
|
|
89
115
|
|
|
@@ -94,11 +120,23 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
94
120
|
ast = undefined;
|
|
95
121
|
|
|
96
122
|
/**
|
|
97
|
-
* The comment
|
|
98
|
-
* @type {Array<
|
|
123
|
+
* The comment tokens in the source code.
|
|
124
|
+
* @type {Array<Token>|undefined}
|
|
99
125
|
*/
|
|
100
126
|
comments;
|
|
101
127
|
|
|
128
|
+
/**
|
|
129
|
+
* A map of token start positions to their corresponding index.
|
|
130
|
+
* @type {Map<number, number>}
|
|
131
|
+
*/
|
|
132
|
+
#tokenStarts;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A map of token end positions to their corresponding index.
|
|
136
|
+
* @type {Map<number, number>}
|
|
137
|
+
*/
|
|
138
|
+
#tokenEnds;
|
|
139
|
+
|
|
102
140
|
/**
|
|
103
141
|
* Creates a new instance.
|
|
104
142
|
* @param {Object} options The options for the instance.
|
|
@@ -108,14 +146,16 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
108
146
|
constructor({ text, ast }) {
|
|
109
147
|
super({ text, ast });
|
|
110
148
|
this.ast = ast;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
149
|
+
|
|
150
|
+
const { comments, starts, ends } = processTokens(this.ast.tokens ?? []);
|
|
151
|
+
this.comments = comments;
|
|
152
|
+
this.#tokenStarts = starts;
|
|
153
|
+
this.#tokenEnds = ends;
|
|
114
154
|
}
|
|
115
155
|
|
|
116
156
|
/**
|
|
117
157
|
* Returns the value of the given comment.
|
|
118
|
-
* @param {
|
|
158
|
+
* @param {Token} comment The comment to get the value of.
|
|
119
159
|
* @returns {string} The value of the comment.
|
|
120
160
|
* @throws {Error} When an unexpected comment type is passed.
|
|
121
161
|
*/
|
|
@@ -134,7 +174,7 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
134
174
|
/**
|
|
135
175
|
* Returns an array of all inline configuration nodes found in the
|
|
136
176
|
* source code.
|
|
137
|
-
* @returns {Array<
|
|
177
|
+
* @returns {Array<Token>} An array of all inline configuration nodes.
|
|
138
178
|
*/
|
|
139
179
|
getInlineConfigNodes() {
|
|
140
180
|
if (!this.#inlineConfigComments) {
|
|
@@ -245,8 +285,8 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
245
285
|
|
|
246
286
|
/**
|
|
247
287
|
* Returns the parent of the given node.
|
|
248
|
-
* @param {
|
|
249
|
-
* @returns {
|
|
288
|
+
* @param {AnyNode} node The node to get the parent of.
|
|
289
|
+
* @returns {AnyNode|undefined} The parent of the node.
|
|
250
290
|
*/
|
|
251
291
|
getParent(node) {
|
|
252
292
|
return this.#parents.get(node);
|
|
@@ -267,12 +307,15 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
267
307
|
|
|
268
308
|
for (const { node, parent, phase } of iterator(this.ast)) {
|
|
269
309
|
if (parent) {
|
|
270
|
-
this.#parents.set(
|
|
310
|
+
this.#parents.set(
|
|
311
|
+
/** @type {AnyNode} */ (node),
|
|
312
|
+
/** @type {AnyNode} */ (parent),
|
|
313
|
+
);
|
|
271
314
|
}
|
|
272
315
|
|
|
273
316
|
steps.push(
|
|
274
317
|
new JSONTraversalStep({
|
|
275
|
-
target: node,
|
|
318
|
+
target: /** @type {AnyNode} */ (node),
|
|
276
319
|
phase: phase === "enter" ? 1 : 2,
|
|
277
320
|
args: [node, parent],
|
|
278
321
|
}),
|
|
@@ -281,10 +324,89 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
281
324
|
|
|
282
325
|
return steps;
|
|
283
326
|
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Gets the token before the given node or token, optionally including comments.
|
|
330
|
+
* @param {AnyNode|Token} nodeOrToken The node or token to get the previous token for.
|
|
331
|
+
* @param {Object} [options] Options object.
|
|
332
|
+
* @param {boolean} [options.includeComments] If true, return comments when they are present.
|
|
333
|
+
* @returns {Token|null} The previous token or comment, or null if there is none.
|
|
334
|
+
*/
|
|
335
|
+
getTokenBefore(nodeOrToken, { includeComments = false } = {}) {
|
|
336
|
+
const index = this.#tokenStarts.get(nodeOrToken.range[0]);
|
|
337
|
+
|
|
338
|
+
if (index === undefined) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
let previousIndex = index - 1;
|
|
343
|
+
if (previousIndex < 0) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const tokens = this.ast.tokens;
|
|
348
|
+
let tokenOrComment = tokens[previousIndex];
|
|
349
|
+
|
|
350
|
+
if (includeComments) {
|
|
351
|
+
return tokenOrComment;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// skip comments
|
|
355
|
+
while (tokenOrComment?.type.endsWith("Comment")) {
|
|
356
|
+
previousIndex--;
|
|
357
|
+
|
|
358
|
+
if (previousIndex < 0) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
tokenOrComment = tokens[previousIndex];
|
|
363
|
+
}
|
|
364
|
+
return tokenOrComment;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Gets the token after the given node or token, skipping any comments unless includeComments is true.
|
|
369
|
+
* @param {AnyNode|Token} nodeOrToken The node or token to get the next token for.
|
|
370
|
+
* @param {Object} [options] Options object.
|
|
371
|
+
* @param {boolean} [options.includeComments=false] If true, return comments when they are present.
|
|
372
|
+
* @returns {Token|null} The next token or comment, or null if there is none.
|
|
373
|
+
*/
|
|
374
|
+
getTokenAfter(nodeOrToken, { includeComments = false } = {}) {
|
|
375
|
+
const index = this.#tokenEnds.get(nodeOrToken.range[1]);
|
|
376
|
+
|
|
377
|
+
if (index === undefined) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let nextIndex = index + 1;
|
|
382
|
+
const tokens = this.ast.tokens;
|
|
383
|
+
if (nextIndex >= tokens.length) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
let tokenOrComment = tokens[nextIndex];
|
|
388
|
+
|
|
389
|
+
if (includeComments) {
|
|
390
|
+
return tokenOrComment;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// skip comments
|
|
394
|
+
while (tokenOrComment?.type.endsWith("Comment")) {
|
|
395
|
+
nextIndex++;
|
|
396
|
+
|
|
397
|
+
if (nextIndex >= tokens.length) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
tokenOrComment = tokens[nextIndex];
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return tokenOrComment;
|
|
405
|
+
}
|
|
284
406
|
}
|
|
285
407
|
|
|
286
408
|
/**
|
|
287
|
-
* @
|
|
409
|
+
* @fileoverview The JSONLanguage class.
|
|
288
410
|
* @author Nicholas C. Zakas
|
|
289
411
|
*/
|
|
290
412
|
|
|
@@ -293,11 +415,14 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
293
415
|
// Types
|
|
294
416
|
//-----------------------------------------------------------------------------
|
|
295
417
|
|
|
296
|
-
/**
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
418
|
+
/**
|
|
419
|
+
*
|
|
420
|
+
* @typedef {OkParseResult<DocumentNode>} JSONOkParseResult
|
|
421
|
+
* @typedef {ParseResult<DocumentNode>} JSONParseResult
|
|
422
|
+
*
|
|
423
|
+
* @typedef {Object} JSONLanguageOptions
|
|
424
|
+
* @property {boolean} [allowTrailingCommas] Whether to allow trailing commas in JSONC mode.
|
|
425
|
+
*/
|
|
301
426
|
|
|
302
427
|
//-----------------------------------------------------------------------------
|
|
303
428
|
// Exports
|
|
@@ -305,7 +430,7 @@ class JSONSourceCode extends TextSourceCodeBase {
|
|
|
305
430
|
|
|
306
431
|
/**
|
|
307
432
|
* JSON Language Object
|
|
308
|
-
* @implements {
|
|
433
|
+
* @implements {Language<{ LangOptions: JSONLanguageOptions; Code: JSONSourceCode; RootNode: DocumentNode; Node: AnyNode }>}
|
|
309
434
|
*/
|
|
310
435
|
class JSONLanguage {
|
|
311
436
|
/**
|
|
@@ -382,7 +507,7 @@ class JSONLanguage {
|
|
|
382
507
|
* Parses the given file into an AST.
|
|
383
508
|
* @param {File} file The virtual file to parse.
|
|
384
509
|
* @param {{languageOptions: JSONLanguageOptions}} context The options to use for parsing.
|
|
385
|
-
* @returns {
|
|
510
|
+
* @returns {JSONParseResult} The result of parsing.
|
|
386
511
|
*/
|
|
387
512
|
parse(file, context) {
|
|
388
513
|
// Note: BOM already removed
|
|
@@ -430,7 +555,7 @@ class JSONLanguage {
|
|
|
430
555
|
/**
|
|
431
556
|
* Creates a new `JSONSourceCode` object from the given information.
|
|
432
557
|
* @param {File} file The virtual file to create a `JSONSourceCode` object from.
|
|
433
|
-
* @param {
|
|
558
|
+
* @param {JSONOkParseResult} parseResult The result returned from `parse()`.
|
|
434
559
|
* @returns {JSONSourceCode} The new `JSONSourceCode` object.
|
|
435
560
|
*/
|
|
436
561
|
createSourceCode(file, parseResult) {
|
|
@@ -442,6 +567,13 @@ class JSONLanguage {
|
|
|
442
567
|
/* eslint-enable class-methods-use-this -- Required to complete interface. */
|
|
443
568
|
}
|
|
444
569
|
|
|
570
|
+
const rules$1 = /** @type {const} */ ({
|
|
571
|
+
"json/no-duplicate-keys": "error",
|
|
572
|
+
"json/no-empty-keys": "error",
|
|
573
|
+
"json/no-unnormalized-keys": "error",
|
|
574
|
+
"json/no-unsafe-values": "error"
|
|
575
|
+
});
|
|
576
|
+
|
|
445
577
|
/**
|
|
446
578
|
* @fileoverview Rule to prevent duplicate keys in JSON.
|
|
447
579
|
* @author Nicholas C. Zakas
|
|
@@ -451,9 +583,11 @@ class JSONLanguage {
|
|
|
451
583
|
// Type Definitions
|
|
452
584
|
//-----------------------------------------------------------------------------
|
|
453
585
|
|
|
454
|
-
/**
|
|
455
|
-
|
|
456
|
-
|
|
586
|
+
/**
|
|
587
|
+
*
|
|
588
|
+
* @typedef {"duplicateKey"} NoDuplicateKeysMessageIds
|
|
589
|
+
* @typedef {JSONRuleDefinition<{ MessageIds: NoDuplicateKeysMessageIds }>} NoDuplicateKeysRuleDefinition
|
|
590
|
+
*/
|
|
457
591
|
|
|
458
592
|
//-----------------------------------------------------------------------------
|
|
459
593
|
// Rule Definition
|
|
@@ -465,7 +599,9 @@ const rule$5 = {
|
|
|
465
599
|
type: "problem",
|
|
466
600
|
|
|
467
601
|
docs: {
|
|
602
|
+
recommended: true,
|
|
468
603
|
description: "Disallow duplicate keys in JSON objects",
|
|
604
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/no-duplicate-keys.md",
|
|
469
605
|
},
|
|
470
606
|
|
|
471
607
|
messages: {
|
|
@@ -520,8 +656,11 @@ const rule$5 = {
|
|
|
520
656
|
// Type Definitions
|
|
521
657
|
//-----------------------------------------------------------------------------
|
|
522
658
|
|
|
523
|
-
/**
|
|
524
|
-
|
|
659
|
+
/**
|
|
660
|
+
*
|
|
661
|
+
* @typedef {"emptyKey"} NoEmptyKeysMessageIds
|
|
662
|
+
* @typedef {JSONRuleDefinition<{ MessageIds: NoEmptyKeysMessageIds }>} NoEmptyKeysRuleDefinition
|
|
663
|
+
*/
|
|
525
664
|
|
|
526
665
|
//-----------------------------------------------------------------------------
|
|
527
666
|
// Rule Definition
|
|
@@ -533,7 +672,9 @@ const rule$4 = {
|
|
|
533
672
|
type: "problem",
|
|
534
673
|
|
|
535
674
|
docs: {
|
|
675
|
+
recommended: true,
|
|
536
676
|
description: "Disallow empty keys in JSON objects",
|
|
677
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/no-empty-keys.md",
|
|
537
678
|
},
|
|
538
679
|
|
|
539
680
|
messages: {
|
|
@@ -560,6 +701,80 @@ const rule$4 = {
|
|
|
560
701
|
},
|
|
561
702
|
};
|
|
562
703
|
|
|
704
|
+
/**
|
|
705
|
+
* @fileoverview Rule to detect unnormalized keys in JSON.
|
|
706
|
+
* @author Bradley Meck Farias
|
|
707
|
+
*/
|
|
708
|
+
|
|
709
|
+
//-----------------------------------------------------------------------------
|
|
710
|
+
// Type Definitions
|
|
711
|
+
//-----------------------------------------------------------------------------
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
*
|
|
715
|
+
* @typedef {"unnormalizedKey"} NoUnnormalizedKeysMessageIds
|
|
716
|
+
* @typedef {{ form: string }} NoUnnormalizedKeysOptions
|
|
717
|
+
* @typedef {JSONRuleDefinition<{ RuleOptions: [NoUnnormalizedKeysOptions], MessageIds: NoUnnormalizedKeysMessageIds }>} NoUnnormalizedKeysRuleDefinition
|
|
718
|
+
*/
|
|
719
|
+
|
|
720
|
+
//-----------------------------------------------------------------------------
|
|
721
|
+
// Rule Definition
|
|
722
|
+
//-----------------------------------------------------------------------------
|
|
723
|
+
|
|
724
|
+
/** @type {NoUnnormalizedKeysRuleDefinition} */
|
|
725
|
+
const rule$3 = {
|
|
726
|
+
meta: {
|
|
727
|
+
type: "problem",
|
|
728
|
+
|
|
729
|
+
docs: {
|
|
730
|
+
recommended: true,
|
|
731
|
+
description: "Disallow JSON keys that are not normalized",
|
|
732
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/no-unnormalized-keys.md",
|
|
733
|
+
},
|
|
734
|
+
|
|
735
|
+
messages: {
|
|
736
|
+
unnormalizedKey: "Unnormalized key '{{key}}' found.",
|
|
737
|
+
},
|
|
738
|
+
|
|
739
|
+
schema: [
|
|
740
|
+
{
|
|
741
|
+
type: "object",
|
|
742
|
+
properties: {
|
|
743
|
+
form: {
|
|
744
|
+
enum: ["NFC", "NFD", "NFKC", "NFKD"],
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
additionalProperties: false,
|
|
748
|
+
},
|
|
749
|
+
],
|
|
750
|
+
},
|
|
751
|
+
|
|
752
|
+
create(context) {
|
|
753
|
+
const form = context.options.length
|
|
754
|
+
? context.options[0].form
|
|
755
|
+
: undefined;
|
|
756
|
+
|
|
757
|
+
return {
|
|
758
|
+
Member(node) {
|
|
759
|
+
const key =
|
|
760
|
+
node.name.type === "String"
|
|
761
|
+
? node.name.value
|
|
762
|
+
: node.name.name;
|
|
763
|
+
|
|
764
|
+
if (key.normalize(form) !== key) {
|
|
765
|
+
context.report({
|
|
766
|
+
loc: node.name.loc,
|
|
767
|
+
messageId: "unnormalizedKey",
|
|
768
|
+
data: {
|
|
769
|
+
key,
|
|
770
|
+
},
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
};
|
|
775
|
+
},
|
|
776
|
+
};
|
|
777
|
+
|
|
563
778
|
/**
|
|
564
779
|
* @fileoverview Rule to detect unsafe values in JSON.
|
|
565
780
|
* @author Bradley Meck Farias
|
|
@@ -569,8 +784,11 @@ const rule$4 = {
|
|
|
569
784
|
// Type Definitions
|
|
570
785
|
//-----------------------------------------------------------------------------
|
|
571
786
|
|
|
572
|
-
/**
|
|
573
|
-
|
|
787
|
+
/**
|
|
788
|
+
*
|
|
789
|
+
* @typedef {"unsafeNumber"|"unsafeInteger"|"unsafeZero"|"subnormal"|"loneSurrogate"} NoUnsafeValuesMessageIds
|
|
790
|
+
* @typedef {JSONRuleDefinition<{ MessageIds: NoUnsafeValuesMessageIds }>} NoUnsafeValuesRuleDefinition
|
|
791
|
+
*/
|
|
574
792
|
|
|
575
793
|
//-----------------------------------------------------------------------------
|
|
576
794
|
// Helpers
|
|
@@ -592,12 +810,14 @@ const NON_ZERO = /[1-9]/u;
|
|
|
592
810
|
//-----------------------------------------------------------------------------
|
|
593
811
|
|
|
594
812
|
/** @type {NoUnsafeValuesRuleDefinition} */
|
|
595
|
-
const rule$
|
|
813
|
+
const rule$2 = {
|
|
596
814
|
meta: {
|
|
597
815
|
type: "problem",
|
|
598
816
|
|
|
599
817
|
docs: {
|
|
818
|
+
recommended: true,
|
|
600
819
|
description: "Disallow JSON values that are unsafe for interchange",
|
|
820
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/no-unsafe-values.md",
|
|
601
821
|
},
|
|
602
822
|
|
|
603
823
|
messages: {
|
|
@@ -708,74 +928,6 @@ const rule$3 = {
|
|
|
708
928
|
},
|
|
709
929
|
};
|
|
710
930
|
|
|
711
|
-
/**
|
|
712
|
-
* @fileoverview Rule to detect unnormalized keys in JSON.
|
|
713
|
-
* @author Bradley Meck Farias
|
|
714
|
-
*/
|
|
715
|
-
|
|
716
|
-
//-----------------------------------------------------------------------------
|
|
717
|
-
// Type Definitions
|
|
718
|
-
//-----------------------------------------------------------------------------
|
|
719
|
-
|
|
720
|
-
/** @typedef {"unnormalizedKey"} NoUnnormalizedKeysMessageIds */
|
|
721
|
-
/** @typedef {import("./types.ts").JSONRuleDefinition<[{form:string}], NoUnnormalizedKeysMessageIds>} NoUnnormalizedKeysRuleDefinition */
|
|
722
|
-
|
|
723
|
-
//-----------------------------------------------------------------------------
|
|
724
|
-
// Rule Definition
|
|
725
|
-
//-----------------------------------------------------------------------------
|
|
726
|
-
|
|
727
|
-
/** @type {NoUnnormalizedKeysRuleDefinition} */
|
|
728
|
-
const rule$2 = {
|
|
729
|
-
meta: {
|
|
730
|
-
type: "problem",
|
|
731
|
-
|
|
732
|
-
docs: {
|
|
733
|
-
description: "Disallow JSON keys that are not normalized",
|
|
734
|
-
},
|
|
735
|
-
|
|
736
|
-
messages: {
|
|
737
|
-
unnormalizedKey: "Unnormalized key '{{key}}' found.",
|
|
738
|
-
},
|
|
739
|
-
|
|
740
|
-
schema: [
|
|
741
|
-
{
|
|
742
|
-
type: "object",
|
|
743
|
-
properties: {
|
|
744
|
-
form: {
|
|
745
|
-
enum: ["NFC", "NFD", "NFKC", "NFKD"],
|
|
746
|
-
},
|
|
747
|
-
},
|
|
748
|
-
additionalProperties: false,
|
|
749
|
-
},
|
|
750
|
-
],
|
|
751
|
-
},
|
|
752
|
-
|
|
753
|
-
create(context) {
|
|
754
|
-
const form = context.options.length
|
|
755
|
-
? context.options[0].form
|
|
756
|
-
: undefined;
|
|
757
|
-
|
|
758
|
-
return {
|
|
759
|
-
Member(node) {
|
|
760
|
-
const key =
|
|
761
|
-
node.name.type === "String"
|
|
762
|
-
? node.name.value
|
|
763
|
-
: node.name.name;
|
|
764
|
-
|
|
765
|
-
if (key.normalize(form) !== key) {
|
|
766
|
-
context.report({
|
|
767
|
-
loc: node.name.loc,
|
|
768
|
-
messageId: "unnormalizedKey",
|
|
769
|
-
data: {
|
|
770
|
-
key,
|
|
771
|
-
},
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
},
|
|
775
|
-
};
|
|
776
|
-
},
|
|
777
|
-
};
|
|
778
|
-
|
|
779
931
|
/**
|
|
780
932
|
* @fileoverview Rule to require JSON object keys to be sorted.
|
|
781
933
|
* Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
|
|
@@ -787,21 +939,21 @@ const rule$2 = {
|
|
|
787
939
|
// Type Definitions
|
|
788
940
|
//-----------------------------------------------------------------------------
|
|
789
941
|
|
|
790
|
-
/** @typedef {"sortKeys"} SortKeysMessageIds */
|
|
791
|
-
|
|
792
942
|
/**
|
|
943
|
+
*
|
|
793
944
|
* @typedef {Object} SortOptions
|
|
794
945
|
* @property {boolean} caseSensitive
|
|
795
946
|
* @property {boolean} natural
|
|
796
947
|
* @property {number} minKeys
|
|
797
948
|
* @property {boolean} allowLineSeparatedGroups
|
|
949
|
+
*
|
|
950
|
+
* @typedef {"sortKeys"} SortKeysMessageIds
|
|
951
|
+
* @typedef {"asc"|"desc"} SortDirection
|
|
952
|
+
* @typedef {[SortDirection, SortOptions]} SortKeysRuleOptions
|
|
953
|
+
* @typedef {JSONRuleDefinition<{ RuleOptions: SortKeysRuleOptions, MessageIds: SortKeysMessageIds }>} SortKeysRuleDefinition
|
|
954
|
+
* @typedef {(a:string,b:string) => boolean} Comparator
|
|
798
955
|
*/
|
|
799
956
|
|
|
800
|
-
/** @typedef {"asc"|"desc"} SortDirection */
|
|
801
|
-
/** @typedef {[SortDirection, SortOptions]} SortKeysRuleOptions */
|
|
802
|
-
/** @typedef {import("./types.ts").JSONRuleDefinition<SortKeysRuleOptions, SortKeysMessageIds>} SortKeysRuleDefinition */
|
|
803
|
-
/** @typedef {(a:string,b:string) => boolean} Comparator */
|
|
804
|
-
|
|
805
957
|
//-----------------------------------------------------------------------------
|
|
806
958
|
// Helpers
|
|
807
959
|
//-----------------------------------------------------------------------------
|
|
@@ -878,7 +1030,9 @@ const rule$1 = {
|
|
|
878
1030
|
],
|
|
879
1031
|
|
|
880
1032
|
docs: {
|
|
1033
|
+
recommended: false,
|
|
881
1034
|
description: `Require JSON object keys to be sorted`,
|
|
1035
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/sort-keys.md",
|
|
882
1036
|
},
|
|
883
1037
|
|
|
884
1038
|
messages: {
|
|
@@ -1007,7 +1161,7 @@ const rule$1 = {
|
|
|
1007
1161
|
};
|
|
1008
1162
|
|
|
1009
1163
|
/**
|
|
1010
|
-
* @fileoverview Rule to ensure top-level items are either an array or
|
|
1164
|
+
* @fileoverview Rule to ensure top-level items are either an array or object.
|
|
1011
1165
|
* @author Joe Hildebrand
|
|
1012
1166
|
*/
|
|
1013
1167
|
|
|
@@ -1015,8 +1169,11 @@ const rule$1 = {
|
|
|
1015
1169
|
// Type Definitions
|
|
1016
1170
|
//-----------------------------------------------------------------------------
|
|
1017
1171
|
|
|
1018
|
-
/**
|
|
1019
|
-
|
|
1172
|
+
/**
|
|
1173
|
+
*
|
|
1174
|
+
* @typedef {"topLevel"} TopLevelInteropMessageIds
|
|
1175
|
+
* @typedef {JSONRuleDefinition<{ MessageIds: TopLevelInteropMessageIds }>} TopLevelInteropRuleDefinition
|
|
1176
|
+
*/
|
|
1020
1177
|
|
|
1021
1178
|
//-----------------------------------------------------------------------------
|
|
1022
1179
|
// Rule Definition
|
|
@@ -1028,8 +1185,10 @@ const rule = {
|
|
|
1028
1185
|
type: "problem",
|
|
1029
1186
|
|
|
1030
1187
|
docs: {
|
|
1188
|
+
recommended: false,
|
|
1031
1189
|
description:
|
|
1032
1190
|
"Require the JSON top-level value to be an array or object",
|
|
1191
|
+
url: "https://github.com/eslint/json/tree/main/docs/rules/top-level-interop.md",
|
|
1033
1192
|
},
|
|
1034
1193
|
|
|
1035
1194
|
messages: {
|
|
@@ -1054,6 +1213,15 @@ const rule = {
|
|
|
1054
1213
|
},
|
|
1055
1214
|
};
|
|
1056
1215
|
|
|
1216
|
+
var rules = {
|
|
1217
|
+
"no-duplicate-keys": rule$5,
|
|
1218
|
+
"no-empty-keys": rule$4,
|
|
1219
|
+
"no-unnormalized-keys": rule$3,
|
|
1220
|
+
"no-unsafe-values": rule$2,
|
|
1221
|
+
"sort-keys": rule$1,
|
|
1222
|
+
"top-level-interop": rule,
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1057
1225
|
/**
|
|
1058
1226
|
* @fileoverview JSON plugin.
|
|
1059
1227
|
* @author Nicholas C. Zakas
|
|
@@ -1067,30 +1235,18 @@ const rule = {
|
|
|
1067
1235
|
const plugin = {
|
|
1068
1236
|
meta: {
|
|
1069
1237
|
name: "@eslint/json",
|
|
1070
|
-
version: "0.
|
|
1238
|
+
version: "0.13.0", // x-release-please-version
|
|
1071
1239
|
},
|
|
1072
1240
|
languages: {
|
|
1073
1241
|
json: new JSONLanguage({ mode: "json" }),
|
|
1074
1242
|
jsonc: new JSONLanguage({ mode: "jsonc" }),
|
|
1075
1243
|
json5: new JSONLanguage({ mode: "json5" }),
|
|
1076
1244
|
},
|
|
1077
|
-
rules
|
|
1078
|
-
"no-duplicate-keys": rule$5,
|
|
1079
|
-
"no-empty-keys": rule$4,
|
|
1080
|
-
"no-unsafe-values": rule$3,
|
|
1081
|
-
"no-unnormalized-keys": rule$2,
|
|
1082
|
-
"sort-keys": rule$1,
|
|
1083
|
-
"top-level-interop": rule,
|
|
1084
|
-
},
|
|
1245
|
+
rules,
|
|
1085
1246
|
configs: {
|
|
1086
1247
|
recommended: {
|
|
1087
1248
|
plugins: {},
|
|
1088
|
-
rules:
|
|
1089
|
-
"json/no-duplicate-keys": "error",
|
|
1090
|
-
"json/no-empty-keys": "error",
|
|
1091
|
-
"json/no-unsafe-values": "error",
|
|
1092
|
-
"json/no-unnormalized-keys": "error",
|
|
1093
|
-
}),
|
|
1249
|
+
rules: rules$1,
|
|
1094
1250
|
},
|
|
1095
1251
|
},
|
|
1096
1252
|
};
|