eslint-plugin-package-json 0.58.0 → 0.59.1

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 CHANGED
@@ -1,11 +1,23 @@
1
1
  # Changelog
2
2
 
3
- # [0.58.0](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.57.0...v0.58.0) (2025-10-22)
3
+ ## [0.59.1](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.59.0...v0.59.1) (2025-10-30)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **deps:** update dependency validate-npm-package-name to v7 ([#1353](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1353)) ([be9970a](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/be9970a18c73521906d1564ca461d94159e88807))
4
9
 
10
+ # [0.59.0](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.58.0...v0.59.0) (2025-10-25)
11
+
12
+ ### Features
13
+
14
+ - **exports-subpaths-style:** add new rule ([#1328](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1328)) ([d1a82ed](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/d1a82edf78b7b4bd446018f1ea3bb77e1bc9c772)), closes [#1322](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1322)
15
+
16
+ # [0.58.0](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.57.0...v0.58.0) (2025-10-22)
5
17
 
6
18
  ### Features
7
19
 
8
- * mark `legacy-recommended` config deprecated ([#1331](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1331)) ([5e20411](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/5e204118f4b6ae4a50f9a50a1c2a64a5bf84a5a7)), closes [#1329](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1329) [#1253](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1253)
20
+ - mark `legacy-recommended` config deprecated ([#1331](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1331)) ([5e20411](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/5e204118f4b6ae4a50f9a50a1c2a64a5bf84a5a7)), closes [#1329](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1329) [#1253](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1253)
9
21
 
10
22
  # [0.57.0](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.4...v0.57.0) (2025-10-16)
11
23
 
package/README.md CHANGED
@@ -166,6 +166,7 @@ The default settings don't conflict, and Prettier plugins can quickly fix up ord
166
166
 
167
167
  | Name                         | Description | 💼 | 🔧 | 💡 | ❌ |
168
168
  | :------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------- | :--- | :- | :- | :- |
169
+ | [exports-subpaths-style](docs/rules/exports-subpaths-style.md) | Enforce consistent format for the exports field (implicit or explicit subpaths). | | 🔧 | | |
169
170
  | [no-empty-fields](docs/rules/no-empty-fields.md) | Reports on unnecessary empty arrays and objects. | ✔️ ✅ | | 💡 | |
170
171
  | [no-redundant-files](docs/rules/no-redundant-files.md) | Prevents adding unnecessary / redundant files. | ✔️ ✅ | | 💡 | |
171
172
  | [order-properties](docs/rules/order-properties.md) | Package properties must be declared in standard order | ✔️ ✅ | 🔧 | | |
@@ -261,7 +262,7 @@ Thanks! 🗂
261
262
  <td align="center" valign="top" width="14.28%"><a href="https://davidlj95.com"><img src="https://avatars.githubusercontent.com/u/8050648?v=4?s=100" width="100px;" alt="David LJ"/><br /><sub><b>David LJ</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=davidlj95" title="Documentation">📖</a></td>
262
263
  <td align="center" valign="top" width="14.28%"><a href="http://lishaduck.github.io"><img src="https://avatars.githubusercontent.com/u/88557639?v=4?s=100" width="100px;" alt="Eli"/><br /><sub><b>Eli</b></sub></a><br /><a href="#ideas-lishaduck" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Alishaduck" title="Bug reports">🐛</a></td>
263
264
  <td align="center" valign="top" width="14.28%"><a href="http://heggria.site"><img src="https://avatars.githubusercontent.com/u/34475327?v=4?s=100" width="100px;" alt="Heggria"/><br /><sub><b>Heggria</b></sub></a><br /><a href="#ideas-heggria" title="Ideas, Planning, & Feedback">🤔</a></td>
264
- <td align="center" valign="top" width="14.28%"><a href="https://hirok.io"><img src="https://avatars.githubusercontent.com/u/1075694?v=4?s=100" width="100px;" alt="Hiroki Osame"/><br /><sub><b>Hiroki Osame</b></sub></a><br /><a href="#ideas-privatenumber" title="Ideas, Planning, & Feedback">🤔</a></td>
265
+ <td align="center" valign="top" width="14.28%"><a href="https://hirok.io"><img src="https://avatars.githubusercontent.com/u/1075694?v=4?s=100" width="100px;" alt="Hiroki Osame"/><br /><sub><b>Hiroki Osame</b></sub></a><br /><a href="#ideas-privatenumber" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=privatenumber" title="Code">💻</a></td>
265
266
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/Zamiell"><img src="https://avatars.githubusercontent.com/u/5511220?v=4?s=100" width="100px;" alt="James"/><br /><sub><b>James</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=Zamiell" title="Code">💻</a> <a href="#ideas-Zamiell" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3AZamiell" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=Zamiell" title="Documentation">📖</a></td>
266
267
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/zetlen"><img src="https://avatars.githubusercontent.com/u/1643758?v=4?s=100" width="100px;" alt="James Zetlen"/><br /><sub><b>James Zetlen</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=zetlen" title="Code">💻</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Azetlen" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=zetlen" title="Documentation">📖</a> <a href="#infra-zetlen" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-zetlen" title="Maintenance">🚧</a> <a href="#tool-zetlen" title="Tools">🔧</a></td>
267
268
  <td align="center" valign="top" width="14.28%"><a href="https://piranna.github.io/"><img src="https://avatars.githubusercontent.com/u/532414?v=4?s=100" width="100px;" alt="Jesús Leganés-Combarro"/><br /><sub><b>Jesús Leganés-Combarro</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=piranna" title="Code">💻</a></td>
package/lib/plugin.js CHANGED
@@ -1,41 +1,43 @@
1
- import { rule } from "./rules/no-empty-fields.js";
2
- import { rule as rule$1 } from "./rules/no-redundant-files.js";
3
- import { rule as rule$2 } from "./rules/order-properties.js";
4
- import { rule as rule$3 } from "./rules/repository-shorthand.js";
1
+ import { rule } from "./rules/exports-subpaths-style.js";
2
+ import { rule as rule$1 } from "./rules/no-empty-fields.js";
3
+ import { rule as rule$2 } from "./rules/no-redundant-files.js";
4
+ import { rule as rule$3 } from "./rules/order-properties.js";
5
+ import { rule as rule$4 } from "./rules/repository-shorthand.js";
5
6
  import { rules } from "./rules/require-properties.js";
6
- import { rule as rule$4 } from "./rules/restrict-dependency-ranges.js";
7
- import { rule as rule$5 } from "./rules/sort-collections.js";
8
- import { rule as rule$6 } from "./rules/unique-dependencies.js";
9
- import { rule as rule$7 } from "./rules/valid-bin.js";
10
- import { rule as rule$8 } from "./rules/valid-local-dependency.js";
11
- import { rule as rule$9 } from "./rules/valid-name.js";
12
- import { rule as rule$10 } from "./rules/valid-package-definition.js";
7
+ import { rule as rule$5 } from "./rules/restrict-dependency-ranges.js";
8
+ import { rule as rule$6 } from "./rules/sort-collections.js";
9
+ import { rule as rule$7 } from "./rules/unique-dependencies.js";
10
+ import { rule as rule$8 } from "./rules/valid-bin.js";
11
+ import { rule as rule$9 } from "./rules/valid-local-dependency.js";
12
+ import { rule as rule$10 } from "./rules/valid-name.js";
13
+ import { rule as rule$11 } from "./rules/valid-package-definition.js";
13
14
  import { rules as rules$1 } from "./rules/valid-properties.js";
14
- import { rule as rule$11 } from "./rules/valid-repository-directory.js";
15
- import { rule as rule$12 } from "./rules/valid-version.js";
15
+ import { rule as rule$12 } from "./rules/valid-repository-directory.js";
16
+ import { rule as rule$13 } from "./rules/valid-version.js";
16
17
  import { createRequire } from "node:module";
17
18
  import * as parserJsonc from "jsonc-eslint-parser";
18
19
 
19
20
  //#region src/plugin.ts
20
21
  const { name, version } = createRequire(import.meta.url)("../package.json");
21
22
  const rules$2 = {
22
- "no-empty-fields": rule,
23
- "no-redundant-files": rule$1,
24
- "order-properties": rule$2,
23
+ "exports-subpaths-style": rule,
24
+ "no-empty-fields": rule$1,
25
+ "no-redundant-files": rule$2,
26
+ "order-properties": rule$3,
25
27
  ...rules,
26
- "repository-shorthand": rule$3,
27
- "restrict-dependency-ranges": rule$4,
28
- "sort-collections": rule$5,
29
- "unique-dependencies": rule$6,
28
+ "repository-shorthand": rule$4,
29
+ "restrict-dependency-ranges": rule$5,
30
+ "sort-collections": rule$6,
31
+ "unique-dependencies": rule$7,
30
32
  ...rules$1,
31
- "valid-bin": rule$7,
32
- "valid-local-dependency": rule$8,
33
- "valid-name": rule$9,
34
- "valid-package-definition": rule$10,
35
- "valid-repository-directory": rule$11,
36
- "valid-version": rule$12
33
+ "valid-bin": rule$8,
34
+ "valid-local-dependency": rule$9,
35
+ "valid-name": rule$10,
36
+ "valid-package-definition": rule$11,
37
+ "valid-repository-directory": rule$12,
38
+ "valid-version": rule$13
37
39
  };
38
- const baseRecommendedRules = { ...Object.fromEntries(Object.entries(rules$2).filter(([, rule$13]) => rule$13.meta.docs?.recommended).map(([name$1]) => ["package-json/" + name$1, "error"])) };
40
+ const baseRecommendedRules = { ...Object.fromEntries(Object.entries(rules$2).filter(([, rule$14]) => rule$14.meta.docs?.recommended).map(([name$1]) => ["package-json/" + name$1, "error"])) };
39
41
  const recommendedRules = {
40
42
  ...baseRecommendedRules,
41
43
  "package-json/valid-package-definition": ["error", { ignoreProperties: Object.entries(baseRecommendedRules).filter(([name$1]) => name$1.startsWith("package-json/valid-") && name$1 !== "package-json/valid-package-definition").map(([name$1]) => name$1.replace("package-json/valid-", "")) }]
@@ -0,0 +1,18 @@
1
+ import { PackageJsonRuleModule } from "../createRule.js";
2
+
3
+ //#region src/rules/exports-subpaths-style.d.ts
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ prefer?: "explicit" | "implicit" | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly prefer: {
10
+ readonly description: "Specifies which exports format to enforce.";
11
+ readonly enum: readonly ["implicit", "explicit"];
12
+ readonly type: "string";
13
+ };
14
+ };
15
+ readonly type: "object";
16
+ }]>;
17
+ //#endregion
18
+ export { rule };
@@ -0,0 +1,73 @@
1
+ import { createRule } from "../createRule.js";
2
+ import { isJSONStringLiteral } from "../utils/predicates.js";
3
+
4
+ //#region src/rules/exports-subpaths-style.ts
5
+ function isImplicitFormat(node) {
6
+ if (node.type === "JSONLiteral") return true;
7
+ return node.properties.every((property) => !isJSONStringLiteral(property.key) || !property.key.value.startsWith("."));
8
+ }
9
+ const rule = createRule({
10
+ create(context) {
11
+ const [{ prefer = "explicit" } = {}] = context.options;
12
+ function validateForExplicit(node) {
13
+ const { value } = node;
14
+ if (value.type !== "JSONLiteral" && value.type !== "JSONObjectExpression" || !isImplicitFormat(value)) return;
15
+ context.report({
16
+ fix(fixer) {
17
+ const valueText = context.sourceCode.getText(value);
18
+ const fixedValue = JSON.stringify({ ".": JSON.parse(valueText) }, null, 2);
19
+ return fixer.replaceText(value, fixedValue);
20
+ },
21
+ messageId: "preferExplicit",
22
+ node: value
23
+ });
24
+ }
25
+ function validateForImplicit(node) {
26
+ const { value } = node;
27
+ if (value.type !== "JSONObjectExpression") return;
28
+ if (value.properties.length !== 1 || !isJSONStringLiteral(value.properties[0].key) || value.properties[0].key.value !== ".") return;
29
+ const dotProperty = value.properties[0];
30
+ context.report({
31
+ fix(fixer) {
32
+ const valueText = context.sourceCode.getText(dotProperty.value);
33
+ const fixedValue = JSON.stringify(JSON.parse(valueText), null, 2);
34
+ return fixer.replaceText(value, fixedValue);
35
+ },
36
+ messageId: "preferImplicit",
37
+ node: value
38
+ });
39
+ }
40
+ return { JSONProperty(node) {
41
+ if (node.key.type !== "JSONLiteral" || node.key.value !== "exports" || node.parent.parent.parent.type !== "Program") return;
42
+ if (prefer === "explicit") validateForExplicit(node);
43
+ else validateForImplicit(node);
44
+ } };
45
+ },
46
+ meta: {
47
+ defaultOptions: [{ prefer: "explicit" }],
48
+ docs: {
49
+ category: "Best Practices",
50
+ description: "Enforce consistent format for the exports field (implicit or explicit subpaths).",
51
+ recommended: false
52
+ },
53
+ fixable: "code",
54
+ messages: {
55
+ preferExplicit: "Prefer explicit subpaths format with \".\" key for single root export.",
56
+ preferImplicit: "Prefer implicit format without \".\" key for single root export."
57
+ },
58
+ schema: [{
59
+ additionalProperties: false,
60
+ properties: { prefer: {
61
+ description: "Specifies which exports format to enforce.",
62
+ enum: ["implicit", "explicit"],
63
+ type: "string"
64
+ } },
65
+ type: "object"
66
+ }],
67
+ type: "suggestion"
68
+ },
69
+ name: "exports-subpaths-style"
70
+ });
71
+
72
+ //#endregion
73
+ export { rule };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "0.58.0",
3
+ "version": "0.59.1",
4
4
  "description": "Rules for consistent, readable, and valid package.json files. 🗂️",
5
5
  "homepage": "https://github.com/JoshuaKGoldberg/eslint-plugin-package-json#readme",
6
6
  "bugs": {
@@ -52,20 +52,20 @@
52
52
  "semver": "^7.7.3",
53
53
  "sort-object-keys": "^2.0.0",
54
54
  "sort-package-json": "^3.4.0",
55
- "validate-npm-package-name": "^6.0.2"
55
+ "validate-npm-package-name": "^7.0.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
59
- "@eslint/js": "9.37.0",
59
+ "@eslint/js": "9.38.0",
60
60
  "@release-it/conventional-changelog": "10.0.0",
61
61
  "@types/estree": "1.0.7",
62
- "@types/node": "22.18.0",
62
+ "@types/node": "24.9.1",
63
63
  "@types/semver": "7.7.0",
64
64
  "@types/validate-npm-package-name": "4.0.2",
65
- "@vitest/coverage-v8": "3.2.0",
65
+ "@vitest/coverage-v8": "4.0.4",
66
66
  "@vitest/eslint-plugin": "1.3.3",
67
67
  "console-fail-test": "0.5.0",
68
- "eslint": "9.37.0",
68
+ "eslint": "9.38.0",
69
69
  "eslint-doc-generator": "2.3.0",
70
70
  "eslint-plugin-eslint-plugin": "7.0.0",
71
71
  "eslint-plugin-jsdoc": "61.1.0",
@@ -78,12 +78,12 @@
78
78
  "jiti": "2.6.0",
79
79
  "json-schema-to-ts": "3.1.1",
80
80
  "jsonc-eslint-parser": "2.4.1",
81
- "knip": "5.65.0",
81
+ "knip": "5.66.0",
82
82
  "lint-staged": "16.2.0",
83
83
  "markdownlint": "0.39.0",
84
84
  "markdownlint-cli": "0.45.0",
85
85
  "prettier": "3.6.0",
86
- "prettier-plugin-curly": "0.3.1",
86
+ "prettier-plugin-curly": "0.4.0",
87
87
  "prettier-plugin-packagejson": "2.5.10",
88
88
  "prettier-plugin-sh": "0.18.0",
89
89
  "release-it": "19.0.1",
@@ -91,13 +91,13 @@
91
91
  "tsdown": "0.15.0",
92
92
  "typescript": "5.9.2",
93
93
  "typescript-eslint": "8.46.0",
94
- "vitest": "3.2.0"
94
+ "vitest": "4.0.4"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "eslint": ">=8.0.0",
98
98
  "jsonc-eslint-parser": "^2.0.0"
99
99
  },
100
- "packageManager": "pnpm@10.18.0",
100
+ "packageManager": "pnpm@10.19.0",
101
101
  "engines": {
102
102
  "node": "^20.19.0 || >=22.12.0"
103
103
  },