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,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
- "dependencies",
6
- "devDependencies",
7
- "optionalDependencies",
8
- "peerDependencies"
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
- additionalProperties: false,
13
- properties: {
14
- forDependencyTypes: {
15
- items: {
16
- enum: DEPENDENCY_TYPES
17
- },
18
- type: "array"
19
- },
20
- forPackages: {
21
- items: {
22
- type: "string"
23
- },
24
- type: "array"
25
- },
26
- forVersions: {
27
- type: "string"
28
- },
29
- rangeType: {
30
- oneOf: [
31
- {
32
- enum: RANGE_TYPES
33
- },
34
- {
35
- items: {
36
- enum: RANGE_TYPES
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
- caret: "^",
48
- pin: "",
49
- tilde: "~"
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
- if (/^workspace:[~^*]$/.test(version)) {
53
- switch (rangeType) {
54
- case "caret":
55
- return "workspace:^";
56
- case "pin":
57
- return "workspace:*";
58
- case "tilde":
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
- if (/^workspace:[*^~]$/.test(version)) {
70
- return true;
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
- return str.charAt(0).toUpperCase() + str.slice(1);
71
+ return str.charAt(0).toUpperCase() + str.slice(1);
77
72
  };
78
73
  const rule = createRule({
79
- create(context) {
80
- if (!context.options[0]) {
81
- return {};
82
- }
83
- const optionsProvided = Array.isArray(context.options[0]) ? [...context.options[0]].reverse() : [context.options[0]];
84
- const optionsArray = optionsProvided.map((option) => ({
85
- ...option,
86
- forPackages: option.forPackages?.map(
87
- (pattern) => new RegExp(pattern)
88
- ),
89
- rangeTypes: Array.isArray(option.rangeType) ? option.rangeType : [option.rangeType]
90
- }));
91
- return {
92
- "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral][value.type=JSONObjectExpression]"(node) {
93
- const dependencyType = node.key.value;
94
- if (!DEPENDENCY_TYPES.includes(dependencyType)) {
95
- return;
96
- }
97
- for (const property of node.value.properties) {
98
- if (!isJSONStringLiteral(property.key) || !isJSONStringLiteral(property.value)) {
99
- continue;
100
- }
101
- const name = property.key.value;
102
- const version = property.value.value;
103
- if (!isVersionSupported(version)) {
104
- continue;
105
- }
106
- const isPinned = !!semver.parse(version) || version === "workspace:*";
107
- const isTildeRange = !!semver.validRange(version) && version.startsWith("~") || version.startsWith("workspace:~");
108
- const isCaretRange = !!semver.validRange(version) && version.startsWith("^") || version.startsWith("workspace:^");
109
- for (const options of optionsArray) {
110
- if (options.forDependencyTypes && !options.forDependencyTypes.includes(dependencyType)) {
111
- continue;
112
- }
113
- if (options.forPackages) {
114
- const isMatch = options.forPackages.some(
115
- (packageNameRegex) => packageNameRegex.test(name)
116
- );
117
- if (!isMatch) {
118
- continue;
119
- }
120
- }
121
- if (options.forVersions && // We can't determine whether any workspace version without a numeric version to accompany it, matches this range
122
- // so we'll just skip it.
123
- (/^workspace:[^~*]?$/.test(version) || // * matches all
124
- version !== "*" && !semver.satisfies(
125
- version.replace(
126
- /(?:workspace:)?[^~]?/,
127
- ""
128
- ),
129
- options.forVersions
130
- ))) {
131
- continue;
132
- }
133
- const rangeTypes = options.rangeTypes;
134
- if (version === "*") {
135
- context.report({
136
- data: {
137
- rangeTypes: rangeTypes.join(", ")
138
- },
139
- messageId: "wrongRangeType",
140
- node: property.value
141
- });
142
- break;
143
- }
144
- const rangeTypeMatch = rangeTypes.find((rangeType) => {
145
- switch (rangeType) {
146
- case "caret":
147
- return isCaretRange;
148
- case "pin":
149
- return isPinned;
150
- case "tilde":
151
- return isTildeRange;
152
- }
153
- });
154
- if (!rangeTypeMatch) {
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
- export {
204
- rule
205
- };
151
+
152
+ //#endregion
153
+ export { rule };
@@ -1,12 +1,7 @@
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/sort-collections.d.ts
6
4
  type Options = string[];
7
- declare const rule: {
8
- create(context: PackageJsonRuleContext<Options>): jsonc_eslint_parser.RuleListener;
9
- meta: eslint.Rule.RuleMetaData;
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
- const defaultCollections = /* @__PURE__ */ new Set([
3
- "config",
4
- "dependencies",
5
- "devDependencies",
6
- "exports",
7
- "optionalDependencies",
8
- "overrides",
9
- "peerDependencies",
10
- "peerDependenciesMeta",
11
- "scripts"
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
- create(context) {
15
- const toSort = context.options[0] ? new Set(context.options[0]) : defaultCollections;
16
- return {
17
- "JSONProperty:exit"(node) {
18
- const { key: nodeKey, value: collection } = node;
19
- if (nodeKey.type !== "JSONLiteral" || collection.type !== "JSONObjectExpression") {
20
- return;
21
- }
22
- const keyPartsReversed = [nodeKey.value];
23
- for (
24
- let currNode = node.parent;
25
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
26
- currNode;
27
- currNode = currNode.parent
28
- ) {
29
- if (currNode.type === "JSONProperty" && currNode.key.type === "JSONLiteral") {
30
- keyPartsReversed.push(currNode.key.value);
31
- } else if (currNode.type === "JSONArrayExpression") {
32
- return;
33
- }
34
- }
35
- const key = keyPartsReversed.reverse().join(".");
36
- if (!toSort.has(key)) {
37
- return;
38
- }
39
- const currentOrder = collection.properties;
40
- const properties = new Set(
41
- currentOrder.map(
42
- (prop) => prop.key.value
43
- )
44
- );
45
- const desiredOrder = currentOrder.slice().sort((a, b) => {
46
- let aKey = a.key.value;
47
- let bKey = b.key.value;
48
- if (keyPartsReversed.at(-1) !== "scripts") {
49
- return aKey > bKey ? 1 : -1;
50
- } else {
51
- let modifier = 0;
52
- if (aKey.startsWith("pre") && properties.has(aKey.substring(3))) {
53
- aKey = aKey.substring(3);
54
- modifier -= 1;
55
- } else if (aKey.startsWith("post") && properties.has(aKey.substring(4))) {
56
- aKey = aKey.substring(4);
57
- modifier += 1;
58
- }
59
- if (bKey.startsWith("pre") && properties.has(bKey.substring(3))) {
60
- bKey = bKey.substring(3);
61
- modifier += 1;
62
- } else if (bKey.startsWith("post") && properties.has(bKey.substring(4))) {
63
- bKey = bKey.substring(4);
64
- modifier -= 1;
65
- }
66
- if (aKey === bKey) {
67
- return modifier;
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
- export {
127
- rule
128
- };
73
+
74
+ //#endregion
75
+ 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/unique-dependencies.d.ts
4
+ declare const rule: PackageJsonRuleModule<unknown[]>;
5
+ //#endregion
6
+ export { rule };