cvx-kit 0.1.7 → 0.1.10
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/CHANGELOG.md +15 -0
- package/README.md +63 -47
- package/dist/agent-tools.d.mts +5 -5
- package/dist/agent-tools.mjs.map +1 -1
- package/dist/auth.d.mts +39 -289
- package/dist/auth.mjs.map +1 -1
- package/dist/components/approvals/_generated/api.d.mts +3 -4
- package/dist/components/approvals/_generated/api.mjs.map +1 -1
- package/dist/components/approvals/_generated/component.d.mts +1 -2
- package/dist/components/approvals/_generated/dataModel.d.mts +4 -5
- package/dist/components/approvals/_generated/server.d.mts +12 -13
- package/dist/components/approvals/_generated/server.mjs.map +1 -1
- package/dist/components/approvals/audit.d.mts +8 -8
- package/dist/components/approvals/audit.mjs +1 -1
- package/dist/components/approvals/audit.mjs.map +1 -1
- package/dist/components/approvals/client.d.mts +10 -10
- package/dist/components/approvals/client.mjs.map +1 -1
- package/dist/components/approvals/constants.d.mts +30 -30
- package/dist/components/approvals/constants.mjs.map +1 -1
- package/dist/components/approvals/convex.config.mjs.map +1 -1
- package/dist/components/approvals/decisions.d.mts +6 -6
- package/dist/components/approvals/decisions.mjs.map +1 -1
- package/dist/components/approvals/functions.d.mts +3 -3
- package/dist/components/approvals/functions.mjs.map +1 -1
- package/dist/components/approvals/health.d.mts +2 -2
- package/dist/components/approvals/health.mjs.map +1 -1
- package/dist/components/approvals/requests.d.mts +8 -8
- package/dist/components/approvals/requests.mjs.map +1 -1
- package/dist/components/approvals/validators.d.mts +29 -29
- package/dist/components/approvals/validators.mjs +1 -1
- package/dist/components/approvals/validators.mjs.map +1 -1
- package/dist/components/approvals/workflow.d.mts +3 -3
- package/dist/components/approvals/workflow.mjs.map +1 -1
- package/dist/components/approvals/workflow_steps.d.mts +15 -15
- package/dist/components/approvals/workflow_steps.mjs.map +1 -1
- package/dist/components/foundation/_generated/api.d.mts +3 -4
- package/dist/components/foundation/_generated/api.mjs.map +1 -1
- package/dist/components/foundation/_generated/component.d.mts +1 -2
- package/dist/components/foundation/_generated/dataModel.d.mts +4 -5
- package/dist/components/foundation/_generated/server.d.mts +12 -13
- package/dist/components/foundation/_generated/server.mjs.map +1 -1
- package/dist/components/foundation/client.d.mts +21 -13
- package/dist/components/foundation/client.mjs.map +1 -1
- package/dist/components/foundation/convex.config.mjs.map +1 -1
- package/dist/components/foundation/functions.d.mts +2 -2
- package/dist/components/foundation/functions.mjs.map +1 -1
- package/dist/components/foundation/modules/command/command.d.mts +14 -14
- package/dist/components/foundation/modules/command/command.mjs.map +1 -1
- package/dist/components/foundation/modules/command/lifecycle.d.mts +12 -13
- package/dist/components/foundation/modules/command/lifecycle.mjs.map +1 -1
- package/dist/components/foundation/modules/observability/observability.d.mts +4 -4
- package/dist/components/foundation/modules/observability/observability.mjs.map +1 -1
- package/dist/components/foundation/modules/query/query.d.mts +5 -5
- package/dist/components/foundation/modules/query/query.mjs.map +1 -1
- package/dist/components/foundation/operation.d.mts +5 -6
- package/dist/components/foundation/operation.mjs.map +1 -1
- package/dist/components/foundation/result.d.mts +6 -6
- package/dist/components/foundation/result.mjs.map +1 -1
- package/dist/components/foundation/telemetry.d.mts +2 -2
- package/dist/components/foundation/telemetry.mjs.map +1 -1
- package/dist/crud.d.mts +6 -5
- package/dist/crud.mjs.map +1 -1
- package/dist/errors.d.mts +4 -4
- package/dist/errors.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/middleware.d.mts +2 -3
- package/dist/middleware.mjs.map +1 -1
- package/dist/modules/contracts/contract.d.mts +12 -13
- package/dist/modules/contracts/contract.mjs.map +1 -1
- package/dist/modules/contracts/convex.d.mts +3 -5
- package/dist/modules/contracts/convex.mjs.map +1 -1
- package/dist/modules/contracts/errors.d.mts +8 -9
- package/dist/modules/contracts/errors.mjs +1 -1
- package/dist/modules/contracts/errors.mjs.map +1 -1
- package/dist/modules/contracts/exposure.d.mts +13 -14
- package/dist/modules/contracts/exposure.mjs +1 -1
- package/dist/modules/contracts/exposure.mjs.map +1 -1
- package/dist/modules/contracts/idempotency.d.mts +15 -16
- package/dist/modules/contracts/idempotency.mjs +1 -1
- package/dist/modules/contracts/idempotency.mjs.map +1 -1
- package/dist/modules/contracts/standard.d.mts +2 -3
- package/dist/modules/contracts/standard.mjs.map +1 -1
- package/dist/modules/contracts/workflow.d.mts +26 -27
- package/dist/modules/contracts/workflow.mjs.map +1 -1
- package/dist/modules/effect/api-runtime.d.mts +20 -11
- package/dist/modules/effect/api-runtime.mjs +1 -1
- package/dist/modules/effect/api-runtime.mjs.map +1 -1
- package/dist/modules/effect/api-zod.d.mts +5 -6
- package/dist/modules/effect/api-zod.mjs.map +1 -1
- package/dist/modules/effect/api.d.mts +6 -7
- package/dist/modules/effect/api.mjs.map +1 -1
- package/dist/modules/effect/command.d.mts +10 -7
- package/dist/modules/effect/command.mjs +1 -1
- package/dist/modules/effect/command.mjs.map +1 -1
- package/dist/modules/effect/crud.d.mts +7 -8
- package/dist/modules/effect/crud.mjs.map +1 -1
- package/dist/modules/effect/errors.d.mts +1 -2
- package/dist/modules/effect/errors.mjs.map +1 -1
- package/dist/modules/effect/foundation.d.mts +3 -4
- package/dist/modules/effect/foundation.mjs.map +1 -1
- package/dist/modules/effect/idempotency.d.mts +2 -3
- package/dist/modules/effect/idempotency.mjs.map +1 -1
- package/dist/modules/effect/normalize.d.mts +2 -3
- package/dist/modules/effect/normalize.mjs.map +1 -1
- package/dist/modules/effect/operation.d.mts +17 -18
- package/dist/modules/effect/operation.mjs.map +1 -1
- package/dist/modules/effect/query.d.mts +8 -5
- package/dist/modules/effect/query.mjs +1 -1
- package/dist/modules/effect/query.mjs.map +1 -1
- package/dist/modules/effect/schema.d.mts +8 -9
- package/dist/modules/effect/schema.mjs.map +1 -1
- package/dist/modules/effect/workflow.d.mts +5 -6
- package/dist/modules/effect/workflow.mjs.map +1 -1
- package/dist/oxlint/architecture.d.mts +6 -7
- package/dist/oxlint/architecture.mjs +1 -1
- package/dist/oxlint/architecture.mjs.map +1 -1
- package/dist/oxlint/ast.d.mts +22 -23
- package/dist/oxlint/ast.mjs +1 -1
- package/dist/oxlint/ast.mjs.map +1 -1
- package/dist/oxlint/ownership.d.mts +2 -3
- package/dist/oxlint/ownership.mjs +1 -1
- package/dist/oxlint/ownership.mjs.map +1 -1
- package/dist/oxlint.d.mts +4 -4
- package/dist/oxlint.mjs +1 -1
- package/dist/oxlint.mjs.map +1 -1
- package/dist/state-machine.d.mts +1 -2
- package/dist/state-machine.mjs.map +1 -1
- package/dist/tenancy.d.mts +6 -6
- package/dist/tenancy.mjs.map +1 -1
- package/dist/triggers.d.mts +6 -6
- package/dist/triggers.mjs.map +1 -1
- package/dist/webhooks.d.mts +5 -6
- package/dist/webhooks.mjs.map +1 -1
- package/dist/zod-table.d.mts +10 -10
- package/dist/zod-table.mjs.map +1 -1
- package/docs/architecture.md +3 -3
- package/docs/auth.md +10 -4
- package/docs/command-context.md +150 -0
- package/docs/commands-legacy.md +511 -0
- package/docs/commands.md +113 -451
- package/docs/conventions.md +15 -5
- package/docs/crud.md +4 -0
- package/docs/domain-operations.md +1 -1
- package/docs/effect.md +14 -3
- package/docs/llms.md +69 -45
- package/docs/migration.md +1 -1
- package/docs/oxlint.md +1 -1
- package/docs/upgrading.md +18 -1
- package/docs/zod-table.md +1 -1
- package/package.json +21 -15
- package/scripts/test-packed-auth.mjs +68 -0
- package/scripts/test-packed-effect.mjs +4 -1
- package/scripts/test-packed-ids.mjs +2 -2
- package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +0 -79
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.mjs","names":[],"sources":["../../../src/modules/effect/query.ts"],"sourcesContent":["import { Effect, Exit } from 'effect'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectOperationArgument,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype EffectOperationResult,\n\ttype EffectValue,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\ntype QueryDefinition = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal heterogeneous storage; selected schemas restore the concrete result at exec.\n\thandler: (input: never, context: never) => unknown\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tguard?: (context: never, input: never) => unknown\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tmiddleware?: (input: never) => unknown\n}\ntype QueryRegistry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<QueryDefinition, 'input' | 'result' | 'handler'> &\n\t\t\tCheckedEffectOperation<Context> & {\n\t\t\t\tprepare?: never\n\t\t\t\taudit?: never\n\t\t\t\taggregates?: never\n\t\t\t\treplayResult?: never\n\t\t\t}\n\t>\n>\ntype OperationKey<Operations> = Extract<keyof Operations, string>\n\nclass QueryMiddlewareError extends Error {\n\treadonly code = 'QUERY_MIDDLEWARE_NEXT_REUSED'\n\treadonly name = 'QueryMiddlewareError'\n\tconstructor() {\n\t\tsuper('A query middleware called next() more than once')\n\t}\n}\nclass QueryConfigurationError extends Error {\n\treadonly code = 'QUERY_OPERATION_NOT_CONFIGURED'\n\treadonly name = 'QueryConfigurationError'\n\tconstructor() {\n\t\tsuper('The selected query operation is not configured')\n\t}\n}\nclass QueryPermissionError extends Error {\n\treadonly code = 'QUERY_PERMISSION_CHECKER_MISSING'\n\treadonly name = 'QueryPermissionError'\n\tconstructor() {\n\t\tsuper('Query permission requires an injected permission checker')\n\t}\n}\n\n/** Injectable domain queries compose lazily; the API chooses native function kind. */\nexport function createEffectQuery<\n\tHost,\n\tContextReturned,\n\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\tPermissionReturned = never,\n\tGuardReturned extends Supported<void> = never,\n>(configuration: {\n\tcontext: (host: Host) => ContextReturned\n\toperations: (\n\t\tdefinitions: ReturnType<\n\t\t\ttypeof effectOperationFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>\n\t\t>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tcheckPermission?: (\n\t\thost: Host,\n\t\tinput: { permission: string; operation: string },\n\t) => PermissionReturned\n\tdefaults?: { metadata?: object; guard?: (context: EffectValue<ContextReturned>) => GuardReturned }\n\tobservability?: ObservabilityOptions | Observability\n}) {\n\tconst definitions = effectOperationFactory<\n\t\tEffectValue<ContextReturned>,\n\t\tRecord<never, never>,\n\t\tCallbackError<GuardReturned>,\n\t\tCallbackRequirements<GuardReturned>\n\t>()\n\tconst operations: Operations = configuration.operations(definitions)\n\tconst observability =\n\t\tconfiguration.observability instanceof Observability\n\t\t\t? configuration.observability\n\t\t\t: new Observability(\n\t\t\t\t\tconfiguration.observability ?? {\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tclassifyError: () => ({ outcome: 'failed', errorCode: 'UNEXPECTED' }),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\tfunction exec<const Key extends OperationKey<Operations>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: Host,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\t| EffectOperationError<Operations[Key]>\n\t\t| CallbackError<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultError<Operations[Key], GuardReturned>,\n\t\t| EffectOperationRequirements<Operations[Key]>\n\t\t| CallbackRequirements<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultRequirements<Operations[Key], GuardReturned>\n\t> {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation)) {\n\t\t\t\treturn Effect.die(new QueryConfigurationError())\n\t\t\t}\n\t\t\t// SAFETY: operation helpers check hooks before this heterogeneous storage seam.\n\t\t\tconst definition: QueryDefinition = operations[operation]\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (parsedInput) => {\n\t\t\t\tconst observation = observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification ?? 'query',\n\t\t\t\t})\n\t\t\t\tconst run = Effect.gen(function* () {\n\t\t\t\t\tif (definition.permission !== undefined) {\n\t\t\t\t\t\tconst check = configuration.checkPermission\n\t\t\t\t\t\tif (!check) return yield* Effect.die(new QueryPermissionError())\n\t\t\t\t\t\tyield* normalizeEffect(() =>\n\t\t\t\t\t\t\tcheck(host, { permission: definition.permission!, operation }),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tconst context = yield* normalizeEffect(() => configuration.context(host))\n\t\t\t\t\tconst metadata = { ...configuration.defaults?.metadata, ...definition.metadata }\n\t\t\t\t\tconst core = (current: EffectValue<ContextReturned>) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst guard = configuration.defaults?.guard\n\t\t\t\t\t\t\tif (guard) yield* normalizeEffect(() => guard(current))\n\t\t\t\t\t\t\tif (definition.guard)\n\t\t\t\t\t\t\t\tyield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored guard parameters.\n\t\t\t\t\t\t\t\t\treturn definition.guard!(current as never, parsedInput as never)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\treturn yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored handler parameters.\n\t\t\t\t\t\t\t\treturn definition.handler(parsedInput as never, current as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\tlet usedNext = false\n\t\t\t\t\tconst middleware = definition.middleware\n\t\t\t\t\tconst output = middleware\n\t\t\t\t\t\t? yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: the selected helper checked this middleware's input and next contract.\n\t\t\t\t\t\t\t\treturn middleware({\n\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t\t\t\tcommand: parsedInput,\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tmetadata,\n\t\t\t\t\t\t\t\t\tnext: (options?: { context?: object }) =>\n\t\t\t\t\t\t\t\t\t\tEffect.suspend(() => {\n\t\t\t\t\t\t\t\t\t\t\tif (usedNext) return Effect.die(new QueryMiddlewareError())\n\t\t\t\t\t\t\t\t\t\t\tusedNext = true\n\t\t\t\t\t\t\t\t\t\t\treturn core(\n\t\t\t\t\t\t\t\t\t\t\t\toptions?.context ? Object.assign({}, context, options.context) : context,\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: yield* core(context)\n\t\t\t\t\treturn yield* decodeEffectContract(definition.result, output)\n\t\t\t\t})\n\t\t\t\treturn run.pipe(\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tobservation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: selected schemas own A; concrete callbacks and the wrapped middleware\n\t\t// own E/R. No interpreter or runner executes this Effect before the caller does.\n\t\treturn execution as ReturnType<typeof exec<Key>>\n\t}\n\tfunction expose<const Owner extends symbol, const Key extends OperationKey<Operations>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<\n\t\tOwner,\n\t\tKey,\n\t\tOperations[Key]['input'],\n\t\tOperationPublicResult<Operations[Key]>\n\t> {\n\t\tif (!Object.hasOwn(operations, operation)) throw new QueryConfigurationError()\n\t\treturn selectOperation(owner, 'query', operation, operations[operation])\n\t}\n\treturn { exec, expose }\n}\n\ntype Policy<Dependencies> = 'checkPermission' extends keyof Dependencies\n\t? Dependencies['checkPermission']\n\t: never\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional type extracts the host; no unknown result is exposed by the registry.\ntype CallbackHost<Callback> = Callback extends (host: infer Host, input: never) => unknown\n\t? Host\n\t: never\ntype CallbackReturned<Callback> = Callback extends (...arguments_: never[]) => infer Returned\n\t? Returned\n\t: never\ntype PolicyHost<Dependencies> = [CallbackHost<Policy<Dependencies>>] extends [never]\n\t? unknown\n\t: CallbackHost<Policy<Dependencies>>\ntype PolicyReturned<Dependencies> = CallbackReturned<Policy<Dependencies>>\nexport type EffectQueryDependencies = {\n\tobservability: Observability\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Host policy storage is erased; the bound generic dependency retains its concrete E/R.\n\tcheckPermission?: (host: never, input: { permission: string; operation: string }) => unknown\n}\n\n/** The public Foundation binds trusted application policies once. */\nexport function bindEffectQuery<const Dependencies extends EffectQueryDependencies>(\n\tdependencies: Dependencies,\n) {\n\treturn function query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefinitions: ReturnType<\n\t\t\t\ttypeof effectOperationFactory<\n\t\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\t\tRecord<never, never>,\n\t\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t\t>\n\t\t\t>,\n\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t> {\n\t\t// SAFETY: Host is constrained to the trusted checker's host type; its concrete\n\t\t// return is retained while restoring the erased invocation argument slot.\n\t\tconst checkPermission = dependencies.checkPermission as (\n\t\t\thost: Host,\n\t\t\tinput: { permission: string; operation: string },\n\t\t) => PolicyReturned<Dependencies>\n\t\treturn createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>({\n\t\t\t...configuration,\n\t\t\tobservability: dependencies.observability,\n\t\t\tcheckPermission: dependencies.checkPermission ? checkPermission : undefined,\n\t\t})\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query.mjs","names":["QueryMiddlewareError","QueryConfigurationError","QueryPermissionError","createEffectQuery","definitions","effectOperationFactory","operations","configuration","observability","Observability","exec","Effect","operation","definition","decodeEffectContract","input","observation","check","normalizeEffect","host","context","metadata","core","guard","current","parsedInput","usedNext","middleware","output","options","Exit","exit","observationFailure","expose","selectOperation","owner","bindEffectQuery","checkPermission","dependencies"],"sources":["../../../src/modules/effect/query.ts"],"sourcesContent":["import { Effect, Exit } from 'effect'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectOperationArgument,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype EffectOperationResult,\n\ttype EffectValue,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\ntype QueryDefinition = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal heterogeneous storage; selected schemas restore the concrete result at exec.\n\thandler: (input: never, context: never) => unknown\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tguard?: (context: never, input: never) => unknown\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tmiddleware?: (input: never) => unknown\n}\ntype QueryRegistry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<QueryDefinition, 'input' | 'result' | 'handler'> &\n\t\t\tCheckedEffectOperation<Context> & {\n\t\t\t\tprepare?: never\n\t\t\t\taudit?: never\n\t\t\t\taggregates?: never\n\t\t\t\treplayResult?: never\n\t\t\t}\n\t>\n>\ntype OperationKey<Operations> = Extract<keyof Operations, string>\n\nclass QueryMiddlewareError extends Error {\n\treadonly code = 'QUERY_MIDDLEWARE_NEXT_REUSED'\n\treadonly name = 'QueryMiddlewareError'\n\tconstructor() {\n\t\tsuper('A query middleware called next() more than once')\n\t}\n}\nclass QueryConfigurationError extends Error {\n\treadonly code = 'QUERY_OPERATION_NOT_CONFIGURED'\n\treadonly name = 'QueryConfigurationError'\n\tconstructor() {\n\t\tsuper('The selected query operation is not configured')\n\t}\n}\nclass QueryPermissionError extends Error {\n\treadonly code = 'QUERY_PERMISSION_CHECKER_MISSING'\n\treadonly name = 'QueryPermissionError'\n\tconstructor() {\n\t\tsuper('Query permission requires an injected permission checker')\n\t}\n}\n\n/** Injectable domain queries compose lazily; the API chooses native function kind. */\nexport function createEffectQuery<\n\tHost,\n\tContextReturned,\n\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\tPermissionReturned = never,\n\tGuardReturned extends Supported<void> = never,\n>(configuration: {\n\tcontext: (host: Host) => ContextReturned\n\toperations: (\n\t\tdefinitions: ReturnType<\n\t\t\ttypeof effectOperationFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>\n\t\t>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tcheckPermission?: (\n\t\thost: Host,\n\t\tinput: { permission: string; operation: string },\n\t) => PermissionReturned\n\tdefaults?: { metadata?: object; guard?: (context: EffectValue<ContextReturned>) => GuardReturned }\n\tobservability?: ObservabilityOptions | Observability\n}) {\n\tconst definitions = effectOperationFactory<\n\t\tEffectValue<ContextReturned>,\n\t\tRecord<never, never>,\n\t\tCallbackError<GuardReturned>,\n\t\tCallbackRequirements<GuardReturned>\n\t>()\n\tconst operations: Operations = configuration.operations(definitions)\n\tconst observability =\n\t\tconfiguration.observability instanceof Observability\n\t\t\t? configuration.observability\n\t\t\t: new Observability(\n\t\t\t\t\tconfiguration.observability ?? {\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tclassifyError: () => ({ outcome: 'failed', errorCode: 'UNEXPECTED' }),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\tfunction exec<const Key extends OperationKey<Operations>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: Host,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\t| EffectOperationError<Operations[Key]>\n\t\t| CallbackError<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultError<Operations[Key], GuardReturned>,\n\t\t| EffectOperationRequirements<Operations[Key]>\n\t\t| CallbackRequirements<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultRequirements<Operations[Key], GuardReturned>\n\t> {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation)) {\n\t\t\t\treturn Effect.die(new QueryConfigurationError())\n\t\t\t}\n\t\t\t// SAFETY: operation helpers check hooks before this heterogeneous storage seam.\n\t\t\tconst definition: QueryDefinition = operations[operation]\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (parsedInput) => {\n\t\t\t\tconst observation = observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification ?? 'query',\n\t\t\t\t})\n\t\t\t\tconst run = Effect.gen(function* () {\n\t\t\t\t\tif (definition.permission !== undefined) {\n\t\t\t\t\t\tconst check = configuration.checkPermission\n\t\t\t\t\t\tif (!check) return yield* Effect.die(new QueryPermissionError())\n\t\t\t\t\t\tyield* normalizeEffect(() =>\n\t\t\t\t\t\t\tcheck(host, { permission: definition.permission!, operation }),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tconst context = yield* normalizeEffect(() => configuration.context(host))\n\t\t\t\t\tconst metadata = { ...configuration.defaults?.metadata, ...definition.metadata }\n\t\t\t\t\tconst core = (current: EffectValue<ContextReturned>) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst guard = configuration.defaults?.guard\n\t\t\t\t\t\t\tif (guard) yield* normalizeEffect(() => guard(current))\n\t\t\t\t\t\t\tif (definition.guard)\n\t\t\t\t\t\t\t\tyield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored guard parameters.\n\t\t\t\t\t\t\t\t\treturn definition.guard!(current as never, parsedInput as never)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\treturn yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored handler parameters.\n\t\t\t\t\t\t\t\treturn definition.handler(parsedInput as never, current as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\tlet usedNext = false\n\t\t\t\t\tconst middleware = definition.middleware\n\t\t\t\t\tconst output = middleware\n\t\t\t\t\t\t? yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: the selected helper checked this middleware's input and next contract.\n\t\t\t\t\t\t\t\treturn middleware({\n\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t\t\t\tcommand: parsedInput,\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tmetadata,\n\t\t\t\t\t\t\t\t\tnext: (options?: { context?: object }) =>\n\t\t\t\t\t\t\t\t\t\tEffect.suspend(() => {\n\t\t\t\t\t\t\t\t\t\t\tif (usedNext) return Effect.die(new QueryMiddlewareError())\n\t\t\t\t\t\t\t\t\t\t\tusedNext = true\n\t\t\t\t\t\t\t\t\t\t\treturn core(\n\t\t\t\t\t\t\t\t\t\t\t\toptions?.context ? Object.assign({}, context, options.context) : context,\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: yield* core(context)\n\t\t\t\t\treturn yield* decodeEffectContract(definition.result, output)\n\t\t\t\t})\n\t\t\t\treturn run.pipe(\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tobservation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: selected schemas own A; concrete callbacks and the wrapped middleware\n\t\t// own E/R. No interpreter or runner executes this Effect before the caller does.\n\t\treturn execution as ReturnType<typeof exec<Key>>\n\t}\n\tfunction expose<const Owner extends symbol, const Key extends OperationKey<Operations>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<\n\t\tOwner,\n\t\tKey,\n\t\tOperations[Key]['input'],\n\t\tOperationPublicResult<Operations[Key]>\n\t> {\n\t\tif (!Object.hasOwn(operations, operation)) throw new QueryConfigurationError()\n\t\treturn selectOperation(owner, 'query', operation, operations[operation])\n\t}\n\treturn {\n\t\texec,\n\t\texpose,\n\t\t/** Bind invocation context without resolving it or running an operation. */\n\t\twithContext(context: Host) {\n\t\t\treturn {\n\t\t\t\texec: <const Key extends OperationKey<Operations>>(\n\t\t\t\t\toperation: Key,\n\t\t\t\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\t\t\t) => exec(operation, input, context),\n\t\t\t}\n\t\t},\n\t}\n}\n\ntype Policy<Dependencies> = 'checkPermission' extends keyof Dependencies\n\t? Dependencies['checkPermission']\n\t: never\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional type extracts the host; no unknown result is exposed by the registry.\ntype CallbackHost<Callback> = Callback extends (host: infer Host, input: never) => unknown\n\t? Host\n\t: never\ntype CallbackReturned<Callback> = Callback extends (...arguments_: never[]) => infer Returned\n\t? Returned\n\t: never\ntype PolicyHost<Dependencies> = [CallbackHost<Policy<Dependencies>>] extends [never]\n\t? unknown\n\t: CallbackHost<Policy<Dependencies>>\ntype PolicyReturned<Dependencies> = CallbackReturned<Policy<Dependencies>>\nexport type EffectQueryDependencies = {\n\tobservability: Observability\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Host policy storage is erased; the bound generic dependency retains its concrete E/R.\n\tcheckPermission?: (host: never, input: { permission: string; operation: string }) => unknown\n}\n\n/** The public Foundation binds trusted application policies once. */\nexport function bindEffectQuery<const Dependencies extends EffectQueryDependencies>(\n\tdependencies: Dependencies,\n) {\n\treturn function query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefinitions: ReturnType<\n\t\t\t\ttypeof effectOperationFactory<\n\t\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\t\tRecord<never, never>,\n\t\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t\t>\n\t\t\t>,\n\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t> {\n\t\t// SAFETY: Host is constrained to the trusted checker's host type; its concrete\n\t\t// return is retained while restoring the erased invocation argument slot.\n\t\tconst checkPermission = dependencies.checkPermission as (\n\t\t\thost: Host,\n\t\t\tinput: { permission: string; operation: string },\n\t\t) => PolicyReturned<Dependencies>\n\t\treturn createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>({\n\t\t\t...configuration,\n\t\t\tobservability: dependencies.observability,\n\t\t\tcheckPermission: dependencies.checkPermission ? checkPermission : undefined,\n\t\t})\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { ContractOutput, ContractSchema, Decoder, LegacyParser, ValidationIssue } from "../contracts/contract.mjs";
|
|
2
2
|
import { Effect, Schema } from "effect";
|
|
3
3
|
//#region src/modules/effect/schema.d.ts
|
|
4
|
-
declare class ContractValidationError {
|
|
4
|
+
export declare class ContractValidationError {
|
|
5
5
|
readonly issues: readonly ValidationIssue[];
|
|
6
6
|
readonly _tag = "ContractValidationError";
|
|
7
7
|
constructor(issues: readonly ValidationIssue[]);
|
|
8
8
|
}
|
|
9
|
-
interface EffectDecoder<Input, Output, Error = never, Requirements = never> extends Decoder<Input, Output, Effect.Effect<Output, Error, Requirements>> {
|
|
9
|
+
export interface EffectDecoder<Input, Output, Error = never, Requirements = never> extends Decoder<Input, Output, Effect.Effect<Output, Error, Requirements>> {
|
|
10
10
|
readonly kind: 'effect-contract';
|
|
11
11
|
}
|
|
12
12
|
/** Explicit custom decoders preserve their exact typed error and service channels. */
|
|
13
|
-
declare function effectContract<Input, Output, Error = never, Requirements = never>(decode: (value: unknown) => Effect.Effect<Output, Error, Requirements>): EffectDecoder<Input, Output, Error, Requirements>;
|
|
13
|
+
export declare function effectContract<Input, Output, Error = never, Requirements = never>(decode: (value: unknown) => Effect.Effect<Output, Error, Requirements>): EffectDecoder<Input, Output, Error, Requirements>;
|
|
14
14
|
/** Encoding requirements remain independent of the decoder's requirements. */
|
|
15
|
-
declare function effectSchema<const S extends Schema.Constraint>(schema: S): {
|
|
15
|
+
export declare function effectSchema<const S extends Schema.Constraint>(schema: S): {
|
|
16
16
|
types?: {
|
|
17
17
|
readonly input: S["Encoded"];
|
|
18
18
|
readonly output: S["Type"];
|
|
@@ -23,11 +23,10 @@ declare function effectSchema<const S extends Schema.Constraint>(schema: S): {
|
|
|
23
23
|
encode: (input: S["Type"], options?: import("effect/SchemaAST").ParseOptions) => Effect.Effect<S["Encoded"], Schema.SchemaError, S["EncodingServices"]>;
|
|
24
24
|
};
|
|
25
25
|
/** The service-free bridge cannot erase decoder requirements. */
|
|
26
|
-
declare function effectStandardSchema<const S extends Schema.ConstraintDecoder<unknown>>(schema: S): import("effect/StandardSchema").StandardSchemaV1<S["Encoded"], S["Type"]> & S;
|
|
27
|
-
type ContractDecoderError<S> = S extends EffectDecoder<unknown, unknown, infer Error, unknown> ? Error : S extends LegacyParser ? never : S extends ContractSchema ? ContractValidationError : never;
|
|
28
|
-
type ContractDecoderRequirements<S> = S extends EffectDecoder<unknown, unknown, unknown, infer Requirements> ? Requirements : never;
|
|
26
|
+
export declare function effectStandardSchema<const S extends Schema.ConstraintDecoder<unknown>>(schema: S): import("effect/StandardSchema").StandardSchemaV1<S["Encoded"], S["Type"]> & S;
|
|
27
|
+
export type ContractDecoderError<S> = S extends EffectDecoder<unknown, unknown, infer Error, unknown> ? Error : S extends LegacyParser ? never : S extends ContractSchema ? ContractValidationError : never;
|
|
28
|
+
export type ContractDecoderRequirements<S> = S extends EffectDecoder<unknown, unknown, unknown, infer Requirements> ? Requirements : never;
|
|
29
29
|
/** Decode input, fresh results, and final replay values within the current Effect scope. */
|
|
30
|
-
declare function decodeEffectContract<S extends ContractSchema>(schema: S, value: unknown): Effect.Effect<ContractOutput<S>, ContractDecoderError<S>, ContractDecoderRequirements<S>>;
|
|
30
|
+
export declare function decodeEffectContract<S extends ContractSchema>(schema: S, value: unknown): Effect.Effect<ContractOutput<S>, ContractDecoderError<S>, ContractDecoderRequirements<S>>;
|
|
31
31
|
//#endregion
|
|
32
|
-
export { ContractDecoderError, ContractDecoderRequirements, ContractValidationError, EffectDecoder, decodeEffectContract, effectContract, effectSchema, effectStandardSchema };
|
|
33
32
|
//# sourceMappingURL=schema.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","names":[],"sources":["../../../src/modules/effect/schema.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters -- Explicit schema decoder boundaries validate untrusted transport input. */\nimport { Effect, Schema } from 'effect'\nimport type {\n\tContractSchema,\n\tContractOutput,\n\tDecoder,\n\tLegacyParser,\n\tNeutralSchema,\n\tValidationIssue,\n} from '../contracts/contract'\nimport { decodeContract } from '../contracts/contract'\n\nexport class ContractValidationError {\n\treadonly _tag = 'ContractValidationError'\n\tconstructor(readonly issues: readonly ValidationIssue[]) {}\n}\nexport interface EffectDecoder<Input, Output, Error = never, Requirements = never> extends Decoder<\n\tInput,\n\tOutput,\n\tEffect.Effect<Output, Error, Requirements>\n> {\n\treadonly kind: 'effect-contract'\n}\n/** Explicit custom decoders preserve their exact typed error and service channels. */\nexport function effectContract<Input, Output, Error = never, Requirements = never>(\n\tdecode: (value: unknown) => Effect.Effect<Output, Error, Requirements>,\n): EffectDecoder<Input, Output, Error, Requirements> {\n\treturn { kind: 'effect-contract', decode }\n}\n/** Encoding requirements remain independent of the decoder's requirements. */\nexport function effectSchema<const S extends Schema.Constraint>(schema: S) {\n\treturn {\n\t\t...effectContract<S['Encoded'], S['Type'], Schema.SchemaError, S['DecodingServices']>(\n\t\t\tSchema.decodeUnknownEffect(schema),\n\t\t),\n\t\tschema,\n\t\tencode: Schema.encodeEffect(schema),\n\t}\n}\n/** The service-free bridge cannot erase decoder requirements. */\nexport function effectStandardSchema<const S extends Schema.ConstraintDecoder<unknown>>(schema: S) {\n\treturn Schema.toStandardSchemaV1(schema)\n}\nexport type ContractDecoderError<S> =\n\tS extends EffectDecoder<unknown, unknown, infer Error, unknown>\n\t\t? Error\n\t\t: S extends LegacyParser\n\t\t\t? never\n\t\t\t: S extends ContractSchema\n\t\t\t\t? ContractValidationError\n\t\t\t\t: never\nexport type ContractDecoderRequirements<S> =\n\tS extends EffectDecoder<unknown, unknown, unknown, infer Requirements> ? Requirements : never\n\n/** Decode input, fresh results, and final replay values within the current Effect scope. */\nexport function decodeEffectContract<S extends ContractSchema>(\n\tschema: S,\n\tvalue: unknown,\n): Effect.Effect<ContractOutput<S>, ContractDecoderError<S>, ContractDecoderRequirements<S>> {\n\tconst decoded = Effect.suspend(() => {\n\t\tif ('kind' in schema && schema.kind === 'effect-contract') {\n\t\t\t// SAFETY: only the explicit optional adapter exposes this discriminator.\n\t\t\treturn schema.decode(value) as Effect.Effect<unknown, unknown, unknown>\n\t\t}\n\t\t// SAFETY: the Effect discriminator was excluded; ordinary adapters return validation results.\n\t\treturn Effect.promise(() => decodeContract(schema as NeutralSchema, value)).pipe(\n\t\t\tEffect.flatMap((result) => {\n\t\t\t\tif (!result.issues) return Effect.succeed(result.value)\n\t\t\t\tconst error = new ContractValidationError(result.issues)\n\t\t\t\t// Legacy parsers have always exposed validation throws as defects.\n\t\t\t\treturn 'parse' in schema ? Effect.die(error) : Effect.fail(error)\n\t\t\t}),\n\t\t)\n\t})\n\t// SAFETY: conditional channels correspond to the explicit Effect branch or neutral validation branch.\n\treturn decoded as Effect.Effect<\n\t\tContractOutput<S>,\n\t\tContractDecoderError<S>,\n\t\tContractDecoderRequirements<S>\n\t>\n}\n"],"mappings":"uGAYA,
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":["ContractValidationError","issues","effectContract","effectSchema","Schema","schema","effectStandardSchema","decodeEffectContract","Effect","value","decodeContract","result","error"],"sources":["../../../src/modules/effect/schema.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters -- Explicit schema decoder boundaries validate untrusted transport input. */\nimport { Effect, Schema } from 'effect'\nimport type {\n\tContractSchema,\n\tContractOutput,\n\tDecoder,\n\tLegacyParser,\n\tNeutralSchema,\n\tValidationIssue,\n} from '../contracts/contract'\nimport { decodeContract } from '../contracts/contract'\n\nexport class ContractValidationError {\n\treadonly _tag = 'ContractValidationError'\n\tconstructor(readonly issues: readonly ValidationIssue[]) {}\n}\nexport interface EffectDecoder<Input, Output, Error = never, Requirements = never> extends Decoder<\n\tInput,\n\tOutput,\n\tEffect.Effect<Output, Error, Requirements>\n> {\n\treadonly kind: 'effect-contract'\n}\n/** Explicit custom decoders preserve their exact typed error and service channels. */\nexport function effectContract<Input, Output, Error = never, Requirements = never>(\n\tdecode: (value: unknown) => Effect.Effect<Output, Error, Requirements>,\n): EffectDecoder<Input, Output, Error, Requirements> {\n\treturn { kind: 'effect-contract', decode }\n}\n/** Encoding requirements remain independent of the decoder's requirements. */\nexport function effectSchema<const S extends Schema.Constraint>(schema: S) {\n\treturn {\n\t\t...effectContract<S['Encoded'], S['Type'], Schema.SchemaError, S['DecodingServices']>(\n\t\t\tSchema.decodeUnknownEffect(schema),\n\t\t),\n\t\tschema,\n\t\tencode: Schema.encodeEffect(schema),\n\t}\n}\n/** The service-free bridge cannot erase decoder requirements. */\nexport function effectStandardSchema<const S extends Schema.ConstraintDecoder<unknown>>(schema: S) {\n\treturn Schema.toStandardSchemaV1(schema)\n}\nexport type ContractDecoderError<S> =\n\tS extends EffectDecoder<unknown, unknown, infer Error, unknown>\n\t\t? Error\n\t\t: S extends LegacyParser\n\t\t\t? never\n\t\t\t: S extends ContractSchema\n\t\t\t\t? ContractValidationError\n\t\t\t\t: never\nexport type ContractDecoderRequirements<S> =\n\tS extends EffectDecoder<unknown, unknown, unknown, infer Requirements> ? Requirements : never\n\n/** Decode input, fresh results, and final replay values within the current Effect scope. */\nexport function decodeEffectContract<S extends ContractSchema>(\n\tschema: S,\n\tvalue: unknown,\n): Effect.Effect<ContractOutput<S>, ContractDecoderError<S>, ContractDecoderRequirements<S>> {\n\tconst decoded = Effect.suspend(() => {\n\t\tif ('kind' in schema && schema.kind === 'effect-contract') {\n\t\t\t// SAFETY: only the explicit optional adapter exposes this discriminator.\n\t\t\treturn schema.decode(value) as Effect.Effect<unknown, unknown, unknown>\n\t\t}\n\t\t// SAFETY: the Effect discriminator was excluded; ordinary adapters return validation results.\n\t\treturn Effect.promise(() => decodeContract(schema as NeutralSchema, value)).pipe(\n\t\t\tEffect.flatMap((result) => {\n\t\t\t\tif (!result.issues) return Effect.succeed(result.value)\n\t\t\t\tconst error = new ContractValidationError(result.issues)\n\t\t\t\t// Legacy parsers have always exposed validation throws as defects.\n\t\t\t\treturn 'parse' in schema ? Effect.die(error) : Effect.fail(error)\n\t\t\t}),\n\t\t)\n\t})\n\t// SAFETY: conditional channels correspond to the explicit Effect branch or neutral validation branch.\n\treturn decoded as Effect.Effect<\n\t\tContractOutput<S>,\n\t\tContractDecoderError<S>,\n\t\tContractDecoderRequirements<S>\n\t>\n}\n"],"mappings":"uGAYA,IAAaA,EAAb,KAAqC,CAEf,OADrB,KAAgB,0BAChB,YAAY,EAA6C,CAApC,KAAA,OAAAC,CAAqC,CAC3D,EASA,SAAgBC,EACf,EACoD,CACpD,MAAO,CAAE,KAAM,kBAAmB,QAAO,CAC1C,CAEA,SAAgBC,EAAgD,EAAW,CAC1E,MAAO,CACN,GAAGD,EACFE,EAAO,oBAAoBC,CAAM,CAClC,EACA,SACA,OAAQD,EAAO,aAAaC,CAAM,CACnC,CACD,CAEA,SAAgBC,EAAwE,EAAW,CAClG,OAAOF,EAAO,mBAAmBC,CAAM,CACxC,CAaA,SAAgBE,EACf,EACA,EAC4F,CAiB5F,OAhBgBC,EAAO,YAClB,SAAUH,GAAUA,EAAO,OAAS,kBAEhCA,EAAO,OAAOI,CAAK,EAGpBD,EAAO,YAAcE,EAAeL,EAAyBI,CAAK,CAAC,CAAC,CAAC,KAC3ED,EAAO,QAAS,GAAW,CAC1B,GAAI,CAACG,EAAO,OAAQ,OAAOH,EAAO,QAAQG,EAAO,KAAK,EACtD,IAAMC,EAAQ,IAAIZ,EAAwBW,EAAO,MAAM,EAEvD,MAAO,UAAWN,EAASG,EAAO,IAAII,CAAK,EAAIJ,EAAO,KAAKI,CAAK,CACjE,CAAC,CACF,CAGY,CAKd"}
|
|
@@ -8,12 +8,12 @@ import { Effect } from "effect";
|
|
|
8
8
|
//#region src/modules/effect/workflow.d.ts
|
|
9
9
|
type Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>;
|
|
10
10
|
/** Services exist only inside a new native invocation; ordinary throws/rejections remain defects. */
|
|
11
|
-
declare function effectWorkflowAttempt<Args, Authorize, Execute>(configuration: {
|
|
11
|
+
export declare function effectWorkflowAttempt<Args, Authorize, Execute>(configuration: {
|
|
12
12
|
authorize: (execution: WorkflowExecution<Args>) => Authorize;
|
|
13
13
|
execute: (execution: WorkflowExecution<Args>, authority: EffectValue<Authorize>) => Execute;
|
|
14
14
|
}): (input: WorkflowExecution<Args>) => Effect.Effect<EffectValue<Execute>, WorkflowBindingError | CallbackError<Authorize | Execute>, CallbackRequirements<Authorize | Execute>>;
|
|
15
15
|
/** Native mutation promise rejects outside the child transaction before mapping declared terminal details. */
|
|
16
|
-
declare function effectTerminalWorkflowAttempt<Args, Authorize, const Result extends ContractSchema, const Failure extends ContractSchema, Terminal extends Supported<ContractInput<Failure> | undefined>>(configuration: ({
|
|
16
|
+
export declare function effectTerminalWorkflowAttempt<Args, Authorize, const Result extends ContractSchema, const Failure extends ContractSchema, Terminal extends Supported<ContractInput<Failure> | undefined>>(configuration: ({
|
|
17
17
|
kind: 'mutation';
|
|
18
18
|
atomicJournalProof: 'host-verified';
|
|
19
19
|
} | {
|
|
@@ -27,7 +27,7 @@ declare function effectTerminalWorkflowAttempt<Args, Authorize, const Result ext
|
|
|
27
27
|
failure: Failure;
|
|
28
28
|
}): (input: WorkflowExecution<Args>) => Effect.Effect<WorkflowOutcome<ContractInput<Result>, ContractOutput<Failure>>, WorkflowBindingError | CallbackError<Authorize | Terminal> | ContractDecoderError<Result | Failure>, CallbackRequirements<Authorize | Terminal> | ContractDecoderRequirements<Result | Failure>>;
|
|
29
29
|
declare const protectedMutation: unique symbol;
|
|
30
|
-
interface EffectReceiptProtectedWorkflowMutation<Args, Result, Error, Requirements> {
|
|
30
|
+
export interface EffectReceiptProtectedWorkflowMutation<Args, Result, Error, Requirements> {
|
|
31
31
|
readonly [protectedMutation]: {
|
|
32
32
|
args: Args;
|
|
33
33
|
result: Result;
|
|
@@ -40,7 +40,7 @@ type Completion<Prepare> = Extract<EffectValue<Prepare>, {
|
|
|
40
40
|
complete: (...arguments_: never[]) => infer Returned;
|
|
41
41
|
} ? Returned : never;
|
|
42
42
|
/** Host runs the handler in the secured inner native mutation transaction, including receipt completion. */
|
|
43
|
-
declare function effectReceiptWorkflowMutation<Args, Authorize, const Replay extends ContractSchema, Prepare extends Supported<EffectIdempotencyPreparation<ContractOutput<Replay>, unknown, unknown>>, Execute extends Supported<ContractOutput<Replay>>>(configuration: {
|
|
43
|
+
export declare function effectReceiptWorkflowMutation<Args, Authorize, const Replay extends ContractSchema, Prepare extends Supported<EffectIdempotencyPreparation<ContractOutput<Replay>, unknown, unknown>>, Execute extends Supported<ContractOutput<Replay>>>(configuration: {
|
|
44
44
|
authorize: (execution: WorkflowExecution<Args>) => Authorize;
|
|
45
45
|
receipt: (authority: EffectValue<Authorize>) => {
|
|
46
46
|
replayResult: Replay;
|
|
@@ -52,7 +52,7 @@ declare function effectReceiptWorkflowMutation<Args, Authorize, const Replay ext
|
|
|
52
52
|
type StateResult<Read> = EffectValue<Read> extends WorkflowHostState<infer Result, unknown> ? Result : never;
|
|
53
53
|
type StateFailure<Read> = EffectValue<Read> extends WorkflowHostState<unknown, infer Failure> ? Failure : never;
|
|
54
54
|
/** The host still owns native manager calls and transactional/CAS writes; each method retains only its used channels. */
|
|
55
|
-
declare function effectWorkflowStatusBindings<Authorize, Read extends Supported<WorkflowHostState>, Write, Native extends Supported<WorkflowNativeStatus>, Receipt extends Supported<WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined>, Cancel, Restart>(configuration: {
|
|
55
|
+
export declare function effectWorkflowStatusBindings<Authorize, Read extends Supported<WorkflowHostState>, Write, Native extends Supported<WorkflowNativeStatus>, Receipt extends Supported<WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined>, Cancel, Restart>(configuration: {
|
|
56
56
|
authorize: () => Authorize;
|
|
57
57
|
read: () => Read;
|
|
58
58
|
write: (expectedGeneration: number, state: WorkflowHostState<StateResult<Read>, StateFailure<Read>>) => Write;
|
|
@@ -73,5 +73,4 @@ declare function effectWorkflowStatusBindings<Authorize, Read extends Supported<
|
|
|
73
73
|
}, WorkflowBindingError | CallbackError<Authorize> | CallbackError<Read> | CallbackError<Restart> | CallbackError<Write>, CallbackRequirements<Authorize> | CallbackRequirements<Read> | CallbackRequirements<Restart> | CallbackRequirements<Write>>;
|
|
74
74
|
};
|
|
75
75
|
//#endregion
|
|
76
|
-
export { EffectReceiptProtectedWorkflowMutation, effectReceiptWorkflowMutation, effectTerminalWorkflowAttempt, effectWorkflowAttempt, effectWorkflowStatusBindings };
|
|
77
76
|
//# sourceMappingURL=workflow.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.mjs","names":[],"sources":["../../../src/modules/effect/workflow.ts"],"sourcesContent":["import { Effect } from 'effect'\nimport type { ContractInput, ContractOutput, ContractSchema } from '../contracts/contract'\nimport {\n\tWorkflowBindingError,\n\tworkflowExecution,\n\tworkflowTransition,\n\tworkflowCancel,\n\tworkflowRestart,\n\ttype WorkflowExecution,\n\ttype WorkflowOutcome,\n\ttype WorkflowHostState,\n\ttype WorkflowNativeStatus,\n} from '../contracts/workflow'\nimport type { IdempotencyInvocation } from '../contracts/idempotency'\nimport type { EffectIdempotencyPreparation } from './idempotency'\nimport type { CallbackError, CallbackRequirements, EffectValue } from './operation'\nimport { normalizeEffect } from './normalize'\nimport {\n\tdecodeEffectContract,\n\ttype ContractDecoderError,\n\ttype ContractDecoderRequirements,\n} from './schema'\n\ntype Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>\n/** Services exist only inside a new native invocation; ordinary throws/rejections remain defects. */\nexport function effectWorkflowAttempt<Args, Authorize, Execute>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\texecute: (execution: WorkflowExecution<Args>, authority: EffectValue<Authorize>) => Execute\n}) {\n\treturn (\n\t\tinput: WorkflowExecution<Args>,\n\t): Effect.Effect<\n\t\tEffectValue<Execute>,\n\t\tWorkflowBindingError | CallbackError<Authorize | Execute>,\n\t\tCallbackRequirements<Authorize | Execute>\n\t> =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\treturn yield* normalizeEffect(() => configuration.execute(execution, authority))\n\t\t})\n}\n/** Native mutation promise rejects outside the child transaction before mapping declared terminal details. */\nexport function effectTerminalWorkflowAttempt<\n\tArgs,\n\tAuthorize,\n\tconst Result extends ContractSchema,\n\tconst Failure extends ContractSchema,\n\tTerminal extends Supported<ContractInput<Failure> | undefined>,\n>(\n\tconfiguration: (\n\t\t| { kind: 'mutation'; atomicJournalProof: 'host-verified' }\n\t\t| {\n\t\t\t\tkind: 'action'\n\t\t\t\tprotectedMutation: EffectReceiptProtectedWorkflowMutation<Args, unknown, unknown, unknown>\n\t\t }\n\t) & {\n\t\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\t\tinvokeMutation: (\n\t\t\texecution: WorkflowExecution<Args>,\n\t\t\tauthority: EffectValue<Authorize>,\n\t\t) => Promise<ContractInput<Result>>\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- A rejected native mutation can throw any value; the host terminal callback classifies it before failure contract validation.\n\t\tterminal: (error: unknown) => Terminal\n\t\tresult: Result\n\t\tfailure: Failure\n\t},\n) {\n\treturn (\n\t\tinput: WorkflowExecution<Args>,\n\t): Effect.Effect<\n\t\tWorkflowOutcome<ContractInput<Result>, ContractOutput<Failure>>,\n\t\t| WorkflowBindingError\n\t\t| CallbackError<Authorize | Terminal>\n\t\t| ContractDecoderError<Result | Failure>,\n\t\tCallbackRequirements<Authorize | Terminal> | ContractDecoderRequirements<Result | Failure>\n\t> =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\tconst native = yield* Effect.tryPromise({\n\t\t\t\ttry: () => configuration.invokeMutation(execution, authority),\n\t\t\t\tcatch: (error) => error,\n\t\t\t}).pipe(\n\t\t\t\tEffect.map((value) => ({ kind: 'success' as const, value })),\n\t\t\t\tEffect.catch((error) => Effect.succeed({ kind: 'rejected' as const, error })),\n\t\t\t)\n\t\t\tif (native.kind === 'rejected') {\n\t\t\t\tconst failure = yield* normalizeEffect(() => configuration.terminal(native.error))\n\t\t\t\tif (failure === undefined) return yield* Effect.die(native.error)\n\t\t\t\t// SAFETY: Terminal is constrained to this exact failure wire input or undefined.\n\t\t\t\tconst error = yield* decodeEffectContract(\n\t\t\t\t\tconfiguration.failure,\n\t\t\t\t\tfailure as ContractInput<Failure>,\n\t\t\t\t)\n\t\t\t\tyield* descriptor({ ...execution, args: error })\n\t\t\t\treturn { version: 1 as const, kind: 'failed' as const, error }\n\t\t\t}\n\t\t\tyield* decodeEffectContract(configuration.result, native.value)\n\t\t\tyield* descriptor({ ...execution, args: native.value })\n\t\t\treturn { version: 1 as const, kind: 'succeeded' as const, value: native.value }\n\t\t})\n}\ndeclare const protectedMutation: unique symbol\nexport interface EffectReceiptProtectedWorkflowMutation<Args, Result, Error, Requirements> {\n\treadonly [protectedMutation]: { args: Args; result: Result }\n\treadonly handler: (\n\t\texecution: WorkflowExecution<Args>,\n\t) => Effect.Effect<Result, Error, Requirements>\n}\ntype Completion<Prepare> =\n\tExtract<EffectValue<Prepare>, { kind: 'execute' }> extends {\n\t\tcomplete: (...arguments_: never[]) => infer Returned\n\t}\n\t\t? Returned\n\t\t: never\n/** Host runs the handler in the secured inner native mutation transaction, including receipt completion. */\nexport function effectReceiptWorkflowMutation<\n\tArgs,\n\tAuthorize,\n\tconst Replay extends ContractSchema,\n\tPrepare extends Supported<EffectIdempotencyPreparation<ContractOutput<Replay>, unknown, unknown>>,\n\tExecute extends Supported<ContractOutput<Replay>>,\n>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\treceipt: (authority: EffectValue<Authorize>) => {\n\t\treplayResult: Replay\n\t\tprepare: (invocation: IdempotencyInvocation) => Prepare\n\t}\n\tinvocation: (\n\t\texecution: WorkflowExecution<Args>,\n\t\tauthority: EffectValue<Authorize>,\n\t) => IdempotencyInvocation\n\texecute: (execution: WorkflowExecution<Args>, authority: EffectValue<Authorize>) => Execute\n}): EffectReceiptProtectedWorkflowMutation<\n\tArgs,\n\tContractOutput<Replay>,\n\t| WorkflowBindingError\n\t| CallbackError<Authorize | Prepare | Execute | Completion<Prepare>>\n\t| ContractDecoderError<Replay>,\n\t| CallbackRequirements<Authorize | Prepare | Execute | Completion<Prepare>>\n\t| ContractDecoderRequirements<Replay>\n> {\n\tconst handler = (input: WorkflowExecution<Args>) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\tconst adapter = configuration.receipt(authority)\n\t\t\tconst preparation = yield* normalizeEffect(() =>\n\t\t\t\tadapter.prepare(configuration.invocation(execution, authority)),\n\t\t\t)\n\t\t\tif (preparation.kind === 'replay')\n\t\t\t\treturn yield* decodeEffectContract(adapter.replayResult, preparation.result)\n\t\t\tconst value = yield* normalizeEffect(() => configuration.execute(execution, authority))\n\t\t\t// SAFETY: the execute branch came from this exact Prepare value; recover its complete callback rather than the broad constraint.\n\t\t\tconst complete = preparation.complete as (\n\t\t\t\tresult: ContractOutput<Replay>,\n\t\t\t) => Completion<Prepare>\n\t\t\t// SAFETY: Execute's supported success is the exact final replay output contract.\n\t\t\tyield* normalizeEffect(() => complete(value as ContractOutput<Replay>))\n\t\t\t// SAFETY: Execute's supported success is the exact final replay output contract.\n\t\t\treturn value as ContractOutput<Replay>\n\t\t})\n\t// SAFETY: only private receipt evidence is asserted; handler's inferred E/R remain checked against the public return.\n\treturn { handler } as ReceiptEvidence<Args, ContractOutput<Replay>, typeof handler>\n}\ntype ReceiptEvidence<Args, Result, Handler> = {\n\thandler: Handler\n\treadonly [protectedMutation]: { args: Args; result: Result }\n}\ntype StateResult<Read> =\n\tEffectValue<Read> extends WorkflowHostState<infer Result, unknown> ? Result : never\ntype StateFailure<Read> =\n\tEffectValue<Read> extends WorkflowHostState<unknown, infer Failure> ? Failure : never\n/** The host still owns native manager calls and transactional/CAS writes; each method retains only its used channels. */\nexport function effectWorkflowStatusBindings<\n\tAuthorize,\n\tRead extends Supported<WorkflowHostState>,\n\tWrite,\n\tNative extends Supported<WorkflowNativeStatus>,\n\tReceipt extends Supported<WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined>,\n\tCancel,\n\tRestart,\n>(configuration: {\n\tauthorize: () => Authorize\n\tread: () => Read\n\twrite: (\n\t\texpectedGeneration: number,\n\t\tstate: WorkflowHostState<StateResult<Read>, StateFailure<Read>>,\n\t) => Write\n\tnativeStatus: () => Native\n\treceiptOutcome: () => Receipt\n\tcancelNative: () => Cancel\n\trestartNative: () => Restart\n}) {\n\ttype State = WorkflowHostState<StateResult<Read>, StateFailure<Read>>\n\tfunction read() {\n\t\t// SAFETY: Read's supported success is the host state whose outcome types are extracted above.\n\t\treturn normalizeEffect(() => configuration.read()).pipe(Effect.map((state) => state as State))\n\t}\n\tfunction apply(\n\t\texpectedGeneration: number,\n\t\tnativeStatus: WorkflowNativeStatus,\n\t\toutcome?: WorkflowOutcome<StateResult<Read>, StateFailure<Read>>,\n\t) {\n\t\treturn Effect.gen(function* () {\n\t\t\tconst current = yield* read()\n\t\t\tconst update = { generation: expectedGeneration, nativeStatus }\n\t\t\tconst transition = yield* protocol(() =>\n\t\t\t\tworkflowTransition(current, outcome === undefined ? update : { ...update, outcome }),\n\t\t\t)\n\t\t\tif (transition.kind === 'applied')\n\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, transition.state))\n\t\t\treturn transition\n\t\t})\n\t}\n\treturn {\n\t\tcallback(\n\t\t\texpectedGeneration: number,\n\t\t\tnativeStatus: WorkflowNativeStatus,\n\t\t\toutcome?: WorkflowOutcome<StateResult<Read>, StateFailure<Read>>,\n\t\t) {\n\t\t\treturn normalizeEffect(() => configuration.authorize()).pipe(\n\t\t\t\tEffect.flatMap(() => apply(expectedGeneration, nativeStatus, outcome)),\n\t\t\t)\n\t\t},\n\t\treconcile(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst native = yield* normalizeEffect(() => configuration.nativeStatus())\n\t\t\t\tconst outcome = yield* normalizeEffect(() => configuration.receiptOutcome())\n\t\t\t\t// SAFETY: Native and Receipt are constrained to these exact host transport values.\n\t\t\t\treturn yield* apply(\n\t\t\t\t\texpectedGeneration,\n\t\t\t\t\tnative as WorkflowNativeStatus,\n\t\t\t\t\toutcome as WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined,\n\t\t\t\t)\n\t\t\t})\n\t\t},\n\t\tcancel(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst current = yield* read()\n\t\t\t\tconst transition = yield* protocol(() => workflowCancel(current, expectedGeneration))\n\t\t\t\tif (transition.kind === 'applied' && current.status === 'running') {\n\t\t\t\t\tyield* normalizeEffect(() => configuration.cancelNative())\n\t\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, transition.state))\n\t\t\t\t}\n\t\t\t\treturn transition\n\t\t\t})\n\t\t},\n\t\trestart(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst current = yield* read()\n\t\t\t\tif (current.generation !== expectedGeneration)\n\t\t\t\t\treturn { kind: 'ignored' as const, state: current }\n\t\t\t\tconst state = yield* protocol(() => workflowRestart(current))\n\t\t\t\tyield* normalizeEffect(() => configuration.restartNative())\n\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, state))\n\t\t\t\treturn { kind: 'applied' as const, state }\n\t\t\t})\n\t\t},\n\t}\n}\nfunction descriptor<Args>(\n\tvalue: WorkflowExecution<Args>,\n): Effect.Effect<WorkflowExecution<Args>, WorkflowBindingError> {\n\treturn protocol(() => workflowExecution(value))\n}\nfunction protocol<A>(evaluate: () => A): Effect.Effect<A, WorkflowBindingError> {\n\treturn Effect.try({\n\t\ttry: evaluate,\n\t\tcatch: (error) => {\n\t\t\tif (error instanceof WorkflowBindingError) return error\n\t\t\tthrow error\n\t\t},\n\t})\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflow.mjs","names":["effectWorkflowAttempt","Effect","execution","descriptor","input","authority","normalizeEffect","configuration","effectTerminalWorkflowAttempt","native","error","failure","decodeEffectContract","effectReceiptWorkflowMutation","adapter","preparation","value","complete","effectWorkflowStatusBindings","read","state","apply","current","update","expectedGeneration","transition","protocol","workflowTransition","outcome","nativeStatus","workflowCancel","workflowRestart","workflowExecution","evaluate","WorkflowBindingError"],"sources":["../../../src/modules/effect/workflow.ts"],"sourcesContent":["import { Effect } from 'effect'\nimport type { ContractInput, ContractOutput, ContractSchema } from '../contracts/contract'\nimport {\n\tWorkflowBindingError,\n\tworkflowExecution,\n\tworkflowTransition,\n\tworkflowCancel,\n\tworkflowRestart,\n\ttype WorkflowExecution,\n\ttype WorkflowOutcome,\n\ttype WorkflowHostState,\n\ttype WorkflowNativeStatus,\n} from '../contracts/workflow'\nimport type { IdempotencyInvocation } from '../contracts/idempotency'\nimport type { EffectIdempotencyPreparation } from './idempotency'\nimport type { CallbackError, CallbackRequirements, EffectValue } from './operation'\nimport { normalizeEffect } from './normalize'\nimport {\n\tdecodeEffectContract,\n\ttype ContractDecoderError,\n\ttype ContractDecoderRequirements,\n} from './schema'\n\ntype Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>\n/** Services exist only inside a new native invocation; ordinary throws/rejections remain defects. */\nexport function effectWorkflowAttempt<Args, Authorize, Execute>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\texecute: (execution: WorkflowExecution<Args>, authority: EffectValue<Authorize>) => Execute\n}) {\n\treturn (\n\t\tinput: WorkflowExecution<Args>,\n\t): Effect.Effect<\n\t\tEffectValue<Execute>,\n\t\tWorkflowBindingError | CallbackError<Authorize | Execute>,\n\t\tCallbackRequirements<Authorize | Execute>\n\t> =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\treturn yield* normalizeEffect(() => configuration.execute(execution, authority))\n\t\t})\n}\n/** Native mutation promise rejects outside the child transaction before mapping declared terminal details. */\nexport function effectTerminalWorkflowAttempt<\n\tArgs,\n\tAuthorize,\n\tconst Result extends ContractSchema,\n\tconst Failure extends ContractSchema,\n\tTerminal extends Supported<ContractInput<Failure> | undefined>,\n>(\n\tconfiguration: (\n\t\t| { kind: 'mutation'; atomicJournalProof: 'host-verified' }\n\t\t| {\n\t\t\t\tkind: 'action'\n\t\t\t\tprotectedMutation: EffectReceiptProtectedWorkflowMutation<Args, unknown, unknown, unknown>\n\t\t }\n\t) & {\n\t\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\t\tinvokeMutation: (\n\t\t\texecution: WorkflowExecution<Args>,\n\t\t\tauthority: EffectValue<Authorize>,\n\t\t) => Promise<ContractInput<Result>>\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- A rejected native mutation can throw any value; the host terminal callback classifies it before failure contract validation.\n\t\tterminal: (error: unknown) => Terminal\n\t\tresult: Result\n\t\tfailure: Failure\n\t},\n) {\n\treturn (\n\t\tinput: WorkflowExecution<Args>,\n\t): Effect.Effect<\n\t\tWorkflowOutcome<ContractInput<Result>, ContractOutput<Failure>>,\n\t\t| WorkflowBindingError\n\t\t| CallbackError<Authorize | Terminal>\n\t\t| ContractDecoderError<Result | Failure>,\n\t\tCallbackRequirements<Authorize | Terminal> | ContractDecoderRequirements<Result | Failure>\n\t> =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\tconst native = yield* Effect.tryPromise({\n\t\t\t\ttry: () => configuration.invokeMutation(execution, authority),\n\t\t\t\tcatch: (error) => error,\n\t\t\t}).pipe(\n\t\t\t\tEffect.map((value) => ({ kind: 'success' as const, value })),\n\t\t\t\tEffect.catch((error) => Effect.succeed({ kind: 'rejected' as const, error })),\n\t\t\t)\n\t\t\tif (native.kind === 'rejected') {\n\t\t\t\tconst failure = yield* normalizeEffect(() => configuration.terminal(native.error))\n\t\t\t\tif (failure === undefined) return yield* Effect.die(native.error)\n\t\t\t\t// SAFETY: Terminal is constrained to this exact failure wire input or undefined.\n\t\t\t\tconst error = yield* decodeEffectContract(\n\t\t\t\t\tconfiguration.failure,\n\t\t\t\t\tfailure as ContractInput<Failure>,\n\t\t\t\t)\n\t\t\t\tyield* descriptor({ ...execution, args: error })\n\t\t\t\treturn { version: 1 as const, kind: 'failed' as const, error }\n\t\t\t}\n\t\t\tyield* decodeEffectContract(configuration.result, native.value)\n\t\t\tyield* descriptor({ ...execution, args: native.value })\n\t\t\treturn { version: 1 as const, kind: 'succeeded' as const, value: native.value }\n\t\t})\n}\ndeclare const protectedMutation: unique symbol\nexport interface EffectReceiptProtectedWorkflowMutation<Args, Result, Error, Requirements> {\n\treadonly [protectedMutation]: { args: Args; result: Result }\n\treadonly handler: (\n\t\texecution: WorkflowExecution<Args>,\n\t) => Effect.Effect<Result, Error, Requirements>\n}\ntype Completion<Prepare> =\n\tExtract<EffectValue<Prepare>, { kind: 'execute' }> extends {\n\t\tcomplete: (...arguments_: never[]) => infer Returned\n\t}\n\t\t? Returned\n\t\t: never\n/** Host runs the handler in the secured inner native mutation transaction, including receipt completion. */\nexport function effectReceiptWorkflowMutation<\n\tArgs,\n\tAuthorize,\n\tconst Replay extends ContractSchema,\n\tPrepare extends Supported<EffectIdempotencyPreparation<ContractOutput<Replay>, unknown, unknown>>,\n\tExecute extends Supported<ContractOutput<Replay>>,\n>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Authorize\n\treceipt: (authority: EffectValue<Authorize>) => {\n\t\treplayResult: Replay\n\t\tprepare: (invocation: IdempotencyInvocation) => Prepare\n\t}\n\tinvocation: (\n\t\texecution: WorkflowExecution<Args>,\n\t\tauthority: EffectValue<Authorize>,\n\t) => IdempotencyInvocation\n\texecute: (execution: WorkflowExecution<Args>, authority: EffectValue<Authorize>) => Execute\n}): EffectReceiptProtectedWorkflowMutation<\n\tArgs,\n\tContractOutput<Replay>,\n\t| WorkflowBindingError\n\t| CallbackError<Authorize | Prepare | Execute | Completion<Prepare>>\n\t| ContractDecoderError<Replay>,\n\t| CallbackRequirements<Authorize | Prepare | Execute | Completion<Prepare>>\n\t| ContractDecoderRequirements<Replay>\n> {\n\tconst handler = (input: WorkflowExecution<Args>) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst execution = yield* descriptor(input)\n\t\t\tconst authority = yield* normalizeEffect(() => configuration.authorize(execution))\n\t\t\tconst adapter = configuration.receipt(authority)\n\t\t\tconst preparation = yield* normalizeEffect(() =>\n\t\t\t\tadapter.prepare(configuration.invocation(execution, authority)),\n\t\t\t)\n\t\t\tif (preparation.kind === 'replay')\n\t\t\t\treturn yield* decodeEffectContract(adapter.replayResult, preparation.result)\n\t\t\tconst value = yield* normalizeEffect(() => configuration.execute(execution, authority))\n\t\t\t// SAFETY: the execute branch came from this exact Prepare value; recover its complete callback rather than the broad constraint.\n\t\t\tconst complete = preparation.complete as (\n\t\t\t\tresult: ContractOutput<Replay>,\n\t\t\t) => Completion<Prepare>\n\t\t\t// SAFETY: Execute's supported success is the exact final replay output contract.\n\t\t\tyield* normalizeEffect(() => complete(value as ContractOutput<Replay>))\n\t\t\t// SAFETY: Execute's supported success is the exact final replay output contract.\n\t\t\treturn value as ContractOutput<Replay>\n\t\t})\n\t// SAFETY: only private receipt evidence is asserted; handler's inferred E/R remain checked against the public return.\n\treturn { handler } as ReceiptEvidence<Args, ContractOutput<Replay>, typeof handler>\n}\ntype ReceiptEvidence<Args, Result, Handler> = {\n\thandler: Handler\n\treadonly [protectedMutation]: { args: Args; result: Result }\n}\ntype StateResult<Read> =\n\tEffectValue<Read> extends WorkflowHostState<infer Result, unknown> ? Result : never\ntype StateFailure<Read> =\n\tEffectValue<Read> extends WorkflowHostState<unknown, infer Failure> ? Failure : never\n/** The host still owns native manager calls and transactional/CAS writes; each method retains only its used channels. */\nexport function effectWorkflowStatusBindings<\n\tAuthorize,\n\tRead extends Supported<WorkflowHostState>,\n\tWrite,\n\tNative extends Supported<WorkflowNativeStatus>,\n\tReceipt extends Supported<WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined>,\n\tCancel,\n\tRestart,\n>(configuration: {\n\tauthorize: () => Authorize\n\tread: () => Read\n\twrite: (\n\t\texpectedGeneration: number,\n\t\tstate: WorkflowHostState<StateResult<Read>, StateFailure<Read>>,\n\t) => Write\n\tnativeStatus: () => Native\n\treceiptOutcome: () => Receipt\n\tcancelNative: () => Cancel\n\trestartNative: () => Restart\n}) {\n\ttype State = WorkflowHostState<StateResult<Read>, StateFailure<Read>>\n\tfunction read() {\n\t\t// SAFETY: Read's supported success is the host state whose outcome types are extracted above.\n\t\treturn normalizeEffect(() => configuration.read()).pipe(Effect.map((state) => state as State))\n\t}\n\tfunction apply(\n\t\texpectedGeneration: number,\n\t\tnativeStatus: WorkflowNativeStatus,\n\t\toutcome?: WorkflowOutcome<StateResult<Read>, StateFailure<Read>>,\n\t) {\n\t\treturn Effect.gen(function* () {\n\t\t\tconst current = yield* read()\n\t\t\tconst update = { generation: expectedGeneration, nativeStatus }\n\t\t\tconst transition = yield* protocol(() =>\n\t\t\t\tworkflowTransition(current, outcome === undefined ? update : { ...update, outcome }),\n\t\t\t)\n\t\t\tif (transition.kind === 'applied')\n\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, transition.state))\n\t\t\treturn transition\n\t\t})\n\t}\n\treturn {\n\t\tcallback(\n\t\t\texpectedGeneration: number,\n\t\t\tnativeStatus: WorkflowNativeStatus,\n\t\t\toutcome?: WorkflowOutcome<StateResult<Read>, StateFailure<Read>>,\n\t\t) {\n\t\t\treturn normalizeEffect(() => configuration.authorize()).pipe(\n\t\t\t\tEffect.flatMap(() => apply(expectedGeneration, nativeStatus, outcome)),\n\t\t\t)\n\t\t},\n\t\treconcile(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst native = yield* normalizeEffect(() => configuration.nativeStatus())\n\t\t\t\tconst outcome = yield* normalizeEffect(() => configuration.receiptOutcome())\n\t\t\t\t// SAFETY: Native and Receipt are constrained to these exact host transport values.\n\t\t\t\treturn yield* apply(\n\t\t\t\t\texpectedGeneration,\n\t\t\t\t\tnative as WorkflowNativeStatus,\n\t\t\t\t\toutcome as WorkflowOutcome<StateResult<Read>, StateFailure<Read>> | undefined,\n\t\t\t\t)\n\t\t\t})\n\t\t},\n\t\tcancel(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst current = yield* read()\n\t\t\t\tconst transition = yield* protocol(() => workflowCancel(current, expectedGeneration))\n\t\t\t\tif (transition.kind === 'applied' && current.status === 'running') {\n\t\t\t\t\tyield* normalizeEffect(() => configuration.cancelNative())\n\t\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, transition.state))\n\t\t\t\t}\n\t\t\t\treturn transition\n\t\t\t})\n\t\t},\n\t\trestart(expectedGeneration: number) {\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* normalizeEffect(() => configuration.authorize())\n\t\t\t\tconst current = yield* read()\n\t\t\t\tif (current.generation !== expectedGeneration)\n\t\t\t\t\treturn { kind: 'ignored' as const, state: current }\n\t\t\t\tconst state = yield* protocol(() => workflowRestart(current))\n\t\t\t\tyield* normalizeEffect(() => configuration.restartNative())\n\t\t\t\tyield* normalizeEffect(() => configuration.write(expectedGeneration, state))\n\t\t\t\treturn { kind: 'applied' as const, state }\n\t\t\t})\n\t\t},\n\t}\n}\nfunction descriptor<Args>(\n\tvalue: WorkflowExecution<Args>,\n): Effect.Effect<WorkflowExecution<Args>, WorkflowBindingError> {\n\treturn protocol(() => workflowExecution(value))\n}\nfunction protocol<A>(evaluate: () => A): Effect.Effect<A, WorkflowBindingError> {\n\treturn Effect.try({\n\t\ttry: evaluate,\n\t\tcatch: (error) => {\n\t\t\tif (error instanceof WorkflowBindingError) return error\n\t\t\tthrow error\n\t\t},\n\t})\n}\n"],"mappings":"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"}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { ResolverFactory } from "oxc-resolver";
|
|
2
2
|
//#region src/oxlint/architecture.d.ts
|
|
3
|
-
interface ArchitectureOptions {
|
|
3
|
+
export interface ArchitectureOptions {
|
|
4
4
|
cwd?: string;
|
|
5
5
|
convexDir?: string;
|
|
6
6
|
}
|
|
7
|
-
interface ArchitectureDiagnostic {
|
|
7
|
+
export interface ArchitectureDiagnostic {
|
|
8
8
|
code: 'missing-root' | 'root-directory' | 'tests' | 'test-location' | 'parse' | 'cycle' | 'symlink' | 'domain-entry' | 'shared-owner';
|
|
9
9
|
file: string;
|
|
10
10
|
message: string;
|
|
11
11
|
}
|
|
12
12
|
/** Full-project checks, independent of the consumer's test runner. No persistent cache. */
|
|
13
|
-
declare function inspectArchitecture(options?: ArchitectureOptions): ArchitectureDiagnostic[];
|
|
14
|
-
declare function createResolver(): ResolverFactory;
|
|
15
|
-
declare function resolveImport(resolver: ResolverFactory, filename: string, source: string): string | null;
|
|
13
|
+
export declare function inspectArchitecture(options?: ArchitectureOptions): ArchitectureDiagnostic[];
|
|
14
|
+
export declare function createResolver(): ResolverFactory;
|
|
15
|
+
export declare function resolveImport(resolver: ResolverFactory, filename: string, source: string): string | null;
|
|
16
16
|
/** The lint rule runs the project scan on one deterministic source file. */
|
|
17
|
-
declare function architectureAnchor(root: string): string | null;
|
|
17
|
+
export declare function architectureAnchor(root: string): string | null;
|
|
18
18
|
//#endregion
|
|
19
|
-
export { ArchitectureDiagnostic, ArchitectureOptions, architectureAnchor, createResolver, inspectArchitecture, resolveImport };
|
|
20
19
|
//# sourceMappingURL=architecture.d.mts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{dirname as e,relative as t,resolve as n,sep as r}from"node:path";import{existsSync as i,readFileSync as a,readdirSync as o,realpathSync as s}from"node:fs";import{Visitor as c,parseSync as l}from"oxc-parser";import{ResolverFactory as u}from"oxc-resolver";function d(o={}){let c=n(o.cwd??process.cwd(),o.convexDir??`convex`),u=i(c)?s(c):c,d=[];if(!i(u))return[{code:`missing-root`,file:`.`,message:`Convex directory does not exist: ${u}`}];let m=h(u,d),y
|
|
1
|
+
import{dirname as e,relative as t,resolve as n,sep as r}from"node:path";import{existsSync as i,readFileSync as a,readdirSync as o,realpathSync as s}from"node:fs";import{Visitor as c,parseSync as l}from"oxc-parser";import{ResolverFactory as u}from"oxc-resolver";function d(o={}){let c=n(o.cwd??process.cwd(),o.convexDir??`convex`),u=i(c)?s(c):c,d=[];if(!i(u))return[{code:`missing-root`,file:`.`,message:`Convex directory does not exist: ${u}`}];let m=h(u,d),y=/* @__PURE__ */ new Set,w=/* @__PURE__ */ new Set,T=/* @__PURE__ */ new Map,E=/* @__PURE__ */ new Map,D=f();for(let i of m){let o=n(u,i),s=l(o,a(o,`utf8`));if(s.errors.length){d.push({code:`parse`,file:i,message:`Cannot validate ${i}: ${s.errors[0].message}`});continue}if(g(i)){i.includes(`__tests__/`)?e(i).endsWith(`__tests__`)&&v(s.program)&&w.add(e(e(i))):d.push({code:`test-location`,file:i,message:`Place tests in a sibling __tests__/ directory.`});continue}if(i.split(`/`).includes(`__tests__`))continue;/^domain\/[^/]+$/.test(i)&&i!==`domain/table.ts`&&d.push({code:`domain-entry`,file:i,message:`Domain source belongs in domain/<module>/ or domain/shared/. Only domain/table.ts assembles module tables.`}),_(s.program)&&i!==`domain/table.ts`&&y.add(e(i));let c=x(i)??``,f=/* @__PURE__ */ new Set;E.set(i,f);for(let e of b(s.program)){let n=p(D,o,e);if(!n)continue;let i=t(u,n).split(r).join(`/`);f.add(i);let a=x(i);if(c&&a&&c!==a){let e=T.get(c)??/* @__PURE__ */ new Set;T.set(c,e),e.add(a)}}}for(let e of y)w.has(e)||d.push({code:`tests`,file:e,message:`${e}/__tests__/ must contain a .test or .spec file with a nonempty, non-skipped test. Parent or child suites do not count.`});d.push(...C(E));for(let e of S(T))d.push({code:`cycle`,file:e[0],message:`Module dependency cycle: ${e.join(` → `)}.`});return d.sort((e,t)=>e.file.localeCompare(t.file)||e.code.localeCompare(t.code))}function f(){return new u({tsconfig:`auto`,extensions:[`.ts`,`.tsx`,`.mts`,`.cts`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`],extensionAlias:{".js":[`.ts`,`.tsx`,`.js`],".mjs":[`.mts`,`.mjs`],".cjs":[`.cts`,`.cjs`]},conditionNames:[`types`,`import`,`node`,`default`],symlinks:!0})}function p(t,r,i){return t.resolveFileSync(r,i).path||(i.startsWith(`.`)?n(e(r),i):null)}function m(e){if(!i(e))return null;if(i(n(e,`convex.config.ts`)))return s(n(e,`convex.config.ts`));e=s(e);for(let t of h(e,[]))if(!t.includes(`__tests__/`)&&!g(t))return n(e,t);return null}function*h(e,i){let a=/* @__PURE__ */ new Set([`_generated`,`__tests__`,`api`,`domain`,`application`,`migrations`,`components`]);function*s(c){for(let l of o(c,{withFileTypes:!0}).sort((e,t)=>e.name.localeCompare(t.name))){let o=n(c,l.name),u=t(e,o).split(r).join(`/`);if(l.isSymbolicLink()){i.push({code:`symlink`,file:u,message:`Keep application source inside its owning directory; symlinked files and folders are not allowed.`});continue}l.isDirectory()?(c===e&&!a.has(l.name)&&i.push({code:`root-directory`,file:u,message:`Root folder ${l.name}/ is not allowed. Use api/, domain/, application/, migrations/, components/, __tests__/, or _generated/.`}),l.name!==`_generated`&&l.name!==`node_modules`&&!l.name.startsWith(`.`)&&(yield*s(o))):/\.[cm]?[jt]sx?$/.test(l.name)&&!/\.d\.[cm]?ts$/.test(l.name)&&(yield u)}}yield*s(e)}function g(e){return/\.(?:test|spec)\.[cm]?[jt]sx?$/.test(e)}function _(e){return e.body.some(e=>{let t=e.type===`ExportNamedDeclaration`?e.declaration:e;return t&&`declare`in t&&t.declare||e.type===`ImportDeclaration`||e.type===`EmptyStatement`?!1:e.type===`ExportNamedDeclaration`?e.exportKind===`type`||!e.declaration?!1:![`TSInterfaceDeclaration`,`TSTypeAliasDeclaration`,`TSDeclareFunction`].includes(e.declaration.type):![`TSInterfaceDeclaration`,`TSTypeAliasDeclaration`,`TSDeclareFunction`,`ExportAllDeclaration`].includes(e.type)})}function v(e){let t=/* @__PURE__ */ new Map([[`test`,`test`],[`it`,`it`],[`describe`,`describe`],[`suite`,`suite`]]);for(let n of e.body){let e=n.type===`ExportNamedDeclaration`?n.declaration:n;if(e?.type===`FunctionDeclaration`&&e.id&&t.delete(e.id.name),e?.type===`VariableDeclaration`)for(let n of e.declarations)n.id.type===`Identifier`&&t.delete(n.id.name);if(n.type===`ImportDeclaration`)for(let e of n.specifiers)t.delete(e.local.name),[`vitest`,`vite-plus/test`,`bun:test`,`node:test`,`@jest/globals`].includes(n.source.value)&&(e.type===`ImportNamespaceSpecifier`?t.set(e.local.name,`*`):e.type===`ImportDefaultSpecifier`?t.set(e.local.name,`test`):e.imported.type===`Identifier`&&t.set(e.local.name,e.imported.name))}let n=[];new c({CallExpression(e){n.push(e)}}).visit(e);let r=n.filter(e=>{let n=y(e.callee,t);return[`test`,`it`,`describe`,`suite`].includes(n[0])&&(n.some(e=>[`skip`,`todo`,`skipIf`,`runIf`].includes(e))||e.arguments.some(e=>e.type===`ObjectExpression`&&e.properties.some(e=>e.type===`Property`&&[`skip`,`todo`].includes(e.key.type===`Identifier`?e.key.name:e.key.type===`Literal`?String(e.key.value):``)&&(e.value.type!==`Literal`||e.value.value!==!1))))});return n.some(e=>{let n=y(e.callee,t);return![`test`,`it`].includes(n[0])||r.some(t=>e.start>=t.start&&e.end<=t.end)?!1:e.arguments.some(e=>(e.type===`ArrowFunctionExpression`||e.type===`FunctionExpression`)&&e.body&&(e.body.type!==`BlockStatement`||e.body.body.some(e=>e.type!==`EmptyStatement`)))})}function y(e,t){if(e.type===`Identifier`){let n=t.get(e.name);return n?[n]:[]}if(e.type===`CallExpression`)return y(e.callee,t);if(e.type===`MemberExpression`){let n=y(e.object,t),r=!e.computed&&e.property.type===`Identifier`?e.property.name:e.property.type===`Literal`?String(e.property.value):``;return!n.length||!r?[]:n[0]===`*`?[r]:[...n,r]}return[]}function b(e){let t=[];return new c({ImportDeclaration(e){e.importKind!==`type`&&(e.specifiers.length===0||e.specifiers.some(e=>e.type!==`ImportSpecifier`||e.importKind!==`type`))&&t.push(e.source.value)},ExportNamedDeclaration(e){e.source&&e.exportKind!==`type`&&e.specifiers.some(e=>e.exportKind!==`type`)&&t.push(e.source.value)},ExportAllDeclaration(e){e.exportKind!==`type`&&t.push(e.source.value)},ImportExpression(e){e.source.type===`Literal`&&String(e.source.value)===e.source.value&&t.push(String(e.source.value))}}).visit(e),t}function x(e){let t=e.split(`/`);return t[0]===`domain`&&t.length>=3&&t[1]!==`__tests__`?`domain/${t[1]}`:null}function S(e){let t=/* @__PURE__ */ new Set,n=[],r=[];function i(a){let o=n.indexOf(a);if(o>=0){r.push([...n.slice(o),a]);return}if(!t.has(a)){n.push(a);for(let t of e.get(a)??[])i(t);n.pop(),t.add(a)}}for(let t of e.keys())i(t);return r}function C(e){let t=/* @__PURE__ */ new Map;for(let[n,r]of e){let i=x(n)??``;if(!i||i===`domain/shared`)continue;let a=/* @__PURE__ */ new Set;function o(n){if(!n.startsWith(`domain/shared/`)||a.has(n))return;a.add(n);let r=t.get(n)??/* @__PURE__ */ new Set;r.add(i),t.set(n,r);for(let t of e.get(n)??[])o(t)}for(let e of r)o(e)}let n=[];for(let[e,r]of t)r.size===1&&n.push({code:`shared-owner`,file:e,message:`This shared implementation is used only by ${[...r][0]}. Move it into that module until another module needs it.`});return n}export{m as architectureAnchor,f as createResolver,d as inspectArchitecture,p as resolveImport};
|
|
2
2
|
//# sourceMappingURL=architecture.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"architecture.mjs","names":[],"sources":["../../src/oxlint/architecture.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs'\nimport { dirname, relative, resolve, sep } from 'node:path'\nimport { parseSync, Visitor, type Program, type Node, type CallExpression } from 'oxc-parser'\nimport { ResolverFactory } from 'oxc-resolver'\n\nexport interface ArchitectureOptions {\n\tcwd?: string\n\tconvexDir?: string\n}\nexport interface ArchitectureDiagnostic {\n\tcode:\n\t\t| 'missing-root'\n\t\t| 'root-directory'\n\t\t| 'tests'\n\t\t| 'test-location'\n\t\t| 'parse'\n\t\t| 'cycle'\n\t\t| 'symlink'\n\t\t| 'domain-entry'\n\t\t| 'shared-owner'\n\tfile: string\n\tmessage: string\n}\n\n/** Full-project checks, independent of the consumer's test runner. No persistent cache. */\nexport function inspectArchitecture(options: ArchitectureOptions = {}): ArchitectureDiagnostic[] {\n\tconst requestedRoot = resolve(options.cwd ?? process.cwd(), options.convexDir ?? 'convex')\n\tconst root = existsSync(requestedRoot) ? realpathSync(requestedRoot) : requestedRoot\n\tconst diagnostics: ArchitectureDiagnostic[] = []\n\tif (!existsSync(root))\n\t\treturn [\n\t\t\t{ code: 'missing-root', file: '.', message: `Convex directory does not exist: ${root}` },\n\t\t]\n\tconst files = sourceFiles(root, diagnostics)\n\tconst required = new Set<string>()\n\tconst tested = new Set<string>()\n\tconst graph = new Map<string, Set<string>>()\n\tconst dependencies = new Map<string, Set<string>>()\n\tconst resolver = createResolver()\n\tfor (const file of files) {\n\t\tconst filename = resolve(root, file)\n\t\tconst parsed = parseSync(filename, readFileSync(filename, 'utf8'))\n\t\tif (parsed.errors.length) {\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'parse',\n\t\t\t\tfile,\n\t\t\t\tmessage: `Cannot validate ${file}: ${parsed.errors[0].message}`,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tif (testFile(file)) {\n\t\t\tif (!file.includes('__tests__/'))\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tcode: 'test-location',\n\t\t\t\t\tfile,\n\t\t\t\t\tmessage: 'Place tests in a sibling __tests__/ directory.',\n\t\t\t\t})\n\t\t\telse if (dirname(file).endsWith('__tests__') && hasRunnableTest(parsed.program))\n\t\t\t\ttested.add(dirname(dirname(file)))\n\t\t\tcontinue\n\t\t}\n\t\tif (file.split('/').includes('__tests__')) continue\n\t\tif (/^domain\\/[^/]+$/.test(file) && file !== 'domain/table.ts')\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'domain-entry',\n\t\t\t\tfile,\n\t\t\t\tmessage:\n\t\t\t\t\t'Domain source belongs in domain/<module>/ or domain/shared/. Only domain/table.ts assembles module tables.',\n\t\t\t})\n\t\tif (executable(parsed.program) && file !== 'domain/table.ts') required.add(dirname(file))\n\t\tconst owner = moduleOwner(file) ?? ''\n\t\tconst targets = new Set<string>()\n\t\tdependencies.set(file, targets)\n\t\tfor (const source of runtimeImports(parsed.program)) {\n\t\t\tconst target = resolveImport(resolver, filename, source)\n\t\t\tif (!target) continue\n\t\t\tconst targetFile = relative(root, target).split(sep).join('/')\n\t\t\ttargets.add(targetFile)\n\t\t\tconst targetOwner = moduleOwner(targetFile)\n\t\t\tif (owner && targetOwner && owner !== targetOwner) {\n\t\t\t\tconst edges = graph.get(owner) ?? new Set<string>()\n\t\t\t\tgraph.set(owner, edges)\n\t\t\t\tedges.add(targetOwner)\n\t\t\t}\n\t\t}\n\t}\n\tfor (const directory of required) {\n\t\tif (!tested.has(directory))\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'tests',\n\t\t\t\tfile: directory,\n\t\t\t\tmessage: `${directory}/__tests__/ must contain a .test or .spec file with a nonempty, non-skipped test. Parent or child suites do not count.`,\n\t\t\t})\n\t}\n\tdiagnostics.push(...sharedOwnership(dependencies))\n\tfor (const cycle of cycles(graph))\n\t\tdiagnostics.push({\n\t\t\tcode: 'cycle',\n\t\t\tfile: cycle[0],\n\t\t\tmessage: `Module dependency cycle: ${cycle.join(' → ')}.`,\n\t\t})\n\treturn diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code))\n}\n\nexport function createResolver() {\n\treturn new ResolverFactory({\n\t\ttsconfig: 'auto',\n\t\textensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json'],\n\t\textensionAlias: {\n\t\t\t'.js': ['.ts', '.tsx', '.js'],\n\t\t\t'.mjs': ['.mts', '.mjs'],\n\t\t\t'.cjs': ['.cts', '.cjs'],\n\t\t},\n\t\tconditionNames: ['types', 'import', 'node', 'default'],\n\t\tsymlinks: true,\n\t})\n}\n\nexport function resolveImport(resolver: ResolverFactory, filename: string, source: string) {\n\tconst found = resolver.resolveFileSync(filename, source).path\n\tif (found) return found\n\t// Keep path checks useful in unsaved/editor fixtures and before Convex codegen.\n\treturn source.startsWith('.') ? resolve(dirname(filename), source) : null\n}\n\n/** The lint rule runs the project scan on one deterministic source file. */\nexport function architectureAnchor(root: string) {\n\tif (!existsSync(root)) return null\n\tif (existsSync(resolve(root, 'convex.config.ts')))\n\t\treturn realpathSync(resolve(root, 'convex.config.ts'))\n\troot = realpathSync(root)\n\tfor (const file of sourceFiles(root, []))\n\t\tif (!file.includes('__tests__/') && !testFile(file)) return resolve(root, file)\n\treturn null\n}\n\nfunction* sourceFiles(root: string, diagnostics: ArchitectureDiagnostic[]): Generator<string> {\n\tconst allowed = new Set([\n\t\t'_generated',\n\t\t'__tests__',\n\t\t'api',\n\t\t'domain',\n\t\t'application',\n\t\t'migrations',\n\t\t'components',\n\t])\n\tfunction* scan(directory: string): Generator<string> {\n\t\tfor (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) =>\n\t\t\ta.name.localeCompare(b.name),\n\t\t)) {\n\t\t\tconst path = resolve(directory, entry.name)\n\t\t\tconst file = relative(root, path).split(sep).join('/')\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tcode: 'symlink',\n\t\t\t\t\tfile,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t'Keep application source inside its owning directory; symlinked files and folders are not allowed.',\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tif (directory === root && !allowed.has(entry.name))\n\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\tcode: 'root-directory',\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\tmessage: `Root folder ${entry.name}/ is not allowed. Use api/, domain/, application/, migrations/, components/, __tests__/, or _generated/.`,\n\t\t\t\t\t})\n\t\t\t\tif (\n\t\t\t\t\tentry.name !== '_generated' &&\n\t\t\t\t\tentry.name !== 'node_modules' &&\n\t\t\t\t\t!entry.name.startsWith('.')\n\t\t\t\t)\n\t\t\t\t\tyield* scan(path)\n\t\t\t} else if (/\\.[cm]?[jt]sx?$/.test(entry.name) && !/\\.d\\.[cm]?ts$/.test(entry.name)) yield file\n\t\t}\n\t}\n\tyield* scan(root)\n}\n\nfunction testFile(file: string) {\n\treturn /\\.(?:test|spec)\\.[cm]?[jt]sx?$/.test(file)\n}\n\nfunction executable(program: Program) {\n\treturn program.body.some((statement) => {\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration && 'declare' in declaration && declaration.declare) return false\n\t\tif (statement.type === 'ImportDeclaration' || statement.type === 'EmptyStatement') return false\n\t\tif (statement.type === 'ExportNamedDeclaration') {\n\t\t\tif (statement.exportKind === 'type' || !statement.declaration) return false\n\t\t\treturn !['TSInterfaceDeclaration', 'TSTypeAliasDeclaration', 'TSDeclareFunction'].includes(\n\t\t\t\tstatement.declaration.type,\n\t\t\t)\n\t\t}\n\t\treturn ![\n\t\t\t'TSInterfaceDeclaration',\n\t\t\t'TSTypeAliasDeclaration',\n\t\t\t'TSDeclareFunction',\n\t\t\t'ExportAllDeclaration',\n\t\t].includes(statement.type)\n\t})\n}\n\nfunction hasRunnableTest(program: Program) {\n\tconst names = new Map([\n\t\t['test', 'test'],\n\t\t['it', 'it'],\n\t\t['describe', 'describe'],\n\t\t['suite', 'suite'],\n\t])\n\tfor (const statement of program.body) {\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration?.type === 'FunctionDeclaration' && declaration.id)\n\t\t\tnames.delete(declaration.id.name)\n\t\tif (declaration?.type === 'VariableDeclaration')\n\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\tif (item.id.type === 'Identifier') names.delete(item.id.name)\n\t\t\t}\n\t\tif (statement.type !== 'ImportDeclaration') continue\n\t\tfor (const specifier of statement.specifiers) {\n\t\t\tnames.delete(specifier.local.name)\n\t\t\tif (\n\t\t\t\t!['vitest', 'vite-plus/test', 'bun:test', 'node:test', '@jest/globals'].includes(\n\t\t\t\t\tstatement.source.value,\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tcontinue\n\t\t\tif (specifier.type === 'ImportNamespaceSpecifier') names.set(specifier.local.name, '*')\n\t\t\telse if (specifier.type === 'ImportDefaultSpecifier') names.set(specifier.local.name, 'test')\n\t\t\telse if (specifier.imported.type === 'Identifier')\n\t\t\t\tnames.set(specifier.local.name, specifier.imported.name)\n\t\t}\n\t}\n\tconst calls: CallExpression[] = []\n\tnew Visitor({\n\t\tCallExpression(node) {\n\t\t\tcalls.push(node)\n\t\t},\n\t}).visit(program)\n\tconst skipped = calls.filter((node) => {\n\t\tconst parts = testCallee(node.callee, names)\n\t\treturn (\n\t\t\t['test', 'it', 'describe', 'suite'].includes(parts[0]) &&\n\t\t\t(parts.some((part) => ['skip', 'todo', 'skipIf', 'runIf'].includes(part)) ||\n\t\t\t\tnode.arguments.some(\n\t\t\t\t\t(argument) =>\n\t\t\t\t\t\targument.type === 'ObjectExpression' &&\n\t\t\t\t\t\targument.properties.some(\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.type === 'Property' &&\n\t\t\t\t\t\t\t\t['skip', 'todo'].includes(\n\t\t\t\t\t\t\t\t\tproperty.key.type === 'Identifier'\n\t\t\t\t\t\t\t\t\t\t? property.key.name\n\t\t\t\t\t\t\t\t\t\t: property.key.type === 'Literal'\n\t\t\t\t\t\t\t\t\t\t\t? String(property.key.value)\n\t\t\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\t) &&\n\t\t\t\t\t\t\t\t!(property.value.type === 'Literal' && property.value.value === false),\n\t\t\t\t\t\t),\n\t\t\t\t))\n\t\t)\n\t})\n\treturn calls.some((node) => {\n\t\tconst parts = testCallee(node.callee, names)\n\t\tif (\n\t\t\t!['test', 'it'].includes(parts[0]) ||\n\t\t\tskipped.some((skip) => node.start >= skip.start && node.end <= skip.end)\n\t\t)\n\t\t\treturn false\n\t\t// each(...) is a factory; only the outer call has the test callback.\n\t\treturn node.arguments.some(\n\t\t\t(argument) =>\n\t\t\t\t(argument.type === 'ArrowFunctionExpression' || argument.type === 'FunctionExpression') &&\n\t\t\t\targument.body &&\n\t\t\t\t(argument.body.type !== 'BlockStatement' ||\n\t\t\t\t\targument.body.body.some((statement) => statement.type !== 'EmptyStatement')),\n\t\t)\n\t})\n}\n\nfunction testCallee(node: Node, names: Map<string, string>): string[] {\n\tif (node.type === 'Identifier') {\n\t\tconst name = names.get(node.name)\n\t\treturn name ? [name] : []\n\t}\n\tif (node.type === 'CallExpression') return testCallee(node.callee, names)\n\tif (node.type === 'MemberExpression') {\n\t\tconst base = testCallee(node.object, names)\n\t\tconst property =\n\t\t\t!node.computed && node.property.type === 'Identifier'\n\t\t\t\t? node.property.name\n\t\t\t\t: node.property.type === 'Literal'\n\t\t\t\t\t? String(node.property.value)\n\t\t\t\t\t: ''\n\t\tif (!base.length || !property) return []\n\t\treturn base[0] === '*' ? [property] : [...base, property]\n\t}\n\treturn []\n}\n\nfunction runtimeImports(program: Program) {\n\tconst imports: string[] = []\n\tnew Visitor({\n\t\tImportDeclaration(node) {\n\t\t\tif (\n\t\t\t\tnode.importKind !== 'type' &&\n\t\t\t\t(node.specifiers.length === 0 ||\n\t\t\t\t\tnode.specifiers.some((s) => s.type !== 'ImportSpecifier' || s.importKind !== 'type'))\n\t\t\t)\n\t\t\t\timports.push(node.source.value)\n\t\t},\n\t\tExportNamedDeclaration(node) {\n\t\t\tif (\n\t\t\t\tnode.source &&\n\t\t\t\tnode.exportKind !== 'type' &&\n\t\t\t\tnode.specifiers.some((specifier) => specifier.exportKind !== 'type')\n\t\t\t)\n\t\t\t\timports.push(node.source.value)\n\t\t},\n\t\tExportAllDeclaration(node) {\n\t\t\tif (node.exportKind !== 'type') imports.push(node.source.value)\n\t\t},\n\t\tImportExpression(node) {\n\t\t\tif (node.source.type === 'Literal' && String(node.source.value) === node.source.value)\n\t\t\t\timports.push(String(node.source.value))\n\t\t},\n\t}).visit(program)\n\treturn imports\n}\n\nfunction moduleOwner(file: string) {\n\tconst parts = file.split('/')\n\treturn parts[0] === 'domain' && parts.length >= 3 && parts[1] !== '__tests__'\n\t\t? `domain/${parts[1]}`\n\t\t: null\n}\n\nfunction cycles(graph: Map<string, Set<string>>) {\n\tconst completed = new Set<string>()\n\tconst stack: string[] = []\n\tconst found: string[][] = []\n\tfunction visit(owner: string) {\n\t\tconst index = stack.indexOf(owner)\n\t\tif (index >= 0) {\n\t\t\tfound.push([...stack.slice(index), owner])\n\t\t\treturn\n\t\t}\n\t\tif (completed.has(owner)) return\n\t\tstack.push(owner)\n\t\tfor (const dependency of graph.get(owner) ?? []) visit(dependency)\n\t\tstack.pop()\n\t\tcompleted.add(owner)\n\t}\n\tfor (const owner of graph.keys()) visit(owner)\n\treturn found\n}\n\nfunction sharedOwnership(dependencies: Map<string, Set<string>>): ArchitectureDiagnostic[] {\n\tconst consumers = new Map<string, Set<string>>()\n\tfor (const [file, targets] of dependencies) {\n\t\tconst owner = moduleOwner(file) ?? ''\n\t\tif (!owner || owner === 'domain/shared') continue\n\t\tconst visited = new Set<string>()\n\t\tfunction visit(target: string) {\n\t\t\tif (!target.startsWith('domain/shared/') || visited.has(target)) return\n\t\t\tvisited.add(target)\n\t\t\tconst owners = consumers.get(target) ?? new Set<string>()\n\t\t\towners.add(owner)\n\t\t\tconsumers.set(target, owners)\n\t\t\tfor (const next of dependencies.get(target) ?? []) visit(next)\n\t\t}\n\t\tfor (const target of targets) visit(target)\n\t}\n\tconst diagnostics: ArchitectureDiagnostic[] = []\n\tfor (const [file, owners] of consumers) {\n\t\tif (owners.size === 1)\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'shared-owner',\n\t\t\t\tfile,\n\t\t\t\tmessage: `This shared implementation is used only by ${[...owners][0]}. Move it into that module until another module needs it.`,\n\t\t\t})\n\t}\n\treturn diagnostics\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"architecture.mjs","names":["inspectArchitecture","requestedRoot","resolve","options","root","existsSync","realpathSync","diagnostics","files","sourceFiles","required","tested","graph","dependencies","resolver","createResolver","file","filename","parsed","parseSync","readFileSync","testFile","dirname","hasRunnableTest","executable","owner","moduleOwner","targets","source","runtimeImports","target","resolveImport","targetFile","relative","sep","targetOwner","edges","directory","sharedOwnership","cycle","cycles","a","b","ResolverFactory","architectureAnchor","allowed","scan","entry","readdirSync","path","program","declaration","statement","names","item","specifier","calls","Visitor","node","skipped","parts","testCallee","part","argument","property","skip","name","base","imports","s","completed","stack","found","visit","index","dependency","consumers","visited","owners","next"],"sources":["../../src/oxlint/architecture.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs'\nimport { dirname, relative, resolve, sep } from 'node:path'\nimport { parseSync, Visitor, type Program, type Node, type CallExpression } from 'oxc-parser'\nimport { ResolverFactory } from 'oxc-resolver'\n\nexport interface ArchitectureOptions {\n\tcwd?: string\n\tconvexDir?: string\n}\nexport interface ArchitectureDiagnostic {\n\tcode:\n\t\t| 'missing-root'\n\t\t| 'root-directory'\n\t\t| 'tests'\n\t\t| 'test-location'\n\t\t| 'parse'\n\t\t| 'cycle'\n\t\t| 'symlink'\n\t\t| 'domain-entry'\n\t\t| 'shared-owner'\n\tfile: string\n\tmessage: string\n}\n\n/** Full-project checks, independent of the consumer's test runner. No persistent cache. */\nexport function inspectArchitecture(options: ArchitectureOptions = {}): ArchitectureDiagnostic[] {\n\tconst requestedRoot = resolve(options.cwd ?? process.cwd(), options.convexDir ?? 'convex')\n\tconst root = existsSync(requestedRoot) ? realpathSync(requestedRoot) : requestedRoot\n\tconst diagnostics: ArchitectureDiagnostic[] = []\n\tif (!existsSync(root))\n\t\treturn [\n\t\t\t{ code: 'missing-root', file: '.', message: `Convex directory does not exist: ${root}` },\n\t\t]\n\tconst files = sourceFiles(root, diagnostics)\n\tconst required = new Set<string>()\n\tconst tested = new Set<string>()\n\tconst graph = new Map<string, Set<string>>()\n\tconst dependencies = new Map<string, Set<string>>()\n\tconst resolver = createResolver()\n\tfor (const file of files) {\n\t\tconst filename = resolve(root, file)\n\t\tconst parsed = parseSync(filename, readFileSync(filename, 'utf8'))\n\t\tif (parsed.errors.length) {\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'parse',\n\t\t\t\tfile,\n\t\t\t\tmessage: `Cannot validate ${file}: ${parsed.errors[0].message}`,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tif (testFile(file)) {\n\t\t\tif (!file.includes('__tests__/'))\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tcode: 'test-location',\n\t\t\t\t\tfile,\n\t\t\t\t\tmessage: 'Place tests in a sibling __tests__/ directory.',\n\t\t\t\t})\n\t\t\telse if (dirname(file).endsWith('__tests__') && hasRunnableTest(parsed.program))\n\t\t\t\ttested.add(dirname(dirname(file)))\n\t\t\tcontinue\n\t\t}\n\t\tif (file.split('/').includes('__tests__')) continue\n\t\tif (/^domain\\/[^/]+$/.test(file) && file !== 'domain/table.ts')\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'domain-entry',\n\t\t\t\tfile,\n\t\t\t\tmessage:\n\t\t\t\t\t'Domain source belongs in domain/<module>/ or domain/shared/. Only domain/table.ts assembles module tables.',\n\t\t\t})\n\t\tif (executable(parsed.program) && file !== 'domain/table.ts') required.add(dirname(file))\n\t\tconst owner = moduleOwner(file) ?? ''\n\t\tconst targets = new Set<string>()\n\t\tdependencies.set(file, targets)\n\t\tfor (const source of runtimeImports(parsed.program)) {\n\t\t\tconst target = resolveImport(resolver, filename, source)\n\t\t\tif (!target) continue\n\t\t\tconst targetFile = relative(root, target).split(sep).join('/')\n\t\t\ttargets.add(targetFile)\n\t\t\tconst targetOwner = moduleOwner(targetFile)\n\t\t\tif (owner && targetOwner && owner !== targetOwner) {\n\t\t\t\tconst edges = graph.get(owner) ?? new Set<string>()\n\t\t\t\tgraph.set(owner, edges)\n\t\t\t\tedges.add(targetOwner)\n\t\t\t}\n\t\t}\n\t}\n\tfor (const directory of required) {\n\t\tif (!tested.has(directory))\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'tests',\n\t\t\t\tfile: directory,\n\t\t\t\tmessage: `${directory}/__tests__/ must contain a .test or .spec file with a nonempty, non-skipped test. Parent or child suites do not count.`,\n\t\t\t})\n\t}\n\tdiagnostics.push(...sharedOwnership(dependencies))\n\tfor (const cycle of cycles(graph))\n\t\tdiagnostics.push({\n\t\t\tcode: 'cycle',\n\t\t\tfile: cycle[0],\n\t\t\tmessage: `Module dependency cycle: ${cycle.join(' → ')}.`,\n\t\t})\n\treturn diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code))\n}\n\nexport function createResolver() {\n\treturn new ResolverFactory({\n\t\ttsconfig: 'auto',\n\t\textensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json'],\n\t\textensionAlias: {\n\t\t\t'.js': ['.ts', '.tsx', '.js'],\n\t\t\t'.mjs': ['.mts', '.mjs'],\n\t\t\t'.cjs': ['.cts', '.cjs'],\n\t\t},\n\t\tconditionNames: ['types', 'import', 'node', 'default'],\n\t\tsymlinks: true,\n\t})\n}\n\nexport function resolveImport(resolver: ResolverFactory, filename: string, source: string) {\n\tconst found = resolver.resolveFileSync(filename, source).path\n\tif (found) return found\n\t// Keep path checks useful in unsaved/editor fixtures and before Convex codegen.\n\treturn source.startsWith('.') ? resolve(dirname(filename), source) : null\n}\n\n/** The lint rule runs the project scan on one deterministic source file. */\nexport function architectureAnchor(root: string) {\n\tif (!existsSync(root)) return null\n\tif (existsSync(resolve(root, 'convex.config.ts')))\n\t\treturn realpathSync(resolve(root, 'convex.config.ts'))\n\troot = realpathSync(root)\n\tfor (const file of sourceFiles(root, []))\n\t\tif (!file.includes('__tests__/') && !testFile(file)) return resolve(root, file)\n\treturn null\n}\n\nfunction* sourceFiles(root: string, diagnostics: ArchitectureDiagnostic[]): Generator<string> {\n\tconst allowed = new Set([\n\t\t'_generated',\n\t\t'__tests__',\n\t\t'api',\n\t\t'domain',\n\t\t'application',\n\t\t'migrations',\n\t\t'components',\n\t])\n\tfunction* scan(directory: string): Generator<string> {\n\t\tfor (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) =>\n\t\t\ta.name.localeCompare(b.name),\n\t\t)) {\n\t\t\tconst path = resolve(directory, entry.name)\n\t\t\tconst file = relative(root, path).split(sep).join('/')\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tcode: 'symlink',\n\t\t\t\t\tfile,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t'Keep application source inside its owning directory; symlinked files and folders are not allowed.',\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tif (directory === root && !allowed.has(entry.name))\n\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\tcode: 'root-directory',\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\tmessage: `Root folder ${entry.name}/ is not allowed. Use api/, domain/, application/, migrations/, components/, __tests__/, or _generated/.`,\n\t\t\t\t\t})\n\t\t\t\tif (\n\t\t\t\t\tentry.name !== '_generated' &&\n\t\t\t\t\tentry.name !== 'node_modules' &&\n\t\t\t\t\t!entry.name.startsWith('.')\n\t\t\t\t)\n\t\t\t\t\tyield* scan(path)\n\t\t\t} else if (/\\.[cm]?[jt]sx?$/.test(entry.name) && !/\\.d\\.[cm]?ts$/.test(entry.name)) yield file\n\t\t}\n\t}\n\tyield* scan(root)\n}\n\nfunction testFile(file: string) {\n\treturn /\\.(?:test|spec)\\.[cm]?[jt]sx?$/.test(file)\n}\n\nfunction executable(program: Program) {\n\treturn program.body.some((statement) => {\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration && 'declare' in declaration && declaration.declare) return false\n\t\tif (statement.type === 'ImportDeclaration' || statement.type === 'EmptyStatement') return false\n\t\tif (statement.type === 'ExportNamedDeclaration') {\n\t\t\tif (statement.exportKind === 'type' || !statement.declaration) return false\n\t\t\treturn !['TSInterfaceDeclaration', 'TSTypeAliasDeclaration', 'TSDeclareFunction'].includes(\n\t\t\t\tstatement.declaration.type,\n\t\t\t)\n\t\t}\n\t\treturn ![\n\t\t\t'TSInterfaceDeclaration',\n\t\t\t'TSTypeAliasDeclaration',\n\t\t\t'TSDeclareFunction',\n\t\t\t'ExportAllDeclaration',\n\t\t].includes(statement.type)\n\t})\n}\n\nfunction hasRunnableTest(program: Program) {\n\tconst names = new Map([\n\t\t['test', 'test'],\n\t\t['it', 'it'],\n\t\t['describe', 'describe'],\n\t\t['suite', 'suite'],\n\t])\n\tfor (const statement of program.body) {\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration?.type === 'FunctionDeclaration' && declaration.id)\n\t\t\tnames.delete(declaration.id.name)\n\t\tif (declaration?.type === 'VariableDeclaration')\n\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\tif (item.id.type === 'Identifier') names.delete(item.id.name)\n\t\t\t}\n\t\tif (statement.type !== 'ImportDeclaration') continue\n\t\tfor (const specifier of statement.specifiers) {\n\t\t\tnames.delete(specifier.local.name)\n\t\t\tif (\n\t\t\t\t!['vitest', 'vite-plus/test', 'bun:test', 'node:test', '@jest/globals'].includes(\n\t\t\t\t\tstatement.source.value,\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tcontinue\n\t\t\tif (specifier.type === 'ImportNamespaceSpecifier') names.set(specifier.local.name, '*')\n\t\t\telse if (specifier.type === 'ImportDefaultSpecifier') names.set(specifier.local.name, 'test')\n\t\t\telse if (specifier.imported.type === 'Identifier')\n\t\t\t\tnames.set(specifier.local.name, specifier.imported.name)\n\t\t}\n\t}\n\tconst calls: CallExpression[] = []\n\tnew Visitor({\n\t\tCallExpression(node) {\n\t\t\tcalls.push(node)\n\t\t},\n\t}).visit(program)\n\tconst skipped = calls.filter((node) => {\n\t\tconst parts = testCallee(node.callee, names)\n\t\treturn (\n\t\t\t['test', 'it', 'describe', 'suite'].includes(parts[0]) &&\n\t\t\t(parts.some((part) => ['skip', 'todo', 'skipIf', 'runIf'].includes(part)) ||\n\t\t\t\tnode.arguments.some(\n\t\t\t\t\t(argument) =>\n\t\t\t\t\t\targument.type === 'ObjectExpression' &&\n\t\t\t\t\t\targument.properties.some(\n\t\t\t\t\t\t\t(property) =>\n\t\t\t\t\t\t\t\tproperty.type === 'Property' &&\n\t\t\t\t\t\t\t\t['skip', 'todo'].includes(\n\t\t\t\t\t\t\t\t\tproperty.key.type === 'Identifier'\n\t\t\t\t\t\t\t\t\t\t? property.key.name\n\t\t\t\t\t\t\t\t\t\t: property.key.type === 'Literal'\n\t\t\t\t\t\t\t\t\t\t\t? String(property.key.value)\n\t\t\t\t\t\t\t\t\t\t\t: '',\n\t\t\t\t\t\t\t\t) &&\n\t\t\t\t\t\t\t\t!(property.value.type === 'Literal' && property.value.value === false),\n\t\t\t\t\t\t),\n\t\t\t\t))\n\t\t)\n\t})\n\treturn calls.some((node) => {\n\t\tconst parts = testCallee(node.callee, names)\n\t\tif (\n\t\t\t!['test', 'it'].includes(parts[0]) ||\n\t\t\tskipped.some((skip) => node.start >= skip.start && node.end <= skip.end)\n\t\t)\n\t\t\treturn false\n\t\t// each(...) is a factory; only the outer call has the test callback.\n\t\treturn node.arguments.some(\n\t\t\t(argument) =>\n\t\t\t\t(argument.type === 'ArrowFunctionExpression' || argument.type === 'FunctionExpression') &&\n\t\t\t\targument.body &&\n\t\t\t\t(argument.body.type !== 'BlockStatement' ||\n\t\t\t\t\targument.body.body.some((statement) => statement.type !== 'EmptyStatement')),\n\t\t)\n\t})\n}\n\nfunction testCallee(node: Node, names: Map<string, string>): string[] {\n\tif (node.type === 'Identifier') {\n\t\tconst name = names.get(node.name)\n\t\treturn name ? [name] : []\n\t}\n\tif (node.type === 'CallExpression') return testCallee(node.callee, names)\n\tif (node.type === 'MemberExpression') {\n\t\tconst base = testCallee(node.object, names)\n\t\tconst property =\n\t\t\t!node.computed && node.property.type === 'Identifier'\n\t\t\t\t? node.property.name\n\t\t\t\t: node.property.type === 'Literal'\n\t\t\t\t\t? String(node.property.value)\n\t\t\t\t\t: ''\n\t\tif (!base.length || !property) return []\n\t\treturn base[0] === '*' ? [property] : [...base, property]\n\t}\n\treturn []\n}\n\nfunction runtimeImports(program: Program) {\n\tconst imports: string[] = []\n\tnew Visitor({\n\t\tImportDeclaration(node) {\n\t\t\tif (\n\t\t\t\tnode.importKind !== 'type' &&\n\t\t\t\t(node.specifiers.length === 0 ||\n\t\t\t\t\tnode.specifiers.some((s) => s.type !== 'ImportSpecifier' || s.importKind !== 'type'))\n\t\t\t)\n\t\t\t\timports.push(node.source.value)\n\t\t},\n\t\tExportNamedDeclaration(node) {\n\t\t\tif (\n\t\t\t\tnode.source &&\n\t\t\t\tnode.exportKind !== 'type' &&\n\t\t\t\tnode.specifiers.some((specifier) => specifier.exportKind !== 'type')\n\t\t\t)\n\t\t\t\timports.push(node.source.value)\n\t\t},\n\t\tExportAllDeclaration(node) {\n\t\t\tif (node.exportKind !== 'type') imports.push(node.source.value)\n\t\t},\n\t\tImportExpression(node) {\n\t\t\tif (node.source.type === 'Literal' && String(node.source.value) === node.source.value)\n\t\t\t\timports.push(String(node.source.value))\n\t\t},\n\t}).visit(program)\n\treturn imports\n}\n\nfunction moduleOwner(file: string) {\n\tconst parts = file.split('/')\n\treturn parts[0] === 'domain' && parts.length >= 3 && parts[1] !== '__tests__'\n\t\t? `domain/${parts[1]}`\n\t\t: null\n}\n\nfunction cycles(graph: Map<string, Set<string>>) {\n\tconst completed = new Set<string>()\n\tconst stack: string[] = []\n\tconst found: string[][] = []\n\tfunction visit(owner: string) {\n\t\tconst index = stack.indexOf(owner)\n\t\tif (index >= 0) {\n\t\t\tfound.push([...stack.slice(index), owner])\n\t\t\treturn\n\t\t}\n\t\tif (completed.has(owner)) return\n\t\tstack.push(owner)\n\t\tfor (const dependency of graph.get(owner) ?? []) visit(dependency)\n\t\tstack.pop()\n\t\tcompleted.add(owner)\n\t}\n\tfor (const owner of graph.keys()) visit(owner)\n\treturn found\n}\n\nfunction sharedOwnership(dependencies: Map<string, Set<string>>): ArchitectureDiagnostic[] {\n\tconst consumers = new Map<string, Set<string>>()\n\tfor (const [file, targets] of dependencies) {\n\t\tconst owner = moduleOwner(file) ?? ''\n\t\tif (!owner || owner === 'domain/shared') continue\n\t\tconst visited = new Set<string>()\n\t\tfunction visit(target: string) {\n\t\t\tif (!target.startsWith('domain/shared/') || visited.has(target)) return\n\t\t\tvisited.add(target)\n\t\t\tconst owners = consumers.get(target) ?? new Set<string>()\n\t\t\towners.add(owner)\n\t\t\tconsumers.set(target, owners)\n\t\t\tfor (const next of dependencies.get(target) ?? []) visit(next)\n\t\t}\n\t\tfor (const target of targets) visit(target)\n\t}\n\tconst diagnostics: ArchitectureDiagnostic[] = []\n\tfor (const [file, owners] of consumers) {\n\t\tif (owners.size === 1)\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: 'shared-owner',\n\t\t\t\tfile,\n\t\t\t\tmessage: `This shared implementation is used only by ${[...owners][0]}. Move it into that module until another module needs it.`,\n\t\t\t})\n\t}\n\treturn diagnostics\n}\n"],"mappings":"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"}
|
package/dist/oxlint/ast.d.mts
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { Context, ESTree, RuleMeta, Visitor } from "@oxlint/plugins";
|
|
3
3
|
//#region src/oxlint/ast.d.ts
|
|
4
|
-
declare const consumerOptions: z.ZodObject<{
|
|
4
|
+
export declare const consumerOptions: z.ZodObject<{
|
|
5
5
|
convexDir: z.ZodDefault<z.ZodString>;
|
|
6
6
|
}, z.core.$strip>;
|
|
7
|
-
declare function appFile(context: Context, filename?: string): string | null;
|
|
8
|
-
declare function imported(context: Context, node: ESTree.Node): {
|
|
7
|
+
export declare function appFile(context: Context, filename?: string): string | null;
|
|
8
|
+
export declare function imported(context: Context, node: ESTree.Node): {
|
|
9
9
|
source: string;
|
|
10
10
|
name: string;
|
|
11
11
|
} | null;
|
|
12
|
-
declare function sourceVisitors(context: Context, check: (node: ESTree.Node, source: string) => void): Visitor;
|
|
13
|
-
declare function isFunctionsImport(context: Context, source: string): boolean;
|
|
14
|
-
declare function typeOnlySource(node: ESTree.Node): boolean;
|
|
15
|
-
declare function isDbAccess(node: ESTree.CallExpression): boolean;
|
|
16
|
-
declare function isExternalCall(context: Context, node: ESTree.CallExpression): boolean;
|
|
17
|
-
declare function containsComponentReference(context: Context, node: ESTree.Node): boolean;
|
|
18
|
-
declare function rootMember(node: ESTree.Node): ESTree.Node;
|
|
19
|
-
declare function memberPath(node: ESTree.Node): string[];
|
|
20
|
-
declare function isTableChain(node: ESTree.Node): boolean;
|
|
21
|
-
declare function isDbWrite(node: ESTree.CallExpression): boolean;
|
|
22
|
-
declare function hasCall(node: ESTree.Node, name: string): boolean;
|
|
23
|
-
declare function metadata(description: string, messages: Record<string, string>): RuleMeta;
|
|
24
|
-
declare function componentRoot(context: Context, filename: string): string | null;
|
|
25
|
-
declare function staticString(node: ESTree.Node | null | undefined): string | null;
|
|
26
|
-
declare function propertyName(node: ESTree.Node): string | null;
|
|
27
|
-
declare function binding(context: Context, node: ESTree.Node): import("@oxlint/plugins").Variable | null;
|
|
28
|
-
declare function exportedNames(program: ESTree.Program): Set<string>;
|
|
29
|
-
declare function exportName(node: ESTree.Node): string | null;
|
|
30
|
-
declare function delegatingBody(node: ESTree.Node): boolean;
|
|
12
|
+
export declare function sourceVisitors(context: Context, check: (node: ESTree.Node, source: string) => void): Visitor;
|
|
13
|
+
export declare function isFunctionsImport(context: Context, source: string): boolean;
|
|
14
|
+
export declare function typeOnlySource(node: ESTree.Node): boolean;
|
|
15
|
+
export declare function isDbAccess(node: ESTree.CallExpression): boolean;
|
|
16
|
+
export declare function isExternalCall(context: Context, node: ESTree.CallExpression): boolean;
|
|
17
|
+
export declare function containsComponentReference(context: Context, node: ESTree.Node): boolean;
|
|
18
|
+
export declare function rootMember(node: ESTree.Node): ESTree.Node;
|
|
19
|
+
export declare function memberPath(node: ESTree.Node): string[];
|
|
20
|
+
export declare function isTableChain(node: ESTree.Node): boolean;
|
|
21
|
+
export declare function isDbWrite(node: ESTree.CallExpression): boolean;
|
|
22
|
+
export declare function hasCall(node: ESTree.Node, name: string): boolean;
|
|
23
|
+
export declare function metadata(description: string, messages: Record<string, string>): RuleMeta;
|
|
24
|
+
export declare function componentRoot(context: Context, filename: string): string | null;
|
|
25
|
+
export declare function staticString(node: ESTree.Node | null | undefined): string | null;
|
|
26
|
+
export declare function propertyName(node: ESTree.Node): string | null;
|
|
27
|
+
export declare function binding(context: Context, node: ESTree.Node): import("@oxlint/plugins").Variable | null;
|
|
28
|
+
export declare function exportedNames(program: ESTree.Program): Set<string>;
|
|
29
|
+
export declare function exportName(node: ESTree.Node): string | null;
|
|
30
|
+
export declare function delegatingBody(node: ESTree.Node): boolean;
|
|
31
31
|
//#endregion
|
|
32
|
-
export { appFile, binding, componentRoot, consumerOptions, containsComponentReference, delegatingBody, exportName, exportedNames, hasCall, imported, isDbAccess, isDbWrite, isExternalCall, isFunctionsImport, isTableChain, memberPath, metadata, propertyName, rootMember, sourceVisitors, staticString, typeOnlySource };
|
|
33
32
|
//# sourceMappingURL=ast.d.mts.map
|
package/dist/oxlint/ast.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createResolver as e,resolveImport as t}from"./architecture.mjs";import{z as n}from"zod";import{dirname as r,relative as i,resolve as a,sep as o}from"node:path";import{existsSync as s,realpathSync as c}from"node:fs";const l=n.object({convexDir:n.string().min(1).default(`convex`)});function u(e,t=e.filename){let n=a(e.cwd,l.parse(e.options[0]??{}).convexDir),r=s(n)?c(n):n,u=i(r,s(t)?c(t):t).split(o).join(`/`);return u===`..`||u.startsWith(`../`)||u.startsWith(`/`)?null:u}function d(e,t){if(t.type===`CallExpression`)return d(e,t.callee);if(t.type===`MemberExpression`){let n=d(e,t.object),r=E(t);return n&&r&&[`*`,`z`,`default`].includes(n.name)?{source:n.source,name:r}:null}if(t.type!==`Identifier`)return null;for(let n of D(e,t)?.defs??[]){if(n.type!==`ImportBinding`||n.parent?.type!==`ImportDeclaration`||n.parent.importKind===`type`)continue;let e=n.node;if(e.type!==`ImportSpecifier`||e.importKind!==`type`)return{source:n.parent.source.value,name:e.type===`ImportSpecifier`?k(e.imported)??``:e.type===`ImportDefaultSpecifier`?`default`:`*`}}return null}function f(e,t){function n(e,n){let r=T(n);r&&t(e,r)}return{ImportDeclaration(e){n(e,e.source)},ExportNamedDeclaration(e){n(e,e.source)},ExportAllDeclaration(e){n(e,e.source)},ImportExpression(e){n(e,e.source)},TSImportType(e){n(e,e.source)},CallExpression(t){t.callee.type===`Identifier`&&t.callee.name===`require`&&!D(e,t.callee)?.defs.length&&n(t,t.arguments[0])}}}function p(n,i){let o=i.startsWith(`.`)?a(r(n.filename),i):t(e(),n.filename,i);return o!==null&&u(n,o)?.replace(/\.[cm]?[jt]s$/,``)===`functions`}function m(e){return e.type===`TSImportType`||e.type===`ImportDeclaration`&&(e.importKind===`type`||e.specifiers.length>0&&e.specifiers.every(e=>e.type===`ImportSpecifier`&&e.importKind===`type`))||(e.type===`ExportNamedDeclaration`||e.type===`ExportAllDeclaration`)&&e.exportKind===`type`}function h(e){return e.callee.type===`MemberExpression`&&e.callee.object.type===`MemberExpression`&&E(e.callee.object)===`db`}function g(e,t){let n=d(e,t.callee);return n&&/^(?:node:)?(?:https?|net|tls|fs)(?:\/|$)|^(?:undici|axios)(?:\/|$)/.test(n.source)?!0:t.callee.type===`Identifier`&&t.callee.name===`fetch`&&!D(e,t.callee)?.defs.length||t.callee.type===`MemberExpression`&&E(t.callee)===`fetch`&&t.callee.object.type===`Identifier`&&t.callee.object.name===`globalThis`&&!D(e,t.callee.object)?.defs.length}function _(e,t){if(t.type===`MemberExpression`){let n=d(e,t.object);return n?.name===`components`&&/_generated\/api/.test(n.source)?!0:_(e,t.object)}return t.type===`ObjectExpression`&&t.properties.some(t=>t.type===`Property`&&_(e,t.value))}function v(e){return e.type===`MemberExpression`?v(e.object):e}function y(e){return e.type===`Identifier`?[e.name]:e.type===`MemberExpression`?[...y(e.object),E(e)??``]:[]}function b(e){return e.type===`MemberExpression`?E(e)===`table`||b(e.object):e.type===`CallExpression`&&b(e.callee)}function x(e){return e.callee.type===`MemberExpression`&&[`insert`,`patch`,`replace`,`delete`].includes(E(e.callee)??``)&&e.callee.object.type===`MemberExpression`&&E(e.callee.object)===`db`}function S(e,t){return e.type===`CallExpression`?e.callee.type===`MemberExpression`&&E(e.callee)===t&&(t!==`query`||E(e.callee.object)===`db`)||S(e.callee,t):e.type===`MemberExpression`&&S(e.object,t)}function C(e,t){return{type:`problem`,docs:{description:e},schema:[],messages:t}}function w(e,t){let n=a(e.cwd,l.parse(e.options[0]??{}).convexDir),r=s(n)?c(n):n,u=i(r,s(t)?c(t):t).split(o).join(`/`).match(/^components\/([^/]+)(?:\/|$)/);return u?a(r,`components`,u[1]):null}function T(e){return e?.type===`Literal`&&`value`in e&&String(e.value)===e.value?String(e.value):e?.type===`TemplateLiteral`&&e.expressions.length===0?e.quasis[0].value.cooked:null}function E(e){return e.type===`MemberExpression`?e.computed?T(e.property):e.property.name:null}function D(e,t){if(t.type!==`Identifier`)return null;let n=e.sourceCode.getScope(t);for(;n;){let e=n.set.get(t.name);if(e)return e;n=n.upper}return null}function O(e){let t
|
|
1
|
+
import{createResolver as e,resolveImport as t}from"./architecture.mjs";import{z as n}from"zod";import{dirname as r,relative as i,resolve as a,sep as o}from"node:path";import{existsSync as s,realpathSync as c}from"node:fs";const l=n.object({convexDir:n.string().min(1).default(`convex`)});function u(e,t=e.filename){let n=a(e.cwd,l.parse(e.options[0]??{}).convexDir),r=s(n)?c(n):n,u=i(r,s(t)?c(t):t).split(o).join(`/`);return u===`..`||u.startsWith(`../`)||u.startsWith(`/`)?null:u}function d(e,t){if(t.type===`CallExpression`)return d(e,t.callee);if(t.type===`MemberExpression`){let n=d(e,t.object),r=E(t);return n&&r&&[`*`,`z`,`default`].includes(n.name)?{source:n.source,name:r}:null}if(t.type!==`Identifier`)return null;for(let n of D(e,t)?.defs??[]){if(n.type!==`ImportBinding`||n.parent?.type!==`ImportDeclaration`||n.parent.importKind===`type`)continue;let e=n.node;if(e.type!==`ImportSpecifier`||e.importKind!==`type`)return{source:n.parent.source.value,name:e.type===`ImportSpecifier`?k(e.imported)??``:e.type===`ImportDefaultSpecifier`?`default`:`*`}}return null}function f(e,t){function n(e,n){let r=T(n);r&&t(e,r)}return{ImportDeclaration(e){n(e,e.source)},ExportNamedDeclaration(e){n(e,e.source)},ExportAllDeclaration(e){n(e,e.source)},ImportExpression(e){n(e,e.source)},TSImportType(e){n(e,e.source)},CallExpression(t){t.callee.type===`Identifier`&&t.callee.name===`require`&&!D(e,t.callee)?.defs.length&&n(t,t.arguments[0])}}}function p(n,i){let o=i.startsWith(`.`)?a(r(n.filename),i):t(e(),n.filename,i);return o!==null&&u(n,o)?.replace(/\.[cm]?[jt]s$/,``)===`functions`}function m(e){return e.type===`TSImportType`||e.type===`ImportDeclaration`&&(e.importKind===`type`||e.specifiers.length>0&&e.specifiers.every(e=>e.type===`ImportSpecifier`&&e.importKind===`type`))||(e.type===`ExportNamedDeclaration`||e.type===`ExportAllDeclaration`)&&e.exportKind===`type`}function h(e){return e.callee.type===`MemberExpression`&&e.callee.object.type===`MemberExpression`&&E(e.callee.object)===`db`}function g(e,t){let n=d(e,t.callee);return n&&/^(?:node:)?(?:https?|net|tls|fs)(?:\/|$)|^(?:undici|axios)(?:\/|$)/.test(n.source)?!0:t.callee.type===`Identifier`&&t.callee.name===`fetch`&&!D(e,t.callee)?.defs.length||t.callee.type===`MemberExpression`&&E(t.callee)===`fetch`&&t.callee.object.type===`Identifier`&&t.callee.object.name===`globalThis`&&!D(e,t.callee.object)?.defs.length}function _(e,t){if(t.type===`MemberExpression`){let n=d(e,t.object);return n?.name===`components`&&/_generated\/api/.test(n.source)?!0:_(e,t.object)}return t.type===`ObjectExpression`&&t.properties.some(t=>t.type===`Property`&&_(e,t.value))}function v(e){return e.type===`MemberExpression`?v(e.object):e}function y(e){return e.type===`Identifier`?[e.name]:e.type===`MemberExpression`?[...y(e.object),E(e)??``]:[]}function b(e){return e.type===`MemberExpression`?E(e)===`table`||b(e.object):e.type===`CallExpression`&&b(e.callee)}function x(e){return e.callee.type===`MemberExpression`&&[`insert`,`patch`,`replace`,`delete`].includes(E(e.callee)??``)&&e.callee.object.type===`MemberExpression`&&E(e.callee.object)===`db`}function S(e,t){return e.type===`CallExpression`?e.callee.type===`MemberExpression`&&E(e.callee)===t&&(t!==`query`||E(e.callee.object)===`db`)||S(e.callee,t):e.type===`MemberExpression`&&S(e.object,t)}function C(e,t){return{type:`problem`,docs:{description:e},schema:[],messages:t}}function w(e,t){let n=a(e.cwd,l.parse(e.options[0]??{}).convexDir),r=s(n)?c(n):n,u=i(r,s(t)?c(t):t).split(o).join(`/`).match(/^components\/([^/]+)(?:\/|$)/);return u?a(r,`components`,u[1]):null}function T(e){return e?.type===`Literal`&&`value`in e&&String(e.value)===e.value?String(e.value):e?.type===`TemplateLiteral`&&e.expressions.length===0?e.quasis[0].value.cooked:null}function E(e){return e.type===`MemberExpression`?e.computed?T(e.property):e.property.name:null}function D(e,t){if(t.type!==`Identifier`)return null;let n=e.sourceCode.getScope(t);for(;n;){let e=n.set.get(t.name);if(e)return e;n=n.upper}return null}function O(e){let t=/* @__PURE__ */ new Set;for(let n of e.body)if(n.type===`ExportNamedDeclaration`&&!n.source)for(let e of n.specifiers)t.add(k(e.local)??``);else n.type===`ExportDefaultDeclaration`&&n.declaration.type===`Identifier`&&t.add(n.declaration.name);return t}function k(e){return e.type===`Identifier`?e.name:T(e)}function A(e){return e.type===`CallExpression`?!0:e.type===`AwaitExpression`?A(e.argument):e.type===`BlockStatement`&&e.body.length>0&&e.body.every(e=>e.type===`ReturnStatement`&&e.argument!==null&&A(e.argument)||e.type===`ExpressionStatement`&&A(e.expression))}export{u as appFile,D as binding,w as componentRoot,l as consumerOptions,_ as containsComponentReference,A as delegatingBody,k as exportName,O as exportedNames,S as hasCall,d as imported,h as isDbAccess,x as isDbWrite,g as isExternalCall,p as isFunctionsImport,b as isTableChain,y as memberPath,C as metadata,E as propertyName,v as rootMember,f as sourceVisitors,T as staticString,m as typeOnlySource};
|
|
2
2
|
//# sourceMappingURL=ast.mjs.map
|