eslint-plugin-package-json 0.16.0 → 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: 20 👪" src="https://img.shields.io/badge/all_contributors-20_👪-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>
@@ -171,6 +171,7 @@ Thanks! 💖
171
171
  <tr>
172
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
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>
174
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>
175
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>
176
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>
@@ -40,9 +40,38 @@ const rule = (0, import_createRule.createRule)({
40
40
  const collection = value;
41
41
  if (collection.type === "JSONObjectExpression" && toSort.includes(key.value)) {
42
42
  const currentOrder = collection.properties;
43
- const desiredOrder = currentOrder.slice().sort(
44
- (a, b) => a.key.value > b.key.value ? 1 : -1
43
+ const scripts = new Set(
44
+ currentOrder.map(
45
+ (prop) => prop.key.value
46
+ )
45
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
+ });
46
75
  if (currentOrder.some(
47
76
  (property, i) => desiredOrder[i] !== property
48
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\"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 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;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":[]}
@@ -17,9 +17,38 @@ const rule = createRule({
17
17
  const collection = value;
18
18
  if (collection.type === "JSONObjectExpression" && toSort.includes(key.value)) {
19
19
  const currentOrder = collection.properties;
20
- const desiredOrder = currentOrder.slice().sort(
21
- (a, b) => a.key.value > b.key.value ? 1 : -1
20
+ const scripts = new Set(
21
+ currentOrder.map(
22
+ (prop) => prop.key.value
23
+ )
22
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
+ });
23
52
  if (currentOrder.some(
24
53
  (property, i) => desiredOrder[i] !== property
25
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\"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 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;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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "0.16.0",
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": {