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.
Files changed (55) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/lib/createRule.d.ts +28 -28
  3. package/lib/createRule.js +18 -12
  4. package/lib/index.d.ts +33 -35
  5. package/lib/index.js +6 -6
  6. package/lib/plugin.d.ts +33 -34
  7. package/lib/plugin.js +62 -80
  8. package/lib/rules/no-empty-fields.d.ts +6 -11
  9. package/lib/rules/no-empty-fields.js +80 -112
  10. package/lib/rules/no-redundant-files.d.ts +5 -10
  11. package/lib/rules/no-redundant-files.js +93 -136
  12. package/lib/rules/order-properties.d.ts +6 -11
  13. package/lib/rules/order-properties.js +92 -116
  14. package/lib/rules/repository-shorthand.d.ts +6 -11
  15. package/lib/rules/repository-shorthand.js +79 -112
  16. package/lib/rules/require-properties.d.ts +7 -12
  17. package/lib/rules/require-properties.js +31 -27
  18. package/lib/rules/restrict-dependency-ranges.d.ts +9 -14
  19. package/lib/rules/restrict-dependency-ranges.js +137 -189
  20. package/lib/rules/sort-collections.d.ts +5 -10
  21. package/lib/rules/sort-collections.js +71 -124
  22. package/lib/rules/unique-dependencies.d.ts +5 -10
  23. package/lib/rules/unique-dependencies.js +58 -82
  24. package/lib/rules/valid-bin.d.ts +6 -11
  25. package/lib/rules/valid-bin.js +59 -78
  26. package/lib/rules/valid-local-dependency.d.ts +5 -10
  27. package/lib/rules/valid-local-dependency.js +49 -57
  28. package/lib/rules/valid-name.d.ts +5 -10
  29. package/lib/rules/valid-name.js +41 -48
  30. package/lib/rules/valid-package-definition.d.ts +6 -11
  31. package/lib/rules/valid-package-definition.js +41 -50
  32. package/lib/rules/valid-properties.d.ts +7 -7
  33. package/lib/rules/valid-properties.js +33 -55
  34. package/lib/rules/valid-repository-directory.d.ts +5 -10
  35. package/lib/rules/valid-repository-directory.js +65 -80
  36. package/lib/rules/valid-version.d.ts +5 -10
  37. package/lib/rules/valid-version.js +35 -36
  38. package/lib/types/estree.d.ts +8 -0
  39. package/lib/utils/createSimpleRequirePropertyRule.d.ts +19 -18
  40. package/lib/utils/createSimpleRequirePropertyRule.js +48 -53
  41. package/lib/utils/createSimpleValidPropertyRule.d.ts +6 -8
  42. package/lib/utils/createSimpleValidPropertyRule.js +45 -39
  43. package/lib/utils/findPropertyWithKeyValue.d.ts +6 -5
  44. package/lib/utils/findPropertyWithKeyValue.js +5 -6
  45. package/lib/utils/formatErrors.d.ts +3 -2
  46. package/lib/utils/formatErrors.js +11 -7
  47. package/lib/utils/isPackageJson.d.ts +3 -2
  48. package/lib/utils/isPackageJson.js +4 -3
  49. package/lib/utils/predicates.d.ts +4 -3
  50. package/lib/utils/predicates.js +6 -6
  51. package/package.json +8 -8
  52. package/lib/tests/rules/ruleTester.d.ts +0 -15
  53. package/lib/tests/rules/ruleTester.js +0 -25
  54. package/lib/types/estree.d.d.ts +0 -7
  55. 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
- switch (node.type) {
8
- case "JSONArrayExpression":
9
- return {
10
- data: {
11
- expressionType: "array"
12
- },
13
- messageId: "emptyExpression"
14
- };
15
- case "JSONObjectExpression":
16
- return {
17
- data: {
18
- expressionType: "object"
19
- },
20
- messageId: "emptyExpression"
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
- const { data, messageId } = getDataAndMessageId(node);
33
- context.report({
34
- data,
35
- messageId,
36
- node,
37
- suggest: [
38
- {
39
- fix: node.type === "JSONProperty" ? fixRemoveObjectProperty(
40
- context,
41
- node
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
- return node.parent.type === "JSONProperty" ? node.parent : node;
34
+ return node.parent.type === "JSONProperty" ? node.parent : node;
54
35
  };
55
36
  const getTopLevelProperty = (node) => {
56
- let n = node;
57
- while (n.parent.parent?.parent?.type !== void 0 && n.parent.parent.parent.type !== "Program") {
58
- n = n.parent;
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
- create(context) {
64
- const ignoreProperties = context.options[0]?.ignoreProperties ?? [];
65
- return {
66
- JSONArrayExpression(node) {
67
- const topLevelProperty = getTopLevelProperty(node);
68
- if (!topLevelProperty) {
69
- return;
70
- }
71
- if (!node.elements.length) {
72
- const topLevelPropertyName = topLevelProperty.value;
73
- if (!ignoreProperties.includes(topLevelPropertyName)) {
74
- report(context, getNode(node));
75
- }
76
- }
77
- },
78
- JSONObjectExpression(node) {
79
- const topLevelProperty = getTopLevelProperty(node);
80
- if (!topLevelProperty) {
81
- return;
82
- }
83
- if (!node.properties.length) {
84
- const topLevelPropertyName = topLevelProperty.value;
85
- if (!ignoreProperties.includes(topLevelPropertyName)) {
86
- report(context, getNode(node));
87
- }
88
- }
89
- }
90
- };
91
- },
92
- meta: {
93
- docs: {
94
- category: "Best Practices",
95
- description: "Reports on unnecessary empty arrays and objects.",
96
- recommended: true
97
- },
98
- hasSuggestions: true,
99
- messages: {
100
- emptyExpression: "This {{expressionType}} does nothing and can be removed.",
101
- emptyFields: "The field '{{field}}' does nothing and can be removed.",
102
- remove: "Remove this empty field."
103
- },
104
- schema: [
105
- {
106
- additionalProperties: false,
107
- properties: {
108
- ignoreProperties: {
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
- export {
122
- rule
123
- };
89
+
90
+ //#endregion
91
+ export { rule };
@@ -1,11 +1,6 @@
1
- import * as eslint from 'eslint';
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
- declare const rule: {
7
- create(context: PackageJsonRuleContext<unknown[]>): jsonc_eslint_parser.RuleListener;
8
- meta: eslint.Rule.RuleMetaData;
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
- /* cspell:disable-next-line */
6
- /^(\.\/)?LICEN(C|S)E(\.|$)/i,
7
- /^(\.\/)?README(\.|$)/i,
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
- if (wildcardsRegex.test(filename)) {
14
- return null;
15
- }
16
- const baseFilename = filename.replace("./", "");
17
- let regex = cachedRegex.get(baseFilename);
18
- if (regex) {
19
- return regex;
20
- } else {
21
- regex = new RegExp(`^(./)?${baseFilename}$`, "i");
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
- create(context) {
28
- const entryCache = { bin: [], files: [] };
29
- const report = (elements, index, messageId) => {
30
- const element = elements[index];
31
- if (isNotNullish(element) && isJSONStringLiteral(element)) {
32
- context.report({
33
- data: { file: element.value },
34
- messageId,
35
- node: element,
36
- suggest: [
37
- {
38
- fix: fixRemoveArrayElement(
39
- context,
40
- index,
41
- elements
42
- ),
43
- messageId: "remove"
44
- }
45
- ]
46
- });
47
- }
48
- };
49
- return {
50
- "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=bin]"(node) {
51
- const binValue = node.value;
52
- if (isJSONStringLiteral(binValue)) {
53
- entryCache.bin.push(binValue.value);
54
- } else if (binValue.type === "JSONObjectExpression") {
55
- for (const prop of binValue.properties) {
56
- if (isJSONStringLiteral(prop.value)) {
57
- entryCache.bin.push(prop.value.value);
58
- }
59
- }
60
- }
61
- },
62
- "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=files]"(node) {
63
- if (node.value.type === "JSONArrayExpression") {
64
- const seen = /* @__PURE__ */ new Set();
65
- const elements = node.value.elements;
66
- entryCache.files = elements;
67
- for (const [index, element] of elements.entries()) {
68
- if (isNotNullish(element) && isJSONStringLiteral(element)) {
69
- if (seen.has(element.value)) {
70
- report(elements, index, "duplicate");
71
- } else {
72
- seen.add(element.value);
73
- }
74
- for (const defaultFile of defaultFiles) {
75
- if (defaultFile.test(element.value)) {
76
- report(
77
- elements,
78
- index,
79
- "unnecessaryDefault"
80
- );
81
- }
82
- }
83
- }
84
- }
85
- }
86
- },
87
- "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=main]"(node) {
88
- if (isJSONStringLiteral(node.value)) {
89
- entryCache.main = node.value.value;
90
- }
91
- },
92
- "Program:exit"() {
93
- const files = entryCache.files;
94
- if (files.length === 0) {
95
- return;
96
- }
97
- const validations = [
98
- // First check if the "main" entry is included in "files".
99
- {
100
- files: entryCache.main ? [entryCache.main] : [],
101
- messageId: "unnecessaryMain"
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
- export {
145
- rule
146
- };
101
+
102
+ //#endregion
103
+ export { rule };
@@ -1,15 +1,10 @@
1
- import * as eslint from 'eslint';
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
- order: Order;
5
+ order: Order;
8
6
  }?];
9
7
  type Order = "legacy" | "sort-package-json" | string[];
10
- declare const rule: {
11
- create(context: PackageJsonRuleContext<Options>): jsonc_eslint_parser.RuleListener;
12
- meta: eslint.Rule.RuleMetaData;
13
- };
14
-
15
- export { rule };
8
+ declare const rule: PackageJsonRuleModule<Options>;
9
+ //#endregion
10
+ export { rule };