@ecopages/core 0.2.0-alpha.7 → 0.2.0-alpha.9

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 (354) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/package.json +212 -92
  3. package/src/adapters/abstract/application-adapter.d.ts +168 -0
  4. package/src/adapters/abstract/application-adapter.js +109 -0
  5. package/src/adapters/abstract/router-adapter.d.ts +26 -0
  6. package/src/adapters/abstract/router-adapter.js +5 -0
  7. package/src/adapters/abstract/server-adapter.d.ts +69 -0
  8. package/src/adapters/abstract/server-adapter.js +15 -0
  9. package/src/adapters/bun/client-bridge.d.ts +34 -0
  10. package/src/adapters/bun/client-bridge.js +48 -0
  11. package/src/adapters/bun/create-app.d.ts +60 -0
  12. package/src/adapters/bun/create-app.js +117 -0
  13. package/src/adapters/bun/hmr-manager.d.ts +143 -0
  14. package/src/adapters/bun/hmr-manager.js +334 -0
  15. package/src/adapters/bun/index.d.ts +2 -0
  16. package/src/adapters/bun/index.js +8 -0
  17. package/src/adapters/bun/server-adapter.d.ts +155 -0
  18. package/src/adapters/bun/server-adapter.js +373 -0
  19. package/src/adapters/bun/server-lifecycle.d.ts +63 -0
  20. package/src/adapters/bun/server-lifecycle.js +92 -0
  21. package/src/adapters/index.d.ts +6 -0
  22. package/src/adapters/index.js +14 -0
  23. package/src/adapters/node/bootstrap-dependency-resolver.d.ts +44 -0
  24. package/src/adapters/node/bootstrap-dependency-resolver.js +172 -0
  25. package/src/adapters/node/create-app.d.ts +21 -0
  26. package/src/adapters/node/create-app.js +143 -0
  27. package/src/adapters/node/index.d.ts +6 -0
  28. package/src/adapters/node/index.js +11 -0
  29. package/src/adapters/node/node-client-bridge.d.ts +26 -0
  30. package/src/adapters/node/node-client-bridge.js +66 -0
  31. package/src/adapters/node/node-hmr-manager.d.ts +133 -0
  32. package/src/adapters/node/node-hmr-manager.js +312 -0
  33. package/src/adapters/node/runtime-adapter.d.ts +46 -0
  34. package/src/adapters/node/runtime-adapter.js +306 -0
  35. package/src/adapters/node/server-adapter.d.ts +161 -0
  36. package/src/adapters/node/server-adapter.js +358 -0
  37. package/src/adapters/node/static-content-server.d.ts +60 -0
  38. package/src/adapters/node/static-content-server.js +194 -0
  39. package/src/adapters/node/write-runtime-manifest.d.ts +26 -0
  40. package/src/adapters/node/write-runtime-manifest.js +12 -0
  41. package/src/adapters/shared/api-response.d.ts +52 -0
  42. package/src/adapters/shared/api-response.js +96 -0
  43. package/src/adapters/shared/application-adapter.d.ts +18 -0
  44. package/src/adapters/shared/application-adapter.js +90 -0
  45. package/src/adapters/shared/define-api-handler.d.ts +25 -0
  46. package/src/adapters/shared/define-api-handler.js +15 -0
  47. package/src/adapters/shared/explicit-static-route-matcher.d.ts +38 -0
  48. package/src/adapters/shared/explicit-static-route-matcher.js +103 -0
  49. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +65 -0
  50. package/src/adapters/shared/file-route-middleware-pipeline.js +99 -0
  51. package/src/adapters/shared/fs-server-response-factory.d.ts +19 -0
  52. package/src/adapters/shared/fs-server-response-factory.js +97 -0
  53. package/src/adapters/shared/fs-server-response-matcher.d.ts +75 -0
  54. package/src/adapters/shared/fs-server-response-matcher.js +160 -0
  55. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +55 -0
  56. package/src/adapters/shared/hmr-entrypoint-registrar.js +87 -0
  57. package/src/adapters/shared/hmr-html-response.d.ts +22 -0
  58. package/src/adapters/shared/hmr-html-response.js +32 -0
  59. package/src/adapters/shared/render-context.d.ts +14 -0
  60. package/src/adapters/shared/render-context.js +70 -0
  61. package/src/adapters/shared/runtime-bootstrap.d.ts +38 -0
  62. package/src/adapters/shared/runtime-bootstrap.js +43 -0
  63. package/src/adapters/shared/server-adapter.d.ts +97 -0
  64. package/src/adapters/shared/server-adapter.js +386 -0
  65. package/src/adapters/shared/server-route-handler.d.ts +89 -0
  66. package/src/adapters/shared/server-route-handler.js +111 -0
  67. package/src/adapters/shared/server-static-builder.d.ts +70 -0
  68. package/src/adapters/shared/server-static-builder.js +99 -0
  69. package/src/build/build-adapter.d.ts +186 -0
  70. package/src/build/build-adapter.js +168 -0
  71. package/src/build/build-manifest.d.ts +27 -0
  72. package/src/build/build-manifest.js +30 -0
  73. package/src/build/build-types.d.ts +57 -0
  74. package/src/build/build-types.js +0 -0
  75. package/src/build/dev-build-coordinator.d.ts +74 -0
  76. package/src/build/dev-build-coordinator.js +161 -0
  77. package/src/build/esbuild-build-adapter.d.ts +72 -0
  78. package/src/build/esbuild-build-adapter.js +422 -0
  79. package/src/build/runtime-build-executor.d.ts +13 -0
  80. package/src/build/runtime-build-executor.js +20 -0
  81. package/src/build/runtime-specifier-alias-plugin.d.ts +15 -0
  82. package/src/build/runtime-specifier-alias-plugin.js +31 -0
  83. package/src/config/config-builder.d.ts +238 -0
  84. package/src/config/config-builder.js +565 -0
  85. package/src/constants.d.ts +45 -0
  86. package/src/constants.js +25 -0
  87. package/src/create-app.d.ts +17 -0
  88. package/src/create-app.js +66 -0
  89. package/src/dev/sc-server.d.ts +30 -0
  90. package/src/dev/sc-server.js +111 -0
  91. package/src/eco/component-render-context.d.ts +105 -0
  92. package/src/eco/component-render-context.js +87 -0
  93. package/src/eco/eco.d.ts +9 -0
  94. package/src/eco/eco.js +114 -0
  95. package/src/eco/eco.types.d.ts +178 -0
  96. package/src/eco/eco.types.js +0 -0
  97. package/src/eco/eco.utils.d.ts +40 -0
  98. package/src/eco/eco.utils.js +40 -0
  99. package/src/eco/global-injector-map.d.ts +16 -0
  100. package/src/eco/global-injector-map.js +80 -0
  101. package/src/eco/lazy-injector-map.d.ts +8 -0
  102. package/src/eco/lazy-injector-map.js +70 -0
  103. package/src/eco/module-dependencies.d.ts +18 -0
  104. package/src/eco/module-dependencies.js +49 -0
  105. package/src/errors/http-error.d.ts +31 -0
  106. package/src/errors/http-error.js +50 -0
  107. package/src/errors/index.d.ts +2 -0
  108. package/src/errors/index.js +4 -0
  109. package/src/errors/locals-access-error.d.ts +4 -0
  110. package/src/errors/locals-access-error.js +9 -0
  111. package/src/global/app-logger.d.ts +2 -0
  112. package/src/global/app-logger.js +6 -0
  113. package/src/hmr/client/hmr-runtime.d.ts +5 -0
  114. package/src/hmr/client/hmr-runtime.js +109 -0
  115. package/src/hmr/hmr-strategy.d.ts +159 -0
  116. package/src/hmr/hmr-strategy.js +29 -0
  117. package/src/hmr/hmr.postcss.test.e2e.d.ts +1 -0
  118. package/src/hmr/hmr.postcss.test.e2e.js +31 -0
  119. package/src/hmr/hmr.test.e2e.d.ts +1 -0
  120. package/src/hmr/hmr.test.e2e.js +43 -0
  121. package/src/hmr/strategies/default-hmr-strategy.d.ts +43 -0
  122. package/src/hmr/strategies/default-hmr-strategy.js +34 -0
  123. package/src/hmr/strategies/js-hmr-strategy.d.ts +139 -0
  124. package/src/hmr/strategies/js-hmr-strategy.js +178 -0
  125. package/src/index.browser.d.ts +3 -0
  126. package/src/index.browser.js +4 -0
  127. package/src/index.d.ts +5 -0
  128. package/src/index.js +10 -0
  129. package/src/integrations/ghtml/ghtml-renderer.d.ts +15 -0
  130. package/src/integrations/ghtml/ghtml-renderer.js +62 -0
  131. package/src/integrations/ghtml/ghtml.plugin.d.ts +20 -0
  132. package/src/integrations/ghtml/ghtml.plugin.js +21 -0
  133. package/src/internal-types.d.ts +221 -0
  134. package/src/internal-types.js +0 -0
  135. package/src/plugins/alias-resolver-plugin.d.ts +2 -0
  136. package/src/plugins/alias-resolver-plugin.js +53 -0
  137. package/src/plugins/eco-component-meta-plugin.d.ts +97 -0
  138. package/src/plugins/eco-component-meta-plugin.js +157 -0
  139. package/src/plugins/integration-plugin.d.ts +136 -0
  140. package/src/plugins/integration-plugin.js +133 -0
  141. package/src/plugins/processor.d.ts +95 -0
  142. package/src/plugins/processor.js +136 -0
  143. package/src/plugins/runtime-capability.d.ts +9 -0
  144. package/src/plugins/runtime-capability.js +0 -0
  145. package/src/public-types.d.ts +1149 -0
  146. package/src/public-types.js +0 -0
  147. package/src/route-renderer/component-graph/component-graph-executor.d.ts +32 -0
  148. package/src/route-renderer/component-graph/component-graph-executor.js +31 -0
  149. package/src/route-renderer/component-graph/component-graph.d.ts +42 -0
  150. package/src/route-renderer/component-graph/component-graph.js +72 -0
  151. package/src/route-renderer/component-graph/component-marker.d.ts +52 -0
  152. package/src/route-renderer/component-graph/component-marker.js +46 -0
  153. package/src/route-renderer/component-graph/component-reference.d.ts +10 -0
  154. package/src/route-renderer/component-graph/component-reference.js +19 -0
  155. package/src/route-renderer/component-graph/marker-graph-resolver.d.ts +77 -0
  156. package/src/route-renderer/component-graph/marker-graph-resolver.js +95 -0
  157. package/src/route-renderer/orchestration/integration-renderer.d.ts +372 -0
  158. package/src/route-renderer/orchestration/integration-renderer.js +589 -0
  159. package/src/route-renderer/orchestration/render-execution.service.d.ts +103 -0
  160. package/src/route-renderer/orchestration/render-execution.service.js +121 -0
  161. package/src/route-renderer/orchestration/render-preparation.service.d.ts +121 -0
  162. package/src/route-renderer/orchestration/render-preparation.service.js +332 -0
  163. package/src/route-renderer/page-loading/dependency-resolver.d.ts +35 -0
  164. package/src/route-renderer/page-loading/dependency-resolver.js +442 -0
  165. package/src/route-renderer/page-loading/page-module-loader.d.ts +87 -0
  166. package/src/route-renderer/page-loading/page-module-loader.js +124 -0
  167. package/src/route-renderer/route-renderer.d.ts +61 -0
  168. package/src/route-renderer/route-renderer.js +87 -0
  169. package/src/router/client/link-intent.js +34 -0
  170. package/src/router/client/link-intent.test.browser.d.ts +1 -0
  171. package/src/router/client/link-intent.test.browser.js +43 -0
  172. package/src/router/client/navigation-coordinator.d.ts +149 -0
  173. package/src/router/client/navigation-coordinator.js +215 -0
  174. package/src/router/server/fs-router-scanner.d.ts +41 -0
  175. package/src/router/server/fs-router-scanner.js +156 -0
  176. package/src/router/server/fs-router.d.ts +26 -0
  177. package/src/router/server/fs-router.js +100 -0
  178. package/src/services/assets/asset-processing-service/asset-processing.service.d.ts +120 -0
  179. package/src/services/assets/asset-processing-service/asset-processing.service.js +331 -0
  180. package/src/services/assets/asset-processing-service/asset.factory.d.ts +17 -0
  181. package/src/services/assets/asset-processing-service/asset.factory.js +82 -0
  182. package/src/services/assets/asset-processing-service/assets.types.d.ts +89 -0
  183. package/src/services/assets/asset-processing-service/assets.types.js +0 -0
  184. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +55 -0
  185. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +48 -0
  186. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +20 -0
  187. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +41 -0
  188. package/src/services/assets/asset-processing-service/index.d.ts +5 -0
  189. package/src/services/assets/asset-processing-service/index.js +5 -0
  190. package/src/services/assets/asset-processing-service/processor.interface.d.ts +22 -0
  191. package/src/services/assets/asset-processing-service/processor.interface.js +6 -0
  192. package/src/services/assets/asset-processing-service/processor.registry.d.ts +8 -0
  193. package/src/services/assets/asset-processing-service/processor.registry.js +15 -0
  194. package/src/services/assets/asset-processing-service/processors/base/base-processor.d.ts +24 -0
  195. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +64 -0
  196. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.d.ts +17 -0
  197. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +72 -0
  198. package/src/services/assets/asset-processing-service/processors/index.d.ts +5 -0
  199. package/src/services/assets/asset-processing-service/processors/index.js +5 -0
  200. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.d.ts +5 -0
  201. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +57 -0
  202. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +8 -0
  203. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +76 -0
  204. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.d.ts +7 -0
  205. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +75 -0
  206. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +5 -0
  207. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +25 -0
  208. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +9 -0
  209. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +66 -0
  210. package/src/services/assets/browser-bundle.service.d.ts +32 -0
  211. package/src/services/assets/browser-bundle.service.js +33 -0
  212. package/src/services/cache/cache.types.d.ts +107 -0
  213. package/src/services/cache/cache.types.js +0 -0
  214. package/src/services/cache/index.d.ts +7 -0
  215. package/src/services/cache/index.js +7 -0
  216. package/src/services/cache/memory-cache-store.d.ts +42 -0
  217. package/src/services/cache/memory-cache-store.js +98 -0
  218. package/src/services/cache/page-cache-service.d.ts +70 -0
  219. package/src/services/cache/page-cache-service.js +152 -0
  220. package/src/services/cache/page-request-cache-coordinator.service.d.ts +75 -0
  221. package/src/services/cache/page-request-cache-coordinator.service.js +109 -0
  222. package/src/services/html/html-rewriter-provider.service.d.ts +37 -0
  223. package/src/services/html/html-rewriter-provider.service.js +65 -0
  224. package/src/services/html/html-transformer.service.d.ts +77 -0
  225. package/src/services/html/html-transformer.service.js +221 -0
  226. package/src/services/invalidation/development-invalidation.service.d.ts +74 -0
  227. package/src/services/invalidation/development-invalidation.service.js +189 -0
  228. package/src/services/module-loading/app-server-module-transpiler.service.d.ts +16 -0
  229. package/src/services/module-loading/app-server-module-transpiler.service.js +34 -0
  230. package/src/services/module-loading/page-module-import.service.d.ts +71 -0
  231. package/src/services/module-loading/page-module-import.service.js +132 -0
  232. package/src/services/module-loading/server-loader.service.d.ts +96 -0
  233. package/src/services/module-loading/server-loader.service.js +32 -0
  234. package/src/services/module-loading/server-module-transpiler.service.d.ts +69 -0
  235. package/src/services/module-loading/server-module-transpiler.service.js +61 -0
  236. package/src/services/runtime-manifest/node-runtime-manifest.service.d.ts +35 -0
  237. package/src/services/runtime-manifest/node-runtime-manifest.service.js +60 -0
  238. package/src/services/runtime-state/dev-graph.service.d.ts +118 -0
  239. package/src/services/runtime-state/dev-graph.service.js +162 -0
  240. package/src/services/runtime-state/entrypoint-dependency-graph.service.d.ts +41 -0
  241. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -0
  242. package/src/services/runtime-state/runtime-specifier-registry.service.d.ts +69 -0
  243. package/src/services/runtime-state/runtime-specifier-registry.service.js +37 -0
  244. package/src/services/runtime-state/server-invalidation-state.service.d.ts +26 -0
  245. package/src/services/runtime-state/server-invalidation-state.service.js +35 -0
  246. package/src/services/validation/schema-validation-service.d.ts +122 -0
  247. package/src/services/validation/schema-validation-service.js +101 -0
  248. package/src/services/validation/standard-schema.types.d.ts +65 -0
  249. package/src/services/validation/standard-schema.types.js +0 -0
  250. package/src/static-site-generator/static-site-generator.d.ts +109 -0
  251. package/src/static-site-generator/static-site-generator.js +353 -0
  252. package/src/utils/css.d.ts +1 -0
  253. package/src/utils/css.js +7 -0
  254. package/src/utils/deep-merge.d.ts +14 -0
  255. package/src/utils/deep-merge.js +32 -0
  256. package/src/utils/hash.d.ts +1 -0
  257. package/src/utils/hash.js +7 -0
  258. package/src/utils/html.d.ts +1 -0
  259. package/src/utils/html.js +4 -0
  260. package/src/utils/invariant.d.ts +5 -0
  261. package/src/utils/invariant.js +11 -0
  262. package/src/utils/locals-utils.d.ts +15 -0
  263. package/src/utils/locals-utils.js +24 -0
  264. package/src/utils/parse-cli-args.d.ts +24 -0
  265. package/src/utils/parse-cli-args.js +47 -0
  266. package/src/utils/path-utils.module.d.ts +5 -0
  267. package/src/utils/path-utils.module.js +14 -0
  268. package/src/utils/resolve-work-dir.d.ts +11 -0
  269. package/src/utils/resolve-work-dir.js +31 -0
  270. package/src/utils/runtime.d.ts +11 -0
  271. package/src/utils/runtime.js +40 -0
  272. package/src/utils/server-utils.module.d.ts +19 -0
  273. package/src/utils/server-utils.module.js +56 -0
  274. package/src/watchers/project-watcher.d.ts +136 -0
  275. package/src/watchers/project-watcher.js +281 -0
  276. package/src/watchers/project-watcher.test-helpers.d.ts +4 -0
  277. package/src/watchers/project-watcher.test-helpers.js +52 -0
  278. package/src/adapters/bun/hmr-manager.test.ts +0 -267
  279. package/src/adapters/node/bootstrap-dependency-resolver.test.ts +0 -282
  280. package/src/adapters/node/node-client-bridge.test.ts +0 -198
  281. package/src/adapters/node/node-hmr-manager.test.ts +0 -322
  282. package/src/adapters/node/runtime-adapter.test.ts +0 -868
  283. package/src/adapters/node/static-content-server.test.ts +0 -60
  284. package/src/adapters/shared/api-response.test.ts +0 -97
  285. package/src/adapters/shared/explicit-static-route-matcher.test.ts +0 -381
  286. package/src/adapters/shared/file-route-middleware-pipeline.test.ts +0 -90
  287. package/src/adapters/shared/fs-server-response-factory.test.ts +0 -187
  288. package/src/adapters/shared/fs-server-response-matcher.test.ts +0 -286
  289. package/src/adapters/shared/hmr-manager.contract.test.ts +0 -196
  290. package/src/adapters/shared/hmr-manager.dispatch.test.ts +0 -220
  291. package/src/adapters/shared/render-context.test.ts +0 -146
  292. package/src/adapters/shared/server-adapter.test.ts +0 -77
  293. package/src/adapters/shared/server-route-handler.test.ts +0 -110
  294. package/src/adapters/shared/server-static-builder.test.ts +0 -316
  295. package/src/build/build-adapter-serialization.test.ts +0 -268
  296. package/src/build/build-adapter.test.ts +0 -815
  297. package/src/build/runtime-specifier-alias-plugin.test.ts +0 -43
  298. package/src/config/config-builder.test.ts +0 -410
  299. package/src/eco/eco.test.ts +0 -678
  300. package/src/eco/eco.utils.test.ts +0 -124
  301. package/src/eco/global-injector-map.test.ts +0 -42
  302. package/src/eco/lazy-injector-map.test.ts +0 -66
  303. package/src/eco/module-dependencies.test.ts +0 -30
  304. package/src/errors/http-error.test.ts +0 -134
  305. package/src/global/utils.test.ts +0 -12
  306. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-have-HMR-script-injected-in-page-1.png +0 -0
  307. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  308. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  309. package/src/hmr/hmr-strategy.test.ts +0 -124
  310. package/src/hmr/strategies/js-hmr-strategy.test.ts +0 -335
  311. package/src/integrations/ghtml/ghtml-renderer.test.ts +0 -63
  312. package/src/plugins/alias-resolver-plugin.test.ts +0 -41
  313. package/src/plugins/eco-component-meta-plugin.test.ts +0 -380
  314. package/src/plugins/integration-plugin.test.ts +0 -111
  315. package/src/plugins/processor.test.ts +0 -148
  316. package/src/route-renderer/component-graph/component-graph-executor.test.ts +0 -41
  317. package/src/route-renderer/component-graph/component-graph.test.ts +0 -63
  318. package/src/route-renderer/component-graph/component-marker.test.ts +0 -73
  319. package/src/route-renderer/component-graph/marker-graph-resolver.test.ts +0 -135
  320. package/src/route-renderer/orchestration/integration-renderer.test.ts +0 -936
  321. package/src/route-renderer/orchestration/render-execution.service.test.ts +0 -97
  322. package/src/route-renderer/orchestration/render-preparation.service.test.ts +0 -235
  323. package/src/route-renderer/page-loading/dependency-resolver.test.ts +0 -345
  324. package/src/route-renderer/page-loading/page-module-loader.test.ts +0 -96
  325. package/src/router/client/navigation-coordinator.test.ts +0 -237
  326. package/src/router/server/fs-router-scanner.test.ts +0 -83
  327. package/src/router/server/fs-router.test.ts +0 -214
  328. package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +0 -385
  329. package/src/services/assets/asset-processing-service/asset.factory.test.ts +0 -63
  330. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +0 -72
  331. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +0 -67
  332. package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +0 -59
  333. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +0 -286
  334. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +0 -227
  335. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +0 -199
  336. package/src/services/assets/browser-bundle.service.test.ts +0 -36
  337. package/src/services/cache/memory-cache-store.test.ts +0 -225
  338. package/src/services/cache/page-cache-service.test.ts +0 -175
  339. package/src/services/cache/page-request-cache-coordinator.service.test.ts +0 -79
  340. package/src/services/html/html-rewriter-provider.service.test.ts +0 -183
  341. package/src/services/html/html-transformer.service.test.ts +0 -378
  342. package/src/services/invalidation/development-invalidation.service.test.ts +0 -77
  343. package/src/services/module-loading/page-module-import.service.test.ts +0 -253
  344. package/src/services/module-loading/server-loader.service.test.ts +0 -161
  345. package/src/services/module-loading/server-module-transpiler.service.test.ts +0 -115
  346. package/src/services/runtime-manifest/node-runtime-manifest.service.test.ts +0 -95
  347. package/src/services/validation/schema-validation-service.test.ts +0 -223
  348. package/src/static-site-generator/static-site-generator.test.ts +0 -307
  349. package/src/utils/deep-merge.test.ts +0 -114
  350. package/src/utils/invariant.test.ts +0 -22
  351. package/src/utils/path-utils.test.ts +0 -15
  352. package/src/utils/server-utils.test.ts +0 -38
  353. package/src/watchers/project-watcher.integration.test.ts +0 -337
  354. package/src/watchers/project-watcher.test.ts +0 -678
@@ -1,936 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { IntegrationRenderer, type RenderToResponseContext } from './integration-renderer.ts';
3
- import type { EcoPagesAppConfig } from '../../internal-types.ts';
4
- import type { AssetProcessingService, ProcessedAsset } from '../../services/assets/asset-processing-service/index.ts';
5
- import type {
6
- ComponentRenderInput,
7
- ComponentRenderResult,
8
- RouteRendererBody,
9
- EcoPagesElement,
10
- IntegrationRendererRenderOptions,
11
- EcoPageFile,
12
- RouteRendererOptions,
13
- EcoComponent,
14
- HtmlTemplateProps,
15
- } from '../../public-types.ts';
16
- import type { EcoPageComponent } from '../../eco/eco.types.ts';
17
-
18
- /**
19
- * Concrete implementation with ed file loading for testing purposes.
20
- */
21
- class TestIntegrationRenderer extends IntegrationRenderer<EcoPagesElement> {
22
- name = 'test-renderer';
23
-
24
- /** Mock data container for page module */
25
- PageModule: EcoPageFile | null = null;
26
- /** Mock HTML template container */
27
- HtmlTemplate: EcoComponent<HtmlTemplateProps> | null = null;
28
- RenderedBody: RouteRendererBody = '<html><body>Test Page</body></html>';
29
- MockComponentRenderResult: ComponentRenderResult | null = null;
30
-
31
- async render(_options: IntegrationRendererRenderOptions<EcoPagesElement>): Promise<RouteRendererBody> {
32
- return this.RenderedBody;
33
- }
34
-
35
- override async renderComponent(_input: ComponentRenderInput): Promise<ComponentRenderResult> {
36
- if (this.MockComponentRenderResult) {
37
- return this.MockComponentRenderResult;
38
- }
39
-
40
- return super.renderComponent(_input);
41
- }
42
-
43
- async renderToResponse<P>(view: EcoComponent<P>, props: P, ctx: RenderToResponseContext): Promise<Response> {
44
- const viewFn = view as (props: P) => EcoPagesElement;
45
- const content = viewFn(props);
46
-
47
- let body: string;
48
- if (ctx.partial) {
49
- body = content as string;
50
- } else {
51
- const Layout = view.config?.layout as ((props: { children: string }) => string) | undefined;
52
- const children = Layout ? Layout({ children: content as string }) : content;
53
- body = `<!DOCTYPE html><html><body>${children}</body></html>`;
54
- }
55
-
56
- const headers = new Headers({ 'Content-Type': 'text/html; charset=utf-8' });
57
- if (ctx.headers) {
58
- for (const [key, value] of Object.entries(ctx.headers)) {
59
- headers.set(key, value);
60
- }
61
- }
62
-
63
- return new Response(body, {
64
- status: ctx.status ?? 200,
65
- headers,
66
- });
67
- }
68
-
69
- /**
70
- * Override protected methods to return data.
71
- */
72
- protected override async importPageFile(_file: string): Promise<EcoPageFile> {
73
- if (!this.PageModule) throw new Error('Mock page module not set');
74
- return this.PageModule;
75
- }
76
-
77
- protected override async getHtmlTemplate(): Promise<EcoComponent<HtmlTemplateProps>> {
78
- if (!this.HtmlTemplate) throw new Error('Mock HTML template not set');
79
- return this.HtmlTemplate;
80
- }
81
-
82
- /**
83
- * Override to avoid asset processing service dependency in tests.
84
- */
85
- protected override async resolveDependencies(
86
- _components: (EcoComponent | Partial<EcoComponent>)[],
87
- ): Promise<ProcessedAsset[]> {
88
- return [];
89
- }
90
-
91
- protected override async buildRouteRenderAssets(_file: string): Promise<ProcessedAsset[]> {
92
- return [];
93
- }
94
-
95
- /**
96
- * Expose protected method for testing.
97
- */
98
- public async testPrepareRenderOptions(options: RouteRendererOptions) {
99
- return this.prepareRenderOptions(options);
100
- }
101
-
102
- public async testProcessComponentDependencies(components: (EcoComponent | Partial<EcoComponent>)[]) {
103
- return this.processComponentDependencies(components);
104
- }
105
-
106
- public testShouldDeferComponentBoundary(input: {
107
- currentIntegration: string;
108
- targetIntegration?: string;
109
- component: EcoComponent;
110
- }) {
111
- return this.shouldDeferComponentBoundary(input);
112
- }
113
- }
114
-
115
- describe('IntegrationRenderer', () => {
116
- const AppConfig = {
117
- absolutePaths: {
118
- pagesDir: '/app/pages',
119
- htmlTemplatePath: '/app/index.ghtml.ts',
120
- },
121
- integrations: [],
122
- defaultMetadata: {
123
- title: 'Default Title',
124
- description: 'Default Description',
125
- },
126
- srcDir: '/app',
127
- } as unknown as EcoPagesAppConfig;
128
-
129
- const AssetService = {
130
- processDependencies: vi.fn(() => Promise.resolve([])),
131
- } as unknown as AssetProcessingService;
132
-
133
- it('should extract cache strategy from page component (static property)', async () => {
134
- const renderer = new TestIntegrationRenderer({
135
- appConfig: AppConfig,
136
- assetProcessingService: AssetService,
137
- runtimeOrigin: 'http://localhost:3000',
138
- });
139
-
140
- /** Mock page with cache strategy */
141
- const PageIdx = (() => 'Page Content') as EcoPageComponent<any>;
142
- /** Simulate eco.page() attaching cache config */
143
- PageIdx.cache = { revalidate: 60 };
144
-
145
- renderer.PageModule = {
146
- default: PageIdx,
147
- };
148
- renderer.HtmlTemplate = (() => 'HTML Template') as EcoComponent<HtmlTemplateProps>;
149
-
150
- const options: RouteRendererOptions = {
151
- file: '/app/pages/cached-page.ts',
152
- params: {},
153
- query: {},
154
- };
155
-
156
- const result = await renderer.testPrepareRenderOptions(options);
157
-
158
- expect(result.cacheStrategy).toEqual({ revalidate: 60 });
159
- });
160
-
161
- it('should return undefined cache strategy if not present', async () => {
162
- const renderer = new TestIntegrationRenderer({
163
- appConfig: AppConfig,
164
- assetProcessingService: AssetService,
165
- runtimeOrigin: 'http://localhost:3000',
166
- });
167
-
168
- /** Mock page without cache strategy */
169
- const PageIdx = (() => 'Page Content') as EcoPageComponent<any>;
170
-
171
- renderer.PageModule = {
172
- default: PageIdx,
173
- };
174
- renderer.HtmlTemplate = (() => 'HTML Template') as EcoComponent<HtmlTemplateProps>;
175
-
176
- const options: RouteRendererOptions = {
177
- file: '/app/pages/simple-page.ts',
178
- params: {},
179
- query: {},
180
- };
181
-
182
- const result = await renderer.testPrepareRenderOptions(options);
183
-
184
- expect(result.cacheStrategy).toBeUndefined();
185
- });
186
-
187
- it('should resolve static props and metadata correctly', async () => {
188
- const renderer = new TestIntegrationRenderer({
189
- appConfig: AppConfig,
190
- assetProcessingService: AssetService,
191
- runtimeOrigin: 'http://localhost:3000',
192
- });
193
-
194
- const PageIdx = (() => 'Page Content') as EcoPageComponent<any>;
195
- /** Attached static methods */
196
- PageIdx.staticProps = async () => ({ props: { title: 'Dynamic Title' } });
197
- PageIdx.metadata = async ({ props }: { props: Record<string, unknown> }) => ({
198
- title: props.title as string,
199
- description: 'Dynamic Description',
200
- });
201
-
202
- renderer.PageModule = {
203
- default: PageIdx,
204
- };
205
- renderer.HtmlTemplate = (() => 'HTML Template') as EcoComponent<HtmlTemplateProps>;
206
-
207
- const options: RouteRendererOptions = {
208
- file: '/app/pages/props-page.ts',
209
- params: {},
210
- query: {},
211
- };
212
-
213
- const result = await renderer.testPrepareRenderOptions(options);
214
-
215
- expect(result.props).toEqual({ title: 'Dynamic Title' });
216
- expect(result.metadata?.title).toBe('Dynamic Title');
217
- });
218
-
219
- it('should keep layout locals safe and page locals guarded on static pages', async () => {
220
- const renderer = new TestIntegrationRenderer({
221
- appConfig: AppConfig,
222
- assetProcessingService: AssetService,
223
- runtimeOrigin: 'http://localhost:3000',
224
- });
225
-
226
- const PageIdx = (() => 'Page Content') as EcoPageComponent<any>;
227
-
228
- renderer.PageModule = {
229
- default: PageIdx,
230
- };
231
- renderer.HtmlTemplate = (() => 'HTML Template') as EcoComponent<HtmlTemplateProps>;
232
-
233
- const result = await renderer.testPrepareRenderOptions({
234
- file: '/app/pages/static-page.ts',
235
- params: {},
236
- query: {},
237
- });
238
-
239
- expect(result.locals).toBeUndefined();
240
- expect(() => (result.pageLocals as Record<string, unknown>).session).toThrow();
241
- });
242
-
243
- it('should provide both locals and pageLocals on dynamic pages', async () => {
244
- const renderer = new TestIntegrationRenderer({
245
- appConfig: AppConfig,
246
- assetProcessingService: AssetService,
247
- runtimeOrigin: 'http://localhost:3000',
248
- });
249
-
250
- const PageIdx = (() => 'Page Content') as EcoPageComponent<any>;
251
- PageIdx.cache = 'dynamic';
252
-
253
- renderer.PageModule = {
254
- default: PageIdx,
255
- };
256
- renderer.HtmlTemplate = (() => 'HTML Template') as EcoComponent<HtmlTemplateProps>;
257
-
258
- const incomingLocals = { session: { userId: 'u-1' } } as Record<string, unknown>;
259
- const result = await renderer.testPrepareRenderOptions({
260
- file: '/app/pages/dynamic-page.ts',
261
- params: {},
262
- query: {},
263
- locals: incomingLocals,
264
- });
265
-
266
- expect(result.locals).toBe(incomingLocals);
267
- expect(result.pageLocals).toBe(incomingLocals);
268
- });
269
-
270
- it('should delegate boundary deferral decisions to the target integration plugin', () => {
271
- const reactPlugin = {
272
- name: 'react',
273
- shouldDeferComponentBoundary: vi.fn(() => true),
274
- initializeRenderer: vi.fn(),
275
- } as unknown as EcoPagesAppConfig['integrations'][number];
276
- const renderer = new TestIntegrationRenderer({
277
- appConfig: {
278
- ...AppConfig,
279
- integrations: [reactPlugin],
280
- } as EcoPagesAppConfig,
281
- assetProcessingService: AssetService,
282
- runtimeOrigin: 'http://localhost:3000',
283
- });
284
- const component = (() => '<div>Component</div>') as EcoComponent<Record<string, unknown>>;
285
-
286
- const result = renderer.testShouldDeferComponentBoundary({
287
- currentIntegration: 'ghtml',
288
- targetIntegration: 'react',
289
- component,
290
- });
291
-
292
- expect(result).toBe(true);
293
- expect(reactPlugin.shouldDeferComponentBoundary).toHaveBeenCalledWith({
294
- currentIntegration: 'ghtml',
295
- targetIntegration: 'react',
296
- component,
297
- });
298
- });
299
-
300
- it('should not defer boundaries when target integration matches current integration', () => {
301
- const reactPlugin = {
302
- name: 'react',
303
- shouldDeferComponentBoundary: vi.fn(() => true),
304
- initializeRenderer: vi.fn(),
305
- } as unknown as EcoPagesAppConfig['integrations'][number];
306
- const renderer = new TestIntegrationRenderer({
307
- appConfig: {
308
- ...AppConfig,
309
- integrations: [reactPlugin],
310
- } as EcoPagesAppConfig,
311
- assetProcessingService: AssetService,
312
- runtimeOrigin: 'http://localhost:3000',
313
- });
314
- const component = (() => '<div>Component</div>') as EcoComponent<Record<string, unknown>>;
315
-
316
- const result = renderer.testShouldDeferComponentBoundary({
317
- currentIntegration: 'react',
318
- targetIntegration: 'react',
319
- component,
320
- });
321
-
322
- expect(result).toBe(false);
323
- expect(reactPlugin.shouldDeferComponentBoundary).not.toHaveBeenCalled();
324
- });
325
-
326
- it('should prefer processed lazy script srcUrl for _resolvedLazyTriggers', async () => {
327
- let capturedDeps: unknown[] = [];
328
- const LazySrcUrl = '/assets/_hmr/components/lit-counter/lit-counter.script.js';
329
- const Service = {
330
- processDependencies: vi.fn(async (deps: unknown[]) => {
331
- capturedDeps = deps;
332
- const lazyFileDep = (
333
- deps as Array<{
334
- kind?: string;
335
- source?: string;
336
- filepath?: string;
337
- attributes?: Record<string, string>;
338
- }>
339
- ).find((dep) => dep.kind === 'script' && dep.source === 'file' && Boolean(dep.filepath));
340
-
341
- return [
342
- {
343
- kind: 'script',
344
- filepath: lazyFileDep?.filepath,
345
- attributes: lazyFileDep?.attributes,
346
- srcUrl: LazySrcUrl,
347
- },
348
- ] as ProcessedAsset[];
349
- }),
350
- } as unknown as AssetProcessingService;
351
-
352
- const renderer = new TestIntegrationRenderer({
353
- appConfig: AppConfig,
354
- assetProcessingService: Service,
355
- runtimeOrigin: 'http://localhost:3000',
356
- });
357
-
358
- const component = ((_) => '<lit-counter></lit-counter>') as EcoComponent<Record<string, unknown>>;
359
- component.config = {
360
- __eco: {
361
- id: 'lit-counter',
362
- integration: 'lit',
363
- file: '/app/components/lit-counter/lit-counter.kita.tsx',
364
- },
365
- dependencies: {
366
- scripts: [
367
- {
368
- src: './lit-counter.script.ts',
369
- lazy: { 'on:interaction': 'click,mouseenter,focusin' },
370
- },
371
- ],
372
- },
373
- };
374
-
375
- await renderer.testProcessComponentDependencies([component]);
376
-
377
- expect(component.config._resolvedLazyScripts).toBeUndefined();
378
- expect(component.config._resolvedLazyTriggers).toHaveLength(1);
379
- expect(component.config._resolvedLazyTriggers?.[0]?.rules).toEqual([
380
- {
381
- 'on:interaction': {
382
- value: 'click,mouseenter,focusin',
383
- scripts: [LazySrcUrl],
384
- },
385
- },
386
- ]);
387
- expect(
388
- capturedDeps.some((dep) => {
389
- if (!dep || typeof dep !== 'object') return false;
390
- const candidate = dep as { source?: string; importPath?: string };
391
- return candidate.source === 'node-module' && candidate.importPath === '@ecopages/scripts-injector';
392
- }),
393
- ).toBe(false);
394
- });
395
-
396
- it('should fallback to static lazy script URL when processed srcUrl is unavailable', async () => {
397
- const Service = {
398
- processDependencies: vi.fn(async () => {
399
- return [
400
- {
401
- kind: 'script',
402
- filepath: '/app/components/lit-counter/lit-counter.script.ts',
403
- },
404
- ] as ProcessedAsset[];
405
- }),
406
- } as unknown as AssetProcessingService;
407
-
408
- const renderer = new TestIntegrationRenderer({
409
- appConfig: AppConfig,
410
- assetProcessingService: Service,
411
- runtimeOrigin: 'http://localhost:3000',
412
- });
413
-
414
- const component = ((_) => '<lit-counter></lit-counter>') as EcoComponent<Record<string, unknown>>;
415
- component.config = {
416
- __eco: {
417
- id: 'lit-counter',
418
- integration: 'lit',
419
- file: '/app/components/lit-counter/lit-counter.kita.tsx',
420
- },
421
- dependencies: {
422
- scripts: [
423
- {
424
- src: './lit-counter.script.ts',
425
- lazy: { 'on:interaction': 'click,mouseenter,focusin' },
426
- },
427
- ],
428
- },
429
- };
430
-
431
- await renderer.testProcessComponentDependencies([component]);
432
-
433
- expect(component.config._resolvedLazyScripts).toBeUndefined();
434
- expect(component.config._resolvedLazyTriggers).toHaveLength(1);
435
- expect(component.config._resolvedLazyTriggers?.[0]?.rules).toEqual([
436
- {
437
- 'on:interaction': {
438
- value: 'click,mouseenter,focusin',
439
- scripts: ['/assets/components/lit-counter/lit-counter.script.js'],
440
- },
441
- },
442
- ]);
443
- });
444
-
445
- describe('renderToResponse', () => {
446
- it('should render a view with default status 200', async () => {
447
- const renderer = new TestIntegrationRenderer({
448
- appConfig: AppConfig,
449
- assetProcessingService: AssetService,
450
- runtimeOrigin: 'http://localhost:3000',
451
- });
452
-
453
- const View = ((props: { title: string }) => `<h1>${props.title}</h1>`) as EcoComponent<{
454
- title: string;
455
- }>;
456
-
457
- const response = await renderer.renderToResponse(View, { title: 'Hello' }, {});
458
-
459
- expect(response.status).toBe(200);
460
- expect(response.headers.get('Content-Type')).toBe('text/html; charset=utf-8');
461
- const body = await response.text();
462
- expect(body).toContain('<h1>Hello</h1>');
463
- });
464
-
465
- it('should render a partial view without layout', async () => {
466
- const renderer = new TestIntegrationRenderer({
467
- appConfig: AppConfig,
468
- assetProcessingService: AssetService,
469
- runtimeOrigin: 'http://localhost:3000',
470
- });
471
-
472
- const View = ((props: { content: string }) => `<div>${props.content}</div>`) as EcoComponent<{
473
- content: string;
474
- }>;
475
-
476
- const response = await renderer.renderToResponse(View, { content: 'Partial' }, { partial: true });
477
-
478
- const body = await response.text();
479
- expect(body).toBe('<div>Partial</div>');
480
- expect(body).not.toContain('<!DOCTYPE html>');
481
- });
482
-
483
- it('should apply custom status code', async () => {
484
- const renderer = new TestIntegrationRenderer({
485
- appConfig: AppConfig,
486
- assetProcessingService: AssetService,
487
- runtimeOrigin: 'http://localhost:3000',
488
- });
489
-
490
- const View = (() => '<p>Not Found</p>') as EcoComponent<object>;
491
-
492
- const response = await renderer.renderToResponse(View, {}, { status: 404 });
493
-
494
- expect(response.status).toBe(404);
495
- });
496
-
497
- it('should apply custom headers', async () => {
498
- const renderer = new TestIntegrationRenderer({
499
- appConfig: AppConfig,
500
- assetProcessingService: AssetService,
501
- runtimeOrigin: 'http://localhost:3000',
502
- });
503
-
504
- const View = (() => '<p>Cached</p>') as EcoComponent<object>;
505
-
506
- const response = await renderer.renderToResponse(
507
- View,
508
- {},
509
- {
510
- headers: {
511
- 'Cache-Control': 'max-age=3600',
512
- 'X-Custom-Header': 'test-value',
513
- },
514
- },
515
- );
516
-
517
- expect(response.headers.get('Cache-Control')).toBe('max-age=3600');
518
- expect(response.headers.get('X-Custom-Header')).toBe('test-value');
519
- });
520
-
521
- it('should render with layout when not partial', async () => {
522
- const renderer = new TestIntegrationRenderer({
523
- appConfig: AppConfig,
524
- assetProcessingService: AssetService,
525
- runtimeOrigin: 'http://localhost:3000',
526
- });
527
-
528
- const Layout = ((props: { children: string }) =>
529
- `<main class="layout">${props.children}</main>`) as EcoComponent<{ children: string }>;
530
-
531
- const View = ((props: { message: string }) => `<p>${props.message}</p>`) as EcoComponent<{
532
- message: string;
533
- }>;
534
- View.config = { layout: Layout };
535
-
536
- const response = await renderer.renderToResponse(View, { message: 'With Layout' }, {});
537
-
538
- const body = await response.text();
539
- expect(body).toContain('<main class="layout">');
540
- expect(body).toContain('<p>With Layout</p>');
541
- });
542
- });
543
-
544
- describe('renderComponent', () => {
545
- it('should render a component with structured output', async () => {
546
- const renderer = new TestIntegrationRenderer({
547
- appConfig: AppConfig,
548
- assetProcessingService: AssetService,
549
- runtimeOrigin: 'http://localhost:3000',
550
- });
551
-
552
- const View = ((props: { title: string }) => `<h1>${props.title}</h1>`) as EcoComponent<{ title: string }>;
553
-
554
- const result = await renderer.renderComponent({
555
- component: View,
556
- props: { title: 'Hello Component' },
557
- });
558
-
559
- expect(result.integrationName).toBe('test-renderer');
560
- expect(result.canAttachAttributes).toBe(true);
561
- expect(result.rootTag).toBe('h1');
562
- expect(result.html).toContain('<h1>Hello Component</h1>');
563
- });
564
- });
565
-
566
- describe('execute component-level artifacts', () => {
567
- it('should handle stream-like render bodies without re-consuming disturbed responses', async () => {
568
- const renderer = new TestIntegrationRenderer({
569
- appConfig: AppConfig,
570
- assetProcessingService: AssetService,
571
- runtimeOrigin: 'http://localhost:3000',
572
- });
573
-
574
- renderer.RenderedBody = new Response('<html><body><main>Stream Body</main></body></html>').body as BodyInit;
575
- renderer.PageModule = {
576
- default: (() => '<main>Stream Body</main>') as unknown as EcoPageComponent<any>,
577
- };
578
- renderer.HtmlTemplate = (() =>
579
- '<html><body><main>Stream Body</main></body></html>') as EcoComponent<HtmlTemplateProps>;
580
-
581
- const result = await renderer.execute({
582
- file: '/app/pages/index.ts',
583
- params: {},
584
- query: {},
585
- });
586
-
587
- const body = await new Response(result.body as BodyInit).text();
588
- expect(body).toContain('<main>Stream Body</main>');
589
- });
590
-
591
- it('should include renderComponent assets and apply root attributes', async () => {
592
- const appConfig = {
593
- ...AppConfig,
594
- } as EcoPagesAppConfig;
595
-
596
- const renderer = new TestIntegrationRenderer({
597
- appConfig,
598
- assetProcessingService: AssetService,
599
- runtimeOrigin: 'http://localhost:3000',
600
- });
601
-
602
- renderer.RenderedBody = '<html><body><main>Test Page</main></body></html>';
603
- renderer.MockComponentRenderResult = {
604
- html: '<main>Test Page</main>',
605
- canAttachAttributes: true,
606
- rootTag: 'main',
607
- integrationName: 'test-renderer',
608
- rootAttributes: { 'data-eco-component-id': 'eco-page-root' },
609
- assets: [
610
- {
611
- kind: 'script',
612
- srcUrl: '/assets/island.js',
613
- position: 'head',
614
- } as ProcessedAsset,
615
- ],
616
- };
617
-
618
- renderer.PageModule = {
619
- default: (() => '<main>Test Page</main>') as unknown as EcoPageComponent<any>,
620
- };
621
- renderer.HtmlTemplate = (() =>
622
- '<html><body><main>Test Page</main></body></html>') as EcoComponent<HtmlTemplateProps>;
623
-
624
- const result = await renderer.execute({
625
- file: '/app/pages/index.ts',
626
- params: {},
627
- query: {},
628
- });
629
-
630
- const body = await new Response(result.body as BodyInit).text();
631
- expect(body).toContain('<main data-eco-component-id="eco-page-root">Test Page</main>');
632
-
633
- const processedDeps = (renderer as any).htmlTransformer.getProcessedDependencies();
634
- expect(processedDeps.some((dep: ProcessedAsset) => dep.srcUrl === '/assets/island.js')).toBe(true);
635
- });
636
-
637
- it('should not force render nested dependency components without resolved props context', async () => {
638
- const explicitRenderer = {
639
- renderComponent: vi.fn(async () => ({
640
- html: '<aside>Nested</aside>',
641
- canAttachAttributes: true,
642
- rootTag: 'aside',
643
- integrationName: 'explicit-renderer',
644
- })),
645
- } as unknown as IntegrationRenderer;
646
-
647
- const appConfig = {
648
- ...AppConfig,
649
- integrations: [
650
- {
651
- name: 'explicit-renderer',
652
- initializeRenderer: () => explicitRenderer,
653
- },
654
- ],
655
- } as unknown as EcoPagesAppConfig;
656
-
657
- const renderer = new TestIntegrationRenderer({
658
- appConfig,
659
- assetProcessingService: AssetService,
660
- runtimeOrigin: 'http://localhost:3000',
661
- });
662
-
663
- renderer.RenderedBody = '<html><body><main>Test Page</main></body></html>';
664
- renderer.MockComponentRenderResult = {
665
- html: '<main>Test Page</main>',
666
- canAttachAttributes: true,
667
- rootTag: 'main',
668
- integrationName: 'test-renderer',
669
- rootAttributes: { 'data-eco-component-id': 'eco-page-root' },
670
- };
671
-
672
- const NestedComponent = (() => '<aside>Nested</aside>') as EcoComponent<Record<string, unknown>>;
673
- NestedComponent.config = {
674
- integration: 'explicit-renderer',
675
- __eco: {
676
- id: 'nested-component',
677
- file: '/app/components/nested-component.ts',
678
- integration: 'test-renderer',
679
- },
680
- };
681
-
682
- const Page = (() => '<main>Test Page</main>') as unknown as EcoPageComponent<any>;
683
- Page.config = {
684
- dependencies: {
685
- components: [NestedComponent],
686
- },
687
- };
688
-
689
- renderer.PageModule = {
690
- default: Page,
691
- };
692
- renderer.HtmlTemplate = (() =>
693
- '<html><body><main>Test Page</main></body></html>') as EcoComponent<HtmlTemplateProps>;
694
-
695
- const result = await renderer.execute({
696
- file: '/app/pages/index.ts',
697
- params: {},
698
- query: {},
699
- });
700
-
701
- expect((explicitRenderer.renderComponent as any).mock.calls).toHaveLength(0);
702
-
703
- const body = await new Response(result.body as BodyInit).text();
704
- expect(body).toContain('<main data-eco-component-id="eco-page-root">Test Page</main>');
705
-
706
- const processedDeps = (renderer as any).htmlTransformer.getProcessedDependencies();
707
- expect(processedDeps.some((dep: ProcessedAsset) => dep.srcUrl === '/assets/nested-explicit.js')).toBe(
708
- false,
709
- );
710
- });
711
-
712
- it('should include global integration dependencies for referenced component integrations once', async () => {
713
- const explicitIntegrationDependency = {
714
- kind: 'script',
715
- srcUrl: '/assets/react-runtime.js',
716
- position: 'head',
717
- } as ProcessedAsset;
718
-
719
- const appConfig = {
720
- ...AppConfig,
721
- integrations: [
722
- {
723
- name: 'react',
724
- initializeRenderer: () => renderer as unknown as IntegrationRenderer,
725
- getResolvedIntegrationDependencies: () => [explicitIntegrationDependency],
726
- },
727
- ],
728
- } as unknown as EcoPagesAppConfig;
729
-
730
- const renderer = new TestIntegrationRenderer({
731
- appConfig,
732
- assetProcessingService: AssetService,
733
- runtimeOrigin: 'http://localhost:3000',
734
- });
735
-
736
- renderer.RenderedBody = '<html><body><main>Test Page</main></body></html>';
737
- renderer.MockComponentRenderResult = {
738
- html: '<main>Test Page</main>',
739
- canAttachAttributes: true,
740
- rootTag: 'main',
741
- integrationName: 'test-renderer',
742
- };
743
-
744
- const ReactNested = (() => '<div>React Nested</div>') as EcoComponent<Record<string, unknown>>;
745
- ReactNested.config = {
746
- integration: 'react',
747
- __eco: {
748
- id: 'react-nested',
749
- file: '/app/components/react-nested.react.tsx',
750
- integration: 'react',
751
- },
752
- };
753
-
754
- const Page = (() => '<main>Test Page</main>') as unknown as EcoPageComponent<any>;
755
- Page.config = {
756
- dependencies: {
757
- components: [ReactNested],
758
- },
759
- };
760
-
761
- renderer.PageModule = {
762
- default: Page,
763
- };
764
- renderer.HtmlTemplate = (() =>
765
- '<html><body><main>Test Page</main></body></html>') as EcoComponent<HtmlTemplateProps>;
766
-
767
- await renderer.execute({
768
- file: '/app/pages/index.ts',
769
- params: {},
770
- query: {},
771
- });
772
-
773
- const processedDeps = (renderer as any).htmlTransformer.getProcessedDependencies();
774
- expect(
775
- processedDeps.filter((dep: ProcessedAsset) => dep.srcUrl === '/assets/react-runtime.js'),
776
- ).toHaveLength(1);
777
- });
778
-
779
- it('should resolve eco-marker nodes via integration renderComponent with referenced props', async () => {
780
- const explicitRenderer = {
781
- renderComponent: vi.fn(async () => ({
782
- html: '<aside>Nested Render</aside>',
783
- canAttachAttributes: true,
784
- rootTag: 'aside',
785
- integrationName: 'explicit-renderer',
786
- rootAttributes: { 'data-eco-component-id': 'nested-1' },
787
- assets: [
788
- {
789
- kind: 'script',
790
- srcUrl: '/assets/nested-render.js',
791
- position: 'head',
792
- } as ProcessedAsset,
793
- ],
794
- })),
795
- } as unknown as IntegrationRenderer;
796
-
797
- const appConfig = {
798
- ...AppConfig,
799
- integrations: [
800
- {
801
- name: 'explicit-renderer',
802
- initializeRenderer: () => explicitRenderer,
803
- },
804
- ],
805
- } as unknown as EcoPagesAppConfig;
806
-
807
- const renderer = new TestIntegrationRenderer({
808
- appConfig,
809
- assetProcessingService: AssetService,
810
- runtimeOrigin: 'http://localhost:3000',
811
- });
812
-
813
- renderer.RenderedBody =
814
- '<html><body><main>Before<eco-marker data-eco-node-id="n_1" data-eco-integration="explicit-renderer" data-eco-component-ref="nested-component" data-eco-props-ref="props-1"></eco-marker>After</main></body></html>';
815
- renderer.MockComponentRenderResult = {
816
- html: '<main>Test Page</main>',
817
- canAttachAttributes: true,
818
- rootTag: 'main',
819
- integrationName: 'test-renderer',
820
- };
821
-
822
- const NestedComponent = (() => '<aside>Nested</aside>') as EcoComponent<Record<string, unknown>>;
823
- NestedComponent.config = {
824
- integration: 'explicit-renderer',
825
- __eco: {
826
- id: 'nested-component',
827
- file: '/app/components/nested-component.ts',
828
- integration: 'explicit-renderer',
829
- },
830
- };
831
-
832
- const Page = (() => '<main>Test Page</main>') as unknown as EcoPageComponent<any>;
833
- Page.config = {
834
- dependencies: {
835
- components: [NestedComponent],
836
- },
837
- };
838
-
839
- renderer.PageModule = {
840
- default: Page,
841
- componentGraphContext: {
842
- propsByRef: {
843
- 'props-1': { count: 3 },
844
- },
845
- },
846
- } as unknown as EcoPageFile;
847
- renderer.HtmlTemplate = (() =>
848
- '<html><body><main>Test Page</main></body></html>') as EcoComponent<HtmlTemplateProps>;
849
-
850
- const result = await renderer.execute({
851
- file: '/app/pages/index.ts',
852
- params: {},
853
- query: {},
854
- });
855
-
856
- const body = await new Response(result.body as BodyInit).text();
857
- expect(body).toContain('<aside data-eco-component-id="nested-1">Nested Render</aside>');
858
- expect(body).not.toContain('<eco-marker');
859
- expect((explicitRenderer.renderComponent as any).mock.calls).toHaveLength(1);
860
- expect((explicitRenderer.renderComponent as any).mock.calls[0][0].props).toEqual({ count: 3 });
861
-
862
- const processedDeps = (renderer as any).htmlTransformer.getProcessedDependencies();
863
- expect(processedDeps.some((dep: ProcessedAsset) => dep.srcUrl === '/assets/nested-render.js')).toBe(true);
864
- });
865
-
866
- it('should fail marker resolution when props reference is missing', async () => {
867
- const explicitRenderer = {
868
- renderComponent: vi.fn(async () => ({
869
- html: '<aside>Nested Render</aside>',
870
- canAttachAttributes: true,
871
- rootTag: 'aside',
872
- integrationName: 'explicit-renderer',
873
- })),
874
- } as unknown as IntegrationRenderer;
875
-
876
- const appConfig = {
877
- ...AppConfig,
878
- integrations: [
879
- {
880
- name: 'explicit-renderer',
881
- initializeRenderer: () => explicitRenderer,
882
- },
883
- ],
884
- } as unknown as EcoPagesAppConfig;
885
-
886
- const renderer = new TestIntegrationRenderer({
887
- appConfig,
888
- assetProcessingService: AssetService,
889
- runtimeOrigin: 'http://localhost:3000',
890
- });
891
-
892
- renderer.RenderedBody =
893
- '<html><body><main><eco-marker data-eco-node-id="n_1" data-eco-integration="explicit-renderer" data-eco-component-ref="nested-component" data-eco-props-ref="props-missing"></eco-marker></main></body></html>';
894
- renderer.MockComponentRenderResult = {
895
- html: '<main>Test Page</main>',
896
- canAttachAttributes: true,
897
- rootTag: 'main',
898
- integrationName: 'test-renderer',
899
- };
900
-
901
- const NestedComponent = (() => '<aside>Nested</aside>') as EcoComponent<Record<string, unknown>>;
902
- NestedComponent.config = {
903
- integration: 'explicit-renderer',
904
- __eco: {
905
- id: 'nested-component',
906
- file: '/app/components/nested-component.ts',
907
- integration: 'explicit-renderer',
908
- },
909
- };
910
-
911
- const Page = (() => '<main>Test Page</main>') as unknown as EcoPageComponent<any>;
912
- Page.config = {
913
- dependencies: {
914
- components: [NestedComponent],
915
- },
916
- };
917
-
918
- renderer.PageModule = {
919
- default: Page,
920
- componentGraphContext: {
921
- propsByRef: {},
922
- },
923
- } as unknown as EcoPageFile;
924
- renderer.HtmlTemplate = (() =>
925
- '<html><body><main>Test Page</main></body></html>') as EcoComponent<HtmlTemplateProps>;
926
-
927
- await expect(
928
- renderer.execute({
929
- file: '/app/pages/index.ts',
930
- params: {},
931
- query: {},
932
- }),
933
- ).rejects.toThrow('Missing props reference for marker: props-missing');
934
- });
935
- });
936
- });