@jasonshimmy/vite-plugin-cer-app 0.23.2 → 0.24.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 (392) hide show
  1. package/dist/cli/checks/lighthouse.d.ts +26 -0
  2. package/dist/cli/checks/lighthouse.d.ts.map +1 -0
  3. package/dist/cli/checks/lighthouse.js +121 -0
  4. package/dist/cli/checks/lighthouse.js.map +1 -0
  5. package/dist/cli/checks/links.d.ts +12 -0
  6. package/dist/cli/checks/links.d.ts.map +1 -0
  7. package/dist/cli/checks/links.js +89 -0
  8. package/dist/cli/checks/links.js.map +1 -0
  9. package/dist/cli/checks/performance.d.ts +17 -0
  10. package/dist/cli/checks/performance.d.ts.map +1 -0
  11. package/dist/cli/checks/performance.js +61 -0
  12. package/dist/cli/checks/performance.js.map +1 -0
  13. package/dist/cli/commands/check.d.ts +3 -0
  14. package/dist/cli/commands/check.d.ts.map +1 -0
  15. package/dist/cli/commands/check.js +85 -0
  16. package/dist/cli/commands/check.js.map +1 -0
  17. package/dist/cli/create/index.d.ts +11 -1
  18. package/dist/cli/create/index.d.ts.map +1 -1
  19. package/dist/cli/create/index.js +135 -65
  20. package/dist/cli/create/index.js.map +1 -1
  21. package/dist/cli/create/templates/spa/package.json.tpl +5 -3
  22. package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
  23. package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
  24. package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
  25. package/dist/cli/index.js +2 -0
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/index.d.ts +3 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/plugin/build-ssg.d.ts +22 -6
  30. package/dist/plugin/build-ssg.d.ts.map +1 -1
  31. package/dist/plugin/build-ssg.js +227 -17
  32. package/dist/plugin/build-ssg.js.map +1 -1
  33. package/dist/plugin/content/parser.d.ts.map +1 -1
  34. package/dist/plugin/content/parser.js +54 -10
  35. package/dist/plugin/content/parser.js.map +1 -1
  36. package/dist/plugin/dev-server.d.ts +4 -1
  37. package/dist/plugin/dev-server.d.ts.map +1 -1
  38. package/dist/plugin/dev-server.js.map +1 -1
  39. package/dist/plugin/dts-generator.d.ts.map +1 -1
  40. package/dist/plugin/dts-generator.js +50 -8
  41. package/dist/plugin/dts-generator.js.map +1 -1
  42. package/dist/plugin/generated-dir.d.ts +2 -0
  43. package/dist/plugin/generated-dir.d.ts.map +1 -1
  44. package/dist/plugin/generated-dir.js +17 -6
  45. package/dist/plugin/generated-dir.js.map +1 -1
  46. package/dist/plugin/html-post-process.d.ts +6 -0
  47. package/dist/plugin/html-post-process.d.ts.map +1 -1
  48. package/dist/plugin/html-post-process.js +24 -0
  49. package/dist/plugin/html-post-process.js.map +1 -1
  50. package/dist/plugin/index.d.ts.map +1 -1
  51. package/dist/plugin/index.js +60 -13
  52. package/dist/plugin/index.js.map +1 -1
  53. package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
  54. package/dist/plugin/transforms/auto-import.js +7 -0
  55. package/dist/plugin/transforms/auto-import.js.map +1 -1
  56. package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
  57. package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
  58. package/dist/plugin/transforms/prune-runtime-css.js +40 -0
  59. package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
  60. package/dist/runtime/app-template.d.ts +1 -1
  61. package/dist/runtime/app-template.d.ts.map +1 -1
  62. package/dist/runtime/app-template.js +206 -36
  63. package/dist/runtime/app-template.js.map +1 -1
  64. package/dist/runtime/composables/index.d.ts +4 -0
  65. package/dist/runtime/composables/index.d.ts.map +1 -1
  66. package/dist/runtime/composables/index.js +2 -0
  67. package/dist/runtime/composables/index.js.map +1 -1
  68. package/dist/runtime/composables/use-active-headings.d.ts +24 -0
  69. package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
  70. package/dist/runtime/composables/use-active-headings.js +112 -0
  71. package/dist/runtime/composables/use-active-headings.js.map +1 -0
  72. package/dist/runtime/composables/use-content-page.d.ts +45 -0
  73. package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
  74. package/dist/runtime/composables/use-content-page.js +179 -0
  75. package/dist/runtime/composables/use-content-page.js.map +1 -0
  76. package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
  77. package/dist/runtime/composables/use-content-search.js +1 -5
  78. package/dist/runtime/composables/use-content-search.js.map +1 -1
  79. package/dist/runtime/composables/use-fetch.d.ts +2 -1
  80. package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
  81. package/dist/runtime/composables/use-fetch.js +112 -43
  82. package/dist/runtime/composables/use-fetch.js.map +1 -1
  83. package/dist/runtime/composables/use-route.d.ts.map +1 -1
  84. package/dist/runtime/composables/use-route.js +39 -11
  85. package/dist/runtime/composables/use-route.js.map +1 -1
  86. package/dist/runtime/content/client.js +2 -2
  87. package/dist/runtime/content/client.js.map +1 -1
  88. package/dist/runtime/entry-server-template.d.ts +16 -1
  89. package/dist/runtime/entry-server-template.d.ts.map +1 -1
  90. package/dist/runtime/entry-server-template.js +120 -13
  91. package/dist/runtime/entry-server-template.js.map +1 -1
  92. package/dist/types/config.d.ts +45 -4
  93. package/dist/types/config.d.ts.map +1 -1
  94. package/dist/types/config.js.map +1 -1
  95. package/dist/types/middleware.d.ts +2 -2
  96. package/dist/types/middleware.d.ts.map +1 -1
  97. package/package.json +22 -19
  98. package/.github/copilot-instructions.md +0 -169
  99. package/.github/workflows/publish.yml +0 -257
  100. package/.nvmrc +0 -1
  101. package/CHANGELOG.md +0 -236
  102. package/CLAUDE.md +0 -113
  103. package/commits.txt +0 -1
  104. package/cypress.config.ts +0 -16
  105. package/docs/authentication.md +0 -285
  106. package/docs/cli.md +0 -324
  107. package/docs/components.md +0 -237
  108. package/docs/composables.md +0 -907
  109. package/docs/configuration.md +0 -696
  110. package/docs/content.md +0 -570
  111. package/docs/data-loading.md +0 -336
  112. package/docs/getting-started.md +0 -237
  113. package/docs/head-management.md +0 -212
  114. package/docs/i18n.md +0 -159
  115. package/docs/layouts.md +0 -224
  116. package/docs/middleware.md +0 -234
  117. package/docs/plugins.md +0 -170
  118. package/docs/rendering-modes.md +0 -377
  119. package/docs/routing.md +0 -485
  120. package/docs/server-api.md +0 -253
  121. package/docs/testing.md +0 -455
  122. package/docs/use-fetch.md +0 -183
  123. package/e2e/cypress/e2e/api.cy.ts +0 -123
  124. package/e2e/cypress/e2e/async-component.cy.ts +0 -27
  125. package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
  126. package/e2e/cypress/e2e/content.cy.ts +0 -425
  127. package/e2e/cypress/e2e/cookie.cy.ts +0 -85
  128. package/e2e/cypress/e2e/data.cy.ts +0 -158
  129. package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
  130. package/e2e/cypress/e2e/fouc.cy.ts +0 -254
  131. package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
  132. package/e2e/cypress/e2e/head.cy.ts +0 -89
  133. package/e2e/cypress/e2e/i18n.cy.ts +0 -79
  134. package/e2e/cypress/e2e/interactive.cy.ts +0 -137
  135. package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
  136. package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
  137. package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
  138. package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
  139. package/e2e/cypress/e2e/middleware.cy.ts +0 -45
  140. package/e2e/cypress/e2e/navigate.cy.ts +0 -39
  141. package/e2e/cypress/e2e/observability.cy.ts +0 -77
  142. package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
  143. package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
  144. package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
  145. package/e2e/cypress/e2e/routes.cy.ts +0 -128
  146. package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
  147. package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
  148. package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
  149. package/e2e/cypress/e2e/session.cy.ts +0 -73
  150. package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
  151. package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
  152. package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
  153. package/e2e/cypress/e2e/use-state.cy.ts +0 -138
  154. package/e2e/cypress/support/commands.ts +0 -120
  155. package/e2e/cypress/support/e2e.ts +0 -10
  156. package/e2e/cypress/tsconfig.json +0 -14
  157. package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
  158. package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
  159. package/e2e/kitchen-sink/app/error.ts +0 -18
  160. package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
  161. package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
  162. package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
  163. package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
  164. package/e2e/kitchen-sink/app/loading.ts +0 -9
  165. package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
  166. package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
  167. package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
  168. package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
  169. package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
  170. package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
  171. package/e2e/kitchen-sink/app/pages/404.ts +0 -9
  172. package/e2e/kitchen-sink/app/pages/about.ts +0 -17
  173. package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
  174. package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
  175. package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
  176. package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
  177. package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
  178. package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
  179. package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
  180. package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
  181. package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
  182. package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
  183. package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
  184. package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
  185. package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
  186. package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
  187. package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
  188. package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
  189. package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
  190. package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
  191. package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
  192. package/e2e/kitchen-sink/app/pages/head.ts +0 -20
  193. package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
  194. package/e2e/kitchen-sink/app/pages/index.ts +0 -27
  195. package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
  196. package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
  197. package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
  198. package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
  199. package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
  200. package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
  201. package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
  202. package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
  203. package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
  204. package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
  205. package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
  206. package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
  207. package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
  208. package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
  209. package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
  210. package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
  211. package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
  212. package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
  213. package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
  214. package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
  215. package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
  216. package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
  217. package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
  218. package/e2e/kitchen-sink/cer-env.d.ts +0 -35
  219. package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
  220. package/e2e/kitchen-sink/cer.config.ts +0 -43
  221. package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
  222. package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
  223. package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
  224. package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
  225. package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
  226. package/e2e/kitchen-sink/content/blog/index.md +0 -8
  227. package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
  228. package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
  229. package/e2e/kitchen-sink/content/index.md +0 -16
  230. package/e2e/kitchen-sink/server/api/echo.ts +0 -12
  231. package/e2e/kitchen-sink/server/api/health.ts +0 -3
  232. package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
  233. package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
  234. package/e2e/kitchen-sink/server/api/session.ts +0 -23
  235. package/e2e/kitchen-sink/server/data/posts.ts +0 -21
  236. package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
  237. package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
  238. package/e2e/kitchen-sink/tsconfig.json +0 -3
  239. package/e2e/scripts/clean.mjs +0 -14
  240. package/eslint.config.ts +0 -22
  241. package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
  242. package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
  243. package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
  244. package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
  245. package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
  246. package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
  247. package/src/__tests__/cli/preview-hardening.test.ts +0 -265
  248. package/src/__tests__/cli/preview-isr.test.ts +0 -320
  249. package/src/__tests__/index.test.ts +0 -21
  250. package/src/__tests__/plugin/app-template.test.ts +0 -166
  251. package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
  252. package/src/__tests__/plugin/build-ssg.test.ts +0 -598
  253. package/src/__tests__/plugin/build-ssr.test.ts +0 -192
  254. package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
  255. package/src/__tests__/plugin/content/emitter.test.ts +0 -117
  256. package/src/__tests__/plugin/content/loader.test.ts +0 -154
  257. package/src/__tests__/plugin/content/parser.test.ts +0 -381
  258. package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
  259. package/src/__tests__/plugin/content/search.test.ts +0 -119
  260. package/src/__tests__/plugin/dev-server.test.ts +0 -813
  261. package/src/__tests__/plugin/dts-generator.test.ts +0 -394
  262. package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
  263. package/src/__tests__/plugin/generated-dir.test.ts +0 -144
  264. package/src/__tests__/plugin/html-post-process.test.ts +0 -146
  265. package/src/__tests__/plugin/path-utils.test.ts +0 -411
  266. package/src/__tests__/plugin/resolve-config.test.ts +0 -233
  267. package/src/__tests__/plugin/scanner.test.ts +0 -186
  268. package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
  269. package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
  270. package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
  271. package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
  272. package/src/__tests__/plugin/virtual/error.test.ts +0 -71
  273. package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
  274. package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
  275. package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
  276. package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
  277. package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
  278. package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
  279. package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
  280. package/src/__tests__/runtime/app-template.test.ts +0 -208
  281. package/src/__tests__/runtime/define-middleware.test.ts +0 -64
  282. package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
  283. package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
  284. package/src/__tests__/runtime/isr-handler.test.ts +0 -338
  285. package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
  286. package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
  287. package/src/__tests__/runtime/oauth-index.test.ts +0 -43
  288. package/src/__tests__/runtime/use-auth.test.ts +0 -169
  289. package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
  290. package/src/__tests__/runtime/use-content-search.test.ts +0 -163
  291. package/src/__tests__/runtime/use-content.test.ts +0 -226
  292. package/src/__tests__/runtime/use-cookie.test.ts +0 -277
  293. package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
  294. package/src/__tests__/runtime/use-fetch.test.ts +0 -377
  295. package/src/__tests__/runtime/use-head.test.ts +0 -311
  296. package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
  297. package/src/__tests__/runtime/use-inject.test.ts +0 -66
  298. package/src/__tests__/runtime/use-locale.test.ts +0 -152
  299. package/src/__tests__/runtime/use-navigate.test.ts +0 -121
  300. package/src/__tests__/runtime/use-page-data.test.ts +0 -298
  301. package/src/__tests__/runtime/use-route.test.ts +0 -156
  302. package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
  303. package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
  304. package/src/__tests__/runtime/use-session.test.ts +0 -320
  305. package/src/__tests__/runtime/use-state.test.ts +0 -340
  306. package/src/__tests__/types/config.test.ts +0 -18
  307. package/src/cli/adapters/cloudflare.ts +0 -335
  308. package/src/cli/adapters/netlify.ts +0 -326
  309. package/src/cli/adapters/vercel.ts +0 -311
  310. package/src/cli/commands/adapt.ts +0 -84
  311. package/src/cli/commands/build.ts +0 -165
  312. package/src/cli/commands/dev.ts +0 -125
  313. package/src/cli/commands/generate.ts +0 -91
  314. package/src/cli/commands/preview-isr.ts +0 -172
  315. package/src/cli/commands/preview.ts +0 -523
  316. package/src/cli/create/index.ts +0 -275
  317. package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
  318. package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
  319. package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
  320. package/src/cli/create/templates/shared/index.html.tpl +0 -12
  321. package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
  322. package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
  323. package/src/cli/create/templates/spa/package.json.tpl +0 -18
  324. package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
  325. package/src/cli/create/templates/ssg/package.json.tpl +0 -19
  326. package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
  327. package/src/cli/create/templates/ssr/package.json.tpl +0 -18
  328. package/src/cli/index.ts +0 -22
  329. package/src/index.ts +0 -20
  330. package/src/plugin/build-ssg.ts +0 -403
  331. package/src/plugin/build-ssr.ts +0 -134
  332. package/src/plugin/content/emitter.ts +0 -50
  333. package/src/plugin/content/index.ts +0 -233
  334. package/src/plugin/content/parser.ts +0 -259
  335. package/src/plugin/content/path-utils.ts +0 -55
  336. package/src/plugin/content/scanner.ts +0 -26
  337. package/src/plugin/content/search.ts +0 -28
  338. package/src/plugin/dev-server.ts +0 -379
  339. package/src/plugin/dts-generator.ts +0 -273
  340. package/src/plugin/generated-dir.ts +0 -121
  341. package/src/plugin/html-post-process.ts +0 -96
  342. package/src/plugin/index.ts +0 -584
  343. package/src/plugin/path-utils.ts +0 -186
  344. package/src/plugin/scanner.ts +0 -65
  345. package/src/plugin/transforms/auto-import.ts +0 -206
  346. package/src/plugin/transforms/head-inject.ts +0 -161
  347. package/src/plugin/virtual/composables.ts +0 -28
  348. package/src/plugin/virtual/content-components.ts +0 -83
  349. package/src/plugin/virtual/error.ts +0 -34
  350. package/src/plugin/virtual/layouts.ts +0 -41
  351. package/src/plugin/virtual/loading.ts +0 -32
  352. package/src/plugin/virtual/middleware.ts +0 -45
  353. package/src/plugin/virtual/plugins.ts +0 -46
  354. package/src/plugin/virtual/routes.ts +0 -514
  355. package/src/plugin/virtual/server-api.ts +0 -85
  356. package/src/plugin/virtual/server-middleware.ts +0 -44
  357. package/src/runtime/app-template.ts +0 -377
  358. package/src/runtime/composables/define-middleware.ts +0 -17
  359. package/src/runtime/composables/define-server-middleware.ts +0 -18
  360. package/src/runtime/composables/index.ts +0 -27
  361. package/src/runtime/composables/use-auth.ts +0 -125
  362. package/src/runtime/composables/use-content-search.ts +0 -205
  363. package/src/runtime/composables/use-content.ts +0 -146
  364. package/src/runtime/composables/use-cookie.ts +0 -135
  365. package/src/runtime/composables/use-fetch.ts +0 -438
  366. package/src/runtime/composables/use-head.ts +0 -234
  367. package/src/runtime/composables/use-inject.ts +0 -49
  368. package/src/runtime/composables/use-locale.ts +0 -109
  369. package/src/runtime/composables/use-navigate.ts +0 -58
  370. package/src/runtime/composables/use-page-data.ts +0 -93
  371. package/src/runtime/composables/use-route.ts +0 -71
  372. package/src/runtime/composables/use-runtime-config.ts +0 -123
  373. package/src/runtime/composables/use-seo-meta.ts +0 -80
  374. package/src/runtime/composables/use-session.ts +0 -186
  375. package/src/runtime/composables/use-state.ts +0 -92
  376. package/src/runtime/content/client.ts +0 -168
  377. package/src/runtime/entry-client-template.ts +0 -39
  378. package/src/runtime/entry-server-template.ts +0 -493
  379. package/src/runtime/isr-handler.ts +0 -184
  380. package/src/runtime/oauth/handler.ts +0 -407
  381. package/src/runtime/oauth/index.ts +0 -49
  382. package/src/runtime/oauth/providers.ts +0 -38
  383. package/src/types/api.ts +0 -40
  384. package/src/types/config.ts +0 -379
  385. package/src/types/content.ts +0 -66
  386. package/src/types/index.ts +0 -7
  387. package/src/types/middleware.ts +0 -63
  388. package/src/types/page.ts +0 -117
  389. package/src/types/plugin.ts +0 -34
  390. package/tsconfig.build.json +0 -10
  391. package/tsconfig.json +0 -19
  392. 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
- }