@confect/cli 7.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.
- package/CHANGELOG.md +60 -0
- package/dist/BuildError.mjs +101 -0
- package/dist/BuildError.mjs.map +1 -0
- package/dist/Bundler.mjs +91 -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 +94 -0
- package/dist/CodegenError.mjs.map +1 -0
- package/dist/FunctionPaths.mjs +1 -1
- package/dist/LeafModule.mjs +167 -0
- package/dist/LeafModule.mjs.map +1 -0
- package/dist/SpecAssemblyNode.mjs +33 -0
- package/dist/SpecAssemblyNode.mjs.map +1 -0
- package/dist/confect/codegen.mjs +221 -72
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +234 -180
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/log.mjs +13 -1
- package/dist/log.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/templates.mjs +65 -72
- package/dist/templates.mjs.map +1 -1
- package/dist/utils.mjs +76 -69
- package/dist/utils.mjs.map +1 -1
- package/package.json +14 -15
- package/src/BuildError.ts +210 -0
- package/src/Bundler.ts +144 -0
- package/src/CodeBlockWriter.ts +65 -0
- package/src/CodegenError.ts +344 -0
- package/src/LeafModule.ts +313 -0
- package/src/SpecAssemblyNode.ts +82 -0
- package/src/confect/codegen.ts +390 -142
- package/src/confect/dev.ts +556 -435
- package/src/log.ts +21 -0
- package/src/templates.ts +141 -109
- package/src/utils.ts +118 -85
package/src/confect/codegen.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { Spec } from "@confect/core";
|
|
2
|
-
import
|
|
2
|
+
import * as DatabaseSchema from "@confect/server/DatabaseSchema";
|
|
3
3
|
import { Command } from "@effect/cli";
|
|
4
4
|
import { FileSystem, Path } from "@effect/platform";
|
|
5
|
-
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";
|
|
6
17
|
import {
|
|
7
18
|
logFileAdded,
|
|
8
19
|
logFileModified,
|
|
@@ -10,66 +21,94 @@ import {
|
|
|
10
21
|
logPending,
|
|
11
22
|
logSuccess,
|
|
12
23
|
} from "../log";
|
|
13
|
-
import {
|
|
14
|
-
|
|
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";
|
|
15
40
|
import * as templates from "../templates";
|
|
41
|
+
import * as Bundler from "../Bundler";
|
|
16
42
|
import {
|
|
17
|
-
bundleAndImport,
|
|
18
43
|
generateAuthConfig,
|
|
19
44
|
generateCrons,
|
|
20
45
|
generateFunctions,
|
|
21
46
|
generateHttp,
|
|
22
47
|
removePathExtension,
|
|
48
|
+
removePathIfExists,
|
|
49
|
+
toModuleImportPath,
|
|
50
|
+
touchConvexSchema,
|
|
23
51
|
writeFileStringAndLog,
|
|
52
|
+
WriteTracker,
|
|
24
53
|
} from "../utils";
|
|
25
54
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const nodeSpec = nodeSpecModule.default;
|
|
42
|
-
|
|
43
|
-
if (!Spec.isNodeSpec(nodeSpec)) {
|
|
44
|
-
return yield* Effect.die("nodeSpec.ts does not export a valid Node Spec");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return Option.some(nodeSpec);
|
|
48
|
-
});
|
|
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
|
+
];
|
|
49
70
|
|
|
50
71
|
export const codegen = Command.make("codegen", {}, () =>
|
|
51
72
|
Effect.gen(function* () {
|
|
52
73
|
yield* logPending("Performing initial sync…");
|
|
53
|
-
yield* codegenHandler
|
|
54
|
-
|
|
74
|
+
yield* codegenHandler.pipe(
|
|
75
|
+
Effect.asVoid,
|
|
76
|
+
Effect.tap(() => logSuccess("Generated files are up-to-date")),
|
|
77
|
+
CodegenError.tapAndLog,
|
|
78
|
+
);
|
|
55
79
|
}),
|
|
56
80
|
).pipe(
|
|
57
81
|
Command.withDescription(
|
|
58
|
-
"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`)",
|
|
59
83
|
),
|
|
60
84
|
);
|
|
61
85
|
|
|
62
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* () {
|
|
63
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);
|
|
64
110
|
yield* Effect.all(
|
|
65
|
-
[
|
|
66
|
-
generateApi,
|
|
67
|
-
generateRefs,
|
|
68
|
-
generateRegisteredFunctions,
|
|
69
|
-
generateNodeApi,
|
|
70
|
-
generateNodeRegisteredFunctions,
|
|
71
|
-
generateServices,
|
|
72
|
-
],
|
|
111
|
+
[generateApi, generateRefs, generateNodeApi, generateServices],
|
|
73
112
|
{ concurrency: "unbounded" },
|
|
74
113
|
);
|
|
75
114
|
const [functionPaths] = yield* Effect.all(
|
|
@@ -82,6 +121,7 @@ export const codegenHandler = Effect.gen(function* () {
|
|
|
82
121
|
],
|
|
83
122
|
{ concurrency: "unbounded" },
|
|
84
123
|
);
|
|
124
|
+
yield* touchConvexSchema;
|
|
85
125
|
return functionPaths;
|
|
86
126
|
});
|
|
87
127
|
|
|
@@ -98,6 +138,273 @@ const generateConfectGeneratedDirectory = Effect.gen(function* () {
|
|
|
98
138
|
}
|
|
99
139
|
});
|
|
100
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
|
+
|
|
101
408
|
const generateApi = Effect.gen(function* () {
|
|
102
409
|
const path = yield* Path.Path;
|
|
103
410
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
@@ -105,12 +412,12 @@ const generateApi = Effect.gen(function* () {
|
|
|
105
412
|
const apiPath = path.join(confectDirectory, "_generated", "api.ts");
|
|
106
413
|
const apiDir = path.dirname(apiPath);
|
|
107
414
|
|
|
108
|
-
const schemaImportPath = yield*
|
|
415
|
+
const schemaImportPath = yield* toModuleImportPath(
|
|
109
416
|
path.relative(apiDir, path.join(confectDirectory, "schema.ts")),
|
|
110
417
|
);
|
|
111
418
|
|
|
112
|
-
const specImportPath = yield*
|
|
113
|
-
path.relative(apiDir, path.join(confectDirectory,
|
|
419
|
+
const specImportPath = yield* toModuleImportPath(
|
|
420
|
+
path.relative(apiDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),
|
|
114
421
|
);
|
|
115
422
|
|
|
116
423
|
const apiContents = yield* templates.api({
|
|
@@ -126,12 +433,12 @@ export const generateNodeApi = Effect.gen(function* () {
|
|
|
126
433
|
const path = yield* Path.Path;
|
|
127
434
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
128
435
|
|
|
129
|
-
const nodeSpecPath = yield*
|
|
436
|
+
const nodeSpecPath = yield* getGeneratedNodeSpecPath;
|
|
130
437
|
const nodeApiPath = path.join(confectDirectory, "_generated", "nodeApi.ts");
|
|
131
438
|
|
|
132
439
|
if (!(yield* fs.exists(nodeSpecPath))) {
|
|
133
440
|
if (yield* fs.exists(nodeApiPath)) {
|
|
134
|
-
yield*
|
|
441
|
+
yield* removePathIfExists(nodeApiPath);
|
|
135
442
|
yield* logFileRemoved(nodeApiPath);
|
|
136
443
|
}
|
|
137
444
|
return;
|
|
@@ -139,11 +446,11 @@ export const generateNodeApi = Effect.gen(function* () {
|
|
|
139
446
|
|
|
140
447
|
const nodeApiDir = path.dirname(nodeApiPath);
|
|
141
448
|
|
|
142
|
-
const schemaImportPath = yield*
|
|
449
|
+
const schemaImportPath = yield* toModuleImportPath(
|
|
143
450
|
path.relative(nodeApiDir, path.join(confectDirectory, "schema.ts")),
|
|
144
451
|
);
|
|
145
452
|
|
|
146
|
-
const nodeSpecImportPath = yield*
|
|
453
|
+
const nodeSpecImportPath = yield* toModuleImportPath(
|
|
147
454
|
path.relative(nodeApiDir, nodeSpecPath),
|
|
148
455
|
);
|
|
149
456
|
|
|
@@ -156,47 +463,52 @@ export const generateNodeApi = Effect.gen(function* () {
|
|
|
156
463
|
});
|
|
157
464
|
|
|
158
465
|
const generateFunctionModules = Effect.gen(function* () {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const confectDirectory = yield* ConfectDirectory.get;
|
|
162
|
-
|
|
163
|
-
const specPath = path.join(confectDirectory, "spec.ts");
|
|
164
|
-
|
|
165
|
-
const specModule = yield* bundleAndImport(specPath);
|
|
166
|
-
const spec = specModule.default;
|
|
167
|
-
|
|
168
|
-
if (!Spec.isConvexSpec(spec)) {
|
|
169
|
-
return yield* Effect.die("spec.ts does not export a valid Convex Spec");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
173
|
-
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
174
|
-
const nodeSpecOption = yield* loadNodeSpec;
|
|
466
|
+
const spec = yield* loadGeneratedSpec;
|
|
467
|
+
const nodeSpecOption = yield* loadGeneratedNodeSpec;
|
|
175
468
|
|
|
176
469
|
const mergedSpec = Option.match(nodeSpecOption, {
|
|
177
470
|
onNone: () => spec,
|
|
178
|
-
onSome: (nodeSpec) =>
|
|
471
|
+
onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),
|
|
179
472
|
});
|
|
180
473
|
|
|
181
474
|
return yield* generateFunctions(mergedSpec);
|
|
182
475
|
});
|
|
183
476
|
|
|
184
|
-
const
|
|
477
|
+
export const validateSchema = Effect.gen(function* () {
|
|
478
|
+
const fs = yield* FileSystem.FileSystem;
|
|
185
479
|
const path = yield* Path.Path;
|
|
186
480
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
187
|
-
const convexDirectory = yield* ConvexDirectory.get;
|
|
188
|
-
|
|
189
481
|
const confectSchemaPath = path.join(confectDirectory, "schema.ts");
|
|
190
482
|
|
|
191
|
-
yield*
|
|
192
|
-
|
|
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 }) => {
|
|
193
490
|
const defaultExport = schemaModule.default;
|
|
194
491
|
|
|
195
|
-
return DatabaseSchema.
|
|
492
|
+
return DatabaseSchema.isDatabaseSchema(defaultExport)
|
|
196
493
|
? Effect.succeed(defaultExport)
|
|
197
|
-
: Effect.
|
|
494
|
+
: Effect.fail(
|
|
495
|
+
new SchemaInvalidDefaultExportError({
|
|
496
|
+
schemaPath: "schema.ts",
|
|
497
|
+
}),
|
|
498
|
+
);
|
|
198
499
|
}),
|
|
199
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.
|
|
200
512
|
|
|
201
513
|
const convexSchemaPath = path.join(convexDirectory, "schema.ts");
|
|
202
514
|
|
|
@@ -231,72 +543,6 @@ const generateServices = Effect.gen(function* () {
|
|
|
231
543
|
yield* writeFileStringAndLog(servicesPath, servicesContentsString);
|
|
232
544
|
});
|
|
233
545
|
|
|
234
|
-
const generateRegisteredFunctions = Effect.gen(function* () {
|
|
235
|
-
const path = yield* Path.Path;
|
|
236
|
-
const confectDirectory = yield* ConfectDirectory.get;
|
|
237
|
-
|
|
238
|
-
const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
|
|
239
|
-
|
|
240
|
-
const registeredFunctionsPath = path.join(
|
|
241
|
-
confectGeneratedDirectory,
|
|
242
|
-
"registeredFunctions.ts",
|
|
243
|
-
);
|
|
244
|
-
const implImportPath = yield* removePathExtension(
|
|
245
|
-
path.relative(
|
|
246
|
-
path.dirname(registeredFunctionsPath),
|
|
247
|
-
path.join(confectDirectory, "impl.ts"),
|
|
248
|
-
),
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
const registeredFunctionsContents = yield* templates.registeredFunctions({
|
|
252
|
-
implImportPath,
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
yield* writeFileStringAndLog(
|
|
256
|
-
registeredFunctionsPath,
|
|
257
|
-
registeredFunctionsContents,
|
|
258
|
-
);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
export const generateNodeRegisteredFunctions = Effect.gen(function* () {
|
|
262
|
-
const fs = yield* FileSystem.FileSystem;
|
|
263
|
-
const path = yield* Path.Path;
|
|
264
|
-
const confectDirectory = yield* ConfectDirectory.get;
|
|
265
|
-
|
|
266
|
-
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
267
|
-
const nodeSpecPath = yield* getNodeSpecPath;
|
|
268
|
-
const nodeRegisteredFunctionsPath = path.join(
|
|
269
|
-
confectDirectory,
|
|
270
|
-
"_generated",
|
|
271
|
-
"nodeRegisteredFunctions.ts",
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
275
|
-
const nodeSpecExists = yield* fs.exists(nodeSpecPath);
|
|
276
|
-
|
|
277
|
-
if (!nodeImplExists || !nodeSpecExists) {
|
|
278
|
-
if (yield* fs.exists(nodeRegisteredFunctionsPath)) {
|
|
279
|
-
yield* fs.remove(nodeRegisteredFunctionsPath);
|
|
280
|
-
yield* logFileRemoved(nodeRegisteredFunctionsPath);
|
|
281
|
-
}
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const nodeImplImportPath = yield* removePathExtension(
|
|
286
|
-
path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
const nodeRegisteredFunctionsContents =
|
|
290
|
-
yield* templates.nodeRegisteredFunctions({
|
|
291
|
-
nodeImplImportPath,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
yield* writeFileStringAndLog(
|
|
295
|
-
nodeRegisteredFunctionsPath,
|
|
296
|
-
nodeRegisteredFunctionsContents,
|
|
297
|
-
);
|
|
298
|
-
});
|
|
299
|
-
|
|
300
546
|
const generateRefs = Effect.gen(function* () {
|
|
301
547
|
const fs = yield* FileSystem.FileSystem;
|
|
302
548
|
const path = yield* Path.Path;
|
|
@@ -306,19 +552,21 @@ const generateRefs = Effect.gen(function* () {
|
|
|
306
552
|
const refsPath = path.join(confectGeneratedDirectory, "refs.ts");
|
|
307
553
|
const refsDir = path.dirname(refsPath);
|
|
308
554
|
|
|
309
|
-
const specImportPath = yield*
|
|
310
|
-
path.relative(refsDir, path.join(confectDirectory,
|
|
555
|
+
const specImportPath = yield* toModuleImportPath(
|
|
556
|
+
path.relative(refsDir, path.join(confectDirectory, GENERATED_SPEC_PATH)),
|
|
311
557
|
);
|
|
312
558
|
|
|
313
|
-
const nodeSpecPath = yield*
|
|
559
|
+
const nodeSpecPath = yield* getGeneratedNodeSpecPath;
|
|
314
560
|
const nodeSpecExists = yield* fs.exists(nodeSpecPath);
|
|
315
561
|
const nodeSpecImportPath = nodeSpecExists
|
|
316
|
-
?
|
|
317
|
-
|
|
562
|
+
? Option.some(
|
|
563
|
+
yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),
|
|
564
|
+
)
|
|
565
|
+
: Option.none<string>();
|
|
318
566
|
|
|
319
567
|
const refsContents = yield* templates.refs({
|
|
320
568
|
specImportPath,
|
|
321
|
-
|
|
569
|
+
nodeSpecImportPath,
|
|
322
570
|
});
|
|
323
571
|
|
|
324
572
|
yield* writeFileStringAndLog(refsPath, refsContents);
|