eslint-plugin-package-json 0.15.6 โ†’ 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  <a href="#contributors" target="_blank">
7
7
  <!-- prettier-ignore-start -->
8
8
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
9
- <img alt="All Contributors: 18 ๐Ÿ‘ช" src="https://img.shields.io/badge/all_contributors-18_๐Ÿ‘ช-21bb42.svg" />
9
+ <img alt="All Contributors: 21 ๐Ÿ‘ช" src="https://img.shields.io/badge/all_contributors-21_๐Ÿ‘ช-21bb42.svg" />
10
10
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
11
11
  <!-- prettier-ignore-end -->
12
12
  </a>
@@ -19,17 +19,17 @@
19
19
 
20
20
  ## Installation
21
21
 
22
- This package requires [ESLint](http://eslint.org) 8 and [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser):
22
+ This package requires [ESLint](http://eslint.org) >=8:
23
23
 
24
24
  ```shell
25
- npm install eslint eslint-plugin-package-json jsonc-eslint-parser --save-dev
25
+ npm install eslint eslint-plugin-package-json --save-dev
26
26
  ```
27
27
 
28
28
  ## Usage
29
29
 
30
30
  ### Flat Config
31
31
 
32
- This plugin's recommended configuration enables its rules on `**/package.json` files, parsing them with [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser):
32
+ This plugin's recommended configuration enables its rules on `**/package.json` files, parsing them with [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser).
33
33
 
34
34
  In your ESLint configuration file:
35
35
 
@@ -63,7 +63,13 @@ See [ESLint's _Configuration Files_ guide](https://eslint.org/docs/latest/use/co
63
63
 
64
64
  ### Legacy Config
65
65
 
66
- Add an override to your ESLint configuration file that specifies this plugin, [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser), and its recommended rules for your `package.json` file:
66
+ Usage with ESLint's legacy ("eslintrc") format requires also installing [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser):
67
+
68
+ ```shell
69
+ npm install jsonc-eslint-parser --save-dev
70
+ ```
71
+
72
+ Add an override to your ESLint configuration file that specifies `jsonc-eslint-parser`, this plugin, and its recommended rules for your `package.json` file:
67
73
 
68
74
  ```js
69
75
  module.exports = {
@@ -113,17 +119,17 @@ The default settings don't conflict, and Prettier plugins can quickly fix up ord
113
119
  ๐Ÿ”ง Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
114
120
  ๐Ÿ’ก Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
115
121
 
116
- | Nameย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  | Description | ๐Ÿ’ผ | ๐Ÿ”ง | ๐Ÿ’ก |
117
- | :--------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------- | :- | :- | :- |
118
- | [order-properties](docs/rules/order-properties.md) | Package properties must be declared in standard order | โœ… | ๐Ÿ”ง | |
119
- | [repository-shorthand](docs/rules/repository-shorthand.md) | Enforce either object or shorthand declaration for repository. | โœ… | ๐Ÿ”ง | |
120
- | [sort-collections](docs/rules/sort-collections.md) | Dependencies, scripts, and configuration values must be declared in alphabetical order. | โœ… | ๐Ÿ”ง | |
121
- | [unique-dependencies](docs/rules/unique-dependencies.md) | Enforce that if repository directory is specified, it matches the path to the package.json file | โœ… | | ๐Ÿ’ก |
122
- | [valid-local-dependency](docs/rules/valid-local-dependency.md) | Checks existence of local dependencies in the package.json | โœ… | | |
123
- | [valid-name](docs/rules/valid-name.md) | Enforce that package names are valid npm package names | โœ… | | |
124
- | [valid-package-def](docs/rules/valid-package-def.md) | Enforce that package.json has all properties required by the npm spec | โœ… | | |
125
- | [valid-repository-directory](docs/rules/valid-repository-directory.md) | Enforce that if repository directory is specified, it matches the path to the package.json file | โœ… | | ๐Ÿ’ก |
126
- | [valid-version](docs/rules/valid-version.md) | Enforce that package versions are valid semver specifiers | โœ… | | |
122
+ | Nameย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย  | Description | ๐Ÿ’ผ | ๐Ÿ”ง | ๐Ÿ’ก |
123
+ | :--------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | :- | :- | :- |
124
+ | [order-properties](docs/rules/order-properties.md) | Package properties must be declared in standard order | โœ… | ๐Ÿ”ง | |
125
+ | [repository-shorthand](docs/rules/repository-shorthand.md) | Enforce either object or shorthand declaration for repository. | โœ… | ๐Ÿ”ง | |
126
+ | [sort-collections](docs/rules/sort-collections.md) | Dependencies, scripts, and configuration values must be declared in alphabetical order. | โœ… | ๐Ÿ”ง | |
127
+ | [unique-dependencies](docs/rules/unique-dependencies.md) | Checks a dependency isn't specified more than once (i.e. in `dependencies` and `devDependencies`) | โœ… | | ๐Ÿ’ก |
128
+ | [valid-local-dependency](docs/rules/valid-local-dependency.md) | Checks existence of local dependencies in the package.json | โœ… | | |
129
+ | [valid-name](docs/rules/valid-name.md) | Enforce that package names are valid npm package names | โœ… | | |
130
+ | [valid-package-def](docs/rules/valid-package-def.md) | Enforce that package.json has all properties required by the npm spec | โœ… | | |
131
+ | [valid-repository-directory](docs/rules/valid-repository-directory.md) | Enforce that if repository directory is specified, it matches the path to the package.json file | โœ… | | ๐Ÿ’ก |
132
+ | [valid-version](docs/rules/valid-version.md) | Enforce that package versions are valid semver specifiers | โœ… | | |
127
133
 
128
134
  <!-- end auto-generated rules list -->
129
135
  <!-- prettier-ignore-end -->
@@ -131,6 +137,11 @@ The default settings don't conflict, and Prettier plugins can quickly fix up ord
131
137
  These rules only run on `package.json` files; they will ignore all other files being linted.
132
138
  They can lint `package.json` files at project root and in any subfolder of the project, making this plugin great for monorepos.
133
139
 
140
+ ## Development
141
+
142
+ See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md), then [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md).
143
+ Thanks! ๐Ÿ’–
144
+
134
145
  ## Contributors
135
146
 
136
147
  <!-- spellchecker: disable -->
@@ -144,20 +155,23 @@ They can lint `package.json` files at project root and in any subfolder of the p
144
155
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/AndreasLindbergPAF"><img src="https://avatars.githubusercontent.com/u/59874563?v=4?s=100" width="100px;" alt="Andreas Lindberg"/><br /><sub><b>Andreas Lindberg</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=author%3Aandreaslindbergpaf" title="Bug reports">๐Ÿ›</a></td>
145
156
  <td align="center" valign="top" width="14.28%"><a href="http://technotes.khitrenovich.com/"><img src="https://avatars.githubusercontent.com/u/3424762?v=4?s=100" width="100px;" alt="Anton Khitrenovich"/><br /><sub><b>Anton Khitrenovich</b></sub></a><br /><a href="#ideas-khitrenovich" title="Ideas, Planning, & Feedback">๐Ÿค”</a></td>
146
157
  <td align="center" valign="top" width="14.28%"><a href="https://azat.io"><img src="https://avatars.githubusercontent.com/u/5698350?v=4?s=100" width="100px;" alt="Azat S."/><br /><sub><b>Azat S.</b></sub></a><br /><a href="#ideas-azat-io" title="Ideas, Planning, & Feedback">๐Ÿค”</a> <a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=azat-io" title="Code">๐Ÿ’ป</a></td>
158
+ <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>
147
159
  <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>
148
160
  <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></td>
149
- <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>
150
161
  </tr>
151
162
  <tr>
163
+ <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>
152
164
  <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>
153
165
  <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></td>
154
166
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/kendallgassner"><img src="https://avatars.githubusercontent.com/u/15275462?v=4?s=100" width="100px;" alt="Kendall Gassner"/><br /><sub><b>Kendall Gassner</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/commits?author=kendallgassner" title="Code">๐Ÿ’ป</a> <a href="#maintenance-kendallgassner" title="Maintenance">๐Ÿšง</a></td>
155
167
  <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>
156
168
  <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>
157
169
  <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>
158
- <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>
159
170
  </tr>
160
171
  <tr>
172
+ <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>
173
+ <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></td>
174
+ <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>
161
175
  <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>
162
176
  <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>
163
177
  <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>
@@ -27,6 +27,7 @@ const defaultCollections = [
27
27
  "devDependencies",
28
28
  "dependencies",
29
29
  "peerDependencies",
30
+ "overrides",
30
31
  "config",
31
32
  "exports"
32
33
  ];
@@ -39,9 +40,38 @@ const rule = (0, import_createRule.createRule)({
39
40
  const collection = value;
40
41
  if (collection.type === "JSONObjectExpression" && toSort.includes(key.value)) {
41
42
  const currentOrder = collection.properties;
42
- const desiredOrder = currentOrder.slice().sort(
43
- (a, b) => a.key.value > b.key.value ? 1 : -1
43
+ const scripts = new Set(
44
+ currentOrder.map(
45
+ (prop) => prop.key.value
46
+ )
44
47
  );
48
+ const desiredOrder = currentOrder.slice().sort((a, b) => {
49
+ let aKey = a.key.value;
50
+ let bKey = b.key.value;
51
+ if (key.value !== "scripts") {
52
+ return aKey > bKey ? 1 : -1;
53
+ } else {
54
+ let modifier = 0;
55
+ if (aKey.startsWith("pre") && scripts.has(aKey.substring(3))) {
56
+ aKey = aKey.substring(3);
57
+ modifier -= 1;
58
+ } else if (aKey.startsWith("post") && scripts.has(aKey.substring(4))) {
59
+ aKey = aKey.substring(4);
60
+ modifier += 1;
61
+ }
62
+ if (bKey.startsWith("pre") && scripts.has(bKey.substring(3))) {
63
+ bKey = bKey.substring(3);
64
+ modifier += 1;
65
+ } else if (bKey.startsWith("post") && scripts.has(bKey.substring(4))) {
66
+ bKey = bKey.substring(4);
67
+ modifier -= 1;
68
+ }
69
+ if (aKey === bKey) {
70
+ return modifier;
71
+ }
72
+ return aKey > bKey ? 1 : -1;
73
+ }
74
+ });
45
75
  if (currentOrder.some(
46
76
  (property, i) => desiredOrder[i] !== property
47
77
  )) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/sort-collections.ts"],"sourcesContent":["import * as ESTree from \"estree\";\nimport { AST } from \"jsonc-eslint-parser\";\n\nimport { createRule } from \"../createRule.js\";\n\nconst defaultCollections = [\n\t\"scripts\",\n\t\"devDependencies\",\n\t\"dependencies\",\n\t\"peerDependencies\",\n\t\"config\",\n\t\"exports\",\n];\n\ntype Options = string[];\n\nexport const rule = createRule<Options>({\n\tcreate(context) {\n\t\tconst toSort = context.options[0] || defaultCollections;\n\t\treturn {\n\t\t\t\"JSONProperty:exit\"(node) {\n\t\t\t\tconst { key, value } = node as AST.JSONProperty & {\n\t\t\t\t\tkey: AST.JSONStringLiteral;\n\t\t\t\t};\n\n\t\t\t\tconst collection = value;\n\t\t\t\tif (\n\t\t\t\t\tcollection.type === \"JSONObjectExpression\" &&\n\t\t\t\t\ttoSort.includes(key.value)\n\t\t\t\t) {\n\t\t\t\t\tconst currentOrder = collection.properties;\n\t\t\t\t\tconst desiredOrder = currentOrder\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.sort((a, b) =>\n\t\t\t\t\t\t\t(a.key as AST.JSONStringLiteral).value >\n\t\t\t\t\t\t\t(b.key as AST.JSONStringLiteral).value\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: -1,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentOrder.some(\n\t\t\t\t\t\t\t(property, i) => desiredOrder[i] !== property,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tkey: key.value,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\treturn fixer.replaceText(\n\t\t\t\t\t\t\t\t\tcollection as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\tdesiredOrder.reduce<\n\t\t\t\t\t\t\t\t\t\t\tRecord<string, unknown>\n\t\t\t\t\t\t\t\t\t\t>((out, property) => {\n\t\t\t\t\t\t\t\t\t\t\tout[\n\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.key as AST.JSONStringLiteral\n\t\t\t\t\t\t\t\t\t\t\t\t).value\n\t\t\t\t\t\t\t\t\t\t\t] = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getText(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.value as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn out;\n\t\t\t\t\t\t\t\t\t\t}, {}),\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t\t\t\t.join(\"\\n \"), // nest indents\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tloc: collection.loc,\n\t\t\t\t\t\t\tmessage: \"Package {{ key }} are not alphabetized\",\n\t\t\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Dependencies, scripts, and configuration values must be declared in alphabetical order.\",\n\t\t\trecommended: true,\n\t\t},\n\t\tfixable: \"code\",\n\t\tschema: [\n\t\t\t{\n\t\t\t\titems: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t\ttype: \"array\",\n\t\t\t},\n\t\t],\n\t},\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,wBAA2B;AAE3B,MAAM,qBAAqB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAIO,MAAM,WAAO,8BAAoB;AAAA,EACvC,OAAO,SAAS;AACf,UAAM,SAAS,QAAQ,QAAQ,CAAC,KAAK;AACrC,WAAO;AAAA,MACN,oBAAoB,MAAM;AACzB,cAAM,EAAE,KAAK,MAAM,IAAI;AAIvB,cAAM,aAAa;AACnB,YACC,WAAW,SAAS,0BACpB,OAAO,SAAS,IAAI,KAAK,GACxB;AACD,gBAAM,eAAe,WAAW;AAChC,gBAAM,eAAe,aACnB,MAAM,EACN;AAAA,YAAK,CAAC,GAAG,MACR,EAAE,IAA8B,QAChC,EAAE,IAA8B,QAC9B,IACA;AAAA,UACJ;AACD,cACC,aAAa;AAAA,YACZ,CAAC,UAAU,MAAM,aAAa,CAAC,MAAM;AAAA,UACtC,GACC;AACD,oBAAQ,OAAO;AAAA,cACd,MAAM;AAAA,gBACL,KAAK,IAAI;AAAA,cACV;AAAA,cACA,IAAI,OAAO;AACV,uBAAO,MAAM;AAAA,kBACZ;AAAA,kBACA,KAAK;AAAA,oBACJ,aAAa,OAEX,CAAC,KAAK,aAAa;AACpB,0BAEE,SAAS,IACR,KACH,IAAI,KAAK;AAAA,wBACR,QAAQ,WAAW;AAAA,0BAClB,SAAS;AAAA,wBACV;AAAA,sBACD;AACA,6BAAO;AAAA,oBACR,GAAG,CAAC,CAAC;AAAA,oBACL;AAAA,oBACA;AAAA,kBACD,EACE,MAAM,IAAI,EACV,KAAK,MAAM;AAAA;AAAA,gBACd;AAAA,cACD;AAAA,cACA,KAAK,WAAW;AAAA,cAChB,SAAS;AAAA,cACT;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,MACP;AAAA,QACC,OAAO;AAAA,UACN,MAAM;AAAA,QACP;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/rules/sort-collections.ts"],"sourcesContent":["import * as ESTree from \"estree\";\nimport { AST } from \"jsonc-eslint-parser\";\n\nimport { createRule } from \"../createRule.js\";\n\nconst defaultCollections = [\n\t\"scripts\",\n\t\"devDependencies\",\n\t\"dependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n\t\"config\",\n\t\"exports\",\n];\n\ntype Options = string[];\n\nexport const rule = createRule<Options>({\n\tcreate(context) {\n\t\tconst toSort = context.options[0] || defaultCollections;\n\t\treturn {\n\t\t\t\"JSONProperty:exit\"(node) {\n\t\t\t\tconst { key, value } = node as AST.JSONProperty & {\n\t\t\t\t\tkey: AST.JSONStringLiteral;\n\t\t\t\t};\n\n\t\t\t\tconst collection = value;\n\t\t\t\tif (\n\t\t\t\t\tcollection.type === \"JSONObjectExpression\" &&\n\t\t\t\t\ttoSort.includes(key.value)\n\t\t\t\t) {\n\t\t\t\t\tconst currentOrder = collection.properties;\n\t\t\t\t\tconst scripts = new Set(\n\t\t\t\t\t\tcurrentOrder.map(\n\t\t\t\t\t\t\t(prop) => (prop.key as AST.JSONStringLiteral).value,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tconst desiredOrder = currentOrder.slice().sort((a, b) => {\n\t\t\t\t\t\tlet aKey = (a.key as AST.JSONStringLiteral).value;\n\t\t\t\t\t\tlet bKey = (b.key as AST.JSONStringLiteral).value;\n\n\t\t\t\t\t\tif (key.value !== \"scripts\") {\n\t\t\t\t\t\t\treturn aKey > bKey ? 1 : -1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlet modifier = 0;\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\taKey.startsWith(\"pre\") &&\n\t\t\t\t\t\t\t\tscripts.has(aKey.substring(3))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\taKey = aKey.substring(3);\n\t\t\t\t\t\t\t\tmodifier -= 1;\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\taKey.startsWith(\"post\") &&\n\t\t\t\t\t\t\t\tscripts.has(aKey.substring(4))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\taKey = aKey.substring(4);\n\t\t\t\t\t\t\t\tmodifier += 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tbKey.startsWith(\"pre\") &&\n\t\t\t\t\t\t\t\tscripts.has(bKey.substring(3))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tbKey = bKey.substring(3);\n\t\t\t\t\t\t\t\tmodifier += 1;\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\tbKey.startsWith(\"post\") &&\n\t\t\t\t\t\t\t\tscripts.has(bKey.substring(4))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tbKey = bKey.substring(4);\n\t\t\t\t\t\t\t\tmodifier -= 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aKey === bKey) {\n\t\t\t\t\t\t\t\treturn modifier;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn aKey > bKey ? 1 : -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentOrder.some(\n\t\t\t\t\t\t\t(property, i) => desiredOrder[i] !== property,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tkey: key.value,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\treturn fixer.replaceText(\n\t\t\t\t\t\t\t\t\tcollection as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\tdesiredOrder.reduce<\n\t\t\t\t\t\t\t\t\t\t\tRecord<string, unknown>\n\t\t\t\t\t\t\t\t\t\t>((out, property) => {\n\t\t\t\t\t\t\t\t\t\t\tout[\n\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.key as AST.JSONStringLiteral\n\t\t\t\t\t\t\t\t\t\t\t\t).value\n\t\t\t\t\t\t\t\t\t\t\t] = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getText(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.value as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn out;\n\t\t\t\t\t\t\t\t\t\t}, {}),\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t\t\t\t.join(\"\\n \"), // nest indents\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tloc: collection.loc,\n\t\t\t\t\t\t\tmessage: \"Package {{ key }} are not alphabetized\",\n\t\t\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Dependencies, scripts, and configuration values must be declared in alphabetical order.\",\n\t\t\trecommended: true,\n\t\t},\n\t\tfixable: \"code\",\n\t\tschema: [\n\t\t\t{\n\t\t\t\titems: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t\ttype: \"array\",\n\t\t\t},\n\t\t],\n\t},\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,wBAA2B;AAE3B,MAAM,qBAAqB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAIO,MAAM,WAAO,8BAAoB;AAAA,EACvC,OAAO,SAAS;AACf,UAAM,SAAS,QAAQ,QAAQ,CAAC,KAAK;AACrC,WAAO;AAAA,MACN,oBAAoB,MAAM;AACzB,cAAM,EAAE,KAAK,MAAM,IAAI;AAIvB,cAAM,aAAa;AACnB,YACC,WAAW,SAAS,0BACpB,OAAO,SAAS,IAAI,KAAK,GACxB;AACD,gBAAM,eAAe,WAAW;AAChC,gBAAM,UAAU,IAAI;AAAA,YACnB,aAAa;AAAA,cACZ,CAAC,SAAU,KAAK,IAA8B;AAAA,YAC/C;AAAA,UACD;AAEA,gBAAM,eAAe,aAAa,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AACxD,gBAAI,OAAQ,EAAE,IAA8B;AAC5C,gBAAI,OAAQ,EAAE,IAA8B;AAE5C,gBAAI,IAAI,UAAU,WAAW;AAC5B,qBAAO,OAAO,OAAO,IAAI;AAAA,YAC1B,OAAO;AACN,kBAAI,WAAW;AAEf,kBACC,KAAK,WAAW,KAAK,KACrB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb,WACC,KAAK,WAAW,MAAM,KACtB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb;AAEA,kBACC,KAAK,WAAW,KAAK,KACrB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb,WACC,KAAK,WAAW,MAAM,KACtB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb;AAEA,kBAAI,SAAS,MAAM;AAClB,uBAAO;AAAA,cACR;AAEA,qBAAO,OAAO,OAAO,IAAI;AAAA,YAC1B;AAAA,UACD,CAAC;AACD,cACC,aAAa;AAAA,YACZ,CAAC,UAAU,MAAM,aAAa,CAAC,MAAM;AAAA,UACtC,GACC;AACD,oBAAQ,OAAO;AAAA,cACd,MAAM;AAAA,gBACL,KAAK,IAAI;AAAA,cACV;AAAA,cACA,IAAI,OAAO;AACV,uBAAO,MAAM;AAAA,kBACZ;AAAA,kBACA,KAAK;AAAA,oBACJ,aAAa,OAEX,CAAC,KAAK,aAAa;AACpB,0BAEE,SAAS,IACR,KACH,IAAI,KAAK;AAAA,wBACR,QAAQ,WAAW;AAAA,0BAClB,SAAS;AAAA,wBACV;AAAA,sBACD;AACA,6BAAO;AAAA,oBACR,GAAG,CAAC,CAAC;AAAA,oBACL;AAAA,oBACA;AAAA,kBACD,EACE,MAAM,IAAI,EACV,KAAK,MAAM;AAAA;AAAA,gBACd;AAAA,cACD;AAAA,cACA,KAAK,WAAW;AAAA,cAChB,SAAS;AAAA,cACT;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,MACP;AAAA,QACC,OAAO;AAAA,UACN,MAAM;AAAA,QACP;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD,CAAC;","names":[]}
@@ -4,6 +4,7 @@ const defaultCollections = [
4
4
  "devDependencies",
5
5
  "dependencies",
6
6
  "peerDependencies",
7
+ "overrides",
7
8
  "config",
8
9
  "exports"
9
10
  ];
@@ -16,9 +17,38 @@ const rule = createRule({
16
17
  const collection = value;
17
18
  if (collection.type === "JSONObjectExpression" && toSort.includes(key.value)) {
18
19
  const currentOrder = collection.properties;
19
- const desiredOrder = currentOrder.slice().sort(
20
- (a, b) => a.key.value > b.key.value ? 1 : -1
20
+ const scripts = new Set(
21
+ currentOrder.map(
22
+ (prop) => prop.key.value
23
+ )
21
24
  );
25
+ const desiredOrder = currentOrder.slice().sort((a, b) => {
26
+ let aKey = a.key.value;
27
+ let bKey = b.key.value;
28
+ if (key.value !== "scripts") {
29
+ return aKey > bKey ? 1 : -1;
30
+ } else {
31
+ let modifier = 0;
32
+ if (aKey.startsWith("pre") && scripts.has(aKey.substring(3))) {
33
+ aKey = aKey.substring(3);
34
+ modifier -= 1;
35
+ } else if (aKey.startsWith("post") && scripts.has(aKey.substring(4))) {
36
+ aKey = aKey.substring(4);
37
+ modifier += 1;
38
+ }
39
+ if (bKey.startsWith("pre") && scripts.has(bKey.substring(3))) {
40
+ bKey = bKey.substring(3);
41
+ modifier += 1;
42
+ } else if (bKey.startsWith("post") && scripts.has(bKey.substring(4))) {
43
+ bKey = bKey.substring(4);
44
+ modifier -= 1;
45
+ }
46
+ if (aKey === bKey) {
47
+ return modifier;
48
+ }
49
+ return aKey > bKey ? 1 : -1;
50
+ }
51
+ });
22
52
  if (currentOrder.some(
23
53
  (property, i) => desiredOrder[i] !== property
24
54
  )) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/sort-collections.ts"],"sourcesContent":["import * as ESTree from \"estree\";\nimport { AST } from \"jsonc-eslint-parser\";\n\nimport { createRule } from \"../createRule.js\";\n\nconst defaultCollections = [\n\t\"scripts\",\n\t\"devDependencies\",\n\t\"dependencies\",\n\t\"peerDependencies\",\n\t\"config\",\n\t\"exports\",\n];\n\ntype Options = string[];\n\nexport const rule = createRule<Options>({\n\tcreate(context) {\n\t\tconst toSort = context.options[0] || defaultCollections;\n\t\treturn {\n\t\t\t\"JSONProperty:exit\"(node) {\n\t\t\t\tconst { key, value } = node as AST.JSONProperty & {\n\t\t\t\t\tkey: AST.JSONStringLiteral;\n\t\t\t\t};\n\n\t\t\t\tconst collection = value;\n\t\t\t\tif (\n\t\t\t\t\tcollection.type === \"JSONObjectExpression\" &&\n\t\t\t\t\ttoSort.includes(key.value)\n\t\t\t\t) {\n\t\t\t\t\tconst currentOrder = collection.properties;\n\t\t\t\t\tconst desiredOrder = currentOrder\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.sort((a, b) =>\n\t\t\t\t\t\t\t(a.key as AST.JSONStringLiteral).value >\n\t\t\t\t\t\t\t(b.key as AST.JSONStringLiteral).value\n\t\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t\t: -1,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentOrder.some(\n\t\t\t\t\t\t\t(property, i) => desiredOrder[i] !== property,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tkey: key.value,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\treturn fixer.replaceText(\n\t\t\t\t\t\t\t\t\tcollection as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\tdesiredOrder.reduce<\n\t\t\t\t\t\t\t\t\t\t\tRecord<string, unknown>\n\t\t\t\t\t\t\t\t\t\t>((out, property) => {\n\t\t\t\t\t\t\t\t\t\t\tout[\n\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.key as AST.JSONStringLiteral\n\t\t\t\t\t\t\t\t\t\t\t\t).value\n\t\t\t\t\t\t\t\t\t\t\t] = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getText(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.value as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn out;\n\t\t\t\t\t\t\t\t\t\t}, {}),\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t\t\t\t.join(\"\\n \"), // nest indents\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tloc: collection.loc,\n\t\t\t\t\t\t\tmessage: \"Package {{ key }} are not alphabetized\",\n\t\t\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Dependencies, scripts, and configuration values must be declared in alphabetical order.\",\n\t\t\trecommended: true,\n\t\t},\n\t\tfixable: \"code\",\n\t\tschema: [\n\t\t\t{\n\t\t\t\titems: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t\ttype: \"array\",\n\t\t\t},\n\t\t],\n\t},\n});\n"],"mappings":"AAGA,SAAS,kBAAkB;AAE3B,MAAM,qBAAqB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAIO,MAAM,OAAO,WAAoB;AAAA,EACvC,OAAO,SAAS;AACf,UAAM,SAAS,QAAQ,QAAQ,CAAC,KAAK;AACrC,WAAO;AAAA,MACN,oBAAoB,MAAM;AACzB,cAAM,EAAE,KAAK,MAAM,IAAI;AAIvB,cAAM,aAAa;AACnB,YACC,WAAW,SAAS,0BACpB,OAAO,SAAS,IAAI,KAAK,GACxB;AACD,gBAAM,eAAe,WAAW;AAChC,gBAAM,eAAe,aACnB,MAAM,EACN;AAAA,YAAK,CAAC,GAAG,MACR,EAAE,IAA8B,QAChC,EAAE,IAA8B,QAC9B,IACA;AAAA,UACJ;AACD,cACC,aAAa;AAAA,YACZ,CAAC,UAAU,MAAM,aAAa,CAAC,MAAM;AAAA,UACtC,GACC;AACD,oBAAQ,OAAO;AAAA,cACd,MAAM;AAAA,gBACL,KAAK,IAAI;AAAA,cACV;AAAA,cACA,IAAI,OAAO;AACV,uBAAO,MAAM;AAAA,kBACZ;AAAA,kBACA,KAAK;AAAA,oBACJ,aAAa,OAEX,CAAC,KAAK,aAAa;AACpB,0BAEE,SAAS,IACR,KACH,IAAI,KAAK;AAAA,wBACR,QAAQ,WAAW;AAAA,0BAClB,SAAS;AAAA,wBACV;AAAA,sBACD;AACA,6BAAO;AAAA,oBACR,GAAG,CAAC,CAAC;AAAA,oBACL;AAAA,oBACA;AAAA,kBACD,EACE,MAAM,IAAI,EACV,KAAK,MAAM;AAAA;AAAA,gBACd;AAAA,cACD;AAAA,cACA,KAAK,WAAW;AAAA,cAChB,SAAS;AAAA,cACT;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,MACP;AAAA,QACC,OAAO;AAAA,UACN,MAAM;AAAA,QACP;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/rules/sort-collections.ts"],"sourcesContent":["import * as ESTree from \"estree\";\nimport { AST } from \"jsonc-eslint-parser\";\n\nimport { createRule } from \"../createRule.js\";\n\nconst defaultCollections = [\n\t\"scripts\",\n\t\"devDependencies\",\n\t\"dependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n\t\"config\",\n\t\"exports\",\n];\n\ntype Options = string[];\n\nexport const rule = createRule<Options>({\n\tcreate(context) {\n\t\tconst toSort = context.options[0] || defaultCollections;\n\t\treturn {\n\t\t\t\"JSONProperty:exit\"(node) {\n\t\t\t\tconst { key, value } = node as AST.JSONProperty & {\n\t\t\t\t\tkey: AST.JSONStringLiteral;\n\t\t\t\t};\n\n\t\t\t\tconst collection = value;\n\t\t\t\tif (\n\t\t\t\t\tcollection.type === \"JSONObjectExpression\" &&\n\t\t\t\t\ttoSort.includes(key.value)\n\t\t\t\t) {\n\t\t\t\t\tconst currentOrder = collection.properties;\n\t\t\t\t\tconst scripts = new Set(\n\t\t\t\t\t\tcurrentOrder.map(\n\t\t\t\t\t\t\t(prop) => (prop.key as AST.JSONStringLiteral).value,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tconst desiredOrder = currentOrder.slice().sort((a, b) => {\n\t\t\t\t\t\tlet aKey = (a.key as AST.JSONStringLiteral).value;\n\t\t\t\t\t\tlet bKey = (b.key as AST.JSONStringLiteral).value;\n\n\t\t\t\t\t\tif (key.value !== \"scripts\") {\n\t\t\t\t\t\t\treturn aKey > bKey ? 1 : -1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlet modifier = 0;\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\taKey.startsWith(\"pre\") &&\n\t\t\t\t\t\t\t\tscripts.has(aKey.substring(3))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\taKey = aKey.substring(3);\n\t\t\t\t\t\t\t\tmodifier -= 1;\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\taKey.startsWith(\"post\") &&\n\t\t\t\t\t\t\t\tscripts.has(aKey.substring(4))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\taKey = aKey.substring(4);\n\t\t\t\t\t\t\t\tmodifier += 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tbKey.startsWith(\"pre\") &&\n\t\t\t\t\t\t\t\tscripts.has(bKey.substring(3))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tbKey = bKey.substring(3);\n\t\t\t\t\t\t\t\tmodifier += 1;\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\tbKey.startsWith(\"post\") &&\n\t\t\t\t\t\t\t\tscripts.has(bKey.substring(4))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tbKey = bKey.substring(4);\n\t\t\t\t\t\t\t\tmodifier -= 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aKey === bKey) {\n\t\t\t\t\t\t\t\treturn modifier;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn aKey > bKey ? 1 : -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrentOrder.some(\n\t\t\t\t\t\t\t(property, i) => desiredOrder[i] !== property,\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tkey: key.value,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\treturn fixer.replaceText(\n\t\t\t\t\t\t\t\t\tcollection as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\tdesiredOrder.reduce<\n\t\t\t\t\t\t\t\t\t\t\tRecord<string, unknown>\n\t\t\t\t\t\t\t\t\t\t>((out, property) => {\n\t\t\t\t\t\t\t\t\t\t\tout[\n\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.key as AST.JSONStringLiteral\n\t\t\t\t\t\t\t\t\t\t\t\t).value\n\t\t\t\t\t\t\t\t\t\t\t] = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getText(\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperty.value as unknown as ESTree.Node,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn out;\n\t\t\t\t\t\t\t\t\t\t}, {}),\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t\t\t\t.join(\"\\n \"), // nest indents\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tloc: collection.loc,\n\t\t\t\t\t\t\tmessage: \"Package {{ key }} are not alphabetized\",\n\t\t\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Dependencies, scripts, and configuration values must be declared in alphabetical order.\",\n\t\t\trecommended: true,\n\t\t},\n\t\tfixable: \"code\",\n\t\tschema: [\n\t\t\t{\n\t\t\t\titems: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t\ttype: \"array\",\n\t\t\t},\n\t\t],\n\t},\n});\n"],"mappings":"AAGA,SAAS,kBAAkB;AAE3B,MAAM,qBAAqB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAIO,MAAM,OAAO,WAAoB;AAAA,EACvC,OAAO,SAAS;AACf,UAAM,SAAS,QAAQ,QAAQ,CAAC,KAAK;AACrC,WAAO;AAAA,MACN,oBAAoB,MAAM;AACzB,cAAM,EAAE,KAAK,MAAM,IAAI;AAIvB,cAAM,aAAa;AACnB,YACC,WAAW,SAAS,0BACpB,OAAO,SAAS,IAAI,KAAK,GACxB;AACD,gBAAM,eAAe,WAAW;AAChC,gBAAM,UAAU,IAAI;AAAA,YACnB,aAAa;AAAA,cACZ,CAAC,SAAU,KAAK,IAA8B;AAAA,YAC/C;AAAA,UACD;AAEA,gBAAM,eAAe,aAAa,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AACxD,gBAAI,OAAQ,EAAE,IAA8B;AAC5C,gBAAI,OAAQ,EAAE,IAA8B;AAE5C,gBAAI,IAAI,UAAU,WAAW;AAC5B,qBAAO,OAAO,OAAO,IAAI;AAAA,YAC1B,OAAO;AACN,kBAAI,WAAW;AAEf,kBACC,KAAK,WAAW,KAAK,KACrB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb,WACC,KAAK,WAAW,MAAM,KACtB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb;AAEA,kBACC,KAAK,WAAW,KAAK,KACrB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb,WACC,KAAK,WAAW,MAAM,KACtB,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,GAC5B;AACD,uBAAO,KAAK,UAAU,CAAC;AACvB,4BAAY;AAAA,cACb;AAEA,kBAAI,SAAS,MAAM;AAClB,uBAAO;AAAA,cACR;AAEA,qBAAO,OAAO,OAAO,IAAI;AAAA,YAC1B;AAAA,UACD,CAAC;AACD,cACC,aAAa;AAAA,YACZ,CAAC,UAAU,MAAM,aAAa,CAAC,MAAM;AAAA,UACtC,GACC;AACD,oBAAQ,OAAO;AAAA,cACd,MAAM;AAAA,gBACL,KAAK,IAAI;AAAA,cACV;AAAA,cACA,IAAI,OAAO;AACV,uBAAO,MAAM;AAAA,kBACZ;AAAA,kBACA,KAAK;AAAA,oBACJ,aAAa,OAEX,CAAC,KAAK,aAAa;AACpB,0BAEE,SAAS,IACR,KACH,IAAI,KAAK;AAAA,wBACR,QAAQ,WAAW;AAAA,0BAClB,SAAS;AAAA,wBACV;AAAA,sBACD;AACA,6BAAO;AAAA,oBACR,GAAG,CAAC,CAAC;AAAA,oBACL;AAAA,oBACA;AAAA,kBACD,EACE,MAAM,IAAI,EACV,KAAK,MAAM;AAAA;AAAA,gBACd;AAAA,cACD;AAAA,cACA,KAAK,WAAW;AAAA,cAChB,SAAS;AAAA,cACT;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,MACP;AAAA,QACC,OAAO;AAAA,UACN,MAAM;AAAA,QACP;AAAA,QACA,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD,CAAC;","names":[]}
@@ -96,7 +96,7 @@ const rule = (0, import_createRule.createRule)({
96
96
  meta: {
97
97
  docs: {
98
98
  category: "Best Practices",
99
- description: "Enforce that if repository directory is specified, it matches the path to the package.json file",
99
+ description: "Checks a dependency isn't specified more than once (i.e. in `dependencies` and `devDependencies`)",
100
100
  recommended: true
101
101
  },
102
102
  hasSuggestions: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/unique-dependencies.ts"],"sourcesContent":["import type { AST as JsonAST } from \"jsonc-eslint-parser\";\n\nimport * as ESTree from \"estree\";\n\nimport { createRule } from \"../createRule.js\";\nimport { isJSONStringLiteral, isNotNullish } from \"../utils/predicates.js\";\n\nconst dependencyPropertyNames = new Set([\n\t\"bundleDependencies\",\n\t\"bundledDependencies\",\n\t\"dependencies\",\n\t\"devDependencies\",\n\t\"optionalDependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n]);\n\nexport const rule = createRule({\n\tcreate(context) {\n\t\tfunction check(\n\t\t\telements: (JsonAST.JSONNode | null)[],\n\t\t\tgetNodeToRemove: (element: JsonAST.JSONNode) => ESTree.Node,\n\t\t) {\n\t\t\tconst seen = new Set();\n\n\t\t\tfor (const element of elements\n\t\t\t\t.filter(isNotNullish)\n\t\t\t\t.filter(isJSONStringLiteral)\n\t\t\t\t.reverse()) {\n\t\t\t\tif (seen.has(element.value)) {\n\t\t\t\t\treport(element);\n\t\t\t\t} else {\n\t\t\t\t\tseen.add(element.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction report(node: JsonAST.JSONNode) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tmessageId: \"overridden\",\n\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\tsuggest: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\tconst removal = getNodeToRemove(node);\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\tfixer.remove(removal),\n\t\t\t\t\t\t\t\t\tfixer.remove(\n\t\t\t\t\t\t\t\t\t\t// A listing that's overridden can't be last,\n\t\t\t\t\t\t\t\t\t\t// so we're guaranteed there's a comma after.\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getTokenAfter(\n\t\t\t\t\t\t\t\t\t\t\tremoval,\n\t\t\t\t\t\t\t\t\t\t)!,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmessageId: \"remove\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t\"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral]\"(\n\t\t\t\tnode: JsonAST.JSONProperty & {\n\t\t\t\t\tkey: JsonAST.JSONStringLiteral;\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tif (!dependencyPropertyNames.has(node.key.value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (node.value.type) {\n\t\t\t\t\tcase \"JSONArrayExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.elements,\n\t\t\t\t\t\t\t(element) => element as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"JSONObjectExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.properties.map(\n\t\t\t\t\t\t\t\t(property) => property.key,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.parent as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Enforce that if repository directory is specified, it matches the path to the package.json file\",\n\t\t\trecommended: true,\n\t\t},\n\t\thasSuggestions: true,\n\t\tmessages: {\n\t\t\toverridden:\n\t\t\t\t\"Package name is overridden by a duplicate listing later on.\",\n\t\t\tremove: \"Remove this redundant dependency listing.\",\n\t\t},\n\t},\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,wBAA2B;AAC3B,wBAAkD;AAElD,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,MAAM,WAAO,8BAAW;AAAA,EAC9B,OAAO,SAAS;AACf,aAAS,MACR,UACA,iBACC;AACD,YAAM,OAAO,oBAAI,IAAI;AAErB,iBAAW,WAAW,SACpB,OAAO,8BAAY,EACnB,OAAO,qCAAmB,EAC1B,QAAQ,GAAG;AACZ,YAAI,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC5B,iBAAO,OAAO;AAAA,QACf,OAAO;AACN,eAAK,IAAI,QAAQ,KAAK;AAAA,QACvB;AAAA,MACD;AAEA,eAAS,OAAO,MAAwB;AACvC,gBAAQ,OAAO;AAAA,UACd,WAAW;AAAA,UACX;AAAA,UACA,SAAS;AAAA,YACR;AAAA,cACC,IAAI,OAAO;AACV,sBAAM,UAAU,gBAAgB,IAAI;AACpC,uBAAO;AAAA,kBACN,MAAM,OAAO,OAAO;AAAA,kBACpB,MAAM;AAAA;AAAA;AAAA;AAAA,oBAIL,QAAQ,WAAW;AAAA,sBAClB;AAAA,oBACD;AAAA,kBACD;AAAA,gBACD;AAAA,cACD;AAAA,cACA,WAAW;AAAA,YACZ;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,MACN,gGACC,MAGC;AACD,YAAI,CAAC,wBAAwB,IAAI,KAAK,IAAI,KAAK,GAAG;AACjD;AAAA,QACD;AAEA,gBAAQ,KAAK,MAAM,MAAM;AAAA,UACxB,KAAK;AACJ;AAAA,cACC,KAAK,MAAM;AAAA,cACX,CAAC,YAAY;AAAA,YACd;AACA;AAAA,UACD,KAAK;AACJ;AAAA,cACC,KAAK,MAAM,WAAW;AAAA,gBACrB,CAAC,aAAa,SAAS;AAAA,cACxB;AAAA,cACA,CAAC,aACA,SAAS;AAAA,YACX;AACA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,gBAAgB;AAAA,IAChB,UAAU;AAAA,MACT,YACC;AAAA,MACD,QAAQ;AAAA,IACT;AAAA,EACD;AACD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/rules/unique-dependencies.ts"],"sourcesContent":["import type { AST as JsonAST } from \"jsonc-eslint-parser\";\n\nimport * as ESTree from \"estree\";\n\nimport { createRule } from \"../createRule.js\";\nimport { isJSONStringLiteral, isNotNullish } from \"../utils/predicates.js\";\n\nconst dependencyPropertyNames = new Set([\n\t\"bundleDependencies\",\n\t\"bundledDependencies\",\n\t\"dependencies\",\n\t\"devDependencies\",\n\t\"optionalDependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n]);\n\nexport const rule = createRule({\n\tcreate(context) {\n\t\tfunction check(\n\t\t\telements: (JsonAST.JSONNode | null)[],\n\t\t\tgetNodeToRemove: (element: JsonAST.JSONNode) => ESTree.Node,\n\t\t) {\n\t\t\tconst seen = new Set();\n\n\t\t\tfor (const element of elements\n\t\t\t\t.filter(isNotNullish)\n\t\t\t\t.filter(isJSONStringLiteral)\n\t\t\t\t.reverse()) {\n\t\t\t\tif (seen.has(element.value)) {\n\t\t\t\t\treport(element);\n\t\t\t\t} else {\n\t\t\t\t\tseen.add(element.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction report(node: JsonAST.JSONNode) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tmessageId: \"overridden\",\n\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\tsuggest: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\tconst removal = getNodeToRemove(node);\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\tfixer.remove(removal),\n\t\t\t\t\t\t\t\t\tfixer.remove(\n\t\t\t\t\t\t\t\t\t\t// A listing that's overridden can't be last,\n\t\t\t\t\t\t\t\t\t\t// so we're guaranteed there's a comma after.\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getTokenAfter(\n\t\t\t\t\t\t\t\t\t\t\tremoval,\n\t\t\t\t\t\t\t\t\t\t)!,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmessageId: \"remove\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t\"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral]\"(\n\t\t\t\tnode: JsonAST.JSONProperty & {\n\t\t\t\t\tkey: JsonAST.JSONStringLiteral;\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tif (!dependencyPropertyNames.has(node.key.value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (node.value.type) {\n\t\t\t\t\tcase \"JSONArrayExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.elements,\n\t\t\t\t\t\t\t(element) => element as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"JSONObjectExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.properties.map(\n\t\t\t\t\t\t\t\t(property) => property.key,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.parent as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Checks a dependency isn't specified more than once (i.e. in `dependencies` and `devDependencies`)\",\n\t\t\trecommended: true,\n\t\t},\n\t\thasSuggestions: true,\n\t\tmessages: {\n\t\t\toverridden:\n\t\t\t\t\"Package name is overridden by a duplicate listing later on.\",\n\t\t\tremove: \"Remove this redundant dependency listing.\",\n\t\t},\n\t},\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,wBAA2B;AAC3B,wBAAkD;AAElD,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,MAAM,WAAO,8BAAW;AAAA,EAC9B,OAAO,SAAS;AACf,aAAS,MACR,UACA,iBACC;AACD,YAAM,OAAO,oBAAI,IAAI;AAErB,iBAAW,WAAW,SACpB,OAAO,8BAAY,EACnB,OAAO,qCAAmB,EAC1B,QAAQ,GAAG;AACZ,YAAI,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC5B,iBAAO,OAAO;AAAA,QACf,OAAO;AACN,eAAK,IAAI,QAAQ,KAAK;AAAA,QACvB;AAAA,MACD;AAEA,eAAS,OAAO,MAAwB;AACvC,gBAAQ,OAAO;AAAA,UACd,WAAW;AAAA,UACX;AAAA,UACA,SAAS;AAAA,YACR;AAAA,cACC,IAAI,OAAO;AACV,sBAAM,UAAU,gBAAgB,IAAI;AACpC,uBAAO;AAAA,kBACN,MAAM,OAAO,OAAO;AAAA,kBACpB,MAAM;AAAA;AAAA;AAAA;AAAA,oBAIL,QAAQ,WAAW;AAAA,sBAClB;AAAA,oBACD;AAAA,kBACD;AAAA,gBACD;AAAA,cACD;AAAA,cACA,WAAW;AAAA,YACZ;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,MACN,gGACC,MAGC;AACD,YAAI,CAAC,wBAAwB,IAAI,KAAK,IAAI,KAAK,GAAG;AACjD;AAAA,QACD;AAEA,gBAAQ,KAAK,MAAM,MAAM;AAAA,UACxB,KAAK;AACJ;AAAA,cACC,KAAK,MAAM;AAAA,cACX,CAAC,YAAY;AAAA,YACd;AACA;AAAA,UACD,KAAK;AACJ;AAAA,cACC,KAAK,MAAM,WAAW;AAAA,gBACrB,CAAC,aAAa,SAAS;AAAA,cACxB;AAAA,cACA,CAAC,aACA,SAAS;AAAA,YACX;AACA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,gBAAgB;AAAA,IAChB,UAAU;AAAA,MACT,YACC;AAAA,MACD,QAAQ;AAAA,IACT;AAAA,EACD;AACD,CAAC;","names":[]}
@@ -73,7 +73,7 @@ const rule = createRule({
73
73
  meta: {
74
74
  docs: {
75
75
  category: "Best Practices",
76
- description: "Enforce that if repository directory is specified, it matches the path to the package.json file",
76
+ description: "Checks a dependency isn't specified more than once (i.e. in `dependencies` and `devDependencies`)",
77
77
  recommended: true
78
78
  },
79
79
  hasSuggestions: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/unique-dependencies.ts"],"sourcesContent":["import type { AST as JsonAST } from \"jsonc-eslint-parser\";\n\nimport * as ESTree from \"estree\";\n\nimport { createRule } from \"../createRule.js\";\nimport { isJSONStringLiteral, isNotNullish } from \"../utils/predicates.js\";\n\nconst dependencyPropertyNames = new Set([\n\t\"bundleDependencies\",\n\t\"bundledDependencies\",\n\t\"dependencies\",\n\t\"devDependencies\",\n\t\"optionalDependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n]);\n\nexport const rule = createRule({\n\tcreate(context) {\n\t\tfunction check(\n\t\t\telements: (JsonAST.JSONNode | null)[],\n\t\t\tgetNodeToRemove: (element: JsonAST.JSONNode) => ESTree.Node,\n\t\t) {\n\t\t\tconst seen = new Set();\n\n\t\t\tfor (const element of elements\n\t\t\t\t.filter(isNotNullish)\n\t\t\t\t.filter(isJSONStringLiteral)\n\t\t\t\t.reverse()) {\n\t\t\t\tif (seen.has(element.value)) {\n\t\t\t\t\treport(element);\n\t\t\t\t} else {\n\t\t\t\t\tseen.add(element.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction report(node: JsonAST.JSONNode) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tmessageId: \"overridden\",\n\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\tsuggest: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\tconst removal = getNodeToRemove(node);\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\tfixer.remove(removal),\n\t\t\t\t\t\t\t\t\tfixer.remove(\n\t\t\t\t\t\t\t\t\t\t// A listing that's overridden can't be last,\n\t\t\t\t\t\t\t\t\t\t// so we're guaranteed there's a comma after.\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getTokenAfter(\n\t\t\t\t\t\t\t\t\t\t\tremoval,\n\t\t\t\t\t\t\t\t\t\t)!,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmessageId: \"remove\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t\"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral]\"(\n\t\t\t\tnode: JsonAST.JSONProperty & {\n\t\t\t\t\tkey: JsonAST.JSONStringLiteral;\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tif (!dependencyPropertyNames.has(node.key.value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (node.value.type) {\n\t\t\t\t\tcase \"JSONArrayExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.elements,\n\t\t\t\t\t\t\t(element) => element as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"JSONObjectExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.properties.map(\n\t\t\t\t\t\t\t\t(property) => property.key,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.parent as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Enforce that if repository directory is specified, it matches the path to the package.json file\",\n\t\t\trecommended: true,\n\t\t},\n\t\thasSuggestions: true,\n\t\tmessages: {\n\t\t\toverridden:\n\t\t\t\t\"Package name is overridden by a duplicate listing later on.\",\n\t\t\tremove: \"Remove this redundant dependency listing.\",\n\t\t},\n\t},\n});\n"],"mappings":"AAIA,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB,oBAAoB;AAElD,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,MAAM,OAAO,WAAW;AAAA,EAC9B,OAAO,SAAS;AACf,aAAS,MACR,UACA,iBACC;AACD,YAAM,OAAO,oBAAI,IAAI;AAErB,iBAAW,WAAW,SACpB,OAAO,YAAY,EACnB,OAAO,mBAAmB,EAC1B,QAAQ,GAAG;AACZ,YAAI,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC5B,iBAAO,OAAO;AAAA,QACf,OAAO;AACN,eAAK,IAAI,QAAQ,KAAK;AAAA,QACvB;AAAA,MACD;AAEA,eAAS,OAAO,MAAwB;AACvC,gBAAQ,OAAO;AAAA,UACd,WAAW;AAAA,UACX;AAAA,UACA,SAAS;AAAA,YACR;AAAA,cACC,IAAI,OAAO;AACV,sBAAM,UAAU,gBAAgB,IAAI;AACpC,uBAAO;AAAA,kBACN,MAAM,OAAO,OAAO;AAAA,kBACpB,MAAM;AAAA;AAAA;AAAA;AAAA,oBAIL,QAAQ,WAAW;AAAA,sBAClB;AAAA,oBACD;AAAA,kBACD;AAAA,gBACD;AAAA,cACD;AAAA,cACA,WAAW;AAAA,YACZ;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,MACN,gGACC,MAGC;AACD,YAAI,CAAC,wBAAwB,IAAI,KAAK,IAAI,KAAK,GAAG;AACjD;AAAA,QACD;AAEA,gBAAQ,KAAK,MAAM,MAAM;AAAA,UACxB,KAAK;AACJ;AAAA,cACC,KAAK,MAAM;AAAA,cACX,CAAC,YAAY;AAAA,YACd;AACA;AAAA,UACD,KAAK;AACJ;AAAA,cACC,KAAK,MAAM,WAAW;AAAA,gBACrB,CAAC,aAAa,SAAS;AAAA,cACxB;AAAA,cACA,CAAC,aACA,SAAS;AAAA,YACX;AACA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,gBAAgB;AAAA,IAChB,UAAU;AAAA,MACT,YACC;AAAA,MACD,QAAQ;AAAA,IACT;AAAA,EACD;AACD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/rules/unique-dependencies.ts"],"sourcesContent":["import type { AST as JsonAST } from \"jsonc-eslint-parser\";\n\nimport * as ESTree from \"estree\";\n\nimport { createRule } from \"../createRule.js\";\nimport { isJSONStringLiteral, isNotNullish } from \"../utils/predicates.js\";\n\nconst dependencyPropertyNames = new Set([\n\t\"bundleDependencies\",\n\t\"bundledDependencies\",\n\t\"dependencies\",\n\t\"devDependencies\",\n\t\"optionalDependencies\",\n\t\"peerDependencies\",\n\t\"overrides\",\n]);\n\nexport const rule = createRule({\n\tcreate(context) {\n\t\tfunction check(\n\t\t\telements: (JsonAST.JSONNode | null)[],\n\t\t\tgetNodeToRemove: (element: JsonAST.JSONNode) => ESTree.Node,\n\t\t) {\n\t\t\tconst seen = new Set();\n\n\t\t\tfor (const element of elements\n\t\t\t\t.filter(isNotNullish)\n\t\t\t\t.filter(isJSONStringLiteral)\n\t\t\t\t.reverse()) {\n\t\t\t\tif (seen.has(element.value)) {\n\t\t\t\t\treport(element);\n\t\t\t\t} else {\n\t\t\t\t\tseen.add(element.value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction report(node: JsonAST.JSONNode) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tmessageId: \"overridden\",\n\t\t\t\t\tnode: node as unknown as ESTree.Node,\n\t\t\t\t\tsuggest: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\t\tconst removal = getNodeToRemove(node);\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\tfixer.remove(removal),\n\t\t\t\t\t\t\t\t\tfixer.remove(\n\t\t\t\t\t\t\t\t\t\t// A listing that's overridden can't be last,\n\t\t\t\t\t\t\t\t\t\t// so we're guaranteed there's a comma after.\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\t\t\tcontext.sourceCode.getTokenAfter(\n\t\t\t\t\t\t\t\t\t\t\tremoval,\n\t\t\t\t\t\t\t\t\t\t)!,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmessageId: \"remove\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t\"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral]\"(\n\t\t\t\tnode: JsonAST.JSONProperty & {\n\t\t\t\t\tkey: JsonAST.JSONStringLiteral;\n\t\t\t\t},\n\t\t\t) {\n\t\t\t\tif (!dependencyPropertyNames.has(node.key.value)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (node.value.type) {\n\t\t\t\t\tcase \"JSONArrayExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.elements,\n\t\t\t\t\t\t\t(element) => element as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"JSONObjectExpression\":\n\t\t\t\t\t\tcheck(\n\t\t\t\t\t\t\tnode.value.properties.map(\n\t\t\t\t\t\t\t\t(property) => property.key,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.parent as unknown as ESTree.Node,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n\n\tmeta: {\n\t\tdocs: {\n\t\t\tcategory: \"Best Practices\",\n\t\t\tdescription:\n\t\t\t\t\"Checks a dependency isn't specified more than once (i.e. in `dependencies` and `devDependencies`)\",\n\t\t\trecommended: true,\n\t\t},\n\t\thasSuggestions: true,\n\t\tmessages: {\n\t\t\toverridden:\n\t\t\t\t\"Package name is overridden by a duplicate listing later on.\",\n\t\t\tremove: \"Remove this redundant dependency listing.\",\n\t\t},\n\t},\n});\n"],"mappings":"AAIA,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB,oBAAoB;AAElD,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,MAAM,OAAO,WAAW;AAAA,EAC9B,OAAO,SAAS;AACf,aAAS,MACR,UACA,iBACC;AACD,YAAM,OAAO,oBAAI,IAAI;AAErB,iBAAW,WAAW,SACpB,OAAO,YAAY,EACnB,OAAO,mBAAmB,EAC1B,QAAQ,GAAG;AACZ,YAAI,KAAK,IAAI,QAAQ,KAAK,GAAG;AAC5B,iBAAO,OAAO;AAAA,QACf,OAAO;AACN,eAAK,IAAI,QAAQ,KAAK;AAAA,QACvB;AAAA,MACD;AAEA,eAAS,OAAO,MAAwB;AACvC,gBAAQ,OAAO;AAAA,UACd,WAAW;AAAA,UACX;AAAA,UACA,SAAS;AAAA,YACR;AAAA,cACC,IAAI,OAAO;AACV,sBAAM,UAAU,gBAAgB,IAAI;AACpC,uBAAO;AAAA,kBACN,MAAM,OAAO,OAAO;AAAA,kBACpB,MAAM;AAAA;AAAA;AAAA;AAAA,oBAIL,QAAQ,WAAW;AAAA,sBAClB;AAAA,oBACD;AAAA,kBACD;AAAA,gBACD;AAAA,cACD;AAAA,cACA,WAAW;AAAA,YACZ;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,MACN,gGACC,MAGC;AACD,YAAI,CAAC,wBAAwB,IAAI,KAAK,IAAI,KAAK,GAAG;AACjD;AAAA,QACD;AAEA,gBAAQ,KAAK,MAAM,MAAM;AAAA,UACxB,KAAK;AACJ;AAAA,cACC,KAAK,MAAM;AAAA,cACX,CAAC,YAAY;AAAA,YACd;AACA;AAAA,UACD,KAAK;AACJ;AAAA,cACC,KAAK,MAAM,WAAW;AAAA,gBACrB,CAAC,aAAa,SAAS;AAAA,cACxB;AAAA,cACA,CAAC,aACA,SAAS;AAAA,YACX;AACA;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM;AAAA,IACL,MAAM;AAAA,MACL,UAAU;AAAA,MACV,aACC;AAAA,MACD,aAAa;AAAA,IACd;AAAA,IACA,gBAAgB;AAAA,IAChB,UAAU;AAAA,MACT,YACC;AAAA,MACD,QAAQ;AAAA,IACT;AAAA,EACD;AACD,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "0.15.6",
3
+ "version": "0.17.0",
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": {
@@ -99,7 +99,7 @@
99
99
  "knip": "^5.0.0",
100
100
  "lint-staged": "^15.2.0",
101
101
  "markdownlint": "^0.36.0",
102
- "markdownlint-cli": "^0.42.0",
102
+ "markdownlint-cli": "^0.43.0",
103
103
  "npm-package-json-lint": "^8.0.0",
104
104
  "npm-package-json-lint-config-default": "^7.0.0",
105
105
  "prettier": "^3.2.4",
@@ -116,7 +116,7 @@
116
116
  "eslint": ">=8.0.0",
117
117
  "jsonc-eslint-parser": "^2.0.0"
118
118
  },
119
- "packageManager": "pnpm@9.12.3",
119
+ "packageManager": "pnpm@9.14.2",
120
120
  "engines": {
121
121
  "node": ">=18"
122
122
  },