@danielfgray/pg-sourcerer 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/cli.js +3 -4
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.d.ts +1 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +1 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/errors.d.ts +14 -1
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js +2 -0
  10. package/dist/errors.js.map +1 -1
  11. package/dist/generate.d.ts +5 -9
  12. package/dist/generate.d.ts.map +1 -1
  13. package/dist/generate.js +27 -29
  14. package/dist/generate.js.map +1 -1
  15. package/dist/index.d.ts +19 -12
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +25 -13
  18. package/dist/index.js.map +1 -1
  19. package/dist/init.d.ts.map +1 -1
  20. package/dist/init.js +39 -9
  21. package/dist/init.js.map +1 -1
  22. package/dist/ir/extensions/queries.d.ts +264 -0
  23. package/dist/ir/extensions/queries.d.ts.map +1 -0
  24. package/dist/ir/extensions/queries.js +153 -0
  25. package/dist/ir/extensions/queries.js.map +1 -0
  26. package/dist/ir/extensions/schema-builder.d.ts +61 -0
  27. package/dist/ir/extensions/schema-builder.d.ts.map +1 -0
  28. package/dist/ir/extensions/schema-builder.js +5 -0
  29. package/dist/ir/extensions/schema-builder.js.map +1 -0
  30. package/dist/lib/conjure.d.ts +66 -0
  31. package/dist/lib/conjure.d.ts.map +1 -1
  32. package/dist/lib/conjure.js +127 -29
  33. package/dist/lib/conjure.js.map +1 -1
  34. package/dist/lib/hex.d.ts +10 -3
  35. package/dist/lib/hex.d.ts.map +1 -1
  36. package/dist/lib/hex.js +18 -8
  37. package/dist/lib/hex.js.map +1 -1
  38. package/dist/plugins/arktype.d.ts +27 -14
  39. package/dist/plugins/arktype.d.ts.map +1 -1
  40. package/dist/plugins/arktype.js +166 -130
  41. package/dist/plugins/arktype.js.map +1 -1
  42. package/dist/plugins/effect.d.ts +53 -0
  43. package/dist/plugins/effect.d.ts.map +1 -0
  44. package/dist/plugins/effect.js +1074 -0
  45. package/dist/plugins/effect.js.map +1 -0
  46. package/dist/plugins/http-elysia.d.ts +32 -0
  47. package/dist/plugins/http-elysia.d.ts.map +1 -0
  48. package/dist/plugins/http-elysia.js +613 -0
  49. package/dist/plugins/http-elysia.js.map +1 -0
  50. package/dist/plugins/http-express.d.ts +36 -0
  51. package/dist/plugins/http-express.d.ts.map +1 -0
  52. package/dist/plugins/http-express.js +388 -0
  53. package/dist/plugins/http-express.js.map +1 -0
  54. package/dist/plugins/http-hono.d.ts +36 -0
  55. package/dist/plugins/http-hono.d.ts.map +1 -0
  56. package/dist/plugins/http-hono.js +453 -0
  57. package/dist/plugins/http-hono.js.map +1 -0
  58. package/dist/plugins/http-orpc.d.ts +55 -0
  59. package/dist/plugins/http-orpc.d.ts.map +1 -0
  60. package/dist/plugins/http-orpc.js +370 -0
  61. package/dist/plugins/http-orpc.js.map +1 -0
  62. package/dist/plugins/http-trpc.d.ts +59 -0
  63. package/dist/plugins/http-trpc.d.ts.map +1 -0
  64. package/dist/plugins/http-trpc.js +392 -0
  65. package/dist/plugins/http-trpc.js.map +1 -0
  66. package/dist/plugins/kysely/queries.d.ts +92 -0
  67. package/dist/plugins/kysely/queries.d.ts.map +1 -0
  68. package/dist/plugins/kysely/queries.js +1169 -0
  69. package/dist/plugins/kysely/queries.js.map +1 -0
  70. package/dist/plugins/kysely/shared.d.ts +59 -0
  71. package/dist/plugins/kysely/shared.d.ts.map +1 -0
  72. package/dist/plugins/kysely/shared.js +247 -0
  73. package/dist/plugins/kysely/shared.js.map +1 -0
  74. package/dist/plugins/kysely/types.d.ts +22 -0
  75. package/dist/plugins/kysely/types.d.ts.map +1 -0
  76. package/dist/plugins/kysely/types.js +428 -0
  77. package/dist/plugins/kysely/types.js.map +1 -0
  78. package/dist/plugins/kysely.d.ts +72 -0
  79. package/dist/plugins/kysely.d.ts.map +1 -0
  80. package/dist/plugins/kysely.js +906 -0
  81. package/dist/plugins/kysely.js.map +1 -0
  82. package/dist/plugins/sql-queries.d.ts +55 -11
  83. package/dist/plugins/sql-queries.d.ts.map +1 -1
  84. package/dist/plugins/sql-queries.js +467 -218
  85. package/dist/plugins/sql-queries.js.map +1 -1
  86. package/dist/plugins/types.d.ts +20 -14
  87. package/dist/plugins/types.d.ts.map +1 -1
  88. package/dist/plugins/types.js +90 -112
  89. package/dist/plugins/types.js.map +1 -1
  90. package/dist/plugins/valibot.d.ts +45 -0
  91. package/dist/plugins/valibot.d.ts.map +1 -0
  92. package/dist/plugins/valibot.js +422 -0
  93. package/dist/plugins/valibot.js.map +1 -0
  94. package/dist/plugins/zod.d.ts +27 -14
  95. package/dist/plugins/zod.d.ts.map +1 -1
  96. package/dist/plugins/zod.js +231 -166
  97. package/dist/plugins/zod.js.map +1 -1
  98. package/dist/services/artifact-store.d.ts +11 -1
  99. package/dist/services/artifact-store.d.ts.map +1 -1
  100. package/dist/services/artifact-store.js +9 -0
  101. package/dist/services/artifact-store.js.map +1 -1
  102. package/dist/services/core-providers.d.ts +15 -0
  103. package/dist/services/core-providers.d.ts.map +1 -0
  104. package/dist/services/core-providers.js +23 -0
  105. package/dist/services/core-providers.js.map +1 -0
  106. package/dist/services/emissions.d.ts +14 -0
  107. package/dist/services/emissions.d.ts.map +1 -1
  108. package/dist/services/emissions.js +86 -47
  109. package/dist/services/emissions.js.map +1 -1
  110. package/dist/services/execution.d.ts +35 -0
  111. package/dist/services/execution.d.ts.map +1 -0
  112. package/dist/services/execution.js +86 -0
  113. package/dist/services/execution.js.map +1 -0
  114. package/dist/services/file-builder.d.ts +4 -0
  115. package/dist/services/file-builder.d.ts.map +1 -1
  116. package/dist/services/file-builder.js.map +1 -1
  117. package/dist/services/inflection.d.ts +2 -2
  118. package/dist/services/inflection.d.ts.map +1 -1
  119. package/dist/services/inflection.js +4 -4
  120. package/dist/services/inflection.js.map +1 -1
  121. package/dist/services/ir-builder.d.ts.map +1 -1
  122. package/dist/services/ir-builder.js +10 -3
  123. package/dist/services/ir-builder.js.map +1 -1
  124. package/dist/services/pg-types.d.ts +31 -0
  125. package/dist/services/pg-types.d.ts.map +1 -1
  126. package/dist/services/pg-types.js +24 -0
  127. package/dist/services/pg-types.js.map +1 -1
  128. package/dist/services/plugin-runner.d.ts +27 -37
  129. package/dist/services/plugin-runner.d.ts.map +1 -1
  130. package/dist/services/plugin-runner.js +73 -171
  131. package/dist/services/plugin-runner.js.map +1 -1
  132. package/dist/services/plugin.d.ts +349 -217
  133. package/dist/services/plugin.d.ts.map +1 -1
  134. package/dist/services/plugin.js +182 -130
  135. package/dist/services/plugin.js.map +1 -1
  136. package/dist/services/resolution.d.ts +38 -0
  137. package/dist/services/resolution.d.ts.map +1 -0
  138. package/dist/services/resolution.js +242 -0
  139. package/dist/services/resolution.js.map +1 -0
  140. package/dist/services/service-registry.d.ts +74 -0
  141. package/dist/services/service-registry.d.ts.map +1 -0
  142. package/dist/services/service-registry.js +61 -0
  143. package/dist/services/service-registry.js.map +1 -0
  144. package/dist/services/symbols.d.ts +59 -0
  145. package/dist/services/symbols.d.ts.map +1 -1
  146. package/dist/services/symbols.js +16 -0
  147. package/dist/services/symbols.js.map +1 -1
  148. package/dist/testing.d.ts +4 -25
  149. package/dist/testing.d.ts.map +1 -1
  150. package/dist/testing.js +2 -23
  151. package/dist/testing.js.map +1 -1
  152. package/package.json +1 -1
  153. package/dist/plugins/effect-model.d.ts +0 -17
  154. package/dist/plugins/effect-model.d.ts.map +0 -1
  155. package/dist/plugins/effect-model.js +0 -409
  156. package/dist/plugins/effect-model.js.map +0 -1
  157. package/dist/plugins/kysely-queries.d.ts +0 -66
  158. package/dist/plugins/kysely-queries.d.ts.map +0 -1
  159. package/dist/plugins/kysely-queries.js +0 -951
  160. package/dist/plugins/kysely-queries.js.map +0 -1
  161. package/dist/plugins/kysely-types.d.ts +0 -35
  162. package/dist/plugins/kysely-types.d.ts.map +0 -1
  163. package/dist/plugins/kysely-types.js +0 -601
  164. package/dist/plugins/kysely-types.js.map +0 -1
@@ -1,289 +1,421 @@
1
1
  /**
2
- * Plugin Types
2
+ * Plugin System
3
3
  *
4
- * Defines the Effect-native plugin interface where plugins are Effects
5
- * that yield the services they need from context.
4
+ * A generic request/plugin coordination system. Core routes requests to plugins
5
+ * without understanding what resources represent (schemas, queries, routes, etc.).
6
+ *
7
+ * Key concepts:
8
+ * - Plugin: Handles requests for a resource kind
9
+ * - Request: A need for a resource with specific params
10
+ * - DeferredResource: A placeholder resolved after plugin execution
11
+ *
12
+ * Execution phases:
13
+ * 1. Registration - Plugins registered, singletons identified
14
+ * 2. Collection - Requests collected via ctx.request()
15
+ * 3. Resolution - Match requests to plugins, build DAG
16
+ * 4. Execution - Run plugins in topological order
17
+ * 5. Finalization - Emit files, resolve imports
6
18
  */
7
- import { Effect, Schema as S } from "effect";
8
- import type { namedTypes as n } from "ast-types";
9
- import type { Artifact, CapabilityKey, SemanticIR, Entity } from "../ir/semantic-ir.js";
10
- import { PluginExecutionFailed } from "../errors.js";
11
- import type { CoreInflection, InflectionConfig } from "./inflection.js";
19
+ import { Context, Layer, Schema as S } from "effect";
20
+ import type { FileBuilder } from "./file-builder.js";
12
21
  import type { SymbolRegistry } from "./symbols.js";
22
+ import type { SemanticIR } from "../ir/semantic-ir.js";
13
23
  import type { TypeHintRegistry } from "./type-hints.js";
14
- import type { FileBuilder } from "./file-builder.js";
15
- import { IR } from "./ir.js";
16
- import { ArtifactStore } from "./artifact-store.js";
17
- import { PluginMeta } from "./plugin-meta.js";
18
- import { Inflection } from "./inflection.js";
19
- import { Emissions } from "./emissions.js";
20
- import { Symbols } from "./symbols.js";
21
- import { TypeHints } from "./type-hints.js";
24
+ import type { CoreInflection } from "./inflection.js";
22
25
  /**
23
- * Context provided to fileName function for output file path generation.
26
+ * A request for a resource of a specific kind with arbitrary params.
24
27
  *
25
- * This gives plugins full programmatic control over file naming,
26
- * with access to entity info and inflection utilities.
28
+ * Core does not interpret the params - they are opaque data passed to providers.
27
29
  */
28
- export interface FileNameContext {
29
- /** Already-inflected entity name */
30
- readonly entityName: string;
31
- /** Raw PostgreSQL object name (table, view, or type name) */
32
- readonly pgName: string;
33
- /** Schema name */
34
- readonly schema: string;
35
- /** Inflection utilities (singularize, pluralize, etc.) */
36
- readonly inflection: CoreInflection;
37
- /** Full entity from IR for advanced use cases */
38
- readonly entity: Entity;
30
+ export interface ResourceRequest {
31
+ /** The resource kind (e.g., "validation-schema", "query-functions") */
32
+ readonly kind: string;
33
+ /** Opaque params interpreted by the provider */
34
+ readonly params: unknown;
35
+ }
36
+ /**
37
+ * A service handler function that processes requests for a specific kind.
38
+ *
39
+ * Registered by plugins via ctx.registerHandler() and invoked by ctx.request().
40
+ * This enables on-demand generation where a later plugin can request resources
41
+ * from an earlier plugin's handler.
42
+ *
43
+ * @typeParam TParams - The request params shape
44
+ * @typeParam TResult - The result shape
45
+ */
46
+ export type ServiceHandler<TParams = unknown, TResult = unknown> = (params: TParams, ctx: PluginContext) => TResult;
47
+ /**
48
+ * A deferred resource reference.
49
+ *
50
+ * Created when a provider calls ctx.request(). The result is populated
51
+ * after the resolution and execution phases complete.
52
+ */
53
+ export interface DeferredResource<T = unknown> {
54
+ /** The resource kind this request is for */
55
+ readonly kind: string;
56
+ /** The params used for this request */
57
+ readonly params: unknown;
58
+ /**
59
+ * The resolved result. Accessing before resolution throws.
60
+ * After resolution, contains the provider's return value.
61
+ */
62
+ readonly result: T;
39
63
  }
40
64
  /**
41
- * Plugin-specific inflection for output file and symbol naming
65
+ * Context provided to plugins during the provide() call.
66
+ *
67
+ * Allows plugins to:
68
+ * - Access the semantic IR
69
+ * - Access type hints and inflection
70
+ * - Register service handlers for on-demand requests
71
+ * - Make requests to other plugins' handlers
72
+ * - Emit files
73
+ * - Register symbols
42
74
  */
43
- export interface PluginInflection {
75
+ export interface PluginContext {
44
76
  /**
45
- * Generate output file path for an entity.
77
+ * The semantic IR containing all entities, enums, relations, etc.
78
+ */
79
+ readonly ir: SemanticIR;
80
+ /**
81
+ * Type hint registry for user-configured type overrides.
82
+ */
83
+ readonly typeHints: TypeHintRegistry;
84
+ /**
85
+ * Inflection service for naming transformations.
86
+ */
87
+ readonly inflection: CoreInflection;
88
+ /**
89
+ * Register a service handler for a resource kind.
46
90
  *
47
- * @param ctx - Context with entity info and inflection utilities
48
- * @returns File path relative to outputDir (include extension)
91
+ * Other plugins can then call ctx.request(kind, params) to invoke this handler.
92
+ * This enables on-demand generation patterns where consumers drive what gets generated.
49
93
  *
50
94
  * @example
51
95
  * ```typescript
52
- * // Default: entity name as file
53
- * fileName: (ctx) => `${ctx.entityName}.ts`
96
+ * // In zod plugin:
97
+ * ctx.registerHandler("schemas", (params, ctx) => {
98
+ * if (params.variant === "params") {
99
+ * return generateParamSchema(params.entity, params.method)
100
+ * }
101
+ * return generateEntitySchema(params.entity, params.shape)
102
+ * })
54
103
  *
55
- * // Lowercase files
56
- * fileName: (ctx) => `${ctx.entityName.toLowerCase()}.ts`
104
+ * // In http-elysia plugin:
105
+ * const schema = ctx.request("schemas", { entity: "User", method: "findById", variant: "params" })
106
+ * ```
57
107
  *
58
- * // Singular lowercase
59
- * fileName: (ctx) => `${ctx.inflection.singularize(ctx.entityName).toLowerCase()}.ts`
108
+ * @param kind - Resource kind this handler provides
109
+ * @param handler - Function to handle requests
110
+ */
111
+ readonly registerHandler: <TParams = unknown, TResult = unknown>(kind: string, handler: ServiceHandler<TParams, TResult>) => void;
112
+ /**
113
+ * Request a resource from a registered handler.
60
114
  *
61
- * // Schema-scoped
62
- * fileName: (ctx) => `${ctx.schema}/${ctx.entityName}.ts`
115
+ * Invokes the handler registered for the given kind with the provided params.
116
+ * If no handler is registered, falls back to the result cache (for static dependencies).
63
117
  *
64
- * // Single file for all entities
65
- * fileName: () => `all-models.ts`
66
- * ```
118
+ * @param kind - Resource kind to request
119
+ * @param params - Opaque params for the handler
120
+ * @returns The result from the handler
121
+ * @throws If no handler is registered and no cached result exists
122
+ */
123
+ readonly request: <T = unknown>(kind: string, params: unknown) => T;
124
+ /**
125
+ * Create a FileBuilder for structured file emission.
126
+ *
127
+ * @param path - Output file path relative to outputDir
128
+ */
129
+ readonly file: (path: string) => FileBuilder;
130
+ /**
131
+ * Symbol registry for cross-file imports.
132
+ * Also used for method symbol registration (plugin-to-plugin coordination).
67
133
  */
68
- readonly outputFile: (ctx: FileNameContext) => string;
69
- readonly symbolName: (entityName: string, artifactKind: string) => string;
134
+ readonly symbols: SymbolRegistry;
70
135
  }
71
136
  /**
72
- * Union of all service tags available to plugins.
73
- *
74
- * Plugins can yield any of these from Effect context:
75
- * ```typescript
76
- * const ir = yield* IR
77
- * const inflection = yield* Inflection
78
- * ```
79
- */
80
- export type PluginServices = IR | Inflection | Emissions | Symbols | TypeHints | ArtifactStore | PluginMeta;
81
- /**
82
- * Effect-native Plugin interface
83
- *
84
- * Plugins are Effects that yield the services they need from context.
85
- * The PluginRunner provides all services via layers.
137
+ * A plugin handles requests for a specific resource kind.
86
138
  *
87
- * @example
88
- * ```typescript
89
- * const myPlugin: Plugin<MyConfig> = {
90
- * name: "my-plugin",
91
- * provides: ["types:row"],
92
- * configSchema: MyConfigSchema,
93
- * inflection: { ... },
139
+ * Core calls canProvide() to match requests to plugins, then calls
140
+ * provide() to generate the resource.
94
141
  *
95
- * run: (config) => Effect.gen(function* () {
96
- * const ir = yield* IR
97
- * const emissions = yield* Emissions
98
- * const meta = yield* PluginMeta
99
- *
100
- * for (const entity of ir.entities.values()) {
101
- * emissions.emit(`types/${entity.name}.ts`, generateType(entity), meta.name)
102
- * }
103
- * })
104
- * }
105
- * ```
142
+ * @typeParam TParams - The expected params shape (opaque to core)
143
+ * @typeParam TResult - The result shape (opaque to core)
106
144
  */
107
- export interface Plugin<TConfig = unknown, TEncoded = TConfig> {
108
- /** Unique plugin name */
145
+ export interface Plugin<TParams = unknown, TResult = unknown> {
146
+ /**
147
+ * Unique plugin name for identification and error messages.
148
+ */
109
149
  readonly name: string;
110
- /** Capabilities this plugin requires (must be provided by earlier plugins) */
111
- readonly requires?: readonly CapabilityKey[];
112
- /** Capabilities this plugin provides */
113
- readonly provides: readonly CapabilityKey[];
114
- /** Configuration schema (Effect Schema) - Schema<TConfig, Encoded> with TConfig as decoded type */
115
- readonly configSchema: S.Schema<TConfig, TEncoded, never>;
116
- /** Plugin-specific inflection for file and symbol naming */
117
- readonly inflection: PluginInflection;
118
150
  /**
119
- * Plugin's default inflection transforms.
151
+ * The resource kind this plugin handles.
152
+ * Multiple plugins can handle the same kind - first match wins.
153
+ */
154
+ readonly kind: string;
155
+ /**
156
+ * If true, this plugin runs once automatically without explicit request.
157
+ * The result is shared by all dependents.
120
158
  *
121
- * These are applied BEFORE user-configured inflection, allowing composition:
122
- * - Plugin sets baseline (e.g., entityName: inflect.pascalCase → "users" → "Users")
123
- * - User config refines (e.g., entityName: inflect.singularize → "Users" → "User")
159
+ * Typical singletons: introspection, semantic-ir
160
+ */
161
+ readonly singleton?: boolean;
162
+ /**
163
+ * Params to use for singleton execution.
164
+ * Only meaningful when singleton is true.
165
+ */
166
+ readonly singletonParams?: TParams;
167
+ /**
168
+ * Check if this plugin can handle a request with the given params.
124
169
  *
125
- * @example
126
- * ```typescript
127
- * import { inflect } from "pg-sourcerer"
170
+ * Called during resolution to match requests to plugins.
171
+ * First plugin that returns true wins.
128
172
  *
129
- * inflectionDefaults: {
130
- * entityName: inflect.pascalCase, // Plugin wants PascalCase class names
131
- * // fieldName not set = plugin preserves field names as-is
132
- * }
133
- * ```
173
+ * @param params - The request params (opaque to core)
174
+ * @returns true if this plugin can handle the request
134
175
  */
135
- readonly inflectionDefaults?: InflectionConfig;
176
+ readonly canProvide: (params: TParams) => boolean;
136
177
  /**
137
- * Plugin execution - returns Effect that yields services from context.
178
+ * Declare what resources this plugin needs before it can run.
138
179
  *
139
- * Accepts the encoded/partial config type. The run function decodes through
140
- * the schema, applying defaults to produce the full TConfig.
180
+ * Used to build the dependency DAG. The results are passed to provide().
141
181
  *
142
- * Services available:
143
- * - IR: SemanticIR (read-only)
144
- * - Inflection: CoreInflection (composed: plugin defaults + user config)
145
- * - Emissions: EmissionBuffer
146
- * - Symbols: SymbolRegistry
147
- * - TypeHints: TypeHintRegistry
148
- * - ArtifactStore: plugin-to-plugin data
149
- * - PluginMeta: current plugin name
182
+ * @param params - The request params
183
+ * @returns Array of resource requests that must be resolved first
150
184
  */
151
- readonly run: (config: TEncoded) => Effect.Effect<void, PluginExecutionFailed, IR | Inflection | Emissions | Symbols | TypeHints | ArtifactStore | PluginMeta>;
185
+ readonly requires?: (params: TParams) => readonly ResourceRequest[];
186
+ /**
187
+ * Declare optional dependencies that enhance this plugin if available.
188
+ *
189
+ * Unlike `requires`, missing optional dependencies don't cause errors.
190
+ * If a provider exists, the dependency is resolved and ordering is enforced.
191
+ * If no provider exists, the dependency is silently skipped.
192
+ *
193
+ * Useful for plugins that have fallback behavior when an optional dependency
194
+ * isn't available (e.g., http-elysia falling back to TypeBox when no schema
195
+ * plugin is registered).
196
+ *
197
+ * @param params - The request params
198
+ * @returns Array of optional resource requests
199
+ */
200
+ readonly optionalRequires?: (params: TParams) => readonly ResourceRequest[];
201
+ /**
202
+ * Generate the resource.
203
+ *
204
+ * Called during execution phase after all dependencies are resolved.
205
+ *
206
+ * @param params - The request params
207
+ * @param deps - Resolved results from requires() in same order
208
+ * @param ctx - Plugin context for sub-requests and emission
209
+ * @returns The resource result (shape is plugin-defined)
210
+ */
211
+ readonly provide: (params: TParams, deps: readonly unknown[], ctx: PluginContext) => TResult;
152
212
  }
213
+ declare const PluginNotFound_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
214
+ readonly _tag: "PluginNotFound";
215
+ } & Readonly<A>;
153
216
  /**
154
- * A plugin factory function that creates ConfiguredPlugin instances.
155
- *
156
- * The factory also exposes the underlying plugin for inspection:
157
- * - `factory.plugin` - The Plugin object with name, provides, requires, etc.
217
+ * No plugin could handle a request.
218
+ */
219
+ export declare class PluginNotFound extends PluginNotFound_base<{
220
+ readonly message: string;
221
+ readonly kind: string;
222
+ readonly params: unknown;
223
+ readonly requestedBy?: string;
224
+ }> {
225
+ }
226
+ declare const PluginCycle_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
227
+ readonly _tag: "PluginCycle";
228
+ } & Readonly<A>;
229
+ /**
230
+ * A cycle was detected in plugin dependencies.
231
+ */
232
+ export declare class PluginCycle extends PluginCycle_base<{
233
+ readonly message: string;
234
+ readonly cycle: readonly string[];
235
+ }> {
236
+ }
237
+ declare const PluginExecutionFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
238
+ readonly _tag: "PluginExecutionFailed";
239
+ } & Readonly<A>;
240
+ /**
241
+ * A plugin failed during execution.
158
242
  */
159
- export interface PluginFactory<TConfig, TEncoded = TConfig> {
160
- (config?: TEncoded): ConfiguredPlugin;
161
- /** The underlying plugin definition */
162
- readonly plugin: Plugin<TConfig, TEncoded>;
243
+ export declare class PluginExecutionFailed extends PluginExecutionFailed_base<{
244
+ readonly message: string;
245
+ readonly plugin: string;
246
+ readonly kind: string;
247
+ readonly params: unknown;
248
+ readonly cause: unknown;
249
+ }> {
163
250
  }
251
+ declare const ResourceNotResolved_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
252
+ readonly _tag: "ResourceNotResolved";
253
+ } & Readonly<A>;
164
254
  /**
165
- * A plugin with its validated configuration
255
+ * Attempted to access a deferred resource before resolution.
166
256
  */
167
- export interface ConfiguredPlugin {
168
- readonly plugin: Plugin<unknown>;
169
- readonly config: unknown;
257
+ export declare class ResourceNotResolved extends ResourceNotResolved_base<{
258
+ readonly message: string;
259
+ readonly kind: string;
260
+ readonly params: unknown;
261
+ }> {
170
262
  }
171
263
  /**
172
- * Logger interface for simple plugins
264
+ * Union of all plugin-related errors.
173
265
  */
174
- export interface SimplePluginLogger {
175
- readonly debug: (message: string) => void;
176
- readonly info: (message: string) => void;
177
- readonly warn: (message: string) => void;
266
+ export type PluginError = PluginNotFound | PluginCycle | PluginExecutionFailed | ResourceNotResolved;
267
+ /**
268
+ * A pending request tracked by the registry.
269
+ * @internal
270
+ */
271
+ export interface PendingRequest {
272
+ readonly kind: string;
273
+ readonly params: unknown;
274
+ readonly requestedBy: string;
275
+ readonly deferred: MutableDeferredResource;
178
276
  }
179
277
  /**
180
- * Context object provided to simple plugins.
278
+ * A mutable deferred resource used during resolution.
279
+ * @internal
280
+ */
281
+ export interface MutableDeferredResource<T = unknown> {
282
+ readonly kind: string;
283
+ readonly params: unknown;
284
+ resolved: boolean;
285
+ value: T | undefined;
286
+ }
287
+ /**
288
+ * Create a mutable deferred resource.
289
+ * @internal
290
+ */
291
+ export declare const createDeferredResource: <T = unknown>(kind: string, params: unknown) => MutableDeferredResource<T>;
292
+ /**
293
+ * Create a read-only deferred resource view.
294
+ * Throws if accessed before resolution.
295
+ * @internal
296
+ */
297
+ export declare const asDeferredResource: <T>(mutable: MutableDeferredResource<T>) => DeferredResource<T>;
298
+ /**
299
+ * Registry for service handlers.
181
300
  *
182
- * This is a convenience wrapper around the Effect services,
183
- * providing a plain object API for plugins that don't need
184
- * full Effect capabilities.
301
+ * Plugins register handlers during their provide() call.
302
+ * Other plugins can then invoke these handlers via ctx.request().
185
303
  */
186
- export interface SimplePluginContext {
187
- /** Read-only access to the IR */
188
- readonly ir: SemanticIR;
189
- /** Core inflection service */
190
- readonly inflection: CoreInflection;
191
- /** Symbol registry for cross-file imports */
192
- readonly symbols: SymbolRegistry;
193
- /** Type hints registry */
194
- readonly typeHints: TypeHintRegistry;
195
- /** Emit string content to a file (buffered) */
196
- readonly emit: (path: string, content: string) => void;
304
+ export interface ServiceRegistry {
197
305
  /**
198
- * Emit an AST program to a file (buffered).
199
- * The plugin runner handles serialization after all plugins run.
306
+ * Register a handler for a resource kind.
307
+ * Multiple handlers can be registered for the same kind - they're tried in order.
200
308
  *
201
- * @param path - Output file path
202
- * @param ast - The AST program node to emit
203
- * @param header - Optional header to prepend (e.g., imports that can't be in AST)
309
+ * @param kind - Resource kind this handler provides
310
+ * @param handler - Function to handle requests
311
+ * @param pluginName - Name of the plugin registering (for error messages)
204
312
  */
205
- readonly emitAst: (path: string, ast: n.Program, header?: string) => void;
206
- /** Append to an already-emitted file */
207
- readonly appendEmit: (path: string, content: string) => void;
208
- /** Get an artifact from a previous plugin */
209
- readonly getArtifact: (capability: CapabilityKey) => Artifact | undefined;
210
- /** Store an artifact for downstream plugins */
211
- readonly setArtifact: (capability: CapabilityKey, data: unknown) => void;
212
- /** Logging */
213
- readonly log: SimplePluginLogger;
214
- /** Current plugin name */
215
- readonly pluginName: string;
216
- /** Plugin's inflection for file and symbol naming */
217
- readonly pluginInflection: PluginInflection;
313
+ readonly register: (kind: string, handler: ServiceHandler, pluginName: string) => void;
218
314
  /**
219
- * Create a FileBuilder for structured file emission.
315
+ * Invoke a handler for the given kind and params.
220
316
  *
221
- * Use this for AST-based code generation with automatic symbol registration:
222
- *
223
- * @example
224
- * ```typescript
225
- * ctx.file("types/User.ts")
226
- * .header("// Auto-generated")
227
- * .import({ kind: "package", names: ["z"], from: "zod" })
228
- * .ast(symbolProgram(...))
229
- * .emit()
230
- * ```
317
+ * @param kind - Resource kind to request
318
+ * @param params - Opaque params for the handler
319
+ * @param ctx - Plugin context to pass to handler
320
+ * @returns The handler result, or undefined if no handler matched
231
321
  */
232
- readonly file: (path: string) => FileBuilder;
322
+ readonly invoke: <T = unknown>(kind: string, params: unknown, ctx: PluginContext) => T | undefined;
323
+ /**
324
+ * Check if any handler is registered for a kind.
325
+ */
326
+ readonly hasHandler: (kind: string) => boolean;
233
327
  }
234
328
  /**
235
- * Definition for a simple plugin (no Effect knowledge required)
329
+ * Create a service registry for handler registration and invocation.
236
330
  */
237
- export interface SimplePluginDef<TConfig = unknown, TEncoded = TConfig> {
238
- /** Unique plugin name */
239
- readonly name: string;
240
- /** Capabilities this plugin requires */
241
- readonly requires?: readonly CapabilityKey[];
242
- /** Capabilities this plugin provides */
243
- readonly provides: readonly CapabilityKey[];
244
- /** Configuration schema - Type is the decoded config, Encoded can differ (e.g., with defaults) */
245
- readonly configSchema: S.Schema<TConfig, TEncoded, never>;
246
- /** Plugin-specific inflection for file and symbol naming */
247
- readonly inflection: PluginInflection;
331
+ export declare const createServiceRegistry: () => ServiceRegistry;
332
+ declare const Services_base: Context.TagClass<Services, "Services", ServiceRegistry>;
333
+ /**
334
+ * Effect service tag for ServiceRegistry.
335
+ */
336
+ export declare class Services extends Services_base {
337
+ }
338
+ /**
339
+ * Plugin registry service interface.
340
+ *
341
+ * Manages plugin registration and request collection during execution.
342
+ */
343
+ export interface PluginRegistry {
344
+ /**
345
+ * Register a plugin for a resource kind.
346
+ *
347
+ * @param plugin - The plugin to register
348
+ */
349
+ readonly register: (plugin: Plugin) => void;
248
350
  /**
249
- * Plugin's default inflection transforms.
351
+ * Request a resource. Returns a deferred reference.
250
352
  *
251
- * These are applied BEFORE user-configured inflection, allowing composition:
252
- * - Plugin sets baseline (e.g., entityName: inflect.pascalCase → "users" → "Users")
253
- * - User config refines (e.g., entityName: inflect.singularize → "Users" → "User")
353
+ * The deferred is populated after resolution and execution phases.
354
+ *
355
+ * @param kind - Resource kind to request
356
+ * @param params - Opaque params for the plugin
357
+ * @param requestedBy - Name of the requester (for error messages)
358
+ * @returns A deferred resource reference
359
+ */
360
+ readonly request: <T = unknown>(kind: string, params: unknown, requestedBy: string) => DeferredResource<T>;
361
+ /**
362
+ * Get all registered plugins.
363
+ * @internal Used by resolution phase.
254
364
  */
255
- readonly inflectionDefaults?: InflectionConfig;
365
+ readonly getPlugins: () => readonly Plugin[];
256
366
  /**
257
- * Plugin execution function.
258
- * Can be sync or async (return void or Promise<void>).
367
+ * Get all pending requests.
368
+ * @internal Used by resolution phase.
259
369
  */
260
- readonly run: (ctx: SimplePluginContext, config: TConfig) => void | Promise<void>;
370
+ readonly getPendingRequests: () => readonly PendingRequest[];
371
+ /**
372
+ * Get singleton plugins.
373
+ * @internal Used by resolution phase to create implicit requests.
374
+ */
375
+ readonly getSingletons: () => readonly Plugin[];
261
376
  }
377
+ declare const Plugins_base: Context.TagClass<Plugins, "Plugins", PluginRegistry>;
262
378
  /**
263
- * Create a plugin factory from a simple function-based definition.
264
- *
265
- * Returns a curried function that accepts config and returns a ConfiguredPlugin.
379
+ * Effect service tag for PluginRegistry.
380
+ */
381
+ export declare class Plugins extends Plugins_base {
382
+ }
383
+ /**
384
+ * Schema for ResourceRequest (for artifact serialization if needed).
385
+ */
386
+ export declare const ResourceRequestSchema: S.Struct<{
387
+ kind: typeof S.String;
388
+ params: typeof S.Unknown;
389
+ }>;
390
+ /**
391
+ * Define a plugin with type inference.
266
392
  *
267
393
  * @example
268
394
  * ```typescript
269
- * const myPlugin = definePlugin({
270
- * name: "my-plugin",
271
- * provides: ["types:row"],
272
- * configSchema: S.Struct({ outputDir: S.String }),
273
- * inflection: { ... },
274
- *
275
- * run: (ctx, config) => {
276
- * for (const entity of ctx.ir.entities.values()) {
277
- * ctx.emit(`${config.outputDir}/${entity.name}.ts`, generateType(entity))
278
- * }
279
- * }
395
+ * const zodSchemas = definePlugin({
396
+ * name: "zod-schemas",
397
+ * kind: "validation-schema",
398
+ * canProvide: (p) => !p.format || p.format === "zod",
399
+ * requires: () => [{ kind: "semantic-ir", params: {} }],
400
+ * provide: (params, [ir], ctx) => {
401
+ * // Generate schema, return symbol ref
402
+ * },
280
403
  * })
281
- *
282
- * // Usage in config:
283
- * plugins: [
284
- * myPlugin({ outputDir: "types" }),
285
- * ]
286
404
  * ```
287
405
  */
288
- export declare function definePlugin<TConfig, TEncoded = TConfig>(def: SimplePluginDef<TConfig, TEncoded>): PluginFactory<TConfig, TEncoded>;
406
+ export declare function definePlugin<TParams = unknown, TResult = unknown>(plugin: Plugin<TParams, TResult>): Plugin<TParams, TResult>;
407
+ /**
408
+ * Create a plugin registry for collecting plugins and requests.
409
+ *
410
+ * Used during generation to:
411
+ * 1. Collect plugin registrations
412
+ * 2. Collect requests during plugin execution
413
+ * 3. Provide data to resolution phase
414
+ */
415
+ export declare const createPluginRegistry: () => PluginRegistry;
416
+ /**
417
+ * Layer providing a fresh plugin registry.
418
+ */
419
+ export declare const PluginsLive: Layer.Layer<Plugins, never, never>;
420
+ export {};
289
421
  //# sourceMappingURL=plugin.d.ts.map