@gaganref/confect-cli 0.0.0-stage → 10.3.1-fork.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1824 -0
- package/LICENSE +7 -0
- package/README.md +16 -2
- package/bin/confect.mjs +26 -0
- package/dist/Ansi.mjs +18 -0
- package/dist/Ansi.mjs.map +1 -0
- package/dist/BuildError.mjs +30 -0
- package/dist/BuildError.mjs.map +1 -0
- package/dist/Bundler.mjs +426 -0
- package/dist/Bundler.mjs.map +1 -0
- package/dist/CodeBlockWriter.mjs +55 -0
- package/dist/CodeBlockWriter.mjs.map +1 -0
- package/dist/CodegenError.mjs +194 -0
- package/dist/CodegenError.mjs.map +1 -0
- package/dist/ConfectDirectory.mjs +35 -0
- package/dist/ConfectDirectory.mjs.map +1 -0
- package/dist/ConvexConfig.mjs +198 -0
- package/dist/ConvexConfig.mjs.map +1 -0
- package/dist/ConvexDirectory.mjs +54 -0
- package/dist/ConvexDirectory.mjs.map +1 -0
- package/dist/Declaration.mjs +258 -0
- package/dist/Declaration.mjs.map +1 -0
- package/dist/DirectoryOptions.mjs +42 -0
- package/dist/DirectoryOptions.mjs.map +1 -0
- package/dist/DocName.mjs +25 -0
- package/dist/DocName.mjs.map +1 -0
- package/dist/EntryPoint.mjs +111 -0
- package/dist/EntryPoint.mjs.map +1 -0
- package/dist/Evaluation.mjs +117 -0
- package/dist/Evaluation.mjs.map +1 -0
- package/dist/EvaluationWorker.mjs +46 -0
- package/dist/EvaluationWorker.mjs.map +1 -0
- package/dist/FunctionModule.mjs +137 -0
- package/dist/FunctionModule.mjs.map +1 -0
- package/dist/FunctionPath.mjs +18 -0
- package/dist/FunctionPath.mjs.map +1 -0
- package/dist/FunctionPaths.mjs +45 -0
- package/dist/FunctionPaths.mjs.map +1 -0
- package/dist/GenerationSnapshot.mjs +183 -0
- package/dist/GenerationSnapshot.mjs.map +1 -0
- package/dist/GroupPath.mjs +51 -0
- package/dist/GroupPath.mjs.map +1 -0
- package/dist/GroupPaths.mjs +8 -0
- package/dist/GroupPaths.mjs.map +1 -0
- package/dist/ImplModulePath.mjs +8 -0
- package/dist/ImplModulePath.mjs.map +1 -0
- package/dist/LeafModule.mjs +285 -0
- package/dist/LeafModule.mjs.map +1 -0
- package/dist/ProjectRoot.mjs +38 -0
- package/dist/ProjectRoot.mjs.map +1 -0
- package/dist/RelativeModulePath.mjs +13 -0
- package/dist/RelativeModulePath.mjs.map +1 -0
- package/dist/Remove.mjs +24 -0
- package/dist/Remove.mjs.map +1 -0
- package/dist/RestoreWatcher.mjs +31 -0
- package/dist/RestoreWatcher.mjs.map +1 -0
- package/dist/Rollback.mjs +50 -0
- package/dist/Rollback.mjs.map +1 -0
- package/dist/SnapshotError.mjs +21 -0
- package/dist/SnapshotError.mjs.map +1 -0
- package/dist/SpecAssemblyNode.mjs +91 -0
- package/dist/SpecAssemblyNode.mjs.map +1 -0
- package/dist/SpecModulePath.mjs +10 -0
- package/dist/SpecModulePath.mjs.map +1 -0
- package/dist/SyncState.mjs +122 -0
- package/dist/SyncState.mjs.map +1 -0
- package/dist/TableModule.mjs +97 -0
- package/dist/TableModule.mjs.map +1 -0
- package/dist/TableModulePath.mjs +8 -0
- package/dist/TableModulePath.mjs.map +1 -0
- package/dist/WatchBuild.mjs +190 -0
- package/dist/WatchBuild.mjs.map +1 -0
- package/dist/WatchGraph.mjs +35 -0
- package/dist/WatchGraph.mjs.map +1 -0
- package/dist/WatchTopology.mjs +55 -0
- package/dist/WatchTopology.mjs.map +1 -0
- package/dist/Watcher.mjs +378 -0
- package/dist/Watcher.mjs.map +1 -0
- package/dist/cliApp.mjs +9 -0
- package/dist/cliApp.mjs.map +1 -0
- package/dist/confect/codegen.mjs +548 -0
- package/dist/confect/codegen.mjs.map +1 -0
- package/dist/confect/declaration.mjs +218 -0
- package/dist/confect/declaration.mjs.map +1 -0
- package/dist/confect/dev.mjs +182 -0
- package/dist/confect/dev.mjs.map +1 -0
- package/dist/confect.mjs +9 -0
- package/dist/confect.mjs.map +1 -0
- package/dist/index.mjs +19 -0
- package/dist/index.mjs.map +1 -0
- package/dist/log.mjs +107 -0
- package/dist/log.mjs.map +1 -0
- package/dist/package.mjs +6 -0
- package/dist/package.mjs.map +1 -0
- package/dist/templates.mjs +448 -0
- package/dist/templates.mjs.map +1 -0
- package/dist/utils.mjs +105 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +51 -3
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { ProjectRoot } from "./ProjectRoot.mjs";
|
|
2
|
+
import { ComponentNodeGroupError, logCodegenError } from "./CodegenError.mjs";
|
|
3
|
+
import { ConvexDirectory } from "./ConvexDirectory.mjs";
|
|
4
|
+
import { ConfectDirectory } from "./ConfectDirectory.mjs";
|
|
5
|
+
import { FunctionPaths } from "./FunctionPaths.mjs";
|
|
6
|
+
import { ImplModulePath } from "./ImplModulePath.mjs";
|
|
7
|
+
import { GenerationSnapshot, functionPaths } from "./GenerationSnapshot.mjs";
|
|
8
|
+
import { Declaration } from "./EntryPoint.mjs";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as FileSystem from "effect/FileSystem";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as HashSet from "effect/HashSet";
|
|
13
|
+
import * as Match from "effect/Match";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import * as Schema from "effect/Schema";
|
|
16
|
+
import * as Console from "effect/Console";
|
|
17
|
+
import * as Layer from "effect/Layer";
|
|
18
|
+
import * as NodeWorker from "@effect/platform-node/NodeWorker";
|
|
19
|
+
import { fork } from "node:child_process";
|
|
20
|
+
import * as LogLevel from "effect/LogLevel";
|
|
21
|
+
import * as References from "effect/References";
|
|
22
|
+
import * as Rpc from "effect/rpc/Rpc";
|
|
23
|
+
import * as RpcClient from "effect/rpc/RpcClient";
|
|
24
|
+
import * as RpcGroup from "effect/rpc/RpcGroup";
|
|
25
|
+
//#region src/Evaluation.ts
|
|
26
|
+
const RequestContext = Schema.Struct({
|
|
27
|
+
projectRoot: Schema.String,
|
|
28
|
+
confectDirectory: Schema.String,
|
|
29
|
+
convexDirectory: Schema.String,
|
|
30
|
+
target: Schema.Union([Schema.Struct({ kind: Schema.Literal("app") }), Schema.Struct({
|
|
31
|
+
kind: Schema.Literal("component"),
|
|
32
|
+
definition: Schema.String
|
|
33
|
+
})]),
|
|
34
|
+
minimumLogLevel: Schema.Literals(LogLevel.values)
|
|
35
|
+
});
|
|
36
|
+
var EvaluationError = class extends Schema.TaggedError()("EvaluationError", { diagnostic: Schema.String }) {};
|
|
37
|
+
const Failure = Schema.Union([EvaluationError, ComponentNodeGroupError]);
|
|
38
|
+
const requests = RpcGroup.make(Rpc.make("Previous", {
|
|
39
|
+
payload: RequestContext,
|
|
40
|
+
success: FunctionPaths,
|
|
41
|
+
error: Failure
|
|
42
|
+
}), Rpc.make("Generate", {
|
|
43
|
+
payload: RequestContext,
|
|
44
|
+
success: GenerationSnapshot,
|
|
45
|
+
error: Failure
|
|
46
|
+
}), Rpc.make("Validate", {
|
|
47
|
+
payload: Schema.Struct({
|
|
48
|
+
...RequestContext.fields,
|
|
49
|
+
paths: Schema.Array(ImplModulePath)
|
|
50
|
+
}),
|
|
51
|
+
success: Schema.Void,
|
|
52
|
+
error: Failure
|
|
53
|
+
}), Rpc.make("Update", {
|
|
54
|
+
payload: Schema.Struct({
|
|
55
|
+
...RequestContext.fields,
|
|
56
|
+
snapshot: GenerationSnapshot,
|
|
57
|
+
declarations: Schema.NonEmptyArray(Declaration),
|
|
58
|
+
paths: Schema.Array(ImplModulePath)
|
|
59
|
+
}),
|
|
60
|
+
success: GenerationSnapshot,
|
|
61
|
+
error: Failure
|
|
62
|
+
}));
|
|
63
|
+
const withWorker = Effect.fn("Evaluation.withWorker")(function* (run) {
|
|
64
|
+
const requestContext = {
|
|
65
|
+
projectRoot: yield* ProjectRoot.get,
|
|
66
|
+
confectDirectory: yield* ConfectDirectory.get,
|
|
67
|
+
convexDirectory: yield* ConvexDirectory.get,
|
|
68
|
+
target: Match.value(yield* ConvexDirectory.target).pipe(Match.when({ kind: "app" }, () => ({ kind: "app" })), Match.when({ kind: "component" }, ({ scope }) => ({
|
|
69
|
+
kind: "component",
|
|
70
|
+
definition: scope.slice(10)
|
|
71
|
+
})), Match.exhaustive),
|
|
72
|
+
minimumLogLevel: yield* References.MinimumLogLevel
|
|
73
|
+
};
|
|
74
|
+
return yield* Effect.scoped(Effect.gen(function* () {
|
|
75
|
+
const child = yield* Effect.acquireRelease(Effect.sync(() => fork(new URL("../dist/EvaluationWorker.mjs", import.meta.url), { serialization: "advanced" })), (evaluator) => Effect.callback((resume) => {
|
|
76
|
+
if (evaluator.exitCode !== null || evaluator.signalCode !== null) {
|
|
77
|
+
resume(Effect.void);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
evaluator.once("exit", () => resume(Effect.void));
|
|
81
|
+
evaluator.kill("SIGKILL");
|
|
82
|
+
}));
|
|
83
|
+
return yield* Effect.gen(function* () {
|
|
84
|
+
return yield* run(yield* RpcClient.make(requests), requestContext);
|
|
85
|
+
}).pipe(Effect.provide(RpcClient.layerProtocolWorker({ size: 1 }).pipe(Layer.provide(NodeWorker.layer(() => child)))));
|
|
86
|
+
})).pipe(Effect.catchTags({
|
|
87
|
+
WorkerError: (error) => Effect.fail(new EvaluationError({ diagnostic: error.message })),
|
|
88
|
+
RpcClientError: (error) => Effect.fail(new EvaluationError({ diagnostic: error.message }))
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
const loadPreviousFunctionPaths = Effect.gen(function* () {
|
|
92
|
+
const fs = yield* FileSystem.FileSystem;
|
|
93
|
+
const path = yield* Path.Path;
|
|
94
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
95
|
+
if (!(yield* fs.exists(path.join(confectDirectory, "_generated", "spec.ts")))) return FunctionPaths.make(HashSet.empty());
|
|
96
|
+
return yield* withWorker((client, requestContext) => client.Previous(requestContext));
|
|
97
|
+
});
|
|
98
|
+
const generateSnapshot = withWorker((client, requestContext) => client.Generate(requestContext));
|
|
99
|
+
generateSnapshot.pipe(Effect.map(functionPaths));
|
|
100
|
+
const updateDeclarations = (snapshot, declarations, paths) => withWorker((client, requestContext) => client.Update({
|
|
101
|
+
...requestContext,
|
|
102
|
+
snapshot,
|
|
103
|
+
declarations,
|
|
104
|
+
paths
|
|
105
|
+
}));
|
|
106
|
+
const validate = (paths) => withWorker((client, requestContext) => client.Validate({
|
|
107
|
+
...requestContext,
|
|
108
|
+
paths
|
|
109
|
+
}));
|
|
110
|
+
const catchAndLog = (effect) => effect.pipe(Effect.asSome, Effect.catchTags({
|
|
111
|
+
EvaluationError: ({ diagnostic }) => Console.error(diagnostic).pipe(Effect.as(Option.none())),
|
|
112
|
+
ComponentNodeGroupError: (error) => logCodegenError(error).pipe(Effect.as(Option.none()))
|
|
113
|
+
}));
|
|
114
|
+
//#endregion
|
|
115
|
+
export { EvaluationError, RequestContext, catchAndLog, generateSnapshot, loadPreviousFunctionPaths, requests, updateDeclarations, validate };
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=Evaluation.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Evaluation.mjs","names":["GenerationSnapshot.GenerationSnapshot","EntryPoint.Declaration","GenerationSnapshot.functionPaths"],"sources":["../src/Evaluation.ts"],"sourcesContent":["import * as NodeWorker from \"@effect/platform-node/NodeWorker\";\nimport { fork } from \"node:child_process\";\nimport * as Console from \"effect/Console\";\nimport * as Effect from \"effect/Effect\";\nimport * as FileSystem from \"effect/FileSystem\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Layer from \"effect/Layer\";\nimport * as LogLevel from \"effect/LogLevel\";\nimport * as Option from \"effect/Option\";\nimport * as Path from \"effect/Path\";\nimport * as Schema from \"effect/Schema\";\nimport * as References from \"effect/References\";\nimport * as Rpc from \"effect/rpc/Rpc\";\nimport * as RpcClient from \"effect/rpc/RpcClient\";\nimport type { RpcClientError } from \"effect/rpc/RpcClientError\";\nimport * as RpcGroup from \"effect/rpc/RpcGroup\";\nimport type * as Array from \"effect/Array\";\nimport * as Match from \"effect/Match\";\nimport { ComponentNodeGroupError, logCodegenError } from \"./CodegenError\";\nimport * as EntryPoint from \"./EntryPoint\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport { FunctionPaths } from \"./FunctionPaths\";\nimport { ImplModulePath } from \"./ImplModulePath\";\nimport { ProjectRoot } from \"./ProjectRoot\";\n\nexport const RequestContext = Schema.Struct({\n projectRoot: Schema.String,\n confectDirectory: Schema.String,\n convexDirectory: Schema.String,\n target: Schema.Union([\n Schema.Struct({ kind: Schema.Literal(\"app\") }),\n Schema.Struct({\n kind: Schema.Literal(\"component\"),\n definition: Schema.String,\n }),\n ]),\n minimumLogLevel: Schema.Literals(LogLevel.values),\n});\nexport type RequestContext = typeof RequestContext.Type;\n\nexport class EvaluationError extends Schema.TaggedError<EvaluationError>()(\n \"EvaluationError\",\n { diagnostic: Schema.String },\n) {}\n\n// A rejected Node group stays typed so the caller can restore component output.\nconst Failure = Schema.Union([EvaluationError, ComponentNodeGroupError]);\n\nexport const requests = RpcGroup.make(\n Rpc.make(\"Previous\", {\n payload: RequestContext,\n success: FunctionPaths,\n error: Failure,\n }),\n Rpc.make(\"Generate\", {\n payload: RequestContext,\n success: GenerationSnapshot.GenerationSnapshot,\n error: Failure,\n }),\n Rpc.make(\"Validate\", {\n payload: Schema.Struct({\n ...RequestContext.fields,\n paths: Schema.Array(ImplModulePath),\n }),\n success: Schema.Void,\n error: Failure,\n }),\n Rpc.make(\"Update\", {\n payload: Schema.Struct({\n ...RequestContext.fields,\n snapshot: GenerationSnapshot.GenerationSnapshot,\n declarations: Schema.NonEmptyArray(EntryPoint.Declaration),\n paths: Schema.Array(ImplModulePath),\n }),\n success: GenerationSnapshot.GenerationSnapshot,\n error: Failure,\n }),\n);\n\nconst withWorker = Effect.fn(\"Evaluation.withWorker\")(function* <A>(\n run: (\n client: RpcClient.RpcClient<RpcGroup.Rpcs<typeof requests>, RpcClientError>,\n requestContext: RequestContext,\n ) => Effect.Effect<\n A,\n EvaluationError | ComponentNodeGroupError | RpcClientError\n >,\n) {\n const requestContext = {\n projectRoot: yield* ProjectRoot.get,\n confectDirectory: yield* ConfectDirectory.get,\n convexDirectory: yield* ConvexDirectory.get,\n target: Match.value(yield* ConvexDirectory.target).pipe(\n Match.when({ kind: \"app\" }, () => ({ kind: \"app\" as const })),\n Match.when({ kind: \"component\" }, ({ scope }) => ({\n kind: \"component\" as const,\n definition: scope.slice(\"component:\".length),\n })),\n Match.exhaustive,\n ),\n minimumLogLevel: yield* References.MinimumLogLevel,\n };\n return yield* Effect.scoped(\n Effect.gen(function* () {\n const child = yield* Effect.acquireRelease(\n Effect.sync(() =>\n fork(new URL(\"../dist/EvaluationWorker.mjs\", import.meta.url), {\n serialization: \"advanced\",\n }),\n ),\n (evaluator) =>\n Effect.callback<void>((resume) => {\n if (evaluator.exitCode !== null || evaluator.signalCode !== null) {\n resume(Effect.void);\n return;\n }\n evaluator.once(\"exit\", () => resume(Effect.void));\n evaluator.kill(\"SIGKILL\");\n }),\n );\n return yield* Effect.gen(function* () {\n const client = yield* RpcClient.make(requests);\n return yield* run(client, requestContext);\n }).pipe(\n Effect.provide(\n RpcClient.layerProtocolWorker({ size: 1 }).pipe(\n Layer.provide(NodeWorker.layer(() => child)),\n ),\n ),\n );\n }),\n ).pipe(\n Effect.catchTags({\n WorkerError: (error) =>\n Effect.fail(new EvaluationError({ diagnostic: error.message })),\n RpcClientError: (error) =>\n Effect.fail(new EvaluationError({ diagnostic: error.message })),\n }),\n );\n});\n\nexport const loadPreviousFunctionPaths = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n if (\n !(yield* fs.exists(path.join(confectDirectory, \"_generated\", \"spec.ts\")))\n ) {\n return FunctionPaths.make(HashSet.empty());\n }\n return yield* withWorker((client, requestContext) =>\n client.Previous(requestContext),\n );\n});\n\nexport const generateSnapshot = withWorker((client, requestContext) =>\n client.Generate(requestContext),\n);\n\nexport const generate = generateSnapshot.pipe(\n Effect.map(GenerationSnapshot.functionPaths),\n);\n\nexport const updateDeclarations = (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n declarations: Array.NonEmptyReadonlyArray<EntryPoint.Declaration>,\n paths: ReadonlyArray<ImplModulePath>,\n) =>\n withWorker((client, requestContext) =>\n client.Update({\n ...requestContext,\n snapshot,\n declarations,\n paths,\n }),\n );\n\nexport const validate = (paths: ReadonlyArray<ImplModulePath>) =>\n withWorker((client, requestContext) =>\n client.Validate({ ...requestContext, paths }),\n );\n\nexport const catchAndLog = <A, R>(\n effect: Effect.Effect<A, EvaluationError | ComponentNodeGroupError, R>,\n): Effect.Effect<Option.Option<A>, never, R> =>\n effect.pipe(\n Effect.asSome,\n Effect.catchTags({\n EvaluationError: ({ diagnostic }) =>\n Console.error(diagnostic).pipe(Effect.as(Option.none<A>())),\n ComponentNodeGroupError: (error) =>\n logCodegenError(error).pipe(Effect.as(Option.none<A>())),\n }),\n );\n"],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ProjectRoot } from "./ProjectRoot.mjs";
|
|
2
|
+
import { ComponentNodeGroupError, isCodegenError, renderCodegenError } from "./CodegenError.mjs";
|
|
3
|
+
import { ConvexDirectory } from "./ConvexDirectory.mjs";
|
|
4
|
+
import { ConfectDirectory } from "./ConfectDirectory.mjs";
|
|
5
|
+
import { validateImplFiles } from "./LeafModule.mjs";
|
|
6
|
+
import { generateWithSnapshot, loadPreviousFunctionPaths, updateDeclarations } from "./confect/codegen.mjs";
|
|
7
|
+
import { EvaluationError, requests } from "./Evaluation.mjs";
|
|
8
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
9
|
+
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as Match from "effect/Match";
|
|
12
|
+
import * as Option from "effect/Option";
|
|
13
|
+
import * as Cause from "effect/Cause";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import * as esbuild from "esbuild";
|
|
16
|
+
import * as Layer from "effect/Layer";
|
|
17
|
+
import * as IdScope from "@confect/core/IdScope";
|
|
18
|
+
import * as References from "effect/References";
|
|
19
|
+
import * as NodeWorkerRunner from "@effect/platform-node/NodeWorkerRunner";
|
|
20
|
+
import * as RpcServer from "effect/rpc/RpcServer";
|
|
21
|
+
//#region src/EvaluationWorker.ts
|
|
22
|
+
const evaluate = (requestContext, effect) => effect.pipe(Effect.provideService(References.MinimumLogLevel, requestContext.minimumLogLevel), Effect.provideService(ProjectRoot, { get: Effect.succeed(requestContext.projectRoot) }), Effect.provideService(ConfectDirectory, { get: Effect.succeed(requestContext.confectDirectory) }), Effect.provideService(ConvexDirectory, {
|
|
23
|
+
get: Effect.succeed(requestContext.convexDirectory),
|
|
24
|
+
target: Match.value(requestContext.target).pipe(Match.when({ kind: "app" }, () => ({
|
|
25
|
+
kind: "app",
|
|
26
|
+
scope: IdScope.app
|
|
27
|
+
})), Match.when({ kind: "component" }, ({ definition }) => ({
|
|
28
|
+
kind: "component",
|
|
29
|
+
scope: IdScope.component(definition)
|
|
30
|
+
})), Match.exhaustive)
|
|
31
|
+
}), Effect.catchCause((cause) => {
|
|
32
|
+
const failure = Cause.findErrorOption(cause);
|
|
33
|
+
if (Option.isSome(failure) && Schema.is(ComponentNodeGroupError)(failure.value)) return Effect.fail(failure.value);
|
|
34
|
+
return Effect.fail(new EvaluationError({ diagnostic: Option.isSome(failure) && isCodegenError(failure.value) ? renderCodegenError(failure.value) : Cause.pretty(cause) }));
|
|
35
|
+
}));
|
|
36
|
+
const handlers = requests.toLayer({
|
|
37
|
+
Previous: (requestContext) => evaluate(requestContext, loadPreviousFunctionPaths),
|
|
38
|
+
Generate: (requestContext) => evaluate(requestContext, generateWithSnapshot.pipe(Effect.map(({ snapshot }) => snapshot))),
|
|
39
|
+
Validate: (request) => evaluate(request, validateImplFiles(request.paths)),
|
|
40
|
+
Update: (request) => evaluate(request, updateDeclarations(request.snapshot, request.declarations, request.paths))
|
|
41
|
+
});
|
|
42
|
+
RpcServer.layer(requests).pipe(Layer.provide(handlers), Layer.provide(NodeServices.layer), Layer.provide(RpcServer.layerProtocolWorkerRunner.pipe(Layer.provide(NodeWorkerRunner.layer))), Layer.launch, Effect.ensuring(Effect.promise(() => esbuild.stop())), NodeRuntime.runMain);
|
|
43
|
+
//#endregion
|
|
44
|
+
export {};
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=EvaluationWorker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EvaluationWorker.mjs","names":["CodegenError.ComponentNodeGroupError","CodegenError.isCodegenError","CodegenError.renderCodegenError"],"sources":["../src/EvaluationWorker.ts"],"sourcesContent":["import * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport * as NodeWorkerRunner from \"@effect/platform-node/NodeWorkerRunner\";\nimport * as IdScope from \"@confect/core/IdScope\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as References from \"effect/References\";\nimport * as Schema from \"effect/Schema\";\nimport * as RpcServer from \"effect/rpc/RpcServer\";\nimport * as esbuild from \"esbuild\";\nimport * as CodegenError from \"./CodegenError\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport type { RequestContext } from \"./Evaluation\";\nimport { EvaluationError, requests } from \"./Evaluation\";\nimport { validateImplFiles } from \"./LeafModule\";\nimport { ProjectRoot } from \"./ProjectRoot\";\nimport {\n generateWithSnapshot,\n loadPreviousFunctionPaths,\n updateDeclarations,\n} from \"./confect/codegen\";\n\nconst evaluate = <A, E, R>(\n requestContext: RequestContext,\n effect: Effect.Effect<A, E, R>,\n) =>\n effect.pipe(\n Effect.provideService(\n References.MinimumLogLevel,\n requestContext.minimumLogLevel,\n ),\n Effect.provideService(ProjectRoot, {\n get: Effect.succeed(requestContext.projectRoot),\n }),\n Effect.provideService(ConfectDirectory, {\n get: Effect.succeed(requestContext.confectDirectory),\n }),\n Effect.provideService(ConvexDirectory, {\n get: Effect.succeed(requestContext.convexDirectory),\n target: Match.value(requestContext.target).pipe(\n Match.when({ kind: \"app\" }, () => ({\n kind: \"app\" as const,\n scope: IdScope.app,\n })),\n Match.when({ kind: \"component\" }, ({ definition }) => ({\n kind: \"component\" as const,\n scope: IdScope.component(definition),\n })),\n Match.exhaustive,\n ),\n }),\n Effect.catchCause(\n (\n cause,\n ): Effect.Effect<\n never,\n EvaluationError | CodegenError.ComponentNodeGroupError\n > => {\n const failure = Cause.findErrorOption(cause);\n if (\n Option.isSome(failure) &&\n Schema.is(CodegenError.ComponentNodeGroupError)(failure.value)\n )\n return Effect.fail(failure.value);\n return Effect.fail(\n new EvaluationError({\n diagnostic:\n Option.isSome(failure) &&\n CodegenError.isCodegenError(failure.value)\n ? CodegenError.renderCodegenError(failure.value)\n : Cause.pretty(cause),\n }),\n );\n },\n ),\n );\n\nconst handlers = requests.toLayer({\n Previous: (requestContext) =>\n evaluate(requestContext, loadPreviousFunctionPaths),\n Generate: (requestContext) =>\n evaluate(\n requestContext,\n generateWithSnapshot.pipe(Effect.map(({ snapshot }) => snapshot)),\n ),\n Validate: (request) => evaluate(request, validateImplFiles(request.paths)),\n Update: (request) =>\n evaluate(\n request,\n updateDeclarations(request.snapshot, request.declarations, request.paths),\n ),\n});\n\nRpcServer.layer(requests).pipe(\n Layer.provide(handlers),\n Layer.provide(NodeServices.layer),\n Layer.provide(\n RpcServer.layerProtocolWorkerRunner.pipe(\n Layer.provide(NodeWorkerRunner.layer),\n ),\n ),\n Layer.launch,\n Effect.ensuring(Effect.promise(() => esbuild.stop())),\n NodeRuntime.runMain,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,YACJ,gBACA,WAEA,OAAO,KACL,OAAO,eACL,WAAW,iBACX,eAAe,eACjB,GACA,OAAO,eAAe,aAAa,EACjC,KAAK,OAAO,QAAQ,eAAe,WAAW,EAChD,CAAC,GACD,OAAO,eAAe,kBAAkB,EACtC,KAAK,OAAO,QAAQ,eAAe,gBAAgB,EACrD,CAAC,GACD,OAAO,eAAe,iBAAiB;CACrC,KAAK,OAAO,QAAQ,eAAe,eAAe;CAClD,QAAQ,MAAM,MAAM,eAAe,MAAM,CAAC,CAAC,KACzC,MAAM,KAAK,EAAE,MAAM,MAAM,UAAU;EACjC,MAAM;EACN,OAAO,QAAQ;CACjB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,YAAY,IAAI,EAAE,kBAAkB;EACrD,MAAM;EACN,OAAO,QAAQ,UAAU,UAAU;CACrC,EAAE,GACF,MAAM,UACR;AACF,CAAC,GACD,OAAO,YAEH,UAIG;CACH,MAAM,UAAU,MAAM,gBAAgB,KAAK;CAC3C,IACE,OAAO,OAAO,OAAO,KACrB,OAAO,GAAGA,uBAAoC,CAAC,CAAC,QAAQ,KAAK,GAE7D,OAAO,OAAO,KAAK,QAAQ,KAAK;CAClC,OAAO,OAAO,KACZ,IAAI,gBAAgB,EAClB,YACE,OAAO,OAAO,OAAO,KACrBC,eAA4B,QAAQ,KAAK,IACrCC,mBAAgC,QAAQ,KAAK,IAC7C,MAAM,OAAO,KAAK,EAC1B,CAAC,CACH;AACF,CACF,CACF;AAEF,MAAM,WAAW,SAAS,QAAQ;CAChC,WAAW,mBACT,SAAS,gBAAgB,yBAAyB;CACpD,WAAW,mBACT,SACE,gBACA,qBAAqB,KAAK,OAAO,KAAK,EAAE,eAAe,QAAQ,CAAC,CAClE;CACF,WAAW,YAAY,SAAS,SAAS,kBAAkB,QAAQ,KAAK,CAAC;CACzE,SAAS,YACP,SACE,SACA,mBAAmB,QAAQ,UAAU,QAAQ,cAAc,QAAQ,KAAK,CAC1E;AACJ,CAAC;AAED,UAAU,MAAM,QAAQ,CAAC,CAAC,KACxB,MAAM,QAAQ,QAAQ,GACtB,MAAM,QAAQ,aAAa,KAAK,GAChC,MAAM,QACJ,UAAU,0BAA0B,KAClC,MAAM,QAAQ,iBAAiB,KAAK,CACtC,CACF,GACA,MAAM,QACN,OAAO,SAAS,OAAO,cAAc,QAAQ,KAAK,CAAC,CAAC,GACpD,YAAY,OACd"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { fromGroupModulePath, modulePath } from "./GroupPath.mjs";
|
|
2
|
+
import { logFileAdded, logFileModified, logFileRemoved } from "./log.mjs";
|
|
3
|
+
import { ConvexDirectory } from "./ConvexDirectory.mjs";
|
|
4
|
+
import { ConfectDirectory } from "./ConfectDirectory.mjs";
|
|
5
|
+
import { CodeBlockWriter } from "./CodeBlockWriter.mjs";
|
|
6
|
+
import { removePathIfExists, toModuleImportPath } from "./utils.mjs";
|
|
7
|
+
import { GroupPaths } from "./GroupPaths.mjs";
|
|
8
|
+
import { functionPaths, plan } from "./GenerationSnapshot.mjs";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as FileSystem from "effect/FileSystem";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as Array from "effect/Array";
|
|
13
|
+
import { pipe } from "effect/Function";
|
|
14
|
+
import * as HashSet from "effect/HashSet";
|
|
15
|
+
import * as Match from "effect/Match";
|
|
16
|
+
//#region src/FunctionModule.ts
|
|
17
|
+
const render = ({ functionNames, registeredFunctionsImportPath, useNode = false }) => renderEffect({
|
|
18
|
+
functionNames,
|
|
19
|
+
registeredFunctionsImportPath,
|
|
20
|
+
useNode
|
|
21
|
+
});
|
|
22
|
+
const renderEffect = Effect.fnUntraced(function* ({ functionNames, registeredFunctionsImportPath, useNode = false }) {
|
|
23
|
+
const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
|
|
24
|
+
if (useNode) {
|
|
25
|
+
yield* cbw.writeLine(`"use node";`);
|
|
26
|
+
yield* cbw.blankLine();
|
|
27
|
+
}
|
|
28
|
+
yield* cbw.writeLine(`import registeredFunctions from "${registeredFunctionsImportPath}";`);
|
|
29
|
+
yield* cbw.newLine();
|
|
30
|
+
yield* Effect.forEach(functionNames, (name) => cbw.writeLine(`export const ${name} = registeredFunctions.${name};`));
|
|
31
|
+
return yield* cbw.toString();
|
|
32
|
+
});
|
|
33
|
+
const generateGroupModule = ({ groupPath, functionNames, registeredFunctionsImportPath, useNode = false }) => generateGroupModuleEffect({
|
|
34
|
+
groupPath,
|
|
35
|
+
functionNames,
|
|
36
|
+
registeredFunctionsImportPath,
|
|
37
|
+
useNode
|
|
38
|
+
});
|
|
39
|
+
const generateGroupModuleEffect = Effect.fnUntraced(function* ({ groupPath, functionNames, registeredFunctionsImportPath, useNode = false }) {
|
|
40
|
+
const fs = yield* FileSystem.FileSystem;
|
|
41
|
+
const path = yield* Path.Path;
|
|
42
|
+
const convexDirectory = yield* ConvexDirectory.get;
|
|
43
|
+
const relativeModulePath = yield* modulePath(groupPath);
|
|
44
|
+
const modulePath$3 = path.join(convexDirectory, relativeModulePath);
|
|
45
|
+
const directoryPath = path.dirname(modulePath$3);
|
|
46
|
+
if (!(yield* fs.exists(directoryPath))) yield* fs.makeDirectory(directoryPath, { recursive: true });
|
|
47
|
+
const functionsContentsString = yield* render({
|
|
48
|
+
functionNames,
|
|
49
|
+
registeredFunctionsImportPath,
|
|
50
|
+
useNode
|
|
51
|
+
});
|
|
52
|
+
if (!(yield* fs.exists(modulePath$3))) {
|
|
53
|
+
yield* fs.writeFileString(modulePath$3, functionsContentsString);
|
|
54
|
+
return "Added";
|
|
55
|
+
}
|
|
56
|
+
if ((yield* fs.readFileString(modulePath$3)) !== functionsContentsString) {
|
|
57
|
+
yield* fs.writeFileString(modulePath$3, functionsContentsString);
|
|
58
|
+
return "Modified";
|
|
59
|
+
}
|
|
60
|
+
return "Unchanged";
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Compute the module import specifier (relative to `modulePath`) for a group's
|
|
64
|
+
* registry file under `confect/_generated/registeredFunctions/`. The registry
|
|
65
|
+
* path mirrors the group's path one-to-one (see
|
|
66
|
+
* `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and
|
|
67
|
+
* Node groups.
|
|
68
|
+
*/
|
|
69
|
+
const registeredFunctionsImportPathForGroup = Effect.fnUntraced(function* (groupPath, modulePath) {
|
|
70
|
+
const path = yield* Path.Path;
|
|
71
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
72
|
+
const registeredFunctionsPath = path.join(confectDirectory, "_generated", "registeredFunctions", ...groupPath.pathSegments) + ".ts";
|
|
73
|
+
return yield* toModuleImportPath(path.relative(path.dirname(modulePath), registeredFunctionsPath));
|
|
74
|
+
});
|
|
75
|
+
const logGroupPaths = Effect.fnUntraced(function* (groupPaths, logFn) {
|
|
76
|
+
const path = yield* Path.Path;
|
|
77
|
+
const convexDirectory = yield* ConvexDirectory.get;
|
|
78
|
+
yield* Effect.forEach(groupPaths, Effect.fnUntraced(function* (gp) {
|
|
79
|
+
const relativeModulePath = yield* modulePath(gp);
|
|
80
|
+
yield* logFn(path.join(convexDirectory, relativeModulePath));
|
|
81
|
+
}));
|
|
82
|
+
});
|
|
83
|
+
const generateFunctions = Effect.fnUntraced(function* (snapshot) {
|
|
84
|
+
const groupPathsFromFs = yield* getGroupPathsFromFs;
|
|
85
|
+
yield* applyFunctionPlan(plan(snapshot, groupPathsFromFs));
|
|
86
|
+
return functionPaths(snapshot);
|
|
87
|
+
});
|
|
88
|
+
const applyFunctionPlan = Effect.fnUntraced(function* (plan) {
|
|
89
|
+
const removed = GroupPaths.make(HashSet.fromIterable(plan.removed));
|
|
90
|
+
yield* removeGroups(removed);
|
|
91
|
+
yield* logGroupPaths(removed, logFileRemoved);
|
|
92
|
+
yield* writeGroups(plan.changed);
|
|
93
|
+
});
|
|
94
|
+
const getGroupPathsFromFs = Effect.gen(function* () {
|
|
95
|
+
const fs = yield* FileSystem.FileSystem;
|
|
96
|
+
const path = yield* Path.Path;
|
|
97
|
+
const convexDirectory = yield* ConvexDirectory.get;
|
|
98
|
+
const RESERVED_CONVEX_TS_FILE_NAMES = /* @__PURE__ */ new Set([
|
|
99
|
+
"schema.ts",
|
|
100
|
+
"http.ts",
|
|
101
|
+
"crons.ts",
|
|
102
|
+
"auth.config.ts",
|
|
103
|
+
"convex.config.ts"
|
|
104
|
+
]);
|
|
105
|
+
const allConvexPaths = yield* fs.readDirectory(convexDirectory, { recursive: true });
|
|
106
|
+
const groupPathArray = yield* pipe(allConvexPaths, Array.filter((convexPath) => path.extname(convexPath) === ".ts" && !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) && path.basename(path.dirname(convexPath)) !== "_generated"), Effect.forEach((groupModulePath) => fromGroupModulePath(groupModulePath)));
|
|
107
|
+
return GroupPaths.make(HashSet.fromIterable(groupPathArray));
|
|
108
|
+
});
|
|
109
|
+
const removeGroups = Effect.fnUntraced(function* (groupPaths) {
|
|
110
|
+
const path = yield* Path.Path;
|
|
111
|
+
const convexDirectory = yield* ConvexDirectory.get;
|
|
112
|
+
yield* Effect.all(HashSet.map(groupPaths, (groupPath) => Effect.gen(function* () {
|
|
113
|
+
const relativeModulePath = yield* modulePath(groupPath);
|
|
114
|
+
const modulePath$2 = path.join(convexDirectory, relativeModulePath);
|
|
115
|
+
yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);
|
|
116
|
+
yield* removePathIfExists(modulePath$2);
|
|
117
|
+
yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);
|
|
118
|
+
})), { concurrency: "unbounded" });
|
|
119
|
+
});
|
|
120
|
+
const writeGroups = (groups) => Effect.forEach(groups, Effect.fnUntraced(function* (group) {
|
|
121
|
+
const path = yield* Path.Path;
|
|
122
|
+
const convexDirectory = yield* ConvexDirectory.get;
|
|
123
|
+
const relativeModulePath = yield* modulePath(group.path);
|
|
124
|
+
const modulePath$1 = path.join(convexDirectory, relativeModulePath);
|
|
125
|
+
const registeredFunctionsImportPath = yield* registeredFunctionsImportPathForGroup(group.path, modulePath$1);
|
|
126
|
+
const change = yield* generateGroupModule({
|
|
127
|
+
groupPath: group.path,
|
|
128
|
+
functionNames: group.functionNames,
|
|
129
|
+
registeredFunctionsImportPath,
|
|
130
|
+
useNode: group.runtime === "Node"
|
|
131
|
+
});
|
|
132
|
+
yield* Match.value(change).pipe(Match.when("Added", () => logFileAdded(modulePath$1)), Match.when("Modified", () => logFileModified(modulePath$1)), Match.when("Unchanged", () => Effect.void), Match.exhaustive);
|
|
133
|
+
}));
|
|
134
|
+
//#endregion
|
|
135
|
+
export { applyFunctionPlan, generateFunctions, generateGroupModule, registeredFunctionsImportPathForGroup, removeGroups, render, writeGroups };
|
|
136
|
+
|
|
137
|
+
//# sourceMappingURL=FunctionModule.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FunctionModule.mjs","names":["GroupPath.modulePath","modulePath","GenerationSnapshot.plan","GenerationSnapshot.functionPaths","GroupPath.fromGroupModulePath"],"sources":["../src/FunctionModule.ts"],"sourcesContent":["import * as FileSystem from \"effect/FileSystem\";\nimport * as Path from \"effect/Path\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Match from \"effect/Match\";\nimport * as GenerationSnapshot from \"./GenerationSnapshot\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\nimport { CodeBlockWriter } from \"./CodeBlockWriter\";\nimport { logFileAdded, logFileModified, logFileRemoved } from \"./log\";\nimport { ConfectDirectory } from \"./ConfectDirectory\";\nimport { ConvexDirectory } from \"./ConvexDirectory\";\nimport { removePathIfExists, toModuleImportPath } from \"./utils\";\n\nexport const render = ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof renderEffect>[0]) =>\n renderEffect({ functionNames, registeredFunctionsImportPath, useNode });\n\nconst renderEffect = Effect.fnUntraced(function* ({\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });\n\n if (useNode) {\n yield* cbw.writeLine(`\"use node\";`);\n yield* cbw.blankLine();\n }\n\n yield* cbw.writeLine(\n `import registeredFunctions from \"${registeredFunctionsImportPath}\";`,\n );\n yield* cbw.newLine();\n yield* Effect.forEach(functionNames, (name) =>\n cbw.writeLine(`export const ${name} = registeredFunctions.${name};`),\n );\n\n return yield* cbw.toString();\n});\n\nexport const generateGroupModule = ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: Parameters<typeof generateGroupModuleEffect>[0]) =>\n generateGroupModuleEffect({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\nconst generateGroupModuleEffect = Effect.fnUntraced(function* ({\n groupPath,\n functionNames,\n registeredFunctionsImportPath,\n useNode = false,\n}: {\n groupPath: GroupPath.GroupPath;\n functionNames: ReadonlyArray<string>;\n registeredFunctionsImportPath: string;\n useNode?: boolean;\n}) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n const directoryPath = path.dirname(modulePath);\n if (!(yield* fs.exists(directoryPath))) {\n yield* fs.makeDirectory(directoryPath, { recursive: true });\n }\n\n const functionsContentsString = yield* render({\n functionNames,\n registeredFunctionsImportPath,\n useNode,\n });\n\n if (!(yield* fs.exists(modulePath))) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Added\" as const;\n }\n const existing = yield* fs.readFileString(modulePath);\n if (existing !== functionsContentsString) {\n yield* fs.writeFileString(modulePath, functionsContentsString);\n return \"Modified\" as const;\n }\n return \"Unchanged\" as const;\n});\n\n/**\n * Compute the module import specifier (relative to `modulePath`) for a group's\n * registry file under `confect/_generated/registeredFunctions/`. The registry\n * path mirrors the group's path one-to-one (see\n * `registeredFunctionsRelativePath` in `LeafModule.ts`) for both Convex and\n * Node groups.\n */\nexport const registeredFunctionsImportPathForGroup = Effect.fnUntraced(\n function* (groupPath: GroupPath.GroupPath, modulePath: string) {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const registeredFunctionsPath =\n path.join(\n confectDirectory,\n \"_generated\",\n \"registeredFunctions\",\n ...groupPath.pathSegments,\n ) + \".ts\";\n\n return yield* toModuleImportPath(\n path.relative(path.dirname(modulePath), registeredFunctionsPath),\n );\n },\n);\n\nconst logGroupPaths = Effect.fnUntraced(function* <R>(\n groupPaths: GroupPaths.GroupPaths,\n logFn: (fullPath: string) => Effect.Effect<void, never, R>,\n): Effect.fn.Return<void, never, R | Path.Path | ConvexDirectory> {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.forEach(\n groupPaths,\n Effect.fnUntraced(function* (gp: GroupPath.GroupPath) {\n const relativeModulePath = yield* GroupPath.modulePath(gp);\n yield* logFn(path.join(convexDirectory, relativeModulePath));\n }),\n );\n});\n\nexport const generateFunctions = Effect.fnUntraced(function* (\n snapshot: GenerationSnapshot.GenerationSnapshot,\n) {\n const groupPathsFromFs = yield* getGroupPathsFromFs;\n yield* applyFunctionPlan(GenerationSnapshot.plan(snapshot, groupPathsFromFs));\n return GenerationSnapshot.functionPaths(snapshot);\n});\n\nexport const applyFunctionPlan = Effect.fnUntraced(function* (\n plan: GenerationSnapshot.ModulePlan,\n) {\n const removed = GroupPaths.GroupPaths.make(\n HashSet.fromIterable(plan.removed),\n );\n yield* removeGroups(removed);\n yield* logGroupPaths(removed, logFileRemoved);\n yield* writeGroups(plan.changed);\n});\n\nconst getGroupPathsFromFs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const RESERVED_CONVEX_TS_FILE_NAMES = new Set([\n \"schema.ts\",\n \"http.ts\",\n \"crons.ts\",\n \"auth.config.ts\",\n \"convex.config.ts\",\n ]);\n\n const allConvexPaths = yield* fs.readDirectory(convexDirectory, {\n recursive: true,\n });\n const groupPathArray = yield* pipe(\n allConvexPaths,\n Array.filter(\n (convexPath) =>\n path.extname(convexPath) === \".ts\" &&\n !RESERVED_CONVEX_TS_FILE_NAMES.has(path.basename(convexPath)) &&\n path.basename(path.dirname(convexPath)) !== \"_generated\",\n ),\n Effect.forEach((groupModulePath) =>\n GroupPath.fromGroupModulePath(groupModulePath),\n ),\n );\n return GroupPaths.GroupPaths.make(HashSet.fromIterable(groupPathArray));\n});\n\nexport const removeGroups = Effect.fnUntraced(function* (\n groupPaths: GroupPaths.GroupPaths,\n) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n\n yield* Effect.all(\n HashSet.map(groupPaths, (groupPath) =>\n Effect.gen(function* () {\n const relativeModulePath = yield* GroupPath.modulePath(groupPath);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n\n yield* Effect.logDebug(`Removing group '${relativeModulePath}'...`);\n\n yield* removePathIfExists(modulePath);\n yield* Effect.logDebug(`Group '${relativeModulePath}' removed`);\n }),\n ),\n { concurrency: \"unbounded\" },\n );\n});\n\nexport const writeGroups = (\n groups: ReadonlyArray<GenerationSnapshot.GroupSummary>,\n) =>\n Effect.forEach(\n groups,\n Effect.fnUntraced(function* (group: GenerationSnapshot.GroupSummary) {\n const path = yield* Path.Path;\n const convexDirectory = yield* ConvexDirectory.get;\n const relativeModulePath = yield* GroupPath.modulePath(group.path);\n const modulePath = path.join(convexDirectory, relativeModulePath);\n const registeredFunctionsImportPath =\n yield* registeredFunctionsImportPathForGroup(group.path, modulePath);\n const change = yield* generateGroupModule({\n groupPath: group.path,\n functionNames: group.functionNames,\n registeredFunctionsImportPath,\n useNode: group.runtime === \"Node\",\n });\n yield* Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(modulePath)),\n Match.when(\"Modified\", () => logFileModified(modulePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n );\n }),\n );\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { GroupPath } from "./GroupPath.mjs";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
//#region src/FunctionPath.ts
|
|
4
|
+
/**
|
|
5
|
+
* The path to a function in the Confect API.
|
|
6
|
+
*/
|
|
7
|
+
var FunctionPath = class extends Schema.Class("FunctionPath")({
|
|
8
|
+
groupPath: GroupPath,
|
|
9
|
+
name: Schema.NonEmptyString
|
|
10
|
+
}) {};
|
|
11
|
+
/**
|
|
12
|
+
* Get the group path from a function path.
|
|
13
|
+
*/
|
|
14
|
+
const groupPath = (functionPath) => functionPath.groupPath;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { FunctionPath, groupPath };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=FunctionPath.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FunctionPath.mjs","names":["GroupPath.GroupPath"],"sources":["../src/FunctionPath.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as GroupPath from \"./GroupPath\";\n\n/**\n * The path to a function in the Confect API.\n */\nexport class FunctionPath extends Schema.Class<FunctionPath>(\"FunctionPath\")({\n groupPath: GroupPath.GroupPath,\n name: Schema.NonEmptyString,\n}) {}\n\n/**\n * Get the group path from a function path.\n */\nexport const groupPath = (functionPath: FunctionPath): GroupPath.GroupPath =>\n functionPath.groupPath;\n\n/**\n * Get the function name from a function path.\n */\nexport const name = (functionPath: FunctionPath): string => functionPath.name;\n\n/**\n * Get the function path as a string.\n */\nexport const toString = (functionPath: FunctionPath): string =>\n `${GroupPath.toString(functionPath.groupPath)}.${functionPath.name}`;\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkC,OAAO,MAAoB,cAAc,CAAC,CAAC;CAC3E,WAAWA;CACX,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,CAAC;;;;AAKJ,MAAa,aAAa,iBACxB,aAAa"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { append, make as make$1 } from "./GroupPath.mjs";
|
|
2
|
+
import { FunctionPath, groupPath } from "./FunctionPath.mjs";
|
|
3
|
+
import { GroupPaths } from "./GroupPaths.mjs";
|
|
4
|
+
import { Spec } from "@confect/core";
|
|
5
|
+
import { pipe } from "effect/Function";
|
|
6
|
+
import * as HashSet from "effect/HashSet";
|
|
7
|
+
import * as Option from "effect/Option";
|
|
8
|
+
import * as Record from "effect/Record";
|
|
9
|
+
import * as Schema from "effect/Schema";
|
|
10
|
+
//#region src/FunctionPaths.ts
|
|
11
|
+
const FunctionPaths = Schema.HashSet(FunctionPath).pipe(Schema.brand("@confect/cli/FunctionPaths"));
|
|
12
|
+
const make = (spec) => makeHelper(Spec.groups(spec), Option.none(), FunctionPaths.make(HashSet.empty()));
|
|
13
|
+
const makeHelper = (groups, currentGroupPath, apiPaths) => Record.reduce(groups, apiPaths, (acc, group, groupName) => {
|
|
14
|
+
const groupPath = Option.match(currentGroupPath, {
|
|
15
|
+
onNone: () => make$1([groupName]),
|
|
16
|
+
onSome: (path) => append(path, groupName)
|
|
17
|
+
});
|
|
18
|
+
const accWithFunctions = Record.reduce(group.functions, acc, (acc_, _fn, name) => FunctionPaths.make(HashSet.add(acc_, FunctionPath.make({
|
|
19
|
+
groupPath,
|
|
20
|
+
name
|
|
21
|
+
}))));
|
|
22
|
+
return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);
|
|
23
|
+
});
|
|
24
|
+
const groupPaths = (functionPaths) => pipe(functionPaths, HashSet.map(groupPath), (paths) => GroupPaths.make(paths));
|
|
25
|
+
const diff = (previousFunctions, currentFunctions) => {
|
|
26
|
+
const currentGroups = groupPaths(currentFunctions);
|
|
27
|
+
const previousGroups = groupPaths(previousFunctions);
|
|
28
|
+
const groupsAdded = GroupPaths.make(HashSet.difference(currentGroups, previousGroups));
|
|
29
|
+
const groupsRemoved = GroupPaths.make(HashSet.difference(previousGroups, currentGroups));
|
|
30
|
+
const functionsAdded = FunctionPaths.make(HashSet.difference(currentFunctions, previousFunctions));
|
|
31
|
+
const existingGroupsToWhichFunctionsWereAdded = GroupPaths.make(HashSet.intersection(currentGroups, groupPaths(functionsAdded)));
|
|
32
|
+
const functionsRemoved = FunctionPaths.make(HashSet.difference(previousFunctions, currentFunctions));
|
|
33
|
+
const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.make(HashSet.intersection(previousGroups, groupPaths(functionsRemoved)));
|
|
34
|
+
return {
|
|
35
|
+
functionsAdded,
|
|
36
|
+
functionsRemoved,
|
|
37
|
+
groupsRemoved,
|
|
38
|
+
groupsAdded,
|
|
39
|
+
groupsChanged: pipe(existingGroupsToWhichFunctionsWereAdded, HashSet.union(existingGroupsToWhichFunctionsWereRemoved), HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)), (paths) => GroupPaths.make(paths))
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { FunctionPaths, diff, groupPaths, make };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=FunctionPaths.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FunctionPaths.mjs","names":["FunctionPath.FunctionPath","GroupPath.make","GroupPath.append","FunctionPath.groupPath"],"sources":["../src/FunctionPaths.ts"],"sourcesContent":["import { type GroupSpec, Spec } from \"@confect/core\";\nimport { pipe } from \"effect/Function\";\nimport * as HashSet from \"effect/HashSet\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Schema from \"effect/Schema\";\nimport * as FunctionPath from \"./FunctionPath\";\nimport * as GroupPath from \"./GroupPath\";\nimport * as GroupPaths from \"./GroupPaths\";\n\nexport const FunctionPaths = Schema.HashSet(FunctionPath.FunctionPath).pipe(\n Schema.brand(\"@confect/cli/FunctionPaths\"),\n);\nexport type FunctionPaths = typeof FunctionPaths.Type;\n\nexport const make = (spec: Spec.AnyWithProps): FunctionPaths =>\n makeHelper(\n Spec.groups(spec),\n Option.none(),\n FunctionPaths.make(HashSet.empty()),\n );\n\nconst makeHelper = (\n groups: {\n [key: string]: GroupSpec.AnyWithProps;\n },\n currentGroupPath: Option.Option<GroupPath.GroupPath>,\n apiPaths: FunctionPaths,\n): FunctionPaths =>\n Record.reduce(groups, apiPaths, (acc, group, groupName) => {\n const groupPath = Option.match(currentGroupPath, {\n onNone: () => GroupPath.make([groupName]),\n onSome: (path) => GroupPath.append(path, groupName),\n });\n\n const accWithFunctions = Record.reduce(\n group.functions,\n acc,\n (acc_, _fn, name) =>\n FunctionPaths.make(\n HashSet.add(\n acc_,\n FunctionPath.FunctionPath.make({\n groupPath,\n name,\n }),\n ),\n ),\n );\n\n return makeHelper(group.groups, Option.some(groupPath), accWithFunctions);\n });\n\nexport const groupPaths = (\n functionPaths: FunctionPaths,\n): GroupPaths.GroupPaths =>\n pipe(functionPaths, HashSet.map(FunctionPath.groupPath), (paths) =>\n GroupPaths.GroupPaths.make(paths),\n );\n\nexport const diff = (\n previousFunctions: FunctionPaths,\n currentFunctions: FunctionPaths,\n): {\n functionsAdded: FunctionPaths;\n functionsRemoved: FunctionPaths;\n groupsRemoved: GroupPaths.GroupPaths;\n groupsAdded: GroupPaths.GroupPaths;\n groupsChanged: GroupPaths.GroupPaths;\n} => {\n const currentGroups = groupPaths(currentFunctions);\n const previousGroups = groupPaths(previousFunctions);\n\n const groupsAdded = GroupPaths.GroupPaths.make(\n HashSet.difference(currentGroups, previousGroups),\n );\n const groupsRemoved = GroupPaths.GroupPaths.make(\n HashSet.difference(previousGroups, currentGroups),\n );\n\n const functionsAdded = FunctionPaths.make(\n HashSet.difference(currentFunctions, previousFunctions),\n );\n const existingGroupsToWhichFunctionsWereAdded = GroupPaths.GroupPaths.make(\n HashSet.intersection(currentGroups, groupPaths(functionsAdded)),\n );\n\n const functionsRemoved = FunctionPaths.make(\n HashSet.difference(previousFunctions, currentFunctions),\n );\n const existingGroupsToWhichFunctionsWereRemoved = GroupPaths.GroupPaths.make(\n HashSet.intersection(previousGroups, groupPaths(functionsRemoved)),\n );\n\n const groupsChanged = pipe(\n existingGroupsToWhichFunctionsWereAdded,\n HashSet.union(existingGroupsToWhichFunctionsWereRemoved),\n HashSet.difference(HashSet.union(groupsAdded, groupsRemoved)),\n (paths) => GroupPaths.GroupPaths.make(paths),\n );\n\n return {\n functionsAdded,\n functionsRemoved,\n groupsRemoved,\n groupsAdded,\n groupsChanged,\n };\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,gBAAgB,OAAO,QAAQA,YAAyB,CAAC,CAAC,KACrE,OAAO,MAAM,4BAA4B,CAC3C;AAGA,MAAa,QAAQ,SACnB,WACE,KAAK,OAAO,IAAI,GAChB,OAAO,KAAK,GACZ,cAAc,KAAK,QAAQ,MAAM,CAAC,CACpC;AAEF,MAAM,cACJ,QAGA,kBACA,aAEA,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,cAAc;CACzD,MAAM,YAAY,OAAO,MAAM,kBAAkB;EAC/C,cAAcC,OAAe,CAAC,SAAS,CAAC;EACxC,SAAS,SAASC,OAAiB,MAAM,SAAS;CACpD,CAAC;CAED,MAAM,mBAAmB,OAAO,OAC9B,MAAM,WACN,MACC,MAAM,KAAK,SACV,cAAc,KACZ,QAAQ,IACN,MAAA,aAC0B,KAAK;EAC7B;EACA;CACF,CAAC,CACH,CACF,CACJ;CAEA,OAAO,WAAW,MAAM,QAAQ,OAAO,KAAK,SAAS,GAAG,gBAAgB;AAC1E,CAAC;AAEH,MAAa,cACX,kBAEA,KAAK,eAAe,QAAQ,IAAIC,SAAsB,IAAI,UAAA,WAClC,KAAK,KAAK,CAClC;AAEF,MAAa,QACX,mBACA,qBAOG;CACH,MAAM,gBAAgB,WAAW,gBAAgB;CACjD,MAAM,iBAAiB,WAAW,iBAAiB;CAEnD,MAAM,cAAA,WAAoC,KACxC,QAAQ,WAAW,eAAe,cAAc,CAClD;CACA,MAAM,gBAAA,WAAsC,KAC1C,QAAQ,WAAW,gBAAgB,aAAa,CAClD;CAEA,MAAM,iBAAiB,cAAc,KACnC,QAAQ,WAAW,kBAAkB,iBAAiB,CACxD;CACA,MAAM,0CAAA,WAAgE,KACpE,QAAQ,aAAa,eAAe,WAAW,cAAc,CAAC,CAChE;CAEA,MAAM,mBAAmB,cAAc,KACrC,QAAQ,WAAW,mBAAmB,gBAAgB,CACxD;CACA,MAAM,4CAAA,WAAkE,KACtE,QAAQ,aAAa,gBAAgB,WAAW,gBAAgB,CAAC,CACnE;CASA,OAAO;EACL;EACA;EACA;EACA;EACA,eAZoB,KACpB,yCACA,QAAQ,MAAM,yCAAyC,GACvD,QAAQ,WAAW,QAAQ,MAAM,aAAa,aAAa,CAAC,IAC3D,UAAA,WAAgC,KAAK,KAAK,CAQ/B;CACd;AACF"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { GroupPath, append, make } from "./GroupPath.mjs";
|
|
2
|
+
import { SnapshotError } from "./SnapshotError.mjs";
|
|
3
|
+
import { ParentChildNameCollisionError } from "./CodegenError.mjs";
|
|
4
|
+
import { FunctionPath } from "./FunctionPath.mjs";
|
|
5
|
+
import { FunctionPaths } from "./FunctionPaths.mjs";
|
|
6
|
+
import { SpecModulePath } from "./SpecModulePath.mjs";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import { Identifier } from "@confect/core";
|
|
9
|
+
import * as Array from "effect/Array";
|
|
10
|
+
import * as Result from "effect/Result";
|
|
11
|
+
import * as HashSet from "effect/HashSet";
|
|
12
|
+
import * as Match from "effect/Match";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import * as Record from "effect/Record";
|
|
15
|
+
import * as HashMap from "effect/HashMap";
|
|
16
|
+
import * as Schema from "effect/Schema";
|
|
17
|
+
import * as String from "effect/String";
|
|
18
|
+
import * as SchemaGetter from "effect/SchemaGetter";
|
|
19
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
20
|
+
//#region src/GenerationSnapshot.ts
|
|
21
|
+
const GroupSummary = Schema.Struct({
|
|
22
|
+
path: GroupPath,
|
|
23
|
+
runtime: Schema.Literals(["Convex", "Node"]),
|
|
24
|
+
functionNames: Schema.Array(Schema.NonEmptyString)
|
|
25
|
+
});
|
|
26
|
+
const GroupTree = Schema.Struct({
|
|
27
|
+
runtime: GroupSummary.fields.runtime,
|
|
28
|
+
functionNames: GroupSummary.fields.functionNames,
|
|
29
|
+
groups: Schema.Record(Schema.String, Schema.suspend(() => GroupTree))
|
|
30
|
+
});
|
|
31
|
+
var Snapshot = class Snapshot {
|
|
32
|
+
#leaves;
|
|
33
|
+
constructor(leaves) {
|
|
34
|
+
this.#leaves = leaves;
|
|
35
|
+
}
|
|
36
|
+
static parseLeaves(leaves) {
|
|
37
|
+
return Result.map(parseNoParentChildNameCollisions(leaves), (parsed) => new Snapshot(parsed));
|
|
38
|
+
}
|
|
39
|
+
get leaves() {
|
|
40
|
+
return this.#leaves;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const Entries = Schema.Array(Schema.Tuple([Schema.String, GroupTree]));
|
|
44
|
+
const CanonicalSpecPath = SpecModulePath.check(Schema.makeFilter((path) => !path.includes("\\")));
|
|
45
|
+
const rootPath = (path) => make(String.split(path.slice(0, -8), "/"));
|
|
46
|
+
const parseTree = (relativePath, path, tree) => Result.gen(function* () {
|
|
47
|
+
yield* Result.try({
|
|
48
|
+
try: () => {
|
|
49
|
+
for (const name of tree.functionNames) Identifier.validateConfectFunctionIdentifier(name);
|
|
50
|
+
},
|
|
51
|
+
catch: () => new SnapshotError({
|
|
52
|
+
reason: "NoncanonicalFunctionNames",
|
|
53
|
+
relativePath,
|
|
54
|
+
pathSegments: path.pathSegments
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
if (HashSet.size(HashSet.fromIterable(tree.functionNames)) !== tree.functionNames.length) return yield* Result.fail(new SnapshotError({
|
|
58
|
+
reason: "NoncanonicalFunctionNames",
|
|
59
|
+
relativePath,
|
|
60
|
+
pathSegments: path.pathSegments
|
|
61
|
+
}));
|
|
62
|
+
for (const [name, child] of Object.entries(tree.groups)) {
|
|
63
|
+
yield* Result.try({
|
|
64
|
+
try: () => Identifier.validateConfectFunctionIdentifier(name),
|
|
65
|
+
catch: () => new SnapshotError({
|
|
66
|
+
reason: "NoncanonicalPath",
|
|
67
|
+
relativePath,
|
|
68
|
+
pathSegments: [...path.pathSegments, name]
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
yield* parseTree(relativePath, append(path, name), child);
|
|
72
|
+
}
|
|
73
|
+
return tree;
|
|
74
|
+
});
|
|
75
|
+
const fromEntries = (entries) => Result.gen(function* () {
|
|
76
|
+
let leaves = HashMap.empty();
|
|
77
|
+
for (const [key, tree] of entries) {
|
|
78
|
+
const relativePath = yield* Schema.decodeResult(CanonicalSpecPath)(key).pipe(Result.mapError((cause) => new SnapshotError({
|
|
79
|
+
reason: "NoncanonicalPath",
|
|
80
|
+
relativePath: key,
|
|
81
|
+
pathSegments: [],
|
|
82
|
+
cause
|
|
83
|
+
})));
|
|
84
|
+
const path = rootPath(relativePath);
|
|
85
|
+
yield* Result.try({
|
|
86
|
+
try: () => {
|
|
87
|
+
for (const segment of path.pathSegments) Identifier.validateConfectFunctionIdentifier(segment);
|
|
88
|
+
},
|
|
89
|
+
catch: () => new SnapshotError({
|
|
90
|
+
reason: "NoncanonicalPath",
|
|
91
|
+
relativePath,
|
|
92
|
+
pathSegments: path.pathSegments
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
if (HashMap.has(leaves, relativePath)) return yield* Result.fail(new SnapshotError({
|
|
96
|
+
reason: "DuplicateLeaf",
|
|
97
|
+
relativePath,
|
|
98
|
+
pathSegments: path.pathSegments
|
|
99
|
+
}));
|
|
100
|
+
const parsed = yield* parseTree(relativePath, path, tree);
|
|
101
|
+
leaves = HashMap.set(leaves, relativePath, parsed);
|
|
102
|
+
}
|
|
103
|
+
return yield* Snapshot.parseLeaves(leaves);
|
|
104
|
+
});
|
|
105
|
+
const parse = (input) => Schema.decodeUnknownResult(Entries)(input).pipe(Result.mapError((cause) => new SnapshotError({
|
|
106
|
+
reason: "InvalidShape",
|
|
107
|
+
relativePath: "",
|
|
108
|
+
pathSegments: [],
|
|
109
|
+
cause
|
|
110
|
+
})), Result.flatMap(fromEntries));
|
|
111
|
+
const GenerationSnapshot = Entries.pipe(Schema.decodeTo(Schema.declare((input) => input instanceof Snapshot), {
|
|
112
|
+
decode: SchemaGetter.transformEffect((entries, options) => Effect.fromResult(fromEntries(entries)).pipe(Effect.mapError((error) => new SchemaIssue.InvalidValue({ message: Match.value(error).pipe(Match.tagsExhaustive({
|
|
113
|
+
SnapshotError: (failure) => failure.message,
|
|
114
|
+
ParentChildNameCollisionError: (failure) => `${failure.parentSpecPath} declares a ${failure.collisionKind} named ${failure.collisionName} that collides with ${failure.childSpecPath}`
|
|
115
|
+
})) }, entries, options)))),
|
|
116
|
+
encode: SchemaGetter.transform((snapshot) => HashMap.toEntries(snapshot.leaves))
|
|
117
|
+
}));
|
|
118
|
+
const summarize = (group) => ({
|
|
119
|
+
runtime: group.runtime,
|
|
120
|
+
functionNames: Record.keys(group.functions),
|
|
121
|
+
groups: Record.map(group.groups, summarize)
|
|
122
|
+
});
|
|
123
|
+
const update = (snapshot, leaves) => Result.gen(function* () {
|
|
124
|
+
if (leaves.length === 0) return snapshot;
|
|
125
|
+
const replacement = yield* fromLoadedLeaves(leaves);
|
|
126
|
+
return yield* Snapshot.parseLeaves(HashMap.union(snapshot.leaves, replacement.leaves));
|
|
127
|
+
});
|
|
128
|
+
const fromLoadedLeaves = (leaves) => parse(leaves.map((leaf) => [leaf.relativePath.replaceAll("\\", "/"), summarize(leaf.spec)]));
|
|
129
|
+
const groups = (snapshot) => {
|
|
130
|
+
const visit = (path, tree) => [{
|
|
131
|
+
path,
|
|
132
|
+
runtime: tree.runtime,
|
|
133
|
+
functionNames: Array.sort(tree.functionNames, String.Order)
|
|
134
|
+
}, ...Array.flatMap(Array.sort(Object.keys(tree.groups), String.Order), (name) => visit(append(path, name), tree.groups[name]))];
|
|
135
|
+
return Array.flatMap(Array.fromIterable(snapshot.leaves), ([path, tree]) => visit(rootPath(path), tree));
|
|
136
|
+
};
|
|
137
|
+
const functionPaths = (snapshot) => FunctionPaths.make(HashSet.fromIterable(Array.flatMap(groups(snapshot), (group) => group.functionNames.map((name) => FunctionPath.make({
|
|
138
|
+
groupPath: group.path,
|
|
139
|
+
name
|
|
140
|
+
})))));
|
|
141
|
+
const generatedGroups = (snapshot) => HashMap.fromIterable(Array.filterMap(groups(snapshot), (group) => group.functionNames.length === 0 ? Result.fail(void 0) : Result.succeed([group.path, group])));
|
|
142
|
+
const plan = (snapshot, existing) => {
|
|
143
|
+
const current = generatedGroups(snapshot);
|
|
144
|
+
return {
|
|
145
|
+
removed: Array.fromIterable(existing).filter((path) => !HashMap.has(current, path)),
|
|
146
|
+
changed: Array.fromIterable(HashMap.values(current))
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
const equivalentGroup = Schema.toEquivalence(GroupSummary);
|
|
150
|
+
const diff = (before, after) => {
|
|
151
|
+
const previous = generatedGroups(before);
|
|
152
|
+
const current = generatedGroups(after);
|
|
153
|
+
return {
|
|
154
|
+
removed: Array.filter(HashMap.keys(previous), (path) => !HashMap.has(current, path)),
|
|
155
|
+
changed: Array.filter(HashMap.values(current), (group) => {
|
|
156
|
+
const old = HashMap.get(previous, group.path);
|
|
157
|
+
return Option.isNone(old) || !equivalentGroup(old.value, group);
|
|
158
|
+
})
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
const parseNoParentChildNameCollisions = (leaves) => {
|
|
162
|
+
for (const childPath of HashMap.keys(leaves)) {
|
|
163
|
+
const segments = rootPath(childPath).pathSegments;
|
|
164
|
+
for (let depth = 1; depth < segments.length; depth++) {
|
|
165
|
+
const parentPath = SpecModulePath.make(`${segments.slice(0, depth).join("/")}.spec.ts`);
|
|
166
|
+
const parent = HashMap.get(leaves, parentPath);
|
|
167
|
+
if (Option.isNone(parent)) continue;
|
|
168
|
+
const collisionName = segments[depth];
|
|
169
|
+
const collisionKind = parent.value.functionNames.includes(collisionName) ? "function" : Object.hasOwn(parent.value.groups, collisionName) ? "group" : void 0;
|
|
170
|
+
if (collisionKind !== void 0) return Result.fail(new ParentChildNameCollisionError({
|
|
171
|
+
parentSpecPath: parentPath,
|
|
172
|
+
childSpecPath: childPath,
|
|
173
|
+
collisionName,
|
|
174
|
+
collisionKind
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return Result.succeed(leaves);
|
|
179
|
+
};
|
|
180
|
+
//#endregion
|
|
181
|
+
export { GenerationSnapshot, GroupSummary, GroupTree, diff, fromLoadedLeaves, functionPaths, parse, plan, update };
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=GenerationSnapshot.mjs.map
|