@pixel-point/toolcraft 0.0.18 → 0.0.19

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 (384) hide show
  1. package/package.json +1 -1
  2. package/src/generate-demand-only-lifecycle.test.mjs +9 -1
  3. package/src/generate-performance-iteration-execution.test.mjs +3 -3
  4. package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
  5. package/src/generate-test-demand-only-lifecycle.mjs +34 -36
  6. package/src/generate-test-dependency-sandbox.mjs +4 -1
  7. package/src/generate-test-doc-assertions.mjs +55 -53
  8. package/src/generate-test-doc-assertions.test.mjs +1 -1
  9. package/src/generate-test-doc-policy-assertions.mjs +1 -1
  10. package/src/generate-test-export-doc-assertions.mjs +53 -0
  11. package/src/generate-test-file-assertions.mjs +51 -8
  12. package/src/generate-test-integrity-assertions.mjs +5 -2
  13. package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
  14. package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
  15. package/src/generate-test-package-assertions.mjs +4 -0
  16. package/src/generate-test-product-fixture.mjs +1 -1
  17. package/src/generate-test-product-fixture.test.mjs +35 -38
  18. package/src/generate-test-product-iteration.mjs +0 -1
  19. package/src/generate-test-product-iteration.test.mjs +0 -1
  20. package/src/generate-test-runtime-boundary-assertions.mjs +20 -0
  21. package/src/generate-test-standalone-assertions.mjs +0 -16
  22. package/src/generate-test-standalone-delivery-stages.mjs +2 -86
  23. package/src/generate.test.mjs +4 -0
  24. package/src/generated-integrity-manifest.test.mjs +5 -2
  25. package/src/generated-source-policy.test.mjs +0 -4
  26. package/src/package-json.mjs +5 -0
  27. package/src/package-json.test.mjs +21 -0
  28. package/src/package-manager.mjs +2 -0
  29. package/src/package-manager.test.mjs +8 -0
  30. package/src/packaged-template-fallback-helpers.mjs +254 -0
  31. package/src/packaged-template-fallback.test.mjs +121 -46
  32. package/src/packaged-template-runtime-assertions.mjs +150 -0
  33. package/templates/runtime/contracts/component-contracts.choices.test.ts +18 -3
  34. package/templates/runtime/contracts/component-contracts.choices.ts +8 -3
  35. package/templates/runtime/contracts/component-contracts.inputs.ts +2 -1
  36. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +18 -4
  37. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
  38. package/templates/runtime/contracts/component-contracts.runtime.ts +7 -4
  39. package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
  40. package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
  41. package/templates/runtime/contracts/decision-contracts.test.ts +18 -12
  42. package/templates/runtime/contracts/decision-contracts.ts +4 -4
  43. package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
  44. package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
  45. package/templates/runtime/export/artifact-download.ts +1 -0
  46. package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
  47. package/templates/runtime/export/artifact-frame-state.ts +16 -0
  48. package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
  49. package/templates/runtime/export/artifact-scene-frame.ts +3 -3
  50. package/templates/runtime/export/export-error.ts +5 -0
  51. package/templates/runtime/export/export-renderer-coverage.ts +54 -0
  52. package/templates/runtime/export/image-artifact-export.ts +2 -2
  53. package/templates/runtime/export/index.ts +13 -0
  54. package/templates/runtime/export/product-export-renderer.test.ts +38 -4
  55. package/templates/runtime/export/product-export-renderer.ts +0 -41
  56. package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
  57. package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
  58. package/templates/runtime/export/svg-artifact-export.ts +120 -0
  59. package/templates/runtime/export/svg-document.test.ts +221 -0
  60. package/templates/runtime/export/svg-document.ts +400 -0
  61. package/templates/runtime/export/svg-policy.ts +47 -0
  62. package/templates/runtime/index.ts +1 -0
  63. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +10 -0
  64. package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
  65. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +46 -1
  66. package/templates/runtime/react/app-shell/toolcraft-app.tsx +7 -2
  67. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
  68. package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
  69. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +1 -1
  70. package/templates/runtime/react/canvas/canvas-shell.tsx +16 -5
  71. package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
  72. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
  73. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
  74. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
  75. package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
  76. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +39 -0
  77. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
  78. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +1 -4
  79. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +2 -2
  80. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
  81. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +2 -2
  82. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +40 -11
  83. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +31 -2
  84. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +4 -1
  85. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
  86. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
  87. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
  88. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
  89. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
  90. package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
  91. package/templates/runtime/schema/artifact-export-actions.ts +49 -0
  92. package/templates/runtime/schema/types.ts +1 -0
  93. package/templates/runtime/state/canvas-background-state.ts +1 -16
  94. package/templates/runtime/state/canvas-state.ts +32 -20
  95. package/templates/runtime/state/control-value-codecs.test.ts +98 -0
  96. package/templates/runtime/state/control-value-codecs.ts +700 -0
  97. package/templates/runtime/state/control-value-normalization.test.ts +1 -1
  98. package/templates/runtime/state/control-value-normalization.ts +127 -135
  99. package/templates/runtime/state/controls-reducer.ts +26 -3
  100. package/templates/runtime/state/create-template-state.test.ts +30 -0
  101. package/templates/runtime/state/create-template-state.ts +52 -31
  102. package/templates/runtime/state/orientation-pose.ts +80 -0
  103. package/templates/runtime/state/persistence-control-values.test.ts +59 -0
  104. package/templates/runtime/state/reducer-controls.test.ts +45 -0
  105. package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
  106. package/templates/runtime/state/reducer-timeline.test.ts +70 -0
  107. package/templates/runtime/state/timeline-reducer.ts +40 -2
  108. package/templates/runtime/testing/performance-schema-queries.ts +2 -2
  109. package/templates/starter/AGENTS.md +21 -22
  110. package/templates/starter/docs/toolcraft/README.md +6 -6
  111. package/templates/starter/docs/toolcraft/acceptance-testing.md +20 -20
  112. package/templates/starter/docs/toolcraft/agent-worklog.md +88 -1
  113. package/templates/starter/docs/toolcraft/assembly-workflow.md +7 -6
  114. package/templates/starter/docs/toolcraft/component-rules.md +2 -2
  115. package/templates/starter/docs/toolcraft/core/layout.md +6 -1
  116. package/templates/starter/docs/toolcraft/core/media-upload.md +1 -1
  117. package/templates/starter/docs/toolcraft/core/performance.md +8 -10
  118. package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
  119. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +2 -1
  120. package/templates/starter/docs/toolcraft/core/setup-export.md +43 -13
  121. package/templates/starter/docs/toolcraft/decision-contract.md +2 -2
  122. package/templates/starter/docs/toolcraft/performance.md +8 -10
  123. package/templates/starter/docs/toolcraft/renderer-technique.md +2 -2
  124. package/templates/starter/docs/toolcraft/schema-reference.md +8 -8
  125. package/templates/starter/docs/toolcraft/workflow.md +14 -14
  126. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +38 -0
  127. package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
  128. package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
  129. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +62 -0
  130. package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
  131. package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
  132. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
  133. package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
  134. package/templates/starter/e2e/browser-proof-session.ts +43 -15
  135. package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
  136. package/templates/starter/e2e/browser-proof-types.ts +15 -0
  137. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +22 -6
  138. package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
  139. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +97 -0
  140. package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
  141. package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
  142. package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
  143. package/templates/starter/e2e/product-observable-helpers.ts +8 -129
  144. package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
  145. package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
  146. package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
  147. package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
  148. package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
  149. package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
  150. package/templates/starter/package.json +2 -0
  151. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  152. package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
  153. package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
  154. package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
  155. package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
  156. package/templates/starter/scripts/run-browser-performance.mjs +0 -6
  157. package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
  158. package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
  159. package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
  160. package/templates/starter/scripts/run-feature-verification.mjs +212 -0
  161. package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
  162. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
  163. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
  164. package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
  165. package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
  166. package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
  167. package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
  168. package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
  169. package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
  170. package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
  171. package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
  172. package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
  173. package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
  174. package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
  175. package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
  176. package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
  177. package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
  178. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
  179. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
  180. package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
  181. package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
  182. package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
  183. package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
  184. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
  185. package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
  186. package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
  187. package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
  188. package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
  189. package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
  190. package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
  191. package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
  192. package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
  193. package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
  194. package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
  195. package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
  196. package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
  197. package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
  198. package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
  199. package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
  200. package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
  201. package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
  202. package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
  203. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
  204. package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
  205. package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
  206. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
  207. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
  208. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
  209. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
  210. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
  211. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
  212. package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
  213. package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
  214. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
  215. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
  216. package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
  217. package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
  218. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
  219. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
  220. package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
  221. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
  222. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
  223. package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
  224. package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
  225. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
  226. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
  227. package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
  228. package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
  229. package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
  230. package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
  231. package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
  232. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
  233. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
  234. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
  235. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
  236. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
  237. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
  238. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
  239. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
  240. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
  241. package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
  242. package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
  243. package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
  244. package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
  245. package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
  246. package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
  247. package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
  248. package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
  249. package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
  250. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
  251. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
  252. package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
  253. package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
  254. package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
  255. package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
  256. package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
  257. package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
  258. package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
  259. package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
  260. package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
  261. package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
  262. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +1 -1
  263. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +10 -1
  264. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +5 -1
  265. package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
  266. package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
  267. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
  268. package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
  269. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
  270. package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
  271. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
  272. package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
  273. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
  274. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
  275. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
  276. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
  277. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
  278. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
  279. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
  280. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
  281. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +51 -20
  282. package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
  283. package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
  284. package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
  285. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +0 -11
  286. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -3
  287. package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
  288. package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
  289. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +18 -0
  290. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
  291. package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
  292. package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
  293. package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
  294. package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
  295. package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
  296. package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
  297. package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
  298. package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
  299. package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
  300. package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
  301. package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
  302. package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
  303. package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
  304. package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
  305. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
  306. package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
  307. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +5 -1
  308. package/templates/starter/src/app/acceptance/output-export-model.ts +4 -0
  309. package/templates/starter/src/app/acceptance/output-export.ts +4 -1
  310. package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
  311. package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
  312. package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
  313. package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
  314. package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
  315. package/templates/starter/src/app/acceptance/types.ts +43 -118
  316. package/templates/starter/src/app/acceptance/validate-coverage.ts +14 -3
  317. package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
  318. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
  319. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +81 -8
  320. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +2 -0
  321. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +2 -0
  322. package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
  323. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +1 -1
  324. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +1 -0
  325. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +1 -0
  326. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
  327. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
  328. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
  329. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
  330. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
  331. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +5 -1
  332. package/templates/starter/src/app/starter-acceptance.image-export-settings.test.ts +2 -0
  333. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +19 -3
  334. package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
  335. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
  336. package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
  337. package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
  338. package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
  339. package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
  340. package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
  341. package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
  342. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +78 -4
  343. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +6 -1
  344. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +18 -1
  345. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
  346. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
  347. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
  348. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
  349. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +2 -0
  350. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
  351. package/templates/starter/src/app/starter-acceptance.ts +34 -8
  352. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +2 -0
  353. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
  354. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +4 -0
  355. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
  356. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
  357. package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
  358. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
  359. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +3 -0
  360. package/templates/starter/tsconfig.json +1 -0
  361. package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
  362. package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
  363. package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
  364. package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
  365. package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
  366. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
  367. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
  368. package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
  369. package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
  370. package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
  371. package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
  372. package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
  373. package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
  374. package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
  375. package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
  376. package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
  377. package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
  378. package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
  379. package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
  380. package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
  381. package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
  382. package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
  383. package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
  384. package/templates/starter/src/app/starter-verification-impact.json +0 -15
@@ -0,0 +1,331 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+
4
+ import type { Download, Page } from "@playwright/test";
5
+ import {
6
+ TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS,
7
+ TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE,
8
+ TOOLCRAFT_SVG_NAMESPACE,
9
+ TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS,
10
+ TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE,
11
+ TOOLCRAFT_SVG_VECTOR_PRIMITIVES,
12
+ } from "@repo/toolcraft-runtime";
13
+
14
+ import type { ToolcraftSvgArtifactInspection } from "./export-artifact-helpers";
15
+
16
+ export type ToolcraftInspectedSvgArtifact = Readonly<{
17
+ inspection: ToolcraftSvgArtifactInspection;
18
+ source: string;
19
+ }>;
20
+
21
+ const inspectedSvgArtifacts = new WeakSet<object>();
22
+
23
+ export function assertToolcraftInspectedSvgArtifact(
24
+ inspection: ToolcraftSvgArtifactInspection,
25
+ ): void {
26
+ if (!inspectedSvgArtifacts.has(inspection)) {
27
+ throw new Error(
28
+ "Infinity SVG evidence requires an artifact from inspectToolcraftSvgDownload.",
29
+ );
30
+ }
31
+ }
32
+
33
+ export async function inspectToolcraftSvgDownload({
34
+ download,
35
+ page,
36
+ }: Readonly<{
37
+ download: Download;
38
+ page: Page;
39
+ }>): Promise<ToolcraftInspectedSvgArtifact> {
40
+ const fileName = download.suggestedFilename();
41
+ if (!fileName.toLowerCase().endsWith(".svg")) {
42
+ throw new Error("Downloaded SVG artifact must use the .svg extension.");
43
+ }
44
+ const downloadPath = await download.path();
45
+ if (!downloadPath) {
46
+ throw new Error("Playwright did not expose the downloaded SVG path.");
47
+ }
48
+ const bytes = await fs.readFile(downloadPath);
49
+ if (bytes.byteLength === 0) {
50
+ throw new Error("Downloaded SVG artifact is empty.");
51
+ }
52
+
53
+ let source: string;
54
+ try {
55
+ source = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
56
+ } catch {
57
+ throw new Error("Downloaded SVG artifact is not valid UTF-8.");
58
+ }
59
+
60
+ const decoded = await page.evaluate(
61
+ async ({
62
+ backgroundAttribute,
63
+ forbiddenNames,
64
+ namespace,
65
+ nonRenderingNames,
66
+ primitiveNames,
67
+ productSceneAttribute,
68
+ svgSource,
69
+ }) => {
70
+ const parsed = new DOMParser().parseFromString(
71
+ svgSource,
72
+ "image/svg+xml",
73
+ );
74
+ if (parsed.querySelector("parsererror")) {
75
+ throw new Error("Downloaded SVG artifact is not valid XML.");
76
+ }
77
+ if (parsed.doctype) {
78
+ throw new Error("Downloaded SVG artifact cannot contain a doctype.");
79
+ }
80
+ const root = parsed.documentElement;
81
+ if (root.localName !== "svg" || root.namespaceURI !== namespace) {
82
+ throw new Error(
83
+ "Downloaded SVG artifact must have a namespaced <svg> root.",
84
+ );
85
+ }
86
+
87
+ const parseDimension = (name: "height" | "width"): number => {
88
+ const raw = root.getAttribute(name)?.trim() ?? "";
89
+ if (!/^(?:\d+\.?\d*|\.\d+)$/u.test(raw)) {
90
+ throw new Error(`Downloaded SVG artifact needs numeric ${name}.`);
91
+ }
92
+ const value = Number(raw);
93
+ if (!Number.isFinite(value) || value <= 0) {
94
+ throw new Error(`Downloaded SVG artifact needs positive ${name}.`);
95
+ }
96
+ return value;
97
+ };
98
+ const width = parseDimension("width");
99
+ const height = parseDimension("height");
100
+ const viewBox = (root.getAttribute("viewBox") ?? "")
101
+ .trim()
102
+ .split(/[\s,]+/u)
103
+ .map(Number);
104
+ if (
105
+ viewBox.length !== 4 ||
106
+ viewBox.some((value) => !Number.isFinite(value)) ||
107
+ Number(viewBox[2]) <= 0 ||
108
+ Number(viewBox[3]) <= 0 ||
109
+ Number(viewBox[2]) !== width ||
110
+ Number(viewBox[3]) !== height
111
+ ) {
112
+ throw new Error(
113
+ "Downloaded SVG artifact needs a coherent positive viewBox.",
114
+ );
115
+ }
116
+
117
+ const productScenes = Array.from(
118
+ root.querySelectorAll(`[${productSceneAttribute}]`),
119
+ );
120
+ const productScene = productScenes[0] ?? null;
121
+ if (
122
+ productScenes.length !== 1 ||
123
+ productScene?.localName !== "g" ||
124
+ productScene.getAttribute(productSceneAttribute) !== "true" ||
125
+ !productScene.parentElement?.isSameNode(root)
126
+ ) {
127
+ throw new Error(
128
+ "Downloaded SVG artifact needs one runtime-owned product scene.",
129
+ );
130
+ }
131
+
132
+ const backgrounds = Array.from(
133
+ root.querySelectorAll(`[${backgroundAttribute}]`),
134
+ );
135
+ if (backgrounds.length > 1) {
136
+ throw new Error("Downloaded SVG artifact has duplicate runtime backgrounds.");
137
+ }
138
+ const background = backgrounds[0] ?? null;
139
+ let backgroundColor: string | null = null;
140
+ if (background) {
141
+ const backgroundFrame = ["x", "y", "width", "height"].map((name) =>
142
+ Number(background.getAttribute(name)),
143
+ );
144
+ if (
145
+ background.getAttribute(backgroundAttribute) !== "true" ||
146
+ background.localName !== "rect" ||
147
+ !background.parentElement?.isSameNode(root) ||
148
+ root.children[0] !== background ||
149
+ backgroundFrame.some((value) => !Number.isFinite(value)) ||
150
+ backgroundFrame.some((value, index) => value !== viewBox[index])
151
+ ) {
152
+ throw new Error(
153
+ "Downloaded SVG artifact has an invalid runtime background frame.",
154
+ );
155
+ }
156
+ backgroundColor = background.getAttribute("fill")?.trim() || null;
157
+ if (!backgroundColor) {
158
+ throw new Error(
159
+ "Downloaded SVG artifact runtime background needs a fill color.",
160
+ );
161
+ }
162
+ }
163
+ const expectedRootChildCount = background ? 2 : 1;
164
+ if (
165
+ root.children.length !== expectedRootChildCount ||
166
+ root.children[expectedRootChildCount - 1] !== productScene
167
+ ) {
168
+ throw new Error(
169
+ "Downloaded SVG artifact has unexpected root-owned content.",
170
+ );
171
+ }
172
+
173
+ const forbidden = new Set(forbiddenNames);
174
+ const primitives = new Set(primitiveNames);
175
+ const nonRendering = new Set(nonRenderingNames);
176
+ const elements = [root, ...root.querySelectorAll("*")];
177
+ const definedIds = new Set<string>();
178
+ const referencedIds = new Set<string>();
179
+ let vectorElementCount = 0;
180
+ for (const element of elements) {
181
+ for (const node of element.childNodes) {
182
+ if (
183
+ node.nodeType !== Node.ELEMENT_NODE &&
184
+ node.nodeType !== Node.TEXT_NODE
185
+ ) {
186
+ throw new Error(
187
+ "Downloaded SVG artifact may contain only elements and text nodes.",
188
+ );
189
+ }
190
+ }
191
+ if (element.namespaceURI !== namespace) {
192
+ throw new Error("Downloaded SVG artifact mixes XML namespaces.");
193
+ }
194
+ const name = element.localName.toLowerCase();
195
+ if (forbidden.has(name)) {
196
+ throw new Error(
197
+ `Downloaded SVG artifact contains forbidden <${element.localName}> content.`,
198
+ );
199
+ }
200
+ if (
201
+ primitives.has(name) &&
202
+ productScene.contains(element)
203
+ ) {
204
+ let ancestor = element.parentElement;
205
+ let hiddenDefinition = false;
206
+ while (ancestor && !ancestor.isSameNode(root)) {
207
+ hiddenDefinition ||= nonRendering.has(ancestor.localName.toLowerCase());
208
+ ancestor = ancestor.parentElement;
209
+ }
210
+ if (!hiddenDefinition) vectorElementCount += 1;
211
+ }
212
+
213
+ for (const attribute of element.attributes) {
214
+ const attributeName = attribute.localName.toLowerCase();
215
+ const value = attribute.value.trim();
216
+ if (attributeName === "id") {
217
+ if (!value || definedIds.has(value)) {
218
+ throw new Error(
219
+ "Downloaded SVG artifact ids must be non-empty and unique.",
220
+ );
221
+ }
222
+ definedIds.add(value);
223
+ }
224
+ if (attributeName.startsWith("on")) {
225
+ throw new Error(
226
+ `Downloaded SVG artifact contains event attribute ${attribute.name}.`,
227
+ );
228
+ }
229
+ if (
230
+ attributeName === "href" ||
231
+ attributeName === "src"
232
+ ) {
233
+ if (!value.startsWith("#")) {
234
+ throw new Error(
235
+ `Downloaded SVG artifact contains external ${attribute.name}.`,
236
+ );
237
+ }
238
+ const referencedId = value.slice(1).trim();
239
+ if (!referencedId) {
240
+ throw new Error(
241
+ `Downloaded SVG artifact ${attribute.name} must name a local element.`,
242
+ );
243
+ }
244
+ referencedIds.add(referencedId);
245
+ }
246
+ const urlPattern = /url\(\s*(['"]?)(.*?)\1\s*\)/giu;
247
+ for (const match of value.matchAll(urlPattern)) {
248
+ const reference = match[2]?.trim() ?? "";
249
+ if (!reference.startsWith("#")) {
250
+ throw new Error(
251
+ `Downloaded SVG artifact contains an external url() in ${attribute.name}.`,
252
+ );
253
+ }
254
+ const referencedId = reference.slice(1).trim();
255
+ if (!referencedId) {
256
+ throw new Error(
257
+ `Downloaded SVG artifact url() in ${attribute.name} must name a local element.`,
258
+ );
259
+ }
260
+ referencedIds.add(referencedId);
261
+ }
262
+ }
263
+ }
264
+ for (const referencedId of referencedIds) {
265
+ if (!definedIds.has(referencedId)) {
266
+ throw new Error(
267
+ `Downloaded SVG artifact local reference #${referencedId} has no target.`,
268
+ );
269
+ }
270
+ }
271
+ if (vectorElementCount === 0) {
272
+ throw new Error(
273
+ "Downloaded SVG artifact contains no visible vector primitive.",
274
+ );
275
+ }
276
+
277
+ const objectUrl = URL.createObjectURL(
278
+ new Blob([svgSource], { type: "image/svg+xml" }),
279
+ );
280
+ const image = new Image();
281
+ try {
282
+ image.src = objectUrl;
283
+ await image.decode();
284
+ if (image.naturalWidth <= 0 || image.naturalHeight <= 0) {
285
+ throw new Error("Downloaded SVG artifact decoded with empty bounds.");
286
+ }
287
+ } finally {
288
+ URL.revokeObjectURL(objectUrl);
289
+ }
290
+
291
+ return {
292
+ backgroundColor,
293
+ height,
294
+ vectorElementCount,
295
+ viewBox: [
296
+ Number(viewBox[0]),
297
+ Number(viewBox[1]),
298
+ Number(viewBox[2]),
299
+ Number(viewBox[3]),
300
+ ] as const,
301
+ width,
302
+ };
303
+ },
304
+ {
305
+ backgroundAttribute: TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE,
306
+ forbiddenNames: TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS,
307
+ namespace: TOOLCRAFT_SVG_NAMESPACE,
308
+ nonRenderingNames: TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS,
309
+ primitiveNames: TOOLCRAFT_SVG_VECTOR_PRIMITIVES,
310
+ productSceneAttribute: TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE,
311
+ svgSource: source,
312
+ },
313
+ );
314
+
315
+ const inspection = Object.freeze({
316
+ byteLength: bytes.byteLength,
317
+ backgroundColor: decoded.backgroundColor,
318
+ contentHash: createHash("sha256").update(bytes).digest("hex"),
319
+ height: decoded.height,
320
+ kind: "svg",
321
+ mediaType: "image/svg+xml",
322
+ vectorElementCount: decoded.vectorElementCount,
323
+ viewBox: decoded.viewBox,
324
+ width: decoded.width,
325
+ });
326
+ inspectedSvgArtifacts.add(inspection);
327
+ return Object.freeze({
328
+ inspection,
329
+ source,
330
+ });
331
+ }
@@ -0,0 +1,34 @@
1
+ import type { Download, Page } from "@playwright/test";
2
+
3
+ export async function createToolcraftSvgFixtureDownload(
4
+ page: Page,
5
+ source: string,
6
+ fileName = "column-graph.svg",
7
+ ): Promise<Download> {
8
+ await page.setContent('<button id="svg-download">Download SVG</button>');
9
+ await page.evaluate(
10
+ ({ downloadFileName, svgSource }) => {
11
+ const button = document.querySelector<HTMLButtonElement>("#svg-download");
12
+ if (!button) throw new Error("SVG fixture download button is missing.");
13
+ button.addEventListener(
14
+ "click",
15
+ () => {
16
+ const url = URL.createObjectURL(
17
+ new Blob([svgSource], { type: "image/svg+xml;charset=utf-8" }),
18
+ );
19
+ const anchor = document.createElement("a");
20
+ anchor.download = downloadFileName;
21
+ anchor.href = url;
22
+ anchor.click();
23
+ setTimeout(() => URL.revokeObjectURL(url), 0);
24
+ },
25
+ { once: true },
26
+ );
27
+ },
28
+ { downloadFileName: fileName, svgSource: source },
29
+ );
30
+
31
+ const downloadPromise = page.waitForEvent("download");
32
+ await page.locator("#svg-download").click();
33
+ return downloadPromise;
34
+ }
@@ -1,28 +1,211 @@
1
- import type { FullConfig, Reporter, Suite } from "@playwright/test/reporter";
1
+ import type {
2
+ FullConfig,
3
+ FullResult,
4
+ Reporter,
5
+ Suite,
6
+ } from "@playwright/test/reporter";
7
+ import path from "node:path";
2
8
 
3
9
  import { deriveToolcraftPerformancePaths } from "@repo/toolcraft-runtime";
4
10
 
5
11
  import { createToolcraftDeliveryCatalog } from "../scripts/playwright-test-title-selection.mjs";
6
12
  import { getToolcraftPlaywrightContainingFile } from "../scripts/playwright-containing-file.mjs";
7
- import { starterAcceptance } from "../src/app/starter-acceptance-data";
13
+ import { getToolcraftMotionReferenceArtifactErrors } from "../scripts/toolcraft-motion-reference-artifacts.mjs";
14
+ import type { ToolcraftAcceptanceValidationInput } from "../src/app/acceptance/validate-coverage";
15
+ import {
16
+ starterAcceptance,
17
+ starterControlSectionInventory,
18
+ starterProductReadiness,
19
+ starterTransferMode,
20
+ validateToolcraftAcceptanceCoverage,
21
+ } from "../src/app/starter-acceptance";
8
22
  import { starterPerformance } from "../src/app/starter-performance";
9
23
  import { starterSchema } from "../src/app/starter-schema";
10
24
 
25
+ type ToolcraftDeliveryCatalogReferenceValidationInput =
26
+ ToolcraftAcceptanceValidationInput & { rootDir: string };
27
+
28
+ type ToolcraftMotionReferenceArtifactValidator =
29
+ typeof getToolcraftMotionReferenceArtifactErrors;
30
+
31
+ type ToolcraftDeliveryCatalogFactoryInput = Readonly<{
32
+ acceptance: typeof starterAcceptance;
33
+ availableTests: readonly Readonly<{ file: string; testName: string }>[];
34
+ derivePerformancePaths: typeof deriveToolcraftPerformancePaths;
35
+ performance: typeof starterPerformance;
36
+ rootDir: string;
37
+ schema: typeof starterSchema;
38
+ }>;
39
+
40
+ type ToolcraftDeliveryCatalogFactory = (
41
+ input: ToolcraftDeliveryCatalogFactoryInput,
42
+ ) => unknown;
43
+
44
+ type ToolcraftDeliveryCatalogReporterState =
45
+ | Readonly<{ kind: "idle" }>
46
+ | Readonly<{ error: unknown; kind: "preparation-failed" }>
47
+ | Readonly<{
48
+ catalogInput: ToolcraftDeliveryCatalogFactoryInput;
49
+ kind: "ready";
50
+ referenceValidationInput: ToolcraftDeliveryCatalogReferenceValidationInput;
51
+ }>;
52
+
53
+ type ToolcraftDeliveryCatalogReporterOptions = Readonly<{
54
+ createCatalog?: ToolcraftDeliveryCatalogFactory;
55
+ validateReferences?: typeof validateToolcraftDeliveryCatalogReferences;
56
+ writeError?: (source: string) => void;
57
+ writeOutput?: (source: string) => void;
58
+ }>;
59
+
60
+ function getToolcraftPlaywrightProjectRoot(config: FullConfig): string {
61
+ if (
62
+ typeof config.configFile !== "string" ||
63
+ config.configFile.length === 0 ||
64
+ !path.isAbsolute(config.configFile)
65
+ ) {
66
+ throw new Error(
67
+ "Toolcraft delivery catalog requires an absolute Playwright configFile so project-relative reference artifacts resolve from the app root.",
68
+ );
69
+ }
70
+ return path.dirname(config.configFile);
71
+ }
72
+
73
+ class ToolcraftReferenceValidationError extends Error {
74
+ override readonly name = "ToolcraftReferenceValidationError";
75
+ }
76
+
77
+ function describeUnexpectedError(
78
+ error: unknown,
79
+ seen: ReadonlySet<unknown> = new Set(),
80
+ ): string {
81
+ if (!(error instanceof Error)) return String(error);
82
+ if (seen.has(error)) return "[circular error cause]";
83
+ const nextSeen = new Set(seen).add(error);
84
+ const description = error.stack ?? `${error.name}: ${error.message}`;
85
+ return error.cause === undefined
86
+ ? description
87
+ : `${description}\nCaused by: ${describeUnexpectedError(error.cause, nextSeen)}`;
88
+ }
89
+
90
+ function describeReporterError(error: unknown): string {
91
+ return error instanceof ToolcraftReferenceValidationError
92
+ ? error.message
93
+ : describeUnexpectedError(error);
94
+ }
95
+
96
+ function assertNever(value: never): never {
97
+ throw new Error(`Unexpected Toolcraft catalog reporter state: ${String(value)}`);
98
+ }
99
+
100
+ export async function validateToolcraftDeliveryCatalogReferences(
101
+ {
102
+ acceptance,
103
+ productReadiness,
104
+ rootDir,
105
+ schema,
106
+ sectionInventory,
107
+ transferMode,
108
+ }: ToolcraftDeliveryCatalogReferenceValidationInput,
109
+ validateArtifacts: ToolcraftMotionReferenceArtifactValidator =
110
+ getToolcraftMotionReferenceArtifactErrors,
111
+ ): Promise<void> {
112
+ const semanticErrors = validateToolcraftAcceptanceCoverage({
113
+ acceptance,
114
+ productReadiness,
115
+ schema,
116
+ sectionInventory,
117
+ transferMode,
118
+ });
119
+ const artifactErrors = transferMode.referenceInputs.length === 0
120
+ ? []
121
+ : await validateArtifacts({
122
+ referenceInputs: transferMode.referenceInputs,
123
+ rootDir,
124
+ });
125
+ const errors = [...semanticErrors, ...artifactErrors];
126
+ if (errors.length > 0) {
127
+ throw new ToolcraftReferenceValidationError(
128
+ `Toolcraft reference validation failed:\n${errors.join("\n")}`,
129
+ );
130
+ }
131
+ }
132
+
11
133
  export default class ToolcraftDeliveryCatalogReporter implements Reporter {
12
- onBegin(config: FullConfig, suite: Suite): void {
13
- const availableTests = suite.allTests().map((entry) => ({
14
- file: getToolcraftPlaywrightContainingFile(entry, config.rootDir),
15
- testName: entry.title,
16
- }));
17
- const catalog = createToolcraftDeliveryCatalog({
18
- acceptance: starterAcceptance,
19
- availableTests,
20
- derivePerformancePaths: deriveToolcraftPerformancePaths,
21
- performance: starterPerformance,
22
- rootDir: config.rootDir,
23
- schema: starterSchema,
134
+ private readonly createCatalog: ToolcraftDeliveryCatalogFactory;
135
+ private state: ToolcraftDeliveryCatalogReporterState = { kind: "idle" };
136
+ private readonly validateReferences: typeof validateToolcraftDeliveryCatalogReferences;
137
+ private readonly writeError: (source: string) => void;
138
+ private readonly writeOutput: (source: string) => void;
139
+
140
+ constructor(options: ToolcraftDeliveryCatalogReporterOptions = {}) {
141
+ this.createCatalog = options.createCatalog ?? createToolcraftDeliveryCatalog;
142
+ this.validateReferences =
143
+ options.validateReferences ?? validateToolcraftDeliveryCatalogReferences;
144
+ this.writeError = options.writeError ?? ((source) => {
145
+ process.stderr.write(source);
146
+ });
147
+ this.writeOutput = options.writeOutput ?? ((source) => {
148
+ process.stdout.write(source);
24
149
  });
25
- process.stdout.write(`${JSON.stringify(catalog)}\n`);
150
+ }
151
+
152
+ onBegin(config: FullConfig, suite: Suite): void {
153
+ try {
154
+ const projectRoot = getToolcraftPlaywrightProjectRoot(config);
155
+ const referenceValidationInput = {
156
+ acceptance: starterAcceptance,
157
+ productReadiness: starterProductReadiness,
158
+ rootDir: projectRoot,
159
+ schema: starterSchema,
160
+ sectionInventory: starterControlSectionInventory,
161
+ transferMode: starterTransferMode,
162
+ };
163
+ const availableTests = suite.allTests().map((entry) => ({
164
+ file: getToolcraftPlaywrightContainingFile(entry, config.rootDir),
165
+ testName: entry.title,
166
+ }));
167
+ const catalogInput = {
168
+ acceptance: starterAcceptance,
169
+ availableTests,
170
+ derivePerformancePaths: deriveToolcraftPerformancePaths,
171
+ performance: starterPerformance,
172
+ rootDir: config.rootDir,
173
+ schema: starterSchema,
174
+ };
175
+ this.state = { catalogInput, kind: "ready", referenceValidationInput };
176
+ } catch (error) {
177
+ this.state = { error, kind: "preparation-failed" };
178
+ }
179
+ }
180
+
181
+ async onEnd(_result: FullResult): Promise<{ status: "failed" } | void> {
182
+ const state = this.state;
183
+ switch (state.kind) {
184
+ case "idle":
185
+ return this.reportFailure(new Error(
186
+ "Toolcraft delivery catalog reporter did not receive a complete onBegin lifecycle.",
187
+ ));
188
+ case "preparation-failed":
189
+ return this.reportFailure(state.error);
190
+ case "ready":
191
+ try {
192
+ await this.validateReferences(state.referenceValidationInput);
193
+ const catalog = this.createCatalog(state.catalogInput);
194
+ this.writeOutput(`${JSON.stringify(catalog)}\n`);
195
+ return;
196
+ } catch (error) {
197
+ return this.reportFailure(error);
198
+ }
199
+ default:
200
+ return assertNever(state);
201
+ }
202
+ }
203
+
204
+ private reportFailure(error: unknown): { status: "failed" } {
205
+ this.writeError(
206
+ `Toolcraft delivery catalog collection failed:\n${describeReporterError(error)}\n`,
207
+ );
208
+ return { status: "failed" };
26
209
  }
27
210
 
28
211
  printsToStdio(): boolean {