alepha 0.15.1 → 0.15.2
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/dist/api/audits/index.d.ts +342 -365
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +10 -33
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +180 -173
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +10 -3
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +162 -155
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +10 -3
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +413 -0
- package/dist/api/keys/index.d.ts.map +1 -0
- package/dist/api/keys/index.js +476 -0
- package/dist/api/keys/index.js.map +1 -0
- package/dist/api/notifications/index.d.ts +10 -4
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +10 -4
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +294 -301
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +30 -37
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +1079 -769
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +2534 -218
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +10 -4
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +12 -4
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +20 -40
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +31 -44
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +432 -8
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +1856 -12
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/core/index.d.ts +179 -7
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +213 -7
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/redis/index.d.ts +1 -0
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +4 -0
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/cli/index.d.ts +488 -5612
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2326 -311
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +194 -46
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +1995 -60
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +42 -19
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +34 -13
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +62 -19
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +42 -19
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +15 -0
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +15 -0
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +315 -20
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +1852 -7
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +90 -8
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +91 -20
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +11 -4
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +11 -4
- package/dist/lock/core/index.js.map +1 -1
- package/dist/logger/index.d.ts +17 -66
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +14 -63
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +15 -35
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +12 -35
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.browser.js +3 -3
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +7 -4
- package/dist/orm/index.bun.js.map +1 -1
- package/dist/orm/index.d.ts +514 -540
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +24 -49
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +18 -10
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js +14 -6
- package/dist/queue/core/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +108 -0
- package/dist/react/auth/index.browser.js.map +1 -0
- package/dist/react/auth/index.d.ts +100 -0
- package/dist/react/auth/index.d.ts.map +1 -0
- package/dist/react/auth/index.js +145 -0
- package/dist/react/auth/index.js.map +1 -0
- package/dist/react/core/index.d.ts +469 -0
- package/dist/react/core/index.d.ts.map +1 -0
- package/dist/react/core/index.js +464 -0
- package/dist/react/core/index.js.map +1 -0
- package/dist/react/form/index.d.ts +232 -0
- package/dist/react/form/index.d.ts.map +1 -0
- package/dist/react/form/index.js +432 -0
- package/dist/react/form/index.js.map +1 -0
- package/dist/react/head/index.browser.js +423 -0
- package/dist/react/head/index.browser.js.map +1 -0
- package/dist/react/head/index.d.ts +288 -0
- package/dist/react/head/index.d.ts.map +1 -0
- package/dist/react/head/index.js +465 -0
- package/dist/react/head/index.js.map +1 -0
- package/dist/react/i18n/index.d.ts +175 -0
- package/dist/react/i18n/index.d.ts.map +1 -0
- package/dist/react/i18n/index.js +224 -0
- package/dist/react/i18n/index.js.map +1 -0
- package/dist/react/router/index.browser.js +1980 -0
- package/dist/react/router/index.browser.js.map +1 -0
- package/dist/react/router/index.d.ts +2068 -0
- package/dist/react/router/index.d.ts.map +1 -0
- package/dist/react/router/index.js +4932 -0
- package/dist/react/router/index.js.map +1 -0
- package/dist/react/websocket/index.d.ts +117 -0
- package/dist/react/websocket/index.d.ts.map +1 -0
- package/dist/react/websocket/index.js +107 -0
- package/dist/react/websocket/index.js.map +1 -0
- package/dist/redis/index.bun.js +4 -0
- package/dist/redis/index.bun.js.map +1 -1
- package/dist/redis/index.d.ts +22 -25
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +16 -25
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +11 -2
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/retry/index.js +11 -2
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +11 -2
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +11 -2
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +110 -19
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +157 -26
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +179 -174
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +12 -7
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +7 -22
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +7 -22
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +10 -2
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +10 -2
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +40 -16
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +7 -5
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +115 -14
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +231 -14
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +13 -23
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js +7 -21
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/health/index.d.ts +25 -19
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/health/index.js +8 -2
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/helmet/index.d.ts +11 -3
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/helmet/index.js +11 -3
- package/dist/server/helmet/index.js.map +1 -1
- package/dist/server/links/index.d.ts +50 -45
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +11 -6
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +10 -3
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +10 -3
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts +9 -3
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/multipart/index.js +9 -3
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +8 -2
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/proxy/index.js +8 -2
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts +30 -35
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js +18 -55
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +137 -4
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +1848 -5
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +301 -6
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1849 -6
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +301 -7
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +1851 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js +496 -0
- package/dist/system/index.browser.js.map +1 -0
- package/dist/{file → system}/index.d.ts +335 -16
- package/dist/system/index.d.ts.map +1 -0
- package/dist/{file → system}/index.js +412 -20
- package/dist/system/index.js.map +1 -0
- package/dist/thread/index.d.ts +11 -2
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/thread/index.js +11 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts +12 -5
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/core/index.js +12 -5
- package/dist/topic/core/index.js.map +1 -1
- package/dist/vite/index.d.ts +4 -6271
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +8 -3
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +12 -8
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +12 -8
- package/dist/websocket/index.js.map +1 -1
- package/package.json +80 -11
- package/src/api/audits/index.ts +10 -33
- package/src/api/files/__tests__/$bucket.spec.ts +1 -1
- package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
- package/src/api/files/controllers/FileController.spec.ts +1 -1
- package/src/api/files/index.ts +10 -3
- package/src/api/files/jobs/FileJobs.spec.ts +1 -1
- package/src/api/files/services/FileService.spec.ts +1 -1
- package/src/api/jobs/index.ts +10 -3
- package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
- package/src/api/keys/controllers/ApiKeyController.ts +103 -0
- package/src/api/keys/entities/apiKeyEntity.ts +41 -0
- package/src/api/keys/index.ts +49 -0
- package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
- package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
- package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
- package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
- package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
- package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
- package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
- package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
- package/src/api/keys/services/ApiKeyService.ts +306 -0
- package/src/api/logs/TODO.md +52 -0
- package/src/api/notifications/index.ts +10 -4
- package/src/api/parameters/index.ts +9 -30
- package/src/api/parameters/primitives/$config.ts +12 -4
- package/src/api/parameters/services/ConfigStore.ts +9 -3
- package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
- package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
- package/src/api/users/index.ts +14 -3
- package/src/api/users/primitives/$realm.ts +33 -5
- package/src/api/users/providers/RealmProvider.ts +1 -12
- package/src/api/users/services/SessionService.ts +1 -1
- package/src/api/verifications/controllers/VerificationController.ts +2 -0
- package/src/api/verifications/index.ts +10 -4
- package/src/batch/index.ts +9 -36
- package/src/batch/primitives/$batch.ts +0 -8
- package/src/batch/providers/BatchProvider.ts +29 -2
- package/src/bucket/__tests__/shared.ts +1 -1
- package/src/bucket/index.ts +13 -6
- package/src/bucket/primitives/$bucket.ts +1 -1
- package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
- package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
- package/src/cache/core/__tests__/shared.ts +30 -0
- package/src/cache/core/index.ts +11 -6
- package/src/cache/core/primitives/$cache.spec.ts +5 -0
- package/src/cache/core/providers/CacheProvider.ts +17 -0
- package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
- package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
- package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
- package/src/cli/apps/AlephaCli.ts +1 -14
- package/src/cli/apps/AlephaPackageBuilderCli.ts +1 -1
- package/src/cli/commands/build.ts +1 -5
- package/src/cli/commands/db.ts +17 -11
- package/src/cli/commands/deploy.ts +1 -1
- package/src/cli/commands/dev.ts +1 -20
- package/src/cli/commands/gen/env.ts +5 -2
- package/src/cli/commands/gen/openapi.ts +5 -2
- package/src/cli/commands/init.spec.ts +544 -0
- package/src/cli/commands/init.ts +89 -55
- package/src/cli/commands/lint.ts +7 -1
- package/src/cli/commands/typecheck.ts +11 -0
- package/src/cli/providers/AppEntryProvider.ts +1 -1
- package/src/cli/providers/ViteBuildProvider.ts +8 -50
- package/src/cli/providers/ViteDevServerProvider.ts +36 -8
- package/src/cli/services/AlephaCliUtils.ts +37 -122
- package/src/cli/services/PackageManagerUtils.ts +127 -11
- package/src/cli/services/ProjectScaffolder.ts +122 -77
- package/src/cli/services/ViteUtils.ts +82 -0
- package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +32 -24
- package/src/cli/templates/gitignore.ts +39 -0
- package/src/cli/{assets → templates}/mainCss.ts +11 -2
- package/src/cli/templates/mainServerTs.ts +33 -0
- package/src/cli/templates/webAppRouterTs.ts +50 -0
- package/src/cli/{assets → templates}/webHelloComponentTsx.ts +2 -2
- package/src/command/helpers/Runner.spec.ts +4 -0
- package/src/command/helpers/Runner.ts +3 -21
- package/src/command/index.ts +12 -4
- package/src/command/providers/CliProvider.spec.ts +1067 -0
- package/src/command/providers/CliProvider.ts +203 -40
- package/src/core/Alepha.ts +2 -2
- package/src/core/__tests__/Alepha-start.spec.ts +4 -4
- package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
- package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +20 -0
- package/src/core/providers/EventManager.spec.ts +0 -71
- package/src/core/providers/EventManager.ts +3 -15
- package/src/core/providers/Json.ts +2 -14
- package/src/datetime/index.ts +15 -0
- package/src/email/index.ts +10 -5
- package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
- package/src/email/providers/LocalEmailProvider.ts +1 -1
- package/src/fake/__tests__/keyName.example.ts +1 -1
- package/src/fake/__tests__/keyName.spec.ts +5 -5
- package/src/fake/index.ts +9 -6
- package/src/fake/providers/FakeProvider.spec.ts +258 -40
- package/src/fake/providers/FakeProvider.ts +133 -19
- package/src/lock/core/index.ts +11 -4
- package/src/logger/index.ts +17 -66
- package/src/mcp/index.ts +10 -27
- package/src/mcp/transports/SseMcpTransport.ts +0 -11
- package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.bun.ts +4 -2
- package/src/orm/index.ts +21 -47
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -0
- package/src/orm/services/Repository.ts +7 -3
- package/src/queue/core/index.ts +14 -6
- package/src/react/auth/__tests__/$auth.spec.ts +202 -0
- package/src/react/auth/hooks/useAuth.ts +32 -0
- package/src/react/auth/index.browser.ts +13 -0
- package/src/react/auth/index.shared.ts +2 -0
- package/src/react/auth/index.ts +48 -0
- package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
- package/src/react/auth/services/ReactAuth.ts +135 -0
- package/src/react/core/__tests__/Router.spec.tsx +169 -0
- package/src/react/core/components/ClientOnly.tsx +49 -0
- package/src/react/core/components/ErrorBoundary.tsx +73 -0
- package/src/react/core/contexts/AlephaContext.ts +7 -0
- package/src/react/core/contexts/AlephaProvider.tsx +42 -0
- package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
- package/src/react/core/hooks/useAction.ts +480 -0
- package/src/react/core/hooks/useAlepha.ts +26 -0
- package/src/react/core/hooks/useClient.ts +17 -0
- package/src/react/core/hooks/useEvents.ts +51 -0
- package/src/react/core/hooks/useInject.ts +12 -0
- package/src/react/core/hooks/useStore.ts +52 -0
- package/src/react/core/index.ts +90 -0
- package/src/react/form/components/FormState.tsx +17 -0
- package/src/react/form/errors/FormValidationError.ts +18 -0
- package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
- package/src/react/form/hooks/useForm.ts +47 -0
- package/src/react/form/hooks/useFormState.ts +130 -0
- package/src/react/form/index.ts +44 -0
- package/src/react/form/services/FormModel.ts +614 -0
- package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
- package/src/react/head/helpers/SeoExpander.ts +142 -0
- package/src/react/head/hooks/useHead.spec.tsx +288 -0
- package/src/react/head/hooks/useHead.ts +62 -0
- package/src/react/head/index.browser.ts +26 -0
- package/src/react/head/index.ts +44 -0
- package/src/react/head/interfaces/Head.ts +105 -0
- package/src/react/head/primitives/$head.ts +25 -0
- package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
- package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
- package/src/react/head/providers/HeadProvider.ts +168 -0
- package/src/react/head/providers/ServerHeadProvider.ts +31 -0
- package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
- package/src/react/i18n/components/Localize.spec.tsx +357 -0
- package/src/react/i18n/components/Localize.tsx +35 -0
- package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
- package/src/react/i18n/hooks/useI18n.ts +18 -0
- package/src/react/i18n/index.ts +41 -0
- package/src/react/i18n/primitives/$dictionary.ts +69 -0
- package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
- package/src/react/i18n/providers/I18nProvider.ts +278 -0
- package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
- package/src/react/router/__tests__/page-head.spec.ts +48 -0
- package/src/react/router/__tests__/seo-head.spec.ts +125 -0
- package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
- package/src/react/router/components/ErrorViewer.tsx +872 -0
- package/src/react/router/components/Link.tsx +23 -0
- package/src/react/router/components/NestedView.tsx +223 -0
- package/src/react/router/components/NotFound.tsx +30 -0
- package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
- package/src/react/router/contexts/RouterLayerContext.ts +12 -0
- package/src/react/router/errors/Redirection.ts +28 -0
- package/src/react/router/hooks/useActive.ts +52 -0
- package/src/react/router/hooks/useQueryParams.ts +63 -0
- package/src/react/router/hooks/useRouter.ts +20 -0
- package/src/react/router/hooks/useRouterState.ts +11 -0
- package/src/react/router/index.browser.ts +45 -0
- package/src/react/router/index.shared.ts +19 -0
- package/src/react/router/index.ts +142 -0
- package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
- package/src/react/router/primitives/$page.spec.tsx +708 -0
- package/src/react/router/primitives/$page.ts +497 -0
- package/src/react/router/providers/ReactBrowserProvider.ts +309 -0
- package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
- package/src/react/router/providers/ReactPageProvider.ts +726 -0
- package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
- package/src/react/router/providers/ReactServerProvider.ts +558 -0
- package/src/react/router/providers/ReactServerTemplateProvider.ts +979 -0
- package/src/react/router/providers/SSRManifestProvider.ts +334 -0
- package/src/react/router/services/ReactPageServerService.ts +48 -0
- package/src/react/router/services/ReactPageService.ts +27 -0
- package/src/react/router/services/ReactRouter.ts +262 -0
- package/src/react/websocket/hooks/useRoom.tsx +242 -0
- package/src/react/websocket/index.ts +7 -0
- package/src/redis/__tests__/redis.spec.ts +13 -0
- package/src/redis/index.ts +9 -25
- package/src/redis/providers/BunRedisProvider.ts +9 -0
- package/src/redis/providers/NodeRedisProvider.ts +8 -0
- package/src/redis/providers/RedisProvider.ts +16 -0
- package/src/retry/index.ts +11 -2
- package/src/router/index.ts +15 -0
- package/src/scheduler/index.ts +11 -2
- package/src/security/__tests__/BasicAuth.spec.ts +2 -0
- package/src/security/__tests__/ServerSecurityProvider.spec.ts +13 -5
- package/src/security/index.ts +15 -10
- package/src/security/interfaces/IssuerResolver.ts +27 -0
- package/src/security/primitives/$issuer.ts +55 -0
- package/src/security/providers/SecurityProvider.ts +179 -0
- package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
- package/src/security/providers/ServerSecurityProvider.ts +36 -22
- package/src/server/auth/index.ts +12 -7
- package/src/server/cache/index.ts +7 -22
- package/src/server/compress/index.ts +10 -2
- package/src/server/cookies/index.ts +7 -5
- package/src/server/cookies/primitives/$cookie.ts +33 -11
- package/src/server/core/index.ts +16 -6
- package/src/server/core/interfaces/ServerRequest.ts +83 -1
- package/src/server/core/primitives/$action.spec.ts +1 -1
- package/src/server/core/primitives/$action.ts +8 -3
- package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
- package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
- package/src/server/core/services/ServerRequestParser.ts +306 -13
- package/src/server/cors/index.ts +7 -21
- package/src/server/cors/primitives/$cors.ts +6 -2
- package/src/server/health/index.ts +8 -2
- package/src/server/helmet/index.ts +11 -3
- package/src/server/links/index.ts +11 -6
- package/src/server/metrics/index.ts +10 -3
- package/src/server/multipart/index.ts +9 -3
- package/src/server/proxy/index.ts +8 -2
- package/src/server/rate-limit/index.ts +21 -25
- package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
- package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
- package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
- package/src/server/static/index.ts +8 -2
- package/src/server/static/providers/ServerStaticProvider.ts +1 -1
- package/src/server/swagger/index.ts +9 -4
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
- package/src/sms/index.ts +9 -5
- package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.ts +1 -1
- package/src/system/index.browser.ts +11 -0
- package/src/system/index.ts +62 -0
- package/src/{file → system}/providers/FileSystemProvider.ts +16 -0
- package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
- package/src/system/providers/MemoryShellProvider.ts +164 -0
- package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
- package/src/{file → system}/providers/NodeFileSystemProvider.ts +36 -0
- package/src/system/providers/NodeShellProvider.ts +184 -0
- package/src/system/providers/ShellProvider.ts +74 -0
- package/src/{file → system}/services/FileDetector.spec.ts +2 -2
- package/src/thread/index.ts +11 -2
- package/src/topic/core/index.ts +12 -5
- package/src/vite/tasks/buildClient.ts +2 -7
- package/src/vite/tasks/buildServer.ts +17 -1
- package/src/websocket/index.ts +12 -8
- package/dist/file/index.d.ts.map +0 -1
- package/dist/file/index.js.map +0 -1
- package/src/cli/assets/mainServerTs.ts +0 -24
- package/src/cli/assets/webAppRouterTs.ts +0 -16
- package/src/cli/providers/ViteTemplateProvider.ts +0 -27
- package/src/file/index.ts +0 -43
- /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
- /package/src/cli/{assets → templates}/apiIndexTs.ts +0 -0
- /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
- /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
- /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
- /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
- /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
- /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
- /package/src/{file → system}/errors/FileError.ts +0 -0
- /package/src/{file → system}/services/FileDetector.ts +0 -0
|
@@ -0,0 +1,1067 @@
|
|
|
1
|
+
import { Alepha, t } from "alepha";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { $command } from "../primitives/$command.ts";
|
|
4
|
+
import { CliProvider } from "./CliProvider.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test subclass that exposes protected methods for unit testing.
|
|
8
|
+
*/
|
|
9
|
+
class TestCliProvider extends CliProvider {
|
|
10
|
+
public testParseFlags = this.parseFlags.bind(this);
|
|
11
|
+
public testParseCommandArgs = this.parseCommandArgs.bind(this);
|
|
12
|
+
public testParseArgumentValue = this.parseArgumentValue.bind(this);
|
|
13
|
+
public testParseModeFlag = this.parseModeFlag.bind(this);
|
|
14
|
+
public testResolveCommand = this.resolveCommand.bind(this);
|
|
15
|
+
public testRemoveConsumedArgs = this.removeConsumedArgs.bind(this);
|
|
16
|
+
public testGetFlagConsumedIndices = this.getFlagConsumedIndices.bind(this);
|
|
17
|
+
public testGenerateArgsUsage = this.generateArgsUsage.bind(this);
|
|
18
|
+
public testGenerateColoredArgsUsage =
|
|
19
|
+
this.generateColoredArgsUsage.bind(this);
|
|
20
|
+
public testGetTypeName = this.getTypeName.bind(this);
|
|
21
|
+
public testGetTopLevelCommands = this.getTopLevelCommands.bind(this);
|
|
22
|
+
public testFindParentCommand = this.findParentCommand.bind(this);
|
|
23
|
+
public testGetCommandPath = this.getCommandPath.bind(this);
|
|
24
|
+
public testFindCommand = this.findCommand.bind(this);
|
|
25
|
+
public testFindPreHooks = this.findPreHooks.bind(this);
|
|
26
|
+
public testFindPostHooks = this.findPostHooks.bind(this);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("CliProvider", () => {
|
|
30
|
+
const createTestCli = () => {
|
|
31
|
+
const alepha = Alepha.create();
|
|
32
|
+
return alepha.inject(TestCliProvider);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
// parseFlags
|
|
37
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
describe("parseFlags", () => {
|
|
40
|
+
it("should parse boolean flags", () => {
|
|
41
|
+
const cli = createTestCli();
|
|
42
|
+
const flagDefs = [
|
|
43
|
+
{ key: "verbose", aliases: ["v", "verbose"], schema: t.boolean() },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const result = cli.testParseFlags(["--verbose"], flagDefs);
|
|
47
|
+
expect(result.verbose).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should parse short boolean flags", () => {
|
|
51
|
+
const cli = createTestCli();
|
|
52
|
+
const flagDefs = [
|
|
53
|
+
{ key: "verbose", aliases: ["v", "verbose"], schema: t.boolean() },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const result = cli.testParseFlags(["-v"], flagDefs);
|
|
57
|
+
expect(result.verbose).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should parse string flags with = syntax", () => {
|
|
61
|
+
const cli = createTestCli();
|
|
62
|
+
const flagDefs = [
|
|
63
|
+
{ key: "name", aliases: ["n", "name"], schema: t.string() },
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const result = cli.testParseFlags(["--name=hello"], flagDefs);
|
|
67
|
+
expect(result.name).toBe("hello");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should parse string flags with space syntax", () => {
|
|
71
|
+
const cli = createTestCli();
|
|
72
|
+
const flagDefs = [
|
|
73
|
+
{ key: "name", aliases: ["n", "name"], schema: t.string() },
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const result = cli.testParseFlags(["--name", "hello"], flagDefs);
|
|
77
|
+
expect(result.name).toBe("hello");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should parse JSON object flags", () => {
|
|
81
|
+
const cli = createTestCli();
|
|
82
|
+
const flagDefs = [
|
|
83
|
+
{ key: "config", aliases: ["config"], schema: t.object({}) },
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const result = cli.testParseFlags(
|
|
87
|
+
["--config", '{"key":"value"}'],
|
|
88
|
+
flagDefs,
|
|
89
|
+
);
|
|
90
|
+
expect(result.config).toEqual({ key: "value" });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should parse JSON array flags", () => {
|
|
94
|
+
const cli = createTestCli();
|
|
95
|
+
const flagDefs = [
|
|
96
|
+
{ key: "items", aliases: ["items"], schema: t.array(t.string()) },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const result = cli.testParseFlags(["--items", '["a","b"]'], flagDefs);
|
|
100
|
+
expect(result.items).toEqual(["a", "b"]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("should throw on unknown flags", () => {
|
|
104
|
+
const cli = createTestCli();
|
|
105
|
+
const flagDefs = [
|
|
106
|
+
{ key: "known", aliases: ["known"], schema: t.boolean() },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
expect(() =>
|
|
110
|
+
cli.testParseFlags(["--unknown", "--known"], flagDefs),
|
|
111
|
+
).toThrow("Unknown flag: --unknown");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should throw on missing required value", () => {
|
|
115
|
+
const cli = createTestCli();
|
|
116
|
+
const flagDefs = [{ key: "name", aliases: ["name"], schema: t.string() }];
|
|
117
|
+
|
|
118
|
+
expect(() => cli.testParseFlags(["--name"], flagDefs)).toThrow(
|
|
119
|
+
"requires a value",
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should throw on invalid JSON", () => {
|
|
124
|
+
const cli = createTestCli();
|
|
125
|
+
const flagDefs = [
|
|
126
|
+
{ key: "config", aliases: ["config"], schema: t.object({}) },
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
expect(() =>
|
|
130
|
+
cli.testParseFlags(["--config", "{invalid}"], flagDefs),
|
|
131
|
+
).toThrow("Invalid JSON");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
// parseArgumentValue
|
|
137
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
describe("parseArgumentValue", () => {
|
|
140
|
+
it("should parse string values", () => {
|
|
141
|
+
const cli = createTestCli();
|
|
142
|
+
expect(cli.testParseArgumentValue("hello", t.string())).toBe("hello");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should parse number values", () => {
|
|
146
|
+
const cli = createTestCli();
|
|
147
|
+
expect(cli.testParseArgumentValue("42", t.number())).toBe(42);
|
|
148
|
+
expect(cli.testParseArgumentValue("3.14", t.number())).toBe(3.14);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should throw on invalid number", () => {
|
|
152
|
+
const cli = createTestCli();
|
|
153
|
+
expect(() => cli.testParseArgumentValue("abc", t.number())).toThrow(
|
|
154
|
+
"Expected number",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should parse integer values", () => {
|
|
159
|
+
const cli = createTestCli();
|
|
160
|
+
expect(cli.testParseArgumentValue("42", t.integer())).toBe(42);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should throw on non-integer for integer schema", () => {
|
|
164
|
+
const cli = createTestCli();
|
|
165
|
+
expect(() => cli.testParseArgumentValue("3.14", t.integer())).toThrow(
|
|
166
|
+
"Expected integer",
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should parse boolean true values", () => {
|
|
171
|
+
const cli = createTestCli();
|
|
172
|
+
expect(cli.testParseArgumentValue("true", t.boolean())).toBe(true);
|
|
173
|
+
expect(cli.testParseArgumentValue("1", t.boolean())).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should parse boolean false values", () => {
|
|
177
|
+
const cli = createTestCli();
|
|
178
|
+
expect(cli.testParseArgumentValue("false", t.boolean())).toBe(false);
|
|
179
|
+
expect(cli.testParseArgumentValue("0", t.boolean())).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should throw on invalid boolean", () => {
|
|
183
|
+
const cli = createTestCli();
|
|
184
|
+
expect(() => cli.testParseArgumentValue("yes", t.boolean())).toThrow(
|
|
185
|
+
"Expected boolean",
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
+
// parseCommandArgs
|
|
192
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
describe("parseCommandArgs", () => {
|
|
195
|
+
it("should return undefined when no schema", () => {
|
|
196
|
+
const cli = createTestCli();
|
|
197
|
+
expect(
|
|
198
|
+
cli.testParseCommandArgs(["arg"], undefined, true),
|
|
199
|
+
).toBeUndefined();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should parse optional args when present", () => {
|
|
203
|
+
const cli = createTestCli();
|
|
204
|
+
const schema = t.optional(t.string());
|
|
205
|
+
expect(cli.testParseCommandArgs(["hello"], schema, true)).toBe("hello");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should return undefined for optional args when missing", () => {
|
|
209
|
+
const cli = createTestCli();
|
|
210
|
+
const schema = t.optional(t.string());
|
|
211
|
+
expect(cli.testParseCommandArgs([], schema, true)).toBeUndefined();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should parse required args", () => {
|
|
215
|
+
const cli = createTestCli();
|
|
216
|
+
const schema = t.string();
|
|
217
|
+
expect(cli.testParseCommandArgs(["hello"], schema, true)).toBe("hello");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("should throw on missing required args", () => {
|
|
221
|
+
const cli = createTestCli();
|
|
222
|
+
const schema = t.string();
|
|
223
|
+
expect(() => cli.testParseCommandArgs([], schema, true)).toThrow(
|
|
224
|
+
"Missing required argument",
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("should parse tuple args", () => {
|
|
229
|
+
const cli = createTestCli();
|
|
230
|
+
const schema = t.tuple([t.string(), t.number()]);
|
|
231
|
+
const result = cli.testParseCommandArgs(["hello", "42"], schema, true);
|
|
232
|
+
expect(result).toEqual(["hello", 42]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("should handle optional tuple items", () => {
|
|
236
|
+
const cli = createTestCli();
|
|
237
|
+
const schema = t.tuple([t.string(), t.optional(t.number())]);
|
|
238
|
+
const result = cli.testParseCommandArgs(["hello"], schema, true);
|
|
239
|
+
expect(result).toEqual(["hello", undefined]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should skip flags when parsing args", () => {
|
|
243
|
+
const cli = createTestCli();
|
|
244
|
+
const schema = t.string();
|
|
245
|
+
const flags = t.object({ verbose: t.optional(t.boolean()) });
|
|
246
|
+
const result = cli.testParseCommandArgs(
|
|
247
|
+
["--verbose", "hello"],
|
|
248
|
+
schema,
|
|
249
|
+
true,
|
|
250
|
+
flags,
|
|
251
|
+
);
|
|
252
|
+
expect(result).toBe("hello");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should skip flag values when parsing args", () => {
|
|
256
|
+
const cli = createTestCli();
|
|
257
|
+
const schema = t.string();
|
|
258
|
+
const flags = t.object({ name: t.optional(t.string()) });
|
|
259
|
+
const result = cli.testParseCommandArgs(
|
|
260
|
+
["--name", "ignored", "actual"],
|
|
261
|
+
schema,
|
|
262
|
+
true,
|
|
263
|
+
flags,
|
|
264
|
+
);
|
|
265
|
+
expect(result).toBe("actual");
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
270
|
+
// parseModeFlag
|
|
271
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
describe("parseModeFlag", () => {
|
|
274
|
+
it("should parse --mode=value", () => {
|
|
275
|
+
const cli = createTestCli();
|
|
276
|
+
expect(cli.testParseModeFlag(["--mode=production"])).toBe("production");
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("should parse -m=value", () => {
|
|
280
|
+
const cli = createTestCli();
|
|
281
|
+
expect(cli.testParseModeFlag(["-m=staging"])).toBe("staging");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("should parse --mode value", () => {
|
|
285
|
+
const cli = createTestCli();
|
|
286
|
+
expect(cli.testParseModeFlag(["--mode", "production"])).toBe(
|
|
287
|
+
"production",
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("should parse -m value", () => {
|
|
292
|
+
const cli = createTestCli();
|
|
293
|
+
expect(cli.testParseModeFlag(["-m", "staging"])).toBe("staging");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("should return undefined when no mode flag", () => {
|
|
297
|
+
const cli = createTestCli();
|
|
298
|
+
expect(cli.testParseModeFlag(["--other", "value"])).toBeUndefined();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should throw when --mode has no value", () => {
|
|
302
|
+
const cli = createTestCli();
|
|
303
|
+
expect(() => cli.testParseModeFlag(["--mode"])).toThrow(
|
|
304
|
+
"requires a value",
|
|
305
|
+
);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("should throw when --mode followed by another flag", () => {
|
|
309
|
+
const cli = createTestCli();
|
|
310
|
+
expect(() => cli.testParseModeFlag(["--mode", "--other"])).toThrow(
|
|
311
|
+
"requires a value",
|
|
312
|
+
);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
317
|
+
// resolveCommand
|
|
318
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
319
|
+
|
|
320
|
+
describe("resolveCommand", () => {
|
|
321
|
+
it("should return undefined for empty args", () => {
|
|
322
|
+
const cli = createTestCli();
|
|
323
|
+
const result = cli.testResolveCommand([]);
|
|
324
|
+
expect(result.command).toBeUndefined();
|
|
325
|
+
expect(result.consumedArgs).toEqual([]);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("should find command by name", () => {
|
|
329
|
+
class TestCommands {
|
|
330
|
+
build = $command({
|
|
331
|
+
name: "build",
|
|
332
|
+
flags: t.object({}),
|
|
333
|
+
handler: async () => {},
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
338
|
+
const cli = alepha.inject(TestCliProvider);
|
|
339
|
+
|
|
340
|
+
const result = cli.testResolveCommand(["build"]);
|
|
341
|
+
expect(result.command?.name).toBe("build");
|
|
342
|
+
expect(result.consumedArgs).toEqual(["build"]);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("should find command by colon notation", () => {
|
|
346
|
+
class TestCommands {
|
|
347
|
+
deployVercel = $command({
|
|
348
|
+
name: "deploy:vercel",
|
|
349
|
+
flags: t.object({}),
|
|
350
|
+
handler: async () => {},
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
355
|
+
const cli = alepha.inject(TestCliProvider);
|
|
356
|
+
|
|
357
|
+
const result = cli.testResolveCommand(["deploy:vercel"]);
|
|
358
|
+
expect(result.command?.name).toBe("deploy:vercel");
|
|
359
|
+
expect(result.consumedArgs).toEqual(["deploy:vercel"]);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("should return undefined for unknown command", () => {
|
|
363
|
+
const cli = createTestCli();
|
|
364
|
+
const result = cli.testResolveCommand(["unknown"]);
|
|
365
|
+
expect(result.command).toBeUndefined();
|
|
366
|
+
expect(result.consumedArgs).toEqual([]);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
371
|
+
// removeConsumedArgs
|
|
372
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
373
|
+
|
|
374
|
+
describe("removeConsumedArgs", () => {
|
|
375
|
+
it("should remove consumed command args", () => {
|
|
376
|
+
const cli = createTestCli();
|
|
377
|
+
const result = cli.testRemoveConsumedArgs(
|
|
378
|
+
["build", "--verbose", "extra"],
|
|
379
|
+
["build"],
|
|
380
|
+
);
|
|
381
|
+
expect(result).toEqual(["--verbose", "extra"]);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("should preserve flags", () => {
|
|
385
|
+
const cli = createTestCli();
|
|
386
|
+
const result = cli.testRemoveConsumedArgs(
|
|
387
|
+
["--flag", "build", "arg"],
|
|
388
|
+
["build"],
|
|
389
|
+
);
|
|
390
|
+
expect(result).toEqual(["--flag", "arg"]);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("should remove multiple consumed args", () => {
|
|
394
|
+
const cli = createTestCli();
|
|
395
|
+
const result = cli.testRemoveConsumedArgs(
|
|
396
|
+
["deploy", "vercel", "--prod"],
|
|
397
|
+
["deploy", "vercel"],
|
|
398
|
+
);
|
|
399
|
+
expect(result).toEqual(["--prod"]);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
404
|
+
// getFlagConsumedIndices
|
|
405
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
406
|
+
|
|
407
|
+
describe("getFlagConsumedIndices", () => {
|
|
408
|
+
it("should mark flag indices as consumed", () => {
|
|
409
|
+
const cli = createTestCli();
|
|
410
|
+
const flagDefs = [
|
|
411
|
+
{ key: "verbose", aliases: ["v", "verbose"], schema: t.boolean() },
|
|
412
|
+
];
|
|
413
|
+
|
|
414
|
+
const result = cli.testGetFlagConsumedIndices(["--verbose"], flagDefs);
|
|
415
|
+
expect(result.has(0)).toBe(true);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("should mark flag value indices as consumed", () => {
|
|
419
|
+
const cli = createTestCli();
|
|
420
|
+
const flagDefs = [{ key: "name", aliases: ["name"], schema: t.string() }];
|
|
421
|
+
|
|
422
|
+
const result = cli.testGetFlagConsumedIndices(
|
|
423
|
+
["--name", "value", "arg"],
|
|
424
|
+
flagDefs,
|
|
425
|
+
);
|
|
426
|
+
expect(result.has(0)).toBe(true); // --name
|
|
427
|
+
expect(result.has(1)).toBe(true); // value
|
|
428
|
+
expect(result.has(2)).toBe(false); // arg
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("should not consume next arg for --flag=value syntax", () => {
|
|
432
|
+
const cli = createTestCli();
|
|
433
|
+
const flagDefs = [{ key: "name", aliases: ["name"], schema: t.string() }];
|
|
434
|
+
|
|
435
|
+
const result = cli.testGetFlagConsumedIndices(
|
|
436
|
+
["--name=value", "arg"],
|
|
437
|
+
flagDefs,
|
|
438
|
+
);
|
|
439
|
+
expect(result.has(0)).toBe(true); // --name=value
|
|
440
|
+
expect(result.has(1)).toBe(false); // arg
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
445
|
+
// generateArgsUsage
|
|
446
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
447
|
+
|
|
448
|
+
describe("generateArgsUsage", () => {
|
|
449
|
+
it("should return empty string for no schema", () => {
|
|
450
|
+
const cli = createTestCli();
|
|
451
|
+
expect(cli.testGenerateArgsUsage(undefined)).toBe("");
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it("should generate optional arg usage", () => {
|
|
455
|
+
const cli = createTestCli();
|
|
456
|
+
const schema = t.optional(t.string({ title: "path" }));
|
|
457
|
+
expect(cli.testGenerateArgsUsage(schema)).toBe(" [path]");
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it("should generate required arg usage", () => {
|
|
461
|
+
const cli = createTestCli();
|
|
462
|
+
const schema = t.string({ title: "path" });
|
|
463
|
+
expect(cli.testGenerateArgsUsage(schema)).toBe(" <path>");
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("should generate tuple arg usage", () => {
|
|
467
|
+
const cli = createTestCli();
|
|
468
|
+
const schema = t.tuple([t.string(), t.optional(t.number())]);
|
|
469
|
+
const result = cli.testGenerateArgsUsage(schema);
|
|
470
|
+
expect(result).toContain("<arg1>");
|
|
471
|
+
expect(result).toContain("[arg2");
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it("should include type for numbers", () => {
|
|
475
|
+
const cli = createTestCli();
|
|
476
|
+
const schema = t.number({ title: "count" });
|
|
477
|
+
expect(cli.testGenerateArgsUsage(schema)).toBe(" <count: number>");
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it("should include type for integers", () => {
|
|
481
|
+
const cli = createTestCli();
|
|
482
|
+
const schema = t.integer({ title: "port" });
|
|
483
|
+
expect(cli.testGenerateArgsUsage(schema)).toBe(" <port: integer>");
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it("should include type for booleans", () => {
|
|
487
|
+
const cli = createTestCli();
|
|
488
|
+
const schema = t.boolean({ title: "force" });
|
|
489
|
+
expect(cli.testGenerateArgsUsage(schema)).toBe(" <force: boolean>");
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
494
|
+
// getTypeName
|
|
495
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
496
|
+
|
|
497
|
+
describe("getTypeName", () => {
|
|
498
|
+
it("should return empty for string", () => {
|
|
499
|
+
const cli = createTestCli();
|
|
500
|
+
expect(cli.testGetTypeName(t.string())).toBe("");
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it("should return ': number' for number", () => {
|
|
504
|
+
const cli = createTestCli();
|
|
505
|
+
expect(cli.testGetTypeName(t.number())).toBe(": number");
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it("should return ': integer' for integer", () => {
|
|
509
|
+
const cli = createTestCli();
|
|
510
|
+
expect(cli.testGetTypeName(t.integer())).toBe(": integer");
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it("should return ': boolean' for boolean", () => {
|
|
514
|
+
const cli = createTestCli();
|
|
515
|
+
expect(cli.testGetTypeName(t.boolean())).toBe(": boolean");
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
520
|
+
// generateColoredArgsUsage
|
|
521
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
522
|
+
|
|
523
|
+
describe("generateColoredArgsUsage", () => {
|
|
524
|
+
it("should return empty string for no schema", () => {
|
|
525
|
+
const cli = createTestCli();
|
|
526
|
+
expect(cli.testGenerateColoredArgsUsage(undefined)).toBe("");
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it("should generate colored optional arg usage", () => {
|
|
530
|
+
const cli = createTestCli();
|
|
531
|
+
const schema = t.optional(t.string({ title: "path" }));
|
|
532
|
+
const result = cli.testGenerateColoredArgsUsage(schema);
|
|
533
|
+
expect(result).toContain("[path]");
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it("should generate colored required arg usage", () => {
|
|
537
|
+
const cli = createTestCli();
|
|
538
|
+
const schema = t.string({ title: "path" });
|
|
539
|
+
const result = cli.testGenerateColoredArgsUsage(schema);
|
|
540
|
+
expect(result).toContain("<path>");
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it("should generate colored tuple arg usage", () => {
|
|
544
|
+
const cli = createTestCli();
|
|
545
|
+
const schema = t.tuple([t.string(), t.optional(t.number())]);
|
|
546
|
+
const result = cli.testGenerateColoredArgsUsage(schema);
|
|
547
|
+
expect(result).toContain("<arg1>");
|
|
548
|
+
expect(result).toContain("[arg2");
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
553
|
+
// findCommand
|
|
554
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
555
|
+
|
|
556
|
+
describe("findCommand", () => {
|
|
557
|
+
it("should return undefined for unknown command", () => {
|
|
558
|
+
const cli = createTestCli();
|
|
559
|
+
expect(cli.testFindCommand("unknown")).toBeUndefined();
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("should find command by name", () => {
|
|
563
|
+
class TestCommands {
|
|
564
|
+
test = $command({
|
|
565
|
+
name: "test",
|
|
566
|
+
flags: t.object({}),
|
|
567
|
+
handler: async () => {},
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
572
|
+
const cli = alepha.inject(TestCliProvider);
|
|
573
|
+
|
|
574
|
+
expect(cli.testFindCommand("test")?.name).toBe("test");
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
it("should find command by alias", () => {
|
|
578
|
+
class TestCommands {
|
|
579
|
+
test = $command({
|
|
580
|
+
name: "test",
|
|
581
|
+
aliases: ["t"],
|
|
582
|
+
flags: t.object({}),
|
|
583
|
+
handler: async () => {},
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
588
|
+
const cli = alepha.inject(TestCliProvider);
|
|
589
|
+
|
|
590
|
+
expect(cli.testFindCommand("t")?.name).toBe("test");
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
595
|
+
// findPreHooks / findPostHooks
|
|
596
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
597
|
+
|
|
598
|
+
describe("findPreHooks", () => {
|
|
599
|
+
it("should return empty array when no hooks", () => {
|
|
600
|
+
const cli = createTestCli();
|
|
601
|
+
expect(cli.testFindPreHooks("build")).toEqual([]);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it("should find pre-hooks for command", () => {
|
|
605
|
+
class TestCommands {
|
|
606
|
+
preBuild = $command({
|
|
607
|
+
name: "prebuild",
|
|
608
|
+
flags: t.object({}),
|
|
609
|
+
handler: async () => {},
|
|
610
|
+
});
|
|
611
|
+
build = $command({
|
|
612
|
+
name: "build",
|
|
613
|
+
flags: t.object({}),
|
|
614
|
+
handler: async () => {},
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
619
|
+
const cli = alepha.inject(TestCliProvider);
|
|
620
|
+
|
|
621
|
+
expect(cli.testFindPreHooks("build").length).toBe(1);
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
describe("findPostHooks", () => {
|
|
626
|
+
it("should return empty array when no hooks", () => {
|
|
627
|
+
const cli = createTestCli();
|
|
628
|
+
expect(cli.testFindPostHooks("build")).toEqual([]);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it("should find post-hooks for command", () => {
|
|
632
|
+
class TestCommands {
|
|
633
|
+
build = $command({
|
|
634
|
+
name: "build",
|
|
635
|
+
flags: t.object({}),
|
|
636
|
+
handler: async () => {},
|
|
637
|
+
});
|
|
638
|
+
postBuild = $command({
|
|
639
|
+
name: "postbuild",
|
|
640
|
+
flags: t.object({}),
|
|
641
|
+
handler: async () => {},
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
646
|
+
const cli = alepha.inject(TestCliProvider);
|
|
647
|
+
|
|
648
|
+
expect(cli.testFindPostHooks("build").length).toBe(1);
|
|
649
|
+
});
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
653
|
+
// getTopLevelCommands
|
|
654
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
655
|
+
|
|
656
|
+
describe("getTopLevelCommands", () => {
|
|
657
|
+
it("should return all commands when no children", () => {
|
|
658
|
+
class TestCommands {
|
|
659
|
+
build = $command({
|
|
660
|
+
name: "build",
|
|
661
|
+
flags: t.object({}),
|
|
662
|
+
handler: async () => {},
|
|
663
|
+
});
|
|
664
|
+
test = $command({
|
|
665
|
+
name: "test",
|
|
666
|
+
flags: t.object({}),
|
|
667
|
+
handler: async () => {},
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
672
|
+
const cli = alepha.inject(TestCliProvider);
|
|
673
|
+
|
|
674
|
+
const topLevel = cli.testGetTopLevelCommands();
|
|
675
|
+
expect(topLevel.length).toBe(2);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
it("should exclude child commands", () => {
|
|
679
|
+
class TestCommands {
|
|
680
|
+
deployVercel = $command({
|
|
681
|
+
name: "vercel",
|
|
682
|
+
flags: t.object({}),
|
|
683
|
+
handler: async () => {},
|
|
684
|
+
});
|
|
685
|
+
deploy = $command({
|
|
686
|
+
name: "deploy",
|
|
687
|
+
flags: t.object({}),
|
|
688
|
+
children: [this.deployVercel],
|
|
689
|
+
handler: async () => {},
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
694
|
+
const cli = alepha.inject(TestCliProvider);
|
|
695
|
+
|
|
696
|
+
const topLevel = cli.testGetTopLevelCommands();
|
|
697
|
+
expect(topLevel.length).toBe(1);
|
|
698
|
+
expect(topLevel[0].name).toBe("deploy");
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
703
|
+
// findParentCommand
|
|
704
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
705
|
+
|
|
706
|
+
describe("findParentCommand", () => {
|
|
707
|
+
it("should return undefined for top-level command", () => {
|
|
708
|
+
class TestCommands {
|
|
709
|
+
build = $command({
|
|
710
|
+
name: "build",
|
|
711
|
+
flags: t.object({}),
|
|
712
|
+
handler: async () => {},
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
717
|
+
const cli = alepha.inject(TestCliProvider);
|
|
718
|
+
const cmd = cli.testFindCommand("build")!;
|
|
719
|
+
|
|
720
|
+
expect(cli.testFindParentCommand(cmd)).toBeUndefined();
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
it("should find parent of child command", () => {
|
|
724
|
+
class TestCommands {
|
|
725
|
+
deployVercel = $command({
|
|
726
|
+
name: "vercel",
|
|
727
|
+
flags: t.object({}),
|
|
728
|
+
handler: async () => {},
|
|
729
|
+
});
|
|
730
|
+
deploy = $command({
|
|
731
|
+
name: "deploy",
|
|
732
|
+
flags: t.object({}),
|
|
733
|
+
children: [this.deployVercel],
|
|
734
|
+
handler: async () => {},
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
739
|
+
const cli = alepha.inject(TestCliProvider);
|
|
740
|
+
const child = cli.testFindCommand("vercel")!;
|
|
741
|
+
|
|
742
|
+
expect(cli.testFindParentCommand(child)?.name).toBe("deploy");
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
747
|
+
// getCommandPath
|
|
748
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
749
|
+
|
|
750
|
+
describe("getCommandPath", () => {
|
|
751
|
+
it("should return simple name for top-level command", () => {
|
|
752
|
+
class TestCommands {
|
|
753
|
+
build = $command({
|
|
754
|
+
name: "build",
|
|
755
|
+
flags: t.object({}),
|
|
756
|
+
handler: async () => {},
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
761
|
+
const cli = alepha.inject(TestCliProvider);
|
|
762
|
+
const cmd = cli.testFindCommand("build")!;
|
|
763
|
+
|
|
764
|
+
expect(cli.testGetCommandPath(cmd)).toBe("build");
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it("should return full path for nested command", () => {
|
|
768
|
+
class TestCommands {
|
|
769
|
+
deployVercel = $command({
|
|
770
|
+
name: "vercel",
|
|
771
|
+
flags: t.object({}),
|
|
772
|
+
handler: async () => {},
|
|
773
|
+
});
|
|
774
|
+
deploy = $command({
|
|
775
|
+
name: "deploy",
|
|
776
|
+
flags: t.object({}),
|
|
777
|
+
children: [this.deployVercel],
|
|
778
|
+
handler: async () => {},
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
783
|
+
const cli = alepha.inject(TestCliProvider);
|
|
784
|
+
const child = cli.testFindCommand("vercel")!;
|
|
785
|
+
|
|
786
|
+
expect(cli.testGetCommandPath(child)).toBe("deploy vercel");
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
791
|
+
// printHelp
|
|
792
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
793
|
+
|
|
794
|
+
describe("printHelp", () => {
|
|
795
|
+
it("should print general help when no command provided", () => {
|
|
796
|
+
class TestCommands {
|
|
797
|
+
build = $command({
|
|
798
|
+
name: "build",
|
|
799
|
+
description: "Build the project",
|
|
800
|
+
flags: t.object({}),
|
|
801
|
+
handler: async () => {},
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
806
|
+
const cli = alepha.inject(TestCliProvider);
|
|
807
|
+
|
|
808
|
+
// Just verify it doesn't throw
|
|
809
|
+
expect(() => cli.printHelp()).not.toThrow();
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
it("should print command-specific help", () => {
|
|
813
|
+
class TestCommands {
|
|
814
|
+
build = $command({
|
|
815
|
+
name: "build",
|
|
816
|
+
description: "Build the project",
|
|
817
|
+
flags: t.object({
|
|
818
|
+
watch: t.optional(t.boolean({ description: "Watch for changes" })),
|
|
819
|
+
}),
|
|
820
|
+
handler: async () => {},
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
825
|
+
const cli = alepha.inject(TestCliProvider);
|
|
826
|
+
const cmd = cli.testFindCommand("build")!;
|
|
827
|
+
|
|
828
|
+
expect(() => cli.printHelp(cmd)).not.toThrow();
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it("should print help for command with children", () => {
|
|
832
|
+
class TestCommands {
|
|
833
|
+
deployVercel = $command({
|
|
834
|
+
name: "vercel",
|
|
835
|
+
description: "Deploy to Vercel",
|
|
836
|
+
flags: t.object({}),
|
|
837
|
+
handler: async () => {},
|
|
838
|
+
});
|
|
839
|
+
deploy = $command({
|
|
840
|
+
name: "deploy",
|
|
841
|
+
description: "Deploy commands",
|
|
842
|
+
flags: t.object({}),
|
|
843
|
+
children: [this.deployVercel],
|
|
844
|
+
handler: async () => {},
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
849
|
+
const cli = alepha.inject(TestCliProvider);
|
|
850
|
+
const cmd = cli.testFindCommand("deploy")!;
|
|
851
|
+
|
|
852
|
+
expect(() => cli.printHelp(cmd)).not.toThrow();
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
it("should print help for command with env vars", () => {
|
|
856
|
+
class TestCommands {
|
|
857
|
+
deploy = $command({
|
|
858
|
+
name: "deploy",
|
|
859
|
+
description: "Deploy to production",
|
|
860
|
+
flags: t.object({}),
|
|
861
|
+
env: t.object({
|
|
862
|
+
API_KEY: t.string({ description: "API key for deployment" }),
|
|
863
|
+
REGION: t.optional(t.string({ description: "Target region" })),
|
|
864
|
+
}),
|
|
865
|
+
handler: async () => {},
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
870
|
+
const cli = alepha.inject(TestCliProvider);
|
|
871
|
+
const cmd = cli.testFindCommand("deploy")!;
|
|
872
|
+
|
|
873
|
+
expect(() => cli.printHelp(cmd)).not.toThrow();
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
it("should print help for command with mode option", () => {
|
|
877
|
+
class TestCommands {
|
|
878
|
+
build = $command({
|
|
879
|
+
name: "build",
|
|
880
|
+
description: "Build for environment",
|
|
881
|
+
flags: t.object({}),
|
|
882
|
+
mode: "development",
|
|
883
|
+
handler: async () => {},
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
888
|
+
const cli = alepha.inject(TestCliProvider);
|
|
889
|
+
const cmd = cli.testFindCommand("build")!;
|
|
890
|
+
|
|
891
|
+
expect(() => cli.printHelp(cmd)).not.toThrow();
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
it("should print help for command with args", () => {
|
|
895
|
+
class TestCommands {
|
|
896
|
+
greet = $command({
|
|
897
|
+
name: "greet",
|
|
898
|
+
description: "Greet someone",
|
|
899
|
+
flags: t.object({}),
|
|
900
|
+
args: t.string({ title: "name" }),
|
|
901
|
+
handler: async () => {},
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
906
|
+
const cli = alepha.inject(TestCliProvider);
|
|
907
|
+
const cmd = cli.testFindCommand("greet")!;
|
|
908
|
+
|
|
909
|
+
expect(() => cli.printHelp(cmd)).not.toThrow();
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
it("should hide commands with hide option in general help", () => {
|
|
913
|
+
class TestCommands {
|
|
914
|
+
visible = $command({
|
|
915
|
+
name: "visible",
|
|
916
|
+
description: "Visible command",
|
|
917
|
+
flags: t.object({}),
|
|
918
|
+
handler: async () => {},
|
|
919
|
+
});
|
|
920
|
+
hidden = $command({
|
|
921
|
+
name: "hidden",
|
|
922
|
+
description: "Hidden command",
|
|
923
|
+
hide: true,
|
|
924
|
+
flags: t.object({}),
|
|
925
|
+
handler: async () => {},
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
930
|
+
const cli = alepha.inject(TestCliProvider);
|
|
931
|
+
|
|
932
|
+
// Just verify it doesn't throw - hidden commands filtered in getTopLevelCommands
|
|
933
|
+
expect(() => cli.printHelp()).not.toThrow();
|
|
934
|
+
});
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
938
|
+
// commands getter
|
|
939
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
940
|
+
|
|
941
|
+
describe("commands", () => {
|
|
942
|
+
it("should return all registered commands", () => {
|
|
943
|
+
class TestCommands {
|
|
944
|
+
build = $command({
|
|
945
|
+
name: "build",
|
|
946
|
+
flags: t.object({}),
|
|
947
|
+
handler: async () => {},
|
|
948
|
+
});
|
|
949
|
+
test = $command({
|
|
950
|
+
name: "test",
|
|
951
|
+
flags: t.object({}),
|
|
952
|
+
handler: async () => {},
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
957
|
+
const cli = alepha.inject(TestCliProvider);
|
|
958
|
+
|
|
959
|
+
expect(cli.commands.length).toBe(2);
|
|
960
|
+
expect(cli.commands.map((c) => c.name).sort()).toEqual(["build", "test"]);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
it("should return empty array when no commands", () => {
|
|
964
|
+
const cli = createTestCli();
|
|
965
|
+
expect(cli.commands).toEqual([]);
|
|
966
|
+
});
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
970
|
+
// run (test helper)
|
|
971
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
972
|
+
|
|
973
|
+
describe("run", () => {
|
|
974
|
+
it("should execute command with string args", async () => {
|
|
975
|
+
let capturedFlags: Record<string, unknown> = {};
|
|
976
|
+
|
|
977
|
+
class TestCommands {
|
|
978
|
+
build = $command({
|
|
979
|
+
name: "build",
|
|
980
|
+
flags: t.object({
|
|
981
|
+
watch: t.optional(t.boolean()),
|
|
982
|
+
}),
|
|
983
|
+
handler: async ({ flags }) => {
|
|
984
|
+
capturedFlags = flags;
|
|
985
|
+
},
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
990
|
+
const cli = alepha.inject(CliProvider);
|
|
991
|
+
const cmd = alepha.inject(TestCommands);
|
|
992
|
+
|
|
993
|
+
await cli.run(cmd.build, "--watch");
|
|
994
|
+
|
|
995
|
+
expect(capturedFlags.watch).toBe(true);
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
it("should execute command with array args", async () => {
|
|
999
|
+
let capturedFlags: Record<string, unknown> = {};
|
|
1000
|
+
|
|
1001
|
+
class TestCommands {
|
|
1002
|
+
greet = $command({
|
|
1003
|
+
name: "greet",
|
|
1004
|
+
flags: t.object({
|
|
1005
|
+
name: t.optional(t.string()),
|
|
1006
|
+
}),
|
|
1007
|
+
handler: async ({ flags }) => {
|
|
1008
|
+
capturedFlags = flags;
|
|
1009
|
+
},
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
1014
|
+
const cli = alepha.inject(CliProvider);
|
|
1015
|
+
const cmd = alepha.inject(TestCommands);
|
|
1016
|
+
|
|
1017
|
+
await cli.run(cmd.greet, ["--name", "World"]);
|
|
1018
|
+
|
|
1019
|
+
expect(capturedFlags.name).toBe("World");
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
it("should execute command with options object", async () => {
|
|
1023
|
+
let capturedRoot = "";
|
|
1024
|
+
|
|
1025
|
+
class TestCommands {
|
|
1026
|
+
init = $command({
|
|
1027
|
+
name: "init",
|
|
1028
|
+
flags: t.object({}),
|
|
1029
|
+
handler: async ({ root }) => {
|
|
1030
|
+
capturedRoot = root;
|
|
1031
|
+
},
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
1036
|
+
const cli = alepha.inject(CliProvider);
|
|
1037
|
+
const cmd = alepha.inject(TestCommands);
|
|
1038
|
+
|
|
1039
|
+
await cli.run(cmd.init, { root: "/custom/path" });
|
|
1040
|
+
|
|
1041
|
+
expect(capturedRoot).toBe("/custom/path");
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
it("should parse command args", async () => {
|
|
1045
|
+
let capturedArgs: unknown;
|
|
1046
|
+
|
|
1047
|
+
class TestCommands {
|
|
1048
|
+
greet = $command({
|
|
1049
|
+
name: "greet",
|
|
1050
|
+
flags: t.object({}),
|
|
1051
|
+
args: t.string(),
|
|
1052
|
+
handler: async ({ args }) => {
|
|
1053
|
+
capturedArgs = args;
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
const alepha = Alepha.create().with(TestCommands);
|
|
1059
|
+
const cli = alepha.inject(CliProvider);
|
|
1060
|
+
const cmd = alepha.inject(TestCommands);
|
|
1061
|
+
|
|
1062
|
+
await cli.run(cmd.greet, "World");
|
|
1063
|
+
|
|
1064
|
+
expect(capturedArgs).toBe("World");
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
});
|