@confect/cli 9.0.0-next.7 → 9.0.0-next.9
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 +9 -2
- package/dist/BuildError.mjs.map +1 -1
- package/dist/Bundler.mjs +5 -2
- package/dist/Bundler.mjs.map +1 -1
- package/dist/CodeBlockWriter.mjs +1 -1
- package/dist/CodeBlockWriter.mjs.map +1 -1
- package/dist/CodegenError.mjs +10 -15
- package/dist/CodegenError.mjs.map +1 -1
- package/dist/ConfectDirectory.mjs +5 -2
- package/dist/ConfectDirectory.mjs.map +1 -1
- package/dist/ConvexDirectory.mjs +6 -2
- package/dist/ConvexDirectory.mjs.map +1 -1
- package/dist/FunctionPath.mjs +1 -1
- package/dist/FunctionPath.mjs.map +1 -1
- package/dist/FunctionPaths.mjs +5 -1
- package/dist/FunctionPaths.mjs.map +1 -1
- package/dist/GroupPath.mjs +9 -2
- package/dist/GroupPath.mjs.map +1 -1
- package/dist/GroupPaths.mjs +1 -1
- package/dist/GroupPaths.mjs.map +1 -1
- package/dist/LeafModule.mjs +17 -24
- package/dist/LeafModule.mjs.map +1 -1
- package/dist/ProjectRoot.mjs +8 -3
- package/dist/ProjectRoot.mjs.map +1 -1
- package/dist/SpecAssemblyNode.mjs +6 -9
- package/dist/SpecAssemblyNode.mjs.map +1 -1
- package/dist/TableModule.mjs +6 -2
- package/dist/TableModule.mjs.map +1 -1
- package/dist/cliApp.mjs +1 -1
- package/dist/cliApp.mjs.map +1 -1
- package/dist/confect/codegen.mjs +36 -72
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +24 -7
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/confect.mjs +2 -2
- package/dist/confect.mjs.map +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/log.mjs +7 -3
- package/dist/log.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/templates.mjs +8 -15
- package/dist/templates.mjs.map +1 -1
- package/dist/utils.mjs +42 -22
- package/dist/utils.mjs.map +1 -1
- package/package.json +3 -3
- package/src/BuildError.ts +9 -2
- package/src/Bundler.ts +5 -2
- package/src/CodeBlockWriter.ts +1 -1
- package/src/CodegenError.ts +7 -38
- package/src/ConfectDirectory.ts +5 -2
- package/src/ConvexDirectory.ts +6 -2
- package/src/FunctionPath.ts +1 -1
- package/src/FunctionPaths.ts +5 -1
- package/src/GroupPath.ts +9 -11
- package/src/GroupPaths.ts +1 -1
- package/src/LeafModule.ts +24 -36
- package/src/ProjectRoot.ts +8 -3
- package/src/SpecAssemblyNode.ts +5 -14
- package/src/TableModule.ts +6 -2
- package/src/cliApp.ts +1 -1
- package/src/confect/codegen.ts +54 -108
- package/src/confect/dev.ts +24 -29
- package/src/confect.ts +2 -2
- package/src/index.ts +3 -2
- package/src/log.ts +7 -3
- package/src/templates.ts +11 -28
- package/src/utils.ts +47 -41
package/src/LeafModule.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { GroupSpec, Registry } from "@confect/core";
|
|
2
2
|
import * as GroupImpl from "@confect/server/GroupImpl";
|
|
3
|
-
import
|
|
3
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
4
|
+
import * as Path from "@effect/platform/Path";
|
|
4
5
|
import type { Context } from "effect";
|
|
5
|
-
import
|
|
6
|
+
import * as Array from "effect/Array";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import * as Option from "effect/Option";
|
|
10
|
+
import * as Ref from "effect/Ref";
|
|
11
|
+
import * as String from "effect/String";
|
|
6
12
|
import { fromBundlerError } from "./BuildError";
|
|
7
13
|
import * as Bundler from "./Bundler";
|
|
8
14
|
import {
|
|
@@ -11,7 +17,6 @@ import {
|
|
|
11
17
|
ImplMissingSpecImportError,
|
|
12
18
|
ImplNotFinalizedError,
|
|
13
19
|
SpecMissingDefaultGroupSpecError,
|
|
14
|
-
SpecRuntimeMismatchError,
|
|
15
20
|
} from "./CodegenError";
|
|
16
21
|
import { ConfectDirectory } from "./ConfectDirectory";
|
|
17
22
|
import { removePathExtension } from "./utils";
|
|
@@ -20,9 +25,15 @@ export interface LeafModule {
|
|
|
20
25
|
readonly relativePath: string;
|
|
21
26
|
readonly pathSegments: readonly [string, ...string[]];
|
|
22
27
|
readonly groupPathDot: string;
|
|
23
|
-
readonly registryGroupPathDot: string;
|
|
24
28
|
readonly exportName: string;
|
|
25
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The runtime declared by the group's spec — `"Node"` for
|
|
31
|
+
* `GroupSpec.makeNode()`, `"Convex"` for `GroupSpec.make()`. `None` while the
|
|
32
|
+
* runtime is unknown: discovery (`toLeafModule`) works from the file path alone,
|
|
33
|
+
* which does not determine the runtime, so this is filled in once the spec has
|
|
34
|
+
* been bundled and validated (see `validateSpec`).
|
|
35
|
+
*/
|
|
36
|
+
readonly runtime: Option.Option<"Convex" | "Node">;
|
|
26
37
|
readonly specImportPath: string;
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -98,24 +109,10 @@ export const specPathForImpl = (implRelativePath: string) =>
|
|
|
98
109
|
export const implPathForSpec = (specRelativePath: string) =>
|
|
99
110
|
swapModuleSuffix(specRelativePath, SPEC_SUFFIX, IMPL_SUFFIX);
|
|
100
111
|
|
|
101
|
-
export const isNodeLeafModule = (relativePath: string) =>
|
|
102
|
-
relativePath.startsWith("node/") || relativePath.startsWith("node\\");
|
|
103
|
-
|
|
104
|
-
export const toNodeRegistryLeaf = (leaf: LeafModule): LeafModule => ({
|
|
105
|
-
...leaf,
|
|
106
|
-
pathSegments: [leaf.exportName],
|
|
107
|
-
groupPathDot: leaf.exportName,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
112
|
export const registeredFunctionsRelativePath = (leaf: LeafModule) =>
|
|
111
113
|
Effect.gen(function* () {
|
|
112
114
|
const path = yield* Path.Path;
|
|
113
|
-
return (
|
|
114
|
-
path.join(
|
|
115
|
-
"registeredFunctions",
|
|
116
|
-
...leaf.pathSegments.slice(leaf.runtime === "Node" ? 1 : 0),
|
|
117
|
-
) + ".ts"
|
|
118
|
-
);
|
|
115
|
+
return path.join("registeredFunctions", ...leaf.pathSegments) + ".ts";
|
|
119
116
|
});
|
|
120
117
|
|
|
121
118
|
export const discoverLeafSpecFiles = Effect.gen(function* () {
|
|
@@ -171,15 +168,14 @@ export const toLeafModule = (specRelativePath: string) =>
|
|
|
171
168
|
const { pathSegments, groupPathDot } =
|
|
172
169
|
yield* groupPathFromRelativeModulePath(specRelativePath);
|
|
173
170
|
const specImportPath = yield* specImportPathFromGenerated(specRelativePath);
|
|
174
|
-
const runtime = isNodeLeafModule(specRelativePath) ? "Node" : "Convex";
|
|
175
171
|
|
|
176
172
|
return {
|
|
177
173
|
relativePath: specRelativePath,
|
|
178
174
|
pathSegments,
|
|
179
175
|
groupPathDot,
|
|
180
176
|
exportName,
|
|
181
|
-
runtime
|
|
182
|
-
|
|
177
|
+
// Unknown until the spec is bundled; see `LeafModule.runtime`.
|
|
178
|
+
runtime: Option.none(),
|
|
183
179
|
specImportPath,
|
|
184
180
|
} satisfies LeafModule;
|
|
185
181
|
});
|
|
@@ -192,11 +188,11 @@ const absoluteModulePath = (relativePath: string) =>
|
|
|
192
188
|
});
|
|
193
189
|
|
|
194
190
|
/**
|
|
195
|
-
* Validate that the leaf's spec file default-exports a `GroupSpec
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
191
|
+
* Validate that the leaf's spec file default-exports a `GroupSpec`. Returns the
|
|
192
|
+
* validated `GroupSpec` so callers can read its runtime and avoid re-bundling for
|
|
193
|
+
* later inspection (e.g. stamping `leaf.runtime` and parent/child name-collision
|
|
194
|
+
* checks at codegen time). The group's runtime (`Convex` vs `Node`) is whatever
|
|
195
|
+
* the spec declares — it is not constrained by the file's location.
|
|
200
196
|
*/
|
|
201
197
|
export const validateSpec = (leaf: LeafModule) =>
|
|
202
198
|
Effect.gen(function* () {
|
|
@@ -213,14 +209,6 @@ export const validateSpec = (leaf: LeafModule) =>
|
|
|
213
209
|
});
|
|
214
210
|
}
|
|
215
211
|
|
|
216
|
-
if (groupSpec.runtime !== leaf.runtime) {
|
|
217
|
-
return yield* new SpecRuntimeMismatchError({
|
|
218
|
-
specPath: leaf.relativePath,
|
|
219
|
-
expectedRuntime: leaf.runtime,
|
|
220
|
-
actualRuntime: groupSpec.runtime,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
212
|
return groupSpec;
|
|
225
213
|
});
|
|
226
214
|
|
package/src/ProjectRoot.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
2
|
+
import * as Path from "@effect/platform/Path";
|
|
3
|
+
import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem";
|
|
4
|
+
import * as Array from "effect/Array";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Ref from "effect/Ref";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
4
9
|
|
|
5
10
|
export class ProjectRoot extends Effect.Service<ProjectRoot>()(
|
|
6
11
|
"@confect/cli/ProjectRoot",
|
package/src/SpecAssemblyNode.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { LeafModule } from "./LeafModule";
|
|
2
|
-
import {
|
|
2
|
+
import { pipe } from "effect/Function";
|
|
3
|
+
import * as Array from "effect/Array";
|
|
4
|
+
import * as Option from "effect/Option";
|
|
5
|
+
import * as Order from "effect/Order";
|
|
6
|
+
import * as Record from "effect/Record";
|
|
3
7
|
|
|
4
8
|
export interface SpecImportBinding {
|
|
5
9
|
readonly importPath: string;
|
|
@@ -48,19 +52,6 @@ export const assemblyNodesFromLeaves = (
|
|
|
48
52
|
leaves: ReadonlyArray<LeafModule>,
|
|
49
53
|
): ReadonlyArray<SpecAssemblyNode> => assemblyNodesAtDepth(leaves, 0);
|
|
50
54
|
|
|
51
|
-
export const partitionByRuntime = (
|
|
52
|
-
leaves: ReadonlyArray<LeafModule>,
|
|
53
|
-
): {
|
|
54
|
-
readonly convex: ReadonlyArray<LeafModule>;
|
|
55
|
-
readonly node: ReadonlyArray<LeafModule>;
|
|
56
|
-
} => {
|
|
57
|
-
const [node, convex] = Array.partition(
|
|
58
|
-
leaves,
|
|
59
|
-
(leaf) => leaf.runtime === "Convex",
|
|
60
|
-
);
|
|
61
|
-
return { convex, node };
|
|
62
|
-
};
|
|
63
|
-
|
|
64
55
|
const importBindingsForNode = (
|
|
65
56
|
node: SpecAssemblyNode,
|
|
66
57
|
): ReadonlyArray<SpecImportBinding> =>
|
package/src/TableModule.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Identifier } from "@confect/core";
|
|
2
2
|
import * as Table from "@confect/server/Table";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
4
|
+
import * as Path from "@effect/platform/Path";
|
|
5
|
+
import { pipe } from "effect/Function";
|
|
6
|
+
import * as Array from "effect/Array";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Order from "effect/Order";
|
|
5
9
|
import { fromBundlerError } from "./BuildError";
|
|
6
10
|
import * as Bundler from "./Bundler";
|
|
7
11
|
import {
|
package/src/cliApp.ts
CHANGED
package/src/confect/codegen.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { Spec, type GroupSpec } from "@confect/core";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import * as Command from "@effect/cli/Command";
|
|
3
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
4
|
+
import * as Path from "@effect/platform/Path";
|
|
5
|
+
import * as Array from "effect/Array";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Either from "effect/Either";
|
|
8
|
+
import * as HashSet from "effect/HashSet";
|
|
9
|
+
import * as Match from "effect/Match";
|
|
10
|
+
import * as Option from "effect/Option";
|
|
11
|
+
import * as Ref from "effect/Ref";
|
|
5
12
|
import * as Bundler from "../Bundler";
|
|
6
13
|
import * as CodegenError from "../CodegenError";
|
|
7
14
|
import {
|
|
@@ -20,7 +27,6 @@ import {
|
|
|
20
27
|
registeredFunctionsRelativePath,
|
|
21
28
|
specPathForImpl,
|
|
22
29
|
toLeafModule,
|
|
23
|
-
toNodeRegistryLeaf,
|
|
24
30
|
validateImpl,
|
|
25
31
|
validateSpec,
|
|
26
32
|
type LeafModule,
|
|
@@ -35,7 +41,6 @@ import {
|
|
|
35
41
|
} from "../log";
|
|
36
42
|
import {
|
|
37
43
|
assemblyNodesFromLeaves,
|
|
38
|
-
partitionByRuntime,
|
|
39
44
|
type SpecAssemblyNode,
|
|
40
45
|
} from "../SpecAssemblyNode";
|
|
41
46
|
import * as TableModule from "../TableModule";
|
|
@@ -57,9 +62,6 @@ const GENERATED_DIRNAME = "_generated";
|
|
|
57
62
|
const GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>
|
|
58
63
|
path.join(GENERATED_DIRNAME, "spec.ts"),
|
|
59
64
|
);
|
|
60
|
-
const GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>
|
|
61
|
-
path.join(GENERATED_DIRNAME, "nodeSpec.ts"),
|
|
62
|
-
);
|
|
63
65
|
const GENERATED_SCHEMA_PATH = Effect.andThen(Path.Path, (path) =>
|
|
64
66
|
path.join(GENERATED_DIRNAME, "schema.ts"),
|
|
65
67
|
);
|
|
@@ -85,6 +87,9 @@ const LEGACY_PATHS = Effect.gen(function* () {
|
|
|
85
87
|
path.join(GENERATED_DIRNAME, "nodeRegisteredFunctions.ts"),
|
|
86
88
|
path.join(GENERATED_DIRNAME, "impl.ts"),
|
|
87
89
|
path.join(GENERATED_DIRNAME, "nodeImpl.ts"),
|
|
90
|
+
// `_generated/nodeSpec.ts` is not part of the generated output (all groups
|
|
91
|
+
// live in `_generated/spec.ts`); delete any copy left by an older version.
|
|
92
|
+
path.join(GENERATED_DIRNAME, "nodeSpec.ts"),
|
|
88
93
|
];
|
|
89
94
|
});
|
|
90
95
|
|
|
@@ -191,8 +196,13 @@ const loadAndValidateLeafModules = Effect.gen(function* () {
|
|
|
191
196
|
|
|
192
197
|
const results = yield* Effect.forEach(specFiles, (specRelativePath) =>
|
|
193
198
|
Effect.gen(function* () {
|
|
194
|
-
const
|
|
195
|
-
const groupSpec = yield* validateSpec(
|
|
199
|
+
const discovered = yield* toLeafModule(specRelativePath);
|
|
200
|
+
const groupSpec = yield* validateSpec(discovered);
|
|
201
|
+
// Fill in the runtime now that the spec is bundled; discovery left it `None`.
|
|
202
|
+
const leaf = {
|
|
203
|
+
...discovered,
|
|
204
|
+
runtime: Option.some(groupSpec.runtime),
|
|
205
|
+
};
|
|
196
206
|
|
|
197
207
|
const implRelativePath = yield* implPathForSpec(specRelativePath);
|
|
198
208
|
const implAbsolutePath = path.join(confectDirectory, implRelativePath);
|
|
@@ -230,15 +240,11 @@ export const validateNoParentChildNameCollisions = (
|
|
|
230
240
|
groupSpecsByRelativePath: ReadonlyMap<string, GroupSpec.AnyWithProps>,
|
|
231
241
|
) =>
|
|
232
242
|
Effect.gen(function* () {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
)
|
|
238
|
-
yield* Effect.forEach(convexNodes, (n) =>
|
|
239
|
-
checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),
|
|
240
|
-
);
|
|
241
|
-
yield* Effect.forEach(nodeNodes, (n) =>
|
|
243
|
+
// Convex and Node groups share one namespace, so they assemble into a
|
|
244
|
+
// single tree. A Node group nested under a Convex parent (or vice versa) is
|
|
245
|
+
// caught here by the parent/child collision check.
|
|
246
|
+
const nodes = assemblyNodesFromLeaves(leaves);
|
|
247
|
+
yield* Effect.forEach(nodes, (n) =>
|
|
242
248
|
checkAssemblyNodeForCollisions(n, groupSpecsByRelativePath),
|
|
243
249
|
);
|
|
244
250
|
});
|
|
@@ -377,34 +383,17 @@ const generateAssembledSpecs = (leaves: ReadonlyArray<LeafModule>) =>
|
|
|
377
383
|
const path = yield* Path.Path;
|
|
378
384
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
379
385
|
const generatedSpecPath = yield* GENERATED_SPEC_PATH;
|
|
380
|
-
const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;
|
|
381
|
-
const { convex, node } = partitionByRuntime(leaves);
|
|
382
|
-
|
|
383
|
-
if (convex.length > 0) {
|
|
384
|
-
const nodes = assemblyNodesFromLeaves(convex);
|
|
385
|
-
const specContents = yield* templates.assembledSpec({
|
|
386
|
-
nodes,
|
|
387
|
-
runtime: "Convex",
|
|
388
|
-
});
|
|
389
|
-
yield* writeFileStringAndLog(
|
|
390
|
-
path.join(confectDirectory, generatedSpecPath),
|
|
391
|
-
specContents,
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
386
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
nodeSpecContents,
|
|
406
|
-
);
|
|
407
|
-
}
|
|
387
|
+
// A single assembled spec holds every group regardless of runtime — a Node
|
|
388
|
+
// group's `makeNode()` lives in its imported leaf spec, so the assembled
|
|
389
|
+
// file is runtime-agnostic. Always emit it (even empty) so downstream
|
|
390
|
+
// readers (`loadGeneratedSpec`, `generateRefs`) always find a spec module.
|
|
391
|
+
const nodes = assemblyNodesFromLeaves(leaves);
|
|
392
|
+
const specContents = yield* templates.assembledSpec({ nodes });
|
|
393
|
+
yield* writeFileStringAndLog(
|
|
394
|
+
path.join(confectDirectory, generatedSpecPath),
|
|
395
|
+
specContents,
|
|
396
|
+
);
|
|
408
397
|
});
|
|
409
398
|
|
|
410
399
|
const validateImplModules = (leaves: ReadonlyArray<LeafModule>) =>
|
|
@@ -452,12 +441,23 @@ const generateGroupRegisteredFunctions = (leaves: ReadonlyArray<LeafModule>) =>
|
|
|
452
441
|
),
|
|
453
442
|
);
|
|
454
443
|
|
|
444
|
+
// Every leaf reaching this point came through
|
|
445
|
+
// `loadAndValidateLeafModules`, which stamps the runtime from the
|
|
446
|
+
// validated spec — so `None` here means that invariant was broken.
|
|
447
|
+
const runtime = yield* Option.match(leaf.runtime, {
|
|
448
|
+
onNone: () =>
|
|
449
|
+
Effect.dieMessage(
|
|
450
|
+
`Runtime for '${leaf.relativePath}' was not resolved before registry generation.`,
|
|
451
|
+
),
|
|
452
|
+
onSome: Effect.succeed,
|
|
453
|
+
});
|
|
454
|
+
|
|
455
455
|
const contents = yield* templates.registeredFunctionsForGroup({
|
|
456
456
|
schemaImportPath,
|
|
457
457
|
specImportPath,
|
|
458
458
|
implImportPath,
|
|
459
459
|
layerExportName: leaf.exportName,
|
|
460
|
-
useNode:
|
|
460
|
+
useNode: runtime === "Node",
|
|
461
461
|
});
|
|
462
462
|
|
|
463
463
|
yield* writeFileStringAndLog(registryPath, contents);
|
|
@@ -512,47 +512,20 @@ const getGeneratedSpecPath = Effect.gen(function* () {
|
|
|
512
512
|
return path.join(confectDirectory, generatedSpecPath);
|
|
513
513
|
});
|
|
514
514
|
|
|
515
|
-
const getGeneratedNodeSpecPath = Effect.gen(function* () {
|
|
516
|
-
const path = yield* Path.Path;
|
|
517
|
-
const confectDirectory = yield* ConfectDirectory.get;
|
|
518
|
-
const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;
|
|
519
|
-
return path.join(confectDirectory, generatedNodeSpecPath);
|
|
520
|
-
});
|
|
521
|
-
|
|
522
515
|
const loadGeneratedSpec = Effect.gen(function* () {
|
|
523
516
|
const specPath = yield* getGeneratedSpecPath;
|
|
524
517
|
const { module: specModule } = yield* Bundler.bundle(specPath);
|
|
525
518
|
const spec = specModule.default;
|
|
526
519
|
|
|
527
|
-
if (!Spec.
|
|
520
|
+
if (!Spec.isSpec(spec)) {
|
|
528
521
|
return yield* Effect.dieMessage(
|
|
529
|
-
"_generated/spec.ts does not export a valid
|
|
522
|
+
"_generated/spec.ts does not export a valid Spec",
|
|
530
523
|
);
|
|
531
524
|
}
|
|
532
525
|
|
|
533
526
|
return spec;
|
|
534
527
|
});
|
|
535
528
|
|
|
536
|
-
const loadGeneratedNodeSpec = Effect.gen(function* () {
|
|
537
|
-
const fs = yield* FileSystem.FileSystem;
|
|
538
|
-
const nodeSpecPath = yield* getGeneratedNodeSpecPath;
|
|
539
|
-
|
|
540
|
-
if (!(yield* fs.exists(nodeSpecPath))) {
|
|
541
|
-
return Option.none<Spec.AnyWithPropsWithRuntime<"Node">>();
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const { module: nodeSpecModule } = yield* Bundler.bundle(nodeSpecPath);
|
|
545
|
-
const nodeSpec = nodeSpecModule.default;
|
|
546
|
-
|
|
547
|
-
if (!Spec.isNodeSpec(nodeSpec)) {
|
|
548
|
-
return yield* Effect.dieMessage(
|
|
549
|
-
"_generated/nodeSpec.ts does not export a valid Node Spec",
|
|
550
|
-
);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return Option.some(nodeSpec);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
529
|
const emptyFunctionPaths = FunctionPaths.FunctionPaths.make(HashSet.empty());
|
|
557
530
|
|
|
558
531
|
export const loadPreviousFunctionPaths = Effect.gen(function* () {
|
|
@@ -565,17 +538,9 @@ export const loadPreviousFunctionPaths = Effect.gen(function* () {
|
|
|
565
538
|
|
|
566
539
|
const specEither = yield* loadGeneratedSpec.pipe(Effect.either);
|
|
567
540
|
|
|
568
|
-
return
|
|
569
|
-
onLeft: () =>
|
|
570
|
-
onRight: (spec) =>
|
|
571
|
-
Effect.gen(function* () {
|
|
572
|
-
const nodeSpecOption = yield* loadGeneratedNodeSpec;
|
|
573
|
-
const mergedSpec = Option.match(nodeSpecOption, {
|
|
574
|
-
onNone: () => spec,
|
|
575
|
-
onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),
|
|
576
|
-
});
|
|
577
|
-
return FunctionPaths.make(mergedSpec);
|
|
578
|
-
}),
|
|
541
|
+
return Either.match(specEither, {
|
|
542
|
+
onLeft: () => emptyFunctionPaths,
|
|
543
|
+
onRight: (spec) => FunctionPaths.make(spec),
|
|
579
544
|
});
|
|
580
545
|
});
|
|
581
546
|
|
|
@@ -606,14 +571,7 @@ const removeGeneratedNodeApi = removeObsoleteGeneratedFile("nodeApi.ts");
|
|
|
606
571
|
|
|
607
572
|
const generateFunctionModules = Effect.gen(function* () {
|
|
608
573
|
const spec = yield* loadGeneratedSpec;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const mergedSpec = Option.match(nodeSpecOption, {
|
|
612
|
-
onNone: () => spec,
|
|
613
|
-
onSome: (nodeSpec) => Spec.merge(spec, nodeSpec),
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
return yield* generateFunctions(mergedSpec);
|
|
574
|
+
return yield* generateFunctions(spec);
|
|
617
575
|
});
|
|
618
576
|
|
|
619
577
|
/**
|
|
@@ -855,7 +813,6 @@ const generateServices = Effect.gen(function* () {
|
|
|
855
813
|
});
|
|
856
814
|
|
|
857
815
|
const generateRefs = Effect.gen(function* () {
|
|
858
|
-
const fs = yield* FileSystem.FileSystem;
|
|
859
816
|
const path = yield* Path.Path;
|
|
860
817
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
861
818
|
|
|
@@ -868,18 +825,7 @@ const generateRefs = Effect.gen(function* () {
|
|
|
868
825
|
path.relative(refsDir, path.join(confectDirectory, generatedSpecPath)),
|
|
869
826
|
);
|
|
870
827
|
|
|
871
|
-
const
|
|
872
|
-
const nodeSpecExists = yield* fs.exists(nodeSpecPath);
|
|
873
|
-
const nodeSpecImportPath = nodeSpecExists
|
|
874
|
-
? Option.some(
|
|
875
|
-
yield* toModuleImportPath(path.relative(refsDir, nodeSpecPath)),
|
|
876
|
-
)
|
|
877
|
-
: Option.none<string>();
|
|
878
|
-
|
|
879
|
-
const refsContents = yield* templates.refs({
|
|
880
|
-
specImportPath,
|
|
881
|
-
nodeSpecImportPath,
|
|
882
|
-
});
|
|
828
|
+
const refsContents = yield* templates.refs({ specImportPath });
|
|
883
829
|
|
|
884
830
|
yield* writeFileStringAndLog(refsPath, refsContents);
|
|
885
831
|
});
|
package/src/confect/dev.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
import * as Command from "@effect/cli/Command";
|
|
2
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
3
|
+
import * as Path from "@effect/platform/Path";
|
|
4
|
+
import * as Ansi from "@effect/printer-ansi/Ansi";
|
|
5
|
+
import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
|
|
6
|
+
import { pipe } from "effect/Function";
|
|
7
|
+
import * as Array from "effect/Array";
|
|
8
|
+
import * as Chunk from "effect/Chunk";
|
|
9
|
+
import * as Clock from "effect/Clock";
|
|
10
|
+
import * as Console from "effect/Console";
|
|
11
|
+
import * as Duration from "effect/Duration";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Equal from "effect/Equal";
|
|
14
|
+
import * as ExecutionStrategy from "effect/ExecutionStrategy";
|
|
15
|
+
import * as Exit from "effect/Exit";
|
|
16
|
+
import * as HashSet from "effect/HashSet";
|
|
17
|
+
import * as Match from "effect/Match";
|
|
18
|
+
import * as Option from "effect/Option";
|
|
19
|
+
import * as Order from "effect/Order";
|
|
20
|
+
import * as Queue from "effect/Queue";
|
|
21
|
+
import * as Ref from "effect/Ref";
|
|
22
|
+
import * as Scope from "effect/Scope";
|
|
23
|
+
import * as Stream from "effect/Stream";
|
|
24
|
+
import * as String from "effect/String";
|
|
25
25
|
import {
|
|
26
26
|
externalPlugin,
|
|
27
27
|
loadTsConfig,
|
|
@@ -54,9 +54,6 @@ const GENERATED_DIRNAME = "_generated";
|
|
|
54
54
|
const GENERATED_SPEC_PATH = Effect.andThen(Path.Path, (path) =>
|
|
55
55
|
path.join(GENERATED_DIRNAME, "spec.ts"),
|
|
56
56
|
);
|
|
57
|
-
const GENERATED_NODE_SPEC_PATH = Effect.andThen(Path.Path, (path) =>
|
|
58
|
-
path.join(GENERATED_DIRNAME, "nodeSpec.ts"),
|
|
59
|
-
);
|
|
60
57
|
|
|
61
58
|
// Quiescence window: the sync loop waits this long for further signals
|
|
62
59
|
// after each batch. One user edit fires `onEnd` on every esbuild
|
|
@@ -421,11 +418,9 @@ const discoverEntryPoints = Effect.gen(function* () {
|
|
|
421
418
|
});
|
|
422
419
|
|
|
423
420
|
const generatedSpecPath = yield* GENERATED_SPEC_PATH;
|
|
424
|
-
const generatedNodeSpecPath = yield* GENERATED_NODE_SPEC_PATH;
|
|
425
421
|
|
|
426
422
|
const fixedEntryOptions = yield* Effect.all([
|
|
427
423
|
tryEntry(generatedSpecPath, "specDirty"),
|
|
428
|
-
tryEntry(generatedNodeSpecPath, "specDirty"),
|
|
429
424
|
// `confect/schema.ts` is no longer user-authored; the runtime
|
|
430
425
|
// `DatabaseSchema` lives at `_generated/schema.ts` (codegen-written,
|
|
431
426
|
// so not an entry point — wiring it through esbuild would form a
|
package/src/confect.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as Command from "@effect/cli/Command";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
3
|
import { codegen } from "./confect/codegen";
|
|
4
4
|
import { dev } from "./confect/dev";
|
|
5
5
|
import { ConfectDirectory } from "./ConfectDirectory";
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import * as NodeContext from "@effect/platform-node/NodeContext";
|
|
4
|
+
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
5
6
|
import { cliApp } from "./cliApp";
|
|
6
7
|
|
|
7
8
|
// Track if we received SIGINT so we can re-raise it after cleanup.
|
package/src/log.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import * as Path from "@effect/platform/Path";
|
|
2
|
+
import * as Ansi from "@effect/printer-ansi/Ansi";
|
|
3
|
+
import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
|
|
4
|
+
import { pipe } from "effect/Function";
|
|
5
|
+
import * as Console from "effect/Console";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as String from "effect/String";
|
|
4
8
|
import type * as FunctionPath from "./FunctionPath";
|
|
5
9
|
import * as GroupPath from "./GroupPath";
|
|
6
10
|
import { ProjectRoot } from "./ProjectRoot";
|
package/src/templates.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Array from "effect/Array";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
2
4
|
import { CodeBlockWriter } from "./CodeBlockWriter";
|
|
3
5
|
import {
|
|
4
6
|
collectImportBindings,
|
|
@@ -263,30 +265,14 @@ export const authConfig = ({ authImportPath }: { authImportPath: string }) =>
|
|
|
263
265
|
return yield* cbw.toString();
|
|
264
266
|
});
|
|
265
267
|
|
|
266
|
-
export const refs = ({
|
|
267
|
-
specImportPath,
|
|
268
|
-
nodeSpecImportPath,
|
|
269
|
-
}: {
|
|
270
|
-
specImportPath: string;
|
|
271
|
-
nodeSpecImportPath: Option.Option<string>;
|
|
272
|
-
}) =>
|
|
268
|
+
export const refs = ({ specImportPath }: { specImportPath: string }) =>
|
|
273
269
|
Effect.gen(function* () {
|
|
274
270
|
const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
|
|
275
271
|
|
|
276
272
|
yield* cbw.writeLine(`import { Refs } from "@confect/core";`);
|
|
277
273
|
yield* cbw.writeLine(`import spec from "${specImportPath}";`);
|
|
278
|
-
yield* Option.match(nodeSpecImportPath, {
|
|
279
|
-
onNone: () => Effect.void,
|
|
280
|
-
onSome: (nodeSpecImportPath_) =>
|
|
281
|
-
cbw.writeLine(`import nodeSpec from "${nodeSpecImportPath_}";`),
|
|
282
|
-
});
|
|
283
274
|
yield* cbw.blankLine();
|
|
284
|
-
yield* cbw.writeLine(
|
|
285
|
-
Option.match(nodeSpecImportPath, {
|
|
286
|
-
onSome: () => `export default Refs.make(spec, nodeSpec);`,
|
|
287
|
-
onNone: () => `export default Refs.make(spec);`,
|
|
288
|
-
}),
|
|
289
|
-
);
|
|
275
|
+
yield* cbw.writeLine(`export default Refs.make(spec);`);
|
|
290
276
|
|
|
291
277
|
return yield* cbw.toString();
|
|
292
278
|
});
|
|
@@ -588,10 +574,8 @@ const writeRootAddAt = (
|
|
|
588
574
|
|
|
589
575
|
export const assembledSpec = ({
|
|
590
576
|
nodes,
|
|
591
|
-
runtime,
|
|
592
577
|
}: {
|
|
593
578
|
nodes: ReadonlyArray<SpecAssemblyNode>;
|
|
594
|
-
runtime: "Convex" | "Node";
|
|
595
579
|
}) =>
|
|
596
580
|
Effect.gen(function* () {
|
|
597
581
|
const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
|
|
@@ -615,14 +599,13 @@ export const assembledSpec = ({
|
|
|
615
599
|
|
|
616
600
|
yield* cbw.blankLine();
|
|
617
601
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
yield* cbw.write(`export default ${specFactory}`);
|
|
602
|
+
// The assembled spec is runtime-agnostic: a Node group's `makeNode()` is
|
|
603
|
+
// already baked into its imported leaf spec, so the root is always
|
|
604
|
+
// `Spec.make()` and binding-less container groups always use
|
|
605
|
+
// `GroupSpec.makeAt` (containers register no functions and carry no runtime).
|
|
606
|
+
yield* cbw.write(`export default Spec.make()`);
|
|
624
607
|
yield* Effect.forEach(nodes, (node) =>
|
|
625
|
-
writeRootAddAt(cbw, node,
|
|
608
|
+
writeRootAddAt(cbw, node, "GroupSpec.makeAt"),
|
|
626
609
|
);
|
|
627
610
|
yield* cbw.write(";");
|
|
628
611
|
yield* cbw.newLine();
|