@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
|
@@ -10,11 +10,22 @@ type NodeStaticContentServerOptions = {
|
|
|
10
10
|
port?: number;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Serves prebuilt static Ecopages output through Node's HTTP server.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* This server is used by the Node preview/build path once the app has already
|
|
18
|
+
* emitted its static output. It intentionally stays small: path sanitization,
|
|
19
|
+
* content-type selection, optional gzip serving, and 404 handling.
|
|
20
|
+
*/
|
|
13
21
|
export class NodeStaticContentServer {
|
|
14
22
|
private readonly appConfig: EcoPagesAppConfig;
|
|
15
23
|
private readonly options: NodeStaticContentServerOptions;
|
|
16
24
|
private server: NodeHttpServer | null = null;
|
|
17
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Creates the Node static-content server for one built app output directory.
|
|
28
|
+
*/
|
|
18
29
|
constructor({ appConfig, options }: { appConfig: EcoPagesAppConfig; options?: NodeStaticContentServerOptions }) {
|
|
19
30
|
this.appConfig = appConfig;
|
|
20
31
|
this.options = {
|
|
@@ -23,10 +34,17 @@ export class NodeStaticContentServer {
|
|
|
23
34
|
};
|
|
24
35
|
}
|
|
25
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Returns whether the given content type should be served from a pre-gzipped
|
|
39
|
+
* companion file when available.
|
|
40
|
+
*/
|
|
26
41
|
private shouldServeGzip(contentType: string): boolean {
|
|
27
42
|
return ['text/javascript', 'text/css'].includes(contentType);
|
|
28
43
|
}
|
|
29
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes a request pathname and rejects directory traversal attempts.
|
|
47
|
+
*/
|
|
30
48
|
private sanitizePath(pathname: string): string | null {
|
|
31
49
|
const withoutLeadingSlash = pathname.replace(/^\/+/, '');
|
|
32
50
|
const normalizedPath = normalize(withoutLeadingSlash);
|
|
@@ -38,6 +56,9 @@ export class NodeStaticContentServer {
|
|
|
38
56
|
return normalizedPath;
|
|
39
57
|
}
|
|
40
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Writes one HTTP response with the provided headers and optional body.
|
|
61
|
+
*/
|
|
41
62
|
private sendResponse(res: ServerResponse, status: number, headers: Record<string, string>, body?: Buffer): void {
|
|
42
63
|
res.statusCode = status;
|
|
43
64
|
for (const [key, value] of Object.entries(headers)) {
|
|
@@ -52,6 +73,9 @@ export class NodeStaticContentServer {
|
|
|
52
73
|
res.end(body);
|
|
53
74
|
}
|
|
54
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Serves the generated 404 page when present, or a plain-text fallback.
|
|
78
|
+
*/
|
|
55
79
|
private sendNotFoundPage(req: IncomingMessage, res: ServerResponse): void {
|
|
56
80
|
const error404TemplatePath = join(this.appConfig.absolutePaths.distDir, '404.html');
|
|
57
81
|
const isHead = (req.method ?? 'GET').toUpperCase() === 'HEAD';
|
|
@@ -70,6 +94,9 @@ export class NodeStaticContentServer {
|
|
|
70
94
|
this.sendResponse(res, 404, { 'Content-Type': 'text/html' }, isHead ? undefined : file);
|
|
71
95
|
}
|
|
72
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Serves one concrete file path, honoring gzip and HEAD semantics.
|
|
99
|
+
*/
|
|
73
100
|
private serveFile(req: IncomingMessage, res: ServerResponse, filePath: string, status = 200): void {
|
|
74
101
|
const contentType = ServerUtils.getContentType(extname(filePath));
|
|
75
102
|
const acceptsGzip = req.headers['accept-encoding']?.includes('gzip');
|
|
@@ -102,6 +129,9 @@ export class NodeStaticContentServer {
|
|
|
102
129
|
this.sendResponse(res, status, { 'Content-Type': contentType }, isHead ? undefined : file);
|
|
103
130
|
}
|
|
104
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Handles one incoming Node HTTP request against the built static output tree.
|
|
134
|
+
*/
|
|
105
135
|
private handleRequest(req: IncomingMessage, res: ServerResponse): void {
|
|
106
136
|
const method = (req.method ?? 'GET').toUpperCase();
|
|
107
137
|
const isHead = method === 'HEAD';
|
|
@@ -161,6 +191,9 @@ export class NodeStaticContentServer {
|
|
|
161
191
|
this.sendNotFoundPage(req, res);
|
|
162
192
|
}
|
|
163
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Starts the static preview server.
|
|
196
|
+
*/
|
|
164
197
|
public async start(): Promise<NodeHttpServer> {
|
|
165
198
|
if (this.server) {
|
|
166
199
|
return this.server;
|
|
@@ -177,6 +210,9 @@ export class NodeStaticContentServer {
|
|
|
177
210
|
return this.server;
|
|
178
211
|
}
|
|
179
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Stops the static preview server and optionally closes active connections.
|
|
215
|
+
*/
|
|
180
216
|
public async stop(force = true): Promise<void> {
|
|
181
217
|
if (!this.server) {
|
|
182
218
|
return;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeAppNodeRuntimeManifest,
|
|
3
|
+
type NodeRuntimeManifest,
|
|
4
|
+
} from '../../services/runtime-manifest/node-runtime-manifest.service.ts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Writes the app-owned Node runtime manifest from a bundled manifest-writer
|
|
8
|
+
* entrypoint.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* The Node thin-host launch plan executes a bundled JavaScript prep artifact
|
|
12
|
+
* instead of evaluating TypeScript config directly in the launcher. This helper
|
|
13
|
+
* is the narrow bridge between that bundle and the core-owned manifest writer.
|
|
14
|
+
*/
|
|
15
|
+
export function writeBundledNodeRuntimeManifest(
|
|
16
|
+
appConfig: {
|
|
17
|
+
rootDir: string;
|
|
18
|
+
absolutePaths: {
|
|
19
|
+
config: string;
|
|
20
|
+
srcDir: string;
|
|
21
|
+
distDir: string;
|
|
22
|
+
workDir?: string;
|
|
23
|
+
};
|
|
24
|
+
loaders: Map<string, unknown>;
|
|
25
|
+
runtime?: {
|
|
26
|
+
nodeRuntimeManifest?: NodeRuntimeManifest;
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
options: {
|
|
30
|
+
entryModulePath: string;
|
|
31
|
+
manifestFilePath: string;
|
|
32
|
+
},
|
|
33
|
+
): void {
|
|
34
|
+
writeAppNodeRuntimeManifest(appConfig as never, {
|
|
35
|
+
entryModulePath: options.entryModulePath,
|
|
36
|
+
manifestFilePath: options.manifestFilePath,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { ApiResponseBuilder } from './api-response';
|
|
3
|
+
|
|
4
|
+
describe('ApiResponseBuilder', () => {
|
|
5
|
+
let builder: ApiResponseBuilder;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
builder = new ApiResponseBuilder();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('json()', () => {
|
|
12
|
+
it('should create JSON response with correct content type and data', async () => {
|
|
13
|
+
const data = { foo: 'bar' };
|
|
14
|
+
const response = builder.json(data);
|
|
15
|
+
|
|
16
|
+
expect(response.headers.get('Content-Type')).toBe('application/json; charset=utf-8');
|
|
17
|
+
expect(await response.json()).toEqual(data);
|
|
18
|
+
expect(response.status).toBe(200);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('text()', () => {
|
|
23
|
+
it('should create text response with correct content type and data', async () => {
|
|
24
|
+
const text = 'Hello World';
|
|
25
|
+
const response = builder.text(text);
|
|
26
|
+
|
|
27
|
+
expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8');
|
|
28
|
+
expect(await response.text()).toBe(text);
|
|
29
|
+
expect(response.status).toBe(200);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('html()', () => {
|
|
34
|
+
it('should create HTML response with correct content type and data', async () => {
|
|
35
|
+
const html = '<h1>Hello</h1>';
|
|
36
|
+
const response = builder.html(html);
|
|
37
|
+
|
|
38
|
+
expect(response.headers.get('Content-Type')).toBe('text/html; charset=utf-8');
|
|
39
|
+
expect(await response.text()).toBe(html);
|
|
40
|
+
expect(response.status).toBe(200);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('status()', () => {
|
|
45
|
+
it('should set custom status code', () => {
|
|
46
|
+
const response = builder.status(404).json({ message: 'Not Found' });
|
|
47
|
+
expect(response.status).toBe(404);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('headers()', () => {
|
|
52
|
+
it('should set custom headers', () => {
|
|
53
|
+
const response = builder.headers({ 'X-Custom': 'Value' }).json({});
|
|
54
|
+
expect(response.headers.get('X-Custom')).toBe('Value');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('redirect()', () => {
|
|
59
|
+
it('should create redirect response with location header', () => {
|
|
60
|
+
const url = 'https://example.com';
|
|
61
|
+
const response = builder.redirect(url);
|
|
62
|
+
|
|
63
|
+
expect(response.headers.get('Location')).toBe(url);
|
|
64
|
+
expect(response.status).toBe(302);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should use explicit status for redirect', () => {
|
|
68
|
+
const response = builder.redirect('https://example.com', 301);
|
|
69
|
+
expect(response.status).toBe(301);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('error()', () => {
|
|
74
|
+
it('should create JSON error response for object data', async () => {
|
|
75
|
+
const error = { code: 'ERR_1', message: 'Error occurred' };
|
|
76
|
+
const response = builder.error(error);
|
|
77
|
+
|
|
78
|
+
expect(response.headers.get('Content-Type')).toBe('application/json; charset=utf-8');
|
|
79
|
+
expect(await response.json()).toEqual({ error });
|
|
80
|
+
expect(response.status).toBe(500);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should create text error response for string data', async () => {
|
|
84
|
+
const error = 'Error occurred';
|
|
85
|
+
const response = builder.error(error);
|
|
86
|
+
|
|
87
|
+
expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8');
|
|
88
|
+
expect(await response.text()).toBe(error);
|
|
89
|
+
expect(response.status).toBe(500);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should use explicit status for error', () => {
|
|
93
|
+
const response = builder.error('Not Found', 404);
|
|
94
|
+
expect(response.status).toBe(404);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import type { EcoPageComponent, StaticRoute, ViewLoader } from '../../public-types.ts';
|
|
3
|
+
import { ExplicitStaticRouteMatcher } from './explicit-static-route-matcher.ts';
|
|
4
|
+
|
|
5
|
+
function createMockView(integration = 'ghtml'): EcoPageComponent<any> {
|
|
6
|
+
const view = (() => '<div>Test</div>') as EcoPageComponent<any>;
|
|
7
|
+
view.config = {
|
|
8
|
+
integration,
|
|
9
|
+
__eco: { id: 'test', file: '/test/-view.ts', integration },
|
|
10
|
+
};
|
|
11
|
+
return view;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function createMockLoader(view?: EcoPageComponent<any>): ViewLoader<any> {
|
|
15
|
+
const actualView = view ?? createMockView();
|
|
16
|
+
return () => Promise.resolve({ default: actualView });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createMockRoute(path: string, view?: EcoPageComponent<any>): StaticRoute {
|
|
20
|
+
return {
|
|
21
|
+
path,
|
|
22
|
+
loader: createMockLoader(view),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createMatcher(staticRoutes: StaticRoute[]) {
|
|
27
|
+
return new ExplicitStaticRouteMatcher({
|
|
28
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
29
|
+
routeRendererFactory: {} as any,
|
|
30
|
+
staticRoutes,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('ExplicitStaticRouteMatcher', () => {
|
|
35
|
+
describe('match', () => {
|
|
36
|
+
test('should match exact static path', () => {
|
|
37
|
+
const matcher = createMatcher([createMockRoute('/about')]);
|
|
38
|
+
|
|
39
|
+
const result = matcher.match('http://localhost:3000/about');
|
|
40
|
+
|
|
41
|
+
expect(result).not.toBeNull();
|
|
42
|
+
expect(result?.route.path).toBe('/about');
|
|
43
|
+
expect(result?.params).toEqual({});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('should match root path', () => {
|
|
47
|
+
const matcher = createMatcher([createMockRoute('/')]);
|
|
48
|
+
|
|
49
|
+
const result = matcher.match('http://localhost:3000/');
|
|
50
|
+
|
|
51
|
+
expect(result).not.toBeNull();
|
|
52
|
+
expect(result?.route.path).toBe('/');
|
|
53
|
+
expect(result?.params).toEqual({});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should match nested static path', () => {
|
|
57
|
+
const matcher = createMatcher([createMockRoute('/docs/getting-started')]);
|
|
58
|
+
|
|
59
|
+
const result = matcher.match('http://localhost:3000/docs/getting-started');
|
|
60
|
+
|
|
61
|
+
expect(result).not.toBeNull();
|
|
62
|
+
expect(result?.route.path).toBe('/docs/getting-started');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should return null for non-matching path', () => {
|
|
66
|
+
const matcher = createMatcher([createMockRoute('/about')]);
|
|
67
|
+
|
|
68
|
+
const result = matcher.match('http://localhost:3000/contact');
|
|
69
|
+
|
|
70
|
+
expect(result).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should return null for partial match', () => {
|
|
74
|
+
const matcher = createMatcher([createMockRoute('/about')]);
|
|
75
|
+
|
|
76
|
+
const result = matcher.match('http://localhost:3000/about/team');
|
|
77
|
+
|
|
78
|
+
expect(result).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('match with :param syntax', () => {
|
|
83
|
+
test('should match dynamic segment with colon syntax', () => {
|
|
84
|
+
const matcher = createMatcher([createMockRoute('/blog/:slug')]);
|
|
85
|
+
|
|
86
|
+
const result = matcher.match('http://localhost:3000/blog/hello-world');
|
|
87
|
+
|
|
88
|
+
expect(result).not.toBeNull();
|
|
89
|
+
expect(result?.params).toEqual({ slug: 'hello-world' });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('should match multiple dynamic segments', () => {
|
|
93
|
+
const matcher = createMatcher([createMockRoute('/blog/:year/:month/:slug')]);
|
|
94
|
+
|
|
95
|
+
const result = matcher.match('http://localhost:3000/blog/2024/01/hello-world');
|
|
96
|
+
|
|
97
|
+
expect(result).not.toBeNull();
|
|
98
|
+
expect(result?.params).toEqual({
|
|
99
|
+
year: '2024',
|
|
100
|
+
month: '01',
|
|
101
|
+
slug: 'hello-world',
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should match mixed static and dynamic segments', () => {
|
|
106
|
+
const matcher = createMatcher([createMockRoute('/users/:id/posts')]);
|
|
107
|
+
|
|
108
|
+
const result = matcher.match('http://localhost:3000/users/123/posts');
|
|
109
|
+
|
|
110
|
+
expect(result).not.toBeNull();
|
|
111
|
+
expect(result?.params).toEqual({ id: '123' });
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('match with [param] syntax', () => {
|
|
116
|
+
test('should match dynamic segment with bracket syntax', () => {
|
|
117
|
+
const matcher = createMatcher([createMockRoute('/blog/[slug]')]);
|
|
118
|
+
|
|
119
|
+
const result = matcher.match('http://localhost:3000/blog/hello-world');
|
|
120
|
+
|
|
121
|
+
expect(result).not.toBeNull();
|
|
122
|
+
expect(result?.params).toEqual({ slug: 'hello-world' });
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('should match multiple bracket parameters', () => {
|
|
126
|
+
const matcher = createMatcher([createMockRoute('/products/[category]/[id]')]);
|
|
127
|
+
|
|
128
|
+
const result = matcher.match('http://localhost:3000/products/electronics/12345');
|
|
129
|
+
|
|
130
|
+
expect(result).not.toBeNull();
|
|
131
|
+
expect(result?.params).toEqual({
|
|
132
|
+
category: 'electronics',
|
|
133
|
+
id: '12345',
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('match with catch-all routes', () => {
|
|
139
|
+
test('should match catch-all with bracket syntax', () => {
|
|
140
|
+
const matcher = createMatcher([createMockRoute('/docs/[...path]')]);
|
|
141
|
+
|
|
142
|
+
const result = matcher.match('http://localhost:3000/docs/api/reference/components');
|
|
143
|
+
|
|
144
|
+
expect(result).not.toBeNull();
|
|
145
|
+
expect(result?.params).toEqual({ path: 'api/reference/components' });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('should match catch-all with colon syntax', () => {
|
|
149
|
+
const matcher = createMatcher([createMockRoute('/files/:...path')]);
|
|
150
|
+
|
|
151
|
+
const result = matcher.match('http://localhost:3000/files/images/2024/photo.jpg');
|
|
152
|
+
|
|
153
|
+
expect(result).not.toBeNull();
|
|
154
|
+
expect(result?.params).toEqual({ path: 'images/2024/photo.jpg' });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('should match catch-all with single segment', () => {
|
|
158
|
+
const matcher = createMatcher([createMockRoute('/docs/[...path]')]);
|
|
159
|
+
|
|
160
|
+
const result = matcher.match('http://localhost:3000/docs/intro');
|
|
161
|
+
|
|
162
|
+
expect(result).not.toBeNull();
|
|
163
|
+
expect(result?.params).toEqual({ path: 'intro' });
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('route priority', () => {
|
|
168
|
+
test('should match first route when multiple routes match', () => {
|
|
169
|
+
const aboutView = createMockView();
|
|
170
|
+
const catchAllView = createMockView();
|
|
171
|
+
|
|
172
|
+
const matcher = createMatcher([
|
|
173
|
+
createMockRoute('/about', aboutView),
|
|
174
|
+
createMockRoute('/[...path]', catchAllView),
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
const result = matcher.match('http://localhost:3000/about');
|
|
178
|
+
|
|
179
|
+
expect(result).not.toBeNull();
|
|
180
|
+
expect(result?.route.path).toBe('/about');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('should match exact route before dynamic route', () => {
|
|
184
|
+
const exactView = createMockView();
|
|
185
|
+
const dynamicView = createMockView();
|
|
186
|
+
|
|
187
|
+
const matcher = createMatcher([
|
|
188
|
+
createMockRoute('/blog/featured', exactView),
|
|
189
|
+
createMockRoute('/blog/:slug', dynamicView),
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
const result = matcher.match('http://localhost:3000/blog/featured');
|
|
193
|
+
|
|
194
|
+
expect(result).not.toBeNull();
|
|
195
|
+
expect(result?.route.path).toBe('/blog/featured');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('edge cases', () => {
|
|
200
|
+
test('should handle URL with query parameters', () => {
|
|
201
|
+
const matcher = createMatcher([createMockRoute('/search')]);
|
|
202
|
+
|
|
203
|
+
const result = matcher.match('http://localhost:3000/search?q=test&page=1');
|
|
204
|
+
|
|
205
|
+
expect(result).not.toBeNull();
|
|
206
|
+
expect(result?.route.path).toBe('/search');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('should handle URL with hash', () => {
|
|
210
|
+
const matcher = createMatcher([createMockRoute('/docs/intro')]);
|
|
211
|
+
|
|
212
|
+
const result = matcher.match('http://localhost:3000/docs/intro#section-1');
|
|
213
|
+
|
|
214
|
+
expect(result).not.toBeNull();
|
|
215
|
+
expect(result?.route.path).toBe('/docs/intro');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('should handle trailing slash', () => {
|
|
219
|
+
const matcher = createMatcher([createMockRoute('/about')]);
|
|
220
|
+
|
|
221
|
+
const result = matcher.match('http://localhost:3000/about/');
|
|
222
|
+
|
|
223
|
+
expect(result).not.toBeNull();
|
|
224
|
+
expect(result?.route.path).toBe('/about');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('should return null for empty routes array', () => {
|
|
228
|
+
const matcher = createMatcher([]);
|
|
229
|
+
|
|
230
|
+
const result = matcher.match('http://localhost:3000/anything');
|
|
231
|
+
|
|
232
|
+
expect(result).toBeNull();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('handleMatch', () => {
|
|
237
|
+
test('should accept integration metadata from view.config.integration', async () => {
|
|
238
|
+
const view = (() => '<div>Test</div>') as EcoPageComponent<any>;
|
|
239
|
+
view.config = {
|
|
240
|
+
integration: 'ghtml',
|
|
241
|
+
__eco: { id: 'test', file: '/test/-view.ts', integration: 'ghtml' },
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const mockResponse = new Response('<html>Test</html>');
|
|
245
|
+
const renderToResponse = vi.fn(() => mockResponse);
|
|
246
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
247
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
248
|
+
routeRendererFactory: {
|
|
249
|
+
getRendererByIntegration: vi.fn(() => ({
|
|
250
|
+
renderToResponse,
|
|
251
|
+
})),
|
|
252
|
+
} as any,
|
|
253
|
+
staticRoutes: [createMockRoute('/about', view)],
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const match = matcher.match('http://localhost:3000/about');
|
|
257
|
+
const response = await matcher.handleMatch(match!);
|
|
258
|
+
|
|
259
|
+
expect(response).toBe(mockResponse);
|
|
260
|
+
expect(renderToResponse).toHaveBeenCalledWith(view, {}, {});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('should throw error when view is missing __eco.integration', async () => {
|
|
264
|
+
const viewWithoutIntegration = (() => '<div>Test</div>') as EcoPageComponent<any>;
|
|
265
|
+
viewWithoutIntegration.config = {
|
|
266
|
+
__eco: undefined,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
270
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
271
|
+
routeRendererFactory: {
|
|
272
|
+
getRendererByIntegration: vi.fn(() => null),
|
|
273
|
+
} as any,
|
|
274
|
+
staticRoutes: [createMockRoute('/about', viewWithoutIntegration)],
|
|
275
|
+
});
|
|
276
|
+
const match = matcher.match('http://localhost:3000/about');
|
|
277
|
+
|
|
278
|
+
expect(match).not.toBeNull();
|
|
279
|
+
await expect(matcher.handleMatch(match!)).rejects.toThrow('missing __eco.integration');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('should throw error when renderer is not found', async () => {
|
|
283
|
+
const view = createMockView('nonexistent-integration');
|
|
284
|
+
const RendererFactory = {
|
|
285
|
+
getRendererByIntegration: vi.fn(() => null),
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
289
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
290
|
+
routeRendererFactory: RendererFactory as any,
|
|
291
|
+
staticRoutes: [createMockRoute('/about', view)],
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const match = matcher.match('http://localhost:3000/about');
|
|
295
|
+
|
|
296
|
+
await expect(matcher.handleMatch(match!)).rejects.toThrow(
|
|
297
|
+
'No renderer found for integration: nonexistent-integration',
|
|
298
|
+
);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('should call renderer.renderToResponse with correct arguments', async () => {
|
|
302
|
+
const view = createMockView('ghtml');
|
|
303
|
+
const mockResponse = new Response('<html>Test</html>');
|
|
304
|
+
const RenderToResponse = vi.fn(() => mockResponse);
|
|
305
|
+
const RendererFactory = {
|
|
306
|
+
getRendererByIntegration: vi.fn(() => ({
|
|
307
|
+
renderToResponse: RenderToResponse,
|
|
308
|
+
})),
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
312
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
313
|
+
routeRendererFactory: RendererFactory as any,
|
|
314
|
+
staticRoutes: [createMockRoute('/about', view)],
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const match = matcher.match('http://localhost:3000/about');
|
|
318
|
+
const response = await matcher.handleMatch(match!);
|
|
319
|
+
|
|
320
|
+
expect(response).toBe(mockResponse);
|
|
321
|
+
expect(RenderToResponse).toHaveBeenCalledTimes(1);
|
|
322
|
+
expect(RenderToResponse).toHaveBeenCalledWith(view, {}, {});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test('should resolve staticProps and pass to renderer', async () => {
|
|
326
|
+
const view = createMockView('ghtml');
|
|
327
|
+
view.staticProps = vi.fn(async () => ({
|
|
328
|
+
props: { title: 'About Page', content: 'Hello' },
|
|
329
|
+
}));
|
|
330
|
+
|
|
331
|
+
const mockResponse = new Response('<html>Test</html>');
|
|
332
|
+
const RenderToResponse = vi.fn(() => mockResponse);
|
|
333
|
+
const RendererFactory = {
|
|
334
|
+
getRendererByIntegration: vi.fn(() => ({
|
|
335
|
+
renderToResponse: RenderToResponse,
|
|
336
|
+
})),
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
340
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
341
|
+
routeRendererFactory: RendererFactory as any,
|
|
342
|
+
staticRoutes: [createMockRoute('/about', view)],
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const match = matcher.match('http://localhost:3000/about');
|
|
346
|
+
await matcher.handleMatch(match!);
|
|
347
|
+
|
|
348
|
+
expect(view.staticProps).toHaveBeenCalledTimes(1);
|
|
349
|
+
expect(RenderToResponse).toHaveBeenCalledWith(view, { title: 'About Page', content: 'Hello' }, {});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test('should pass params to staticProps', async () => {
|
|
353
|
+
const view = createMockView('ghtml');
|
|
354
|
+
view.staticProps = vi.fn(async ({ pathname }) => ({
|
|
355
|
+
props: { slug: pathname.params.slug },
|
|
356
|
+
}));
|
|
357
|
+
|
|
358
|
+
const mockResponse = new Response('<html>Test</html>');
|
|
359
|
+
const RendererFactory = {
|
|
360
|
+
getRendererByIntegration: vi.fn(() => ({
|
|
361
|
+
renderToResponse: vi.fn(() => mockResponse),
|
|
362
|
+
})),
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
const matcher = new ExplicitStaticRouteMatcher({
|
|
366
|
+
appConfig: { baseUrl: 'http://localhost:3000' } as any,
|
|
367
|
+
routeRendererFactory: RendererFactory as any,
|
|
368
|
+
staticRoutes: [createMockRoute('/blog/:slug', view)],
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const match = matcher.match('http://localhost:3000/blog/hello-world');
|
|
372
|
+
await matcher.handleMatch(match!);
|
|
373
|
+
|
|
374
|
+
expect(view.staticProps).toHaveBeenCalledWith(
|
|
375
|
+
expect.objectContaining({
|
|
376
|
+
pathname: { params: { slug: 'hello-world' } },
|
|
377
|
+
}),
|
|
378
|
+
);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
@@ -9,6 +9,12 @@ export const EXPLICIT_STATIC_ROUTE_MATCHER_ERRORS = {
|
|
|
9
9
|
noRendererForIntegration: (integrationName: string) => `No renderer found for integration: ${integrationName}`,
|
|
10
10
|
} as const;
|
|
11
11
|
|
|
12
|
+
function getViewIntegrationName(view: {
|
|
13
|
+
config?: { integration?: string; __eco?: { integration?: string } };
|
|
14
|
+
}): string | undefined {
|
|
15
|
+
return view.config?.integration ?? view.config?.__eco?.integration;
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
export interface ExplicitStaticRouteMatcherOptions {
|
|
13
19
|
appConfig: EcoPagesAppConfig;
|
|
14
20
|
routeRendererFactory: RouteRendererFactory;
|
|
@@ -102,7 +108,7 @@ export class ExplicitStaticRouteMatcher {
|
|
|
102
108
|
const mod = await route.loader();
|
|
103
109
|
const view = mod.default;
|
|
104
110
|
|
|
105
|
-
const integrationName = view
|
|
111
|
+
const integrationName = getViewIntegrationName(view);
|
|
106
112
|
if (!integrationName) {
|
|
107
113
|
throw new Error(EXPLICIT_STATIC_ROUTE_MATCHER_ERRORS.missingIntegration(route.path));
|
|
108
114
|
}
|