@eslint/json 0.9.1 → 0.11.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/dist/esm/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // @ts-self-types="./index.d.ts"
2
2
  import { iterator, visitorKeys, parse } from '@humanwhocodes/momoa';
3
3
  import { ConfigCommentParser, TextSourceCodeBase, Directive, VisitNodeStep } from '@eslint/plugin-kit';
4
+ import naturalCompare from 'natural-compare';
4
5
 
5
6
  /**
6
7
  * @fileoverview The JSONSourceCode class.
@@ -19,11 +20,12 @@ import { ConfigCommentParser, TextSourceCodeBase, Directive, VisitNodeStep } fro
19
20
  /** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
20
21
  /** @typedef {import("@eslint/core").File} File */
21
22
  /** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
22
- /** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
23
23
  /** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
24
24
  /** @typedef {import("@eslint/core").FileProblem} FileProblem */
25
25
  /** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
26
26
  /** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
27
+ /** @typedef {import("./types.ts").IJSONSourceCode} IJSONSourceCode */
28
+ /** @typedef {import("./types.ts").JSONSyntaxElement} JSONSyntaxElement */
27
29
 
28
30
  //-----------------------------------------------------------------------------
29
31
  // Helpers
@@ -64,6 +66,7 @@ class JSONTraversalStep extends VisitNodeStep {
64
66
 
65
67
  /**
66
68
  * JSON Source Code Object
69
+ * @implements {IJSONSourceCode}
67
70
  */
68
71
  class JSONSourceCode extends TextSourceCodeBase {
69
72
  /**
@@ -140,7 +143,7 @@ class JSONSourceCode extends TextSourceCodeBase {
140
143
  );
141
144
  }
142
145
 
143
- return this.#inlineConfigComments;
146
+ return this.#inlineConfigComments ?? [];
144
147
  }
145
148
 
146
149
  /**
@@ -293,10 +296,8 @@ class JSONSourceCode extends TextSourceCodeBase {
293
296
  /** @typedef {import("@eslint/core").Language} Language */
294
297
  /** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
295
298
  /** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
296
- /**
297
- * @typedef {Object} JSONLanguageOptions
298
- * @property {boolean} [allowTrailingCommas] Whether to allow trailing commas.
299
- */
299
+ /** @typedef {import("./types.ts").IJSONLanguage} IJSONLanguage */
300
+ /** @typedef {import("./types.ts").JSONLanguageOptions} JSONLanguageOptions */
300
301
 
301
302
  //-----------------------------------------------------------------------------
302
303
  // Exports
@@ -304,7 +305,7 @@ class JSONSourceCode extends TextSourceCodeBase {
304
305
 
305
306
  /**
306
307
  * JSON Language Object
307
- * @implements {Language}
308
+ * @implements {IJSONLanguage}
308
309
  */
309
310
  class JSONLanguage {
310
311
  /**
@@ -446,13 +447,22 @@ class JSONLanguage {
446
447
  * @author Nicholas C. Zakas
447
448
  */
448
449
 
450
+ //-----------------------------------------------------------------------------
451
+ // Type Definitions
452
+ //-----------------------------------------------------------------------------
453
+
454
+ /** @typedef {"duplicateKey"} NoDuplicateKeysMessageIds */
455
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoDuplicateKeysMessageIds>} NoDuplicateKeysRuleDefinition */
456
+ /** @typedef {import("@humanwhocodes/momoa").MemberNode} MemberNode */
457
+
449
458
  //-----------------------------------------------------------------------------
450
459
  // Rule Definition
451
460
  //-----------------------------------------------------------------------------
452
461
 
453
- var noDuplicateKeys = {
462
+ /** @type {NoDuplicateKeysRuleDefinition} */
463
+ const rule$5 = {
454
464
  meta: {
455
- type: /** @type {const} */ ("problem"),
465
+ type: "problem",
456
466
 
457
467
  docs: {
458
468
  description: "Disallow duplicate keys in JSON objects",
@@ -464,7 +474,10 @@ var noDuplicateKeys = {
464
474
  },
465
475
 
466
476
  create(context) {
477
+ /** @type {Array<Map<string, MemberNode>|undefined>} */
467
478
  const objectKeys = [];
479
+
480
+ /** @type {Map<string, MemberNode>|undefined} */
468
481
  let keys;
469
482
 
470
483
  return {
@@ -503,9 +516,21 @@ var noDuplicateKeys = {
503
516
  * @author Nicholas C. Zakas
504
517
  */
505
518
 
506
- var noEmptyKeys = {
519
+ //-----------------------------------------------------------------------------
520
+ // Type Definitions
521
+ //-----------------------------------------------------------------------------
522
+
523
+ /** @typedef {"emptyKey"} NoEmptyKeysMessageIds */
524
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoEmptyKeysMessageIds>} NoEmptyKeysRuleDefinition */
525
+
526
+ //-----------------------------------------------------------------------------
527
+ // Rule Definition
528
+ //-----------------------------------------------------------------------------
529
+
530
+ /** @type {NoEmptyKeysRuleDefinition} */
531
+ const rule$4 = {
507
532
  meta: {
508
- type: /** @type {const} */ ("problem"),
533
+ type: "problem",
509
534
 
510
535
  docs: {
511
536
  description: "Disallow empty keys in JSON objects",
@@ -540,15 +565,36 @@ var noEmptyKeys = {
540
565
  * @author Bradley Meck Farias
541
566
  */
542
567
 
543
- // RFC 8259's `number` production, as a regex. Capture the integer part
544
- // and the fractional part.
568
+ //-----------------------------------------------------------------------------
569
+ // Type Definitions
570
+ //-----------------------------------------------------------------------------
571
+
572
+ /** @typedef {"unsafeNumber"|"unsafeInteger"|"unsafeZero"|"subnormal"|"loneSurrogate"} NoUnsafeValuesMessageIds */
573
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoUnsafeValuesMessageIds>} NoUnsafeValuesRuleDefinition */
574
+
575
+ //-----------------------------------------------------------------------------
576
+ // Helpers
577
+ //-----------------------------------------------------------------------------
578
+
579
+ /*
580
+ * This rule is based on the JSON grammar from RFC 8259, section 6.
581
+ * https://tools.ietf.org/html/rfc8259#section-6
582
+ *
583
+ * We separately capture the integer and fractional parts of a number, so that
584
+ * we can check for unsafe numbers that will evaluate to Infinity.
585
+ */
545
586
  const NUMBER =
546
587
  /^-?(?<int>0|([1-9][0-9]*))(?:\.(?<frac>[0-9]+))?(?:[eE][+-]?[0-9]+)?$/u;
547
588
  const NON_ZERO = /[1-9]/u;
548
589
 
549
- var noUnsafeValues = {
590
+ //-----------------------------------------------------------------------------
591
+ // Rule Definition
592
+ //-----------------------------------------------------------------------------
593
+
594
+ /** @type {NoUnsafeValuesRuleDefinition} */
595
+ const rule$3 = {
550
596
  meta: {
551
- type: /** @type {const} */ ("problem"),
597
+ type: "problem",
552
598
 
553
599
  docs: {
554
600
  description: "Disallow JSON values that are unsafe for interchange",
@@ -622,7 +668,9 @@ var noUnsafeValues = {
622
668
  loc: node.loc,
623
669
  messageId: "subnormal",
624
670
  // Value included so that it's seen in scientific notation
625
- data: node,
671
+ data: {
672
+ value,
673
+ },
626
674
  });
627
675
  }
628
676
  }
@@ -665,9 +713,21 @@ var noUnsafeValues = {
665
713
  * @author Bradley Meck Farias
666
714
  */
667
715
 
668
- var noUnnormalizedKeys = {
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 = {
669
729
  meta: {
670
- type: /** @type {const} */ ("problem"),
730
+ type: "problem",
671
731
 
672
732
  docs: {
673
733
  description: "Disallow JSON keys that are not normalized",
@@ -691,9 +751,10 @@ var noUnnormalizedKeys = {
691
751
  },
692
752
 
693
753
  create(context) {
694
- const normalization = context.options.length
695
- ? text => text.normalize(context.options[0].form)
696
- : text => text.normalize();
754
+ const form = context.options.length
755
+ ? context.options[0].form
756
+ : undefined;
757
+
697
758
  return {
698
759
  Member(node) {
699
760
  const key =
@@ -701,7 +762,7 @@ var noUnnormalizedKeys = {
701
762
  ? node.name.value
702
763
  : node.name.name;
703
764
 
704
- if (normalization(key) !== key) {
765
+ if (key.normalize(form) !== key) {
705
766
  context.report({
706
767
  loc: node.name.loc,
707
768
  messageId: "unnormalizedKey",
@@ -715,14 +776,256 @@ var noUnnormalizedKeys = {
715
776
  },
716
777
  };
717
778
 
779
+ /**
780
+ * @fileoverview Rule to require JSON object keys to be sorted.
781
+ * Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
782
+ * @author Robin Thomas
783
+ */
784
+
785
+
786
+ //-----------------------------------------------------------------------------
787
+ // Type Definitions
788
+ //-----------------------------------------------------------------------------
789
+
790
+ /** @typedef {"sortKeys"} SortKeysMessageIds */
791
+
792
+ /**
793
+ * @typedef {Object} SortOptions
794
+ * @property {boolean} caseSensitive
795
+ * @property {boolean} natural
796
+ * @property {number} minKeys
797
+ * @property {boolean} allowLineSeparatedGroups
798
+ */
799
+
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
+ //-----------------------------------------------------------------------------
806
+ // Helpers
807
+ //-----------------------------------------------------------------------------
808
+
809
+ const hasNonWhitespace = /\S/u;
810
+
811
+ const comparators = {
812
+ ascending: {
813
+ alphanumeric: {
814
+ /** @type {Comparator} */
815
+ sensitive: (a, b) => a <= b,
816
+
817
+ /** @type {Comparator} */
818
+ insensitive: (a, b) => a.toLowerCase() <= b.toLowerCase(),
819
+ },
820
+ natural: {
821
+ /** @type {Comparator} */
822
+ sensitive: (a, b) => naturalCompare(a, b) <= 0,
823
+
824
+ /** @type {Comparator} */
825
+ insensitive: (a, b) =>
826
+ naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0,
827
+ },
828
+ },
829
+ descending: {
830
+ alphanumeric: {
831
+ /** @type {Comparator} */
832
+ sensitive: (a, b) =>
833
+ comparators.ascending.alphanumeric.sensitive(b, a),
834
+
835
+ /** @type {Comparator} */
836
+ insensitive: (a, b) =>
837
+ comparators.ascending.alphanumeric.insensitive(b, a),
838
+ },
839
+ natural: {
840
+ /** @type {Comparator} */
841
+ sensitive: (a, b) => comparators.ascending.natural.sensitive(b, a),
842
+
843
+ /** @type {Comparator} */
844
+ insensitive: (a, b) =>
845
+ comparators.ascending.natural.insensitive(b, a),
846
+ },
847
+ },
848
+ };
849
+
850
+ /**
851
+ * Gets the MemberNode's string key value.
852
+ * @param {MemberNode} member
853
+ * @return {string}
854
+ */
855
+ function getKey(member) {
856
+ return member.name.type === "Identifier"
857
+ ? member.name.name
858
+ : member.name.value;
859
+ }
860
+
861
+ //-----------------------------------------------------------------------------
862
+ // Rule Definition
863
+ //-----------------------------------------------------------------------------
864
+
865
+ /** @type {SortKeysRuleDefinition} */
866
+ const rule$1 = {
867
+ meta: {
868
+ type: "suggestion",
869
+
870
+ defaultOptions: [
871
+ "asc",
872
+ {
873
+ allowLineSeparatedGroups: false,
874
+ caseSensitive: true,
875
+ minKeys: 2,
876
+ natural: false,
877
+ },
878
+ ],
879
+
880
+ docs: {
881
+ description: `Require JSON object keys to be sorted`,
882
+ },
883
+
884
+ messages: {
885
+ sortKeys:
886
+ "Expected object keys to be in {{sortName}} case-{{sensitivity}} {{direction}} order. '{{thisName}}' should be before '{{prevName}}'.",
887
+ },
888
+
889
+ schema: [
890
+ {
891
+ enum: ["asc", "desc"],
892
+ },
893
+ {
894
+ type: "object",
895
+ properties: {
896
+ caseSensitive: {
897
+ type: "boolean",
898
+ },
899
+ natural: {
900
+ type: "boolean",
901
+ },
902
+ minKeys: {
903
+ type: "integer",
904
+ minimum: 2,
905
+ },
906
+ allowLineSeparatedGroups: {
907
+ type: "boolean",
908
+ },
909
+ },
910
+ additionalProperties: false,
911
+ },
912
+ ],
913
+ },
914
+
915
+ create(context) {
916
+ const [
917
+ directionShort,
918
+ { allowLineSeparatedGroups, caseSensitive, natural, minKeys },
919
+ ] = context.options;
920
+
921
+ const direction = directionShort === "asc" ? "ascending" : "descending";
922
+ const sortName = natural ? "natural" : "alphanumeric";
923
+ const sensitivity = caseSensitive ? "sensitive" : "insensitive";
924
+ const isValidOrder = comparators[direction][sortName][sensitivity];
925
+
926
+ // Note that @humanwhocodes/momoa doesn't include comments in the object.members tree, so we can't just see if a member is preceded by a comment
927
+ const commentLineNums = new Set();
928
+ for (const comment of context.sourceCode.comments) {
929
+ for (
930
+ let lineNum = comment.loc.start.line;
931
+ lineNum <= comment.loc.end.line;
932
+ lineNum += 1
933
+ ) {
934
+ commentLineNums.add(lineNum);
935
+ }
936
+ }
937
+
938
+ /**
939
+ * Checks if two members are line-separated.
940
+ * @param {MemberNode} prevMember The previous member.
941
+ * @param {MemberNode} member The current member.
942
+ * @return {boolean}
943
+ */
944
+ function isLineSeparated(prevMember, member) {
945
+ // Note that there can be comments *inside* members, e.g. `{"foo: /* comment *\/ "bar"}`, but these are ignored when calculating line-separated groups
946
+ const prevMemberEndLine = prevMember.loc.end.line;
947
+ const thisStartLine = member.loc.start.line;
948
+ if (thisStartLine - prevMemberEndLine < 2) {
949
+ return false;
950
+ }
951
+
952
+ for (
953
+ let lineNum = prevMemberEndLine + 1;
954
+ lineNum < thisStartLine;
955
+ lineNum += 1
956
+ ) {
957
+ if (
958
+ !commentLineNums.has(lineNum) &&
959
+ !hasNonWhitespace.test(
960
+ context.sourceCode.lines[lineNum - 1],
961
+ )
962
+ ) {
963
+ return true;
964
+ }
965
+ }
966
+
967
+ return false;
968
+ }
969
+
970
+ return {
971
+ Object(node) {
972
+ let prevMember;
973
+ let prevName;
974
+
975
+ if (node.members.length < minKeys) {
976
+ return;
977
+ }
978
+
979
+ for (const member of node.members) {
980
+ const thisName = getKey(member);
981
+
982
+ if (
983
+ prevMember &&
984
+ !isValidOrder(prevName, thisName) &&
985
+ (!allowLineSeparatedGroups ||
986
+ !isLineSeparated(prevMember, member))
987
+ ) {
988
+ context.report({
989
+ loc: member.name.loc,
990
+ messageId: "sortKeys",
991
+ data: {
992
+ thisName,
993
+ prevName,
994
+ direction,
995
+ sensitivity,
996
+ sortName,
997
+ },
998
+ });
999
+ }
1000
+
1001
+ prevMember = member;
1002
+ prevName = thisName;
1003
+ }
1004
+ },
1005
+ };
1006
+ },
1007
+ };
1008
+
718
1009
  /**
719
1010
  * @fileoverview Rule to ensure top-level items are either an array or ojbect.
720
1011
  * @author Joe Hildebrand
721
1012
  */
722
1013
 
723
- var topLevelInterop = {
1014
+ //-----------------------------------------------------------------------------
1015
+ // Type Definitions
1016
+ //-----------------------------------------------------------------------------
1017
+
1018
+ /** @typedef {"topLevel"} TopLevelInteropMessageIds */
1019
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], TopLevelInteropMessageIds>} TopLevelInteropRuleDefinition */
1020
+
1021
+ //-----------------------------------------------------------------------------
1022
+ // Rule Definition
1023
+ //-----------------------------------------------------------------------------
1024
+
1025
+ /** @type {TopLevelInteropRuleDefinition} */
1026
+ const rule = {
724
1027
  meta: {
725
- type: /** @type {const} */ ("problem"),
1028
+ type: "problem",
726
1029
 
727
1030
  docs: {
728
1031
  description:
@@ -764,7 +1067,7 @@ var topLevelInterop = {
764
1067
  const plugin = {
765
1068
  meta: {
766
1069
  name: "@eslint/json",
767
- version: "0.9.1", // x-release-please-version
1070
+ version: "0.11.0", // x-release-please-version
768
1071
  },
769
1072
  languages: {
770
1073
  json: new JSONLanguage({ mode: "json" }),
@@ -772,11 +1075,12 @@ const plugin = {
772
1075
  json5: new JSONLanguage({ mode: "json5" }),
773
1076
  },
774
1077
  rules: {
775
- "no-duplicate-keys": noDuplicateKeys,
776
- "no-empty-keys": noEmptyKeys,
777
- "no-unsafe-values": noUnsafeValues,
778
- "no-unnormalized-keys": noUnnormalizedKeys,
779
- "top-level-interop": topLevelInterop,
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,
780
1084
  },
781
1085
  configs: {
782
1086
  recommended: {
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @fileoverview Additional types for this package.
3
+ * @author Nicholas C. Zakas
4
+ */
5
+ import type { RuleVisitor, TextSourceCode, Language, LanguageOptions, RuleDefinition } from "@eslint/core";
6
+ import { DocumentNode, MemberNode, ElementNode, ObjectNode, ArrayNode, StringNode, NullNode, NumberNode, BooleanNode, NaNNode, InfinityNode, IdentifierNode, AnyNode, Token } from "@humanwhocodes/momoa";
7
+ type ValueNodeParent = DocumentNode | MemberNode | ElementNode;
8
+ /**
9
+ * A JSON syntax element, including nodes and tokens.
10
+ */
11
+ export type JSONSyntaxElement = Token | AnyNode;
12
+ /**
13
+ * Language options provided for JSON files.
14
+ */
15
+ export interface JSONLanguageOptions extends LanguageOptions {
16
+ /**
17
+ * Whether to allow trailing commas. Only valid in JSONC.
18
+ */
19
+ allowTrailingCommas?: boolean;
20
+ }
21
+ /**
22
+ * The visitor format returned from rules in this package.
23
+ */
24
+ export interface JSONRuleVisitor extends RuleVisitor {
25
+ Document?(node: DocumentNode): void;
26
+ Member?(node: MemberNode, parent?: ObjectNode): void;
27
+ Element?(node: ElementNode, parent?: ArrayNode): void;
28
+ Object?(node: ObjectNode, parent?: ValueNodeParent): void;
29
+ Array?(node: ArrayNode, parent?: ValueNodeParent): void;
30
+ String?(node: StringNode, parent?: ValueNodeParent): void;
31
+ Null?(node: NullNode, parent?: ValueNodeParent): void;
32
+ Number?(node: NumberNode, parent?: ValueNodeParent): void;
33
+ Boolean?(node: BooleanNode, parent?: ValueNodeParent): void;
34
+ NaN?(node: NaNNode, parent?: ValueNodeParent): void;
35
+ Infinity?(node: InfinityNode, parent?: ValueNodeParent): void;
36
+ Identifier?(node: IdentifierNode, parent?: ValueNodeParent): void;
37
+ "Document:exit"?(node: DocumentNode): void;
38
+ "Member:exit"?(node: MemberNode, parent?: ObjectNode): void;
39
+ "Element:exit"?(node: ElementNode, parent?: ArrayNode): void;
40
+ "Object:exit"?(node: ObjectNode, parent?: ValueNodeParent): void;
41
+ "Array:exit"?(node: ArrayNode, parent?: ValueNodeParent): void;
42
+ "String:exit"?(node: StringNode, parent?: ValueNodeParent): void;
43
+ "Null:exit"?(node: NullNode, parent?: ValueNodeParent): void;
44
+ "Number:exit"?(node: NumberNode, parent?: ValueNodeParent): void;
45
+ "Boolean:exit"?(node: BooleanNode, parent?: ValueNodeParent): void;
46
+ "NaN:exit"?(node: NaNNode, parent?: ValueNodeParent): void;
47
+ "Infinity:exit"?(node: InfinityNode, parent?: ValueNodeParent): void;
48
+ "Identifier:exit"?(node: IdentifierNode, parent?: ValueNodeParent): void;
49
+ }
50
+ /**
51
+ * The `SourceCode` implementation for JSON files.
52
+ */
53
+ export interface IJSONSourceCode extends TextSourceCode<{
54
+ LangOptions: JSONLanguageOptions;
55
+ RootNode: DocumentNode;
56
+ SyntaxElementWithLoc: JSONSyntaxElement;
57
+ ConfigNode: Token;
58
+ }> {
59
+ /**
60
+ * Get the text of a syntax element.
61
+ * @param syntaxElement The syntax element to get the text of.
62
+ * @param beforeCount The number of characters to include before the syntax element.
63
+ * @param afterCount The number of characters to include after the syntax element.
64
+ * @returns The text of the syntax element.
65
+ */
66
+ getText(syntaxElement: JSONSyntaxElement, beforeCount?: number, afterCount?: number): string;
67
+ /**
68
+ * Any comments found in a JSONC or JSON5 file.
69
+ */
70
+ comments: Array<Token> | undefined;
71
+ /**
72
+ * The lines of text found in the file.
73
+ */
74
+ lines: Array<string>;
75
+ }
76
+ export type IJSONLanguage = Language<{
77
+ LangOptions: JSONLanguageOptions;
78
+ Code: IJSONSourceCode;
79
+ RootNode: DocumentNode;
80
+ Node: AnyNode;
81
+ }>;
82
+ export type JSONRuleDefinition<JSONRuleOptions extends unknown[], JSONRuleMessageIds extends string = ""> = RuleDefinition<{
83
+ LangOptions: JSONLanguageOptions;
84
+ Code: IJSONSourceCode;
85
+ RuleOptions: JSONRuleOptions;
86
+ Visitor: JSONRuleVisitor;
87
+ Node: AnyNode;
88
+ MessageIds: JSONRuleMessageIds;
89
+ ExtRuleDocs: {};
90
+ }>;
91
+ export {};