@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
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The module specifiers of the JavaScript files a configuration does not check, read for what
3
+ * the compiler leaves unresolved. Unchecked JavaScript reports no unfound module, and a
4
+ * JavaScript file may name a file that is absent on purpose, so an unresolved one is no failure
5
+ * of the program: a relative one is noted, and only a configuration whose imported dependencies
6
+ * are none of them installed fails, because its program is not the one the project runs.
7
+ */
8
+ import { isBinaryExpression, isCallExpression, isParenthesizedExpression, isStringLiteralLikeNode, isTryStatement, SyntaxKind, } from "@typescript/native/ast";
9
+ import { packageOfSpecifier } from "../dependencies.js";
10
+ import { readManifestAt } from "../fs/manifest.js";
11
+ import { JAVASCRIPT_FILE } from "../javascript-file.js";
12
+ import { ancestors, dirnamePath, isRelativeSpecifier, relativePath, resolvePath, } from "../paths.js";
13
+ import { renderPosition } from "../position.js";
14
+ import { batched } from "../session.js";
15
+ import { dependencySpecifiers } from "./module-lookup.js";
16
+ /**
17
+ * Whether one specifier is loaded optionally: written inside a `try` block, or as a call whose
18
+ * result an `||` or a `??` falls back from, so the program is written for its absence.
19
+ */
20
+ function optional(node) {
21
+ const call = node.parent;
22
+ let operand = call;
23
+ let parent = call.parent;
24
+ while (parent !== undefined && isParenthesizedExpression(parent)) {
25
+ operand = parent;
26
+ parent = parent.parent;
27
+ }
28
+ if (isCallExpression(call) &&
29
+ parent !== undefined &&
30
+ isBinaryExpression(parent) &&
31
+ parent.left === operand &&
32
+ (parent.operatorToken.kind === SyntaxKind.BarBarToken ||
33
+ parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken)) {
34
+ return true;
35
+ }
36
+ for (let at = node; at !== undefined; at = at.parent) {
37
+ const above = at.parent;
38
+ if (above !== undefined && isTryStatement(above) && above.tryBlock === at) {
39
+ return true;
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+ /**
45
+ * Whether a manifest at or above `dir`, no higher than `root`, declares the package `name`. A
46
+ * manifest that does not parse or cannot be read ends the search, because what it declares is
47
+ * unanswered and a manifest above it is another package's.
48
+ */
49
+ function declared(host, dir, root, name) {
50
+ for (const at of ancestors(dir, root)) {
51
+ const read = readManifestAt(host, at);
52
+ if (read.kind === "malformed" || read.kind === "unread") {
53
+ return false;
54
+ }
55
+ if (read.kind === "read" && dependencySpecifiers(read.manifest, name).length > 0) {
56
+ return true;
57
+ }
58
+ }
59
+ return false;
60
+ }
61
+ /**
62
+ * The specifiers of every JavaScript file of `project`, where its options do not check
63
+ * JavaScript, each asked of the compiler in batched round trips. A relative one naming a path
64
+ * below one of the run's output directories names build output, which a build writes later.
65
+ */
66
+ export function readSpecifiers(engine, host, project, { checked, root, outputs }) {
67
+ if (checked) {
68
+ return { unresolved: [], uninstalled: undefined };
69
+ }
70
+ const usages = [];
71
+ for (const file of project.ownSourceFiles()) {
72
+ if (JAVASCRIPT_FILE.test(file.fileName)) {
73
+ for (const node of file.imports) {
74
+ if (isStringLiteralLikeNode(node) && !optional(node)) {
75
+ usages.push({ file, node });
76
+ }
77
+ }
78
+ }
79
+ }
80
+ const answers = batched(engine, usages, ({ file, node }) => project.program.getResolvedModuleFromModuleSpecifier.gen(node, file.fileName));
81
+ const unresolved = [];
82
+ let missing;
83
+ let installed = false;
84
+ for (const [at, usage] of usages.entries()) {
85
+ const resolved = (answers[at]?.resolvedFileName ?? "") !== "";
86
+ const specifier = usage.node.text;
87
+ const name = packageOfSpecifier(specifier);
88
+ if (isRelativeSpecifier(specifier)) {
89
+ const named = resolvePath(dirnamePath(usage.file.fileName), specifier);
90
+ if (!resolved && !outputs.some((dir) => relativePath(dir, named) !== undefined)) {
91
+ unresolved.push({
92
+ specifier,
93
+ position: renderPosition(usage.file, root, usage.node.getStart()),
94
+ });
95
+ }
96
+ }
97
+ else if (name !== undefined && declared(host, dirnamePath(usage.file.fileName), root, name)) {
98
+ installed ||= resolved;
99
+ missing ??= resolved ? undefined : usage;
100
+ }
101
+ }
102
+ if (installed || missing === undefined) {
103
+ return { unresolved, uninstalled: undefined };
104
+ }
105
+ const { path, line } = renderPosition(missing.file, root, missing.node.getStart());
106
+ return {
107
+ unresolved,
108
+ uninstalled: {
109
+ failureClass: "missing-module",
110
+ detail: `${path}:${String(line)}: ${path} imports ${JSON.stringify(missing.node.text)}, a declared dependency, and no dependency the configuration's JavaScript files import is installed: run the package manager's install`,
111
+ },
112
+ };
113
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * The programs a run forms for the JavaScript files no compiler configuration lists: one per
3
+ * package, over the files git would track that are no build output, each written as a
4
+ * configuration only the snapshot holds, with the module system of the runtime its package
5
+ * is written for.
6
+ */
7
+ import { readCommands } from "../commands/read.js";
8
+ import { CONVENTION_ROWS } from "../entries/convention-rows.js";
9
+ import { holdsManifest, MANIFEST, readManifestAt } from "../fs/manifest.js";
10
+ import { filesBelow } from "../fs/tree.js";
11
+ import { JAVASCRIPT_FILE, minifiedBy, minifiedByName } from "../javascript-file.js";
12
+ import { isRecord } from "../json-document.js";
13
+ import { manifestCommands } from "../roots/manifest.js";
14
+ import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.js";
15
+ import { bytewise } from "../text/compare.js";
16
+ import { writtenPath } from "./workspace-programs.js";
17
+ /** The name a package's program is written beside, made free by {@link writtenPath}. */
18
+ const GROUP_CONFIGURATION = "jsconfig.json";
19
+ /**
20
+ * The options of a formed program before its runtime is chosen: unchecked JavaScript, no
21
+ * emit, no installed package's JavaScript, which is not the target's code and grows the
22
+ * program with the depth of `node_modules`, and every type package visible.
23
+ */
24
+ const FORMED_OPTIONS = {
25
+ allowJs: true,
26
+ checkJs: false,
27
+ noEmit: true,
28
+ skipLibCheck: true,
29
+ maxNodeModuleJsDepth: 0,
30
+ target: "esnext",
31
+ jsx: "preserve",
32
+ resolveJsonModule: true,
33
+ };
34
+ /** Whether one file is minified build output; one that cannot be read is left to the compiler. */
35
+ function minifiedFile(host, file) {
36
+ if (minifiedByName(file) !== undefined) {
37
+ return true;
38
+ }
39
+ try {
40
+ return minifiedBy(file, host.readFile(file)) !== undefined;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ /**
47
+ * The JavaScript files below `root` a program may be formed over: none in a skipped
48
+ * directory, none git ignores, none minified, none `context` covers and none below one of
49
+ * its output directories. A convention row's generated directory leaves out more, once the
50
+ * rows are read: {@link formedGroups}.
51
+ */
52
+ export function candidateFiles(host, root, { covered, outputs, ignored }) {
53
+ return filesBelow(host, root, (name) => JAVASCRIPT_FILE.test(name))
54
+ .map((path) => joinPath(root, path))
55
+ .filter((file) => !covered.has(file) &&
56
+ !outputs.some((dir) => relativePath(dir, file) !== undefined) &&
57
+ !ignored(file) &&
58
+ !minifiedFile(host, file));
59
+ }
60
+ /**
61
+ * The candidates below `root` grouped by package, in directory order, less every file below a
62
+ * directory an applied row of `conventions` names as generated: each file belongs to the
63
+ * nearest directory at or above it, up to `root`, that holds a `package.json`, a manifest that
64
+ * does not parse included, and to `root` where none does.
65
+ */
66
+ export function formedGroups(host, root, candidates, conventions) {
67
+ const generated = conventions.generated.map(({ dir, below }) => joinPath(dir, below));
68
+ const groups = new Map();
69
+ for (const file of candidates) {
70
+ if (generated.some((dir) => relativePath(dir, file) !== undefined)) {
71
+ continue;
72
+ }
73
+ const dir = packageOf(host, root, file);
74
+ groups.set(dir, [...(groups.get(dir) ?? []), file]);
75
+ }
76
+ return [...groups]
77
+ .sort(([a], [b]) => bytewise(a, b))
78
+ .map(([dir, files]) => ({
79
+ dir,
80
+ manifest: readManifestAt(host, dir),
81
+ files: files.sort(bytewise),
82
+ }));
83
+ }
84
+ /** The directory whose `package.json` groups one file: the nearest at or above it, up to `root`. */
85
+ export function packageOf(host, root, file) {
86
+ return ancestors(dirnamePath(file), root).find((at) => holdsManifest(host, at)) ?? root;
87
+ }
88
+ const RUNTIME_OPTIONS = {
89
+ bundler: { module: "preserve", moduleResolution: "bundler" },
90
+ node: { module: "nodenext", moduleResolution: "nodenext" },
91
+ };
92
+ /** Whether one configuration is a program the run formed to resolve its modules as Node does. */
93
+ export function formedForNode(configuration) {
94
+ const options = configuration.written?.["compilerOptions"];
95
+ return isRecord(options) && options["moduleResolution"] === RUNTIME_OPTIONS.node.moduleResolution;
96
+ }
97
+ /** The manifest members that say a package is written for Node. */
98
+ const NODE_MEMBERS = ["main", "exports", "bin", "type"];
99
+ /**
100
+ * Whether one manifest says its package runs under Node: a Node member, `engines.node`
101
+ * included, or a command string of it that runs a file with `node`, as `commands/read.ts` reads it.
102
+ */
103
+ function writtenForNode(host, dir, manifest) {
104
+ const { engines } = manifest;
105
+ return (NODE_MEMBERS.some((member) => manifest[member] !== undefined) ||
106
+ (isRecord(engines) && engines["node"] !== undefined) ||
107
+ manifestCommands(host, dir, manifest).some(({ command }) => readCommands(command, dir).runs.some((run) => run.runtime === "node")));
108
+ }
109
+ /**
110
+ * The manifests, by path as `conventions` names them, an applied row of a tool that bundles
111
+ * applies through.
112
+ */
113
+ export function bundlingManifests(conventions) {
114
+ return new Set(conventions.applied
115
+ .filter((one) => CONVENTION_ROWS.some((row) => row.name === one.name && row.bundles === true))
116
+ .map((one) => one.manifest));
117
+ }
118
+ /**
119
+ * Each group's program, given the module system of the runtime its package is written for: a
120
+ * bundler's where a row of a tool that bundles applies through the group's manifest or the
121
+ * root's, else Node's where its manifest says the package runs under Node or a command string of
122
+ * it runs a file with `node`, under which a file's
123
+ * extension and its package's `type` decide its module format, else a bundler's, which reads a
124
+ * file with no module syntax as a classic script, as a browser loads it.
125
+ */
126
+ export function formedPrograms(engine, host, groups, { root, origin, bundling, idOf }) {
127
+ return groups.map((group) => {
128
+ const manifest = group.manifest.kind === "absent" ? undefined : joinPath(group.dir, MANIFEST);
129
+ const below = manifest === undefined ? undefined : relativePath(root, manifest);
130
+ const runtime = !bundling.has(MANIFEST) &&
131
+ (below === undefined || !bundling.has(below)) &&
132
+ group.manifest.kind === "read" &&
133
+ writtenForNode(host, group.dir, group.manifest.manifest)
134
+ ? "node"
135
+ : "bundler";
136
+ const configFile = writtenPath(host, joinPath(group.dir, GROUP_CONFIGURATION));
137
+ const written = {
138
+ compilerOptions: { ...FORMED_OPTIONS, ...RUNTIME_OPTIONS[runtime] },
139
+ files: group.files,
140
+ };
141
+ return {
142
+ group,
143
+ configuration: {
144
+ id: idOf(manifest),
145
+ configFile,
146
+ origin,
147
+ parsed: engine.parseConfigJson(written, configFile),
148
+ written,
149
+ },
150
+ };
151
+ });
152
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * The globals a test runner injects into every file it runs, which no import names: a
3
+ * Vitest configuration whose `test.globals` is `true` gives each test and each file it
4
+ * loads `describe`, `it`, `expect` and `vi` (https://vitest.dev/config/globals). A program
5
+ * analyzed without the runner's declarations of them reads every use as an error, so a
6
+ * configuration under such a runner is read with them; and a file that calls one is
7
+ * written for the runner, as one that imports it is.
8
+ */
9
+ import { isAsExpression, isBinaryExpression, isCallExpression, isExportAssignment, isExpressionStatement, isIdentifier, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, SyntaxKind, } from "@typescript/native/ast";
10
+ import { isRecord } from "../json-document.js";
11
+ import { ancestors, dirnamePath, joinPath } from "../paths.js";
12
+ import { UNANSWERED } from "../query.js";
13
+ import { filesIn } from "../fs/tree.js";
14
+ import { holdsManifest, INSTALLED_PACKAGES } from "../fs/manifest.js";
15
+ import { isTargetConfiguration } from "./discover.js";
16
+ /** The test runner whose configuration injects the globals, and the `types` entry declaring them. */
17
+ export const GLOBALS_RUNNER = "vitest";
18
+ const GLOBALS_TYPES = "vitest/globals";
19
+ /** The configuration files the runner reads its settings from, by name. */
20
+ const RUNNER_CONFIG = /^(?:vitest|vite)\.config\.(?:js|mjs|cjs|ts|mts|cts)$/u;
21
+ /** The globals `vitest/globals` declares that a test or a helper calls or reads a member of. */
22
+ const GLOBAL_NAMES = new Set([
23
+ "afterAll",
24
+ "afterEach",
25
+ "assert",
26
+ "assertType",
27
+ "beforeAll",
28
+ "beforeEach",
29
+ "bench",
30
+ "describe",
31
+ "expect",
32
+ "expectTypeOf",
33
+ "it",
34
+ "onTestFailed",
35
+ "onTestFinished",
36
+ "suite",
37
+ "test",
38
+ "vi",
39
+ "vitest",
40
+ ]);
41
+ /** The expression one wrapper that changes no value holds, and a call's first argument. */
42
+ function configObject(node) {
43
+ let at = node;
44
+ while (at !== undefined) {
45
+ if (isParenthesizedExpression(at) || isAsExpression(at) || isSatisfiesExpression(at)) {
46
+ at = at.expression;
47
+ }
48
+ else if (isCallExpression(at)) {
49
+ at = at.arguments[0];
50
+ }
51
+ else {
52
+ return at;
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+ /** The value one object literal writes for one member as `name: value`. */
58
+ function member(object, name) {
59
+ if (object === undefined || !isObjectLiteralExpression(object)) {
60
+ return undefined;
61
+ }
62
+ for (const property of object.properties) {
63
+ if (isPropertyAssignment(property) &&
64
+ isIdentifier(property.name) &&
65
+ property.name.text === name) {
66
+ return configObject(property.initializer);
67
+ }
68
+ }
69
+ return undefined;
70
+ }
71
+ /** Whether one runner configuration's default export sets `test.globals` to `true`. */
72
+ function setsGlobals(file) {
73
+ for (const statement of file.statements) {
74
+ let exported;
75
+ if (isExportAssignment(statement)) {
76
+ exported = statement.expression;
77
+ }
78
+ else if (isExpressionStatement(statement) && isBinaryExpression(statement.expression)) {
79
+ const { left, operatorToken, right } = statement.expression;
80
+ if (operatorToken.kind === SyntaxKind.EqualsToken &&
81
+ isPropertyAccessExpression(left) &&
82
+ isIdentifier(left.expression) &&
83
+ left.expression.text === "module" &&
84
+ isIdentifier(left.name) &&
85
+ left.name.text === "exports") {
86
+ exported = right;
87
+ }
88
+ }
89
+ const object = exported === undefined ? undefined : configObject(exported);
90
+ const globals = member(member(object, "test"), "globals");
91
+ if (globals?.kind === SyntaxKind.TrueKeyword) {
92
+ return true;
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+ /** Whether the runner's configuration in one manifest's directory injects the globals. */
98
+ function injectsGlobals(host, parse, dir) {
99
+ return filesIn(host, dir, (name) => RUNNER_CONFIG.test(name)).some((name) => {
100
+ const path = joinPath(dir, name);
101
+ try {
102
+ return setsGlobals(parse(path, host.readFile(path)));
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ });
108
+ }
109
+ /** Whether a file declaring the globals is installed where the configuration resolves packages from. */
110
+ function globalsInstalled(host, configFile) {
111
+ return ancestors(dirnamePath(configFile)).some((dir) => host.kindOf(joinPath(dir, INSTALLED_PACKAGES, GLOBALS_RUNNER, "globals.d.ts")) === "file");
112
+ }
113
+ /** The directory of the manifest nearest one configuration file, at or above its own. */
114
+ function manifestDir(host, configFile) {
115
+ return ancestors(dirnamePath(configFile)).find((dir) => holdsManifest(host, dir));
116
+ }
117
+ function typesOf(value) {
118
+ return Array.isArray(value) && value.every((one) => typeof one === "string") ? value : undefined;
119
+ }
120
+ /**
121
+ * The plans with the globals' declarations added to the `types` of each target configuration
122
+ * whose nearest manifest's runner configuration injects them and that can resolve them.
123
+ */
124
+ export function testGlobals(host, parse, plans) {
125
+ const injects = new Map();
126
+ return plans.map((plan) => {
127
+ const dir = manifestDir(host, plan.configFile);
128
+ if (!isTargetConfiguration(plan) ||
129
+ dir === undefined ||
130
+ !globalsInstalled(host, plan.configFile)) {
131
+ return plan;
132
+ }
133
+ if (!injects.has(dir)) {
134
+ injects.set(dir, injectsGlobals(host, parse, dir));
135
+ }
136
+ const base = typesOf(plan.options.types) ?? [];
137
+ const { build } = plan;
138
+ if (injects.get(dir) !== true) {
139
+ return plan;
140
+ }
141
+ if (build.kind === "program") {
142
+ const listed = typesOf(build.params.compilerOptions.types) ?? base;
143
+ return listed.includes(GLOBALS_TYPES)
144
+ ? plan
145
+ : {
146
+ ...plan,
147
+ build: {
148
+ kind: "program",
149
+ params: {
150
+ ...build.params,
151
+ compilerOptions: {
152
+ ...build.params.compilerOptions,
153
+ types: [...listed, GLOBALS_TYPES],
154
+ },
155
+ },
156
+ },
157
+ };
158
+ }
159
+ const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
160
+ const held = written["compilerOptions"];
161
+ const options = isRecord(held) ? held : {};
162
+ const listed = typesOf(options["types"]) ?? base;
163
+ return listed.includes(GLOBALS_TYPES)
164
+ ? plan
165
+ : {
166
+ ...plan,
167
+ build: {
168
+ kind: "configuration",
169
+ value: {
170
+ ...written,
171
+ compilerOptions: { ...options, types: [...listed, GLOBALS_TYPES] },
172
+ },
173
+ },
174
+ };
175
+ });
176
+ }
177
+ /**
178
+ * Whether one file names a global the runner injects, which is how a file written for the
179
+ * runner's globals reads: a call of one of the names or a read of a member of it that
180
+ * resolves to a declaration outside the project's own files, the runner's declaration
181
+ * file. A name the file binds, imported, declared or a parameter, resolves to its own.
182
+ */
183
+ export function namesTestGlobals(project, file) {
184
+ const named = [];
185
+ const visit = (node) => {
186
+ const callee = isCallExpression(node)
187
+ ? node.expression
188
+ : isPropertyAccessExpression(node)
189
+ ? node.expression
190
+ : undefined;
191
+ if (callee !== undefined && isIdentifier(callee) && GLOBAL_NAMES.has(callee.text)) {
192
+ named.push(callee);
193
+ }
194
+ node.forEachChild(visit);
195
+ };
196
+ file.forEachChild(visit);
197
+ if (named.length === 0) {
198
+ return false;
199
+ }
200
+ const own = project.ownPaths();
201
+ return project
202
+ .symbolsAt(named.map((node) => project.handle(node)))
203
+ .some((symbol) => symbol === UNANSWERED ||
204
+ (symbol !== undefined &&
205
+ symbol.declarations.length > 0 &&
206
+ symbol.declarations.every((handle) => !own.has(handle.path))));
207
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The test files a derived matrix holds although no configuration's file list names them.
3
+ * The test runner compiles such a file with the options of the nearest compiler
4
+ * configuration at or above it, so the file joins that configuration's program as a file
5
+ * its list names, unless a `package.json` below that configuration's directory makes the
6
+ * file another package's, which its own test runner compiles.
7
+ */
8
+ import { sourcePaths } from "../file-facts.js";
9
+ import { ancestors, dirnamePath, joinPath } from "../paths.js";
10
+ import { bytewise } from "../text/compare.js";
11
+ import { holdsManifest } from "../fs/manifest.js";
12
+ const PREFERRED = "/tsconfig.json";
13
+ /** The configurations of one directory in the order a file joins them: `tsconfig.json` first. */
14
+ function byPreference(a, b) {
15
+ const first = a.endsWith(PREFERRED) ? 0 : 1;
16
+ const second = b.endsWith(PREFERRED) ? 0 : 1;
17
+ return first - second || bytewise(a, b);
18
+ }
19
+ /**
20
+ * Per configuration of `configurations`, the absolute paths of the test files that join it:
21
+ * each file below `root` a pattern of `patterns` names, that no configuration's file list
22
+ * holds, joins the configuration nearest at or above its directory when no `package.json`
23
+ * sits between them.
24
+ */
25
+ export function joinedTestFiles(host, root, configurations, patterns) {
26
+ const listed = new Set();
27
+ const byDir = new Map();
28
+ for (const { configFile, parsed } of configurations) {
29
+ parsed.fileNames.forEach((name) => listed.add(name));
30
+ const dir = dirnamePath(configFile);
31
+ byDir.set(dir, [...(byDir.get(dir) ?? []), configFile].sort(byPreference));
32
+ }
33
+ const joins = new Map();
34
+ for (const path of sourcePaths(host, root)) {
35
+ const file = joinPath(root, path);
36
+ if (listed.has(file) || !patterns.some((pattern) => pattern.test(path))) {
37
+ continue;
38
+ }
39
+ for (const dir of ancestors(dirnamePath(file), root)) {
40
+ const [nearest] = byDir.get(dir) ?? [];
41
+ if (nearest !== undefined) {
42
+ joins.set(nearest, [...(joins.get(nearest) ?? []), file]);
43
+ break;
44
+ }
45
+ if (holdsManifest(host, dir)) {
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ return joins;
51
+ }
52
+ /**
53
+ * The plans with each joined test file added to the configuration it joins: to a described
54
+ * program's root files, or to the file list of a configuration only the snapshot holds, which
55
+ * lists every file the configuration lists and the joined ones.
56
+ */
57
+ export function joinedTests(plans, joins) {
58
+ return plans.map((plan) => {
59
+ const files = joins.get(plan.configFile);
60
+ const { build } = plan;
61
+ if (files === undefined) {
62
+ return plan;
63
+ }
64
+ if (build.kind === "program") {
65
+ return {
66
+ ...plan,
67
+ build: {
68
+ kind: "program",
69
+ params: { ...build.params, rootFiles: [...(build.params.rootFiles ?? []), ...files] },
70
+ },
71
+ };
72
+ }
73
+ const written = build.kind === "configuration" ? build.value : { extends: plan.configFile };
74
+ return {
75
+ ...plan,
76
+ build: {
77
+ kind: "configuration",
78
+ value: { ...written, files: [...plan.parsed.fileNames, ...files], include: [] },
79
+ },
80
+ };
81
+ });
82
+ }
@@ -6,8 +6,9 @@
6
6
  * workspace imports, so only its commands are entry points.
7
7
  */
8
8
  import { emittedFrom } from "./emit-map.js";
9
- import { readManifest } from "./manifest.js";
10
- import { joinPath, relativePath } from "./paths.js";
9
+ import { readManifest } from "../roots/manifest.js";
10
+ import { joinPath, relativePath } from "../paths.js";
11
+ import { MANIFEST } from "../fs/manifest.js";
11
12
  /** The one character a subpath pattern of a manifest's `exports` holds. */
12
13
  const SUBPATH_WILDCARD = "*";
13
14
  /** The paths one written target stands for in its member's sources, itself included. */
@@ -53,8 +54,7 @@ export function memberEntries(host, resolver, targetRoot) {
53
54
  return [];
54
55
  }
55
56
  const manifest = readManifest(host, member.dir);
56
- const where = relativePath(targetRoot, joinPath(member.dir, "package.json")) ??
57
- joinPath(member.dir, "package.json");
57
+ const where = relativePath(targetRoot, joinPath(member.dir, MANIFEST)) ?? joinPath(member.dir, MANIFEST);
58
58
  const kept = manifest.entries.flatMap((entry) => {
59
59
  const exported = entry.member.startsWith("exports");
60
60
  if (member.private && exported) {