@confect/cli 8.0.0 → 9.0.0-next.0

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,7 +1,19 @@
1
- import { DatabaseSchema, Spec } from "@confect/core";
1
+ import { Spec } from "@confect/core";
2
+ import * as DatabaseSchema from "@confect/server/DatabaseSchema";
2
3
  import { Command } from "@effect/cli";
3
4
  import { FileSystem, Path } from "@effect/platform";
4
- import { Effect, Match, Option } from "effect";
5
+ import { Array, Effect, Either, HashSet, Match, Option, Ref } from "effect";
6
+ import { fromBundlerError } from "../BuildError";
7
+ import * as CodegenError from "../CodegenError";
8
+ import {
9
+ MissingImplFileError,
10
+ MissingSchemaFileError,
11
+ MissingSpecFileError,
12
+ SchemaInvalidDefaultExportError,
13
+ } from "../CodegenError";
14
+ import { ConfectDirectory } from "../ConfectDirectory";
15
+ import { ConvexDirectory } from "../ConvexDirectory";
16
+ import * as FunctionPaths from "../FunctionPaths";
5
17
  import {
6
18
  logFileAdded,
7
19
  logFileModified,
@@ -9,66 +21,94 @@ import {
9
21
  logPending,
10
22
  logSuccess,
11
23
  } from "../log";
12
- import { ConfectDirectory } from "../ConfectDirectory";
13
- import { ConvexDirectory } from "../ConvexDirectory";
24
+ import {
25
+ discoverLeafImplFiles,
26
+ discoverLeafSpecFiles,
27
+ implPathForSpec,
28
+ registeredFunctionsRelativePath,
29
+ specPathForImpl,
30
+ toLeafModule,
31
+ toNodeRegistryLeaf,
32
+ validateImpl,
33
+ validateSpec,
34
+ type LeafModule,
35
+ } from "../LeafModule";
36
+ import {
37
+ assemblyNodesFromLeaves,
38
+ partitionByRuntime,
39
+ } from "../SpecAssemblyNode";
14
40
  import * as templates from "../templates";
41
+ import * as Bundler from "../Bundler";
15
42
  import {
16
- bundleAndImport,
17
43
  generateAuthConfig,
18
44
  generateCrons,
19
45
  generateFunctions,
20
46
  generateHttp,
21
47
  removePathExtension,
48
+ removePathIfExists,
49
+ toModuleImportPath,
50
+ touchConvexSchema,
22
51
  writeFileStringAndLog,
52
+ WriteTracker,
23
53
  } from "../utils";
24
54
 
25
- const getNodeSpecPath = Effect.gen(function* () {
26
- const path = yield* Path.Path;
27
- const confectDirectory = yield* ConfectDirectory.get;
28
- return path.join(confectDirectory, "nodeSpec.ts");
29
- });
30
-
31
- const loadNodeSpec = Effect.gen(function* () {
32
- const fs = yield* FileSystem.FileSystem;
33
- const nodeSpecPath = yield* getNodeSpecPath;
34
-
35
- if (!(yield* fs.exists(nodeSpecPath))) {
36
- return Option.none<Spec.AnyWithPropsWithRuntime<"Node">>();
37
- }
38
-
39
- const nodeSpecModule = yield* bundleAndImport(nodeSpecPath);
40
- const nodeSpec = nodeSpecModule.default;
41
-
42
- if (!Spec.isNodeSpec(nodeSpec)) {
43
- return yield* Effect.die("nodeSpec.ts does not export a valid Node Spec");
44
- }
45
-
46
- return Option.some(nodeSpec);
47
- });
55
+ const GENERATED_SPEC_PATH = "_generated/spec.ts";
56
+ const GENERATED_NODE_SPEC_PATH = "_generated/nodeSpec.ts";
57
+
58
+ const LEGACY_PATHS = [
59
+ "spec.ts",
60
+ "nodeSpec.ts",
61
+ "impl.ts",
62
+ "nodeImpl.ts",
63
+ "notesAndRandom.impl.ts",
64
+ "groups.impl.ts",
65
+ "_generated/registeredFunctions.ts",
66
+ "_generated/nodeRegisteredFunctions.ts",
67
+ "_generated/impl.ts",
68
+ "_generated/nodeImpl.ts",
69
+ ];
48
70
 
49
71
  export const codegen = Command.make("codegen", {}, () =>
50
72
  Effect.gen(function* () {
51
73
  yield* logPending("Performing initial sync…");
52
- yield* codegenHandler;
53
- yield* logSuccess("Generated files are up-to-date");
74
+ yield* codegenHandler.pipe(
75
+ Effect.asVoid,
76
+ Effect.tap(() => logSuccess("Generated files are up-to-date")),
77
+ CodegenError.tapAndLog,
78
+ );
54
79
  }),
55
80
  ).pipe(
56
81
  Command.withDescription(
57
- "Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)",
82
+ "Generate `confect/_generated` files and the contents of the `convex` directory (except `convex.config.ts` and `tsconfig.json`)",
58
83
  ),
59
84
  );
60
85
 
61
86
  export const codegenHandler = Effect.gen(function* () {
87
+ const tracker = yield* Ref.make(false);
88
+
89
+ const functionPaths = yield* runCodegen.pipe(
90
+ Effect.provideService(WriteTracker, tracker),
91
+ );
92
+
93
+ const anyWritesHappened = yield* Ref.get(tracker);
94
+ return { functionPaths, anyWritesHappened };
95
+ });
96
+
97
+ const runCodegen = Effect.gen(function* () {
62
98
  yield* generateConfectGeneratedDirectory;
99
+ // Validate schema first so its missing-file / invalid-default-export
100
+ // diagnostics surface ahead of impl bundling, which transitively depends
101
+ // on schema via `_generated/api.ts` and would otherwise blow up with a
102
+ // less actionable bundler error.
103
+ yield* validateSchema;
104
+ const leaves = yield* loadAndValidateLeafModules;
105
+ yield* removeLegacyFiles;
106
+ yield* generateAssembledSpecs(leaves);
107
+ yield* validateImplModules(leaves);
108
+ yield* generateGroupRegisteredFunctions(leaves);
109
+ yield* removeObsoleteRegisteredFunctions(leaves);
63
110
  yield* Effect.all(
64
- [
65
- generateApi,
66
- generateRefs,
67
- generateRegisteredFunctions,
68
- generateNodeApi,
69
- generateNodeRegisteredFunctions,
70
- generateServices,
71
- ],
111
+ [generateApi, generateRefs, generateNodeApi, generateServices],
72
112
  { concurrency: "unbounded" },
73
113
  );
74
114
  const [functionPaths] = yield* Effect.all(
@@ -81,6 +121,7 @@ export const codegenHandler = Effect.gen(function* () {
81
121
  ],
82
122
  { concurrency: "unbounded" },
83
123
  );
124
+ yield* touchConvexSchema;
84
125
  return functionPaths;
85
126
  });
86
127
 
@@ -97,6 +138,273 @@ const generateConfectGeneratedDirectory = Effect.gen(function* () {
97
138
  }
98
139
  });
99
140
 
141
+ const loadAndValidateLeafModules = Effect.gen(function* () {
142
+ const fs = yield* FileSystem.FileSystem;
143
+ const path = yield* Path.Path;
144
+ const confectDirectory = yield* ConfectDirectory.get;
145
+ const specFiles = yield* discoverLeafSpecFiles;
146
+
147
+ const leaves = yield* Effect.forEach(specFiles, (specRelativePath) =>
148
+ Effect.gen(function* () {
149
+ const leaf = yield* toLeafModule(specRelativePath);
150
+ yield* validateSpec(leaf);
151
+
152
+ const implRelativePath = yield* implPathForSpec(specRelativePath);
153
+ const implAbsolutePath = path.join(confectDirectory, implRelativePath);
154
+ if (!(yield* fs.exists(implAbsolutePath))) {
155
+ return yield* new MissingImplFileError({
156
+ specPath: specRelativePath,
157
+ expectedImplPath: implRelativePath,
158
+ });
159
+ }
160
+
161
+ return leaf;
162
+ }),
163
+ );
164
+
165
+ yield* validateOrphanImpls(specFiles);
166
+
167
+ return leaves;
168
+ });
169
+
170
+ const validateOrphanImpls = (specFiles: ReadonlyArray<string>) =>
171
+ Effect.gen(function* () {
172
+ const fs = yield* FileSystem.FileSystem;
173
+ const path = yield* Path.Path;
174
+ const confectDirectory = yield* ConfectDirectory.get;
175
+ const implFiles = yield* discoverLeafImplFiles;
176
+ const specPaths = new Set(specFiles);
177
+
178
+ yield* Effect.forEach(implFiles, (implRelativePath) =>
179
+ Effect.gen(function* () {
180
+ const specRelativePath = yield* specPathForImpl(implRelativePath);
181
+ if (specPaths.has(specRelativePath)) {
182
+ return;
183
+ }
184
+
185
+ const specAbsolutePath = path.join(confectDirectory, specRelativePath);
186
+ if (!(yield* fs.exists(specAbsolutePath))) {
187
+ return yield* new MissingSpecFileError({
188
+ implPath: implRelativePath,
189
+ expectedSpecPath: specRelativePath,
190
+ });
191
+ }
192
+ }),
193
+ );
194
+ });
195
+
196
+ const removeLegacyFiles = Effect.gen(function* () {
197
+ const fs = yield* FileSystem.FileSystem;
198
+ const path = yield* Path.Path;
199
+ const confectDirectory = yield* ConfectDirectory.get;
200
+
201
+ yield* Effect.forEach(LEGACY_PATHS, (relativePath) =>
202
+ Effect.gen(function* () {
203
+ const absolutePath = path.join(confectDirectory, relativePath);
204
+ if (yield* fs.exists(absolutePath)) {
205
+ yield* removePathIfExists(absolutePath);
206
+ yield* logFileRemoved(absolutePath);
207
+ }
208
+ }),
209
+ );
210
+ });
211
+
212
+ const generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>
213
+ Effect.gen(function* () {
214
+ const path = yield* Path.Path;
215
+ const confectDirectory = yield* ConfectDirectory.get;
216
+ const { convex, node } = partitionByRuntime(leaves);
217
+
218
+ if (convex.length > 0) {
219
+ const nodes = assemblyNodesFromLeaves(convex);
220
+ const specContents = yield* templates.assembledSpec({
221
+ nodes,
222
+ runtime: "Convex",
223
+ });
224
+ yield* writeFileStringAndLog(
225
+ path.join(confectDirectory, GENERATED_SPEC_PATH),
226
+ specContents,
227
+ );
228
+ }
229
+
230
+ if (node.length > 0) {
231
+ const nodes = assemblyNodesFromLeaves(
232
+ Array.map(node, toNodeRegistryLeaf),
233
+ );
234
+ const nodeSpecContents = yield* templates.assembledSpec({
235
+ nodes,
236
+ runtime: "Node",
237
+ });
238
+ yield* writeFileStringAndLog(
239
+ path.join(confectDirectory, GENERATED_NODE_SPEC_PATH),
240
+ nodeSpecContents,
241
+ );
242
+ }
243
+ });
244
+
245
+ const validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>
246
+ Effect.forEach(leaves, validateImpl);
247
+
248
+ const generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>
249
+ Effect.gen(function* () {
250
+ const path = yield* Path.Path;
251
+ const confectDirectory = yield* ConfectDirectory.get;
252
+
253
+ yield* Effect.forEach(leaves, (leaf) =>
254
+ Effect.gen(function* () {
255
+ const registryRelativePath =
256
+ yield* registeredFunctionsRelativePath(leaf);
257
+ const registryPath = path.join(
258
+ confectDirectory,
259
+ "_generated",
260
+ registryRelativePath,
261
+ );
262
+ const registryDir = path.dirname(registryPath);
263
+ const fs = yield* FileSystem.FileSystem;
264
+ if (!(yield* fs.exists(registryDir))) {
265
+ yield* fs.makeDirectory(registryDir, { recursive: true });
266
+ }
267
+
268
+ const implRelativePath = yield* implPathForSpec(leaf.relativePath);
269
+ const apiFileName = leaf.runtime === "Node" ? "nodeApi.ts" : "api.ts";
270
+ const apiImportPath = yield* toModuleImportPath(
271
+ path.relative(
272
+ path.dirname(registryPath),
273
+ path.join(confectDirectory, "_generated", apiFileName),
274
+ ),
275
+ );
276
+ const implImportPath = yield* toModuleImportPath(
277
+ path.relative(
278
+ path.dirname(registryPath),
279
+ path.join(confectDirectory, implRelativePath),
280
+ ),
281
+ );
282
+
283
+ const contents = yield* templates.registeredFunctionsForGroup({
284
+ apiImportPath,
285
+ groupPathDot: leaf.registryGroupPathDot,
286
+ implImportPath,
287
+ layerExportName: leaf.exportName,
288
+ useNode: leaf.runtime === "Node",
289
+ });
290
+
291
+ yield* writeFileStringAndLog(registryPath, contents);
292
+ }),
293
+ );
294
+ });
295
+
296
+ const removeObsoleteRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>
297
+ Effect.gen(function* () {
298
+ const fs = yield* FileSystem.FileSystem;
299
+ const path = yield* Path.Path;
300
+ const confectDirectory = yield* ConfectDirectory.get;
301
+ const registryRoot = path.join(
302
+ confectDirectory,
303
+ "_generated",
304
+ "registeredFunctions",
305
+ );
306
+
307
+ if (!(yield* fs.exists(registryRoot))) {
308
+ return;
309
+ }
310
+
311
+ const expected = new Set(
312
+ yield* Effect.forEach(leaves, (leaf) =>
313
+ registeredFunctionsRelativePath(leaf),
314
+ ),
315
+ );
316
+
317
+ const existing = yield* fs.readDirectory(registryRoot, { recursive: true });
318
+ yield* Effect.forEach(existing, (relativePath) => {
319
+ if (path.extname(relativePath) !== ".ts") {
320
+ return Effect.void;
321
+ }
322
+ const normalized = path.join("registeredFunctions", relativePath);
323
+ if (!expected.has(normalized)) {
324
+ return Effect.gen(function* () {
325
+ const absolutePath = path.join(registryRoot, relativePath);
326
+ if (yield* fs.exists(absolutePath)) {
327
+ yield* removePathIfExists(absolutePath);
328
+ yield* logFileRemoved(absolutePath);
329
+ }
330
+ });
331
+ }
332
+ return Effect.void;
333
+ });
334
+ });
335
+
336
+ const getGeneratedSpecPath = Effect.gen(function* () {
337
+ const path = yield* Path.Path;
338
+ const confectDirectory = yield* ConfectDirectory.get;
339
+ return path.join(confectDirectory, GENERATED_SPEC_PATH);
340
+ });
341
+
342
+ const getGeneratedNodeSpecPath = Effect.gen(function* () {
343
+ const path = yield* Path.Path;
344
+ const confectDirectory = yield* ConfectDirectory.get;
345
+ return path.join(confectDirectory, GENERATED_NODE_SPEC_PATH);
346
+ });
347
+
348
+ const loadGeneratedSpec = Effect.gen(function* () {
349
+ const specPath = yield* getGeneratedSpecPath;
350
+ const { module: specModule } = yield* Bundler.bundle(specPath);
351
+ const spec = specModule.default;
352
+
353
+ if (!Spec.isConvexSpec(spec)) {
354
+ return yield* Effect.dieMessage(
355
+ "_generated/spec.ts does not export a valid Convex Spec",
356
+ );
357
+ }
358
+
359
+ return spec;
360
+ });
361
+
362
+ const loadGeneratedNodeSpec = Effect.gen(function* () {
363
+ const fs = yield* FileSystem.FileSystem;
364
+ const nodeSpecPath = yield* getGeneratedNodeSpecPath;
365
+
366
+ if (!(yield* fs.exists(nodeSpecPath))) {
367
+ return Option.none<Spec.AnyWithPropsWithRuntime<"Node">>();
368
+ }
369
+
370
+ const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);
371
+ const nodeSpec = nodeSpecModule.default;
372
+
373
+ if (!Spec.isNodeSpec(nodeSpec)) {
374
+ return yield* Effect.dieMessage(
375
+ "_generated/nodeSpec.ts does not export a valid Node Spec",
376
+ );
377
+ }
378
+
379
+ return Option.some(nodeSpec);
380
+ });
381
+
382
+ const emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());
383
+
384
+ export const loadPreviousFunctionPaths = Effect.gen(function* () {
385
+ const fs = yield* FileSystem.FileSystem;
386
+ const specPath = yield* getGeneratedSpecPath;
387
+
388
+ if (!(yield* fs.exists(specPath))) {
389
+ return emptyFunctionPaths;
390
+ }
391
+
392
+ const specEither = yield* loadGeneratedSpec.pipe(Effect.either);
393
+
394
+ return yield* Either.match(specEither, {
395
+ onLeft: () => Effect.succeed(emptyFunctionPaths),
396
+ onRight: (spec) =>
397
+ Effect.gen(function* () {
398
+ const nodeSpecOption = yield* loadGeneratedNodeSpec;
399
+ const mergedSpec = Option.match(nodeSpecOption, {
400
+ onNone: () => spec,
401
+ onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),
402
+ });
403
+ return FunctionPaths.make(mergedSpec);
404
+ }),
405
+ });
406
+ });
407
+
100
408
  const generateApi = Effect.gen(function* () {
101
409
  const path = yield* Path.Path;
102
410
  const confectDirectory = yield* ConfectDirectory.get;
@@ -104,12 +412,12 @@ const generateApi = Effect.gen(function* () {
104
412
  const apiPath = path.join(confectDirectory, "_generated", "api.ts");
105
413
  const apiDir = path.dirname(apiPath);
106
414
 
107
- const schemaImportPath = yield* removePathExtension(
415
+ const schemaImportPath = yield* toModuleImportPath(
108
416
  path.relative(apiDir, path.join(confectDirectory, "schema.ts")),
109
417
  );
110
418
 
111
- const specImportPath = yield* removePathExtension(
112
- path.relative(apiDir, path.join(confectDirectory, "spec.ts")),
419
+ const specImportPath = yield* toModuleImportPath(
420
+ path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),
113
421
  );
114
422
 
115
423
  const apiContents = yield* templates.api({
@@ -125,12 +433,12 @@ export const generateNodeApi = Effect.gen(function* () {
125
433
  const path = yield* Path.Path;
126
434
  const confectDirectory = yield* ConfectDirectory.get;
127
435
 
128
- const nodeSpecPath = yield* getNodeSpecPath;
436
+ const nodeSpecPath = yield* getGeneratedNodeSpecPath;
129
437
  const nodeApiPath = path.join(confectDirectory, "_generated", "nodeApi.ts");
130
438
 
131
439
  if (!(yield* fs.exists(nodeSpecPath))) {
132
440
  if (yield* fs.exists(nodeApiPath)) {
133
- yield* fs.remove(nodeApiPath);
441
+ yield* removePathIfExists(nodeApiPath);
134
442
  yield* logFileRemoved(nodeApiPath);
135
443
  }
136
444
  return;
@@ -138,11 +446,11 @@ export const generateNodeApi = Effect.gen(function* () {
138
446
 
139
447
  const nodeApiDir = path.dirname(nodeApiPath);
140
448
 
141
- const schemaImportPath = yield* removePathExtension(
449
+ const schemaImportPath = yield* toModuleImportPath(
142
450
  path.relative(nodeApiDir, path.join(confectDirectory, "schema.ts")),
143
451
  );
144
452
 
145
- const nodeSpecImportPath = yield* removePathExtension(
453
+ const nodeSpecImportPath = yield* toModuleImportPath(
146
454
  path.relative(nodeApiDir, nodeSpecPath),
147
455
  );
148
456
 
@@ -155,47 +463,52 @@ export const generateNodeApi = Effect.gen(function* () {
155
463
  });
156
464
 
157
465
  const generateFunctionModules = Effect.gen(function* () {
158
- const fs = yield* FileSystem.FileSystem;
159
- const path = yield* Path.Path;
160
- const confectDirectory = yield* ConfectDirectory.get;
161
-
162
- const specPath = path.join(confectDirectory, "spec.ts");
163
-
164
- const specModule = yield* bundleAndImport(specPath);
165
- const spec = specModule.default;
166
-
167
- if (!Spec.isConvexSpec(spec)) {
168
- return yield* Effect.die("spec.ts does not export a valid Convex Spec");
169
- }
170
-
171
- const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
172
- const nodeImplExists = yield* fs.exists(nodeImplPath);
173
- const nodeSpecOption = yield* loadNodeSpec;
466
+ const spec = yield* loadGeneratedSpec;
467
+ const nodeSpecOption = yield* loadGeneratedNodeSpec;
174
468
 
175
469
  const mergedSpec = Option.match(nodeSpecOption, {
176
470
  onNone: () => spec,
177
- onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),
471
+ onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),
178
472
  });
179
473
 
180
474
  return yield* generateFunctions(mergedSpec);
181
475
  });
182
476
 
183
- const generateSchema = Effect.gen(function* () {
477
+ export const validateSchema = Effect.gen(function* () {
478
+ const fs = yield* FileSystem.FileSystem;
184
479
  const path = yield* Path.Path;
185
480
  const confectDirectory = yield* ConfectDirectory.get;
186
- const convexDirectory = yield* ConvexDirectory.get;
187
-
188
481
  const confectSchemaPath = path.join(confectDirectory, "schema.ts");
189
482
 
190
- yield* bundleAndImport(confectSchemaPath).pipe(
191
- Effect.andThen((schemaModule) => {
483
+ if (!(yield* fs.exists(confectSchemaPath))) {
484
+ return yield* new MissingSchemaFileError({ schemaPath: "schema.ts" });
485
+ }
486
+
487
+ yield* Bundler.bundle(confectSchemaPath).pipe(
488
+ Effect.mapError((error) => fromBundlerError("schema.ts", error)),
489
+ Effect.andThen(({ module: schemaModule }) => {
192
490
  const defaultExport = schemaModule.default;
193
491
 
194
492
  return DatabaseSchema.isDatabaseSchema(defaultExport)
195
493
  ? Effect.succeed(defaultExport)
196
- : Effect.die("Invalid schema module");
494
+ : Effect.fail(
495
+ new SchemaInvalidDefaultExportError({
496
+ schemaPath: "schema.ts",
497
+ }),
498
+ );
197
499
  }),
198
500
  );
501
+ });
502
+
503
+ const generateSchema = Effect.gen(function* () {
504
+ const path = yield* Path.Path;
505
+ const confectDirectory = yield* ConfectDirectory.get;
506
+ const convexDirectory = yield* ConvexDirectory.get;
507
+
508
+ const confectSchemaPath = path.join(confectDirectory, "schema.ts");
509
+
510
+ // `validateSchema` runs once at the top of `runCodegen`; no need to
511
+ // bundle the schema again here.
199
512
 
200
513
  const convexSchemaPath = path.join(convexDirectory, "schema.ts");
201
514
 
@@ -230,72 +543,6 @@ const generateServices = Effect.gen(function* () {
230
543
  yield* writeFileStringAndLog(servicesPath, servicesContentsString);
231
544
  });
232
545
 
233
- const generateRegisteredFunctions = Effect.gen(function* () {
234
- const path = yield* Path.Path;
235
- const confectDirectory = yield* ConfectDirectory.get;
236
-
237
- const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
238
-
239
- const registeredFunctionsPath = path.join(
240
- confectGeneratedDirectory,
241
- "registeredFunctions.ts",
242
- );
243
- const implImportPath = yield* removePathExtension(
244
- path.relative(
245
- path.dirname(registeredFunctionsPath),
246
- path.join(confectDirectory, "impl.ts"),
247
- ),
248
- );
249
-
250
- const registeredFunctionsContents = yield* templates.registeredFunctions({
251
- implImportPath,
252
- });
253
-
254
- yield* writeFileStringAndLog(
255
- registeredFunctionsPath,
256
- registeredFunctionsContents,
257
- );
258
- });
259
-
260
- export const generateNodeRegisteredFunctions = Effect.gen(function* () {
261
- const fs = yield* FileSystem.FileSystem;
262
- const path = yield* Path.Path;
263
- const confectDirectory = yield* ConfectDirectory.get;
264
-
265
- const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
266
- const nodeSpecPath = yield* getNodeSpecPath;
267
- const nodeRegisteredFunctionsPath = path.join(
268
- confectDirectory,
269
- "_generated",
270
- "nodeRegisteredFunctions.ts",
271
- );
272
-
273
- const nodeImplExists = yield* fs.exists(nodeImplPath);
274
- const nodeSpecExists = yield* fs.exists(nodeSpecPath);
275
-
276
- if (!nodeImplExists || !nodeSpecExists) {
277
- if (yield* fs.exists(nodeRegisteredFunctionsPath)) {
278
- yield* fs.remove(nodeRegisteredFunctionsPath);
279
- yield* logFileRemoved(nodeRegisteredFunctionsPath);
280
- }
281
- return;
282
- }
283
-
284
- const nodeImplImportPath = yield* removePathExtension(
285
- path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),
286
- );
287
-
288
- const nodeRegisteredFunctionsContents =
289
- yield* templates.nodeRegisteredFunctions({
290
- nodeImplImportPath,
291
- });
292
-
293
- yield* writeFileStringAndLog(
294
- nodeRegisteredFunctionsPath,
295
- nodeRegisteredFunctionsContents,
296
- );
297
- });
298
-
299
546
  const generateRefs = Effect.gen(function* () {
300
547
  const fs = yield* FileSystem.FileSystem;
301
548
  const path = yield* Path.Path;
@@ -305,19 +552,21 @@ const generateRefs = Effect.gen(function* () {
305
552
  const refsPath = path.join(confectGeneratedDirectory, "refs.ts");
306
553
  const refsDir = path.dirname(refsPath);
307
554
 
308
- const specImportPath = yield* removePathExtension(
309
- path.relative(refsDir, path.join(confectDirectory, "spec.ts")),
555
+ const specImportPath = yield* toModuleImportPath(
556
+ path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),
310
557
  );
311
558
 
312
- const nodeSpecPath = yield* getNodeSpecPath;
559
+ const nodeSpecPath = yield* getGeneratedNodeSpecPath;
313
560
  const nodeSpecExists = yield* fs.exists(nodeSpecPath);
314
561
  const nodeSpecImportPath = nodeSpecExists
315
- ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))
316
- : null;
562
+ ? Option.some(
563
+ yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),
564
+ )
565
+ : Option.none<string>();
317
566
 
318
567
  const refsContents = yield* templates.refs({
319
568
  specImportPath,
320
- ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),
569
+ nodeSpecImportPath,
321
570
  });
322
571
 
323
572
  yield* writeFileStringAndLog(refsPath, refsContents);