@confect/cli 9.0.0-next.6 → 9.0.0-next.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/BuildError.mjs +9 -2
  3. package/dist/BuildError.mjs.map +1 -1
  4. package/dist/Bundler.mjs +5 -2
  5. package/dist/Bundler.mjs.map +1 -1
  6. package/dist/CodeBlockWriter.mjs +1 -1
  7. package/dist/CodeBlockWriter.mjs.map +1 -1
  8. package/dist/CodegenError.mjs +7 -2
  9. package/dist/CodegenError.mjs.map +1 -1
  10. package/dist/ConfectDirectory.mjs +5 -2
  11. package/dist/ConfectDirectory.mjs.map +1 -1
  12. package/dist/ConvexDirectory.mjs +6 -2
  13. package/dist/ConvexDirectory.mjs.map +1 -1
  14. package/dist/FunctionPath.mjs +1 -1
  15. package/dist/FunctionPath.mjs.map +1 -1
  16. package/dist/FunctionPaths.mjs +5 -1
  17. package/dist/FunctionPaths.mjs.map +1 -1
  18. package/dist/GroupPath.mjs +9 -2
  19. package/dist/GroupPath.mjs.map +1 -1
  20. package/dist/GroupPaths.mjs +1 -1
  21. package/dist/GroupPaths.mjs.map +1 -1
  22. package/dist/LeafModule.mjs +8 -2
  23. package/dist/LeafModule.mjs.map +1 -1
  24. package/dist/ProjectRoot.mjs +8 -3
  25. package/dist/ProjectRoot.mjs.map +1 -1
  26. package/dist/SpecAssemblyNode.mjs +5 -1
  27. package/dist/SpecAssemblyNode.mjs.map +1 -1
  28. package/dist/TableModule.mjs +6 -2
  29. package/dist/TableModule.mjs.map +1 -1
  30. package/dist/cliApp.mjs +1 -1
  31. package/dist/cliApp.mjs.map +1 -1
  32. package/dist/confect/codegen.mjs +10 -3
  33. package/dist/confect/codegen.mjs.map +1 -1
  34. package/dist/confect/dev.mjs +24 -4
  35. package/dist/confect/dev.mjs.map +1 -1
  36. package/dist/confect.mjs +2 -2
  37. package/dist/confect.mjs.map +1 -1
  38. package/dist/index.mjs +3 -2
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/log.mjs +7 -3
  41. package/dist/log.mjs.map +1 -1
  42. package/dist/package.mjs +1 -1
  43. package/dist/templates.mjs +3 -1
  44. package/dist/templates.mjs.map +1 -1
  45. package/dist/utils.mjs +25 -15
  46. package/dist/utils.mjs.map +1 -1
  47. package/package.json +3 -3
  48. package/src/BuildError.ts +9 -2
  49. package/src/Bundler.ts +5 -2
  50. package/src/CodeBlockWriter.ts +1 -1
  51. package/src/CodegenError.ts +7 -2
  52. package/src/ConfectDirectory.ts +5 -2
  53. package/src/ConvexDirectory.ts +6 -2
  54. package/src/FunctionPath.ts +1 -1
  55. package/src/FunctionPaths.ts +5 -1
  56. package/src/GroupPath.ts +9 -11
  57. package/src/GroupPaths.ts +1 -1
  58. package/src/LeafModule.ts +8 -2
  59. package/src/ProjectRoot.ts +8 -3
  60. package/src/SpecAssemblyNode.ts +5 -1
  61. package/src/TableModule.ts +6 -2
  62. package/src/cliApp.ts +1 -1
  63. package/src/confect/codegen.ts +10 -3
  64. package/src/confect/dev.ts +24 -24
  65. package/src/confect.ts +2 -2
  66. package/src/index.ts +3 -2
  67. package/src/log.ts +7 -3
  68. package/src/templates.ts +3 -1
  69. package/src/utils.ts +12 -13
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # @confect/cli
2
2
 
3
+ ## 9.0.0-next.8
4
+
5
+ ### Patch Changes
6
+
7
+ - 3fec285: Import Effect from its submodule paths internally to shrink per-function cold-start bundles.
8
+
9
+ Confect's packages now import Effect modules from their submodule paths (`import * as Schema from "effect/Schema"`) instead of the `"effect"` barrel (`import { Schema } from "effect"`).
10
+
11
+ ### Why
12
+
13
+ A barrel import of a namespace re-export defeats esbuild's tree-shaking: accessing `Schema.X` from `import { Schema } from "effect"` retains the _entire_ `Schema` namespace, because the bundler can't prune property access on the barrel's `export * as Schema`. So every Convex function's cold-start bundle was pulling all of `effect/Schema` and `effect/Stream` — and, transitively through Schema's `Arbitrary`, `fast-check` — whether the function used them or not.
14
+
15
+ Importing from the submodule path tree-shakes normally. On a minimal function this cut the bundle esbuild produces by ~54% (the `effect/Schema` module alone by ~75%) and its cold-start module-evaluation time by ~35%, with `fast-check` dropped entirely. This is also the import style Effect v4 recommends, so it's forward-compatible. A `no-restricted-imports` ESLint rule now enforces it across the codebase (type-only imports and `@effect/vitest` are exempt).
16
+
17
+ No API changes — your existing code keeps working.
18
+
19
+ ### Getting the full win in your own code
20
+
21
+ This change shrinks the Confect code in every function bundle, but a function's bundle also includes your own `confect/tables/*` and `*.spec.ts` files. esbuild retains the union across all importers, so a single barrel import anywhere in a function's module graph re-pins the whole `effect/Schema` namespace and undoes the reduction. To get the full bundle/cold-start savings, import Effect from its submodule paths in your own Confect files too:
22
+
23
+ ```diff
24
+ - import { Schema } from "effect";
25
+ + import * as Schema from "effect/Schema";
26
+ ```
27
+
28
+ Bare helpers (`pipe`, `flow`, `identity`) come from `"effect/Function"`.
29
+
30
+ - Updated dependencies [3fec285]
31
+ - @confect/core@9.0.0-next.8
32
+ - @confect/server@9.0.0-next.8
33
+
34
+ ## 9.0.0-next.7
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies [5d19484]
39
+ - @confect/core@9.0.0-next.7
40
+ - @confect/server@9.0.0-next.7
41
+
3
42
  ## 9.0.0-next.6
4
43
 
5
44
  ### Major Changes
@@ -1,6 +1,13 @@
1
1
  import { formatPathDoc } from "./log.mjs";
2
- import { Array, Effect, Match, Option, Schema, String, pipe } from "effect";
3
- import { Ansi, AnsiDoc } from "@effect/printer-ansi";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Array from "effect/Array";
4
+ import * as Match from "effect/Match";
5
+ import * as Option from "effect/Option";
6
+ import { pipe } from "effect/Function";
7
+ import * as Ansi from "@effect/printer-ansi/Ansi";
8
+ import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
9
+ import * as Schema from "effect/Schema";
10
+ import * as String from "effect/String";
4
11
  import * as esbuild from "esbuild";
5
12
 
6
13
  //#region src/BuildError.ts
@@ -1 +1 @@
1
- {"version":3,"file":"BuildError.mjs","names":[],"sources":["../src/BuildError.ts"],"sourcesContent":["import { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Array, Effect, Match, Option, pipe, Schema, String } from \"effect\";\nimport * as esbuild from \"esbuild\";\nimport { formatPathDoc } from \"./log\";\n\n// --- Variants ---\n\nexport class BundleFailedError extends Schema.TaggedError<BundleFailedError>()(\n \"BundleFailedError\",\n {\n file: Schema.String,\n errors: Schema.Array(Schema.Unknown),\n },\n) {}\n\nexport class ImportFailedError extends Schema.TaggedError<ImportFailedError>()(\n \"ImportFailedError\",\n {\n file: Schema.String,\n cause: Schema.Unknown,\n },\n) {}\n\nexport const BuildError = Schema.Union(BundleFailedError, ImportFailedError);\nexport type BuildError = typeof BuildError.Type;\n\nexport const isBuildError = (error: unknown): error is BuildError =>\n Schema.is(BuildError)(error);\n\n// --- Bundler adapter ---\n\n/**\n * Internal failure produced by the esbuild bundle/import pipeline. Always\n * remapped to a {@link BuildError} (which carries enough context for the CLI\n * to render it) before reaching a user-surface boundary.\n */\nexport class BundlerError extends Schema.TaggedError<BundlerError>()(\n \"BundlerError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\nconst isEsbuildBuildFailure = (error: unknown): error is esbuild.BuildFailure =>\n typeof error === \"object\" &&\n error !== null &&\n \"errors\" in error &&\n globalThis.Array.isArray((error as esbuild.BuildFailure).errors);\n\nexport const fromBundlerError = (\n file: string,\n error: BundlerError,\n): BuildError =>\n isEsbuildBuildFailure(error.cause)\n ? new BundleFailedError({ file, errors: error.cause.errors })\n : new ImportFailedError({ file, cause: error.cause });\n\n// --- Rendering ---\n\nconst cross = pipe(AnsiDoc.char(\"✘\"), AnsiDoc.annotate(Ansi.red));\n\nconst errorGutter = pipe(\n AnsiDoc.char(\"│\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n);\n\nconst withErrorGutterBlock = (output: string): string =>\n pipe(\n String.split(output, \"\\n\"),\n Array.map((line) =>\n pipe(line, String.trim) === \"\" ? errorGutter : `${errorGutter} ${line}`,\n ),\n Array.join(\"\\n\"),\n (guttered) => `${errorGutter}\\n${guttered}\\n${errorGutter}`,\n );\n\nconst formatBuildMessage = (\n error: esbuild.Message | undefined,\n formattedMessage: string,\n): string => {\n const lines = String.split(formattedMessage, \"\\n\");\n const redErrorText = pipe(\n AnsiDoc.text(error?.text ?? \"\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n const replaced = pipe(\n Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)),\n Option.match({\n onNone: () => lines,\n onSome: (index) => Array.modify(lines, index, () => redErrorText),\n }),\n );\n return pipe(replaced, Array.join(\"\\n\"));\n};\n\n/**\n * Render a list of esbuild messages into a styled, gutter-prefixed block.\n * Used by both {@link renderBundleFailedError} and the dev-mode esbuild\n * watcher's `onEnd` hook (where the messages don't flow through the\n * tagged-error pipeline).\n */\nexport const formatEsbuildMessages = (\n errors: readonly esbuild.Message[],\n formattedMessages: readonly string[],\n): string =>\n pipe(\n formattedMessages,\n Array.map((message, i) => formatBuildMessage(errors[i], message)),\n Array.join(\"\"),\n String.trimEnd,\n withErrorGutterBlock,\n );\n\nconst renderImportFailedError = (error: ImportFailedError): AnsiDoc.AnsiDoc => {\n const causeMessage =\n error.cause instanceof Error\n ? error.cause.message\n : typeof error.cause === \"string\"\n ? error.cause\n : globalThis.String(error.cause);\n const oneLineCause = pipe(\n String.split(causeMessage, \"\\n\"),\n Array.findFirst((line) => pipe(line, String.trim, String.isNonEmpty)),\n Option.map(String.trim),\n Option.getOrElse(() => \"unknown error\"),\n );\n return pipe(\n cross,\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n AnsiDoc.text(\"Failed to load bundled module \"),\n formatPathDoc(error.file),\n AnsiDoc.text(\n `: ${oneLineCause}; check the file's top-level imports and side effects.`,\n ),\n ]),\n ),\n );\n};\n\n/**\n * Render a {@link BundleFailedError} as a multi-line, ANSI-styled string:\n * a one-line `✘ <file>: build errors` header followed by the\n * gutter-prefixed esbuild diagnostic block. Multi-line is appropriate\n * here because a single `BundleFailedError` carries an array of distinct\n * esbuild messages.\n */\nconst renderBundleFailedError = (error: BundleFailedError): string => {\n const messages = error.errors as readonly esbuild.Message[];\n const formatted = esbuild.formatMessagesSync(messages as esbuild.Message[], {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n });\n const header = pipe(\n cross,\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([formatPathDoc(error.file), AnsiDoc.text(\": build errors\")]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n return `${header}\\n${formatEsbuildMessages(messages, formatted)}`;\n};\n\n/**\n * Render any {@link BuildError} into a styled, ready-to-print string.\n * `ImportFailedError` collapses to a single line; `BundleFailedError`\n * expands to a header plus one diagnostic block per esbuild message.\n */\nexport const renderBuildError = (error: BuildError): string =>\n Match.value(error).pipe(\n Match.tag(\"BundleFailedError\", renderBundleFailedError),\n Match.tag(\"ImportFailedError\", (e) =>\n pipe(renderImportFailedError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.exhaustive,\n );\n\nexport const logBuildError = (error: BuildError) =>\n Effect.sync(() => console.error(renderBuildError(error)));\n\n/**\n * Render a flat list of esbuild messages as a single error block with a\n * generic `✘ Build errors` header. Used by dev-mode when multiple\n * watchers surface the same underlying error and we want to log the\n * coalesced set rather than one block per watcher.\n */\nconst renderCoalescedBuildErrors = (\n messages: readonly esbuild.Message[],\n): string => {\n const formatted = esbuild.formatMessagesSync(messages as esbuild.Message[], {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n });\n const header = pipe(\n cross,\n AnsiDoc.catWithSpace(AnsiDoc.text(\"Build errors\")),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n return `${header}\\n${formatEsbuildMessages(messages, formatted)}`;\n};\n\nexport const logCoalescedBuildErrors = (messages: readonly esbuild.Message[]) =>\n Effect.sync(() => {\n if (messages.length === 0) return;\n console.error(renderCoalescedBuildErrors(messages));\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"BuildError.mjs","names":[],"sources":["../src/BuildError.ts"],"sourcesContent":["import * as Ansi from \"@effect/printer-ansi/Ansi\";\nimport * as AnsiDoc from \"@effect/printer-ansi/AnsiDoc\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as String from \"effect/String\";\nimport * as esbuild from \"esbuild\";\nimport { formatPathDoc } from \"./log\";\n\n// --- Variants ---\n\nexport class BundleFailedError extends Schema.TaggedError<BundleFailedError>()(\n \"BundleFailedError\",\n {\n file: Schema.String,\n errors: Schema.Array(Schema.Unknown),\n },\n) {}\n\nexport class ImportFailedError extends Schema.TaggedError<ImportFailedError>()(\n \"ImportFailedError\",\n {\n file: Schema.String,\n cause: Schema.Unknown,\n },\n) {}\n\nexport const BuildError = Schema.Union(BundleFailedError, ImportFailedError);\nexport type BuildError = typeof BuildError.Type;\n\nexport const isBuildError = (error: unknown): error is BuildError =>\n Schema.is(BuildError)(error);\n\n// --- Bundler adapter ---\n\n/**\n * Internal failure produced by the esbuild bundle/import pipeline. Always\n * remapped to a {@link BuildError} (which carries enough context for the CLI\n * to render it) before reaching a user-surface boundary.\n */\nexport class BundlerError extends Schema.TaggedError<BundlerError>()(\n \"BundlerError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\nconst isEsbuildBuildFailure = (error: unknown): error is esbuild.BuildFailure =>\n typeof error === \"object\" &&\n error !== null &&\n \"errors\" in error &&\n globalThis.Array.isArray((error as esbuild.BuildFailure).errors);\n\nexport const fromBundlerError = (\n file: string,\n error: BundlerError,\n): BuildError =>\n isEsbuildBuildFailure(error.cause)\n ? new BundleFailedError({ file, errors: error.cause.errors })\n : new ImportFailedError({ file, cause: error.cause });\n\n// --- Rendering ---\n\nconst cross = pipe(AnsiDoc.char(\"✘\"), AnsiDoc.annotate(Ansi.red));\n\nconst errorGutter = pipe(\n AnsiDoc.char(\"│\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n);\n\nconst withErrorGutterBlock = (output: string): string =>\n pipe(\n String.split(output, \"\\n\"),\n Array.map((line) =>\n pipe(line, String.trim) === \"\" ? errorGutter : `${errorGutter} ${line}`,\n ),\n Array.join(\"\\n\"),\n (guttered) => `${errorGutter}\\n${guttered}\\n${errorGutter}`,\n );\n\nconst formatBuildMessage = (\n error: esbuild.Message | undefined,\n formattedMessage: string,\n): string => {\n const lines = String.split(formattedMessage, \"\\n\");\n const redErrorText = pipe(\n AnsiDoc.text(error?.text ?? \"\"),\n AnsiDoc.annotate(Ansi.red),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n const replaced = pipe(\n Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)),\n Option.match({\n onNone: () => lines,\n onSome: (index) => Array.modify(lines, index, () => redErrorText),\n }),\n );\n return pipe(replaced, Array.join(\"\\n\"));\n};\n\n/**\n * Render a list of esbuild messages into a styled, gutter-prefixed block.\n * Used by both {@link renderBundleFailedError} and the dev-mode esbuild\n * watcher's `onEnd` hook (where the messages don't flow through the\n * tagged-error pipeline).\n */\nexport const formatEsbuildMessages = (\n errors: readonly esbuild.Message[],\n formattedMessages: readonly string[],\n): string =>\n pipe(\n formattedMessages,\n Array.map((message, i) => formatBuildMessage(errors[i], message)),\n Array.join(\"\"),\n String.trimEnd,\n withErrorGutterBlock,\n );\n\nconst renderImportFailedError = (error: ImportFailedError): AnsiDoc.AnsiDoc => {\n const causeMessage =\n error.cause instanceof Error\n ? error.cause.message\n : typeof error.cause === \"string\"\n ? error.cause\n : globalThis.String(error.cause);\n const oneLineCause = pipe(\n String.split(causeMessage, \"\\n\"),\n Array.findFirst((line) => pipe(line, String.trim, String.isNonEmpty)),\n Option.map(String.trim),\n Option.getOrElse(() => \"unknown error\"),\n );\n return pipe(\n cross,\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n AnsiDoc.text(\"Failed to load bundled module \"),\n formatPathDoc(error.file),\n AnsiDoc.text(\n `: ${oneLineCause}; check the file's top-level imports and side effects.`,\n ),\n ]),\n ),\n );\n};\n\n/**\n * Render a {@link BundleFailedError} as a multi-line, ANSI-styled string:\n * a one-line `✘ <file>: build errors` header followed by the\n * gutter-prefixed esbuild diagnostic block. Multi-line is appropriate\n * here because a single `BundleFailedError` carries an array of distinct\n * esbuild messages.\n */\nconst renderBundleFailedError = (error: BundleFailedError): string => {\n const messages = error.errors as readonly esbuild.Message[];\n const formatted = esbuild.formatMessagesSync(messages as esbuild.Message[], {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n });\n const header = pipe(\n cross,\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([formatPathDoc(error.file), AnsiDoc.text(\": build errors\")]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n return `${header}\\n${formatEsbuildMessages(messages, formatted)}`;\n};\n\n/**\n * Render any {@link BuildError} into a styled, ready-to-print string.\n * `ImportFailedError` collapses to a single line; `BundleFailedError`\n * expands to a header plus one diagnostic block per esbuild message.\n */\nexport const renderBuildError = (error: BuildError): string =>\n Match.value(error).pipe(\n Match.tag(\"BundleFailedError\", renderBundleFailedError),\n Match.tag(\"ImportFailedError\", (e) =>\n pipe(renderImportFailedError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.exhaustive,\n );\n\nexport const logBuildError = (error: BuildError) =>\n Effect.sync(() => console.error(renderBuildError(error)));\n\n/**\n * Render a flat list of esbuild messages as a single error block with a\n * generic `✘ Build errors` header. Used by dev-mode when multiple\n * watchers surface the same underlying error and we want to log the\n * coalesced set rather than one block per watcher.\n */\nconst renderCoalescedBuildErrors = (\n messages: readonly esbuild.Message[],\n): string => {\n const formatted = esbuild.formatMessagesSync(messages as esbuild.Message[], {\n kind: \"error\",\n color: true,\n terminalWidth: 80,\n });\n const header = pipe(\n cross,\n AnsiDoc.catWithSpace(AnsiDoc.text(\"Build errors\")),\n AnsiDoc.render({ style: \"pretty\" }),\n );\n return `${header}\\n${formatEsbuildMessages(messages, formatted)}`;\n};\n\nexport const logCoalescedBuildErrors = (messages: readonly esbuild.Message[]) =>\n Effect.sync(() => {\n if (messages.length === 0) return;\n console.error(renderCoalescedBuildErrors(messages));\n });\n"],"mappings":"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"}
package/dist/Bundler.mjs CHANGED
@@ -1,8 +1,11 @@
1
1
  import { BundlerError } from "./BuildError.mjs";
2
- import { Array, Effect, Option, pipe } from "effect";
3
- import { Path } from "@effect/platform";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Path from "@effect/platform/Path";
4
+ import * as Array from "effect/Array";
5
+ import * as Option from "effect/Option";
4
6
  import { dirname, isAbsolute, resolve } from "node:path";
5
7
  import { bundleRequire } from "bundle-require";
8
+ import { pipe } from "effect/Function";
6
9
 
7
10
  //#region src/Bundler.ts
8
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Bundler.mjs","names":[],"sources":["../src/Bundler.ts"],"sourcesContent":["import { dirname, isAbsolute, resolve } from \"node:path\";\nimport { Path } from \"@effect/platform\";\nimport { bundleRequire } from \"bundle-require\";\nimport { Array, Effect, Option, pipe } from \"effect\";\nimport type * as esbuild from \"esbuild\";\nimport { BundlerError } from \"./BuildError\";\n\nexport interface Bundled {\n readonly module: any;\n readonly metafile: esbuild.Metafile;\n}\n\n/**\n * `bundle-require` sets `absWorkingDir: cwd` on the underlying esbuild build,\n * so the metafile's input keys (and each input's `imports[].path`) are stored\n * relative to that cwd. Callers reach for the metafile with absolute paths\n * (e.g. {@link directlyImports}), so we normalize every key/import path to\n * absolute up front. That way the lookup logic stays oblivious to whatever\n * cwd was used during bundling.\n */\nconst absolutizeMetafile = (\n metafile: esbuild.Metafile,\n cwd: string,\n): esbuild.Metafile => {\n const absolutize = (p: string) => (isAbsolute(p) ? p : resolve(cwd, p));\n const inputs: esbuild.Metafile[\"inputs\"] = {};\n for (const [key, value] of Object.entries(metafile.inputs)) {\n inputs[absolutize(key)] = {\n ...value,\n imports: value.imports.map((i) => ({ ...i, path: absolutize(i.path) })),\n };\n }\n const outputs: esbuild.Metafile[\"outputs\"] = {};\n for (const [key, value] of Object.entries(metafile.outputs)) {\n outputs[absolutize(key)] = value;\n }\n return { inputs, outputs };\n};\n\n/**\n * Bundle a TypeScript entry point with esbuild via {@link bundleRequire} and\n * import the result. `bundle-require` writes a temp `.mjs` next to the source,\n * `import()`s it, and deletes it — so bare-specifier externals (third-party\n * packages, workspace deps) resolve through the user's normal `node_modules`\n * walk, and tsconfig `paths` aliases stay inside the bundle.\n *\n * `cwd` is set to the entry's directory so `bundle-require`'s `tsconfig.json`\n * discovery (which walks upward from `cwd`) lands on the project's tsconfig\n * regardless of where `confect codegen` was invoked from, and so esbuild\n * resolves relative imports against the entry's location.\n *\n * The returned pair carries both the imported module and the esbuild metafile\n * so callers can inspect the import graph (see {@link directlyImports}); the\n * metafile is captured via a small `onEnd` plugin because `bundle-require`\n * itself only exposes a flat `dependencies: string[]`.\n */\nexport const bundle = (\n entryPoint: string,\n): Effect.Effect<Bundled, BundlerError> =>\n Effect.gen(function* () {\n let metafile: esbuild.Metafile | undefined;\n const captureMetafile: esbuild.Plugin = {\n name: \"confect:capture-metafile\",\n setup(build) {\n build.onEnd((result) => {\n metafile = result.metafile;\n });\n },\n };\n\n const cwd = dirname(entryPoint);\n const result = yield* Effect.tryPromise({\n try: () =>\n bundleRequire({\n filepath: entryPoint,\n cwd,\n format: \"esm\",\n esbuildOptions: {\n plugins: [captureMetafile],\n logLevel: \"silent\",\n },\n }),\n catch: (cause) => new BundlerError({ cause }),\n });\n\n if (!metafile) {\n return yield* Effect.dieMessage(\"esbuild metafile missing\");\n }\n\n return { module: result.mod, metafile: absolutizeMetafile(metafile, cwd) };\n });\n\nconst findMetafileInputKey = (\n metafile: esbuild.Metafile,\n absolutePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const resolved = path.resolve(absolutePath);\n return Array.findFirst(\n Object.keys(metafile.inputs),\n (key) => path.resolve(key) === resolved,\n );\n });\n\n/**\n * Returns `true` when the module bundled from `sourceAbsolutePath` declares a\n * direct import of `targetAbsolutePath` (according to the bundle's esbuild\n * metafile). Returns `false` if either path is missing from the metafile.\n */\nexport const directlyImports = (\n bundled: Bundled,\n sourceAbsolutePath: string,\n targetAbsolutePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const sourceKey = yield* findMetafileInputKey(\n bundled.metafile,\n sourceAbsolutePath,\n );\n const targetKey = yield* findMetafileInputKey(\n bundled.metafile,\n targetAbsolutePath,\n );\n\n return pipe(\n Option.all([sourceKey, targetKey]),\n Option.flatMap(([sourceKey_, targetKey_]) =>\n Option.fromNullable(bundled.metafile.inputs[sourceKey_]).pipe(\n Option.map((sourceInput) => {\n const targetResolved = path.resolve(targetKey_);\n return sourceInput.imports.some(\n (importedFile) =>\n path.resolve(importedFile.path) === targetResolved,\n );\n }),\n ),\n ),\n Option.getOrElse(() => false),\n );\n });\n"],"mappings":";;;;;;;;;;;;;;;AAoBA,MAAM,sBACJ,UACA,QACqB;CACrB,MAAM,cAAc,MAAe,WAAW,EAAE,GAAG,IAAI,QAAQ,KAAK,EAAE;CACtE,MAAM,SAAqC,EAAE;AAC7C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,QAAO,WAAW,IAAI,IAAI;EACxB,GAAG;EACH,SAAS,MAAM,QAAQ,KAAK,OAAO;GAAE,GAAG;GAAG,MAAM,WAAW,EAAE,KAAK;GAAE,EAAE;EACxE;CAEH,MAAM,UAAuC,EAAE;AAC/C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,QAAQ,CACzD,SAAQ,WAAW,IAAI,IAAI;AAE7B,QAAO;EAAE;EAAQ;EAAS;;;;;;;;;;;;;;;;;;;AAoB5B,MAAa,UACX,eAEA,OAAO,IAAI,aAAa;CACtB,IAAI;CACJ,MAAM,kBAAkC;EACtC,MAAM;EACN,MAAM,OAAO;AACX,SAAM,OAAO,WAAW;AACtB,eAAW,OAAO;KAClB;;EAEL;CAED,MAAM,MAAM,QAAQ,WAAW;CAC/B,MAAM,SAAS,OAAO,OAAO,WAAW;EACtC,WACE,cAAc;GACZ,UAAU;GACV;GACA,QAAQ;GACR,gBAAgB;IACd,SAAS,CAAC,gBAAgB;IAC1B,UAAU;IACX;GACF,CAAC;EACJ,QAAQ,UAAU,IAAI,aAAa,EAAE,OAAO,CAAC;EAC9C,CAAC;AAEF,KAAI,CAAC,SACH,QAAO,OAAO,OAAO,WAAW,2BAA2B;AAG7D,QAAO;EAAE,QAAQ,OAAO;EAAK,UAAU,mBAAmB,UAAU,IAAI;EAAE;EAC1E;AAEJ,MAAM,wBACJ,UACA,iBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,WAAW,KAAK,QAAQ,aAAa;AAC3C,QAAO,MAAM,UACX,OAAO,KAAK,SAAS,OAAO,GAC3B,QAAQ,KAAK,QAAQ,IAAI,KAAK,SAChC;EACD;;;;;;AAOJ,MAAa,mBACX,SACA,oBACA,uBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,YAAY,OAAO,qBACvB,QAAQ,UACR,mBACD;CACD,MAAM,YAAY,OAAO,qBACvB,QAAQ,UACR,mBACD;AAED,QAAO,KACL,OAAO,IAAI,CAAC,WAAW,UAAU,CAAC,EAClC,OAAO,SAAS,CAAC,YAAY,gBAC3B,OAAO,aAAa,QAAQ,SAAS,OAAO,YAAY,CAAC,KACvD,OAAO,KAAK,gBAAgB;EAC1B,MAAM,iBAAiB,KAAK,QAAQ,WAAW;AAC/C,SAAO,YAAY,QAAQ,MACxB,iBACC,KAAK,QAAQ,aAAa,KAAK,KAAK,eACvC;GACD,CACH,CACF,EACD,OAAO,gBAAgB,MAAM,CAC9B;EACD"}
1
+ {"version":3,"file":"Bundler.mjs","names":[],"sources":["../src/Bundler.ts"],"sourcesContent":["import { dirname, isAbsolute, resolve } from \"node:path\";\nimport * as Path from \"@effect/platform/Path\";\nimport { bundleRequire } from \"bundle-require\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport type * as esbuild from \"esbuild\";\nimport { BundlerError } from \"./BuildError\";\n\nexport interface Bundled {\n readonly module: any;\n readonly metafile: esbuild.Metafile;\n}\n\n/**\n * `bundle-require` sets `absWorkingDir: cwd` on the underlying esbuild build,\n * so the metafile's input keys (and each input's `imports[].path`) are stored\n * relative to that cwd. Callers reach for the metafile with absolute paths\n * (e.g. {@link directlyImports}), so we normalize every key/import path to\n * absolute up front. That way the lookup logic stays oblivious to whatever\n * cwd was used during bundling.\n */\nconst absolutizeMetafile = (\n metafile: esbuild.Metafile,\n cwd: string,\n): esbuild.Metafile => {\n const absolutize = (p: string) => (isAbsolute(p) ? p : resolve(cwd, p));\n const inputs: esbuild.Metafile[\"inputs\"] = {};\n for (const [key, value] of Object.entries(metafile.inputs)) {\n inputs[absolutize(key)] = {\n ...value,\n imports: value.imports.map((i) => ({ ...i, path: absolutize(i.path) })),\n };\n }\n const outputs: esbuild.Metafile[\"outputs\"] = {};\n for (const [key, value] of Object.entries(metafile.outputs)) {\n outputs[absolutize(key)] = value;\n }\n return { inputs, outputs };\n};\n\n/**\n * Bundle a TypeScript entry point with esbuild via {@link bundleRequire} and\n * import the result. `bundle-require` writes a temp `.mjs` next to the source,\n * `import()`s it, and deletes it — so bare-specifier externals (third-party\n * packages, workspace deps) resolve through the user's normal `node_modules`\n * walk, and tsconfig `paths` aliases stay inside the bundle.\n *\n * `cwd` is set to the entry's directory so `bundle-require`'s `tsconfig.json`\n * discovery (which walks upward from `cwd`) lands on the project's tsconfig\n * regardless of where `confect codegen` was invoked from, and so esbuild\n * resolves relative imports against the entry's location.\n *\n * The returned pair carries both the imported module and the esbuild metafile\n * so callers can inspect the import graph (see {@link directlyImports}); the\n * metafile is captured via a small `onEnd` plugin because `bundle-require`\n * itself only exposes a flat `dependencies: string[]`.\n */\nexport const bundle = (\n entryPoint: string,\n): Effect.Effect<Bundled, BundlerError> =>\n Effect.gen(function* () {\n let metafile: esbuild.Metafile | undefined;\n const captureMetafile: esbuild.Plugin = {\n name: \"confect:capture-metafile\",\n setup(build) {\n build.onEnd((result) => {\n metafile = result.metafile;\n });\n },\n };\n\n const cwd = dirname(entryPoint);\n const result = yield* Effect.tryPromise({\n try: () =>\n bundleRequire({\n filepath: entryPoint,\n cwd,\n format: \"esm\",\n esbuildOptions: {\n plugins: [captureMetafile],\n logLevel: \"silent\",\n },\n }),\n catch: (cause) => new BundlerError({ cause }),\n });\n\n if (!metafile) {\n return yield* Effect.dieMessage(\"esbuild metafile missing\");\n }\n\n return { module: result.mod, metafile: absolutizeMetafile(metafile, cwd) };\n });\n\nconst findMetafileInputKey = (\n metafile: esbuild.Metafile,\n absolutePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const resolved = path.resolve(absolutePath);\n return Array.findFirst(\n Object.keys(metafile.inputs),\n (key) => path.resolve(key) === resolved,\n );\n });\n\n/**\n * Returns `true` when the module bundled from `sourceAbsolutePath` declares a\n * direct import of `targetAbsolutePath` (according to the bundle's esbuild\n * metafile). Returns `false` if either path is missing from the metafile.\n */\nexport const directlyImports = (\n bundled: Bundled,\n sourceAbsolutePath: string,\n targetAbsolutePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const sourceKey = yield* findMetafileInputKey(\n bundled.metafile,\n sourceAbsolutePath,\n );\n const targetKey = yield* findMetafileInputKey(\n bundled.metafile,\n targetAbsolutePath,\n );\n\n return pipe(\n Option.all([sourceKey, targetKey]),\n Option.flatMap(([sourceKey_, targetKey_]) =>\n Option.fromNullable(bundled.metafile.inputs[sourceKey_]).pipe(\n Option.map((sourceInput) => {\n const targetResolved = path.resolve(targetKey_);\n return sourceInput.imports.some(\n (importedFile) =>\n path.resolve(importedFile.path) === targetResolved,\n );\n }),\n ),\n ),\n Option.getOrElse(() => false),\n );\n });\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,MAAM,sBACJ,UACA,QACqB;CACrB,MAAM,cAAc,MAAe,WAAW,EAAE,GAAG,IAAI,QAAQ,KAAK,EAAE;CACtE,MAAM,SAAqC,EAAE;AAC7C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,OAAO,CACxD,QAAO,WAAW,IAAI,IAAI;EACxB,GAAG;EACH,SAAS,MAAM,QAAQ,KAAK,OAAO;GAAE,GAAG;GAAG,MAAM,WAAW,EAAE,KAAK;GAAE,EAAE;EACxE;CAEH,MAAM,UAAuC,EAAE;AAC/C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,QAAQ,CACzD,SAAQ,WAAW,IAAI,IAAI;AAE7B,QAAO;EAAE;EAAQ;EAAS;;;;;;;;;;;;;;;;;;;AAoB5B,MAAa,UACX,eAEA,OAAO,IAAI,aAAa;CACtB,IAAI;CACJ,MAAM,kBAAkC;EACtC,MAAM;EACN,MAAM,OAAO;AACX,SAAM,OAAO,WAAW;AACtB,eAAW,OAAO;KAClB;;EAEL;CAED,MAAM,MAAM,QAAQ,WAAW;CAC/B,MAAM,SAAS,OAAO,OAAO,WAAW;EACtC,WACE,cAAc;GACZ,UAAU;GACV;GACA,QAAQ;GACR,gBAAgB;IACd,SAAS,CAAC,gBAAgB;IAC1B,UAAU;IACX;GACF,CAAC;EACJ,QAAQ,UAAU,IAAI,aAAa,EAAE,OAAO,CAAC;EAC9C,CAAC;AAEF,KAAI,CAAC,SACH,QAAO,OAAO,OAAO,WAAW,2BAA2B;AAG7D,QAAO;EAAE,QAAQ,OAAO;EAAK,UAAU,mBAAmB,UAAU,IAAI;EAAE;EAC1E;AAEJ,MAAM,wBACJ,UACA,iBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,WAAW,KAAK,QAAQ,aAAa;AAC3C,QAAO,MAAM,UACX,OAAO,KAAK,SAAS,OAAO,GAC3B,QAAQ,KAAK,QAAQ,IAAI,KAAK,SAChC;EACD;;;;;;AAOJ,MAAa,mBACX,SACA,oBACA,uBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,YAAY,OAAO,qBACvB,QAAQ,UACR,mBACD;CACD,MAAM,YAAY,OAAO,qBACvB,QAAQ,UACR,mBACD;AAED,QAAO,KACL,OAAO,IAAI,CAAC,WAAW,UAAU,CAAC,EAClC,OAAO,SAAS,CAAC,YAAY,gBAC3B,OAAO,aAAa,QAAQ,SAAS,OAAO,YAAY,CAAC,KACvD,OAAO,KAAK,gBAAgB;EAC1B,MAAM,iBAAiB,KAAK,QAAQ,WAAW;AAC/C,SAAO,YAAY,QAAQ,MACxB,iBACC,KAAK,QAAQ,aAAa,KAAK,KAAK,eACvC;GACD,CACH,CACF,EACD,OAAO,gBAAgB,MAAM,CAC9B;EACD"}
@@ -1,4 +1,4 @@
1
- import { Effect } from "effect";
1
+ import * as Effect from "effect/Effect";
2
2
  import CodeBlockWriter_ from "code-block-writer";
3
3
 
4
4
  //#region src/CodeBlockWriter.ts
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockWriter.mjs","names":[],"sources":["../src/CodeBlockWriter.ts"],"sourcesContent":["import type { Options as CodeBlockWriterOptions } from \"code-block-writer\";\nimport CodeBlockWriter_ from \"code-block-writer\";\nimport { Effect } from \"effect\";\n\nexport class CodeBlockWriter {\n private readonly writer: CodeBlockWriter_;\n\n constructor(opts?: Partial<CodeBlockWriterOptions>) {\n this.writer = new CodeBlockWriter_(opts);\n }\n\n indent<E = never, R = never>(\n effect: Effect.Effect<void, E, R>,\n ): Effect.Effect<void, E, R> {\n return Effect.gen(this, function* () {\n const indentationLevel = this.writer.getIndentationLevel();\n this.writer.setIndentationLevel(indentationLevel + 1);\n yield* effect;\n this.writer.setIndentationLevel(indentationLevel);\n });\n }\n\n writeLine<E = never, R = never>(line: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.writeLine(line);\n });\n }\n\n write<E = never, R = never>(text: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.write(text);\n });\n }\n\n quote<E = never, R = never>(text: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.quote(text);\n });\n }\n\n conditionalWriteLine<E = never, R = never>(\n condition: boolean,\n text: string,\n ): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.conditionalWriteLine(condition, text);\n });\n }\n\n newLine<E = never, R = never>(): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.newLine();\n });\n }\n\n blankLine<E = never, R = never>(): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.blankLine();\n });\n }\n\n toString<E = never, R = never>(): Effect.Effect<string, E, R> {\n return Effect.sync(() => this.writer.toString());\n }\n}\n"],"mappings":";;;;AAIA,IAAa,kBAAb,MAA6B;CAC3B,AAAiB;CAEjB,YAAY,MAAwC;AAClD,OAAK,SAAS,IAAI,iBAAiB,KAAK;;CAG1C,OACE,QAC2B;AAC3B,SAAO,OAAO,IAAI,MAAM,aAAa;GACnC,MAAM,mBAAmB,KAAK,OAAO,qBAAqB;AAC1D,QAAK,OAAO,oBAAoB,mBAAmB,EAAE;AACrD,UAAO;AACP,QAAK,OAAO,oBAAoB,iBAAiB;IACjD;;CAGJ,UAAgC,MAAyC;AACvE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,UAAU,KAAK;IAC3B;;CAGJ,MAA4B,MAAyC;AACnE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,MAAM,KAAK;IACvB;;CAGJ,MAA4B,MAAyC;AACnE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,MAAM,KAAK;IACvB;;CAGJ,qBACE,WACA,MAC2B;AAC3B,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,qBAAqB,WAAW,KAAK;IACjD;;CAGJ,UAA2D;AACzD,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,SAAS;IACrB;;CAGJ,YAA6D;AAC3D,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,WAAW;IACvB;;CAGJ,WAA8D;AAC5D,SAAO,OAAO,WAAW,KAAK,OAAO,UAAU,CAAC"}
1
+ {"version":3,"file":"CodeBlockWriter.mjs","names":[],"sources":["../src/CodeBlockWriter.ts"],"sourcesContent":["import type { Options as CodeBlockWriterOptions } from \"code-block-writer\";\nimport CodeBlockWriter_ from \"code-block-writer\";\nimport * as Effect from \"effect/Effect\";\n\nexport class CodeBlockWriter {\n private readonly writer: CodeBlockWriter_;\n\n constructor(opts?: Partial<CodeBlockWriterOptions>) {\n this.writer = new CodeBlockWriter_(opts);\n }\n\n indent<E = never, R = never>(\n effect: Effect.Effect<void, E, R>,\n ): Effect.Effect<void, E, R> {\n return Effect.gen(this, function* () {\n const indentationLevel = this.writer.getIndentationLevel();\n this.writer.setIndentationLevel(indentationLevel + 1);\n yield* effect;\n this.writer.setIndentationLevel(indentationLevel);\n });\n }\n\n writeLine<E = never, R = never>(line: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.writeLine(line);\n });\n }\n\n write<E = never, R = never>(text: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.write(text);\n });\n }\n\n quote<E = never, R = never>(text: string): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.quote(text);\n });\n }\n\n conditionalWriteLine<E = never, R = never>(\n condition: boolean,\n text: string,\n ): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.conditionalWriteLine(condition, text);\n });\n }\n\n newLine<E = never, R = never>(): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.newLine();\n });\n }\n\n blankLine<E = never, R = never>(): Effect.Effect<void, E, R> {\n return Effect.sync(() => {\n this.writer.blankLine();\n });\n }\n\n toString<E = never, R = never>(): Effect.Effect<string, E, R> {\n return Effect.sync(() => this.writer.toString());\n }\n}\n"],"mappings":";;;;AAIA,IAAa,kBAAb,MAA6B;CAC3B,AAAiB;CAEjB,YAAY,MAAwC;AAClD,OAAK,SAAS,IAAI,iBAAiB,KAAK;;CAG1C,OACE,QAC2B;AAC3B,SAAO,OAAO,IAAI,MAAM,aAAa;GACnC,MAAM,mBAAmB,KAAK,OAAO,qBAAqB;AAC1D,QAAK,OAAO,oBAAoB,mBAAmB,EAAE;AACrD,UAAO;AACP,QAAK,OAAO,oBAAoB,iBAAiB;IACjD;;CAGJ,UAAgC,MAAyC;AACvE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,UAAU,KAAK;IAC3B;;CAGJ,MAA4B,MAAyC;AACnE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,MAAM,KAAK;IACvB;;CAGJ,MAA4B,MAAyC;AACnE,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,MAAM,KAAK;IACvB;;CAGJ,qBACE,WACA,MAC2B;AAC3B,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,qBAAqB,WAAW,KAAK;IACjD;;CAGJ,UAA2D;AACzD,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,SAAS;IACrB;;CAGJ,YAA6D;AAC3D,SAAO,OAAO,WAAW;AACvB,QAAK,OAAO,WAAW;IACvB;;CAGJ,WAA8D;AAC5D,SAAO,OAAO,WAAW,KAAK,OAAO,UAAU,CAAC"}
@@ -1,7 +1,12 @@
1
1
  import { formatPathDoc } from "./log.mjs";
2
2
  import { BuildError, isBuildError, renderBuildError } from "./BuildError.mjs";
3
- import { Effect, Match, Option, Schema, pipe } from "effect";
4
- import { Ansi, AnsiDoc } from "@effect/printer-ansi";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Match from "effect/Match";
5
+ import * as Option from "effect/Option";
6
+ import { pipe } from "effect/Function";
7
+ import * as Ansi from "@effect/printer-ansi/Ansi";
8
+ import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
9
+ import * as Schema from "effect/Schema";
5
10
 
6
11
  //#region src/CodegenError.ts
7
12
  var MissingImplFileError = class extends Schema.TaggedError()("MissingImplFileError", {
@@ -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 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 InvalidTableDefaultExportError extends Schema.TaggedError<InvalidTableDefaultExportError>()(\n \"InvalidTableDefaultExportError\",\n {\n tablePath: Schema.String,\n },\n) {}\n\nexport class InvalidTableFilenameError extends Schema.TaggedError<InvalidTableFilenameError>()(\n \"InvalidTableFilenameError\",\n {\n tablePath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class DuplicateTableNameError extends Schema.TaggedError<DuplicateTableNameError>()(\n \"DuplicateTableNameError\",\n {\n // Every table name that more than one file resolves to, each paired with\n // the colliding file paths. All collisions are captured in a single pass\n // so the user can fix them together rather than re-running codegen once\n // per conflict.\n collisions: Schema.Array(\n Schema.Struct({\n tableName: Schema.String,\n tablePaths: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class LegacySchemaFileError extends Schema.TaggedError<LegacySchemaFileError>()(\n \"LegacySchemaFileError\",\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 ParentChildNameCollisionError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n DuplicateTableNameError,\n LegacySchemaFileError,\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(databaseSchema, 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(databaseSchema, 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 renderInvalidTableDefaultExportError = (\n error: InvalidTableDefaultExportError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Table \"),\n formatPathDoc(error.tablePath),\n AnsiDoc.text(\n \" must default-export a Table (e.g. `export default Table.make({ ... })`); convert any named export to a default export.\",\n ),\n );\n\nconst renderInvalidTableFilenameError = (\n error: InvalidTableFilenameError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Table \"),\n formatPathDoc(error.tablePath),\n AnsiDoc.text(\n ` has an invalid filename: ${error.reason} Convex table names must start with a letter and contain only letters, numbers, and underscores; leading underscores are reserved for system tables.`,\n ),\n );\n\nconst renderDuplicateTableNameError = (\n error: DuplicateTableNameError,\n): AnsiDoc.AnsiDoc => {\n const conflicts = error.collisions\n .map(\n ({ tableName, tablePaths }) =>\n `\\`${tableName}\\` (${tablePaths.join(\", \")})`,\n )\n .join(\"; \");\n return singleLine(\n AnsiDoc.text(\n `Multiple files under \\`confect/tables/\\` resolve to the same table name. Table names are derived from filenames, so each must be unique across the directory (including subdirectories); rename or remove all but one. Conflicts: ${conflicts}.`,\n ),\n );\n};\n\nconst renderLegacySchemaFileError = (\n error: LegacySchemaFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Found a legacy \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \". Delete it: tables in `confect/tables/*.ts` are now the single source of truth, and the runtime schema is generated as `confect/_generated/schema.ts`.\",\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(\"ParentChildNameCollisionError\", (e) =>\n pipe(\n renderParentChildNameCollisionError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"InvalidTableDefaultExportError\", (e) =>\n pipe(\n renderInvalidTableDefaultExportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"InvalidTableFilenameError\", (e) =>\n pipe(\n renderInvalidTableFilenameError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"DuplicateTableNameError\", (e) =>\n pipe(\n renderDuplicateTableNameError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"LegacySchemaFileError\", (e) =>\n pipe(renderLegacySchemaFileError(e), AnsiDoc.render({ style: \"pretty\" })),\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 * as Ansi from \"@effect/printer-ansi/Ansi\";\nimport * as AnsiDoc from \"@effect/printer-ansi/AnsiDoc\";\nimport { pipe } from \"effect/Function\";\nimport * as Effect from \"effect/Effect\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\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 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 InvalidTableDefaultExportError extends Schema.TaggedError<InvalidTableDefaultExportError>()(\n \"InvalidTableDefaultExportError\",\n {\n tablePath: Schema.String,\n },\n) {}\n\nexport class InvalidTableFilenameError extends Schema.TaggedError<InvalidTableFilenameError>()(\n \"InvalidTableFilenameError\",\n {\n tablePath: Schema.String,\n reason: Schema.String,\n },\n) {}\n\nexport class DuplicateTableNameError extends Schema.TaggedError<DuplicateTableNameError>()(\n \"DuplicateTableNameError\",\n {\n // Every table name that more than one file resolves to, each paired with\n // the colliding file paths. All collisions are captured in a single pass\n // so the user can fix them together rather than re-running codegen once\n // per conflict.\n collisions: Schema.Array(\n Schema.Struct({\n tableName: Schema.String,\n tablePaths: Schema.Array(Schema.String),\n }),\n ),\n },\n) {}\n\nexport class LegacySchemaFileError extends Schema.TaggedError<LegacySchemaFileError>()(\n \"LegacySchemaFileError\",\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 ParentChildNameCollisionError,\n InvalidTableDefaultExportError,\n InvalidTableFilenameError,\n DuplicateTableNameError,\n LegacySchemaFileError,\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(databaseSchema, 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(databaseSchema, 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 renderInvalidTableDefaultExportError = (\n error: InvalidTableDefaultExportError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Table \"),\n formatPathDoc(error.tablePath),\n AnsiDoc.text(\n \" must default-export a Table (e.g. `export default Table.make({ ... })`); convert any named export to a default export.\",\n ),\n );\n\nconst renderInvalidTableFilenameError = (\n error: InvalidTableFilenameError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Table \"),\n formatPathDoc(error.tablePath),\n AnsiDoc.text(\n ` has an invalid filename: ${error.reason} Convex table names must start with a letter and contain only letters, numbers, and underscores; leading underscores are reserved for system tables.`,\n ),\n );\n\nconst renderDuplicateTableNameError = (\n error: DuplicateTableNameError,\n): AnsiDoc.AnsiDoc => {\n const conflicts = error.collisions\n .map(\n ({ tableName, tablePaths }) =>\n `\\`${tableName}\\` (${tablePaths.join(\", \")})`,\n )\n .join(\"; \");\n return singleLine(\n AnsiDoc.text(\n `Multiple files under \\`confect/tables/\\` resolve to the same table name. Table names are derived from filenames, so each must be unique across the directory (including subdirectories); rename or remove all but one. Conflicts: ${conflicts}.`,\n ),\n );\n};\n\nconst renderLegacySchemaFileError = (\n error: LegacySchemaFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Found a legacy \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \". Delete it: tables in `confect/tables/*.ts` are now the single source of truth, and the runtime schema is generated as `confect/_generated/schema.ts`.\",\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(\"ParentChildNameCollisionError\", (e) =>\n pipe(\n renderParentChildNameCollisionError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"InvalidTableDefaultExportError\", (e) =>\n pipe(\n renderInvalidTableDefaultExportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"InvalidTableFilenameError\", (e) =>\n pipe(\n renderInvalidTableFilenameError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"DuplicateTableNameError\", (e) =>\n pipe(\n renderDuplicateTableNameError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"LegacySchemaFileError\", (e) =>\n pipe(renderLegacySchemaFileError(e), AnsiDoc.render({ style: \"pretty\" })),\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":";;;;;;;;;;;AAYA,IAAa,uBAAb,cAA0C,OAAO,aAAmC,CAClF,wBACA;CACE,UAAU,OAAO;CACjB,kBAAkB,OAAO;CAC1B,CACF,CAAC;AAEF,IAAa,uBAAb,cAA0C,OAAO,aAAmC,CAClF,wBACA;CACE,UAAU,OAAO;CACjB,kBAAkB,OAAO;CAC1B,CACF,CAAC;AAEF,IAAa,mCAAb,cAAsD,OAAO,aAA+C,CAC1G,oCACA,EACE,UAAU,OAAO,QAClB,CACF,CAAC;AAEF,IAAa,2BAAb,cAA8C,OAAO,aAAuC,CAC1F,4BACA;CACE,UAAU,OAAO;CACjB,iBAAiB,OAAO,QAAQ,UAAU,OAAO;CACjD,eAAe,OAAO,QAAQ,UAAU,OAAO;CAChD,CACF,CAAC;AAEF,IAAa,6BAAb,cAAgD,OAAO,aAAyC,CAC9F,8BACA;CACE,UAAU,OAAO;CACjB,kBAAkB,OAAO;CAC1B,CACF,CAAC;AAEF,IAAa,+BAAb,cAAkD,OAAO,aAA2C,CAClG,gCACA,EACE,UAAU,OAAO,QAClB,CACF,CAAC;AAEF,IAAa,wBAAb,cAA2C,OAAO,aAAoC,CACpF,yBACA,EACE,UAAU,OAAO,QAClB,CACF,CAAC;AAEF,IAAa,4BAAb,cAA+C,OAAO,aAAwC,CAC5F,6BACA;CACE,UAAU,OAAO;CACjB,WAAW,OAAO;CAClB,sBAAsB,OAAO,MAAM,OAAO,OAAO;CAClD,CACF,CAAC;AAEF,IAAa,gCAAb,cAAmD,OAAO,aAA4C,CACpG,iCACA;CACE,gBAAgB,OAAO;CACvB,eAAe,OAAO;CACtB,eAAe,OAAO;CACtB,eAAe,OAAO,QAAQ,YAAY,QAAQ;CACnD,CACF,CAAC;AAEF,IAAa,iCAAb,cAAoD,OAAO,aAA6C,CACtG,kCACA,EACE,WAAW,OAAO,QACnB,CACF,CAAC;AAEF,IAAa,4BAAb,cAA+C,OAAO,aAAwC,CAC5F,6BACA;CACE,WAAW,OAAO;CAClB,QAAQ,OAAO;CAChB,CACF,CAAC;AAEF,IAAa,0BAAb,cAA6C,OAAO,aAAsC,CACxF,2BACA,EAKE,YAAY,OAAO,MACjB,OAAO,OAAO;CACZ,WAAW,OAAO;CAClB,YAAY,OAAO,MAAM,OAAO,OAAO;CACxC,CAAC,CACH,EACF,CACF,CAAC;AAEF,IAAa,wBAAb,cAA2C,OAAO,aAAoC,CACpF,yBACA,EACE,YAAY,OAAO,QACpB,CACF,CAAC;AAEF,MAAa,eAAe,OAAO,MACjC,YACA,sBACA,sBACA,kCACA,0BACA,4BACA,8BACA,uBACA,2BACA,+BACA,gCACA,2BACA,yBACA,sBACD;AAGD,MAAa,kBAAkB,UAA0C;AACvE,KAAI,aAAa,MAAM,CAAE,QAAO;AAChC,QAAO,OAAO,GAAG,aAAa,CAAC,MAAM;;AAKvC,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,EAAE,QAAQ,SAAS,KAAK,IAAI,CAAC;AAEjE,MAAM,oBAAoB,aAA6B;CACrD,MAAM,UAAU,KAAK,IACnB,SAAS,YAAY,IAAI,EACzB,SAAS,YAAY,KAAK,CAC3B;CACD,MAAM,WAAW,UAAU,IAAI,WAAW,SAAS,MAAM,UAAU,EAAE;AACrE,QAAO,SAAS,SAAS,WAAW,GAChC,SAAS,MAAM,GAAG,GAAmB,GACrC;;AAGN,MAAM,cACJ,GAAG,UACiB,KAAK,OAAO,QAAQ,aAAa,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE5E,MAAM,8BACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KAAK,gCAAgC,EAC7C,cAAc,MAAM,iBAAiB,EACrC,QAAQ,KAAK,iDAAiD,CAC/D;AAEH,MAAM,8BACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KAAK,gCAAgC,EAC7C,cAAc,MAAM,iBAAiB,EACrC,QAAQ,KACN,+DACD,CACF;AAEH,MAAM,0CACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,4FACD,CACF;AAEH,MAAM,kCACJ,UACoB;CACpB,MAAM,cACJ,MAAM,oBAAoB,SACtB,yBACA;CACN,MAAM,WACJ,MAAM,oBAAoB,SACtB,0CACA;AACN,QAAO,WACL,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,eAAe,MAAM,cAAc,uCAAuC,MAAM,gBAAgB,QAAQ,cAAc,WACvH,CACF;;AAGH,MAAM,oCACJ,UACoB;CACpB,MAAM,OAAO,iBAAiB,MAAM,iBAAiB;AACrD,QAAO,WACL,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,mDAAmD,KAAK,WAAW,KAAK,6DACzE,CACF;;AAGH,MAAM,sCACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,gKACD,CACF;AAEH,MAAM,+BACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,yKACD,CACF;AAEH,MAAM,mCACJ,UACoB;CACpB,MAAM,QAAQ,MAAM,qBAAqB,KAAK,KAAK;AACnD,QAAO,WACL,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,SAAS,EAC7B,QAAQ,KACN,0DAA0D,MAAM,UAAU,eAAe,MAAM,4FAChG,CACF;;AAGH,MAAM,wCACJ,UAEA,WACE,QAAQ,KAAK,SAAS,EACtB,cAAc,MAAM,UAAU,EAC9B,QAAQ,KACN,0HACD,CACF;AAEH,MAAM,mCACJ,UAEA,WACE,QAAQ,KAAK,SAAS,EACtB,cAAc,MAAM,UAAU,EAC9B,QAAQ,KACN,6BAA6B,MAAM,OAAO,sJAC3C,CACF;AAEH,MAAM,iCACJ,UACoB;CACpB,MAAM,YAAY,MAAM,WACrB,KACE,EAAE,WAAW,iBACZ,KAAK,UAAU,MAAM,WAAW,KAAK,KAAK,CAAC,GAC9C,CACA,KAAK,KAAK;AACb,QAAO,WACL,QAAQ,KACN,qOAAqO,UAAU,GAChP,CACF;;AAGH,MAAM,+BACJ,UAEA,WACE,QAAQ,KAAK,kBAAkB,EAC/B,cAAc,MAAM,WAAW,EAC/B,QAAQ,KACN,0JACD,CACF;AAEH,MAAM,uCACJ,UAEA,WACE,QAAQ,KAAK,QAAQ,EACrB,cAAc,MAAM,eAAe,EACnC,QAAQ,KACN,eAAe,MAAM,cAAc,KAAK,MAAM,cAAc,4DAC7D,EACD,cAAc,MAAM,cAAc,EAClC,QAAQ,KACN,4EACD,CACF;;;;;;;AAQH,MAAa,sBAAsB,UAAgC;AACjE,KAAI,aAAa,MAAM,CAAE,QAAO,iBAAiB,MAAM;AACvD,QAAO,MAAM,MAAM,MAAM,CAAC,KACxB,MAAM,IAAI,yBAAyB,MACjC,KAAK,2BAA2B,EAAE,EAAE,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC,CACzE,EACD,MAAM,IAAI,yBAAyB,MACjC,KAAK,2BAA2B,EAAE,EAAE,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC,CACzE,EACD,MAAM,IAAI,qCAAqC,MAC7C,KACE,uCAAuC,EAAE,EACzC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,6BAA6B,MACrC,KACE,+BAA+B,EAAE,EACjC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,+BAA+B,MACvC,KACE,iCAAiC,EAAE,EACnC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,iCAAiC,MACzC,KACE,mCAAmC,EAAE,EACrC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,0BAA0B,MAClC,KAAK,4BAA4B,EAAE,EAAE,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC,CAC1E,EACD,MAAM,IAAI,8BAA8B,MACtC,KACE,gCAAgC,EAAE,EAClC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,kCAAkC,MAC1C,KACE,oCAAoC,EAAE,EACtC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,mCAAmC,MAC3C,KACE,qCAAqC,EAAE,EACvC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,8BAA8B,MACtC,KACE,gCAAgC,EAAE,EAClC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,4BAA4B,MACpC,KACE,8BAA8B,EAAE,EAChC,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF,EACD,MAAM,IAAI,0BAA0B,MAClC,KAAK,4BAA4B,EAAE,EAAE,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC,CAC1E,EACD,MAAM,WACP;;AAGH,MAAa,mBAAmB,UAC9B,OAAO,WAAW,QAAQ,MAAM,mBAAmB,MAAM,CAAC,CAAC;;;;;;;AAU7D,MAAa,aACX,WAEA,OAAO,KACL,OAAO,UAAU,UACf,eAAe,MAAM,GAAG,gBAAgB,MAAM,GAAG,OAAO,KACzD,CACF;;;;;;;AAQH,MAAa,eACX,WAEA,OAAO,QAAQ,OAAO,IAAI,QAAQ,OAAO,KAAQ,EAAE,iBAAiB,UAClE,gBAAgB,MAAM,CAAC,KAAK,OAAO,GAAG,OAAO,MAAS,CAAC,CAAC,CACzD"}
@@ -1,6 +1,9 @@
1
1
  import { ConvexDirectory } from "./ConvexDirectory.mjs";
2
- import { Effect, Ref, Schema } from "effect";
3
- import { FileSystem, Path } from "@effect/platform";
2
+ import * as Effect from "effect/Effect";
3
+ import * as FileSystem from "@effect/platform/FileSystem";
4
+ import * as Path from "@effect/platform/Path";
5
+ import * as Ref from "effect/Ref";
6
+ import * as Schema from "effect/Schema";
4
7
 
5
8
  //#region src/ConfectDirectory.ts
6
9
  var ConfectDirectory = class extends Effect.Service()("@confect/cli/ConfectDirectory", {
@@ -1 +1 @@
1
- {"version":3,"file":"ConfectDirectory.mjs","names":[],"sources":["../src/ConfectDirectory.ts"],"sourcesContent":["import { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Ref, Schema } from \"effect\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\n\nexport class ConfectDirectory extends Effect.Service<ConfectDirectory>()(\n \"@confect/cli/ConfectDirectory\",\n {\n effect: Effect.gen(function* () {\n const convexDirectory = yield* findConfectDirectory;\n\n const ref = yield* Ref.make<string>(convexDirectory);\n\n return { get: Ref.get(ref) } as const;\n }),\n dependencies: [ConvexDirectory.Default],\n accessors: true,\n },\n) {}\n\nexport class ConfectDirectoryNotFoundError extends Schema.TaggedError<ConfectDirectoryNotFoundError>()(\n \"ConfectDirectoryNotFoundError\",\n {},\n) {\n override get message(): string {\n return \"Could not find Confect directory\";\n }\n}\n\nexport const findConfectDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectDirectory = path.join(path.dirname(convexDirectory), \"confect\");\n\n if (yield* fs.exists(confectDirectory)) {\n return confectDirectory;\n } else {\n return yield* new ConfectDirectoryNotFoundError();\n }\n});\n"],"mappings":";;;;;AAIA,IAAa,mBAAb,cAAsC,OAAO,SAA2B,CACtE,iCACA;CACE,QAAQ,OAAO,IAAI,aAAa;EAC9B,MAAM,kBAAkB,OAAO;EAE/B,MAAM,MAAM,OAAO,IAAI,KAAa,gBAAgB;AAEpD,SAAO,EAAE,KAAK,IAAI,IAAI,IAAI,EAAE;GAC5B;CACF,cAAc,CAAC,gBAAgB,QAAQ;CACvC,WAAW;CACZ,CACF,CAAC;AAEF,IAAa,gCAAb,cAAmD,OAAO,aAA4C,CACpG,iCACA,EAAE,CACH,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO;;;AAIX,MAAa,uBAAuB,OAAO,IAAI,aAAa;CAC1D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,mBAAmB,KAAK,KAAK,KAAK,QAAQ,gBAAgB,EAAE,UAAU;AAE5E,KAAI,OAAO,GAAG,OAAO,iBAAiB,CACpC,QAAO;KAEP,QAAO,OAAO,IAAI,+BAA+B;EAEnD"}
1
+ {"version":3,"file":"ConfectDirectory.mjs","names":[],"sources":["../src/ConfectDirectory.ts"],"sourcesContent":["import * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport * as Effect from \"effect/Effect\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\n\nexport class ConfectDirectory extends Effect.Service<ConfectDirectory>()(\n \"@confect/cli/ConfectDirectory\",\n {\n effect: Effect.gen(function* () {\n const convexDirectory = yield* findConfectDirectory;\n\n const ref = yield* Ref.make<string>(convexDirectory);\n\n return { get: Ref.get(ref) } as const;\n }),\n dependencies: [ConvexDirectory.Default],\n accessors: true,\n },\n) {}\n\nexport class ConfectDirectoryNotFoundError extends Schema.TaggedError<ConfectDirectoryNotFoundError>()(\n \"ConfectDirectoryNotFoundError\",\n {},\n) {\n override get message(): string {\n return \"Could not find Confect directory\";\n }\n}\n\nexport const findConfectDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectDirectory = path.join(path.dirname(convexDirectory), \"confect\");\n\n if (yield* fs.exists(confectDirectory)) {\n return confectDirectory;\n } else {\n return yield* new ConfectDirectoryNotFoundError();\n }\n});\n"],"mappings":";;;;;;;;AAOA,IAAa,mBAAb,cAAsC,OAAO,SAA2B,CACtE,iCACA;CACE,QAAQ,OAAO,IAAI,aAAa;EAC9B,MAAM,kBAAkB,OAAO;EAE/B,MAAM,MAAM,OAAO,IAAI,KAAa,gBAAgB;AAEpD,SAAO,EAAE,KAAK,IAAI,IAAI,IAAI,EAAE;GAC5B;CACF,cAAc,CAAC,gBAAgB,QAAQ;CACvC,WAAW;CACZ,CACF,CAAC;AAEF,IAAa,gCAAb,cAAmD,OAAO,aAA4C,CACpG,iCACA,EAAE,CACH,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO;;;AAIX,MAAa,uBAAuB,OAAO,IAAI,aAAa;CAC1D,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,kBAAkB,OAAO,gBAAgB;CAE/C,MAAM,mBAAmB,KAAK,KAAK,KAAK,QAAQ,gBAAgB,EAAE,UAAU;AAE5E,KAAI,OAAO,GAAG,OAAO,iBAAiB,CACpC,QAAO;KAEP,QAAO,OAAO,IAAI,+BAA+B;EAEnD"}
@@ -1,6 +1,10 @@
1
1
  import { ProjectRoot } from "./ProjectRoot.mjs";
2
- import { Effect, Option, Ref, Schema } from "effect";
3
- import { FileSystem, Path } from "@effect/platform";
2
+ import * as Effect from "effect/Effect";
3
+ import * as FileSystem from "@effect/platform/FileSystem";
4
+ import * as Path from "@effect/platform/Path";
5
+ import * as Option from "effect/Option";
6
+ import * as Ref from "effect/Ref";
7
+ import * as Schema from "effect/Schema";
4
8
 
5
9
  //#region src/ConvexDirectory.ts
6
10
  var ConvexDirectory = class extends Effect.Service()("@confect/cli/ConvexDirectory", {
@@ -1 +1 @@
1
- {"version":3,"file":"ConvexDirectory.mjs","names":[],"sources":["../src/ConvexDirectory.ts"],"sourcesContent":["import { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Option, Ref, Schema } from \"effect\";\nimport { ProjectRoot } from \"./ProjectRoot\";\n\nexport class ConvexDirectory extends Effect.Service<ConvexDirectory>()(\n \"@confect/cli/ConvexDirectory\",\n {\n effect: Effect.gen(function* () {\n const convexDirectory = yield* findConvexDirectory;\n\n const ref = yield* Ref.make<string>(convexDirectory);\n\n return { get: Ref.get(ref) } as const;\n }),\n dependencies: [ProjectRoot.Default],\n accessors: true,\n },\n) {}\n\nexport class ConvexDirectoryNotFoundError extends Schema.TaggedError<ConvexDirectoryNotFoundError>()(\n \"ConvexDirectoryNotFoundError\",\n {},\n) {\n override get message(): string {\n return \"Could not find Convex directory\";\n }\n}\n\n/**\n * Schema for `convex.json` configuration file.\n * @see https://docs.convex.dev/production/project-configuration\n */\nconst ConvexJsonConfig = Schema.parseJson(\n Schema.Struct({\n functions: Schema.optional(Schema.String),\n }),\n);\n\nconst findConvexDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const projectRoot = yield* ProjectRoot.get;\n\n const defaultPath = path.join(projectRoot, \"convex\");\n\n const convexJsonPath = path.join(projectRoot, \"convex.json\");\n\n const convexDirectory = yield* Effect.if(fs.exists(convexJsonPath), {\n onTrue: () =>\n fs.readFileString(convexJsonPath).pipe(\n Effect.andThen(Schema.decodeOption(ConvexJsonConfig)),\n Effect.map((config) =>\n Option.fromNullable(config.functions).pipe(\n Option.map((functionsDir) => path.join(projectRoot, functionsDir)),\n ),\n ),\n Effect.andThen(Option.getOrElse(() => defaultPath)),\n ),\n onFalse: () => Effect.succeed(defaultPath),\n });\n\n if (yield* fs.exists(convexDirectory)) {\n return convexDirectory;\n } else {\n return yield* new ConvexDirectoryNotFoundError();\n }\n});\n"],"mappings":";;;;;AAIA,IAAa,kBAAb,cAAqC,OAAO,SAA0B,CACpE,gCACA;CACE,QAAQ,OAAO,IAAI,aAAa;EAC9B,MAAM,kBAAkB,OAAO;EAE/B,MAAM,MAAM,OAAO,IAAI,KAAa,gBAAgB;AAEpD,SAAO,EAAE,KAAK,IAAI,IAAI,IAAI,EAAE;GAC5B;CACF,cAAc,CAAC,YAAY,QAAQ;CACnC,WAAW;CACZ,CACF,CAAC;AAEF,IAAa,+BAAb,cAAkD,OAAO,aAA2C,CAClG,gCACA,EAAE,CACH,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO;;;;;;;AAQX,MAAM,mBAAmB,OAAO,UAC9B,OAAO,OAAO,EACZ,WAAW,OAAO,SAAS,OAAO,OAAO,EAC1C,CAAC,CACH;AAED,MAAM,sBAAsB,OAAO,IAAI,aAAa;CAClD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,cAAc,OAAO,YAAY;CAEvC,MAAM,cAAc,KAAK,KAAK,aAAa,SAAS;CAEpD,MAAM,iBAAiB,KAAK,KAAK,aAAa,cAAc;CAE5D,MAAM,kBAAkB,OAAO,OAAO,GAAG,GAAG,OAAO,eAAe,EAAE;EAClE,cACE,GAAG,eAAe,eAAe,CAAC,KAChC,OAAO,QAAQ,OAAO,aAAa,iBAAiB,CAAC,EACrD,OAAO,KAAK,WACV,OAAO,aAAa,OAAO,UAAU,CAAC,KACpC,OAAO,KAAK,iBAAiB,KAAK,KAAK,aAAa,aAAa,CAAC,CACnE,CACF,EACD,OAAO,QAAQ,OAAO,gBAAgB,YAAY,CAAC,CACpD;EACH,eAAe,OAAO,QAAQ,YAAY;EAC3C,CAAC;AAEF,KAAI,OAAO,GAAG,OAAO,gBAAgB,CACnC,QAAO;KAEP,QAAO,OAAO,IAAI,8BAA8B;EAElD"}
1
+ {"version":3,"file":"ConvexDirectory.mjs","names":[],"sources":["../src/ConvexDirectory.ts"],"sourcesContent":["import * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as Schema from \"effect/Schema\";\nimport { ProjectRoot } from \"./ProjectRoot\";\n\nexport class ConvexDirectory extends Effect.Service<ConvexDirectory>()(\n \"@confect/cli/ConvexDirectory\",\n {\n effect: Effect.gen(function* () {\n const convexDirectory = yield* findConvexDirectory;\n\n const ref = yield* Ref.make<string>(convexDirectory);\n\n return { get: Ref.get(ref) } as const;\n }),\n dependencies: [ProjectRoot.Default],\n accessors: true,\n },\n) {}\n\nexport class ConvexDirectoryNotFoundError extends Schema.TaggedError<ConvexDirectoryNotFoundError>()(\n \"ConvexDirectoryNotFoundError\",\n {},\n) {\n override get message(): string {\n return \"Could not find Convex directory\";\n }\n}\n\n/**\n * Schema for `convex.json` configuration file.\n * @see https://docs.convex.dev/production/project-configuration\n */\nconst ConvexJsonConfig = Schema.parseJson(\n Schema.Struct({\n functions: Schema.optional(Schema.String),\n }),\n);\n\nconst findConvexDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n const projectRoot = yield* ProjectRoot.get;\n\n const defaultPath = path.join(projectRoot, \"convex\");\n\n const convexJsonPath = path.join(projectRoot, \"convex.json\");\n\n const convexDirectory = yield* Effect.if(fs.exists(convexJsonPath), {\n onTrue: () =>\n fs.readFileString(convexJsonPath).pipe(\n Effect.andThen(Schema.decodeOption(ConvexJsonConfig)),\n Effect.map((config) =>\n Option.fromNullable(config.functions).pipe(\n Option.map((functionsDir) => path.join(projectRoot, functionsDir)),\n ),\n ),\n Effect.andThen(Option.getOrElse(() => defaultPath)),\n ),\n onFalse: () => Effect.succeed(defaultPath),\n });\n\n if (yield* fs.exists(convexDirectory)) {\n return convexDirectory;\n } else {\n return yield* new ConvexDirectoryNotFoundError();\n }\n});\n"],"mappings":";;;;;;;;;AAQA,IAAa,kBAAb,cAAqC,OAAO,SAA0B,CACpE,gCACA;CACE,QAAQ,OAAO,IAAI,aAAa;EAC9B,MAAM,kBAAkB,OAAO;EAE/B,MAAM,MAAM,OAAO,IAAI,KAAa,gBAAgB;AAEpD,SAAO,EAAE,KAAK,IAAI,IAAI,IAAI,EAAE;GAC5B;CACF,cAAc,CAAC,YAAY,QAAQ;CACnC,WAAW;CACZ,CACF,CAAC;AAEF,IAAa,+BAAb,cAAkD,OAAO,aAA2C,CAClG,gCACA,EAAE,CACH,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO;;;;;;;AAQX,MAAM,mBAAmB,OAAO,UAC9B,OAAO,OAAO,EACZ,WAAW,OAAO,SAAS,OAAO,OAAO,EAC1C,CAAC,CACH;AAED,MAAM,sBAAsB,OAAO,IAAI,aAAa;CAClD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,cAAc,OAAO,YAAY;CAEvC,MAAM,cAAc,KAAK,KAAK,aAAa,SAAS;CAEpD,MAAM,iBAAiB,KAAK,KAAK,aAAa,cAAc;CAE5D,MAAM,kBAAkB,OAAO,OAAO,GAAG,GAAG,OAAO,eAAe,EAAE;EAClE,cACE,GAAG,eAAe,eAAe,CAAC,KAChC,OAAO,QAAQ,OAAO,aAAa,iBAAiB,CAAC,EACrD,OAAO,KAAK,WACV,OAAO,aAAa,OAAO,UAAU,CAAC,KACpC,OAAO,KAAK,iBAAiB,KAAK,KAAK,aAAa,aAAa,CAAC,CACnE,CACF,EACD,OAAO,QAAQ,OAAO,gBAAgB,YAAY,CAAC,CACpD;EACH,eAAe,OAAO,QAAQ,YAAY;EAC3C,CAAC;AAEF,KAAI,OAAO,GAAG,OAAO,gBAAgB,CACnC,QAAO;KAEP,QAAO,OAAO,IAAI,8BAA8B;EAElD"}
@@ -1,5 +1,5 @@
1
1
  import { GroupPath } from "./GroupPath.mjs";
2
- import { Schema } from "effect";
2
+ import * as Schema from "effect/Schema";
3
3
 
4
4
  //#region src/FunctionPath.ts
5
5
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as GroupPath from \"./GroupPath\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,eAAe,CAAC;CAC3E,WAAWA;CACX,MAAM,OAAO;CACd,CAAC,CAAC;;;;AAKH,MAAa,aAAa,iBACxB,aAAa"}
1
+ {"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,eAAe,CAAC;CAC3E,WAAWA;CACX,MAAM,OAAO;CACd,CAAC,CAAC;;;;AAKH,MAAa,aAAa,iBACxB,aAAa"}
@@ -1,7 +1,11 @@
1
1
  import { append, make as make$1 } from "./GroupPath.mjs";
2
2
  import { FunctionPath, groupPath } from "./FunctionPath.mjs";
3
3
  import { GroupPaths } from "./GroupPaths.mjs";
4
- import { HashSet, Option, Record, Schema, pipe } from "effect";
4
+ import * as HashSet from "effect/HashSet";
5
+ import * as Option from "effect/Option";
6
+ import { pipe } from "effect/Function";
7
+ import * as Schema from "effect/Schema";
8
+ import * as Record from "effect/Record";
5
9
 
6
10
  //#region src/FunctionPaths.ts
7
11
  const FunctionPaths = Schema.HashSetFromSelf(FunctionPath).pipe(Schema.brand("@confect/cli/FunctionPaths"));
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import type { GroupSpec, Spec } from \"@confect/core\";\nimport { HashSet, Option, pipe, Record, Schema } from \"effect\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\n\nexport const FunctionPaths = Schema.HashSetFromSelf(\n FunctionPath.FunctionPath,\n).pipe(Schema.brand(\"@confect/cli/FunctionPaths\"));\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(spec.groups, Option.none(), FunctionPaths.make(HashSet.empty()));\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, functionName) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name: functionName,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(\n functionPaths,\n HashSet.map(FunctionPath.groupPath),\n GroupPaths.GroupPaths.make,\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n GroupPaths.GroupPaths.make,\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;AAMA,MAAa,gBAAgB,OAAO,gBAClCA,aACD,CAAC,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAGlD,MAAa,QAAQ,SACnB,WAAW,KAAK,QAAQ,OAAO,MAAM,EAAE,cAAc,KAAK,QAAQ,OAAO,CAAC,CAAC;AAE7E,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAM,YAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,UAAU,CAAC;EACzC,SAAS,SAASC,OAAiB,MAAM,UAAU;EACpD,CAAC;CAEF,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,iBACV,cAAc,KACZ,QAAQ,IACN,mBAC0B,KAAK;EAC7B;EACA,MAAM;EACP,CAAC,CACH,CACF,CACJ;AAED,QAAO,WAAW,MAAM,QAAQ,OAAO,KAAK,UAAU,EAAE,iBAAiB;EACzE;AAEJ,MAAa,cACX,kBAEA,KACE,eACA,QAAQ,IAAIC,UAAuB,aACb,KACvB;AAEH,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,iBAAiB;CAClD,MAAM,iBAAiB,WAAW,kBAAkB;CAEpD,MAAM,yBAAoC,KACxC,QAAQ,WAAW,eAAe,eAAe,CAClD;CACD,MAAM,2BAAsC,KAC1C,QAAQ,WAAW,gBAAgB,cAAc,CAClD;CAED,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,kBAAkB,CACxD;CACD,MAAM,qDAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,eAAe,CAAC,CAChE;CAED,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,iBAAiB,CACxD;CACD,MAAM,uDAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,iBAAiB,CAAC,CACnE;AASD,QAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,0CAA0C,EACxD,QAAQ,WAAW,QAAQ,MAAM,aAAa,cAAc,CAAC,aACvC,KACvB;EAQA"}
1
+ {"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import type { GroupSpec, Spec } from \"@confect/core\";\nimport { pipe } from \"effect/Function\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\n\nexport const FunctionPaths = Schema.HashSetFromSelf(\n FunctionPath.FunctionPath,\n).pipe(Schema.brand(\"@confect/cli/FunctionPaths\"));\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(spec.groups, Option.none(), FunctionPaths.make(HashSet.empty()));\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, functionName) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name: functionName,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(\n functionPaths,\n HashSet.map(FunctionPath.groupPath),\n GroupPaths.GroupPaths.make,\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n GroupPaths.GroupPaths.make,\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,gBAAgB,OAAO,gBAClCA,aACD,CAAC,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAGlD,MAAa,QAAQ,SACnB,WAAW,KAAK,QAAQ,OAAO,MAAM,EAAE,cAAc,KAAK,QAAQ,OAAO,CAAC,CAAC;AAE7E,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAM,YAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,UAAU,CAAC;EACzC,SAAS,SAASC,OAAiB,MAAM,UAAU;EACpD,CAAC;CAEF,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,iBACV,cAAc,KACZ,QAAQ,IACN,mBAC0B,KAAK;EAC7B;EACA,MAAM;EACP,CAAC,CACH,CACF,CACJ;AAED,QAAO,WAAW,MAAM,QAAQ,OAAO,KAAK,UAAU,EAAE,iBAAiB;EACzE;AAEJ,MAAa,cACX,kBAEA,KACE,eACA,QAAQ,IAAIC,UAAuB,aACb,KACvB;AAEH,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,iBAAiB;CAClD,MAAM,iBAAiB,WAAW,kBAAkB;CAEpD,MAAM,yBAAoC,KACxC,QAAQ,WAAW,eAAe,eAAe,CAClD;CACD,MAAM,2BAAsC,KAC1C,QAAQ,WAAW,gBAAgB,cAAc,CAClD;CAED,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,kBAAkB,CACxD;CACD,MAAM,qDAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,eAAe,CAAC,CAChE;CAED,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,iBAAiB,CACxD;CACD,MAAM,uDAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,iBAAiB,CAAC,CACnE;AASD,QAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,0CAA0C,EACxD,QAAQ,WAAW,QAAQ,MAAM,aAAa,cAAc,CAAC,aACvC,KACvB;EAQA"}
@@ -1,6 +1,13 @@
1
- import { Array, Data, Effect, Option, Record, Schema, String, pipe } from "effect";
1
+ import * as Effect from "effect/Effect";
2
2
  import "@confect/core";
3
- import { Path } from "@effect/platform";
3
+ import * as Path from "@effect/platform/Path";
4
+ import * as Array from "effect/Array";
5
+ import * as Option from "effect/Option";
6
+ import { pipe } from "effect/Function";
7
+ import * as Schema from "effect/Schema";
8
+ import * as String from "effect/String";
9
+ import * as Data from "effect/Data";
10
+ import * as Record from "effect/Record";
4
11
 
5
12
  //#region src/GroupPath.ts
6
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"GroupPath.mjs","names":[],"sources":["../src/GroupPath.ts"],"sourcesContent":["import { type GroupSpec, type Spec } from \"@confect/core\";\nimport { Path } from \"@effect/platform\";\nimport {\n Array,\n Data,\n Effect,\n Option,\n pipe,\n Record,\n Schema,\n String,\n} from \"effect\";\n\n/**\n * The path to a group in the Confect API.\n */\nexport class GroupPath extends Schema.Class<GroupPath>(\"GroupPath\")({\n pathSegments: Schema.Data(Schema.NonEmptyArray(Schema.NonEmptyString)),\n}) {}\n\n/**\n * Create a GroupPath from path segments.\n */\nexport const make = (pathSegments: readonly [string, ...string[]]): GroupPath =>\n GroupPath.make({ pathSegments: Data.array(pathSegments) });\n\n/**\n * Append a group name to a GroupPath to create a new GroupPath.\n */\nexport const append = (groupPath: GroupPath, groupName: string): GroupPath =>\n make([...groupPath.pathSegments, groupName]);\n\n/**\n * Expects a path string of the form `./group1/group2.ts`, relative to the Convex functions directory.\n */\nexport const fromGroupModulePath = (groupModulePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n const { dir, name, ext } = path.parse(groupModulePath);\n\n if (ext === \".ts\") {\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n yield* Effect.logDebug(Array.append(dirSegments, name));\n return make(Array.append(dirSegments, name));\n } else {\n return yield* new GroupModulePathIsNotATypeScriptFileError({\n path: groupModulePath,\n });\n }\n });\n\n/**\n * Get the module path for a group, relative to the Convex functions directory.\n */\nexport const modulePath = (groupPath: GroupPath) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return path.join(...groupPath.pathSegments) + \".ts\";\n });\n\nexport const getGroupSpec = (\n spec: Spec.AnyWithProps,\n groupPath: GroupPath,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n groupPath.pathSegments,\n Array.matchLeft({\n onEmpty: () => Option.none(),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(spec.groups, head),\n Option.flatMap((group) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(group, tail)\n : Option.some(group),\n ),\n ),\n }),\n );\n\nconst getGroupSpecHelper = (\n group: GroupSpec.AnyWithProps,\n remainingPath: ReadonlyArray<string>,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n remainingPath,\n Array.matchLeft({\n onEmpty: () => Option.some(group),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(group.groups, head),\n Option.flatMap((subGroup) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(subGroup, tail)\n : Option.some(subGroup),\n ),\n ),\n }),\n );\n\nexport const toString = (groupPath: GroupPath) =>\n Array.join(groupPath.pathSegments, \".\");\n\nexport class GroupModulePathIsNotATypeScriptFileError extends Schema.TaggedError<GroupModulePathIsNotATypeScriptFileError>()(\n \"GroupModulePathIsNotATypeScriptFileError\",\n {\n path: Schema.NonEmptyString,\n },\n) {\n override get message(): string {\n return `Expected group module path to end with .ts, got ${this.path}`;\n }\n}\n"],"mappings":";;;;;;;;AAgBA,IAAa,YAAb,cAA+B,OAAO,MAAiB,YAAY,CAAC,EAClE,cAAc,OAAO,KAAK,OAAO,cAAc,OAAO,eAAe,CAAC,EACvE,CAAC,CAAC;;;;AAKH,MAAa,QAAQ,iBACnB,UAAU,KAAK,EAAE,cAAc,KAAK,MAAM,aAAa,EAAE,CAAC;;;;AAK5D,MAAa,UAAU,WAAsB,cAC3C,KAAK,CAAC,GAAG,UAAU,cAAc,UAAU,CAAC;;;;AAK9C,MAAa,uBAAuB,oBAClC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,gBAAgB;AAEtD,KAAI,QAAQ,OAAO;EACjB,MAAM,cAAc,MAAM,OACxB,OAAO,MAAM,KAAK,KAAK,IAAI,EAC3B,OAAO,WACR;AACD,SAAO,OAAO,SAAS,MAAM,OAAO,aAAa,KAAK,CAAC;AACvD,SAAO,KAAK,MAAM,OAAO,aAAa,KAAK,CAAC;OAE5C,QAAO,OAAO,IAAI,yCAAyC,EACzD,MAAM,iBACP,CAAC;EAEJ;;;;AAKJ,MAAa,cAAc,cACzB,OAAO,IAAI,aAAa;AAGtB,SAFa,OAAO,KAAK,MAEb,KAAK,GAAG,UAAU,aAAa,GAAG;EAC9C;AAEJ,MAAa,gBACX,MACA,cAEA,KACE,UAAU,cACV,MAAM,UAAU;CACd,eAAe,OAAO,MAAM;CAC5B,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,KAAK,QAAQ,KAAK,EAC7B,OAAO,SAAS,UACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,OAAO,KAAK,GAC/B,OAAO,KAAK,MAAM,CACvB,CACF;CACJ,CAAC,CACH;AAEH,MAAM,sBACJ,OACA,kBAEA,KACE,eACA,MAAM,UAAU;CACd,eAAe,OAAO,KAAK,MAAM;CACjC,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,MAAM,QAAQ,KAAK,EAC9B,OAAO,SAAS,aACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,UAAU,KAAK,GAClC,OAAO,KAAK,SAAS,CAC1B,CACF;CACJ,CAAC,CACH;AAEH,MAAa,YAAY,cACvB,MAAM,KAAK,UAAU,cAAc,IAAI;AAEzC,IAAa,2CAAb,cAA8D,OAAO,aAAuD,CAC1H,4CACA,EACE,MAAM,OAAO,gBACd,CACF,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO,mDAAmD,KAAK"}
1
+ {"version":3,"file":"GroupPath.mjs","names":[],"sources":["../src/GroupPath.ts"],"sourcesContent":["import { type GroupSpec, type Spec } from \"@confect/core\";\nimport * as Path from \"@effect/platform/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport * as String from \"effect/String\";\n\n/**\n * The path to a group in the Confect API.\n */\nexport class GroupPath extends Schema.Class<GroupPath>(\"GroupPath\")({\n pathSegments: Schema.Data(Schema.NonEmptyArray(Schema.NonEmptyString)),\n}) {}\n\n/**\n * Create a GroupPath from path segments.\n */\nexport const make = (pathSegments: readonly [string, ...string[]]): GroupPath =>\n GroupPath.make({ pathSegments: Data.array(pathSegments) });\n\n/**\n * Append a group name to a GroupPath to create a new GroupPath.\n */\nexport const append = (groupPath: GroupPath, groupName: string): GroupPath =>\n make([...groupPath.pathSegments, groupName]);\n\n/**\n * Expects a path string of the form `./group1/group2.ts`, relative to the Convex functions directory.\n */\nexport const fromGroupModulePath = (groupModulePath: string) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n const { dir, name, ext } = path.parse(groupModulePath);\n\n if (ext === \".ts\") {\n const dirSegments = Array.filter(\n String.split(dir, path.sep),\n String.isNonEmpty,\n );\n yield* Effect.logDebug(Array.append(dirSegments, name));\n return make(Array.append(dirSegments, name));\n } else {\n return yield* new GroupModulePathIsNotATypeScriptFileError({\n path: groupModulePath,\n });\n }\n });\n\n/**\n * Get the module path for a group, relative to the Convex functions directory.\n */\nexport const modulePath = (groupPath: GroupPath) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return path.join(...groupPath.pathSegments) + \".ts\";\n });\n\nexport const getGroupSpec = (\n spec: Spec.AnyWithProps,\n groupPath: GroupPath,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n groupPath.pathSegments,\n Array.matchLeft({\n onEmpty: () => Option.none(),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(spec.groups, head),\n Option.flatMap((group) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(group, tail)\n : Option.some(group),\n ),\n ),\n }),\n );\n\nconst getGroupSpecHelper = (\n group: GroupSpec.AnyWithProps,\n remainingPath: ReadonlyArray<string>,\n): Option.Option<GroupSpec.AnyWithProps> =>\n pipe(\n remainingPath,\n Array.matchLeft({\n onEmpty: () => Option.some(group),\n onNonEmpty: (head, tail) =>\n pipe(\n Record.get(group.groups, head),\n Option.flatMap((subGroup) =>\n Array.isNonEmptyArray(tail)\n ? getGroupSpecHelper(subGroup, tail)\n : Option.some(subGroup),\n ),\n ),\n }),\n );\n\nexport const toString = (groupPath: GroupPath) =>\n Array.join(groupPath.pathSegments, \".\");\n\nexport class GroupModulePathIsNotATypeScriptFileError extends Schema.TaggedError<GroupModulePathIsNotATypeScriptFileError>()(\n \"GroupModulePathIsNotATypeScriptFileError\",\n {\n path: Schema.NonEmptyString,\n },\n) {\n override get message(): string {\n return `Expected group module path to end with .ts, got ${this.path}`;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,IAAa,YAAb,cAA+B,OAAO,MAAiB,YAAY,CAAC,EAClE,cAAc,OAAO,KAAK,OAAO,cAAc,OAAO,eAAe,CAAC,EACvE,CAAC,CAAC;;;;AAKH,MAAa,QAAQ,iBACnB,UAAU,KAAK,EAAE,cAAc,KAAK,MAAM,aAAa,EAAE,CAAC;;;;AAK5D,MAAa,UAAU,WAAsB,cAC3C,KAAK,CAAC,GAAG,UAAU,cAAc,UAAU,CAAC;;;;AAK9C,MAAa,uBAAuB,oBAClC,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,KAAK;CAEzB,MAAM,EAAE,KAAK,MAAM,QAAQ,KAAK,MAAM,gBAAgB;AAEtD,KAAI,QAAQ,OAAO;EACjB,MAAM,cAAc,MAAM,OACxB,OAAO,MAAM,KAAK,KAAK,IAAI,EAC3B,OAAO,WACR;AACD,SAAO,OAAO,SAAS,MAAM,OAAO,aAAa,KAAK,CAAC;AACvD,SAAO,KAAK,MAAM,OAAO,aAAa,KAAK,CAAC;OAE5C,QAAO,OAAO,IAAI,yCAAyC,EACzD,MAAM,iBACP,CAAC;EAEJ;;;;AAKJ,MAAa,cAAc,cACzB,OAAO,IAAI,aAAa;AAGtB,SAFa,OAAO,KAAK,MAEb,KAAK,GAAG,UAAU,aAAa,GAAG;EAC9C;AAEJ,MAAa,gBACX,MACA,cAEA,KACE,UAAU,cACV,MAAM,UAAU;CACd,eAAe,OAAO,MAAM;CAC5B,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,KAAK,QAAQ,KAAK,EAC7B,OAAO,SAAS,UACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,OAAO,KAAK,GAC/B,OAAO,KAAK,MAAM,CACvB,CACF;CACJ,CAAC,CACH;AAEH,MAAM,sBACJ,OACA,kBAEA,KACE,eACA,MAAM,UAAU;CACd,eAAe,OAAO,KAAK,MAAM;CACjC,aAAa,MAAM,SACjB,KACE,OAAO,IAAI,MAAM,QAAQ,KAAK,EAC9B,OAAO,SAAS,aACd,MAAM,gBAAgB,KAAK,GACvB,mBAAmB,UAAU,KAAK,GAClC,OAAO,KAAK,SAAS,CAC1B,CACF;CACJ,CAAC,CACH;AAEH,MAAa,YAAY,cACvB,MAAM,KAAK,UAAU,cAAc,IAAI;AAEzC,IAAa,2CAAb,cAA8D,OAAO,aAAuD,CAC1H,4CACA,EACE,MAAM,OAAO,gBACd,CACF,CAAC;CACA,IAAa,UAAkB;AAC7B,SAAO,mDAAmD,KAAK"}
@@ -1,5 +1,5 @@
1
1
  import { GroupPath } from "./GroupPath.mjs";
2
- import { Schema } from "effect";
2
+ import * as Schema from "effect/Schema";
3
3
 
4
4
  //#region src/GroupPaths.ts
5
5
  const GroupPaths = Schema.HashSetFromSelf(GroupPath).pipe(Schema.brand("@confect/cli/GroupPaths"));
@@ -1 +1 @@
1
- {"version":3,"file":"GroupPaths.mjs","names":["GroupPath.GroupPath"],"sources":["../src/GroupPaths.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as GroupPath from \"./GroupPath\";\n\nexport const GroupPaths = Schema.HashSetFromSelf(GroupPath.GroupPath).pipe(\n Schema.brand(\"@confect/cli/GroupPaths\"),\n);\nexport type GroupPaths = typeof GroupPaths.Type;\n"],"mappings":";;;;AAGA,MAAa,aAAa,OAAO,gBAAgBA,UAAoB,CAAC,KACpE,OAAO,MAAM,0BAA0B,CACxC"}
1
+ {"version":3,"file":"GroupPaths.mjs","names":["GroupPath.GroupPath"],"sources":["../src/GroupPaths.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath\";\n\nexport const GroupPaths = Schema.HashSetFromSelf(GroupPath.GroupPath).pipe(\n Schema.brand(\"@confect/cli/GroupPaths\"),\n);\nexport type GroupPaths = typeof GroupPaths.Type;\n"],"mappings":";;;;AAGA,MAAa,aAAa,OAAO,gBAAgBA,UAAoB,CAAC,KACpE,OAAO,MAAM,0BAA0B,CACxC"}
@@ -3,9 +3,15 @@ import { bundle, directlyImports } from "./Bundler.mjs";
3
3
  import { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError } from "./CodegenError.mjs";
4
4
  import { ConfectDirectory } from "./ConfectDirectory.mjs";
5
5
  import { removePathExtension } from "./utils.mjs";
6
- import { Array, Effect, Layer, Option, Ref, String } from "effect";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Layer from "effect/Layer";
7
8
  import { GroupSpec, Registry } from "@confect/core";
8
- import { FileSystem, Path } from "@effect/platform";
9
+ import * as FileSystem from "@effect/platform/FileSystem";
10
+ import * as Path from "@effect/platform/Path";
11
+ import * as Array from "effect/Array";
12
+ import * as Option from "effect/Option";
13
+ import * as Ref from "effect/Ref";
14
+ import * as String from "effect/String";
9
15
  import * as GroupImpl from "@confect/server/GroupImpl";
10
16
 
11
17
  //#region src/LeafModule.ts
@@ -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). 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: leaf.groupPathDot,\n missingFunctionNames: missing,\n });\n }\n });\n"],"mappings":"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"}
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 * as FileSystem from \"@effect/platform/FileSystem\";\nimport * as Path from \"@effect/platform/Path\";\nimport type { Context } from \"effect\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Ref from \"effect/Ref\";\nimport * as String from \"effect/String\";\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: leaf.groupPathDot,\n missingFunctionNames: missing,\n });\n }\n });\n"],"mappings":"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"}