@fougere/core 0.2.0-alpha.2 → 0.4.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/boot/AppLifecycle.d.ts +18 -0
- package/dist/boot/AppLifecycle.d.ts.map +1 -0
- package/dist/boot/AppLifecycle.js +42 -0
- package/dist/boot/AppLifecycle.js.map +1 -0
- package/dist/boot/Emissions.d.ts +126 -0
- package/dist/boot/Emissions.d.ts.map +1 -0
- package/dist/boot/Emissions.js +233 -0
- package/dist/boot/Emissions.js.map +1 -0
- package/dist/boot/HandlerFacade.d.ts +72 -0
- package/dist/boot/HandlerFacade.d.ts.map +1 -0
- package/dist/boot/HandlerFacade.js +174 -0
- package/dist/boot/HandlerFacade.js.map +1 -0
- package/dist/boot/Lifecycle.d.ts +4 -0
- package/dist/boot/Lifecycle.d.ts.map +1 -0
- package/dist/boot/Lifecycle.js +3 -0
- package/dist/boot/Lifecycle.js.map +1 -0
- package/dist/boot/ambient-port.d.ts +38 -0
- package/dist/boot/ambient-port.d.ts.map +1 -0
- package/dist/boot/ambient-port.js +2 -0
- package/dist/boot/ambient-port.js.map +1 -0
- package/dist/boot/ambient.als.d.ts +3 -0
- package/dist/boot/ambient.als.d.ts.map +1 -0
- package/dist/boot/ambient.als.js +34 -0
- package/dist/boot/ambient.als.js.map +1 -0
- package/dist/boot/ambient.queue.d.ts +10 -0
- package/dist/boot/ambient.queue.d.ts.map +1 -0
- package/dist/boot/ambient.queue.js +60 -0
- package/dist/boot/ambient.queue.js.map +1 -0
- package/dist/boot/apply.d.ts +22 -0
- package/dist/boot/apply.d.ts.map +1 -0
- package/dist/boot/apply.js +38 -0
- package/dist/boot/apply.js.map +1 -0
- package/dist/boot/auth.d.ts +53 -0
- package/dist/boot/auth.d.ts.map +1 -0
- package/dist/boot/auth.js +2 -0
- package/dist/boot/auth.js.map +1 -0
- package/dist/{binding.d.ts → boot/binding.d.ts} +14 -17
- package/dist/boot/binding.d.ts.map +1 -0
- package/dist/{binding.js → boot/binding.js} +19 -10
- package/dist/boot/binding.js.map +1 -0
- package/dist/{boot.d.ts → boot/boot.d.ts} +25 -5
- package/dist/boot/boot.d.ts.map +1 -0
- package/dist/boot/boot.js +70 -0
- package/dist/boot/boot.js.map +1 -0
- package/dist/boot/bootstrap.d.ts.map +1 -0
- package/dist/boot/bootstrap.js +722 -0
- package/dist/boot/bootstrap.js.map +1 -0
- package/dist/boot/frame.d.ts +44 -0
- package/dist/boot/frame.d.ts.map +1 -0
- package/dist/boot/frame.js +172 -0
- package/dist/boot/frame.js.map +1 -0
- package/dist/boot/ownership.d.ts +42 -0
- package/dist/boot/ownership.d.ts.map +1 -0
- package/dist/boot/ownership.js +127 -0
- package/dist/boot/ownership.js.map +1 -0
- package/dist/boot/ports.d.ts +17 -0
- package/dist/boot/ports.d.ts.map +1 -0
- package/dist/boot/ports.js +57 -0
- package/dist/boot/ports.js.map +1 -0
- package/dist/{remote.d.ts → boot/remote.d.ts} +11 -3
- package/dist/boot/remote.d.ts.map +1 -0
- package/dist/{remote.js → boot/remote.js} +26 -28
- package/dist/boot/remote.js.map +1 -0
- package/dist/{seed.d.ts → boot/seed.d.ts} +13 -1
- package/dist/boot/seed.d.ts.map +1 -0
- package/dist/{seed.js → boot/seed.js} +24 -3
- package/dist/boot/seed.js.map +1 -0
- package/dist/boot/together.d.ts +26 -0
- package/dist/boot/together.d.ts.map +1 -0
- package/dist/boot/together.js +163 -0
- package/dist/boot/together.js.map +1 -0
- package/dist/boot/types.d.ts +260 -0
- package/dist/boot/types.d.ts.map +1 -0
- package/dist/boot/types.js.map +1 -0
- package/dist/builtins/config.d.ts +9 -0
- package/dist/builtins/config.d.ts.map +1 -1
- package/dist/builtins/config.js +16 -1
- package/dist/builtins/config.js.map +1 -1
- package/dist/builtins/logger.d.ts +37 -4
- package/dist/builtins/logger.d.ts.map +1 -1
- package/dist/builtins/logger.js +66 -7
- package/dist/builtins/logger.js.map +1 -1
- package/dist/config-loader.d.ts +39 -35
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +15 -54
- package/dist/config-loader.js.map +1 -1
- package/dist/contract/Call.d.ts +10 -0
- package/dist/contract/Call.d.ts.map +1 -0
- package/dist/contract/Call.js +15 -0
- package/dist/contract/Call.js.map +1 -0
- package/dist/contract/Invocation.d.ts +27 -0
- package/dist/contract/Invocation.d.ts.map +1 -0
- package/dist/contract/Invocation.js +59 -0
- package/dist/contract/Invocation.js.map +1 -0
- package/dist/contract/RouteAddress.d.ts +17 -0
- package/dist/contract/RouteAddress.d.ts.map +1 -0
- package/dist/contract/RouteAddress.js +38 -0
- package/dist/contract/RouteAddress.js.map +1 -0
- package/dist/contract.d.ts +25 -19
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +25 -10
- package/dist/contract.js.map +1 -1
- package/dist/crypto/encoding.d.ts +25 -0
- package/dist/crypto/encoding.d.ts.map +1 -0
- package/dist/crypto/encoding.js +58 -0
- package/dist/crypto/encoding.js.map +1 -0
- package/dist/crypto/node.d.ts +4 -0
- package/dist/crypto/node.d.ts.map +1 -0
- package/dist/crypto/node.js +25 -0
- package/dist/crypto/node.js.map +1 -0
- package/dist/crypto/port.d.ts +42 -0
- package/dist/crypto/port.d.ts.map +1 -0
- package/dist/crypto/port.js +19 -0
- package/dist/crypto/port.js.map +1 -0
- package/dist/crypto/webcrypto.d.ts +4 -0
- package/dist/crypto/webcrypto.d.ts.map +1 -0
- package/dist/crypto/webcrypto.js +34 -0
- package/dist/crypto/webcrypto.js.map +1 -0
- package/dist/dispatch/ArgumentResolver.d.ts +10 -0
- package/dist/dispatch/ArgumentResolver.d.ts.map +1 -0
- package/dist/dispatch/ArgumentResolver.js +12 -0
- package/dist/dispatch/ArgumentResolver.js.map +1 -0
- package/dist/dispatch/ArrayResult.d.ts +3 -0
- package/dist/dispatch/ArrayResult.d.ts.map +1 -0
- package/dist/dispatch/ArrayResult.js +11 -0
- package/dist/dispatch/ArrayResult.js.map +1 -0
- package/dist/dispatch/DispatchEvent.d.ts +18 -0
- package/dist/dispatch/DispatchEvent.d.ts.map +1 -0
- package/dist/dispatch/DispatchEvent.js +30 -0
- package/dist/dispatch/DispatchEvent.js.map +1 -0
- package/dist/dispatch/DispatchLifecycle.d.ts +9 -0
- package/dist/dispatch/DispatchLifecycle.d.ts.map +1 -0
- package/dist/dispatch/DispatchLifecycle.js +25 -0
- package/dist/dispatch/DispatchLifecycle.js.map +1 -0
- package/dist/dispatch/DispatchPort.d.ts +6 -0
- package/dist/dispatch/DispatchPort.d.ts.map +1 -0
- package/dist/dispatch/DispatchPort.js +2 -0
- package/dist/dispatch/DispatchPort.js.map +1 -0
- package/dist/dispatch/Dispatcher.d.ts +16 -0
- package/dist/dispatch/Dispatcher.d.ts.map +1 -0
- package/dist/dispatch/Dispatcher.js +44 -0
- package/dist/dispatch/Dispatcher.js.map +1 -0
- package/dist/dispatch/InFlight.d.ts +12 -0
- package/dist/dispatch/InFlight.d.ts.map +1 -0
- package/dist/dispatch/InFlight.js +46 -0
- package/dist/dispatch/InFlight.js.map +1 -0
- package/dist/dispatch/InputValidator.d.ts +7 -0
- package/dist/dispatch/InputValidator.d.ts.map +1 -0
- package/dist/dispatch/InputValidator.js +22 -0
- package/dist/dispatch/InputValidator.js.map +1 -0
- package/dist/dispatch/LocalRoutePolicy.d.ts +11 -0
- package/dist/dispatch/LocalRoutePolicy.d.ts.map +1 -0
- package/dist/dispatch/LocalRoutePolicy.js +32 -0
- package/dist/dispatch/LocalRoutePolicy.js.map +1 -0
- package/dist/dispatch/OperationExecutor.d.ts +25 -0
- package/dist/dispatch/OperationExecutor.d.ts.map +1 -0
- package/dist/dispatch/OperationExecutor.js +32 -0
- package/dist/dispatch/OperationExecutor.js.map +1 -0
- package/dist/dispatch/OperationRoute.d.ts +13 -0
- package/dist/dispatch/OperationRoute.d.ts.map +1 -0
- package/dist/dispatch/OperationRoute.js +15 -0
- package/dist/dispatch/OperationRoute.js.map +1 -0
- package/dist/dispatch/OutputProjector.d.ts +12 -0
- package/dist/dispatch/OutputProjector.d.ts.map +1 -0
- package/dist/dispatch/OutputProjector.js +30 -0
- package/dist/dispatch/OutputProjector.js.map +1 -0
- package/dist/dispatch/OutputView.d.ts +8 -0
- package/dist/dispatch/OutputView.d.ts.map +1 -0
- package/dist/dispatch/OutputView.js +10 -0
- package/dist/dispatch/OutputView.js.map +1 -0
- package/dist/dispatch/PresenterArgumentResolver.d.ts +12 -0
- package/dist/dispatch/PresenterArgumentResolver.d.ts.map +1 -0
- package/dist/dispatch/PresenterArgumentResolver.js +20 -0
- package/dist/dispatch/PresenterArgumentResolver.js.map +1 -0
- package/dist/dispatch/PresenterExecutor.d.ts +11 -0
- package/dist/dispatch/PresenterExecutor.d.ts.map +1 -0
- package/dist/dispatch/PresenterExecutor.js +56 -0
- package/dist/dispatch/PresenterExecutor.js.map +1 -0
- package/dist/dispatch/RemoteRouteResolver.d.ts +13 -0
- package/dist/dispatch/RemoteRouteResolver.d.ts.map +1 -0
- package/dist/dispatch/RemoteRouteResolver.js +18 -0
- package/dist/dispatch/RemoteRouteResolver.js.map +1 -0
- package/dist/dispatch/Route.d.ts +10 -0
- package/dist/dispatch/Route.d.ts.map +1 -0
- package/dist/dispatch/Route.js +2 -0
- package/dist/dispatch/Route.js.map +1 -0
- package/dist/dispatch/RouteNotFoundError.d.ts +10 -0
- package/dist/dispatch/RouteNotFoundError.d.ts.map +1 -0
- package/dist/dispatch/RouteNotFoundError.js +24 -0
- package/dist/dispatch/RouteNotFoundError.js.map +1 -0
- package/dist/dispatch/RoutePolicy.d.ts +8 -0
- package/dist/dispatch/RoutePolicy.d.ts.map +1 -0
- package/dist/dispatch/RoutePolicy.js +2 -0
- package/dist/dispatch/RoutePolicy.js.map +1 -0
- package/dist/dispatch/RouteRegistry.d.ts +18 -0
- package/dist/dispatch/RouteRegistry.d.ts.map +1 -0
- package/dist/dispatch/RouteRegistry.js +62 -0
- package/dist/dispatch/RouteRegistry.js.map +1 -0
- package/dist/dispatch/RouteResolver.d.ts +7 -0
- package/dist/dispatch/RouteResolver.d.ts.map +1 -0
- package/dist/dispatch/RouteResolver.js +2 -0
- package/dist/dispatch/RouteResolver.js.map +1 -0
- package/dist/dispatch/StorageGuard.d.ts +15 -0
- package/dist/dispatch/StorageGuard.d.ts.map +1 -0
- package/dist/dispatch/StorageGuard.js +63 -0
- package/dist/dispatch/StorageGuard.js.map +1 -0
- package/dist/effective-operation.d.ts +90 -0
- package/dist/effective-operation.d.ts.map +1 -0
- package/dist/effective-operation.js +449 -0
- package/dist/effective-operation.js.map +1 -0
- package/dist/emit.d.ts +2 -2
- package/dist/emit.d.ts.map +1 -1
- package/dist/emit.js +2 -2
- package/dist/emit.js.map +1 -1
- package/dist/entry/DynamicFacade.d.ts +10 -0
- package/dist/entry/DynamicFacade.d.ts.map +1 -0
- package/dist/entry/DynamicFacade.js +27 -0
- package/dist/entry/DynamicFacade.js.map +1 -0
- package/dist/entry/FacadeEntry.d.ts +11 -0
- package/dist/entry/FacadeEntry.d.ts.map +1 -0
- package/dist/entry/FacadeEntry.js +26 -0
- package/dist/entry/FacadeEntry.js.map +1 -0
- package/dist/entry/TransportEntry.d.ts +13 -0
- package/dist/entry/TransportEntry.d.ts.map +1 -0
- package/dist/entry/TransportEntry.js +24 -0
- package/dist/entry/TransportEntry.js.map +1 -0
- package/dist/frond-config.d.ts +24 -7
- package/dist/frond-config.d.ts.map +1 -1
- package/dist/frond-config.js.map +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +3 -2
- package/dist/graph.js.map +1 -1
- package/dist/identity-keys.d.ts +14 -0
- package/dist/identity-keys.d.ts.map +1 -0
- package/dist/identity-keys.js +37 -0
- package/dist/identity-keys.js.map +1 -0
- package/dist/identity.d.ts +58 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +182 -0
- package/dist/identity.js.map +1 -0
- package/dist/imports.d.ts +2 -2
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +7 -3
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +57 -38
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -32
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +16 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +25 -0
- package/dist/loader.js.map +1 -0
- package/dist/node.d.ts +21 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +24 -0
- package/dist/node.js.map +1 -0
- package/dist/orm.d.ts +69 -8
- package/dist/orm.d.ts.map +1 -1
- package/dist/orm.js +35 -2
- package/dist/orm.js.map +1 -1
- package/dist/prefab/collector.d.ts +29 -0
- package/dist/prefab/collector.d.ts.map +1 -0
- package/dist/prefab/collector.js +34 -0
- package/dist/prefab/collector.js.map +1 -0
- package/dist/{crud.d.ts → prefab/crud.d.ts} +7 -8
- package/dist/prefab/crud.d.ts.map +1 -0
- package/dist/{crud.js → prefab/crud.js} +39 -5
- package/dist/prefab/crud.js.map +1 -0
- package/dist/prefab/mirror.d.ts +52 -0
- package/dist/prefab/mirror.d.ts.map +1 -0
- package/dist/prefab/mirror.js +66 -0
- package/dist/prefab/mirror.js.map +1 -0
- package/dist/prefab/prefab.d.ts +15 -0
- package/dist/prefab/prefab.d.ts.map +1 -0
- package/dist/prefab/prefab.js +19 -0
- package/dist/prefab/prefab.js.map +1 -0
- package/dist/{presenter.d.ts → prefab/presenter.d.ts} +6 -17
- package/dist/prefab/presenter.d.ts.map +1 -0
- package/dist/{presenter.js → prefab/presenter.js} +5 -23
- package/dist/prefab/presenter.js.map +1 -0
- package/dist/prefab/repository.d.ts +104 -0
- package/dist/prefab/repository.d.ts.map +1 -0
- package/dist/prefab/repository.js +62 -0
- package/dist/prefab/repository.js.map +1 -0
- package/dist/scan/Fronds.d.ts +45 -0
- package/dist/scan/Fronds.d.ts.map +1 -0
- package/dist/scan/Fronds.js +66 -0
- package/dist/scan/Fronds.js.map +1 -0
- package/dist/scan/conventions.d.ts +74 -0
- package/dist/scan/conventions.d.ts.map +1 -0
- package/dist/scan/conventions.js +82 -0
- package/dist/scan/conventions.js.map +1 -0
- package/dist/scan/emit.d.ts +14 -0
- package/dist/scan/emit.d.ts.map +1 -0
- package/dist/scan/emit.js +212 -0
- package/dist/scan/emit.js.map +1 -0
- package/dist/scan/frond.d.ts +224 -0
- package/dist/scan/frond.d.ts.map +1 -0
- package/dist/scan/frond.js +2 -0
- package/dist/scan/frond.js.map +1 -0
- package/dist/{handler-parser.d.ts → scan/handler-parser.d.ts} +20 -9
- package/dist/scan/handler-parser.d.ts.map +1 -0
- package/dist/scan/handler-parser.js +665 -0
- package/dist/scan/handler-parser.js.map +1 -0
- package/dist/scan/scan-cache.d.ts +16 -0
- package/dist/scan/scan-cache.d.ts.map +1 -0
- package/dist/{scan-cache.js → scan/scan-cache.js} +27 -20
- package/dist/scan/scan-cache.js.map +1 -0
- package/dist/scan/scanner.d.ts +20 -0
- package/dist/scan/scanner.d.ts.map +1 -0
- package/dist/{scanner.js → scan/scanner.js} +212 -167
- package/dist/scan/scanner.js.map +1 -0
- package/dist/verify.d.ts +16 -3
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +21 -18
- package/dist/verify.js.map +1 -1
- package/dist/{call.d.ts → wire/call.d.ts} +76 -7
- package/dist/wire/call.d.ts.map +1 -0
- package/dist/{call.js → wire/call.js} +53 -80
- package/dist/wire/call.js.map +1 -0
- package/dist/{middleware.d.ts → wire/errors.d.ts} +18 -19
- package/dist/wire/errors.d.ts.map +1 -0
- package/dist/{middleware.js → wire/errors.js} +26 -14
- package/dist/wire/errors.js.map +1 -0
- package/dist/{errors.d.ts → wire/http-error.d.ts} +5 -6
- package/dist/wire/http-error.d.ts.map +1 -0
- package/dist/{errors.js → wire/http-error.js} +7 -6
- package/dist/wire/http-error.js.map +1 -0
- package/dist/wire/invocation.d.ts +4 -0
- package/dist/wire/invocation.d.ts.map +1 -0
- package/dist/wire/invocation.js +3 -0
- package/dist/wire/invocation.js.map +1 -0
- package/dist/{middleware/logger.d.ts → wire/loggerMiddleware.d.ts} +3 -3
- package/dist/wire/loggerMiddleware.d.ts.map +1 -0
- package/dist/{middleware/logger.js → wire/loggerMiddleware.js} +2 -2
- package/dist/wire/loggerMiddleware.js.map +1 -0
- package/dist/wire/middleware.d.ts +29 -0
- package/dist/wire/middleware.d.ts.map +1 -0
- package/dist/wire/middleware.js +20 -0
- package/dist/wire/middleware.js.map +1 -0
- package/dist/{operation.d.ts → wire/operation.d.ts} +39 -10
- package/dist/wire/operation.d.ts.map +1 -0
- package/dist/wire/operation.js +167 -0
- package/dist/wire/operation.js.map +1 -0
- package/package.json +27 -8
- package/src/boot/AppLifecycle.ts +50 -0
- package/src/boot/Emissions.ts +263 -0
- package/src/boot/HandlerFacade.ts +242 -0
- package/src/boot/Lifecycle.ts +3 -0
- package/src/boot/ambient-port.ts +41 -0
- package/src/boot/ambient.als.ts +43 -0
- package/src/boot/ambient.queue.ts +75 -0
- package/src/boot/apply.ts +47 -0
- package/src/boot/auth.ts +55 -0
- package/src/boot/binding.ts +182 -0
- package/src/boot/boot.ts +125 -0
- package/src/boot/bootstrap.ts +839 -0
- package/src/boot/frame.ts +210 -0
- package/src/boot/ownership.ts +140 -0
- package/src/boot/ports.ts +66 -0
- package/src/boot/remote.ts +179 -0
- package/src/boot/seed.ts +158 -0
- package/src/boot/together.ts +215 -0
- package/src/boot/types.ts +261 -0
- package/src/builtins/config.ts +19 -0
- package/src/builtins/logger.ts +175 -0
- package/src/config-loader.ts +146 -0
- package/src/contract/Call.ts +18 -0
- package/src/contract/Invocation.ts +72 -0
- package/src/contract/RouteAddress.ts +49 -0
- package/src/contract.ts +74 -0
- package/src/crypto/encoding.ts +59 -0
- package/src/crypto/node.ts +30 -0
- package/src/crypto/port.ts +45 -0
- package/src/crypto/webcrypto.ts +55 -0
- package/src/define.ts +10 -0
- package/src/dispatch/ArgumentResolver.ts +17 -0
- package/src/dispatch/ArrayResult.ts +10 -0
- package/src/dispatch/DispatchEvent.ts +38 -0
- package/src/dispatch/DispatchLifecycle.ts +23 -0
- package/src/dispatch/DispatchPort.ts +6 -0
- package/src/dispatch/Dispatcher.ts +48 -0
- package/src/dispatch/InFlight.ts +49 -0
- package/src/dispatch/InputValidator.ts +28 -0
- package/src/dispatch/LocalRoutePolicy.ts +34 -0
- package/src/dispatch/OperationExecutor.ts +60 -0
- package/src/dispatch/OperationRoute.ts +18 -0
- package/src/dispatch/OutputProjector.ts +32 -0
- package/src/dispatch/OutputView.ts +9 -0
- package/src/dispatch/PresenterArgumentResolver.ts +25 -0
- package/src/dispatch/PresenterExecutor.ts +55 -0
- package/src/dispatch/RemoteRouteResolver.ts +21 -0
- package/src/dispatch/Route.ts +11 -0
- package/src/dispatch/RouteNotFoundError.ts +29 -0
- package/src/dispatch/RoutePolicy.ts +8 -0
- package/src/dispatch/RouteRegistry.ts +73 -0
- package/src/dispatch/RouteResolver.ts +7 -0
- package/src/dispatch/StorageGuard.ts +71 -0
- package/src/effective-operation.ts +597 -0
- package/src/emit.ts +90 -0
- package/src/entry/DynamicFacade.ts +28 -0
- package/src/entry/FacadeEntry.ts +32 -0
- package/src/entry/TransportEntry.ts +30 -0
- package/src/frond-config.ts +138 -0
- package/src/graph.ts +180 -0
- package/src/identity-keys.ts +43 -0
- package/src/identity.ts +235 -0
- package/src/imports.ts +123 -0
- package/src/index.ts +106 -0
- package/src/loader.ts +41 -0
- package/src/node.ts +28 -0
- package/src/orm.ts +252 -0
- package/src/prefab/collector.ts +36 -0
- package/src/prefab/crud.ts +188 -0
- package/src/prefab/mirror.ts +122 -0
- package/src/prefab/prefab.ts +46 -0
- package/src/prefab/presenter.ts +63 -0
- package/src/prefab/repository.ts +170 -0
- package/src/scan/Fronds.ts +73 -0
- package/src/scan/conventions.ts +122 -0
- package/src/scan/emit.ts +231 -0
- package/src/scan/frond.ts +235 -0
- package/src/scan/handler-parser.ts +818 -0
- package/src/scan/scan-cache.ts +115 -0
- package/src/scan/scanner.ts +758 -0
- package/src/verify.ts +193 -0
- package/src/wire/call.ts +369 -0
- package/src/wire/errors.ts +124 -0
- package/src/wire/http-error.ts +77 -0
- package/src/wire/invocation.ts +10 -0
- package/src/wire/loggerMiddleware.ts +29 -0
- package/src/wire/middleware.ts +47 -0
- package/src/wire/operation.ts +258 -0
- package/dist/binding.d.ts.map +0 -1
- package/dist/binding.js.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/boot.js +0 -53
- package/dist/boot.js.map +0 -1
- package/dist/bootstrap.d.ts.map +0 -1
- package/dist/bootstrap.js +0 -879
- package/dist/bootstrap.js.map +0 -1
- package/dist/call.d.ts.map +0 -1
- package/dist/call.js.map +0 -1
- package/dist/collector.d.ts +0 -28
- package/dist/collector.d.ts.map +0 -1
- package/dist/collector.js +0 -32
- package/dist/collector.js.map +0 -1
- package/dist/crud.d.ts.map +0 -1
- package/dist/crud.js.map +0 -1
- package/dist/egress.d.ts +0 -52
- package/dist/egress.d.ts.map +0 -1
- package/dist/egress.js +0 -186
- package/dist/egress.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/handler-parser.d.ts.map +0 -1
- package/dist/handler-parser.js +0 -505
- package/dist/handler-parser.js.map +0 -1
- package/dist/invocation.d.ts +0 -20
- package/dist/invocation.d.ts.map +0 -1
- package/dist/invocation.js +0 -15
- package/dist/invocation.js.map +0 -1
- package/dist/middleware/error-handler.d.ts +0 -15
- package/dist/middleware/error-handler.d.ts.map +0 -1
- package/dist/middleware/error-handler.js +0 -29
- package/dist/middleware/error-handler.js.map +0 -1
- package/dist/middleware/logger.d.ts.map +0 -1
- package/dist/middleware/logger.js.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js.map +0 -1
- package/dist/mirror.d.ts +0 -93
- package/dist/mirror.d.ts.map +0 -1
- package/dist/mirror.js +0 -96
- package/dist/mirror.js.map +0 -1
- package/dist/operation.d.ts.map +0 -1
- package/dist/operation.js +0 -95
- package/dist/operation.js.map +0 -1
- package/dist/presenter.d.ts.map +0 -1
- package/dist/presenter.js.map +0 -1
- package/dist/remote.d.ts.map +0 -1
- package/dist/remote.js.map +0 -1
- package/dist/repository.d.ts +0 -55
- package/dist/repository.d.ts.map +0 -1
- package/dist/repository.js +0 -26
- package/dist/repository.js.map +0 -1
- package/dist/scan-cache.d.ts +0 -10
- package/dist/scan-cache.d.ts.map +0 -1
- package/dist/scan-cache.js.map +0 -1
- package/dist/scanner.d.ts +0 -34
- package/dist/scanner.d.ts.map +0 -1
- package/dist/scanner.js.map +0 -1
- package/dist/seed.d.ts.map +0 -1
- package/dist/seed.js.map +0 -1
- package/dist/types.d.ts +0 -421
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- /package/dist/{bootstrap.d.ts → boot/bootstrap.d.ts} +0 -0
- /package/dist/{types.js → boot/types.js} +0 -0
|
@@ -1,34 +1,27 @@
|
|
|
1
1
|
import { readdir, readFile } from 'node:fs/promises';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { join, dirname, basename, resolve as resolvePath } from 'node:path';
|
|
4
|
-
import { pathToFileURL } from 'node:url';
|
|
5
4
|
import { ANONYMOUS_SCHEMA_NAME } from '@fougere/schema';
|
|
6
|
-
import { cardinalityOf } from '
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { loadFrondConfig } from '
|
|
10
|
-
import { emitKeyOf } from '
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
activeLoader = loader;
|
|
20
|
-
}
|
|
21
|
-
/** Used by config-loader to load fougere.config.ts via the same TS-aware loader. */
|
|
22
|
-
export function getModuleLoader() {
|
|
23
|
-
return activeLoader;
|
|
24
|
-
}
|
|
5
|
+
import { cardinalityOf } from '../wire/operation.js';
|
|
6
|
+
import { computeBindingPlan } from '../boot/binding.js';
|
|
7
|
+
import { parseAllHandlerMethods, parsePresenterMethods, parseConstructorParams, resetTypePrograms, seedTypeProgram, } from './handler-parser.js';
|
|
8
|
+
import { loadFrondConfig } from '../frond-config.js';
|
|
9
|
+
import { emitKeyOf } from '../emit.js';
|
|
10
|
+
import { getPresenterFields } from '../prefab/presenter.js';
|
|
11
|
+
import { ormKeyOf, togetherKeyOf } from '../orm.js';
|
|
12
|
+
import { targetOf, viewsOf, outputOf } from '../prefab/prefab.js';
|
|
13
|
+
import { ownedBy, repositoryKeyOf } from '../prefab/repository.js';
|
|
14
|
+
import { lowerFirst } from '@fougere/schema';
|
|
15
|
+
import { Fronds } from './Fronds.js';
|
|
16
|
+
import { getModuleLoader } from '../loader.js';
|
|
17
|
+
import { DEFAULT_CONVENTIONS, resolveConventions, frondPackage, providerDirsOf, frondDirsOf, } from './conventions.js';
|
|
25
18
|
// FS
|
|
26
19
|
/**
|
|
27
20
|
* What this scan run could not do. Reset by {@link scanProject}, which owns a run.
|
|
28
21
|
*
|
|
29
|
-
* Module-scoped like the loader and the cache root above: the scanner already has
|
|
30
|
-
*
|
|
31
|
-
*
|
|
22
|
+
* Module-scoped like the loader and the cache root above: the scanner already has a
|
|
23
|
+
* notion of "the current run". Three sites record — measured — so a per-run object
|
|
24
|
+
* would carry twenty methods to spare one line of reset.
|
|
32
25
|
*/
|
|
33
26
|
let diagnostics = [];
|
|
34
27
|
function record(d) {
|
|
@@ -72,7 +65,7 @@ async function files(path) {
|
|
|
72
65
|
}
|
|
73
66
|
// Module
|
|
74
67
|
async function loadModule(filePath) {
|
|
75
|
-
return await
|
|
68
|
+
return await getModuleLoader()(filePath);
|
|
76
69
|
}
|
|
77
70
|
async function loadDefault(filePath) {
|
|
78
71
|
const mod = await loadModule(filePath);
|
|
@@ -98,21 +91,6 @@ function findWorkspaceRoot(from) {
|
|
|
98
91
|
}
|
|
99
92
|
return resolvePath(from); // fallback: use project root itself
|
|
100
93
|
}
|
|
101
|
-
// Convention
|
|
102
|
-
/** Directories whose classes register as providers — two spellings, one behaviour. */
|
|
103
|
-
const PROVIDER_DIRS = ['services', 'repositories'];
|
|
104
|
-
/**
|
|
105
|
-
* The frond vocabulary — every directory {@link scanFrond} reads. A frond directory says
|
|
106
|
-
* nothing else, which is why this list is what a reader needs to bound one: the Nuxt
|
|
107
|
-
* module watches these for the root frond (watching the root itself would match every
|
|
108
|
-
* write), and a flat app's tsconfig lists them instead of `["."]`, which would swallow
|
|
109
|
-
* `app/` and `nuxt.config.ts`.
|
|
110
|
-
*/
|
|
111
|
-
export const FROND_DIRS = [
|
|
112
|
-
'entities', 'handlers', 'presenters', 'collectors', 'seeds', ...PROVIDER_DIRS,
|
|
113
|
-
];
|
|
114
|
-
export { toRegistrationName } from './contract.js';
|
|
115
|
-
import { toRegistrationName } from './contract.js';
|
|
116
94
|
/**
|
|
117
95
|
* Strip the 'Handler' suffix → the name the handler answers to. 'PostHandler' → 'post'.
|
|
118
96
|
*
|
|
@@ -122,7 +100,7 @@ import { toRegistrationName } from './contract.js';
|
|
|
122
100
|
*/
|
|
123
101
|
function toAddress(className) {
|
|
124
102
|
const base = className.endsWith('Handler') ? className.slice(0, -7) : className;
|
|
125
|
-
return
|
|
103
|
+
return lowerFirst(base);
|
|
126
104
|
}
|
|
127
105
|
// Scan
|
|
128
106
|
/**
|
|
@@ -146,53 +124,73 @@ function depKeyOf(type) {
|
|
|
146
124
|
// façade or a doublure, which is what makes the topology invisible from a signature.
|
|
147
125
|
const facadeOf = type.name === 'Facade' ? type.generics?.[0]?.name : undefined;
|
|
148
126
|
if (facadeOf)
|
|
149
|
-
return
|
|
127
|
+
return lowerFirst(facadeOf);
|
|
150
128
|
// `Emit<PostPublished>` — the third port, and the only one that names a SUBJECT rather
|
|
151
129
|
// than an interlocutor. Read like the other two: the type names what arrives, here a
|
|
152
130
|
// function that announces. Who receives it is not in the signature and never will be.
|
|
153
131
|
const factOf = type.name === 'Emit' ? type.generics?.[0]?.name : undefined;
|
|
154
132
|
if (factOf)
|
|
155
133
|
return emitKeyOf(factOf);
|
|
134
|
+
// `Together<[Account, Ledger], [RateMirror]>` — the fifth reading, and the only one whose
|
|
135
|
+
// argument is a SET rather than one subject. The AST hands each tuple back as a single
|
|
136
|
+
// string, so they are split here, where every other question of "how was it written" lives.
|
|
137
|
+
const frame = type.name === 'Together' ? type.generics?.[0]?.name : undefined;
|
|
138
|
+
if (frame)
|
|
139
|
+
return togetherKeyOf(tupleMembers(frame), tupleMembers(type.generics?.[1]?.name ?? ''));
|
|
140
|
+
// `RepositoryOf<Post>` — what an author writes when no repository file exists. The dual
|
|
141
|
+
// of the line below: one names the port, the other the holder, and both resolve to a key
|
|
142
|
+
// rather than to a class the author would have to invent.
|
|
143
|
+
const held = type.name === 'RepositoryOf' ? type.generics?.[0]?.name : undefined;
|
|
144
|
+
if (held)
|
|
145
|
+
return repositoryKeyOf(held);
|
|
156
146
|
const target = type.name === 'EntityOrm' ? type.generics?.[0]?.name : undefined;
|
|
157
147
|
if (!target)
|
|
158
148
|
return type.name;
|
|
159
149
|
return ormKeyOf(target);
|
|
160
150
|
}
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
/** Cached parsePresenterMethods — skips TS loading when cache is warm. */
|
|
173
|
-
async function cachedPresenterMethods(filePath) {
|
|
174
|
-
const hash = hashFile(filePath);
|
|
175
|
-
const key = filePath + ':presenter';
|
|
176
|
-
const cached = getCached(key, hash);
|
|
177
|
-
if (cached)
|
|
178
|
-
return cached;
|
|
179
|
-
const methods = await parsePresenterMethods(filePath);
|
|
180
|
-
setCached(key, hash, methods);
|
|
181
|
-
return methods;
|
|
151
|
+
/**
|
|
152
|
+
* `'[Account, Ledger]'` → `['Account', 'Ledger']`.
|
|
153
|
+
*
|
|
154
|
+
* The tuple was chosen over the variadic form the parser reads more cleanly, because the
|
|
155
|
+
* variadic one costs arities-with-defaults and a `never` filter on the TypeScript side
|
|
156
|
+
* while the tuple maps to `[EntityOrm<Account>, EntityOrm<Ledger>]` in one line. The
|
|
157
|
+
* parser does not get to decide alone; this split is what that choice costs.
|
|
158
|
+
*/
|
|
159
|
+
function tupleMembers(raw) {
|
|
160
|
+
return raw.replace(/^\[|\]$/g, '').split(',').map((member) => member.trim()).filter(Boolean);
|
|
182
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* These readings are semantic: an unchanged file can mean something different after an
|
|
164
|
+
* imported alias changes. The parser's TypeScript Program is the cache for one scan; a
|
|
165
|
+
* cache keyed only by this file's bytes would be unsound.
|
|
166
|
+
*/
|
|
167
|
+
const ctorParamsOf = (filePath) => parseConstructorParams(filePath);
|
|
168
|
+
const presenterMethodsOf = (filePath) => parsePresenterMethods(filePath);
|
|
169
|
+
const handlerMethodsOf = (filePath, projectRoot) => parseAllHandlerMethods(filePath, projectRoot);
|
|
183
170
|
async function toProvider(filePath) {
|
|
184
171
|
const ctor = await loadClass(filePath);
|
|
185
|
-
const params = await
|
|
172
|
+
const params = await ctorParamsOf(filePath);
|
|
186
173
|
const deps = params.map((p) => depKeyOf(p.type));
|
|
187
|
-
// A repository inherits its constructor from `Repository(
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
174
|
+
// A repository inherits its constructor from `Repository(…)`, so the file declares none
|
|
175
|
+
// and the scan reads no parameter. The mixin knows what it was built for and says so at
|
|
176
|
+
// runtime — same escape as `Crud.__ops`, and the same reason: what a prefab fabricates,
|
|
177
|
+
// only the prefab can describe.
|
|
178
|
+
//
|
|
179
|
+
// An AGGREGATE owns several, and its base takes them in the declared order. It is handed
|
|
180
|
+
// no frame: the boundary and the unit of work are two statements, and a frame is ASKED FOR
|
|
181
|
+
// like anywhere else — see `prefab/repository.ts`.
|
|
182
|
+
const owned = ownedBy(ctor);
|
|
183
|
+
const target = targetOf(ctor);
|
|
184
|
+
if (owned.length > 1 && deps.length === 0) {
|
|
185
|
+
deps.push(...owned.map((entity) => ormKeyOf(lowerFirst(entity.name))));
|
|
194
186
|
}
|
|
195
|
-
|
|
187
|
+
else if (target && deps.length === 0) {
|
|
188
|
+
deps.push(ormKeyOf(lowerFirst(target.name)));
|
|
189
|
+
}
|
|
190
|
+
// No `name` beside `ctor`: a provider registers under `ctor.name`, which is what
|
|
191
|
+
// `depKeyOf` returns since it reads the type as written. The camelCase field that
|
|
192
|
+
// used to sit here called itself the registration key and was one nowhere.
|
|
193
|
+
return { ctor, deps, filePath };
|
|
196
194
|
}
|
|
197
195
|
async function toEntityEntry(filePath) {
|
|
198
196
|
const exported = await loadDefault(filePath);
|
|
@@ -206,7 +204,7 @@ async function toEntityEntry(filePath) {
|
|
|
206
204
|
const declaredName = runtimeName && runtimeName !== ANONYMOUS_SCHEMA_NAME
|
|
207
205
|
? runtimeName
|
|
208
206
|
: basename(filePath).replace(/\.[^.]+$/, '');
|
|
209
|
-
const name =
|
|
207
|
+
const name = lowerFirst(declaredName);
|
|
210
208
|
return { name, entityClass: exported, filePath };
|
|
211
209
|
}
|
|
212
210
|
/**
|
|
@@ -214,8 +212,8 @@ async function toEntityEntry(filePath) {
|
|
|
214
212
|
* Handles arrays, generics (uses base name), and simple references.
|
|
215
213
|
*/
|
|
216
214
|
function resolveSchema(type, moduleExports) {
|
|
217
|
-
//
|
|
218
|
-
|
|
215
|
+
// An array's element type IS `type.name` — the arity rides beside it, so nothing has
|
|
216
|
+
// to be unwrapped here.
|
|
219
217
|
// For generics like Pagination<Post>, also check inner types
|
|
220
218
|
if (type.generics) {
|
|
221
219
|
for (const g of type.generics) {
|
|
@@ -231,7 +229,7 @@ function resolveSchema(type, moduleExports) {
|
|
|
231
229
|
}
|
|
232
230
|
}
|
|
233
231
|
}
|
|
234
|
-
const resolved = moduleExports[name];
|
|
232
|
+
const resolved = moduleExports[type.name];
|
|
235
233
|
if (resolved && typeof resolved === 'function' && 'getFields' in resolved) {
|
|
236
234
|
return resolved;
|
|
237
235
|
}
|
|
@@ -243,20 +241,11 @@ function resolveSchema(type, moduleExports) {
|
|
|
243
241
|
* Resolves schemas for all params (not just the first) and stores
|
|
244
242
|
* full signatures for the binding algorithm.
|
|
245
243
|
*/
|
|
246
|
-
async function inferOperations(filePath, moduleExports, projectRoot) {
|
|
244
|
+
async function inferOperations(filePath, handlerName, moduleExports, collectorTypeNames, explicitInputs, declared, projectRoot) {
|
|
247
245
|
const map = new Map();
|
|
248
246
|
let parsed;
|
|
249
247
|
try {
|
|
250
|
-
|
|
251
|
-
const cacheKey = filePath + ':all' + (projectRoot ? ':inherited' : '');
|
|
252
|
-
const cached = getCached(cacheKey, hash);
|
|
253
|
-
if (cached) {
|
|
254
|
-
parsed = cached;
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
parsed = await parseAllHandlerMethods(filePath, projectRoot);
|
|
258
|
-
setCached(cacheKey, hash, parsed);
|
|
259
|
-
}
|
|
248
|
+
parsed = await handlerMethodsOf(filePath, projectRoot);
|
|
260
249
|
}
|
|
261
250
|
catch (cause) {
|
|
262
251
|
// The handler still gets a façade — its methods exist at runtime — but with no
|
|
@@ -302,11 +291,34 @@ async function inferOperations(filePath, moduleExports, projectRoot) {
|
|
|
302
291
|
signature: method,
|
|
303
292
|
...(method.description && { description: method.description }),
|
|
304
293
|
};
|
|
305
|
-
//
|
|
306
|
-
|
|
294
|
+
// A convention may omit a declaration only when it has one answer. Only values the
|
|
295
|
+
// caller supplies through the body are candidates: a schema-typed collector, fact or
|
|
296
|
+
// context parameter is not input merely because it names an entity. The old loop
|
|
297
|
+
// ignored provenance and assigned the first schema it met, so swapping two parameters
|
|
298
|
+
// silently changed the contract the façade used to judge the request body.
|
|
299
|
+
const binding = computeBindingPlan(method.params, collectorTypeNames);
|
|
300
|
+
const candidates = method.params.flatMap((param, index) => {
|
|
301
|
+
if (binding[index]?.source.kind !== 'body')
|
|
302
|
+
return [];
|
|
307
303
|
const schema = resolveSchema(param.type, moduleExports);
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
return schema ? [{ param, schema }] : [];
|
|
305
|
+
});
|
|
306
|
+
if (candidates.length === 1) {
|
|
307
|
+
meta.input = candidates[0].schema;
|
|
308
|
+
}
|
|
309
|
+
else if (candidates.length > 1
|
|
310
|
+
&& declared[method.name]?.input === undefined
|
|
311
|
+
&& !explicitInputs.has(method.name)) {
|
|
312
|
+
const subject = `${handlerName}.${method.name}`;
|
|
313
|
+
record({
|
|
314
|
+
severity: 'blocking',
|
|
315
|
+
code: 'input-contract-ambiguous',
|
|
316
|
+
filePath,
|
|
317
|
+
subject,
|
|
318
|
+
message: `Cannot infer the input contract for ${subject}: ${candidates.length} entity `
|
|
319
|
+
+ `candidates — ${candidates.map(({ param }) => `${param.name}: ${param.type.raw}`).join('; ')}. `
|
|
320
|
+
+ `Declare operations.${method.name}.input in frond.config.ts.`,
|
|
321
|
+
});
|
|
310
322
|
}
|
|
311
323
|
if (method.returnType) {
|
|
312
324
|
meta.output = resolveSchema(method.returnType, moduleExports);
|
|
@@ -317,7 +329,7 @@ async function inferOperations(filePath, moduleExports, projectRoot) {
|
|
|
317
329
|
}
|
|
318
330
|
return map;
|
|
319
331
|
}
|
|
320
|
-
async function toHandlerEntry(filePath, entityByClassName, projectRoot, surface) {
|
|
332
|
+
async function toHandlerEntry(filePath, entityByClassName, collectorTypeNames, explicitInputs, projectRoot, surface) {
|
|
321
333
|
const mod = await loadModule(filePath);
|
|
322
334
|
const ctor = mod.default;
|
|
323
335
|
if (typeof ctor !== 'function' || !ctor.prototype)
|
|
@@ -330,15 +342,20 @@ async function toHandlerEntry(filePath, entityByClassName, projectRoot, surface)
|
|
|
330
342
|
augmented[className] = entityClass;
|
|
331
343
|
}
|
|
332
344
|
const address = toAddress(ctor.name);
|
|
333
|
-
const
|
|
334
|
-
const
|
|
345
|
+
const declaredOps = ctor.__ops ?? {};
|
|
346
|
+
const operations = await inferOperations(filePath, ctor.name, augmented, collectorTypeNames, explicitInputs, declaredOps, projectRoot);
|
|
347
|
+
const ctorParams = await ctorParamsOf(filePath);
|
|
335
348
|
const deps = ctorParams.map((p) => depKeyOf(p.type));
|
|
336
349
|
// Read output override from Crud(Entity, Output) — static __output property
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const
|
|
350
|
+
// A handler-wide view, when it is not simply the entity — the two are compared by
|
|
351
|
+
// identity, which is why both slots are read through the same door.
|
|
352
|
+
const subject = targetOf(ctor);
|
|
353
|
+
const declared = outputOf(ctor);
|
|
354
|
+
const outputOverride = declared && subject && declared !== subject
|
|
355
|
+
? declared
|
|
356
|
+
: undefined;
|
|
340
357
|
return {
|
|
341
|
-
name:
|
|
358
|
+
name: lowerFirst(ctor.name),
|
|
342
359
|
address,
|
|
343
360
|
ctor: ctor,
|
|
344
361
|
operations,
|
|
@@ -351,7 +368,7 @@ async function toHandlerEntry(filePath, entityByClassName, projectRoot, surface)
|
|
|
351
368
|
/** Strip '.seed' suffix → entity name. 'Author.seed.ts' → 'author'. */
|
|
352
369
|
function toSeedEntityName(fileName) {
|
|
353
370
|
const base = fileName.replace(/\.seed\.(ts|js)$/, '').replace(/\.(ts|js)$/, '');
|
|
354
|
-
return
|
|
371
|
+
return lowerFirst(base);
|
|
355
372
|
}
|
|
356
373
|
async function toSeedEntry(filePath) {
|
|
357
374
|
const data = await loadDefault(filePath);
|
|
@@ -363,17 +380,17 @@ async function toSeedEntry(filePath) {
|
|
|
363
380
|
}
|
|
364
381
|
async function toPresenterEntry(filePath) {
|
|
365
382
|
const ctor = await loadClass(filePath);
|
|
366
|
-
const target =
|
|
383
|
+
const target = targetOf(ctor);
|
|
367
384
|
if (!target)
|
|
368
385
|
return null;
|
|
369
|
-
const entityName =
|
|
386
|
+
const entityName = lowerFirst(target.name);
|
|
370
387
|
const fields = getPresenterFields(ctor);
|
|
371
|
-
const presenterParams = await
|
|
388
|
+
const presenterParams = await ctorParamsOf(filePath);
|
|
372
389
|
const deps = presenterParams.map((p) => depKeyOf(p.type));
|
|
373
390
|
// Parse method return types from source
|
|
374
391
|
let fieldMeta = [];
|
|
375
392
|
try {
|
|
376
|
-
const parsed = await
|
|
393
|
+
const parsed = await presenterMethodsOf(filePath);
|
|
377
394
|
fieldMeta = parsed.map((m) => ({
|
|
378
395
|
name: m.name,
|
|
379
396
|
returnType: m.returnType?.name,
|
|
@@ -384,61 +401,83 @@ async function toPresenterEntry(filePath) {
|
|
|
384
401
|
// Everything after the rows is bound like a handler's argument.
|
|
385
402
|
params: m.params.slice(1),
|
|
386
403
|
}));
|
|
404
|
+
// The rows parameter is stripped just above, and nothing used to check its SHAPE.
|
|
405
|
+
// A computed field receives the PAGE and answers one value per row, so a method
|
|
406
|
+
// written `items(order: Order)` compiles and dies at the first call with a 500
|
|
407
|
+
// (`expected 1 value(s) for 1 row(s), got 0`) — while the information sat here, at
|
|
408
|
+
// the scan. Every own method of a presenter IS a computed field
|
|
409
|
+
// (`getPresenterFields`), so there is no private helper to spare.
|
|
410
|
+
//
|
|
411
|
+
// An ERROR at boot, not a refusal: a `blocking` scan diagnostic is logged and the
|
|
412
|
+
// app still starts (`bootstrap.ts`, and the comment above that loop says why). Making
|
|
413
|
+
// it refuse means deciding that a declaration which cannot work is an unresolved
|
|
414
|
+
// CONTRACT — the one thing that does stop the boot — and that is a decision, not a
|
|
415
|
+
// severity.
|
|
416
|
+
for (const method of parsed) {
|
|
417
|
+
const rows = method.params[0];
|
|
418
|
+
if (rows && rows.type.array === true)
|
|
419
|
+
continue;
|
|
420
|
+
record({
|
|
421
|
+
severity: 'blocking',
|
|
422
|
+
code: 'presenter-field-not-page',
|
|
423
|
+
filePath,
|
|
424
|
+
subject: `${ctor.name ?? 'Presenter'}.${method.name}`,
|
|
425
|
+
message: `${method.name}(${rows ? `${rows.name}: ${rows.type.raw}` : ''}) is a computed `
|
|
426
|
+
+ `field, so it receives the PAGE and must answer one value per row. Declare `
|
|
427
|
+
+ `${method.name}(${rows?.name ?? 'rows'}: ${target.name ?? 'Entity'}[]) `
|
|
428
|
+
+ `and return an array of the same length.`,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
387
431
|
}
|
|
388
432
|
catch { /* parse failure — fall back to untyped */ }
|
|
389
433
|
// Declared at runtime on the class, so it survives a scan that resolved nothing.
|
|
390
|
-
return { entityName, ctor, fields, fieldMeta, views:
|
|
434
|
+
return { entityName, ctor, fields, fieldMeta, views: viewsOf(ctor), deps, filePath };
|
|
391
435
|
}
|
|
392
436
|
async function toCollectorEntry(filePath) {
|
|
393
437
|
const ctor = await loadClass(filePath);
|
|
394
|
-
const target =
|
|
438
|
+
const target = targetOf(ctor);
|
|
395
439
|
if (!target)
|
|
396
440
|
return null;
|
|
397
|
-
|
|
398
|
-
|
|
441
|
+
// The target's NAME and nothing else — a collector reads no fields, so the class it
|
|
442
|
+
// was built on needs no schema.
|
|
443
|
+
const typeName = lowerFirst(target.name);
|
|
444
|
+
const collectorParams = await ctorParamsOf(filePath);
|
|
399
445
|
const deps = collectorParams.map((p) => depKeyOf(p.type));
|
|
400
|
-
return {
|
|
446
|
+
return { typeName, ctor, deps, filePath };
|
|
401
447
|
}
|
|
402
|
-
async function scanFrond(frondPath, name, source, projectRoot) {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
entities
|
|
418
|
-
|
|
448
|
+
async function scanFrond(frondPath, name, source, conventions, projectRoot) {
|
|
449
|
+
const { entities: entitiesDir, handlers: handlersDir, presenters: presentersDir, collectors: collectorsDir, seeds: seedsDir, } = conventions.dirs;
|
|
450
|
+
/**
|
|
451
|
+
* A convention directory, read by whoever knows the shape it holds.
|
|
452
|
+
*
|
|
453
|
+
* The same three lines were written six times — list, read in parallel, drop what the
|
|
454
|
+
* reader refused — which is what made `handlers/` quietly special: it grew a second
|
|
455
|
+
* pass for its surfaces and nothing else could.
|
|
456
|
+
*/
|
|
457
|
+
const collect = async (dir, read) => {
|
|
458
|
+
const entries = await Promise.all((await files(join(frondPath, dir))).map(read));
|
|
459
|
+
return entries.filter((entry) => entry !== null);
|
|
460
|
+
};
|
|
461
|
+
// services/ and repositories/ — two spellings, one provider list.
|
|
462
|
+
const providers = (await Promise.all(providerDirsOf(conventions).map((dir) => collect(dir, toProvider)))).flat();
|
|
463
|
+
const entities = await collect(entitiesDir, toEntityEntry);
|
|
464
|
+
const collectors = await collect(collectorsDir, toCollectorEntry);
|
|
465
|
+
const collectorTypeNames = new Set(collectors.map((collector) => collector.typeName));
|
|
466
|
+
const frondConfig = await loadFrondConfig(frondPath);
|
|
467
|
+
const explicitInputs = new Set(Object.entries(frondConfig?.operations ?? {})
|
|
468
|
+
.filter(([, contract]) => contract.input !== undefined)
|
|
469
|
+
.map(([operation]) => operation));
|
|
470
|
+
// Handlers resolve `T` against the entities, so those come first.
|
|
419
471
|
const entityByClassName = new Map(entities.map((e) => [e.entityClass.name, e.entityClass]));
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
const surfacePaths = await files(join(frondPath, 'handlers', surfaceName));
|
|
426
|
-
handlers.push(...await Promise.all(surfacePaths.map((f) => toHandlerEntry(f, entityByClassName, projectRoot, surfaceName))));
|
|
472
|
+
const handlers = await collect(handlersDir, (f) => toHandlerEntry(f, entityByClassName, collectorTypeNames, explicitInputs, projectRoot));
|
|
473
|
+
// A subdirectory of handlers/ is a named surface — the one directory whose CHILDREN
|
|
474
|
+
// are part of the convention too.
|
|
475
|
+
for (const surface of await dirs(join(frondPath, handlersDir))) {
|
|
476
|
+
handlers.push(...await collect(join(handlersDir, surface), (f) => toHandlerEntry(f, entityByClassName, collectorTypeNames, explicitInputs, projectRoot, surface)));
|
|
427
477
|
}
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
const presenterEntries = await Promise.all(presenterPaths.map((f) => toPresenterEntry(f)));
|
|
431
|
-
presenters.push(...presenterEntries.filter((p) => p !== null));
|
|
432
|
-
// Scan collectors/
|
|
433
|
-
const collectorPaths = await files(join(frondPath, 'collectors'));
|
|
434
|
-
const collectorEntries = await Promise.all(collectorPaths.map((f) => toCollectorEntry(f)));
|
|
435
|
-
collectors.push(...collectorEntries.filter((c) => c !== null));
|
|
436
|
-
// Scan seeds/
|
|
437
|
-
const seedPaths = await files(join(frondPath, 'seeds'));
|
|
438
|
-
const seedEntries = await Promise.all(seedPaths.map((f) => toSeedEntry(f)));
|
|
439
|
-
seeds.push(...seedEntries.filter((s) => s !== null));
|
|
478
|
+
const presenters = await collect(presentersDir, toPresenterEntry);
|
|
479
|
+
const seeds = await collect(seedsDir, toSeedEntry);
|
|
440
480
|
// Mark exposed entries: frond.config.ts takes precedence, then @expose decorator
|
|
441
|
-
const frondConfig = await loadFrondConfig(frondPath);
|
|
442
481
|
if (frondConfig?.expose) {
|
|
443
482
|
const exposeSet = new Set(frondConfig.expose);
|
|
444
483
|
for (const e of entities) {
|
|
@@ -490,7 +529,7 @@ async function scanFrond(frondPath, name, source, projectRoot) {
|
|
|
490
529
|
* Carrying the convention is what makes a frond; the key never marked anything and
|
|
491
530
|
* nothing read it. It earns its keep as the one thing the directory cannot say: that
|
|
492
531
|
* `fronds/blog-v2/` serves the frond still called `blog` — so a rename on disk does not
|
|
493
|
-
* rename the entity keys, the `@
|
|
532
|
+
* rename the entity keys, the `@fronds/*` import or a `remotes:` entry.
|
|
494
533
|
*/
|
|
495
534
|
async function frondNameOf(frondPath, dirName) {
|
|
496
535
|
try {
|
|
@@ -513,20 +552,20 @@ async function frondNameOf(frondPath, dirName) {
|
|
|
513
552
|
* are ordinary top-level names in projects that never heard of Fougere, and a domain
|
|
514
553
|
* without a single entity is not a domain.
|
|
515
554
|
*/
|
|
516
|
-
async function rootFrondOf(root, workspaceRoot) {
|
|
517
|
-
if ((await files(join(root,
|
|
555
|
+
async function rootFrondOf(root, workspaceRoot, conventions) {
|
|
556
|
+
if ((await files(join(root, conventions.dirs.entities))).length === 0)
|
|
518
557
|
return null;
|
|
519
558
|
const name = await frondNameOf(root, basename(resolvePath(root)));
|
|
520
|
-
return scanFrond(root, name, { path: root, package:
|
|
559
|
+
return scanFrond(root, name, { path: root, package: frondPackage(name, conventions) }, conventions, workspaceRoot);
|
|
521
560
|
}
|
|
522
561
|
/**
|
|
523
|
-
* `@
|
|
562
|
+
* `@fronds/<name>` → the directory it names, for every frond of a project.
|
|
524
563
|
*
|
|
525
564
|
* The framework states this convention — `FrondSource.package` has always spelled it, and
|
|
526
565
|
* `fougere sync` writes it into a consumer's tsconfig — and until now its own reader could
|
|
527
566
|
* not resolve it. The Nuxt module registered a Vite alias, so a `.vue` page could import
|
|
528
|
-
* `@
|
|
529
|
-
* naming its neighbour got `Cannot find module '@
|
|
567
|
+
* `@fronds/blog/entities/Post`, while the SCAN loaded sources through a bare jiti: a frond
|
|
568
|
+
* naming its neighbour got `Cannot find module '@fronds/user/entities/User.js'`. So the one
|
|
530
569
|
* form that survives a split was the one form that did not run.
|
|
531
570
|
*
|
|
532
571
|
* Hand it to the module loader — `createJiti(url, { alias: await frondAliases(root) })` —
|
|
@@ -534,23 +573,23 @@ async function rootFrondOf(root, workspaceRoot) {
|
|
|
534
573
|
* `package.json` read, no parsing: it is deliberately callable BEFORE the loader exists,
|
|
535
574
|
* which is what makes the chicken-and-egg go away.
|
|
536
575
|
*/
|
|
537
|
-
export async function frondAliases(root) {
|
|
538
|
-
const frondsDir = join(root,
|
|
576
|
+
export async function frondAliases(root, conventions = DEFAULT_CONVENTIONS) {
|
|
577
|
+
const frondsDir = join(root, conventions.fronds);
|
|
539
578
|
const aliases = {};
|
|
540
579
|
// The root itself is a frond when it carries `entities/` — same rule as the scan.
|
|
541
|
-
if ((await files(join(root,
|
|
542
|
-
aliases[
|
|
580
|
+
if ((await files(join(root, conventions.dirs.entities))).length > 0) {
|
|
581
|
+
aliases[frondPackage(await frondNameOf(root, basename(resolvePath(root))), conventions)] = resolvePath(root);
|
|
543
582
|
}
|
|
544
583
|
for (const dir of await dirs(frondsDir)) {
|
|
545
584
|
const path = join(frondsDir, dir);
|
|
546
|
-
aliases[
|
|
585
|
+
aliases[frondPackage(await frondNameOf(path, dir), conventions)] = resolvePath(path);
|
|
547
586
|
}
|
|
548
587
|
/**
|
|
549
588
|
* A SYNCED frond answers to the same name.
|
|
550
589
|
*
|
|
551
590
|
* `fougere sync` writes `.fougere/remotes/<name>/` and registers it in `remotes.json`,
|
|
552
|
-
* which the Nuxt module already reads to alias `@
|
|
553
|
-
* what makes the convention mean ONE thing: a consumer writes `@
|
|
591
|
+
* which the Nuxt module already reads to alias `@fronds/<name>`. Doing it here too is
|
|
592
|
+
* what makes the convention mean ONE thing: a consumer writes `@fronds/blog/entities/Post`
|
|
554
593
|
* and never learns whether that frond is on this disk or was fetched from a card.
|
|
555
594
|
*
|
|
556
595
|
* A local frond wins a name collision — its source is the truth, a synced copy is a
|
|
@@ -559,9 +598,9 @@ export async function frondAliases(root) {
|
|
|
559
598
|
try {
|
|
560
599
|
const registry = JSON.parse(await readFile(join(root, '.fougere', 'remotes.json'), 'utf8'));
|
|
561
600
|
for (const [name, entry] of Object.entries(registry)) {
|
|
562
|
-
if (typeof entry?.path !== 'string' || aliases[
|
|
601
|
+
if (typeof entry?.path !== 'string' || aliases[frondPackage(name, conventions)])
|
|
563
602
|
continue;
|
|
564
|
-
aliases[
|
|
603
|
+
aliases[frondPackage(name, conventions)] = resolvePath(entry.path);
|
|
565
604
|
}
|
|
566
605
|
}
|
|
567
606
|
catch {
|
|
@@ -570,27 +609,33 @@ export async function frondAliases(root) {
|
|
|
570
609
|
}
|
|
571
610
|
return aliases;
|
|
572
611
|
}
|
|
573
|
-
export async function scanProject(root, filter) {
|
|
574
|
-
|
|
612
|
+
export async function scanProject(root, filter, conventionsInput) {
|
|
613
|
+
const conventions = resolveConventions(conventionsInput);
|
|
614
|
+
resetTypePrograms();
|
|
575
615
|
// A run owns its findings: two scans in one process (a test suite, a watcher)
|
|
576
616
|
// must not inherit each other's.
|
|
577
617
|
diagnostics = [];
|
|
578
|
-
const frondsDir = join(root,
|
|
618
|
+
const frondsDir = join(root, conventions.fronds);
|
|
579
619
|
const dirNames = await dirs(frondsDir);
|
|
580
620
|
// Resolve workspace root (parent of packages/) for package import resolution
|
|
581
621
|
// For monorepo: root is the project dir (e.g. demos/nuxt-blog), workspace root is the repo root
|
|
582
622
|
const workspaceRoot = findWorkspaceRoot(root);
|
|
623
|
+
// One program for this run. Seeded here because the parser rebuilds on every root it
|
|
624
|
+
// has not seen, and a frond lives outside its project's tsconfig `include`. Both keys
|
|
625
|
+
// are seeded: heritage reads under the workspace root, a constructor under none.
|
|
626
|
+
const declarations = (await Promise.all([root, ...dirNames.map((dir) => join(frondsDir, dir))].flatMap((frondPath) => frondDirsOf(conventions).map((dir) => files(join(frondPath, dir)))))).flat();
|
|
627
|
+
await seedTypeProgram(declarations, workspaceRoot);
|
|
628
|
+
await seedTypeProgram(declarations);
|
|
583
629
|
const [rootFrond, under] = await Promise.all([
|
|
584
|
-
rootFrondOf(root, workspaceRoot),
|
|
630
|
+
rootFrondOf(root, workspaceRoot, conventions),
|
|
585
631
|
Promise.all(dirNames.map(async (dir) => {
|
|
586
632
|
const name = await frondNameOf(join(frondsDir, dir), dir);
|
|
587
|
-
return scanFrond(join(frondsDir, dir), name, { path: join(frondsDir, dir), package:
|
|
633
|
+
return scanFrond(join(frondsDir, dir), name, { path: join(frondsDir, dir), package: frondPackage(name, conventions) }, conventions, workspaceRoot);
|
|
588
634
|
})),
|
|
589
635
|
]);
|
|
590
636
|
// The app's own domain first, then the ones it took in.
|
|
591
637
|
const all = rootFrond ? [rootFrond, ...under] : under;
|
|
592
|
-
const fronds = filter ? all.filter((f) => filter.includes(f.name)) : all;
|
|
593
|
-
flushCache();
|
|
638
|
+
const fronds = Fronds.scanned(filter ? all.filter((f) => filter.includes(f.name)) : all);
|
|
594
639
|
return { fronds, diagnostics };
|
|
595
640
|
}
|
|
596
641
|
//# sourceMappingURL=scanner.js.map
|