@jasonshimmy/vite-plugin-cer-app 0.23.2 → 0.25.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 (404) hide show
  1. package/dist/cli/adapters/netlify.js +4 -2
  2. package/dist/cli/adapters/netlify.js.map +1 -1
  3. package/dist/cli/checks/lighthouse.d.ts +26 -0
  4. package/dist/cli/checks/lighthouse.d.ts.map +1 -0
  5. package/dist/cli/checks/lighthouse.js +121 -0
  6. package/dist/cli/checks/lighthouse.js.map +1 -0
  7. package/dist/cli/checks/links.d.ts +12 -0
  8. package/dist/cli/checks/links.d.ts.map +1 -0
  9. package/dist/cli/checks/links.js +89 -0
  10. package/dist/cli/checks/links.js.map +1 -0
  11. package/dist/cli/checks/performance.d.ts +17 -0
  12. package/dist/cli/checks/performance.d.ts.map +1 -0
  13. package/dist/cli/checks/performance.js +61 -0
  14. package/dist/cli/checks/performance.js.map +1 -0
  15. package/dist/cli/commands/check.d.ts +3 -0
  16. package/dist/cli/commands/check.d.ts.map +1 -0
  17. package/dist/cli/commands/check.js +85 -0
  18. package/dist/cli/commands/check.js.map +1 -0
  19. package/dist/cli/commands/preview.d.ts.map +1 -1
  20. package/dist/cli/commands/preview.js +4 -2
  21. package/dist/cli/commands/preview.js.map +1 -1
  22. package/dist/cli/create/index.d.ts +11 -1
  23. package/dist/cli/create/index.d.ts.map +1 -1
  24. package/dist/cli/create/index.js +135 -65
  25. package/dist/cli/create/index.js.map +1 -1
  26. package/dist/cli/create/templates/spa/package.json.tpl +5 -3
  27. package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
  28. package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
  29. package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
  30. package/dist/cli/index.js +2 -0
  31. package/dist/cli/index.js.map +1 -1
  32. package/dist/index.d.ts +4 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/plugin/build-ssg.d.ts +22 -6
  35. package/dist/plugin/build-ssg.d.ts.map +1 -1
  36. package/dist/plugin/build-ssg.js +226 -17
  37. package/dist/plugin/build-ssg.js.map +1 -1
  38. package/dist/plugin/content/index.d.ts +1 -1
  39. package/dist/plugin/content/index.d.ts.map +1 -1
  40. package/dist/plugin/content/index.js +8 -8
  41. package/dist/plugin/content/index.js.map +1 -1
  42. package/dist/plugin/content/parser.d.ts +3 -3
  43. package/dist/plugin/content/parser.d.ts.map +1 -1
  44. package/dist/plugin/content/parser.js +103 -24
  45. package/dist/plugin/content/parser.js.map +1 -1
  46. package/dist/plugin/dev-server.d.ts +4 -1
  47. package/dist/plugin/dev-server.d.ts.map +1 -1
  48. package/dist/plugin/dev-server.js.map +1 -1
  49. package/dist/plugin/dts-generator.d.ts.map +1 -1
  50. package/dist/plugin/dts-generator.js +50 -8
  51. package/dist/plugin/dts-generator.js.map +1 -1
  52. package/dist/plugin/generated-dir.d.ts +2 -0
  53. package/dist/plugin/generated-dir.d.ts.map +1 -1
  54. package/dist/plugin/generated-dir.js +17 -6
  55. package/dist/plugin/generated-dir.js.map +1 -1
  56. package/dist/plugin/html-post-process.d.ts +7 -0
  57. package/dist/plugin/html-post-process.d.ts.map +1 -1
  58. package/dist/plugin/html-post-process.js +26 -0
  59. package/dist/plugin/html-post-process.js.map +1 -1
  60. package/dist/plugin/index.d.ts.map +1 -1
  61. package/dist/plugin/index.js +60 -13
  62. package/dist/plugin/index.js.map +1 -1
  63. package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
  64. package/dist/plugin/transforms/auto-import.js +7 -0
  65. package/dist/plugin/transforms/auto-import.js.map +1 -1
  66. package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
  67. package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
  68. package/dist/plugin/transforms/prune-runtime-css.js +40 -0
  69. package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
  70. package/dist/runtime/app-template.d.ts +1 -1
  71. package/dist/runtime/app-template.d.ts.map +1 -1
  72. package/dist/runtime/app-template.js +206 -36
  73. package/dist/runtime/app-template.js.map +1 -1
  74. package/dist/runtime/composables/index.d.ts +4 -0
  75. package/dist/runtime/composables/index.d.ts.map +1 -1
  76. package/dist/runtime/composables/index.js +2 -0
  77. package/dist/runtime/composables/index.js.map +1 -1
  78. package/dist/runtime/composables/use-active-headings.d.ts +24 -0
  79. package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
  80. package/dist/runtime/composables/use-active-headings.js +112 -0
  81. package/dist/runtime/composables/use-active-headings.js.map +1 -0
  82. package/dist/runtime/composables/use-content-page.d.ts +45 -0
  83. package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
  84. package/dist/runtime/composables/use-content-page.js +181 -0
  85. package/dist/runtime/composables/use-content-page.js.map +1 -0
  86. package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
  87. package/dist/runtime/composables/use-content-search.js +1 -5
  88. package/dist/runtime/composables/use-content-search.js.map +1 -1
  89. package/dist/runtime/composables/use-fetch.d.ts +2 -1
  90. package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
  91. package/dist/runtime/composables/use-fetch.js +112 -43
  92. package/dist/runtime/composables/use-fetch.js.map +1 -1
  93. package/dist/runtime/composables/use-route.d.ts.map +1 -1
  94. package/dist/runtime/composables/use-route.js +39 -11
  95. package/dist/runtime/composables/use-route.js.map +1 -1
  96. package/dist/runtime/content/client.js +2 -2
  97. package/dist/runtime/content/client.js.map +1 -1
  98. package/dist/runtime/entry-server-template.d.ts +16 -1
  99. package/dist/runtime/entry-server-template.d.ts.map +1 -1
  100. package/dist/runtime/entry-server-template.js +120 -13
  101. package/dist/runtime/entry-server-template.js.map +1 -1
  102. package/dist/types/config.d.ts +45 -4
  103. package/dist/types/config.d.ts.map +1 -1
  104. package/dist/types/config.js.map +1 -1
  105. package/dist/types/content.d.ts +18 -1
  106. package/dist/types/content.d.ts.map +1 -1
  107. package/dist/types/middleware.d.ts +2 -2
  108. package/dist/types/middleware.d.ts.map +1 -1
  109. package/package.json +22 -19
  110. package/.github/copilot-instructions.md +0 -169
  111. package/.github/workflows/publish.yml +0 -257
  112. package/.nvmrc +0 -1
  113. package/CHANGELOG.md +0 -236
  114. package/CLAUDE.md +0 -113
  115. package/commits.txt +0 -1
  116. package/cypress.config.ts +0 -16
  117. package/docs/authentication.md +0 -285
  118. package/docs/cli.md +0 -324
  119. package/docs/components.md +0 -237
  120. package/docs/composables.md +0 -907
  121. package/docs/configuration.md +0 -696
  122. package/docs/content.md +0 -570
  123. package/docs/data-loading.md +0 -336
  124. package/docs/getting-started.md +0 -237
  125. package/docs/head-management.md +0 -212
  126. package/docs/i18n.md +0 -159
  127. package/docs/layouts.md +0 -224
  128. package/docs/middleware.md +0 -234
  129. package/docs/plugins.md +0 -170
  130. package/docs/rendering-modes.md +0 -377
  131. package/docs/routing.md +0 -485
  132. package/docs/server-api.md +0 -253
  133. package/docs/testing.md +0 -455
  134. package/docs/use-fetch.md +0 -183
  135. package/e2e/cypress/e2e/api.cy.ts +0 -123
  136. package/e2e/cypress/e2e/async-component.cy.ts +0 -27
  137. package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
  138. package/e2e/cypress/e2e/content.cy.ts +0 -425
  139. package/e2e/cypress/e2e/cookie.cy.ts +0 -85
  140. package/e2e/cypress/e2e/data.cy.ts +0 -158
  141. package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
  142. package/e2e/cypress/e2e/fouc.cy.ts +0 -254
  143. package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
  144. package/e2e/cypress/e2e/head.cy.ts +0 -89
  145. package/e2e/cypress/e2e/i18n.cy.ts +0 -79
  146. package/e2e/cypress/e2e/interactive.cy.ts +0 -137
  147. package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
  148. package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
  149. package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
  150. package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
  151. package/e2e/cypress/e2e/middleware.cy.ts +0 -45
  152. package/e2e/cypress/e2e/navigate.cy.ts +0 -39
  153. package/e2e/cypress/e2e/observability.cy.ts +0 -77
  154. package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
  155. package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
  156. package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
  157. package/e2e/cypress/e2e/routes.cy.ts +0 -128
  158. package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
  159. package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
  160. package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
  161. package/e2e/cypress/e2e/session.cy.ts +0 -73
  162. package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
  163. package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
  164. package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
  165. package/e2e/cypress/e2e/use-state.cy.ts +0 -138
  166. package/e2e/cypress/support/commands.ts +0 -120
  167. package/e2e/cypress/support/e2e.ts +0 -10
  168. package/e2e/cypress/tsconfig.json +0 -14
  169. package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
  170. package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
  171. package/e2e/kitchen-sink/app/error.ts +0 -18
  172. package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
  173. package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
  174. package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
  175. package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
  176. package/e2e/kitchen-sink/app/loading.ts +0 -9
  177. package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
  178. package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
  179. package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
  180. package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
  181. package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
  182. package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
  183. package/e2e/kitchen-sink/app/pages/404.ts +0 -9
  184. package/e2e/kitchen-sink/app/pages/about.ts +0 -17
  185. package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
  186. package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
  187. package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
  188. package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
  189. package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
  190. package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
  191. package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
  192. package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
  193. package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
  194. package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
  195. package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
  196. package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
  197. package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
  198. package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
  199. package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
  200. package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
  201. package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
  202. package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
  203. package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
  204. package/e2e/kitchen-sink/app/pages/head.ts +0 -20
  205. package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
  206. package/e2e/kitchen-sink/app/pages/index.ts +0 -27
  207. package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
  208. package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
  209. package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
  210. package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
  211. package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
  212. package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
  213. package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
  214. package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
  215. package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
  216. package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
  217. package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
  218. package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
  219. package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
  220. package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
  221. package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
  222. package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
  223. package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
  224. package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
  225. package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
  226. package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
  227. package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
  228. package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
  229. package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
  230. package/e2e/kitchen-sink/cer-env.d.ts +0 -35
  231. package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
  232. package/e2e/kitchen-sink/cer.config.ts +0 -43
  233. package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
  234. package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
  235. package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
  236. package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
  237. package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
  238. package/e2e/kitchen-sink/content/blog/index.md +0 -8
  239. package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
  240. package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
  241. package/e2e/kitchen-sink/content/index.md +0 -16
  242. package/e2e/kitchen-sink/server/api/echo.ts +0 -12
  243. package/e2e/kitchen-sink/server/api/health.ts +0 -3
  244. package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
  245. package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
  246. package/e2e/kitchen-sink/server/api/session.ts +0 -23
  247. package/e2e/kitchen-sink/server/data/posts.ts +0 -21
  248. package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
  249. package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
  250. package/e2e/kitchen-sink/tsconfig.json +0 -3
  251. package/e2e/scripts/clean.mjs +0 -14
  252. package/eslint.config.ts +0 -22
  253. package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
  254. package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
  255. package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
  256. package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
  257. package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
  258. package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
  259. package/src/__tests__/cli/preview-hardening.test.ts +0 -265
  260. package/src/__tests__/cli/preview-isr.test.ts +0 -320
  261. package/src/__tests__/index.test.ts +0 -21
  262. package/src/__tests__/plugin/app-template.test.ts +0 -166
  263. package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
  264. package/src/__tests__/plugin/build-ssg.test.ts +0 -598
  265. package/src/__tests__/plugin/build-ssr.test.ts +0 -192
  266. package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
  267. package/src/__tests__/plugin/content/emitter.test.ts +0 -117
  268. package/src/__tests__/plugin/content/loader.test.ts +0 -154
  269. package/src/__tests__/plugin/content/parser.test.ts +0 -381
  270. package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
  271. package/src/__tests__/plugin/content/search.test.ts +0 -119
  272. package/src/__tests__/plugin/dev-server.test.ts +0 -813
  273. package/src/__tests__/plugin/dts-generator.test.ts +0 -394
  274. package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
  275. package/src/__tests__/plugin/generated-dir.test.ts +0 -144
  276. package/src/__tests__/plugin/html-post-process.test.ts +0 -146
  277. package/src/__tests__/plugin/path-utils.test.ts +0 -411
  278. package/src/__tests__/plugin/resolve-config.test.ts +0 -233
  279. package/src/__tests__/plugin/scanner.test.ts +0 -186
  280. package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
  281. package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
  282. package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
  283. package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
  284. package/src/__tests__/plugin/virtual/error.test.ts +0 -71
  285. package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
  286. package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
  287. package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
  288. package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
  289. package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
  290. package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
  291. package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
  292. package/src/__tests__/runtime/app-template.test.ts +0 -208
  293. package/src/__tests__/runtime/define-middleware.test.ts +0 -64
  294. package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
  295. package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
  296. package/src/__tests__/runtime/isr-handler.test.ts +0 -338
  297. package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
  298. package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
  299. package/src/__tests__/runtime/oauth-index.test.ts +0 -43
  300. package/src/__tests__/runtime/use-auth.test.ts +0 -169
  301. package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
  302. package/src/__tests__/runtime/use-content-search.test.ts +0 -163
  303. package/src/__tests__/runtime/use-content.test.ts +0 -226
  304. package/src/__tests__/runtime/use-cookie.test.ts +0 -277
  305. package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
  306. package/src/__tests__/runtime/use-fetch.test.ts +0 -377
  307. package/src/__tests__/runtime/use-head.test.ts +0 -311
  308. package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
  309. package/src/__tests__/runtime/use-inject.test.ts +0 -66
  310. package/src/__tests__/runtime/use-locale.test.ts +0 -152
  311. package/src/__tests__/runtime/use-navigate.test.ts +0 -121
  312. package/src/__tests__/runtime/use-page-data.test.ts +0 -298
  313. package/src/__tests__/runtime/use-route.test.ts +0 -156
  314. package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
  315. package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
  316. package/src/__tests__/runtime/use-session.test.ts +0 -320
  317. package/src/__tests__/runtime/use-state.test.ts +0 -340
  318. package/src/__tests__/types/config.test.ts +0 -18
  319. package/src/cli/adapters/cloudflare.ts +0 -335
  320. package/src/cli/adapters/netlify.ts +0 -326
  321. package/src/cli/adapters/vercel.ts +0 -311
  322. package/src/cli/commands/adapt.ts +0 -84
  323. package/src/cli/commands/build.ts +0 -165
  324. package/src/cli/commands/dev.ts +0 -125
  325. package/src/cli/commands/generate.ts +0 -91
  326. package/src/cli/commands/preview-isr.ts +0 -172
  327. package/src/cli/commands/preview.ts +0 -523
  328. package/src/cli/create/index.ts +0 -275
  329. package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
  330. package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
  331. package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
  332. package/src/cli/create/templates/shared/index.html.tpl +0 -12
  333. package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
  334. package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
  335. package/src/cli/create/templates/spa/package.json.tpl +0 -18
  336. package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
  337. package/src/cli/create/templates/ssg/package.json.tpl +0 -19
  338. package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
  339. package/src/cli/create/templates/ssr/package.json.tpl +0 -18
  340. package/src/cli/index.ts +0 -22
  341. package/src/index.ts +0 -20
  342. package/src/plugin/build-ssg.ts +0 -403
  343. package/src/plugin/build-ssr.ts +0 -134
  344. package/src/plugin/content/emitter.ts +0 -50
  345. package/src/plugin/content/index.ts +0 -233
  346. package/src/plugin/content/parser.ts +0 -259
  347. package/src/plugin/content/path-utils.ts +0 -55
  348. package/src/plugin/content/scanner.ts +0 -26
  349. package/src/plugin/content/search.ts +0 -28
  350. package/src/plugin/dev-server.ts +0 -379
  351. package/src/plugin/dts-generator.ts +0 -273
  352. package/src/plugin/generated-dir.ts +0 -121
  353. package/src/plugin/html-post-process.ts +0 -96
  354. package/src/plugin/index.ts +0 -584
  355. package/src/plugin/path-utils.ts +0 -186
  356. package/src/plugin/scanner.ts +0 -65
  357. package/src/plugin/transforms/auto-import.ts +0 -206
  358. package/src/plugin/transforms/head-inject.ts +0 -161
  359. package/src/plugin/virtual/composables.ts +0 -28
  360. package/src/plugin/virtual/content-components.ts +0 -83
  361. package/src/plugin/virtual/error.ts +0 -34
  362. package/src/plugin/virtual/layouts.ts +0 -41
  363. package/src/plugin/virtual/loading.ts +0 -32
  364. package/src/plugin/virtual/middleware.ts +0 -45
  365. package/src/plugin/virtual/plugins.ts +0 -46
  366. package/src/plugin/virtual/routes.ts +0 -514
  367. package/src/plugin/virtual/server-api.ts +0 -85
  368. package/src/plugin/virtual/server-middleware.ts +0 -44
  369. package/src/runtime/app-template.ts +0 -377
  370. package/src/runtime/composables/define-middleware.ts +0 -17
  371. package/src/runtime/composables/define-server-middleware.ts +0 -18
  372. package/src/runtime/composables/index.ts +0 -27
  373. package/src/runtime/composables/use-auth.ts +0 -125
  374. package/src/runtime/composables/use-content-search.ts +0 -205
  375. package/src/runtime/composables/use-content.ts +0 -146
  376. package/src/runtime/composables/use-cookie.ts +0 -135
  377. package/src/runtime/composables/use-fetch.ts +0 -438
  378. package/src/runtime/composables/use-head.ts +0 -234
  379. package/src/runtime/composables/use-inject.ts +0 -49
  380. package/src/runtime/composables/use-locale.ts +0 -109
  381. package/src/runtime/composables/use-navigate.ts +0 -58
  382. package/src/runtime/composables/use-page-data.ts +0 -93
  383. package/src/runtime/composables/use-route.ts +0 -71
  384. package/src/runtime/composables/use-runtime-config.ts +0 -123
  385. package/src/runtime/composables/use-seo-meta.ts +0 -80
  386. package/src/runtime/composables/use-session.ts +0 -186
  387. package/src/runtime/composables/use-state.ts +0 -92
  388. package/src/runtime/content/client.ts +0 -168
  389. package/src/runtime/entry-client-template.ts +0 -39
  390. package/src/runtime/entry-server-template.ts +0 -493
  391. package/src/runtime/isr-handler.ts +0 -184
  392. package/src/runtime/oauth/handler.ts +0 -407
  393. package/src/runtime/oauth/index.ts +0 -49
  394. package/src/runtime/oauth/providers.ts +0 -38
  395. package/src/types/api.ts +0 -40
  396. package/src/types/config.ts +0 -379
  397. package/src/types/content.ts +0 -66
  398. package/src/types/index.ts +0 -7
  399. package/src/types/middleware.ts +0 -63
  400. package/src/types/page.ts +0 -117
  401. package/src/types/plugin.ts +0 -34
  402. package/tsconfig.build.json +0 -10
  403. package/tsconfig.json +0 -19
  404. package/vitest.config.ts +0 -33
@@ -1,186 +0,0 @@
1
- import { basename, relative } from 'pathe'
2
-
3
- export interface RouteEntry {
4
- filePath: string
5
- routePath: string
6
- tagName: string
7
- isDynamic: boolean
8
- isCatchAll: boolean
9
- }
10
-
11
- /**
12
- * Converts a file path to a route path.
13
- * e.g. app/pages/blog/[slug].ts -> /blog/:slug
14
- */
15
- export function fileToRoutePath(filePath: string, pagesRoot: string): string {
16
- // Get path relative to pagesRoot, strip extension
17
- let rel = relative(pagesRoot, filePath)
18
- rel = rel.replace(/\.[jt]s$/, '')
19
-
20
- // Split into segments
21
- const segments = rel.split('/')
22
-
23
- const transformed: string[] = []
24
- for (const seg of segments) {
25
- // Strip route groups: (groupName)
26
- if (/^\(.*\)$/.test(seg)) {
27
- continue
28
- }
29
-
30
- // index becomes empty string (handled by parent)
31
- if (seg === 'index') {
32
- continue
33
- }
34
-
35
- // [...rest] -> :rest* (named splat so the param is accessible in components)
36
- const catchAllMatch = seg.match(/^\[\.\.\.(.+)\]$/)
37
- if (catchAllMatch) {
38
- transformed.push(`:${catchAllMatch[1]}*`)
39
- continue
40
- }
41
-
42
- // [param] -> :param
43
- const dynamicMatch = seg.match(/^\[(.+)\]$/)
44
- if (dynamicMatch) {
45
- transformed.push(`:${dynamicMatch[1]}`)
46
- continue
47
- }
48
-
49
- transformed.push(seg)
50
- }
51
-
52
- const path = '/' + transformed.join('/')
53
- // Normalize double slashes
54
- return path.replace(/\/+/g, '/')
55
- }
56
-
57
- /**
58
- * Converts a file path to a kebab-case custom element tag name.
59
- * e.g. app/pages/blog/[slug].ts -> page-blog-slug
60
- */
61
- export function fileToTagName(filePath: string, pagesRoot: string): string {
62
- let rel = relative(pagesRoot, filePath)
63
- rel = rel.replace(/\.[jt]s$/, '')
64
-
65
- // Strip route groups
66
- const segments = rel.split('/').filter((seg) => !/^\(.*\)$/.test(seg))
67
-
68
- // Mirror fileToRoutePath: strip 'index' segments unless it's the only segment
69
- // e.g. blog/index.ts -> page-blog (not page-blog-index), index.ts -> page-index
70
- const tagSegments = segments
71
- .map((seg) => seg.replace(/\[/g, '').replace(/\]/g, '').replace(/\./g, ''))
72
- .filter((seg, _, arr) => !(seg === 'index' && arr.length > 1))
73
-
74
- // Prefix with 'page-'
75
- const name = 'page-' + tagSegments.join('-')
76
- // Collapse multiple dashes and convert to lowercase
77
- return name
78
- .toLowerCase()
79
- .replace(/-+/g, '-')
80
- .replace(/^-|-$/g, '')
81
- }
82
-
83
- /**
84
- * Converts a layout file path to a kebab-case custom element tag name.
85
- * e.g. app/layouts/default.ts -> layout-default
86
- */
87
- export function fileToLayoutTagName(filePath: string, layoutsRoot: string): string {
88
- let rel = relative(layoutsRoot, filePath)
89
- rel = rel.replace(/\.[jt]s$/, '')
90
-
91
- const segments = rel.split('/')
92
- const name = 'layout-' + segments.join('-')
93
- return name
94
- .toLowerCase()
95
- .replace(/-+/g, '-')
96
- .replace(/^-|-$/g, '')
97
- }
98
-
99
- /**
100
- * Sorts routes: static first, then dynamic, then catch-all.
101
- */
102
- export function sortRoutes(routes: RouteEntry[]): RouteEntry[] {
103
- return [...routes].sort((a, b) => {
104
- // Catch-all always last
105
- if (a.isCatchAll && !b.isCatchAll) return 1
106
- if (!a.isCatchAll && b.isCatchAll) return -1
107
-
108
- // Dynamic after static
109
- if (a.isDynamic && !b.isDynamic) return 1
110
- if (!a.isDynamic && b.isDynamic) return -1
111
-
112
- // Alphabetical among same type
113
- return a.routePath.localeCompare(b.routePath)
114
- })
115
- }
116
-
117
- /**
118
- * Determines if a route path contains dynamic segments.
119
- */
120
- export function isRouteDynamic(routePath: string): boolean {
121
- return routePath.includes(':')
122
- }
123
-
124
- /**
125
- * Determines if a route path is a catch-all.
126
- */
127
- export function isRouteCatchAll(routePath: string): boolean {
128
- return routePath.includes('*')
129
- }
130
-
131
- /**
132
- * Builds a full RouteEntry from a file path.
133
- */
134
- export function buildRouteEntry(filePath: string, pagesRoot: string): RouteEntry {
135
- const routePath = fileToRoutePath(filePath, pagesRoot)
136
- const tagName = fileToTagName(filePath, pagesRoot)
137
- return {
138
- filePath,
139
- routePath,
140
- tagName,
141
- isDynamic: isRouteDynamic(routePath),
142
- isCatchAll: isRouteCatchAll(routePath),
143
- }
144
- }
145
-
146
- /**
147
- * Returns the layout name (key) from a layout file path.
148
- * e.g. app/layouts/default.ts -> 'default'
149
- */
150
- export function fileToLayoutName(filePath: string, layoutsRoot: string): string {
151
- let rel = relative(layoutsRoot, filePath)
152
- rel = rel.replace(/\.[jt]s$/, '')
153
- return rel.replace(/\//g, '-').toLowerCase()
154
- }
155
-
156
- /**
157
- * Returns a safe JS identifier for a file path (for import aliases).
158
- */
159
- export function fileToImportAlias(filePath: string, prefix: string = '_m'): string {
160
- const base = basename(filePath).replace(/\.[jt]s$/, '')
161
- const safe = base
162
- .replace(/[^a-zA-Z0-9_]/g, '_')
163
- .replace(/^(\d)/, '_$1')
164
- return `${prefix}_${safe}`
165
- }
166
-
167
- /**
168
- * Returns the numeric sort prefix from a filename (e.g. "01.store.ts" -> 1).
169
- * Returns Infinity if no numeric prefix.
170
- */
171
- export function extractPluginOrder(fileName: string): number {
172
- const match = basename(fileName).match(/^(\d+)\./)
173
- return match ? parseInt(match[1], 10) : Infinity
174
- }
175
-
176
- /**
177
- * Sorts plugin files by leading numeric prefix then alphabetically.
178
- */
179
- export function sortPluginFiles(files: string[]): string[] {
180
- return [...files].sort((a, b) => {
181
- const aOrder = extractPluginOrder(a)
182
- const bOrder = extractPluginOrder(b)
183
- if (aOrder !== bOrder) return aOrder - bOrder
184
- return a.localeCompare(b)
185
- })
186
- }
@@ -1,65 +0,0 @@
1
- import fg from 'fast-glob'
2
- import type { FSWatcher } from 'vite'
3
-
4
- /**
5
- * Scans a directory for files matching the given glob pattern.
6
- * Returns absolute file paths sorted alphabetically.
7
- */
8
- export async function scanDirectory(pattern: string, cwd: string): Promise<string[]> {
9
- const files = await fg(pattern, {
10
- cwd,
11
- absolute: true,
12
- onlyFiles: true,
13
- ignore: ['**/node_modules/**', '**/.git/**'],
14
- })
15
- return files.sort()
16
- }
17
-
18
- /**
19
- * Creates a file watcher for the given directories using Vite's built-in watcher.
20
- * Calls `onChange(event, absoluteFilePath)` on add/unlink events.
21
- *
22
- * @param watcher - The FSWatcher from Vite's dev server (server.watcher)
23
- * @param dirs - Absolute directory paths to watch
24
- * @param onChange - Callback invoked with event type and absolute file path
25
- * @returns A cleanup function that removes the listeners
26
- */
27
- export function createWatcher(
28
- watcher: FSWatcher,
29
- dirs: string[],
30
- onChange: (event: string, file: string) => void,
31
- ): () => void {
32
- // Add directories to Vite's watcher
33
- for (const dir of dirs) {
34
- watcher.add(dir)
35
- }
36
-
37
- const handleAdd = (file: string) => {
38
- if (dirs.some((dir) => file.startsWith(dir))) {
39
- onChange('add', file)
40
- }
41
- }
42
-
43
- const handleUnlink = (file: string) => {
44
- if (dirs.some((dir) => file.startsWith(dir))) {
45
- onChange('unlink', file)
46
- }
47
- }
48
-
49
- const handleChange = (file: string) => {
50
- if (dirs.some((dir) => file.startsWith(dir))) {
51
- onChange('change', file)
52
- }
53
- }
54
-
55
- watcher.on('add', handleAdd)
56
- watcher.on('unlink', handleUnlink)
57
- watcher.on('change', handleChange)
58
-
59
- // Return cleanup function
60
- return () => {
61
- watcher.off('add', handleAdd)
62
- watcher.off('unlink', handleUnlink)
63
- watcher.off('change', handleChange)
64
- }
65
- }
@@ -1,206 +0,0 @@
1
- import MagicString from 'magic-string'
2
- import { normalize } from 'pathe'
3
-
4
- export interface AutoImportOptions {
5
- srcDir: string
6
- /** Absolute path to server/middleware/ directory */
7
- serverMiddlewareDir?: string
8
- /** Map of composable export name → absolute file path */
9
- composableExports?: Map<string, string>
10
- }
11
-
12
- // P1-5: Per-identifier import maps. Only the identifiers actually referenced in
13
- // a file are injected — this eliminates the full-group injection that prevented
14
- // tree-shaking when a page used only one framework composable.
15
-
16
- /** Maps each runtime identifier to its source module. All from the main runtime package. */
17
- const RUNTIME_MAP: Record<string, string> = {
18
- component: '@jasonshimmy/custom-elements-runtime',
19
- defineAsyncComponent: '@jasonshimmy/custom-elements-runtime',
20
- html: '@jasonshimmy/custom-elements-runtime',
21
- css: '@jasonshimmy/custom-elements-runtime',
22
- ref: '@jasonshimmy/custom-elements-runtime',
23
- computed: '@jasonshimmy/custom-elements-runtime',
24
- watch: '@jasonshimmy/custom-elements-runtime',
25
- watchEffect: '@jasonshimmy/custom-elements-runtime',
26
- useProps: '@jasonshimmy/custom-elements-runtime',
27
- useEmit: '@jasonshimmy/custom-elements-runtime',
28
- useOnConnected: '@jasonshimmy/custom-elements-runtime',
29
- useOnDisconnected: '@jasonshimmy/custom-elements-runtime',
30
- useOnAttributeChanged: '@jasonshimmy/custom-elements-runtime',
31
- useOnError: '@jasonshimmy/custom-elements-runtime',
32
- useStyle: '@jasonshimmy/custom-elements-runtime',
33
- useDesignTokens: '@jasonshimmy/custom-elements-runtime',
34
- useGlobalStyle: '@jasonshimmy/custom-elements-runtime',
35
- useExpose: '@jasonshimmy/custom-elements-runtime',
36
- useSlots: '@jasonshimmy/custom-elements-runtime',
37
- provide: '@jasonshimmy/custom-elements-runtime',
38
- inject: '@jasonshimmy/custom-elements-runtime',
39
- createComposable: '@jasonshimmy/custom-elements-runtime',
40
- nextTick: '@jasonshimmy/custom-elements-runtime',
41
- defineModel: '@jasonshimmy/custom-elements-runtime',
42
- getCurrentComponentContext: '@jasonshimmy/custom-elements-runtime',
43
- isReactiveState: '@jasonshimmy/custom-elements-runtime',
44
- unsafeHTML: '@jasonshimmy/custom-elements-runtime',
45
- decodeEntities: '@jasonshimmy/custom-elements-runtime',
46
- useTeleport: '@jasonshimmy/custom-elements-runtime',
47
- }
48
-
49
- /** Maps each directive identifier to its source module (directives sub-path). */
50
- const DIRECTIVE_MAP: Record<string, string> = {
51
- when: '@jasonshimmy/custom-elements-runtime/directives',
52
- each: '@jasonshimmy/custom-elements-runtime/directives',
53
- match: '@jasonshimmy/custom-elements-runtime/directives',
54
- anchorBlock: '@jasonshimmy/custom-elements-runtime/directives',
55
- }
56
-
57
- /** Maps each framework composable to its source module. */
58
- const FRAMEWORK_MAP: Record<string, string> = {
59
- useHead: '@jasonshimmy/vite-plugin-cer-app/composables',
60
- usePageData: '@jasonshimmy/vite-plugin-cer-app/composables',
61
- useInject: '@jasonshimmy/vite-plugin-cer-app/composables',
62
- useRuntimeConfig: '@jasonshimmy/vite-plugin-cer-app/composables',
63
- defineMiddleware: '@jasonshimmy/vite-plugin-cer-app/composables',
64
- defineServerMiddleware: '@jasonshimmy/vite-plugin-cer-app/composables',
65
- useSeoMeta: '@jasonshimmy/vite-plugin-cer-app/composables',
66
- useCookie: '@jasonshimmy/vite-plugin-cer-app/composables',
67
- useSession: '@jasonshimmy/vite-plugin-cer-app/composables',
68
- useAuth: '@jasonshimmy/vite-plugin-cer-app/composables',
69
- useFetch: '@jasonshimmy/vite-plugin-cer-app/composables',
70
- useRoute: '@jasonshimmy/vite-plugin-cer-app/composables',
71
- navigateTo: '@jasonshimmy/vite-plugin-cer-app/composables',
72
- useState: '@jasonshimmy/vite-plugin-cer-app/composables',
73
- useLocale: '@jasonshimmy/vite-plugin-cer-app/composables',
74
- queryContent: '@jasonshimmy/vite-plugin-cer-app/composables',
75
- useContentSearch: '@jasonshimmy/vite-plugin-cer-app/composables',
76
- }
77
-
78
- // All identifier maps — processed in order. Earlier maps take precedence for
79
- // the "already imported from this module" duplicate check.
80
- const ALL_MAPS = [RUNTIME_MAP, DIRECTIVE_MAP, FRAMEWORK_MAP]
81
-
82
- /**
83
- * Returns true if the file already manually imports from the given source module.
84
- * When true, we skip auto-injecting identifiers from that module to avoid duplicates.
85
- */
86
- function isAlreadyImported(code: string, sourceModule: string): boolean {
87
- return (
88
- code.includes(`from '${sourceModule}'`) ||
89
- code.includes(`from "${sourceModule}"`)
90
- )
91
- }
92
-
93
- /**
94
- * Builds minimal import statements containing only the identifiers actually
95
- * referenced in the file. Groups identifiers by source module. Skips modules
96
- * that the file already imports from manually.
97
- *
98
- * Returns an array of import statement strings (one per source module used).
99
- */
100
- function buildMinimalImportStatements(code: string, maps: Record<string, string>[]): string[] {
101
- // Group identifier → source module, collecting only used ones.
102
- const grouped = new Map<string, string[]>()
103
-
104
- for (const map of maps) {
105
- for (const [identifier, sourceModule] of Object.entries(map)) {
106
- // Skip if the file already imports from this module.
107
- if (isAlreadyImported(code, sourceModule)) continue
108
- // Skip if identifier not referenced in the file.
109
- const pattern = new RegExp(`\\b${identifier}\\b`)
110
- if (!pattern.test(code)) continue
111
-
112
- const existing = grouped.get(sourceModule) ?? []
113
- existing.push(identifier)
114
- grouped.set(sourceModule, existing)
115
- }
116
- }
117
-
118
- return Array.from(grouped.entries()).map(
119
- ([mod, ids]) => `import { ${ids.join(', ')} } from '${mod}';`,
120
- )
121
- }
122
-
123
- /**
124
- * Auto-import transform: injects runtime and directive imports at the top of
125
- * files inside app/pages/, app/layouts/, or app/components/ if those
126
- * identifiers are not already imported.
127
- *
128
- * Returns the transformed code string, or null if no injection was needed.
129
- */
130
- export function autoImportTransform(
131
- code: string,
132
- id: string,
133
- opts: AutoImportOptions,
134
- ): string | null {
135
- const normalizedId = normalize(id)
136
- const srcDir = normalize(opts.srcDir)
137
-
138
- // Transform files inside app/pages/, app/layouts/, app/components/, app/middleware/
139
- // AND special convention files directly in app/ (loading.ts, error.ts, etc.)
140
- const isSubDir =
141
- normalizedId.startsWith(srcDir + '/pages/') ||
142
- normalizedId.startsWith(srcDir + '/layouts/') ||
143
- normalizedId.startsWith(srcDir + '/components/') ||
144
- normalizedId.startsWith(srcDir + '/middleware/') ||
145
- normalizedId.startsWith(srcDir + '/composables/')
146
- // Files directly in srcDir root (e.g. app/loading.ts, app/error.ts)
147
- const isRootConventionFile =
148
- normalizedId.startsWith(srcDir + '/') &&
149
- !normalizedId.slice(srcDir.length + 1).includes('/')
150
- // server/middleware/ files also get framework auto-imports
151
- const serverMiddlewareDir = opts.serverMiddlewareDir ? normalize(opts.serverMiddlewareDir) : null
152
- const isServerMiddleware = serverMiddlewareDir != null && normalizedId.startsWith(serverMiddlewareDir + '/')
153
- const isTargetDir = isSubDir || isRootConventionFile || isServerMiddleware
154
-
155
- if (!isTargetDir) return null
156
-
157
- // Skip virtual modules and non-ts files
158
- if (id.startsWith('\0') || (!id.endsWith('.ts') && !id.endsWith('.js'))) return null
159
-
160
- // Skip virtual:cer-composables injection for files inside app/composables/ to
161
- // avoid circular imports (the virtual module re-exports from all composable files).
162
- const isComposablesDir = normalizedId.startsWith(srcDir + '/composables/')
163
- const composableImport = isComposablesDir ? null : buildComposableImport(code, opts.composableExports)
164
-
165
- // Build per-identifier import statements from all maps.
166
- const importLines = buildMinimalImportStatements(code, ALL_MAPS)
167
-
168
- if (importLines.length === 0 && !composableImport) return null
169
-
170
- const ms = new MagicString(code)
171
- const injectLines: string[] = [...importLines]
172
-
173
- if (composableImport) {
174
- injectLines.push(composableImport)
175
- }
176
-
177
- ms.prepend(injectLines.join('\n') + '\n')
178
-
179
- return ms.toString()
180
- }
181
-
182
- /**
183
- * Builds an import statement for any composable names used in the file
184
- * that are not already imported.
185
- * Returns null if no injection is needed.
186
- */
187
- function buildComposableImport(code: string, composableExports?: Map<string, string>): string | null {
188
- if (!composableExports || composableExports.size === 0) return null
189
-
190
- // Skip if already importing from virtual:cer-composables
191
- if (code.includes("from 'virtual:cer-composables'") || code.includes('from "virtual:cer-composables"')) {
192
- return null
193
- }
194
-
195
- const needed: string[] = []
196
- for (const name of composableExports.keys()) {
197
- const pattern = new RegExp(`\\b${name}\\b`)
198
- if (pattern.test(code)) {
199
- needed.push(name)
200
- }
201
- }
202
-
203
- if (needed.length === 0) return null
204
-
205
- return `import { ${needed.join(', ')} } from 'virtual:cer-composables';`
206
- }
@@ -1,161 +0,0 @@
1
- export interface HeadTag {
2
- tag: string
3
- attrs?: Record<string, string>
4
- innerHTML?: string
5
- }
6
-
7
- export interface HeadInput {
8
- title?: string
9
- meta?: Array<Record<string, string>>
10
- link?: Array<Record<string, string>>
11
- script?: Array<Record<string, string>>
12
- style?: Array<Record<string, string>>
13
- }
14
-
15
- /**
16
- * Inserts stringified head tags before the closing </head> tag.
17
- * If no </head> is found, prepends to the document.
18
- */
19
- export function injectHead(html: string, headTags: HeadTag[]): string {
20
- if (headTags.length === 0) return html
21
-
22
- const serialized = headTags.map(serializeTag).join('\n')
23
-
24
- const closeHeadIdx = html.indexOf('</head>')
25
- if (closeHeadIdx !== -1) {
26
- return html.slice(0, closeHeadIdx) + serialized + '\n' + html.slice(closeHeadIdx)
27
- }
28
-
29
- // No </head> found: prepend
30
- return serialized + '\n' + html
31
- }
32
-
33
- /**
34
- * Serializes a single HeadTag to an HTML string.
35
- */
36
- function serializeTag(tag: HeadTag): string {
37
- const attrs = tag.attrs
38
- ? Object.entries(tag.attrs)
39
- .map(([k, v]) => (v === '' ? k : `${k}="${escapeAttr(v)}"`))
40
- .join(' ')
41
- : ''
42
-
43
- const openTag = attrs ? `<${tag.tag} ${attrs}>` : `<${tag.tag}>`
44
-
45
- if (tag.innerHTML !== undefined) {
46
- return `${openTag}${tag.innerHTML}</${tag.tag}>`
47
- }
48
-
49
- // Self-closing for void elements
50
- const voidTags = new Set(['meta', 'link', 'base', 'br', 'hr', 'img', 'input'])
51
- if (voidTags.has(tag.tag)) {
52
- return attrs ? `<${tag.tag} ${attrs}>` : `<${tag.tag}>`
53
- }
54
-
55
- return `${openTag}</${tag.tag}>`
56
- }
57
-
58
- function escapeAttr(value: string): string {
59
- return value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
60
- }
61
-
62
- /**
63
- * HeadCollector gathers HeadInput objects during SSR and serializes them
64
- * to an HTML string for injection into the document head.
65
- */
66
- export class HeadCollector {
67
- private readonly _collected: HeadInput[] = []
68
-
69
- collect(tags: HeadInput): void {
70
- this._collected.push(tags)
71
- }
72
-
73
- serialize(): string {
74
- const tags = headInputToTags(this._collected)
75
- return tags.map(serializeTag).join('\n')
76
- }
77
-
78
- reset(): void {
79
- this._collected.length = 0
80
- }
81
-
82
- getCollected(): HeadInput[] {
83
- return [...this._collected]
84
- }
85
- }
86
-
87
- /**
88
- * Converts an array of HeadInput objects to a flat array of HeadTags.
89
- * Later entries override earlier ones for title; meta/link/script/style are merged.
90
- */
91
- function headInputToTags(inputs: HeadInput[]): HeadTag[] {
92
- const tags: HeadTag[] = []
93
-
94
- // Collect title — last one wins
95
- let title: string | undefined
96
- for (const input of inputs) {
97
- if (input.title !== undefined) {
98
- title = input.title
99
- }
100
- }
101
- if (title !== undefined) {
102
- tags.push({ tag: 'title', innerHTML: escapeHtml(title) })
103
- }
104
-
105
- // Collect meta tags (deduplicate by name/property)
106
- const metaMap = new Map<string, Record<string, string>>()
107
- for (const input of inputs) {
108
- if (input.meta) {
109
- for (const meta of input.meta) {
110
- const key = meta.name ?? meta.property ?? meta.charset ?? JSON.stringify(meta)
111
- metaMap.set(key, meta)
112
- }
113
- }
114
- }
115
- for (const attrs of metaMap.values()) {
116
- tags.push({ tag: 'meta', attrs })
117
- }
118
-
119
- // Collect link tags (deduplicate by rel+href)
120
- const linkMap = new Map<string, Record<string, string>>()
121
- for (const input of inputs) {
122
- if (input.link) {
123
- for (const link of input.link) {
124
- const key = `${link.rel ?? ''}:${link.href ?? ''}`
125
- linkMap.set(key, link)
126
- }
127
- }
128
- }
129
- for (const attrs of linkMap.values()) {
130
- tags.push({ tag: 'link', attrs })
131
- }
132
-
133
- // Collect script tags
134
- for (const input of inputs) {
135
- if (input.script) {
136
- for (const script of input.script) {
137
- const { innerHTML, ...attrs } = script as Record<string, string>
138
- tags.push({ tag: 'script', attrs, innerHTML })
139
- }
140
- }
141
- }
142
-
143
- // Collect style tags
144
- for (const input of inputs) {
145
- if (input.style) {
146
- for (const style of input.style) {
147
- const { innerHTML, ...attrs } = style as Record<string, string>
148
- tags.push({ tag: 'style', attrs, innerHTML })
149
- }
150
- }
151
- }
152
-
153
- return tags
154
- }
155
-
156
- function escapeHtml(str: string): string {
157
- return str
158
- .replace(/&/g, '&amp;')
159
- .replace(/</g, '&lt;')
160
- .replace(/>/g, '&gt;')
161
- }
@@ -1,28 +0,0 @@
1
- import { existsSync } from 'node:fs'
2
- import { scanDirectory } from '../scanner.js'
3
-
4
- /**
5
- * Generates the virtual:cer-composables module code.
6
- * Scans app/composables/ and re-exports all composable functions.
7
- */
8
- export async function generateComposablesCode(composablesDir: string): Promise<string> {
9
- if (!existsSync(composablesDir)) {
10
- return `// AUTO-GENERATED by @jasonshimmy/vite-plugin-cer-app\n// No composables directory found\n`
11
- }
12
-
13
- const files = await scanDirectory('**/*.ts', composablesDir)
14
-
15
- if (files.length === 0) {
16
- return `// AUTO-GENERATED by @jasonshimmy/vite-plugin-cer-app\n// No composables found\n`
17
- }
18
-
19
- const lines: string[] = ['// AUTO-GENERATED by @jasonshimmy/vite-plugin-cer-app', '']
20
-
21
- for (const file of files) {
22
- lines.push(`export * from ${JSON.stringify(file)}`)
23
- }
24
-
25
- lines.push('')
26
-
27
- return lines.join('\n')
28
- }