@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.10

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 (276) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/mapper-connection.js +2 -1
  3. package/dist/bin/node-host.js +24 -5
  4. package/dist/src/analysis.js +181 -341
  5. package/dist/src/augmentations.js +106 -13
  6. package/dist/src/automatic-types.js +10 -29
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +2 -3
  10. package/dist/src/config.js +6 -82
  11. package/dist/src/configuration-files.js +28 -176
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +1 -1
  14. package/dist/src/consumers.js +3 -30
  15. package/dist/src/contextual-uses.js +56 -9
  16. package/dist/src/contract/config.generated.js +558 -0
  17. package/dist/src/contract/contract.generated.js +1244 -0
  18. package/dist/src/contract/report.generated.js +862 -0
  19. package/dist/src/convention-rows.js +73 -3
  20. package/dist/src/conventions.js +36 -66
  21. package/dist/src/dependencies.js +103 -40
  22. package/dist/src/edges.js +38 -122
  23. package/dist/src/element-access.js +4 -6
  24. package/dist/src/entry-point-gaps.js +2 -8
  25. package/dist/src/entry-points.js +11 -27
  26. package/dist/src/enum-group.js +3 -10
  27. package/dist/src/erased-stores.js +4 -6
  28. package/dist/src/exempt-classes.js +1 -63
  29. package/dist/src/exempt.js +21 -40
  30. package/dist/src/failure.js +36 -0
  31. package/dist/src/file-facts.js +2 -25
  32. package/dist/src/findings/completion.js +139 -72
  33. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  34. package/dist/src/findings/emitters.js +5 -5
  35. package/dist/src/findings/interfaces.js +4 -5
  36. package/dist/src/findings/intra-function.js +13 -10
  37. package/dist/src/findings/non-code-artifacts.js +7 -8
  38. package/dist/src/findings/reads-and-writes.js +16 -13
  39. package/dist/src/findings/self-check.js +10 -12
  40. package/dist/src/findings/unused-declarations.js +41 -32
  41. package/dist/src/findings/visibility-narrowing.js +19 -16
  42. package/dist/src/findings-pass.js +8 -15
  43. package/dist/src/framework-lifecycle.js +7 -7
  44. package/dist/src/fs/document.js +52 -0
  45. package/dist/src/fs/manifest.js +72 -0
  46. package/dist/src/fs/tree.js +88 -0
  47. package/dist/src/generated-file.js +7 -4
  48. package/dist/src/git-ignore.js +39 -26
  49. package/dist/src/graph.js +5 -3
  50. package/dist/src/html-entries.js +6 -33
  51. package/dist/src/in-operands.js +2 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/injection-container.js +1 -1
  54. package/dist/src/intra-function-parts.js +63 -43
  55. package/dist/src/inventory.js +2 -21
  56. package/dist/src/javascript-file.js +33 -0
  57. package/dist/src/json-document.js +198 -67
  58. package/dist/src/keyof-comparisons.js +4 -6
  59. package/dist/src/kinds.js +3 -366
  60. package/dist/src/load/classify.js +270 -0
  61. package/dist/src/load/diagnostics.js +80 -0
  62. package/dist/src/load/discover.js +277 -0
  63. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  64. package/dist/src/load/expected-module.js +136 -0
  65. package/dist/src/load/load.js +27 -0
  66. package/dist/src/load/module-lookup.js +37 -0
  67. package/dist/src/load/plan.js +313 -0
  68. package/dist/src/load/specifiers.js +115 -0
  69. package/dist/src/load/synthesize.js +140 -0
  70. package/dist/src/load/test-globals.js +207 -0
  71. package/dist/src/load/test-joins.js +82 -0
  72. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  73. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  74. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
  75. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  76. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  77. package/dist/src/manifest.js +49 -54
  78. package/dist/src/matrix.js +76 -4
  79. package/dist/src/mdx-entries.js +3 -26
  80. package/dist/src/outside-tests.js +1 -1
  81. package/dist/src/partial.js +2 -1
  82. package/dist/src/paths.js +26 -15
  83. package/dist/src/position.js +2 -1
  84. package/dist/src/print.js +11 -79
  85. package/dist/src/product.js +13 -0
  86. package/dist/src/query.js +1 -0
  87. package/dist/src/ref.js +1 -0
  88. package/dist/src/references.js +48 -30
  89. package/dist/src/report-schema.js +51 -0
  90. package/dist/src/report.js +57 -41
  91. package/dist/src/reporters/annotations.js +15 -8
  92. package/dist/src/reporters/sarif.js +16 -10
  93. package/dist/src/reporters/template.js +4 -19
  94. package/dist/src/resolve.js +245 -729
  95. package/dist/src/roots.js +273 -87
  96. package/dist/src/run.js +66 -77
  97. package/dist/src/schema.js +320 -343
  98. package/dist/src/scope.js +38 -115
  99. package/dist/src/serialization-contract.js +595 -21
  100. package/dist/src/session.js +34 -29
  101. package/dist/src/source-files.js +1 -1
  102. package/dist/src/suppress-file.js +25 -28
  103. package/dist/src/suppress-inline.js +3 -2
  104. package/dist/src/suppress.js +33 -51
  105. package/dist/src/sweep.js +7 -9
  106. package/dist/src/symbol-keys.js +3 -5
  107. package/dist/src/template-field.js +9 -19
  108. package/dist/src/test-support.js +8 -11
  109. package/dist/src/text/compare.js +26 -0
  110. package/dist/src/text/glob.js +194 -0
  111. package/dist/src/text/named-files.js +54 -0
  112. package/dist/src/text/shell.js +159 -0
  113. package/dist/src/text/yaml.js +393 -0
  114. package/dist/src/type-errors.js +11 -232
  115. package/dist/src/unseen-loads.js +100 -0
  116. package/dist/src/unwrap.js +23 -0
  117. package/dist/src/usage.js +10 -0
  118. package/dist/src/verbs/analyze.js +166 -126
  119. package/dist/src/verbs/describe.js +9 -16
  120. package/dist/src/verbs/explain.js +10 -7
  121. package/dist/src/verbs/print-config.js +2 -1
  122. package/dist/src/verbs/print-projects.js +6 -4
  123. package/dist/src/verbs/print-retained.js +4 -2
  124. package/dist/src/verbs/print-roots.js +4 -2
  125. package/dist/src/verbs/verb.js +1 -5
  126. package/dist/src/verbs/version.js +14 -3
  127. package/dist/src/workflow-steps.js +62 -64
  128. package/jsr.json +1 -1
  129. package/package.json +4 -3
  130. package/src/analysis.ts +245 -502
  131. package/src/augmentations.ts +135 -17
  132. package/src/automatic-types.ts +11 -29
  133. package/src/build-scripts.ts +543 -0
  134. package/src/component-layer.ts +4 -2
  135. package/src/components.ts +2 -4
  136. package/src/config.ts +31 -302
  137. package/src/configuration-files.ts +34 -179
  138. package/src/configured-declarations.ts +18 -23
  139. package/src/conformance-record.ts +1 -1
  140. package/src/consumers.ts +6 -57
  141. package/src/contextual-uses.ts +64 -12
  142. package/src/contract/config.generated.ts +818 -0
  143. package/src/contract/contract.generated.ts +1308 -0
  144. package/src/contract/report.generated.ts +1237 -0
  145. package/src/convention-rows.ts +85 -3
  146. package/src/conventions.ts +46 -84
  147. package/src/dependencies.ts +118 -46
  148. package/src/edges.ts +41 -140
  149. package/src/element-access.ts +4 -7
  150. package/src/entry-point-gaps.ts +3 -9
  151. package/src/entry-points.ts +12 -38
  152. package/src/enum-group.ts +2 -11
  153. package/src/erased-stores.ts +3 -7
  154. package/src/exempt-classes.ts +1 -75
  155. package/src/exempt.ts +36 -50
  156. package/src/failure.ts +63 -0
  157. package/src/file-facts.ts +9 -24
  158. package/src/finding.ts +14 -9
  159. package/src/findings/boundary.ts +2 -0
  160. package/src/findings/completion.ts +181 -84
  161. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  162. package/src/findings/emitter.ts +8 -9
  163. package/src/findings/emitters.ts +7 -7
  164. package/src/findings/interfaces.ts +4 -6
  165. package/src/findings/intra-function.ts +13 -11
  166. package/src/findings/non-code-artifacts.ts +9 -11
  167. package/src/findings/reads-and-writes.ts +20 -16
  168. package/src/findings/self-check.ts +11 -17
  169. package/src/findings/unused-declarations.ts +45 -32
  170. package/src/findings/visibility-narrowing.ts +20 -17
  171. package/src/findings-pass.ts +10 -19
  172. package/src/framework-lifecycle.ts +7 -7
  173. package/src/fs/document.ts +70 -0
  174. package/src/fs/manifest.ts +92 -0
  175. package/src/fs/tree.ts +110 -0
  176. package/src/generated-file.ts +7 -4
  177. package/src/git-ignore.ts +50 -26
  178. package/src/graph.ts +5 -3
  179. package/src/host.ts +12 -5
  180. package/src/html-entries.ts +6 -33
  181. package/src/in-operands.ts +2 -1
  182. package/src/index.ts +1 -1
  183. package/src/injection-container.ts +1 -1
  184. package/src/intra-function-parts.ts +73 -44
  185. package/src/inventory.ts +2 -20
  186. package/src/javascript-file.ts +37 -0
  187. package/src/json-document.ts +241 -76
  188. package/src/keyof-comparisons.ts +3 -7
  189. package/src/kinds.ts +5 -413
  190. package/src/load/classify.ts +397 -0
  191. package/src/load/diagnostics.ts +144 -0
  192. package/src/load/discover.ts +455 -0
  193. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  194. package/src/load/expected-module.ts +188 -0
  195. package/src/load/load.ts +73 -0
  196. package/src/load/module-lookup.ts +50 -0
  197. package/src/load/plan.ts +504 -0
  198. package/src/load/specifiers.ts +168 -0
  199. package/src/load/synthesize.ts +211 -0
  200. package/src/load/test-globals.ts +251 -0
  201. package/src/load/test-joins.ts +98 -0
  202. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  203. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  204. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
  205. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  206. package/src/{workspace.ts → load/workspace.ts} +90 -134
  207. package/src/manifest.ts +81 -75
  208. package/src/matrix.ts +122 -4
  209. package/src/mdx-entries.ts +3 -26
  210. package/src/outside-tests.ts +1 -1
  211. package/src/partial.ts +3 -2
  212. package/src/paths.ts +27 -15
  213. package/src/position.ts +2 -1
  214. package/src/print.ts +12 -92
  215. package/src/product.ts +18 -0
  216. package/src/query.ts +11 -0
  217. package/src/ref.ts +1 -0
  218. package/src/references.ts +52 -31
  219. package/src/report-schema.ts +68 -0
  220. package/src/report.ts +101 -224
  221. package/src/reporters/annotations.ts +22 -11
  222. package/src/reporters/json.ts +1 -1
  223. package/src/reporters/reporter.ts +2 -4
  224. package/src/reporters/reporters.ts +1 -1
  225. package/src/reporters/sarif.ts +29 -16
  226. package/src/reporters/template.ts +4 -20
  227. package/src/reporters/text.ts +3 -3
  228. package/src/resolve.ts +283 -1114
  229. package/src/roots.ts +339 -104
  230. package/src/run.ts +75 -91
  231. package/src/schema.ts +391 -388
  232. package/src/scope.ts +46 -138
  233. package/src/serialization-contract.ts +763 -22
  234. package/src/session.ts +70 -54
  235. package/src/source-files.ts +1 -1
  236. package/src/suppress-file.ts +24 -33
  237. package/src/suppress-inline.ts +2 -2
  238. package/src/suppress.ts +43 -58
  239. package/src/sweep.ts +23 -9
  240. package/src/symbol-keys.ts +2 -5
  241. package/src/template-field.ts +15 -25
  242. package/src/test-support.ts +17 -13
  243. package/src/text/compare.ts +27 -0
  244. package/src/text/glob.ts +210 -0
  245. package/src/text/named-files.inputs.json +1522 -0
  246. package/src/text/named-files.ts +68 -0
  247. package/src/text/shell.ts +161 -0
  248. package/src/text/yaml.ts +423 -0
  249. package/src/type-errors.ts +18 -288
  250. package/src/unseen-loads.ts +134 -0
  251. package/src/unwrap.ts +34 -0
  252. package/src/usage.ts +10 -0
  253. package/src/verbs/analyze.ts +224 -162
  254. package/src/verbs/describe.ts +14 -15
  255. package/src/verbs/explain.ts +10 -11
  256. package/src/verbs/print-config.ts +2 -1
  257. package/src/verbs/print-projects.ts +6 -4
  258. package/src/verbs/print-retained.ts +4 -2
  259. package/src/verbs/print-roots.ts +4 -2
  260. package/src/verbs/verb.ts +2 -8
  261. package/src/verbs/version.ts +15 -3
  262. package/src/workflow-steps.ts +74 -64
  263. package/dist/src/base-url.js +0 -18
  264. package/dist/src/discover.js +0 -468
  265. package/dist/src/glob.js +0 -65
  266. package/dist/src/pnpm-workspace.js +0 -120
  267. package/dist/src/setup-failure.js +0 -23
  268. package/dist/src/test-joins.js +0 -101
  269. package/dist/src/version.js +0 -7
  270. package/src/base-url.ts +0 -24
  271. package/src/discover.ts +0 -653
  272. package/src/glob.ts +0 -67
  273. package/src/pnpm-workspace.ts +0 -135
  274. package/src/setup-failure.ts +0 -39
  275. package/src/test-joins.ts +0 -120
  276. package/src/version.ts +0 -7
@@ -10,8 +10,8 @@ const SCRIPT = "{js,jsx,ts,tsx}";
10
10
  const MODULE = "{js,mjs,ts,mts}";
11
11
  const ANY_MODULE = "{js,mjs,cjs,ts,mts,cts}";
12
12
  const VITE_CONFIG = `vite.config.${ANY_MODULE}`;
13
- /** The legacy configuration files of ESLint that hold JSON or a CommonJS module. */
14
- const ESLINTRC = [".eslintrc", ".eslintrc.json", ".eslintrc.{js,cjs}"];
13
+ /** The legacy configuration files of ESLint: JSON, YAML or a CommonJS module. */
14
+ const ESLINTRC = [".eslintrc", ".eslintrc.json", ".eslintrc.{yml,yaml}", ".eslintrc.{js,cjs}"];
15
15
  const SVELTEKIT_ROUTE_FILES = "+{page,layout,server,page.server,layout.server,error}";
16
16
  /** SvelteKit's entries other than its parameter matchers. */
17
17
  const SVELTEKIT_ENTRIES = [
@@ -61,6 +61,50 @@ const ANGULAR_PACKAGE_KEYS = [
61
61
  "styles",
62
62
  "scripts",
63
63
  ].map((key) => ({ key, files: ["angular.json"] }));
64
+ /**
65
+ * The row of a code generator that writes its output below one directory its
66
+ * configuration's `property` sets, `fallback` where no configuration file sets it, so
67
+ * every file there is a generated file.
68
+ */
69
+ function outputDirectoryRow(row) {
70
+ return {
71
+ name: row.name,
72
+ package: row.package,
73
+ range: row.range,
74
+ entries: [],
75
+ generated: ["<output>"],
76
+ moves: [
77
+ {
78
+ id: "output",
79
+ defaults: [row.fallback],
80
+ readings: [{ property: row.property, files: row.files }],
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ /**
86
+ * The test runners and the assertion, mock and runner libraries whose import is test
87
+ * evidence beside each runner a row reads test files for. Each applies whether or not a
88
+ * manifest declares it, so none is a row.
89
+ */
90
+ export const TEST_LIBRARIES = [
91
+ "@jest/globals",
92
+ "@playwright/test",
93
+ "ava",
94
+ "chai",
95
+ "expect",
96
+ "jasmine",
97
+ "jest",
98
+ "mocha",
99
+ "msw",
100
+ "nock",
101
+ "node:test",
102
+ "sinon",
103
+ "tap",
104
+ "uvu",
105
+ ];
106
+ /** The scopes every package of which is a test library. */
107
+ export const TEST_LIBRARY_SCOPES = ["@testing-library/"];
64
108
  /** Every row, ordered by name and then by range. */
65
109
  export const CONVENTION_ROWS = [
66
110
  {
@@ -81,6 +125,7 @@ export const CONVENTION_ROWS = [
81
125
  },
82
126
  {
83
127
  name: "astro",
128
+ bundles: true,
84
129
  package: "astro",
85
130
  range: ">=5.0.0 <8.0.0",
86
131
  entries: [
@@ -126,6 +171,7 @@ export const CONVENTION_ROWS = [
126
171
  range: ">=4.0.0 <10.0.0",
127
172
  entries: [],
128
173
  moves: [],
174
+ packageKeys: [{ key: "parser", files: ESLINTRC }],
129
175
  prefixedNames: [
130
176
  { property: "plugins", files: ESLINTRC, prefix: "eslint-plugin" },
131
177
  { property: "extends", files: ESLINTRC, prefix: "eslint-plugin", marker: "plugin:" },
@@ -149,12 +195,13 @@ export const CONVENTION_ROWS = [
149
195
  {
150
196
  name: "expo-router",
151
197
  package: "expo-router",
152
- range: ">=3.0.0 <58.0.0",
198
+ range: ">=3.0.0 <59.0.0",
153
199
  entries: [`{,src/}app/**/*.${SCRIPT}`],
154
200
  moves: [],
155
201
  },
156
202
  {
157
203
  name: "next",
204
+ bundles: true,
158
205
  package: "next",
159
206
  range: ">=13.4.0 <17.0.0",
160
207
  generated: [".next"],
@@ -172,6 +219,7 @@ export const CONVENTION_ROWS = [
172
219
  },
173
220
  {
174
221
  name: "nuxt",
222
+ bundles: true,
175
223
  package: "nuxt",
176
224
  range: ">=3.0.0 <5.0.0",
177
225
  generated: [".nuxt"],
@@ -241,8 +289,17 @@ export const CONVENTION_ROWS = [
241
289
  { key: "oclif.hooks", directory: false },
242
290
  ],
243
291
  },
292
+ outputDirectoryRow({
293
+ name: "panda",
294
+ package: "@pandacss/dev",
295
+ range: ">=0.1.0 <2.0.0",
296
+ files: [`panda.config.${ANY_MODULE}`],
297
+ property: "outdir",
298
+ fallback: "styled-system",
299
+ }),
244
300
  {
245
301
  name: "parcel",
302
+ bundles: true,
246
303
  package: "parcel",
247
304
  range: ">=2.0.0 <3.0.0",
248
305
  entries: [],
@@ -308,6 +365,13 @@ export const CONVENTION_ROWS = [
308
365
  },
309
366
  ],
310
367
  },
368
+ {
369
+ name: "react-scripts",
370
+ package: "react-scripts",
371
+ range: ">=1.0.0 <6.0.0",
372
+ entries: [`src/index.${SCRIPT}`, "src/setupProxy.js", `src/setupTests.${SCRIPT}`],
373
+ moves: [],
374
+ },
311
375
  {
312
376
  name: "remix",
313
377
  package: "@remix-run/dev",
@@ -335,6 +399,7 @@ export const CONVENTION_ROWS = [
335
399
  },
336
400
  {
337
401
  name: "rolldown",
402
+ bundles: true,
338
403
  package: "rolldown",
339
404
  range: ">=1.0.0 <2.0.0",
340
405
  entries: [],
@@ -380,6 +445,7 @@ export const CONVENTION_ROWS = [
380
445
  },
381
446
  {
382
447
  name: "storybook",
448
+ bundles: true,
383
449
  package: "storybook",
384
450
  range: ">=7.0.0 <11.0.0",
385
451
  entries: [
@@ -413,6 +479,7 @@ export const CONVENTION_ROWS = [
413
479
  },
414
480
  {
415
481
  name: "sveltekit",
482
+ bundles: true,
416
483
  package: "@sveltejs/kit",
417
484
  range: ">=2.0.0 <3.0.0",
418
485
  entries: [...SVELTEKIT_ENTRIES, "<params>/*.{js,ts}"],
@@ -478,6 +545,7 @@ export const CONVENTION_ROWS = [
478
545
  },
479
546
  {
480
547
  name: "sveltekit",
548
+ bundles: true,
481
549
  package: "@sveltejs/kit",
482
550
  range: ">=3.0.0 <4.0.0",
483
551
  entries: [...SVELTEKIT_ENTRIES, "<params>.{js,ts}"],
@@ -570,6 +638,7 @@ export const CONVENTION_ROWS = [
570
638
  },
571
639
  {
572
640
  name: "vite",
641
+ bundles: true,
573
642
  package: "vite",
574
643
  range: ">=8.0.0 <9.0.0",
575
644
  entries: [],
@@ -585,6 +654,7 @@ export const CONVENTION_ROWS = [
585
654
  },
586
655
  {
587
656
  name: "vitepress",
657
+ bundles: true,
588
658
  package: "vitepress",
589
659
  range: ">=1.0.0 <2.0.0-0 || >=2.0.0-alpha.0 <3.0.0",
590
660
  entries: [
@@ -5,34 +5,30 @@
5
5
  * directory a configuration property moves read from the property's literal value.
6
6
  * No configuration file is run.
7
7
  */
8
- import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isClassDeclaration, isComputedPropertyName, isExportAssignment, isExportDeclaration, isExpressionStatement, isFunctionDeclaration, isIdentifier, isImportDeclaration, isNamedExports, isNamespaceImport, isNoSubstitutionTemplateLiteral, isNonNullExpression, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
8
+ import { isArrayLiteralExpression, isBinaryExpression, isCallExpression, isClassDeclaration, isComputedPropertyName, isExportAssignment, isExportDeclaration, isExpressionStatement, isFunctionDeclaration, isIdentifier, isImportDeclaration, isNamedExports, isNamespaceImport, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectBindingPattern, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteral, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
9
9
  import { lineOf } from "./component-files.js";
10
10
  import { CONVENTION_ROWS, } from "./convention-rows.js";
11
11
  import { documentStrings } from "./configuration-files.js";
12
- import { globExpression } from "./glob.js";
13
- import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "./paths.js";
12
+ import { ancestors, dirnamePath, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
14
13
  import { satisfies } from "./version-range.js";
14
+ import { bytewise } from "./text/compare.js";
15
+ import { isRecord } from "./json-document.js";
16
+ import { unwrapped } from "./unwrap.js";
17
+ import { filesIn } from "./fs/tree.js";
18
+ import { DEPENDENCY_SECTIONS, INSTALLED_PACKAGES, MANIFEST, readJSON } from "./fs/manifest.js";
19
+ import { globExpression } from "./text/glob.js";
20
+ import { yamlDocument } from "./text/yaml.js";
15
21
  const JSON_EXTENSION = ".json";
22
+ /**
23
+ * A configuration file its tool reads as a YAML document, read as the JSON document it
24
+ * denotes. Its nodes' offsets are that JSON text's, so no move may read one: a failure's
25
+ * line would name the wrong line.
26
+ */
27
+ const YAML_NAME = /\.ya?ml$/u;
16
28
  /** A configuration file with no extension that its tool reads as a JSON document. */
17
29
  const JSON_RC = /^\.[\w-]+rc$/u;
18
30
  /** The sections an installed package is required by, so its absence fails the run. */
19
31
  const REQUIRED_SECTIONS = ["dependencies", "devDependencies"];
20
- const DEPENDENCY_SECTIONS = [
21
- ...REQUIRED_SECTIONS,
22
- "peerDependencies",
23
- "optionalDependencies",
24
- ];
25
- function isRecord(value) {
26
- return typeof value === "object" && value !== null && !Array.isArray(value);
27
- }
28
- function readJSON(host, path) {
29
- try {
30
- return JSON.parse(host.readFile(path));
31
- }
32
- catch {
33
- return undefined;
34
- }
35
- }
36
32
  function declares(manifest, name, sections = DEPENDENCY_SECTIONS) {
37
33
  if (!isRecord(manifest)) {
38
34
  return false;
@@ -48,32 +44,15 @@ function declares(manifest, name, sections = DEPENDENCY_SECTIONS) {
48
44
  * none, or `undefined` where no `node_modules` holds it.
49
45
  */
50
46
  function installedVersion(host, dir, name) {
51
- for (let at = normalizePath(dir);; at = dirnamePath(at)) {
52
- const path = joinPath(at, "node_modules", name, "package.json");
47
+ for (const at of ancestors(dir)) {
48
+ const path = joinPath(at, INSTALLED_PACKAGES, name, MANIFEST);
53
49
  if (host.kindOf(path) === "file") {
54
50
  const manifest = readJSON(host, path);
55
51
  const version = isRecord(manifest) ? manifest["version"] : undefined;
56
52
  return typeof version === "string" ? version : "";
57
53
  }
58
- if (dirnamePath(at) === at) {
59
- return undefined;
60
- }
61
- }
62
- }
63
- /** Whether one node wraps an expression without changing its value. */
64
- function isWrapper(node) {
65
- return (isParenthesizedExpression(node) ||
66
- isAsExpression(node) ||
67
- isSatisfiesExpression(node) ||
68
- isNonNullExpression(node));
69
- }
70
- /** The expression a wrapper that changes no value holds. */
71
- function unwrapped(node) {
72
- let at = node;
73
- while (isWrapper(at)) {
74
- at = at.expression;
75
54
  }
76
- return at;
55
+ return undefined;
77
56
  }
78
57
  /** The key one property is written with, where it is written as a name or as literal text. */
79
58
  function keyOf(property) {
@@ -562,17 +541,7 @@ function expand(template, resolved) {
562
541
  /** The configuration files in one directory that one glob names, by name. */
563
542
  function configurationFiles(host, dir, glob) {
564
543
  const expression = globExpression(glob);
565
- let entries;
566
- try {
567
- entries = host.readDirectory(dir);
568
- }
569
- catch {
570
- return [];
571
- }
572
- return entries
573
- .filter((entry) => !entry.directory && expression.test(entry.name))
574
- .map((entry) => entry.name)
575
- .sort();
544
+ return filesIn(host, dir, (name) => expression.test(name));
576
545
  }
577
546
  function resolveMove(host, parse, dir, row, move, resolved) {
578
547
  const set = [];
@@ -614,6 +583,14 @@ function readingFiles(host, parse, dir, files) {
614
583
  catch {
615
584
  continue;
616
585
  }
586
+ if (YAML_NAME.test(name)) {
587
+ const value = yamlDocument(text);
588
+ if (value !== undefined) {
589
+ const json = JSON.stringify(value);
590
+ found.push({ name, text: json, file: parse(`${path}${JSON_EXTENSION}`, json) });
591
+ }
592
+ continue;
593
+ }
617
594
  found.push({
618
595
  name,
619
596
  text,
@@ -652,7 +629,7 @@ function shortNameUses(host, parse, dir, manifest, readings) {
652
629
  }
653
630
  }
654
631
  }
655
- return [...used].filter((name) => declared.has(name)).sort(compare);
632
+ return [...used].filter((name) => declared.has(name)).sort(bytewise);
656
633
  }
657
634
  /**
658
635
  * The package one value of a prefixed-name reading names, or none: ESLint's own naming,
@@ -703,7 +680,7 @@ function prefixedNameUses(host, parse, dir, manifest, readings) {
703
680
  }
704
681
  }
705
682
  }
706
- return [...used].sort(compare);
683
+ return [...used].sort(bytewise);
707
684
  }
708
685
  /** The declared dependencies an applied row's helper settings use. */
709
686
  function helperUses(host, parse, dir, manifest, readings) {
@@ -760,13 +737,6 @@ function packageKeyUses(host, parse, dir, manifest, keys) {
760
737
  text.startsWith(`${name}/`) ||
761
738
  (text.startsWith(`${name}:`) && text.length > name.length + 1)));
762
739
  }
763
- /** Two strings ordered bytewise. */
764
- function compare(a, b) {
765
- if (a === b) {
766
- return 0;
767
- }
768
- return a < b ? -1 : 1;
769
- }
770
740
  /**
771
741
  * What the rows decide over the manifests the analysis reads. A row `disabled` names
772
742
  * is skipped before anything is read for it.
@@ -780,7 +750,7 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
780
750
  const selected = new Map();
781
751
  const testFiles = new Set();
782
752
  for (const manifest of manifests) {
783
- const declared = readJSON(host, joinPath(manifest.dir, "package.json"));
753
+ const declared = readJSON(host, joinPath(manifest.dir, MANIFEST));
784
754
  const versions = new Map();
785
755
  const missing = new Set();
786
756
  for (const row of rows) {
@@ -801,7 +771,7 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
801
771
  failures.push({
802
772
  dir: manifest.dir,
803
773
  failure: {
804
- setupClass: "missing-module",
774
+ failureClass: "missing-module",
805
775
  detail: `${manifest.path} declares ${row.package}, which no node_modules at or ` +
806
776
  `above its directory holds: run the package manager's install`,
807
777
  },
@@ -826,7 +796,7 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
826
796
  failures.push({
827
797
  dir: manifest.dir,
828
798
  failure: {
829
- setupClass: "convention-not-literal",
799
+ failureClass: "convention-not-literal",
830
800
  detail: where === "." ? failed : `${where}/${failed}`,
831
801
  },
832
802
  });
@@ -878,15 +848,15 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
878
848
  }
879
849
  }
880
850
  const unique = [...new Map(applied.map((one) => [JSON.stringify(one), one])).values()];
881
- unique.sort((a, b) => compare(a.name, b.name) ||
882
- compare(a.manifest, b.manifest) ||
883
- compare(JSON.stringify(a), JSON.stringify(b)));
851
+ unique.sort((a, b) => bytewise(a.name, b.name) ||
852
+ bytewise(a.manifest, b.manifest) ||
853
+ bytewise(JSON.stringify(a), JSON.stringify(b)));
884
854
  return {
885
855
  applied: unique,
886
856
  globs,
887
857
  generated,
888
858
  failures,
889
- uses: [...uses].sort(compare),
859
+ uses: [...uses].sort(bytewise),
890
860
  selected,
891
861
  testFiles,
892
862
  };
@@ -10,14 +10,16 @@ import { isArrayLiteralExpression, isCallExpression, isExportDeclaration, isExpr
10
10
  import { automaticTypes } from "./automatic-types.js";
11
11
  import { configurationFiles, declaredIn as declaredBeside, dependenciesNamed, moduleStrings, outsideChain, } from "./configuration-files.js";
12
12
  import { nodeKey, packageScope } from "./inventory.js";
13
- import { scriptTokens } from "./manifest.js";
14
- import { dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath } from "./paths.js";
13
+ import { ancestors, dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath, } from "./paths.js";
15
14
  import { UNANSWERED } from "./query.js";
16
15
  import { sourceFilesOf } from "./source-files.js";
17
- import { workflowTokens } from "./workflow-steps.js";
18
- const MANIFEST = "package.json";
19
- const MODULES_DIR = "node_modules";
20
- const MODULES_SEGMENT = `/${MODULES_DIR}/`;
16
+ import { manifestCommands } from "./manifest.js";
17
+ import { workflowCommands, workflowTokens } from "./workflow-steps.js";
18
+ import { bytewise } from "./text/compare.js";
19
+ import { isRecord } from "./json-document.js";
20
+ import { inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, readDocument } from "./fs/manifest.js";
21
+ import { commandsOf, scriptTokens } from "./text/shell.js";
22
+ const MODULES_SEGMENT = `/${INSTALLED_PACKAGES}/`;
21
23
  const TYPES_SCOPE = "@types/";
22
24
  /** A script token naming a JavaScript file by a path no expansion changes. */
23
25
  const SCRIPT_FILE = /^[^$`{*?[~]+\.(?:js|mjs|cjs)$/u;
@@ -39,25 +41,6 @@ export function configurationNeeds(packages) {
39
41
  }
40
42
  /** The key of {@link ProjectNeeds.at} for a use no file of the target governs. */
41
43
  const ANYWHERE = "";
42
- function isRecord(value) {
43
- return typeof value === "object" && value !== null && !Array.isArray(value);
44
- }
45
- /** One JSON document's decoded value, or undefined where it cannot be read or parsed. */
46
- function readJSON(host, path) {
47
- let text;
48
- try {
49
- text = host.readFile(path);
50
- }
51
- catch {
52
- return undefined;
53
- }
54
- try {
55
- return { text, value: JSON.parse(text) };
56
- }
57
- catch {
58
- return undefined;
59
- }
60
- }
61
44
  /**
62
45
  * The package a bare module specifier names: its first segment, or its first two
63
46
  * where it starts with a scope. A relative, absolute or scheme-prefixed specifier and
@@ -280,7 +263,7 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
280
263
  }
281
264
  for (const { strings, manifestDirs } of configuration.documents) {
282
265
  for (const manifestDir of manifestDirs) {
283
- const names = declaredAt(joinPath(manifestDir, "package.json"));
266
+ const names = declaredAt(joinPath(manifestDir, MANIFEST));
284
267
  for (const text of strings) {
285
268
  use([PROJECT_OWNER], dependenciesNamed(text, names), joinPath(manifestDir, MANIFEST));
286
269
  }
@@ -289,7 +272,7 @@ export function projectNeeds(project, held, host, targetRoot, parse) {
289
272
  const ranFiles = outsideChain(host, targetRoot, files, parse, scriptRunFiles(host, targetRoot, files));
290
273
  for (const { file, manifestDirs } of [...configuration.outside, ...ranFiles]) {
291
274
  for (const manifestDir of manifestDirs) {
292
- const names = declaredAt(joinPath(manifestDir, "package.json"));
275
+ const names = declaredAt(joinPath(manifestDir, MANIFEST));
293
276
  for (const { text } of moduleStrings(file)) {
294
277
  use([PROJECT_OWNER], dependenciesNamed(text, names), joinPath(manifestDir, MANIFEST));
295
278
  }
@@ -307,8 +290,8 @@ function scriptRunFiles(host, targetRoot, files) {
307
290
  const root = resolvePath(host.workingDirectory(), targetRoot);
308
291
  const dirs = new Set([root]);
309
292
  for (const name of files.byName.keys()) {
310
- for (let dir = dirnamePath(name); !dirs.has(dir); dir = dirnamePath(dir)) {
311
- if (relativePath(root, dir) === undefined) {
293
+ for (const dir of ancestors(dirnamePath(name), root)) {
294
+ if (dirs.has(dir)) {
312
295
  break;
313
296
  }
314
297
  dirs.add(dir);
@@ -318,7 +301,7 @@ function scriptRunFiles(host, targetRoot, files) {
318
301
  [root, new Set(workflowTokens(host, root))],
319
302
  ]);
320
303
  for (const dir of dirs) {
321
- const read = readJSON(host, joinPath(dir, MANIFEST));
304
+ const read = readDocument(host, joinPath(dir, MANIFEST));
322
305
  if (read !== undefined && isRecord(read.value)) {
323
306
  const own = scriptTokensOf(read.value);
324
307
  tokens.set(dir, dir === root ? new Set([...own, ...(tokens.get(root) ?? [])]) : own);
@@ -330,7 +313,8 @@ function scriptRunFiles(host, targetRoot, files) {
330
313
  const path = SCRIPT_FILE.test(token) ? resolvePath(manifestDir, token) : undefined;
331
314
  const below = path === undefined ? undefined : relativePath(root, path);
332
315
  if (path !== undefined &&
333
- below?.split("/").includes(MODULES_DIR) === false &&
316
+ below !== undefined &&
317
+ !inInstalledPackages(below) &&
334
318
  !files.byName.has(path) &&
335
319
  host.kindOf(path) === "file") {
336
320
  found.push({ path, manifestDir });
@@ -600,8 +584,8 @@ function lineAndColumn(text, offset) {
600
584
  }
601
585
  /** The installed copy of one dependency, read where the package manager puts it for the target. */
602
586
  function installedOf(host, root, name) {
603
- for (let dir = root;; dir = dirnamePath(dir)) {
604
- const read = readJSON(host, joinPath(dir, MODULES_DIR, name, MANIFEST));
587
+ for (const dir of ancestors(root)) {
588
+ const read = readDocument(host, joinPath(dir, INSTALLED_PACKAGES, name, MANIFEST));
605
589
  if (read !== undefined && isRecord(read.value)) {
606
590
  const bin = read.value["bin"];
607
591
  const peers = read.value["peerDependencies"];
@@ -617,10 +601,8 @@ function installedOf(host, root, name) {
617
601
  : [],
618
602
  };
619
603
  }
620
- if (dirnamePath(dir) === dir) {
621
- return undefined;
622
- }
623
604
  }
605
+ return undefined;
624
606
  }
625
607
  /** Every dependency the manifest text at `path` declares, in the order the text writes them. */
626
608
  function declaredIn(text, manifest, path, scope) {
@@ -664,6 +646,82 @@ function scriptTokensOf(manifest) {
664
646
  }
665
647
  return found;
666
648
  }
649
+ /**
650
+ * The runtime flags whose value is a module loaded before the entry, as `--flag value` or
651
+ * `--flag=value`: https://nodejs.org/api/cli.html#--importmodule,
652
+ * https://nodejs.org/api/cli.html#--experimental-loadermodule,
653
+ * https://nodejs.org/api/cli.html#-r---require-module
654
+ */
655
+ const PRELOAD_FLAGS = new Set([
656
+ "--experimental-loader",
657
+ "--import",
658
+ "--loader",
659
+ "--require",
660
+ "-r",
661
+ ]);
662
+ /**
663
+ * The programs that pass a preload flag to the runtime they start: Node itself, and the
664
+ * runners that forward Node's flags or read the same `--require`:
665
+ * https://mochajs.org/#-require-module-r-module, https://tsx.is/node-enhancement,
666
+ * https://typestrong.org/ts-node/docs/options#require,
667
+ * https://github.com/remy/nodemon#running-non-node-scripts
668
+ */
669
+ const PRELOADING_PROGRAMS = new Set([
670
+ "mocha",
671
+ "node",
672
+ "nodemon",
673
+ "ts-node",
674
+ "tsx",
675
+ ]);
676
+ /** The programs that run the command after them, and an environment assignment before it. */
677
+ const LAUNCHERS = new Set(["cross-env", "env", "npx"]);
678
+ const ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/u;
679
+ /**
680
+ * The packages `scripts` preload by a runtime flag's bare module specifier, a flag
681
+ * counting only in a command whose program passes it to the runtime, and for Node only
682
+ * before the script it runs, whose own arguments come after it.
683
+ */
684
+ function preloadsOf(scripts) {
685
+ const found = new Set();
686
+ for (const script of scripts) {
687
+ for (const command of commandsOf(script)) {
688
+ const tokens = scriptTokens(command);
689
+ let at = 0;
690
+ while (at < tokens.length &&
691
+ (ASSIGNMENT.test(tokens[at] ?? "") || LAUNCHERS.has(tokens[at] ?? ""))) {
692
+ at += 1;
693
+ }
694
+ const path = tokens[at] ?? "";
695
+ const program = path.slice(path.lastIndexOf("/") + 1);
696
+ if (!PRELOADING_PROGRAMS.has(program)) {
697
+ continue;
698
+ }
699
+ for (at += 1; at < tokens.length; at += 1) {
700
+ const token = tokens[at] ?? "";
701
+ if (!token.startsWith("-")) {
702
+ if (program === "node") {
703
+ break;
704
+ }
705
+ continue;
706
+ }
707
+ const equals = token.indexOf("=");
708
+ const flag = equals < 0 ? token : token.slice(0, equals);
709
+ if (!PRELOAD_FLAGS.has(flag)) {
710
+ continue;
711
+ }
712
+ if (equals < 0) {
713
+ at += 1;
714
+ }
715
+ const value = equals < 0 ? tokens[at] : token.slice(equals + 1);
716
+ const name = value === undefined ? undefined : packageOfSpecifier(value);
717
+ if (name !== undefined) {
718
+ found.add(name);
719
+ }
720
+ }
721
+ }
722
+ }
723
+ return found;
724
+ }
667
725
  /** Whether a path below the target root lies in the directory `dir` below it, `""` being the root. */
668
726
  function isInside(path, dir) {
669
727
  return dir === "" || path.startsWith(`${dir}/`);
@@ -735,22 +793,27 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
735
793
  }
736
794
  }
737
795
  const workflow = new Set(workflowTokens(host, targetRoot));
796
+ const workflowPreloads = preloadsOf(workflowCommands(host, targetRoot));
738
797
  const declared = [];
739
798
  const ran = new Set();
740
799
  const peers = new Map();
741
800
  const uninstalledHere = new Set(nested);
742
801
  for (const [dir, path] of manifests) {
743
- const read = readJSON(host, joinPath(dir, MANIFEST));
802
+ const read = readDocument(host, joinPath(dir, MANIFEST));
744
803
  if (read === undefined || !isRecord(read.value)) {
745
804
  continue;
746
805
  }
747
806
  const tokens = scriptTokensOf(read.value);
807
+ const preloads = preloadsOf(manifestCommands(host, dir, read.value).map(({ command }) => command));
748
808
  for (const dependency of declaredIn(read.text, read.value, path, scopeOf(path))) {
749
809
  const found = installedOf(host, dir, dependency.name);
750
810
  if (found === undefined && uninstalledHere.has(dir)) {
751
811
  continue;
752
812
  }
753
813
  declared.push(dependency);
814
+ if (preloads.has(dependency.name) || workflowPreloads.has(dependency.name)) {
815
+ ran.add(declarationKey(dependency));
816
+ }
754
817
  if (found === undefined) {
755
818
  continue;
756
819
  }
@@ -812,7 +875,7 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
812
875
  const heldBy = new Map();
813
876
  for (const [key, held] of holders) {
814
877
  if (!live.has(key) && !ran.has(key)) {
815
- heldBy.set(key, [...held].sort((a, b) => (a < b ? -1 : 1)));
878
+ heldBy.set(key, [...held].sort(bytewise));
816
879
  }
817
880
  }
818
881
  const users = new Map();
@@ -824,7 +887,7 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
824
887
  for (const id of candidates) {
825
888
  const sole = [...(uses.get(id) ?? [])].filter((one) => users.get(one) === 1 && names.has(one));
826
889
  if (sole.length > 0) {
827
- lastUses.set(id, sole.sort((a, b) => (a < b ? -1 : 1)));
890
+ lastUses.set(id, sole.sort(bytewise));
828
891
  }
829
892
  }
830
893
  const owners = new Map();
@@ -836,7 +899,7 @@ export function dependenciesOf(host, targetRoot, perProject, candidates, members
836
899
  }
837
900
  }
838
901
  const fileLastUses = new Map();
839
- for (const [one, held] of [...owners].sort(([a], [b]) => (a < b ? -1 : 1))) {
902
+ for (const [one, held] of [...owners].sort(([a], [b]) => bytewise(a, b))) {
840
903
  const paths = new Set([...held].map((owner) => owner.replace(/:\d+:\d+$/u, "")));
841
904
  const [path] = paths;
842
905
  if (paths.size === 1 && path !== undefined && path !== PROJECT_OWNER) {