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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +351 -1
  2. package/dist/BuildError.mjs +9 -2
  3. package/dist/BuildError.mjs.map +1 -1
  4. package/dist/Bundler.mjs +67 -57
  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 +36 -21
  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 +20 -24
  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 +9 -11
  27. package/dist/SpecAssemblyNode.mjs.map +1 -1
  28. package/dist/TableModule.mjs +94 -0
  29. package/dist/TableModule.mjs.map +1 -0
  30. package/dist/cliApp.mjs +1 -1
  31. package/dist/cliApp.mjs.map +1 -1
  32. package/dist/confect/codegen.mjs +272 -141
  33. package/dist/confect/codegen.mjs.map +1 -1
  34. package/dist/confect/dev.mjs +36 -17
  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 +9 -4
  41. package/dist/log.mjs.map +1 -1
  42. package/dist/package.mjs +1 -1
  43. package/dist/templates.mjs +139 -48
  44. package/dist/templates.mjs.map +1 -1
  45. package/dist/utils.mjs +42 -22
  46. package/dist/utils.mjs.map +1 -1
  47. package/package.json +33 -50
  48. package/dist/index.d.mts +0 -1
  49. package/src/BuildError.ts +0 -210
  50. package/src/Bundler.ts +0 -144
  51. package/src/CodeBlockWriter.ts +0 -65
  52. package/src/CodegenError.ts +0 -344
  53. package/src/ConfectDirectory.ts +0 -42
  54. package/src/ConvexDirectory.ts +0 -68
  55. package/src/FunctionPath.ts +0 -27
  56. package/src/FunctionPaths.ts +0 -103
  57. package/src/GroupPath.ts +0 -118
  58. package/src/GroupPaths.ts +0 -7
  59. package/src/LeafModule.ts +0 -313
  60. package/src/ProjectRoot.ts +0 -50
  61. package/src/SpecAssemblyNode.ts +0 -82
  62. package/src/cliApp.ts +0 -8
  63. package/src/confect/codegen.ts +0 -589
  64. package/src/confect/dev.ts +0 -749
  65. package/src/confect.ts +0 -19
  66. package/src/index.ts +0 -22
  67. package/src/log.ts +0 -104
  68. package/src/templates.ts +0 -477
  69. package/src/utils.ts +0 -429
@@ -1 +1 @@
1
- {"version":3,"file":"Bundler.mjs","names":[],"sources":["../src/Bundler.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport { Path } from \"@effect/platform\";\nimport { Array, Effect, Option, pipe } from \"effect\";\nimport * as esbuild from \"esbuild\";\nimport { BundlerError } from \"./BuildError\";\n\nexport interface Bundled {\n readonly module: any;\n readonly metafile: esbuild.Metafile;\n}\n\nexport const EXTERNAL_PACKAGES = [\n \"@confect/core\",\n \"@confect/server\",\n \"effect\",\n \"@effect/*\",\n];\n\nconst isExternalImport = (path: string) =>\n EXTERNAL_PACKAGES.some((p) => {\n if (p.endsWith(\"/*\")) {\n return path.startsWith(p.slice(0, -1));\n }\n return path === p || path.startsWith(p + \"/\");\n });\n\nexport const absoluteExternalsPlugin: esbuild.Plugin = {\n name: \"absolute-externals\",\n setup(build) {\n build.onResolve({ filter: /.*/ }, async (args) => {\n if (args.kind !== \"import-statement\" && args.kind !== \"dynamic-import\")\n return;\n if (!isExternalImport(args.path)) return;\n // `import.meta.resolve`'s second argument is silently ignored in modern\n // Node, so resolution would always walk up from the CLI's bundled file\n // (`packages/cli/dist/utils.mjs`) instead of from the user's project.\n // Use `createRequire` keyed on the importing file's directory so we\n // resolve out of *their* `node_modules`. The synthetic filename is just\n // a CommonJS resolution anchor; the file does not need to exist.\n const parentFile = pathToFileURL(args.resolveDir + \"/_\").href;\n const require_ = createRequire(parentFile);\n const resolvedPath = require_.resolve(args.path);\n const resolved = pathToFileURL(resolvedPath).href;\n return { path: resolved, external: true };\n });\n },\n};\n\nconst buildEntry = (entryPoint: string) =>\n Effect.tryPromise({\n try: () =>\n esbuild.build({\n entryPoints: [entryPoint],\n bundle: true,\n write: false,\n platform: \"node\",\n format: \"esm\",\n logLevel: \"silent\",\n metafile: true,\n plugins: [absoluteExternalsPlugin],\n }),\n catch: (cause) => new BundlerError({ cause }),\n });\n\nconst importBundledModule = (result: esbuild.BuildResult) => {\n const code = result.outputFiles![0]!.text;\n const dataUrl =\n \"data:text/javascript;base64,\" + Buffer.from(code).toString(\"base64\");\n return import(dataUrl);\n};\n\n/**\n * Bundle a TypeScript entry point with esbuild and import the result via a\n * data URL. This handles extensionless `.ts` imports regardless of whether\n * the user's project sets `\"type\": \"module\"` in package.json. The returned\n * pair carries both the imported module and the esbuild metafile so callers\n * can inspect the import graph (see {@link directlyImports}).\n */\nexport const bundle = (\n entryPoint: string,\n): Effect.Effect<Bundled, BundlerError> =>\n Effect.gen(function* () {\n const result = yield* buildEntry(entryPoint);\n const module = yield* Effect.tryPromise({\n try: () => importBundledModule(result),\n catch: (cause) => new BundlerError({ cause }),\n });\n if (!result.metafile) {\n return yield* Effect.dieMessage(\"esbuild metafile missing\");\n }\n return { module, metafile: result.metafile };\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":";;;;;;;;AAYA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACD;AAED,MAAM,oBAAoB,SACxB,kBAAkB,MAAM,MAAM;AAC5B,KAAI,EAAE,SAAS,KAAK,CAClB,QAAO,KAAK,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC;AAExC,QAAO,SAAS,KAAK,KAAK,WAAW,IAAI,IAAI;EAC7C;AAEJ,MAAa,0BAA0C;CACrD,MAAM;CACN,MAAM,OAAO;AACX,QAAM,UAAU,EAAE,QAAQ,MAAM,EAAE,OAAO,SAAS;AAChD,OAAI,KAAK,SAAS,sBAAsB,KAAK,SAAS,iBACpD;AACF,OAAI,CAAC,iBAAiB,KAAK,KAAK,CAAE;GAOlC,MAAM,aAAa,cAAc,KAAK,aAAa,KAAK,CAAC;AAIzD,UAAO;IAAE,MADQ,cAFA,cAAc,WAAW,CACZ,QAAQ,KAAK,KAAK,CACJ,CAAC;IACpB,UAAU;IAAM;IACzC;;CAEL;AAED,MAAM,cAAc,eAClB,OAAO,WAAW;CAChB,WACE,QAAQ,MAAM;EACZ,aAAa,CAAC,WAAW;EACzB,QAAQ;EACR,OAAO;EACP,UAAU;EACV,QAAQ;EACR,UAAU;EACV,UAAU;EACV,SAAS,CAAC,wBAAwB;EACnC,CAAC;CACJ,QAAQ,UAAU,IAAI,aAAa,EAAE,OAAO,CAAC;CAC9C,CAAC;AAEJ,MAAM,uBAAuB,WAAgC;CAC3D,MAAM,OAAO,OAAO,YAAa,GAAI;AAGrC,QAAO,OADL,iCAAiC,OAAO,KAAK,KAAK,CAAC,SAAS,SAAS;;;;;;;;;AAWzE,MAAa,UACX,eAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW,WAAW;CAC5C,MAAM,SAAS,OAAO,OAAO,WAAW;EACtC,WAAW,oBAAoB,OAAO;EACtC,QAAQ,UAAU,IAAI,aAAa,EAAE,OAAO,CAAC;EAC9C,CAAC;AACF,KAAI,CAAC,OAAO,SACV,QAAO,OAAO,OAAO,WAAW,2BAA2B;AAE7D,QAAO;EAAE;EAAQ,UAAU,OAAO;EAAU;EAC5C;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) =>\n Object.assign({}, i, { path: absolutize(i.path) }),\n ),\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,MAC1B,OAAO,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,WAAW,EAAE,KAAK,EAAE,CAAC,CACnD;EACF;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", {
@@ -13,11 +18,6 @@ var MissingSpecFileError = class extends Schema.TaggedError()("MissingSpecFileEr
13
18
  expectedSpecPath: Schema.String
14
19
  }) {};
15
20
  var SpecMissingDefaultGroupSpecError = class extends Schema.TaggedError()("SpecMissingDefaultGroupSpecError", { specPath: Schema.String }) {};
16
- var SpecRuntimeMismatchError = class extends Schema.TaggedError()("SpecRuntimeMismatchError", {
17
- specPath: Schema.String,
18
- expectedRuntime: Schema.Literal("Convex", "Node"),
19
- actualRuntime: Schema.Literal("Convex", "Node")
20
- }) {};
21
21
  var ImplMissingSpecImportError = class extends Schema.TaggedError()("ImplMissingSpecImportError", {
22
22
  implPath: Schema.String,
23
23
  expectedSpecPath: Schema.String
@@ -29,9 +29,23 @@ var ImplMissingFunctionsError = class extends Schema.TaggedError()("ImplMissingF
29
29
  groupPath: Schema.String,
30
30
  missingFunctionNames: Schema.Array(Schema.String)
31
31
  }) {};
32
- var SchemaInvalidDefaultExportError = class extends Schema.TaggedError()("SchemaInvalidDefaultExportError", { schemaPath: Schema.String }) {};
33
- var MissingSchemaFileError = class extends Schema.TaggedError()("MissingSchemaFileError", { schemaPath: Schema.String }) {};
34
- const CodegenError = Schema.Union(BuildError, MissingImplFileError, MissingSpecFileError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, ImplMissingSpecImportError, ImplMissingDefaultLayerError, ImplNotFinalizedError, ImplMissingFunctionsError, SchemaInvalidDefaultExportError, MissingSchemaFileError);
32
+ var ParentChildNameCollisionError = class extends Schema.TaggedError()("ParentChildNameCollisionError", {
33
+ parentSpecPath: Schema.String,
34
+ childSpecPath: Schema.String,
35
+ collisionName: Schema.String,
36
+ collisionKind: Schema.Literal("function", "group")
37
+ }) {};
38
+ var InvalidTableDefaultExportError = class extends Schema.TaggedError()("InvalidTableDefaultExportError", { tablePath: Schema.String }) {};
39
+ var InvalidTableFilenameError = class extends Schema.TaggedError()("InvalidTableFilenameError", {
40
+ tablePath: Schema.String,
41
+ reason: Schema.String
42
+ }) {};
43
+ var DuplicateTableNameError = class extends Schema.TaggedError()("DuplicateTableNameError", { collisions: Schema.Array(Schema.Struct({
44
+ tableName: Schema.String,
45
+ tablePaths: Schema.Array(Schema.String)
46
+ })) }) {};
47
+ var LegacySchemaFileError = class extends Schema.TaggedError()("LegacySchemaFileError", { schemaPath: Schema.String }) {};
48
+ const CodegenError = Schema.Union(BuildError, MissingImplFileError, MissingSpecFileError, SpecMissingDefaultGroupSpecError, ImplMissingSpecImportError, ImplMissingDefaultLayerError, ImplNotFinalizedError, ImplMissingFunctionsError, ParentChildNameCollisionError, InvalidTableDefaultExportError, InvalidTableFilenameError, DuplicateTableNameError, LegacySchemaFileError);
35
49
  const isCodegenError = (error) => {
36
50
  if (isBuildError(error)) return true;
37
51
  return Schema.is(CodegenError)(error);
@@ -46,23 +60,24 @@ const singleLine = (...parts) => pipe(cross, AnsiDoc.catWithSpace(AnsiDoc.hcat(p
46
60
  const renderMissingImplFileError = (error) => singleLine(AnsiDoc.text("Spec "), formatPathDoc(error.specPath), AnsiDoc.text(" has no sibling impl; create "), formatPathDoc(error.expectedImplPath), AnsiDoc.text(" and default-export a GroupImpl layer from it."));
47
61
  const renderMissingSpecFileError = (error) => singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(" has no sibling spec; create "), formatPathDoc(error.expectedSpecPath), AnsiDoc.text(" and default-export a GroupSpec from it, or remove the impl."));
48
62
  const renderSpecMissingDefaultGroupSpecError = (error) => singleLine(AnsiDoc.text("Spec "), formatPathDoc(error.specPath), AnsiDoc.text(" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode()."));
49
- const renderSpecRuntimeMismatchError = (error) => {
50
- const constructor = error.expectedRuntime === "Node" ? "GroupSpec.makeNode()" : "GroupSpec.make()";
51
- const moveHint = error.expectedRuntime === "Node" ? " or move the file into confect/node/." : " or move the file out of confect/node/.";
52
- return singleLine(AnsiDoc.text("Spec "), formatPathDoc(error.specPath), AnsiDoc.text(` declares a ${error.actualRuntime} GroupSpec but its location requires ${error.expectedRuntime}; use ${constructor}${moveHint}`));
53
- };
54
63
  const renderImplMissingSpecImportError = (error) => {
55
64
  const stem = stemFromSpecPath(error.expectedSpecPath);
56
65
  return singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(` does not import its sibling spec; add \`import ${stem} from "./${stem}.spec"\` and pass it to FunctionImpl.make / GroupImpl.make.`));
57
66
  };
58
- const renderImplMissingDefaultLayerError = (error) => singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(api, groupSpec).pipe(Layer.provide(...))` and `export default` it."));
59
- const renderImplNotFinalizedError = (error) => singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(api, group).pipe(Layer.provide(...), GroupImpl.finalize)`)."));
67
+ const renderImplMissingDefaultLayerError = (error) => singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(databaseSchema, groupSpec).pipe(Layer.provide(...))` and `export default` it."));
68
+ const renderImplNotFinalizedError = (error) => singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(databaseSchema, group).pipe(Layer.provide(...), GroupImpl.finalize)`)."));
60
69
  const renderImplMissingFunctionsError = (error) => {
61
70
  const names = error.missingFunctionNames.join(", ");
62
71
  return singleLine(AnsiDoc.text("Impl "), formatPathDoc(error.implPath), AnsiDoc.text(` 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.`));
63
72
  };
64
- const renderSchemaInvalidDefaultExportError = (error) => singleLine(AnsiDoc.text("Schema "), formatPathDoc(error.schemaPath), AnsiDoc.text(" must default-export a DatabaseSchema; build it with DatabaseSchema.make({ ... })."));
65
- const renderMissingSchemaFileError = (error) => singleLine(AnsiDoc.text("Schema "), formatPathDoc(error.schemaPath), AnsiDoc.text(" is required but is missing; create it and default-export a DatabaseSchema (DatabaseSchema.make({ ... }))."));
73
+ const renderInvalidTableDefaultExportError = (error) => singleLine(AnsiDoc.text("Table "), formatPathDoc(error.tablePath), AnsiDoc.text(" must default-export a Table (e.g. `export default Table.make({ ... })`); convert any named export to a default export."));
74
+ const renderInvalidTableFilenameError = (error) => singleLine(AnsiDoc.text("Table "), formatPathDoc(error.tablePath), AnsiDoc.text(` 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.`));
75
+ const renderDuplicateTableNameError = (error) => {
76
+ const conflicts = error.collisions.map(({ tableName, tablePaths }) => `\`${tableName}\` (${tablePaths.join(", ")})`).join("; ");
77
+ return singleLine(AnsiDoc.text(`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}.`));
78
+ };
79
+ const renderLegacySchemaFileError = (error) => singleLine(AnsiDoc.text("Found a legacy "), formatPathDoc(error.schemaPath), AnsiDoc.text(". 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`."));
80
+ const renderParentChildNameCollisionError = (error) => singleLine(AnsiDoc.text("Spec "), formatPathDoc(error.parentSpecPath), AnsiDoc.text(` declares a ${error.collisionKind} \`${error.collisionName}\` whose name collides with the sibling subdirectory spec `), formatPathDoc(error.childSpecPath), AnsiDoc.text(`. Rename one of them so the assembled spec has a unique key at this path.`));
66
81
  /**
67
82
  * Render any {@link CodegenError} into a styled, ready-to-print string.
68
83
  * Single-error variants render to a one-line `✘`-prefixed message;
@@ -71,7 +86,7 @@ const renderMissingSchemaFileError = (error) => singleLine(AnsiDoc.text("Schema
71
86
  */
72
87
  const renderCodegenError = (error) => {
73
88
  if (isBuildError(error)) return renderBuildError(error);
74
- return Match.value(error).pipe(Match.tag("MissingImplFileError", (e) => pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSpecFileError", (e) => pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecMissingDefaultGroupSpecError", (e) => pipe(renderSpecMissingDefaultGroupSpecError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecRuntimeMismatchError", (e) => pipe(renderSpecRuntimeMismatchError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingSpecImportError", (e) => pipe(renderImplMissingSpecImportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingDefaultLayerError", (e) => pipe(renderImplMissingDefaultLayerError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplNotFinalizedError", (e) => pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingFunctionsError", (e) => pipe(renderImplMissingFunctionsError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SchemaInvalidDefaultExportError", (e) => pipe(renderSchemaInvalidDefaultExportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSchemaFileError", (e) => pipe(renderMissingSchemaFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.exhaustive);
89
+ return Match.value(error).pipe(Match.tag("MissingImplFileError", (e) => pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("MissingSpecFileError", (e) => pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("SpecMissingDefaultGroupSpecError", (e) => pipe(renderSpecMissingDefaultGroupSpecError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingSpecImportError", (e) => pipe(renderImplMissingSpecImportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingDefaultLayerError", (e) => pipe(renderImplMissingDefaultLayerError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplNotFinalizedError", (e) => pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ImplMissingFunctionsError", (e) => pipe(renderImplMissingFunctionsError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("ParentChildNameCollisionError", (e) => pipe(renderParentChildNameCollisionError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("InvalidTableDefaultExportError", (e) => pipe(renderInvalidTableDefaultExportError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("InvalidTableFilenameError", (e) => pipe(renderInvalidTableFilenameError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("DuplicateTableNameError", (e) => pipe(renderDuplicateTableNameError(e), AnsiDoc.render({ style: "pretty" }))), Match.tag("LegacySchemaFileError", (e) => pipe(renderLegacySchemaFileError(e), AnsiDoc.render({ style: "pretty" }))), Match.exhaustive);
75
90
  };
76
91
  const logCodegenError = (error) => Effect.sync(() => console.error(renderCodegenError(error)));
77
92
  /**
@@ -90,5 +105,5 @@ const tapAndLog = (effect) => effect.pipe(Effect.tapError((error) => isCodegenEr
90
105
  const catchAndLog = (effect) => Effect.catchIf(Effect.map(effect, Option.some), isCodegenError, (error) => logCodegenError(error).pipe(Effect.as(Option.none())));
91
106
 
92
107
  //#endregion
93
- export { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, MissingImplFileError, MissingSchemaFileError, MissingSpecFileError, SchemaInvalidDefaultExportError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError, catchAndLog, tapAndLog };
108
+ export { DuplicateTableNameError, ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, InvalidTableDefaultExportError, InvalidTableFilenameError, LegacySchemaFileError, MissingImplFileError, MissingSpecFileError, ParentChildNameCollisionError, SpecMissingDefaultGroupSpecError, catchAndLog, tapAndLog };
94
109
  //# sourceMappingURL=CodegenError.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodegenError.mjs","names":[],"sources":["../src/CodegenError.ts"],"sourcesContent":["import { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Effect, Match, Option, pipe, Schema } from \"effect\";\nimport { BuildError, isBuildError, renderBuildError } from \"./BuildError\";\nimport { formatPathDoc } from \"./log\";\n\n// --- Variants ---\n\nexport class MissingImplFileError extends Schema.TaggedError<MissingImplFileError>()(\n \"MissingImplFileError\",\n {\n specPath: Schema.String,\n expectedImplPath: Schema.String,\n },\n) {}\n\nexport class MissingSpecFileError extends Schema.TaggedError<MissingSpecFileError>()(\n \"MissingSpecFileError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class SpecMissingDefaultGroupSpecError extends Schema.TaggedError<SpecMissingDefaultGroupSpecError>()(\n \"SpecMissingDefaultGroupSpecError\",\n {\n specPath: Schema.String,\n },\n) {}\n\nexport class SpecRuntimeMismatchError extends Schema.TaggedError<SpecRuntimeMismatchError>()(\n \"SpecRuntimeMismatchError\",\n {\n specPath: Schema.String,\n expectedRuntime: Schema.Literal(\"Convex\", \"Node\"),\n actualRuntime: Schema.Literal(\"Convex\", \"Node\"),\n },\n) {}\n\nexport class ImplMissingSpecImportError extends Schema.TaggedError<ImplMissingSpecImportError>()(\n \"ImplMissingSpecImportError\",\n {\n implPath: Schema.String,\n expectedSpecPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingDefaultLayerError extends Schema.TaggedError<ImplMissingDefaultLayerError>()(\n \"ImplMissingDefaultLayerError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplNotFinalizedError extends Schema.TaggedError<ImplNotFinalizedError>()(\n \"ImplNotFinalizedError\",\n {\n implPath: Schema.String,\n },\n) {}\n\nexport class ImplMissingFunctionsError extends Schema.TaggedError<ImplMissingFunctionsError>()(\n \"ImplMissingFunctionsError\",\n {\n implPath: Schema.String,\n groupPath: Schema.String,\n missingFunctionNames: Schema.Array(Schema.String),\n },\n) {}\n\nexport class SchemaInvalidDefaultExportError extends Schema.TaggedError<SchemaInvalidDefaultExportError>()(\n \"SchemaInvalidDefaultExportError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport class MissingSchemaFileError extends Schema.TaggedError<MissingSchemaFileError>()(\n \"MissingSchemaFileError\",\n {\n schemaPath: Schema.String,\n },\n) {}\n\nexport const CodegenError = Schema.Union(\n BuildError,\n MissingImplFileError,\n MissingSpecFileError,\n SpecMissingDefaultGroupSpecError,\n SpecRuntimeMismatchError,\n ImplMissingSpecImportError,\n ImplMissingDefaultLayerError,\n ImplNotFinalizedError,\n ImplMissingFunctionsError,\n SchemaInvalidDefaultExportError,\n MissingSchemaFileError,\n);\nexport type CodegenError = typeof CodegenError.Type;\n\nexport const isCodegenError = (error: unknown): error is CodegenError => {\n if (isBuildError(error)) return true;\n return Schema.is(CodegenError)(error);\n};\n\n// --- Per-variant rendering ---\n\nconst cross = pipe(AnsiDoc.char(\"✘\"), AnsiDoc.annotate(Ansi.red));\n\nconst stemFromSpecPath = (specPath: string): string => {\n const lastSep = Math.max(\n specPath.lastIndexOf(\"/\"),\n specPath.lastIndexOf(\"\\\\\"),\n );\n const basename = lastSep < 0 ? specPath : specPath.slice(lastSep + 1);\n return basename.endsWith(\".spec.ts\")\n ? basename.slice(0, -\".spec.ts\".length)\n : basename;\n};\n\nconst singleLine = (\n ...parts: ReadonlyArray<AnsiDoc.AnsiDoc>\n): AnsiDoc.AnsiDoc => pipe(cross, AnsiDoc.catWithSpace(AnsiDoc.hcat(parts)));\n\nconst renderMissingImplFileError = (\n error: MissingImplFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\" has no sibling impl; create \"),\n formatPathDoc(error.expectedImplPath),\n AnsiDoc.text(\" and default-export a GroupImpl layer from it.\"),\n );\n\nconst renderMissingSpecFileError = (\n error: MissingSpecFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\" has no sibling spec; create \"),\n formatPathDoc(error.expectedSpecPath),\n AnsiDoc.text(\n \" and default-export a GroupSpec from it, or remove the impl.\",\n ),\n );\n\nconst renderSpecMissingDefaultGroupSpecError = (\n error: SpecMissingDefaultGroupSpecError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n \" must default-export a GroupSpec; build it with GroupSpec.make() or GroupSpec.makeNode().\",\n ),\n );\n\nconst renderSpecRuntimeMismatchError = (\n error: SpecRuntimeMismatchError,\n): AnsiDoc.AnsiDoc => {\n const constructor =\n error.expectedRuntime === \"Node\"\n ? \"GroupSpec.makeNode()\"\n : \"GroupSpec.make()\";\n const moveHint =\n error.expectedRuntime === \"Node\"\n ? \" or move the file into confect/node/.\"\n : \" or move the file out of confect/node/.\";\n return singleLine(\n AnsiDoc.text(\"Spec \"),\n formatPathDoc(error.specPath),\n AnsiDoc.text(\n ` declares a ${error.actualRuntime} GroupSpec but its location requires ${error.expectedRuntime}; use ${constructor}${moveHint}`,\n ),\n );\n};\n\nconst renderImplMissingSpecImportError = (\n error: ImplMissingSpecImportError,\n): AnsiDoc.AnsiDoc => {\n const stem = stemFromSpecPath(error.expectedSpecPath);\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not import its sibling spec; add \\`import ${stem} from \"./${stem}.spec\"\\` and pass it to FunctionImpl.make / GroupImpl.make.`,\n ),\n );\n};\n\nconst renderImplMissingDefaultLayerError = (\n error: ImplMissingDefaultLayerError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" must default-export a GroupImpl layer; wrap your handlers with `GroupImpl.make(api, groupSpec).pipe(Layer.provide(...))` and `export default` it.\",\n ),\n );\n\nconst renderImplNotFinalizedError = (\n error: ImplNotFinalizedError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n \" is not finalized; append `GroupImpl.finalize` to the end of the pipeline (e.g. `GroupImpl.make(api, group).pipe(Layer.provide(...), GroupImpl.finalize)`).\",\n ),\n );\n\nconst renderImplMissingFunctionsError = (\n error: ImplMissingFunctionsError,\n): AnsiDoc.AnsiDoc => {\n const names = error.missingFunctionNames.join(\", \");\n return singleLine(\n AnsiDoc.text(\"Impl \"),\n formatPathDoc(error.implPath),\n AnsiDoc.text(\n ` does not implement every function declared by group \\`${error.groupPath}\\`; missing: ${names}. Add a \\`FunctionImpl.make\\` for each missing function and provide it to the group layer.`,\n ),\n );\n};\n\nconst renderSchemaInvalidDefaultExportError = (\n error: SchemaInvalidDefaultExportError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" must default-export a DatabaseSchema; build it with DatabaseSchema.make({ ... }).\",\n ),\n );\n\nconst renderMissingSchemaFileError = (\n error: MissingSchemaFileError,\n): AnsiDoc.AnsiDoc =>\n singleLine(\n AnsiDoc.text(\"Schema \"),\n formatPathDoc(error.schemaPath),\n AnsiDoc.text(\n \" is required but is missing; create it and default-export a DatabaseSchema (DatabaseSchema.make({ ... })).\",\n ),\n );\n\n/**\n * Render any {@link CodegenError} into a styled, ready-to-print string.\n * Single-error variants render to a one-line `✘`-prefixed message;\n * `BundleFailedError` (the only multi-error variant) renders to a header\n * plus an esbuild diagnostic block.\n */\nexport const renderCodegenError = (error: CodegenError): string => {\n if (isBuildError(error)) return renderBuildError(error);\n return Match.value(error).pipe(\n Match.tag(\"MissingImplFileError\", (e) =>\n pipe(renderMissingImplFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"MissingSpecFileError\", (e) =>\n pipe(renderMissingSpecFileError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"SpecMissingDefaultGroupSpecError\", (e) =>\n pipe(\n renderSpecMissingDefaultGroupSpecError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SpecRuntimeMismatchError\", (e) =>\n pipe(\n renderSpecRuntimeMismatchError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingSpecImportError\", (e) =>\n pipe(\n renderImplMissingSpecImportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplMissingDefaultLayerError\", (e) =>\n pipe(\n renderImplMissingDefaultLayerError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"ImplNotFinalizedError\", (e) =>\n pipe(renderImplNotFinalizedError(e), AnsiDoc.render({ style: \"pretty\" })),\n ),\n Match.tag(\"ImplMissingFunctionsError\", (e) =>\n pipe(\n renderImplMissingFunctionsError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"SchemaInvalidDefaultExportError\", (e) =>\n pipe(\n renderSchemaInvalidDefaultExportError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.tag(\"MissingSchemaFileError\", (e) =>\n pipe(\n renderMissingSchemaFileError(e),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n ),\n Match.exhaustive,\n );\n};\n\nexport const logCodegenError = (error: CodegenError) =>\n Effect.sync(() => console.error(renderCodegenError(error)));\n\n// --- Effect combinators ---\n\n/**\n * Log any {@link CodegenError} thrown by `effect` and propagate the failure\n * unchanged so the caller's error channel is preserved (used by the\n * `codegen` command, which needs the failure to surface as a non-zero exit\n * code).\n */\nexport const tapAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E, R> =>\n effect.pipe(\n Effect.tapError((error) =>\n isCodegenError(error) ? logCodegenError(error) : Effect.void,\n ),\n );\n\n/**\n * Catch any {@link CodegenError} thrown by `effect`, log it, and resolve to\n * `Option.none()` (used by the `dev` command's sync loop, which continues\n * after a failed sync rather than exiting). Success resolves to\n * `Option.some(value)`.\n */\nexport const catchAndLog = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R> =>\n Effect.catchIf(Effect.map(effect, Option.some<A>), isCodegenError, (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n ) as Effect.Effect<Option.Option<A>, Exclude<E, CodegenError>, R>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodegenError.mjs","names":[],"sources":["../src/CodegenError.ts"],"sourcesContent":["import * 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 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 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 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(\"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,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"}
@@ -1,11 +1,17 @@
1
1
  import { fromBundlerError } from "./BuildError.mjs";
2
- import { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, SpecMissingDefaultGroupSpecError, SpecRuntimeMismatchError } from "./CodegenError.mjs";
3
- import { ConfectDirectory } from "./ConfectDirectory.mjs";
4
2
  import { bundle, directlyImports } from "./Bundler.mjs";
3
+ import { ImplMissingDefaultLayerError, ImplMissingFunctionsError, ImplMissingSpecImportError, ImplNotFinalizedError, SpecMissingDefaultGroupSpecError } from "./CodegenError.mjs";
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
@@ -41,14 +47,8 @@ const specImportPathFromGenerated = (specRelativePath) => Effect.gen(function* (
41
47
  });
42
48
  const specPathForImpl = (implRelativePath) => swapModuleSuffix(implRelativePath, IMPL_SUFFIX, SPEC_SUFFIX);
43
49
  const implPathForSpec = (specRelativePath) => swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);
44
- const isNodeLeafModule = (relativePath) => relativePath.startsWith("node/") || relativePath.startsWith("node\\");
45
- const toNodeRegistryLeaf = (leaf) => ({
46
- ...leaf,
47
- pathSegments: [leaf.exportName],
48
- groupPathDot: leaf.exportName
49
- });
50
50
  const registeredFunctionsRelativePath = (leaf) => Effect.gen(function* () {
51
- return (yield* Path.Path).join("registeredFunctions", ...leaf.pathSegments.slice(leaf.runtime === "Node" ? 1 : 0)) + ".ts";
51
+ return (yield* Path.Path).join("registeredFunctions", ...leaf.pathSegments) + ".ts";
52
52
  });
53
53
  const discoverLeafSpecFiles = Effect.gen(function* () {
54
54
  const fs = yield* FileSystem.FileSystem;
@@ -80,14 +80,12 @@ const toLeafModule = (specRelativePath) => Effect.gen(function* () {
80
80
  const exportName = yield* exportNameFromModulePath(specRelativePath);
81
81
  const { pathSegments, groupPathDot } = yield* groupPathFromRelativeModulePath(specRelativePath);
82
82
  const specImportPath = yield* specImportPathFromGenerated(specRelativePath);
83
- const runtime = isNodeLeafModule(specRelativePath) ? "Node" : "Convex";
84
83
  return {
85
84
  relativePath: specRelativePath,
86
85
  pathSegments,
87
86
  groupPathDot,
88
87
  exportName,
89
- runtime,
90
- registryGroupPathDot: runtime === "Node" ? exportName : groupPathDot,
88
+ runtime: Option.none(),
91
89
  specImportPath
92
90
  };
93
91
  });
@@ -96,20 +94,18 @@ const absoluteModulePath = (relativePath) => Effect.gen(function* () {
96
94
  return (yield* Path.Path).resolve(confectDirectory, relativePath);
97
95
  });
98
96
  /**
99
- * Validate that the leaf's spec file default-exports a `GroupSpec` whose
100
- * runtime matches the leaf's location (`Convex` for files outside
101
- * `confect/node/`, `Node` for files inside it).
97
+ * Validate that the leaf's spec file default-exports a `GroupSpec`. Returns the
98
+ * validated `GroupSpec` so callers can read its runtime and avoid re-bundling for
99
+ * later inspection (e.g. stamping `leaf.runtime` and parent/child name-collision
100
+ * checks at codegen time). The group's runtime (`Convex` vs `Node`) is whatever
101
+ * the spec declares — it is not constrained by the file's location.
102
102
  */
103
103
  const validateSpec = (leaf) => Effect.gen(function* () {
104
104
  const absolutePath = yield* absoluteModulePath(leaf.relativePath);
105
105
  const { module } = yield* bundle(absolutePath).pipe(Effect.mapError((error) => fromBundlerError(leaf.relativePath, error)));
106
106
  const groupSpec = module.default;
107
107
  if (!GroupSpec.isGroupSpec(groupSpec)) return yield* new SpecMissingDefaultGroupSpecError({ specPath: leaf.relativePath });
108
- if (groupSpec.runtime !== leaf.runtime) return yield* new SpecRuntimeMismatchError({
109
- specPath: leaf.relativePath,
110
- expectedRuntime: leaf.runtime,
111
- actualRuntime: groupSpec.runtime
112
- });
108
+ return groupSpec;
113
109
  });
114
110
  /**
115
111
  * Walk the built `Context` for a `Finalized` `GroupImpl` service value. The
@@ -157,11 +153,11 @@ const validateImpl = (leaf) => Effect.gen(function* () {
157
153
  const missing = expectedFunctionNames.filter((name) => !registeredSet.has(name));
158
154
  if (missing.length > 0) return yield* new ImplMissingFunctionsError({
159
155
  implPath: implRelativePath,
160
- groupPath: finalizedGroupImpl.groupPath,
156
+ groupPath: leaf.groupPathDot,
161
157
  missingFunctionNames: missing
162
158
  });
163
159
  });
164
160
 
165
161
  //#endregion
166
- export { discoverLeafImplFiles, discoverLeafSpecFiles, implPathForSpec, isLeafImplPath, isLeafSpecPath, registeredFunctionsRelativePath, specPathForImpl, toLeafModule, toNodeRegistryLeaf, validateImpl, validateSpec };
162
+ export { discoverLeafImplFiles, discoverLeafSpecFiles, implPathForSpec, isLeafImplPath, isLeafSpecPath, registeredFunctionsRelativePath, specPathForImpl, toLeafModule, validateImpl, validateSpec };
167
163
  //# sourceMappingURL=LeafModule.mjs.map