@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.
- package/README.md +213 -12
- package/package.json +100 -188
- package/src/adapters/README.md +39 -0
- package/src/adapters/bun/hmr-manager.test.ts +267 -0
- package/src/adapters/bun/hmr-manager.ts +180 -47
- package/src/adapters/bun/index.ts +1 -2
- package/src/adapters/bun/server-adapter.ts +41 -34
- package/src/adapters/bun/server-lifecycle.ts +40 -70
- package/src/adapters/index.ts +1 -1
- package/src/adapters/node/bootstrap-dependency-resolver.test.ts +282 -0
- package/src/adapters/node/bootstrap-dependency-resolver.ts +301 -0
- package/src/adapters/node/index.ts +7 -0
- package/src/adapters/node/node-client-bridge.test.ts +198 -0
- package/src/adapters/node/node-hmr-manager.test.ts +322 -0
- package/src/adapters/node/node-hmr-manager.ts +207 -97
- package/src/adapters/node/runtime-adapter.test.ts +868 -0
- package/src/adapters/node/runtime-adapter.ts +439 -0
- package/src/adapters/node/server-adapter.ts +31 -104
- package/src/adapters/node/static-content-server.test.ts +60 -0
- package/src/adapters/node/static-content-server.ts +36 -0
- package/src/adapters/node/write-runtime-manifest.ts +38 -0
- package/src/adapters/shared/api-response.test.ts +97 -0
- package/src/{define-api-handler.ts → adapters/shared/define-api-handler.ts} +1 -1
- package/src/adapters/shared/explicit-static-route-matcher.test.ts +381 -0
- package/src/adapters/shared/explicit-static-route-matcher.ts +7 -1
- package/src/adapters/shared/file-route-middleware-pipeline.test.ts +90 -0
- package/src/adapters/shared/file-route-middleware-pipeline.ts +6 -2
- package/src/adapters/shared/fs-server-response-factory.test.ts +187 -0
- package/src/adapters/shared/fs-server-response-matcher.test.ts +286 -0
- package/src/adapters/shared/fs-server-response-matcher.ts +17 -10
- package/src/adapters/shared/hmr-entrypoint-registrar.ts +149 -0
- package/src/adapters/shared/hmr-html-response.ts +52 -0
- package/src/adapters/shared/hmr-manager.contract.test.ts +196 -0
- package/src/adapters/shared/hmr-manager.dispatch.test.ts +220 -0
- package/src/adapters/shared/render-context.test.ts +146 -0
- package/src/adapters/shared/render-context.ts +21 -6
- package/src/adapters/shared/runtime-bootstrap.ts +79 -0
- package/src/adapters/shared/server-adapter.test.ts +77 -0
- package/src/adapters/shared/server-adapter.ts +51 -4
- package/src/adapters/shared/server-route-handler.test.ts +110 -0
- package/src/adapters/shared/server-route-handler.ts +5 -18
- package/src/adapters/shared/server-static-builder.test.ts +316 -0
- package/src/adapters/shared/server-static-builder.ts +92 -8
- package/src/build/README.md +101 -0
- package/src/build/build-adapter-serialization.test.ts +268 -0
- package/src/build/build-adapter.test.ts +815 -0
- package/src/build/build-adapter.ts +234 -6
- package/src/build/build-manifest.ts +54 -0
- package/src/build/dev-build-coordinator.ts +221 -0
- package/src/build/esbuild-build-adapter.ts +132 -84
- package/src/build/runtime-build-executor.ts +34 -0
- package/src/build/runtime-specifier-alias-plugin.test.ts +43 -0
- package/src/build/runtime-specifier-alias-plugin.ts +58 -0
- package/src/config/README.md +33 -0
- package/src/config/config-builder.test.ts +410 -0
- package/src/config/config-builder.ts +281 -49
- package/src/constants.ts +15 -0
- package/src/declarations.d.ts +18 -13
- package/src/eco/README.md +70 -16
- package/src/eco/component-render-context.ts +39 -17
- package/src/eco/eco.test.ts +678 -0
- package/src/eco/eco.ts +29 -8
- package/src/eco/eco.types.ts +20 -1
- package/src/eco/eco.utils.test.ts +124 -0
- package/src/eco/global-injector-map.test.ts +42 -0
- package/src/eco/lazy-injector-map.test.ts +66 -0
- package/src/eco/module-dependencies.test.ts +30 -0
- package/src/errors/http-error.test.ts +134 -0
- package/src/global/utils.test.ts +12 -0
- package/src/hmr/README.md +26 -0
- 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
- package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
- package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
- package/src/hmr/client/hmr-runtime.ts +38 -7
- package/src/hmr/hmr-strategy.test.ts +124 -0
- package/src/hmr/hmr.postcss.test.e2e.ts +41 -0
- package/src/hmr/hmr.test.e2e.ts +29 -38
- package/src/hmr/strategies/js-hmr-strategy.test.ts +335 -0
- package/src/hmr/strategies/js-hmr-strategy.ts +71 -78
- package/src/index.ts +1 -1
- package/src/integrations/ghtml/ghtml-renderer.test.ts +63 -0
- package/src/integrations/ghtml/ghtml-renderer.ts +4 -1
- package/src/internal-types.ts +39 -19
- package/src/plugins/README.md +34 -0
- package/src/plugins/alias-resolver-plugin.test.ts +41 -0
- package/src/plugins/alias-resolver-plugin.ts +21 -3
- package/src/plugins/eco-component-meta-plugin.test.ts +380 -0
- package/src/plugins/eco-component-meta-plugin.ts +10 -3
- package/src/plugins/integration-plugin.test.ts +111 -0
- package/src/plugins/integration-plugin.ts +45 -3
- package/src/plugins/processor.test.ts +148 -0
- package/src/plugins/processor.ts +22 -2
- package/src/plugins/runtime-capability.ts +14 -0
- package/src/public-types.ts +73 -11
- package/src/route-renderer/GRAPH.md +16 -20
- package/src/route-renderer/README.md +8 -21
- package/src/route-renderer/component-graph/component-graph-executor.test.ts +41 -0
- package/src/route-renderer/component-graph/component-graph.test.ts +63 -0
- package/src/route-renderer/component-graph/component-marker.test.ts +73 -0
- package/src/route-renderer/component-graph/component-reference.ts +29 -0
- package/src/route-renderer/component-graph/marker-graph-resolver.test.ts +135 -0
- package/src/route-renderer/{marker-graph-resolver.ts → component-graph/marker-graph-resolver.ts} +11 -9
- package/src/route-renderer/orchestration/integration-renderer.test.ts +936 -0
- package/src/route-renderer/{integration-renderer.ts → orchestration/integration-renderer.ts} +113 -19
- package/src/route-renderer/orchestration/render-execution.service.test.ts +97 -0
- package/src/route-renderer/{render-execution.service.ts → orchestration/render-execution.service.ts} +109 -37
- package/src/route-renderer/orchestration/render-preparation.service.test.ts +235 -0
- package/src/route-renderer/{render-preparation.service.ts → orchestration/render-preparation.service.ts} +127 -9
- package/src/route-renderer/page-loading/dependency-resolver.test.ts +345 -0
- package/src/route-renderer/{dependency-resolver.ts → page-loading/dependency-resolver.ts} +28 -12
- package/src/route-renderer/page-loading/page-module-loader.test.ts +96 -0
- package/src/route-renderer/{page-module-loader.ts → page-loading/page-module-loader.ts} +49 -21
- package/src/route-renderer/route-renderer.ts +36 -1
- package/src/router/README.md +26 -0
- package/src/router/client/link-intent.d.ts +53 -0
- package/src/router/client/link-intent.test.browser.ts +51 -0
- package/src/router/client/link-intent.ts +92 -0
- package/src/router/client/navigation-coordinator.test.ts +237 -0
- package/src/router/client/navigation-coordinator.ts +433 -0
- package/src/router/server/fs-router-scanner.test.ts +83 -0
- package/src/router/{fs-router-scanner.ts → server/fs-router-scanner.ts} +12 -10
- package/src/router/server/fs-router.test.ts +214 -0
- package/src/router/{fs-router.ts → server/fs-router.ts} +2 -2
- package/src/services/README.md +29 -0
- package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +385 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/asset-processing.service.ts +101 -6
- package/src/services/assets/asset-processing-service/asset.factory.test.ts +63 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/asset.factory.ts +2 -2
- package/src/services/{asset-processing-service → assets/asset-processing-service}/assets.types.ts +2 -1
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +72 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.ts +95 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +67 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.ts +78 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/index.ts +2 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.interface.ts +1 -1
- package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +59 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-processor.ts +11 -5
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-script-processor.ts +17 -27
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +286 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/file-script.processor.ts +3 -3
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +227 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/node-module-script.processor.ts +5 -4
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +199 -0
- package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/file-stylesheet.processor.ts +4 -1
- package/src/services/assets/browser-bundle.service.test.ts +36 -0
- package/src/services/assets/browser-bundle.service.ts +53 -0
- package/src/services/cache/index.ts +3 -3
- package/src/services/cache/memory-cache-store.test.ts +225 -0
- package/src/services/cache/memory-cache-store.ts +1 -1
- package/src/services/cache/page-cache-service.test.ts +175 -0
- package/src/services/cache/page-cache-service.ts +3 -3
- package/src/services/cache/page-request-cache-coordinator.service.test.ts +79 -0
- package/src/services/{page-request-cache-coordinator.service.ts → cache/page-request-cache-coordinator.service.ts} +9 -6
- package/src/services/html/html-rewriter-provider.service.test.ts +183 -0
- package/src/services/html/html-rewriter-provider.service.ts +103 -0
- package/src/services/html/html-transformer.service.test.ts +378 -0
- package/src/services/html/html-transformer.service.ts +279 -0
- package/src/services/invalidation/development-invalidation.service.test.ts +77 -0
- package/src/services/invalidation/development-invalidation.service.ts +261 -0
- package/src/services/module-loading/app-server-module-transpiler.service.ts +52 -0
- package/src/services/module-loading/page-module-import.service.test.ts +253 -0
- package/src/services/module-loading/page-module-import.service.ts +200 -0
- package/src/services/module-loading/server-loader.service.test.ts +161 -0
- package/src/services/module-loading/server-loader.service.ts +130 -0
- package/src/services/module-loading/server-module-transpiler.service.test.ts +115 -0
- package/src/services/module-loading/server-module-transpiler.service.ts +105 -0
- package/src/services/runtime-manifest/node-runtime-manifest.service.test.ts +95 -0
- package/src/services/runtime-manifest/node-runtime-manifest.service.ts +101 -0
- package/src/services/runtime-state/dev-graph.service.ts +217 -0
- package/src/services/runtime-state/entrypoint-dependency-graph.service.ts +136 -0
- package/src/services/runtime-state/runtime-specifier-registry.service.ts +96 -0
- package/src/services/runtime-state/server-invalidation-state.service.ts +68 -0
- package/src/services/validation/schema-validation-service.test.ts +223 -0
- package/src/services/{schema-validation-service.ts → validation/schema-validation-service.ts} +1 -1
- package/src/static-site-generator/README.md +26 -0
- package/src/static-site-generator/static-site-generator.test.ts +307 -0
- package/src/static-site-generator/static-site-generator.ts +109 -6
- package/src/utils/deep-merge.test.ts +114 -0
- package/src/utils/invariant.test.ts +22 -0
- package/src/utils/path-utils.test.ts +15 -0
- package/src/utils/resolve-work-dir.ts +45 -0
- package/src/utils/server-utils.test.ts +38 -0
- package/src/watchers/project-watcher.integration.test.ts +337 -0
- package/src/watchers/project-watcher.test-helpers.ts +1 -0
- package/src/watchers/project-watcher.test.ts +678 -0
- package/src/watchers/project-watcher.ts +49 -50
- package/CHANGELOG.md +0 -94
- package/src/adapters/abstract/application-adapter.d.ts +0 -168
- package/src/adapters/abstract/application-adapter.js +0 -109
- package/src/adapters/abstract/router-adapter.d.ts +0 -26
- package/src/adapters/abstract/router-adapter.js +0 -5
- package/src/adapters/abstract/server-adapter.d.ts +0 -69
- package/src/adapters/abstract/server-adapter.js +0 -15
- package/src/adapters/bun/client-bridge.d.ts +0 -34
- package/src/adapters/bun/client-bridge.js +0 -48
- package/src/adapters/bun/create-app.d.ts +0 -60
- package/src/adapters/bun/create-app.js +0 -117
- package/src/adapters/bun/define-api-handler.d.ts +0 -61
- package/src/adapters/bun/define-api-handler.js +0 -15
- package/src/adapters/bun/define-api-handler.ts +0 -114
- package/src/adapters/bun/hmr-manager.d.ts +0 -79
- package/src/adapters/bun/hmr-manager.js +0 -222
- package/src/adapters/bun/index.d.ts +0 -3
- package/src/adapters/bun/index.js +0 -8
- package/src/adapters/bun/server-adapter.d.ts +0 -155
- package/src/adapters/bun/server-adapter.js +0 -368
- package/src/adapters/bun/server-lifecycle.d.ts +0 -52
- package/src/adapters/bun/server-lifecycle.js +0 -120
- package/src/adapters/index.d.ts +0 -6
- package/src/adapters/index.js +0 -14
- package/src/adapters/node/create-app.d.ts +0 -21
- package/src/adapters/node/create-app.js +0 -143
- package/src/adapters/node/index.d.ts +0 -4
- package/src/adapters/node/index.js +0 -8
- package/src/adapters/node/node-client-bridge.d.ts +0 -26
- package/src/adapters/node/node-client-bridge.js +0 -66
- package/src/adapters/node/node-hmr-manager.d.ts +0 -62
- package/src/adapters/node/node-hmr-manager.js +0 -221
- package/src/adapters/node/server-adapter.d.ts +0 -190
- package/src/adapters/node/server-adapter.js +0 -420
- package/src/adapters/node/static-content-server.d.ts +0 -24
- package/src/adapters/node/static-content-server.js +0 -166
- package/src/adapters/shared/api-response.d.ts +0 -52
- package/src/adapters/shared/api-response.js +0 -96
- package/src/adapters/shared/application-adapter.d.ts +0 -18
- package/src/adapters/shared/application-adapter.js +0 -90
- package/src/adapters/shared/explicit-static-route-matcher.d.ts +0 -38
- package/src/adapters/shared/explicit-static-route-matcher.js +0 -100
- package/src/adapters/shared/file-route-middleware-pipeline.d.ts +0 -65
- package/src/adapters/shared/file-route-middleware-pipeline.js +0 -98
- package/src/adapters/shared/fs-server-response-factory.d.ts +0 -19
- package/src/adapters/shared/fs-server-response-factory.js +0 -97
- package/src/adapters/shared/fs-server-response-matcher.d.ts +0 -71
- package/src/adapters/shared/fs-server-response-matcher.js +0 -155
- package/src/adapters/shared/render-context.d.ts +0 -14
- package/src/adapters/shared/render-context.js +0 -69
- package/src/adapters/shared/server-adapter.d.ts +0 -87
- package/src/adapters/shared/server-adapter.js +0 -353
- package/src/adapters/shared/server-route-handler.d.ts +0 -89
- package/src/adapters/shared/server-route-handler.js +0 -120
- package/src/adapters/shared/server-static-builder.d.ts +0 -38
- package/src/adapters/shared/server-static-builder.js +0 -46
- package/src/build/build-adapter.d.ts +0 -75
- package/src/build/build-adapter.js +0 -54
- package/src/build/build-types.d.ts +0 -57
- package/src/build/build-types.js +0 -0
- package/src/build/esbuild-build-adapter.d.ts +0 -69
- package/src/build/esbuild-build-adapter.js +0 -391
- package/src/config/config-builder.d.ts +0 -227
- package/src/config/config-builder.js +0 -392
- package/src/constants.d.ts +0 -32
- package/src/constants.js +0 -21
- package/src/create-app.d.ts +0 -17
- package/src/create-app.js +0 -66
- package/src/define-api-handler.d.ts +0 -25
- package/src/define-api-handler.js +0 -15
- package/src/dev/sc-server.d.ts +0 -30
- package/src/dev/sc-server.js +0 -111
- package/src/eco/component-render-context.d.ts +0 -105
- package/src/eco/component-render-context.js +0 -77
- package/src/eco/eco.d.ts +0 -9
- package/src/eco/eco.js +0 -110
- package/src/eco/eco.types.d.ts +0 -170
- package/src/eco/eco.types.js +0 -0
- package/src/eco/eco.utils.d.ts +0 -40
- package/src/eco/eco.utils.js +0 -40
- package/src/eco/global-injector-map.d.ts +0 -16
- package/src/eco/global-injector-map.js +0 -80
- package/src/eco/lazy-injector-map.d.ts +0 -8
- package/src/eco/lazy-injector-map.js +0 -70
- package/src/eco/module-dependencies.d.ts +0 -18
- package/src/eco/module-dependencies.js +0 -49
- package/src/errors/http-error.d.ts +0 -31
- package/src/errors/http-error.js +0 -50
- package/src/errors/index.d.ts +0 -2
- package/src/errors/index.js +0 -4
- package/src/errors/locals-access-error.d.ts +0 -4
- package/src/errors/locals-access-error.js +0 -9
- package/src/global/app-logger.d.ts +0 -2
- package/src/global/app-logger.js +0 -6
- package/src/hmr/client/hmr-runtime.d.ts +0 -10
- package/src/hmr/client/hmr-runtime.js +0 -86
- package/src/hmr/hmr-strategy.d.ts +0 -159
- package/src/hmr/hmr-strategy.js +0 -29
- package/src/hmr/hmr.test.e2e.d.ts +0 -1
- package/src/hmr/hmr.test.e2e.js +0 -50
- package/src/hmr/strategies/default-hmr-strategy.d.ts +0 -43
- package/src/hmr/strategies/default-hmr-strategy.js +0 -34
- package/src/hmr/strategies/js-hmr-strategy.d.ts +0 -136
- package/src/hmr/strategies/js-hmr-strategy.js +0 -192
- package/src/index.browser.d.ts +0 -3
- package/src/index.browser.js +0 -4
- package/src/index.d.ts +0 -5
- package/src/index.js +0 -10
- package/src/integrations/ghtml/ghtml-renderer.d.ts +0 -15
- package/src/integrations/ghtml/ghtml-renderer.js +0 -60
- package/src/integrations/ghtml/ghtml.plugin.d.ts +0 -20
- package/src/integrations/ghtml/ghtml.plugin.js +0 -21
- package/src/internal-types.d.ts +0 -200
- package/src/internal-types.js +0 -0
- package/src/plugins/alias-resolver-plugin.d.ts +0 -2
- package/src/plugins/alias-resolver-plugin.js +0 -39
- package/src/plugins/eco-component-meta-plugin.d.ts +0 -95
- package/src/plugins/eco-component-meta-plugin.js +0 -157
- package/src/plugins/integration-plugin.d.ts +0 -102
- package/src/plugins/integration-plugin.js +0 -100
- package/src/plugins/processor.d.ts +0 -82
- package/src/plugins/processor.js +0 -122
- package/src/public-types.d.ts +0 -1094
- package/src/public-types.js +0 -0
- package/src/route-renderer/component-graph-executor.d.ts +0 -32
- package/src/route-renderer/component-graph-executor.js +0 -31
- package/src/route-renderer/component-graph.d.ts +0 -42
- package/src/route-renderer/component-graph.js +0 -72
- package/src/route-renderer/component-marker.d.ts +0 -52
- package/src/route-renderer/component-marker.js +0 -46
- package/src/route-renderer/dependency-resolver.d.ts +0 -24
- package/src/route-renderer/dependency-resolver.js +0 -428
- package/src/route-renderer/html-post-processing.service.d.ts +0 -40
- package/src/route-renderer/html-post-processing.service.js +0 -86
- package/src/route-renderer/html-post-processing.service.ts +0 -103
- package/src/route-renderer/integration-renderer.d.ts +0 -339
- package/src/route-renderer/integration-renderer.js +0 -526
- package/src/route-renderer/marker-graph-resolver.d.ts +0 -76
- package/src/route-renderer/marker-graph-resolver.js +0 -93
- package/src/route-renderer/page-module-loader.d.ts +0 -61
- package/src/route-renderer/page-module-loader.js +0 -102
- package/src/route-renderer/render-execution.service.d.ts +0 -69
- package/src/route-renderer/render-execution.service.js +0 -91
- package/src/route-renderer/render-preparation.service.d.ts +0 -112
- package/src/route-renderer/render-preparation.service.js +0 -243
- package/src/route-renderer/route-renderer.d.ts +0 -26
- package/src/route-renderer/route-renderer.js +0 -68
- package/src/router/fs-router-scanner.d.ts +0 -41
- package/src/router/fs-router-scanner.js +0 -155
- package/src/router/fs-router.d.ts +0 -26
- package/src/router/fs-router.js +0 -100
- package/src/services/asset-processing-service/asset-processing.service.d.ts +0 -41
- package/src/services/asset-processing-service/asset-processing.service.js +0 -250
- package/src/services/asset-processing-service/asset.factory.d.ts +0 -17
- package/src/services/asset-processing-service/asset.factory.js +0 -82
- package/src/services/asset-processing-service/assets.types.d.ts +0 -88
- package/src/services/asset-processing-service/assets.types.js +0 -0
- package/src/services/asset-processing-service/index.d.ts +0 -3
- package/src/services/asset-processing-service/index.js +0 -3
- package/src/services/asset-processing-service/processor.interface.d.ts +0 -22
- package/src/services/asset-processing-service/processor.interface.js +0 -6
- package/src/services/asset-processing-service/processor.registry.d.ts +0 -8
- package/src/services/asset-processing-service/processor.registry.js +0 -15
- package/src/services/asset-processing-service/processors/base/base-processor.d.ts +0 -24
- package/src/services/asset-processing-service/processors/base/base-processor.js +0 -59
- package/src/services/asset-processing-service/processors/base/base-script-processor.d.ts +0 -16
- package/src/services/asset-processing-service/processors/base/base-script-processor.js +0 -80
- package/src/services/asset-processing-service/processors/index.d.ts +0 -5
- package/src/services/asset-processing-service/processors/index.js +0 -5
- package/src/services/asset-processing-service/processors/script/content-script.processor.d.ts +0 -5
- package/src/services/asset-processing-service/processors/script/content-script.processor.js +0 -57
- package/src/services/asset-processing-service/processors/script/file-script.processor.d.ts +0 -8
- package/src/services/asset-processing-service/processors/script/file-script.processor.js +0 -76
- package/src/services/asset-processing-service/processors/script/node-module-script.processor.d.ts +0 -7
- package/src/services/asset-processing-service/processors/script/node-module-script.processor.js +0 -74
- package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -5
- package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +0 -25
- package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -9
- package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +0 -63
- package/src/services/cache/cache.types.d.ts +0 -107
- package/src/services/cache/cache.types.js +0 -0
- package/src/services/cache/index.d.ts +0 -7
- package/src/services/cache/index.js +0 -7
- package/src/services/cache/memory-cache-store.d.ts +0 -42
- package/src/services/cache/memory-cache-store.js +0 -98
- package/src/services/cache/page-cache-service.d.ts +0 -70
- package/src/services/cache/page-cache-service.js +0 -152
- package/src/services/html-transformer.service.d.ts +0 -50
- package/src/services/html-transformer.service.js +0 -163
- package/src/services/html-transformer.service.ts +0 -217
- package/src/services/page-module-import.service.d.ts +0 -37
- package/src/services/page-module-import.service.js +0 -88
- package/src/services/page-module-import.service.ts +0 -129
- package/src/services/page-request-cache-coordinator.service.d.ts +0 -75
- package/src/services/page-request-cache-coordinator.service.js +0 -107
- package/src/services/schema-validation-service.d.ts +0 -122
- package/src/services/schema-validation-service.js +0 -101
- package/src/services/validation/standard-schema.types.d.ts +0 -65
- package/src/services/validation/standard-schema.types.js +0 -0
- package/src/static-site-generator/static-site-generator.d.ts +0 -57
- package/src/static-site-generator/static-site-generator.js +0 -272
- package/src/utils/css.d.ts +0 -1
- package/src/utils/css.js +0 -7
- package/src/utils/deep-merge.d.ts +0 -14
- package/src/utils/deep-merge.js +0 -32
- package/src/utils/hash.d.ts +0 -1
- package/src/utils/hash.js +0 -7
- package/src/utils/html.d.ts +0 -1
- package/src/utils/html.js +0 -4
- package/src/utils/invariant.d.ts +0 -5
- package/src/utils/invariant.js +0 -11
- package/src/utils/locals-utils.d.ts +0 -15
- package/src/utils/locals-utils.js +0 -24
- package/src/utils/parse-cli-args.d.ts +0 -24
- package/src/utils/parse-cli-args.js +0 -47
- package/src/utils/path-utils.module.d.ts +0 -5
- package/src/utils/path-utils.module.js +0 -14
- package/src/utils/runtime.d.ts +0 -11
- package/src/utils/runtime.js +0 -40
- package/src/utils/server-utils.module.d.ts +0 -19
- package/src/utils/server-utils.module.js +0 -56
- package/src/watchers/project-watcher.d.ts +0 -132
- package/src/watchers/project-watcher.js +0 -281
- package/src/watchers/project-watcher.test-helpers.d.ts +0 -4
- package/src/watchers/project-watcher.test-helpers.js +0 -51
- /package/src/route-renderer/{component-graph-executor.ts → component-graph/component-graph-executor.ts} +0 -0
- /package/src/route-renderer/{component-graph.ts → component-graph/component-graph.ts} +0 -0
- /package/src/route-renderer/{component-marker.ts → component-graph/component-marker.ts} +0 -0
- /package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.registry.ts +0 -0
- /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/index.ts +0 -0
- /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/content-script.processor.ts +0 -0
- /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/content-stylesheet.processor.ts +0 -0
package/src/eco/eco.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
EcoComponent,
|
|
8
|
+
EcoHtmlComponent,
|
|
9
|
+
EcoLayoutComponent,
|
|
8
10
|
EcoPagesElement,
|
|
9
11
|
EcoPageComponent,
|
|
10
12
|
GetMetadata,
|
|
@@ -18,6 +20,8 @@ import type { CacheStrategy } from '../services/cache/cache.types.ts';
|
|
|
18
20
|
import type {
|
|
19
21
|
ComponentOptions,
|
|
20
22
|
Eco,
|
|
23
|
+
HtmlOptions,
|
|
24
|
+
LayoutOptions,
|
|
21
25
|
PageOptions,
|
|
22
26
|
PageOptionsBase,
|
|
23
27
|
PagePropsFor,
|
|
@@ -25,7 +29,8 @@ import type {
|
|
|
25
29
|
PageRequires,
|
|
26
30
|
} from './eco.types.ts';
|
|
27
31
|
import { createNodeId, createPropsRef, createSlotRef, getComponentRenderContext } from './component-render-context.ts';
|
|
28
|
-
import { createComponentMarker, parseComponentMarkers } from '../route-renderer/component-marker.ts';
|
|
32
|
+
import { createComponentMarker, parseComponentMarkers } from '../route-renderer/component-graph/component-marker.ts';
|
|
33
|
+
import { getComponentReference } from '../route-renderer/component-graph/component-reference.ts';
|
|
29
34
|
import { addTriggerAttribute, isThenable, wrapWithScriptsInjector } from './eco.utils.ts';
|
|
30
35
|
|
|
31
36
|
/**
|
|
@@ -57,13 +62,7 @@ function createComponentFactory<P, E>(options: ComponentOptions<P, E>): EcoCompo
|
|
|
57
62
|
if (shouldEmitMarker && renderContext) {
|
|
58
63
|
const nodeId = createNodeId(renderContext);
|
|
59
64
|
const propsRef = createPropsRef(renderContext);
|
|
60
|
-
const componentRef = comp
|
|
61
|
-
|
|
62
|
-
if (!componentRef) {
|
|
63
|
-
throw new Error(
|
|
64
|
-
'[ecopages] Missing component reference metadata for cross-integration marker emission.',
|
|
65
|
-
);
|
|
66
|
-
}
|
|
65
|
+
const componentRef = getComponentReference(comp);
|
|
67
66
|
|
|
68
67
|
const componentProps = (props ?? {}) as Record<string, unknown>;
|
|
69
68
|
renderContext.propsByRef[propsRef] = componentProps;
|
|
@@ -129,6 +128,26 @@ function component<P = {}, E = EcoPagesElement>(options: ComponentOptions<P, E>)
|
|
|
129
128
|
return createComponentFactory(options);
|
|
130
129
|
}
|
|
131
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Creates a document shell component.
|
|
133
|
+
*
|
|
134
|
+
* Phase 1 keeps this as a semantic alias over eco.component() so existing
|
|
135
|
+
* renderer behavior remains unchanged.
|
|
136
|
+
*/
|
|
137
|
+
function html<E = EcoPagesElement>(options: HtmlOptions<E>): EcoHtmlComponent<E> {
|
|
138
|
+
return createComponentFactory(options) as EcoHtmlComponent<E>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Creates a route layout component.
|
|
143
|
+
*
|
|
144
|
+
* Phase 1 keeps this as a semantic alias over eco.component() so existing
|
|
145
|
+
* renderer behavior remains unchanged.
|
|
146
|
+
*/
|
|
147
|
+
function layout<E = EcoPagesElement>(options: LayoutOptions<E>): EcoLayoutComponent<E> {
|
|
148
|
+
return createComponentFactory(options) as EcoLayoutComponent<E>;
|
|
149
|
+
}
|
|
150
|
+
|
|
132
151
|
/**
|
|
133
152
|
* Creates a page component with typed props and optional static helpers.
|
|
134
153
|
*/
|
|
@@ -214,6 +233,8 @@ function staticProps<P>(fn: GetStaticProps<P>): GetStaticProps<P> {
|
|
|
214
233
|
*/
|
|
215
234
|
export const eco: Eco = {
|
|
216
235
|
component,
|
|
236
|
+
html,
|
|
237
|
+
layout,
|
|
217
238
|
page,
|
|
218
239
|
metadata,
|
|
219
240
|
staticPaths,
|
package/src/eco/eco.types.ts
CHANGED
|
@@ -7,11 +7,16 @@ import type {
|
|
|
7
7
|
DependencyLazyTrigger,
|
|
8
8
|
EcoComponent,
|
|
9
9
|
EcoComponentDependencies,
|
|
10
|
+
EcoHtmlComponent,
|
|
10
11
|
EcoInjectedMeta,
|
|
12
|
+
EcoLayoutComponent,
|
|
13
|
+
EcoPageLayoutComponent,
|
|
11
14
|
EcoPagesElement,
|
|
12
15
|
GetMetadata,
|
|
13
16
|
GetStaticPaths,
|
|
14
17
|
GetStaticProps,
|
|
18
|
+
HtmlTemplateProps,
|
|
19
|
+
LayoutProps,
|
|
15
20
|
Middleware,
|
|
16
21
|
RequestLocals,
|
|
17
22
|
RequestPageContext,
|
|
@@ -45,6 +50,10 @@ export interface ComponentOptions<P, E = EcoPagesElement> {
|
|
|
45
50
|
render: (props: P) => E | Promise<E>;
|
|
46
51
|
}
|
|
47
52
|
|
|
53
|
+
export type HtmlOptions<E = EcoPagesElement> = ComponentOptions<HtmlTemplateProps, E>;
|
|
54
|
+
|
|
55
|
+
export type LayoutOptions<E = EcoPagesElement> = ComponentOptions<LayoutProps<E>, E>;
|
|
56
|
+
|
|
48
57
|
/**
|
|
49
58
|
* Base options shared by all page variants
|
|
50
59
|
*/
|
|
@@ -53,7 +62,7 @@ export interface PageOptionsBase<T, E = EcoPagesElement> {
|
|
|
53
62
|
__eco?: EcoInjectedMeta;
|
|
54
63
|
integration?: string;
|
|
55
64
|
dependencies?: EcoComponentDependencies;
|
|
56
|
-
layout?:
|
|
65
|
+
layout?: EcoPageLayoutComponent<E>;
|
|
57
66
|
|
|
58
67
|
/**
|
|
59
68
|
* Define static paths for dynamic routes (e.g., [slug].tsx).
|
|
@@ -169,6 +178,16 @@ export interface Eco {
|
|
|
169
178
|
*/
|
|
170
179
|
component: <P = {}, E = EcoPagesElement>(options: ComponentOptions<P, E>) => EcoComponent<P, E>;
|
|
171
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Create a document shell component for the HTML wrapper.
|
|
183
|
+
*/
|
|
184
|
+
html: <E = EcoPagesElement>(options: HtmlOptions<E>) => EcoHtmlComponent<E>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Create a route layout component.
|
|
188
|
+
*/
|
|
189
|
+
layout: <E = EcoPagesElement>(options: LayoutOptions<E>) => EcoLayoutComponent<E>;
|
|
190
|
+
|
|
172
191
|
/**
|
|
173
192
|
* Create a page component with type-safe props from getStaticProps.
|
|
174
193
|
* Returns an EcoPageComponent with attached staticPaths, staticProps, and metadata.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { addTriggerAttribute, isThenable } from './eco.utils.ts';
|
|
3
|
+
|
|
4
|
+
const TRIGGER_ID = 'eco-trigger-abc123';
|
|
5
|
+
|
|
6
|
+
describe('addTriggerAttribute', () => {
|
|
7
|
+
describe('basic element injection', () => {
|
|
8
|
+
test('injects into a plain div', () => {
|
|
9
|
+
const result = addTriggerAttribute('<div>content</div>', TRIGGER_ID);
|
|
10
|
+
expect(result).toBe(`<div data-eco-trigger="${TRIGGER_ID}">content</div>`);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('injects into a custom element', () => {
|
|
14
|
+
const result = addTriggerAttribute('<my-counter value="0"></my-counter>', TRIGGER_ID);
|
|
15
|
+
expect(result).toBe(`<my-counter data-eco-trigger="${TRIGGER_ID}" value="0"></my-counter>`);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('injects into an element that already has attributes', () => {
|
|
19
|
+
const result = addTriggerAttribute('<div class="foo" id="bar">content</div>', TRIGGER_ID);
|
|
20
|
+
expect(result).toBe(`<div data-eco-trigger="${TRIGGER_ID}" class="foo" id="bar">content</div>`);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('injects into a self-closing void element', () => {
|
|
24
|
+
const result = addTriggerAttribute('<img src="x.png" alt="" />', TRIGGER_ID);
|
|
25
|
+
expect(result).toBe(`<img data-eco-trigger="${TRIGGER_ID}" src="x.png" alt="" />`);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('injects into an element with no attributes and immediate close', () => {
|
|
29
|
+
const result = addTriggerAttribute('<section></section>', TRIGGER_ID);
|
|
30
|
+
expect(result).toBe(`<section data-eco-trigger="${TRIGGER_ID}"></section>`);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('leading non-element nodes are skipped', () => {
|
|
35
|
+
test('skips leading whitespace and injects into the first element', () => {
|
|
36
|
+
const result = addTriggerAttribute(' \n <div>content</div>', TRIGGER_ID);
|
|
37
|
+
expect(result).toBe(` \n <div data-eco-trigger="${TRIGGER_ID}">content</div>`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('skips a leading HTML comment', () => {
|
|
41
|
+
const result = addTriggerAttribute('<!-- wrapper --><div>content</div>', TRIGGER_ID);
|
|
42
|
+
expect(result).toBe(`<!-- wrapper --><div data-eco-trigger="${TRIGGER_ID}">content</div>`);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('skips multiple leading HTML comments', () => {
|
|
46
|
+
const result = addTriggerAttribute('<!-- a --><!-- b --><span>text</span>', TRIGGER_ID);
|
|
47
|
+
expect(result).toBe(`<!-- a --><!-- b --><span data-eco-trigger="${TRIGGER_ID}">text</span>`);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('skips a leading doctype declaration', () => {
|
|
51
|
+
const result = addTriggerAttribute('<!DOCTYPE html><html lang="en"></html>', TRIGGER_ID);
|
|
52
|
+
expect(result).toBe(`<!DOCTYPE html><html data-eco-trigger="${TRIGGER_ID}" lang="en"></html>`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('skips a leading XML processing instruction', () => {
|
|
56
|
+
const result = addTriggerAttribute('<?xml version="1.0"?><root/>', TRIGGER_ID);
|
|
57
|
+
expect(result).toBe(`<?xml version="1.0"?><root data-eco-trigger="${TRIGGER_ID}"/>`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('skips comment then whitespace then element', () => {
|
|
61
|
+
const result = addTriggerAttribute('<!-- note -->\n<article>body</article>', TRIGGER_ID);
|
|
62
|
+
expect(result).toBe(`<!-- note -->\n<article data-eco-trigger="${TRIGGER_ID}">body</article>`);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('only the first element is modified', () => {
|
|
67
|
+
test('does not inject into sibling elements', () => {
|
|
68
|
+
const result = addTriggerAttribute('<div>first</div><div>second</div>', TRIGGER_ID);
|
|
69
|
+
expect(result).toBe(`<div data-eco-trigger="${TRIGGER_ID}">first</div><div>second</div>`);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('fallback when no element is found', () => {
|
|
74
|
+
test('returns the original string unchanged when there is no opening tag', () => {
|
|
75
|
+
const input = 'just some text';
|
|
76
|
+
expect(addTriggerAttribute(input, TRIGGER_ID)).toBe(input);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('returns the original string unchanged when input is empty', () => {
|
|
80
|
+
expect(addTriggerAttribute('', TRIGGER_ID)).toBe('');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('non-string input coercion', () => {
|
|
85
|
+
test('coerces a number to string before injecting', () => {
|
|
86
|
+
const result = addTriggerAttribute(42, TRIGGER_ID);
|
|
87
|
+
expect(result).toBe('42');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('coerces null to the string "null"', () => {
|
|
91
|
+
expect(addTriggerAttribute(null, TRIGGER_ID)).toBe('null');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('isThenable', () => {
|
|
97
|
+
test('returns true for a native Promise', () => {
|
|
98
|
+
expect(isThenable(Promise.resolve())).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('returns true for a plain object with a then function', () => {
|
|
102
|
+
expect(isThenable({ then: () => {} })).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('returns false for a plain string', () => {
|
|
106
|
+
expect(isThenable('hello')).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('returns false for a number', () => {
|
|
110
|
+
expect(isThenable(42)).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('returns false for null', () => {
|
|
114
|
+
expect(isThenable(null)).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('returns false for an object without then', () => {
|
|
118
|
+
expect(isThenable({ value: 1 })).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('returns false when then is not a function', () => {
|
|
122
|
+
expect(isThenable({ then: 'not-a-function' })).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { buildGlobalInjectorBootstrapContent, buildGlobalInjectorMapScript } from './global-injector-map.ts';
|
|
3
|
+
import type { ResolvedLazyTrigger } from '../public-types.ts';
|
|
4
|
+
|
|
5
|
+
describe('buildGlobalInjectorMapScript', () => {
|
|
6
|
+
test('builds merged map by trigger id and escapes script closing tags', () => {
|
|
7
|
+
const triggers: ResolvedLazyTrigger[] = [
|
|
8
|
+
{
|
|
9
|
+
triggerId: 'eco-trigger-one',
|
|
10
|
+
rules: [
|
|
11
|
+
{ 'on:interaction': { value: 'click', scripts: ['/a.js', '/b</script>.js'] } },
|
|
12
|
+
{ 'on:idle': { scripts: ['/idle.js'] } },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
triggerId: 'eco-trigger-one',
|
|
17
|
+
rules: [{ 'on:interaction': { value: 'click', scripts: ['/a.js', '/c.js'] } }],
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const payload = buildGlobalInjectorMapScript(triggers);
|
|
22
|
+
expect(payload).toContain('<\\/script>');
|
|
23
|
+
|
|
24
|
+
const map = JSON.parse(payload) as Record<string, Record<string, { scripts: string[]; value?: string }>>;
|
|
25
|
+
expect(map['eco-trigger-one']?.['on:idle']?.scripts).toEqual(['/idle.js']);
|
|
26
|
+
expect(map['eco-trigger-one']?.['on:interaction']).toEqual({
|
|
27
|
+
value: 'click',
|
|
28
|
+
scripts: ['/a.js', '/b</script>.js', '/c.js'],
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('buildGlobalInjectorBootstrapContent', () => {
|
|
34
|
+
test('binds refresh to after-swap and avoids before-swap cleanup listener', () => {
|
|
35
|
+
const bootstrap = buildGlobalInjectorBootstrapContent('/assets/injector-global.js');
|
|
36
|
+
|
|
37
|
+
expect(bootstrap).toContain("document.addEventListener('eco:after-swap', handleAfterSwap);");
|
|
38
|
+
expect(bootstrap).not.toContain("document.addEventListener('eco:before-swap'");
|
|
39
|
+
expect(bootstrap).not.toContain('const handleBeforeSwap');
|
|
40
|
+
expect(bootstrap).toContain("document.removeEventListener('eco:after-swap', handleAfterSwap);");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { buildInjectorMapScript } from './lazy-injector-map.ts';
|
|
3
|
+
import type { InjectorMapConfig } from '@ecopages/scripts-injector/types';
|
|
4
|
+
import type { ResolvedLazyScriptGroup } from '../public-types.ts';
|
|
5
|
+
|
|
6
|
+
describe('buildInjectorMapScript', () => {
|
|
7
|
+
test('builds injector map for mixed lazy triggers', () => {
|
|
8
|
+
const lazyGroups: ResolvedLazyScriptGroup[] = [
|
|
9
|
+
{ lazy: { 'on:idle': true }, scripts: './idle-a.js, /idle-b.js' },
|
|
10
|
+
{ lazy: { 'on:interaction': 'click' }, scripts: './int-a.js' },
|
|
11
|
+
{ lazy: { 'on:visible': '0.5' }, scripts: '/vis-a.js' },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const result = buildInjectorMapScript(lazyGroups);
|
|
15
|
+
const map = JSON.parse(result) as InjectorMapConfig;
|
|
16
|
+
|
|
17
|
+
expect(map['on:idle']).toEqual({ scripts: ['/idle-a.js', '/idle-b.js'] });
|
|
18
|
+
expect(map['on:interaction']).toEqual({
|
|
19
|
+
value: 'click',
|
|
20
|
+
scripts: ['/int-a.js'],
|
|
21
|
+
});
|
|
22
|
+
expect(map['on:visible']).toEqual({
|
|
23
|
+
value: '0.5',
|
|
24
|
+
scripts: ['/vis-a.js'],
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('dedupes scripts and merges interaction events while preserving order', () => {
|
|
29
|
+
const lazyGroups: ResolvedLazyScriptGroup[] = [
|
|
30
|
+
{ lazy: { 'on:interaction': 'click,mouseenter' }, scripts: './one.js,./two.js' },
|
|
31
|
+
{ lazy: { 'on:interaction': 'mouseenter,focusin' }, scripts: '/two.js,/three.js' },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const result = buildInjectorMapScript(lazyGroups);
|
|
35
|
+
const map = JSON.parse(result) as InjectorMapConfig;
|
|
36
|
+
|
|
37
|
+
expect(map['on:interaction']).toEqual({
|
|
38
|
+
value: 'click,mouseenter,focusin',
|
|
39
|
+
scripts: ['/one.js', '/two.js', '/three.js'],
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('keeps existing on:visible threshold when a later boolean trigger is encountered', () => {
|
|
44
|
+
const lazyGroups: ResolvedLazyScriptGroup[] = [
|
|
45
|
+
{ lazy: { 'on:visible': '100px' }, scripts: './threshold.js' },
|
|
46
|
+
{ lazy: { 'on:visible': true }, scripts: './fallback.js' },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const result = buildInjectorMapScript(lazyGroups);
|
|
50
|
+
const map = JSON.parse(result) as InjectorMapConfig;
|
|
51
|
+
|
|
52
|
+
expect(map['on:visible']).toEqual({
|
|
53
|
+
value: '100px',
|
|
54
|
+
scripts: ['/threshold.js', '/fallback.js'],
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('escapes closing script tags in output payload', () => {
|
|
59
|
+
const lazyGroups: ResolvedLazyScriptGroup[] = [
|
|
60
|
+
{ lazy: { 'on:idle': true }, scripts: '/safe.js, /x</script>y.js' },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const result = buildInjectorMapScript(lazyGroups);
|
|
64
|
+
expect(result).toContain('<\\/script>');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { normalizeModuleDeclarations, parseModuleDeclaration } from './module-dependencies.ts';
|
|
3
|
+
|
|
4
|
+
describe('module dependencies parser', () => {
|
|
5
|
+
test('parses simple module declaration', () => {
|
|
6
|
+
expect(parseModuleDeclaration('react-aria-components')).toEqual({
|
|
7
|
+
from: 'react-aria-components',
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('parses declaration with named imports', () => {
|
|
12
|
+
expect(parseModuleDeclaration('react-aria-components{Table,Select}')).toEqual({
|
|
13
|
+
from: 'react-aria-components',
|
|
14
|
+
imports: ['Table', 'Select'],
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('normalizes and deduplicates module declarations', () => {
|
|
19
|
+
expect(
|
|
20
|
+
normalizeModuleDeclarations([
|
|
21
|
+
'react-aria-components{Table,Select}',
|
|
22
|
+
'react-aria-components{Table,Select}',
|
|
23
|
+
'lodash-es{debounce}',
|
|
24
|
+
]),
|
|
25
|
+
).toEqual([
|
|
26
|
+
{ from: 'react-aria-components', imports: ['Table', 'Select'] },
|
|
27
|
+
{ from: 'lodash-es', imports: ['debounce'] },
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { HttpError } from './http-error.ts';
|
|
3
|
+
|
|
4
|
+
describe('HttpError', () => {
|
|
5
|
+
describe('constructor', () => {
|
|
6
|
+
test('creates error with status and message', () => {
|
|
7
|
+
const error = new HttpError(400, 'Bad request');
|
|
8
|
+
|
|
9
|
+
expect(error).toBeInstanceOf(Error);
|
|
10
|
+
expect(error).toBeInstanceOf(HttpError);
|
|
11
|
+
expect(error.status).toBe(400);
|
|
12
|
+
expect(error.message).toBe('Bad request');
|
|
13
|
+
expect(error.name).toBe('HttpError');
|
|
14
|
+
expect(error.details).toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('creates error with details', () => {
|
|
18
|
+
const details = { field: 'email', reason: 'invalid format' };
|
|
19
|
+
const error = new HttpError(400, 'Validation failed', details);
|
|
20
|
+
|
|
21
|
+
expect(error.details).toEqual(details);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('toJSON', () => {
|
|
26
|
+
test('serializes error without details', () => {
|
|
27
|
+
const error = new HttpError(404, 'Not found');
|
|
28
|
+
|
|
29
|
+
expect(error.toJSON()).toEqual({
|
|
30
|
+
error: 'Not found',
|
|
31
|
+
status: 404,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('serializes error with details', () => {
|
|
36
|
+
const details = { body: [{ path: ['title'], message: 'Required' }] };
|
|
37
|
+
const error = new HttpError(400, 'Validation failed', details);
|
|
38
|
+
|
|
39
|
+
expect(error.toJSON()).toEqual({
|
|
40
|
+
error: 'Validation failed',
|
|
41
|
+
status: 400,
|
|
42
|
+
details,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('toResponse', () => {
|
|
48
|
+
test('creates Response with correct status and body', async () => {
|
|
49
|
+
const error = new HttpError(403, 'Access denied');
|
|
50
|
+
const response = error.toResponse();
|
|
51
|
+
|
|
52
|
+
expect(response).toBeInstanceOf(Response);
|
|
53
|
+
expect(response.status).toBe(403);
|
|
54
|
+
expect(response.headers.get('content-type')).toContain('application/json');
|
|
55
|
+
|
|
56
|
+
const body = await response.json();
|
|
57
|
+
expect(body).toEqual({ error: 'Access denied', status: 403 });
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('factory methods', () => {
|
|
62
|
+
test('BadRequest creates 400 error', () => {
|
|
63
|
+
const error = HttpError.BadRequest();
|
|
64
|
+
expect(error.status).toBe(400);
|
|
65
|
+
expect(error.message).toBe('Bad Request');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('BadRequest accepts custom message and details', () => {
|
|
69
|
+
const details = { field: 'name' };
|
|
70
|
+
const error = HttpError.BadRequest('Invalid input', details);
|
|
71
|
+
|
|
72
|
+
expect(error.message).toBe('Invalid input');
|
|
73
|
+
expect(error.details).toEqual(details);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('Unauthorized creates 401 error', () => {
|
|
77
|
+
const error = HttpError.Unauthorized();
|
|
78
|
+
expect(error.status).toBe(401);
|
|
79
|
+
expect(error.message).toBe('Unauthorized');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('Unauthorized accepts custom message', () => {
|
|
83
|
+
const error = HttpError.Unauthorized('Token expired');
|
|
84
|
+
expect(error.message).toBe('Token expired');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('Forbidden creates 403 error', () => {
|
|
88
|
+
const error = HttpError.Forbidden();
|
|
89
|
+
expect(error.status).toBe(403);
|
|
90
|
+
expect(error.message).toBe('Forbidden');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Forbidden accepts custom message', () => {
|
|
94
|
+
const error = HttpError.Forbidden('Admin access required');
|
|
95
|
+
expect(error.message).toBe('Admin access required');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('NotFound creates 404 error', () => {
|
|
99
|
+
const error = HttpError.NotFound();
|
|
100
|
+
expect(error.status).toBe(404);
|
|
101
|
+
expect(error.message).toBe('Not Found');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('NotFound accepts custom message', () => {
|
|
105
|
+
const error = HttpError.NotFound('Post not found');
|
|
106
|
+
expect(error.message).toBe('Post not found');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('Conflict creates 409 error', () => {
|
|
110
|
+
const error = HttpError.Conflict();
|
|
111
|
+
expect(error.status).toBe(409);
|
|
112
|
+
expect(error.message).toBe('Conflict');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('Conflict accepts custom message and details', () => {
|
|
116
|
+
const details = { resource: 'user', conflict: 'email already exists' };
|
|
117
|
+
const error = HttpError.Conflict('Resource conflict', details);
|
|
118
|
+
|
|
119
|
+
expect(error.message).toBe('Resource conflict');
|
|
120
|
+
expect(error.details).toEqual(details);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('InternalServerError creates 500 error', () => {
|
|
124
|
+
const error = HttpError.InternalServerError();
|
|
125
|
+
expect(error.status).toBe(500);
|
|
126
|
+
expect(error.message).toBe('Internal Server Error');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('InternalServerError accepts custom message', () => {
|
|
130
|
+
const error = HttpError.InternalServerError('Database connection failed');
|
|
131
|
+
expect(error.message).toBe('Database connection failed');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { invariant } from '../utils/invariant.ts';
|
|
3
|
+
|
|
4
|
+
describe('Utils', () => {
|
|
5
|
+
test('invariant should throw error when condition is falsy', () => {
|
|
6
|
+
expect(() => invariant(false, 'Test error')).toThrowError('[ecopages] Test error');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('invariant should not throw error when condition is truthy', () => {
|
|
10
|
+
expect(() => invariant(true, 'Test error')).not.toThrow();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# HMR Layer
|
|
2
|
+
|
|
3
|
+
This directory contains the framework-owned hot-update strategy contracts used by runtime adapters and integrations.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The HMR layer separates change classification from update execution.
|
|
8
|
+
|
|
9
|
+
It is responsible for:
|
|
10
|
+
|
|
11
|
+
- defining the shared HMR manager and strategy contracts
|
|
12
|
+
- letting integrations contribute framework-specific update strategies
|
|
13
|
+
- keeping adapter transports independent from update policy
|
|
14
|
+
|
|
15
|
+
## How It Fits
|
|
16
|
+
|
|
17
|
+
1. `ProjectWatcher` observes file changes.
|
|
18
|
+
2. `DevelopmentInvalidationService` classifies the change.
|
|
19
|
+
3. The active HMR manager selects a strategy.
|
|
20
|
+
4. The strategy coordinates browser rebuilds, metadata reloads, and client broadcasts.
|
|
21
|
+
|
|
22
|
+
## Design Rule
|
|
23
|
+
|
|
24
|
+
Generic invalidation policy belongs in core services.
|
|
25
|
+
Framework-specific update behavior belongs in HMR strategies.
|
|
26
|
+
Runtime-specific WebSocket or event-stream transport belongs in adapters.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Injected into the browser to handle Hot Module Replacement updates.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { getEcoNavigationRuntime } from '../../router/client/navigation-coordinator.ts';
|
|
7
|
+
|
|
6
8
|
interface HMRPayload {
|
|
7
9
|
type: 'reload' | 'error' | 'update' | 'css-update' | 'layout-update';
|
|
8
10
|
path?: string;
|
|
@@ -41,14 +43,16 @@ interface HMRPayload {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
async function handleMessage(payload: HMRPayload) {
|
|
46
|
+
const navigationRuntime = getEcoNavigationRuntime(window);
|
|
47
|
+
|
|
44
48
|
switch (payload.type) {
|
|
45
49
|
case 'reload':
|
|
50
|
+
await waitForNavigationToSettle(navigationRuntime);
|
|
46
51
|
location.reload();
|
|
47
52
|
break;
|
|
48
53
|
case 'layout-update': {
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
await reloadFn({ clearCache: true });
|
|
54
|
+
await waitForNavigationToSettle(navigationRuntime);
|
|
55
|
+
if (await navigationRuntime.reloadCurrentPage({ clearCache: true })) {
|
|
52
56
|
} else {
|
|
53
57
|
location.reload();
|
|
54
58
|
}
|
|
@@ -78,7 +82,9 @@ interface HMRPayload {
|
|
|
78
82
|
async function applyUpdate(path: string, timestamp?: number) {
|
|
79
83
|
try {
|
|
80
84
|
const url = path + '?t=' + (timestamp || Date.now());
|
|
81
|
-
const handlers = window.
|
|
85
|
+
const handlers = window.__ECO_PAGES__?.hmrHandlers;
|
|
86
|
+
const navigationRuntime = getEcoNavigationRuntime(window);
|
|
87
|
+
await waitForNavigationToSettle(navigationRuntime);
|
|
82
88
|
|
|
83
89
|
if (handlers?.[path]) {
|
|
84
90
|
await handlers[path](url);
|
|
@@ -89,15 +95,40 @@ interface HMRPayload {
|
|
|
89
95
|
|
|
90
96
|
// If we're inside the EcoRouter, we need to trigger a router navigation to render the new component.
|
|
91
97
|
// Passing clearCache: false preserves the persisted layout cache.
|
|
92
|
-
|
|
93
|
-
if (typeof reloadFn === 'function') {
|
|
94
|
-
await reloadFn({ clearCache: false });
|
|
98
|
+
if (await navigationRuntime.reloadCurrentPage({ clearCache: false })) {
|
|
95
99
|
}
|
|
96
100
|
} catch (e) {
|
|
97
101
|
console.error('[ecopages] Failed to apply HMR update:', e);
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
|
|
105
|
+
async function waitForNavigationToSettle(navigationRuntime: ReturnType<typeof getEcoNavigationRuntime>) {
|
|
106
|
+
if (!navigationRuntime.hasPendingNavigationTransaction()) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await new Promise<void>((resolve) => {
|
|
111
|
+
const startedAt = performance.now();
|
|
112
|
+
const timeoutMs = 2000;
|
|
113
|
+
|
|
114
|
+
const poll = () => {
|
|
115
|
+
if (!navigationRuntime.hasPendingNavigationTransaction()) {
|
|
116
|
+
resolve();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (performance.now() - startedAt >= timeoutMs) {
|
|
121
|
+
resolve();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
requestAnimationFrame(poll);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
requestAnimationFrame(poll);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
101
132
|
/**
|
|
102
133
|
* Hot-reload CSS by updating stylesheet link href with cache-busting query param.
|
|
103
134
|
* This causes the browser to re-fetch the stylesheet without a full page reload.
|