@confect/cli 9.0.0-next.0 → 9.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @confect/cli
2
2
 
3
+ ## 9.0.0-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - bf13919: Generate a unique import binding per spec leaf in `_generated/spec.ts`, even when sibling `*.spec.ts` files share a basename across directories.
8
+
9
+ Previously, codegen keyed import bindings by file basename (the filename minus `.spec.ts`). When two leaves shared a basename they collapsed to a single binding, last write wins. Every `addGroupAt(...)` site that should have referenced any of the colliding leaves ended up referencing the same survivor, and every impl whose sibling spec was dropped failed `validateImpl` with `Could not resolve group path for the provided GroupSpec.` because the assembled tree no longer contained that spec object's identity.
10
+
11
+ Each binding now carries its own `localName` derived from the leaf's full path segments (e.g. `scripts_operational_seed_mutations`), used both as the imported identifier and at the matching `addGroupAt` site. Top-level leaves with single-segment paths are unchanged (`env`, `notes`, etc.).
12
+ - @confect/core@9.0.0-next.2
13
+ - @confect/server@9.0.0-next.2
14
+
15
+ ## 9.0.0-next.1
16
+
17
+ ### Patch Changes
18
+
19
+ - 7cb20ab: Allow a `confect/{path}.spec.ts` file to declare functions even when a sibling `confect/{path}/` subdirectory contains further specs.
20
+
21
+ Previously, every function on the parent spec silently disappeared from the generated api and refs in this layout: `refs.{path}.{fn}` was not defined, while `refs.{path}.{child}.{fn}` (from the subdirectory specs) worked. The parent's `*.impl.ts` continued to type-check on its own, so the missing functions only showed up when something tried to call them.
22
+
23
+ Both `confect codegen` and `confect dev` now generate the parent's functions and the subdirectory's groups side by side, as `refs.{path}.{fn}` and `refs.{path}.{child}.{fn}`.
24
+
25
+ Codegen also now reports a clear error when the parent spec declares a function or subgroup whose name matches one of the subdirectory's child segments, rather than letting the conflict turn into a runtime refs collision. `confect codegen` exits non-zero on this error; `confect dev` logs it and keeps watching so the next save can recover.
26
+ - @confect/core@9.0.0-next.1
27
+ - @confect/server@9.0.0-next.1
28
+
3
29
  ## 9.0.0-next.0
4
30
 
5
31
  ### Major Changes
@@ -30,8 +30,14 @@ var ImplMissingFunctionsError = class extends Schema.TaggedError()("ImplMissingF
30
30
  missingFunctionNames: Schema.Array(Schema.String)
31
31
  }) {};
32
32
  var SchemaInvalidDefaultExportError = class extends Schema.TaggedError()("SchemaInvalidDefaultExportError", { schemaPath: Schema.String }) {};
33
+ var ParentChildNameCollisionError = class extends Schema.TaggedError()("ParentChildNameCollisionError", {
34
+ parentSpecPath: Schema.String,
35
+ childSpecPath: Schema.String,
36
+ collisionName: Schema.String,
37
+ collisionKind: Schema.Literal("function", "group")
38
+ }) {};
33
39
  var MissingSchemaFileError = class extends Schema.TaggedError()("MissingSchemaFileError", { schemaPath: Schema.String }) {};
34
- const CodegenError = Schema.Union(BuildError, MissingImplFileError, MissingSpecFileError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, ImplMissingSpecImportError, ImplMissingDefaultLayerError, ImplNotFinalizedError, ImplMissingFunctionsError, SchemaInvalidDefaultExportError, MissingSchemaFileError);
40
+ const CodegenError = Schema.Union(BuildError, MissingImplFileError, MissingSpecFileError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, ImplMissingSpecImportError, ImplMissingDefaultLayerError, ImplNotFinalizedError, ImplMissingFunctionsError, SchemaInvalidDefaultExportError, MissingSchemaFileError, ParentChildNameCollisionError);
35
41
  const isCodegenError = (error) => {
36
42
  if (isBuildError(error)) return true;
37
43
  return Schema.is(CodegenError)(error);
@@ -63,6 +69,7 @@ const renderImplMissingFunctionsError = (error) => {
63
69
  };
64
70
  const renderSchemaInvalidDefaultExportError = (error) => singleLine(AnsiDoc.text("Schema "), formatPathDoc(error.schemaPath), AnsiDoc.text(" must default-export a DatabaseSchema; build it with DatabaseSchema.make({ ... })."));
65
71
  const renderMissingSchemaFileError = (error) => singleLine(AnsiDoc.text("Schema "), formatPathDoc(error.schemaPath), AnsiDoc.text(" is required but is missing; create it and default-export a DatabaseSchema (DatabaseSchema.make({ ... }))."));
72
+ const renderParentChildNameCollisionError = (error) => singleLine(AnsiDoc.text("Spec "), formatPathDoc(error.parentSpecPath), AnsiDoc.text(` declares a ${error.collisionKind} \`${error.collisionName}\` whose name collides with the sibling subdirectory spec `), formatPathDoc(error.childSpecPath), AnsiDoc.text(`. Rename one of them so the assembled spec has a unique key at this path.`));
66
73
  /**
67
74
  * Render any {@link CodegenError} into a styled, ready-to-print string.
68
75
  * Single-error variants render to a one-line `✘`-prefixed message;
@@ -71,7 +78,7 @@ const renderMissingSchemaFileError = (error) => singleLine(AnsiDoc.text("Schema
71
78
  */
72
79
  const renderCodegenError = (error) => {
73
80
  if (isBuildError(error)) return renderBuildError(error);
74
- return Match.value(error).pipe(Match.tag("MissingImplFileError", (e) => pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSpecFileError", (e) => pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecMissingDefaultGroupSpecError", (e) => pipe(renderSpecMissingDefaultGroupSpecError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecRuntimeMismatchError", (e) => pipe(renderSpecRuntimeMismatchError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingSpecImportError", (e) => pipe(renderImplMissingSpecImportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingDefaultLayerError", (e) => pipe(renderImplMissingDefaultLayerError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplNotFinalizedError", (e) => pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingFunctionsError", (e) => pipe(renderImplMissingFunctionsError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SchemaInvalidDefaultExportError", (e) => pipe(renderSchemaInvalidDefaultExportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSchemaFileError", (e) => pipe(renderMissingSchemaFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.exhaustive);
81
+ return Match.value(error).pipe(Match.tag("MissingImplFileError", (e) => pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSpecFileError", (e) => pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecMissingDefaultGroupSpecError", (e) => pipe(renderSpecMissingDefaultGroupSpecError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecRuntimeMismatchError", (e) => pipe(renderSpecRuntimeMismatchError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingSpecImportError", (e) => pipe(renderImplMissingSpecImportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingDefaultLayerError", (e) => pipe(renderImplMissingDefaultLayerError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplNotFinalizedError", (e) => pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingFunctionsError", (e) => pipe(renderImplMissingFunctionsError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SchemaInvalidDefaultExportError", (e) => pipe(renderSchemaInvalidDefaultExportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSchemaFileError", (e) => pipe(renderMissingSchemaFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ParentChildNameCollisionError", (e) => pipe(renderParentChildNameCollisionError(e), AnsiDoc.render({ style: "pretty" }))), Match.exhaustive);
75
82
  };
76
83
  const logCodegenError = (error) => Effect.sync(() => console.error(renderCodegenError(error)));
77
84
  /**
@@ -90,5 +97,5 @@ const tapAndLog = (effect) => effect.pipe(Effect.tapError((error) => isCodegenEr
90
97
  const catchAndLog = (effect) => Effect.catchIf(Effect.map(effect, Option.some), isCodegenError, (error) => logCodegenError(error).pipe(Effect.as(Option.none())));
91
98
 
92
99
  //#endregion
93
- export { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, MissingImplFileError, MissingSchemaFileError, MissingSpecFileError, SchemaInvalidDefaultExportError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, catchAndLog, tapAndLog };
100
+ export { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, MissingImplFileError, MissingSchemaFileError, MissingSpecFileError, ParentChildNameCollisionError, SchemaInvalidDefaultExportError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, catchAndLog, tapAndLog };
94
101
  //# sourceMappingURL=CodegenError.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodegenError.mjs","names":[],"sources":["../src/CodegenError.ts"],"sourcesContent":["import { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Effect, Match, Option, pipe, Schema } from \"effect\";\nimport { BuildError, isBuildError, renderBuildError } from \"./BuildError\";\nimport { formatPathDoc } from \"./log\";\n\n// --- Variants ---\n\nexport class MissingImplFileError extends Schema.TaggedError<MissingImplFileError>()(\n \"MissingImplFileError\",\n {\n specPath: Schema.String,\n expectedImplPath: Schema.String,\n },\n) {}\n\nexport class MissingSpecFileError extends Schema.TaggedError<MissingSpecFileError>()(\n \"MissingSpecFileError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class SpecMissingDefaultGroupSpecError extends Schema.TaggedError<SpecMissingDefaultGroupSpecError>()(\n \"SpecMissingDefaultGroupSpecError\",\n {\n specPath: Schema.String,\n },\n) {}\n\nexport class SpecRuntimeMismatchError extends Schema.TaggedError<SpecRuntimeMismatchError>()(\n \"SpecRuntimeMismatchError\",\n {\n specPath: Schema.String,\n expectedRuntime: Schema.Literal(\"Convex\", \"Node\"),\n actualRuntime: Schema.Literal(\"Convex\", \"Node\"),\n },\n) {}\n\nexport class ImplMissingSpecImportError extends Schema.TaggedError<ImplMissingSpecImportError>()(\n \"ImplMissingSpecImportError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingDefaultLayerError extends Schema.TaggedError<ImplMissingDefaultLayerError>()(\n \"ImplMissingDefaultLayerError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplNotFinalizedError extends Schema.TaggedError<ImplNotFinalizedError>()(\n \"ImplNotFinalizedError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingFunctionsError extends Schema.TaggedError<ImplMissingFunctionsError>()(\n \"ImplMissingFunctionsError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingFunctionNames: Schema.Array(Schema.String),\n },\n) {}\n\nexport class SchemaInvalidDefaultExportError extends Schema.TaggedError<SchemaInvalidDefaultExportError>()(\n \"SchemaInvalidDefaultExportError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport class MissingSchemaFileError extends Schema.TaggedError<MissingSchemaFileError>()(\n \"MissingSchemaFileError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport const CodegenError = Schema.Union(\n BuildError,\n MissingImplFileError,\n MissingSpecFileError,\n SpecMissingDefaultGroupSpecError,\n SpecRuntimeMismatchError,\n ImplMissingSpecImportError,\n ImplMissingDefaultLayerError,\n ImplNotFinalizedError,\n ImplMissingFunctionsError,\n SchemaInvalidDefaultExportError,\n MissingSchemaFileError,\n);\nexport type CodegenError = typeof CodegenError.Type;\n\nexport const isCodegenError = (error: unknown): error is CodegenError => {\n if (isBuildError(error)) return true;\n return Schema.is(CodegenError)(error);\n};\n\n// --- Per-variant rendering ---\n\nconst cross = pipe(AnsiDoc.char(\"✘\"), AnsiDoc.annotate(Ansi.red));\n\nconst stemFromSpecPath = (specPath: string): string => {\n const lastSep = Math.max(\n specPath.lastIndexOf(\"/\"),\n specPath.lastIndexOf(\"\\\\\"),\n );\n const basename = lastSep < 0 ? specPath : specPath.slice(lastSep + 1);\n return basename.endsWith(\".spec.ts\")\n ? basename.slice(0, -\".spec.ts\".length)\n : basename;\n};\n\nconst singleLine = (\n ...parts: ReadonlyArray<AnsiDoc.AnsiDoc>\n): AnsiDoc.AnsiDoc => pipe(cross, AnsiDoc.catWithSpace(AnsiDoc.hcat(parts)));\n\nconst renderMissingImplFileError = (\n error: MissingImplFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\" has no sibling impl; create \"),\n formatPathDoc(error.expectedImplPath),\n AnsiDoc.text(\" and default-export a GroupImpl layer from it.\"),\n );\n\nconst renderMissingSpecFileError = (\n error: MissingSpecFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\" has no sibling spec; create \"),\n formatPathDoc(error.expectedSpecPath),\n AnsiDoc.text(\n \" and default-export a GroupSpec from it, or remove the impl.\",\n ),\n );\n\nconst renderSpecMissingDefaultGroupSpecError = (\n error: SpecMissingDefaultGroupSpecError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n \" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode().\",\n ),\n );\n\nconst renderSpecRuntimeMismatchError = (\n error: SpecRuntimeMismatchError,\n): AnsiDoc.AnsiDoc => {\n const constructor =\n error.expectedRuntime === \"Node\"\n ? \"GroupSpec.makeNode()\"\n : \"GroupSpec.make()\";\n const moveHint =\n error.expectedRuntime === \"Node\"\n ? \" or move the file into confect/node/.\"\n : \" or move the file out of confect/node/.\";\n return singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n ` declares a ${error.actualRuntime} GroupSpec but its location requires ${error.expectedRuntime}; use ${constructor}${moveHint}`,\n ),\n );\n};\n\nconst renderImplMissingSpecImportError = (\n error: ImplMissingSpecImportError,\n): AnsiDoc.AnsiDoc => {\n const stem = stemFromSpecPath(error.expectedSpecPath);\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not import its sibling spec; add \\`import ${stem} from \"./${stem}.spec\"\\` and pass it to FunctionImpl.make / GroupImpl.make.`,\n ),\n );\n};\n\nconst renderImplMissingDefaultLayerError = (\n error: ImplMissingDefaultLayerError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(api, groupSpec).pipe(Layer.provide(...))` and `export default` it.\",\n ),\n );\n\nconst renderImplNotFinalizedError = (\n error: ImplNotFinalizedError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(api, group).pipe(Layer.provide(...), GroupImpl.finalize)`).\",\n ),\n );\n\nconst renderImplMissingFunctionsError = (\n error: ImplMissingFunctionsError,\n): AnsiDoc.AnsiDoc => {\n const names = error.missingFunctionNames.join(\", \");\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not implement every function declared by group \\`${error.groupPath}\\`; missing: ${names}. Add a \\`FunctionImpl.make\\` for each missing function and provide it to the group layer.`,\n ),\n );\n};\n\nconst renderSchemaInvalidDefaultExportError = (\n error: SchemaInvalidDefaultExportError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" must default-export a DatabaseSchema; build it with DatabaseSchema.make({ ... }).\",\n ),\n );\n\nconst renderMissingSchemaFileError = (\n error: MissingSchemaFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" is required but is missing; create it and default-export a DatabaseSchema (DatabaseSchema.make({ ... })).\",\n ),\n );\n\n/**\n * Render any {@link CodegenError} into a styled, ready-to-print string.\n * Single-error variants render to a one-line `✘`-prefixed message;\n * `BundleFailedError` (the only multi-error variant) renders to a header\n * plus an esbuild diagnostic block.\n */\nexport const renderCodegenError = (error: CodegenError): string => {\n if (isBuildError(error)) return renderBuildError(error);\n return Match.value(error).pipe(\n Match.tag(\"MissingImplFileError\", (e) =>\n pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"MissingSpecFileError\", (e) =>\n pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"SpecMissingDefaultGroupSpecError\", (e) =>\n pipe(\n renderSpecMissingDefaultGroupSpecError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SpecRuntimeMismatchError\", (e) =>\n pipe(\n renderSpecRuntimeMismatchError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingSpecImportError\", (e) =>\n pipe(\n renderImplMissingSpecImportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingDefaultLayerError\", (e) =>\n pipe(\n renderImplMissingDefaultLayerError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplNotFinalizedError\", (e) =>\n pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"ImplMissingFunctionsError\", (e) =>\n pipe(\n renderImplMissingFunctionsError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SchemaInvalidDefaultExportError\", (e) =>\n pipe(\n renderSchemaInvalidDefaultExportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"MissingSchemaFileError\", (e) =>\n pipe(\n renderMissingSchemaFileError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.exhaustive,\n );\n};\n\nexport const logCodegenError = (error: CodegenError) =>\n Effect.sync(() => console.error(renderCodegenError(error)));\n\n// --- Effect combinators ---\n\n/**\n * Log any {@link CodegenError} thrown by `effect` and propagate the failure\n * unchanged so the caller's error channel is preserved (used by the\n * `codegen` command, which needs the failure to surface as a non-zero exit\n * code).\n */\nexport const tapAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E, R> =>\n effect.pipe(\n Effect.tapError((error) =>\n isCodegenError(error) ? logCodegenError(error) : Effect.void,\n ),\n );\n\n/**\n * Catch any {@link CodegenError} thrown by `effect`, log it, and resolve to\n * `Option.none()` (used by the `dev` command's sync loop, which continues\n * after a failed sync rather than exiting). Success resolves to\n * `Option.some(value)`.\n */\nexport const catchAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R> =>\n Effect.catchIf(Effect.map(effect, Option.some<A>), isCodegenError, (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n ) as Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodegenError.mjs","names":[],"sources":["../src/CodegenError.ts"],"sourcesContent":["import { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Effect, Match, Option, pipe, Schema } from \"effect\";\nimport { BuildError, isBuildError, renderBuildError } from \"./BuildError\";\nimport { formatPathDoc } from \"./log\";\n\n// --- Variants ---\n\nexport class MissingImplFileError extends Schema.TaggedError<MissingImplFileError>()(\n \"MissingImplFileError\",\n {\n specPath: Schema.String,\n expectedImplPath: Schema.String,\n },\n) {}\n\nexport class MissingSpecFileError extends Schema.TaggedError<MissingSpecFileError>()(\n \"MissingSpecFileError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class SpecMissingDefaultGroupSpecError extends Schema.TaggedError<SpecMissingDefaultGroupSpecError>()(\n \"SpecMissingDefaultGroupSpecError\",\n {\n specPath: Schema.String,\n },\n) {}\n\nexport class SpecRuntimeMismatchError extends Schema.TaggedError<SpecRuntimeMismatchError>()(\n \"SpecRuntimeMismatchError\",\n {\n specPath: Schema.String,\n expectedRuntime: Schema.Literal(\"Convex\", \"Node\"),\n actualRuntime: Schema.Literal(\"Convex\", \"Node\"),\n },\n) {}\n\nexport class ImplMissingSpecImportError extends Schema.TaggedError<ImplMissingSpecImportError>()(\n \"ImplMissingSpecImportError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingDefaultLayerError extends Schema.TaggedError<ImplMissingDefaultLayerError>()(\n \"ImplMissingDefaultLayerError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplNotFinalizedError extends Schema.TaggedError<ImplNotFinalizedError>()(\n \"ImplNotFinalizedError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingFunctionsError extends Schema.TaggedError<ImplMissingFunctionsError>()(\n \"ImplMissingFunctionsError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingFunctionNames: Schema.Array(Schema.String),\n },\n) {}\n\nexport class SchemaInvalidDefaultExportError extends Schema.TaggedError<SchemaInvalidDefaultExportError>()(\n \"SchemaInvalidDefaultExportError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport class ParentChildNameCollisionError extends Schema.TaggedError<ParentChildNameCollisionError>()(\n \"ParentChildNameCollisionError\",\n {\n parentSpecPath: Schema.String,\n childSpecPath: Schema.String,\n collisionName: Schema.String,\n collisionKind: Schema.Literal(\"function\", \"group\"),\n },\n) {}\n\nexport class MissingSchemaFileError extends Schema.TaggedError<MissingSchemaFileError>()(\n \"MissingSchemaFileError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport const CodegenError = Schema.Union(\n BuildError,\n MissingImplFileError,\n MissingSpecFileError,\n SpecMissingDefaultGroupSpecError,\n SpecRuntimeMismatchError,\n ImplMissingSpecImportError,\n ImplMissingDefaultLayerError,\n ImplNotFinalizedError,\n ImplMissingFunctionsError,\n SchemaInvalidDefaultExportError,\n MissingSchemaFileError,\n ParentChildNameCollisionError,\n);\nexport type CodegenError = typeof CodegenError.Type;\n\nexport const isCodegenError = (error: unknown): error is CodegenError => {\n if (isBuildError(error)) return true;\n return Schema.is(CodegenError)(error);\n};\n\n// --- Per-variant rendering ---\n\nconst cross = pipe(AnsiDoc.char(\"✘\"), AnsiDoc.annotate(Ansi.red));\n\nconst stemFromSpecPath = (specPath: string): string => {\n const lastSep = Math.max(\n specPath.lastIndexOf(\"/\"),\n specPath.lastIndexOf(\"\\\\\"),\n );\n const basename = lastSep < 0 ? specPath : specPath.slice(lastSep + 1);\n return basename.endsWith(\".spec.ts\")\n ? basename.slice(0, -\".spec.ts\".length)\n : basename;\n};\n\nconst singleLine = (\n ...parts: ReadonlyArray<AnsiDoc.AnsiDoc>\n): AnsiDoc.AnsiDoc => pipe(cross, AnsiDoc.catWithSpace(AnsiDoc.hcat(parts)));\n\nconst renderMissingImplFileError = (\n error: MissingImplFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\" has no sibling impl; create \"),\n formatPathDoc(error.expectedImplPath),\n AnsiDoc.text(\" and default-export a GroupImpl layer from it.\"),\n );\n\nconst renderMissingSpecFileError = (\n error: MissingSpecFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\" has no sibling spec; create \"),\n formatPathDoc(error.expectedSpecPath),\n AnsiDoc.text(\n \" and default-export a GroupSpec from it, or remove the impl.\",\n ),\n );\n\nconst renderSpecMissingDefaultGroupSpecError = (\n error: SpecMissingDefaultGroupSpecError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n \" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode().\",\n ),\n );\n\nconst renderSpecRuntimeMismatchError = (\n error: SpecRuntimeMismatchError,\n): AnsiDoc.AnsiDoc => {\n const constructor =\n error.expectedRuntime === \"Node\"\n ? \"GroupSpec.makeNode()\"\n : \"GroupSpec.make()\";\n const moveHint =\n error.expectedRuntime === \"Node\"\n ? \" or move the file into confect/node/.\"\n : \" or move the file out of confect/node/.\";\n return singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n ` declares a ${error.actualRuntime} GroupSpec but its location requires ${error.expectedRuntime}; use ${constructor}${moveHint}`,\n ),\n );\n};\n\nconst renderImplMissingSpecImportError = (\n error: ImplMissingSpecImportError,\n): AnsiDoc.AnsiDoc => {\n const stem = stemFromSpecPath(error.expectedSpecPath);\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not import its sibling spec; add \\`import ${stem} from \"./${stem}.spec\"\\` and pass it to FunctionImpl.make / GroupImpl.make.`,\n ),\n );\n};\n\nconst renderImplMissingDefaultLayerError = (\n error: ImplMissingDefaultLayerError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(api, groupSpec).pipe(Layer.provide(...))` and `export default` it.\",\n ),\n );\n\nconst renderImplNotFinalizedError = (\n error: ImplNotFinalizedError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(api, group).pipe(Layer.provide(...), GroupImpl.finalize)`).\",\n ),\n );\n\nconst renderImplMissingFunctionsError = (\n error: ImplMissingFunctionsError,\n): AnsiDoc.AnsiDoc => {\n const names = error.missingFunctionNames.join(\", \");\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not implement every function declared by group \\`${error.groupPath}\\`; missing: ${names}. Add a \\`FunctionImpl.make\\` for each missing function and provide it to the group layer.`,\n ),\n );\n};\n\nconst renderSchemaInvalidDefaultExportError = (\n error: SchemaInvalidDefaultExportError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" must default-export a DatabaseSchema; build it with DatabaseSchema.make({ ... }).\",\n ),\n );\n\nconst renderMissingSchemaFileError = (\n error: MissingSchemaFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" is required but is missing; create it and default-export a DatabaseSchema (DatabaseSchema.make({ ... })).\",\n ),\n );\n\nconst renderParentChildNameCollisionError = (\n error: ParentChildNameCollisionError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.parentSpecPath),\n AnsiDoc.text(\n ` declares a ${error.collisionKind} \\`${error.collisionName}\\` whose name collides with the sibling subdirectory spec `,\n ),\n formatPathDoc(error.childSpecPath),\n AnsiDoc.text(\n `. Rename one of them so the assembled spec has a unique key at this path.`,\n ),\n );\n\n/**\n * Render any {@link CodegenError} into a styled, ready-to-print string.\n * Single-error variants render to a one-line `✘`-prefixed message;\n * `BundleFailedError` (the only multi-error variant) renders to a header\n * plus an esbuild diagnostic block.\n */\nexport const renderCodegenError = (error: CodegenError): string => {\n if (isBuildError(error)) return renderBuildError(error);\n return Match.value(error).pipe(\n Match.tag(\"MissingImplFileError\", (e) =>\n pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"MissingSpecFileError\", (e) =>\n pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"SpecMissingDefaultGroupSpecError\", (e) =>\n pipe(\n renderSpecMissingDefaultGroupSpecError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SpecRuntimeMismatchError\", (e) =>\n pipe(\n renderSpecRuntimeMismatchError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingSpecImportError\", (e) =>\n pipe(\n renderImplMissingSpecImportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingDefaultLayerError\", (e) =>\n pipe(\n renderImplMissingDefaultLayerError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplNotFinalizedError\", (e) =>\n pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"ImplMissingFunctionsError\", (e) =>\n pipe(\n renderImplMissingFunctionsError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SchemaInvalidDefaultExportError\", (e) =>\n pipe(\n renderSchemaInvalidDefaultExportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"MissingSchemaFileError\", (e) =>\n pipe(\n renderMissingSchemaFileError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ParentChildNameCollisionError\", (e) =>\n pipe(\n renderParentChildNameCollisionError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.exhaustive,\n );\n};\n\nexport const logCodegenError = (error: CodegenError) =>\n Effect.sync(() => console.error(renderCodegenError(error)));\n\n// --- Effect combinators ---\n\n/**\n * Log any {@link CodegenError} thrown by `effect` and propagate the failure\n * unchanged so the caller's error channel is preserved (used by the\n * `codegen` command, which needs the failure to surface as a non-zero exit\n * code).\n */\nexport const tapAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E, R> =>\n effect.pipe(\n Effect.tapError((error) =>\n isCodegenError(error) ? logCodegenError(error) : Effect.void,\n ),\n );\n\n/**\n * Catch any {@link CodegenError} thrown by `effect`, log it, and resolve to\n * `Option.none()` (used by the `dev` command's sync loop, which continues\n * after a failed sync rather than exiting). Success resolves to\n * `Option.some(value)`.\n */\nexport const catchAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R> =>\n Effect.catchIf(Effect.map(effect, Option.some<A>), isCodegenError, (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n ) as Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R>;\n"],"mappings":"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"}
@@ -98,7 +98,9 @@ const absoluteModulePath = (relativePath) => Effect.gen(function* () {
98
98
  /**
99
99
  * Validate that the leaf's spec file default-exports a `GroupSpec` whose
100
100
  * runtime matches the leaf's location (`Convex` for files outside
101
- * `confect/node/`, `Node` for files inside it).
101
+ * `confect/node/`, `Node` for files inside it). Returns the validated
102
+ * `GroupSpec` so callers can avoid re-bundling for later inspection (e.g.
103
+ * parent/child name-collision checks at codegen time).
102
104
  */
103
105
  const validateSpec = (leaf) => Effect.gen(function* () {
104
106
  const absolutePath = yield* absoluteModulePath(leaf.relativePath);
@@ -110,6 +112,7 @@ const validateSpec = (leaf) => Effect.gen(function* () {
110
112
  expectedRuntime: leaf.runtime,
111
113
  actualRuntime: groupSpec.runtime
112
114
  });
115
+ return groupSpec;
113
116
  });
114
117
  /**
115
118
  * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The
@@ -1 +1 @@
1
- {"version":3,"file":"LeafModule.mjs","names":["Bundler.bundle","Bundler.directlyImports"],"sources":["../src/LeafModule.ts"],"sourcesContent":["import { GroupSpec, Registry } from \"@confect/core\";\nimport * as GroupImpl from \"@confect/server/GroupImpl\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport type { Context } from \"effect\";\nimport { Array, Effect, Layer, Option, Ref, String } from \"effect\";\nimport { fromBundlerError } from \"./BuildError\";\nimport * as Bundler from \"./Bundler\";\nimport {\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n SpecMissingDefaultGroupSpecError,\n SpecRuntimeMismatchError,\n} from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { removePathExtension } from \"./utils\";\n\nexport interface LeafModule {\n readonly relativePath: string;\n readonly pathSegments: readonly [string, ...string[]];\n readonly groupPathDot: string;\n readonly registryGroupPathDot: string;\n readonly exportName: string;\n readonly runtime: \"Convex\" | \"Node\";\n readonly specImportPath: string;\n}\n\nexport const SPEC_SUFFIX = \".spec.ts\";\nexport const IMPL_SUFFIX = \".impl.ts\";\n\nconst swapModuleSuffix = (\n relativePath: string,\n fromSuffix: string,\n toSuffix: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n if (ext !== \".ts\" || !name.endsWith(fromSuffix.slice(0, -\".ts\".length))) {\n return relativePath;\n }\n\n const stem = name.slice(0, -fromSuffix.slice(0, -\".ts\".length).length);\n const nextName = `${stem}${toSuffix.slice(0, -\".ts\".length)}`;\n return dir.length > 0\n ? path.join(dir, `${nextName}${ext}`)\n : `${nextName}${ext}`;\n });\n\nexport const isLeafSpecPath = (relativePath: string) =>\n relativePath.endsWith(SPEC_SUFFIX);\n\nexport const isLeafImplPath = (relativePath: string) =>\n relativePath.endsWith(IMPL_SUFFIX);\n\nexport const exportNameFromModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { name, ext } = path.parse(relativePath);\n if (ext !== \".ts\") {\n return name;\n }\n return name.endsWith(\".spec\") ? name.slice(0, -\".spec\".length) : name;\n });\n\nexport const groupPathFromRelativeModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n const stem =\n ext === \".ts\" && name.endsWith(\".spec\")\n ? name.slice(0, -\".spec\".length)\n : name;\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n const pathSegments = Array.append(dirSegments, stem) as [\n string,\n ...string[],\n ];\n return {\n pathSegments,\n groupPathDot: Array.join(pathSegments, \".\"),\n };\n });\n\nexport const specImportPathFromGenerated = (specRelativePath: string) =>\n Effect.gen(function* () {\n const withoutExt = yield* removePathExtension(specRelativePath);\n return `../${withoutExt}`;\n });\n\nexport const specPathForImpl = (implRelativePath: string) =>\n swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);\n\nexport const implPathForSpec = (specRelativePath: string) =>\n swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);\n\nexport const isNodeLeafModule = (relativePath: string) =>\n relativePath.startsWith(\"node/\") || relativePath.startsWith(\"node\\\\\");\n\nexport const toNodeRegistryLeaf = (leaf: LeafModule): LeafModule => ({\n ...leaf,\n pathSegments: [leaf.exportName],\n groupPathDot: leaf.exportName,\n});\n\nexport const registeredFunctionsRelativePath = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n return (\n path.join(\n \"registeredFunctions\",\n ...leaf.pathSegments.slice(leaf.runtime === \"Node\" ? 1 : 0),\n ) + \".ts\"\n );\n });\n\nexport const discoverLeafSpecFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = new Set([\"_generated\", \"tables\"]);\n const excludedFiles = new Set([\"nodeSpec.ts\", \"spec.ts\"]);\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafSpecPath(relativePath)) {\n return false;\n }\n\n if (excludedFiles.has(relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) => excludedDirs.has(segment));\n });\n});\n\nexport const discoverLeafImplFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = new Set([\"_generated\", \"tables\"]);\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafImplPath(relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) => excludedDirs.has(segment));\n });\n});\n\nexport const toLeafModule = (specRelativePath: string) =>\n Effect.gen(function* () {\n const exportName = yield* exportNameFromModulePath(specRelativePath);\n const { pathSegments, groupPathDot } =\n yield* groupPathFromRelativeModulePath(specRelativePath);\n const specImportPath = yield* specImportPathFromGenerated(specRelativePath);\n const runtime = isNodeLeafModule(specRelativePath) ? \"Node\" : \"Convex\";\n\n return {\n relativePath: specRelativePath,\n pathSegments,\n groupPathDot,\n exportName,\n runtime,\n registryGroupPathDot: runtime === \"Node\" ? exportName : groupPathDot,\n specImportPath,\n } satisfies LeafModule;\n });\n\nconst absoluteModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const confectDirectory = yield* ConfectDirectory.get;\n const path = yield* Path.Path;\n return path.resolve(confectDirectory, relativePath);\n });\n\n/**\n * Validate that the leaf's spec file default-exports a `GroupSpec` whose\n * runtime matches the leaf's location (`Convex` for files outside\n * `confect/node/`, `Node` for files inside it).\n */\nexport const validateSpec = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const absolutePath = yield* absoluteModulePath(leaf.relativePath);\n const { module } = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n\n const groupSpec = module.default;\n\n if (!GroupSpec.isGroupSpec(groupSpec)) {\n return yield* new SpecMissingDefaultGroupSpecError({\n specPath: leaf.relativePath,\n });\n }\n\n if (groupSpec.runtime !== leaf.runtime) {\n return yield* new SpecRuntimeMismatchError({\n specPath: leaf.relativePath,\n expectedRuntime: leaf.runtime,\n actualRuntime: groupSpec.runtime,\n });\n }\n });\n\n/**\n * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The\n * lookup is value-shaped (via `GroupImpl.isFinalizedGroupImpl`) so we don't\n * need to know the group's path up front to construct a typed tag for it.\n */\nconst findFinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<GroupImpl.AnyFinalized> =>\n Array.findFirst(context.unsafeMap.values(), GroupImpl.isFinalizedGroupImpl);\n\n/**\n * Build the impl layer with a fresh `Registry` so each validation is\n * isolated from prior validations' `FunctionImpl.make` writes. The CLI no\n * longer reads the registry directly — `GroupImpl.finalize` snapshots the\n * registered function names onto the produced `Finalized` `GroupImpl`\n * service value — but a fresh `Ref` is still required because the default\n * `Context.Reference` is cached globally and would otherwise accumulate\n * items across impls.\n */\nconst buildImplLayer = (implLayer: Layer.Layer<unknown>) =>\n Effect.gen(function* () {\n const registry = Ref.unsafeMake<Registry.RegistryItems>({});\n return yield* Layer.build(\n implLayer as Layer.Layer<unknown, never, never>,\n ).pipe(Effect.provideService(Registry.Registry, registry));\n }).pipe(Effect.scoped);\n\n/**\n * Validate that the leaf's sibling impl file imports the spec, default-exports\n * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every\n * function declared by the spec.\n */\nexport const validateImpl = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const implAbsolutePath = yield* absoluteModulePath(implRelativePath);\n const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);\n\n const bundled = yield* Bundler.bundle(implAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(implRelativePath, error)),\n );\n\n if (\n !(yield* Bundler.directlyImports(\n bundled,\n implAbsolutePath,\n specAbsolutePath,\n ))\n ) {\n return yield* new ImplMissingSpecImportError({\n implPath: implRelativePath,\n expectedSpecPath: leaf.relativePath,\n });\n }\n\n if (!Layer.isLayer(bundled.module.default)) {\n return yield* new ImplMissingDefaultLayerError({\n implPath: implRelativePath,\n });\n }\n\n const { module: specModule } = yield* Bundler.bundle(specAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n const groupSpec = specModule.default as GroupSpec.AnyWithProps;\n const expectedFunctionNames = Object.keys(groupSpec.functions);\n\n const context = yield* buildImplLayer(\n bundled.module.default as Layer.Layer<unknown>,\n );\n const finalizedGroupImpl = yield* Option.match(\n findFinalizedGroupImpl(context),\n {\n onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),\n onSome: Effect.succeed,\n },\n );\n\n const registeredSet = new Set(finalizedGroupImpl.registeredFunctionNames);\n const missing = expectedFunctionNames.filter(\n (name) => !registeredSet.has(name),\n );\n\n if (missing.length > 0) {\n return yield* new ImplMissingFunctionsError({\n implPath: implRelativePath,\n groupPath: finalizedGroupImpl.groupPath,\n missingFunctionNames: missing,\n });\n }\n });\n"],"mappings":";;;;;;;;;;;AA4BA,MAAa,cAAc;AAC3B,MAAa,cAAc;AAE3B,MAAM,oBACJ,cACA,YACA,aAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,aAAa;AACnD,KAAI,QAAQ,SAAS,CAAC,KAAK,SAAS,WAAW,MAAM,GAAG,GAAc,CAAC,CACrE,QAAO;CAIT,MAAM,WAAW,GADJ,KAAK,MAAM,GAAG,CAAC,WAAW,MAAM,GAAG,GAAc,CAAC,OAAO,GAC3C,SAAS,MAAM,GAAG,GAAc;AAC3D,QAAO,IAAI,SAAS,IAChB,KAAK,KAAK,KAAK,GAAG,WAAW,MAAM,GACnC,GAAG,WAAW;EAClB;AAEJ,MAAa,kBAAkB,iBAC7B,aAAa,SAAS,YAAY;AAEpC,MAAa,kBAAkB,iBAC7B,aAAa,SAAS,YAAY;AAEpC,MAAa,4BAA4B,iBACvC,OAAO,IAAI,aAAa;CAEtB,MAAM,EAAE,MAAM,SADD,OAAO,KAAK,MACE,MAAM,aAAa;AAC9C,KAAI,QAAQ,MACV,QAAO;AAET,QAAO,KAAK,SAAS,QAAQ,GAAG,KAAK,MAAM,GAAG,GAAgB,GAAG;EACjE;AAEJ,MAAa,mCAAmC,iBAC9C,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,aAAa;CACnD,MAAM,OACJ,QAAQ,SAAS,KAAK,SAAS,QAAQ,GACnC,KAAK,MAAM,GAAG,GAAgB,GAC9B;CACN,MAAM,cAAc,MAAM,OACxB,OAAO,MAAM,KAAK,KAAK,IAAI,EAC3B,OAAO,WACR;CACD,MAAM,eAAe,MAAM,OAAO,aAAa,KAAK;AAIpD,QAAO;EACL;EACA,cAAc,MAAM,KAAK,cAAc,IAAI;EAC5C;EACD;AAEJ,MAAa,+BAA+B,qBAC1C,OAAO,IAAI,aAAa;AAEtB,QAAO,MADY,OAAO,oBAAoB,iBAAiB;EAE/D;AAEJ,MAAa,mBAAmB,qBAC9B,iBAAiB,kBAAkB,aAAa,YAAY;AAE9D,MAAa,mBAAmB,qBAC9B,iBAAiB,kBAAkB,aAAa,YAAY;AAE9D,MAAa,oBAAoB,iBAC/B,aAAa,WAAW,QAAQ,IAAI,aAAa,WAAW,SAAS;AAEvE,MAAa,sBAAsB,UAAkC;CACnE,GAAG;CACH,cAAc,CAAC,KAAK,WAAW;CAC/B,cAAc,KAAK;CACpB;AAED,MAAa,mCAAmC,SAC9C,OAAO,IAAI,aAAa;AAEtB,SADa,OAAO,KAAK,MAElB,KACH,uBACA,GAAG,KAAK,aAAa,MAAM,KAAK,YAAY,SAAS,IAAI,EAAE,CAC5D,GAAG;EAEN;AAEJ,MAAa,wBAAwB,OAAO,IAAI,aAAa;CAC3D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,eAAe,IAAI,IAAI,CAAC,cAAc,SAAS,CAAC;CACtD,MAAM,gBAAgB,IAAI,IAAI,CAAC,eAAe,UAAU,CAAC;CAEzD,MAAM,WAAW,OAAO,GAAG,cAAc,kBAAkB,EACzD,WAAW,MACZ,CAAC;AAEF,QAAO,MAAM,OAAO,WAAW,iBAAiB;AAC9C,MAAI,CAAC,eAAe,aAAa,CAC/B,QAAO;AAGT,MAAI,cAAc,IAAI,aAAa,CACjC,QAAO;EAGT,MAAM,WAAW,OAAO,MAAM,cAAc,KAAK,IAAI;AACrD,SAAO,CAAC,MAAM,KAAK,WAAW,YAAY,aAAa,IAAI,QAAQ,CAAC;GACpE;EACF;AAEF,MAAa,wBAAwB,OAAO,IAAI,aAAa;CAC3D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,eAAe,IAAI,IAAI,CAAC,cAAc,SAAS,CAAC;CAEtD,MAAM,WAAW,OAAO,GAAG,cAAc,kBAAkB,EACzD,WAAW,MACZ,CAAC;AAEF,QAAO,MAAM,OAAO,WAAW,iBAAiB;AAC9C,MAAI,CAAC,eAAe,aAAa,CAC/B,QAAO;EAGT,MAAM,WAAW,OAAO,MAAM,cAAc,KAAK,IAAI;AACrD,SAAO,CAAC,MAAM,KAAK,WAAW,YAAY,aAAa,IAAI,QAAQ,CAAC;GACpE;EACF;AAEF,MAAa,gBAAgB,qBAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,aAAa,OAAO,yBAAyB,iBAAiB;CACpE,MAAM,EAAE,cAAc,iBACpB,OAAO,gCAAgC,iBAAiB;CAC1D,MAAM,iBAAiB,OAAO,4BAA4B,iBAAiB;CAC3E,MAAM,UAAU,iBAAiB,iBAAiB,GAAG,SAAS;AAE9D,QAAO;EACL,cAAc;EACd;EACA;EACA;EACA;EACA,sBAAsB,YAAY,SAAS,aAAa;EACxD;EACD;EACD;AAEJ,MAAM,sBAAsB,iBAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,mBAAmB,OAAO,iBAAiB;AAEjD,SADa,OAAO,KAAK,MACb,QAAQ,kBAAkB,aAAa;EACnD;;;;;;AAOJ,MAAa,gBAAgB,SAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,eAAe,OAAO,mBAAmB,KAAK,aAAa;CACjE,MAAM,EAAE,WAAW,OAAOA,OAAe,aAAa,CAAC,KACrD,OAAO,UAAU,UAAU,iBAAiB,KAAK,cAAc,MAAM,CAAC,CACvE;CAED,MAAM,YAAY,OAAO;AAEzB,KAAI,CAAC,UAAU,YAAY,UAAU,CACnC,QAAO,OAAO,IAAI,iCAAiC,EACjD,UAAU,KAAK,cAChB,CAAC;AAGJ,KAAI,UAAU,YAAY,KAAK,QAC7B,QAAO,OAAO,IAAI,yBAAyB;EACzC,UAAU,KAAK;EACf,iBAAiB,KAAK;EACtB,eAAe,UAAU;EAC1B,CAAC;EAEJ;;;;;;AAOJ,MAAM,0BACJ,YAEA,MAAM,UAAU,QAAQ,UAAU,QAAQ,EAAE,UAAU,qBAAqB;;;;;;;;;;AAW7E,MAAM,kBAAkB,cACtB,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,IAAI,WAAmC,EAAE,CAAC;AAC3D,QAAO,OAAO,MAAM,MAClB,UACD,CAAC,KAAK,OAAO,eAAe,SAAS,UAAU,SAAS,CAAC;EAC1D,CAAC,KAAK,OAAO,OAAO;;;;;;AAOxB,MAAa,gBAAgB,SAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,mBAAmB,OAAO,gBAAgB,KAAK,aAAa;CAClE,MAAM,mBAAmB,OAAO,mBAAmB,iBAAiB;CACpE,MAAM,mBAAmB,OAAO,mBAAmB,KAAK,aAAa;CAErE,MAAM,UAAU,OAAOA,OAAe,iBAAiB,CAAC,KACtD,OAAO,UAAU,UAAU,iBAAiB,kBAAkB,MAAM,CAAC,CACtE;AAED,KACE,EAAE,OAAOC,gBACP,SACA,kBACA,iBACD,EAED,QAAO,OAAO,IAAI,2BAA2B;EAC3C,UAAU;EACV,kBAAkB,KAAK;EACxB,CAAC;AAGJ,KAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,QAAQ,CACxC,QAAO,OAAO,IAAI,6BAA6B,EAC7C,UAAU,kBACX,CAAC;CAGJ,MAAM,EAAE,QAAQ,eAAe,OAAOD,OAAe,iBAAiB,CAAC,KACrE,OAAO,UAAU,UAAU,iBAAiB,KAAK,cAAc,MAAM,CAAC,CACvE;CACD,MAAM,YAAY,WAAW;CAC7B,MAAM,wBAAwB,OAAO,KAAK,UAAU,UAAU;CAE9D,MAAM,UAAU,OAAO,eACrB,QAAQ,OAAO,QAChB;CACD,MAAM,qBAAqB,OAAO,OAAO,MACvC,uBAAuB,QAAQ,EAC/B;EACE,cAAc,IAAI,sBAAsB,EAAE,UAAU,kBAAkB,CAAC;EACvE,QAAQ,OAAO;EAChB,CACF;CAED,MAAM,gBAAgB,IAAI,IAAI,mBAAmB,wBAAwB;CACzE,MAAM,UAAU,sBAAsB,QACnC,SAAS,CAAC,cAAc,IAAI,KAAK,CACnC;AAED,KAAI,QAAQ,SAAS,EACnB,QAAO,OAAO,IAAI,0BAA0B;EAC1C,UAAU;EACV,WAAW,mBAAmB;EAC9B,sBAAsB;EACvB,CAAC;EAEJ"}
1
+ {"version":3,"file":"LeafModule.mjs","names":["Bundler.bundle","Bundler.directlyImports"],"sources":["../src/LeafModule.ts"],"sourcesContent":["import { GroupSpec, Registry } from \"@confect/core\";\nimport * as GroupImpl from \"@confect/server/GroupImpl\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport type { Context } from \"effect\";\nimport { Array, Effect, Layer, Option, Ref, String } from \"effect\";\nimport { fromBundlerError } from \"./BuildError\";\nimport * as Bundler from \"./Bundler\";\nimport {\n ImplMissingDefaultLayerError,\n ImplMissingFunctionsError,\n ImplMissingSpecImportError,\n ImplNotFinalizedError,\n SpecMissingDefaultGroupSpecError,\n SpecRuntimeMismatchError,\n} from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { removePathExtension } from \"./utils\";\n\nexport interface LeafModule {\n readonly relativePath: string;\n readonly pathSegments: readonly [string, ...string[]];\n readonly groupPathDot: string;\n readonly registryGroupPathDot: string;\n readonly exportName: string;\n readonly runtime: \"Convex\" | \"Node\";\n readonly specImportPath: string;\n}\n\nexport const SPEC_SUFFIX = \".spec.ts\";\nexport const IMPL_SUFFIX = \".impl.ts\";\n\nconst swapModuleSuffix = (\n relativePath: string,\n fromSuffix: string,\n toSuffix: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n if (ext !== \".ts\" || !name.endsWith(fromSuffix.slice(0, -\".ts\".length))) {\n return relativePath;\n }\n\n const stem = name.slice(0, -fromSuffix.slice(0, -\".ts\".length).length);\n const nextName = `${stem}${toSuffix.slice(0, -\".ts\".length)}`;\n return dir.length > 0\n ? path.join(dir, `${nextName}${ext}`)\n : `${nextName}${ext}`;\n });\n\nexport const isLeafSpecPath = (relativePath: string) =>\n relativePath.endsWith(SPEC_SUFFIX);\n\nexport const isLeafImplPath = (relativePath: string) =>\n relativePath.endsWith(IMPL_SUFFIX);\n\nexport const exportNameFromModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { name, ext } = path.parse(relativePath);\n if (ext !== \".ts\") {\n return name;\n }\n return name.endsWith(\".spec\") ? name.slice(0, -\".spec\".length) : name;\n });\n\nexport const groupPathFromRelativeModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const { dir, name, ext } = path.parse(relativePath);\n const stem =\n ext === \".ts\" && name.endsWith(\".spec\")\n ? name.slice(0, -\".spec\".length)\n : name;\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n const pathSegments = Array.append(dirSegments, stem) as [\n string,\n ...string[],\n ];\n return {\n pathSegments,\n groupPathDot: Array.join(pathSegments, \".\"),\n };\n });\n\nexport const specImportPathFromGenerated = (specRelativePath: string) =>\n Effect.gen(function* () {\n const withoutExt = yield* removePathExtension(specRelativePath);\n return `../${withoutExt}`;\n });\n\nexport const specPathForImpl = (implRelativePath: string) =>\n swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);\n\nexport const implPathForSpec = (specRelativePath: string) =>\n swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);\n\nexport const isNodeLeafModule = (relativePath: string) =>\n relativePath.startsWith(\"node/\") || relativePath.startsWith(\"node\\\\\");\n\nexport const toNodeRegistryLeaf = (leaf: LeafModule): LeafModule => ({\n ...leaf,\n pathSegments: [leaf.exportName],\n groupPathDot: leaf.exportName,\n});\n\nexport const registeredFunctionsRelativePath = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n return (\n path.join(\n \"registeredFunctions\",\n ...leaf.pathSegments.slice(leaf.runtime === \"Node\" ? 1 : 0),\n ) + \".ts\"\n );\n });\n\nexport const discoverLeafSpecFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = new Set([\"_generated\", \"tables\"]);\n const excludedFiles = new Set([\"nodeSpec.ts\", \"spec.ts\"]);\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafSpecPath(relativePath)) {\n return false;\n }\n\n if (excludedFiles.has(relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) => excludedDirs.has(segment));\n });\n});\n\nexport const discoverLeafImplFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const excludedDirs = new Set([\"_generated\", \"tables\"]);\n\n const allPaths = yield* fs.readDirectory(confectDirectory, {\n recursive: true,\n });\n\n return Array.filter(allPaths, (relativePath) => {\n if (!isLeafImplPath(relativePath)) {\n return false;\n }\n\n const segments = String.split(relativePath, path.sep);\n return !Array.some(segments, (segment) => excludedDirs.has(segment));\n });\n});\n\nexport const toLeafModule = (specRelativePath: string) =>\n Effect.gen(function* () {\n const exportName = yield* exportNameFromModulePath(specRelativePath);\n const { pathSegments, groupPathDot } =\n yield* groupPathFromRelativeModulePath(specRelativePath);\n const specImportPath = yield* specImportPathFromGenerated(specRelativePath);\n const runtime = isNodeLeafModule(specRelativePath) ? \"Node\" : \"Convex\";\n\n return {\n relativePath: specRelativePath,\n pathSegments,\n groupPathDot,\n exportName,\n runtime,\n registryGroupPathDot: runtime === \"Node\" ? exportName : groupPathDot,\n specImportPath,\n } satisfies LeafModule;\n });\n\nconst absoluteModulePath = (relativePath: string) =>\n Effect.gen(function* () {\n const confectDirectory = yield* ConfectDirectory.get;\n const path = yield* Path.Path;\n return path.resolve(confectDirectory, relativePath);\n });\n\n/**\n * Validate that the leaf's spec file default-exports a `GroupSpec` whose\n * runtime matches the leaf's location (`Convex` for files outside\n * `confect/node/`, `Node` for files inside it). Returns the validated\n * `GroupSpec` so callers can avoid re-bundling for later inspection (e.g.\n * parent/child name-collision checks at codegen time).\n */\nexport const validateSpec = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const absolutePath = yield* absoluteModulePath(leaf.relativePath);\n const { module } = yield* Bundler.bundle(absolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n\n const groupSpec = module.default;\n\n if (!GroupSpec.isGroupSpec(groupSpec)) {\n return yield* new SpecMissingDefaultGroupSpecError({\n specPath: leaf.relativePath,\n });\n }\n\n if (groupSpec.runtime !== leaf.runtime) {\n return yield* new SpecRuntimeMismatchError({\n specPath: leaf.relativePath,\n expectedRuntime: leaf.runtime,\n actualRuntime: groupSpec.runtime,\n });\n }\n\n return groupSpec;\n });\n\n/**\n * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The\n * lookup is value-shaped (via `GroupImpl.isFinalizedGroupImpl`) so we don't\n * need to know the group's path up front to construct a typed tag for it.\n */\nconst findFinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<GroupImpl.AnyFinalized> =>\n Array.findFirst(context.unsafeMap.values(), GroupImpl.isFinalizedGroupImpl);\n\n/**\n * Build the impl layer with a fresh `Registry` so each validation is\n * isolated from prior validations' `FunctionImpl.make` writes. The CLI no\n * longer reads the registry directly — `GroupImpl.finalize` snapshots the\n * registered function names onto the produced `Finalized` `GroupImpl`\n * service value — but a fresh `Ref` is still required because the default\n * `Context.Reference` is cached globally and would otherwise accumulate\n * items across impls.\n */\nconst buildImplLayer = (implLayer: Layer.Layer<unknown>) =>\n Effect.gen(function* () {\n const registry = Ref.unsafeMake<Registry.RegistryItems>({});\n return yield* Layer.build(\n implLayer as Layer.Layer<unknown, never, never>,\n ).pipe(Effect.provideService(Registry.Registry, registry));\n }).pipe(Effect.scoped);\n\n/**\n * Validate that the leaf's sibling impl file imports the spec, default-exports\n * a finalized `GroupImpl` layer, and provides a `FunctionImpl` for every\n * function declared by the spec.\n */\nexport const validateImpl = (leaf: LeafModule) =>\n Effect.gen(function* () {\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const implAbsolutePath = yield* absoluteModulePath(implRelativePath);\n const specAbsolutePath = yield* absoluteModulePath(leaf.relativePath);\n\n const bundled = yield* Bundler.bundle(implAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(implRelativePath, error)),\n );\n\n if (\n !(yield* Bundler.directlyImports(\n bundled,\n implAbsolutePath,\n specAbsolutePath,\n ))\n ) {\n return yield* new ImplMissingSpecImportError({\n implPath: implRelativePath,\n expectedSpecPath: leaf.relativePath,\n });\n }\n\n if (!Layer.isLayer(bundled.module.default)) {\n return yield* new ImplMissingDefaultLayerError({\n implPath: implRelativePath,\n });\n }\n\n const { module: specModule } = yield* Bundler.bundle(specAbsolutePath).pipe(\n Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)),\n );\n const groupSpec = specModule.default as GroupSpec.AnyWithProps;\n const expectedFunctionNames = Object.keys(groupSpec.functions);\n\n const context = yield* buildImplLayer(\n bundled.module.default as Layer.Layer<unknown>,\n );\n const finalizedGroupImpl = yield* Option.match(\n findFinalizedGroupImpl(context),\n {\n onNone: () => new ImplNotFinalizedError({ implPath: implRelativePath }),\n onSome: Effect.succeed,\n },\n );\n\n const registeredSet = new Set(finalizedGroupImpl.registeredFunctionNames);\n const missing = expectedFunctionNames.filter(\n (name) => !registeredSet.has(name),\n );\n\n if (missing.length > 0) {\n return yield* new ImplMissingFunctionsError({\n implPath: implRelativePath,\n groupPath: finalizedGroupImpl.groupPath,\n missingFunctionNames: missing,\n });\n }\n });\n"],"mappings":"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"}
@@ -3,7 +3,8 @@ import { Array, Option, Order, Record, pipe } from "effect";
3
3
  //#region src/SpecAssemblyNode.ts
4
4
  const importBindingFromLeaf = (leaf) => ({
5
5
  importPath: leaf.specImportPath,
6
- exportName: leaf.exportName
6
+ exportName: leaf.exportName,
7
+ localName: leaf.pathSegments.join("_")
7
8
  });
8
9
  const assemblyNodesAtDepth = (leaves, depth) => pipe(Array.groupBy(leaves, (leaf) => leaf.pathSegments[depth]), Record.toEntries, Array.sortBy(Order.mapInput(Order.string, ([segment]) => segment)), Array.map(([segment, groupLeaves]) => {
9
10
  const terminal = Array.findFirst(groupLeaves, (leaf) => leaf.pathSegments.length === depth + 1);
@@ -26,7 +27,7 @@ const importBindingsForNode = (node) => pipe(node.children, Array.flatMap(import
26
27
  onNone: () => childBindings,
27
28
  onSome: (binding) => Array.prepend(childBindings, binding)
28
29
  }));
29
- const collectImportBindings = (nodes) => pipe(Array.flatMap(nodes, importBindingsForNode), (bindings) => Record.fromIterableBy(bindings, (binding) => binding.exportName), Record.toEntries, Array.sortBy(Order.mapInput(Order.string, ([exportName]) => exportName)), Array.map(([, binding]) => binding));
30
+ const collectImportBindings = (nodes) => pipe(Array.flatMap(nodes, importBindingsForNode), (bindings) => Record.fromIterableBy(bindings, (binding) => binding.importPath), Record.toEntries, Array.map(([, binding]) => binding), Array.sortBy(Order.mapInput(Order.string, (binding) => binding.localName)));
30
31
 
31
32
  //#endregion
32
33
  export { assemblyNodesFromLeaves, collectImportBindings, partitionByRuntime };
@@ -1 +1 @@
1
- {"version":3,"file":"SpecAssemblyNode.mjs","names":[],"sources":["../src/SpecAssemblyNode.ts"],"sourcesContent":["import type { LeafModule } from \"./LeafModule\";\nimport { Array, Option, Order, pipe, Record } from \"effect\";\n\nexport interface SpecImportBinding {\n readonly importPath: string;\n readonly exportName: string;\n}\n\nexport interface SpecAssemblyNode {\n readonly segment: string;\n readonly importBinding: Option.Option<SpecImportBinding>;\n readonly children: ReadonlyArray<SpecAssemblyNode>;\n}\n\nconst importBindingFromLeaf = (leaf: LeafModule): SpecImportBinding => ({\n importPath: leaf.specImportPath,\n exportName: leaf.exportName,\n});\n\nconst assemblyNodesAtDepth = (\n leaves: ReadonlyArray<LeafModule>,\n depth: number,\n): ReadonlyArray<SpecAssemblyNode> =>\n pipe(\n Array.groupBy(leaves, (leaf) => leaf.pathSegments[depth]!),\n Record.toEntries,\n Array.sortBy(Order.mapInput(Order.string, ([segment]) => segment)),\n Array.map(([segment, groupLeaves]) => {\n const terminal = Array.findFirst(\n groupLeaves,\n (leaf) => leaf.pathSegments.length === depth + 1,\n );\n const descendants = Array.filter(\n groupLeaves,\n (leaf) => leaf.pathSegments.length > depth + 1,\n );\n return {\n segment,\n importBinding: Option.map(terminal, importBindingFromLeaf),\n children: assemblyNodesAtDepth(descendants, depth + 1),\n };\n }),\n );\n\nexport const assemblyNodesFromLeaves = (\n leaves: ReadonlyArray<LeafModule>,\n): ReadonlyArray<SpecAssemblyNode> => assemblyNodesAtDepth(leaves, 0);\n\nexport const partitionByRuntime = (\n leaves: ReadonlyArray<LeafModule>,\n): {\n readonly convex: ReadonlyArray<LeafModule>;\n readonly node: ReadonlyArray<LeafModule>;\n} => {\n const [node, convex] = Array.partition(\n leaves,\n (leaf) => leaf.runtime === \"Convex\",\n );\n return { convex, node };\n};\n\nconst importBindingsForNode = (\n node: SpecAssemblyNode,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(node.children, Array.flatMap(importBindingsForNode), (childBindings) =>\n Option.match(node.importBinding, {\n onNone: () => childBindings,\n onSome: (binding) => Array.prepend(childBindings, binding),\n }),\n );\n\nexport const collectImportBindings = (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(\n Array.flatMap(nodes, importBindingsForNode),\n (bindings) =>\n Record.fromIterableBy(bindings, (binding) => binding.exportName),\n Record.toEntries,\n Array.sortBy(Order.mapInput(Order.string, ([exportName]) => exportName)),\n Array.map(([, binding]) => binding),\n );\n"],"mappings":";;;AAcA,MAAM,yBAAyB,UAAyC;CACtE,YAAY,KAAK;CACjB,YAAY,KAAK;CAClB;AAED,MAAM,wBACJ,QACA,UAEA,KACE,MAAM,QAAQ,SAAS,SAAS,KAAK,aAAa,OAAQ,EAC1D,OAAO,WACP,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,CAAC,aAAa,QAAQ,CAAC,EAClE,MAAM,KAAK,CAAC,SAAS,iBAAiB;CACpC,MAAM,WAAW,MAAM,UACrB,cACC,SAAS,KAAK,aAAa,WAAW,QAAQ,EAChD;CACD,MAAM,cAAc,MAAM,OACxB,cACC,SAAS,KAAK,aAAa,SAAS,QAAQ,EAC9C;AACD,QAAO;EACL;EACA,eAAe,OAAO,IAAI,UAAU,sBAAsB;EAC1D,UAAU,qBAAqB,aAAa,QAAQ,EAAE;EACvD;EACD,CACH;AAEH,MAAa,2BACX,WACoC,qBAAqB,QAAQ,EAAE;AAErE,MAAa,sBACX,WAIG;CACH,MAAM,CAAC,MAAM,UAAU,MAAM,UAC3B,SACC,SAAS,KAAK,YAAY,SAC5B;AACD,QAAO;EAAE;EAAQ;EAAM;;AAGzB,MAAM,yBACJ,SAEA,KAAK,KAAK,UAAU,MAAM,QAAQ,sBAAsB,GAAG,kBACzD,OAAO,MAAM,KAAK,eAAe;CAC/B,cAAc;CACd,SAAS,YAAY,MAAM,QAAQ,eAAe,QAAQ;CAC3D,CAAC,CACH;AAEH,MAAa,yBACX,UAEA,KACE,MAAM,QAAQ,OAAO,sBAAsB,GAC1C,aACC,OAAO,eAAe,WAAW,YAAY,QAAQ,WAAW,EAClE,OAAO,WACP,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,CAAC,gBAAgB,WAAW,CAAC,EACxE,MAAM,KAAK,GAAG,aAAa,QAAQ,CACpC"}
1
+ {"version":3,"file":"SpecAssemblyNode.mjs","names":[],"sources":["../src/SpecAssemblyNode.ts"],"sourcesContent":["import type { LeafModule } from \"./LeafModule\";\nimport { Array, Option, Order, pipe, Record } from \"effect\";\n\nexport interface SpecImportBinding {\n readonly importPath: string;\n readonly exportName: string;\n readonly localName: string;\n}\n\nexport interface SpecAssemblyNode {\n readonly segment: string;\n readonly importBinding: Option.Option<SpecImportBinding>;\n readonly children: ReadonlyArray<SpecAssemblyNode>;\n}\n\nconst importBindingFromLeaf = (leaf: LeafModule): SpecImportBinding => ({\n importPath: leaf.specImportPath,\n exportName: leaf.exportName,\n localName: leaf.pathSegments.join(\"_\"),\n});\n\nconst assemblyNodesAtDepth = (\n leaves: ReadonlyArray<LeafModule>,\n depth: number,\n): ReadonlyArray<SpecAssemblyNode> =>\n pipe(\n Array.groupBy(leaves, (leaf) => leaf.pathSegments[depth]!),\n Record.toEntries,\n Array.sortBy(Order.mapInput(Order.string, ([segment]) => segment)),\n Array.map(([segment, groupLeaves]) => {\n const terminal = Array.findFirst(\n groupLeaves,\n (leaf) => leaf.pathSegments.length === depth + 1,\n );\n const descendants = Array.filter(\n groupLeaves,\n (leaf) => leaf.pathSegments.length > depth + 1,\n );\n return {\n segment,\n importBinding: Option.map(terminal, importBindingFromLeaf),\n children: assemblyNodesAtDepth(descendants, depth + 1),\n };\n }),\n );\n\nexport const assemblyNodesFromLeaves = (\n leaves: ReadonlyArray<LeafModule>,\n): ReadonlyArray<SpecAssemblyNode> => assemblyNodesAtDepth(leaves, 0);\n\nexport const partitionByRuntime = (\n leaves: ReadonlyArray<LeafModule>,\n): {\n readonly convex: ReadonlyArray<LeafModule>;\n readonly node: ReadonlyArray<LeafModule>;\n} => {\n const [node, convex] = Array.partition(\n leaves,\n (leaf) => leaf.runtime === \"Convex\",\n );\n return { convex, node };\n};\n\nconst importBindingsForNode = (\n node: SpecAssemblyNode,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(node.children, Array.flatMap(importBindingsForNode), (childBindings) =>\n Option.match(node.importBinding, {\n onNone: () => childBindings,\n onSome: (binding) => Array.prepend(childBindings, binding),\n }),\n );\n\nexport const collectImportBindings = (\n nodes: ReadonlyArray<SpecAssemblyNode>,\n): ReadonlyArray<SpecImportBinding> =>\n pipe(\n Array.flatMap(nodes, importBindingsForNode),\n (bindings) =>\n Record.fromIterableBy(bindings, (binding) => binding.importPath),\n Record.toEntries,\n Array.map(([, binding]) => binding),\n Array.sortBy(Order.mapInput(Order.string, (binding) => binding.localName)),\n );\n"],"mappings":";;;AAeA,MAAM,yBAAyB,UAAyC;CACtE,YAAY,KAAK;CACjB,YAAY,KAAK;CACjB,WAAW,KAAK,aAAa,KAAK,IAAI;CACvC;AAED,MAAM,wBACJ,QACA,UAEA,KACE,MAAM,QAAQ,SAAS,SAAS,KAAK,aAAa,OAAQ,EAC1D,OAAO,WACP,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,CAAC,aAAa,QAAQ,CAAC,EAClE,MAAM,KAAK,CAAC,SAAS,iBAAiB;CACpC,MAAM,WAAW,MAAM,UACrB,cACC,SAAS,KAAK,aAAa,WAAW,QAAQ,EAChD;CACD,MAAM,cAAc,MAAM,OACxB,cACC,SAAS,KAAK,aAAa,SAAS,QAAQ,EAC9C;AACD,QAAO;EACL;EACA,eAAe,OAAO,IAAI,UAAU,sBAAsB;EAC1D,UAAU,qBAAqB,aAAa,QAAQ,EAAE;EACvD;EACD,CACH;AAEH,MAAa,2BACX,WACoC,qBAAqB,QAAQ,EAAE;AAErE,MAAa,sBACX,WAIG;CACH,MAAM,CAAC,MAAM,UAAU,MAAM,UAC3B,SACC,SAAS,KAAK,YAAY,SAC5B;AACD,QAAO;EAAE;EAAQ;EAAM;;AAGzB,MAAM,yBACJ,SAEA,KAAK,KAAK,UAAU,MAAM,QAAQ,sBAAsB,GAAG,kBACzD,OAAO,MAAM,KAAK,eAAe;CAC/B,cAAc;CACd,SAAS,YAAY,MAAM,QAAQ,eAAe,QAAQ;CAC3D,CAAC,CACH;AAEH,MAAa,yBACX,UAEA,KACE,MAAM,QAAQ,OAAO,sBAAsB,GAC1C,aACC,OAAO,eAAe,WAAW,YAAY,QAAQ,WAAW,EAClE,OAAO,WACP,MAAM,KAAK,GAAG,aAAa,QAAQ,EACnC,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,YAAY,QAAQ,UAAU,CAAC,CAC3E"}
@@ -1,6 +1,6 @@
1
1
  import { logFileAdded, logFileModified, logFileRemoved, logPending, logSuccess } from "../log.mjs";
2
2
  import { fromBundlerError } from "../BuildError.mjs";
3
- import { MissingImplFileError, MissingSchemaFileError, MissingSpecFileError, SchemaInvalidDefaultExportError, tapAndLog } from "../CodegenError.mjs";
3
+ import { MissingImplFileError, MissingSchemaFileError, MissingSpecFileError, ParentChildNameCollisionError, SchemaInvalidDefaultExportError, tapAndLog } from "../CodegenError.mjs";
4
4
  import { ConvexDirectory } from "../ConvexDirectory.mjs";
5
5
  import { ConfectDirectory } from "../ConfectDirectory.mjs";
6
6
  import { FunctionPaths, make } from "../FunctionPaths.mjs";
@@ -44,8 +44,9 @@ const codegenHandler = Effect.gen(function* () {
44
44
  const runCodegen = Effect.gen(function* () {
45
45
  yield* generateConfectGeneratedDirectory;
46
46
  yield* validateSchema;
47
- const leaves = yield* loadAndValidateLeafModules;
47
+ const { leaves, groupSpecsByRelativePath } = yield* loadAndValidateLeafModules;
48
48
  yield* removeLegacyFiles;
49
+ yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);
49
50
  yield* generateAssembledSpecs(leaves);
50
51
  yield* validateImplModules(leaves);
51
52
  yield* generateGroupRegisteredFunctions(leaves);
@@ -80,20 +81,89 @@ const loadAndValidateLeafModules = Effect.gen(function* () {
80
81
  const path = yield* Path.Path;
81
82
  const confectDirectory = yield* ConfectDirectory.get;
82
83
  const specFiles = yield* discoverLeafSpecFiles;
83
- const leaves = yield* Effect.forEach(specFiles, (specRelativePath) => Effect.gen(function* () {
84
+ const results = yield* Effect.forEach(specFiles, (specRelativePath) => Effect.gen(function* () {
84
85
  const leaf = yield* toLeafModule(specRelativePath);
85
- yield* validateSpec(leaf);
86
+ const groupSpec = yield* validateSpec(leaf);
86
87
  const implRelativePath = yield* implPathForSpec(specRelativePath);
87
88
  const implAbsolutePath = path.join(confectDirectory, implRelativePath);
88
89
  if (!(yield* fs.exists(implAbsolutePath))) return yield* new MissingImplFileError({
89
90
  specPath: specRelativePath,
90
91
  expectedImplPath: implRelativePath
91
92
  });
92
- return leaf;
93
+ return {
94
+ leaf,
95
+ groupSpec
96
+ };
93
97
  }));
94
98
  yield* validateOrphanImpls(specFiles);
95
- return leaves;
99
+ return {
100
+ leaves: Array.map(results, ({ leaf }) => leaf),
101
+ groupSpecsByRelativePath: new Map(Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]))
102
+ };
103
+ });
104
+ /**
105
+ * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}
106
+ * when a parent leaf declares a function or subgroup whose name matches a
107
+ * sibling subdirectory spec's segment. Without this check the colliding
108
+ * descendant would overwrite the parent's entry in the assembled
109
+ * `GroupSpec.groups` map at runtime, surfacing as a confusing
110
+ * `Refs.make` error rather than a codegen-time diagnostic.
111
+ */
112
+ const validateNoParentChildNameCollisions = (leaves, groupSpecsByRelativePath) => Effect.gen(function* () {
113
+ const { convex, node } = partitionByRuntime(leaves);
114
+ const convexNodes = assemblyNodesFromLeaves(convex);
115
+ const nodeNodes = assemblyNodesFromLeaves(Array.map(node, toNodeRegistryLeaf));
116
+ yield* Effect.forEach(convexNodes, (n) => checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath));
117
+ yield* Effect.forEach(nodeNodes, (n) => checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath));
118
+ });
119
+ const checkAssemblyNodeForCollisions = (node, groupSpecsByRelativePath) => Effect.gen(function* () {
120
+ yield* Option.match(node.importBinding, {
121
+ onNone: () => Effect.void,
122
+ onSome: (binding) => Effect.gen(function* () {
123
+ if (node.children.length === 0) return;
124
+ const parentRelativePath = bindingToRelativeSpecPath(binding.importPath);
125
+ const parentGroupSpec = groupSpecsByRelativePath.get(parentRelativePath);
126
+ if (parentGroupSpec === void 0) return;
127
+ yield* Effect.forEach(node.children, (child) => {
128
+ if (Object.prototype.hasOwnProperty.call(parentGroupSpec.functions, child.segment)) return Effect.fail(new ParentChildNameCollisionError({
129
+ parentSpecPath: parentRelativePath,
130
+ childSpecPath: childRepresentativeSpecPath(child),
131
+ collisionName: child.segment,
132
+ collisionKind: "function"
133
+ }));
134
+ if (Object.prototype.hasOwnProperty.call(parentGroupSpec.groups, child.segment)) return Effect.fail(new ParentChildNameCollisionError({
135
+ parentSpecPath: parentRelativePath,
136
+ childSpecPath: childRepresentativeSpecPath(child),
137
+ collisionName: child.segment,
138
+ collisionKind: "group"
139
+ }));
140
+ return Effect.void;
141
+ });
142
+ })
143
+ });
144
+ yield* Effect.forEach(node.children, (child) => checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath));
96
145
  });
146
+ /**
147
+ * `LeafModule.specImportPath` is the import path used from inside the
148
+ * generated `_generated/spec.ts` (e.g. `"../notes.spec"`). Strip the
149
+ * `../` prefix and re-add the `.ts` extension to recover the leaf's
150
+ * confect-relative spec path used as the key in
151
+ * `groupSpecsByRelativePath`.
152
+ */
153
+ const bindingToRelativeSpecPath = (importPath) => {
154
+ return `${importPath.startsWith("../") ? importPath.slice(3) : importPath}.ts`;
155
+ };
156
+ /**
157
+ * A child assembly node may itself be a parent without a leaf (when the
158
+ * actual leaves live only in deeper subdirectories). In that case we
159
+ * surface the first descendant leaf as a representative path so the
160
+ * error message points at something the user actually wrote.
161
+ */
162
+ const childRepresentativeSpecPath = (node) => {
163
+ if (Option.isSome(node.importBinding)) return bindingToRelativeSpecPath(node.importBinding.value.importPath);
164
+ for (const child of node.children) return childRepresentativeSpecPath(child);
165
+ return node.segment;
166
+ };
97
167
  const validateOrphanImpls = (specFiles) => Effect.gen(function* () {
98
168
  const fs = yield* FileSystem.FileSystem;
99
169
  const path = yield* Path.Path;
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","templates.api","templates.nodeApi","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport * as DatabaseSchema from \"@confect/server/DatabaseSchema\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport { fromBundlerError } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n MissingImplFileError,\n MissingSchemaFileError,\n MissingSpecFileError,\n SchemaInvalidDefaultExportError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport {\n discoverLeafImplFiles,\n discoverLeafSpecFiles,\n implPathForSpec,\n registeredFunctionsRelativePath,\n specPathForImpl,\n toLeafModule,\n toNodeRegistryLeaf,\n validateImpl,\n validateSpec,\n type LeafModule,\n} from \"../LeafModule\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n} from \"../SpecAssemblyNode\";\nimport * as templates from \"../templates\";\nimport * as Bundler from \"../Bundler\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_SPEC_PATH = \"_generated/spec.ts\";\nconst GENERATED_NODE_SPEC_PATH = \"_generated/nodeSpec.ts\";\n\nconst LEGACY_PATHS = [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n \"notesAndRandom.impl.ts\",\n \"groups.impl.ts\",\n \"_generated/registeredFunctions.ts\",\n \"_generated/nodeRegisteredFunctions.ts\",\n \"_generated/impl.ts\",\n \"_generated/nodeImpl.ts\",\n];\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler.pipe(\n Effect.asVoid,\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.tapAndLog,\n );\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n const tracker = yield* Ref.make(false);\n\n const functionPaths = yield* runCodegen.pipe(\n Effect.provideService(WriteTracker, tracker),\n );\n\n const anyWritesHappened = yield* Ref.get(tracker);\n return { functionPaths, anyWritesHappened };\n});\n\nconst runCodegen = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n // Validate schema first so its missing-file / invalid-default-export\n // diagnostics surface ahead of impl bundling, which transitively depends\n // on schema via `_generated/api.ts` and would otherwise blow up with a\n // less actionable bundler error.\n yield* validateSchema;\n const leaves = yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* generateAssembledSpecs(leaves);\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n yield* Effect.all(\n [generateApi, generateRefs, generateNodeApi, generateServices],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* touchConvexSchema;\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst loadAndValidateLeafModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const leaves = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n yield* validateSpec(leaf);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return leaf;\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n return leaves;\n});\n\nconst validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = new Set(specFiles);\n\n yield* Effect.forEach(implFiles, (implRelativePath) =>\n Effect.gen(function* () {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (specPaths.has(specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n });\n\nconst removeLegacyFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(LEGACY_PATHS, (relativePath) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n }),\n );\n});\n\nconst generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const { convex, node } = partitionByRuntime(leaves);\n\n if (convex.length > 0) {\n const nodes = assemblyNodesFromLeaves(convex);\n const specContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Convex\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_SPEC_PATH),\n specContents,\n );\n }\n\n if (node.length > 0) {\n const nodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n const nodeSpecContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Node\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_NODE_SPEC_PATH),\n nodeSpecContents,\n );\n }\n });\n\nconst validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.forEach(leaves, validateImpl);\n\nconst generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(leaves, (leaf) =>\n Effect.gen(function* () {\n const registryRelativePath =\n yield* registeredFunctionsRelativePath(leaf);\n const registryPath = path.join(\n confectDirectory,\n \"_generated\",\n registryRelativePath,\n );\n const registryDir = path.dirname(registryPath);\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(registryDir))) {\n yield* fs.makeDirectory(registryDir, { recursive: true });\n }\n\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const apiFileName = leaf.runtime === \"Node\" ? \"nodeApi.ts\" : \"api.ts\";\n const apiImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", apiFileName),\n ),\n );\n const implImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, implRelativePath),\n ),\n );\n\n const contents = yield* templates.registeredFunctionsForGroup({\n apiImportPath,\n groupPathDot: leaf.registryGroupPathDot,\n implImportPath,\n layerExportName: leaf.exportName,\n useNode: leaf.runtime === \"Node\",\n });\n\n yield* writeFileStringAndLog(registryPath, contents);\n }),\n );\n });\n\nconst removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const registryRoot = path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n );\n\n if (!(yield* fs.exists(registryRoot))) {\n return;\n }\n\n const expected = new Set(\n yield* Effect.forEach(leaves, (leaf) =>\n registeredFunctionsRelativePath(leaf),\n ),\n );\n\n const existing = yield* fs.readDirectory(registryRoot, { recursive: true });\n yield* Effect.forEach(existing, (relativePath) => {\n if (path.extname(relativePath) !== \".ts\") {\n return Effect.void;\n }\n const normalized = path.join(\"registeredFunctions\", relativePath);\n if (!expected.has(normalized)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(registryRoot, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst getGeneratedSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_SPEC_PATH);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_NODE_SPEC_PATH);\n});\n\nconst loadGeneratedSpec = Effect.gen(function* () {\n const specPath = yield* getGeneratedSpecPath;\n const { module: specModule } = yield* Bundler.bundle(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.dieMessage(\n \"_generated/spec.ts does not export a valid Convex Spec\",\n );\n }\n\n return spec;\n});\n\nconst loadGeneratedNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.dieMessage(\n \"_generated/nodeSpec.ts does not export a valid Node Spec\",\n );\n }\n\n return Option.some(nodeSpec);\n});\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getGeneratedSpecPath;\n\n if (!(yield* fs.exists(specPath))) {\n return emptyFunctionPaths;\n }\n\n const specEither = yield* loadGeneratedSpec.pipe(Effect.either);\n\n return yield* Either.match(specEither, {\n onLeft: () => Effect.succeed(emptyFunctionPaths),\n onRight: (spec) =>\n Effect.gen(function* () {\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n return FunctionPaths.make(mergedSpec);\n }),\n });\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* removePathIfExists(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const spec = yield* loadGeneratedSpec;\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nexport const validateSchema = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n if (!(yield* fs.exists(confectSchemaPath))) {\n return yield* new MissingSchemaFileError({ schemaPath: \"schema.ts\" });\n }\n\n yield* Bundler.bundle(confectSchemaPath).pipe(\n Effect.mapError((error) => fromBundlerError(\"schema.ts\", error)),\n Effect.andThen(({ module: schemaModule }) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isDatabaseSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.fail(\n new SchemaInvalidDefaultExportError({\n schemaPath: \"schema.ts\",\n }),\n );\n }),\n );\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n // `validateSchema` runs once at the top of `runCodegen`; no need to\n // bundle the schema again here.\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? Option.some(\n yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),\n )\n : Option.none<string>();\n\n const refsContents = yield* templates.refs({\n specImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":";;;;;;;;;;;;;;;;;;AAsDA,MAAM,sBAAsB;AAC5B,MAAM,2BAA2B;AAEjC,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAa,UAAU,QAAQ,KAAK,WAAW,EAAE,QAC/C,OAAO,IAAI,aAAa;AACtB,QAAO,WAAW,2BAA2B;AAC7C,QAAO,eAAe,KACpB,OAAO,QACP,OAAO,UAAU,WAAW,iCAAiC,CAAC,EAC9DA,UACD;EACD,CACH,CAAC,KACA,QAAQ,gBACN,iIACD,CACF;AAED,MAAa,iBAAiB,OAAO,IAAI,aAAa;CACpD,MAAM,UAAU,OAAO,IAAI,KAAK,MAAM;AAOtC,QAAO;EAAE,eALa,OAAO,WAAW,KACtC,OAAO,eAAe,cAAc,QAAQ,CAC7C;EAGuB,mBADE,OAAO,IAAI,IAAI,QAAQ;EACN;EAC3C;AAEF,MAAM,aAAa,OAAO,IAAI,aAAa;AACzC,QAAO;AAKP,QAAO;CACP,MAAM,SAAS,OAAO;AACtB,QAAO;AACP,QAAO,uBAAuB,OAAO;AACrC,QAAO,oBAAoB,OAAO;AAClC,QAAO,iCAAiC,OAAO;AAC/C,QAAO,kCAAkC,OAAO;AAChD,QAAO,OAAO,IACZ;EAAC;EAAa;EAAc;EAAiB;EAAiB,EAC9D,EAAE,aAAa,aAAa,CAC7B;CACD,MAAM,CAAC,iBAAiB,OAAO,OAAO,IACpC;EACE;EACA;EACA,aAAa,aAAa;EAC1B,aAAa,cAAc;EAC3B,aAAa,mBAAmB;EACjC,EACD,EAAE,aAAa,aAAa,CAC7B;AACD,QAAO;AACP,QAAO;EACP;AAEF,MAAM,oCAAoC,OAAO,IAAI,aAAa;CAChE,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AAEjD,KAAI,EAAE,OAAO,GAAG,OAAO,KAAK,KAAK,kBAAkB,aAAa,CAAC,GAAG;AAClE,SAAO,GAAG,cAAc,KAAK,KAAK,kBAAkB,aAAa,EAAE,EACjE,WAAW,MACZ,CAAC;AACF,SAAO,aAAa,KAAK,KAAK,kBAAkB,aAAa,GAAG,IAAI;;EAEtE;AAEF,MAAM,6BAA6B,OAAO,IAAI,aAAa;CACzD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,YAAY,OAAO;CAEzB,MAAM,SAAS,OAAO,OAAO,QAAQ,YAAY,qBAC/C,OAAO,IAAI,aAAa;EACtB,MAAM,OAAO,OAAO,aAAa,iBAAiB;AAClD,SAAO,aAAa,KAAK;EAEzB,MAAM,mBAAmB,OAAO,gBAAgB,iBAAiB;EACjE,MAAM,mBAAmB,KAAK,KAAK,kBAAkB,iBAAiB;AACtE,MAAI,EAAE,OAAO,GAAG,OAAO,iBAAiB,EACtC,QAAO,OAAO,IAAI,qBAAqB;GACrC,UAAU;GACV,kBAAkB;GACnB,CAAC;AAGJ,SAAO;GACP,CACH;AAED,QAAO,oBAAoB,UAAU;AAErC,QAAO;EACP;AAEF,MAAM,uBAAuB,cAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,YAAY,OAAO;CACzB,MAAM,YAAY,IAAI,IAAI,UAAU;AAEpC,QAAO,OAAO,QAAQ,YAAY,qBAChC,OAAO,IAAI,aAAa;EACtB,MAAM,mBAAmB,OAAO,gBAAgB,iBAAiB;AACjE,MAAI,UAAU,IAAI,iBAAiB,CACjC;EAGF,MAAM,mBAAmB,KAAK,KAAK,kBAAkB,iBAAiB;AACtE,MAAI,EAAE,OAAO,GAAG,OAAO,iBAAiB,EACtC,QAAO,OAAO,IAAI,qBAAqB;GACrC,UAAU;GACV,kBAAkB;GACnB,CAAC;GAEJ,CACH;EACD;AAEJ,MAAM,oBAAoB,OAAO,IAAI,aAAa;CAChD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AAEjD,QAAO,OAAO,QAAQ,eAAe,iBACnC,OAAO,IAAI,aAAa;EACtB,MAAM,eAAe,KAAK,KAAK,kBAAkB,aAAa;AAC9D,MAAI,OAAO,GAAG,OAAO,aAAa,EAAE;AAClC,UAAO,mBAAmB,aAAa;AACvC,UAAO,eAAe,aAAa;;GAErC,CACH;EACD;AAEF,MAAM,0BAA0B,WAC9B,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,EAAE,QAAQ,SAAS,mBAAmB,OAAO;AAEnD,KAAI,OAAO,SAAS,GAAG;EACrB,MAAM,QAAQ,wBAAwB,OAAO;EAC7C,MAAM,eAAe,OAAOC,cAAwB;GAClD;GACA,SAAS;GACV,CAAC;AACF,SAAO,sBACL,KAAK,KAAK,kBAAkB,oBAAoB,EAChD,aACD;;AAGH,KAAI,KAAK,SAAS,GAAG;EACnB,MAAM,QAAQ,wBACZ,MAAM,IAAI,MAAM,mBAAmB,CACpC;EACD,MAAM,mBAAmB,OAAOA,cAAwB;GACtD;GACA,SAAS;GACV,CAAC;AACF,SAAO,sBACL,KAAK,KAAK,kBAAkB,yBAAyB,EACrD,iBACD;;EAEH;AAEJ,MAAM,uBAAuB,WAC3B,OAAO,QAAQ,QAAQ,aAAa;AAEtC,MAAM,oCAAoC,WACxC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AAEjD,QAAO,OAAO,QAAQ,SAAS,SAC7B,OAAO,IAAI,aAAa;EACtB,MAAM,uBACJ,OAAO,gCAAgC,KAAK;EAC9C,MAAM,eAAe,KAAK,KACxB,kBACA,cACA,qBACD;EACD,MAAM,cAAc,KAAK,QAAQ,aAAa;EAC9C,MAAM,KAAK,OAAO,WAAW;AAC7B,MAAI,EAAE,OAAO,GAAG,OAAO,YAAY,EACjC,QAAO,GAAG,cAAc,aAAa,EAAE,WAAW,MAAM,CAAC;EAG3D,MAAM,mBAAmB,OAAO,gBAAgB,KAAK,aAAa;EAClE,MAAM,cAAc,KAAK,YAAY,SAAS,eAAe;EAC7D,MAAM,gBAAgB,OAAO,mBAC3B,KAAK,SACH,KAAK,QAAQ,aAAa,EAC1B,KAAK,KAAK,kBAAkB,cAAc,YAAY,CACvD,CACF;EACD,MAAM,iBAAiB,OAAO,mBAC5B,KAAK,SACH,KAAK,QAAQ,aAAa,EAC1B,KAAK,KAAK,kBAAkB,iBAAiB,CAC9C,CACF;AAUD,SAAO,sBAAsB,cARZ,OAAOC,4BAAsC;GAC5D;GACA,cAAc,KAAK;GACnB;GACA,iBAAiB,KAAK;GACtB,SAAS,KAAK,YAAY;GAC3B,CAAC,CAEkD;GACpD,CACH;EACD;AAEJ,MAAM,qCAAqC,WACzC,OAAO,IAAI,aAAa;CACtB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,eAAe,KAAK,KACxB,kBACA,cACA,sBACD;AAED,KAAI,EAAE,OAAO,GAAG,OAAO,aAAa,EAClC;CAGF,MAAM,WAAW,IAAI,IACnB,OAAO,OAAO,QAAQ,SAAS,SAC7B,gCAAgC,KAAK,CACtC,CACF;CAED,MAAM,WAAW,OAAO,GAAG,cAAc,cAAc,EAAE,WAAW,MAAM,CAAC;AAC3E,QAAO,OAAO,QAAQ,WAAW,iBAAiB;AAChD,MAAI,KAAK,QAAQ,aAAa,KAAK,MACjC,QAAO,OAAO;EAEhB,MAAM,aAAa,KAAK,KAAK,uBAAuB,aAAa;AACjE,MAAI,CAAC,SAAS,IAAI,WAAW,CAC3B,QAAO,OAAO,IAAI,aAAa;GAC7B,MAAM,eAAe,KAAK,KAAK,cAAc,aAAa;AAC1D,OAAI,OAAO,GAAG,OAAO,aAAa,EAAE;AAClC,WAAO,mBAAmB,aAAa;AACvC,WAAO,eAAe,aAAa;;IAErC;AAEJ,SAAO,OAAO;GACd;EACF;AAEJ,MAAM,uBAAuB,OAAO,IAAI,aAAa;CACnD,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AACjD,QAAO,KAAK,KAAK,kBAAkB,oBAAoB;EACvD;AAEF,MAAM,2BAA2B,OAAO,IAAI,aAAa;CACvD,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;AACjD,QAAO,KAAK,KAAK,kBAAkB,yBAAyB;EAC5D;AAEF,MAAM,oBAAoB,OAAO,IAAI,aAAa;CAChD,MAAM,WAAW,OAAO;CACxB,MAAM,EAAE,QAAQ,eAAe,OAAOC,OAAe,SAAS;CAC9D,MAAM,OAAO,WAAW;AAExB,KAAI,CAAC,KAAK,aAAa,KAAK,CAC1B,QAAO,OAAO,OAAO,WACnB,yDACD;AAGH,QAAO;EACP;AAEF,MAAM,wBAAwB,OAAO,IAAI,aAAa;CACpD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,eAAe,OAAO;AAE5B,KAAI,EAAE,OAAO,GAAG,OAAO,aAAa,EAClC,QAAO,OAAO,MAA4C;CAG5D,MAAM,EAAE,QAAQ,mBAAmB,OAAOA,OAAe,aAAa;CACtE,MAAM,WAAW,eAAe;AAEhC,KAAI,CAAC,KAAK,WAAW,SAAS,CAC5B,QAAO,OAAO,OAAO,WACnB,2DACD;AAGH,QAAO,OAAO,KAAK,SAAS;EAC5B;AAEF,MAAM,mCAAiD,KAAK,QAAQ,OAAO,CAAC;AAE5E,MAAa,4BAA4B,OAAO,IAAI,aAAa;CAC/D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,WAAW,OAAO;AAExB,KAAI,EAAE,OAAO,GAAG,OAAO,SAAS,EAC9B,QAAO;CAGT,MAAM,aAAa,OAAO,kBAAkB,KAAK,OAAO,OAAO;AAE/D,QAAO,OAAO,OAAO,MAAM,YAAY;EACrC,cAAc,OAAO,QAAQ,mBAAmB;EAChD,UAAU,SACR,OAAO,IAAI,aAAa;GACtB,MAAM,iBAAiB,OAAO;GAC9B,MAAM,aAAa,OAAO,MAAM,gBAAgB;IAC9C,cAAc;IACd,SAAS,aAAa,KAAK,MAAM,MAAM,SAAS;IACjD,CAAC;AACF,UAAOC,KAAmB,WAAW;IACrC;EACL,CAAC;EACF;AAEF,MAAM,cAAc,OAAO,IAAI,aAAa;CAC1C,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,UAAU,KAAK,KAAK,kBAAkB,cAAc,SAAS;CACnE,MAAM,SAAS,KAAK,QAAQ,QAAQ;CAEpC,MAAM,mBAAmB,OAAO,mBAC9B,KAAK,SAAS,QAAQ,KAAK,KAAK,kBAAkB,YAAY,CAAC,CAChE;CAED,MAAM,iBAAiB,OAAO,mBAC5B,KAAK,SAAS,QAAQ,KAAK,KAAK,kBAAkB,oBAAoB,CAAC,CACxE;AAOD,QAAO,sBAAsB,SALT,OAAOC,IAAc;EACvC;EACA;EACD,CAAC,CAEgD;EAClD;AAEF,MAAa,kBAAkB,OAAO,IAAI,aAAa;CACrD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,eAAe,OAAO;CAC5B,MAAM,cAAc,KAAK,KAAK,kBAAkB,cAAc,aAAa;AAE3E,KAAI,EAAE,OAAO,GAAG,OAAO,aAAa,GAAG;AACrC,MAAI,OAAO,GAAG,OAAO,YAAY,EAAE;AACjC,UAAO,mBAAmB,YAAY;AACtC,UAAO,eAAe,YAAY;;AAEpC;;CAGF,MAAM,aAAa,KAAK,QAAQ,YAAY;CAE5C,MAAM,mBAAmB,OAAO,mBAC9B,KAAK,SAAS,YAAY,KAAK,KAAK,kBAAkB,YAAY,CAAC,CACpE;CAED,MAAM,qBAAqB,OAAO,mBAChC,KAAK,SAAS,YAAY,aAAa,CACxC;AAOD,QAAO,sBAAsB,aALL,OAAOC,QAAkB;EAC/C;EACA;EACD,CAAC,CAEwD;EAC1D;AAEF,MAAM,0BAA0B,OAAO,IAAI,aAAa;CACtD,MAAM,OAAO,OAAO;CACpB,MAAM,iBAAiB,OAAO;AAO9B,QAAO,OAAO,kBALK,OAAO,MAAM,gBAAgB;EAC9C,cAAc;EACd,SAAS,aAAa,KAAK,MAAM,MAAM,SAAS;EACjD,CAAC,CAEyC;EAC3C;AAEF,MAAa,iBAAiB,OAAO,IAAI,aAAa;CACpD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,oBAAoB,KAAK,KAAK,kBAAkB,YAAY;AAElE,KAAI,EAAE,OAAO,GAAG,OAAO,kBAAkB,EACvC,QAAO,OAAO,IAAI,uBAAuB,EAAE,YAAY,aAAa,CAAC;AAGvE,QAAOH,OAAe,kBAAkB,CAAC,KACvC,OAAO,UAAU,UAAU,iBAAiB,aAAa,MAAM,CAAC,EAChE,OAAO,SAAS,EAAE,QAAQ,mBAAmB;EAC3C,MAAM,gBAAgB,aAAa;AAEnC,SAAO,eAAe,iBAAiB,cAAc,GACjD,OAAO,QAAQ,cAAc,GAC7B,OAAO,KACL,IAAI,gCAAgC,EAClC,YAAY,aACb,CAAC,CACH;GACL,CACH;EACD;AAEF,MAAM,iBAAiB,OAAO,IAAI,aAAa;CAC7C,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CACjD,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,oBAAoB,KAAK,KAAK,kBAAkB,YAAY;CAKlE,MAAM,mBAAmB,KAAK,KAAK,iBAAiB,YAAY;CAMhE,MAAM,uBAAuB,OAAO,oBAJT,KAAK,SAC9B,KAAK,QAAQ,iBAAiB,EAC9B,kBACD,CAC0E;AAK3E,QAAO,sBAAsB,kBAJN,OAAOI,OAAiB,EAC7C,kBAAkB,sBACnB,CAAC,CAE4D;EAC9D;AAEF,MAAM,mBAAmB,OAAO,IAAI,aAAa;CAC/C,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,4BAA4B,KAAK,KAAK,kBAAkB,aAAa;CAE3E,MAAM,eAAe,KAAK,KAAK,2BAA2B,cAAc;CACxE,MAAM,mBAAmB,KAAK,SAC5B,KAAK,QAAQ,aAAa,EAC1B,KAAK,KAAK,kBAAkB,SAAS,CACtC;AAMD,QAAO,sBAAsB,cAJE,OAAOC,SAAmB,EACvD,kBACD,CAAC,CAEgE;EAClE;AAEF,MAAM,eAAe,OAAO,IAAI,aAAa;CAC3C,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,mBAAmB,OAAO,iBAAiB;CAEjD,MAAM,4BAA4B,KAAK,KAAK,kBAAkB,aAAa;CAC3E,MAAM,WAAW,KAAK,KAAK,2BAA2B,UAAU;CAChE,MAAM,UAAU,KAAK,QAAQ,SAAS;CAEtC,MAAM,iBAAiB,OAAO,mBAC5B,KAAK,SAAS,SAAS,KAAK,KAAK,kBAAkB,oBAAoB,CAAC,CACzE;CAED,MAAM,eAAe,OAAO;CAE5B,MAAM,sBADiB,OAAO,GAAG,OAAO,aAAa,IAEjD,OAAO,KACL,OAAO,mBAAmB,KAAK,SAAS,SAAS,aAAa,CAAC,CAChE,GACD,OAAO,MAAc;AAOzB,QAAO,sBAAsB,UALR,OAAOC,KAAe;EACzC;EACA;EACD,CAAC,CAEkD;EACpD;AAEF,MAAM,gBAAgB,WACpB,OAAO,KACL,OAAO,IACL,OAAO,MAAM;CACX,cAAc,OAAO;CACrB,SAAS,EAAE,QAAQ,qBACjB,MAAM,MAAM,OAAO,CAAC,KAClB,MAAM,KAAK,eAAe,aAAa,eAAe,CAAC,EACvD,MAAM,KAAK,kBAAkB,gBAAgB,eAAe,CAAC,EAC7D,MAAM,KAAK,mBAAmB,OAAO,KAAK,EAC1C,MAAM,WACP;CACJ,CAAC,CACH,CACF"}
1
+ {"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","templates.api","templates.nodeApi","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { type GroupSpec, Spec } from \"@confect/core\";\nimport * as DatabaseSchema from \"@confect/server/DatabaseSchema\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport { fromBundlerError } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n MissingImplFileError,\n MissingSchemaFileError,\n MissingSpecFileError,\n ParentChildNameCollisionError,\n SchemaInvalidDefaultExportError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport {\n discoverLeafImplFiles,\n discoverLeafSpecFiles,\n implPathForSpec,\n registeredFunctionsRelativePath,\n specPathForImpl,\n toLeafModule,\n toNodeRegistryLeaf,\n validateImpl,\n validateSpec,\n type LeafModule,\n} from \"../LeafModule\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n type SpecAssemblyNode,\n} from \"../SpecAssemblyNode\";\nimport * as templates from \"../templates\";\nimport * as Bundler from \"../Bundler\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_SPEC_PATH = \"_generated/spec.ts\";\nconst GENERATED_NODE_SPEC_PATH = \"_generated/nodeSpec.ts\";\n\nconst LEGACY_PATHS = [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n \"notesAndRandom.impl.ts\",\n \"groups.impl.ts\",\n \"_generated/registeredFunctions.ts\",\n \"_generated/nodeRegisteredFunctions.ts\",\n \"_generated/impl.ts\",\n \"_generated/nodeImpl.ts\",\n];\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler.pipe(\n Effect.asVoid,\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.tapAndLog,\n );\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n const tracker = yield* Ref.make(false);\n\n const functionPaths = yield* runCodegen.pipe(\n Effect.provideService(WriteTracker, tracker),\n );\n\n const anyWritesHappened = yield* Ref.get(tracker);\n return { functionPaths, anyWritesHappened };\n});\n\nconst runCodegen = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n // Validate schema first so its missing-file / invalid-default-export\n // diagnostics surface ahead of impl bundling, which transitively depends\n // on schema via `_generated/api.ts` and would otherwise blow up with a\n // less actionable bundler error.\n yield* validateSchema;\n const { leaves, groupSpecsByRelativePath } =\n yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);\n yield* generateAssembledSpecs(leaves);\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n yield* Effect.all(\n [generateApi, generateRefs, generateNodeApi, generateServices],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* touchConvexSchema;\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst loadAndValidateLeafModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n const groupSpec = yield* validateSpec(leaf);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return { leaf, groupSpec };\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n const leaves = Array.map(results, ({ leaf }) => leaf);\n const groupSpecsByRelativePath = new Map(\n Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),\n );\n\n return { leaves, groupSpecsByRelativePath };\n});\n\n/**\n * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}\n * when a parent leaf declares a function or subgroup whose name matches a\n * sibling subdirectory spec's segment. Without this check the colliding\n * descendant would overwrite the parent's entry in the assembled\n * `GroupSpec.groups` map at runtime, surfacing as a confusing\n * `Refs.make` error rather than a codegen-time diagnostic.\n */\nexport const validateNoParentChildNameCollisions = (\n leaves: ReadonlyArray<LeafModule>,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n) =>\n Effect.gen(function* () {\n const { convex, node } = partitionByRuntime(leaves);\n const convexNodes = assemblyNodesFromLeaves(convex);\n const nodeNodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n yield* Effect.forEach(convexNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n yield* Effect.forEach(nodeNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n });\n\nconst checkAssemblyNodeForCollisions = (\n node: SpecAssemblyNode,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n): Effect.Effect<void, ParentChildNameCollisionError> =>\n Effect.gen(function* () {\n yield* Option.match(node.importBinding, {\n onNone: () => Effect.void,\n onSome: (binding) =>\n Effect.gen(function* () {\n if (node.children.length === 0) return;\n const parentRelativePath = bindingToRelativeSpecPath(\n binding.importPath,\n );\n const parentGroupSpec =\n groupSpecsByRelativePath.get(parentRelativePath);\n if (parentGroupSpec === undefined) return;\n yield* Effect.forEach(node.children, (child) => {\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.functions,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"function\",\n }),\n );\n }\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.groups,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"group\",\n }),\n );\n }\n return Effect.void;\n });\n }),\n });\n yield* Effect.forEach(node.children, (child) =>\n checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),\n );\n });\n\n/**\n * `LeafModule.specImportPath` is the import path used from inside the\n * generated `_generated/spec.ts` (e.g. `\"../notes.spec\"`). Strip the\n * `../` prefix and re-add the `.ts` extension to recover the leaf's\n * confect-relative spec path used as the key in\n * `groupSpecsByRelativePath`.\n */\nconst bindingToRelativeSpecPath = (importPath: string): string => {\n const withoutDotDot = importPath.startsWith(\"../\")\n ? importPath.slice(3)\n : importPath;\n return `${withoutDotDot}.ts`;\n};\n\n/**\n * A child assembly node may itself be a parent without a leaf (when the\n * actual leaves live only in deeper subdirectories). In that case we\n * surface the first descendant leaf as a representative path so the\n * error message points at something the user actually wrote.\n */\nconst childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {\n if (Option.isSome(node.importBinding)) {\n return bindingToRelativeSpecPath(node.importBinding.value.importPath);\n }\n for (const child of node.children) {\n return childRepresentativeSpecPath(child);\n }\n return node.segment;\n};\n\nconst validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = new Set(specFiles);\n\n yield* Effect.forEach(implFiles, (implRelativePath) =>\n Effect.gen(function* () {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (specPaths.has(specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n });\n\nconst removeLegacyFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(LEGACY_PATHS, (relativePath) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n }),\n );\n});\n\nconst generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const { convex, node } = partitionByRuntime(leaves);\n\n if (convex.length > 0) {\n const nodes = assemblyNodesFromLeaves(convex);\n const specContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Convex\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_SPEC_PATH),\n specContents,\n );\n }\n\n if (node.length > 0) {\n const nodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n const nodeSpecContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Node\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_NODE_SPEC_PATH),\n nodeSpecContents,\n );\n }\n });\n\nconst validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.forEach(leaves, validateImpl);\n\nconst generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(leaves, (leaf) =>\n Effect.gen(function* () {\n const registryRelativePath =\n yield* registeredFunctionsRelativePath(leaf);\n const registryPath = path.join(\n confectDirectory,\n \"_generated\",\n registryRelativePath,\n );\n const registryDir = path.dirname(registryPath);\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(registryDir))) {\n yield* fs.makeDirectory(registryDir, { recursive: true });\n }\n\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const apiFileName = leaf.runtime === \"Node\" ? \"nodeApi.ts\" : \"api.ts\";\n const apiImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", apiFileName),\n ),\n );\n const implImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, implRelativePath),\n ),\n );\n\n const contents = yield* templates.registeredFunctionsForGroup({\n apiImportPath,\n groupPathDot: leaf.registryGroupPathDot,\n implImportPath,\n layerExportName: leaf.exportName,\n useNode: leaf.runtime === \"Node\",\n });\n\n yield* writeFileStringAndLog(registryPath, contents);\n }),\n );\n });\n\nconst removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const registryRoot = path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n );\n\n if (!(yield* fs.exists(registryRoot))) {\n return;\n }\n\n const expected = new Set(\n yield* Effect.forEach(leaves, (leaf) =>\n registeredFunctionsRelativePath(leaf),\n ),\n );\n\n const existing = yield* fs.readDirectory(registryRoot, { recursive: true });\n yield* Effect.forEach(existing, (relativePath) => {\n if (path.extname(relativePath) !== \".ts\") {\n return Effect.void;\n }\n const normalized = path.join(\"registeredFunctions\", relativePath);\n if (!expected.has(normalized)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(registryRoot, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst getGeneratedSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_SPEC_PATH);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_NODE_SPEC_PATH);\n});\n\nconst loadGeneratedSpec = Effect.gen(function* () {\n const specPath = yield* getGeneratedSpecPath;\n const { module: specModule } = yield* Bundler.bundle(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.dieMessage(\n \"_generated/spec.ts does not export a valid Convex Spec\",\n );\n }\n\n return spec;\n});\n\nconst loadGeneratedNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.dieMessage(\n \"_generated/nodeSpec.ts does not export a valid Node Spec\",\n );\n }\n\n return Option.some(nodeSpec);\n});\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getGeneratedSpecPath;\n\n if (!(yield* fs.exists(specPath))) {\n return emptyFunctionPaths;\n }\n\n const specEither = yield* loadGeneratedSpec.pipe(Effect.either);\n\n return yield* Either.match(specEither, {\n onLeft: () => Effect.succeed(emptyFunctionPaths),\n onRight: (spec) =>\n Effect.gen(function* () {\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n return FunctionPaths.make(mergedSpec);\n }),\n });\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* removePathIfExists(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const spec = yield* loadGeneratedSpec;\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nexport const validateSchema = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n if (!(yield* fs.exists(confectSchemaPath))) {\n return yield* new MissingSchemaFileError({ schemaPath: \"schema.ts\" });\n }\n\n yield* Bundler.bundle(confectSchemaPath).pipe(\n Effect.mapError((error) => fromBundlerError(\"schema.ts\", error)),\n Effect.andThen(({ module: schemaModule }) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isDatabaseSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.fail(\n new SchemaInvalidDefaultExportError({\n schemaPath: \"schema.ts\",\n }),\n );\n }),\n );\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n // `validateSchema` runs once at the top of `runCodegen`; no need to\n // bundle the schema again here.\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? Option.some(\n yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),\n )\n : Option.none<string>();\n\n const refsContents = yield* templates.refs({\n specImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
package/dist/package.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "9.0.0-next.0";
2
+ var version = "9.0.0-next.2";
3
3
 
4
4
  //#endregion
5
5
  export { version };
@@ -187,10 +187,13 @@ const writeGroupFactoryCall = (cbw, node, groupFactory) => Effect.gen(function*
187
187
  yield* cbw.write(")");
188
188
  yield* Effect.forEach(node.children, (child) => writeChildAddGroupAt(cbw, child, groupFactory));
189
189
  });
190
- const writeGroupAssembly = (cbw, node, groupFactory) => node.children.length === 0 ? Option.match(node.importBinding, {
190
+ const writeGroupAssembly = (cbw, node, groupFactory) => Option.match(node.importBinding, {
191
191
  onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),
192
- onSome: (binding) => cbw.write(binding.exportName)
193
- }) : writeGroupFactoryCall(cbw, node, groupFactory);
192
+ onSome: (binding) => Effect.gen(function* () {
193
+ yield* cbw.write(binding.localName);
194
+ yield* Effect.forEach(node.children, (child) => writeChildAddGroupAt(cbw, child, groupFactory));
195
+ })
196
+ });
194
197
  const writeRootAddAt = (cbw, node, groupFactory) => Effect.gen(function* () {
195
198
  yield* cbw.write(".addAt(");
196
199
  yield* cbw.quote(node.segment);
@@ -200,9 +203,10 @@ const writeRootAddAt = (cbw, node, groupFactory) => Effect.gen(function* () {
200
203
  });
201
204
  const assembledSpec = ({ nodes, runtime }) => Effect.gen(function* () {
202
205
  const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
203
- const needsGroupSpec = Array.some(nodes, (node) => node.children.length > 0);
206
+ const nodeRequiresGroupFactory = (node) => Option.isNone(node.importBinding) || Array.some(node.children, nodeRequiresGroupFactory);
207
+ const needsGroupSpec = Array.some(nodes, nodeRequiresGroupFactory);
204
208
  yield* cbw.writeLine(needsGroupSpec ? `import { GroupSpec, Spec } from "@confect/core";` : `import { Spec } from "@confect/core";`);
205
- yield* Effect.forEach(collectImportBindings(nodes), (binding) => cbw.writeLine(`import ${binding.exportName} from "${binding.importPath}";`));
209
+ yield* Effect.forEach(collectImportBindings(nodes), (binding) => cbw.writeLine(`import ${binding.localName} from "${binding.importPath}";`));
206
210
  yield* cbw.blankLine();
207
211
  const specFactory = runtime === "Convex" ? "Spec.make()" : "Spec.makeNode()";
208
212
  const groupFactory = runtime === "Convex" ? "GroupSpec.makeAt" : "GroupSpec.makeNodeAt";
@@ -1 +1 @@
1
- {"version":3,"file":"templates.mjs","names":[],"sources":["../src/templates.ts"],"sourcesContent":["import { Array, Effect, Option } from \"effect\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter\";\nimport {\n collectImportBindings,\n type SpecAssemblyNode,\n} from \"./SpecAssemblyNode\";\n\nexport const functions = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: string[];\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (functionName) =>\n cbw.writeLine(\n `export const ${functionName} = registeredFunctions.${functionName};`,\n ),\n );\n\n return yield* cbw.toString();\n });\n\nexport const schema = ({ schemaImportPath }: { schemaImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import schemaDefinition from \"${schemaImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(\n `export default schemaDefinition.convexSchemaDefinition;`,\n );\n\n return yield* cbw.toString();\n });\n\nexport const http = ({ httpImportPath }: { httpImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import http from \"${httpImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default http;`);\n\n return yield* cbw.toString();\n });\n\nexport const crons = ({ cronsImportPath }: { cronsImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import crons from \"${cronsImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default crons.convexCronJobs;`);\n\n return yield* cbw.toString();\n });\n\nexport const authConfig = ({ authImportPath }: { authImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import auth from \"${authImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default auth;`);\n\n return yield* cbw.toString();\n });\n\nexport const refs = ({\n specImportPath,\n nodeSpecImportPath,\n}: {\n specImportPath: string;\n nodeSpecImportPath: Option.Option<string>;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Refs } from \"@confect/core\";`);\n yield* cbw.writeLine(`import spec from \"${specImportPath}\";`);\n yield* Option.match(nodeSpecImportPath, {\n onNone: () => Effect.void,\n onSome: (nodeSpecImportPath_) =>\n cbw.writeLine(`import nodeSpec from \"${nodeSpecImportPath_}\";`),\n });\n yield* cbw.blankLine();\n yield* cbw.writeLine(\n Option.match(nodeSpecImportPath, {\n onSome: () => `export default Refs.make(spec, nodeSpec);`,\n onNone: () => `export default Refs.make(spec);`,\n }),\n );\n\n return yield* cbw.toString();\n });\n\nexport const api = ({\n schemaImportPath,\n specImportPath,\n}: {\n schemaImportPath: string;\n specImportPath: string;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Api } from \"@confect/server\";`);\n yield* cbw.writeLine(`import schema from \"${schemaImportPath}\";`);\n yield* cbw.writeLine(`import spec from \"${specImportPath}\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default Api.make(schema, spec);`);\n\n return yield* cbw.toString();\n });\n\nexport const nodeApi = ({\n schemaImportPath,\n nodeSpecImportPath,\n}: {\n schemaImportPath: string;\n nodeSpecImportPath: string;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Api } from \"@confect/server\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`import schema from \"${schemaImportPath}\";`);\n yield* cbw.writeLine(`import nodeSpec from \"${nodeSpecImportPath}\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default Api.make(schema, nodeSpec);`);\n\n return yield* cbw.toString();\n });\n\nexport const registeredFunctionsForGroup = ({\n apiImportPath,\n groupPathDot,\n implImportPath,\n layerExportName,\n useNode = false,\n}: {\n apiImportPath: string;\n groupPathDot: string;\n implImportPath: string;\n layerExportName: string;\n useNode?: boolean;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(\n `import { RegisteredFunctions } from \"@confect/server\";`,\n );\n yield* cbw.writeLine(\n `import { RegisteredNodeFunction } from \"@confect/server/node\";`,\n );\n } else {\n yield* cbw.writeLine(\n `import { RegisteredConvexFunction, RegisteredFunctions } from \"@confect/server\";`,\n );\n }\n\n yield* cbw.writeLine(`import api from \"${apiImportPath}\";`);\n yield* cbw.writeLine(`import ${layerExportName} from \"${implImportPath}\";`);\n yield* cbw.blankLine();\n const quotedGroupPath = `\"${groupPathDot.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n yield* cbw.writeLine(\n useNode\n ? `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredNodeFunction.make);`\n : `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredConvexFunction.make);`,\n );\n\n return yield* cbw.toString();\n });\n\nexport const services = ({ schemaImportPath }: { schemaImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n // Imports\n yield* cbw.writeLine(\"import {\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"ActionCtx as ActionCtx_,\");\n yield* cbw.writeLine(\"ActionRunner as ActionRunner_,\");\n yield* cbw.writeLine(\"Auth as Auth_,\");\n yield* cbw.writeLine(\"type DataModel,\");\n yield* cbw.writeLine(\"DatabaseReader as DatabaseReader_,\");\n yield* cbw.writeLine(\"DatabaseWriter as DatabaseWriter_,\");\n yield* cbw.writeLine(\"MutationCtx as MutationCtx_,\");\n yield* cbw.writeLine(\"MutationRunner as MutationRunner_,\");\n yield* cbw.writeLine(\"QueryCtx as QueryCtx_,\");\n yield* cbw.writeLine(\"QueryRunner as QueryRunner_,\");\n yield* cbw.writeLine(\"Scheduler as Scheduler_,\");\n yield* cbw.writeLine(\"StorageActionWriter as StorageActionWriter_,\");\n yield* cbw.writeLine(\"StorageReader as StorageReader_,\");\n yield* cbw.writeLine(\"StorageWriter as StorageWriter_,\");\n yield* cbw.writeLine(\"VectorSearch as VectorSearch_,\");\n }),\n );\n yield* cbw.writeLine(`} from \"@confect/server\";`);\n yield* cbw.writeLine(\n `import type schemaDefinition from \"${schemaImportPath}\";`,\n );\n yield* cbw.blankLine();\n\n // Auth\n yield* cbw.writeLine(\"export const Auth = Auth_.Auth;\");\n yield* cbw.writeLine(\"export type Auth = typeof Auth.Identifier;\");\n yield* cbw.blankLine();\n\n // Scheduler\n yield* cbw.writeLine(\"export const Scheduler = Scheduler_.Scheduler;\");\n yield* cbw.writeLine(\n \"export type Scheduler = typeof Scheduler.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageReader\n yield* cbw.writeLine(\n \"export const StorageReader = StorageReader_.StorageReader;\",\n );\n yield* cbw.writeLine(\n \"export type StorageReader = typeof StorageReader.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageWriter\n yield* cbw.writeLine(\n \"export const StorageWriter = StorageWriter_.StorageWriter;\",\n );\n yield* cbw.writeLine(\n \"export type StorageWriter = typeof StorageWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageActionWriter\n yield* cbw.writeLine(\n \"export const StorageActionWriter = StorageActionWriter_.StorageActionWriter;\",\n );\n yield* cbw.writeLine(\n \"export type StorageActionWriter = typeof StorageActionWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // VectorSearch\n yield* cbw.writeLine(\"export const VectorSearch =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"VectorSearch_.VectorSearch<DataModel.FromSchema<typeof schemaDefinition>>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type VectorSearch = typeof VectorSearch.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // DatabaseReader\n yield* cbw.writeLine(\"export const DatabaseReader =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DatabaseReader_.DatabaseReader<typeof schemaDefinition>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type DatabaseReader = typeof DatabaseReader.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // DatabaseWriter\n yield* cbw.writeLine(\"export const DatabaseWriter =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DatabaseWriter_.DatabaseWriter<typeof schemaDefinition>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type DatabaseWriter = typeof DatabaseWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // QueryRunner\n yield* cbw.writeLine(\n \"export const QueryRunner = QueryRunner_.QueryRunner;\",\n );\n yield* cbw.writeLine(\n \"export type QueryRunner = typeof QueryRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // MutationRunner\n yield* cbw.writeLine(\n \"export const MutationRunner = MutationRunner_.MutationRunner;\",\n );\n yield* cbw.writeLine(\n \"export type MutationRunner = typeof MutationRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // ActionRunner\n yield* cbw.writeLine(\n \"export const ActionRunner = ActionRunner_.ActionRunner;\",\n );\n yield* cbw.writeLine(\n \"export type ActionRunner = typeof ActionRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // QueryCtx\n yield* cbw.writeLine(\"export const QueryCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"QueryCtx_.QueryCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\"export type QueryCtx = typeof QueryCtx.Identifier;\");\n yield* cbw.blankLine();\n\n // MutationCtx\n yield* cbw.writeLine(\"export const MutationCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"MutationCtx_.MutationCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\n \"export type MutationCtx = typeof MutationCtx.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // ActionCtx\n yield* cbw.writeLine(\"export const ActionCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"ActionCtx_.ActionCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\n \"export type ActionCtx = typeof ActionCtx.Identifier;\",\n );\n\n return yield* cbw.toString();\n });\n\nconst writeChildAddGroupAt = (\n cbw: CodeBlockWriter,\n child: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(\".addGroupAt(\");\n yield* cbw.quote(child.segment);\n yield* cbw.write(\", \");\n yield* writeGroupAssembly(cbw, child, groupFactory);\n yield* cbw.write(\")\");\n });\n\nconst writeGroupFactoryCall = (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(groupFactory);\n yield* cbw.write(\"(\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\")\");\n\n yield* Effect.forEach(node.children, (child) =>\n writeChildAddGroupAt(cbw, child, groupFactory),\n );\n });\n\nconst writeGroupAssembly: (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n) => Effect.Effect<void> = (cbw, node, groupFactory) =>\n node.children.length === 0\n ? Option.match(node.importBinding, {\n onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),\n onSome: (binding) => cbw.write(binding.exportName),\n })\n : writeGroupFactoryCall(cbw, node, groupFactory);\n\nconst writeRootAddAt = (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(\".addAt(\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\", \");\n\n yield* writeGroupAssembly(cbw, node, groupFactory);\n\n yield* cbw.write(\")\");\n });\n\nexport const assembledSpec = ({\n nodes,\n runtime,\n}: {\n nodes: ReadonlyArray<SpecAssemblyNode>;\n runtime: \"Convex\" | \"Node\";\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n const needsGroupSpec = Array.some(\n nodes,\n (node) => node.children.length > 0,\n );\n yield* cbw.writeLine(\n needsGroupSpec\n ? `import { GroupSpec, Spec } from \"@confect/core\";`\n : `import { Spec } from \"@confect/core\";`,\n );\n\n yield* Effect.forEach(collectImportBindings(nodes), (binding) =>\n cbw.writeLine(\n `import ${binding.exportName} from \"${binding.importPath}\";`,\n ),\n );\n\n yield* cbw.blankLine();\n\n const specFactory =\n runtime === \"Convex\" ? \"Spec.make()\" : \"Spec.makeNode()\";\n const groupFactory =\n runtime === \"Convex\" ? \"GroupSpec.makeAt\" : \"GroupSpec.makeNodeAt\";\n\n yield* cbw.write(`export default ${specFactory}`);\n yield* Effect.forEach(nodes, (node) =>\n writeRootAddAt(cbw, node, groupFactory),\n );\n yield* cbw.write(\";\");\n yield* cbw.newLine();\n\n return yield* cbw.toString();\n });\n"],"mappings":";;;;;AAOA,MAAa,aAAa,EACxB,eACA,+BACA,UAAU,YAMV,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,KAAI,SAAS;AACX,SAAO,IAAI,UAAU,cAAc;AACnC,SAAO,IAAI,WAAW;;AAGxB,QAAO,IAAI,UACT,oCAAoC,8BAA8B,IACnE;AACD,QAAO,IAAI,SAAS;AACpB,QAAO,OAAO,QAAQ,gBAAgB,iBACpC,IAAI,UACF,gBAAgB,aAAa,yBAAyB,aAAa,GACpE,CACF;AAED,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,UAAU,EAAE,uBACvB,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,iCAAiC,iBAAiB,IAAI;AAC3E,QAAO,IAAI,SAAS;AACpB,QAAO,IAAI,UACT,0DACD;AAED,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,QAAQ,EAAE,qBACrB,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,qBAAqB,eAAe,IAAI;AAC7D,QAAO,IAAI,SAAS;AACpB,QAAO,IAAI,UAAU,uBAAuB;AAE5C,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,SAAS,EAAE,sBACtB,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,sBAAsB,gBAAgB,IAAI;AAC/D,QAAO,IAAI,SAAS;AACpB,QAAO,IAAI,UAAU,uCAAuC;AAE5D,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,cAAc,EAAE,qBAC3B,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,qBAAqB,eAAe,IAAI;AAC7D,QAAO,IAAI,SAAS;AACpB,QAAO,IAAI,UAAU,uBAAuB;AAE5C,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,QAAQ,EACnB,gBACA,yBAKA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,wCAAwC;AAC7D,QAAO,IAAI,UAAU,qBAAqB,eAAe,IAAI;AAC7D,QAAO,OAAO,MAAM,oBAAoB;EACtC,cAAc,OAAO;EACrB,SAAS,wBACP,IAAI,UAAU,yBAAyB,oBAAoB,IAAI;EAClE,CAAC;AACF,QAAO,IAAI,WAAW;AACtB,QAAO,IAAI,UACT,OAAO,MAAM,oBAAoB;EAC/B,cAAc;EACd,cAAc;EACf,CAAC,CACH;AAED,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,OAAO,EAClB,kBACA,qBAKA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,yCAAyC;AAC9D,QAAO,IAAI,UAAU,uBAAuB,iBAAiB,IAAI;AACjE,QAAO,IAAI,UAAU,qBAAqB,eAAe,IAAI;AAC7D,QAAO,IAAI,WAAW;AACtB,QAAO,IAAI,UAAU,yCAAyC;AAE9D,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,WAAW,EACtB,kBACA,yBAKA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,QAAO,IAAI,UAAU,yCAAyC;AAC9D,QAAO,IAAI,WAAW;AACtB,QAAO,IAAI,UAAU,uBAAuB,iBAAiB,IAAI;AACjE,QAAO,IAAI,UAAU,yBAAyB,mBAAmB,IAAI;AACrE,QAAO,IAAI,WAAW;AACtB,QAAO,IAAI,UAAU,6CAA6C;AAElE,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,+BAA+B,EAC1C,eACA,cACA,gBACA,iBACA,UAAU,YAQV,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAE5D,KAAI,SAAS;AACX,SAAO,IAAI,UACT,yDACD;AACD,SAAO,IAAI,UACT,iEACD;OAED,QAAO,IAAI,UACT,mFACD;AAGH,QAAO,IAAI,UAAU,oBAAoB,cAAc,IAAI;AAC3D,QAAO,IAAI,UAAU,UAAU,gBAAgB,SAAS,eAAe,IAAI;AAC3E,QAAO,IAAI,WAAW;CACtB,MAAM,kBAAkB,IAAI,aAAa,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,OAAM,CAAC;AACrF,QAAO,IAAI,UACT,UACI,yDAAyD,gBAAgB,IAAI,gBAAgB,mCAC7F,yDAAyD,gBAAgB,IAAI,gBAAgB,mCAClG;AAED,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAa,YAAY,EAAE,uBACzB,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;AAG5D,QAAO,IAAI,UAAU,WAAW;AAChC,QAAO,IAAI,OACT,OAAO,IAAI,aAAa;AACtB,SAAO,IAAI,UAAU,2BAA2B;AAChD,SAAO,IAAI,UAAU,iCAAiC;AACtD,SAAO,IAAI,UAAU,iBAAiB;AACtC,SAAO,IAAI,UAAU,kBAAkB;AACvC,SAAO,IAAI,UAAU,qCAAqC;AAC1D,SAAO,IAAI,UAAU,qCAAqC;AAC1D,SAAO,IAAI,UAAU,+BAA+B;AACpD,SAAO,IAAI,UAAU,qCAAqC;AAC1D,SAAO,IAAI,UAAU,yBAAyB;AAC9C,SAAO,IAAI,UAAU,+BAA+B;AACpD,SAAO,IAAI,UAAU,2BAA2B;AAChD,SAAO,IAAI,UAAU,+CAA+C;AACpE,SAAO,IAAI,UAAU,mCAAmC;AACxD,SAAO,IAAI,UAAU,mCAAmC;AACxD,SAAO,IAAI,UAAU,iCAAiC;GACtD,CACH;AACD,QAAO,IAAI,UAAU,4BAA4B;AACjD,QAAO,IAAI,UACT,sCAAsC,iBAAiB,IACxD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,kCAAkC;AACvD,QAAO,IAAI,UAAU,6CAA6C;AAClE,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,iDAAiD;AACtE,QAAO,IAAI,UACT,uDACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,6DACD;AACD,QAAO,IAAI,UACT,+DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,6DACD;AACD,QAAO,IAAI,UACT,+DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,+EACD;AACD,QAAO,IAAI,UACT,2EACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,8BAA8B;AACnD,QAAO,IAAI,OACT,IAAI,UACF,+EACD,CACF;AACD,QAAO,IAAI,UACT,6DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,gCAAgC;AACrD,QAAO,IAAI,OACT,IAAI,UACF,6DACD,CACF;AACD,QAAO,IAAI,UACT,iEACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,gCAAgC;AACrD,QAAO,IAAI,OACT,IAAI,UACF,6DACD,CACF;AACD,QAAO,IAAI,UACT,iEACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,uDACD;AACD,QAAO,IAAI,UACT,2DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,gEACD;AACD,QAAO,IAAI,UACT,iEACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UACT,0DACD;AACD,QAAO,IAAI,UACT,6DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,0BAA0B;AAC/C,QAAO,IAAI,OACT,OAAO,IAAI,aAAa;AACtB,SAAO,IAAI,UAAU,sBAAsB;AAC3C,SAAO,IAAI,OACT,IAAI,UACF,oEACD,CACF;AACD,SAAO,IAAI,UAAU,OAAO;GAC5B,CACH;AACD,QAAO,IAAI,UAAU,qDAAqD;AAC1E,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,6BAA6B;AAClD,QAAO,IAAI,OACT,OAAO,IAAI,aAAa;AACtB,SAAO,IAAI,UAAU,4BAA4B;AACjD,SAAO,IAAI,OACT,IAAI,UACF,oEACD,CACF;AACD,SAAO,IAAI,UAAU,OAAO;GAC5B,CACH;AACD,QAAO,IAAI,UACT,2DACD;AACD,QAAO,IAAI,WAAW;AAGtB,QAAO,IAAI,UAAU,2BAA2B;AAChD,QAAO,IAAI,OACT,OAAO,IAAI,aAAa;AACtB,SAAO,IAAI,UAAU,wBAAwB;AAC7C,SAAO,IAAI,OACT,IAAI,UACF,oEACD,CACF;AACD,SAAO,IAAI,UAAU,OAAO;GAC5B,CACH;AACD,QAAO,IAAI,UACT,uDACD;AAED,QAAO,OAAO,IAAI,UAAU;EAC5B;AAEJ,MAAM,wBACJ,KACA,OACA,iBAEA,OAAO,IAAI,aAAa;AACtB,QAAO,IAAI,MAAM,eAAe;AAChC,QAAO,IAAI,MAAM,MAAM,QAAQ;AAC/B,QAAO,IAAI,MAAM,KAAK;AACtB,QAAO,mBAAmB,KAAK,OAAO,aAAa;AACnD,QAAO,IAAI,MAAM,IAAI;EACrB;AAEJ,MAAM,yBACJ,KACA,MACA,iBAEA,OAAO,IAAI,aAAa;AACtB,QAAO,IAAI,MAAM,aAAa;AAC9B,QAAO,IAAI,MAAM,IAAI;AACrB,QAAO,IAAI,MAAM,KAAK,QAAQ;AAC9B,QAAO,IAAI,MAAM,IAAI;AAErB,QAAO,OAAO,QAAQ,KAAK,WAAW,UACpC,qBAAqB,KAAK,OAAO,aAAa,CAC/C;EACD;AAEJ,MAAM,sBAIsB,KAAK,MAAM,iBACrC,KAAK,SAAS,WAAW,IACrB,OAAO,MAAM,KAAK,eAAe;CAC/B,cAAc,sBAAsB,KAAK,MAAM,aAAa;CAC5D,SAAS,YAAY,IAAI,MAAM,QAAQ,WAAW;CACnD,CAAC,GACF,sBAAsB,KAAK,MAAM,aAAa;AAEpD,MAAM,kBACJ,KACA,MACA,iBAEA,OAAO,IAAI,aAAa;AACtB,QAAO,IAAI,MAAM,UAAU;AAC3B,QAAO,IAAI,MAAM,KAAK,QAAQ;AAC9B,QAAO,IAAI,MAAM,KAAK;AAEtB,QAAO,mBAAmB,KAAK,MAAM,aAAa;AAElD,QAAO,IAAI,MAAM,IAAI;EACrB;AAEJ,MAAa,iBAAiB,EAC5B,OACA,cAKA,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,IAAI,gBAAgB,EAAE,sBAAsB,GAAG,CAAC;CAE5D,MAAM,iBAAiB,MAAM,KAC3B,QACC,SAAS,KAAK,SAAS,SAAS,EAClC;AACD,QAAO,IAAI,UACT,iBACI,qDACA,wCACL;AAED,QAAO,OAAO,QAAQ,sBAAsB,MAAM,GAAG,YACnD,IAAI,UACF,UAAU,QAAQ,WAAW,SAAS,QAAQ,WAAW,IAC1D,CACF;AAED,QAAO,IAAI,WAAW;CAEtB,MAAM,cACJ,YAAY,WAAW,gBAAgB;CACzC,MAAM,eACJ,YAAY,WAAW,qBAAqB;AAE9C,QAAO,IAAI,MAAM,kBAAkB,cAAc;AACjD,QAAO,OAAO,QAAQ,QAAQ,SAC5B,eAAe,KAAK,MAAM,aAAa,CACxC;AACD,QAAO,IAAI,MAAM,IAAI;AACrB,QAAO,IAAI,SAAS;AAEpB,QAAO,OAAO,IAAI,UAAU;EAC5B"}
1
+ {"version":3,"file":"templates.mjs","names":[],"sources":["../src/templates.ts"],"sourcesContent":["import { Array, Effect, Option } from \"effect\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter\";\nimport {\n collectImportBindings,\n type SpecAssemblyNode,\n} from \"./SpecAssemblyNode\";\n\nexport const functions = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: string[];\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (functionName) =>\n cbw.writeLine(\n `export const ${functionName} = registeredFunctions.${functionName};`,\n ),\n );\n\n return yield* cbw.toString();\n });\n\nexport const schema = ({ schemaImportPath }: { schemaImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import schemaDefinition from \"${schemaImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(\n `export default schemaDefinition.convexSchemaDefinition;`,\n );\n\n return yield* cbw.toString();\n });\n\nexport const http = ({ httpImportPath }: { httpImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import http from \"${httpImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default http;`);\n\n return yield* cbw.toString();\n });\n\nexport const crons = ({ cronsImportPath }: { cronsImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import crons from \"${cronsImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default crons.convexCronJobs;`);\n\n return yield* cbw.toString();\n });\n\nexport const authConfig = ({ authImportPath }: { authImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import auth from \"${authImportPath}\";`);\n yield* cbw.newLine();\n yield* cbw.writeLine(`export default auth;`);\n\n return yield* cbw.toString();\n });\n\nexport const refs = ({\n specImportPath,\n nodeSpecImportPath,\n}: {\n specImportPath: string;\n nodeSpecImportPath: Option.Option<string>;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Refs } from \"@confect/core\";`);\n yield* cbw.writeLine(`import spec from \"${specImportPath}\";`);\n yield* Option.match(nodeSpecImportPath, {\n onNone: () => Effect.void,\n onSome: (nodeSpecImportPath_) =>\n cbw.writeLine(`import nodeSpec from \"${nodeSpecImportPath_}\";`),\n });\n yield* cbw.blankLine();\n yield* cbw.writeLine(\n Option.match(nodeSpecImportPath, {\n onSome: () => `export default Refs.make(spec, nodeSpec);`,\n onNone: () => `export default Refs.make(spec);`,\n }),\n );\n\n return yield* cbw.toString();\n });\n\nexport const api = ({\n schemaImportPath,\n specImportPath,\n}: {\n schemaImportPath: string;\n specImportPath: string;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Api } from \"@confect/server\";`);\n yield* cbw.writeLine(`import schema from \"${schemaImportPath}\";`);\n yield* cbw.writeLine(`import spec from \"${specImportPath}\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default Api.make(schema, spec);`);\n\n return yield* cbw.toString();\n });\n\nexport const nodeApi = ({\n schemaImportPath,\n nodeSpecImportPath,\n}: {\n schemaImportPath: string;\n nodeSpecImportPath: string;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n yield* cbw.writeLine(`import { Api } from \"@confect/server\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`import schema from \"${schemaImportPath}\";`);\n yield* cbw.writeLine(`import nodeSpec from \"${nodeSpecImportPath}\";`);\n yield* cbw.blankLine();\n yield* cbw.writeLine(`export default Api.make(schema, nodeSpec);`);\n\n return yield* cbw.toString();\n });\n\nexport const registeredFunctionsForGroup = ({\n apiImportPath,\n groupPathDot,\n implImportPath,\n layerExportName,\n useNode = false,\n}: {\n apiImportPath: string;\n groupPathDot: string;\n implImportPath: string;\n layerExportName: string;\n useNode?: boolean;\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(\n `import { RegisteredFunctions } from \"@confect/server\";`,\n );\n yield* cbw.writeLine(\n `import { RegisteredNodeFunction } from \"@confect/server/node\";`,\n );\n } else {\n yield* cbw.writeLine(\n `import { RegisteredConvexFunction, RegisteredFunctions } from \"@confect/server\";`,\n );\n }\n\n yield* cbw.writeLine(`import api from \"${apiImportPath}\";`);\n yield* cbw.writeLine(`import ${layerExportName} from \"${implImportPath}\";`);\n yield* cbw.blankLine();\n const quotedGroupPath = `\"${groupPathDot.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n yield* cbw.writeLine(\n useNode\n ? `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredNodeFunction.make);`\n : `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredConvexFunction.make);`,\n );\n\n return yield* cbw.toString();\n });\n\nexport const services = ({ schemaImportPath }: { schemaImportPath: string }) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n // Imports\n yield* cbw.writeLine(\"import {\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"ActionCtx as ActionCtx_,\");\n yield* cbw.writeLine(\"ActionRunner as ActionRunner_,\");\n yield* cbw.writeLine(\"Auth as Auth_,\");\n yield* cbw.writeLine(\"type DataModel,\");\n yield* cbw.writeLine(\"DatabaseReader as DatabaseReader_,\");\n yield* cbw.writeLine(\"DatabaseWriter as DatabaseWriter_,\");\n yield* cbw.writeLine(\"MutationCtx as MutationCtx_,\");\n yield* cbw.writeLine(\"MutationRunner as MutationRunner_,\");\n yield* cbw.writeLine(\"QueryCtx as QueryCtx_,\");\n yield* cbw.writeLine(\"QueryRunner as QueryRunner_,\");\n yield* cbw.writeLine(\"Scheduler as Scheduler_,\");\n yield* cbw.writeLine(\"StorageActionWriter as StorageActionWriter_,\");\n yield* cbw.writeLine(\"StorageReader as StorageReader_,\");\n yield* cbw.writeLine(\"StorageWriter as StorageWriter_,\");\n yield* cbw.writeLine(\"VectorSearch as VectorSearch_,\");\n }),\n );\n yield* cbw.writeLine(`} from \"@confect/server\";`);\n yield* cbw.writeLine(\n `import type schemaDefinition from \"${schemaImportPath}\";`,\n );\n yield* cbw.blankLine();\n\n // Auth\n yield* cbw.writeLine(\"export const Auth = Auth_.Auth;\");\n yield* cbw.writeLine(\"export type Auth = typeof Auth.Identifier;\");\n yield* cbw.blankLine();\n\n // Scheduler\n yield* cbw.writeLine(\"export const Scheduler = Scheduler_.Scheduler;\");\n yield* cbw.writeLine(\n \"export type Scheduler = typeof Scheduler.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageReader\n yield* cbw.writeLine(\n \"export const StorageReader = StorageReader_.StorageReader;\",\n );\n yield* cbw.writeLine(\n \"export type StorageReader = typeof StorageReader.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageWriter\n yield* cbw.writeLine(\n \"export const StorageWriter = StorageWriter_.StorageWriter;\",\n );\n yield* cbw.writeLine(\n \"export type StorageWriter = typeof StorageWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // StorageActionWriter\n yield* cbw.writeLine(\n \"export const StorageActionWriter = StorageActionWriter_.StorageActionWriter;\",\n );\n yield* cbw.writeLine(\n \"export type StorageActionWriter = typeof StorageActionWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // VectorSearch\n yield* cbw.writeLine(\"export const VectorSearch =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"VectorSearch_.VectorSearch<DataModel.FromSchema<typeof schemaDefinition>>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type VectorSearch = typeof VectorSearch.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // DatabaseReader\n yield* cbw.writeLine(\"export const DatabaseReader =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DatabaseReader_.DatabaseReader<typeof schemaDefinition>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type DatabaseReader = typeof DatabaseReader.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // DatabaseWriter\n yield* cbw.writeLine(\"export const DatabaseWriter =\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DatabaseWriter_.DatabaseWriter<typeof schemaDefinition>();\",\n ),\n );\n yield* cbw.writeLine(\n \"export type DatabaseWriter = typeof DatabaseWriter.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // QueryRunner\n yield* cbw.writeLine(\n \"export const QueryRunner = QueryRunner_.QueryRunner;\",\n );\n yield* cbw.writeLine(\n \"export type QueryRunner = typeof QueryRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // MutationRunner\n yield* cbw.writeLine(\n \"export const MutationRunner = MutationRunner_.MutationRunner;\",\n );\n yield* cbw.writeLine(\n \"export type MutationRunner = typeof MutationRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // ActionRunner\n yield* cbw.writeLine(\n \"export const ActionRunner = ActionRunner_.ActionRunner;\",\n );\n yield* cbw.writeLine(\n \"export type ActionRunner = typeof ActionRunner.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // QueryCtx\n yield* cbw.writeLine(\"export const QueryCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"QueryCtx_.QueryCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\"export type QueryCtx = typeof QueryCtx.Identifier;\");\n yield* cbw.blankLine();\n\n // MutationCtx\n yield* cbw.writeLine(\"export const MutationCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"MutationCtx_.MutationCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\n \"export type MutationCtx = typeof MutationCtx.Identifier;\",\n );\n yield* cbw.blankLine();\n\n // ActionCtx\n yield* cbw.writeLine(\"export const ActionCtx =\");\n yield* cbw.indent(\n Effect.gen(function* () {\n yield* cbw.writeLine(\"ActionCtx_.ActionCtx<\");\n yield* cbw.indent(\n cbw.writeLine(\n \"DataModel.ToConvex<DataModel.FromSchema<typeof schemaDefinition>>\",\n ),\n );\n yield* cbw.writeLine(\">();\");\n }),\n );\n yield* cbw.writeLine(\n \"export type ActionCtx = typeof ActionCtx.Identifier;\",\n );\n\n return yield* cbw.toString();\n });\n\nconst writeChildAddGroupAt = (\n cbw: CodeBlockWriter,\n child: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(\".addGroupAt(\");\n yield* cbw.quote(child.segment);\n yield* cbw.write(\", \");\n yield* writeGroupAssembly(cbw, child, groupFactory);\n yield* cbw.write(\")\");\n });\n\nconst writeGroupFactoryCall = (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(groupFactory);\n yield* cbw.write(\"(\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\")\");\n\n yield* Effect.forEach(node.children, (child) =>\n writeChildAddGroupAt(cbw, child, groupFactory),\n );\n });\n\nconst writeGroupAssembly: (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n) => Effect.Effect<void> = (cbw, node, groupFactory) =>\n Option.match(node.importBinding, {\n onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),\n onSome: (binding) =>\n Effect.gen(function* () {\n yield* cbw.write(binding.localName);\n yield* Effect.forEach(node.children, (child) =>\n writeChildAddGroupAt(cbw, child, groupFactory),\n );\n }),\n });\n\nconst writeRootAddAt = (\n cbw: CodeBlockWriter,\n node: SpecAssemblyNode,\n groupFactory: string,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* cbw.write(\".addAt(\");\n yield* cbw.quote(node.segment);\n yield* cbw.write(\", \");\n\n yield* writeGroupAssembly(cbw, node, groupFactory);\n\n yield* cbw.write(\")\");\n });\n\nexport const assembledSpec = ({\n nodes,\n runtime,\n}: {\n nodes: ReadonlyArray<SpecAssemblyNode>;\n runtime: \"Convex\" | \"Node\";\n}) =>\n Effect.gen(function* () {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n const nodeRequiresGroupFactory = (node: SpecAssemblyNode): boolean =>\n Option.isNone(node.importBinding) ||\n Array.some(node.children, nodeRequiresGroupFactory);\n\n const needsGroupSpec = Array.some(nodes, nodeRequiresGroupFactory);\n yield* cbw.writeLine(\n needsGroupSpec\n ? `import { GroupSpec, Spec } from \"@confect/core\";`\n : `import { Spec } from \"@confect/core\";`,\n );\n\n yield* Effect.forEach(collectImportBindings(nodes), (binding) =>\n cbw.writeLine(\n `import ${binding.localName} from \"${binding.importPath}\";`,\n ),\n );\n\n yield* cbw.blankLine();\n\n const specFactory =\n runtime === \"Convex\" ? \"Spec.make()\" : \"Spec.makeNode()\";\n const groupFactory =\n runtime === \"Convex\" ? \"GroupSpec.makeAt\" : \"GroupSpec.makeNodeAt\";\n\n yield* cbw.write(`export default ${specFactory}`);\n yield* Effect.forEach(nodes, (node) =>\n writeRootAddAt(cbw, node, groupFactory),\n );\n yield* cbw.write(\";\");\n yield* cbw.newLine();\n\n return yield* cbw.toString();\n });\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@confect/cli",
3
- "version": "9.0.0-next.0",
3
+ "version": "9.0.0-next.2",
4
4
  "description": "Developer tooling for codegen and sync",
5
5
  "repository": {
6
6
  "type": "git",
@@ -65,8 +65,8 @@
65
65
  },
66
66
  "peerDependencies": {
67
67
  "effect": "^3.21.2",
68
- "@confect/core": "^9.0.0-next.0",
69
- "@confect/server": "^9.0.0-next.0"
68
+ "@confect/core": "^9.0.0-next.2",
69
+ "@confect/server": "^9.0.0-next.2"
70
70
  },
71
71
  "engines": {
72
72
  "node": ">=22",
@@ -75,6 +75,16 @@ export class SchemaInvalidDefaultExportError extends Schema.TaggedError<SchemaIn
75
75
  },
76
76
  ) {}
77
77
 
78
+ export class ParentChildNameCollisionError extends Schema.TaggedError<ParentChildNameCollisionError>()(
79
+ "ParentChildNameCollisionError",
80
+ {
81
+ parentSpecPath: Schema.String,
82
+ childSpecPath: Schema.String,
83
+ collisionName: Schema.String,
84
+ collisionKind: Schema.Literal("function", "group"),
85
+ },
86
+ ) {}
87
+
78
88
  export class MissingSchemaFileError extends Schema.TaggedError<MissingSchemaFileError>()(
79
89
  "MissingSchemaFileError",
80
90
  {
@@ -94,6 +104,7 @@ export const CodegenError = Schema.Union(
94
104
  ImplMissingFunctionsError,
95
105
  SchemaInvalidDefaultExportError,
96
106
  MissingSchemaFileError,
107
+ ParentChildNameCollisionError,
97
108
  );
98
109
  export type CodegenError = typeof CodegenError.Type;
99
110
 
@@ -246,6 +257,21 @@ const renderMissingSchemaFileError = (
246
257
  ),
247
258
  );
248
259
 
260
+ const renderParentChildNameCollisionError = (
261
+ error: ParentChildNameCollisionError,
262
+ ): AnsiDoc.AnsiDoc =>
263
+ singleLine(
264
+ AnsiDoc.text("Spec "),
265
+ formatPathDoc(error.parentSpecPath),
266
+ AnsiDoc.text(
267
+ ` declares a ${error.collisionKind} \`${error.collisionName}\` whose name collides with the sibling subdirectory spec `,
268
+ ),
269
+ formatPathDoc(error.childSpecPath),
270
+ AnsiDoc.text(
271
+ `. Rename one of them so the assembled spec has a unique key at this path.`,
272
+ ),
273
+ );
274
+
249
275
  /**
250
276
  * Render any {@link CodegenError} into a styled, ready-to-print string.
251
277
  * Single-error variants render to a one-line `✘`-prefixed message;
@@ -306,6 +332,12 @@ export const renderCodegenError = (error: CodegenError): string => {
306
332
  AnsiDoc.render({ style: "pretty" }),
307
333
  ),
308
334
  ),
335
+ Match.tag("ParentChildNameCollisionError", (e) =>
336
+ pipe(
337
+ renderParentChildNameCollisionError(e),
338
+ AnsiDoc.render({ style: "pretty" }),
339
+ ),
340
+ ),
309
341
  Match.exhaustive,
310
342
  );
311
343
  };
package/src/LeafModule.ts CHANGED
@@ -194,7 +194,9 @@ const absoluteModulePath = (relativePath: string) =>
194
194
  /**
195
195
  * Validate that the leaf's spec file default-exports a `GroupSpec` whose
196
196
  * runtime matches the leaf's location (`Convex` for files outside
197
- * `confect/node/`, `Node` for files inside it).
197
+ * `confect/node/`, `Node` for files inside it). Returns the validated
198
+ * `GroupSpec` so callers can avoid re-bundling for later inspection (e.g.
199
+ * parent/child name-collision checks at codegen time).
198
200
  */
199
201
  export const validateSpec = (leaf: LeafModule) =>
200
202
  Effect.gen(function* () {
@@ -218,6 +220,8 @@ export const validateSpec = (leaf: LeafModule) =>
218
220
  actualRuntime: groupSpec.runtime,
219
221
  });
220
222
  }
223
+
224
+ return groupSpec;
221
225
  });
222
226
 
223
227
  /**
@@ -4,6 +4,7 @@ import { Array, Option, Order, pipe, Record } from "effect";
4
4
  export interface SpecImportBinding {
5
5
  readonly importPath: string;
6
6
  readonly exportName: string;
7
+ readonly localName: string;
7
8
  }
8
9
 
9
10
  export interface SpecAssemblyNode {
@@ -15,6 +16,7 @@ export interface SpecAssemblyNode {
15
16
  const importBindingFromLeaf = (leaf: LeafModule): SpecImportBinding => ({
16
17
  importPath: leaf.specImportPath,
17
18
  exportName: leaf.exportName,
19
+ localName: leaf.pathSegments.join("_"),
18
20
  });
19
21
 
20
22
  const assemblyNodesAtDepth = (
@@ -75,8 +77,8 @@ export const collectImportBindings = (
75
77
  pipe(
76
78
  Array.flatMap(nodes, importBindingsForNode),
77
79
  (bindings) =>
78
- Record.fromIterableBy(bindings, (binding) => binding.exportName),
80
+ Record.fromIterableBy(bindings, (binding) => binding.importPath),
79
81
  Record.toEntries,
80
- Array.sortBy(Order.mapInput(Order.string, ([exportName]) => exportName)),
81
82
  Array.map(([, binding]) => binding),
83
+ Array.sortBy(Order.mapInput(Order.string, (binding) => binding.localName)),
82
84
  );
@@ -1,4 +1,4 @@
1
- import { Spec } from "@confect/core";
1
+ import { type GroupSpec, Spec } from "@confect/core";
2
2
  import * as DatabaseSchema from "@confect/server/DatabaseSchema";
3
3
  import { Command } from "@effect/cli";
4
4
  import { FileSystem, Path } from "@effect/platform";
@@ -9,6 +9,7 @@ import {
9
9
  MissingImplFileError,
10
10
  MissingSchemaFileError,
11
11
  MissingSpecFileError,
12
+ ParentChildNameCollisionError,
12
13
  SchemaInvalidDefaultExportError,
13
14
  } from "../CodegenError";
14
15
  import { ConfectDirectory } from "../ConfectDirectory";
@@ -36,6 +37,7 @@ import {
36
37
  import {
37
38
  assemblyNodesFromLeaves,
38
39
  partitionByRuntime,
40
+ type SpecAssemblyNode,
39
41
  } from "../SpecAssemblyNode";
40
42
  import * as templates from "../templates";
41
43
  import * as Bundler from "../Bundler";
@@ -101,8 +103,10 @@ const runCodegen = Effect.gen(function* () {
101
103
  // on schema via `_generated/api.ts` and would otherwise blow up with a
102
104
  // less actionable bundler error.
103
105
  yield* validateSchema;
104
- const leaves = yield* loadAndValidateLeafModules;
106
+ const { leaves, groupSpecsByRelativePath } =
107
+ yield* loadAndValidateLeafModules;
105
108
  yield* removeLegacyFiles;
109
+ yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);
106
110
  yield* generateAssembledSpecs(leaves);
107
111
  yield* validateImplModules(leaves);
108
112
  yield* generateGroupRegisteredFunctions(leaves);
@@ -144,10 +148,10 @@ const loadAndValidateLeafModules = Effect.gen(function* () {
144
148
  const confectDirectory = yield* ConfectDirectory.get;
145
149
  const specFiles = yield* discoverLeafSpecFiles;
146
150
 
147
- const leaves = yield* Effect.forEach(specFiles, (specRelativePath) =>
151
+ const results = yield* Effect.forEach(specFiles, (specRelativePath) =>
148
152
  Effect.gen(function* () {
149
153
  const leaf = yield* toLeafModule(specRelativePath);
150
- yield* validateSpec(leaf);
154
+ const groupSpec = yield* validateSpec(leaf);
151
155
 
152
156
  const implRelativePath = yield* implPathForSpec(specRelativePath);
153
157
  const implAbsolutePath = path.join(confectDirectory, implRelativePath);
@@ -158,15 +162,132 @@ const loadAndValidateLeafModules = Effect.gen(function* () {
158
162
  });
159
163
  }
160
164
 
161
- return leaf;
165
+ return { leaf, groupSpec };
162
166
  }),
163
167
  );
164
168
 
165
169
  yield* validateOrphanImpls(specFiles);
166
170
 
167
- return leaves;
171
+ const leaves = Array.map(results, ({ leaf }) => leaf);
172
+ const groupSpecsByRelativePath = new Map(
173
+ Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),
174
+ );
175
+
176
+ return { leaves, groupSpecsByRelativePath };
168
177
  });
169
178
 
179
+ /**
180
+ * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}
181
+ * when a parent leaf declares a function or subgroup whose name matches a
182
+ * sibling subdirectory spec's segment. Without this check the colliding
183
+ * descendant would overwrite the parent's entry in the assembled
184
+ * `GroupSpec.groups` map at runtime, surfacing as a confusing
185
+ * `Refs.make` error rather than a codegen-time diagnostic.
186
+ */
187
+ export const validateNoParentChildNameCollisions = (
188
+ leaves: ReadonlyArray<LeafModule>,
189
+ groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,
190
+ ) =>
191
+ Effect.gen(function* () {
192
+ const { convex, node } = partitionByRuntime(leaves);
193
+ const convexNodes = assemblyNodesFromLeaves(convex);
194
+ const nodeNodes = assemblyNodesFromLeaves(
195
+ Array.map(node, toNodeRegistryLeaf),
196
+ );
197
+ yield* Effect.forEach(convexNodes, (n) =>
198
+ checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),
199
+ );
200
+ yield* Effect.forEach(nodeNodes, (n) =>
201
+ checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),
202
+ );
203
+ });
204
+
205
+ const checkAssemblyNodeForCollisions = (
206
+ node: SpecAssemblyNode,
207
+ groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,
208
+ ): Effect.Effect<void, ParentChildNameCollisionError> =>
209
+ Effect.gen(function* () {
210
+ yield* Option.match(node.importBinding, {
211
+ onNone: () => Effect.void,
212
+ onSome: (binding) =>
213
+ Effect.gen(function* () {
214
+ if (node.children.length === 0) return;
215
+ const parentRelativePath = bindingToRelativeSpecPath(
216
+ binding.importPath,
217
+ );
218
+ const parentGroupSpec =
219
+ groupSpecsByRelativePath.get(parentRelativePath);
220
+ if (parentGroupSpec === undefined) return;
221
+ yield* Effect.forEach(node.children, (child) => {
222
+ if (
223
+ Object.prototype.hasOwnProperty.call(
224
+ parentGroupSpec.functions,
225
+ child.segment,
226
+ )
227
+ ) {
228
+ return Effect.fail(
229
+ new ParentChildNameCollisionError({
230
+ parentSpecPath: parentRelativePath,
231
+ childSpecPath: childRepresentativeSpecPath(child),
232
+ collisionName: child.segment,
233
+ collisionKind: "function",
234
+ }),
235
+ );
236
+ }
237
+ if (
238
+ Object.prototype.hasOwnProperty.call(
239
+ parentGroupSpec.groups,
240
+ child.segment,
241
+ )
242
+ ) {
243
+ return Effect.fail(
244
+ new ParentChildNameCollisionError({
245
+ parentSpecPath: parentRelativePath,
246
+ childSpecPath: childRepresentativeSpecPath(child),
247
+ collisionName: child.segment,
248
+ collisionKind: "group",
249
+ }),
250
+ );
251
+ }
252
+ return Effect.void;
253
+ });
254
+ }),
255
+ });
256
+ yield* Effect.forEach(node.children, (child) =>
257
+ checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),
258
+ );
259
+ });
260
+
261
+ /**
262
+ * `LeafModule.specImportPath` is the import path used from inside the
263
+ * generated `_generated/spec.ts` (e.g. `"../notes.spec"`). Strip the
264
+ * `../` prefix and re-add the `.ts` extension to recover the leaf's
265
+ * confect-relative spec path used as the key in
266
+ * `groupSpecsByRelativePath`.
267
+ */
268
+ const bindingToRelativeSpecPath = (importPath: string): string => {
269
+ const withoutDotDot = importPath.startsWith("../")
270
+ ? importPath.slice(3)
271
+ : importPath;
272
+ return `${withoutDotDot}.ts`;
273
+ };
274
+
275
+ /**
276
+ * A child assembly node may itself be a parent without a leaf (when the
277
+ * actual leaves live only in deeper subdirectories). In that case we
278
+ * surface the first descendant leaf as a representative path so the
279
+ * error message points at something the user actually wrote.
280
+ */
281
+ const childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {
282
+ if (Option.isSome(node.importBinding)) {
283
+ return bindingToRelativeSpecPath(node.importBinding.value.importPath);
284
+ }
285
+ for (const child of node.children) {
286
+ return childRepresentativeSpecPath(child);
287
+ }
288
+ return node.segment;
289
+ };
290
+
170
291
  const validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>
171
292
  Effect.gen(function* () {
172
293
  const fs = yield* FileSystem.FileSystem;
package/src/templates.ts CHANGED
@@ -411,12 +411,16 @@ const writeGroupAssembly: (
411
411
  node: SpecAssemblyNode,
412
412
  groupFactory: string,
413
413
  ) => Effect.Effect<void> = (cbw, node, groupFactory) =>
414
- node.children.length === 0
415
- ? Option.match(node.importBinding, {
416
- onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),
417
- onSome: (binding) => cbw.write(binding.exportName),
418
- })
419
- : writeGroupFactoryCall(cbw, node, groupFactory);
414
+ Option.match(node.importBinding, {
415
+ onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),
416
+ onSome: (binding) =>
417
+ Effect.gen(function* () {
418
+ yield* cbw.write(binding.localName);
419
+ yield* Effect.forEach(node.children, (child) =>
420
+ writeChildAddGroupAt(cbw, child, groupFactory),
421
+ );
422
+ }),
423
+ });
420
424
 
421
425
  const writeRootAddAt = (
422
426
  cbw: CodeBlockWriter,
@@ -443,10 +447,11 @@ export const assembledSpec = ({
443
447
  Effect.gen(function* () {
444
448
  const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
445
449
 
446
- const needsGroupSpec = Array.some(
447
- nodes,
448
- (node) => node.children.length > 0,
449
- );
450
+ const nodeRequiresGroupFactory = (node: SpecAssemblyNode): boolean =>
451
+ Option.isNone(node.importBinding) ||
452
+ Array.some(node.children, nodeRequiresGroupFactory);
453
+
454
+ const needsGroupSpec = Array.some(nodes, nodeRequiresGroupFactory);
450
455
  yield* cbw.writeLine(
451
456
  needsGroupSpec
452
457
  ? `import { GroupSpec, Spec } from "@confect/core";`
@@ -455,7 +460,7 @@ export const assembledSpec = ({
455
460
 
456
461
  yield* Effect.forEach(collectImportBindings(nodes), (binding) =>
457
462
  cbw.writeLine(
458
- `import ${binding.exportName} from "${binding.importPath}";`,
463
+ `import ${binding.localName} from "${binding.importPath}";`,
459
464
  ),
460
465
  );
461
466