eslint-plugin-package-json 0.52.0 → 0.53.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/CHANGELOG.md +14 -2
- package/lib/createRule.d.ts +28 -28
- package/lib/createRule.js +18 -12
- package/lib/index.d.ts +33 -35
- package/lib/index.js +6 -6
- package/lib/plugin.d.ts +33 -34
- package/lib/plugin.js +62 -80
- package/lib/rules/no-empty-fields.d.ts +6 -11
- package/lib/rules/no-empty-fields.js +80 -112
- package/lib/rules/no-redundant-files.d.ts +5 -10
- package/lib/rules/no-redundant-files.js +93 -136
- package/lib/rules/order-properties.d.ts +6 -11
- package/lib/rules/order-properties.js +92 -116
- package/lib/rules/repository-shorthand.d.ts +6 -11
- package/lib/rules/repository-shorthand.js +79 -112
- package/lib/rules/require-properties.d.ts +7 -12
- package/lib/rules/require-properties.js +31 -27
- package/lib/rules/restrict-dependency-ranges.d.ts +9 -14
- package/lib/rules/restrict-dependency-ranges.js +137 -189
- package/lib/rules/sort-collections.d.ts +5 -10
- package/lib/rules/sort-collections.js +71 -124
- package/lib/rules/unique-dependencies.d.ts +5 -10
- package/lib/rules/unique-dependencies.js +58 -82
- package/lib/rules/valid-bin.d.ts +6 -11
- package/lib/rules/valid-bin.js +59 -78
- package/lib/rules/valid-local-dependency.d.ts +5 -10
- package/lib/rules/valid-local-dependency.js +49 -57
- package/lib/rules/valid-name.d.ts +5 -10
- package/lib/rules/valid-name.js +41 -48
- package/lib/rules/valid-package-definition.d.ts +6 -11
- package/lib/rules/valid-package-definition.js +41 -50
- package/lib/rules/valid-properties.d.ts +7 -7
- package/lib/rules/valid-properties.js +33 -55
- package/lib/rules/valid-repository-directory.d.ts +5 -10
- package/lib/rules/valid-repository-directory.js +65 -80
- package/lib/rules/valid-version.d.ts +5 -10
- package/lib/rules/valid-version.js +35 -36
- package/lib/types/estree.d.ts +8 -0
- package/lib/utils/createSimpleRequirePropertyRule.d.ts +19 -18
- package/lib/utils/createSimpleRequirePropertyRule.js +48 -53
- package/lib/utils/createSimpleValidPropertyRule.d.ts +6 -8
- package/lib/utils/createSimpleValidPropertyRule.js +45 -39
- package/lib/utils/findPropertyWithKeyValue.d.ts +6 -5
- package/lib/utils/findPropertyWithKeyValue.js +5 -6
- package/lib/utils/formatErrors.d.ts +3 -2
- package/lib/utils/formatErrors.js +11 -7
- package/lib/utils/isPackageJson.d.ts +3 -2
- package/lib/utils/isPackageJson.js +4 -3
- package/lib/utils/predicates.d.ts +4 -3
- package/lib/utils/predicates.js +6 -6
- package/package.json +8 -8
- package/lib/tests/rules/ruleTester.d.ts +0 -15
- package/lib/tests/rules/ruleTester.js +0 -25
- package/lib/types/estree.d.d.ts +0 -7
- package/lib/types/estree.d.js +0 -0
|
@@ -1,205 +1,153 @@
|
|
|
1
|
-
import semver from "semver";
|
|
2
1
|
import { createRule } from "../createRule.js";
|
|
3
2
|
import { isJSONStringLiteral } from "../utils/predicates.js";
|
|
3
|
+
import semver from "semver";
|
|
4
|
+
|
|
5
|
+
//#region src/rules/restrict-dependency-ranges.ts
|
|
4
6
|
const DEPENDENCY_TYPES = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
"dependencies",
|
|
8
|
+
"devDependencies",
|
|
9
|
+
"optionalDependencies",
|
|
10
|
+
"peerDependencies"
|
|
11
|
+
];
|
|
12
|
+
const RANGE_TYPES = [
|
|
13
|
+
"caret",
|
|
14
|
+
"pin",
|
|
15
|
+
"tilde"
|
|
9
16
|
];
|
|
10
|
-
const RANGE_TYPES = ["caret", "pin", "tilde"];
|
|
11
17
|
const schemaOptions = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
type: "array"
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
required: ["rangeType"],
|
|
44
|
-
type: "object"
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
properties: {
|
|
20
|
+
forDependencyTypes: {
|
|
21
|
+
description: "Apply a range type restriction for an entire group of dependencies by which type of dependencies they belong to.",
|
|
22
|
+
items: { enum: DEPENDENCY_TYPES },
|
|
23
|
+
type: "array"
|
|
24
|
+
},
|
|
25
|
+
forPackages: {
|
|
26
|
+
description: "The exact name of a package, or a regex pattern used to match a group of packages by name.",
|
|
27
|
+
items: { type: "string" },
|
|
28
|
+
type: "array"
|
|
29
|
+
},
|
|
30
|
+
forVersions: {
|
|
31
|
+
description: "Apply a restriction to a specific semver range.",
|
|
32
|
+
type: "string"
|
|
33
|
+
},
|
|
34
|
+
rangeType: {
|
|
35
|
+
description: "Identifies which range type or types you want to apply to packages that match any of the other match options (or all dependencies if no other options are provided).",
|
|
36
|
+
oneOf: [{ enum: RANGE_TYPES }, {
|
|
37
|
+
items: { enum: RANGE_TYPES },
|
|
38
|
+
type: "array"
|
|
39
|
+
}]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
required: ["rangeType"],
|
|
43
|
+
type: "object"
|
|
45
44
|
};
|
|
46
45
|
const SYMBOLS = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
caret: "^",
|
|
47
|
+
pin: "",
|
|
48
|
+
tilde: "~"
|
|
50
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Given the original version, update it to use the correct range type.
|
|
52
|
+
*/
|
|
51
53
|
const changeVersionRange = (version, rangeType) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
default:
|
|
60
|
-
return "workspace:~";
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return version.replace(
|
|
64
|
-
/^(workspace:)?(\^|~|<=?|>=?)?/,
|
|
65
|
-
`$1${SYMBOLS[rangeType]}`
|
|
66
|
-
);
|
|
54
|
+
if (/^workspace:[~^*]$/.test(version)) switch (rangeType) {
|
|
55
|
+
case "caret": return "workspace:^";
|
|
56
|
+
case "pin": return "workspace:*";
|
|
57
|
+
case "tilde":
|
|
58
|
+
default: return "workspace:~";
|
|
59
|
+
}
|
|
60
|
+
return version.replace(/^(workspace:)?(\^|~|<=?|>=?)?/, `$1${SYMBOLS[rangeType]}`);
|
|
67
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Check if the version is in a form that this rule supports.
|
|
64
|
+
*/
|
|
68
65
|
const isVersionSupported = (version) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const rawVersion = version.replace(/^workspace:/, "");
|
|
73
|
-
return !!semver.validRange(rawVersion);
|
|
66
|
+
if (/^workspace:[*^~]$/.test(version)) return true;
|
|
67
|
+
const rawVersion = version.replace(/^workspace:/, "");
|
|
68
|
+
return !!semver.validRange(rawVersion);
|
|
74
69
|
};
|
|
75
70
|
const capitalize = (str) => {
|
|
76
|
-
|
|
71
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
77
72
|
};
|
|
78
73
|
const rule = createRule({
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
context.report({
|
|
156
|
-
data: {
|
|
157
|
-
rangeTypes: rangeTypes.join(", ")
|
|
158
|
-
},
|
|
159
|
-
messageId: "wrongRangeType",
|
|
160
|
-
node: property.value,
|
|
161
|
-
suggest: rangeTypes.map((rangeType) => ({
|
|
162
|
-
fix(fixer) {
|
|
163
|
-
return fixer.replaceText(
|
|
164
|
-
property.value,
|
|
165
|
-
`"${changeVersionRange(version, rangeType)}"`
|
|
166
|
-
);
|
|
167
|
-
},
|
|
168
|
-
messageId: `changeTo${capitalize(rangeType)}`
|
|
169
|
-
}))
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
},
|
|
178
|
-
meta: {
|
|
179
|
-
docs: {
|
|
180
|
-
description: "Restricts the range of dependencies to allow or disallow specific types of ranges."
|
|
181
|
-
},
|
|
182
|
-
hasSuggestions: true,
|
|
183
|
-
messages: {
|
|
184
|
-
changeToCaret: "Change to use a caret range.",
|
|
185
|
-
changeToPin: "Pin the version.",
|
|
186
|
-
changeToTilde: "Change to use a tilde range.",
|
|
187
|
-
wrongRangeType: "This dependency is using the wrong range type. Acceptable range type(s): {{rangeTypes}}"
|
|
188
|
-
},
|
|
189
|
-
schema: [
|
|
190
|
-
{
|
|
191
|
-
oneOf: [
|
|
192
|
-
schemaOptions,
|
|
193
|
-
{
|
|
194
|
-
items: schemaOptions,
|
|
195
|
-
type: "array"
|
|
196
|
-
}
|
|
197
|
-
]
|
|
198
|
-
}
|
|
199
|
-
],
|
|
200
|
-
type: "suggestion"
|
|
201
|
-
}
|
|
74
|
+
create(context) {
|
|
75
|
+
if (!context.options[0]) return {};
|
|
76
|
+
const optionsProvided = Array.isArray(context.options[0]) ? [...context.options[0]].reverse() : [context.options[0]];
|
|
77
|
+
const optionsArray = optionsProvided.map((option) => ({
|
|
78
|
+
...option,
|
|
79
|
+
forPackages: option.forPackages?.map((pattern) => new RegExp(pattern)),
|
|
80
|
+
rangeTypes: Array.isArray(option.rangeType) ? option.rangeType : [option.rangeType]
|
|
81
|
+
}));
|
|
82
|
+
return { "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral][value.type=JSONObjectExpression]"(node) {
|
|
83
|
+
const dependencyType = node.key.value;
|
|
84
|
+
if (!DEPENDENCY_TYPES.includes(dependencyType)) return;
|
|
85
|
+
for (const property of node.value.properties) {
|
|
86
|
+
if (!isJSONStringLiteral(property.key) || !isJSONStringLiteral(property.value)) continue;
|
|
87
|
+
const name = property.key.value;
|
|
88
|
+
const version = property.value.value;
|
|
89
|
+
if (!isVersionSupported(version)) continue;
|
|
90
|
+
const isPinned = !!semver.parse(version) || version === "workspace:*";
|
|
91
|
+
const isTildeRange = !!semver.validRange(version) && version.startsWith("~") || version.startsWith("workspace:~");
|
|
92
|
+
const isCaretRange = !!semver.validRange(version) && version.startsWith("^") || version.startsWith("workspace:^");
|
|
93
|
+
for (const options of optionsArray) {
|
|
94
|
+
if (options.forDependencyTypes && !options.forDependencyTypes.includes(dependencyType)) continue;
|
|
95
|
+
if (options.forPackages) {
|
|
96
|
+
const isMatch = options.forPackages.some((packageNameRegex) => packageNameRegex.test(name));
|
|
97
|
+
if (!isMatch) continue;
|
|
98
|
+
}
|
|
99
|
+
if (options.forVersions && (/^workspace:[^~*]?$/.test(version) || version !== "*" && !semver.satisfies(version.replace(/(?:workspace:)?[^~]?/, ""), options.forVersions))) continue;
|
|
100
|
+
const rangeTypes = options.rangeTypes;
|
|
101
|
+
if (version === "*") {
|
|
102
|
+
context.report({
|
|
103
|
+
data: { rangeTypes: rangeTypes.join(", ") },
|
|
104
|
+
messageId: "wrongRangeType",
|
|
105
|
+
node: property.value
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
const rangeTypeMatch = rangeTypes.find((rangeType) => {
|
|
110
|
+
switch (rangeType) {
|
|
111
|
+
case "caret": return isCaretRange;
|
|
112
|
+
case "pin": return isPinned;
|
|
113
|
+
case "tilde": return isTildeRange;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (!rangeTypeMatch) context.report({
|
|
117
|
+
data: { rangeTypes: rangeTypes.join(", ") },
|
|
118
|
+
messageId: "wrongRangeType",
|
|
119
|
+
node: property.value,
|
|
120
|
+
suggest: rangeTypes.map((rangeType) => ({
|
|
121
|
+
fix(fixer) {
|
|
122
|
+
return fixer.replaceText(property.value, `"${changeVersionRange(version, rangeType)}"`);
|
|
123
|
+
},
|
|
124
|
+
messageId: `changeTo${capitalize(rangeType)}`
|
|
125
|
+
}))
|
|
126
|
+
});
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} };
|
|
131
|
+
},
|
|
132
|
+
meta: {
|
|
133
|
+
defaultOptions: [[]],
|
|
134
|
+
docs: { description: "Restricts the range of dependencies to allow or disallow specific types of ranges." },
|
|
135
|
+
hasSuggestions: true,
|
|
136
|
+
messages: {
|
|
137
|
+
changeToCaret: "Change to use a caret range.",
|
|
138
|
+
changeToPin: "Pin the version.",
|
|
139
|
+
changeToTilde: "Change to use a tilde range.",
|
|
140
|
+
wrongRangeType: "This dependency is using the wrong range type. Acceptable range type(s): {{rangeTypes}}"
|
|
141
|
+
},
|
|
142
|
+
schema: [{ oneOf: [schemaOptions, {
|
|
143
|
+
description: "Array of configuration options, specifying range requirements.",
|
|
144
|
+
items: schemaOptions,
|
|
145
|
+
type: "array"
|
|
146
|
+
}] }],
|
|
147
|
+
type: "suggestion"
|
|
148
|
+
},
|
|
149
|
+
name: "restrict-dependency-ranges"
|
|
202
150
|
});
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
export { rule };
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as jsonc_eslint_parser from 'jsonc-eslint-parser';
|
|
3
|
-
import { PackageJsonRuleContext } from '../createRule.js';
|
|
4
|
-
import 'estree';
|
|
1
|
+
import { PackageJsonRuleModule } from "../createRule.js";
|
|
5
2
|
|
|
3
|
+
//#region src/rules/sort-collections.d.ts
|
|
6
4
|
type Options = string[];
|
|
7
|
-
declare const rule:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export { rule };
|
|
5
|
+
declare const rule: PackageJsonRuleModule<Options>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { rule };
|
|
@@ -1,128 +1,75 @@
|
|
|
1
1
|
import { createRule } from "../createRule.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import sortPackageJson from "sort-package-json";
|
|
3
|
+
|
|
4
|
+
//#region src/rules/sort-collections.ts
|
|
5
|
+
const defaultCollections = new Set([
|
|
6
|
+
"config",
|
|
7
|
+
"dependencies",
|
|
8
|
+
"devDependencies",
|
|
9
|
+
"exports",
|
|
10
|
+
"optionalDependencies",
|
|
11
|
+
"overrides",
|
|
12
|
+
"peerDependencies",
|
|
13
|
+
"peerDependenciesMeta",
|
|
14
|
+
"scripts"
|
|
12
15
|
]);
|
|
13
16
|
const rule = createRule({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return aKey > bKey ? 1 : -1;
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
if (currentOrder.some(
|
|
73
|
-
(property, i) => desiredOrder[i] !== property
|
|
74
|
-
)) {
|
|
75
|
-
context.report({
|
|
76
|
-
data: {
|
|
77
|
-
key
|
|
78
|
-
},
|
|
79
|
-
fix(fixer) {
|
|
80
|
-
return fixer.replaceText(
|
|
81
|
-
collection,
|
|
82
|
-
JSON.stringify(
|
|
83
|
-
desiredOrder.reduce((out, property) => {
|
|
84
|
-
out[property.key.value] = JSON.parse(
|
|
85
|
-
context.sourceCode.getText(
|
|
86
|
-
property.value
|
|
87
|
-
)
|
|
88
|
-
);
|
|
89
|
-
return out;
|
|
90
|
-
}, {}),
|
|
91
|
-
null,
|
|
92
|
-
2
|
|
93
|
-
).split("\n").join("\n ")
|
|
94
|
-
// nest indents
|
|
95
|
-
);
|
|
96
|
-
},
|
|
97
|
-
loc: collection.loc,
|
|
98
|
-
messageId: "notAlphabetized",
|
|
99
|
-
node
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
},
|
|
105
|
-
meta: {
|
|
106
|
-
docs: {
|
|
107
|
-
category: "Best Practices",
|
|
108
|
-
description: "Dependencies, scripts, and configuration values must be declared in alphabetical order.",
|
|
109
|
-
recommended: true
|
|
110
|
-
},
|
|
111
|
-
fixable: "code",
|
|
112
|
-
messages: {
|
|
113
|
-
notAlphabetized: "Package {{ key }} are not alphabetized"
|
|
114
|
-
},
|
|
115
|
-
schema: [
|
|
116
|
-
{
|
|
117
|
-
items: {
|
|
118
|
-
type: "string"
|
|
119
|
-
},
|
|
120
|
-
type: "array"
|
|
121
|
-
}
|
|
122
|
-
],
|
|
123
|
-
type: "layout"
|
|
124
|
-
}
|
|
17
|
+
create(context) {
|
|
18
|
+
const toSort = context.options[0] ? new Set(context.options[0]) : defaultCollections;
|
|
19
|
+
return { "JSONProperty:exit"(node) {
|
|
20
|
+
const { key: nodeKey, value: collection } = node;
|
|
21
|
+
if (nodeKey.type !== "JSONLiteral" || collection.type !== "JSONObjectExpression") return;
|
|
22
|
+
const keyPartsReversed = [nodeKey.value];
|
|
23
|
+
for (let currNode = node.parent; currNode; currNode = currNode.parent) if (currNode.type === "JSONProperty" && currNode.key.type === "JSONLiteral") keyPartsReversed.push(currNode.key.value);
|
|
24
|
+
else if (currNode.type === "JSONArrayExpression") return;
|
|
25
|
+
const key = keyPartsReversed.reverse().join(".");
|
|
26
|
+
if (!toSort.has(key)) return;
|
|
27
|
+
const currentOrder = collection.properties;
|
|
28
|
+
let desiredOrder;
|
|
29
|
+
if (keyPartsReversed.at(-1) !== "scripts") desiredOrder = currentOrder.slice().sort((a, b) => {
|
|
30
|
+
const aKey = a.key.value;
|
|
31
|
+
const bKey = b.key.value;
|
|
32
|
+
return aKey > bKey ? 1 : -1;
|
|
33
|
+
});
|
|
34
|
+
else {
|
|
35
|
+
const scriptsSource = context.sourceCode.getText(node);
|
|
36
|
+
const minimalJson = JSON.parse(`{${scriptsSource}}`);
|
|
37
|
+
const { scripts: sortedScripts } = sortPackageJson(minimalJson);
|
|
38
|
+
const propertyNodeMap = Object.fromEntries(collection.properties.map((prop) => [prop.key.value, prop]));
|
|
39
|
+
desiredOrder = Object.keys(sortedScripts).map((prop) => propertyNodeMap[prop]);
|
|
40
|
+
}
|
|
41
|
+
if (currentOrder.some((property, i) => desiredOrder[i] !== property)) context.report({
|
|
42
|
+
data: { key },
|
|
43
|
+
fix(fixer) {
|
|
44
|
+
return fixer.replaceText(collection, JSON.stringify(desiredOrder.reduce((out, property) => {
|
|
45
|
+
out[property.key.value] = JSON.parse(context.sourceCode.getText(property.value));
|
|
46
|
+
return out;
|
|
47
|
+
}, {}), null, 2).split("\n").join("\n "));
|
|
48
|
+
},
|
|
49
|
+
loc: collection.loc,
|
|
50
|
+
messageId: "notAlphabetized",
|
|
51
|
+
node
|
|
52
|
+
});
|
|
53
|
+
} };
|
|
54
|
+
},
|
|
55
|
+
meta: {
|
|
56
|
+
defaultOptions: [Array.from(defaultCollections)],
|
|
57
|
+
docs: {
|
|
58
|
+
category: "Best Practices",
|
|
59
|
+
description: "Dependencies, scripts, and configuration values must be declared in alphabetical order.",
|
|
60
|
+
recommended: true
|
|
61
|
+
},
|
|
62
|
+
fixable: "code",
|
|
63
|
+
messages: { notAlphabetized: "Package {{ key }} are not alphabetized" },
|
|
64
|
+
schema: [{
|
|
65
|
+
description: "Array of package properties to require sorting.",
|
|
66
|
+
items: { type: "string" },
|
|
67
|
+
type: "array"
|
|
68
|
+
}],
|
|
69
|
+
type: "layout"
|
|
70
|
+
},
|
|
71
|
+
name: "sort-collections"
|
|
125
72
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { rule };
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as jsonc_eslint_parser from 'jsonc-eslint-parser';
|
|
3
|
-
import { PackageJsonRuleContext } from '../createRule.js';
|
|
4
|
-
import 'estree';
|
|
1
|
+
import { PackageJsonRuleModule } from "../createRule.js";
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export { rule };
|
|
3
|
+
//#region src/rules/unique-dependencies.d.ts
|
|
4
|
+
declare const rule: PackageJsonRuleModule<unknown[]>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { rule };
|