@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.20

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 (402) hide show
  1. package/README.md +3 -1
  2. package/THIRD_PARTY_NOTICES.md +27 -0
  3. package/dist/bin/mapper-connection.js +2 -1
  4. package/dist/bin/node-host.js +24 -5
  5. package/dist/src/alias-chain.js +2 -7
  6. package/dist/src/amd.js +81 -0
  7. package/dist/src/analysis.js +269 -432
  8. package/dist/src/augmentations.js +64 -3
  9. package/dist/src/automatic-types.js +10 -29
  10. package/dist/src/bindings.js +382 -0
  11. package/dist/src/calls.js +279 -43
  12. package/dist/src/commands/held.js +499 -0
  13. package/dist/src/commands/read.js +161 -0
  14. package/dist/src/commands/shell.js +169 -0
  15. package/dist/src/commands/tools.js +1847 -0
  16. package/dist/src/component-files.js +3 -2
  17. package/dist/src/component-layer.js +4 -2
  18. package/dist/src/config.js +6 -82
  19. package/dist/src/conformance-record.js +1 -1
  20. package/dist/src/consumers.js +10 -38
  21. package/dist/src/contextual-uses.js +57 -26
  22. package/dist/src/contract/config.generated.js +561 -0
  23. package/dist/src/contract/contract.generated.js +1369 -0
  24. package/dist/src/contract/report.generated.js +866 -0
  25. package/dist/src/dependencies.js +164 -121
  26. package/dist/src/destructuring.js +1 -19
  27. package/dist/src/edges.js +38 -122
  28. package/dist/src/element-access.js +181 -168
  29. package/dist/src/entries/build-scripts.js +222 -0
  30. package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
  31. package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
  32. package/dist/src/entries/conventions.js +740 -0
  33. package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
  34. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
  35. package/dist/src/entries/run-directories.js +77 -0
  36. package/dist/src/entries/sources.js +144 -0
  37. package/dist/src/entries/static-module.js +670 -0
  38. package/dist/src/entries/test-runners.js +650 -0
  39. package/dist/src/entries/workflow-steps.js +345 -0
  40. package/dist/src/enum-group.js +3 -10
  41. package/dist/src/erased-stores.js +4 -6
  42. package/dist/src/exempt-classes.js +1 -63
  43. package/dist/src/exempt.js +21 -66
  44. package/dist/src/exposure.js +400 -0
  45. package/dist/src/extensions.js +37 -0
  46. package/dist/src/facts.js +38 -0
  47. package/dist/src/failure.js +36 -0
  48. package/dist/src/file-facts.js +3 -26
  49. package/dist/src/findings/completion.js +109 -56
  50. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  51. package/dist/src/findings/emitters.js +27 -41
  52. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  53. package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
  54. package/dist/src/findings/interfaces.js +4 -5
  55. package/dist/src/findings/intra-function.js +16 -13
  56. package/dist/src/findings/non-code-artifacts.js +17 -12
  57. package/dist/src/findings/reads-and-writes.js +86 -27
  58. package/dist/src/findings/self-check.js +44 -30
  59. package/dist/src/findings/unused-declarations.js +29 -45
  60. package/dist/src/findings/visibility-narrowing.js +23 -31
  61. package/dist/src/findings-pass.js +13 -21
  62. package/dist/src/framework-lifecycle.js +46 -19
  63. package/dist/src/fs/document.js +52 -0
  64. package/dist/src/fs/manifest.js +67 -0
  65. package/dist/src/fs/tree.js +88 -0
  66. package/dist/src/generated-file.js +174 -28
  67. package/dist/src/git-ignore.js +39 -26
  68. package/dist/src/import-bindings.js +73 -28
  69. package/dist/src/index/sites.js +557 -0
  70. package/dist/src/index.js +2 -2
  71. package/dist/src/indexed-access.js +523 -478
  72. package/dist/src/injection-container.js +2 -2
  73. package/dist/src/interface-satisfaction.js +1 -1
  74. package/dist/src/intra-function-parts.js +63 -43
  75. package/dist/src/inventory/commonjs.js +507 -0
  76. package/dist/src/inventory/enumerate.js +167 -0
  77. package/dist/src/inventory/syntax.js +236 -0
  78. package/dist/src/inventory.js +323 -724
  79. package/dist/src/javascript-file.js +48 -0
  80. package/dist/src/json-document.js +198 -67
  81. package/dist/src/keyof-comparisons.js +126 -107
  82. package/dist/src/kinds.js +3 -366
  83. package/dist/src/{components.js → liveness/components.js} +2 -3
  84. package/dist/src/{graph.js → liveness/graph.js} +52 -28
  85. package/dist/src/liveness/matrix.js +99 -0
  86. package/dist/src/liveness/sweep.js +558 -0
  87. package/dist/src/load/classify.js +289 -0
  88. package/dist/src/load/diagnostics.js +87 -0
  89. package/dist/src/load/discover.js +285 -0
  90. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  91. package/dist/src/load/expected-module.js +136 -0
  92. package/dist/src/load/load.js +27 -0
  93. package/dist/src/load/module-lookup.js +37 -0
  94. package/dist/src/load/package-scope.js +56 -0
  95. package/dist/src/load/plan.js +313 -0
  96. package/dist/src/load/specifiers.js +113 -0
  97. package/dist/src/load/synthesize.js +152 -0
  98. package/dist/src/load/test-globals.js +207 -0
  99. package/dist/src/load/test-joins.js +82 -0
  100. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  101. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  102. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
  103. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  104. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  105. package/dist/src/module-declarations.js +70 -85
  106. package/dist/src/overrides.js +134 -112
  107. package/dist/src/partial.js +2 -1
  108. package/dist/src/paths.js +82 -16
  109. package/dist/src/platform-calls.js +78 -0
  110. package/dist/src/platform-symbols.js +134 -0
  111. package/dist/src/position.js +43 -1
  112. package/dist/src/print.js +11 -79
  113. package/dist/src/product.js +13 -0
  114. package/dist/src/query.js +47 -0
  115. package/dist/src/ref.js +12 -20
  116. package/dist/src/references/read-rule.js +1 -0
  117. package/dist/src/references/read-rules.js +48 -0
  118. package/dist/src/references/sink.js +237 -0
  119. package/dist/src/references/sources.js +450 -0
  120. package/dist/src/references.js +117 -1074
  121. package/dist/src/report-schema.js +51 -0
  122. package/dist/src/report.js +57 -41
  123. package/dist/src/reporters/annotations.js +15 -8
  124. package/dist/src/reporters/sarif.js +16 -10
  125. package/dist/src/reporters/template.js +4 -19
  126. package/dist/src/resolve.js +246 -730
  127. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
  128. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
  129. package/dist/src/roots/manifest.js +216 -0
  130. package/dist/src/roots/published-reach.js +412 -0
  131. package/dist/src/roots/root-set.js +487 -0
  132. package/dist/src/roots/unseen-loads.js +236 -0
  133. package/dist/src/run.js +66 -77
  134. package/dist/src/schema.js +320 -343
  135. package/dist/src/scope.js +38 -115
  136. package/dist/src/serialization-contract.js +601 -22
  137. package/dist/src/session.js +37 -29
  138. package/dist/src/source-files.js +6 -10
  139. package/dist/src/stores.js +4 -2
  140. package/dist/src/suppress-file.js +25 -28
  141. package/dist/src/suppress-inline.js +36 -83
  142. package/dist/src/suppress.js +50 -71
  143. package/dist/src/symbol-keys.js +92 -88
  144. package/dist/src/template-field.js +9 -19
  145. package/dist/src/tests/file-class.js +76 -0
  146. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  147. package/dist/src/{test-support.js → tests/support.js} +5 -12
  148. package/dist/src/text/compare.js +26 -0
  149. package/dist/src/text/glob.js +194 -0
  150. package/dist/src/text/named-files.js +298 -0
  151. package/dist/src/text/yaml.js +684 -0
  152. package/dist/src/type-errors.js +11 -232
  153. package/dist/src/type-parameter-reads.js +178 -139
  154. package/dist/src/unimplemented-callees.js +262 -242
  155. package/dist/src/unwrap.js +23 -0
  156. package/dist/src/usage.js +10 -0
  157. package/dist/src/vendor/unbash/ansi-c.js +132 -0
  158. package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
  159. package/dist/src/vendor/unbash/arithmetic.js +591 -0
  160. package/dist/src/vendor/unbash/assignment.js +131 -0
  161. package/dist/src/vendor/unbash/chars.js +48 -0
  162. package/dist/src/vendor/unbash/command.js +41 -0
  163. package/dist/src/vendor/unbash/expansion.js +80 -0
  164. package/dist/src/vendor/unbash/glob.js +268 -0
  165. package/dist/src/vendor/unbash/heredoc.js +27 -0
  166. package/dist/src/vendor/unbash/internal-types.js +1 -0
  167. package/dist/src/vendor/unbash/lexer.js +4274 -0
  168. package/dist/src/vendor/unbash/limits.js +3 -0
  169. package/dist/src/vendor/unbash/parser.js +1366 -0
  170. package/dist/src/vendor/unbash/parts.js +57 -0
  171. package/dist/src/vendor/unbash/substitution-context.js +8 -0
  172. package/dist/src/vendor/unbash/traversal.js +212 -0
  173. package/dist/src/vendor/unbash/types.js +1 -0
  174. package/dist/src/vendor/unbash/word-value.js +61 -0
  175. package/dist/src/vendor/unbash/word.js +40 -0
  176. package/dist/src/verbs/analyze.js +194 -127
  177. package/dist/src/verbs/describe.js +13 -18
  178. package/dist/src/verbs/explain.js +85 -139
  179. package/dist/src/verbs/print-config.js +2 -1
  180. package/dist/src/verbs/print-projects.js +6 -4
  181. package/dist/src/verbs/print-retained.js +7 -5
  182. package/dist/src/verbs/print-roots.js +4 -2
  183. package/dist/src/verbs/verb.js +1 -5
  184. package/dist/src/verbs/version.js +14 -3
  185. package/jsr.json +2 -1
  186. package/package.json +14 -8
  187. package/src/alias-chain.ts +2 -9
  188. package/src/amd.ts +130 -0
  189. package/src/analysis.ts +424 -650
  190. package/src/augmentations.ts +93 -4
  191. package/src/automatic-types.ts +12 -30
  192. package/src/bindings.ts +460 -0
  193. package/src/calls.ts +338 -46
  194. package/src/commands/held.ts +632 -0
  195. package/src/commands/read.ts +242 -0
  196. package/src/commands/shell.ts +228 -0
  197. package/src/commands/tools.ts +2382 -0
  198. package/src/component-files.ts +4 -2
  199. package/src/component-layer.ts +4 -2
  200. package/src/config.ts +31 -302
  201. package/src/conformance-record.ts +1 -1
  202. package/src/consumers.ts +16 -66
  203. package/src/contextual-uses.ts +66 -34
  204. package/src/contract/config.generated.ts +821 -0
  205. package/src/contract/contract.generated.ts +1452 -0
  206. package/src/contract/report.generated.ts +1241 -0
  207. package/src/dependencies.ts +222 -127
  208. package/src/destructuring.ts +1 -31
  209. package/src/edges.ts +41 -140
  210. package/src/element-access.ts +190 -187
  211. package/src/entries/build-scripts.ts +292 -0
  212. package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
  213. package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
  214. package/src/{conventions.ts → entries/conventions.ts} +367 -583
  215. package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
  216. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
  217. package/src/entries/run-directories.ts +108 -0
  218. package/src/entries/sources.ts +266 -0
  219. package/src/entries/static-module.ts +858 -0
  220. package/src/entries/test-runners.ts +835 -0
  221. package/src/entries/workflow-steps.ts +432 -0
  222. package/src/enum-group.ts +2 -11
  223. package/src/erased-stores.ts +3 -7
  224. package/src/exempt-classes.ts +1 -75
  225. package/src/exempt.ts +70 -98
  226. package/src/exposure.ts +492 -0
  227. package/src/extensions.ts +45 -0
  228. package/src/facts.ts +46 -0
  229. package/src/failure.ts +63 -0
  230. package/src/file-facts.ts +15 -25
  231. package/src/finding.ts +10 -10
  232. package/src/findings/boundary.ts +11 -0
  233. package/src/findings/completion.ts +133 -64
  234. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  235. package/src/findings/emitter.ts +9 -10
  236. package/src/findings/emitters.ts +38 -52
  237. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  238. package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
  239. package/src/findings/interfaces.ts +7 -9
  240. package/src/findings/intra-function.ts +16 -14
  241. package/src/findings/non-code-artifacts.ts +24 -15
  242. package/src/findings/reads-and-writes.ts +118 -41
  243. package/src/findings/self-check.ts +51 -38
  244. package/src/findings/unused-declarations.ts +31 -49
  245. package/src/findings/visibility-narrowing.ts +36 -40
  246. package/src/findings-pass.ts +15 -31
  247. package/src/framework-lifecycle.ts +47 -19
  248. package/src/fs/document.ts +70 -0
  249. package/src/fs/manifest.ts +96 -0
  250. package/src/fs/tree.ts +110 -0
  251. package/src/generated-file.ts +242 -35
  252. package/src/git-ignore.ts +50 -26
  253. package/src/host.ts +12 -5
  254. package/src/import-bindings.ts +98 -29
  255. package/src/index/sites.ts +781 -0
  256. package/src/index.ts +2 -2
  257. package/src/indexed-access.ts +570 -527
  258. package/src/injection-container.ts +2 -2
  259. package/src/interface-satisfaction.ts +2 -2
  260. package/src/intra-function-parts.ts +73 -44
  261. package/src/inventory/commonjs.ts +696 -0
  262. package/src/inventory/enumerate.ts +203 -0
  263. package/src/inventory/syntax.ts +311 -0
  264. package/src/inventory.ts +442 -895
  265. package/src/javascript-file.ts +54 -0
  266. package/src/json-document.ts +241 -76
  267. package/src/keyof-comparisons.ts +133 -122
  268. package/src/kinds.ts +5 -413
  269. package/src/{components.ts → liveness/components.ts} +4 -6
  270. package/src/{graph.ts → liveness/graph.ts} +100 -35
  271. package/src/liveness/matrix.ts +162 -0
  272. package/src/liveness/sweep.ts +855 -0
  273. package/src/load/classify.ts +433 -0
  274. package/src/load/diagnostics.ts +154 -0
  275. package/src/load/discover.ts +471 -0
  276. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  277. package/src/load/expected-module.ts +194 -0
  278. package/src/load/load.ts +73 -0
  279. package/src/load/module-lookup.ts +50 -0
  280. package/src/load/package-scope.ts +74 -0
  281. package/src/load/plan.ts +513 -0
  282. package/src/load/specifiers.ts +171 -0
  283. package/src/load/synthesize.ts +230 -0
  284. package/src/load/test-globals.ts +251 -0
  285. package/src/load/test-joins.ts +98 -0
  286. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  287. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  288. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
  289. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  290. package/src/{workspace.ts → load/workspace.ts} +90 -134
  291. package/src/module-declarations.ts +74 -98
  292. package/src/overrides.ts +162 -134
  293. package/src/partial.ts +3 -2
  294. package/src/paths.ts +92 -16
  295. package/src/platform-calls.ts +119 -0
  296. package/src/platform-symbols.ts +189 -0
  297. package/src/position.ts +44 -1
  298. package/src/print.ts +12 -92
  299. package/src/product.ts +18 -0
  300. package/src/query.ts +92 -0
  301. package/src/ref.ts +12 -20
  302. package/src/references/read-rule.ts +60 -0
  303. package/src/references/read-rules.ts +55 -0
  304. package/src/references/sink.ts +314 -0
  305. package/src/references/sources.ts +632 -0
  306. package/src/references.ts +187 -1450
  307. package/src/report-schema.ts +68 -0
  308. package/src/report.ts +103 -226
  309. package/src/reporters/annotations.ts +22 -11
  310. package/src/reporters/json.ts +1 -1
  311. package/src/reporters/reporter.ts +2 -4
  312. package/src/reporters/reporters.ts +1 -1
  313. package/src/reporters/sarif.ts +29 -16
  314. package/src/reporters/template.ts +4 -20
  315. package/src/reporters/text.ts +3 -3
  316. package/src/resolve.ts +284 -1115
  317. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +27 -29
  318. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
  319. package/src/roots/manifest.ts +303 -0
  320. package/src/roots/published-reach.ts +486 -0
  321. package/src/{roots.ts → roots/root-set.ts} +286 -469
  322. package/src/roots/unseen-loads.ts +345 -0
  323. package/src/run.ts +75 -91
  324. package/src/schema.ts +391 -388
  325. package/src/scope.ts +46 -138
  326. package/src/serialization-contract.ts +769 -23
  327. package/src/session.ts +87 -55
  328. package/src/source-files.ts +6 -11
  329. package/src/stores.ts +15 -3
  330. package/src/suppress-file.ts +24 -33
  331. package/src/suppress-inline.ts +55 -91
  332. package/src/suppress.ts +78 -79
  333. package/src/symbol-keys.ts +104 -107
  334. package/src/template-field.ts +15 -25
  335. package/src/tests/file-class.ts +135 -0
  336. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  337. package/src/{test-support.ts → tests/support.ts} +15 -21
  338. package/src/text/compare.ts +27 -0
  339. package/src/text/glob.ts +210 -0
  340. package/src/text/named-files.ts +388 -0
  341. package/src/text/yaml.ts +747 -0
  342. package/src/type-errors.ts +18 -288
  343. package/src/type-parameter-reads.ts +187 -158
  344. package/src/unimplemented-callees.ts +297 -280
  345. package/src/unwrap.ts +34 -0
  346. package/src/usage.ts +10 -0
  347. package/src/vendor/unbash/LICENSE +15 -0
  348. package/src/vendor/unbash/VENDORED.md +16 -0
  349. package/src/vendor/unbash/ansi-c.ts +132 -0
  350. package/src/vendor/unbash/arithmetic-parts.ts +53 -0
  351. package/src/vendor/unbash/arithmetic.ts +641 -0
  352. package/src/vendor/unbash/assignment.ts +163 -0
  353. package/src/vendor/unbash/chars.ts +48 -0
  354. package/src/vendor/unbash/command.ts +47 -0
  355. package/src/vendor/unbash/expansion.ts +144 -0
  356. package/src/vendor/unbash/glob.ts +284 -0
  357. package/src/vendor/unbash/heredoc.ts +34 -0
  358. package/src/vendor/unbash/internal-types.ts +94 -0
  359. package/src/vendor/unbash/lexer.ts +4352 -0
  360. package/src/vendor/unbash/limits.ts +3 -0
  361. package/src/vendor/unbash/parser.ts +1612 -0
  362. package/src/vendor/unbash/parts.ts +96 -0
  363. package/src/vendor/unbash/substitution-context.ts +20 -0
  364. package/src/vendor/unbash/traversal.ts +182 -0
  365. package/src/vendor/unbash/types.ts +660 -0
  366. package/src/vendor/unbash/word-value.ts +64 -0
  367. package/src/vendor/unbash/word.ts +50 -0
  368. package/src/verbs/analyze.ts +255 -164
  369. package/src/verbs/describe.ts +19 -17
  370. package/src/verbs/explain.ts +93 -169
  371. package/src/verbs/print-config.ts +2 -1
  372. package/src/verbs/print-projects.ts +6 -4
  373. package/src/verbs/print-retained.ts +7 -5
  374. package/src/verbs/print-roots.ts +4 -2
  375. package/src/verbs/verb.ts +2 -8
  376. package/src/verbs/version.ts +15 -3
  377. package/dist/src/base-url.js +0 -18
  378. package/dist/src/conventions.js +0 -937
  379. package/dist/src/discover.js +0 -468
  380. package/dist/src/entry-points.js +0 -529
  381. package/dist/src/glob.js +0 -65
  382. package/dist/src/manifest.js +0 -165
  383. package/dist/src/matrix.js +0 -246
  384. package/dist/src/pnpm-workspace.js +0 -120
  385. package/dist/src/roots.js +0 -672
  386. package/dist/src/setup-failure.js +0 -23
  387. package/dist/src/sweep.js +0 -224
  388. package/dist/src/test-joins.js +0 -101
  389. package/dist/src/version.js +0 -7
  390. package/dist/src/workflow-steps.js +0 -185
  391. package/src/base-url.ts +0 -24
  392. package/src/discover.ts +0 -653
  393. package/src/entry-points.ts +0 -687
  394. package/src/glob.ts +0 -67
  395. package/src/manifest.ts +0 -234
  396. package/src/matrix.ts +0 -423
  397. package/src/pnpm-workspace.ts +0 -135
  398. package/src/setup-failure.ts +0 -39
  399. package/src/sweep.ts +0 -347
  400. package/src/test-joins.ts +0 -120
  401. package/src/version.ts +0 -7
  402. package/src/workflow-steps.ts +0 -216
@@ -8,27 +8,48 @@
8
8
  */
9
9
 
10
10
  import {
11
- isCallExpression,
12
- isExportDeclaration,
13
- isIdentifier,
14
- isImportDeclaration,
15
11
  isNoSubstitutionTemplateLiteral,
16
12
  isStringLiteral,
17
- SyntaxKind,
18
13
  type Node,
19
14
  type SourceFile,
20
15
  } from "@typescript/native/ast";
21
- import type { Host } from "./host.ts";
22
- import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
23
- import type { SourceFiles } from "./source-files.ts";
24
-
25
- const MANIFEST = "package.json";
16
+ import { relativeSpecifiers } from "./static-module.ts";
17
+ import type { Host } from "../host.ts";
18
+ import {
19
+ ancestors,
20
+ dirnamePath,
21
+ isAbsolutePath,
22
+ joinPath,
23
+ relativePath,
24
+ resolvePath,
25
+ startsRelativePath,
26
+ } from "../paths.ts";
27
+ import type { SourceFiles } from "../source-files.ts";
28
+ import { bytewise } from "../text/compare.ts";
29
+ import { isRecord } from "../json-document.ts";
30
+ import { filesIn } from "../fs/tree.ts";
31
+ import {
32
+ DEPENDENCY_SECTIONS,
33
+ holdsManifest,
34
+ inInstalledPackages,
35
+ manifestAt,
36
+ readJSON,
37
+ } from "../fs/manifest.ts";
38
+ import { readCommands } from "../commands/read.ts";
39
+ import { manifestCommands } from "../roots/manifest.ts";
40
+ import { APPENDED_EXTENSIONS, extensionOf, MODULE_EXTENSIONS } from "../extensions.ts";
41
+
42
+ /** The extensions of a configuration module, as an expression's alternatives. */
43
+ const MODULE_NAME = MODULE_EXTENSIONS.map((one) => one.slice(1)).join("|");
26
44
 
27
45
  /** A configuration module's name, each form with the spelling a root reports it by. */
28
46
  const MODULE_FORMS: readonly { readonly name: RegExp; readonly form: string }[] = [
29
- { name: /^[\w-]+\.config\.(?:js|mjs|cjs|ts|mts|cts)$/u, form: "<stem>.config.<ext>" },
30
47
  {
31
- name: /^[\w-]+\.[\w-]+\.config\.(?:js|mjs|cjs|ts|mts|cts)$/u,
48
+ name: new RegExp(String.raw`^[\w-]+\.config\.(?:${MODULE_NAME})$`, "u"),
49
+ form: "<stem>.config.<ext>",
50
+ },
51
+ {
52
+ name: new RegExp(String.raw`^[\w-]+\.[\w-]+\.config\.(?:${MODULE_NAME})$`, "u"),
32
53
  form: "<stem>.<qualifier>.config.<ext>",
33
54
  },
34
55
  { name: /^\.[\w-]+rc\.(?:js|mjs|cjs)$/u, form: ".<stem>rc.<ext>" },
@@ -37,17 +58,6 @@ const MODULE_FORMS: readonly { readonly name: RegExp; readonly form: string }[]
37
58
  /** A JSON configuration file's name. */
38
59
  const DOCUMENT_NAME = /^(?:[\w-]+(?:\.[\w-]+)?\.config\.json|\.[\w-]+rc(?:\.json)?)$/u;
39
60
 
40
- /** The manifest members a dependency is declared in. */
41
- const DEPENDENCY_MEMBERS = [
42
- "dependencies",
43
- "devDependencies",
44
- "peerDependencies",
45
- "optionalDependencies",
46
- ] as const;
47
-
48
- /** The prefixes a string names a file with, relative to the file that writes it. */
49
- const RELATIVE_PREFIXES = ["./", "../"] as const;
50
-
51
61
  /** The JavaScript extensions a relative specifier from a configuration file stands for TypeScript under. */
52
62
  const COUNTERPARTS: readonly (readonly [string, readonly string[]])[] = [
53
63
  [".js", [".ts", ".tsx"]],
@@ -56,9 +66,6 @@ const COUNTERPARTS: readonly (readonly [string, readonly string[]])[] = [
56
66
  [".cjs", [".cts"]],
57
67
  ];
58
68
 
59
- /** The extensions appended to a relative specifier from a configuration file, in order. */
60
- const APPENDED = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"] as const;
61
-
62
69
  /** The extensions the program's module resolution appends to a specifier written without one. */
63
70
  export const RESOLVED_EXTENSIONS = [
64
71
  ".ts",
@@ -72,9 +79,6 @@ export const RESOLVED_EXTENSIONS = [
72
79
  ".cjs",
73
80
  ] as const;
74
81
 
75
- /** The directory a package manager installs packages into, whose files are no project's own. */
76
- const MODULES_DIR = "node_modules";
77
-
78
82
  /** The file's name, the last segment of its path. */
79
83
  function basename(path: string): string {
80
84
  return path.slice(path.lastIndexOf("/") + 1);
@@ -82,11 +86,8 @@ function basename(path: string): string {
82
86
 
83
87
  /** Whether one path is the project's own: below the target root and in no `node_modules`. */
84
88
  function isProjectPath(root: string, path: string): boolean {
85
- return relativePath(root, path)?.split("/").includes(MODULES_DIR) === false;
86
- }
87
-
88
- function isRecord(value: unknown): value is Record<string, unknown> {
89
- return typeof value === "object" && value !== null && !Array.isArray(value);
89
+ const below = relativePath(root, path);
90
+ return below !== undefined && !inInstalledPackages(below);
90
91
  }
91
92
 
92
93
  /** The form one file name is as a configuration module, or undefined where it is none. */
@@ -120,167 +121,31 @@ export interface OutsideModule {
120
121
  readonly manifestDirs: readonly string[];
121
122
  }
122
123
 
123
- /** The flags a tool's command line names its configuration file with. */
124
- const CONFIG_FLAGS: ReadonlySet<string> = new Set(["--config", "-c"]);
125
-
126
- /** The extensions of a module a configuration flag may name. */
127
- const MODULE_EXTENSIONS = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"] as const;
128
-
129
- /** The characters that end a word outside quotes and separate nothing: blanks. */
130
- // Stryker disable next-line Regex: its \v to \V mutant is no valid escape under the u flag, so the whole module fails to parse
131
- const BLANK = /[ \t\r\f\v]/u;
132
-
133
- /** The characters that end a word outside quotes and begin an operator: newline included. */
134
- const OPERATOR = /[\n;&|()<>]/u;
135
-
136
- /** The characters a backslash escapes inside double quotes; before any other it stands for itself. */
137
- const DOUBLE_QUOTE_ESCAPES = new Set(["$", "`", '"', "\\"]);
138
-
139
124
  /**
140
- * The words of one command line, as POSIX token recognition reads quotes, backslashes,
141
- * line continuations, comments and operators. A word an expansion may change (an unquoted
142
- * `$`, backquote, glob character or leading `~`, or a `$` or backquote in double quotes)
143
- * is computed, and so is the rest of a line whose quote is never closed. A computed word
144
- * and each operator are undefined, so a flag's file is never read across them.
145
- */
146
- function shellWords(command: string): readonly (string | undefined)[] {
147
- const words: (string | undefined)[] = [];
148
- let word: string | undefined;
149
- let computed = false;
150
- const end = (): void => {
151
- if (word !== undefined) {
152
- words.push(computed ? undefined : word);
153
- }
154
- word = undefined;
155
- computed = false;
156
- };
157
- for (let at = 0; at < command.length; at += 1) {
158
- const char = command.charAt(at);
159
- if (char === "\\" && command.charAt(at + 1) === "\n") {
160
- at += 1;
161
- } else if (BLANK.test(char)) {
162
- end();
163
- } else if (OPERATOR.test(char)) {
164
- end();
165
- words.push(undefined);
166
- } else if (char === "#" && word === undefined) {
167
- const newline = command.indexOf("\n", at);
168
- at = newline < 0 ? command.length : newline - 1;
169
- } else if (char === "\\") {
170
- at += 1;
171
- word = (word ?? "") + command.charAt(at);
172
- } else if (char === "'" || char === '"') {
173
- const close = closingQuote(command, at);
174
- if (close < 0) {
175
- word ??= "";
176
- computed = true;
177
- break;
178
- }
179
- const quoted =
180
- char === "'"
181
- ? { text: command.slice(at + 1, close), computed: false }
182
- : doubleQuoted(command.slice(at + 1, close));
183
- word = (word ?? "") + quoted.text;
184
- computed ||= quoted.computed;
185
- at = close;
186
- } else {
187
- computed ||= /[$`*?[]/u.test(char) || (char === "~" && word === undefined);
188
- word = (word ?? "") + char;
189
- }
190
- }
191
- end();
192
- return words;
193
- }
194
-
195
- /** The text between one pair of double quotes, unescaped, and whether an expansion may change it. */
196
- function doubleQuoted(inner: string): { readonly text: string; readonly computed: boolean } {
197
- let text = "";
198
- let computed = false;
199
- for (let at = 0; at < inner.length; at += 1) {
200
- const char = inner.charAt(at);
201
- const next = inner.charAt(at + 1);
202
- if (char === "\\" && next === "\n") {
203
- at += 1;
204
- } else if (char === "\\" && DOUBLE_QUOTE_ESCAPES.has(next)) {
205
- text += next;
206
- at += 1;
207
- } else {
208
- computed ||= char === "$" || char === "`";
209
- text += char;
210
- }
211
- }
212
- return { text, computed };
213
- }
214
-
215
- /** The index of the quote that closes the one at `open`, or -1 where none does. */
216
- function closingQuote(command: string, open: number): number {
217
- const quote = command.charAt(open);
218
- for (let at = open + 1; at < command.length; at += 1) {
219
- const char = command.charAt(at);
220
- if (char === quote) {
221
- return at;
222
- }
223
- if (quote === '"' && char === "\\") {
224
- at += 1;
225
- }
226
- }
227
- return -1;
228
- }
229
-
230
- /**
231
- * The files the scripts of the manifest in one directory name after a configuration flag,
232
- * `--config <file>`, `-c <file>` or `--config=<file>`, each a JSON file or a module below
233
- * the target root and in no `node_modules`.
125
+ * The files the command strings of the manifest in one directory name after a configuration
126
+ * flag, as `commands/read.ts` reads them against the directory each command runs in, each a
127
+ * JSON file or a module below the target root and in no `node_modules`.
234
128
  */
235
129
  function scriptConfigurations(host: Host, root: string, dir: string): readonly string[] {
236
- let scripts: unknown;
237
- try {
238
- const manifest: unknown = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
239
- scripts = isRecord(manifest) ? manifest["scripts"] : undefined;
240
- } catch {
241
- return [];
242
- }
243
- if (!isRecord(scripts)) {
244
- return [];
245
- }
130
+ const manifest = manifestAt(host, dir);
246
131
  const found: string[] = [];
247
- for (const command of Object.values(scripts)) {
248
- if (typeof command !== "string") {
249
- continue;
250
- }
251
- const words = shellWords(command);
252
- words.forEach((word, at) => {
253
- const named =
254
- word !== undefined && CONFIG_FLAGS.has(word)
255
- ? words[at + 1]
256
- : word === undefined
257
- ? undefined
258
- : /^--config=(.+)$/su.exec(word)?.[1];
259
- const path = named === undefined ? undefined : resolvePath(dir, named);
132
+ for (const { command } of manifest === undefined ? [] : manifestCommands(host, dir, manifest)) {
133
+ for (const { dir: runs, written } of readCommands(command, dir).configurations) {
134
+ const path = resolvePath(runs, written);
260
135
  if (
261
- path !== undefined &&
262
136
  [".json", ...MODULE_EXTENSIONS].some((extension) => path.endsWith(extension)) &&
263
137
  isProjectPath(root, path) &&
264
138
  host.kindOf(path) === "file"
265
139
  ) {
266
140
  found.push(path);
267
141
  }
268
- });
142
+ }
269
143
  }
270
144
  return found;
271
145
  }
272
146
 
273
- /** The decoded value of one JSON file, or undefined where it cannot be read or parsed. */
274
- function readDocument(host: Host, path: string): unknown {
275
- try {
276
- return JSON.parse(host.readFile(path)) as unknown;
277
- } catch {
278
- return undefined;
279
- }
280
- }
281
-
282
147
  /** The configuration files one project holds and sits beside. */
283
- interface ConfigurationFiles {
148
+ export interface ConfigurationFiles {
284
149
  /**
285
150
  * Every own file that is a configuration module, with the form its name has and the
286
151
  * directory of the manifest whose dependencies its strings are read against.
@@ -346,10 +211,10 @@ export function configurationFiles(
346
211
  ): ConfigurationFiles {
347
212
  const root = resolvePath(host.workingDirectory(), targetRoot);
348
213
  const manifests = new Map<string, boolean>();
349
- const holdsManifest = (dir: string): boolean => {
214
+ const manifestHeld = (dir: string): boolean => {
350
215
  let held = manifests.get(dir);
351
216
  if (held === undefined) {
352
- held = host.kindOf(joinPath(dir, MANIFEST)) === "file";
217
+ held = holdsManifest(host, dir);
353
218
  manifests.set(dir, held);
354
219
  }
355
220
  return held;
@@ -360,34 +225,24 @@ export function configurationFiles(
360
225
  for (const file of files.byPath.values()) {
361
226
  const form = configurationModuleForm(basename(file.fileName));
362
227
  const fileDir = dirnamePath(file.fileName);
363
- if (form !== undefined && holdsManifest(fileDir)) {
228
+ if (form !== undefined && manifestHeld(fileDir)) {
364
229
  modules.push({ file, form, manifestDir: fileDir });
365
230
  }
366
- for (
367
- let dir = dirnamePath(file.fileName);
368
- relativePath(root, dir) !== undefined && !dirs.has(dir);
369
- dir = dirnamePath(dir)
370
- ) {
231
+ for (const dir of ancestors(dirnamePath(file.fileName), root)) {
232
+ if (dirs.has(dir)) {
233
+ break;
234
+ }
371
235
  dirs.add(dir);
372
236
  }
373
237
  }
374
238
 
375
239
  const pending: { path: string; manifestDir: string }[] = [];
376
240
  const named: { path: string; manifestDir: string }[] = [];
377
- for (const dir of [...dirs].sort()) {
378
- if (!holdsManifest(dir)) {
241
+ for (const dir of [...dirs].sort(bytewise)) {
242
+ if (!manifestHeld(dir)) {
379
243
  continue;
380
244
  }
381
- let names: readonly string[];
382
- try {
383
- names = host
384
- .readDirectory(dir)
385
- .filter((entry) => !entry.directory && isConfigurationDocumentName(entry.name))
386
- .map((entry) => entry.name)
387
- .sort();
388
- } catch {
389
- names = [];
390
- }
245
+ const names = filesIn(host, dir, isConfigurationDocumentName);
391
246
  pending.push(...names.map((name) => ({ path: joinPath(dir, name), manifestDir: dir })));
392
247
  for (const path of scriptConfigurations(host, root, dir)) {
393
248
  const held = files.byName.get(path);
@@ -410,7 +265,7 @@ export function configurationFiles(
410
265
  continue;
411
266
  }
412
267
  if (document === undefined) {
413
- const value = readDocument(host, next.path);
268
+ const value = readJSON(host, next.path);
414
269
  if (value === undefined) {
415
270
  unreadable.add(next.path);
416
271
  continue;
@@ -420,9 +275,7 @@ export function configurationFiles(
420
275
  }
421
276
  document.manifestDirs.push(next.manifestDir);
422
277
  for (const text of document.strings) {
423
- const path = RELATIVE_PREFIXES.some((prefix) => text.startsWith(prefix))
424
- ? resolvePath(dirnamePath(next.path), text)
425
- : undefined;
278
+ const path = startsRelativePath(text) ? resolvePath(dirnamePath(next.path), text) : undefined;
426
279
  if (
427
280
  path?.endsWith(".json") === true &&
428
281
  isProjectPath(root, path) &&
@@ -438,59 +291,10 @@ export function configurationFiles(
438
291
  outside:
439
292
  parse === undefined
440
293
  ? []
441
- : outsideModules(host, root, [...dirs], files, holdsManifest, parse, named),
442
- };
443
- }
444
-
445
- /** The literal module specifier one `require(...)` or `import(...)` call names, if any. */
446
- function calledSpecifier(node: Node): Node | undefined {
447
- if (!isCallExpression(node) || node.arguments.length !== 1) {
448
- return undefined;
449
- }
450
- const callee = node.expression;
451
- const loads =
452
- callee.kind === SyntaxKind.ImportKeyword || (isIdentifier(callee) && callee.text === "require");
453
- return loads ? node.arguments[0] : undefined;
454
- }
455
-
456
- /**
457
- * The relative specifiers one file's imports and re-exports name, and those its
458
- * `require(...)` and `import(...)` calls name by a literal.
459
- */
460
- export function relativeSpecifiers(file: SourceFile): readonly string[] {
461
- const known = specifiersOf.get(file);
462
- if (known !== undefined) {
463
- return known;
464
- }
465
- const found: string[] = [];
466
- const named = (specifier: Node | undefined): void => {
467
- if (
468
- specifier !== undefined &&
469
- (isStringLiteral(specifier) || isNoSubstitutionTemplateLiteral(specifier)) &&
470
- RELATIVE_PREFIXES.some((prefix) => specifier.text.startsWith(prefix))
471
- ) {
472
- found.push(specifier.text);
473
- }
474
- };
475
- const visit = (node: Node): void => {
476
- named(calledSpecifier(node));
477
- node.forEachChild(visit);
294
+ : outsideModules(host, root, [...dirs], files, manifestHeld, parse, named),
478
295
  };
479
- for (const statement of file.statements) {
480
- named(
481
- isImportDeclaration(statement) || isExportDeclaration(statement)
482
- ? statement.moduleSpecifier
483
- : undefined,
484
- );
485
- visit(statement);
486
- }
487
- specifiersOf.set(file, found);
488
- return found;
489
296
  }
490
297
 
491
- /** What {@link relativeSpecifiers} found in each file, which every project of a run reads alike. */
492
- const specifiersOf = new WeakMap<SourceFile, readonly string[]>();
493
-
494
298
  /**
495
299
  * The files no program holds that a chain from `seeds` reads: each seed, and each file
496
300
  * below the target root one imports, re-exports or loads by a relative specifier that no
@@ -518,7 +322,7 @@ export function outsideChain(
518
322
  export function specifierCandidates(dir: string, specifier: string): readonly string[] {
519
323
  const path = resolvePath(dir, specifier);
520
324
  const candidates: string[] = [];
521
- if (APPENDED.some((extension) => path.endsWith(extension))) {
325
+ if (extensionOf(path, APPENDED_EXTENSIONS) !== undefined) {
522
326
  candidates.push(path);
523
327
  }
524
328
  for (const [extension, counterparts] of COUNTERPARTS) {
@@ -527,8 +331,8 @@ export function specifierCandidates(dir: string, specifier: string): readonly st
527
331
  candidates.push(...counterparts.map((one) => stem + one));
528
332
  }
529
333
  }
530
- candidates.push(...APPENDED.map((extension) => path + extension));
531
- candidates.push(...APPENDED.map((extension) => joinPath(path, `index${extension}`)));
334
+ candidates.push(...APPENDED_EXTENSIONS.map((extension) => path + extension));
335
+ candidates.push(...APPENDED_EXTENSIONS.map((extension) => joinPath(path, `index${extension}`)));
532
336
  return candidates;
533
337
  }
534
338
 
@@ -551,25 +355,16 @@ function outsideModules(
551
355
  root: string,
552
356
  dirs: readonly string[],
553
357
  files: SourceFiles,
554
- holdsManifest: (dir: string) => boolean,
358
+ manifestHeld: (dir: string) => boolean,
555
359
  parse: ParseFile,
556
360
  named: readonly { readonly path: string; readonly manifestDir: string }[],
557
361
  ): readonly OutsideModule[] {
558
362
  const pending: { path: string; manifestDir: string }[] = [...named];
559
- for (const dir of [...dirs].sort()) {
560
- if (!holdsManifest(dir)) {
561
- continue;
562
- }
563
- let names: readonly string[];
564
- try {
565
- names = host
566
- .readDirectory(dir)
567
- .filter((entry) => !entry.directory && configurationModuleForm(entry.name) !== undefined)
568
- .map((entry) => entry.name)
569
- .sort();
570
- } catch {
363
+ for (const dir of [...dirs].sort(bytewise)) {
364
+ if (!manifestHeld(dir)) {
571
365
  continue;
572
366
  }
367
+ const names = filesIn(host, dir, (name) => configurationModuleForm(name) !== undefined);
573
368
  pending.push(...names.map((name) => ({ path: joinPath(dir, name), manifestDir: dir })));
574
369
  }
575
370
  const found = new Map<string, { file: SourceFile; manifestDirs: string[] }>();
@@ -607,17 +402,12 @@ function outsideModules(
607
402
 
608
403
  /** Every dependency the manifest in one directory declares, or none where it holds none to read. */
609
404
  export function declaredIn(host: Host, dir: string): readonly string[] {
610
- let value: unknown;
611
- try {
612
- value = JSON.parse(host.readFile(joinPath(dir, MANIFEST)));
613
- } catch {
614
- return [];
615
- }
616
- if (!isRecord(value)) {
405
+ const value = manifestAt(host, dir);
406
+ if (value === undefined) {
617
407
  return [];
618
408
  }
619
409
  const names = new Set<string>();
620
- for (const member of DEPENDENCY_MEMBERS) {
410
+ for (const member of DEPENDENCY_SECTIONS) {
621
411
  const section = value[member];
622
412
  if (isRecord(section)) {
623
413
  Object.keys(section).forEach((name) => names.add(name));
@@ -638,7 +428,7 @@ export function dependenciesNamed(text: string, declared: readonly string[]): re
638
428
  * none.
639
429
  */
640
430
  export function filesNamedBy(files: SourceFiles, dir: string, text: string): readonly SourceFile[] {
641
- if (text === "" || text.startsWith("/") || /[*?[{]/u.test(text)) {
431
+ if (text === "" || isAbsolutePath(text) || /[*?[{]/u.test(text)) {
642
432
  return [];
643
433
  }
644
434
  const path = resolvePath(dir, text);