eslint-plugin-package-json 0.56.2 → 0.56.4

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 (35) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +19 -7
  3. package/lib/createRule.d.ts +13 -4
  4. package/lib/createRule.js +4 -0
  5. package/lib/index.d.ts +4 -9
  6. package/lib/plugin.d.ts +4 -2
  7. package/lib/plugin.js +1 -2
  8. package/lib/rules/no-empty-fields.d.ts +15 -5
  9. package/lib/rules/no-redundant-files.d.ts +1 -1
  10. package/lib/rules/no-redundant-files.js +1 -2
  11. package/lib/rules/order-properties.d.ts +20 -5
  12. package/lib/rules/order-properties.js +5 -7
  13. package/lib/rules/repository-shorthand.d.ts +13 -5
  14. package/lib/rules/require-properties.d.ts +11 -2
  15. package/lib/rules/restrict-dependency-ranges.d.ts +87 -10
  16. package/lib/rules/restrict-dependency-ranges.js +4 -7
  17. package/lib/rules/sort-collections.d.ts +7 -2
  18. package/lib/rules/sort-collections.js +2 -5
  19. package/lib/rules/unique-dependencies.d.ts +1 -1
  20. package/lib/rules/valid-bin.d.ts +12 -4
  21. package/lib/rules/valid-bin.js +1 -2
  22. package/lib/rules/valid-local-dependency.d.ts +1 -1
  23. package/lib/rules/valid-local-dependency.js +1 -2
  24. package/lib/rules/valid-name.d.ts +1 -1
  25. package/lib/rules/valid-package-definition.d.ts +15 -5
  26. package/lib/rules/valid-package-definition.js +1 -2
  27. package/lib/rules/valid-properties.d.ts +1 -1
  28. package/lib/rules/valid-repository-directory.d.ts +1 -1
  29. package/lib/rules/valid-version.d.ts +1 -1
  30. package/lib/types/estree.d.ts +1 -3
  31. package/lib/utils/createSimpleRequirePropertyRule.d.ts +12 -4
  32. package/lib/utils/createSimpleRequirePropertyRule.js +31 -32
  33. package/lib/utils/createSimpleValidPropertyRule.d.ts +1 -1
  34. package/lib/utils/createSimpleValidPropertyRule.js +27 -29
  35. package/package.json +16 -18
package/CHANGELOG.md CHANGED
@@ -1,11 +1,23 @@
1
1
  # Changelog
2
2
 
3
- ## [0.56.2](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.1...v0.56.2) (2025-09-04)
3
+ ## [0.56.4](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.3...v0.56.4) (2025-10-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * re-adopt jsonc-eslint-parser's RuleListener type ([#1319](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1319)) ([2c4c7c2](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/2c4c7c2591732f1b298e5e6eb279afe5f7d52cab)), closes [#000](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/000)
4
9
 
10
+ ## [0.56.3](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.2...v0.56.3) (2025-09-15)
11
+
12
+ ### Bug Fixes
13
+
14
+ - **plugin:** update types to be compatible with `defineConfig` ([#1245](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1245)) ([861e5e1](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/861e5e129b3a5e3455b6b2a2a26d453086f20c14)), closes [#1242](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1242)
15
+
16
+ ## [0.56.2](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.1...v0.56.2) (2025-09-04)
5
17
 
6
18
  ### Bug Fixes
7
19
 
8
- * improve sort-collections docs and error messages ([#1250](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1250)) ([1864376](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/1864376039db3db690423051b0dd8a2104395aa4)), closes [#1243](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1243) [#1243](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1243)
20
+ - improve sort-collections docs and error messages ([#1250](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1250)) ([1864376](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commit/1864376039db3db690423051b0dd8a2104395aa4)), closes [#1243](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1243) [#1243](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/1243)
9
21
 
10
22
  ## [0.56.1](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.56.0...v0.56.1) (2025-08-31)
11
23
 
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  <p align="center">
9
9
  <!-- prettier-ignore-start -->
10
10
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
11
- <a href="#contributors" target="_blank"><img alt="👪 All Contributors: 29" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-29-21bb42.svg" /></a>
11
+ <a href="#contributors" target="_blank"><img alt="👪 All Contributors: 30" src="https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-30-21bb42.svg" /></a>
12
12
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
13
13
  <!-- prettier-ignore-end -->
14
14
  <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/.github/CODE_OF_CONDUCT.md" target="_blank"><img alt="🤝 Code of Conduct: Kept" src="https://img.shields.io/badge/%F0%9F%A4%9D_code_of_conduct-kept-21bb42" /></a>
@@ -130,10 +130,21 @@ export default {
130
130
 
131
131
  #### `enforceForPrivate`
132
132
 
133
- **Type:** `boolean`
133
+ - **Type:** `boolean`
134
+ - **Default:** [see below]
134
135
 
135
- Determines whether `require-*` rules, if used, should enforce the presence of the corresponding property in package.json files with `"private": true`.
136
- By default, all `require-*` rules except for [`require-name`](docs/rules/require-name.md) and [`require-version`](docs/rules/require-version.md) will report if the corresponding property is missing in package.json with `"private": true`.
136
+ When a package.json file has a `"private": true` field, it indicates that the package will not be published to npm (or another online registry).
137
+ Some fields that are nice to have in public packages become less relevant when a package is private.
138
+ This option determines whether `require-*` rules, if used, should enforce the presence of the corresponding property in package.json files that have `"private": true`.
139
+
140
+ By default, this is:
141
+
142
+ - `false` for [`require-name`](docs/rules/require-name.md) and [`require-version`](docs/rules/require-version.md).
143
+ - `true` for every other `require-*` rule.
144
+
145
+ By specifying this setting as `true` or `false`, it will override the defaults and apply the setting for ALL rules.
146
+ In that case, either all `require-*` rules will be applied to private packages or no `require-*` rules will be applied to private packages.
147
+ Even then, you can override the setting again at the rule level, by using the rule's `ignorePrivate` option, which will take precedence over this global setting.
137
148
 
138
149
  ### Usage Alongside Prettier
139
150
 
@@ -249,7 +260,7 @@ Thanks! 🗂
249
260
  <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>
250
261
  <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>
251
262
  <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>
252
- <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></td>
263
+ <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>
253
264
  <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>
254
265
  <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>
255
266
  <td align="center" valign="top" width="14.28%"><a href="http://www.joshuakgoldberg.com/"><img src="https://avatars.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt="Josh Goldberg ✨"/><br /><sub><b>Josh Goldberg ✨</b></sub></a><br /><a href="#tool-JoshuaKGoldberg" title="Tools">🔧</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3AJoshuaKGoldberg" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=JoshuaKGoldberg" title="Code">💻</a> <a href="#infra-JoshuaKGoldberg" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=JoshuaKGoldberg" title="Documentation">📖</a> <a href="#maintenance-JoshuaKGoldberg" title="Maintenance">🚧</a> <a href="#ideas-JoshuaKGoldberg" title="Ideas, Planning, & Feedback">🤔</a> <a href="#content-JoshuaKGoldberg" title="Content">🖋</a> <a href="#projectManagement-JoshuaKGoldberg" title="Project Management">📆</a></td>
@@ -259,20 +270,21 @@ Thanks! 🗂
259
270
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/KristjanESPERANTO"><img src="https://avatars.githubusercontent.com/u/35647502?v=4?s=100" width="100px;" alt="Kristjan ESPERANTO"/><br /><sub><b>Kristjan ESPERANTO</b></sub></a><br /><a href="#ideas-kristjanesperanto" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Akristjanesperanto" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=kristjanesperanto" title="Code">💻</a></td>
260
271
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/lo1tuma"><img src="https://avatars.githubusercontent.com/u/169170?v=4?s=100" width="100px;" alt="Mathias Schreck"/><br /><sub><b>Mathias Schreck</b></sub></a><br /><a href="#ideas-lo1tuma" title="Ideas, Planning, & Feedback">🤔</a></td>
261
272
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/Cellule"><img src="https://avatars.githubusercontent.com/u/4157103?v=4?s=100" width="100px;" alt="Michael "Mike" Ferris"/><br /><sub><b>Michael "Mike" Ferris</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=cellule" title="Code">💻</a></td>
273
+ <td align="center" valign="top" width="14.28%"><a href="https://morrisoncole.co.uk"><img src="https://avatars.githubusercontent.com/u/963368?v=4?s=100" width="100px;" alt="Morrison Cole"/><br /><sub><b>Morrison Cole</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3AMorrisonCole" title="Bug reports">🐛</a></td>
262
274
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/nschonni"><img src="https://avatars.githubusercontent.com/u/1297909?v=4?s=100" width="100px;" alt="Nick Schonning"/><br /><sub><b>Nick Schonning</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=nschonni" title="Code">💻</a></td>
263
275
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/rakleed"><img src="https://avatars.githubusercontent.com/u/19418601?v=4?s=100" width="100px;" alt="Pavel"/><br /><sub><b>Pavel</b></sub></a><br /><a href="#ideas-rakleed" title="Ideas, Planning, & Feedback">🤔</a> <a href="#tool-rakleed" title="Tools">🔧</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=rakleed" title="Documentation">📖</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=rakleed" title="Code">💻</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Arakleed" title="Bug reports">🐛</a></td>
264
- <td align="center" valign="top" width="14.28%"><a href="https://sasial.dev"><img src="https://avatars.githubusercontent.com/u/44125644?v=4?s=100" width="100px;" alt="Sasial"/><br /><sub><b>Sasial</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=sasial-dev" title="Code">💻</a></td>
265
276
  </tr>
266
277
  <tr>
278
+ <td align="center" valign="top" width="14.28%"><a href="https://sasial.dev"><img src="https://avatars.githubusercontent.com/u/44125644?v=4?s=100" width="100px;" alt="Sasial"/><br /><sub><b>Sasial</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=sasial-dev" title="Code">💻</a></td>
267
279
  <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/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=sirugh" title="Code">💻</a></td>
268
280
  <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/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Ahyoban" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=hyoban" title="Code">💻</a> <a href="#ideas-hyoban" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=hyoban" title="Documentation">📖</a></td>
269
281
  <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/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Aota-meshi" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=ota-meshi" title="Code">💻</a></td>
270
282
  <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/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Ab3rnhard" title="Bug reports">🐛</a></td>
271
283
  <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/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=chouchouji" title="Code">💻</a></td>
272
284
  <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/JoshuaKGoldberg/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/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Amichaelfaith" title="Bug reports">🐛</a> <a href="#tool-michaelfaith" title="Tools">🔧</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=michaelfaith" title="Documentation">📖</a></td>
273
- <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/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=roottool" title="Code">💻</a></td>
274
285
  </tr>
275
286
  <tr>
287
+ <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/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=roottool" title="Code">💻</a></td>
276
288
  <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/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Asunnytsang1998" title="Bug reports">🐛</a></td>
277
289
  </tr>
278
290
  </tbody>
@@ -1,5 +1,6 @@
1
1
  import { AST, RuleListener } from "jsonc-eslint-parser";
2
2
  import * as ESTree from "estree";
3
+ import { FromSchema, JSONSchema } from "json-schema-to-ts";
3
4
  import { AST as AST$1, Rule, SourceCode } from "eslint";
4
5
 
5
6
  //#region src/createRule.d.ts
@@ -31,15 +32,23 @@ interface PackageJsonRuleContext<Options extends unknown[] = unknown[]> extends
31
32
  };
32
33
  sourceCode: PackageJsonSourceCode;
33
34
  }
34
- interface PackageJsonRuleModule<Options extends unknown[] = unknown[]> {
35
+ interface PackageJsonRuleModule<Options extends unknown[] = unknown[], Schema extends JSONSchema[] = JSONSchema[]> {
35
36
  create(context: PackageJsonRuleContext<Options>): RuleListener;
36
- meta: Rule.RuleMetaData;
37
+ meta: Omit<Rule.RuleMetaData, "defaultOptions" | "schema"> & {
38
+ defaultOptions?: NoInfer<Options>;
39
+ schema?: Schema;
40
+ };
37
41
  }
38
42
  interface PackageJsonSourceCode extends SourceCode {
39
43
  ast: PackageJsonAst;
40
44
  }
41
- declare function createRule<Options extends unknown[]>(rule: PackageJsonRuleModule<Options> & {
45
+ type InferJsonSchemasTupleType<T extends JSONSchema[]> = { [K in keyof T]?: FromSchema<T[K]> };
46
+ /**
47
+ * Rule options type is inferred from the JSON schema by [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts).
48
+ * If you're not satisfied with the inferred type, you may specify it manually in the first type parameter.
49
+ */
50
+ declare function createRule<OptionsOverride extends unknown[] = never, const Schema extends JSONSchema[] = JSONSchema[], _OptionsResolved extends unknown[] = ([OptionsOverride] extends [never] ? InferJsonSchemasTupleType<Schema> : OptionsOverride)>(rule: PackageJsonRuleModule<_OptionsResolved, Schema> & {
42
51
  name: string;
43
- }): PackageJsonRuleModule<Options>;
52
+ }): PackageJsonRuleModule<_OptionsResolved, Schema>;
44
53
  //#endregion
45
54
  export { JsonAstBodyExpression, JsonAstBodyProperty, JsonAstBodyStatement, PackageJsonAst, PackageJsonPluginSettings, PackageJsonRuleContext, PackageJsonRuleModule, PackageJsonSourceCode, createRule };
package/lib/createRule.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import { isPackageJson } from "./utils/isPackageJson.js";
2
2
 
3
3
  //#region src/createRule.ts
4
+ /**
5
+ * Rule options type is inferred from the JSON schema by [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts).
6
+ * If you're not satisfied with the inferred type, you may specify it manually in the first type parameter.
7
+ */
4
8
  function createRule(rule) {
5
9
  return {
6
10
  create(context) {
package/lib/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { PackageJsonPluginSettings, PackageJsonRuleModule } from "./createRule.js";
2
2
  import { plugin } from "./plugin.js";
3
3
  import * as jsonc_eslint_parser0 from "jsonc-eslint-parser";
4
+ import * as json_schema_to_ts0 from "json-schema-to-ts";
5
+ import * as eslint0 from "eslint";
4
6
 
5
7
  //#region src/index.d.ts
6
- declare const rules: Record<string, PackageJsonRuleModule<unknown[]>>;
8
+ declare const rules: Record<string, PackageJsonRuleModule<unknown[], json_schema_to_ts0.JSONSchema[]>>;
7
9
  declare const configs: {
8
10
  "legacy-recommended": {
9
11
  plugins: string[];
@@ -20,14 +22,7 @@ declare const configs: {
20
22
  };
21
23
  name: string;
22
24
  plugins: {
23
- readonly "package-json": {
24
- configs: /*elided*/any;
25
- meta: {
26
- name: string;
27
- version: string;
28
- };
29
- rules: Record<string, PackageJsonRuleModule<unknown[]>>;
30
- };
25
+ readonly "package-json": eslint0.ESLint.Plugin;
31
26
  };
32
27
  rules: {
33
28
  "package-json/valid-package-definition": ["error", {
package/lib/plugin.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { PackageJsonRuleModule } from "./createRule.js";
2
2
  import * as parserJsonc from "jsonc-eslint-parser";
3
+ import * as json_schema_to_ts0 from "json-schema-to-ts";
4
+ import { ESLint } from "eslint";
3
5
 
4
6
  //#region src/plugin.d.ts
5
7
  declare const plugin: {
@@ -19,7 +21,7 @@ declare const plugin: {
19
21
  };
20
22
  name: string;
21
23
  plugins: {
22
- readonly "package-json": /*elided*/any;
24
+ readonly "package-json": ESLint.Plugin;
23
25
  };
24
26
  rules: {
25
27
  "package-json/valid-package-definition": ["error", {
@@ -32,7 +34,7 @@ declare const plugin: {
32
34
  name: string;
33
35
  version: string;
34
36
  };
35
- rules: Record<string, PackageJsonRuleModule<unknown[]>>;
37
+ rules: Record<string, PackageJsonRuleModule<unknown[], json_schema_to_ts0.JSONSchema[]>>;
36
38
  };
37
39
  //#endregion
38
40
  export { plugin };
package/lib/plugin.js CHANGED
@@ -17,8 +17,7 @@ import { createRequire } from "node:module";
17
17
  import * as parserJsonc from "jsonc-eslint-parser";
18
18
 
19
19
  //#region src/plugin.ts
20
- const require = createRequire(import.meta.url);
21
- const { name, version } = require("../package.json");
20
+ const { name, version } = createRequire(import.meta.url)("../package.json");
22
21
  const rules$2 = {
23
22
  "no-empty-fields": rule,
24
23
  "no-redundant-files": rule$1,
@@ -1,10 +1,20 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/no-empty-fields.d.ts
4
- interface Option {
5
- ignoreProperties?: string[];
6
- }
7
- type Options = [Option?];
8
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ ignoreProperties?: string[] | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly ignoreProperties: {
10
+ readonly description: "Array of top-level properties to ignore.";
11
+ readonly items: {
12
+ readonly type: "string";
13
+ };
14
+ readonly type: "array";
15
+ };
16
+ };
17
+ readonly type: "object";
18
+ }]>;
9
19
  //#endregion
10
20
  export { rule };
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/no-redundant-files.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -73,8 +73,7 @@ const rule = createRule({
73
73
  messageId: "unnecessaryBin"
74
74
  }];
75
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);
76
+ if (getCachedLocalFileRegex(fileEntry.value)?.test(fileToCheck)) report(files, index, validation.messageId);
78
77
  }
79
78
  }
80
79
  };
@@ -1,10 +1,25 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/order-properties.d.ts
4
- type Options = [{
5
- order: Order;
6
- }?];
7
- type Order = "legacy" | "sort-package-json" | string[];
8
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ order?: "sort-package-json" | "legacy" | string[] | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly order: {
10
+ readonly anyOf: readonly [{
11
+ readonly enum: readonly ["legacy", "sort-package-json"];
12
+ readonly type: readonly ["string"];
13
+ }, {
14
+ readonly items: {
15
+ readonly type: readonly ["string"];
16
+ };
17
+ readonly type: readonly ["array"];
18
+ }];
19
+ readonly description: "Specifies the sorting order of top-level properties.";
20
+ };
21
+ };
22
+ readonly type: "object";
23
+ }]>;
9
24
  //#endregion
10
25
  export { rule };
@@ -39,18 +39,16 @@ const rule = createRule({
39
39
  create(context) {
40
40
  return { "Program:exit"() {
41
41
  const { ast, text } = context.sourceCode;
42
- const options = {
43
- order: "sort-package-json",
44
- ...context.options[0]
45
- };
46
- const requiredOrder = options.order === "legacy" ? standardOrderLegacy : options.order === "sort-package-json" ? sortOrder : options.order;
42
+ const options = { ...context.options[0] };
43
+ options.order ??= "sort-package-json";
44
+ const { order } = options;
45
+ const requiredOrder = order === "legacy" ? standardOrderLegacy : order === "sort-package-json" ? sortOrder : order;
47
46
  const json = JSON.parse(text);
48
47
  const orderedSource = sortObjectKeys(json, [...requiredOrder, ...Object.keys(json)]);
49
48
  const orderedKeys = Object.keys(orderedSource);
50
49
  const { properties } = ast.body[0].expression;
51
50
  for (let i = 0; i < properties.length; i += 1) {
52
- const property = properties[i].key;
53
- const { value } = property;
51
+ const { value } = properties[i].key;
54
52
  if (value === orderedKeys[i]) continue;
55
53
  context.report({
56
54
  data: { property: value },
@@ -1,10 +1,18 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/repository-shorthand.d.ts
4
- type Form = "object" | "shorthand";
5
- type Options = [{
6
- form: Form;
7
- }?];
8
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ form?: "object" | "shorthand" | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly form: {
10
+ readonly description: "Specifies which repository form to enforce.";
11
+ readonly enum: readonly ["object", "shorthand"];
12
+ readonly type: readonly ["string"];
13
+ };
14
+ };
15
+ readonly type: "object";
16
+ }]>;
9
17
  //#endregion
10
18
  export { rule };
@@ -3,8 +3,17 @@ import { PackageJsonRuleModule } from "../createRule.js";
3
3
  //#region src/rules/require-properties.d.ts
4
4
  declare const rules: {
5
5
  [k: string]: PackageJsonRuleModule<[({
6
- ignorePrivate?: boolean;
7
- } | undefined)?]>;
6
+ ignorePrivate: boolean;
7
+ } | undefined)?], [{
8
+ readonly additionalProperties: false;
9
+ readonly properties: {
10
+ readonly ignorePrivate: {
11
+ readonly default: boolean;
12
+ readonly type: "boolean";
13
+ };
14
+ };
15
+ readonly type: "object";
16
+ }]>;
8
17
  };
9
18
  //#endregion
10
19
  export { rules };
@@ -1,15 +1,92 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/restrict-dependency-ranges.d.ts
4
- interface Option {
5
- forDependencyTypes?: string[];
6
- forPackages?: string[];
7
- forVersions?: string;
8
- rangeType: RangeType | RangeType[];
9
- }
10
- type Options = [Option | Option[] | undefined];
11
- declare const RANGE_TYPES: readonly ["caret", "pin", "tilde"];
12
- type RangeType = (typeof RANGE_TYPES)[number];
13
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ forDependencyTypes?: string[] | undefined;
6
+ forPackages?: string[] | undefined;
7
+ forVersions?: string | undefined;
8
+ rangeType: "caret" | "pin" | "tilde" | ("caret" | "pin" | "tilde")[];
9
+ } | {
10
+ forDependencyTypes?: string[] | undefined;
11
+ forPackages?: string[] | undefined;
12
+ forVersions?: string | undefined;
13
+ rangeType: "caret" | "pin" | "tilde" | ("caret" | "pin" | "tilde")[];
14
+ }[] | undefined)?], [{
15
+ readonly oneOf: readonly [{
16
+ readonly additionalProperties: false;
17
+ readonly properties: {
18
+ readonly forDependencyTypes: {
19
+ readonly description: "Apply a range type restriction for an entire group of dependencies by which type of dependencies they belong to.";
20
+ readonly items: {
21
+ readonly enum: string[];
22
+ };
23
+ readonly type: "array";
24
+ };
25
+ readonly forPackages: {
26
+ readonly description: "The exact name of a package, or a regex pattern used to match a group of packages by name.";
27
+ readonly items: {
28
+ readonly type: "string";
29
+ };
30
+ readonly type: "array";
31
+ };
32
+ readonly forVersions: {
33
+ readonly description: "Apply a restriction to a specific semver range.";
34
+ readonly type: "string";
35
+ };
36
+ readonly rangeType: {
37
+ readonly 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).";
38
+ readonly oneOf: readonly [{
39
+ readonly enum: readonly ["caret", "pin", "tilde"];
40
+ }, {
41
+ readonly items: {
42
+ readonly enum: readonly ["caret", "pin", "tilde"];
43
+ };
44
+ readonly type: "array";
45
+ }];
46
+ };
47
+ };
48
+ readonly required: readonly ["rangeType"];
49
+ readonly type: "object";
50
+ }, {
51
+ readonly description: "Array of configuration options, specifying range requirements.";
52
+ readonly items: {
53
+ readonly additionalProperties: false;
54
+ readonly properties: {
55
+ readonly forDependencyTypes: {
56
+ readonly description: "Apply a range type restriction for an entire group of dependencies by which type of dependencies they belong to.";
57
+ readonly items: {
58
+ readonly enum: string[];
59
+ };
60
+ readonly type: "array";
61
+ };
62
+ readonly forPackages: {
63
+ readonly description: "The exact name of a package, or a regex pattern used to match a group of packages by name.";
64
+ readonly items: {
65
+ readonly type: "string";
66
+ };
67
+ readonly type: "array";
68
+ };
69
+ readonly forVersions: {
70
+ readonly description: "Apply a restriction to a specific semver range.";
71
+ readonly type: "string";
72
+ };
73
+ readonly rangeType: {
74
+ readonly 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).";
75
+ readonly oneOf: readonly [{
76
+ readonly enum: readonly ["caret", "pin", "tilde"];
77
+ }, {
78
+ readonly items: {
79
+ readonly enum: readonly ["caret", "pin", "tilde"];
80
+ };
81
+ readonly type: "array";
82
+ }];
83
+ };
84
+ };
85
+ readonly required: readonly ["rangeType"];
86
+ readonly type: "object";
87
+ };
88
+ readonly type: "array";
89
+ }];
90
+ }]>;
14
91
  //#endregion
15
92
  export { rule };
@@ -73,8 +73,7 @@ const capitalize = (str) => {
73
73
  const rule = createRule({
74
74
  create(context) {
75
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) => ({
76
+ const optionsArray = (Array.isArray(context.options[0]) ? [...context.options[0]].reverse() : [context.options[0]]).map((option) => ({
78
77
  ...option,
79
78
  forPackages: option.forPackages?.map((pattern) => new RegExp(pattern)),
80
79
  rangeTypes: Array.isArray(option.rangeType) ? option.rangeType : [option.rangeType]
@@ -93,8 +92,7 @@ const rule = createRule({
93
92
  for (const options of optionsArray) {
94
93
  if (options.forDependencyTypes && !options.forDependencyTypes.includes(dependencyType)) continue;
95
94
  if (options.forPackages) {
96
- const isMatch = options.forPackages.some((packageNameRegex) => packageNameRegex.test(name));
97
- if (!isMatch) continue;
95
+ if (!options.forPackages.some((packageNameRegex) => packageNameRegex.test(name))) continue;
98
96
  }
99
97
  if (options.forVersions && (/^workspace:[^~*]?$/.test(version) || version !== "*" && !semver.satisfies(version.replace(/(?:workspace:)?[^~]?/, ""), options.forVersions))) continue;
100
98
  const rangeTypes = options.rangeTypes;
@@ -106,14 +104,13 @@ const rule = createRule({
106
104
  });
107
105
  break;
108
106
  }
109
- const rangeTypeMatch = rangeTypes.find((rangeType) => {
107
+ if (!rangeTypes.find((rangeType) => {
110
108
  switch (rangeType) {
111
109
  case "caret": return isCaretRange;
112
110
  case "pin": return isPinned;
113
111
  case "tilde": return isTildeRange;
114
112
  }
115
- });
116
- if (!rangeTypeMatch) context.report({
113
+ })) context.report({
117
114
  data: { rangeTypes: rangeTypes.join(", ") },
118
115
  messageId: "wrongRangeType",
119
116
  node: property.value,
@@ -1,7 +1,12 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/sort-collections.d.ts
4
- type Options = string[];
5
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[(string[] | undefined)?], [{
5
+ readonly description: "Array of package properties to require sorting.";
6
+ readonly items: {
7
+ readonly type: "string";
8
+ };
9
+ readonly type: "array";
10
+ }]>;
6
11
  //#endregion
7
12
  export { rule };
@@ -27,14 +27,11 @@ const rule = createRule({
27
27
  const currentOrder = collection.properties;
28
28
  let desiredOrder;
29
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;
30
+ return a.key.value > b.key.value ? 1 : -1;
33
31
  });
34
32
  else {
35
33
  const scriptsSource = context.sourceCode.getText(node);
36
- const minimalJson = JSON.parse(`{${scriptsSource}}`);
37
- const { scripts: sortedScripts } = sortPackageJson(minimalJson);
34
+ const { scripts: sortedScripts } = sortPackageJson(JSON.parse(`{${scriptsSource}}`));
38
35
  const propertyNodeMap = Object.fromEntries(collection.properties.map((prop) => [prop.key.value, prop]));
39
36
  desiredOrder = Object.keys(sortedScripts).map((prop) => propertyNodeMap[prop]);
40
37
  }
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/unique-dependencies.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -1,9 +1,17 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-bin.d.ts
4
- type Options = [{
5
- enforceCase: boolean;
6
- }?];
7
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ enforceCase?: boolean | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly enforceCase: {
10
+ readonly description: "Enforce that the bin's keys should be in kebab case.";
11
+ readonly type: "boolean";
12
+ };
13
+ };
14
+ readonly type: "object";
15
+ }]>;
8
16
  //#endregion
9
17
  export { rule };
@@ -9,8 +9,7 @@ const rule = createRule({
9
9
  const shouldEnforceCase = !!context.options[0]?.enforceCase;
10
10
  return { "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=bin]"(node) {
11
11
  const binValueNode = node.value;
12
- const binValue = JSON.parse(context.sourceCode.getText(binValueNode));
13
- const errors = validateBin(binValue);
12
+ const errors = validateBin(JSON.parse(context.sourceCode.getText(binValueNode)));
14
13
  if (errors.length) context.report({
15
14
  data: { errors: formatErrors(errors) },
16
15
  messageId: "validationError",
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-local-dependency.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -9,8 +9,7 @@ const linkRegex = /^link:/;
9
9
  const rule = createRule({
10
10
  create(context) {
11
11
  return { "Program:exit"() {
12
- const original = JSON.parse(context.sourceCode.text);
13
- const { dependencies, devDependencies, peerDependencies } = original;
12
+ const { dependencies, devDependencies, peerDependencies } = JSON.parse(context.sourceCode.text);
14
13
  const depObjs = [
15
14
  Object.entries(dependencies ?? {}),
16
15
  Object.entries(peerDependencies ?? {}),
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-name.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -1,10 +1,20 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-package-definition.d.ts
4
- interface Option {
5
- ignoreProperties?: string[];
6
- }
7
- type Options = [Option?];
8
- declare const rule: PackageJsonRuleModule<Options>;
4
+ declare const rule: PackageJsonRuleModule<[({
5
+ ignoreProperties?: string[] | undefined;
6
+ } | undefined)?], [{
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly ignoreProperties: {
10
+ readonly description: "Array of top-level package properties to ignore.";
11
+ readonly items: {
12
+ readonly type: "string";
13
+ };
14
+ readonly type: "array";
15
+ };
16
+ };
17
+ readonly type: "object";
18
+ }]>;
9
19
  //#endregion
10
20
  export { rule };
@@ -12,8 +12,7 @@ const rule = createRule({
12
12
  create(context) {
13
13
  const ignoreProperties = context.options[0]?.ignoreProperties ?? [];
14
14
  return { "Program:exit"() {
15
- const validation = validate(context.sourceCode.text);
16
- const usableErrors = validation.errors?.filter((error) => {
15
+ const usableErrors = validate(context.sourceCode.text).errors?.filter((error) => {
17
16
  return isUsableError(error.message) && !ignoreProperties.includes(error.field);
18
17
  }) ?? [];
19
18
  for (const error of usableErrors) if (error.message) context.report({
@@ -3,7 +3,7 @@ import { PackageJsonRuleModule } from "../createRule.js";
3
3
  //#region src/rules/valid-properties.d.ts
4
4
  /** All basic valid- flavor rules */
5
5
  declare const rules: {
6
- [k: string]: PackageJsonRuleModule<unknown[]>;
6
+ [k: string]: PackageJsonRuleModule<[], []>;
7
7
  };
8
8
  //#endregion
9
9
  export { rules };
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-repository-directory.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -1,6 +1,6 @@
1
1
  import { PackageJsonRuleModule } from "../createRule.js";
2
2
 
3
3
  //#region src/rules/valid-version.d.ts
4
- declare const rule: PackageJsonRuleModule<unknown[]>;
4
+ declare const rule: PackageJsonRuleModule<[], []>;
5
5
  //#endregion
6
6
  export { rule };
@@ -5,6 +5,4 @@ declare module "estree" {
5
5
  interface NodeMap {
6
6
  JSONNode: JSONNode;
7
7
  }
8
- }
9
- //#endregion
10
- export {};
8
+ }
@@ -11,9 +11,6 @@ interface CreateRequirePropertyRuleOptions {
11
11
  */
12
12
  isRecommended?: boolean;
13
13
  }
14
- type Options = [{
15
- ignorePrivate?: boolean;
16
- }?];
17
14
  /**
18
15
  * Given a top-level property name, create a rule that requires that property to be present.
19
16
  * Optionally, include it in the recommended config.
@@ -24,7 +21,18 @@ declare const createSimpleRequirePropertyRule: (propertyName: string, {
24
21
  ignorePrivateDefault,
25
22
  isRecommended
26
23
  }?: CreateRequirePropertyRuleOptions) => {
27
- rule: PackageJsonRuleModule<Options>;
24
+ rule: PackageJsonRuleModule<[({
25
+ ignorePrivate: boolean;
26
+ } | undefined)?], [{
27
+ readonly additionalProperties: false;
28
+ readonly properties: {
29
+ readonly ignorePrivate: {
30
+ readonly default: boolean;
31
+ readonly type: "boolean";
32
+ };
33
+ };
34
+ readonly type: "object";
35
+ }]>;
28
36
  ruleName: string;
29
37
  };
30
38
  //#endregion
@@ -10,39 +10,38 @@ import { isJSONStringLiteral } from "./predicates.js";
10
10
  */
11
11
  const createSimpleRequirePropertyRule = (propertyName, { ignorePrivateDefault = false, isRecommended } = {}) => {
12
12
  const ruleName = `require-${propertyName}`;
13
- const rule = createRule({
14
- create(context) {
15
- const enforceForPrivate = context.settings.packageJson?.enforceForPrivate;
16
- const ignorePrivate = context.options[0]?.ignorePrivate ?? (typeof enforceForPrivate === "boolean" ? !enforceForPrivate : ignorePrivateDefault);
17
- return { "Program > JSONExpressionStatement > JSONObjectExpression"(node) {
18
- if (ignorePrivate && node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === "private" && property.value.type === "JSONLiteral" && property.value.value === true)) return;
19
- if (!node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === propertyName)) context.report({
20
- data: { property: propertyName },
21
- messageId: "missing",
22
- node: context.sourceCode.ast
23
- });
24
- } };
25
- },
26
- meta: {
27
- docs: {
28
- description: `Requires the \`${propertyName}\` property to be present.`,
29
- recommended: isRecommended
30
- },
31
- messages: { missing: "Property '{{property}}' is required." },
32
- schema: [{
33
- additionalProperties: false,
34
- properties: { ignorePrivate: {
35
- default: ignorePrivateDefault,
36
- type: "boolean"
37
- } },
38
- type: "object"
39
- }],
40
- type: "suggestion"
41
- },
42
- name: ruleName
43
- });
44
13
  return {
45
- rule,
14
+ rule: createRule({
15
+ create(context) {
16
+ const enforceForPrivate = context.settings.packageJson?.enforceForPrivate;
17
+ const ignorePrivate = context.options[0]?.ignorePrivate ?? (typeof enforceForPrivate === "boolean" ? !enforceForPrivate : ignorePrivateDefault);
18
+ return { "Program > JSONExpressionStatement > JSONObjectExpression"(node) {
19
+ if (ignorePrivate && node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === "private" && property.value.type === "JSONLiteral" && property.value.value === true)) return;
20
+ if (!node.properties.some((property) => isJSONStringLiteral(property.key) && property.key.value === propertyName)) context.report({
21
+ data: { property: propertyName },
22
+ messageId: "missing",
23
+ node: context.sourceCode.ast
24
+ });
25
+ } };
26
+ },
27
+ meta: {
28
+ docs: {
29
+ description: `Requires the \`${propertyName}\` property to be present.`,
30
+ recommended: isRecommended
31
+ },
32
+ messages: { missing: "Property '{{property}}' is required." },
33
+ schema: [{
34
+ additionalProperties: false,
35
+ properties: { ignorePrivate: {
36
+ default: ignorePrivateDefault,
37
+ type: "boolean"
38
+ } },
39
+ type: "object"
40
+ }],
41
+ type: "suggestion"
42
+ },
43
+ name: ruleName
44
+ }),
46
45
  ruleName
47
46
  };
48
47
  };
@@ -9,7 +9,7 @@ type ValidationFunction = (value: unknown) => string[];
9
9
  * to create a more complex rule, create it in its own file.
10
10
  */
11
11
  declare const createSimpleValidPropertyRule: (propertyName: string, validationFunction: ValidationFunction, aliases?: string[]) => {
12
- rule: PackageJsonRuleModule<unknown[]>;
12
+ rule: PackageJsonRuleModule<[], []>;
13
13
  ruleName: string;
14
14
  };
15
15
  //#endregion
@@ -11,36 +11,34 @@ import { formatErrors } from "./formatErrors.js";
11
11
  const createSimpleValidPropertyRule = (propertyName, validationFunction, aliases = []) => {
12
12
  const ruleName = `valid-${propertyName}`;
13
13
  const propertyNames = [propertyName, ...aliases];
14
- const rule = createRule({
15
- create(context) {
16
- return propertyNames.reduce((acc, name) => {
17
- acc[`Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=${name}]`] = (node) => {
18
- const valueNode = node.value;
19
- const value = JSON.parse(context.sourceCode.getText(valueNode));
20
- const errors = validationFunction(value);
21
- if (errors.length) context.report({
22
- data: { errors: formatErrors(errors) },
23
- messageId: "validationError",
24
- node: valueNode
25
- });
26
- };
27
- return acc;
28
- }, {});
29
- },
30
- meta: {
31
- docs: {
32
- category: "Best Practices",
33
- description: `Enforce that the \`${propertyName}\`${aliases.length ? ` (also: ${aliases.map((alias) => `\`${alias}\``).join(", ")})` : ""} property is valid.`,
34
- recommended: true
35
- },
36
- messages: { validationError: `Invalid ${propertyName}: {{ errors }}` },
37
- schema: [],
38
- type: "problem"
39
- },
40
- name: ruleName
41
- });
42
14
  return {
43
- rule,
15
+ rule: createRule({
16
+ create(context) {
17
+ return propertyNames.reduce((acc, name) => {
18
+ acc[`Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=${name}]`] = (node) => {
19
+ const valueNode = node.value;
20
+ const errors = validationFunction(JSON.parse(context.sourceCode.getText(valueNode)));
21
+ if (errors.length) context.report({
22
+ data: { errors: formatErrors(errors) },
23
+ messageId: "validationError",
24
+ node: valueNode
25
+ });
26
+ };
27
+ return acc;
28
+ }, {});
29
+ },
30
+ meta: {
31
+ docs: {
32
+ category: "Best Practices",
33
+ description: `Enforce that the \`${propertyName}\`${aliases.length ? ` (also: ${aliases.map((alias) => `\`${alias}\``).join(", ")})` : ""} property is valid.`,
34
+ recommended: true
35
+ },
36
+ messages: { validationError: `Invalid ${propertyName}: {{ errors }}` },
37
+ schema: [],
38
+ type: "problem"
39
+ },
40
+ name: ruleName
41
+ }),
44
42
  ruleName
45
43
  };
46
44
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "0.56.2",
3
+ "version": "0.56.4",
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": {
@@ -35,7 +35,6 @@
35
35
  "lint:docs": "eslint-doc-generator --check",
36
36
  "lint:knip": "knip",
37
37
  "lint:md": "markdownlint \"**/*.md\" \".github/**/*.md\" --rules sentences-per-line",
38
- "lint:packages": "pnpm dedupe --check",
39
38
  "prepare": "husky",
40
39
  "test": "vitest",
41
40
  "typecheck": "tsc"
@@ -57,9 +56,8 @@
57
56
  },
58
57
  "devDependencies": {
59
58
  "@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
60
- "@eslint/js": "9.34.0",
59
+ "@eslint/js": "9.37.0",
61
60
  "@release-it/conventional-changelog": "10.0.0",
62
- "@types/eslint-plugin-markdown": "2.0.2",
63
61
  "@types/estree": "1.0.7",
64
62
  "@types/node": "22.18.0",
65
63
  "@types/semver": "7.7.0",
@@ -68,21 +66,21 @@
68
66
  "@vitest/coverage-v8": "3.2.0",
69
67
  "@vitest/eslint-plugin": "1.3.3",
70
68
  "console-fail-test": "0.5.0",
71
- "eslint": "9.34.0",
72
- "eslint-doc-generator": "2.2.0",
69
+ "eslint": "9.37.0",
70
+ "eslint-doc-generator": "2.3.0",
73
71
  "eslint-plugin-eslint-plugin": "7.0.0",
74
- "eslint-plugin-jsdoc": "54.1.0",
75
- "eslint-plugin-jsonc": "2.20.0",
76
- "eslint-plugin-markdown": "5.1.0",
72
+ "eslint-plugin-jsdoc": "60.8.0",
73
+ "eslint-plugin-jsonc": "2.21.0",
77
74
  "eslint-plugin-n": "17.21.0",
78
75
  "eslint-plugin-perfectionist": "4.15.0",
79
76
  "eslint-plugin-regexp": "2.10.0",
80
- "eslint-plugin-yml": "1.18.0",
77
+ "eslint-plugin-yml": "1.19.0",
81
78
  "husky": "9.1.7",
82
- "jiti": "2.5.0",
83
- "jsonc-eslint-parser": "2.4.0",
84
- "knip": "5.63.0",
85
- "lint-staged": "16.1.0",
79
+ "jiti": "2.6.0",
80
+ "json-schema-to-ts": "3.1.1",
81
+ "jsonc-eslint-parser": "2.4.1",
82
+ "knip": "5.64.0",
83
+ "lint-staged": "16.2.0",
86
84
  "markdownlint": "0.38.0",
87
85
  "markdownlint-cli": "0.45.0",
88
86
  "prettier": "3.6.0",
@@ -91,18 +89,18 @@
91
89
  "prettier-plugin-sh": "0.18.0",
92
90
  "release-it": "19.0.1",
93
91
  "sentences-per-line": "0.3.0",
94
- "tsdown": "0.14.0",
92
+ "tsdown": "0.15.0",
95
93
  "typescript": "5.9.2",
96
- "typescript-eslint": "8.41.0",
94
+ "typescript-eslint": "8.46.0",
97
95
  "vitest": "3.2.0"
98
96
  },
99
97
  "peerDependencies": {
100
98
  "eslint": ">=8.0.0",
101
99
  "jsonc-eslint-parser": "^2.0.0"
102
100
  },
103
- "packageManager": "pnpm@10.15.0",
101
+ "packageManager": "pnpm@10.18.0",
104
102
  "engines": {
105
- "node": "^=20.19.0 || >=22.12.0"
103
+ "node": "^20.19.0 || >=22.12.0"
106
104
  },
107
105
  "publishConfig": {
108
106
  "provenance": true