quiver-cli 1.3.0 → 2.0.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 (384) hide show
  1. package/README.md +197 -239
  2. package/dist/cli.js +3163 -2040
  3. package/package.json +10 -11
  4. package/template/.agents/AGENTS.md +0 -26
  5. package/template/.agents/commands/cp.md +0 -108
  6. package/template/.agents/commands/next-setup.md +0 -1064
  7. package/template/.agents/commands/review.md +0 -68
  8. package/template/.agents/commands/terraform-readme.md +0 -38
  9. package/template/.agents/config.json +0 -80
  10. package/template/.agents/plugins/opencode/rtk.ts +0 -34
  11. package/template/.agents/skills/agent-browser/SKILL.md +0 -51
  12. package/template/.agents/skills/apps/skybridge/SKILL.md +0 -50
  13. package/template/.agents/skills/code/cleanup/SKILL.md +0 -26
  14. package/template/.agents/skills/code/improve/SKILL.md +0 -122
  15. package/template/.agents/skills/code/improve/references/audit-playbook.md +0 -130
  16. package/template/.agents/skills/code/improve/references/closing-the-loop.md +0 -96
  17. package/template/.agents/skills/code/improve/references/plan-template.md +0 -197
  18. package/template/.agents/skills/code/vercel-react-best-practices/AGENTS.md +0 -3810
  19. package/template/.agents/skills/code/vercel-react-best-practices/README.md +0 -123
  20. package/template/.agents/skills/code/vercel-react-best-practices/SKILL.md +0 -149
  21. package/template/.agents/skills/code/vercel-react-best-practices/metadata.json +0 -15
  22. package/template/.agents/skills/code/vercel-react-best-practices/rules/_sections.md +0 -46
  23. package/template/.agents/skills/code/vercel-react-best-practices/rules/_template.md +0 -28
  24. package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-effect-event-deps.md +0 -56
  25. package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  26. package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  27. package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  28. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  29. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +0 -37
  30. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-defer-await.md +0 -82
  31. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  32. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-parallel.md +0 -28
  33. package/template/.agents/skills/code/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  34. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-analyzable-paths.md +0 -63
  35. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -60
  36. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  37. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  38. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  39. package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  40. package/template/.agents/skills/code/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  41. package/template/.agents/skills/code/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  42. package/template/.agents/skills/code/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  43. package/template/.agents/skills/code/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  44. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  45. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  46. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  47. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  48. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  49. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  50. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  51. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  52. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  53. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  54. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  55. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-request-idle-callback.md +0 -105
  56. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  57. package/template/.agents/skills/code/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  58. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  59. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  60. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  61. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  62. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  63. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  64. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  65. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  66. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  67. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  68. package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  69. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  70. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  71. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  72. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  73. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  74. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  75. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  76. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  77. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  78. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  79. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  80. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
  81. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  82. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
  83. package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  84. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  85. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  86. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  87. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  88. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  89. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -149
  90. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-no-shared-module-state.md +0 -50
  91. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  92. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +0 -34
  93. package/template/.agents/skills/code/vercel-react-best-practices/rules/server-serialization.md +0 -38
  94. package/template/.agents/skills/data/prisma-cli/SKILL.md +0 -247
  95. package/template/.agents/skills/data/prisma-cli/references/db-execute.md +0 -78
  96. package/template/.agents/skills/data/prisma-cli/references/db-pull.md +0 -185
  97. package/template/.agents/skills/data/prisma-cli/references/db-push.md +0 -148
  98. package/template/.agents/skills/data/prisma-cli/references/db-seed.md +0 -188
  99. package/template/.agents/skills/data/prisma-cli/references/debug.md +0 -46
  100. package/template/.agents/skills/data/prisma-cli/references/dev.md +0 -157
  101. package/template/.agents/skills/data/prisma-cli/references/format.md +0 -48
  102. package/template/.agents/skills/data/prisma-cli/references/generate.md +0 -173
  103. package/template/.agents/skills/data/prisma-cli/references/init.md +0 -136
  104. package/template/.agents/skills/data/prisma-cli/references/mcp.md +0 -38
  105. package/template/.agents/skills/data/prisma-cli/references/migrate-deploy.md +0 -127
  106. package/template/.agents/skills/data/prisma-cli/references/migrate-dev.md +0 -145
  107. package/template/.agents/skills/data/prisma-cli/references/migrate-diff.md +0 -89
  108. package/template/.agents/skills/data/prisma-cli/references/migrate-reset.md +0 -78
  109. package/template/.agents/skills/data/prisma-cli/references/migrate-resolve.md +0 -57
  110. package/template/.agents/skills/data/prisma-cli/references/migrate-status.md +0 -65
  111. package/template/.agents/skills/data/prisma-cli/references/studio.md +0 -137
  112. package/template/.agents/skills/data/prisma-cli/references/validate.md +0 -53
  113. package/template/.agents/skills/data/prisma-client-api/SKILL.md +0 -216
  114. package/template/.agents/skills/data/prisma-client-api/references/client-methods.md +0 -223
  115. package/template/.agents/skills/data/prisma-client-api/references/constructor.md +0 -208
  116. package/template/.agents/skills/data/prisma-client-api/references/filters.md +0 -256
  117. package/template/.agents/skills/data/prisma-client-api/references/model-queries.md +0 -281
  118. package/template/.agents/skills/data/prisma-client-api/references/query-options.md +0 -276
  119. package/template/.agents/skills/data/prisma-client-api/references/raw-queries.md +0 -194
  120. package/template/.agents/skills/data/prisma-client-api/references/relations.md +0 -308
  121. package/template/.agents/skills/data/prisma-client-api/references/transactions.md +0 -184
  122. package/template/.agents/skills/design/impeccable/SKILL.md +0 -84
  123. package/template/.agents/skills/design/impeccable/reference/adapt.md +0 -312
  124. package/template/.agents/skills/design/impeccable/reference/adapt.native.md +0 -58
  125. package/template/.agents/skills/design/impeccable/reference/android.md +0 -40
  126. package/template/.agents/skills/design/impeccable/reference/animate.md +0 -86
  127. package/template/.agents/skills/design/impeccable/reference/audit.md +0 -136
  128. package/template/.agents/skills/design/impeccable/reference/audit.native.md +0 -139
  129. package/template/.agents/skills/design/impeccable/reference/bolder.md +0 -31
  130. package/template/.agents/skills/design/impeccable/reference/clarify.md +0 -94
  131. package/template/.agents/skills/design/impeccable/reference/colorize.md +0 -86
  132. package/template/.agents/skills/design/impeccable/reference/craft-floor.md +0 -42
  133. package/template/.agents/skills/design/impeccable/reference/craft.md +0 -5
  134. package/template/.agents/skills/design/impeccable/reference/critique.md +0 -788
  135. package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +0 -90
  136. package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +0 -24
  137. package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +0 -37
  138. package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +0 -92
  139. package/template/.agents/skills/design/impeccable/reference/delight.md +0 -70
  140. package/template/.agents/skills/design/impeccable/reference/distill.md +0 -111
  141. package/template/.agents/skills/design/impeccable/reference/doctor.md +0 -53
  142. package/template/.agents/skills/design/impeccable/reference/document.md +0 -416
  143. package/template/.agents/skills/design/impeccable/reference/extract.md +0 -69
  144. package/template/.agents/skills/design/impeccable/reference/harden.md +0 -336
  145. package/template/.agents/skills/design/impeccable/reference/hooks.md +0 -105
  146. package/template/.agents/skills/design/impeccable/reference/init.md +0 -125
  147. package/template/.agents/skills/design/impeccable/reference/ios.md +0 -45
  148. package/template/.agents/skills/design/impeccable/reference/layout.md +0 -84
  149. package/template/.agents/skills/design/impeccable/reference/live-setup.md +0 -102
  150. package/template/.agents/skills/design/impeccable/reference/live.md +0 -323
  151. package/template/.agents/skills/design/impeccable/reference/new-work.md +0 -105
  152. package/template/.agents/skills/design/impeccable/reference/onboard.md +0 -234
  153. package/template/.agents/skills/design/impeccable/reference/operate.md +0 -61
  154. package/template/.agents/skills/design/impeccable/reference/optimize.md +0 -258
  155. package/template/.agents/skills/design/impeccable/reference/overdrive.md +0 -127
  156. package/template/.agents/skills/design/impeccable/reference/polish.md +0 -97
  157. package/template/.agents/skills/design/impeccable/reference/quieter.md +0 -99
  158. package/template/.agents/skills/design/impeccable/reference/routing.md +0 -18
  159. package/template/.agents/skills/design/impeccable/reference/shape.md +0 -59
  160. package/template/.agents/skills/design/impeccable/reference/typeset.md +0 -80
  161. package/template/.agents/skills/design/impeccable/reference/visualize.md +0 -47
  162. package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +0 -94
  163. package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +0 -558
  164. package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +0 -334
  165. package/template/.agents/skills/design/impeccable/scripts/context.mjs +0 -1450
  166. package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +0 -213
  167. package/template/.agents/skills/design/impeccable/scripts/detect-csp.mjs +0 -198
  168. package/template/.agents/skills/design/impeccable/scripts/detect.mjs +0 -21
  169. package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +0 -2023
  170. package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +0 -438
  171. package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +0 -983
  172. package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +0 -8283
  173. package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +0 -50
  174. package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +0 -372
  175. package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +0 -768
  176. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +0 -1186
  177. package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +0 -264
  178. package/template/.agents/skills/design/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -189
  179. package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +0 -18
  180. package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +0 -212
  181. package/template/.agents/skills/design/impeccable/scripts/detector/profile/profiler.mjs +0 -166
  182. package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +0 -617
  183. package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +0 -5580
  184. package/template/.agents/skills/design/impeccable/scripts/detector/shared/color.mjs +0 -124
  185. package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +0 -112
  186. package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +0 -30
  187. package/template/.agents/skills/design/impeccable/scripts/detector/shared/inline-ignores.mjs +0 -148
  188. package/template/.agents/skills/design/impeccable/scripts/detector/shared/page.mjs +0 -7
  189. package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +0 -336
  190. package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +0 -133
  191. package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +0 -240
  192. package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +0 -741
  193. package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +0 -516
  194. package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +0 -2100
  195. package/template/.agents/skills/design/impeccable/scripts/hook.mjs +0 -78
  196. package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +0 -93
  197. package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +0 -200
  198. package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +0 -357
  199. package/template/.agents/skills/design/impeccable/scripts/lib/design-parser.mjs +0 -842
  200. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +0 -658
  201. package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +0 -137
  202. package/template/.agents/skills/design/impeccable/scripts/lib/is-generated.mjs +0 -69
  203. package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +0 -5
  204. package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +0 -362
  205. package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +0 -457
  206. package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +0 -169
  207. package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +0 -457
  208. package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +0 -151
  209. package/template/.agents/skills/design/impeccable/scripts/lib/target-args.mjs +0 -42
  210. package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +0 -33
  211. package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +0 -146
  212. package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +0 -617
  213. package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +0 -60
  214. package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +0 -55
  215. package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +0 -28
  216. package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +0 -199
  217. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +0 -47
  218. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +0 -73
  219. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +0 -143
  220. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +0 -197
  221. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +0 -49
  222. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +0 -161
  223. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +0 -17
  224. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +0 -26
  225. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +0 -71
  226. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +0 -247
  227. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +0 -70
  228. package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +0 -42
  229. package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +0 -149
  230. package/template/.agents/skills/design/impeccable/scripts/live/insert-ui.mjs +0 -458
  231. package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +0 -142
  232. package/template/.agents/skills/design/impeccable/scripts/live/manual-apply.mjs +0 -939
  233. package/template/.agents/skills/design/impeccable/scripts/live/manual-edit-routes.mjs +0 -357
  234. package/template/.agents/skills/design/impeccable/scripts/live/manual-edits-buffer.mjs +0 -152
  235. package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +0 -14
  236. package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +0 -508
  237. package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +0 -563
  238. package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +0 -105
  239. package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +0 -105
  240. package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +0 -961
  241. package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +0 -1342
  242. package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +0 -316
  243. package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +0 -280
  244. package/template/.agents/skills/design/impeccable/scripts/live/ui-core.mjs +0 -180
  245. package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +0 -171
  246. package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +0 -954
  247. package/template/.agents/skills/design/impeccable/scripts/live-browser-dom.js +0 -146
  248. package/template/.agents/skills/design/impeccable/scripts/live-browser-session.js +0 -123
  249. package/template/.agents/skills/design/impeccable/scripts/live-browser.js +0 -12512
  250. package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +0 -1244
  251. package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +0 -107
  252. package/template/.agents/skills/design/impeccable/scripts/live-copy-edit-agent.mjs +0 -683
  253. package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +0 -51
  254. package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +0 -503
  255. package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +0 -292
  256. package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +0 -368
  257. package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +0 -429
  258. package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +0 -123
  259. package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +0 -1661
  260. package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +0 -71
  261. package/template/.agents/skills/design/impeccable/scripts/live-target.mjs +0 -30
  262. package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +0 -927
  263. package/template/.agents/skills/design/impeccable/scripts/live.mjs +0 -359
  264. package/template/.agents/skills/design/impeccable/scripts/modern-screenshot.umd.js +0 -14
  265. package/template/.agents/skills/design/impeccable/scripts/palette.mjs +0 -628
  266. package/template/.agents/skills/design/impeccable/scripts/pin.mjs +0 -221
  267. package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +0 -932
  268. package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +0 -74
  269. package/template/.agents/skills/design/shadcn/SKILL.md +0 -277
  270. package/template/.agents/skills/design/shadcn/agents/openai.yml +0 -5
  271. package/template/.agents/skills/design/shadcn/assets/shadcn-small.png +0 -0
  272. package/template/.agents/skills/design/shadcn/assets/shadcn.png +0 -0
  273. package/template/.agents/skills/design/shadcn/cli.md +0 -290
  274. package/template/.agents/skills/design/shadcn/customization.md +0 -209
  275. package/template/.agents/skills/design/shadcn/evals/evals.json +0 -77
  276. package/template/.agents/skills/design/shadcn/mcp.md +0 -105
  277. package/template/.agents/skills/design/shadcn/registry.md +0 -277
  278. package/template/.agents/skills/design/shadcn/rules/base-vs-radix.md +0 -306
  279. package/template/.agents/skills/design/shadcn/rules/chat.md +0 -224
  280. package/template/.agents/skills/design/shadcn/rules/composition.md +0 -213
  281. package/template/.agents/skills/design/shadcn/rules/forms.md +0 -192
  282. package/template/.agents/skills/design/shadcn/rules/icons.md +0 -101
  283. package/template/.agents/skills/design/shadcn/rules/styling.md +0 -185
  284. package/template/.agents/skills/find-skills/SKILL.md +0 -141
  285. package/template/.agents/skills/hono/SKILL.md +0 -579
  286. package/template/.agents/skills/integrations/langfuse/SKILL.md +0 -146
  287. package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +0 -41
  288. package/template/.agents/skills/integrations/langfuse/references/cli.md +0 -60
  289. package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +0 -88
  290. package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +0 -121
  291. package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +0 -291
  292. package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +0 -35
  293. package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +0 -79
  294. package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +0 -55
  295. package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +0 -76
  296. package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +0 -92
  297. package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +0 -73
  298. package/template/.agents/skills/integrations/posthog/SKILL.md +0 -102
  299. package/template/.agents/skills/integrations/posthog/references/error-tracking-alerts.md +0 -63
  300. package/template/.agents/skills/integrations/posthog/references/error-tracking-assigning-issues.md +0 -77
  301. package/template/.agents/skills/integrations/posthog/references/error-tracking-fingerprints.md +0 -57
  302. package/template/.agents/skills/integrations/posthog/references/error-tracking-monitoring.md +0 -140
  303. package/template/.agents/skills/integrations/posthog/references/error-tracking-nextjs.md +0 -490
  304. package/template/.agents/skills/integrations/posthog/references/error-tracking-source-maps.md +0 -45
  305. package/template/.agents/skills/integrations/posthog/references/feature-flags-best-practices.md +0 -139
  306. package/template/.agents/skills/integrations/posthog/references/feature-flags-react.md +0 -302
  307. package/template/.agents/skills/integrations/posthog/references/identify-users.md +0 -202
  308. package/template/.agents/skills/integrations/posthog/references/integration-example.md +0 -706
  309. package/template/.agents/skills/integrations/posthog/references/integration-nextjs.md +0 -385
  310. package/template/.agents/skills/integrations/posthog/references/integration-step-1-begin.md +0 -43
  311. package/template/.agents/skills/integrations/posthog/references/integration-step-2-edit.md +0 -37
  312. package/template/.agents/skills/integrations/posthog/references/integration-step-3-revise.md +0 -22
  313. package/template/.agents/skills/integrations/posthog/references/integration-step-4-conclude.md +0 -38
  314. package/template/.agents/skills/integrations/posthog/references/llm-analytics-anthropic.md +0 -200
  315. package/template/.agents/skills/integrations/posthog/references/llm-analytics-basics.md +0 -62
  316. package/template/.agents/skills/integrations/posthog/references/llm-analytics-costs.md +0 -197
  317. package/template/.agents/skills/integrations/posthog/references/llm-analytics-manual-capture.md +0 -397
  318. package/template/.agents/skills/integrations/posthog/references/llm-analytics-traces.md +0 -98
  319. package/template/.agents/skills/integrations/posthog/references/llm-analytics-vercel-ai.md +0 -120
  320. package/template/.agents/skills/repo/repo-ci/SKILL.md +0 -265
  321. package/template/.agents/skills/repo/repo-init-next-js/SKILL.md +0 -129
  322. package/template/.agents/skills/repo/repo-init-next-js/references/file-contents.md +0 -800
  323. package/template/.agents/skills/repo/repo-init-next-js/scripts/setup.sh +0 -47
  324. package/template/.agents/skills/repo/repo-init-node/SKILL.md +0 -196
  325. package/template/.agents/skills/skill-creator/LICENSE.txt +0 -202
  326. package/template/.agents/skills/skill-creator/SKILL.md +0 -485
  327. package/template/.agents/skills/skill-creator/agents/analyzer.md +0 -274
  328. package/template/.agents/skills/skill-creator/agents/comparator.md +0 -202
  329. package/template/.agents/skills/skill-creator/agents/grader.md +0 -223
  330. package/template/.agents/skills/skill-creator/assets/eval_review.html +0 -146
  331. package/template/.agents/skills/skill-creator/eval-viewer/generate_review.py +0 -471
  332. package/template/.agents/skills/skill-creator/eval-viewer/viewer.html +0 -1325
  333. package/template/.agents/skills/skill-creator/references/schemas.md +0 -430
  334. package/template/.agents/skills/skill-creator/scripts/__init__.py +0 -0
  335. package/template/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
  336. package/template/.agents/skills/skill-creator/scripts/generate_report.py +0 -326
  337. package/template/.agents/skills/skill-creator/scripts/improve_description.py +0 -247
  338. package/template/.agents/skills/skill-creator/scripts/package_skill.py +0 -136
  339. package/template/.agents/skills/skill-creator/scripts/quick_validate.py +0 -103
  340. package/template/.agents/skills/skill-creator/scripts/run_eval.py +0 -310
  341. package/template/.agents/skills/skill-creator/scripts/run_loop.py +0 -328
  342. package/template/.agents/skills/skill-creator/scripts/utils.py +0 -47
  343. package/template/.agents/skills/supabase/CHANGELOG.md +0 -71
  344. package/template/.agents/skills/supabase/SKILL.md +0 -145
  345. package/template/.agents/skills/supabase/assets/feedback-issue-template.md +0 -17
  346. package/template/.agents/skills/supabase/references/skill-feedback.md +0 -17
  347. package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +0 -73
  348. package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +0 -64
  349. package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +0 -170
  350. package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +0 -39
  351. package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +0 -34
  352. package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +0 -55
  353. package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +0 -49
  354. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +0 -46
  355. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +0 -44
  356. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +0 -41
  357. package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +0 -46
  358. package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +0 -54
  359. package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +0 -53
  360. package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +0 -50
  361. package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +0 -50
  362. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +0 -56
  363. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +0 -68
  364. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +0 -50
  365. package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +0 -54
  366. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +0 -45
  367. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +0 -55
  368. package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +0 -55
  369. package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +0 -44
  370. package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +0 -40
  371. package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +0 -48
  372. package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +0 -43
  373. package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +0 -45
  374. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +0 -80
  375. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +0 -46
  376. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +0 -59
  377. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +0 -55
  378. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +0 -55
  379. package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +0 -61
  380. package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +0 -54
  381. package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +0 -50
  382. package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +0 -63
  383. package/template/.agents/skills/writing/humanizer/SKILL.md +0 -621
  384. package/template/.agents/upstreams.json +0 -116
@@ -1,961 +0,0 @@
1
- /**
2
- * AST-based Svelte scaffolding for live component previews.
3
- *
4
- * The scaffolder turns the selected block of a route's markup into a detached
5
- * preview component whose dynamic values arrive as props. The old
6
- * implementation matched `{...}` with a regex, which flattened control-flow
7
- * blocks ({#each}, {#if}) into scalar text props and shipped structurally
8
- * wrong previews. This module uses the app's own svelte compiler
9
- * (parse with modern: true) and replaces only expressions that are FREE,
10
- * i.e. reference identifiers not bound by an enclosing template scope:
11
- *
12
- * {#each stages as stage, i} stages -> collection prop (array)
13
- * <span>{stage.label}</span> bound -> left verbatim
14
- * {/each}
15
- * <p>{footerNote}</p> free -> text prop (string)
16
- *
17
- * Constructs that cannot work in a detached component (component tags whose
18
- * imports live in the route file, bind:/use: directives, await blocks,
19
- * render tags) mark the analysis unsupported; the caller falls back to
20
- * source-preview mode, which keeps the markup inside the route file where
21
- * those references still resolve. A wrong preview is worse than a plain one.
22
- *
23
- * The compiler is resolved from the APP's node_modules, never bundled: the
24
- * preview must be parsed by the same svelte version that will compile it.
25
- */
26
-
27
- import { createRequire } from 'node:module';
28
- import path from 'node:path';
29
-
30
- const HANDLER_ATTR_RE = /^on[a-z]/;
31
-
32
- /**
33
- * Resolve the app's svelte compiler synchronously (svelte 5 ships a CJS
34
- * compiler build, so createRequire works and the accept/scaffold pipeline
35
- * stays synchronous). Returns { parse, compile, VERSION } or null.
36
- */
37
- export function loadSvelteCompiler(appRoot) {
38
- try {
39
- const req = createRequire(path.join(appRoot, 'package.json'));
40
- const mod = req('svelte/compiler');
41
- if (typeof mod.parse !== 'function') return null;
42
- const major = parseInt(String(mod.VERSION || '0'), 10);
43
- if (major < 5) return null; // detached mount() previews are svelte 5 only
44
- return { parse: mod.parse, compile: mod.compile, VERSION: mod.VERSION };
45
- } catch {
46
- return null;
47
- }
48
- }
49
-
50
- // ---------------------------------------------------------------------------
51
- // ESTree helpers
52
- // ---------------------------------------------------------------------------
53
-
54
- /**
55
- * Collect the root identifiers an ESTree expression reads. Walks generically;
56
- * skips non-computed member properties and non-computed/non-shorthand object
57
- * keys, which are names, not references.
58
- */
59
- export function collectRootIdentifiers(node, out = new Set()) {
60
- if (!node || typeof node !== 'object') return out;
61
- if (Array.isArray(node)) {
62
- for (const item of node) collectRootIdentifiers(item, out);
63
- return out;
64
- }
65
- switch (node.type) {
66
- case 'Identifier':
67
- out.add(node.name);
68
- return out;
69
- case 'MemberExpression':
70
- collectRootIdentifiers(node.object, out);
71
- if (node.computed) collectRootIdentifiers(node.property, out);
72
- return out;
73
- case 'Property':
74
- if (node.computed) collectRootIdentifiers(node.key, out);
75
- collectRootIdentifiers(node.value, out);
76
- return out;
77
- case 'ArrowFunctionExpression':
78
- case 'FunctionExpression': {
79
- // Params shadow outer names inside the body.
80
- const bound = new Set();
81
- for (const param of node.params || []) collectPatternNames(param, bound);
82
- const inner = collectRootIdentifiers(node.body, new Set());
83
- for (const name of inner) if (!bound.has(name)) out.add(name);
84
- return out;
85
- }
86
- default: {
87
- for (const key of Object.keys(node)) {
88
- if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
89
- collectRootIdentifiers(node[key], out);
90
- }
91
- return out;
92
- }
93
- }
94
- }
95
-
96
- /** Collect names bound by a destructuring pattern (each contexts, const tags). */
97
- export function collectPatternNames(pattern, out = new Set()) {
98
- if (!pattern || typeof pattern !== 'object') return out;
99
- switch (pattern.type) {
100
- case 'Identifier':
101
- out.add(pattern.name);
102
- return out;
103
- case 'ObjectPattern':
104
- for (const prop of pattern.properties || []) {
105
- if (prop.type === 'RestElement') collectPatternNames(prop.argument, out);
106
- else collectPatternNames(prop.value, out);
107
- }
108
- return out;
109
- case 'ArrayPattern':
110
- for (const el of pattern.elements || []) if (el) collectPatternNames(el, out);
111
- return out;
112
- case 'AssignmentPattern':
113
- collectPatternNames(pattern.left, out);
114
- return out;
115
- case 'RestElement':
116
- collectPatternNames(pattern.argument, out);
117
- return out;
118
- default:
119
- return out;
120
- }
121
- }
122
-
123
- // ---------------------------------------------------------------------------
124
- // Template analysis
125
- // ---------------------------------------------------------------------------
126
-
127
- class Analysis {
128
- constructor(source) {
129
- this.source = source;
130
- this.replacements = []; // { start, end, prop } source ranges to swap
131
- this.contract = []; // [{ prop, expr, kind, ... }]
132
- this.byExpr = new Map(); // expr text -> contract entry
133
- this.usedNames = new Set();
134
- this.unsupported = null;
135
- }
136
-
137
- fail(reason) {
138
- if (!this.unsupported) this.unsupported = reason;
139
- }
140
-
141
- propFor(exprText, kind, extra = {}) {
142
- const existing = this.byExpr.get(exprText);
143
- if (existing) return existing;
144
- const base = derivePropName(exprText);
145
- let name = base;
146
- let n = 2;
147
- while (this.usedNames.has(name)) name = `${base}${n++}`;
148
- this.usedNames.add(name);
149
- const entry = { prop: name, expr: exprText, kind, ...extra };
150
- this.byExpr.set(exprText, entry);
151
- this.contract.push(entry);
152
- return entry;
153
- }
154
- }
155
-
156
- // A derived prop name lands in `let { <name> } = $props()`; a reserved word
157
- // there is a syntax error the session only hits at import time.
158
- const RESERVED_PROP_NAMES = new Set([
159
- 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
160
- 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'false',
161
- 'finally', 'for', 'function', 'if', 'implements', 'import', 'in',
162
- 'instanceof', 'interface', 'let', 'new', 'null', 'package', 'private',
163
- 'protected', 'public', 'return', 'static', 'super', 'switch', 'this',
164
- 'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', 'while',
165
- 'with', 'yield',
166
- ]);
167
-
168
- export function derivePropName(expr) {
169
- const tail = String(expr).match(/(?:\.|\[["']?)([A-Za-z_$][\w$]*)["']?\]?\s*$/);
170
- const candidate = (tail && tail[1])
171
- || (String(expr).match(/^([A-Za-z_$][\w$]*)$/) || [])[1]
172
- || 'value';
173
- return RESERVED_PROP_NAMES.has(candidate) ? `${candidate}Value` : candidate;
174
- }
175
-
176
- function exprText(source, node) {
177
- return source.slice(node.start, node.end);
178
- }
179
-
180
- // Identifiers that resolve in ANY module scope. They are neither hydratable
181
- // props nor evidence of route coupling, so they count as neither free nor
182
- // bound: `{Math.round(x)}` must not mint a prop named `round`, and
183
- // `{fmt(stage.label)}` must not pass as global-only.
184
- const GLOBAL_IDENTIFIERS = new Set([
185
- 'Math', 'JSON', 'Date', 'Intl', 'Number', 'String', 'Boolean', 'Array',
186
- 'Object', 'Map', 'Set', 'Promise', 'RegExp', 'NaN', 'Infinity', 'undefined',
187
- 'isNaN', 'isFinite', 'parseInt', 'parseFloat', 'encodeURIComponent',
188
- 'decodeURIComponent', 'console', 'window', 'document', 'navigator',
189
- 'location', 'structuredClone', 'crypto',
190
- ]);
191
-
192
- function classifyRoots(node, scopes) {
193
- const roots = collectRootIdentifiers(node);
194
- let bound = 0;
195
- let free = 0;
196
- for (const name of roots) {
197
- if (GLOBAL_IDENTIFIERS.has(name)) continue;
198
- if (scopes.some((scope) => scope.has(name))) bound++;
199
- else free++;
200
- }
201
- return { bound, free };
202
- }
203
-
204
- function isFree(node, scopes) {
205
- const { bound, free } = classifyRoots(node, scopes);
206
- return free > 0 && bound === 0;
207
- }
208
-
209
- /**
210
- * An expression mixing loop-bound and outer free identifiers (e.g.
211
- * `{fmt(stage.label)}` where `fmt` lives in the route script) can neither
212
- * become a prop (the bound part varies per item) nor survive detachment
213
- * verbatim (the free name is undeclared in the preview and throws at mount,
214
- * past the compile gate, because globals make it legal to the compiler).
215
- * Source-preview mode is the only correct home for it.
216
- */
217
- function failOnMixedExpression(node, scopes, analysis, source) {
218
- const { bound, free } = classifyRoots(node, scopes);
219
- if (bound > 0 && free > 0) {
220
- analysis.fail(`expression mixing loop and outer identifiers ({${exprText(source, node).slice(0, 60)}}) requires source-preview mode`);
221
- return true;
222
- }
223
- return false;
224
- }
225
-
226
- /**
227
- * Analyze a parsed template fragment. `scopes` is a stack of Sets of bound
228
- * names; the outermost call passes an empty stack.
229
- */
230
- function analyzeFragment(fragment, analysis, scopes) {
231
- if (!fragment || !Array.isArray(fragment.nodes)) return;
232
- // ConstTag declarations bind for the whole fragment.
233
- const fragmentScope = new Set();
234
- const nextScopes = [...scopes, fragmentScope];
235
- for (const node of fragment.nodes) {
236
- if (node.type === 'ConstTag' && node.declaration) {
237
- for (const decl of node.declaration.declarations || []) {
238
- collectPatternNames(decl.id, fragmentScope);
239
- }
240
- }
241
- }
242
- for (const node of fragment.nodes) analyzeNode(node, analysis, nextScopes);
243
- }
244
-
245
- function analyzeNode(node, analysis, scopes) {
246
- if (!node || analysis.unsupported) return;
247
- switch (node.type) {
248
- case 'Text':
249
- case 'Comment':
250
- return;
251
- case 'ExpressionTag': {
252
- if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
253
- if (isFree(node.expression, scopes)) {
254
- const text = exprText(analysis.source, node.expression);
255
- const entry = analysis.propFor(text, 'text');
256
- // node.start/end include the braces; keep them, swap the inside.
257
- analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
258
- }
259
- return;
260
- }
261
- case 'HtmlTag': {
262
- if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
263
- if (isFree(node.expression, scopes)) {
264
- const text = exprText(analysis.source, node.expression);
265
- const entry = analysis.propFor(text, 'raw');
266
- analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
267
- }
268
- return;
269
- }
270
- case 'ConstTag': {
271
- // Its expression may read free names; leave them: the declaration
272
- // travels with the markup and stays valid only if its inputs do.
273
- if (node.declaration) {
274
- for (const decl of node.declaration.declarations || []) {
275
- if (decl.init && failOnMixedExpression(decl.init, scopes, analysis, analysis.source)) return;
276
- if (decl.init && isFree(decl.init, scopes)) {
277
- const text = exprText(analysis.source, decl.init);
278
- const entry = analysis.propFor(text, 'text');
279
- analysis.replacements.push({ start: decl.init.start, end: decl.init.end, prop: entry.prop });
280
- }
281
- }
282
- }
283
- return;
284
- }
285
- case 'EachBlock': {
286
- if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
287
- if (isFree(node.expression, scopes)) {
288
- const text = exprText(analysis.source, node.expression);
289
- const item = describeEachItem(node, analysis.source);
290
- // Keyed each: the key must evaluate to a distinct value per hydrated
291
- // item or Svelte throws each_key_duplicate at mount. A key that is a
292
- // plain member of the item (the common `(item.id)` shape) gets a
293
- // synthetic per-index value injected by the browser (keyField).
294
- // Anything else cannot be hydrated safely; source-preview mode keeps
295
- // it correct.
296
- if (node.key) {
297
- const keyInfo = classifyEachKey(node);
298
- if (keyInfo.unsupported) {
299
- analysis.fail(keyInfo.unsupported);
300
- return;
301
- }
302
- if (keyInfo.keyField) {
303
- if (item.textSlots.some((slot) => slot.key === keyInfo.keyField)) {
304
- // The key doubles as a displayed slot; a synthetic value would
305
- // change visible text, and the displayed text may not be
306
- // unique. Not previewable in a detached component.
307
- analysis.fail('each key that is also a displayed field requires source-preview mode');
308
- return;
309
- }
310
- item.keyField = keyInfo.keyField;
311
- }
312
- }
313
- const entry = analysis.propFor(text, 'collection', { item });
314
- analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
315
- }
316
- const bound = new Set();
317
- if (node.context) collectPatternNames(node.context, bound);
318
- if (node.index) bound.add(node.index);
319
- analyzeFragment(node.body, analysis, [...scopes, bound]);
320
- if (node.fallback) analyzeFragment(node.fallback, analysis, scopes);
321
- return;
322
- }
323
- case 'IfBlock': {
324
- if (failOnMixedExpression(node.test, scopes, analysis, analysis.source)) return;
325
- if (isFree(node.test, scopes)) {
326
- const text = exprText(analysis.source, node.test);
327
- // The browser hydrates a free condition from what the live page
328
- // currently shows: when the consequent's root element is present
329
- // under the picked element, the condition is on.
330
- const entry = analysis.propFor(text, 'condition', {
331
- probe: describeElementProbe(node.consequent),
332
- });
333
- analysis.replacements.push({ start: node.test.start, end: node.test.end, prop: entry.prop });
334
- }
335
- analyzeFragment(node.consequent, analysis, scopes);
336
- if (node.alternate) analyzeFragment(node.alternate, analysis, scopes);
337
- return;
338
- }
339
- case 'KeyBlock': {
340
- if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
341
- if (isFree(node.expression, scopes)) {
342
- const text = exprText(analysis.source, node.expression);
343
- const entry = analysis.propFor(text, 'text');
344
- analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
345
- }
346
- analyzeFragment(node.fragment, analysis, scopes);
347
- return;
348
- }
349
- case 'SnippetBlock': {
350
- const bound = new Set();
351
- for (const param of node.parameters || []) collectPatternNames(param, bound);
352
- // The snippet's own name becomes available to render tags in this file.
353
- analyzeFragment(node.body, analysis, [...scopes, bound]);
354
- return;
355
- }
356
- case 'RegularElement':
357
- case 'SlotElement':
358
- case 'TitleElement': {
359
- if (node.name === 'script') {
360
- // An inline script inside the selected block carries route-scoped
361
- // code; running it a second time from a detached preview is wrong.
362
- analysis.fail('inline script element requires source-preview mode');
363
- return;
364
- }
365
- analyzeAttributes(node, analysis, scopes);
366
- if (!analysis.unsupported) analyzeFragment(node.fragment, analysis, scopes);
367
- return;
368
- }
369
- case 'SvelteElement':
370
- case 'SvelteFragment':
371
- case 'SvelteBoundary': {
372
- analyzeAttributes(node, analysis, scopes);
373
- if (!analysis.unsupported) analyzeFragment(node.fragment, analysis, scopes);
374
- return;
375
- }
376
- case 'Component':
377
- case 'SvelteComponent':
378
- case 'SvelteSelf':
379
- // The component's import lives in the route file; a detached preview
380
- // cannot resolve it. Source-preview mode keeps it working.
381
- analysis.fail(`component tag <${node.name || 'Component'}> requires source-preview mode`);
382
- return;
383
- case 'RenderTag':
384
- analysis.fail('render tag requires source-preview mode');
385
- return;
386
- case 'AwaitBlock':
387
- analysis.fail('await block requires source-preview mode');
388
- return;
389
- case 'SvelteHead':
390
- case 'SvelteWindow':
391
- case 'SvelteDocument':
392
- case 'SvelteBody':
393
- analysis.fail(`${node.type} requires source-preview mode`);
394
- return;
395
- default: {
396
- if (node.fragment) analyzeFragment(node.fragment, analysis, scopes);
397
- return;
398
- }
399
- }
400
- }
401
-
402
- function analyzeAttributes(node, analysis, scopes) {
403
- for (const attr of node.attributes || []) {
404
- switch (attr.type) {
405
- case 'Attribute': {
406
- if (attr.value === true) break;
407
- const parts = Array.isArray(attr.value) ? attr.value : [attr.value];
408
- for (const part of parts) {
409
- if (!part || part.type !== 'ExpressionTag') continue;
410
- if (failOnMixedExpression(part.expression, scopes, analysis, analysis.source)) return;
411
- if (!isFree(part.expression, scopes)) continue;
412
- const text = exprText(analysis.source, part.expression);
413
- const kind = HANDLER_ATTR_RE.test(attr.name) ? 'handler' : 'text';
414
- const entry = analysis.propFor(text, kind);
415
- analysis.replacements.push({ start: part.expression.start, end: part.expression.end, prop: entry.prop });
416
- }
417
- break;
418
- }
419
- case 'ClassDirective': {
420
- const expr = attr.expression;
421
- if (expr && failOnMixedExpression(expr, scopes, analysis, analysis.source)) return;
422
- if (expr && isFree(expr, scopes)) {
423
- const text = exprText(analysis.source, expr);
424
- // The directive's class name is literal, so the live DOM answers
425
- // the condition directly: the class is either present or not.
426
- const entry = analysis.propFor(text, 'condition', {
427
- probe: { className: attr.name },
428
- });
429
- analysis.replacements.push({ start: expr.start, end: expr.end, prop: entry.prop });
430
- }
431
- break;
432
- }
433
- case 'StyleDirective': {
434
- // Unlike ClassDirective, a style directive stores its value in
435
- // attribute shape: `true` for the shorthand, else an array of parts.
436
- const parts = attr.value === true ? [] : (Array.isArray(attr.value) ? attr.value : [attr.value]);
437
- for (const part of parts) {
438
- if (part?.type === 'ExpressionTag'
439
- && failOnMixedExpression(part.expression, scopes, analysis, analysis.source)) {
440
- return;
441
- }
442
- }
443
- const dynamic = parts.some((part) => part?.type === 'ExpressionTag' && isFree(part.expression, scopes));
444
- const shorthandFree = attr.value === true && isFree({ type: 'Identifier', name: attr.name }, scopes);
445
- if (dynamic || shorthandFree) {
446
- // style:opacity={x} carries a css VALUE, not a boolean, and the
447
- // computed value on the live element is not reliably recoverable in
448
- // the shape the expression produced. A falsified style is worse
449
- // than an HMR-resetting preview.
450
- analysis.fail(`style:${attr.name} with a dynamic value requires source-preview mode`);
451
- }
452
- break;
453
- }
454
- case 'BindDirective':
455
- analysis.fail(`bind:${attr.name} requires source-preview mode`);
456
- return;
457
- case 'UseDirective':
458
- analysis.fail(`use:${attr.name} requires source-preview mode`);
459
- return;
460
- case 'AnimateDirective':
461
- case 'TransitionDirective':
462
- // Motion directives reference route-scoped or svelte/transition
463
- // imports; a detached preview cannot resolve them.
464
- analysis.fail(`${attr.type} requires source-preview mode`);
465
- return;
466
- case 'OnDirective': {
467
- // Legacy on:click syntax; treat like handler attributes.
468
- const expr = attr.expression;
469
- if (expr && failOnMixedExpression(expr, scopes, analysis, analysis.source)) return;
470
- if (expr && isFree(expr, scopes)) {
471
- const text = exprText(analysis.source, expr);
472
- const entry = analysis.propFor(text, 'handler');
473
- analysis.replacements.push({ start: expr.start, end: expr.end, prop: entry.prop });
474
- }
475
- break;
476
- }
477
- case 'SpreadAttribute':
478
- analysis.fail('spread attribute requires source-preview mode');
479
- return;
480
- default:
481
- break;
482
- }
483
- }
484
- }
485
-
486
- /**
487
- * Describe the repeating item of an each block for browser-side hydration:
488
- * the item's root element (tag + static classes, used to count live
489
- * iterations) and the ordered text slots that reference loop bindings.
490
- */
491
- function describeEachItem(node, source) {
492
- const body = node.body;
493
- const rootEl = (body?.nodes || []).find((n) => n.type === 'RegularElement');
494
-
495
- const textSlots = [];
496
- const staticTexts = [];
497
- let nestedUnsupported = false;
498
- const collectStatics = (fragment) => {
499
- for (const child of fragment?.nodes || []) {
500
- if (child.type === 'Text') {
501
- const trimmed = String(child.data || '').trim();
502
- if (trimmed) staticTexts.push(trimmed);
503
- } else if (child.type === 'IfBlock') {
504
- collectStatics(child.consequent);
505
- if (child.alternate) collectStatics(child.alternate);
506
- } else if (child.type === 'EachBlock') {
507
- collectStatics(child.body);
508
- } else if (child.fragment) {
509
- collectStatics(child.fragment);
510
- }
511
- }
512
- };
513
- collectStatics(body);
514
- const attrSlots = [];
515
- // The hydration item is a SHALLOW object whose string fields are the exact
516
- // property names the markup accesses, filled from the rendered page. That
517
- // model supports one item access per slot, optionally wrapped in a global
518
- // transform ({Math.round(r.score)} hydrates `score`). Shapes it cannot
519
- // represent split two ways: CRASHY ones would throw at mount time against a
520
- // shallow item (deep paths like r.meta.label, method calls like r.format())
521
- // and force the source-preview fallback; LOSSY ones render wrong but safe
522
- // (bare {r}, multi-access expressions that would double their text) and
523
- // also fall back in text position, where the damage is visible.
524
- const boundAs = (name, scopeInfos) => {
525
- for (let i = scopeInfos.length - 1; i >= 0; i--) {
526
- const info = scopeInfos[i];
527
- if (info.indexName === name) return 'index';
528
- if (info.itemName === name) return 'item';
529
- if (info.names.has(name)) return 'field';
530
- }
531
- return null;
532
- };
533
- const slotKeysOf = (expression, scopeInfos) => {
534
- const keys = new Set();
535
- let crashy = false;
536
- let lossy = false;
537
- let touches = false;
538
- const visit = (node, ctx) => {
539
- if (!node || typeof node !== 'object' || crashy) return;
540
- if (Array.isArray(node)) {
541
- for (const item of node) visit(item, {});
542
- return;
543
- }
544
- switch (node.type) {
545
- case 'Identifier': {
546
- const kind = boundAs(node.name, scopeInfos);
547
- if (!kind) return;
548
- touches = true;
549
- if (kind === 'index') return; // the runtime each provides it
550
- if (kind === 'item') { lossy = true; return; } // bare item reference
551
- if (ctx.callee) { crashy = true; return; } // field() on a hydrated string
552
- keys.add(node.name); // destructured context field
553
- return;
554
- }
555
- case 'MemberExpression': {
556
- if (
557
- !node.computed
558
- && node.object?.type === 'Identifier'
559
- && boundAs(node.object.name, scopeInfos) === 'item'
560
- && node.property?.type === 'Identifier'
561
- ) {
562
- touches = true;
563
- // item.a.b or item.method(): a shallow string field throws here.
564
- if (ctx.memberObject || ctx.callee) { crashy = true; return; }
565
- keys.add(node.property.name);
566
- return;
567
- }
568
- visit(node.object, { memberObject: true });
569
- if (node.computed) visit(node.property, {});
570
- return;
571
- }
572
- case 'CallExpression':
573
- visit(node.callee, { callee: true });
574
- for (const arg of node.arguments || []) visit(arg, {});
575
- return;
576
- case 'ArrowFunctionExpression':
577
- case 'FunctionExpression': {
578
- // Closures cannot hydrate; only lossy when they capture the item.
579
- const roots = collectRootIdentifiers(node);
580
- if ([...roots].some((name) => boundAs(name, scopeInfos))) { touches = true; lossy = true; }
581
- return;
582
- }
583
- case 'Property':
584
- if (node.computed) visit(node.key, {});
585
- visit(node.value, {});
586
- return;
587
- default: {
588
- for (const key of Object.keys(node)) {
589
- if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
590
- visit(node[key], {});
591
- }
592
- }
593
- }
594
- };
595
- visit(expression, {});
596
- if (crashy) return { crashy: true };
597
- if (lossy || keys.size > 1) return { lossy: true };
598
- if (!touches || keys.size === 0) return { skip: true };
599
- return { key: [...keys][0] };
600
- };
601
- const staticClassesOf = (el) => {
602
- const classes = [];
603
- for (const attr of el?.attributes || []) {
604
- if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
605
- for (const part of attr.value) {
606
- if (part.type === 'Text') classes.push(...part.data.split(/\s+/).filter(Boolean));
607
- }
608
- }
609
- }
610
- return classes;
611
- };
612
- const scopeInfoOf = (eachNode) => {
613
- const names = new Set();
614
- if (eachNode.context) collectPatternNames(eachNode.context, names);
615
- return {
616
- names,
617
- itemName: eachNode.context?.type === 'Identifier' ? eachNode.context.name : null,
618
- indexName: eachNode.index || null,
619
- };
620
- };
621
- const walkForSlots = (fragment, scopeInfos) => {
622
- for (const child of fragment?.nodes || []) {
623
- if (child.type === 'ExpressionTag') {
624
- const slot = slotKeysOf(child.expression, scopeInfos);
625
- if (slot.crashy || slot.lossy) { nestedUnsupported = true; continue; }
626
- if (slot.skip) continue;
627
- textSlots.push({ key: slot.key, expr: exprText(source, child.expression) });
628
- } else if (child.type === 'RegularElement' || child.type === 'SvelteElement') {
629
- // Bound values in ATTRIBUTES (href={link.href}, src={item.img}) are
630
- // part of the item too: the browser reads the rendered attribute off
631
- // the live element, so the preview does not mount with empty links.
632
- // Only a single-expression attribute hydrates exactly; a mixed value
633
- // ("card {r.status}") stays unhydrated because the rendered attribute
634
- // is not separable into its parts, which was the prior behavior.
635
- for (const attr of child.attributes || []) {
636
- if (attr.type !== 'Attribute' || attr.value === true) continue;
637
- if (HANDLER_ATTR_RE.test(attr.name)) continue; // functions cannot hydrate
638
- const parts = Array.isArray(attr.value) ? attr.value : [attr.value];
639
- const exprParts = parts.filter((part) => part?.type === 'ExpressionTag');
640
- for (const part of exprParts) {
641
- const slot = slotKeysOf(part.expression, scopeInfos);
642
- if (slot.crashy) { nestedUnsupported = true; continue; }
643
- if (slot.skip || slot.lossy) continue;
644
- if (parts.length !== 1) continue; // mixed static+dynamic value
645
- attrSlots.push({
646
- key: slot.key,
647
- expr: exprText(source, part.expression),
648
- attr: attr.name,
649
- tag: child.name || null,
650
- classes: staticClassesOf(child),
651
- });
652
- }
653
- }
654
- walkForSlots(child.fragment, scopeInfos);
655
- continue;
656
- } else if (child.type === 'EachBlock') {
657
- const roots = collectRootIdentifiers(child.expression);
658
- const boundNested = [...roots].some((name) => boundAs(name, scopeInfos));
659
- if (boundNested) nestedUnsupported = true; // nested per-item arrays: no hydration plan yet
660
- walkForSlots(child.body, [...scopeInfos, scopeInfoOf(child)]);
661
- } else if (child.type === 'IfBlock') {
662
- walkForSlots(child.consequent, scopeInfos);
663
- if (child.alternate) walkForSlots(child.alternate, scopeInfos);
664
- } else if (child.fragment) {
665
- walkForSlots(child.fragment, scopeInfos);
666
- }
667
- }
668
- };
669
- walkForSlots(body, [scopeInfoOf(node)]);
670
-
671
- const staticClasses = [];
672
- for (const attr of rootEl?.attributes || []) {
673
- if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
674
- for (const part of attr.value) {
675
- if (part.type === 'Text') staticClasses.push(...part.data.split(/\s+/).filter(Boolean));
676
- }
677
- }
678
- }
679
-
680
- return {
681
- rootTag: rootEl?.name || null,
682
- rootClasses: staticClasses,
683
- textSlots,
684
- attrSlots,
685
- staticTexts,
686
- nestedUnsupported,
687
- };
688
- }
689
-
690
- /**
691
- * Classify a keyed each block's key expression:
692
- * { keyField } member of the loop item (e.g. `(expense.id)` when the
693
- * context binds `expense`): browser injects a unique
694
- * per-index value under that field.
695
- * {} key is the whole loop item or the index: already
696
- * distinct per iteration, nothing to inject.
697
- * { unsupported } free or complex keys: cannot hydrate distinct values.
698
- */
699
- function classifyEachKey(node) {
700
- const bound = new Set();
701
- if (node.context) collectPatternNames(node.context, bound);
702
- if (node.index) bound.add(node.index);
703
- const key = node.key;
704
- const roots = collectRootIdentifiers(key);
705
- const usesLoopBinding = [...roots].some((name) => bound.has(name));
706
- if (!usesLoopBinding) {
707
- // A key that ignores the loop item is constant across iterations:
708
- // guaranteed duplicate keys at mount.
709
- return { unsupported: 'each key not derived from the loop item requires source-preview mode' };
710
- }
711
- if (key.type === 'Identifier' && bound.has(key.name)) return {};
712
- if (
713
- key.type === 'MemberExpression'
714
- && !key.computed
715
- && key.object?.type === 'Identifier'
716
- && bound.has(key.object.name)
717
- && key.property?.type === 'Identifier'
718
- ) {
719
- return { keyField: key.property.name };
720
- }
721
- return { unsupported: 'complex each key requires source-preview mode' };
722
- }
723
-
724
- /**
725
- * Describe a fragment's root element for browser presence probing:
726
- * { tag, classes } of the first RegularElement, or null for text-only
727
- * fragments (which cannot be probed reliably).
728
- */
729
- function describeElementProbe(fragment) {
730
- const rootEl = (fragment?.nodes || []).find((n) => n.type === 'RegularElement');
731
- if (!rootEl) return null;
732
- const classes = [];
733
- for (const attr of rootEl.attributes || []) {
734
- if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
735
- for (const part of attr.value) {
736
- if (part.type === 'Text') classes.push(...part.data.split(/\s+/).filter(Boolean));
737
- }
738
- }
739
- }
740
- return { tag: rootEl.name, classes };
741
- }
742
-
743
- // ---------------------------------------------------------------------------
744
- // Public API
745
- // ---------------------------------------------------------------------------
746
-
747
- /**
748
- * Analyze a markup block and produce the prop-substituted scaffold markup and
749
- * the v2 prop contract. Returns { ok: false, reason } when the block needs
750
- * source-preview mode (parse failure or unsupported construct).
751
- */
752
- export function analyzeSvelteMarkup(markup, parse) {
753
- const source = String(markup || '');
754
- let ast;
755
- try {
756
- ast = parse(source, { modern: true });
757
- } catch (err) {
758
- return { ok: false, reason: `svelte parse failed: ${err.message}` };
759
- }
760
- if (ast.instance || ast.module) {
761
- return { ok: false, reason: 'selected block contains a script tag' };
762
- }
763
- const analysis = new Analysis(source);
764
- analyzeFragment(ast.fragment, analysis, []);
765
- if (analysis.unsupported) {
766
- return { ok: false, reason: analysis.unsupported };
767
- }
768
- for (const entry of analysis.contract) {
769
- if (entry.kind === 'collection' && entry.item?.nestedUnsupported) {
770
- return { ok: false, reason: 'per-item content (nested blocks or expressions) this preview cannot hydrate requires source-preview mode' };
771
- }
772
- }
773
-
774
- const markupWithProps = applyReplacements(source, analysis.replacements);
775
- return {
776
- ok: true,
777
- markupWithProps,
778
- contract: analysis.contract.map((entry) => ({
779
- prop: entry.prop,
780
- expr: entry.expr,
781
- kind: entry.kind,
782
- // Kept for backward compatibility with v1 consumers (fake e2e agent,
783
- // text-only restore paths).
784
- placeholder: `{${entry.expr}}`,
785
- ...(entry.item ? { item: entry.item } : {}),
786
- ...(entry.probe ? { probe: entry.probe } : {}),
787
- })),
788
- };
789
- }
790
-
791
- function applyReplacements(source, replacements) {
792
- const sorted = [...replacements].sort((a, b) => b.start - a.start);
793
- let out = source;
794
- for (const { start, end, prop } of sorted) {
795
- out = out.slice(0, start) + prop + out.slice(end);
796
- }
797
- return out;
798
- }
799
-
800
- /**
801
- * Restore a variant's markup back to route-source form: every free
802
- * identifier that matches a contract prop is replaced by its original
803
- * expression. AST-based so `{#each stages as stage}` restores to
804
- * `{#each data.stages as stage}` even though the prop appears without braces.
805
- */
806
- export function restoreSvelteMarkup(markup, contract, parse) {
807
- const source = String(markup || '');
808
- const byProp = new Map();
809
- for (const entry of contract || []) byProp.set(entry.prop, entry.expr);
810
- if (byProp.size === 0) return { ok: true, markup: source };
811
-
812
- let ast;
813
- try {
814
- ast = parse(source, { modern: true });
815
- } catch (err) {
816
- return { ok: false, reason: `variant parse failed: ${err.message}` };
817
- }
818
-
819
- const replacements = [];
820
- const visitExpr = (expression, scopes) => {
821
- if (!expression) return;
822
- collectFreeIdentifierRanges(expression, scopes, (name, start, end) => {
823
- const original = byProp.get(name);
824
- if (original != null && original !== name) replacements.push({ start, end, prop: original });
825
- });
826
- };
827
-
828
- const walk = (fragment, scopes) => {
829
- const fragmentScope = new Set();
830
- const nextScopes = [...scopes, fragmentScope];
831
- for (const node of fragment?.nodes || []) {
832
- if (node.type === 'ConstTag' && node.declaration) {
833
- for (const decl of node.declaration.declarations || []) collectPatternNames(decl.id, fragmentScope);
834
- }
835
- }
836
- for (const node of fragment?.nodes || []) {
837
- switch (node?.type) {
838
- case 'ExpressionTag':
839
- case 'HtmlTag':
840
- visitExpr(node.expression, nextScopes);
841
- break;
842
- case 'ConstTag':
843
- for (const decl of node.declaration?.declarations || []) visitExpr(decl.init, nextScopes);
844
- break;
845
- case 'EachBlock': {
846
- visitExpr(node.expression, nextScopes);
847
- const bound = new Set();
848
- if (node.context) collectPatternNames(node.context, bound);
849
- if (node.index) bound.add(node.index);
850
- // The key evaluates per item, so the loop context and index are in
851
- // scope there. Visiting it with outer scopes only let a contract
852
- // prop that shares a loop binding's name rewrite the key.
853
- if (node.key) visitExpr(node.key, [...nextScopes, bound]);
854
- walk(node.body, [...nextScopes, bound]);
855
- if (node.fallback) walk(node.fallback, nextScopes);
856
- break;
857
- }
858
- case 'IfBlock':
859
- visitExpr(node.test, nextScopes);
860
- walk(node.consequent, nextScopes);
861
- if (node.alternate) walk(node.alternate, nextScopes);
862
- break;
863
- case 'KeyBlock':
864
- visitExpr(node.expression, nextScopes);
865
- walk(node.fragment, nextScopes);
866
- break;
867
- case 'SnippetBlock': {
868
- const bound = new Set();
869
- for (const param of node.parameters || []) collectPatternNames(param, bound);
870
- walk(node.body, [...nextScopes, bound]);
871
- break;
872
- }
873
- default: {
874
- for (const attr of node?.attributes || []) {
875
- if (attr.type === 'Attribute' && Array.isArray(attr.value)) {
876
- for (const part of attr.value) {
877
- if (part?.type === 'ExpressionTag') visitExpr(part.expression, nextScopes);
878
- }
879
- } else if (attr.expression) {
880
- visitExpr(attr.expression, nextScopes);
881
- }
882
- }
883
- if (node?.fragment) walk(node.fragment, nextScopes);
884
- }
885
- }
886
- }
887
- };
888
- walk(ast.fragment, []);
889
-
890
- return { ok: true, markup: applyReplacements(source, replacements) };
891
- }
892
-
893
- /**
894
- * Report [name, start, end] for every free root identifier READ in an
895
- * expression (skips member properties, object keys, shadowed names).
896
- */
897
- function collectFreeIdentifierRanges(node, scopes, emit) {
898
- const visit = (n, localBound) => {
899
- if (!n || typeof n !== 'object') return;
900
- if (Array.isArray(n)) { for (const item of n) visit(item, localBound); return; }
901
- switch (n.type) {
902
- case 'Identifier': {
903
- const bound = localBound.has(n.name) || scopes.some((s) => s.has(n.name));
904
- if (!bound) emit(n.name, n.start, n.end);
905
- return;
906
- }
907
- case 'MemberExpression':
908
- visit(n.object, localBound);
909
- if (n.computed) visit(n.property, localBound);
910
- return;
911
- case 'Property':
912
- if (n.computed) visit(n.key, localBound);
913
- visit(n.value, localBound);
914
- return;
915
- case 'ArrowFunctionExpression':
916
- case 'FunctionExpression': {
917
- const inner = new Set(localBound);
918
- for (const param of n.params || []) collectPatternNames(param, inner);
919
- visit(n.body, inner);
920
- return;
921
- }
922
- default:
923
- for (const key of Object.keys(n)) {
924
- if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
925
- visit(n[key], localBound);
926
- }
927
- }
928
- };
929
- visit(node, new Set());
930
- }
931
-
932
- /**
933
- * Build the preview component's script block from a v2 contract, with
934
- * defaults that keep an unhydrated mount rendering instead of crashing.
935
- */
936
- export function buildPropsScriptV2(contract) {
937
- if (!contract || contract.length === 0) {
938
- return '<script>\n /** @type {Record<string, never>} */\n let {} = $props();\n</script>\n';
939
- }
940
- const defaults = {
941
- text: "''",
942
- raw: "''",
943
- condition: 'false',
944
- collection: '[]',
945
- handler: '() => {}',
946
- };
947
- const types = {
948
- text: 'string',
949
- raw: 'string',
950
- condition: 'boolean',
951
- collection: 'Array<Record<string, unknown>>',
952
- handler: '() => void',
953
- };
954
- const names = contract
955
- .map((c) => `${c.prop} = ${defaults[c.kind] ?? "''"}`)
956
- .join(', ');
957
- const typeFields = contract
958
- .map((c) => ` ${c.prop}?: ${types[c.kind] ?? 'string'};`)
959
- .join('\n');
960
- return `<script>\n /** @type {{\n${typeFields}\n }} */\n let { ${names} } = $props();\n</script>\n`;
961
- }