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

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 (418) hide show
  1. package/README.md +213 -12
  2. package/package.json +100 -188
  3. package/src/adapters/README.md +39 -0
  4. package/src/adapters/bun/hmr-manager.test.ts +267 -0
  5. package/src/adapters/bun/hmr-manager.ts +180 -47
  6. package/src/adapters/bun/index.ts +1 -2
  7. package/src/adapters/bun/server-adapter.ts +41 -34
  8. package/src/adapters/bun/server-lifecycle.ts +40 -70
  9. package/src/adapters/index.ts +1 -1
  10. package/src/adapters/node/bootstrap-dependency-resolver.test.ts +282 -0
  11. package/src/adapters/node/bootstrap-dependency-resolver.ts +301 -0
  12. package/src/adapters/node/index.ts +7 -0
  13. package/src/adapters/node/node-client-bridge.test.ts +198 -0
  14. package/src/adapters/node/node-hmr-manager.test.ts +322 -0
  15. package/src/adapters/node/node-hmr-manager.ts +207 -97
  16. package/src/adapters/node/runtime-adapter.test.ts +868 -0
  17. package/src/adapters/node/runtime-adapter.ts +439 -0
  18. package/src/adapters/node/server-adapter.ts +31 -104
  19. package/src/adapters/node/static-content-server.test.ts +60 -0
  20. package/src/adapters/node/static-content-server.ts +36 -0
  21. package/src/adapters/node/write-runtime-manifest.ts +38 -0
  22. package/src/adapters/shared/api-response.test.ts +97 -0
  23. package/src/{define-api-handler.ts → adapters/shared/define-api-handler.ts} +1 -1
  24. package/src/adapters/shared/explicit-static-route-matcher.test.ts +381 -0
  25. package/src/adapters/shared/explicit-static-route-matcher.ts +7 -1
  26. package/src/adapters/shared/file-route-middleware-pipeline.test.ts +90 -0
  27. package/src/adapters/shared/file-route-middleware-pipeline.ts +6 -2
  28. package/src/adapters/shared/fs-server-response-factory.test.ts +187 -0
  29. package/src/adapters/shared/fs-server-response-matcher.test.ts +286 -0
  30. package/src/adapters/shared/fs-server-response-matcher.ts +17 -10
  31. package/src/adapters/shared/hmr-entrypoint-registrar.ts +149 -0
  32. package/src/adapters/shared/hmr-html-response.ts +52 -0
  33. package/src/adapters/shared/hmr-manager.contract.test.ts +196 -0
  34. package/src/adapters/shared/hmr-manager.dispatch.test.ts +220 -0
  35. package/src/adapters/shared/render-context.test.ts +146 -0
  36. package/src/adapters/shared/render-context.ts +21 -6
  37. package/src/adapters/shared/runtime-bootstrap.ts +79 -0
  38. package/src/adapters/shared/server-adapter.test.ts +77 -0
  39. package/src/adapters/shared/server-adapter.ts +51 -4
  40. package/src/adapters/shared/server-route-handler.test.ts +110 -0
  41. package/src/adapters/shared/server-route-handler.ts +5 -18
  42. package/src/adapters/shared/server-static-builder.test.ts +316 -0
  43. package/src/adapters/shared/server-static-builder.ts +92 -8
  44. package/src/build/README.md +101 -0
  45. package/src/build/build-adapter-serialization.test.ts +268 -0
  46. package/src/build/build-adapter.test.ts +815 -0
  47. package/src/build/build-adapter.ts +234 -6
  48. package/src/build/build-manifest.ts +54 -0
  49. package/src/build/dev-build-coordinator.ts +221 -0
  50. package/src/build/esbuild-build-adapter.ts +132 -84
  51. package/src/build/runtime-build-executor.ts +34 -0
  52. package/src/build/runtime-specifier-alias-plugin.test.ts +43 -0
  53. package/src/build/runtime-specifier-alias-plugin.ts +58 -0
  54. package/src/config/README.md +33 -0
  55. package/src/config/config-builder.test.ts +410 -0
  56. package/src/config/config-builder.ts +281 -49
  57. package/src/constants.ts +15 -0
  58. package/src/declarations.d.ts +18 -13
  59. package/src/eco/README.md +70 -16
  60. package/src/eco/component-render-context.ts +39 -17
  61. package/src/eco/eco.test.ts +678 -0
  62. package/src/eco/eco.ts +29 -8
  63. package/src/eco/eco.types.ts +20 -1
  64. package/src/eco/eco.utils.test.ts +124 -0
  65. package/src/eco/global-injector-map.test.ts +42 -0
  66. package/src/eco/lazy-injector-map.test.ts +66 -0
  67. package/src/eco/module-dependencies.test.ts +30 -0
  68. package/src/errors/http-error.test.ts +134 -0
  69. package/src/global/utils.test.ts +12 -0
  70. package/src/hmr/README.md +26 -0
  71. 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
  72. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  73. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  74. package/src/hmr/client/hmr-runtime.ts +38 -7
  75. package/src/hmr/hmr-strategy.test.ts +124 -0
  76. package/src/hmr/hmr.postcss.test.e2e.ts +41 -0
  77. package/src/hmr/hmr.test.e2e.ts +29 -38
  78. package/src/hmr/strategies/js-hmr-strategy.test.ts +335 -0
  79. package/src/hmr/strategies/js-hmr-strategy.ts +71 -78
  80. package/src/index.ts +1 -1
  81. package/src/integrations/ghtml/ghtml-renderer.test.ts +63 -0
  82. package/src/integrations/ghtml/ghtml-renderer.ts +4 -1
  83. package/src/internal-types.ts +39 -19
  84. package/src/plugins/README.md +34 -0
  85. package/src/plugins/alias-resolver-plugin.test.ts +41 -0
  86. package/src/plugins/alias-resolver-plugin.ts +21 -3
  87. package/src/plugins/eco-component-meta-plugin.test.ts +380 -0
  88. package/src/plugins/eco-component-meta-plugin.ts +10 -3
  89. package/src/plugins/integration-plugin.test.ts +111 -0
  90. package/src/plugins/integration-plugin.ts +45 -3
  91. package/src/plugins/processor.test.ts +148 -0
  92. package/src/plugins/processor.ts +22 -2
  93. package/src/plugins/runtime-capability.ts +14 -0
  94. package/src/public-types.ts +73 -11
  95. package/src/route-renderer/GRAPH.md +16 -20
  96. package/src/route-renderer/README.md +8 -21
  97. package/src/route-renderer/component-graph/component-graph-executor.test.ts +41 -0
  98. package/src/route-renderer/component-graph/component-graph.test.ts +63 -0
  99. package/src/route-renderer/component-graph/component-marker.test.ts +73 -0
  100. package/src/route-renderer/component-graph/component-reference.ts +29 -0
  101. package/src/route-renderer/component-graph/marker-graph-resolver.test.ts +135 -0
  102. package/src/route-renderer/{marker-graph-resolver.ts → component-graph/marker-graph-resolver.ts} +11 -9
  103. package/src/route-renderer/orchestration/integration-renderer.test.ts +936 -0
  104. package/src/route-renderer/{integration-renderer.ts → orchestration/integration-renderer.ts} +113 -19
  105. package/src/route-renderer/orchestration/render-execution.service.test.ts +97 -0
  106. package/src/route-renderer/{render-execution.service.ts → orchestration/render-execution.service.ts} +109 -37
  107. package/src/route-renderer/orchestration/render-preparation.service.test.ts +235 -0
  108. package/src/route-renderer/{render-preparation.service.ts → orchestration/render-preparation.service.ts} +127 -9
  109. package/src/route-renderer/page-loading/dependency-resolver.test.ts +345 -0
  110. package/src/route-renderer/{dependency-resolver.ts → page-loading/dependency-resolver.ts} +28 -12
  111. package/src/route-renderer/page-loading/page-module-loader.test.ts +96 -0
  112. package/src/route-renderer/{page-module-loader.ts → page-loading/page-module-loader.ts} +49 -21
  113. package/src/route-renderer/route-renderer.ts +36 -1
  114. package/src/router/README.md +26 -0
  115. package/src/router/client/link-intent.d.ts +53 -0
  116. package/src/router/client/link-intent.test.browser.ts +51 -0
  117. package/src/router/client/link-intent.ts +92 -0
  118. package/src/router/client/navigation-coordinator.test.ts +237 -0
  119. package/src/router/client/navigation-coordinator.ts +433 -0
  120. package/src/router/server/fs-router-scanner.test.ts +83 -0
  121. package/src/router/{fs-router-scanner.ts → server/fs-router-scanner.ts} +12 -10
  122. package/src/router/server/fs-router.test.ts +214 -0
  123. package/src/router/{fs-router.ts → server/fs-router.ts} +2 -2
  124. package/src/services/README.md +29 -0
  125. package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +385 -0
  126. package/src/services/{asset-processing-service → assets/asset-processing-service}/asset-processing.service.ts +101 -6
  127. package/src/services/assets/asset-processing-service/asset.factory.test.ts +63 -0
  128. package/src/services/{asset-processing-service → assets/asset-processing-service}/asset.factory.ts +2 -2
  129. package/src/services/{asset-processing-service → assets/asset-processing-service}/assets.types.ts +2 -1
  130. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +72 -0
  131. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.ts +95 -0
  132. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +67 -0
  133. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.ts +78 -0
  134. package/src/services/{asset-processing-service → assets/asset-processing-service}/index.ts +2 -0
  135. package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.interface.ts +1 -1
  136. package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +59 -0
  137. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-processor.ts +11 -5
  138. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-script-processor.ts +17 -27
  139. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +286 -0
  140. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/file-script.processor.ts +3 -3
  141. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +227 -0
  142. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/node-module-script.processor.ts +5 -4
  143. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +199 -0
  144. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/file-stylesheet.processor.ts +4 -1
  145. package/src/services/assets/browser-bundle.service.test.ts +36 -0
  146. package/src/services/assets/browser-bundle.service.ts +53 -0
  147. package/src/services/cache/index.ts +3 -3
  148. package/src/services/cache/memory-cache-store.test.ts +225 -0
  149. package/src/services/cache/memory-cache-store.ts +1 -1
  150. package/src/services/cache/page-cache-service.test.ts +175 -0
  151. package/src/services/cache/page-cache-service.ts +3 -3
  152. package/src/services/cache/page-request-cache-coordinator.service.test.ts +79 -0
  153. package/src/services/{page-request-cache-coordinator.service.ts → cache/page-request-cache-coordinator.service.ts} +9 -6
  154. package/src/services/html/html-rewriter-provider.service.test.ts +183 -0
  155. package/src/services/html/html-rewriter-provider.service.ts +103 -0
  156. package/src/services/html/html-transformer.service.test.ts +378 -0
  157. package/src/services/html/html-transformer.service.ts +279 -0
  158. package/src/services/invalidation/development-invalidation.service.test.ts +77 -0
  159. package/src/services/invalidation/development-invalidation.service.ts +261 -0
  160. package/src/services/module-loading/app-server-module-transpiler.service.ts +52 -0
  161. package/src/services/module-loading/page-module-import.service.test.ts +253 -0
  162. package/src/services/module-loading/page-module-import.service.ts +200 -0
  163. package/src/services/module-loading/server-loader.service.test.ts +161 -0
  164. package/src/services/module-loading/server-loader.service.ts +130 -0
  165. package/src/services/module-loading/server-module-transpiler.service.test.ts +115 -0
  166. package/src/services/module-loading/server-module-transpiler.service.ts +105 -0
  167. package/src/services/runtime-manifest/node-runtime-manifest.service.test.ts +95 -0
  168. package/src/services/runtime-manifest/node-runtime-manifest.service.ts +101 -0
  169. package/src/services/runtime-state/dev-graph.service.ts +217 -0
  170. package/src/services/runtime-state/entrypoint-dependency-graph.service.ts +136 -0
  171. package/src/services/runtime-state/runtime-specifier-registry.service.ts +96 -0
  172. package/src/services/runtime-state/server-invalidation-state.service.ts +68 -0
  173. package/src/services/validation/schema-validation-service.test.ts +223 -0
  174. package/src/services/{schema-validation-service.ts → validation/schema-validation-service.ts} +1 -1
  175. package/src/static-site-generator/README.md +26 -0
  176. package/src/static-site-generator/static-site-generator.test.ts +307 -0
  177. package/src/static-site-generator/static-site-generator.ts +109 -6
  178. package/src/utils/deep-merge.test.ts +114 -0
  179. package/src/utils/invariant.test.ts +22 -0
  180. package/src/utils/path-utils.test.ts +15 -0
  181. package/src/utils/resolve-work-dir.ts +45 -0
  182. package/src/utils/server-utils.test.ts +38 -0
  183. package/src/watchers/project-watcher.integration.test.ts +337 -0
  184. package/src/watchers/project-watcher.test-helpers.ts +1 -0
  185. package/src/watchers/project-watcher.test.ts +678 -0
  186. package/src/watchers/project-watcher.ts +49 -50
  187. package/CHANGELOG.md +0 -94
  188. package/src/adapters/abstract/application-adapter.d.ts +0 -168
  189. package/src/adapters/abstract/application-adapter.js +0 -109
  190. package/src/adapters/abstract/router-adapter.d.ts +0 -26
  191. package/src/adapters/abstract/router-adapter.js +0 -5
  192. package/src/adapters/abstract/server-adapter.d.ts +0 -69
  193. package/src/adapters/abstract/server-adapter.js +0 -15
  194. package/src/adapters/bun/client-bridge.d.ts +0 -34
  195. package/src/adapters/bun/client-bridge.js +0 -48
  196. package/src/adapters/bun/create-app.d.ts +0 -60
  197. package/src/adapters/bun/create-app.js +0 -117
  198. package/src/adapters/bun/define-api-handler.d.ts +0 -61
  199. package/src/adapters/bun/define-api-handler.js +0 -15
  200. package/src/adapters/bun/define-api-handler.ts +0 -114
  201. package/src/adapters/bun/hmr-manager.d.ts +0 -79
  202. package/src/adapters/bun/hmr-manager.js +0 -222
  203. package/src/adapters/bun/index.d.ts +0 -3
  204. package/src/adapters/bun/index.js +0 -8
  205. package/src/adapters/bun/server-adapter.d.ts +0 -155
  206. package/src/adapters/bun/server-adapter.js +0 -368
  207. package/src/adapters/bun/server-lifecycle.d.ts +0 -52
  208. package/src/adapters/bun/server-lifecycle.js +0 -120
  209. package/src/adapters/index.d.ts +0 -6
  210. package/src/adapters/index.js +0 -14
  211. package/src/adapters/node/create-app.d.ts +0 -21
  212. package/src/adapters/node/create-app.js +0 -143
  213. package/src/adapters/node/index.d.ts +0 -4
  214. package/src/adapters/node/index.js +0 -8
  215. package/src/adapters/node/node-client-bridge.d.ts +0 -26
  216. package/src/adapters/node/node-client-bridge.js +0 -66
  217. package/src/adapters/node/node-hmr-manager.d.ts +0 -62
  218. package/src/adapters/node/node-hmr-manager.js +0 -221
  219. package/src/adapters/node/server-adapter.d.ts +0 -190
  220. package/src/adapters/node/server-adapter.js +0 -420
  221. package/src/adapters/node/static-content-server.d.ts +0 -24
  222. package/src/adapters/node/static-content-server.js +0 -166
  223. package/src/adapters/shared/api-response.d.ts +0 -52
  224. package/src/adapters/shared/api-response.js +0 -96
  225. package/src/adapters/shared/application-adapter.d.ts +0 -18
  226. package/src/adapters/shared/application-adapter.js +0 -90
  227. package/src/adapters/shared/explicit-static-route-matcher.d.ts +0 -38
  228. package/src/adapters/shared/explicit-static-route-matcher.js +0 -100
  229. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +0 -65
  230. package/src/adapters/shared/file-route-middleware-pipeline.js +0 -98
  231. package/src/adapters/shared/fs-server-response-factory.d.ts +0 -19
  232. package/src/adapters/shared/fs-server-response-factory.js +0 -97
  233. package/src/adapters/shared/fs-server-response-matcher.d.ts +0 -71
  234. package/src/adapters/shared/fs-server-response-matcher.js +0 -155
  235. package/src/adapters/shared/render-context.d.ts +0 -14
  236. package/src/adapters/shared/render-context.js +0 -69
  237. package/src/adapters/shared/server-adapter.d.ts +0 -87
  238. package/src/adapters/shared/server-adapter.js +0 -353
  239. package/src/adapters/shared/server-route-handler.d.ts +0 -89
  240. package/src/adapters/shared/server-route-handler.js +0 -120
  241. package/src/adapters/shared/server-static-builder.d.ts +0 -38
  242. package/src/adapters/shared/server-static-builder.js +0 -46
  243. package/src/build/build-adapter.d.ts +0 -75
  244. package/src/build/build-adapter.js +0 -54
  245. package/src/build/build-types.d.ts +0 -57
  246. package/src/build/build-types.js +0 -0
  247. package/src/build/esbuild-build-adapter.d.ts +0 -69
  248. package/src/build/esbuild-build-adapter.js +0 -391
  249. package/src/config/config-builder.d.ts +0 -227
  250. package/src/config/config-builder.js +0 -392
  251. package/src/constants.d.ts +0 -32
  252. package/src/constants.js +0 -21
  253. package/src/create-app.d.ts +0 -17
  254. package/src/create-app.js +0 -66
  255. package/src/define-api-handler.d.ts +0 -25
  256. package/src/define-api-handler.js +0 -15
  257. package/src/dev/sc-server.d.ts +0 -30
  258. package/src/dev/sc-server.js +0 -111
  259. package/src/eco/component-render-context.d.ts +0 -105
  260. package/src/eco/component-render-context.js +0 -77
  261. package/src/eco/eco.d.ts +0 -9
  262. package/src/eco/eco.js +0 -110
  263. package/src/eco/eco.types.d.ts +0 -170
  264. package/src/eco/eco.types.js +0 -0
  265. package/src/eco/eco.utils.d.ts +0 -40
  266. package/src/eco/eco.utils.js +0 -40
  267. package/src/eco/global-injector-map.d.ts +0 -16
  268. package/src/eco/global-injector-map.js +0 -80
  269. package/src/eco/lazy-injector-map.d.ts +0 -8
  270. package/src/eco/lazy-injector-map.js +0 -70
  271. package/src/eco/module-dependencies.d.ts +0 -18
  272. package/src/eco/module-dependencies.js +0 -49
  273. package/src/errors/http-error.d.ts +0 -31
  274. package/src/errors/http-error.js +0 -50
  275. package/src/errors/index.d.ts +0 -2
  276. package/src/errors/index.js +0 -4
  277. package/src/errors/locals-access-error.d.ts +0 -4
  278. package/src/errors/locals-access-error.js +0 -9
  279. package/src/global/app-logger.d.ts +0 -2
  280. package/src/global/app-logger.js +0 -6
  281. package/src/hmr/client/hmr-runtime.d.ts +0 -10
  282. package/src/hmr/client/hmr-runtime.js +0 -86
  283. package/src/hmr/hmr-strategy.d.ts +0 -159
  284. package/src/hmr/hmr-strategy.js +0 -29
  285. package/src/hmr/hmr.test.e2e.d.ts +0 -1
  286. package/src/hmr/hmr.test.e2e.js +0 -50
  287. package/src/hmr/strategies/default-hmr-strategy.d.ts +0 -43
  288. package/src/hmr/strategies/default-hmr-strategy.js +0 -34
  289. package/src/hmr/strategies/js-hmr-strategy.d.ts +0 -136
  290. package/src/hmr/strategies/js-hmr-strategy.js +0 -192
  291. package/src/index.browser.d.ts +0 -3
  292. package/src/index.browser.js +0 -4
  293. package/src/index.d.ts +0 -5
  294. package/src/index.js +0 -10
  295. package/src/integrations/ghtml/ghtml-renderer.d.ts +0 -15
  296. package/src/integrations/ghtml/ghtml-renderer.js +0 -60
  297. package/src/integrations/ghtml/ghtml.plugin.d.ts +0 -20
  298. package/src/integrations/ghtml/ghtml.plugin.js +0 -21
  299. package/src/internal-types.d.ts +0 -200
  300. package/src/internal-types.js +0 -0
  301. package/src/plugins/alias-resolver-plugin.d.ts +0 -2
  302. package/src/plugins/alias-resolver-plugin.js +0 -39
  303. package/src/plugins/eco-component-meta-plugin.d.ts +0 -95
  304. package/src/plugins/eco-component-meta-plugin.js +0 -157
  305. package/src/plugins/integration-plugin.d.ts +0 -102
  306. package/src/plugins/integration-plugin.js +0 -100
  307. package/src/plugins/processor.d.ts +0 -82
  308. package/src/plugins/processor.js +0 -122
  309. package/src/public-types.d.ts +0 -1094
  310. package/src/public-types.js +0 -0
  311. package/src/route-renderer/component-graph-executor.d.ts +0 -32
  312. package/src/route-renderer/component-graph-executor.js +0 -31
  313. package/src/route-renderer/component-graph.d.ts +0 -42
  314. package/src/route-renderer/component-graph.js +0 -72
  315. package/src/route-renderer/component-marker.d.ts +0 -52
  316. package/src/route-renderer/component-marker.js +0 -46
  317. package/src/route-renderer/dependency-resolver.d.ts +0 -24
  318. package/src/route-renderer/dependency-resolver.js +0 -428
  319. package/src/route-renderer/html-post-processing.service.d.ts +0 -40
  320. package/src/route-renderer/html-post-processing.service.js +0 -86
  321. package/src/route-renderer/html-post-processing.service.ts +0 -103
  322. package/src/route-renderer/integration-renderer.d.ts +0 -339
  323. package/src/route-renderer/integration-renderer.js +0 -526
  324. package/src/route-renderer/marker-graph-resolver.d.ts +0 -76
  325. package/src/route-renderer/marker-graph-resolver.js +0 -93
  326. package/src/route-renderer/page-module-loader.d.ts +0 -61
  327. package/src/route-renderer/page-module-loader.js +0 -102
  328. package/src/route-renderer/render-execution.service.d.ts +0 -69
  329. package/src/route-renderer/render-execution.service.js +0 -91
  330. package/src/route-renderer/render-preparation.service.d.ts +0 -112
  331. package/src/route-renderer/render-preparation.service.js +0 -243
  332. package/src/route-renderer/route-renderer.d.ts +0 -26
  333. package/src/route-renderer/route-renderer.js +0 -68
  334. package/src/router/fs-router-scanner.d.ts +0 -41
  335. package/src/router/fs-router-scanner.js +0 -155
  336. package/src/router/fs-router.d.ts +0 -26
  337. package/src/router/fs-router.js +0 -100
  338. package/src/services/asset-processing-service/asset-processing.service.d.ts +0 -41
  339. package/src/services/asset-processing-service/asset-processing.service.js +0 -250
  340. package/src/services/asset-processing-service/asset.factory.d.ts +0 -17
  341. package/src/services/asset-processing-service/asset.factory.js +0 -82
  342. package/src/services/asset-processing-service/assets.types.d.ts +0 -88
  343. package/src/services/asset-processing-service/assets.types.js +0 -0
  344. package/src/services/asset-processing-service/index.d.ts +0 -3
  345. package/src/services/asset-processing-service/index.js +0 -3
  346. package/src/services/asset-processing-service/processor.interface.d.ts +0 -22
  347. package/src/services/asset-processing-service/processor.interface.js +0 -6
  348. package/src/services/asset-processing-service/processor.registry.d.ts +0 -8
  349. package/src/services/asset-processing-service/processor.registry.js +0 -15
  350. package/src/services/asset-processing-service/processors/base/base-processor.d.ts +0 -24
  351. package/src/services/asset-processing-service/processors/base/base-processor.js +0 -59
  352. package/src/services/asset-processing-service/processors/base/base-script-processor.d.ts +0 -16
  353. package/src/services/asset-processing-service/processors/base/base-script-processor.js +0 -80
  354. package/src/services/asset-processing-service/processors/index.d.ts +0 -5
  355. package/src/services/asset-processing-service/processors/index.js +0 -5
  356. package/src/services/asset-processing-service/processors/script/content-script.processor.d.ts +0 -5
  357. package/src/services/asset-processing-service/processors/script/content-script.processor.js +0 -57
  358. package/src/services/asset-processing-service/processors/script/file-script.processor.d.ts +0 -8
  359. package/src/services/asset-processing-service/processors/script/file-script.processor.js +0 -76
  360. package/src/services/asset-processing-service/processors/script/node-module-script.processor.d.ts +0 -7
  361. package/src/services/asset-processing-service/processors/script/node-module-script.processor.js +0 -74
  362. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -5
  363. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +0 -25
  364. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -9
  365. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +0 -63
  366. package/src/services/cache/cache.types.d.ts +0 -107
  367. package/src/services/cache/cache.types.js +0 -0
  368. package/src/services/cache/index.d.ts +0 -7
  369. package/src/services/cache/index.js +0 -7
  370. package/src/services/cache/memory-cache-store.d.ts +0 -42
  371. package/src/services/cache/memory-cache-store.js +0 -98
  372. package/src/services/cache/page-cache-service.d.ts +0 -70
  373. package/src/services/cache/page-cache-service.js +0 -152
  374. package/src/services/html-transformer.service.d.ts +0 -50
  375. package/src/services/html-transformer.service.js +0 -163
  376. package/src/services/html-transformer.service.ts +0 -217
  377. package/src/services/page-module-import.service.d.ts +0 -37
  378. package/src/services/page-module-import.service.js +0 -88
  379. package/src/services/page-module-import.service.ts +0 -129
  380. package/src/services/page-request-cache-coordinator.service.d.ts +0 -75
  381. package/src/services/page-request-cache-coordinator.service.js +0 -107
  382. package/src/services/schema-validation-service.d.ts +0 -122
  383. package/src/services/schema-validation-service.js +0 -101
  384. package/src/services/validation/standard-schema.types.d.ts +0 -65
  385. package/src/services/validation/standard-schema.types.js +0 -0
  386. package/src/static-site-generator/static-site-generator.d.ts +0 -57
  387. package/src/static-site-generator/static-site-generator.js +0 -272
  388. package/src/utils/css.d.ts +0 -1
  389. package/src/utils/css.js +0 -7
  390. package/src/utils/deep-merge.d.ts +0 -14
  391. package/src/utils/deep-merge.js +0 -32
  392. package/src/utils/hash.d.ts +0 -1
  393. package/src/utils/hash.js +0 -7
  394. package/src/utils/html.d.ts +0 -1
  395. package/src/utils/html.js +0 -4
  396. package/src/utils/invariant.d.ts +0 -5
  397. package/src/utils/invariant.js +0 -11
  398. package/src/utils/locals-utils.d.ts +0 -15
  399. package/src/utils/locals-utils.js +0 -24
  400. package/src/utils/parse-cli-args.d.ts +0 -24
  401. package/src/utils/parse-cli-args.js +0 -47
  402. package/src/utils/path-utils.module.d.ts +0 -5
  403. package/src/utils/path-utils.module.js +0 -14
  404. package/src/utils/runtime.d.ts +0 -11
  405. package/src/utils/runtime.js +0 -40
  406. package/src/utils/server-utils.module.d.ts +0 -19
  407. package/src/utils/server-utils.module.js +0 -56
  408. package/src/watchers/project-watcher.d.ts +0 -132
  409. package/src/watchers/project-watcher.js +0 -281
  410. package/src/watchers/project-watcher.test-helpers.d.ts +0 -4
  411. package/src/watchers/project-watcher.test-helpers.js +0 -51
  412. /package/src/route-renderer/{component-graph-executor.ts → component-graph/component-graph-executor.ts} +0 -0
  413. /package/src/route-renderer/{component-graph.ts → component-graph/component-graph.ts} +0 -0
  414. /package/src/route-renderer/{component-marker.ts → component-graph/component-marker.ts} +0 -0
  415. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.registry.ts +0 -0
  416. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/index.ts +0 -0
  417. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/content-script.processor.ts +0 -0
  418. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/content-stylesheet.processor.ts +0 -0
@@ -0,0 +1,678 @@
1
+ /**
2
+ * Unit tests for the eco namespace API
3
+ */
4
+
5
+ import { describe, expect, test } from 'vitest';
6
+ import { createRequire } from 'node:module';
7
+ import { eco } from './eco.ts';
8
+ import type { EcoComponent, GetMetadataContext, HtmlTemplateProps, LayoutProps, StaticPath } from '../public-types.ts';
9
+ import type { EcoPagesAppConfig } from 'src/internal-types.ts';
10
+ import { getComponentRenderContext, runWithComponentRenderContext } from './component-render-context.ts';
11
+
12
+ const mockAppConfig = {} as EcoPagesAppConfig;
13
+
14
+ describe('eco namespace', () => {
15
+ describe('eco.component()', () => {
16
+ test('should create a component with basic dependencies', () => {
17
+ type Props = { count: number };
18
+ const Counter = eco.component<Props>({
19
+ dependencies: {
20
+ stylesheets: ['./counter.css'],
21
+ scripts: ['./counter.script.ts'],
22
+ },
23
+ render: ({ count }) => `<my-counter count="${count}"></my-counter>`,
24
+ });
25
+
26
+ expect(Counter).toBeDefined();
27
+ expect(typeof Counter).toBe('function');
28
+ expect(Counter.config).toBeDefined();
29
+ expect(Counter.config?.dependencies?.stylesheets).toEqual(['./counter.css']);
30
+ expect(Counter.config?.dependencies?.scripts).toEqual(['./counter.script.ts']);
31
+ });
32
+
33
+ test('should render component without lazy dependencies', () => {
34
+ const Component = eco.component({
35
+ render: () => '<div>Hello</div>',
36
+ });
37
+
38
+ const result = Component({});
39
+ expect(result).toBe('<div>Hello</div>');
40
+ });
41
+
42
+ test('should create component with lazy dependencies', () => {
43
+ const Counter = eco.component({
44
+ dependencies: {
45
+ stylesheets: ['./counter.css'],
46
+ scripts: [{ src: './counter.script.ts', lazy: { 'on:interaction': 'mouseenter,focusin' } }],
47
+ },
48
+ render: () => '<my-counter></my-counter>',
49
+ });
50
+
51
+ expect(Counter.config?.dependencies?.scripts).toEqual([
52
+ { src: './counter.script.ts', lazy: { 'on:interaction': 'mouseenter,focusin' } },
53
+ ]);
54
+ });
55
+
56
+ test('should auto-wrap component with scripts-injector when lazy scripts are resolved', () => {
57
+ const Counter = eco.component({
58
+ dependencies: {
59
+ scripts: [{ src: './counter.script.ts', lazy: { 'on:interaction': 'mouseenter,focusin' } }],
60
+ },
61
+ render: () => '<my-counter></my-counter>',
62
+ });
63
+
64
+ if (Counter.config) {
65
+ Counter.config._resolvedLazyScripts = [
66
+ { lazy: { 'on:interaction': 'mouseenter,focusin' }, scripts: '/_assets/counter.js' },
67
+ ];
68
+ }
69
+
70
+ const result = Counter({});
71
+ expect(result).toContain('<scripts-injector');
72
+ expect(result).toContain('<script type="ecopages/injector-map">');
73
+ expect(result).toContain(
74
+ '"on:interaction":{"value":"mouseenter,focusin","scripts":["/_assets/counter.js"]}',
75
+ );
76
+ expect(result).toContain('<my-counter></my-counter>');
77
+ expect(result).toContain('</scripts-injector>');
78
+ });
79
+
80
+ test('should handle on:idle trigger', () => {
81
+ const Component = eco.component({
82
+ dependencies: {
83
+ scripts: [{ src: './script.ts', lazy: { 'on:idle': true } }],
84
+ },
85
+ render: () => '<div>Content</div>',
86
+ });
87
+
88
+ if (Component.config) {
89
+ Component.config._resolvedLazyScripts = [{ lazy: { 'on:idle': true }, scripts: '/_assets/script.js' }];
90
+ }
91
+
92
+ const result = Component({});
93
+ expect(result).toContain('"on:idle":{"scripts":["/_assets/script.js"]}');
94
+ });
95
+
96
+ test('should handle on:visible trigger with boolean', () => {
97
+ const Component = eco.component({
98
+ dependencies: {
99
+ scripts: [{ src: './script.ts', lazy: { 'on:visible': true } }],
100
+ },
101
+ render: () => '<div>Content</div>',
102
+ });
103
+
104
+ if (Component.config) {
105
+ Component.config._resolvedLazyScripts = [
106
+ { lazy: { 'on:visible': true }, scripts: '/_assets/script.js' },
107
+ ];
108
+ }
109
+
110
+ const result = Component({});
111
+ expect(result).toContain('"on:visible":{"scripts":["/_assets/script.js"]}');
112
+ });
113
+
114
+ test('should handle on:visible trigger with threshold value', () => {
115
+ const Component = eco.component({
116
+ dependencies: {
117
+ scripts: [{ src: './script.ts', lazy: { 'on:visible': '0.5' } }],
118
+ },
119
+ render: () => '<div>Content</div>',
120
+ });
121
+
122
+ if (Component.config) {
123
+ Component.config._resolvedLazyScripts = [
124
+ { lazy: { 'on:visible': '0.5' }, scripts: '/_assets/script.js' },
125
+ ];
126
+ }
127
+
128
+ const result = Component({});
129
+ expect(result).toContain('"on:visible":{"value":"0.5","scripts":["/_assets/script.js"]}');
130
+ });
131
+
132
+ test('should not wrap when lazy script entries exist but _resolvedLazyScripts is not set', () => {
133
+ const Component = eco.component({
134
+ dependencies: {
135
+ scripts: [{ src: './script.ts', lazy: { 'on:interaction': 'mouseenter' } }],
136
+ },
137
+ render: () => '<div>Content</div>',
138
+ });
139
+
140
+ const result = Component({});
141
+ expect(result).toBe('<div>Content</div>');
142
+ expect(result).not.toContain('scripts-injector');
143
+ });
144
+
145
+ test('should pass props to render function', () => {
146
+ type Props = { name: string; count: number };
147
+ const Component = eco.component<Props>({
148
+ render: ({ name, count }) => `<div>${name}: ${count}</div>`,
149
+ });
150
+
151
+ const result = Component({ name: 'Counter', count: 5 });
152
+ expect(result).toBe('<div>Counter: 5</div>');
153
+ });
154
+
155
+ test('should support multiple lazy triggers in dependencies.scripts', () => {
156
+ const Component = eco.component({
157
+ dependencies: {
158
+ scripts: [
159
+ { src: './idle.ts', lazy: { 'on:idle': true } },
160
+ { src: './visible.ts', lazy: { 'on:visible': '0.5' } },
161
+ ],
162
+ },
163
+ render: () => '<section>Content</section>',
164
+ });
165
+
166
+ if (Component.config) {
167
+ Component.config._resolvedLazyScripts = [
168
+ { lazy: { 'on:idle': true }, scripts: '/_assets/idle.js' },
169
+ { lazy: { 'on:visible': '0.5' }, scripts: '/_assets/visible.js' },
170
+ ];
171
+ }
172
+
173
+ const result = Component({});
174
+ expect(result).toContain('"on:idle":{"scripts":["/_assets/idle.js"]}');
175
+ expect(result).toContain('"on:visible":{"value":"0.5","scripts":["/_assets/visible.js"]}');
176
+ expect(result).toContain('<section>Content</section>');
177
+ expect((result.match(/<scripts-injector/g) ?? []).length).toBe(1);
178
+ });
179
+
180
+ test('should set explicit integration on component config', () => {
181
+ const Component = eco.component({
182
+ integration: 'lit',
183
+ render: () => '<div>Content</div>',
184
+ });
185
+
186
+ expect(Component.config?.integration).toBe('lit');
187
+ });
188
+
189
+ test('should emit marker output for React components from non-React context when metadata exists', async () => {
190
+ const require = createRequire(import.meta.url);
191
+ const React = require('react') as {
192
+ createElement: (tag: string, props: Record<string, unknown>, children: string) => unknown;
193
+ };
194
+
195
+ const ReactButton = eco.component({
196
+ integration: 'react',
197
+ __eco: {
198
+ id: 'react-button',
199
+ file: '/app/components/react-button.react.tsx',
200
+ integration: 'react',
201
+ },
202
+ render: () => React.createElement('button', { type: 'button' }, 'Click'),
203
+ });
204
+
205
+ const execution = await runWithComponentRenderContext(
206
+ {
207
+ currentIntegration: 'lit',
208
+ boundaryContext: {
209
+ decideBoundaryRender: ({ targetIntegration }) =>
210
+ targetIntegration === 'react' ? 'defer' : 'inline',
211
+ },
212
+ },
213
+ async () => ReactButton({}),
214
+ );
215
+
216
+ expect(execution.value).toContain('<eco-marker');
217
+ expect(execution.value).toContain('data-eco-integration="react"');
218
+ expect(execution.value).toContain('data-eco-component-ref="react-button"');
219
+ });
220
+
221
+ test('should emit a runtime fallback reference when React marker metadata is missing', async () => {
222
+ const require = createRequire(import.meta.url);
223
+ const React = require('react') as {
224
+ createElement: (tag: string, props: Record<string, unknown>, children: string) => unknown;
225
+ };
226
+
227
+ const ReactButton = eco.component({
228
+ integration: 'react',
229
+ render: () => React.createElement('button', { type: 'button' }, 'Click'),
230
+ });
231
+
232
+ const execution = await runWithComponentRenderContext(
233
+ {
234
+ currentIntegration: 'lit',
235
+ boundaryContext: {
236
+ decideBoundaryRender: ({ targetIntegration }) =>
237
+ targetIntegration === 'react' ? 'defer' : 'inline',
238
+ },
239
+ },
240
+ async () => ReactButton({}),
241
+ );
242
+
243
+ expect(execution.value).toContain('<eco-marker');
244
+ expect(execution.value).toContain('data-eco-component-ref="eco-runtime-component-');
245
+ });
246
+
247
+ test('should render inline when boundary context returns inline for a React component', async () => {
248
+ const ReactButton = eco.component({
249
+ integration: 'react',
250
+ __eco: {
251
+ id: 'react-button',
252
+ file: '/app/components/react-button.react.tsx',
253
+ integration: 'react',
254
+ },
255
+ render: () => '<button type="button">Click</button>',
256
+ });
257
+
258
+ const execution = await runWithComponentRenderContext(
259
+ {
260
+ currentIntegration: 'lit',
261
+ boundaryContext: {
262
+ decideBoundaryRender: () => 'inline',
263
+ },
264
+ },
265
+ async () => ReactButton({}),
266
+ );
267
+
268
+ expect(execution.value).toBe('<button type="button">Click</button>');
269
+ expect(execution.value).not.toContain('<eco-marker');
270
+ expect(execution.graphContext.propsByRef).toEqual({});
271
+ expect(execution.graphContext.slotChildrenByRef).toEqual({});
272
+ });
273
+
274
+ test('should share render context across duplicated module instances', async () => {
275
+ const duplicateModule = (await import(
276
+ './component-render-context.ts?duplicate-instance' as string
277
+ )) as typeof import('./component-render-context.ts');
278
+
279
+ const execution = await runWithComponentRenderContext(
280
+ {
281
+ currentIntegration: 'kitajs',
282
+ boundaryContext: {
283
+ decideBoundaryRender: () => 'inline',
284
+ },
285
+ },
286
+ async () => {
287
+ expect(getComponentRenderContext()?.currentIntegration).toBe('kitajs');
288
+ expect(duplicateModule.getComponentRenderContext()?.currentIntegration).toBe('kitajs');
289
+ return 'shared-context';
290
+ },
291
+ );
292
+
293
+ expect(execution.value).toBe('shared-context');
294
+ });
295
+ });
296
+
297
+ describe('eco.html()', () => {
298
+ test('should create a document shell component with html props', () => {
299
+ const Html = eco.html({
300
+ render: ({ children, language = 'en' }: HtmlTemplateProps) =>
301
+ `<html lang="${language}"><body>${children}</body></html>`,
302
+ });
303
+
304
+ const result = Html({
305
+ children: '<main>Hello</main>',
306
+ metadata: { title: 'Home', description: 'Welcome' },
307
+ pageProps: {},
308
+ });
309
+
310
+ expect(typeof Html).toBe('function');
311
+ expect(result).toBe('<html lang="en"><body><main>Hello</main></body></html>');
312
+ });
313
+ });
314
+
315
+ describe('eco.layout()', () => {
316
+ test('should create a route layout component with layout props', () => {
317
+ const Layout = eco.layout({
318
+ render: ({ children, locals }: LayoutProps<string>) =>
319
+ `<main data-user="${locals?.user ?? 'guest'}">${children}</main>`,
320
+ });
321
+
322
+ const result = Layout({ children: '<h1>Page</h1>', locals: { user: '123' } });
323
+
324
+ expect(typeof Layout).toBe('function');
325
+ expect(result).toBe('<main data-user="123"><h1>Page</h1></main>');
326
+ });
327
+
328
+ test('should work when used as page layout', () => {
329
+ const Layout = eco.layout<string>({
330
+ render: ({ children }) => `<main>${children}</main>`,
331
+ });
332
+
333
+ const Page = eco.page({
334
+ layout: Layout,
335
+ render: () => '<h1>Page Content</h1>',
336
+ });
337
+
338
+ expect(Page.config?.layout).toBe(Layout);
339
+ expect(Page.config?.dependencies?.components).toContain(Layout);
340
+ });
341
+ });
342
+
343
+ describe('eco.page()', () => {
344
+ test('should create a page without staticProps', () => {
345
+ const Page = eco.page({
346
+ dependencies: {
347
+ components: [],
348
+ },
349
+ render: () => '<h1>Welcome</h1>',
350
+ });
351
+
352
+ expect(Page).toBeDefined();
353
+ expect(typeof Page).toBe('function');
354
+ expect(Page.config).toBeDefined();
355
+ });
356
+
357
+ test('should create a page with typed props', () => {
358
+ type PageProps = { params?: { slug?: string }; query?: Record<string, string> };
359
+ const Page = eco.page<PageProps>({
360
+ render: ({ params }) => `<h1>${params?.slug || 'Home'}</h1>`,
361
+ });
362
+
363
+ const result = Page({ params: { slug: 'test-post' } });
364
+ expect(result).toBe('<h1>test-post</h1>');
365
+ });
366
+
367
+ test('should work with lazy dependencies on pages', () => {
368
+ const Page = eco.page({
369
+ dependencies: {
370
+ scripts: [{ src: './page.script.ts', lazy: { 'on:interaction': 'click' } }],
371
+ },
372
+ render: () => '<div>Page Content</div>',
373
+ });
374
+
375
+ if (Page.config) {
376
+ Page.config._resolvedLazyScripts = [
377
+ { lazy: { 'on:interaction': 'click' }, scripts: '/_assets/page.js' },
378
+ ];
379
+ }
380
+
381
+ const result = Page({});
382
+ expect(result).toContain('<scripts-injector');
383
+ expect(result).toContain('"on:interaction":{"value":"click","scripts":["/_assets/page.js"]}');
384
+ });
385
+
386
+ test('should store layout in config and include in dependencies', async () => {
387
+ const Layout = eco.component<{ children: string }>({
388
+ render: ({ children }) => `<main class="layout">${children}</main>`,
389
+ });
390
+
391
+ const Page = eco.page({
392
+ layout: Layout,
393
+ render: () => '<h1>Page Content</h1>',
394
+ });
395
+
396
+ expect(Page.config?.layout).toBe(Layout);
397
+ expect(Page.config?.dependencies?.components).toContain(Layout);
398
+ const result = await Page({});
399
+ expect(result).toBe('<h1>Page Content</h1>');
400
+ });
401
+
402
+ test('should render raw content (layout wrapping happens at render time)', async () => {
403
+ const Layout = eco.component<{ children: string }>({
404
+ render: ({ children }) => `<main class="layout">${children}</main>`,
405
+ });
406
+
407
+ const Page = eco.page({
408
+ layout: Layout,
409
+ render: async () => {
410
+ await Promise.resolve();
411
+ return '<h1>Async Content</h1>';
412
+ },
413
+ });
414
+
415
+ expect(Page.config?.layout).toBe(Layout);
416
+ const result = await Page({});
417
+ expect(result).toBe('<h1>Async Content</h1>');
418
+ });
419
+
420
+ test('should include layout in dependencies when provided', () => {
421
+ const Layout = eco.component<{ children: string }>({
422
+ dependencies: {
423
+ stylesheets: ['./layout.css'],
424
+ },
425
+ render: ({ children }) => `<main>${children}</main>`,
426
+ });
427
+
428
+ const Page = eco.page({
429
+ layout: Layout,
430
+ dependencies: {
431
+ stylesheets: ['./page.css'],
432
+ },
433
+ render: () => '<h1>Content</h1>',
434
+ });
435
+
436
+ expect(Page.config?.dependencies?.components).toContain(Layout);
437
+ expect(Page.config?.dependencies?.stylesheets).toEqual(['./page.css']);
438
+ });
439
+
440
+ test('should set explicit integration on page config', () => {
441
+ const Page = eco.page({
442
+ integration: 'react',
443
+ render: () => '<h1>Page</h1>',
444
+ });
445
+
446
+ expect(Page.config?.integration).toBe('react');
447
+ });
448
+ });
449
+
450
+ describe('eco.metadata()', () => {
451
+ test('should be an identity function', () => {
452
+ const metadataFn = () => ({
453
+ title: 'Home',
454
+ description: 'Welcome',
455
+ });
456
+
457
+ const wrapped = eco.metadata(metadataFn);
458
+ expect(wrapped).toBe(metadataFn);
459
+ });
460
+
461
+ test('should work with async metadata function', async () => {
462
+ const metadataFn = async () => ({
463
+ title: 'Home',
464
+ description: 'Welcome',
465
+ });
466
+
467
+ const wrapped = eco.metadata(metadataFn);
468
+ const result = await wrapped({ props: {}, params: {}, query: {}, appConfig: mockAppConfig });
469
+ expect(result.title).toBe('Home');
470
+ });
471
+
472
+ test('should work with props-based metadata', () => {
473
+ const metadataFn = async () => ({ title: 'My Post', description: 'Post excerpt' });
474
+ const wrapped = eco.metadata(metadataFn);
475
+ expect(wrapped).toBe(metadataFn);
476
+ });
477
+ });
478
+
479
+ describe('eco.staticPaths()', () => {
480
+ test('should be an identity function', () => {
481
+ const staticPathsFn = async () => ({
482
+ paths: [{ params: { slug: 'post-1' } }, { params: { slug: 'post-2' } }],
483
+ });
484
+
485
+ const wrapped = eco.staticPaths(staticPathsFn);
486
+ expect(wrapped).toBe(staticPathsFn);
487
+ });
488
+
489
+ test('should preserve function behavior', async () => {
490
+ const staticPathsFn = async () => ({
491
+ paths: [{ params: { slug: 'post-1' } }, { params: { slug: 'post-2' } }],
492
+ });
493
+
494
+ const wrapped = eco.staticPaths(staticPathsFn);
495
+ const result = await wrapped({ appConfig: mockAppConfig, runtimeOrigin: '' });
496
+ expect(result.paths).toHaveLength(2);
497
+ expect(result.paths[0].params.slug).toBe('post-1');
498
+ });
499
+ });
500
+
501
+ describe('eco.staticProps()', () => {
502
+ test('should be an identity function', () => {
503
+ const staticPropsFn = async ({ pathname }: any) => ({
504
+ props: { slug: pathname.params.slug },
505
+ });
506
+
507
+ const wrapped = eco.staticProps(staticPropsFn);
508
+ expect(wrapped).toBe(staticPropsFn);
509
+ });
510
+
511
+ test('should preserve function behavior', async () => {
512
+ const staticPropsFn = async ({ pathname }: any) => ({
513
+ props: { post: { title: 'Test Post', slug: pathname.params.slug } },
514
+ });
515
+
516
+ const wrapped = eco.staticProps(staticPropsFn);
517
+ const result = await wrapped({
518
+ pathname: { params: { slug: 'my-post' } },
519
+ appConfig: mockAppConfig,
520
+ runtimeOrigin: '',
521
+ });
522
+ expect(result.props.post.title).toBe('Test Post');
523
+ expect(result.props.post.slug).toBe('my-post');
524
+ });
525
+ });
526
+
527
+ describe('integration', () => {
528
+ test('should work with nested components', () => {
529
+ const Button = eco.component<{ label: string }>({
530
+ dependencies: {
531
+ scripts: [
532
+ {
533
+ src: './button.script.ts',
534
+ lazy: {
535
+ 'on:interaction': 'click',
536
+ },
537
+ },
538
+ ],
539
+ },
540
+ render: ({ label }) => `<button>${label}</button>`,
541
+ });
542
+
543
+ const Card = eco.component<{ title: string; children: string }>({
544
+ dependencies: {
545
+ components: [Button as EcoComponent],
546
+ },
547
+ render: ({ title, children }) => `<div class="card"><h2>${title}</h2>${children}</div>`,
548
+ });
549
+
550
+ expect(Card.config?.dependencies?.components).toContain(Button);
551
+ });
552
+ });
553
+
554
+ test('should attach staticPaths when provided (consolidated API)', () => {
555
+ const staticPathsFn = async () => ({
556
+ paths: [{ params: { slug: 'post-1' } }, { params: { slug: 'post-2' } }],
557
+ });
558
+
559
+ const Page = eco.page({
560
+ staticPaths: staticPathsFn,
561
+ render: () => '<h1>Page</h1>',
562
+ });
563
+
564
+ expect(Page.staticPaths).toBe(staticPathsFn);
565
+ });
566
+
567
+ test('should attach staticProps when provided (consolidated API)', () => {
568
+ type Props = { title: string; slug: string };
569
+
570
+ const staticPropsFn = async ({ pathname }: { pathname: StaticPath }) => ({
571
+ props: { title: 'Test', slug: pathname.params.slug as string },
572
+ });
573
+
574
+ const Page = eco.page<Props>({
575
+ staticProps: staticPropsFn,
576
+ render: ({ title }) => `<h1>${title}</h1>`,
577
+ });
578
+
579
+ expect(Page.staticProps).toBe(staticPropsFn);
580
+ });
581
+
582
+ test('should attach metadata when provided (consolidated API)', () => {
583
+ type Props = { title: string };
584
+
585
+ const metadataFn = ({ props: { title } }: GetMetadataContext<Props>) => ({
586
+ title,
587
+ description: `Page: ${title}`,
588
+ });
589
+
590
+ const Page = eco.page<Props>({
591
+ metadata: metadataFn,
592
+ render: ({ title }) => `<h1>${title}</h1>`,
593
+ });
594
+
595
+ expect(Page.metadata).toBe(metadataFn);
596
+ });
597
+
598
+ test('should attach all static functions together (consolidated API)', async () => {
599
+ type Props = { title: string; slug: string };
600
+
601
+ const Page = eco.page<Props>({
602
+ staticPaths: async () => ({
603
+ paths: [{ params: { slug: 'hello' } }],
604
+ }),
605
+ staticProps: async ({ pathname }) => ({
606
+ props: { title: 'Hello World', slug: pathname.params.slug as string },
607
+ }),
608
+ metadata: ({ props: { title } }) => ({
609
+ title,
610
+ description: `Page: ${title}`,
611
+ }),
612
+ render: ({ title }) => `<h1>${title}</h1>`,
613
+ });
614
+
615
+ expect(Page.staticPaths).toBeDefined();
616
+ expect(Page.staticProps).toBeDefined();
617
+ expect(Page.metadata).toBeDefined();
618
+
619
+ // Verify they work correctly
620
+ const paths = await Page.staticPaths!({ appConfig: mockAppConfig, runtimeOrigin: '' });
621
+ expect(paths.paths).toHaveLength(1);
622
+
623
+ const props = await Page.staticProps!({
624
+ pathname: { params: { slug: 'hello' } },
625
+ appConfig: mockAppConfig,
626
+ runtimeOrigin: '',
627
+ });
628
+ expect(props.props.title).toBe('Hello World');
629
+
630
+ const result = Page({ title: 'Hello World', slug: 'hello' });
631
+ expect(result).toBe('<h1>Hello World</h1>');
632
+ });
633
+
634
+ test('should not have static functions when not provided', () => {
635
+ const Page = eco.page({
636
+ render: () => '<h1>Simple Page</h1>',
637
+ });
638
+
639
+ expect(Page.staticPaths).toBeUndefined();
640
+ expect(Page.staticProps).toBeUndefined();
641
+ expect(Page.metadata).toBeUndefined();
642
+ });
643
+
644
+ test('should attach cache strategy "static" when provided', () => {
645
+ const Page = eco.page({
646
+ cache: 'static',
647
+ render: () => '<h1>Static Page</h1>',
648
+ });
649
+
650
+ expect(Page.cache).toBe('static');
651
+ });
652
+
653
+ test('should attach cache strategy "dynamic" when provided', () => {
654
+ const Page = eco.page({
655
+ cache: 'dynamic',
656
+ render: () => '<h1>Dynamic Page</h1>',
657
+ });
658
+
659
+ expect(Page.cache).toBe('dynamic');
660
+ });
661
+
662
+ test('should attach cache strategy with revalidation when provided', () => {
663
+ const Page = eco.page({
664
+ cache: { revalidate: 3600, tags: ['blog'] },
665
+ render: () => '<h1>Blog Page</h1>',
666
+ });
667
+
668
+ expect(Page.cache).toEqual({ revalidate: 3600, tags: ['blog'] });
669
+ });
670
+
671
+ test('should not have cache when not provided', () => {
672
+ const Page = eco.page({
673
+ render: () => '<h1>Page Without Cache</h1>',
674
+ });
675
+
676
+ expect(Page.cache).toBeUndefined();
677
+ });
678
+ });