@endora-commerce/cli 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/bin/endora.d.ts +28 -0
  4. package/dist/bin/endora.d.ts.map +1 -0
  5. package/dist/bin/endora.js +926 -0
  6. package/dist/bin/endora.js.map +1 -0
  7. package/dist/check/estate.d.ts +189 -0
  8. package/dist/check/estate.d.ts.map +1 -0
  9. package/dist/check/estate.js +1037 -0
  10. package/dist/check/estate.js.map +1 -0
  11. package/dist/check/hosts.d.ts +25 -0
  12. package/dist/check/hosts.d.ts.map +1 -0
  13. package/dist/check/hosts.js +1347 -0
  14. package/dist/check/hosts.js.map +1 -0
  15. package/dist/check/index.d.ts +60 -0
  16. package/dist/check/index.d.ts.map +1 -0
  17. package/dist/check/index.js +111 -0
  18. package/dist/check/index.js.map +1 -0
  19. package/dist/check/layout.d.ts +136 -0
  20. package/dist/check/layout.d.ts.map +1 -0
  21. package/dist/check/layout.js +262 -0
  22. package/dist/check/layout.js.map +1 -0
  23. package/dist/check/ledger.d.ts +98 -0
  24. package/dist/check/ledger.d.ts.map +1 -0
  25. package/dist/check/ledger.js +173 -0
  26. package/dist/check/ledger.js.map +1 -0
  27. package/dist/check/peer-owners.d.ts +116 -0
  28. package/dist/check/peer-owners.d.ts.map +1 -0
  29. package/dist/check/peer-owners.js +225 -0
  30. package/dist/check/peer-owners.js.map +1 -0
  31. package/dist/check/report.d.ts +33 -0
  32. package/dist/check/report.d.ts.map +1 -0
  33. package/dist/check/report.js +107 -0
  34. package/dist/check/report.js.map +1 -0
  35. package/dist/check/run.d.ts +147 -0
  36. package/dist/check/run.d.ts.map +1 -0
  37. package/dist/check/run.js +111 -0
  38. package/dist/check/run.js.map +1 -0
  39. package/dist/checks.d.ts +17 -0
  40. package/dist/checks.d.ts.map +1 -0
  41. package/dist/checks.js +17 -0
  42. package/dist/checks.js.map +1 -0
  43. package/dist/dev/index.d.ts +83 -0
  44. package/dist/dev/index.d.ts.map +1 -0
  45. package/dist/dev/index.js +298 -0
  46. package/dist/dev/index.js.map +1 -0
  47. package/dist/generate/divergence.d.ts +38 -0
  48. package/dist/generate/divergence.d.ts.map +1 -0
  49. package/dist/generate/divergence.js +237 -0
  50. package/dist/generate/divergence.js.map +1 -0
  51. package/dist/generate/index.d.ts +90 -0
  52. package/dist/generate/index.d.ts.map +1 -0
  53. package/dist/generate/index.js +369 -0
  54. package/dist/generate/index.js.map +1 -0
  55. package/dist/index.d.ts +23 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +35 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/inputs/declaration.d.ts +18 -0
  60. package/dist/inputs/declaration.d.ts.map +1 -0
  61. package/dist/inputs/declaration.js +64 -0
  62. package/dist/inputs/declaration.js.map +1 -0
  63. package/dist/inputs/env-file.d.ts +73 -0
  64. package/dist/inputs/env-file.d.ts.map +1 -0
  65. package/dist/inputs/env-file.js +134 -0
  66. package/dist/inputs/env-file.js.map +1 -0
  67. package/dist/inputs/prompt.d.ts +21 -0
  68. package/dist/inputs/prompt.d.ts.map +1 -0
  69. package/dist/inputs/prompt.js +59 -0
  70. package/dist/inputs/prompt.js.map +1 -0
  71. package/dist/inputs/resolve.d.ts +163 -0
  72. package/dist/inputs/resolve.d.ts.map +1 -0
  73. package/dist/inputs/resolve.js +290 -0
  74. package/dist/inputs/resolve.js.map +1 -0
  75. package/dist/install/host.d.ts +27 -0
  76. package/dist/install/host.d.ts.map +1 -0
  77. package/dist/install/host.js +90 -0
  78. package/dist/install/host.js.map +1 -0
  79. package/dist/install/index.d.ts +173 -0
  80. package/dist/install/index.d.ts.map +1 -0
  81. package/dist/install/index.js +793 -0
  82. package/dist/install/index.js.map +1 -0
  83. package/dist/install/wizard.d.ts +144 -0
  84. package/dist/install/wizard.d.ts.map +1 -0
  85. package/dist/install/wizard.js +362 -0
  86. package/dist/install/wizard.js.map +1 -0
  87. package/dist/lib/admin-artefacts.d.ts +70 -0
  88. package/dist/lib/admin-artefacts.d.ts.map +1 -0
  89. package/dist/lib/admin-artefacts.js +354 -0
  90. package/dist/lib/admin-artefacts.js.map +1 -0
  91. package/dist/lib/admin-surfaces.d.ts +298 -0
  92. package/dist/lib/admin-surfaces.d.ts.map +1 -0
  93. package/dist/lib/admin-surfaces.js +669 -0
  94. package/dist/lib/admin-surfaces.js.map +1 -0
  95. package/dist/lib/delegated-composer.d.ts +85 -0
  96. package/dist/lib/delegated-composer.d.ts.map +1 -0
  97. package/dist/lib/delegated-composer.js +241 -0
  98. package/dist/lib/delegated-composer.js.map +1 -0
  99. package/dist/lib/divergence-artefacts.d.ts +305 -0
  100. package/dist/lib/divergence-artefacts.d.ts.map +1 -0
  101. package/dist/lib/divergence-artefacts.js +828 -0
  102. package/dist/lib/divergence-artefacts.js.map +1 -0
  103. package/dist/lib/divergence.d.ts +337 -0
  104. package/dist/lib/divergence.d.ts.map +1 -0
  105. package/dist/lib/divergence.js +1005 -0
  106. package/dist/lib/divergence.js.map +1 -0
  107. package/dist/lib/docs-artefacts.d.ts +395 -0
  108. package/dist/lib/docs-artefacts.d.ts.map +1 -0
  109. package/dist/lib/docs-artefacts.js +781 -0
  110. package/dist/lib/docs-artefacts.js.map +1 -0
  111. package/dist/lib/emitted-exports.d.ts +21 -0
  112. package/dist/lib/emitted-exports.d.ts.map +1 -0
  113. package/dist/lib/emitted-exports.js +96 -0
  114. package/dist/lib/emitted-exports.js.map +1 -0
  115. package/dist/lib/emitted-freshness.d.ts +112 -0
  116. package/dist/lib/emitted-freshness.d.ts.map +1 -0
  117. package/dist/lib/emitted-freshness.js +288 -0
  118. package/dist/lib/emitted-freshness.js.map +1 -0
  119. package/dist/lib/entity-index-artefact.d.ts +95 -0
  120. package/dist/lib/entity-index-artefact.d.ts.map +1 -0
  121. package/dist/lib/entity-index-artefact.js +210 -0
  122. package/dist/lib/entity-index-artefact.js.map +1 -0
  123. package/dist/lib/instance-build-inputs.d.ts +108 -0
  124. package/dist/lib/instance-build-inputs.d.ts.map +1 -0
  125. package/dist/lib/instance-build-inputs.js +165 -0
  126. package/dist/lib/instance-build-inputs.js.map +1 -0
  127. package/dist/lib/module-docs.d.ts +473 -0
  128. package/dist/lib/module-docs.d.ts.map +1 -0
  129. package/dist/lib/module-docs.js +711 -0
  130. package/dist/lib/module-docs.js.map +1 -0
  131. package/dist/lib/module-package-subpaths.d.ts +56 -0
  132. package/dist/lib/module-package-subpaths.d.ts.map +1 -0
  133. package/dist/lib/module-package-subpaths.js +223 -0
  134. package/dist/lib/module-package-subpaths.js.map +1 -0
  135. package/dist/lib/module-packages.d.ts +200 -0
  136. package/dist/lib/module-packages.d.ts.map +1 -0
  137. package/dist/lib/module-packages.js +580 -0
  138. package/dist/lib/module-packages.js.map +1 -0
  139. package/dist/lib/module-population.d.ts +129 -0
  140. package/dist/lib/module-population.d.ts.map +1 -0
  141. package/dist/lib/module-population.js +172 -0
  142. package/dist/lib/module-population.js.map +1 -0
  143. package/dist/lib/module-roots.d.ts +337 -0
  144. package/dist/lib/module-roots.d.ts.map +1 -0
  145. package/dist/lib/module-roots.js +586 -0
  146. package/dist/lib/module-roots.js.map +1 -0
  147. package/dist/lib/nested-checkouts.d.ts +33 -0
  148. package/dist/lib/nested-checkouts.d.ts.map +1 -0
  149. package/dist/lib/nested-checkouts.js +160 -0
  150. package/dist/lib/nested-checkouts.js.map +1 -0
  151. package/dist/lib/platform-root.d.ts +43 -0
  152. package/dist/lib/platform-root.d.ts.map +1 -0
  153. package/dist/lib/platform-root.js +134 -0
  154. package/dist/lib/platform-root.js.map +1 -0
  155. package/dist/lib/platform-surface.d.ts +235 -0
  156. package/dist/lib/platform-surface.d.ts.map +1 -0
  157. package/dist/lib/platform-surface.js +393 -0
  158. package/dist/lib/platform-surface.js.map +1 -0
  159. package/dist/lib/port-registrations.d.ts +223 -0
  160. package/dist/lib/port-registrations.d.ts.map +1 -0
  161. package/dist/lib/port-registrations.js +532 -0
  162. package/dist/lib/port-registrations.js.map +1 -0
  163. package/dist/lib/read-size.d.ts +154 -0
  164. package/dist/lib/read-size.d.ts.map +1 -0
  165. package/dist/lib/read-size.js +182 -0
  166. package/dist/lib/read-size.js.map +1 -0
  167. package/dist/lib/registration-owners.d.ts +79 -0
  168. package/dist/lib/registration-owners.d.ts.map +1 -0
  169. package/dist/lib/registration-owners.js +77 -0
  170. package/dist/lib/registration-owners.js.map +1 -0
  171. package/dist/lib/release-index.d.ts +53 -0
  172. package/dist/lib/release-index.d.ts.map +1 -0
  173. package/dist/lib/release-index.js +162 -0
  174. package/dist/lib/release-index.js.map +1 -0
  175. package/dist/lib/repeating-timers.d.ts +79 -0
  176. package/dist/lib/repeating-timers.d.ts.map +1 -0
  177. package/dist/lib/repeating-timers.js +189 -0
  178. package/dist/lib/repeating-timers.js.map +1 -0
  179. package/dist/lib/source-text.d.ts +34 -0
  180. package/dist/lib/source-text.d.ts.map +1 -0
  181. package/dist/lib/source-text.js +80 -0
  182. package/dist/lib/source-text.js.map +1 -0
  183. package/dist/lib/specifiers.d.ts +20 -0
  184. package/dist/lib/specifiers.d.ts.map +1 -0
  185. package/dist/lib/specifiers.js +130 -0
  186. package/dist/lib/specifiers.js.map +1 -0
  187. package/dist/lib/sql-tables.d.ts +166 -0
  188. package/dist/lib/sql-tables.d.ts.map +1 -0
  189. package/dist/lib/sql-tables.js +464 -0
  190. package/dist/lib/sql-tables.js.map +1 -0
  191. package/dist/lib/switchable-modules.d.ts +54 -0
  192. package/dist/lib/switchable-modules.d.ts.map +1 -0
  193. package/dist/lib/switchable-modules.js +104 -0
  194. package/dist/lib/switchable-modules.js.map +1 -0
  195. package/dist/lib/tailwind-sources.d.ts +136 -0
  196. package/dist/lib/tailwind-sources.d.ts.map +1 -0
  197. package/dist/lib/tailwind-sources.js +307 -0
  198. package/dist/lib/tailwind-sources.js.map +1 -0
  199. package/dist/lib/ui-layer.d.ts +54 -0
  200. package/dist/lib/ui-layer.d.ts.map +1 -0
  201. package/dist/lib/ui-layer.js +57 -0
  202. package/dist/lib/ui-layer.js.map +1 -0
  203. package/dist/lib/workspace-packages.d.ts +186 -0
  204. package/dist/lib/workspace-packages.d.ts.map +1 -0
  205. package/dist/lib/workspace-packages.js +351 -0
  206. package/dist/lib/workspace-packages.js.map +1 -0
  207. package/dist/new-instance/deploy.d.ts +211 -0
  208. package/dist/new-instance/deploy.d.ts.map +1 -0
  209. package/dist/new-instance/deploy.js +1381 -0
  210. package/dist/new-instance/deploy.js.map +1 -0
  211. package/dist/new-instance/docs-toolchain.d.ts +66 -0
  212. package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
  213. package/dist/new-instance/docs-toolchain.js +69 -0
  214. package/dist/new-instance/docs-toolchain.js.map +1 -0
  215. package/dist/new-instance/host.d.ts +124 -0
  216. package/dist/new-instance/host.d.ts.map +1 -0
  217. package/dist/new-instance/host.js +276 -0
  218. package/dist/new-instance/host.js.map +1 -0
  219. package/dist/new-instance/index.d.ts +118 -0
  220. package/dist/new-instance/index.d.ts.map +1 -0
  221. package/dist/new-instance/index.js +567 -0
  222. package/dist/new-instance/index.js.map +1 -0
  223. package/dist/new-instance/modules.d.ts +188 -0
  224. package/dist/new-instance/modules.d.ts.map +1 -0
  225. package/dist/new-instance/modules.js +392 -0
  226. package/dist/new-instance/modules.js.map +1 -0
  227. package/dist/new-instance/template.d.ts +505 -0
  228. package/dist/new-instance/template.d.ts.map +1 -0
  229. package/dist/new-instance/template.js +1886 -0
  230. package/dist/new-instance/template.js.map +1 -0
  231. package/dist/new-module/emit.d.ts +67 -0
  232. package/dist/new-module/emit.d.ts.map +1 -0
  233. package/dist/new-module/emit.js +1393 -0
  234. package/dist/new-module/emit.js.map +1 -0
  235. package/dist/new-module/host.d.ts +67 -0
  236. package/dist/new-module/host.d.ts.map +1 -0
  237. package/dist/new-module/host.js +224 -0
  238. package/dist/new-module/host.js.map +1 -0
  239. package/dist/new-module/index.d.ts +32 -0
  240. package/dist/new-module/index.d.ts.map +1 -0
  241. package/dist/new-module/index.js +193 -0
  242. package/dist/new-module/index.js.map +1 -0
  243. package/dist/new-module/spec.d.ts +188 -0
  244. package/dist/new-module/spec.d.ts.map +1 -0
  245. package/dist/new-module/spec.js +404 -0
  246. package/dist/new-module/spec.js.map +1 -0
  247. package/dist/new-module/text.d.ts +15 -0
  248. package/dist/new-module/text.d.ts.map +1 -0
  249. package/dist/new-module/text.js +22 -0
  250. package/dist/new-module/text.js.map +1 -0
  251. package/dist/new-storefront/dockerfile.d.ts +20 -0
  252. package/dist/new-storefront/dockerfile.d.ts.map +1 -0
  253. package/dist/new-storefront/dockerfile.js +131 -0
  254. package/dist/new-storefront/dockerfile.js.map +1 -0
  255. package/dist/new-storefront/gitignore.d.ts +23 -0
  256. package/dist/new-storefront/gitignore.d.ts.map +1 -0
  257. package/dist/new-storefront/gitignore.js +39 -0
  258. package/dist/new-storefront/gitignore.js.map +1 -0
  259. package/dist/new-storefront/index.d.ts +93 -0
  260. package/dist/new-storefront/index.d.ts.map +1 -0
  261. package/dist/new-storefront/index.js +329 -0
  262. package/dist/new-storefront/index.js.map +1 -0
  263. package/dist/new-storefront/npmrc.d.ts +98 -0
  264. package/dist/new-storefront/npmrc.d.ts.map +1 -0
  265. package/dist/new-storefront/npmrc.js +217 -0
  266. package/dist/new-storefront/npmrc.js.map +1 -0
  267. package/dist/new-storefront/reference.d.ts +189 -0
  268. package/dist/new-storefront/reference.d.ts.map +1 -0
  269. package/dist/new-storefront/reference.js +430 -0
  270. package/dist/new-storefront/reference.js.map +1 -0
  271. package/dist/new-storefront/rewrite.d.ts +171 -0
  272. package/dist/new-storefront/rewrite.d.ts.map +1 -0
  273. package/dist/new-storefront/rewrite.js +701 -0
  274. package/dist/new-storefront/rewrite.js.map +1 -0
  275. package/dist/release-index.json +284 -0
  276. package/dist/rules/action-route-permissions.d.ts +141 -0
  277. package/dist/rules/action-route-permissions.d.ts.map +1 -0
  278. package/dist/rules/action-route-permissions.js +556 -0
  279. package/dist/rules/action-route-permissions.js.map +1 -0
  280. package/dist/rules/bundle-pairing.d.ts +74 -0
  281. package/dist/rules/bundle-pairing.d.ts.map +1 -0
  282. package/dist/rules/bundle-pairing.js +281 -0
  283. package/dist/rules/bundle-pairing.js.map +1 -0
  284. package/dist/rules/channel-resolution.d.ts +17 -0
  285. package/dist/rules/channel-resolution.d.ts.map +1 -0
  286. package/dist/rules/channel-resolution.js +382 -0
  287. package/dist/rules/channel-resolution.js.map +1 -0
  288. package/dist/rules/command-coverage.d.ts +210 -0
  289. package/dist/rules/command-coverage.d.ts.map +1 -0
  290. package/dist/rules/command-coverage.js +714 -0
  291. package/dist/rules/command-coverage.js.map +1 -0
  292. package/dist/rules/container-imports.d.ts +60 -0
  293. package/dist/rules/container-imports.d.ts.map +1 -0
  294. package/dist/rules/container-imports.js +158 -0
  295. package/dist/rules/container-imports.js.map +1 -0
  296. package/dist/rules/default-language-prose.d.ts +212 -0
  297. package/dist/rules/default-language-prose.d.ts.map +1 -0
  298. package/dist/rules/default-language-prose.js +710 -0
  299. package/dist/rules/default-language-prose.js.map +1 -0
  300. package/dist/rules/diacritic-folds.d.ts +238 -0
  301. package/dist/rules/diacritic-folds.d.ts.map +1 -0
  302. package/dist/rules/diacritic-folds.js +681 -0
  303. package/dist/rules/diacritic-folds.js.map +1 -0
  304. package/dist/rules/entity-tenant-classification.d.ts +171 -0
  305. package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
  306. package/dist/rules/entity-tenant-classification.js +323 -0
  307. package/dist/rules/entity-tenant-classification.js.map +1 -0
  308. package/dist/rules/entry-presence.d.ts +142 -0
  309. package/dist/rules/entry-presence.d.ts.map +1 -0
  310. package/dist/rules/entry-presence.js +339 -0
  311. package/dist/rules/entry-presence.js.map +1 -0
  312. package/dist/rules/entry-scope.d.ts +91 -0
  313. package/dist/rules/entry-scope.d.ts.map +1 -0
  314. package/dist/rules/entry-scope.js +404 -0
  315. package/dist/rules/entry-scope.js.map +1 -0
  316. package/dist/rules/env-inputs.d.ts +222 -0
  317. package/dist/rules/env-inputs.d.ts.map +1 -0
  318. package/dist/rules/env-inputs.js +951 -0
  319. package/dist/rules/env-inputs.js.map +1 -0
  320. package/dist/rules/kernel-boundary.d.ts +37 -0
  321. package/dist/rules/kernel-boundary.d.ts.map +1 -0
  322. package/dist/rules/kernel-boundary.js +195 -0
  323. package/dist/rules/kernel-boundary.js.map +1 -0
  324. package/dist/rules/nul-bytes.d.ts +233 -0
  325. package/dist/rules/nul-bytes.d.ts.map +1 -0
  326. package/dist/rules/nul-bytes.js +332 -0
  327. package/dist/rules/nul-bytes.js.map +1 -0
  328. package/dist/rules/platform-surface.d.ts +479 -0
  329. package/dist/rules/platform-surface.d.ts.map +1 -0
  330. package/dist/rules/platform-surface.js +749 -0
  331. package/dist/rules/platform-surface.js.map +1 -0
  332. package/dist/rules/port-catches.d.ts +225 -0
  333. package/dist/rules/port-catches.d.ts.map +1 -0
  334. package/dist/rules/port-catches.js +1374 -0
  335. package/dist/rules/port-catches.js.map +1 -0
  336. package/dist/rules/port-shape.d.ts +213 -0
  337. package/dist/rules/port-shape.d.ts.map +1 -0
  338. package/dist/rules/port-shape.js +670 -0
  339. package/dist/rules/port-shape.js.map +1 -0
  340. package/dist/rules/queue-names.d.ts +108 -0
  341. package/dist/rules/queue-names.d.ts.map +1 -0
  342. package/dist/rules/queue-names.js +395 -0
  343. package/dist/rules/queue-names.js.map +1 -0
  344. package/dist/rules/singleton-identity.d.ts +205 -0
  345. package/dist/rules/singleton-identity.d.ts.map +1 -0
  346. package/dist/rules/singleton-identity.js +830 -0
  347. package/dist/rules/singleton-identity.js.map +1 -0
  348. package/dist/rules/subscribe-seam.d.ts +121 -0
  349. package/dist/rules/subscribe-seam.d.ts.map +1 -0
  350. package/dist/rules/subscribe-seam.js +594 -0
  351. package/dist/rules/subscribe-seam.js.map +1 -0
  352. package/dist/rules/transaction-context.d.ts +40 -0
  353. package/dist/rules/transaction-context.d.ts.map +1 -0
  354. package/dist/rules/transaction-context.js +294 -0
  355. package/dist/rules/transaction-context.js.map +1 -0
  356. package/package.json +59 -0
@@ -0,0 +1,464 @@
1
+ /**
2
+ * SQL table identifiers, read out of TypeScript sources through the compiler
3
+ * API (feature 077, D-87).
4
+ *
5
+ * `check-module-boundary.ts` polices one rule — a module does not reach into
6
+ * another module's internals — through two predicates, and this file is the
7
+ * syntax half of the second one. The first predicate reads import specifiers
8
+ * (`lib/specifiers.ts`); a raw `select … from another_module_table` names no
9
+ * specifier at all, compiles, runs, and returns rows.
10
+ *
11
+ * Two extractions live here, and both are deliberately **syntactic only**:
12
+ * ownership is decided by the check, which is the file that knows what a module
13
+ * is.
14
+ *
15
+ * - {@link sqlTableAccesses} — the table identifiers a source *uses*, through
16
+ * two recognition paths: a **statement** literal, and a knex query
17
+ * **builder** (issue #187).
18
+ * - {@link declaredTableNames} — the table names a source *declares*, from an
19
+ * `@Entity()` class or from `create table` DDL. Both sources are needed: an
20
+ * owner map built from entity classes alone maps 220 tables and misses every
21
+ * join table and every channel bridge, which is 39 of the 157 findings the
22
+ * D-87 sweep measured — including the one carrying a live defect.
23
+ *
24
+ * ## Why this reads literal **nodes** and never source text
25
+ *
26
+ * The first spike for D-87 was a regex over source text. It hallucinated a dozen
27
+ * tables — `every`, `bumps`, `used`, `path` — because an apostrophe in an
28
+ * English comment opens a string literal that runs to the next apostrophe, and
29
+ * the prose in between parses as SQL often enough to matter. Reading
30
+ * `ts.StringLiteral` / template-literal nodes removes comments from the
31
+ * population by construction rather than by an exclusion someone has to
32
+ * maintain, which is why `sql-in-a-comment` is one of the check's red proofs.
33
+ *
34
+ * ## What a statement has to look like
35
+ *
36
+ * A literal joins the population when it *starts* with `select`, `insert into`,
37
+ * `update`, `delete from` or `with`, **and** carries the rest of that statement's
38
+ * skeleton: a `select` needs a `from`, an `update` needs a `set`, a `with` needs
39
+ * a `select`. The second half is not decoration — `'Update products in the
40
+ * catalog'` is English prose that a start-anchored test alone reads as an
41
+ * `UPDATE` against `products`, and a check that reports it teaches its readers
42
+ * to ignore it.
43
+ *
44
+ * ## What a builder has to look like (issue #187)
45
+ *
46
+ * A knex builder names its table as an **argument to a call**, so no statement
47
+ * literal exists to anchor on:
48
+ *
49
+ * ```ts
50
+ * await knexForStock('warehouse_channel_assignments as a')
51
+ * .join('warehouses as w', 'w.id', 'a.warehouse_id')
52
+ * ```
53
+ *
54
+ * Both tables are `inventory`'s, read from inside `orders`' placement
55
+ * transaction, and both predicates were blind to them — the import predicate
56
+ * because a builder names no specifier, the statement path because there is no
57
+ * statement. **Ten** such accesses, in six files, stood outside a `sql=111` that
58
+ * read as the whole coupling, which is exactly the "`violations=0` licenses a
59
+ * package split the tree has not earned" failure D-87 exists to end. The grep
60
+ * that raised the issue found seven; the three it missed are the aliasing object
61
+ * form (`knex({ p: 'products' })`) and two reaches into **kernel** tables, which
62
+ * is the argument for reading nodes rather than grepping a spelling.
63
+ *
64
+ * Two shapes are recognised, and the population is bounded twice over — by the
65
+ * argument position and by the check's table→owner map, which only knows real
66
+ * tables:
67
+ *
68
+ * - **{@link TABLE_ARGUMENT_METHODS}** — a string literal in the *first*
69
+ * argument of `from`, `into`, `table` or a member of the join family. The
70
+ * list is enumerated rather than "any string on any builder method" because
71
+ * `where('status', …)`, `select('id')` and `orderBy(…)` take **columns**: a
72
+ * column spelled like another module's table would flood the ledger and the
73
+ * check would be switched off. Only the first argument is read, because
74
+ * `join(table, first, second)`'s remaining arguments are column references.
75
+ * - **the knex callable itself** — `knex('products')`, which starts 36 of the
76
+ * tree's 43 builder queries over a known table and which is not a method
77
+ * call at all.
78
+ * Its callee carries no name to key on, so the identifier must be **bound to
79
+ * a `getKnex()` result in the same file**; nothing else opens that door.
80
+ *
81
+ * The method list is receiver-agnostic on purpose. `Array.prototype.join` and
82
+ * `path.join` share the `join` spelling, and the tree calls the first 238 times;
83
+ * what keeps them out is that their arguments (`', '`, a path segment) are not
84
+ * table names in the owner map. The alternative — requiring every builder chain
85
+ * to root syntactically in a knex binding — would refuse them by construction
86
+ * but go **silently** blind on the builder held in a variable or taken as a
87
+ * parameter, which `catalog-admin.service.ts` and `promotion-stats-service.ts`
88
+ * both do. A spelling collision is a visible finding a reader resolves; a
89
+ * receiver rule is a miss nobody sees, and this file's whole reason for existing
90
+ * is that the second kind of failure is the expensive one.
91
+ */
92
+ import ts from 'typescript';
93
+ /**
94
+ * A literal's text, with `${…}` substitutions replaced by a placeholder.
95
+ *
96
+ * A template expression is the common shape for a query with an `in (…)` list
97
+ * built by `ids.map(() => '?').join(',')`; splicing the spans back together
98
+ * keeps every table identifier around the substitution visible, which a
99
+ * `getText()` read would too but with the interpolation source mixed in.
100
+ */
101
+ function literalText(node) {
102
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
103
+ return node.text;
104
+ if (ts.isTemplateExpression(node)) {
105
+ let text = node.head.text;
106
+ for (const span of node.templateSpans)
107
+ text += ` ? ${span.literal.text}`;
108
+ return text;
109
+ }
110
+ return null;
111
+ }
112
+ /**
113
+ * The source, parsed with parent pointers.
114
+ *
115
+ * The parents are what let the builder path walk a call chain outwards to decide
116
+ * whether it writes; the statement path needs only the positions.
117
+ */
118
+ function parse(source, file) {
119
+ return ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);
120
+ }
121
+ /** Every string / template literal in `sf`, with its line. */
122
+ function literals(sf) {
123
+ const found = [];
124
+ const visit = (node) => {
125
+ const text = literalText(node);
126
+ if (text !== null) {
127
+ found.push({ text, line: sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1 });
128
+ }
129
+ node.forEachChild(visit);
130
+ };
131
+ sf.forEachChild(visit);
132
+ return found;
133
+ }
134
+ /** `select` / `insert into` / `update` / `delete from` / `with`, at the head. */
135
+ const STATEMENT_HEAD = /^\s*(?:--[^\n]*\n|\s)*(select|insert\s+into|update|delete\s+from|with)\b/i;
136
+ /**
137
+ * The rest of the skeleton each head needs before the literal is read as SQL.
138
+ *
139
+ * Without this, prose scores: `'Update products in the catalog'` is an `UPDATE`
140
+ * against `catalog`'s `products` table to a start-anchored test.
141
+ */
142
+ const STATEMENT_BODY = {
143
+ select: /\bfrom\b/i,
144
+ insert: /\binto\b/i,
145
+ update: /\bset\b/i,
146
+ delete: /\bfrom\b/i,
147
+ with: /\bselect\b/i,
148
+ };
149
+ /**
150
+ * `from` / `join` / `into` / `update` and the identifier after it.
151
+ *
152
+ * The optional `"schema".` prefix is dropped: what decides ownership is the
153
+ * table, and this repository has exactly one schema.
154
+ */
155
+ const TABLE_REFERENCE = /\b(from|join|into|update)\s+(?:only\s+)?(?:"?[a-z_][a-z0-9_]*"?\.)?"?([a-z_][a-z0-9_]*)"?/gi;
156
+ /** `with x as (…)` — a CTE name is not a table, and may shadow one. */
157
+ const CTE_NAME = /\bwith\s+(?:recursive\s+)?([a-z_][a-z0-9_]*)|,\s*([a-z_][a-z0-9_]*)\s+as\s*\(/gi;
158
+ /** SQL keywords that follow `update` / `into` in shapes that name no table. */
159
+ const NOT_A_TABLE = new Set(['set', 'select', 'values', 'only', 'lateral', 'table']);
160
+ /**
161
+ * Every table identifier `source` names, through either recognition path.
162
+ *
163
+ * `file` is used for the source-file name the compiler API wants and for line
164
+ * numbers only; nothing here touches disk, so a caller may pass a path that does
165
+ * not exist. That is what lets the check's red proofs enter here, with source
166
+ * text, rather than below with a resolved table list.
167
+ */
168
+ export function sqlTableAccesses(source, file) {
169
+ const sf = parse(source, file);
170
+ const found = [...statementAccesses(sf), ...builderAccesses(sf)];
171
+ found.sort((a, b) => a.line - b.line);
172
+ return found;
173
+ }
174
+ /** The tables named inside a SQL statement literal — D-87's original path. */
175
+ function statementAccesses(sf) {
176
+ const found = [];
177
+ for (const literal of literals(sf)) {
178
+ const head = STATEMENT_HEAD.exec(literal.text);
179
+ if (head === null)
180
+ continue;
181
+ const verb = (head[1] ?? '').trim().split(/\s+/)[0]?.toLowerCase() ?? '';
182
+ const body = STATEMENT_BODY[verb];
183
+ if (body === undefined || !body.test(literal.text))
184
+ continue;
185
+ const bound = new Set();
186
+ for (const match of literal.text.matchAll(CTE_NAME)) {
187
+ const name = match[1] ?? match[2];
188
+ if (name !== undefined)
189
+ bound.add(name.toLowerCase());
190
+ }
191
+ const statement = literal.text.replace(/\s+/g, ' ').trim().slice(0, 80);
192
+ const seen = new Set();
193
+ for (const match of literal.text.matchAll(TABLE_REFERENCE)) {
194
+ const keyword = (match[1] ?? '').toLowerCase();
195
+ const table = (match[2] ?? '').toLowerCase();
196
+ if (table === '' || NOT_A_TABLE.has(table) || bound.has(table))
197
+ continue;
198
+ if (seen.has(table))
199
+ continue;
200
+ seen.add(table);
201
+ const write = keyword === 'into' || keyword === 'update' || (verb === 'delete' && keyword === 'from');
202
+ found.push({
203
+ table,
204
+ direction: write ? 'write' : 'read',
205
+ syntax: 'statement',
206
+ line: literal.line,
207
+ statement,
208
+ });
209
+ }
210
+ }
211
+ return found;
212
+ }
213
+ // ---------------------------------------------------------------------------
214
+ // The knex query builder (issue #187)
215
+ // ---------------------------------------------------------------------------
216
+ /**
217
+ * Builder methods whose **first** argument names a table.
218
+ *
219
+ * Enumerated, and this is the list the header argues for: `where`, `select`,
220
+ * `orderBy`, `count` and the rest take **columns**, so matching any string
221
+ * literal on any builder method would report a column spelled like another
222
+ * module's table and the ledger would fill with noise. The tree calls four of
223
+ * these today (`from`, `join`, `leftJoin`, `innerJoin`); the other join variants
224
+ * are the same knex surface, and leaving one out would make the day somebody
225
+ * writes `rightJoin` the day the check goes quietly blind.
226
+ */
227
+ const TABLE_ARGUMENT_METHODS = new Set([
228
+ 'from',
229
+ 'into',
230
+ 'table',
231
+ 'join',
232
+ 'innerJoin',
233
+ 'leftJoin',
234
+ 'leftOuterJoin',
235
+ 'rightJoin',
236
+ 'rightOuterJoin',
237
+ 'fullOuterJoin',
238
+ 'crossJoin',
239
+ ]);
240
+ /**
241
+ * Builder methods that move rows, anywhere in the chain the table is named in.
242
+ *
243
+ * `into` is here as well as in {@link TABLE_ARGUMENT_METHODS} because
244
+ * `knex.insert(rows).into('x')` names the table on the write method itself.
245
+ */
246
+ const WRITE_METHODS = new Set([
247
+ 'insert',
248
+ 'update',
249
+ 'delete',
250
+ 'del',
251
+ 'upsert',
252
+ 'truncate',
253
+ 'increment',
254
+ 'decrement',
255
+ 'into',
256
+ ]);
257
+ /**
258
+ * `em.getKnex()`, `em.getConnection().getKnex()`, `this.emFactory().getKnex()`.
259
+ *
260
+ * Exported because `check-transaction-context` refuses the same handle for a
261
+ * different reason (issue #200: it carries no transaction context), and two
262
+ * copies of "what a knex handle looks like" would drift — the receiver is
263
+ * spelled at least three ways in this tree already.
264
+ */
265
+ export function isGetKnexCall(node) {
266
+ return (ts.isCallExpression(node) &&
267
+ ts.isPropertyAccessExpression(node.expression) &&
268
+ node.expression.name.text === 'getKnex');
269
+ }
270
+ /**
271
+ * The identifiers this file binds to a knex instance.
272
+ *
273
+ * The knex callable is `knex('products')` — a call whose callee carries no
274
+ * method name to key on — so the only structural evidence available is the
275
+ * binding, and the tree writes exactly one shape for it — a `const` initialised
276
+ * from a `getKnex()` call, 32 times: `knex` in 30 of them, `knexForStock` and
277
+ * `knexEmpty` in the other two. Keying on the binding rather than on the
278
+ * identifier's spelling keeps the rule a property of the code and not of what
279
+ * somebody named a variable.
280
+ */
281
+ function knexBindings(sf) {
282
+ const bound = new Set();
283
+ const visit = (node) => {
284
+ if (ts.isVariableDeclaration(node) &&
285
+ ts.isIdentifier(node.name) &&
286
+ node.initializer !== undefined &&
287
+ isGetKnexCall(node.initializer)) {
288
+ bound.add(node.name.text);
289
+ }
290
+ node.forEachChild(visit);
291
+ };
292
+ sf.forEachChild(visit);
293
+ return bound;
294
+ }
295
+ /** The table a builder argument names, or `null` when it names no table. */
296
+ function builderTableName(text) {
297
+ // `'warehouses as w'` — knex's alias form, and the one `order-service.ts`
298
+ // writes. Everything after the alias keyword belongs to the alias.
299
+ const withoutAlias = text.split(/\s+as\s+/i)[0] ?? '';
300
+ const bare = withoutAlias.trim().replace(/^"(.*)"$/, '$1');
301
+ // `"public".products` / `w.id` — the qualifier is dropped for the same reason
302
+ // the statement path drops it: this repository has one schema, and what is
303
+ // left of a column reference (`id`) is not a table name in the owner map.
304
+ const unqualified = bare.includes('.') ? (bare.split('.').pop() ?? '') : bare;
305
+ const table = unqualified.toLowerCase();
306
+ return /^[a-z_][a-z0-9_]*$/.test(table) ? table : null;
307
+ }
308
+ /** Every table a call argument names: a string literal, or an alias object's values. */
309
+ function tableArguments(argument) {
310
+ if (argument === undefined)
311
+ return [];
312
+ const text = ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)
313
+ ? argument.text
314
+ : null;
315
+ if (text !== null) {
316
+ const table = builderTableName(text);
317
+ return table === null ? [] : [table];
318
+ }
319
+ // `knex({ p: 'products' })` — the alias is the key and the table is the value.
320
+ if (!ts.isObjectLiteralExpression(argument))
321
+ return [];
322
+ const tables = [];
323
+ for (const property of argument.properties) {
324
+ if (!ts.isPropertyAssignment(property))
325
+ continue;
326
+ if (!ts.isStringLiteral(property.initializer))
327
+ continue;
328
+ const table = builderTableName(property.initializer.text);
329
+ if (table !== null)
330
+ tables.push(table);
331
+ }
332
+ return tables;
333
+ }
334
+ /**
335
+ * The outermost call chain `node` sits in.
336
+ *
337
+ * `knex('x').where(…).update(…)` is one expression, and the write method can sit
338
+ * on either side of the table: `update` follows it and `insert` precedes it in
339
+ * `knex.insert(rows).into('x')`. Walking out to the whole chain and then reading
340
+ * every method name in it answers both without a rule per shape.
341
+ */
342
+ function outermostChain(node) {
343
+ let current = node;
344
+ for (;;) {
345
+ const parent = current.parent;
346
+ if (parent === undefined)
347
+ return current;
348
+ if (ts.isPropertyAccessExpression(parent) && parent.expression === current)
349
+ current = parent;
350
+ else if (ts.isCallExpression(parent) && parent.expression === current)
351
+ current = parent;
352
+ else
353
+ return current;
354
+ }
355
+ }
356
+ /** Whether any method in the chain moves rows. */
357
+ function chainWrites(chain) {
358
+ let writes = false;
359
+ const visit = (node) => {
360
+ if (writes)
361
+ return;
362
+ if (ts.isPropertyAccessExpression(node) && WRITE_METHODS.has(node.name.text))
363
+ writes = true;
364
+ node.forEachChild(visit);
365
+ };
366
+ visit(chain);
367
+ return writes;
368
+ }
369
+ /** Every table a knex query builder in `sf` names. */
370
+ function builderAccesses(sf) {
371
+ const bound = knexBindings(sf);
372
+ const found = [];
373
+ const visit = (node) => {
374
+ if (ts.isCallExpression(node)) {
375
+ const callee = node.expression;
376
+ // A table-taking builder method, or the knex callable itself. Either way
377
+ // only the **first** argument is read: `join(table, first, second)`'s
378
+ // remaining arguments are column references.
379
+ const namesATable = (ts.isPropertyAccessExpression(callee) && TABLE_ARGUMENT_METHODS.has(callee.name.text)) ||
380
+ (ts.isIdentifier(callee) && bound.has(callee.text)) ||
381
+ isGetKnexCall(callee);
382
+ const named = namesATable ? tableArguments(node.arguments[0]) : [];
383
+ if (named.length > 0) {
384
+ const chain = outermostChain(node);
385
+ const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
386
+ const statement = chain.getText(sf).replace(/\s+/g, ' ').trim().slice(0, 80);
387
+ const direction = chainWrites(chain) ? 'write' : 'read';
388
+ for (const table of named) {
389
+ found.push({ table, direction, syntax: 'builder', line, statement });
390
+ }
391
+ }
392
+ }
393
+ node.forEachChild(visit);
394
+ };
395
+ sf.forEachChild(visit);
396
+ return found;
397
+ }
398
+ /** `create table "x"` / `create table if not exists x`, inside a SQL literal. */
399
+ const CREATE_TABLE = /\bcreate\s+table\s+(?:if\s+not\s+exists\s+)?"?([a-z_][a-z0-9_]*)"?/gi;
400
+ /**
401
+ * The table names `source` declares, from either owner-map source.
402
+ *
403
+ * An `@Entity()` class declares its `tableName` option, or — for the classes
404
+ * that do not set one — the name `PluralizingNamingStrategy` derives from the
405
+ * class name, imported rather than reimplemented so the two cannot drift.
406
+ * `create table` DDL is read out of the same literal nodes as everything else,
407
+ * so a migration that mentions a table in a comment declares nothing.
408
+ */
409
+ export function declaredTableNames(source, file, tableNameOf) {
410
+ const found = [];
411
+ const seen = new Set();
412
+ const add = (table, from) => {
413
+ if (seen.has(table))
414
+ return;
415
+ seen.add(table);
416
+ found.push({ table, source: from });
417
+ };
418
+ const sf = parse(source, file);
419
+ if (source.includes('@Entity')) {
420
+ const visit = (node) => {
421
+ if (ts.isClassDeclaration(node) && ts.canHaveDecorators(node)) {
422
+ for (const decorator of ts.getDecorators(node) ?? []) {
423
+ const call = decorator.expression;
424
+ if (!ts.isCallExpression(call))
425
+ continue;
426
+ if (!ts.isIdentifier(call.expression) || call.expression.text !== 'Entity')
427
+ continue;
428
+ const declared = entityTableName(call);
429
+ if (declared !== null)
430
+ add(declared, 'entity');
431
+ else if (node.name)
432
+ add(tableNameOf(node.name.text), 'entity');
433
+ }
434
+ }
435
+ node.forEachChild(visit);
436
+ };
437
+ sf.forEachChild(visit);
438
+ }
439
+ for (const literal of literals(sf)) {
440
+ for (const match of literal.text.matchAll(CREATE_TABLE)) {
441
+ const table = match[1];
442
+ if (table !== undefined)
443
+ add(table.toLowerCase(), 'migration');
444
+ }
445
+ }
446
+ return found;
447
+ }
448
+ /** The `tableName` option of an `@Entity({ … })` call, when it sets one. */
449
+ function entityTableName(call) {
450
+ const [argument] = call.arguments;
451
+ if (argument === undefined || !ts.isObjectLiteralExpression(argument))
452
+ return null;
453
+ for (const property of argument.properties) {
454
+ if (!ts.isPropertyAssignment(property))
455
+ continue;
456
+ const name = ts.isIdentifier(property.name) ? property.name.text : null;
457
+ if (name !== 'tableName')
458
+ continue;
459
+ if (ts.isStringLiteral(property.initializer))
460
+ return property.initializer.text;
461
+ }
462
+ return null;
463
+ }
464
+ //# sourceMappingURL=sql-tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-tables.js","sourceRoot":"","sources":["../../src/lib/sql-tables.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The part of a manifest this derivation reads. Structural rather than
3
+ * `ModuleManifest`, so a fixture can supply the two fields it looks at and
4
+ * nothing else.
5
+ */
6
+ export interface ManifestActivationInput {
7
+ readonly id: string;
8
+ readonly activation?: {
9
+ readonly settingCode?: string;
10
+ readonly default?: boolean;
11
+ readonly nonDeactivatable?: boolean;
12
+ readonly reason?: string;
13
+ } | undefined;
14
+ }
15
+ /** Raised when the manifest index could not be read, or read as empty. */
16
+ export declare class ManifestIndexUnreadableError extends Error {
17
+ readonly name = "ManifestIndexUnreadableError";
18
+ }
19
+ /** The modules the orchestrator refuses to switch off, on either axis. */
20
+ export declare function lockedOwners(manifests: readonly ManifestActivationInput[]): ReadonlySet<string>;
21
+ /** A module an operator can switch off — the complement of the locked set. */
22
+ export declare function isSwitchableModule(moduleId: string, locked: ReadonlySet<string>): boolean;
23
+ /**
24
+ * Read the manifests out of the generated index at `indexPath`.
25
+ *
26
+ * **The path is given, never built** (feature 080, T040a). It used to be
27
+ * `join(srcRoot, 'modules/_lifecycle/manifest-index.generated.ts')` — the
28
+ * module tree's location spelled out inside the one derivation whose job is to
29
+ * make that location a fact rather than a constant, so a layout move broke the
30
+ * reader every check's population floor rests on. `lib/module-roots.ts` locates
31
+ * it by search over the workspace members and hands it here.
32
+ *
33
+ * Throws `ManifestIndexUnreadableError` when the index is missing or empty; a
34
+ * caller turns that into exit 2, never into a pass.
35
+ */
36
+ export declare function loadManifestActivations(indexPath: string): Promise<readonly ManifestActivationInput[]>;
37
+ /**
38
+ * Where each registered module's manifest actually is, straight from the index.
39
+ *
40
+ * The index records it (feature 080, T041a) because a module's own directory is
41
+ * `dirname` of it, and three origins answer differently: a module in the
42
+ * application tree with `<src>/modules/<id>/manifest.ts`, a packaged one with
43
+ * its `package.json`, and — since T040b — the one module the host itself owns,
44
+ * whose directory is neither. `lib/module-roots.ts` reads this to place that
45
+ * last one, rather than inferring it from a directory that is deliberately not
46
+ * named after its module id.
47
+ *
48
+ * Same reader and same import as {@link loadManifestActivations}, so the two
49
+ * cannot come to disagree about which modules exist or where they are.
50
+ */
51
+ export declare function loadManifestLocations(indexPath: string): Promise<ReadonlyMap<string, string>>;
52
+ /** The locked set, straight from the generated index. */
53
+ export declare function loadLockedOwners(indexPath: string): Promise<ReadonlySet<string>>;
54
+ //# sourceMappingURL=switchable-modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switchable-modules.d.ts","sourceRoot":"","sources":["../../src/lib/switchable-modules.ts"],"names":[],"mappings":"AA0BA;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,CAAC,EAChB;QACE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B,GACD,SAAS,CAAC;CACf;AAED,0EAA0E;AAC1E,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,SAAkB,IAAI,kCAAkC;CACzD;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAC1B,SAAS,EAAE,SAAS,uBAAuB,EAAE,GAC5C,WAAW,CAAC,MAAM,CAAC,CAMrB;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAEzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CAiB7C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAetC;AAED,yDAAyD;AACzD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAEtF"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The one derivation of "can an operator switch this module off?" (D-63/D-68).
3
+ *
4
+ * Two checks need it and neither may own it. `check-port-catches` reports a
5
+ * `catch` as `OWNER LOCKED` when every gate it swallows belongs to a module the
6
+ * orchestrator refuses to switch off; `check-entry-presence` leaves such a
7
+ * module's boot hooks out of its population, because a hook cannot fail to
8
+ * decide a presence that has no off state. Both answers rest on the same fact —
9
+ * the module's manifest declares `activation.nonDeactivatable` — and both are
10
+ * only safe if the fact is **read at check time** rather than written down: an
11
+ * owner who withdraws a lock must re-red every site that was resting on it, in
12
+ * the same run, with no ledger to edit. A hand-maintained list would go stale
13
+ * silently, which is the failure mode two-way ledgers exist to prevent. D-68
14
+ * says so explicitly — "the two checks share one helper in
15
+ * `backend/scripts/lib/`" — and this is that helper.
16
+ *
17
+ * `lockedOwners` is pure and takes the manifests, so each check's red proofs can
18
+ * drive the classification from a fixture that enters at the top of the
19
+ * analysis. `loadLockedOwners` is the one place that knows where the generated
20
+ * index lives; it **refuses an empty index** rather than returning an empty set,
21
+ * because "no module is locked" and "the index did not load" would otherwise be
22
+ * the same answer — and the second silently changes both checks' verdicts while
23
+ * looking like a normal run (issue #113).
24
+ */
25
+ import { pathToFileURL } from 'node:url';
26
+ /** Raised when the manifest index could not be read, or read as empty. */
27
+ export class ManifestIndexUnreadableError extends Error {
28
+ name = 'ManifestIndexUnreadableError';
29
+ }
30
+ /** The modules the orchestrator refuses to switch off, on either axis. */
31
+ export function lockedOwners(manifests) {
32
+ return new Set(manifests
33
+ .filter((manifest) => manifest.activation?.nonDeactivatable === true)
34
+ .map((manifest) => manifest.id));
35
+ }
36
+ /** A module an operator can switch off — the complement of the locked set. */
37
+ export function isSwitchableModule(moduleId, locked) {
38
+ return !locked.has(moduleId);
39
+ }
40
+ /**
41
+ * Read the manifests out of the generated index at `indexPath`.
42
+ *
43
+ * **The path is given, never built** (feature 080, T040a). It used to be
44
+ * `join(srcRoot, 'modules/_lifecycle/manifest-index.generated.ts')` — the
45
+ * module tree's location spelled out inside the one derivation whose job is to
46
+ * make that location a fact rather than a constant, so a layout move broke the
47
+ * reader every check's population floor rests on. `lib/module-roots.ts` locates
48
+ * it by search over the workspace members and hands it here.
49
+ *
50
+ * Throws `ManifestIndexUnreadableError` when the index is missing or empty; a
51
+ * caller turns that into exit 2, never into a pass.
52
+ */
53
+ export async function loadManifestActivations(indexPath) {
54
+ let entries;
55
+ try {
56
+ const loaded = (await import(pathToFileURL(indexPath).href));
57
+ entries = loaded.DISCOVERED_MANIFESTS ?? [];
58
+ }
59
+ catch (err) {
60
+ throw new ManifestIndexUnreadableError(`${indexPath} could not be imported: ${String(err)}`);
61
+ }
62
+ if (entries.length === 0) {
63
+ throw new ManifestIndexUnreadableError(`${indexPath} declared no modules`);
64
+ }
65
+ return entries.map((entry) => ({
66
+ id: entry.id,
67
+ activation: entry.manifest.activation,
68
+ }));
69
+ }
70
+ /**
71
+ * Where each registered module's manifest actually is, straight from the index.
72
+ *
73
+ * The index records it (feature 080, T041a) because a module's own directory is
74
+ * `dirname` of it, and three origins answer differently: a module in the
75
+ * application tree with `<src>/modules/<id>/manifest.ts`, a packaged one with
76
+ * its `package.json`, and — since T040b — the one module the host itself owns,
77
+ * whose directory is neither. `lib/module-roots.ts` reads this to place that
78
+ * last one, rather than inferring it from a directory that is deliberately not
79
+ * named after its module id.
80
+ *
81
+ * Same reader and same import as {@link loadManifestActivations}, so the two
82
+ * cannot come to disagree about which modules exist or where they are.
83
+ */
84
+ export async function loadManifestLocations(indexPath) {
85
+ let entries;
86
+ try {
87
+ const loaded = (await import(pathToFileURL(indexPath).href));
88
+ entries = loaded.DISCOVERED_MANIFESTS ?? [];
89
+ }
90
+ catch (err) {
91
+ throw new ManifestIndexUnreadableError(`${indexPath} could not be imported: ${String(err)}`);
92
+ }
93
+ const located = new Map();
94
+ for (const entry of entries) {
95
+ if (entry.manifestPath !== undefined)
96
+ located.set(entry.id, entry.manifestPath);
97
+ }
98
+ return located;
99
+ }
100
+ /** The locked set, straight from the generated index. */
101
+ export async function loadLockedOwners(indexPath) {
102
+ return lockedOwners(await loadManifestActivations(indexPath));
103
+ }
104
+ //# sourceMappingURL=switchable-modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switchable-modules.js","sourceRoot":"","sources":["../../src/lib/switchable-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAmBzC,0EAA0E;AAC1E,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IACnC,IAAI,GAAG,8BAA8B,CAAC;CACzD;AAED,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAC1B,SAA6C;IAE7C,OAAO,IAAI,GAAG,CACZ,SAAS;SACN,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;SACpE,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAClC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAA2B;IAC9E,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,SAAiB;IAEjB,IAAI,OAA0E,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAE1D,CAAC;QACF,OAAO,GAAG,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,4BAA4B,CAAC,GAAG,SAAS,2BAA2B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,4BAA4B,CAAC,GAAG,SAAS,sBAAsB,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7B,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAmD;KAC/E,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAiB;IAEjB,IAAI,OAA6D,CAAC;IAClE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAE1D,CAAC;QACF,OAAO,GAAG,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,4BAA4B,CAAC,GAAG,SAAS,2BAA2B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,OAAO,YAAY,CAAC,MAAM,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;AAChE,CAAC"}