@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/README.md CHANGED
@@ -161,6 +161,7 @@ export default [
161
161
  like integers but are too large, and
162
162
  [subnormal numbers](https://en.wikipedia.org/wiki/Subnormal_number).
163
163
  - `no-unnormalized-keys` - warns on keys containing [unnormalized characters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize#description). You can optionally specify the normalization form via `{ form: "form_name" }`, where `form_name` can be any of `"NFC"`, `"NFD"`, `"NFKC"`, or `"NFKD"`.
164
+ - `sort-keys` - warns when keys are not in the specified order. Based on the ESLint [`sort-keys`](https://eslint.org/docs/latest/rules/sort-keys) rule.
164
165
  - `top-level-interop` - warns when the top-level item in the document is neither an array nor an object. This can be enabled to ensure maximal interoperability with the oldest JSON parsers.
165
166
 
166
167
  ## Configuration Comments
@@ -255,9 +256,9 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
255
256
 
256
257
  <h3>Platinum Sponsors</h3>
257
258
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3>
258
- <p><a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a></p><h3>Silver Sponsors</h3>
259
- <p><a href="https://www.serptriumph.com/"><img src="https://images.opencollective.com/serp-triumph5/fea3074/logo.png" alt="SERP Triumph" height="64"></a> <a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/fe76f99/logo.png" alt="JetBrains" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3>
260
- <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a></p>
259
+ <p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
260
+ <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/fe76f99/logo.png" alt="JetBrains" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
261
+ <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nolebase.ayaka.io"><img src="https://avatars.githubusercontent.com/u/11081491" alt="Neko" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
261
262
  <h3>Technology Sponsors</h3>
262
263
  Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
263
264
  <p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var momoa = require('@humanwhocodes/momoa');
6
6
  var pluginKit = require('@eslint/plugin-kit');
7
+ var naturalCompare = require('natural-compare');
7
8
 
8
9
  /**
9
10
  * @fileoverview The JSONSourceCode class.
@@ -22,11 +23,12 @@ var pluginKit = require('@eslint/plugin-kit');
22
23
  /** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
23
24
  /** @typedef {import("@eslint/core").File} File */
24
25
  /** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
25
- /** @typedef {import("@eslint/core").TextSourceCode} TextSourceCode */
26
26
  /** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
27
27
  /** @typedef {import("@eslint/core").FileProblem} FileProblem */
28
28
  /** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
29
29
  /** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
30
+ /** @typedef {import("./types.ts").IJSONSourceCode} IJSONSourceCode */
31
+ /** @typedef {import("./types.ts").JSONSyntaxElement} JSONSyntaxElement */
30
32
 
31
33
  //-----------------------------------------------------------------------------
32
34
  // Helpers
@@ -67,6 +69,7 @@ class JSONTraversalStep extends pluginKit.VisitNodeStep {
67
69
 
68
70
  /**
69
71
  * JSON Source Code Object
72
+ * @implements {IJSONSourceCode}
70
73
  */
71
74
  class JSONSourceCode extends pluginKit.TextSourceCodeBase {
72
75
  /**
@@ -143,7 +146,7 @@ class JSONSourceCode extends pluginKit.TextSourceCodeBase {
143
146
  );
144
147
  }
145
148
 
146
- return this.#inlineConfigComments;
149
+ return this.#inlineConfigComments ?? [];
147
150
  }
148
151
 
149
152
  /**
@@ -296,10 +299,8 @@ class JSONSourceCode extends pluginKit.TextSourceCodeBase {
296
299
  /** @typedef {import("@eslint/core").Language} Language */
297
300
  /** @typedef {import("@eslint/core").OkParseResult<DocumentNode>} OkParseResult */
298
301
  /** @typedef {import("@eslint/core").ParseResult<DocumentNode>} ParseResult */
299
- /**
300
- * @typedef {Object} JSONLanguageOptions
301
- * @property {boolean} [allowTrailingCommas] Whether to allow trailing commas.
302
- */
302
+ /** @typedef {import("./types.ts").IJSONLanguage} IJSONLanguage */
303
+ /** @typedef {import("./types.ts").JSONLanguageOptions} JSONLanguageOptions */
303
304
 
304
305
  //-----------------------------------------------------------------------------
305
306
  // Exports
@@ -307,7 +308,7 @@ class JSONSourceCode extends pluginKit.TextSourceCodeBase {
307
308
 
308
309
  /**
309
310
  * JSON Language Object
310
- * @implements {Language}
311
+ * @implements {IJSONLanguage}
311
312
  */
312
313
  class JSONLanguage {
313
314
  /**
@@ -449,13 +450,22 @@ class JSONLanguage {
449
450
  * @author Nicholas C. Zakas
450
451
  */
451
452
 
453
+ //-----------------------------------------------------------------------------
454
+ // Type Definitions
455
+ //-----------------------------------------------------------------------------
456
+
457
+ /** @typedef {"duplicateKey"} NoDuplicateKeysMessageIds */
458
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoDuplicateKeysMessageIds>} NoDuplicateKeysRuleDefinition */
459
+ /** @typedef {import("@humanwhocodes/momoa").MemberNode} MemberNode */
460
+
452
461
  //-----------------------------------------------------------------------------
453
462
  // Rule Definition
454
463
  //-----------------------------------------------------------------------------
455
464
 
456
- var noDuplicateKeys = {
465
+ /** @type {NoDuplicateKeysRuleDefinition} */
466
+ const rule$5 = {
457
467
  meta: {
458
- type: /** @type {const} */ ("problem"),
468
+ type: "problem",
459
469
 
460
470
  docs: {
461
471
  description: "Disallow duplicate keys in JSON objects",
@@ -467,7 +477,10 @@ var noDuplicateKeys = {
467
477
  },
468
478
 
469
479
  create(context) {
480
+ /** @type {Array<Map<string, MemberNode>|undefined>} */
470
481
  const objectKeys = [];
482
+
483
+ /** @type {Map<string, MemberNode>|undefined} */
471
484
  let keys;
472
485
 
473
486
  return {
@@ -506,9 +519,21 @@ var noDuplicateKeys = {
506
519
  * @author Nicholas C. Zakas
507
520
  */
508
521
 
509
- var noEmptyKeys = {
522
+ //-----------------------------------------------------------------------------
523
+ // Type Definitions
524
+ //-----------------------------------------------------------------------------
525
+
526
+ /** @typedef {"emptyKey"} NoEmptyKeysMessageIds */
527
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoEmptyKeysMessageIds>} NoEmptyKeysRuleDefinition */
528
+
529
+ //-----------------------------------------------------------------------------
530
+ // Rule Definition
531
+ //-----------------------------------------------------------------------------
532
+
533
+ /** @type {NoEmptyKeysRuleDefinition} */
534
+ const rule$4 = {
510
535
  meta: {
511
- type: /** @type {const} */ ("problem"),
536
+ type: "problem",
512
537
 
513
538
  docs: {
514
539
  description: "Disallow empty keys in JSON objects",
@@ -543,15 +568,36 @@ var noEmptyKeys = {
543
568
  * @author Bradley Meck Farias
544
569
  */
545
570
 
546
- // RFC 8259's `number` production, as a regex. Capture the integer part
547
- // and the fractional part.
571
+ //-----------------------------------------------------------------------------
572
+ // Type Definitions
573
+ //-----------------------------------------------------------------------------
574
+
575
+ /** @typedef {"unsafeNumber"|"unsafeInteger"|"unsafeZero"|"subnormal"|"loneSurrogate"} NoUnsafeValuesMessageIds */
576
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], NoUnsafeValuesMessageIds>} NoUnsafeValuesRuleDefinition */
577
+
578
+ //-----------------------------------------------------------------------------
579
+ // Helpers
580
+ //-----------------------------------------------------------------------------
581
+
582
+ /*
583
+ * This rule is based on the JSON grammar from RFC 8259, section 6.
584
+ * https://tools.ietf.org/html/rfc8259#section-6
585
+ *
586
+ * We separately capture the integer and fractional parts of a number, so that
587
+ * we can check for unsafe numbers that will evaluate to Infinity.
588
+ */
548
589
  const NUMBER =
549
590
  /^-?(?<int>0|([1-9][0-9]*))(?:\.(?<frac>[0-9]+))?(?:[eE][+-]?[0-9]+)?$/u;
550
591
  const NON_ZERO = /[1-9]/u;
551
592
 
552
- var noUnsafeValues = {
593
+ //-----------------------------------------------------------------------------
594
+ // Rule Definition
595
+ //-----------------------------------------------------------------------------
596
+
597
+ /** @type {NoUnsafeValuesRuleDefinition} */
598
+ const rule$3 = {
553
599
  meta: {
554
- type: /** @type {const} */ ("problem"),
600
+ type: "problem",
555
601
 
556
602
  docs: {
557
603
  description: "Disallow JSON values that are unsafe for interchange",
@@ -625,7 +671,9 @@ var noUnsafeValues = {
625
671
  loc: node.loc,
626
672
  messageId: "subnormal",
627
673
  // Value included so that it's seen in scientific notation
628
- data: node,
674
+ data: {
675
+ value,
676
+ },
629
677
  });
630
678
  }
631
679
  }
@@ -668,9 +716,21 @@ var noUnsafeValues = {
668
716
  * @author Bradley Meck Farias
669
717
  */
670
718
 
671
- var noUnnormalizedKeys = {
719
+ //-----------------------------------------------------------------------------
720
+ // Type Definitions
721
+ //-----------------------------------------------------------------------------
722
+
723
+ /** @typedef {"unnormalizedKey"} NoUnnormalizedKeysMessageIds */
724
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[{form:string}], NoUnnormalizedKeysMessageIds>} NoUnnormalizedKeysRuleDefinition */
725
+
726
+ //-----------------------------------------------------------------------------
727
+ // Rule Definition
728
+ //-----------------------------------------------------------------------------
729
+
730
+ /** @type {NoUnnormalizedKeysRuleDefinition} */
731
+ const rule$2 = {
672
732
  meta: {
673
- type: /** @type {const} */ ("problem"),
733
+ type: "problem",
674
734
 
675
735
  docs: {
676
736
  description: "Disallow JSON keys that are not normalized",
@@ -694,9 +754,10 @@ var noUnnormalizedKeys = {
694
754
  },
695
755
 
696
756
  create(context) {
697
- const normalization = context.options.length
698
- ? text => text.normalize(context.options[0].form)
699
- : text => text.normalize();
757
+ const form = context.options.length
758
+ ? context.options[0].form
759
+ : undefined;
760
+
700
761
  return {
701
762
  Member(node) {
702
763
  const key =
@@ -704,7 +765,7 @@ var noUnnormalizedKeys = {
704
765
  ? node.name.value
705
766
  : node.name.name;
706
767
 
707
- if (normalization(key) !== key) {
768
+ if (key.normalize(form) !== key) {
708
769
  context.report({
709
770
  loc: node.name.loc,
710
771
  messageId: "unnormalizedKey",
@@ -718,14 +779,256 @@ var noUnnormalizedKeys = {
718
779
  },
719
780
  };
720
781
 
782
+ /**
783
+ * @fileoverview Rule to require JSON object keys to be sorted.
784
+ * Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
785
+ * @author Robin Thomas
786
+ */
787
+
788
+
789
+ //-----------------------------------------------------------------------------
790
+ // Type Definitions
791
+ //-----------------------------------------------------------------------------
792
+
793
+ /** @typedef {"sortKeys"} SortKeysMessageIds */
794
+
795
+ /**
796
+ * @typedef {Object} SortOptions
797
+ * @property {boolean} caseSensitive
798
+ * @property {boolean} natural
799
+ * @property {number} minKeys
800
+ * @property {boolean} allowLineSeparatedGroups
801
+ */
802
+
803
+ /** @typedef {"asc"|"desc"} SortDirection */
804
+ /** @typedef {[SortDirection, SortOptions]} SortKeysRuleOptions */
805
+ /** @typedef {import("./types.ts").JSONRuleDefinition<SortKeysRuleOptions, SortKeysMessageIds>} SortKeysRuleDefinition */
806
+ /** @typedef {(a:string,b:string) => boolean} Comparator */
807
+
808
+ //-----------------------------------------------------------------------------
809
+ // Helpers
810
+ //-----------------------------------------------------------------------------
811
+
812
+ const hasNonWhitespace = /\S/u;
813
+
814
+ const comparators = {
815
+ ascending: {
816
+ alphanumeric: {
817
+ /** @type {Comparator} */
818
+ sensitive: (a, b) => a <= b,
819
+
820
+ /** @type {Comparator} */
821
+ insensitive: (a, b) => a.toLowerCase() <= b.toLowerCase(),
822
+ },
823
+ natural: {
824
+ /** @type {Comparator} */
825
+ sensitive: (a, b) => naturalCompare(a, b) <= 0,
826
+
827
+ /** @type {Comparator} */
828
+ insensitive: (a, b) =>
829
+ naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0,
830
+ },
831
+ },
832
+ descending: {
833
+ alphanumeric: {
834
+ /** @type {Comparator} */
835
+ sensitive: (a, b) =>
836
+ comparators.ascending.alphanumeric.sensitive(b, a),
837
+
838
+ /** @type {Comparator} */
839
+ insensitive: (a, b) =>
840
+ comparators.ascending.alphanumeric.insensitive(b, a),
841
+ },
842
+ natural: {
843
+ /** @type {Comparator} */
844
+ sensitive: (a, b) => comparators.ascending.natural.sensitive(b, a),
845
+
846
+ /** @type {Comparator} */
847
+ insensitive: (a, b) =>
848
+ comparators.ascending.natural.insensitive(b, a),
849
+ },
850
+ },
851
+ };
852
+
853
+ /**
854
+ * Gets the MemberNode's string key value.
855
+ * @param {MemberNode} member
856
+ * @return {string}
857
+ */
858
+ function getKey(member) {
859
+ return member.name.type === "Identifier"
860
+ ? member.name.name
861
+ : member.name.value;
862
+ }
863
+
864
+ //-----------------------------------------------------------------------------
865
+ // Rule Definition
866
+ //-----------------------------------------------------------------------------
867
+
868
+ /** @type {SortKeysRuleDefinition} */
869
+ const rule$1 = {
870
+ meta: {
871
+ type: "suggestion",
872
+
873
+ defaultOptions: [
874
+ "asc",
875
+ {
876
+ allowLineSeparatedGroups: false,
877
+ caseSensitive: true,
878
+ minKeys: 2,
879
+ natural: false,
880
+ },
881
+ ],
882
+
883
+ docs: {
884
+ description: `Require JSON object keys to be sorted`,
885
+ },
886
+
887
+ messages: {
888
+ sortKeys:
889
+ "Expected object keys to be in {{sortName}} case-{{sensitivity}} {{direction}} order. '{{thisName}}' should be before '{{prevName}}'.",
890
+ },
891
+
892
+ schema: [
893
+ {
894
+ enum: ["asc", "desc"],
895
+ },
896
+ {
897
+ type: "object",
898
+ properties: {
899
+ caseSensitive: {
900
+ type: "boolean",
901
+ },
902
+ natural: {
903
+ type: "boolean",
904
+ },
905
+ minKeys: {
906
+ type: "integer",
907
+ minimum: 2,
908
+ },
909
+ allowLineSeparatedGroups: {
910
+ type: "boolean",
911
+ },
912
+ },
913
+ additionalProperties: false,
914
+ },
915
+ ],
916
+ },
917
+
918
+ create(context) {
919
+ const [
920
+ directionShort,
921
+ { allowLineSeparatedGroups, caseSensitive, natural, minKeys },
922
+ ] = context.options;
923
+
924
+ const direction = directionShort === "asc" ? "ascending" : "descending";
925
+ const sortName = natural ? "natural" : "alphanumeric";
926
+ const sensitivity = caseSensitive ? "sensitive" : "insensitive";
927
+ const isValidOrder = comparators[direction][sortName][sensitivity];
928
+
929
+ // 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
930
+ const commentLineNums = new Set();
931
+ for (const comment of context.sourceCode.comments) {
932
+ for (
933
+ let lineNum = comment.loc.start.line;
934
+ lineNum <= comment.loc.end.line;
935
+ lineNum += 1
936
+ ) {
937
+ commentLineNums.add(lineNum);
938
+ }
939
+ }
940
+
941
+ /**
942
+ * Checks if two members are line-separated.
943
+ * @param {MemberNode} prevMember The previous member.
944
+ * @param {MemberNode} member The current member.
945
+ * @return {boolean}
946
+ */
947
+ function isLineSeparated(prevMember, member) {
948
+ // Note that there can be comments *inside* members, e.g. `{"foo: /* comment *\/ "bar"}`, but these are ignored when calculating line-separated groups
949
+ const prevMemberEndLine = prevMember.loc.end.line;
950
+ const thisStartLine = member.loc.start.line;
951
+ if (thisStartLine - prevMemberEndLine < 2) {
952
+ return false;
953
+ }
954
+
955
+ for (
956
+ let lineNum = prevMemberEndLine + 1;
957
+ lineNum < thisStartLine;
958
+ lineNum += 1
959
+ ) {
960
+ if (
961
+ !commentLineNums.has(lineNum) &&
962
+ !hasNonWhitespace.test(
963
+ context.sourceCode.lines[lineNum - 1],
964
+ )
965
+ ) {
966
+ return true;
967
+ }
968
+ }
969
+
970
+ return false;
971
+ }
972
+
973
+ return {
974
+ Object(node) {
975
+ let prevMember;
976
+ let prevName;
977
+
978
+ if (node.members.length < minKeys) {
979
+ return;
980
+ }
981
+
982
+ for (const member of node.members) {
983
+ const thisName = getKey(member);
984
+
985
+ if (
986
+ prevMember &&
987
+ !isValidOrder(prevName, thisName) &&
988
+ (!allowLineSeparatedGroups ||
989
+ !isLineSeparated(prevMember, member))
990
+ ) {
991
+ context.report({
992
+ loc: member.name.loc,
993
+ messageId: "sortKeys",
994
+ data: {
995
+ thisName,
996
+ prevName,
997
+ direction,
998
+ sensitivity,
999
+ sortName,
1000
+ },
1001
+ });
1002
+ }
1003
+
1004
+ prevMember = member;
1005
+ prevName = thisName;
1006
+ }
1007
+ },
1008
+ };
1009
+ },
1010
+ };
1011
+
721
1012
  /**
722
1013
  * @fileoverview Rule to ensure top-level items are either an array or ojbect.
723
1014
  * @author Joe Hildebrand
724
1015
  */
725
1016
 
726
- var topLevelInterop = {
1017
+ //-----------------------------------------------------------------------------
1018
+ // Type Definitions
1019
+ //-----------------------------------------------------------------------------
1020
+
1021
+ /** @typedef {"topLevel"} TopLevelInteropMessageIds */
1022
+ /** @typedef {import("./types.ts").JSONRuleDefinition<[], TopLevelInteropMessageIds>} TopLevelInteropRuleDefinition */
1023
+
1024
+ //-----------------------------------------------------------------------------
1025
+ // Rule Definition
1026
+ //-----------------------------------------------------------------------------
1027
+
1028
+ /** @type {TopLevelInteropRuleDefinition} */
1029
+ const rule = {
727
1030
  meta: {
728
- type: /** @type {const} */ ("problem"),
1031
+ type: "problem",
729
1032
 
730
1033
  docs: {
731
1034
  description:
@@ -767,7 +1070,7 @@ var topLevelInterop = {
767
1070
  const plugin = {
768
1071
  meta: {
769
1072
  name: "@eslint/json",
770
- version: "0.9.1", // x-release-please-version
1073
+ version: "0.11.0", // x-release-please-version
771
1074
  },
772
1075
  languages: {
773
1076
  json: new JSONLanguage({ mode: "json" }),
@@ -775,11 +1078,12 @@ const plugin = {
775
1078
  json5: new JSONLanguage({ mode: "json5" }),
776
1079
  },
777
1080
  rules: {
778
- "no-duplicate-keys": noDuplicateKeys,
779
- "no-empty-keys": noEmptyKeys,
780
- "no-unsafe-values": noUnsafeValues,
781
- "no-unnormalized-keys": noUnnormalizedKeys,
782
- "top-level-interop": topLevelInterop,
1081
+ "no-duplicate-keys": rule$5,
1082
+ "no-empty-keys": rule$4,
1083
+ "no-unsafe-values": rule$3,
1084
+ "no-unnormalized-keys": rule$2,
1085
+ "sort-keys": rule$1,
1086
+ "top-level-interop": rule,
783
1087
  },
784
1088
  configs: {
785
1089
  recommended: {