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,123 +1,91 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fixRemoveArrayElement,
|
|
3
|
-
fixRemoveObjectProperty
|
|
4
|
-
} from "eslint-fix-utils";
|
|
5
1
|
import { createRule } from "../createRule.js";
|
|
2
|
+
import { fixRemoveArrayElement, fixRemoveObjectProperty } from "eslint-fix-utils";
|
|
3
|
+
|
|
4
|
+
//#region src/rules/no-empty-fields.ts
|
|
6
5
|
const getDataAndMessageId = (node) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
case "JSONProperty":
|
|
23
|
-
return {
|
|
24
|
-
data: {
|
|
25
|
-
field: node.key.value
|
|
26
|
-
},
|
|
27
|
-
messageId: "emptyFields"
|
|
28
|
-
};
|
|
29
|
-
}
|
|
6
|
+
switch (node.type) {
|
|
7
|
+
case "JSONArrayExpression": return {
|
|
8
|
+
data: { expressionType: "array" },
|
|
9
|
+
messageId: "emptyExpression"
|
|
10
|
+
};
|
|
11
|
+
case "JSONObjectExpression": return {
|
|
12
|
+
data: { expressionType: "object" },
|
|
13
|
+
messageId: "emptyExpression"
|
|
14
|
+
};
|
|
15
|
+
case "JSONProperty": return {
|
|
16
|
+
data: { field: node.key.value },
|
|
17
|
+
messageId: "emptyFields"
|
|
18
|
+
};
|
|
19
|
+
}
|
|
30
20
|
};
|
|
31
21
|
const report = (context, node) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
) : fixRemoveArrayElement(
|
|
43
|
-
context,
|
|
44
|
-
node,
|
|
45
|
-
node.parent
|
|
46
|
-
),
|
|
47
|
-
messageId: "remove"
|
|
48
|
-
}
|
|
49
|
-
]
|
|
50
|
-
});
|
|
22
|
+
const { data, messageId } = getDataAndMessageId(node);
|
|
23
|
+
context.report({
|
|
24
|
+
data,
|
|
25
|
+
messageId,
|
|
26
|
+
node,
|
|
27
|
+
suggest: [{
|
|
28
|
+
fix: node.type === "JSONProperty" ? fixRemoveObjectProperty(context, node) : fixRemoveArrayElement(context, node, node.parent),
|
|
29
|
+
messageId: "remove"
|
|
30
|
+
}]
|
|
31
|
+
});
|
|
51
32
|
};
|
|
52
33
|
const getNode = (node) => {
|
|
53
|
-
|
|
34
|
+
return node.parent.type === "JSONProperty" ? node.parent : node;
|
|
54
35
|
};
|
|
55
36
|
const getTopLevelProperty = (node) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
return n.type === "JSONProperty" ? n.key : void 0;
|
|
37
|
+
let n = node;
|
|
38
|
+
while (n.parent.parent?.parent?.type !== void 0 && n.parent.parent.parent.type !== "Program") n = n.parent;
|
|
39
|
+
return n.type === "JSONProperty" ? n.key : void 0;
|
|
61
40
|
};
|
|
62
41
|
const rule = createRule({
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
items: {
|
|
110
|
-
type: "string"
|
|
111
|
-
},
|
|
112
|
-
type: "array"
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
type: "object"
|
|
116
|
-
}
|
|
117
|
-
],
|
|
118
|
-
type: "suggestion"
|
|
119
|
-
}
|
|
42
|
+
create(context) {
|
|
43
|
+
const ignoreProperties = context.options[0]?.ignoreProperties ?? [];
|
|
44
|
+
return {
|
|
45
|
+
JSONArrayExpression(node) {
|
|
46
|
+
const topLevelProperty = getTopLevelProperty(node);
|
|
47
|
+
if (!topLevelProperty) return;
|
|
48
|
+
if (!node.elements.length) {
|
|
49
|
+
const topLevelPropertyName = topLevelProperty.value;
|
|
50
|
+
if (!ignoreProperties.includes(topLevelPropertyName)) report(context, getNode(node));
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
JSONObjectExpression(node) {
|
|
54
|
+
const topLevelProperty = getTopLevelProperty(node);
|
|
55
|
+
if (!topLevelProperty) return;
|
|
56
|
+
if (!node.properties.length) {
|
|
57
|
+
const topLevelPropertyName = topLevelProperty.value;
|
|
58
|
+
if (!ignoreProperties.includes(topLevelPropertyName)) report(context, getNode(node));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
meta: {
|
|
64
|
+
defaultOptions: [{ ignoreProperties: [] }],
|
|
65
|
+
docs: {
|
|
66
|
+
category: "Best Practices",
|
|
67
|
+
description: "Reports on unnecessary empty arrays and objects.",
|
|
68
|
+
recommended: true
|
|
69
|
+
},
|
|
70
|
+
hasSuggestions: true,
|
|
71
|
+
messages: {
|
|
72
|
+
emptyExpression: "This {{expressionType}} does nothing and can be removed.",
|
|
73
|
+
emptyFields: "The field '{{field}}' does nothing and can be removed.",
|
|
74
|
+
remove: "Remove this empty field."
|
|
75
|
+
},
|
|
76
|
+
schema: [{
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
properties: { ignoreProperties: {
|
|
79
|
+
description: "Array of top-level properties to ignore.",
|
|
80
|
+
items: { type: "string" },
|
|
81
|
+
type: "array"
|
|
82
|
+
} },
|
|
83
|
+
type: "object"
|
|
84
|
+
}],
|
|
85
|
+
type: "suggestion"
|
|
86
|
+
},
|
|
87
|
+
name: "no-empty-fields"
|
|
120
88
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
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/no-redundant-files.d.ts
|
|
4
|
+
declare const rule: PackageJsonRuleModule<unknown[]>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { rule };
|
|
@@ -1,146 +1,103 @@
|
|
|
1
|
-
import { fixRemoveArrayElement } from "eslint-fix-utils";
|
|
2
1
|
import { createRule } from "../createRule.js";
|
|
3
2
|
import { isJSONStringLiteral, isNotNullish } from "../utils/predicates.js";
|
|
3
|
+
import { fixRemoveArrayElement } from "eslint-fix-utils";
|
|
4
|
+
|
|
5
|
+
//#region src/rules/no-redundant-files.ts
|
|
4
6
|
const defaultFiles = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/^(\.\/)?package\.json$/i
|
|
7
|
+
/^(\.\/)?LICEN(C|S)E(\.|$)/i,
|
|
8
|
+
/^(\.\/)?README(\.|$)/i,
|
|
9
|
+
/^(\.\/)?package\.json$/i
|
|
9
10
|
];
|
|
10
11
|
const wildcardsRegex = /[*?[\]{}]/;
|
|
11
12
|
const cachedRegex = /* @__PURE__ */ new Map();
|
|
12
13
|
const getCachedLocalFileRegex = (filename) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
cachedRegex.set(baseFilename, regex);
|
|
23
|
-
return regex;
|
|
24
|
-
}
|
|
14
|
+
if (wildcardsRegex.test(filename)) return null;
|
|
15
|
+
const baseFilename = filename.replace("./", "");
|
|
16
|
+
let regex = cachedRegex.get(baseFilename);
|
|
17
|
+
if (regex) return regex;
|
|
18
|
+
else {
|
|
19
|
+
regex = new RegExp(`^(./)?${baseFilename}$`, "i");
|
|
20
|
+
cachedRegex.set(baseFilename, regex);
|
|
21
|
+
return regex;
|
|
22
|
+
}
|
|
25
23
|
};
|
|
26
24
|
const rule = createRule({
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
// Next check if any "bin" entries are included in "files".
|
|
104
|
-
{
|
|
105
|
-
files: entryCache.bin,
|
|
106
|
-
messageId: "unnecessaryBin"
|
|
107
|
-
}
|
|
108
|
-
];
|
|
109
|
-
for (const validation of validations) {
|
|
110
|
-
for (const fileToCheck of validation.files) {
|
|
111
|
-
for (const [index, fileEntry] of files.entries()) {
|
|
112
|
-
if (isNotNullish(fileEntry) && isJSONStringLiteral(fileEntry)) {
|
|
113
|
-
const regex = getCachedLocalFileRegex(
|
|
114
|
-
fileEntry.value
|
|
115
|
-
);
|
|
116
|
-
if (regex?.test(fileToCheck)) {
|
|
117
|
-
report(files, index, validation.messageId);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
},
|
|
126
|
-
meta: {
|
|
127
|
-
docs: {
|
|
128
|
-
category: "Best Practices",
|
|
129
|
-
description: "Prevents adding unnecessary / redundant files.",
|
|
130
|
-
recommended: false
|
|
131
|
-
},
|
|
132
|
-
hasSuggestions: true,
|
|
133
|
-
messages: {
|
|
134
|
-
duplicate: 'Files has more than one entry for "{{file}}".',
|
|
135
|
-
remove: "Remove this redundant entry.",
|
|
136
|
-
unnecessaryBin: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's included in "bin".`,
|
|
137
|
-
unnecessaryDefault: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's included by default.`,
|
|
138
|
-
unnecessaryMain: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's the "main" entry.`
|
|
139
|
-
},
|
|
140
|
-
schema: [],
|
|
141
|
-
type: "suggestion"
|
|
142
|
-
}
|
|
25
|
+
create(context) {
|
|
26
|
+
const entryCache = {
|
|
27
|
+
bin: [],
|
|
28
|
+
files: []
|
|
29
|
+
};
|
|
30
|
+
const report = (elements, index, messageId) => {
|
|
31
|
+
const element = elements[index];
|
|
32
|
+
if (isNotNullish(element) && isJSONStringLiteral(element)) context.report({
|
|
33
|
+
data: { file: element.value },
|
|
34
|
+
messageId,
|
|
35
|
+
node: element,
|
|
36
|
+
suggest: [{
|
|
37
|
+
fix: fixRemoveArrayElement(context, index, elements),
|
|
38
|
+
messageId: "remove"
|
|
39
|
+
}]
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=bin]"(node) {
|
|
44
|
+
const binValue = node.value;
|
|
45
|
+
if (isJSONStringLiteral(binValue)) entryCache.bin.push(binValue.value);
|
|
46
|
+
else if (binValue.type === "JSONObjectExpression") {
|
|
47
|
+
for (const prop of binValue.properties) if (isJSONStringLiteral(prop.value)) entryCache.bin.push(prop.value.value);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=files]"(node) {
|
|
51
|
+
if (node.value.type === "JSONArrayExpression") {
|
|
52
|
+
const seen = /* @__PURE__ */ new Set();
|
|
53
|
+
const elements = node.value.elements;
|
|
54
|
+
entryCache.files = elements;
|
|
55
|
+
for (const [index, element] of elements.entries()) if (isNotNullish(element) && isJSONStringLiteral(element)) {
|
|
56
|
+
if (seen.has(element.value)) report(elements, index, "duplicate");
|
|
57
|
+
else seen.add(element.value);
|
|
58
|
+
for (const defaultFile of defaultFiles) if (defaultFile.test(element.value)) report(elements, index, "unnecessaryDefault");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=main]"(node) {
|
|
63
|
+
if (isJSONStringLiteral(node.value)) entryCache.main = node.value.value;
|
|
64
|
+
},
|
|
65
|
+
"Program:exit"() {
|
|
66
|
+
const files = entryCache.files;
|
|
67
|
+
if (files.length === 0) return;
|
|
68
|
+
const validations = [{
|
|
69
|
+
files: entryCache.main ? [entryCache.main] : [],
|
|
70
|
+
messageId: "unnecessaryMain"
|
|
71
|
+
}, {
|
|
72
|
+
files: entryCache.bin,
|
|
73
|
+
messageId: "unnecessaryBin"
|
|
74
|
+
}];
|
|
75
|
+
for (const validation of validations) for (const fileToCheck of validation.files) for (const [index, fileEntry] of files.entries()) if (isNotNullish(fileEntry) && isJSONStringLiteral(fileEntry)) {
|
|
76
|
+
const regex = getCachedLocalFileRegex(fileEntry.value);
|
|
77
|
+
if (regex?.test(fileToCheck)) report(files, index, validation.messageId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
meta: {
|
|
83
|
+
docs: {
|
|
84
|
+
category: "Best Practices",
|
|
85
|
+
description: "Prevents adding unnecessary / redundant files.",
|
|
86
|
+
recommended: false
|
|
87
|
+
},
|
|
88
|
+
hasSuggestions: true,
|
|
89
|
+
messages: {
|
|
90
|
+
duplicate: "Files has more than one entry for \"{{file}}\".",
|
|
91
|
+
remove: "Remove this redundant entry.",
|
|
92
|
+
unnecessaryBin: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's included in "bin".`,
|
|
93
|
+
unnecessaryDefault: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's included by default.`,
|
|
94
|
+
unnecessaryMain: `Explicitly declaring "{{file}}" in "files" is unnecessary; it's the "main" entry.`
|
|
95
|
+
},
|
|
96
|
+
schema: [],
|
|
97
|
+
type: "suggestion"
|
|
98
|
+
},
|
|
99
|
+
name: "no-redundant-files"
|
|
143
100
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
};
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
export { rule };
|
|
@@ -1,15 +1,10 @@
|
|
|
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/order-properties.d.ts
|
|
6
4
|
type Options = [{
|
|
7
|
-
|
|
5
|
+
order: Order;
|
|
8
6
|
}?];
|
|
9
7
|
type Order = "legacy" | "sort-package-json" | string[];
|
|
10
|
-
declare const rule:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export { rule };
|
|
8
|
+
declare const rule: PackageJsonRuleModule<Options>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { rule };
|