eslint-plugin-package-json 1.9.0 โ†’ 1.10.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/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
  <p align="center">
16
16
  <!-- prettier-ignore-start -->
17
17
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
18
- <a href="#contributors" target="_blank"><img alt="๐Ÿ‘ช All Contributors: 44" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-44-21bb42.svg" /></a>
18
+ <a href="#contributors" target="_blank"><img alt="๐Ÿ‘ช All Contributors: 45" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-45-21bb42.svg" /></a>
19
19
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
20
20
  <!-- prettier-ignore-end -->
21
21
  <a href="https://codecov.io/gh/michaelfaith/eslint-plugin-package-json" target="_blank"><img alt="๐Ÿงช Coverage" src="https://img.shields.io/codecov/c/github/michaelfaith/eslint-plugin-package-json?label=%F0%9F%A7%AA%20coverage" /></a>
@@ -49,6 +49,7 @@ See [Getting Started](https://eslint-plugin-package-json.dev/getting-started) fo
49
49
  | [prefer-rolling-workspace-spec](https://eslint-plugin-package-json.dev/rules/prefer-rolling-workspace-spec) | Require that dependencies declared with workspace protocol use a rolling workspace spec instead of a specific semver range. | | | ๐Ÿ’ก |
50
50
  | [repository-shorthand](https://eslint-plugin-package-json.dev/rules/repository-shorthand) | Enforce either object or shorthand declaration for repository. | โœ… | ๐Ÿ”ง | |
51
51
  | [require-attribution](https://eslint-plugin-package-json.dev/rules/require-attribution) | Ensures that proper attribution is included, requiring that either `author` or `contributors` is defined, and that if `contributors` is present, it should include at least one contributor. | โœ… | | ๐Ÿ’ก |
52
+ | [require-package-json-export](https://eslint-plugin-package-json.dev/rules/require-package-json-export) | Ensures that if a package specifies `exports` (or `publishConfig.exports`), an explicit `package.json` export is included. | | | ๐Ÿ’ก |
52
53
  | [restrict-dependency-ranges](https://eslint-plugin-package-json.dev/rules/restrict-dependency-ranges) | Restricts the range of dependencies to allow or disallow specific types of ranges. | | | ๐Ÿ’ก |
53
54
  | [restrict-dist-tags](https://eslint-plugin-package-json.dev/rules/restrict-dist-tags) | Restricts dependency dist-tags to an allowed list and selected dependency types. | | | |
54
55
  | [restrict-private-properties](https://eslint-plugin-package-json.dev/rules/restrict-private-properties) | Disallows unnecessary properties in private packages. | | ๐Ÿ”ง | ๐Ÿ’ก |
@@ -238,13 +239,14 @@ Thanks! ๐Ÿป
238
239
  <tr>
239
240
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sirugh"><img src="https://avatars.githubusercontent.com/u/1278869?v=4?s=100" width="100px;" alt="Stephen"/><br /><sub><b>Stephen</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=sirugh" title="Code">๐Ÿ’ป</a></td>
240
241
  <td align="center" valign="top" width="14.28%"><a href="https://hyoban.cc"><img src="https://avatars.githubusercontent.com/u/38493346?v=4?s=100" width="100px;" alt="Stephen Zhou"/><br /><sub><b>Stephen Zhou</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Ahyoban" title="Bug reports">๐Ÿ›</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=hyoban" title="Code">๐Ÿ’ป</a> <a href="#ideas-hyoban" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=hyoban" title="Documentation">๐Ÿ“–</a></td>
242
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/thernstig"><img src="https://avatars.githubusercontent.com/u/30827238?v=4?s=100" width="100px;" alt="Tobias Hernstig"/><br /><sub><b>Tobias Hernstig</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Athernstig" title="Bug reports">๐Ÿ›</a></td>
241
243
  <td align="center" valign="top" width="14.28%"><a href="https://www.wesleytodd.com/"><img src="https://avatars.githubusercontent.com/u/1027776?v=4?s=100" width="100px;" alt="Wes Todd"/><br /><sub><b>Wes Todd</b></sub></a><br /><a href="#ideas-wesleytodd" title="Ideas, Planning, & Feedback">๐Ÿค”</a></td>
242
244
  <td align="center" valign="top" width="14.28%"><a href="https://ota-meshi.github.io/"><img src="https://avatars.githubusercontent.com/u/16508807?v=4?s=100" width="100px;" alt="Yosuke Ota"/><br /><sub><b>Yosuke Ota</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Aota-meshi" title="Bug reports">๐Ÿ›</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=ota-meshi" title="Code">๐Ÿ’ป</a></td>
243
245
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/b3rnhard"><img src="https://avatars.githubusercontent.com/u/10774404?v=4?s=100" width="100px;" alt="b3rnhard"/><br /><sub><b>b3rnhard</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Ab3rnhard" title="Bug reports">๐Ÿ›</a></td>
244
246
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/chouchouji"><img src="https://avatars.githubusercontent.com/u/70570907?v=4?s=100" width="100px;" alt="chouchouji"/><br /><sub><b>chouchouji</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=chouchouji" title="Code">๐Ÿ’ป</a></td>
245
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/michaelfaith"><img src="https://avatars.githubusercontent.com/u/8071845?v=4?s=100" width="100px;" alt="michael faith"/><br /><sub><b>michael faith</b></sub></a><br /><a href="#infra-michaelfaith" title="Infrastructure (Hosting, Build-Tools, etc)">๐Ÿš‡</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=michaelfaith" title="Code">๐Ÿ’ป</a> <a href="#maintenance-michaelfaith" title="Maintenance">๐Ÿšง</a> <a href="#ideas-michaelfaith" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Amichaelfaith" title="Bug reports">๐Ÿ›</a> <a href="#tool-michaelfaith" title="Tools">๐Ÿ”ง</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=michaelfaith" title="Documentation">๐Ÿ“–</a> <a href="#projectManagement-michaelfaith" title="Project Management">๐Ÿ“†</a></td>
246
247
  </tr>
247
248
  <tr>
249
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/michaelfaith"><img src="https://avatars.githubusercontent.com/u/8071845?v=4?s=100" width="100px;" alt="michael faith"/><br /><sub><b>michael faith</b></sub></a><br /><a href="#infra-michaelfaith" title="Infrastructure (Hosting, Build-Tools, etc)">๐Ÿš‡</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=michaelfaith" title="Code">๐Ÿ’ป</a> <a href="#maintenance-michaelfaith" title="Maintenance">๐Ÿšง</a> <a href="#ideas-michaelfaith" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Amichaelfaith" title="Bug reports">๐Ÿ›</a> <a href="#tool-michaelfaith" title="Tools">๐Ÿ”ง</a> <a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=michaelfaith" title="Documentation">๐Ÿ“–</a> <a href="#projectManagement-michaelfaith" title="Project Management">๐Ÿ“†</a></td>
248
250
  <td align="center" valign="top" width="14.28%"><a href="https://roottool.vercel.app"><img src="https://avatars.githubusercontent.com/u/11808736?v=4?s=100" width="100px;" alt="roottool"/><br /><sub><b>roottool</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/commits?author=roottool" title="Code">๐Ÿ’ป</a></td>
249
251
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sunnytsang1998"><img src="https://avatars.githubusercontent.com/u/207208443?v=4?s=100" width="100px;" alt="sunnytsang1998"/><br /><sub><b>sunnytsang1998</b></sub></a><br /><a href="https://github.com/michaelfaith/eslint-plugin-package-json/issues?q=author%3Asunnytsang1998" title="Bug reports">๐Ÿ›</a></td>
250
252
  </tr>
@@ -1,4 +1,4 @@
1
- import { t as plugin$1 } from "../plugin-2AyGRwRO.mjs";
1
+ import { t as plugin$1 } from "../plugin-CjXd6iqs.mjs";
2
2
  import { toCompatRule } from "eslint-json-compat-utils";
3
3
  //#region src/experimental/plugin.ts
4
4
  const language = "json/json";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as plugin } from "./plugin-2AyGRwRO.mjs";
1
+ import { t as plugin } from "./plugin-CjXd6iqs.mjs";
2
2
  //#region src/index.ts
3
3
  const rules = plugin.rules;
4
4
  const configs = plugin.configs;
@@ -41,8 +41,7 @@ function createRule(rule) {
41
41
  const ruleGroup = rule.meta.docs?.ruleGroup;
42
42
  return {
43
43
  create(context) {
44
- if (!isPackageJson(context.filename)) return {};
45
- return rule.create(context);
44
+ return isPackageJson(context.filename) ? rule.create(context) : {};
46
45
  },
47
46
  meta: {
48
47
  ...rule.meta,
@@ -55,7 +54,7 @@ function createRule(rule) {
55
54
  }
56
55
  //#endregion
57
56
  //#region src/rules/bin-name-casing.ts
58
- const rule$20 = createRule({
57
+ const rule$21 = createRule({
59
58
  create(context) {
60
59
  return { "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=bin]"(node) {
61
60
  if (node.value.type === "JSONObjectExpression") for (const property of node.value.properties) {
@@ -93,17 +92,17 @@ const rule$20 = createRule({
93
92
  });
94
93
  //#endregion
95
94
  //#region src/rules/exports-subpaths-style.ts
96
- function isImplicitFormat(node) {
95
+ function isImplicitFormat$1(node) {
97
96
  if (node.type === "JSONLiteral") return true;
98
97
  return node.properties.every((property) => !isJSONStringLiteral(property.key) || !property.key.value.startsWith("."));
99
98
  }
100
- const rule$19 = createRule({
99
+ const rule$20 = createRule({
101
100
  create(context) {
102
101
  const [{ prefer = "explicit" } = {}] = context.options;
103
102
  function validateForExplicit(node) {
104
103
  const { value } = node;
105
104
  if (isJSONNullLiteral(value)) return;
106
- if (value.type !== "JSONLiteral" && value.type !== "JSONObjectExpression" || !isImplicitFormat(value)) return;
105
+ if (value.type !== "JSONLiteral" && value.type !== "JSONObjectExpression" || !isImplicitFormat$1(value)) return;
107
106
  context.report({
108
107
  fix(fixer) {
109
108
  const valueText = context.sourceCode.getText(value);
@@ -200,25 +199,21 @@ const getTopLevelProperty = (node) => {
200
199
  return n.type === "JSONProperty" ? n.key : void 0;
201
200
  };
202
201
  const defaultIgnoreProperties = ["files"];
203
- const rule$18 = createRule({
202
+ const rule$19 = createRule({
204
203
  create(context) {
205
204
  const ignoreProperties = new Set(context.options[0]?.ignoreProperties ?? defaultIgnoreProperties);
206
205
  return {
207
206
  JSONArrayExpression(node) {
208
207
  const topLevelProperty = getTopLevelProperty(node);
209
- if (!topLevelProperty) return;
210
- if (!node.elements.length) {
211
- const topLevelPropertyName = topLevelProperty.value;
212
- if (!ignoreProperties.has(topLevelPropertyName)) report(context, getNode(node));
213
- }
208
+ if (!topLevelProperty || node.elements.length) return;
209
+ const topLevelPropertyName = topLevelProperty.value;
210
+ if (!ignoreProperties.has(topLevelPropertyName)) report(context, getNode(node));
214
211
  },
215
212
  JSONObjectExpression(node) {
216
213
  const topLevelProperty = getTopLevelProperty(node);
217
- if (!topLevelProperty) return;
218
- if (!node.properties.length) {
219
- const topLevelPropertyName = topLevelProperty.value;
220
- if (!ignoreProperties.has(topLevelPropertyName)) report(context, getNode(node));
221
- }
214
+ if (!topLevelProperty || node.properties.length) return;
215
+ const topLevelPropertyName = topLevelProperty.value;
216
+ if (!ignoreProperties.has(topLevelPropertyName)) report(context, getNode(node));
222
217
  }
223
218
  };
224
219
  },
@@ -256,7 +251,7 @@ const getBundledDependencyNames = (value) => {
256
251
  if (value?.type === "JSONArrayExpression") for (const element of value.elements.filter(isNotNullish).filter(isJSONStringLiteral)) names.add(element.value);
257
252
  return names;
258
253
  };
259
- const rule$17 = createRule({
254
+ const rule$18 = createRule({
260
255
  create(context) {
261
256
  const ignorePrivate = context.options[0]?.ignorePrivate ?? true;
262
257
  let isPrivate = false;
@@ -327,7 +322,7 @@ const getCachedLocalFileRegex = (filename) => {
327
322
  return regex;
328
323
  }
329
324
  };
330
- const rule$16 = createRule({
325
+ const rule$17 = createRule({
331
326
  create(context) {
332
327
  const entryCache = {
333
328
  bin: [],
@@ -404,7 +399,7 @@ const rule$16 = createRule({
404
399
  });
405
400
  //#endregion
406
401
  //#region src/rules/no-redundant-publishConfig.ts
407
- const rule$15 = createRule({
402
+ const rule$16 = createRule({
408
403
  create(context) {
409
404
  let packageName;
410
405
  let publishConfigAccessProperty;
@@ -450,7 +445,7 @@ const rule$15 = createRule({
450
445
  });
451
446
  //#endregion
452
447
  //#region src/rules/order-properties.ts
453
- const rule$14 = createRule({
448
+ const rule$15 = createRule({
454
449
  create(context) {
455
450
  return { "Program:exit"() {
456
451
  const { ast, text } = context.sourceCode;
@@ -477,6 +472,7 @@ const rule$14 = createRule({
477
472
  loc: properties[i].loc,
478
473
  messageId: "incorrectOrder"
479
474
  });
475
+ return;
480
476
  }
481
477
  } };
482
478
  },
@@ -510,7 +506,7 @@ const rule$14 = createRule({
510
506
  //#region src/rules/prefer-rolling-workspace-spec.ts
511
507
  const rollingWorkspaceSpecRegex = /^workspace:[*^~]?$/;
512
508
  const convertibleSpecRegex = /^(workspace:[~^])/;
513
- const rule$13 = createRule({
509
+ const rule$14 = createRule({
514
510
  create(context) {
515
511
  const { ignoreDependencies = [], ignorePatterns = [] } = context.options[0] ?? {};
516
512
  const ignoreRegexes = ignorePatterns.map((pattern) => new RegExp(pattern));
@@ -608,14 +604,13 @@ const createUrl = (shorthand) => {
608
604
  }
609
605
  return `${providerUrls.github}${shorthand}`;
610
606
  };
611
- const rule$12 = createRule({
607
+ const rule$13 = createRule({
612
608
  create(context) {
613
609
  const [{ form = "object" } = {}] = context.options;
614
610
  function validateRepositoryForObject(node) {
615
611
  if (isJSONStringLiteral(node.value)) context.report({
616
612
  fix(fixer) {
617
- if (!isJSONStringLiteral(node.value) || node.value.value.split("/").filter(Boolean).length !== 2) return null;
618
- return fixer.replaceText(node.value, JSON.stringify({
613
+ return !isJSONStringLiteral(node.value) || node.value.value.split("/").filter(Boolean).length !== 2 ? null : fixer.replaceText(node.value, JSON.stringify({
619
614
  type: "git",
620
615
  url: createUrl(node.value.value)
621
616
  }, null, 2));
@@ -687,7 +682,7 @@ const rule$12 = createRule({
687
682
  });
688
683
  //#endregion
689
684
  //#region src/rules/require-attribution.ts
690
- const rule$11 = createRule({
685
+ const rule$12 = createRule({
691
686
  create(context) {
692
687
  const preferContributorsOnly = context.options[0]?.preferContributorsOnly ?? false;
693
688
  const ignorePrivate = context.options[0]?.ignorePrivate ?? true;
@@ -774,6 +769,86 @@ const rule$11 = createRule({
774
769
  name: "require-attribution"
775
770
  });
776
771
  //#endregion
772
+ //#region src/utils/increaseIndent.ts
773
+ const increaseIndent = (original, additional) => original.split("\n").join(`\n${additional}`);
774
+ //#endregion
775
+ //#region src/rules/require-package-json-export.ts
776
+ function isImplicitFormat(node) {
777
+ return node.properties.every((property) => !isJSONStringLiteral(property.key) || !property.key.value.startsWith("."));
778
+ }
779
+ const rule$11 = createRule({
780
+ create(context) {
781
+ let publishConfigExportsValueNode;
782
+ let exportsValueNode;
783
+ return {
784
+ "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=exports]"(node) {
785
+ if (node.value.type === "JSONObjectExpression" || isJSONStringLiteral(node.value)) exportsValueNode = node.value;
786
+ },
787
+ "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=publishConfig] > JSONObjectExpression > JSONProperty[key.value=exports]"(node) {
788
+ if (node.value.type === "JSONObjectExpression" || isJSONStringLiteral(node.value)) publishConfigExportsValueNode = node.value;
789
+ },
790
+ "Program:exit"() {
791
+ const exportsNode = publishConfigExportsValueNode ?? exportsValueNode;
792
+ if (!exportsNode) return;
793
+ const isPublishConfig = !!publishConfigExportsValueNode;
794
+ const { text } = context.sourceCode;
795
+ const { indent, type } = detectIndent(text);
796
+ const indentUnit = type === "tab" ? " " : indent || " ";
797
+ const extraIndent = isPublishConfig ? `${indentUnit}${indentUnit}` : indentUnit;
798
+ if (isJSONStringLiteral(exportsNode) || isImplicitFormat(exportsNode)) {
799
+ context.report({
800
+ messageId: "missing",
801
+ node: exportsNode,
802
+ suggest: [{
803
+ messageId: "addExport",
804
+ fix(fixer) {
805
+ const valueText = context.sourceCode.getText(exportsNode);
806
+ const fixedValue = increaseIndent(JSON.stringify({
807
+ ".": JSON.parse(valueText),
808
+ "./package.json": "./package.json"
809
+ }, null, indentUnit), extraIndent);
810
+ return fixer.replaceText(exportsNode, fixedValue);
811
+ }
812
+ }]
813
+ });
814
+ return;
815
+ }
816
+ if (exportsNode.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === "./package.json")) return;
817
+ context.report({
818
+ messageId: "missing",
819
+ node: exportsNode,
820
+ suggest: [{
821
+ messageId: "addExport",
822
+ fix(fixer) {
823
+ const valueText = context.sourceCode.getText(exportsNode);
824
+ const existingExports = JSON.parse(valueText);
825
+ const fixedValue = increaseIndent(JSON.stringify({
826
+ ...existingExports,
827
+ "./package.json": "./package.json"
828
+ }, null, indentUnit), extraIndent);
829
+ return fixer.replaceText(exportsNode, fixedValue);
830
+ }
831
+ }]
832
+ });
833
+ }
834
+ };
835
+ },
836
+ meta: {
837
+ docs: {
838
+ category: "Best Practices",
839
+ description: "Ensures that if a package specifies `exports` (or `publishConfig.exports`), an explicit `package.json` export is included."
840
+ },
841
+ hasSuggestions: true,
842
+ messages: {
843
+ missing: "An export for the package.json is required, and missing.",
844
+ addExport: "Add package.json export."
845
+ },
846
+ schema: [],
847
+ type: "suggestion"
848
+ },
849
+ name: "require-package-json-export"
850
+ });
851
+ //#endregion
777
852
  //#region src/utils/createSimpleRequirePropertyRule.ts
778
853
  /**
779
854
  * Given a top-level property name, create a rule that requires that property to be present.
@@ -790,21 +865,20 @@ const createSimpleRequirePropertyRule = (propertyName, { category, fixValue, ign
790
865
  const ignorePrivate = context.options[0]?.ignorePrivate ?? (typeof enforceForPrivate === "boolean" ? !enforceForPrivate : ignorePrivateDefault);
791
866
  return { "Program > JSONExpressionStatement > JSONObjectExpression"(node) {
792
867
  if (ignorePrivate && node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === "private" && property.value.type === "JSONLiteral" && property.value.value === true)) return;
793
- if (node.properties.every((property) => !(isJSONStringLiteral(property.key) && property.key.value === propertyName))) {
794
- const resolvedValue = typeof fixValue === "function" ? fixValue() : fixValue;
795
- context.report({
796
- data: { property: propertyName },
797
- fix: resolvedValue === void 0 ? void 0 : function* (fixer) {
798
- yield fixer.insertTextAfterRange([0, 1], `\n "${propertyName}": ${JSON.stringify(resolvedValue, null, 2).split("\n").join("\n ")}`);
799
- yield node.properties.length > 0 ? fixer.insertTextAfterRange([0, 1], ",") : fixer.insertTextAfterRange([0, 1], "\n");
800
- },
801
- loc: {
802
- column: 0,
803
- line: 1
804
- },
805
- messageId: "missing"
806
- });
807
- }
868
+ if (node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === propertyName)) return;
869
+ const resolvedValue = typeof fixValue === "function" ? fixValue() : fixValue;
870
+ context.report({
871
+ data: { property: propertyName },
872
+ fix: resolvedValue === void 0 ? void 0 : function* (fixer) {
873
+ yield fixer.insertTextAfterRange([0, 1], `\n "${propertyName}": ${JSON.stringify(resolvedValue, null, 2).split("\n").join("\n ")}`);
874
+ yield node.properties.length > 0 ? fixer.insertTextAfterRange([0, 1], ",") : fixer.insertTextAfterRange([0, 1], "\n");
875
+ },
876
+ loc: {
877
+ column: 0,
878
+ line: 1
879
+ },
880
+ messageId: "missing"
881
+ });
808
882
  } };
809
883
  },
810
884
  meta: {
@@ -1001,7 +1075,7 @@ const schemaOptions = {
1001
1075
  const normalizeRangeType = (rangeTypeOrSymbol) => RANGE_TYPES.find((rangeType) => "symbol" in rangeType && rangeType.symbol === rangeTypeOrSymbol || rangeType.alias === rangeTypeOrSymbol);
1002
1076
  /** @returns `undefined` if workspace versions are not supported for the specified {@link rangeType} */
1003
1077
  const getWorkspaceVersionForRange = (rangeType) => {
1004
- if ("workspaceSymbol" in rangeType) return `workspace:${rangeType.workspaceSymbol}`;
1078
+ return "workspaceSymbol" in rangeType ? `workspace:${rangeType.workspaceSymbol}` : void 0;
1005
1079
  };
1006
1080
  /** For displaying a range type in a user-facing way (ie. an error message). */
1007
1081
  const displayRangeType = (rangeType) => "symbol" in rangeType ? rangeType.symbol : rangeType.alias;
@@ -1392,8 +1466,7 @@ const rule$5 = createRule({
1392
1466
  const bKey = b.key.value;
1393
1467
  const ai = rank(aKey);
1394
1468
  const bi = rank(bKey);
1395
- if (ai !== bi) return ai - bi;
1396
- return naturalCompare(aKey, bKey);
1469
+ return ai === bi ? naturalCompare(aKey, bKey) : ai - bi;
1397
1470
  });
1398
1471
  if (currentOrder.some((property, i) => desiredOrder[i] !== property)) context.report({
1399
1472
  data: { key },
@@ -1557,10 +1630,9 @@ const rule$3 = createRule({
1557
1630
  if (!dependencyPropertyNames.has(node.key.value)) return;
1558
1631
  const nodeValueType = node.value.type;
1559
1632
  if (nodeValueType === "JSONArrayExpression") check(node.value.elements, (element) => element);
1560
- if (nodeValueType === "JSONObjectExpression") {
1561
- check(node.value.properties.map((property) => property.key), (property) => property.parent);
1562
- if (trackForCrossGroupUniqueness.includes(node.key.value)) dependenciesCache[node.key.value] = node.value.properties;
1563
- }
1633
+ if (nodeValueType !== "JSONObjectExpression") return;
1634
+ check(node.value.properties.map((property) => property.key), (property) => property.parent);
1635
+ if (trackForCrossGroupUniqueness.includes(node.key.value)) dependenciesCache[node.key.value] = node.value.properties;
1564
1636
  },
1565
1637
  "Program:exit"() {
1566
1638
  const dependencyNames = new Set(dependenciesCache.dependencies.map((node) => node.key).filter(isJSONStringLiteral).map((dependencyNameNode) => dependencyNameNode.value));
@@ -1810,8 +1882,7 @@ function* lookup(cwd = process.cwd()) {
1810
1882
  }
1811
1883
  }
1812
1884
  function parsePackageJson(filepath) {
1813
- if (!filepath || !fs.existsSync(filepath)) return null;
1814
- return handlePackageManager(filepath);
1885
+ return !filepath || !fs.existsSync(filepath) ? null : handlePackageManager(filepath);
1815
1886
  }
1816
1887
  /**
1817
1888
  * Detects the package manager used in the project.
@@ -1855,10 +1926,10 @@ function getNameAndVersion(pkg) {
1855
1926
  version: normalizeVersion(version)
1856
1927
  };
1857
1928
  }
1858
- if (typeof pkg.devEngines?.packageManager?.name === "string") return {
1929
+ return typeof pkg.devEngines?.packageManager?.name === "string" ? {
1859
1930
  name: pkg.devEngines.packageManager.name,
1860
1931
  version: normalizeVersion(pkg.devEngines.packageManager.version)
1861
- };
1932
+ } : void 0;
1862
1933
  }
1863
1934
  function handlePackageManager(filepath) {
1864
1935
  try {
@@ -2007,17 +2078,18 @@ const rule = createRule({
2007
2078
  //#region src/plugin.ts
2008
2079
  const require = createRequire(import.meta.url);
2009
2080
  const rules = {
2010
- "bin-name-casing": rule$20,
2011
- "exports-subpaths-style": rule$19,
2012
- "no-empty-fields": rule$18,
2013
- "no-local-dependencies": rule$17,
2014
- "no-redundant-files": rule$16,
2015
- "no-redundant-publishConfig": rule$15,
2016
- "order-properties": rule$14,
2017
- "prefer-rolling-workspace-spec": rule$13,
2018
- "require-attribution": rule$11,
2081
+ "bin-name-casing": rule$21,
2082
+ "exports-subpaths-style": rule$20,
2083
+ "no-empty-fields": rule$19,
2084
+ "no-local-dependencies": rule$18,
2085
+ "no-redundant-files": rule$17,
2086
+ "no-redundant-publishConfig": rule$16,
2087
+ "order-properties": rule$15,
2088
+ "prefer-rolling-workspace-spec": rule$14,
2089
+ "require-attribution": rule$12,
2090
+ "require-package-json-export": rule$11,
2019
2091
  ...rules$2,
2020
- "repository-shorthand": rule$12,
2092
+ "repository-shorthand": rule$13,
2021
2093
  "restrict-dependency-ranges": rule$10,
2022
2094
  "restrict-dist-tags": rule$9,
2023
2095
  "restrict-private-properties": rule$8,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
4
4
  "description": "Rules for consistent, readable, and valid package.json files. ๐Ÿ—‚๏ธ",
5
5
  "homepage": "https://github.com/michaelfaith/eslint-plugin-package-json#readme",
6
6
  "bugs": {
@@ -36,12 +36,16 @@
36
36
  "./experimental": {
37
37
  "types": "./dist/experimental/index.d.mts",
38
38
  "default": "./dist/experimental/index.mjs"
39
- }
39
+ },
40
+ "./package.json": "./package.json"
40
41
  },
41
42
  "main": "dist/index.mjs",
42
43
  "files": [
43
44
  "dist/"
44
45
  ],
46
+ "lint-staged": {
47
+ "*": "oxfmt --no-error-on-unmatched-pattern"
48
+ },
45
49
  "dependencies": {
46
50
  "@altano/repository-tools": "^2.0.1",
47
51
  "@types/estree": "^1.0.0",
@@ -58,49 +62,45 @@
58
62
  },
59
63
  "devDependencies": {
60
64
  "@astrojs/check": "0.9.10",
61
- "@astrojs/markdown-satteri": "0.4.1",
62
- "@astrojs/starlight": "0.42.0",
65
+ "@astrojs/markdown-satteri": "0.4.2",
66
+ "@astrojs/starlight": "0.42.4",
63
67
  "@catppuccin/starlight": "2.1.0",
64
68
  "@eslint-community/eslint-plugin-eslint-comments": "4.8.1",
65
69
  "@eslint/js": "10.0.1",
66
70
  "@eslint/json": "2.1.0",
67
71
  "@eslint/markdown": "8.0.3",
68
- "@ianvs/prettier-plugin-sort-imports": "4.7.1",
69
- "@types/node": "24.13.4",
72
+ "@types/node": "24.13.6",
70
73
  "@types/semver": "7.8.0",
71
74
  "@typescript/native": "npm:typescript@7.0.2",
72
75
  "@vitest/coverage-v8": "5.0.1",
73
76
  "@vitest/eslint-plugin": "1.6.27",
74
- "astro": "7.3.2",
75
- "astro-og-canvas": "0.13.1",
77
+ "astro": "7.3.5",
78
+ "astro-og-canvas": "0.13.2",
76
79
  "canvaskit-wasm": "0.42.0",
77
- "console-fail-test": "0.6.1",
78
- "eslint": "10.10.0",
80
+ "console-fail-test": "0.9.0",
81
+ "eslint": "10.11.0",
79
82
  "eslint-doc-generator": "3.7.1",
80
83
  "eslint-plugin-eslint-plugin": "7.6.2",
81
- "eslint-plugin-jsdoc": "64.4.0",
84
+ "eslint-plugin-jsdoc": "64.5.4",
82
85
  "eslint-plugin-jsonc": "3.4.2",
83
86
  "eslint-plugin-n": "18.3.0",
84
87
  "eslint-plugin-node-dependencies": "2.2.0",
85
- "eslint-plugin-perfectionist": "5.11.0",
86
- "eslint-plugin-regexp": "3.3.0",
87
- "eslint-plugin-unicorn": "74.0.0",
88
+ "eslint-plugin-perfectionist": "5.12.1",
89
+ "eslint-plugin-regexp": "3.3.1",
90
+ "eslint-plugin-unicorn": "76.0.0",
88
91
  "eslint-plugin-yml": "3.8.1",
89
92
  "jiti": "2.7.0",
90
93
  "json-schema-to-ts": "3.1.1",
91
- "knip": "6.35.1",
94
+ "knip": "6.38.0",
95
+ "lint-staged": "17.6.0",
96
+ "oxfmt": "0.70.0",
92
97
  "pkg-pr-new": "0.0.88",
93
- "prettier": "3.9.6",
94
- "prettier-plugin-curly": "0.4.1",
95
- "prettier-plugin-packagejson": "3.0.2",
96
- "prettier-plugin-sh": "0.19.0",
97
- "pretty-quick": "4.2.2",
98
98
  "sharp": "0.35.4",
99
99
  "simple-git-hooks": "2.14.0",
100
100
  "starlight-auto-sidebar": "0.4.1",
101
101
  "tsdown": "0.23.0",
102
102
  "typescript": "npm:@typescript/typescript6@6.0.2",
103
- "typescript-eslint": "8.70.0",
103
+ "typescript-eslint": "8.70.1",
104
104
  "vitest": "5.0.1"
105
105
  },
106
106
  "peerDependencies": {
@@ -118,7 +118,7 @@
118
118
  "scripts": {
119
119
  "build": "tsdown",
120
120
  "docs:generate": "pnpm build --no-dts && eslint-doc-generator --ignore-config recommended-publishable",
121
- "format": "prettier .",
121
+ "format": "oxfmt",
122
122
  "lint": "eslint . --max-warnings 0",
123
123
  "lint:knip": "knip",
124
124
  "site:build": "astro build",