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

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.
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","templates.api","templates.nodeApi","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { type GroupSpec, Spec } from \"@confect/core\";\nimport * as DatabaseSchema from \"@confect/server/DatabaseSchema\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport { fromBundlerError } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n MissingImplFileError,\n MissingSchemaFileError,\n MissingSpecFileError,\n ParentChildNameCollisionError,\n SchemaInvalidDefaultExportError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport {\n discoverLeafImplFiles,\n discoverLeafSpecFiles,\n implPathForSpec,\n registeredFunctionsRelativePath,\n specPathForImpl,\n toLeafModule,\n toNodeRegistryLeaf,\n validateImpl,\n validateSpec,\n type LeafModule,\n} from \"../LeafModule\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n type SpecAssemblyNode,\n} from \"../SpecAssemblyNode\";\nimport * as templates from \"../templates\";\nimport * as Bundler from \"../Bundler\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_SPEC_PATH = \"_generated/spec.ts\";\nconst GENERATED_NODE_SPEC_PATH = \"_generated/nodeSpec.ts\";\n\nconst LEGACY_PATHS = [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n \"notesAndRandom.impl.ts\",\n \"groups.impl.ts\",\n \"_generated/registeredFunctions.ts\",\n \"_generated/nodeRegisteredFunctions.ts\",\n \"_generated/impl.ts\",\n \"_generated/nodeImpl.ts\",\n];\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler.pipe(\n Effect.asVoid,\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.tapAndLog,\n );\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n const tracker = yield* Ref.make(false);\n\n const functionPaths = yield* runCodegen.pipe(\n Effect.provideService(WriteTracker, tracker),\n );\n\n const anyWritesHappened = yield* Ref.get(tracker);\n return { functionPaths, anyWritesHappened };\n});\n\nconst runCodegen = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n // Validate schema first so its missing-file / invalid-default-export\n // diagnostics surface ahead of impl bundling, which transitively depends\n // on schema via `_generated/api.ts` and would otherwise blow up with a\n // less actionable bundler error.\n yield* validateSchema;\n const { leaves, groupSpecsByRelativePath } =\n yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);\n yield* generateAssembledSpecs(leaves);\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n yield* Effect.all(\n [generateApi, generateRefs, generateNodeApi, generateServices],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* touchConvexSchema;\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst loadAndValidateLeafModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n const groupSpec = yield* validateSpec(leaf);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return { leaf, groupSpec };\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n const leaves = Array.map(results, ({ leaf }) => leaf);\n const groupSpecsByRelativePath = new Map(\n Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),\n );\n\n return { leaves, groupSpecsByRelativePath };\n});\n\n/**\n * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}\n * when a parent leaf declares a function or subgroup whose name matches a\n * sibling subdirectory spec's segment. Without this check the colliding\n * descendant would overwrite the parent's entry in the assembled\n * `GroupSpec.groups` map at runtime, surfacing as a confusing\n * `Refs.make` error rather than a codegen-time diagnostic.\n */\nexport const validateNoParentChildNameCollisions = (\n leaves: ReadonlyArray<LeafModule>,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n) =>\n Effect.gen(function* () {\n const { convex, node } = partitionByRuntime(leaves);\n const convexNodes = assemblyNodesFromLeaves(convex);\n const nodeNodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n yield* Effect.forEach(convexNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n yield* Effect.forEach(nodeNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n });\n\nconst checkAssemblyNodeForCollisions = (\n node: SpecAssemblyNode,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n): Effect.Effect<void, ParentChildNameCollisionError> =>\n Effect.gen(function* () {\n yield* Option.match(node.importBinding, {\n onNone: () => Effect.void,\n onSome: (binding) =>\n Effect.gen(function* () {\n if (node.children.length === 0) return;\n const parentRelativePath = bindingToRelativeSpecPath(\n binding.importPath,\n );\n const parentGroupSpec =\n groupSpecsByRelativePath.get(parentRelativePath);\n if (parentGroupSpec === undefined) return;\n yield* Effect.forEach(node.children, (child) => {\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.functions,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"function\",\n }),\n );\n }\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.groups,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"group\",\n }),\n );\n }\n return Effect.void;\n });\n }),\n });\n yield* Effect.forEach(node.children, (child) =>\n checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),\n );\n });\n\n/**\n * `LeafModule.specImportPath` is the import path used from inside the\n * generated `_generated/spec.ts` (e.g. `\"../notes.spec\"`). Strip the\n * `../` prefix and re-add the `.ts` extension to recover the leaf's\n * confect-relative spec path used as the key in\n * `groupSpecsByRelativePath`.\n */\nconst bindingToRelativeSpecPath = (importPath: string): string => {\n const withoutDotDot = importPath.startsWith(\"../\")\n ? importPath.slice(3)\n : importPath;\n return `${withoutDotDot}.ts`;\n};\n\n/**\n * A child assembly node may itself be a parent without a leaf (when the\n * actual leaves live only in deeper subdirectories). In that case we\n * surface the first descendant leaf as a representative path so the\n * error message points at something the user actually wrote.\n */\nconst childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {\n if (Option.isSome(node.importBinding)) {\n return bindingToRelativeSpecPath(node.importBinding.value.importPath);\n }\n for (const child of node.children) {\n return childRepresentativeSpecPath(child);\n }\n return node.segment;\n};\n\nconst validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = new Set(specFiles);\n\n yield* Effect.forEach(implFiles, (implRelativePath) =>\n Effect.gen(function* () {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (specPaths.has(specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n });\n\nconst removeLegacyFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(LEGACY_PATHS, (relativePath) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n }),\n );\n});\n\nconst generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const { convex, node } = partitionByRuntime(leaves);\n\n if (convex.length > 0) {\n const nodes = assemblyNodesFromLeaves(convex);\n const specContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Convex\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_SPEC_PATH),\n specContents,\n );\n }\n\n if (node.length > 0) {\n const nodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n const nodeSpecContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Node\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, GENERATED_NODE_SPEC_PATH),\n nodeSpecContents,\n );\n }\n });\n\nconst validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.forEach(leaves, validateImpl);\n\nconst generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(leaves, (leaf) =>\n Effect.gen(function* () {\n const registryRelativePath =\n yield* registeredFunctionsRelativePath(leaf);\n const registryPath = path.join(\n confectDirectory,\n \"_generated\",\n registryRelativePath,\n );\n const registryDir = path.dirname(registryPath);\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(registryDir))) {\n yield* fs.makeDirectory(registryDir, { recursive: true });\n }\n\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const apiFileName = leaf.runtime === \"Node\" ? \"nodeApi.ts\" : \"api.ts\";\n const apiImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", apiFileName),\n ),\n );\n const implImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, implRelativePath),\n ),\n );\n\n const contents = yield* templates.registeredFunctionsForGroup({\n apiImportPath,\n groupPathDot: leaf.registryGroupPathDot,\n implImportPath,\n layerExportName: leaf.exportName,\n useNode: leaf.runtime === \"Node\",\n });\n\n yield* writeFileStringAndLog(registryPath, contents);\n }),\n );\n });\n\nconst removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const registryRoot = path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n );\n\n if (!(yield* fs.exists(registryRoot))) {\n return;\n }\n\n const expected = new Set(\n yield* Effect.forEach(leaves, (leaf) =>\n registeredFunctionsRelativePath(leaf),\n ),\n );\n\n const existing = yield* fs.readDirectory(registryRoot, { recursive: true });\n yield* Effect.forEach(existing, (relativePath) => {\n if (path.extname(relativePath) !== \".ts\") {\n return Effect.void;\n }\n const normalized = path.join(\"registeredFunctions\", relativePath);\n if (!expected.has(normalized)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(registryRoot, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst getGeneratedSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_SPEC_PATH);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, GENERATED_NODE_SPEC_PATH);\n});\n\nconst loadGeneratedSpec = Effect.gen(function* () {\n const specPath = yield* getGeneratedSpecPath;\n const { module: specModule } = yield* Bundler.bundle(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.dieMessage(\n \"_generated/spec.ts does not export a valid Convex Spec\",\n );\n }\n\n return spec;\n});\n\nconst loadGeneratedNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.dieMessage(\n \"_generated/nodeSpec.ts does not export a valid Node Spec\",\n );\n }\n\n return Option.some(nodeSpec);\n});\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getGeneratedSpecPath;\n\n if (!(yield* fs.exists(specPath))) {\n return emptyFunctionPaths;\n }\n\n const specEither = yield* loadGeneratedSpec.pipe(Effect.either);\n\n return yield* Either.match(specEither, {\n onLeft: () => Effect.succeed(emptyFunctionPaths),\n onRight: (spec) =>\n Effect.gen(function* () {\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n return FunctionPaths.make(mergedSpec);\n }),\n });\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* removePathIfExists(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* toModuleImportPath(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const spec = yield* loadGeneratedSpec;\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nexport const validateSchema = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n if (!(yield* fs.exists(confectSchemaPath))) {\n return yield* new MissingSchemaFileError({ schemaPath: \"schema.ts\" });\n }\n\n yield* Bundler.bundle(confectSchemaPath).pipe(\n Effect.mapError((error) => fromBundlerError(\"schema.ts\", error)),\n Effect.andThen(({ module: schemaModule }) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isDatabaseSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.fail(\n new SchemaInvalidDefaultExportError({\n schemaPath: \"schema.ts\",\n }),\n );\n }),\n );\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n\n // `validateSchema` runs once at the top of `runCodegen`; no need to\n // bundle the schema again here.\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),\n );\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? Option.some(\n yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),\n )\n : Option.none<string>();\n\n const refsContents = yield* templates.refs({\n specImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"codegen.mjs","names":["CodegenError.tapAndLog","TableModule.discover","TableModule.validate","templates.assembledSpec","templates.registeredFunctionsForGroup","Bundler.bundle","FunctionPaths.make","TableModule.TABLES_DIRNAME","templates.id","templates.tableWrapper","templates.runtimeSchema","templates.convexSchema","templates.schema","templates.services","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec, type GroupSpec } from \"@confect/core\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Array, Effect, Either, HashSet, Match, Option, Ref } from \"effect\";\nimport * as Bundler from \"../Bundler\";\nimport * as CodegenError from \"../CodegenError\";\nimport {\n LegacySchemaFileError,\n MissingImplFileError,\n MissingSpecFileError,\n ParentChildNameCollisionError,\n} from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport {\n discoverLeafImplFiles,\n discoverLeafSpecFiles,\n implPathForSpec,\n registeredFunctionsRelativePath,\n specPathForImpl,\n toLeafModule,\n toNodeRegistryLeaf,\n validateImpl,\n validateSpec,\n type LeafModule,\n} from \"../LeafModule\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n logWarn,\n} from \"../log\";\nimport {\n assemblyNodesFromLeaves,\n partitionByRuntime,\n type SpecAssemblyNode,\n} from \"../SpecAssemblyNode\";\nimport * as TableModule from \"../TableModule\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathIfExists,\n toModuleImportPath,\n touchConvexSchema,\n writeFileStringAndLog,\n WriteTracker,\n} from \"../utils\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\nconst GENERATED_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"schema.ts\"),\n);\nconst GENERATED_CONVEX_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"convexSchema.ts\"),\n);\nconst GENERATED_ID_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"id.ts\"),\n);\nconst GENERATED_TABLES_DIRNAME = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"tables\"),\n);\n\nconst LEGACY_PATHS = Effect.gen(function* () {\n const path = yield* Path.Path;\n\n return [\n \"spec.ts\",\n \"nodeSpec.ts\",\n \"impl.ts\",\n \"nodeImpl.ts\",\n path.join(GENERATED_DIRNAME, \"registeredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeRegisteredFunctions.ts\"),\n path.join(GENERATED_DIRNAME, \"impl.ts\"),\n path.join(GENERATED_DIRNAME, \"nodeImpl.ts\"),\n ];\n});\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler.pipe(\n Effect.asVoid,\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.tapAndLog,\n );\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n const tracker = yield* Ref.make(false);\n\n const functionPaths = yield* runCodegen.pipe(\n Effect.provideService(WriteTracker, tracker),\n );\n\n const anyWritesHappened = yield* Ref.get(tracker);\n return { functionPaths, anyWritesHappened };\n});\n\nconst runCodegen = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n // Reject a legacy `confect/schema.ts` up front so the user-facing\n // migration message surfaces before any bundler error from impl\n // validation (each impl imports `_generated/schema.ts`).\n yield* rejectLegacySchemaFile;\n // List `confect/tables/*.ts` (filename-only — no bundling yet) so the\n // `_generated/id.ts` constructor can be emitted *before* we bundle any\n // user-authored table module. Tables import from `_generated/id.ts` for\n // cross-table id refs, so it must exist on disk first.\n const tableModules = yield* TableModule.discover;\n yield* warnIfNoTables(tableModules);\n yield* generateIdConstructor(tableModules);\n // Now that `_generated/id.ts` is on disk, bundle each table module and\n // check its default export is an `UnnamedTable`. Surface diagnostics\n // here (rather than later) so they appear before impl-validation noise.\n yield* TableModule.validate(tableModules);\n yield* generateTableWrappers(tableModules);\n yield* removeObsoleteTableWrappers(tableModules);\n yield* generateRuntimeSchema(tableModules);\n const { leaves, groupSpecsByRelativePath } =\n yield* loadAndValidateLeafModules;\n yield* removeLegacyFiles;\n yield* validateNoParentChildNameCollisions(leaves, groupSpecsByRelativePath);\n yield* generateAssembledSpecs(leaves);\n // `_generated/api.ts` / `nodeApi.ts` are no longer imported by generated or\n // impl code (impls take the database schema from `_generated/schema`\n // directly), so remove any copies left over from earlier versions before\n // impl validation runs.\n yield* Effect.all(\n [\n removeGeneratedApi,\n generateRefs,\n removeGeneratedNodeApi,\n generateServices,\n generateConvexSchema(tableModules),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* validateImplModules(leaves);\n yield* generateGroupRegisteredFunctions(leaves);\n yield* removeObsoleteRegisteredFunctions(leaves);\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateConvexSchemaReexport,\n logGenerated(generateHttp),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n yield* touchConvexSchema;\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst loadAndValidateLeafModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const specFiles = yield* discoverLeafSpecFiles;\n\n const results = yield* Effect.forEach(specFiles, (specRelativePath) =>\n Effect.gen(function* () {\n const leaf = yield* toLeafModule(specRelativePath);\n const groupSpec = yield* validateSpec(leaf);\n\n const implRelativePath = yield* implPathForSpec(specRelativePath);\n const implAbsolutePath = path.join(confectDirectory, implRelativePath);\n if (!(yield* fs.exists(implAbsolutePath))) {\n return yield* new MissingImplFileError({\n specPath: specRelativePath,\n expectedImplPath: implRelativePath,\n });\n }\n\n return { leaf, groupSpec };\n }),\n );\n\n yield* validateOrphanImpls(specFiles);\n\n const leaves = Array.map(results, ({ leaf }) => leaf);\n const groupSpecsByRelativePath = new Map(\n Array.map(results, ({ leaf, groupSpec }) => [leaf.relativePath, groupSpec]),\n );\n\n return { leaves, groupSpecsByRelativePath };\n});\n\n/**\n * Walk the assembly tree and fail with a {@link ParentChildNameCollisionError}\n * when a parent leaf declares a function or subgroup whose name matches a\n * sibling subdirectory spec's segment. Without this check the colliding\n * descendant would overwrite the parent's entry in the assembled\n * `GroupSpec.groups` map at runtime, surfacing as a confusing\n * `Refs.make` error rather than a codegen-time diagnostic.\n */\nexport const validateNoParentChildNameCollisions = (\n leaves: ReadonlyArray<LeafModule>,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n) =>\n Effect.gen(function* () {\n const { convex, node } = partitionByRuntime(leaves);\n const convexNodes = assemblyNodesFromLeaves(convex);\n const nodeNodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n yield* Effect.forEach(convexNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n yield* Effect.forEach(nodeNodes, (n) =>\n checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),\n );\n });\n\nconst checkAssemblyNodeForCollisions = (\n node: SpecAssemblyNode,\n groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,\n): Effect.Effect<void, ParentChildNameCollisionError> =>\n Effect.gen(function* () {\n yield* Option.match(node.importBinding, {\n onNone: () => Effect.void,\n onSome: (binding) =>\n Effect.gen(function* () {\n if (node.children.length === 0) return;\n const parentRelativePath = bindingToRelativeSpecPath(\n binding.importPath,\n );\n const parentGroupSpec =\n groupSpecsByRelativePath.get(parentRelativePath);\n if (parentGroupSpec === undefined) return;\n yield* Effect.forEach(node.children, (child) => {\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.functions,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"function\",\n }),\n );\n }\n if (\n Object.prototype.hasOwnProperty.call(\n parentGroupSpec.groups,\n child.segment,\n )\n ) {\n return Effect.fail(\n new ParentChildNameCollisionError({\n parentSpecPath: parentRelativePath,\n childSpecPath: childRepresentativeSpecPath(child),\n collisionName: child.segment,\n collisionKind: \"group\",\n }),\n );\n }\n return Effect.void;\n });\n }),\n });\n yield* Effect.forEach(node.children, (child) =>\n checkAssemblyNodeForCollisions(child, groupSpecsByRelativePath),\n );\n });\n\n/**\n * `LeafModule.specImportPath` is the import path used from inside the\n * generated `_generated/spec.ts` (e.g. `\"../notes.spec\"`). Strip the\n * `../` prefix and re-add the `.ts` extension to recover the leaf's\n * confect-relative spec path used as the key in\n * `groupSpecsByRelativePath`.\n */\nconst bindingToRelativeSpecPath = (importPath: string): string => {\n const withoutDotDot = importPath.startsWith(\"../\")\n ? importPath.slice(3)\n : importPath;\n return `${withoutDotDot}.ts`;\n};\n\n/**\n * A child assembly node may itself be a parent without a leaf (when the\n * actual leaves live only in deeper subdirectories). In that case we\n * surface the first descendant leaf as a representative path so the\n * error message points at something the user actually wrote.\n */\nconst childRepresentativeSpecPath = (node: SpecAssemblyNode): string => {\n if (Option.isSome(node.importBinding)) {\n return bindingToRelativeSpecPath(node.importBinding.value.importPath);\n }\n for (const child of node.children) {\n return childRepresentativeSpecPath(child);\n }\n return node.segment;\n};\n\nconst validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const implFiles = yield* discoverLeafImplFiles;\n const specPaths = new Set(specFiles);\n\n yield* Effect.forEach(implFiles, (implRelativePath) =>\n Effect.gen(function* () {\n const specRelativePath = yield* specPathForImpl(implRelativePath);\n if (specPaths.has(specRelativePath)) {\n return;\n }\n\n const specAbsolutePath = path.join(confectDirectory, specRelativePath);\n if (!(yield* fs.exists(specAbsolutePath))) {\n return yield* new MissingSpecFileError({\n implPath: implRelativePath,\n expectedSpecPath: specRelativePath,\n });\n }\n }),\n );\n });\n\nconst removeLegacyFiles = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const legacyPaths = yield* LEGACY_PATHS;\n\n yield* Effect.forEach(legacyPaths, (relativePath) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n }),\n );\n});\n\nconst generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n const { convex, node } = partitionByRuntime(leaves);\n\n if (convex.length > 0) {\n const nodes = assemblyNodesFromLeaves(convex);\n const specContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Convex\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, generatedSpecPath),\n specContents,\n );\n }\n\n if (node.length > 0) {\n const nodes = assemblyNodesFromLeaves(\n Array.map(node, toNodeRegistryLeaf),\n );\n const nodeSpecContents = yield* templates.assembledSpec({\n nodes,\n runtime: \"Node\",\n });\n yield* writeFileStringAndLog(\n path.join(confectDirectory, generatedNodeSpecPath),\n nodeSpecContents,\n );\n }\n });\n\nconst validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.forEach(leaves, validateImpl);\n\nconst generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* Effect.forEach(leaves, (leaf) =>\n Effect.gen(function* () {\n const registryRelativePath =\n yield* registeredFunctionsRelativePath(leaf);\n const registryPath = path.join(\n confectDirectory,\n \"_generated\",\n registryRelativePath,\n );\n const registryDir = path.dirname(registryPath);\n const fs = yield* FileSystem.FileSystem;\n if (!(yield* fs.exists(registryDir))) {\n yield* fs.makeDirectory(registryDir, { recursive: true });\n }\n\n const implRelativePath = yield* implPathForSpec(leaf.relativePath);\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, \"_generated\", \"schema.ts\"),\n ),\n );\n // The group's own leaf spec (sibling of its impl), referenced\n // type-only by the registry to shape its returned record.\n const specImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, leaf.relativePath),\n ),\n );\n const implImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(registryPath),\n path.join(confectDirectory, implRelativePath),\n ),\n );\n\n const contents = yield* templates.registeredFunctionsForGroup({\n schemaImportPath,\n specImportPath,\n implImportPath,\n layerExportName: leaf.exportName,\n useNode: leaf.runtime === \"Node\",\n });\n\n yield* writeFileStringAndLog(registryPath, contents);\n }),\n );\n });\n\nconst removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const registryRoot = path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n );\n\n if (!(yield* fs.exists(registryRoot))) {\n return;\n }\n\n const expected = new Set(\n yield* Effect.forEach(leaves, (leaf) =>\n registeredFunctionsRelativePath(leaf),\n ),\n );\n\n const existing = yield* fs.readDirectory(registryRoot, { recursive: true });\n yield* Effect.forEach(existing, (relativePath) => {\n if (path.extname(relativePath) !== \".ts\") {\n return Effect.void;\n }\n const normalized = path.join(\"registeredFunctions\", relativePath);\n if (!expected.has(normalized)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(registryRoot, relativePath);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst getGeneratedSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n return path.join(confectDirectory, generatedSpecPath);\n});\n\nconst getGeneratedNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n return path.join(confectDirectory, generatedNodeSpecPath);\n});\n\nconst loadGeneratedSpec = Effect.gen(function* () {\n const specPath = yield* getGeneratedSpecPath;\n const { module: specModule } = yield* Bundler.bundle(specPath);\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.dieMessage(\n \"_generated/spec.ts does not export a valid Convex Spec\",\n );\n }\n\n return spec;\n});\n\nconst loadGeneratedNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.dieMessage(\n \"_generated/nodeSpec.ts does not export a valid Node Spec\",\n );\n }\n\n return Option.some(nodeSpec);\n});\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const specPath = yield* getGeneratedSpecPath;\n\n if (!(yield* fs.exists(specPath))) {\n return emptyFunctionPaths;\n }\n\n const specEither = yield* loadGeneratedSpec.pipe(Effect.either);\n\n return yield* Either.match(specEither, {\n onLeft: () => Effect.succeed(emptyFunctionPaths),\n onRight: (spec) =>\n Effect.gen(function* () {\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n return FunctionPaths.make(mergedSpec);\n }),\n });\n});\n\n/**\n * Remove a now-obsolete `_generated/<name>.ts` if present (and log it), for\n * projects upgrading from a version that still emitted it.\n */\nconst removeObsoleteGeneratedFile = (fileName: string) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const filePath = path.join(confectDirectory, \"_generated\", fileName);\n\n if (yield* fs.exists(filePath)) {\n yield* removePathIfExists(filePath);\n yield* logFileRemoved(filePath);\n }\n });\n\n// `_generated/api.ts` is no longer imported by generated or impl code: impls\n// take the database schema (`_generated/schema`) directly, and per-group\n// registries reference the spec type-only. Remove any stale copy.\nconst removeGeneratedApi = removeObsoleteGeneratedFile(\"api.ts\");\n\n// `_generated/nodeApi.ts` is obsolete for the same reason.\nconst removeGeneratedNodeApi = removeObsoleteGeneratedFile(\"nodeApi.ts\");\n\nconst generateFunctionModules = Effect.gen(function* () {\n const spec = yield* loadGeneratedSpec;\n const nodeSpecOption = yield* loadGeneratedNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\n/**\n * The user-authored `confect/schema.ts` is no longer supported: codegen now\n * owns both `_generated/schema.ts` (runtime) and `_generated/convexSchema.ts`\n * (deploy), derived from a single scan of `confect/tables/*.ts`. Detect a\n * stray file and fail with a clear migration message — leaving it in place\n * would silently shadow the codegen-owned `_generated/schema.ts` /\n * `_generated/convexSchema.ts`.\n */\nconst rejectLegacySchemaFile = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const legacyPath = path.join(confectDirectory, \"schema.ts\");\n\n if (yield* fs.exists(legacyPath)) {\n return yield* new LegacySchemaFileError({ schemaPath: \"schema.ts\" });\n }\n});\n\n/**\n * Surface a yellow `⚠` warning when codegen sees no tables — either the\n * `confect/tables/` directory is missing or it contains no `.ts` files.\n * Generation still succeeds (emitting an empty `DatabaseSchema` and\n * `defineSchema({})`), since action-only / table-free Confect backends\n * are legal — but the warning catches the much more common case of a\n * typoed directory or files placed under the wrong root.\n */\nconst warnIfNoTables = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n tableModules.length === 0\n ? logWarn(\n `No tables discovered in \\`confect/${TableModule.TABLES_DIRNAME}/\\`. ` +\n `Generating an empty schema; add a \\`Table.make(...)\\` module under that ` +\n `directory unless this backend is intentionally tables-free.`,\n )\n : Effect.void;\n\nconst tableModuleBindings = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n generatedFilePath: string,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedDir = path.dirname(generatedFilePath);\n\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n\n return yield* Effect.forEach(tableModules, (tm) =>\n Effect.gen(function* () {\n const wrapperAbsolutePath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const importPath = yield* toModuleImportPath(\n path.relative(generatedDir, wrapperAbsolutePath),\n );\n return {\n importPath,\n tableName: tm.tableName,\n };\n }),\n );\n });\n\nconst generateIdConstructor = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedIdPath = yield* GENERATED_ID_PATH;\n const idPath = path.join(confectDirectory, generatedIdPath);\n\n const tableNames = tableModules.map((tm) => tm.tableName);\n const contents = yield* templates.id({ tableNames });\n\n yield* writeFileStringAndLog(idPath, contents);\n });\n\nconst generateTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n yield* fs.makeDirectory(wrappersDir, { recursive: true });\n }\n\n yield* Effect.forEach(\n tableModules,\n (tm) =>\n Effect.gen(function* () {\n const wrapperPath = path.join(\n confectDirectory,\n generatedTablesDirname,\n `${tm.tableName}.ts`,\n );\n const unnamedAbsolutePath = path.join(\n confectDirectory,\n tm.relativePath,\n );\n const unnamedImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(wrapperPath), unnamedAbsolutePath),\n );\n const contents = yield* templates.tableWrapper({\n tableName: tm.tableName,\n unnamedImportPath,\n });\n yield* writeFileStringAndLog(wrapperPath, contents);\n }),\n { concurrency: \"unbounded\" },\n );\n });\n\n/**\n * Remove any stale `_generated/tables/*.ts` wrapper whose source table\n * has been deleted or renamed. Mirrors `removeObsoleteRegisteredFunctions`\n * for the wrapper directory.\n */\nconst removeObsoleteTableWrappers = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedTablesDirname = yield* GENERATED_TABLES_DIRNAME;\n const wrappersDir = path.join(confectDirectory, generatedTablesDirname);\n\n if (!(yield* fs.exists(wrappersDir))) {\n return;\n }\n\n const expected = new Set(tableModules.map((tm) => `${tm.tableName}.ts`));\n const existing = yield* fs.readDirectory(wrappersDir, { recursive: true });\n yield* Effect.forEach(existing, (entry) => {\n if (path.extname(entry) !== \".ts\") {\n return Effect.void;\n }\n if (!expected.has(entry)) {\n return Effect.gen(function* () {\n const absolutePath = path.join(wrappersDir, entry);\n if (yield* fs.exists(absolutePath)) {\n yield* removePathIfExists(absolutePath);\n yield* logFileRemoved(absolutePath);\n }\n });\n }\n return Effect.void;\n });\n });\n\nconst generateRuntimeSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaPath = path.join(confectDirectory, generatedSchemaPath);\n\n const bindings = yield* tableModuleBindings(tableModules, schemaPath);\n const contents = yield* templates.runtimeSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(schemaPath, contents);\n });\n\nconst generateConvexSchema = (\n tableModules: ReadonlyArray<TableModule.TableModule>,\n) =>\n Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const generatedConvexSchemaPath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n const convexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaPath,\n );\n\n const bindings = yield* tableModuleBindings(tableModules, convexSchemaPath);\n const contents = yield* templates.convexSchema({ tableModules: bindings });\n\n yield* writeFileStringAndLog(convexSchemaPath, contents);\n });\n\nconst generateConvexSchemaReexport = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n const generatedConvexSchemaRelativePath = yield* GENERATED_CONVEX_SCHEMA_PATH;\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n const generatedConvexSchemaPath = path.join(\n confectDirectory,\n generatedConvexSchemaRelativePath,\n );\n\n const convexSchemaImportPath = yield* toModuleImportPath(\n path.relative(path.dirname(convexSchemaPath), generatedConvexSchemaPath),\n );\n\n const schemaContents = yield* templates.schema({\n convexSchemaImportPath,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const generatedSchemaPath = yield* GENERATED_SCHEMA_PATH;\n const schemaImportPath = yield* toModuleImportPath(\n path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, generatedSchemaPath),\n ),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n\n const specImportPath = yield* toModuleImportPath(\n path.relative(refsDir, path.join(confectDirectory, generatedSpecPath)),\n );\n\n const nodeSpecPath = yield* getGeneratedNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? Option.some(\n yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),\n )\n : Option.none<string>();\n\n const refsContents = yield* templates.refs({\n specImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
@@ -5,19 +5,20 @@ import { catchAndLog } from "../CodegenError.mjs";
5
5
  import { ConvexDirectory } from "../ConvexDirectory.mjs";
6
6
  import { ConfectDirectory } from "../ConfectDirectory.mjs";
7
7
  import { FunctionPaths, diff } from "../FunctionPaths.mjs";
8
- import { absoluteExternalsPlugin } from "../Bundler.mjs";
9
8
  import { generateAuthConfig, generateCrons, generateHttp } from "../utils.mjs";
10
9
  import { discoverLeafImplFiles, isLeafImplPath, isLeafSpecPath } from "../LeafModule.mjs";
11
10
  import { codegenHandler, loadPreviousFunctionPaths } from "./codegen.mjs";
12
11
  import { Array, Chunk, Clock, Console, Duration, Effect, Equal, ExecutionStrategy, Exit, HashSet, Match, Option, Order, Queue, Ref, Scope, Stream, String, pipe } from "effect";
13
12
  import { Command } from "@effect/cli";
14
13
  import { FileSystem, Path } from "@effect/platform";
14
+ import { externalPlugin, loadTsConfig, tsconfigPathsToRegExp } from "bundle-require";
15
15
  import { Ansi, AnsiDoc } from "@effect/printer-ansi";
16
16
  import * as esbuild from "esbuild";
17
17
 
18
18
  //#region src/confect/dev.ts
19
- const GENERATED_SPEC_PATH = "_generated/spec.ts";
20
- const GENERATED_NODE_SPEC_PATH = "_generated/nodeSpec.ts";
19
+ const GENERATED_DIRNAME = "_generated";
20
+ const GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) => path.join(GENERATED_DIRNAME, "spec.ts"));
21
+ const GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) => path.join(GENERATED_DIRNAME, "nodeSpec.ts"));
21
22
  const COALESCE_QUIESCENCE = Duration.millis(300);
22
23
  const COALESCE_MAX_WAIT = Duration.seconds(5);
23
24
  const ECHO_COOLDOWN = Duration.millis(500);
@@ -38,7 +39,7 @@ const changeChar = (change) => Match.value(change).pipe(Match.when("Added", () =
38
39
  color: Ansi.red
39
40
  })), Match.when("Modified", () => ({
40
41
  char: "~",
41
- color: Ansi.yellow
42
+ color: Ansi.magenta
42
43
  })), Match.exhaustive);
43
44
  const logFileChangeIndented = (change, fullPath) => Effect.gen(function* () {
44
45
  const prefix = (yield* ProjectRoot.get) + (yield* Path.Path).sep;
@@ -162,10 +163,11 @@ const discoverEntryPoints = Effect.gen(function* () {
162
163
  pendingKey
163
164
  });
164
165
  });
166
+ const generatedSpecPath = yield* GENERATED_SPEC_PATH;
167
+ const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;
165
168
  const fixedEntryOptions = yield* Effect.all([
166
- tryEntry(GENERATED_SPEC_PATH, "specDirty"),
167
- tryEntry(GENERATED_NODE_SPEC_PATH, "specDirty"),
168
- tryEntry("schema.ts", "specDirty"),
169
+ tryEntry(generatedSpecPath, "specDirty"),
170
+ tryEntry(generatedNodeSpecPath, "specDirty"),
169
171
  tryEntry("http.ts", "httpDirty"),
170
172
  tryEntry("crons.ts", "cronsDirty"),
171
173
  tryEntry("auth.ts", "authDirty")
@@ -174,7 +176,7 @@ const discoverEntryPoints = Effect.gen(function* () {
174
176
  const implEntryOptions = yield* Effect.forEach(implRelativePaths, (relativePath) => tryEntry(relativePath, "specDirty"));
175
177
  return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);
176
178
  });
177
- const esbuildOptions = (entry, signal, pendingRef, watcherErrorsRef) => {
179
+ const esbuildOptions = (entry, notExternal, signal, pendingRef, watcherErrorsRef) => {
178
180
  const initialBuildSeenRef = Ref.unsafeMake(false);
179
181
  return {
180
182
  entryPoints: [entry.absolutePath],
@@ -184,7 +186,7 @@ const esbuildOptions = (entry, signal, pendingRef, watcherErrorsRef) => {
184
186
  platform: "node",
185
187
  format: "esm",
186
188
  logLevel: "silent",
187
- plugins: [absoluteExternalsPlugin, {
189
+ plugins: [externalPlugin({ notExternal: [...notExternal] }), {
188
190
  name: "notify-rebuild",
189
191
  setup(build) {
190
192
  build.onEnd((result) => {
@@ -208,8 +210,8 @@ const esbuildOptions = (entry, signal, pendingRef, watcherErrorsRef) => {
208
210
  }]
209
211
  };
210
212
  };
211
- const createEntryPointWatcher = (entry, signal, pendingRef, watcherErrorsRef) => Effect.acquireRelease(Effect.promise(async () => {
212
- const ctx = await esbuild.context(esbuildOptions(entry, signal, pendingRef, watcherErrorsRef));
213
+ const createEntryPointWatcher = (entry, notExternal, signal, pendingRef, watcherErrorsRef) => Effect.acquireRelease(Effect.promise(async () => {
214
+ const ctx = await esbuild.context(esbuildOptions(entry, notExternal, signal, pendingRef, watcherErrorsRef));
213
215
  await ctx.watch();
214
216
  return ctx;
215
217
  }), (ctx) => Effect.gen(function* () {
@@ -232,6 +234,7 @@ const createEntryPointWatcher = (entry, signal, pendingRef, watcherErrorsRef) =>
232
234
  const entryPointsWatcher = (signal, pendingRef, restartQueue, watcherErrorsRef) => Effect.gen(function* () {
233
235
  const parentScope = yield* Effect.scope;
234
236
  const scopesRef = yield* Ref.make(/* @__PURE__ */ new Map());
237
+ const notExternal = tsconfigPathsToRegExp(loadTsConfig(yield* ProjectRoot.get)?.data.compilerOptions?.paths ?? {});
235
238
  const sync = Effect.gen(function* () {
236
239
  const desired = yield* discoverEntryPoints;
237
240
  const desiredByPath = new Map(desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]));
@@ -244,7 +247,7 @@ const entryPointsWatcher = (signal, pendingRef, restartQueue, watcherErrorsRef)
244
247
  yield* Effect.forEach(desired, (entry) => Effect.gen(function* () {
245
248
  if ((yield* Ref.get(scopesRef)).has(entry.absolutePath)) return;
246
249
  const childScope = yield* Scope.fork(parentScope, ExecutionStrategy.sequential);
247
- yield* createEntryPointWatcher(entry, signal, pendingRef, watcherErrorsRef).pipe(Scope.extend(childScope));
250
+ yield* createEntryPointWatcher(entry, notExternal, signal, pendingRef, watcherErrorsRef).pipe(Scope.extend(childScope));
248
251
  yield* Ref.update(scopesRef, (scopes) => {
249
252
  const updated = new Map(scopes);
250
253
  updated.set(entry.absolutePath, childScope);
@@ -1 +1 @@
1
- {"version":3,"file":"dev.mjs","names":["FunctionPaths.diff","CodegenError.catchAndLog"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport {\n Array,\n Chunk,\n Clock,\n Console,\n Duration,\n Effect,\n Equal,\n ExecutionStrategy,\n Exit,\n HashSet,\n Match,\n Option,\n Order,\n pipe,\n Queue,\n Ref,\n Scope,\n Stream,\n String,\n} from \"effect\";\nimport * as esbuild from \"esbuild\";\nimport { logCoalescedBuildErrors } from \"../BuildError\";\nimport { absoluteExternalsPlugin } from \"../Bundler\";\nimport * as CodegenError from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport type * as GroupPaths from \"../GroupPaths\";\nimport {\n discoverLeafImplFiles,\n isLeafImplPath,\n isLeafSpecPath,\n} from \"../LeafModule\";\nimport {\n logFunctionAdded,\n logFunctionRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ProjectRoot } from \"../ProjectRoot\";\nimport { generateAuthConfig, generateCrons, generateHttp } from \"../utils\";\nimport { codegenHandler, loadPreviousFunctionPaths } from \"./codegen\";\n\nconst GENERATED_SPEC_PATH = \"_generated/spec.ts\";\nconst GENERATED_NODE_SPEC_PATH = \"_generated/nodeSpec.ts\";\n\n// Quiescence window: the sync loop waits this long for further signals\n// after each batch. One user edit fires `onEnd` on every esbuild\n// watcher that touches the file, and rebuild times vary across entry\n// points so the onEnds can be spread over hundreds of milliseconds.\n// The drain keeps extending its wait (bounded by `COALESCE_MAX_WAIT`)\n// until no new signals arrive within the window, collapsing the whole\n// burst into a single codegen cycle.\nconst COALESCE_QUIESCENCE = Duration.millis(300);\n\n// Upper bound on `drainUntilQuiescent` so a pathological infinite\n// signal stream can't pin the sync loop forever.\nconst COALESCE_MAX_WAIT = Duration.seconds(5);\n\n// How long to wait for esbuild watchers to react to codegen's own\n// writes (e.g. an updated `_generated/spec.ts`). Added on top of the\n// quiescence drain when codegen reported writes happened.\nconst ECHO_COOLDOWN = Duration.millis(500);\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly httpDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\ntype PendingKey = keyof Pending;\n\nconst pendingInit: Pending = {\n specDirty: false,\n httpDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\n\nconst isPendingDirty = (p: Pending): boolean =>\n p.specDirty || p.httpDirty || p.cronsDirty || p.authDirty;\n\ntype WatcherErrors = ReadonlyMap<string, readonly esbuild.Message[]>;\n\nconst emptyWatcherErrors: WatcherErrors = new Map();\n\nconst changeChar = (change: \"Added\" | \"Removed\" | \"Modified\") =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => ({ char: \"+\", color: Ansi.green })),\n Match.when(\"Removed\", () => ({ char: \"-\", color: Ansi.red })),\n Match.when(\"Modified\", () => ({ char: \"~\", color: Ansi.yellow })),\n Match.exhaustive,\n );\n\nconst logFileChangeIndented = (\n change: \"Added\" | \"Removed\" | \"Modified\",\n fullPath: string,\n) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n const { char, color } = changeChar(change);\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nconst logFunctionPathDiff = (\n previous: FunctionPaths.FunctionPaths,\n current: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n const logForGroups = (\n groupPaths: GroupPaths.GroupPaths,\n fnPaths: FunctionPaths.FunctionPaths,\n logFn: typeof logFunctionAdded,\n ) =>\n Effect.forEach(groupPaths, (gp) =>\n Effect.forEach(\n Array.fromIterable(\n HashSet.filter(fnPaths, (fp) => Equal.equals(fp.groupPath, gp)),\n ),\n logFn,\n ),\n );\n\n yield* logForGroups(groupsRemoved, functionsRemoved, logFunctionRemoved);\n yield* logForGroups(groupsAdded, functionsAdded, logFunctionAdded);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAdded,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemoved,\n );\n }),\n );\n });\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const previousFunctionPaths = yield* loadPreviousFunctionPaths;\n const initialResult = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths }) =>\n logFunctionPathDiff(previousFunctionPaths, functionPaths),\n ),\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.catchAndLog,\n );\n const initialFunctionPaths = Option.match(initialResult, {\n onNone: () => emptyFunctionPaths,\n onSome: ({ functionPaths }) => functionPaths,\n });\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const restartQueue = yield* Queue.sliding<void>(1);\n const watcherErrorsRef = yield* Ref.make<WatcherErrors>(emptyWatcherErrors);\n\n yield* Effect.all(\n [\n Effect.scoped(\n entryPointsWatcher(\n signal,\n pendingRef,\n restartQueue,\n watcherErrorsRef,\n ),\n ),\n confectStructureWatcher(signal, pendingRef, restartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths, watcherErrorsRef),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst esbuildMessageKey = (m: esbuild.Message): string =>\n `${m.location?.file ?? \"\"}:${m.location?.line ?? \"\"}:${m.location?.column ?? \"\"}:${m.text}`;\n\nconst allMessages = (errors: WatcherErrors): ReadonlyArray<esbuild.Message> =>\n pipe(Array.fromIterable(errors.values()), Array.flatten);\n\nconst dedupeWatcherErrors = (\n errors: WatcherErrors,\n): ReadonlyArray<esbuild.Message> =>\n pipe(\n allMessages(errors),\n Array.dedupeWith(\n (messageA, messageB) =>\n esbuildMessageKey(messageA) === esbuildMessageKey(messageB),\n ),\n );\n\nconst watcherErrorsSignature = (errors: WatcherErrors): string =>\n pipe(\n allMessages(errors),\n Array.map(esbuildMessageKey),\n Array.dedupe,\n Array.sort(Order.string),\n Array.join(\"\\n\"),\n );\n\n/**\n * Log any watcher errors that haven't already been logged at their\n * current signature. Suppresses the per-watcher fanout that happens\n * when one root cause (e.g. a missing import) breaks every entry\n * point's build at the same source location.\n */\nconst logChangedWatcherErrors = (\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n lastLoggedSignatureRef: Ref.Ref<string>,\n) =>\n Effect.gen(function* () {\n const errors = yield* Ref.get(watcherErrorsRef);\n const signature = watcherErrorsSignature(errors);\n const previous = yield* Ref.get(lastLoggedSignatureRef);\n if (signature === previous) return;\n yield* Ref.set(lastLoggedSignatureRef, signature);\n if (errors.size === 0) return;\n yield* logCoalescedBuildErrors(dedupeWatcherErrors(errors));\n });\n\n/**\n * Block until the signal queue has been quiet for `quiescence`. esbuild\n * watchers' `onEnd` events for a single user edit can be spread across\n * hundreds of milliseconds, so a fixed window misses late arrivals.\n * Bounded by `maxWait` so pathological signal floods can't pin the\n * loop forever.\n */\nconst drainUntilQuiescent = (\n signal: Queue.Queue<void>,\n quiescence: Duration.Duration,\n maxWait: Duration.Duration,\n) =>\n Effect.gen(function* () {\n const start = yield* Clock.currentTimeMillis;\n const maxMillis = Duration.toMillis(maxWait);\n yield* Effect.iterate(true as boolean, {\n while: (keepGoing) => keepGoing,\n body: () =>\n Effect.gen(function* () {\n yield* Effect.sleep(quiescence);\n const drained = yield* Queue.takeAll(signal);\n if (Chunk.isEmpty(drained)) return false;\n const now = yield* Clock.currentTimeMillis;\n return now - start < maxMillis;\n }),\n });\n });\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const lastLoggedErrorsRef = yield* Ref.make<string>(\"\");\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop…\");\n // Wait for the first signal of a burst, then keep absorbing\n // follow-up signals from other watchers' onEnds until the queue\n // stays quiet for `COALESCE_QUIESCENCE`.\n yield* Queue.take(signal);\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n\n yield* logChangedWatcherErrors(watcherErrorsRef, lastLoggedErrorsRef);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (!isPendingDirty(pending)) {\n // No-op signal (e.g. a late echo after a previous cycle\n // already drained). Stay silent.\n return;\n }\n\n yield* logPending(\"Dependencies may have changed, reloading…\");\n\n if (pending.specDirty) {\n const current = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths: nextFunctionPaths }) =>\n Effect.gen(function* () {\n const previous = yield* Ref.get(functionPathsRef);\n yield* logFunctionPathDiff(previous, nextFunctionPaths);\n yield* Ref.set(functionPathsRef, nextFunctionPaths);\n }),\n ),\n CodegenError.catchAndLog,\n );\n if (Option.isNone(current)) {\n return;\n }\n // Drain any stragglers from this cycle's burst (slow watchers\n // whose onEnd fired after the first quiescence) plus, when\n // codegen wrote, the echo signals esbuild emits in response\n // to our writes. Reset `pendingRef` so those drained signals\n // don't carry a dirty flag into the next cycle.\n if (current.value.anyWritesHappened) {\n yield* Effect.sleep(ECHO_COOLDOWN);\n }\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n yield* Ref.set(pendingRef, pendingInit);\n }\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.cronsDirty\n ? [syncOptionalFile(generateCrons, \"crons.ts\")]\n : []),\n ...(pending.authDirty\n ? [syncOptionalFile(generateAuthConfig, \"auth.config.ts\")]\n : []),\n ];\n\n yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles)\n ? Effect.all(dirtyOptionalFiles, { concurrency: \"unbounded\" })\n : Effect.void;\n\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n );\n });\n\ninterface EntryPoint {\n readonly absolutePath: string;\n readonly displayPath: string;\n readonly pendingKey: PendingKey;\n}\n\n/**\n * Every file whose import graph codegen should react to. Each one becomes\n * its own scoped esbuild watcher; the union of their watches gives us\n * dependency-aware tracking of anything reachable from `confect/`,\n * including files outside `confect/`.\n */\nconst discoverEntryPoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const projectRoot = yield* ProjectRoot.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const tryEntry = (relativePath: string, pendingKey: PendingKey) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (!(yield* fs.exists(absolutePath))) {\n return Option.none<EntryPoint>();\n }\n return Option.some<EntryPoint>({\n absolutePath,\n displayPath: path.relative(projectRoot, absolutePath),\n pendingKey,\n });\n });\n\n const fixedEntryOptions = yield* Effect.all([\n tryEntry(GENERATED_SPEC_PATH, \"specDirty\"),\n tryEntry(GENERATED_NODE_SPEC_PATH, \"specDirty\"),\n tryEntry(\"schema.ts\", \"specDirty\"),\n tryEntry(\"http.ts\", \"httpDirty\"),\n tryEntry(\"crons.ts\", \"cronsDirty\"),\n tryEntry(\"auth.ts\", \"authDirty\"),\n ]);\n\n const implRelativePaths = yield* discoverLeafImplFiles;\n const implEntryOptions = yield* Effect.forEach(\n implRelativePaths,\n (relativePath) => tryEntry(relativePath, \"specDirty\"),\n );\n\n return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);\n});\n\nconst esbuildOptions = (\n entry: EntryPoint,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) => {\n // First `onEnd` fires when esbuild finishes the watcher's initial\n // build. At startup that's an echo of the just-completed initial\n // codegen pass; for a watcher spawned mid-session (e.g. a newly\n // added impl) it's an echo of the codegen run that triggered the\n // restart. Either way, the entry's contents were already accounted\n // for, so we record any errors but don't flip dirty or push a\n // signal — only genuine subsequent rebuilds should do that.\n const initialBuildSeenRef = Ref.unsafeMake(false);\n return {\n entryPoints: [entry.absolutePath],\n bundle: true,\n write: false,\n metafile: true,\n platform: \"node\" as const,\n format: \"esm\" as const,\n logLevel: \"silent\" as const,\n plugins: [\n absoluteExternalsPlugin,\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n Effect.runPromise(\n Effect.gen(function* () {\n const wasInitial = yield* Ref.getAndSet(\n initialBuildSeenRef,\n true,\n );\n const isInitial = !wasInitial;\n yield* Ref.update(watcherErrorsRef, (current) => {\n const next = new Map(current);\n if (result.errors.length > 0) {\n next.set(entry.absolutePath, result.errors);\n } else {\n next.delete(entry.absolutePath);\n }\n return next;\n });\n if (isInitial && result.errors.length === 0) return;\n yield* Ref.update(pendingRef, (p) => ({\n ...p,\n [entry.pendingKey]: true,\n }));\n yield* Queue.offer(signal, undefined);\n }),\n );\n });\n },\n },\n ],\n };\n};\n\nconst createEntryPointWatcher = (\n entry: EntryPoint,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const ctx = await esbuild.context(\n esbuildOptions(entry, signal, pendingRef, watcherErrorsRef),\n );\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.gen(function* () {\n yield* Effect.promise(() => ctx.dispose());\n // Clear any errors recorded by this watcher so a disposed\n // watcher can't leave stale errors visible to the sync loop.\n yield* Ref.update(watcherErrorsRef, (current) => {\n if (!current.has(entry.absolutePath)) return current;\n const next = new Map(current);\n next.delete(entry.absolutePath);\n return next;\n });\n yield* Effect.logDebug(\n `esbuild watcher disposed: ${entry.displayPath}`,\n );\n }),\n );\n\n/**\n * Holds one scoped esbuild watcher per entry point and reconciles the set\n * whenever something offers to `restartQueue`. Adding or removing an entry\n * point only spawns/disposes the affected watcher; unchanged entries keep\n * their existing context, so a structural change doesn't churn watchers\n * for unrelated files.\n */\nconst entryPointsWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const parentScope = yield* Effect.scope;\n const scopesRef = yield* Ref.make(new Map<string, Scope.CloseableScope>());\n\n const sync = Effect.gen(function* () {\n const desired = yield* discoverEntryPoints;\n const desiredByPath = new Map(\n desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]),\n );\n const current = yield* Ref.get(scopesRef);\n\n yield* Effect.forEach(\n Array.fromIterable(current),\n ([absolutePath, childScope]) =>\n desiredByPath.has(absolutePath)\n ? Effect.void\n : Scope.close(childScope, Exit.void).pipe(\n Effect.andThen(\n Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.delete(absolutePath);\n return updated;\n }),\n ),\n ),\n );\n\n yield* Effect.forEach(desired, (entry) =>\n Effect.gen(function* () {\n const existing = yield* Ref.get(scopesRef);\n if (existing.has(entry.absolutePath)) return;\n\n const childScope = yield* Scope.fork(\n parentScope,\n ExecutionStrategy.sequential,\n );\n yield* createEntryPointWatcher(\n entry,\n signal,\n pendingRef,\n watcherErrorsRef,\n ).pipe(Scope.extend(childScope));\n yield* Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.set(entry.absolutePath, childScope);\n return updated;\n });\n }),\n );\n });\n\n yield* sync;\n\n return yield* Effect.forever(\n Queue.take(restartQueue).pipe(Effect.andThen(sync)),\n );\n });\n\n/**\n * Single recursive `fs.watch` on `confect/`. Flips the matching dirty flag\n * for any change to an entry-point-shaped file (so codegen runs without\n * waiting on a newly spawned esbuild watcher), and offers to\n * `restartQueue` when an entry point is created or removed so the watcher\n * manager picks up the new set.\n */\nconst confectStructureWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* pipe(\n fs.watch(confectDirectory, { recursive: true }),\n Stream.debounce(Duration.millis(200)),\n Stream.runForEach((event) =>\n handleConfectChange({\n relativePath: path.relative(confectDirectory, event.path),\n eventTag: event._tag,\n signal,\n pendingRef,\n restartQueue,\n }),\n ),\n );\n });\n\nconst TOP_LEVEL_OPTIONAL_KEYS: ReadonlyMap<string, PendingKey> = new Map([\n [\"http.ts\", \"httpDirty\"],\n [\"crons.ts\", \"cronsDirty\"],\n [\"auth.ts\", \"authDirty\"],\n]);\n\nconst flipDirtyAndSignal = (\n pendingRef: Ref.Ref<Pending>,\n signal: Queue.Queue<void>,\n key: PendingKey,\n restartQueue: Queue.Queue<void>,\n restart: boolean,\n) =>\n pipe(\n Ref.update(pendingRef, (p) => ({ ...p, [key]: true })),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n restart ? Queue.offer(restartQueue, undefined) : Effect.void,\n ),\n );\n\nconst handleConfectChange = ({\n relativePath,\n eventTag,\n signal,\n pendingRef,\n restartQueue,\n}: {\n relativePath: string;\n eventTag: \"Create\" | \"Update\" | \"Remove\";\n signal: Queue.Queue<void>;\n pendingRef: Ref.Ref<Pending>;\n restartQueue: Queue.Queue<void>;\n}) => {\n // _generated/ files are written by codegen itself; reacting to them here\n // would form a loop. The esbuild watchers track the generated specs as\n // entry points, so changes there flow back through `notify-rebuild`.\n if (relativePath.split(/[/\\\\]/).includes(\"_generated\")) {\n return Effect.void;\n }\n\n if (!relativePath.endsWith(\".ts\")) {\n return Effect.void;\n }\n\n const isLifecycleChange = eventTag !== \"Update\";\n\n const topLevelKey = TOP_LEVEL_OPTIONAL_KEYS.get(relativePath);\n if (topLevelKey !== undefined) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n topLevelKey,\n restartQueue,\n isLifecycleChange,\n );\n }\n\n if (relativePath === \"schema.ts\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n if (isLeafSpecPath(relativePath) || isLeafImplPath(relativePath)) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // Any other `.ts` under `confect/` (helpers like `tables/Notes.ts`).\n // Updates to such files are handled by the esbuild watcher for whichever\n // entry point imports them — its onEnd flips the right dirty flag.\n // Creates are our safety net: when a previously-missing import is added,\n // esbuild may not have its parent directory on a poll path, so we\n // re-run codegen on Create here.\n if (eventTag === \"Create\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n false,\n );\n }\n\n return Effect.void;\n};\n\nconst syncOptionalFile = (generate: typeof generateHttp, convexFile: string) =>\n pipe(\n generate,\n Effect.andThen(\n Option.match({\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Unchanged\", () => Effect.void),\n Match.whenOr(\"Added\", \"Modified\", (addedOrModified) =>\n logFileChangeIndented(addedOrModified, convexFilePath),\n ),\n Match.exhaustive,\n ),\n onNone: () =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const convexFilePath = path.join(convexDirectory, convexFile);\n\n if (yield* fs.exists(convexFilePath)) {\n yield* fs.remove(convexFilePath);\n yield* logFileChangeIndented(\"Removed\", convexFilePath);\n }\n }),\n }),\n ),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"dev.mjs","names":["FunctionPaths.diff","CodegenError.catchAndLog"],"sources":["../../src/confect/dev.ts"],"sourcesContent":["import { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport {\n Array,\n Chunk,\n Clock,\n Console,\n Duration,\n Effect,\n Equal,\n ExecutionStrategy,\n Exit,\n HashSet,\n Match,\n Option,\n Order,\n pipe,\n Queue,\n Ref,\n Scope,\n Stream,\n String,\n} from \"effect\";\nimport {\n externalPlugin,\n loadTsConfig,\n tsconfigPathsToRegExp,\n} from \"bundle-require\";\nimport * as esbuild from \"esbuild\";\nimport { logCoalescedBuildErrors } from \"../BuildError\";\nimport * as CodegenError from \"../CodegenError\";\nimport { ConfectDirectory } from \"../ConfectDirectory\";\nimport { ConvexDirectory } from \"../ConvexDirectory\";\nimport * as FunctionPaths from \"../FunctionPaths\";\nimport type * as GroupPaths from \"../GroupPaths\";\nimport {\n discoverLeafImplFiles,\n isLeafImplPath,\n isLeafSpecPath,\n} from \"../LeafModule\";\nimport {\n logFunctionAdded,\n logFunctionRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ProjectRoot } from \"../ProjectRoot\";\nimport { generateAuthConfig, generateCrons, generateHttp } from \"../utils\";\nimport { codegenHandler, loadPreviousFunctionPaths } from \"./codegen\";\n\nconst GENERATED_DIRNAME = \"_generated\";\n\nconst GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"spec.ts\"),\n);\nconst GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>\n path.join(GENERATED_DIRNAME, \"nodeSpec.ts\"),\n);\n\n// Quiescence window: the sync loop waits this long for further signals\n// after each batch. One user edit fires `onEnd` on every esbuild\n// watcher that touches the file, and rebuild times vary across entry\n// points so the onEnds can be spread over hundreds of milliseconds.\n// The drain keeps extending its wait (bounded by `COALESCE_MAX_WAIT`)\n// until no new signals arrive within the window, collapsing the whole\n// burst into a single codegen cycle.\nconst COALESCE_QUIESCENCE = Duration.millis(300);\n\n// Upper bound on `drainUntilQuiescent` so a pathological infinite\n// signal stream can't pin the sync loop forever.\nconst COALESCE_MAX_WAIT = Duration.seconds(5);\n\n// How long to wait for esbuild watchers to react to codegen's own\n// writes (e.g. an updated `_generated/spec.ts`). Added on top of the\n// quiescence drain when codegen reported writes happened.\nconst ECHO_COOLDOWN = Duration.millis(500);\n\nconst emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());\n\ntype Pending = {\n readonly specDirty: boolean;\n readonly httpDirty: boolean;\n readonly cronsDirty: boolean;\n readonly authDirty: boolean;\n};\n\ntype PendingKey = keyof Pending;\n\nconst pendingInit: Pending = {\n specDirty: false,\n httpDirty: false,\n cronsDirty: false,\n authDirty: false,\n};\n\nconst isPendingDirty = (p: Pending): boolean =>\n p.specDirty || p.httpDirty || p.cronsDirty || p.authDirty;\n\ntype WatcherErrors = ReadonlyMap<string, readonly esbuild.Message[]>;\n\nconst emptyWatcherErrors: WatcherErrors = new Map();\n\nconst changeChar = (change: \"Added\" | \"Removed\" | \"Modified\") =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => ({ char: \"+\", color: Ansi.green })),\n Match.when(\"Removed\", () => ({ char: \"-\", color: Ansi.red })),\n Match.when(\"Modified\", () => ({ char: \"~\", color: Ansi.magenta })),\n Match.exhaustive,\n );\n\nconst logFileChangeIndented = (\n change: \"Added\" | \"Removed\" | \"Modified\",\n fullPath: string,\n) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n const { char, color } = changeChar(change);\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nconst logFunctionPathDiff = (\n previous: FunctionPaths.FunctionPaths,\n current: FunctionPaths.FunctionPaths,\n) =>\n Effect.gen(function* () {\n const {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n } = FunctionPaths.diff(previous, current);\n\n const logForGroups = (\n groupPaths: GroupPaths.GroupPaths,\n fnPaths: FunctionPaths.FunctionPaths,\n logFn: typeof logFunctionAdded,\n ) =>\n Effect.forEach(groupPaths, (gp) =>\n Effect.forEach(\n Array.fromIterable(\n HashSet.filter(fnPaths, (fp) => Equal.equals(fp.groupPath, gp)),\n ),\n logFn,\n ),\n );\n\n yield* logForGroups(groupsRemoved, functionsRemoved, logFunctionRemoved);\n yield* logForGroups(groupsAdded, functionsAdded, logFunctionAdded);\n yield* Effect.forEach(groupsChanged, (gp) =>\n Effect.gen(function* () {\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsAdded, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionAdded,\n );\n yield* Effect.forEach(\n Array.fromIterable(\n HashSet.filter(functionsRemoved, (fp) =>\n Equal.equals(fp.groupPath, gp),\n ),\n ),\n logFunctionRemoved,\n );\n }),\n );\n });\n\nexport const dev = Command.make(\"dev\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n const previousFunctionPaths = yield* loadPreviousFunctionPaths;\n const initialResult = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths }) =>\n logFunctionPathDiff(previousFunctionPaths, functionPaths),\n ),\n Effect.tap(() => logSuccess(\"Generated files are up-to-date\")),\n CodegenError.catchAndLog,\n );\n const initialFunctionPaths = Option.match(initialResult, {\n onNone: () => emptyFunctionPaths,\n onSome: ({ functionPaths }) => functionPaths,\n });\n\n const pendingRef = yield* Ref.make<Pending>(pendingInit);\n const signal = yield* Queue.sliding<void>(1);\n const restartQueue = yield* Queue.sliding<void>(1);\n const watcherErrorsRef = yield* Ref.make<WatcherErrors>(emptyWatcherErrors);\n\n yield* Effect.all(\n [\n Effect.scoped(\n entryPointsWatcher(\n signal,\n pendingRef,\n restartQueue,\n watcherErrorsRef,\n ),\n ),\n confectStructureWatcher(signal, pendingRef, restartQueue),\n syncLoop(signal, pendingRef, initialFunctionPaths, watcherErrorsRef),\n ],\n { concurrency: \"unbounded\" },\n );\n }),\n).pipe(Command.withDescription(\"Start the Confect development server\"));\n\nconst esbuildMessageKey = (m: esbuild.Message): string =>\n `${m.location?.file ?? \"\"}:${m.location?.line ?? \"\"}:${m.location?.column ?? \"\"}:${m.text}`;\n\nconst allMessages = (errors: WatcherErrors): ReadonlyArray<esbuild.Message> =>\n pipe(Array.fromIterable(errors.values()), Array.flatten);\n\nconst dedupeWatcherErrors = (\n errors: WatcherErrors,\n): ReadonlyArray<esbuild.Message> =>\n pipe(\n allMessages(errors),\n Array.dedupeWith(\n (messageA, messageB) =>\n esbuildMessageKey(messageA) === esbuildMessageKey(messageB),\n ),\n );\n\nconst watcherErrorsSignature = (errors: WatcherErrors): string =>\n pipe(\n allMessages(errors),\n Array.map(esbuildMessageKey),\n Array.dedupe,\n Array.sort(Order.string),\n Array.join(\"\\n\"),\n );\n\n/**\n * Log any watcher errors that haven't already been logged at their\n * current signature. Suppresses the per-watcher fanout that happens\n * when one root cause (e.g. a missing import) breaks every entry\n * point's build at the same source location.\n */\nconst logChangedWatcherErrors = (\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n lastLoggedSignatureRef: Ref.Ref<string>,\n) =>\n Effect.gen(function* () {\n const errors = yield* Ref.get(watcherErrorsRef);\n const signature = watcherErrorsSignature(errors);\n const previous = yield* Ref.get(lastLoggedSignatureRef);\n if (signature === previous) return;\n yield* Ref.set(lastLoggedSignatureRef, signature);\n if (errors.size === 0) return;\n yield* logCoalescedBuildErrors(dedupeWatcherErrors(errors));\n });\n\n/**\n * Block until the signal queue has been quiet for `quiescence`. esbuild\n * watchers' `onEnd` events for a single user edit can be spread across\n * hundreds of milliseconds, so a fixed window misses late arrivals.\n * Bounded by `maxWait` so pathological signal floods can't pin the\n * loop forever.\n */\nconst drainUntilQuiescent = (\n signal: Queue.Queue<void>,\n quiescence: Duration.Duration,\n maxWait: Duration.Duration,\n) =>\n Effect.gen(function* () {\n const start = yield* Clock.currentTimeMillis;\n const maxMillis = Duration.toMillis(maxWait);\n yield* Effect.iterate(true as boolean, {\n while: (keepGoing) => keepGoing,\n body: () =>\n Effect.gen(function* () {\n yield* Effect.sleep(quiescence);\n const drained = yield* Queue.takeAll(signal);\n if (Chunk.isEmpty(drained)) return false;\n const now = yield* Clock.currentTimeMillis;\n return now - start < maxMillis;\n }),\n });\n });\n\nconst syncLoop = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n initialFunctionPaths: FunctionPaths.FunctionPaths,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const functionPathsRef = yield* Ref.make(initialFunctionPaths);\n const lastLoggedErrorsRef = yield* Ref.make<string>(\"\");\n\n return yield* Effect.forever(\n Effect.gen(function* () {\n yield* Effect.logDebug(\"Running sync loop…\");\n // Wait for the first signal of a burst, then keep absorbing\n // follow-up signals from other watchers' onEnds until the queue\n // stays quiet for `COALESCE_QUIESCENCE`.\n yield* Queue.take(signal);\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n\n yield* logChangedWatcherErrors(watcherErrorsRef, lastLoggedErrorsRef);\n\n const pending = yield* Ref.getAndSet(pendingRef, pendingInit);\n\n if (!isPendingDirty(pending)) {\n // No-op signal (e.g. a late echo after a previous cycle\n // already drained). Stay silent.\n return;\n }\n\n yield* logPending(\"Dependencies may have changed, reloading…\");\n\n if (pending.specDirty) {\n const current = yield* codegenHandler.pipe(\n Effect.tap(({ functionPaths: nextFunctionPaths }) =>\n Effect.gen(function* () {\n const previous = yield* Ref.get(functionPathsRef);\n yield* logFunctionPathDiff(previous, nextFunctionPaths);\n yield* Ref.set(functionPathsRef, nextFunctionPaths);\n }),\n ),\n CodegenError.catchAndLog,\n );\n if (Option.isNone(current)) {\n return;\n }\n // Drain any stragglers from this cycle's burst (slow watchers\n // whose onEnd fired after the first quiescence) plus, when\n // codegen wrote, the echo signals esbuild emits in response\n // to our writes. Reset `pendingRef` so those drained signals\n // don't carry a dirty flag into the next cycle.\n if (current.value.anyWritesHappened) {\n yield* Effect.sleep(ECHO_COOLDOWN);\n }\n yield* drainUntilQuiescent(\n signal,\n COALESCE_QUIESCENCE,\n COALESCE_MAX_WAIT,\n );\n yield* Ref.set(pendingRef, pendingInit);\n }\n\n const dirtyOptionalFiles = [\n ...(pending.httpDirty\n ? [syncOptionalFile(generateHttp, \"http.ts\")]\n : []),\n ...(pending.cronsDirty\n ? [syncOptionalFile(generateCrons, \"crons.ts\")]\n : []),\n ...(pending.authDirty\n ? [syncOptionalFile(generateAuthConfig, \"auth.config.ts\")]\n : []),\n ];\n\n yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles)\n ? Effect.all(dirtyOptionalFiles, { concurrency: \"unbounded\" })\n : Effect.void;\n\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n );\n });\n\ninterface EntryPoint {\n readonly absolutePath: string;\n readonly displayPath: string;\n readonly pendingKey: PendingKey;\n}\n\n/**\n * Every file whose import graph codegen should react to. Each one becomes\n * its own scoped esbuild watcher; the union of their watches gives us\n * dependency-aware tracking of anything reachable from `confect/`,\n * including files outside `confect/`.\n */\nconst discoverEntryPoints = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const projectRoot = yield* ProjectRoot.get;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const tryEntry = (relativePath: string, pendingKey: PendingKey) =>\n Effect.gen(function* () {\n const absolutePath = path.join(confectDirectory, relativePath);\n if (!(yield* fs.exists(absolutePath))) {\n return Option.none<EntryPoint>();\n }\n return Option.some<EntryPoint>({\n absolutePath,\n displayPath: path.relative(projectRoot, absolutePath),\n pendingKey,\n });\n });\n\n const generatedSpecPath = yield* GENERATED_SPEC_PATH;\n const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;\n\n const fixedEntryOptions = yield* Effect.all([\n tryEntry(generatedSpecPath, \"specDirty\"),\n tryEntry(generatedNodeSpecPath, \"specDirty\"),\n // `confect/schema.ts` is no longer user-authored; the runtime\n // `DatabaseSchema` lives at `_generated/schema.ts` (codegen-written,\n // so not an entry point — wiring it through esbuild would form a\n // codegen→write→onEnd→codegen loop). Updates to `confect/tables/*.ts`\n // still reach this dev loop via the impl entry points' import graphs;\n // brand-new tables are caught by the Create-event safety net below.\n tryEntry(\"http.ts\", \"httpDirty\"),\n tryEntry(\"crons.ts\", \"cronsDirty\"),\n tryEntry(\"auth.ts\", \"authDirty\"),\n ]);\n\n const implRelativePaths = yield* discoverLeafImplFiles;\n const implEntryOptions = yield* Effect.forEach(\n implRelativePaths,\n (relativePath) => tryEntry(relativePath, \"specDirty\"),\n );\n\n return Array.getSomes([...fixedEntryOptions, ...implEntryOptions]);\n});\n\nconst esbuildOptions = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) => {\n // First `onEnd` fires when esbuild finishes the watcher's initial\n // build. At startup that's an echo of the just-completed initial\n // codegen pass; for a watcher spawned mid-session (e.g. a newly\n // added impl) it's an echo of the codegen run that triggered the\n // restart. Either way, the entry's contents were already accounted\n // for, so we record any errors but don't flip dirty or push a\n // signal — only genuine subsequent rebuilds should do that.\n const initialBuildSeenRef = Ref.unsafeMake(false);\n return {\n entryPoints: [entry.absolutePath],\n bundle: true,\n write: false,\n metafile: true,\n platform: \"node\" as const,\n format: \"esm\" as const,\n logLevel: \"silent\" as const,\n plugins: [\n externalPlugin({ notExternal: [...notExternal] }),\n {\n name: \"notify-rebuild\",\n setup(build: esbuild.PluginBuild) {\n build.onEnd((result) => {\n Effect.runPromise(\n Effect.gen(function* () {\n const wasInitial = yield* Ref.getAndSet(\n initialBuildSeenRef,\n true,\n );\n const isInitial = !wasInitial;\n yield* Ref.update(watcherErrorsRef, (current) => {\n const next = new Map(current);\n if (result.errors.length > 0) {\n next.set(entry.absolutePath, result.errors);\n } else {\n next.delete(entry.absolutePath);\n }\n return next;\n });\n if (isInitial && result.errors.length === 0) return;\n yield* Ref.update(pendingRef, (p) => ({\n ...p,\n [entry.pendingKey]: true,\n }));\n yield* Queue.offer(signal, undefined);\n }),\n );\n });\n },\n },\n ],\n };\n};\n\nconst createEntryPointWatcher = (\n entry: EntryPoint,\n notExternal: ReadonlyArray<RegExp>,\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.acquireRelease(\n Effect.promise(async () => {\n const ctx = await esbuild.context(\n esbuildOptions(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ),\n );\n await ctx.watch();\n return ctx;\n }),\n (ctx) =>\n Effect.gen(function* () {\n yield* Effect.promise(() => ctx.dispose());\n // Clear any errors recorded by this watcher so a disposed\n // watcher can't leave stale errors visible to the sync loop.\n yield* Ref.update(watcherErrorsRef, (current) => {\n if (!current.has(entry.absolutePath)) return current;\n const next = new Map(current);\n next.delete(entry.absolutePath);\n return next;\n });\n yield* Effect.logDebug(\n `esbuild watcher disposed: ${entry.displayPath}`,\n );\n }),\n );\n\n/**\n * Holds one scoped esbuild watcher per entry point and reconciles the set\n * whenever something offers to `restartQueue`. Adding or removing an entry\n * point only spawns/disposes the affected watcher; unchanged entries keep\n * their existing context, so a structural change doesn't churn watchers\n * for unrelated files.\n */\nconst entryPointsWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n watcherErrorsRef: Ref.Ref<WatcherErrors>,\n) =>\n Effect.gen(function* () {\n const parentScope = yield* Effect.scope;\n const scopesRef = yield* Ref.make(new Map<string, Scope.CloseableScope>());\n const projectRoot = yield* ProjectRoot.get;\n // Discover the user's `tsconfig.json#paths` once at watcher startup so\n // `~/...`-style aliases pointing into the user's source tree get bundled\n // by esbuild instead of externalized via `bundle-require`'s `node_modules`\n // heuristic. `loadTsConfig` walks up from `projectRoot` to find a\n // `tsconfig.json`; if none exists, `paths` is empty and `notExternal` is\n // `[]`, leaving the externalization rule unchanged.\n const tsconfig = loadTsConfig(projectRoot);\n const notExternal = tsconfigPathsToRegExp(\n tsconfig?.data.compilerOptions?.paths ?? {},\n );\n\n const sync = Effect.gen(function* () {\n const desired = yield* discoverEntryPoints;\n const desiredByPath = new Map(\n desired.map((entryPoint) => [entryPoint.absolutePath, entryPoint]),\n );\n const current = yield* Ref.get(scopesRef);\n\n yield* Effect.forEach(\n Array.fromIterable(current),\n ([absolutePath, childScope]) =>\n desiredByPath.has(absolutePath)\n ? Effect.void\n : Scope.close(childScope, Exit.void).pipe(\n Effect.andThen(\n Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.delete(absolutePath);\n return updated;\n }),\n ),\n ),\n );\n\n yield* Effect.forEach(desired, (entry) =>\n Effect.gen(function* () {\n const existing = yield* Ref.get(scopesRef);\n if (existing.has(entry.absolutePath)) return;\n\n const childScope = yield* Scope.fork(\n parentScope,\n ExecutionStrategy.sequential,\n );\n yield* createEntryPointWatcher(\n entry,\n notExternal,\n signal,\n pendingRef,\n watcherErrorsRef,\n ).pipe(Scope.extend(childScope));\n yield* Ref.update(scopesRef, (scopes) => {\n const updated = new Map(scopes);\n updated.set(entry.absolutePath, childScope);\n return updated;\n });\n }),\n );\n });\n\n yield* sync;\n\n return yield* Effect.forever(\n Queue.take(restartQueue).pipe(Effect.andThen(sync)),\n );\n });\n\n/**\n * Single recursive `fs.watch` on `confect/`. Flips the matching dirty flag\n * for any change to an entry-point-shaped file (so codegen runs without\n * waiting on a newly spawned esbuild watcher), and offers to\n * `restartQueue` when an entry point is created or removed so the watcher\n * manager picks up the new set.\n */\nconst confectStructureWatcher = (\n signal: Queue.Queue<void>,\n pendingRef: Ref.Ref<Pending>,\n restartQueue: Queue.Queue<void>,\n) =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n yield* pipe(\n fs.watch(confectDirectory, { recursive: true }),\n Stream.debounce(Duration.millis(200)),\n Stream.runForEach((event) =>\n handleConfectChange({\n relativePath: path.relative(confectDirectory, event.path),\n eventTag: event._tag,\n signal,\n pendingRef,\n restartQueue,\n }),\n ),\n );\n });\n\nconst TOP_LEVEL_OPTIONAL_KEYS: ReadonlyMap<string, PendingKey> = new Map([\n [\"http.ts\", \"httpDirty\"],\n [\"crons.ts\", \"cronsDirty\"],\n [\"auth.ts\", \"authDirty\"],\n]);\n\nconst flipDirtyAndSignal = (\n pendingRef: Ref.Ref<Pending>,\n signal: Queue.Queue<void>,\n key: PendingKey,\n restartQueue: Queue.Queue<void>,\n restart: boolean,\n) =>\n pipe(\n Ref.update(pendingRef, (p) => ({ ...p, [key]: true })),\n Effect.andThen(Queue.offer(signal, undefined)),\n Effect.andThen(\n restart ? Queue.offer(restartQueue, undefined) : Effect.void,\n ),\n );\n\nconst handleConfectChange = ({\n relativePath,\n eventTag,\n signal,\n pendingRef,\n restartQueue,\n}: {\n relativePath: string;\n eventTag: \"Create\" | \"Update\" | \"Remove\";\n signal: Queue.Queue<void>;\n pendingRef: Ref.Ref<Pending>;\n restartQueue: Queue.Queue<void>;\n}) => {\n // _generated/ files are written by codegen itself; reacting to them here\n // would form a loop. The esbuild watchers track the generated specs as\n // entry points, so changes there flow back through `notify-rebuild`.\n if (relativePath.split(/[/\\\\]/).includes(\"_generated\")) {\n return Effect.void;\n }\n\n if (!relativePath.endsWith(\".ts\")) {\n return Effect.void;\n }\n\n const isLifecycleChange = eventTag !== \"Update\";\n\n const topLevelKey = TOP_LEVEL_OPTIONAL_KEYS.get(relativePath);\n if (topLevelKey !== undefined) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n topLevelKey,\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // A stray `confect/schema.ts` (now codegen-owned at\n // `_generated/schema.ts`) shouldn't exist; flagging it here ensures the\n // next codegen pass surfaces the migration error\n // (`LegacySchemaFileError`) instead of silently ignoring the file.\n if (relativePath === \"schema.ts\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n if (isLeafSpecPath(relativePath) || isLeafImplPath(relativePath)) {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n isLifecycleChange,\n );\n }\n\n // Any other `.ts` under `confect/` (helpers like `tables/notes.ts`).\n // Updates to such files are handled by the esbuild watcher for whichever\n // entry point imports them — its onEnd flips the right dirty flag.\n // Creates are our safety net: when a previously-missing import is added,\n // esbuild may not have its parent directory on a poll path, so we\n // re-run codegen on Create here.\n if (eventTag === \"Create\") {\n return flipDirtyAndSignal(\n pendingRef,\n signal,\n \"specDirty\",\n restartQueue,\n false,\n );\n }\n\n return Effect.void;\n};\n\nconst syncOptionalFile = (generate: typeof generateHttp, convexFile: string) =>\n pipe(\n generate,\n Effect.andThen(\n Option.match({\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Unchanged\", () => Effect.void),\n Match.whenOr(\"Added\", \"Modified\", (addedOrModified) =>\n logFileChangeIndented(addedOrModified, convexFilePath),\n ),\n Match.exhaustive,\n ),\n onNone: () =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const convexFilePath = path.join(convexDirectory, convexFile);\n\n if (yield* fs.exists(convexFilePath)) {\n yield* fs.remove(convexFilePath);\n yield* logFileChangeIndented(\"Removed\", convexFilePath);\n }\n }),\n }),\n ),\n );\n"],"mappings":"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"}
package/dist/log.mjs CHANGED
@@ -24,15 +24,16 @@ const logFile = (char, color) => (fullPath) => Effect.gen(function* () {
24
24
  });
25
25
  const logFileAdded = logFile("+", Ansi.green);
26
26
  const logFileRemoved = logFile("-", Ansi.red);
27
- const logFileModified = logFile("~", Ansi.yellow);
27
+ const logFileModified = logFile("~", Ansi.magenta);
28
28
  const logFunction = (char, color) => (functionPath) => Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(toString(functionPath.groupPath) + "."), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(color))])), AnsiDoc.render({ style: "pretty" })));
29
29
  const logFunctionAdded = logFunction("+", Ansi.green);
30
30
  const logFunctionRemoved = logFunction("-", Ansi.red);
31
31
  const logStatus = (char, charColor) => (message) => Console.log(pipe(AnsiDoc.char(char), AnsiDoc.annotate(charColor), AnsiDoc.catWithSpace(AnsiDoc.text(message)), AnsiDoc.render({ style: "pretty" })));
32
32
  const logSuccess = logStatus("✔︎", Ansi.green);
33
33
  const logFailure = logStatus("✘", Ansi.red);
34
- const logPending = logStatus("⭘", Ansi.yellow);
34
+ const logPending = logStatus("⭘", Ansi.cyan);
35
+ const logWarn = logStatus("⚠", Ansi.yellow);
35
36
 
36
37
  //#endregion
37
- export { formatPathDoc, logFileAdded, logFileModified, logFileRemoved, logFunctionAdded, logFunctionRemoved, logPending, logSuccess };
38
+ export { formatPathDoc, logFileAdded, logFileModified, logFileRemoved, logFunctionAdded, logFunctionRemoved, logPending, logSuccess, logWarn };
38
39
  //# sourceMappingURL=log.mjs.map
package/dist/log.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"log.mjs","names":["GroupPath.toString"],"sources":["../src/log.ts"],"sourcesContent":["import { Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Console, Effect, pipe, String } from \"effect\";\nimport type * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport { ProjectRoot } from \"./ProjectRoot\";\n\n// --- Path styling ---\n\n/**\n * Render a relative path as an AnsiDoc with the directory portion\n * dimmed (`Ansi.blackBright`) and the file leaf rendered in the\n * default terminal color. Used inline anywhere a file path appears\n * in a CLI message.\n */\nexport const formatPathDoc = (relativePath: string): AnsiDoc.AnsiDoc => {\n const lastSep = Math.max(\n relativePath.lastIndexOf(\"/\"),\n relativePath.lastIndexOf(\"\\\\\"),\n );\n const dir = lastSep < 0 ? \"\" : relativePath.slice(0, lastSep + 1);\n const leaf = lastSep < 0 ? relativePath : relativePath.slice(lastSep + 1);\n return AnsiDoc.hcat([\n pipe(AnsiDoc.text(dir), AnsiDoc.annotate(Ansi.blackBright)),\n AnsiDoc.text(leaf),\n ]);\n};\n\n// --- File operation logs ---\n\nconst logFile = (char: string, color: Ansi.Ansi) => (fullPath: string) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nexport const logFileAdded = logFile(\"+\", Ansi.green);\n\nexport const logFileRemoved = logFile(\"-\", Ansi.red);\n\nexport const logFileModified = logFile(\"~\", Ansi.yellow);\n\n// --- Function subline logs ---\n\nconst logFunction =\n (char: string, color: Ansi.Ansi) =>\n (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const logFunctionAdded = logFunction(\"+\", Ansi.green);\n\nexport const logFunctionRemoved = logFunction(\"-\", Ansi.red);\n\n// --- Process status logs ---\n\nconst logStatus = (char: string, charColor: Ansi.Ansi) => (message: string) =>\n Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(charColor),\n AnsiDoc.catWithSpace(AnsiDoc.text(message)),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const logSuccess = logStatus(\"✔︎\", Ansi.green);\n\nexport const logFailure = logStatus(\"✘\", Ansi.red);\n\nexport const logPending = logStatus(\"⭘\", Ansi.yellow);\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAa,iBAAiB,iBAA0C;CACtE,MAAM,UAAU,KAAK,IACnB,aAAa,YAAY,IAAI,EAC7B,aAAa,YAAY,KAAK,CAC/B;CACD,MAAM,MAAM,UAAU,IAAI,KAAK,aAAa,MAAM,GAAG,UAAU,EAAE;CACjE,MAAM,OAAO,UAAU,IAAI,eAAe,aAAa,MAAM,UAAU,EAAE;AACzE,QAAO,QAAQ,KAAK,CAClB,KAAK,QAAQ,KAAK,IAAI,EAAE,QAAQ,SAAS,KAAK,YAAY,CAAC,EAC3D,QAAQ,KAAK,KAAK,CACnB,CAAC;;AAKJ,MAAM,WAAW,MAAc,WAAsB,aACnD,OAAO,IAAI,aAAa;CAItB,MAAM,UAHc,OAAO,YAAY,QAC1B,OAAO,KAAK,MAES;CAClC,MAAM,SAAS,KAAK,UAAU,OAAO,WAAW,OAAO,CAAC,GACpD,KAAK,UAAU,OAAO,MAAM,OAAO,OAAO,CAAC,GAC3C;AAEJ,QAAO,QAAQ,IACb,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,SAAS,MAAM,EACvB,QAAQ,aACN,QAAQ,KAAK,CACX,KAAK,QAAQ,KAAK,OAAO,EAAE,QAAQ,SAAS,KAAK,YAAY,CAAC,EAC9D,KAAK,QAAQ,KAAK,OAAO,EAAE,QAAQ,SAAS,MAAM,CAAC,CACpD,CAAC,CACH,EACD,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;EACD;AAEJ,MAAa,eAAe,QAAQ,KAAK,KAAK,MAAM;AAEpD,MAAa,iBAAiB,QAAQ,KAAK,KAAK,IAAI;AAEpD,MAAa,kBAAkB,QAAQ,KAAK,KAAK,OAAO;AAIxD,MAAM,eACH,MAAc,WACd,iBACC,QAAQ,IACN,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE,QAAQ,SAAS,MAAM,CAAC,CAAC,EAC9D,QAAQ,aACN,QAAQ,KAAK,CACX,KACE,QAAQ,KAAKA,SAAmB,aAAa,UAAU,GAAG,IAAI,EAC9D,QAAQ,SAAS,KAAK,YAAY,CACnC,EACD,KAAK,QAAQ,KAAK,aAAa,KAAK,EAAE,QAAQ,SAAS,MAAM,CAAC,CAC/D,CAAC,CACH,EACD,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;AAEL,MAAa,mBAAmB,YAAY,KAAK,KAAK,MAAM;AAE5D,MAAa,qBAAqB,YAAY,KAAK,KAAK,IAAI;AAI5D,MAAM,aAAa,MAAc,eAA0B,YACzD,QAAQ,IACN,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,SAAS,UAAU,EAC3B,QAAQ,aAAa,QAAQ,KAAK,QAAQ,CAAC,EAC3C,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;AAEH,MAAa,aAAa,UAAU,MAAM,KAAK,MAAM;AAErD,MAAa,aAAa,UAAU,KAAK,KAAK,IAAI;AAElD,MAAa,aAAa,UAAU,KAAK,KAAK,OAAO"}
1
+ {"version":3,"file":"log.mjs","names":["GroupPath.toString"],"sources":["../src/log.ts"],"sourcesContent":["import { Path } from \"@effect/platform\";\nimport { Ansi, AnsiDoc } from \"@effect/printer-ansi\";\nimport { Console, Effect, pipe, String } from \"effect\";\nimport type * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport { ProjectRoot } from \"./ProjectRoot\";\n\n// --- Path styling ---\n\n/**\n * Render a relative path as an AnsiDoc with the directory portion\n * dimmed (`Ansi.blackBright`) and the file leaf rendered in the\n * default terminal color. Used inline anywhere a file path appears\n * in a CLI message.\n */\nexport const formatPathDoc = (relativePath: string): AnsiDoc.AnsiDoc => {\n const lastSep = Math.max(\n relativePath.lastIndexOf(\"/\"),\n relativePath.lastIndexOf(\"\\\\\"),\n );\n const dir = lastSep < 0 ? \"\" : relativePath.slice(0, lastSep + 1);\n const leaf = lastSep < 0 ? relativePath : relativePath.slice(lastSep + 1);\n return AnsiDoc.hcat([\n pipe(AnsiDoc.text(dir), AnsiDoc.annotate(Ansi.blackBright)),\n AnsiDoc.text(leaf),\n ]);\n};\n\n// --- File operation logs ---\n\nconst logFile = (char: string, color: Ansi.Ansi) => (fullPath: string) =>\n Effect.gen(function* () {\n const projectRoot = yield* ProjectRoot.get;\n const path = yield* Path.Path;\n\n const prefix = projectRoot + path.sep;\n const suffix = pipe(fullPath, String.startsWith(prefix))\n ? pipe(fullPath, String.slice(prefix.length))\n : fullPath;\n\n yield* Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(color),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)),\n pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n });\n\nexport const logFileAdded = logFile(\"+\", Ansi.green);\n\nexport const logFileRemoved = logFile(\"-\", Ansi.red);\n\nexport const logFileModified = logFile(\"~\", Ansi.magenta);\n\n// --- Function subline logs ---\n\nconst logFunction =\n (char: string, color: Ansi.Ansi) =>\n (functionPath: FunctionPath.FunctionPath) =>\n Console.log(\n pipe(\n AnsiDoc.text(\" \"),\n AnsiDoc.cat(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color))),\n AnsiDoc.catWithSpace(\n AnsiDoc.hcat([\n pipe(\n AnsiDoc.text(GroupPath.toString(functionPath.groupPath) + \".\"),\n AnsiDoc.annotate(Ansi.blackBright),\n ),\n pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(color)),\n ]),\n ),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const logFunctionAdded = logFunction(\"+\", Ansi.green);\n\nexport const logFunctionRemoved = logFunction(\"-\", Ansi.red);\n\n// --- Process status logs ---\n\nconst logStatus = (char: string, charColor: Ansi.Ansi) => (message: string) =>\n Console.log(\n pipe(\n AnsiDoc.char(char),\n AnsiDoc.annotate(charColor),\n AnsiDoc.catWithSpace(AnsiDoc.text(message)),\n AnsiDoc.render({ style: \"pretty\" }),\n ),\n );\n\nexport const logSuccess = logStatus(\"✔︎\", Ansi.green);\n\nexport const logFailure = logStatus(\"✘\", Ansi.red);\n\nexport const logPending = logStatus(\"⭘\", Ansi.cyan);\n\nexport const logWarn = logStatus(\"⚠\", Ansi.yellow);\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAa,iBAAiB,iBAA0C;CACtE,MAAM,UAAU,KAAK,IACnB,aAAa,YAAY,IAAI,EAC7B,aAAa,YAAY,KAAK,CAC/B;CACD,MAAM,MAAM,UAAU,IAAI,KAAK,aAAa,MAAM,GAAG,UAAU,EAAE;CACjE,MAAM,OAAO,UAAU,IAAI,eAAe,aAAa,MAAM,UAAU,EAAE;AACzE,QAAO,QAAQ,KAAK,CAClB,KAAK,QAAQ,KAAK,IAAI,EAAE,QAAQ,SAAS,KAAK,YAAY,CAAC,EAC3D,QAAQ,KAAK,KAAK,CACnB,CAAC;;AAKJ,MAAM,WAAW,MAAc,WAAsB,aACnD,OAAO,IAAI,aAAa;CAItB,MAAM,UAHc,OAAO,YAAY,QAC1B,OAAO,KAAK,MAES;CAClC,MAAM,SAAS,KAAK,UAAU,OAAO,WAAW,OAAO,CAAC,GACpD,KAAK,UAAU,OAAO,MAAM,OAAO,OAAO,CAAC,GAC3C;AAEJ,QAAO,QAAQ,IACb,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,SAAS,MAAM,EACvB,QAAQ,aACN,QAAQ,KAAK,CACX,KAAK,QAAQ,KAAK,OAAO,EAAE,QAAQ,SAAS,KAAK,YAAY,CAAC,EAC9D,KAAK,QAAQ,KAAK,OAAO,EAAE,QAAQ,SAAS,MAAM,CAAC,CACpD,CAAC,CACH,EACD,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;EACD;AAEJ,MAAa,eAAe,QAAQ,KAAK,KAAK,MAAM;AAEpD,MAAa,iBAAiB,QAAQ,KAAK,KAAK,IAAI;AAEpD,MAAa,kBAAkB,QAAQ,KAAK,KAAK,QAAQ;AAIzD,MAAM,eACH,MAAc,WACd,iBACC,QAAQ,IACN,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE,QAAQ,SAAS,MAAM,CAAC,CAAC,EAC9D,QAAQ,aACN,QAAQ,KAAK,CACX,KACE,QAAQ,KAAKA,SAAmB,aAAa,UAAU,GAAG,IAAI,EAC9D,QAAQ,SAAS,KAAK,YAAY,CACnC,EACD,KAAK,QAAQ,KAAK,aAAa,KAAK,EAAE,QAAQ,SAAS,MAAM,CAAC,CAC/D,CAAC,CACH,EACD,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;AAEL,MAAa,mBAAmB,YAAY,KAAK,KAAK,MAAM;AAE5D,MAAa,qBAAqB,YAAY,KAAK,KAAK,IAAI;AAI5D,MAAM,aAAa,MAAc,eAA0B,YACzD,QAAQ,IACN,KACE,QAAQ,KAAK,KAAK,EAClB,QAAQ,SAAS,UAAU,EAC3B,QAAQ,aAAa,QAAQ,KAAK,QAAQ,CAAC,EAC3C,QAAQ,OAAO,EAAE,OAAO,UAAU,CAAC,CACpC,CACF;AAEH,MAAa,aAAa,UAAU,MAAM,KAAK,MAAM;AAErD,MAAa,aAAa,UAAU,KAAK,KAAK,IAAI;AAElD,MAAa,aAAa,UAAU,KAAK,KAAK,KAAK;AAEnD,MAAa,UAAU,UAAU,KAAK,KAAK,OAAO"}
package/dist/package.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "9.0.0-next.4";
2
+ var version = "9.0.0-next.6";
3
3
 
4
4
  //#endregion
5
5
  export { version };