@eslint/json 0.9.0 → 0.10.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 +3 -2
- package/dist/cjs/index.cjs +181 -1
- package/dist/cjs/index.d.cts +45 -0
- package/dist/esm/index.d.ts +45 -0
- package/dist/esm/index.js +181 -1
- package/package.json +5 -4
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
|
|
@@ -256,8 +257,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
|
|
|
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
259
|
<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
|
|
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://
|
|
260
|
+
<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>
|
|
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></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>
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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.
|
|
@@ -718,6 +719,184 @@ var noUnnormalizedKeys = {
|
|
|
718
719
|
},
|
|
719
720
|
};
|
|
720
721
|
|
|
722
|
+
/**
|
|
723
|
+
* @fileoverview Rule to require JSON object keys to be sorted. Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
|
|
724
|
+
* @author Robin Thomas
|
|
725
|
+
*/
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
const hasNonWhitespace = /\S/u;
|
|
729
|
+
|
|
730
|
+
const comparators = {
|
|
731
|
+
ascending: {
|
|
732
|
+
alphanumeric: {
|
|
733
|
+
sensitive: (a, b) => a <= b,
|
|
734
|
+
insensitive: (a, b) => a.toLowerCase() <= b.toLowerCase(),
|
|
735
|
+
},
|
|
736
|
+
natural: {
|
|
737
|
+
sensitive: (a, b) => naturalCompare(a, b) <= 0,
|
|
738
|
+
insensitive: (a, b) =>
|
|
739
|
+
naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0,
|
|
740
|
+
},
|
|
741
|
+
},
|
|
742
|
+
descending: {
|
|
743
|
+
alphanumeric: {
|
|
744
|
+
sensitive: (a, b) =>
|
|
745
|
+
comparators.ascending.alphanumeric.sensitive(b, a),
|
|
746
|
+
insensitive: (a, b) =>
|
|
747
|
+
comparators.ascending.alphanumeric.insensitive(b, a),
|
|
748
|
+
},
|
|
749
|
+
natural: {
|
|
750
|
+
sensitive: (a, b) => comparators.ascending.natural.sensitive(b, a),
|
|
751
|
+
insensitive: (a, b) =>
|
|
752
|
+
comparators.ascending.natural.insensitive(b, a),
|
|
753
|
+
},
|
|
754
|
+
},
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
function getKey(member) {
|
|
758
|
+
return member.name.type === `Identifier`
|
|
759
|
+
? member.name.name
|
|
760
|
+
: member.name.value;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
var sortKeys = {
|
|
764
|
+
meta: {
|
|
765
|
+
type: /** @type {const} */ ("suggestion"),
|
|
766
|
+
|
|
767
|
+
defaultOptions: [
|
|
768
|
+
"asc",
|
|
769
|
+
{
|
|
770
|
+
allowLineSeparatedGroups: false,
|
|
771
|
+
caseSensitive: true,
|
|
772
|
+
minKeys: 2,
|
|
773
|
+
natural: false,
|
|
774
|
+
},
|
|
775
|
+
],
|
|
776
|
+
|
|
777
|
+
docs: {
|
|
778
|
+
description: `Require JSON object keys to be sorted`,
|
|
779
|
+
},
|
|
780
|
+
|
|
781
|
+
messages: {
|
|
782
|
+
sortKeys:
|
|
783
|
+
"Expected object keys to be in {{sortName}} case-{{sensitivity}} {{direction}} order. '{{thisName}}' should be before '{{prevName}}'.",
|
|
784
|
+
},
|
|
785
|
+
|
|
786
|
+
schema: [
|
|
787
|
+
{
|
|
788
|
+
enum: ["asc", "desc"],
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
type: "object",
|
|
792
|
+
properties: {
|
|
793
|
+
caseSensitive: {
|
|
794
|
+
type: "boolean",
|
|
795
|
+
},
|
|
796
|
+
natural: {
|
|
797
|
+
type: "boolean",
|
|
798
|
+
},
|
|
799
|
+
minKeys: {
|
|
800
|
+
type: "integer",
|
|
801
|
+
minimum: 2,
|
|
802
|
+
},
|
|
803
|
+
allowLineSeparatedGroups: {
|
|
804
|
+
type: "boolean",
|
|
805
|
+
},
|
|
806
|
+
},
|
|
807
|
+
additionalProperties: false,
|
|
808
|
+
},
|
|
809
|
+
],
|
|
810
|
+
},
|
|
811
|
+
|
|
812
|
+
create(context) {
|
|
813
|
+
const [
|
|
814
|
+
directionShort,
|
|
815
|
+
{ allowLineSeparatedGroups, caseSensitive, natural, minKeys },
|
|
816
|
+
] = context.options;
|
|
817
|
+
|
|
818
|
+
const direction = directionShort === "asc" ? "ascending" : "descending";
|
|
819
|
+
const sortName = natural ? "natural" : "alphanumeric";
|
|
820
|
+
const sensitivity = caseSensitive ? "sensitive" : "insensitive";
|
|
821
|
+
const isValidOrder = comparators[direction][sortName][sensitivity];
|
|
822
|
+
|
|
823
|
+
// 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
|
|
824
|
+
const commentLineNums = new Set();
|
|
825
|
+
for (const comment of context.sourceCode.comments) {
|
|
826
|
+
for (
|
|
827
|
+
let lineNum = comment.loc.start.line;
|
|
828
|
+
lineNum <= comment.loc.end.line;
|
|
829
|
+
lineNum += 1
|
|
830
|
+
) {
|
|
831
|
+
commentLineNums.add(lineNum);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Note that there can be comments *inside* members, e.g. `{"foo: /* comment *\/ "bar"}`, but these are ignored when calculating line-separated groups
|
|
836
|
+
function isLineSeparated(prevMember, member) {
|
|
837
|
+
const prevMemberEndLine = prevMember.loc.end.line;
|
|
838
|
+
const thisStartLine = member.loc.start.line;
|
|
839
|
+
if (thisStartLine - prevMemberEndLine < 2) {
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
for (
|
|
844
|
+
let lineNum = prevMemberEndLine + 1;
|
|
845
|
+
lineNum < thisStartLine;
|
|
846
|
+
lineNum += 1
|
|
847
|
+
) {
|
|
848
|
+
if (
|
|
849
|
+
!commentLineNums.has(lineNum) &&
|
|
850
|
+
!hasNonWhitespace.test(
|
|
851
|
+
context.sourceCode.lines[lineNum - 1],
|
|
852
|
+
)
|
|
853
|
+
) {
|
|
854
|
+
return true;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
return {
|
|
862
|
+
Object(node) {
|
|
863
|
+
let prevMember;
|
|
864
|
+
let prevName;
|
|
865
|
+
|
|
866
|
+
if (node.members.length < minKeys) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
for (const member of node.members) {
|
|
871
|
+
const thisName = getKey(member);
|
|
872
|
+
|
|
873
|
+
if (
|
|
874
|
+
prevMember &&
|
|
875
|
+
!isValidOrder(prevName, thisName) &&
|
|
876
|
+
(!allowLineSeparatedGroups ||
|
|
877
|
+
!isLineSeparated(prevMember, member))
|
|
878
|
+
) {
|
|
879
|
+
context.report({
|
|
880
|
+
loc: member.name.loc,
|
|
881
|
+
messageId: "sortKeys",
|
|
882
|
+
data: {
|
|
883
|
+
thisName,
|
|
884
|
+
prevName,
|
|
885
|
+
direction,
|
|
886
|
+
sensitivity,
|
|
887
|
+
sortName,
|
|
888
|
+
},
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
prevMember = member;
|
|
893
|
+
prevName = thisName;
|
|
894
|
+
}
|
|
895
|
+
},
|
|
896
|
+
};
|
|
897
|
+
},
|
|
898
|
+
};
|
|
899
|
+
|
|
721
900
|
/**
|
|
722
901
|
* @fileoverview Rule to ensure top-level items are either an array or ojbect.
|
|
723
902
|
* @author Joe Hildebrand
|
|
@@ -767,7 +946,7 @@ var topLevelInterop = {
|
|
|
767
946
|
const plugin = {
|
|
768
947
|
meta: {
|
|
769
948
|
name: "@eslint/json",
|
|
770
|
-
version: "0.
|
|
949
|
+
version: "0.10.0", // x-release-please-version
|
|
771
950
|
},
|
|
772
951
|
languages: {
|
|
773
952
|
json: new JSONLanguage({ mode: "json" }),
|
|
@@ -779,6 +958,7 @@ const plugin = {
|
|
|
779
958
|
"no-empty-keys": noEmptyKeys,
|
|
780
959
|
"no-unsafe-values": noUnsafeValues,
|
|
781
960
|
"no-unnormalized-keys": noUnnormalizedKeys,
|
|
961
|
+
"sort-keys": sortKeys,
|
|
782
962
|
"top-level-interop": topLevelInterop,
|
|
783
963
|
},
|
|
784
964
|
configs: {
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -244,6 +244,51 @@ declare namespace plugin {
|
|
|
244
244
|
Member(node: any): void;
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
|
+
"sort-keys": {
|
|
248
|
+
meta: {
|
|
249
|
+
type: "suggestion";
|
|
250
|
+
defaultOptions: (string | {
|
|
251
|
+
allowLineSeparatedGroups: boolean;
|
|
252
|
+
caseSensitive: boolean;
|
|
253
|
+
minKeys: number;
|
|
254
|
+
natural: boolean;
|
|
255
|
+
})[];
|
|
256
|
+
docs: {
|
|
257
|
+
description: string;
|
|
258
|
+
};
|
|
259
|
+
messages: {
|
|
260
|
+
sortKeys: string;
|
|
261
|
+
};
|
|
262
|
+
schema: ({
|
|
263
|
+
enum: string[];
|
|
264
|
+
type?: undefined;
|
|
265
|
+
properties?: undefined;
|
|
266
|
+
additionalProperties?: undefined;
|
|
267
|
+
} | {
|
|
268
|
+
type: string;
|
|
269
|
+
properties: {
|
|
270
|
+
caseSensitive: {
|
|
271
|
+
type: string;
|
|
272
|
+
};
|
|
273
|
+
natural: {
|
|
274
|
+
type: string;
|
|
275
|
+
};
|
|
276
|
+
minKeys: {
|
|
277
|
+
type: string;
|
|
278
|
+
minimum: number;
|
|
279
|
+
};
|
|
280
|
+
allowLineSeparatedGroups: {
|
|
281
|
+
type: string;
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
additionalProperties: boolean;
|
|
285
|
+
enum?: undefined;
|
|
286
|
+
})[];
|
|
287
|
+
};
|
|
288
|
+
create(context: any): {
|
|
289
|
+
Object(node: any): void;
|
|
290
|
+
};
|
|
291
|
+
};
|
|
247
292
|
"top-level-interop": {
|
|
248
293
|
meta: {
|
|
249
294
|
type: "problem";
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -244,6 +244,51 @@ declare namespace plugin {
|
|
|
244
244
|
Member(node: any): void;
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
|
+
"sort-keys": {
|
|
248
|
+
meta: {
|
|
249
|
+
type: "suggestion";
|
|
250
|
+
defaultOptions: (string | {
|
|
251
|
+
allowLineSeparatedGroups: boolean;
|
|
252
|
+
caseSensitive: boolean;
|
|
253
|
+
minKeys: number;
|
|
254
|
+
natural: boolean;
|
|
255
|
+
})[];
|
|
256
|
+
docs: {
|
|
257
|
+
description: string;
|
|
258
|
+
};
|
|
259
|
+
messages: {
|
|
260
|
+
sortKeys: string;
|
|
261
|
+
};
|
|
262
|
+
schema: ({
|
|
263
|
+
enum: string[];
|
|
264
|
+
type?: undefined;
|
|
265
|
+
properties?: undefined;
|
|
266
|
+
additionalProperties?: undefined;
|
|
267
|
+
} | {
|
|
268
|
+
type: string;
|
|
269
|
+
properties: {
|
|
270
|
+
caseSensitive: {
|
|
271
|
+
type: string;
|
|
272
|
+
};
|
|
273
|
+
natural: {
|
|
274
|
+
type: string;
|
|
275
|
+
};
|
|
276
|
+
minKeys: {
|
|
277
|
+
type: string;
|
|
278
|
+
minimum: number;
|
|
279
|
+
};
|
|
280
|
+
allowLineSeparatedGroups: {
|
|
281
|
+
type: string;
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
additionalProperties: boolean;
|
|
285
|
+
enum?: undefined;
|
|
286
|
+
})[];
|
|
287
|
+
};
|
|
288
|
+
create(context: any): {
|
|
289
|
+
Object(node: any): void;
|
|
290
|
+
};
|
|
291
|
+
};
|
|
247
292
|
"top-level-interop": {
|
|
248
293
|
meta: {
|
|
249
294
|
type: "problem";
|
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.
|
|
@@ -715,6 +716,184 @@ var noUnnormalizedKeys = {
|
|
|
715
716
|
},
|
|
716
717
|
};
|
|
717
718
|
|
|
719
|
+
/**
|
|
720
|
+
* @fileoverview Rule to require JSON object keys to be sorted. Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
|
|
721
|
+
* @author Robin Thomas
|
|
722
|
+
*/
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
const hasNonWhitespace = /\S/u;
|
|
726
|
+
|
|
727
|
+
const comparators = {
|
|
728
|
+
ascending: {
|
|
729
|
+
alphanumeric: {
|
|
730
|
+
sensitive: (a, b) => a <= b,
|
|
731
|
+
insensitive: (a, b) => a.toLowerCase() <= b.toLowerCase(),
|
|
732
|
+
},
|
|
733
|
+
natural: {
|
|
734
|
+
sensitive: (a, b) => naturalCompare(a, b) <= 0,
|
|
735
|
+
insensitive: (a, b) =>
|
|
736
|
+
naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0,
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
descending: {
|
|
740
|
+
alphanumeric: {
|
|
741
|
+
sensitive: (a, b) =>
|
|
742
|
+
comparators.ascending.alphanumeric.sensitive(b, a),
|
|
743
|
+
insensitive: (a, b) =>
|
|
744
|
+
comparators.ascending.alphanumeric.insensitive(b, a),
|
|
745
|
+
},
|
|
746
|
+
natural: {
|
|
747
|
+
sensitive: (a, b) => comparators.ascending.natural.sensitive(b, a),
|
|
748
|
+
insensitive: (a, b) =>
|
|
749
|
+
comparators.ascending.natural.insensitive(b, a),
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
function getKey(member) {
|
|
755
|
+
return member.name.type === `Identifier`
|
|
756
|
+
? member.name.name
|
|
757
|
+
: member.name.value;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
var sortKeys = {
|
|
761
|
+
meta: {
|
|
762
|
+
type: /** @type {const} */ ("suggestion"),
|
|
763
|
+
|
|
764
|
+
defaultOptions: [
|
|
765
|
+
"asc",
|
|
766
|
+
{
|
|
767
|
+
allowLineSeparatedGroups: false,
|
|
768
|
+
caseSensitive: true,
|
|
769
|
+
minKeys: 2,
|
|
770
|
+
natural: false,
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
|
|
774
|
+
docs: {
|
|
775
|
+
description: `Require JSON object keys to be sorted`,
|
|
776
|
+
},
|
|
777
|
+
|
|
778
|
+
messages: {
|
|
779
|
+
sortKeys:
|
|
780
|
+
"Expected object keys to be in {{sortName}} case-{{sensitivity}} {{direction}} order. '{{thisName}}' should be before '{{prevName}}'.",
|
|
781
|
+
},
|
|
782
|
+
|
|
783
|
+
schema: [
|
|
784
|
+
{
|
|
785
|
+
enum: ["asc", "desc"],
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
type: "object",
|
|
789
|
+
properties: {
|
|
790
|
+
caseSensitive: {
|
|
791
|
+
type: "boolean",
|
|
792
|
+
},
|
|
793
|
+
natural: {
|
|
794
|
+
type: "boolean",
|
|
795
|
+
},
|
|
796
|
+
minKeys: {
|
|
797
|
+
type: "integer",
|
|
798
|
+
minimum: 2,
|
|
799
|
+
},
|
|
800
|
+
allowLineSeparatedGroups: {
|
|
801
|
+
type: "boolean",
|
|
802
|
+
},
|
|
803
|
+
},
|
|
804
|
+
additionalProperties: false,
|
|
805
|
+
},
|
|
806
|
+
],
|
|
807
|
+
},
|
|
808
|
+
|
|
809
|
+
create(context) {
|
|
810
|
+
const [
|
|
811
|
+
directionShort,
|
|
812
|
+
{ allowLineSeparatedGroups, caseSensitive, natural, minKeys },
|
|
813
|
+
] = context.options;
|
|
814
|
+
|
|
815
|
+
const direction = directionShort === "asc" ? "ascending" : "descending";
|
|
816
|
+
const sortName = natural ? "natural" : "alphanumeric";
|
|
817
|
+
const sensitivity = caseSensitive ? "sensitive" : "insensitive";
|
|
818
|
+
const isValidOrder = comparators[direction][sortName][sensitivity];
|
|
819
|
+
|
|
820
|
+
// 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
|
|
821
|
+
const commentLineNums = new Set();
|
|
822
|
+
for (const comment of context.sourceCode.comments) {
|
|
823
|
+
for (
|
|
824
|
+
let lineNum = comment.loc.start.line;
|
|
825
|
+
lineNum <= comment.loc.end.line;
|
|
826
|
+
lineNum += 1
|
|
827
|
+
) {
|
|
828
|
+
commentLineNums.add(lineNum);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Note that there can be comments *inside* members, e.g. `{"foo: /* comment *\/ "bar"}`, but these are ignored when calculating line-separated groups
|
|
833
|
+
function isLineSeparated(prevMember, member) {
|
|
834
|
+
const prevMemberEndLine = prevMember.loc.end.line;
|
|
835
|
+
const thisStartLine = member.loc.start.line;
|
|
836
|
+
if (thisStartLine - prevMemberEndLine < 2) {
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
for (
|
|
841
|
+
let lineNum = prevMemberEndLine + 1;
|
|
842
|
+
lineNum < thisStartLine;
|
|
843
|
+
lineNum += 1
|
|
844
|
+
) {
|
|
845
|
+
if (
|
|
846
|
+
!commentLineNums.has(lineNum) &&
|
|
847
|
+
!hasNonWhitespace.test(
|
|
848
|
+
context.sourceCode.lines[lineNum - 1],
|
|
849
|
+
)
|
|
850
|
+
) {
|
|
851
|
+
return true;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return {
|
|
859
|
+
Object(node) {
|
|
860
|
+
let prevMember;
|
|
861
|
+
let prevName;
|
|
862
|
+
|
|
863
|
+
if (node.members.length < minKeys) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
for (const member of node.members) {
|
|
868
|
+
const thisName = getKey(member);
|
|
869
|
+
|
|
870
|
+
if (
|
|
871
|
+
prevMember &&
|
|
872
|
+
!isValidOrder(prevName, thisName) &&
|
|
873
|
+
(!allowLineSeparatedGroups ||
|
|
874
|
+
!isLineSeparated(prevMember, member))
|
|
875
|
+
) {
|
|
876
|
+
context.report({
|
|
877
|
+
loc: member.name.loc,
|
|
878
|
+
messageId: "sortKeys",
|
|
879
|
+
data: {
|
|
880
|
+
thisName,
|
|
881
|
+
prevName,
|
|
882
|
+
direction,
|
|
883
|
+
sensitivity,
|
|
884
|
+
sortName,
|
|
885
|
+
},
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
prevMember = member;
|
|
890
|
+
prevName = thisName;
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
};
|
|
894
|
+
},
|
|
895
|
+
};
|
|
896
|
+
|
|
718
897
|
/**
|
|
719
898
|
* @fileoverview Rule to ensure top-level items are either an array or ojbect.
|
|
720
899
|
* @author Joe Hildebrand
|
|
@@ -764,7 +943,7 @@ var topLevelInterop = {
|
|
|
764
943
|
const plugin = {
|
|
765
944
|
meta: {
|
|
766
945
|
name: "@eslint/json",
|
|
767
|
-
version: "0.
|
|
946
|
+
version: "0.10.0", // x-release-please-version
|
|
768
947
|
},
|
|
769
948
|
languages: {
|
|
770
949
|
json: new JSONLanguage({ mode: "json" }),
|
|
@@ -776,6 +955,7 @@ const plugin = {
|
|
|
776
955
|
"no-empty-keys": noEmptyKeys,
|
|
777
956
|
"no-unsafe-values": noUnsafeValues,
|
|
778
957
|
"no-unnormalized-keys": noUnnormalizedKeys,
|
|
958
|
+
"sort-keys": sortKeys,
|
|
779
959
|
"top-level-interop": topLevelInterop,
|
|
780
960
|
},
|
|
781
961
|
configs: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint/json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "JSON linting plugin for ESLint",
|
|
5
5
|
"author": "Nicholas C. Zakas",
|
|
6
6
|
"type": "module",
|
|
@@ -63,11 +63,12 @@
|
|
|
63
63
|
],
|
|
64
64
|
"license": "Apache-2.0",
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@eslint/
|
|
67
|
-
"@
|
|
66
|
+
"@eslint/core": "^0.10.0",
|
|
67
|
+
"@eslint/plugin-kit": "^0.2.5",
|
|
68
|
+
"@humanwhocodes/momoa": "^3.3.4",
|
|
69
|
+
"natural-compare": "^1.4.0"
|
|
68
70
|
},
|
|
69
71
|
"devDependencies": {
|
|
70
|
-
"@eslint/core": "^0.6.0",
|
|
71
72
|
"@types/eslint": "^8.56.10",
|
|
72
73
|
"c8": "^9.1.0",
|
|
73
74
|
"dedent": "^1.5.3",
|