@confect/cli 1.0.0-next.3 → 1.0.0-next.4

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.
@@ -4,7 +4,13 @@ import { Command } from "@effect/cli";
4
4
  import { FileSystem, Path } from "@effect/platform";
5
5
  import { Effect, Match, Option } from "effect";
6
6
  import * as tsx from "tsx/esm/api";
7
- import { logCompleted, logFileAdded, logFileModified } from "../log";
7
+ import {
8
+ logFileAdded,
9
+ logFileModified,
10
+ logFileRemoved,
11
+ logPending,
12
+ logSuccess,
13
+ } from "../log";
8
14
  import { ConfectDirectory } from "../services/ConfectDirectory";
9
15
  import { ConvexDirectory } from "../services/ConvexDirectory";
10
16
  import * as templates from "../templates";
@@ -18,10 +24,39 @@ import {
18
24
  writeFileStringAndLog,
19
25
  } from "../utils";
20
26
 
27
+ const getNodeSpecPath = Effect.gen(function* () {
28
+ const path = yield* Path.Path;
29
+ const confectDirectory = yield* ConfectDirectory.get;
30
+ return path.join(confectDirectory, "nodeSpec.ts");
31
+ });
32
+
33
+ const loadNodeSpec = Effect.gen(function* () {
34
+ const fs = yield* FileSystem.FileSystem;
35
+ const path = yield* Path.Path;
36
+ const nodeSpecPath = yield* getNodeSpecPath;
37
+
38
+ if (!(yield* fs.exists(nodeSpecPath))) {
39
+ return Option.none<Spec.AnyWithPropsWithRuntime<"Node">>();
40
+ }
41
+
42
+ const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);
43
+ const nodeSpecModule = yield* Effect.promise(() =>
44
+ tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),
45
+ );
46
+ const nodeSpec = nodeSpecModule.default;
47
+
48
+ if (!Spec.isNodeSpec(nodeSpec)) {
49
+ return yield* Effect.die("nodeSpec.ts does not export a valid Node Spec");
50
+ }
51
+
52
+ return Option.some(nodeSpec);
53
+ });
54
+
21
55
  export const codegen = Command.make("codegen", {}, () =>
22
56
  Effect.gen(function* () {
57
+ yield* logPending("Performing initial sync…");
23
58
  yield* codegenHandler;
24
- yield* logCompleted("Generated files are up-to-date");
59
+ yield* logSuccess("Generated files are up-to-date");
25
60
  }),
26
61
  ).pipe(
27
62
  Command.withDescription(
@@ -32,7 +67,14 @@ export const codegen = Command.make("codegen", {}, () =>
32
67
  export const codegenHandler = Effect.gen(function* () {
33
68
  yield* generateConfectGeneratedDirectory;
34
69
  yield* Effect.all(
35
- [generateApi, generateRefs, generateRegisteredFunctions, generateServices],
70
+ [
71
+ generateApi,
72
+ generateRefs,
73
+ generateRegisteredFunctions,
74
+ generateNodeApi,
75
+ generateNodeRegisteredFunctions,
76
+ generateServices,
77
+ ],
36
78
  { concurrency: "unbounded" },
37
79
  );
38
80
  const [functionPaths] = yield* Effect.all(
@@ -67,19 +109,14 @@ const generateApi = Effect.gen(function* () {
67
109
  const confectDirectory = yield* ConfectDirectory.get;
68
110
 
69
111
  const apiPath = path.join(confectDirectory, "_generated", "api.ts");
112
+ const apiDir = path.dirname(apiPath);
70
113
 
71
114
  const schemaImportPath = yield* removePathExtension(
72
- path.relative(
73
- path.dirname(apiPath),
74
- path.join(confectDirectory, "schema.ts"),
75
- ),
115
+ path.relative(apiDir, path.join(confectDirectory, "schema.ts")),
76
116
  );
77
117
 
78
118
  const specImportPath = yield* removePathExtension(
79
- path.relative(
80
- path.dirname(apiPath),
81
- path.join(confectDirectory, "spec.ts"),
82
- ),
119
+ path.relative(apiDir, path.join(confectDirectory, "spec.ts")),
83
120
  );
84
121
 
85
122
  const apiContents = yield* templates.api({
@@ -90,7 +127,42 @@ const generateApi = Effect.gen(function* () {
90
127
  yield* writeFileStringAndLog(apiPath, apiContents);
91
128
  });
92
129
 
130
+ export const generateNodeApi = Effect.gen(function* () {
131
+ const fs = yield* FileSystem.FileSystem;
132
+ const path = yield* Path.Path;
133
+ const confectDirectory = yield* ConfectDirectory.get;
134
+
135
+ const nodeSpecPath = yield* getNodeSpecPath;
136
+ const nodeApiPath = path.join(confectDirectory, "_generated", "nodeApi.ts");
137
+
138
+ if (!(yield* fs.exists(nodeSpecPath))) {
139
+ if (yield* fs.exists(nodeApiPath)) {
140
+ yield* fs.remove(nodeApiPath);
141
+ yield* logFileRemoved(nodeApiPath);
142
+ }
143
+ return;
144
+ }
145
+
146
+ const nodeApiDir = path.dirname(nodeApiPath);
147
+
148
+ const schemaImportPath = yield* removePathExtension(
149
+ path.relative(nodeApiDir, path.join(confectDirectory, "schema.ts")),
150
+ );
151
+
152
+ const nodeSpecImportPath = yield* removePathExtension(
153
+ path.relative(nodeApiDir, nodeSpecPath),
154
+ );
155
+
156
+ const nodeApiContents = yield* templates.nodeApi({
157
+ schemaImportPath,
158
+ nodeSpecImportPath,
159
+ });
160
+
161
+ yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);
162
+ });
163
+
93
164
  const generateFunctionModules = Effect.gen(function* () {
165
+ const fs = yield* FileSystem.FileSystem;
94
166
  const path = yield* Path.Path;
95
167
  const confectDirectory = yield* ConfectDirectory.get;
96
168
 
@@ -102,11 +174,20 @@ const generateFunctionModules = Effect.gen(function* () {
102
174
  );
103
175
  const spec = specModule.default;
104
176
 
105
- if (!Spec.isSpec(spec)) {
106
- return yield* Effect.die("spec.ts does not export a valid Spec");
177
+ if (!Spec.isConvexSpec(spec)) {
178
+ return yield* Effect.die("spec.ts does not export a valid Convex Spec");
107
179
  }
108
180
 
109
- return yield* generateFunctions(spec);
181
+ const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
182
+ const nodeImplExists = yield* fs.exists(nodeImplPath);
183
+ const nodeSpecOption = yield* loadNodeSpec;
184
+
185
+ const mergedSpec = Option.match(nodeSpecOption, {
186
+ onNone: () => spec,
187
+ onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),
188
+ });
189
+
190
+ return yield* generateFunctions(mergedSpec);
110
191
  });
111
192
 
112
193
  const generateSchema = Effect.gen(function* () {
@@ -189,23 +270,67 @@ const generateRegisteredFunctions = Effect.gen(function* () {
189
270
  );
190
271
  });
191
272
 
273
+ export const generateNodeRegisteredFunctions = Effect.gen(function* () {
274
+ const fs = yield* FileSystem.FileSystem;
275
+ const path = yield* Path.Path;
276
+ const confectDirectory = yield* ConfectDirectory.get;
277
+
278
+ const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
279
+ const nodeSpecPath = yield* getNodeSpecPath;
280
+ const nodeRegisteredFunctionsPath = path.join(
281
+ confectDirectory,
282
+ "_generated",
283
+ "nodeRegisteredFunctions.ts",
284
+ );
285
+
286
+ const nodeImplExists = yield* fs.exists(nodeImplPath);
287
+ const nodeSpecExists = yield* fs.exists(nodeSpecPath);
288
+
289
+ if (!nodeImplExists || !nodeSpecExists) {
290
+ if (yield* fs.exists(nodeRegisteredFunctionsPath)) {
291
+ yield* fs.remove(nodeRegisteredFunctionsPath);
292
+ yield* logFileRemoved(nodeRegisteredFunctionsPath);
293
+ }
294
+ return;
295
+ }
296
+
297
+ const nodeImplImportPath = yield* removePathExtension(
298
+ path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),
299
+ );
300
+
301
+ const nodeRegisteredFunctionsContents =
302
+ yield* templates.nodeRegisteredFunctions({
303
+ nodeImplImportPath,
304
+ });
305
+
306
+ yield* writeFileStringAndLog(
307
+ nodeRegisteredFunctionsPath,
308
+ nodeRegisteredFunctionsContents,
309
+ );
310
+ });
311
+
192
312
  const generateRefs = Effect.gen(function* () {
313
+ const fs = yield* FileSystem.FileSystem;
193
314
  const path = yield* Path.Path;
194
315
  const confectDirectory = yield* ConfectDirectory.get;
195
316
 
196
317
  const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
197
-
198
- const confectSpecPath = path.join(confectDirectory, "spec.ts");
199
318
  const refsPath = path.join(confectGeneratedDirectory, "refs.ts");
319
+ const refsDir = path.dirname(refsPath);
200
320
 
201
- const relativeImportPath = path.relative(
202
- path.dirname(refsPath),
203
- confectSpecPath,
321
+ const specImportPath = yield* removePathExtension(
322
+ path.relative(refsDir, path.join(confectDirectory, "spec.ts")),
204
323
  );
205
- const importPathWithoutExt = yield* removePathExtension(relativeImportPath);
324
+
325
+ const nodeSpecPath = yield* getNodeSpecPath;
326
+ const nodeSpecExists = yield* fs.exists(nodeSpecPath);
327
+ const nodeSpecImportPath = nodeSpecExists
328
+ ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))
329
+ : null;
206
330
 
207
331
  const refsContents = yield* templates.refs({
208
- specImportPath: importPathWithoutExt,
332
+ specImportPath,
333
+ ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),
209
334
  });
210
335
 
211
336
  yield* writeFileStringAndLog(refsPath, refsContents);