@confect/cli 1.0.0-next.3 → 1.0.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 +15 -0
- package/dist/confect/codegen.mjs +83 -11
- package/dist/confect/codegen.mjs.map +1 -1
- package/dist/confect/dev.mjs +156 -131
- package/dist/confect/dev.mjs.map +1 -1
- package/dist/log.mjs +5 -4
- package/dist/log.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/templates.mjs +34 -8
- package/dist/templates.mjs.map +1 -1
- package/dist/utils.mjs +17 -11
- package/dist/utils.mjs.map +1 -1
- package/package.json +3 -3
- package/src/confect/codegen.ts +146 -21
- package/src/confect/dev.ts +310 -283
- package/src/log.ts +14 -37
- package/src/templates.ts +78 -6
- package/src/utils.ts +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @confect/cli
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 2ff70a7: Initial release.
|
|
8
|
+
|
|
9
|
+
## 1.0.0-next.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 46109fb: Support Node actions
|
|
14
|
+
- Updated dependencies [46109fb]
|
|
15
|
+
- @confect/server@1.0.0-next.4
|
|
16
|
+
- @confect/core@1.0.0-next.4
|
|
17
|
+
|
|
3
18
|
## 1.0.0-next.3
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/confect/codegen.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logFileAdded, logFileModified, logFileRemoved, logPending, logSuccess } from "../log.mjs";
|
|
2
2
|
import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
|
|
3
3
|
import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
|
|
4
|
-
import { api, refs, registeredFunctions, schema, services } from "../templates.mjs";
|
|
4
|
+
import { api, nodeApi, nodeRegisteredFunctions, refs, registeredFunctions, schema, services } from "../templates.mjs";
|
|
5
5
|
import { generateAuthConfig, generateConvexConfig, generateCrons, generateFunctions, generateHttp, removePathExtension, writeFileStringAndLog } from "../utils.mjs";
|
|
6
6
|
import { Effect, Match, Option } from "effect";
|
|
7
7
|
import { Command } from "@effect/cli";
|
|
@@ -11,9 +11,25 @@ import { FileSystem, Path } from "@effect/platform";
|
|
|
11
11
|
import * as tsx from "tsx/esm/api";
|
|
12
12
|
|
|
13
13
|
//#region src/confect/codegen.ts
|
|
14
|
+
const getNodeSpecPath = Effect.gen(function* () {
|
|
15
|
+
const path = yield* Path.Path;
|
|
16
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
17
|
+
return path.join(confectDirectory, "nodeSpec.ts");
|
|
18
|
+
});
|
|
19
|
+
const loadNodeSpec = Effect.gen(function* () {
|
|
20
|
+
const fs = yield* FileSystem.FileSystem;
|
|
21
|
+
const path = yield* Path.Path;
|
|
22
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
23
|
+
if (!(yield* fs.exists(nodeSpecPath))) return Option.none();
|
|
24
|
+
const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);
|
|
25
|
+
const nodeSpec = (yield* Effect.promise(() => tsx.tsImport(nodeSpecPathUrl.href, import.meta.url))).default;
|
|
26
|
+
if (!Spec.isNodeSpec(nodeSpec)) return yield* Effect.die("nodeSpec.ts does not export a valid Node Spec");
|
|
27
|
+
return Option.some(nodeSpec);
|
|
28
|
+
});
|
|
14
29
|
const codegen = Command.make("codegen", {}, () => Effect.gen(function* () {
|
|
30
|
+
yield* logPending("Performing initial sync…");
|
|
15
31
|
yield* codegenHandler;
|
|
16
|
-
yield*
|
|
32
|
+
yield* logSuccess("Generated files are up-to-date");
|
|
17
33
|
})).pipe(Command.withDescription("Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)"));
|
|
18
34
|
const codegenHandler = Effect.gen(function* () {
|
|
19
35
|
yield* generateConfectGeneratedDirectory;
|
|
@@ -21,6 +37,8 @@ const codegenHandler = Effect.gen(function* () {
|
|
|
21
37
|
generateApi,
|
|
22
38
|
generateRefs,
|
|
23
39
|
generateRegisteredFunctions,
|
|
40
|
+
generateNodeApi,
|
|
41
|
+
generateNodeRegisteredFunctions,
|
|
24
42
|
generateServices
|
|
25
43
|
], { concurrency: "unbounded" });
|
|
26
44
|
const [functionPaths] = yield* Effect.all([
|
|
@@ -46,21 +64,50 @@ const generateApi = Effect.gen(function* () {
|
|
|
46
64
|
const path = yield* Path.Path;
|
|
47
65
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
48
66
|
const apiPath = path.join(confectDirectory, "_generated", "api.ts");
|
|
49
|
-
const
|
|
50
|
-
const
|
|
67
|
+
const apiDir = path.dirname(apiPath);
|
|
68
|
+
const schemaImportPath = yield* removePathExtension(path.relative(apiDir, path.join(confectDirectory, "schema.ts")));
|
|
69
|
+
const specImportPath = yield* removePathExtension(path.relative(apiDir, path.join(confectDirectory, "spec.ts")));
|
|
51
70
|
yield* writeFileStringAndLog(apiPath, yield* api({
|
|
52
71
|
schemaImportPath,
|
|
53
72
|
specImportPath
|
|
54
73
|
}));
|
|
55
74
|
});
|
|
75
|
+
const generateNodeApi = Effect.gen(function* () {
|
|
76
|
+
const fs = yield* FileSystem.FileSystem;
|
|
77
|
+
const path = yield* Path.Path;
|
|
78
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
79
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
80
|
+
const nodeApiPath = path.join(confectDirectory, "_generated", "nodeApi.ts");
|
|
81
|
+
if (!(yield* fs.exists(nodeSpecPath))) {
|
|
82
|
+
if (yield* fs.exists(nodeApiPath)) {
|
|
83
|
+
yield* fs.remove(nodeApiPath);
|
|
84
|
+
yield* logFileRemoved(nodeApiPath);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const nodeApiDir = path.dirname(nodeApiPath);
|
|
89
|
+
const schemaImportPath = yield* removePathExtension(path.relative(nodeApiDir, path.join(confectDirectory, "schema.ts")));
|
|
90
|
+
const nodeSpecImportPath = yield* removePathExtension(path.relative(nodeApiDir, nodeSpecPath));
|
|
91
|
+
yield* writeFileStringAndLog(nodeApiPath, yield* nodeApi({
|
|
92
|
+
schemaImportPath,
|
|
93
|
+
nodeSpecImportPath
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
56
96
|
const generateFunctionModules = Effect.gen(function* () {
|
|
97
|
+
const fs = yield* FileSystem.FileSystem;
|
|
57
98
|
const path = yield* Path.Path;
|
|
58
99
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
59
100
|
const specPath = path.join(confectDirectory, "spec.ts");
|
|
60
101
|
const specPathUrl = yield* path.toFileUrl(specPath);
|
|
61
102
|
const spec = (yield* Effect.promise(() => tsx.tsImport(specPathUrl.href, import.meta.url))).default;
|
|
62
|
-
if (!Spec.
|
|
63
|
-
|
|
103
|
+
if (!Spec.isConvexSpec(spec)) return yield* Effect.die("spec.ts does not export a valid Convex Spec");
|
|
104
|
+
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
105
|
+
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
106
|
+
const nodeSpecOption = yield* loadNodeSpec;
|
|
107
|
+
return yield* generateFunctions(Option.match(nodeSpecOption, {
|
|
108
|
+
onNone: () => spec,
|
|
109
|
+
onSome: (nodeSpec) => nodeImplExists ? Spec.merge(spec, nodeSpec) : spec
|
|
110
|
+
}));
|
|
64
111
|
});
|
|
65
112
|
const generateSchema = Effect.gen(function* () {
|
|
66
113
|
const path = yield* Path.Path;
|
|
@@ -92,14 +139,39 @@ const generateRegisteredFunctions = Effect.gen(function* () {
|
|
|
92
139
|
const implImportPath = yield* removePathExtension(path.relative(path.dirname(registeredFunctionsPath), path.join(confectDirectory, "impl.ts")));
|
|
93
140
|
yield* writeFileStringAndLog(registeredFunctionsPath, yield* registeredFunctions({ implImportPath }));
|
|
94
141
|
});
|
|
142
|
+
const generateNodeRegisteredFunctions = Effect.gen(function* () {
|
|
143
|
+
const fs = yield* FileSystem.FileSystem;
|
|
144
|
+
const path = yield* Path.Path;
|
|
145
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
146
|
+
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
147
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
148
|
+
const nodeRegisteredFunctionsPath = path.join(confectDirectory, "_generated", "nodeRegisteredFunctions.ts");
|
|
149
|
+
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
150
|
+
const nodeSpecExists = yield* fs.exists(nodeSpecPath);
|
|
151
|
+
if (!nodeImplExists || !nodeSpecExists) {
|
|
152
|
+
if (yield* fs.exists(nodeRegisteredFunctionsPath)) {
|
|
153
|
+
yield* fs.remove(nodeRegisteredFunctionsPath);
|
|
154
|
+
yield* logFileRemoved(nodeRegisteredFunctionsPath);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const nodeImplImportPath = yield* removePathExtension(path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath));
|
|
159
|
+
yield* writeFileStringAndLog(nodeRegisteredFunctionsPath, yield* nodeRegisteredFunctions({ nodeImplImportPath }));
|
|
160
|
+
});
|
|
95
161
|
const generateRefs = Effect.gen(function* () {
|
|
162
|
+
const fs = yield* FileSystem.FileSystem;
|
|
96
163
|
const path = yield* Path.Path;
|
|
97
164
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
98
165
|
const confectGeneratedDirectory = path.join(confectDirectory, "_generated");
|
|
99
|
-
const confectSpecPath = path.join(confectDirectory, "spec.ts");
|
|
100
166
|
const refsPath = path.join(confectGeneratedDirectory, "refs.ts");
|
|
101
|
-
const
|
|
102
|
-
yield*
|
|
167
|
+
const refsDir = path.dirname(refsPath);
|
|
168
|
+
const specImportPath = yield* removePathExtension(path.relative(refsDir, path.join(confectDirectory, "spec.ts")));
|
|
169
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
170
|
+
const nodeSpecImportPath = (yield* fs.exists(nodeSpecPath)) ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath)) : null;
|
|
171
|
+
yield* writeFileStringAndLog(refsPath, yield* refs({
|
|
172
|
+
specImportPath,
|
|
173
|
+
...nodeSpecImportPath === null ? {} : { nodeSpecImportPath }
|
|
174
|
+
}));
|
|
103
175
|
});
|
|
104
176
|
const logGenerated = (effect) => effect.pipe(Effect.tap(Option.match({
|
|
105
177
|
onNone: () => Effect.void,
|
|
@@ -107,5 +179,5 @@ const logGenerated = (effect) => effect.pipe(Effect.tap(Option.match({
|
|
|
107
179
|
})));
|
|
108
180
|
|
|
109
181
|
//#endregion
|
|
110
|
-
export { codegen, codegenHandler };
|
|
182
|
+
export { codegen, codegenHandler, generateNodeApi, generateNodeRegisteredFunctions };
|
|
111
183
|
//# sourceMappingURL=codegen.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.mjs","names":["templates.api","templates.schema","templates.services","templates.registeredFunctions","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { DatabaseSchema } from \"@confect/server\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Match, Option } from \"effect\";\nimport * as tsx from \"tsx/esm/api\";\nimport { logCompleted, logFileAdded, logFileModified } from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n writeFileStringAndLog,\n} from \"../utils\";\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* codegenHandler;\n yield* logCompleted(\"Generated files are up-to-date\");\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n yield* Effect.all(\n [generateApi, generateRefs, generateRegisteredFunctions, generateServices],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateConvexConfig),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(apiPath),\n path.join(confectDirectory, \"schema.ts\"),\n ),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(apiPath),\n path.join(confectDirectory, \"spec.ts\"),\n ),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const specPath = path.join(confectDirectory, \"spec.ts\");\n const specPathUrl = yield* path.toFileUrl(specPath);\n\n const specModule = yield* Effect.promise(() =>\n tsx.tsImport(specPathUrl.href, import.meta.url),\n );\n const spec = specModule.default;\n\n if (!Spec.isSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Spec\");\n }\n\n return yield* generateFunctions(spec);\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n const confectSchemaUrl = yield* path.toFileUrl(confectSchemaPath);\n\n yield* Effect.promise(() =>\n tsx.tsImport(confectSchemaUrl.href, import.meta.url),\n ).pipe(\n Effect.andThen((schemaModule) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.die(\"Invalid schema module\");\n }),\n );\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRegisteredFunctions = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const registeredFunctionsPath = path.join(\n confectGeneratedDirectory,\n \"registeredFunctions.ts\",\n );\n const implImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(registeredFunctionsPath),\n path.join(confectDirectory, \"impl.ts\"),\n ),\n );\n\n const registeredFunctionsContents = yield* templates.registeredFunctions({\n implImportPath,\n });\n\n yield* writeFileStringAndLog(\n registeredFunctionsPath,\n registeredFunctionsContents,\n );\n});\n\nconst generateRefs = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const confectSpecPath = path.join(confectDirectory, \"spec.ts\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(refsPath),\n confectSpecPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n\n const refsContents = yield* templates.refs({\n specImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"codegen.mjs","names":["templates.api","templates.nodeApi","templates.schema","templates.services","templates.registeredFunctions","templates.nodeRegisteredFunctions","templates.refs"],"sources":["../../src/confect/codegen.ts"],"sourcesContent":["import { Spec } from \"@confect/core\";\nimport { DatabaseSchema } from \"@confect/server\";\nimport { Command } from \"@effect/cli\";\nimport { FileSystem, Path } from \"@effect/platform\";\nimport { Effect, Match, Option } from \"effect\";\nimport * as tsx from \"tsx/esm/api\";\nimport {\n logFileAdded,\n logFileModified,\n logFileRemoved,\n logPending,\n logSuccess,\n} from \"../log\";\nimport { ConfectDirectory } from \"../services/ConfectDirectory\";\nimport { ConvexDirectory } from \"../services/ConvexDirectory\";\nimport * as templates from \"../templates\";\nimport {\n generateAuthConfig,\n generateConvexConfig,\n generateCrons,\n generateFunctions,\n generateHttp,\n removePathExtension,\n writeFileStringAndLog,\n} from \"../utils\";\n\nconst getNodeSpecPath = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n return path.join(confectDirectory, \"nodeSpec.ts\");\n});\n\nconst loadNodeSpec = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const nodeSpecPath = yield* getNodeSpecPath;\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n return Option.none<Spec.AnyWithPropsWithRuntime<\"Node\">>();\n }\n\n const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);\n const nodeSpecModule = yield* Effect.promise(() =>\n tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),\n );\n const nodeSpec = nodeSpecModule.default;\n\n if (!Spec.isNodeSpec(nodeSpec)) {\n return yield* Effect.die(\"nodeSpec.ts does not export a valid Node Spec\");\n }\n\n return Option.some(nodeSpec);\n});\n\nexport const codegen = Command.make(\"codegen\", {}, () =>\n Effect.gen(function* () {\n yield* logPending(\"Performing initial sync…\");\n yield* codegenHandler;\n yield* logSuccess(\"Generated files are up-to-date\");\n }),\n).pipe(\n Command.withDescription(\n \"Generate `confect/_generated` files and the contents of the `convex` directory (except `tsconfig.json`)\",\n ),\n);\n\nexport const codegenHandler = Effect.gen(function* () {\n yield* generateConfectGeneratedDirectory;\n yield* Effect.all(\n [\n generateApi,\n generateRefs,\n generateRegisteredFunctions,\n generateNodeApi,\n generateNodeRegisteredFunctions,\n generateServices,\n ],\n { concurrency: \"unbounded\" },\n );\n const [functionPaths] = yield* Effect.all(\n [\n generateFunctionModules,\n generateSchema,\n logGenerated(generateHttp),\n logGenerated(generateConvexConfig),\n logGenerated(generateCrons),\n logGenerated(generateAuthConfig),\n ],\n { concurrency: \"unbounded\" },\n );\n return functionPaths;\n});\n\nconst generateConfectGeneratedDirectory = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n if (!(yield* fs.exists(path.join(confectDirectory, \"_generated\")))) {\n yield* fs.makeDirectory(path.join(confectDirectory, \"_generated\"), {\n recursive: true,\n });\n yield* logFileAdded(path.join(confectDirectory, \"_generated\") + \"/\");\n }\n});\n\nconst generateApi = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const apiPath = path.join(confectDirectory, \"_generated\", \"api.ts\");\n const apiDir = path.dirname(apiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const specImportPath = yield* removePathExtension(\n path.relative(apiDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const apiContents = yield* templates.api({\n schemaImportPath,\n specImportPath,\n });\n\n yield* writeFileStringAndLog(apiPath, apiContents);\n});\n\nexport const generateNodeApi = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeApiPath = path.join(confectDirectory, \"_generated\", \"nodeApi.ts\");\n\n if (!(yield* fs.exists(nodeSpecPath))) {\n if (yield* fs.exists(nodeApiPath)) {\n yield* fs.remove(nodeApiPath);\n yield* logFileRemoved(nodeApiPath);\n }\n return;\n }\n\n const nodeApiDir = path.dirname(nodeApiPath);\n\n const schemaImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, path.join(confectDirectory, \"schema.ts\")),\n );\n\n const nodeSpecImportPath = yield* removePathExtension(\n path.relative(nodeApiDir, nodeSpecPath),\n );\n\n const nodeApiContents = yield* templates.nodeApi({\n schemaImportPath,\n nodeSpecImportPath,\n });\n\n yield* writeFileStringAndLog(nodeApiPath, nodeApiContents);\n});\n\nconst generateFunctionModules = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const specPath = path.join(confectDirectory, \"spec.ts\");\n const specPathUrl = yield* path.toFileUrl(specPath);\n\n const specModule = yield* Effect.promise(() =>\n tsx.tsImport(specPathUrl.href, import.meta.url),\n );\n const spec = specModule.default;\n\n if (!Spec.isConvexSpec(spec)) {\n return yield* Effect.die(\"spec.ts does not export a valid Convex Spec\");\n }\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecOption = yield* loadNodeSpec;\n\n const mergedSpec = Option.match(nodeSpecOption, {\n onNone: () => spec,\n onSome: (nodeSpec) => (nodeImplExists ? Spec.merge(spec, nodeSpec) : spec),\n });\n\n return yield* generateFunctions(mergedSpec);\n});\n\nconst generateSchema = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n const convexDirectory = yield* ConvexDirectory.get;\n\n const confectSchemaPath = path.join(confectDirectory, \"schema.ts\");\n const confectSchemaUrl = yield* path.toFileUrl(confectSchemaPath);\n\n yield* Effect.promise(() =>\n tsx.tsImport(confectSchemaUrl.href, import.meta.url),\n ).pipe(\n Effect.andThen((schemaModule) => {\n const defaultExport = schemaModule.default;\n\n return DatabaseSchema.isSchema(defaultExport)\n ? Effect.succeed(defaultExport)\n : Effect.die(\"Invalid schema module\");\n }),\n );\n\n const convexSchemaPath = path.join(convexDirectory, \"schema.ts\");\n\n const relativeImportPath = path.relative(\n path.dirname(convexSchemaPath),\n confectSchemaPath,\n );\n const importPathWithoutExt = yield* removePathExtension(relativeImportPath);\n const schemaContents = yield* templates.schema({\n schemaImportPath: importPathWithoutExt,\n });\n\n yield* writeFileStringAndLog(convexSchemaPath, schemaContents);\n});\n\nconst generateServices = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const servicesPath = path.join(confectGeneratedDirectory, \"services.ts\");\n const schemaImportPath = path.relative(\n path.dirname(servicesPath),\n path.join(confectDirectory, \"schema\"),\n );\n\n const servicesContentsString = yield* templates.services({\n schemaImportPath,\n });\n\n yield* writeFileStringAndLog(servicesPath, servicesContentsString);\n});\n\nconst generateRegisteredFunctions = Effect.gen(function* () {\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n\n const registeredFunctionsPath = path.join(\n confectGeneratedDirectory,\n \"registeredFunctions.ts\",\n );\n const implImportPath = yield* removePathExtension(\n path.relative(\n path.dirname(registeredFunctionsPath),\n path.join(confectDirectory, \"impl.ts\"),\n ),\n );\n\n const registeredFunctionsContents = yield* templates.registeredFunctions({\n implImportPath,\n });\n\n yield* writeFileStringAndLog(\n registeredFunctionsPath,\n registeredFunctionsContents,\n );\n});\n\nexport const generateNodeRegisteredFunctions = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const nodeImplPath = path.join(confectDirectory, \"nodeImpl.ts\");\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeRegisteredFunctionsPath = path.join(\n confectDirectory,\n \"_generated\",\n \"nodeRegisteredFunctions.ts\",\n );\n\n const nodeImplExists = yield* fs.exists(nodeImplPath);\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n\n if (!nodeImplExists || !nodeSpecExists) {\n if (yield* fs.exists(nodeRegisteredFunctionsPath)) {\n yield* fs.remove(nodeRegisteredFunctionsPath);\n yield* logFileRemoved(nodeRegisteredFunctionsPath);\n }\n return;\n }\n\n const nodeImplImportPath = yield* removePathExtension(\n path.relative(path.dirname(nodeRegisteredFunctionsPath), nodeImplPath),\n );\n\n const nodeRegisteredFunctionsContents =\n yield* templates.nodeRegisteredFunctions({\n nodeImplImportPath,\n });\n\n yield* writeFileStringAndLog(\n nodeRegisteredFunctionsPath,\n nodeRegisteredFunctionsContents,\n );\n});\n\nconst generateRefs = Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const confectDirectory = yield* ConfectDirectory.get;\n\n const confectGeneratedDirectory = path.join(confectDirectory, \"_generated\");\n const refsPath = path.join(confectGeneratedDirectory, \"refs.ts\");\n const refsDir = path.dirname(refsPath);\n\n const specImportPath = yield* removePathExtension(\n path.relative(refsDir, path.join(confectDirectory, \"spec.ts\")),\n );\n\n const nodeSpecPath = yield* getNodeSpecPath;\n const nodeSpecExists = yield* fs.exists(nodeSpecPath);\n const nodeSpecImportPath = nodeSpecExists\n ? yield* removePathExtension(path.relative(refsDir, nodeSpecPath))\n : null;\n\n const refsContents = yield* templates.refs({\n specImportPath,\n ...(nodeSpecImportPath === null ? {} : { nodeSpecImportPath }),\n });\n\n yield* writeFileStringAndLog(refsPath, refsContents);\n});\n\nconst logGenerated = (effect: typeof generateHttp) =>\n effect.pipe(\n Effect.tap(\n Option.match({\n onNone: () => Effect.void,\n onSome: ({ change, convexFilePath }) =>\n Match.value(change).pipe(\n Match.when(\"Added\", () => logFileAdded(convexFilePath)),\n Match.when(\"Modified\", () => logFileModified(convexFilePath)),\n Match.when(\"Unchanged\", () => Effect.void),\n Match.exhaustive,\n ),\n }),\n ),\n );\n"],"mappings":"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"}
|
package/dist/confect/dev.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { modulePath, toString } from "../GroupPath.mjs";
|
|
2
2
|
import { ProjectRoot } from "../services/ProjectRoot.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { logFailure, logPending, logSuccess } from "../log.mjs";
|
|
4
4
|
import { ConvexDirectory } from "../services/ConvexDirectory.mjs";
|
|
5
5
|
import { ConfectDirectory } from "../services/ConfectDirectory.mjs";
|
|
6
6
|
import { diff, make } from "../FunctionPaths.mjs";
|
|
7
7
|
import { generateAuthConfig, generateConvexConfig, generateCrons, generateHttp, removeGroups, writeGroups } from "../utils.mjs";
|
|
8
|
-
import { codegenHandler } from "./codegen.mjs";
|
|
9
|
-
import { Array, Console,
|
|
8
|
+
import { codegenHandler, generateNodeApi, generateNodeRegisteredFunctions } from "./codegen.mjs";
|
|
9
|
+
import { Array, Console, Deferred, Duration, Effect, Equal, HashSet, Match, Option, Queue, Ref, Schema, Stream, String, pipe } from "effect";
|
|
10
10
|
import { Command } from "@effect/cli";
|
|
11
11
|
import { Spec } from "@confect/core";
|
|
12
12
|
import { FileSystem, Path } from "@effect/platform";
|
|
@@ -17,23 +17,12 @@ import * as esbuild from "esbuild";
|
|
|
17
17
|
//#region src/confect/dev.ts
|
|
18
18
|
const pendingInit = {
|
|
19
19
|
specDirty: false,
|
|
20
|
+
nodeImplDirty: false,
|
|
20
21
|
httpDirty: false,
|
|
21
22
|
appDirty: false,
|
|
22
23
|
cronsDirty: false,
|
|
23
24
|
authDirty: false
|
|
24
25
|
};
|
|
25
|
-
const FileChange = Data.taggedEnum();
|
|
26
|
-
const logChangeReport = (changes) => Effect.gen(function* () {
|
|
27
|
-
yield* logCompleted("Generated files are up-to-date");
|
|
28
|
-
yield* Effect.when(Effect.forEach(changes, (change) => FileChange.$match(change, {
|
|
29
|
-
OptionalFile: ({ change: c, filePath }) => logFileChangeIndented(c, filePath),
|
|
30
|
-
GroupModule: ({ change: c, filePath, functionsAdded, functionsRemoved }) => Effect.gen(function* () {
|
|
31
|
-
yield* logFileChangeIndented(c, filePath);
|
|
32
|
-
yield* Effect.forEach(functionsAdded, logFunctionAddedIndented);
|
|
33
|
-
yield* Effect.forEach(functionsRemoved, logFunctionRemovedIndented);
|
|
34
|
-
})
|
|
35
|
-
})), () => Array.isNonEmptyReadonlyArray(changes));
|
|
36
|
-
});
|
|
37
26
|
const changeChar = (change) => Match.value(change).pipe(Match.when("Added", () => ({
|
|
38
27
|
char: "+",
|
|
39
28
|
color: Ansi.green
|
|
@@ -48,27 +37,36 @@ const logFileChangeIndented = (change, fullPath) => Effect.gen(function* () {
|
|
|
48
37
|
const prefix = (yield* ProjectRoot.get) + (yield* Path.Path).sep;
|
|
49
38
|
const suffix = pipe(fullPath, String.startsWith(prefix)) ? pipe(fullPath, String.slice(prefix.length)) : fullPath;
|
|
50
39
|
const { char, color } = changeChar(change);
|
|
51
|
-
yield* Console.log(pipe(AnsiDoc.
|
|
40
|
+
yield* Console.log(pipe(AnsiDoc.char(char), AnsiDoc.annotate(color), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(prefix), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(suffix), AnsiDoc.annotate(color))])), AnsiDoc.render({ style: "pretty" })));
|
|
52
41
|
});
|
|
53
|
-
const logFunctionAddedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text("
|
|
54
|
-
const logFunctionRemovedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text("
|
|
42
|
+
const logFunctionAddedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char("+"), AnsiDoc.annotate(Ansi.green))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(toString(functionPath.groupPath) + "."), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.green))])), AnsiDoc.render({ style: "pretty" })));
|
|
43
|
+
const logFunctionRemovedIndented = (functionPath) => Console.log(pipe(AnsiDoc.text(" "), AnsiDoc.cat(pipe(AnsiDoc.char("-"), AnsiDoc.annotate(Ansi.red))), AnsiDoc.catWithSpace(AnsiDoc.hcat([pipe(AnsiDoc.text(toString(functionPath.groupPath) + "."), AnsiDoc.annotate(Ansi.blackBright)), pipe(AnsiDoc.text(functionPath.name), AnsiDoc.annotate(Ansi.red))])), AnsiDoc.render({ style: "pretty" })));
|
|
55
44
|
const dev = Command.make("dev", {}, () => Effect.gen(function* () {
|
|
45
|
+
yield* logPending("Performing initial sync…");
|
|
56
46
|
const initialFunctionPaths = yield* codegenHandler;
|
|
57
47
|
const pendingRef = yield* Ref.make(pendingInit);
|
|
58
48
|
const signal = yield* Queue.sliding(1);
|
|
49
|
+
const specWatcherRestartQueue = yield* Queue.sliding(1);
|
|
59
50
|
yield* Effect.all([
|
|
60
|
-
specFileWatcher(signal, pendingRef),
|
|
61
|
-
confectDirectoryWatcher(signal, pendingRef),
|
|
51
|
+
specFileWatcher(signal, pendingRef, specWatcherRestartQueue),
|
|
52
|
+
confectDirectoryWatcher(signal, pendingRef, specWatcherRestartQueue),
|
|
62
53
|
syncLoop(signal, pendingRef, initialFunctionPaths)
|
|
63
54
|
], { concurrency: "unbounded" });
|
|
64
55
|
})).pipe(Command.withDescription("Start the Confect development server"));
|
|
65
56
|
const syncLoop = (signal, pendingRef, initialFunctionPaths) => Effect.gen(function* () {
|
|
66
57
|
const functionPathsRef = yield* Ref.make(initialFunctionPaths);
|
|
67
|
-
const
|
|
58
|
+
const initialSyncDone = yield* Deferred.make();
|
|
68
59
|
return yield* Effect.forever(Effect.gen(function* () {
|
|
69
60
|
yield* Effect.logDebug("Running sync loop...");
|
|
70
61
|
yield* Queue.take(signal);
|
|
62
|
+
const isDone = yield* Deferred.isDone(initialSyncDone);
|
|
63
|
+
yield* Effect.when(logPending("Dependencies changed, reloading…"), () => isDone);
|
|
64
|
+
yield* Deferred.succeed(initialSyncDone, void 0);
|
|
71
65
|
const pending = yield* Ref.getAndSet(pendingRef, pendingInit);
|
|
66
|
+
if (pending.specDirty || pending.nodeImplDirty) {
|
|
67
|
+
yield* generateNodeApi;
|
|
68
|
+
yield* generateNodeRegisteredFunctions;
|
|
69
|
+
}
|
|
72
70
|
const specResult = yield* Effect.if(pending.specDirty, {
|
|
73
71
|
onTrue: () => loadSpec.pipe(Effect.andThen(Effect.fn(function* (spec) {
|
|
74
72
|
yield* Effect.logDebug("Spec loaded");
|
|
@@ -78,144 +76,162 @@ const syncLoop = (signal, pendingRef, initialFunctionPaths) => Effect.gen(functi
|
|
|
78
76
|
const current = make(spec);
|
|
79
77
|
const { functionsAdded, functionsRemoved, groupsRemoved, groupsAdded, groupsChanged } = diff(previous, current);
|
|
80
78
|
yield* removeGroups(groupsRemoved);
|
|
81
|
-
|
|
79
|
+
yield* Effect.forEach(groupsRemoved, (gp) => Effect.gen(function* () {
|
|
82
80
|
const relativeModulePath = yield* modulePath(gp);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
filePath: path.join(convexDirectory, relativeModulePath),
|
|
86
|
-
functionsAdded: [],
|
|
87
|
-
functionsRemoved: Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp)))
|
|
88
|
-
});
|
|
81
|
+
yield* logFileChangeIndented("Removed", path.join(convexDirectory, relativeModulePath));
|
|
82
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionRemovedIndented);
|
|
89
83
|
}));
|
|
90
84
|
yield* writeGroups(spec, groupsAdded);
|
|
91
|
-
|
|
85
|
+
yield* Effect.forEach(groupsAdded, (gp) => Effect.gen(function* () {
|
|
92
86
|
const relativeModulePath = yield* modulePath(gp);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
filePath: path.join(convexDirectory, relativeModulePath),
|
|
96
|
-
functionsAdded: Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))),
|
|
97
|
-
functionsRemoved: []
|
|
98
|
-
});
|
|
87
|
+
yield* logFileChangeIndented("Added", path.join(convexDirectory, relativeModulePath));
|
|
88
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionAddedIndented);
|
|
99
89
|
}));
|
|
100
90
|
yield* writeGroups(spec, groupsChanged);
|
|
101
|
-
|
|
91
|
+
yield* Effect.forEach(groupsChanged, (gp) => Effect.gen(function* () {
|
|
102
92
|
const relativeModulePath = yield* modulePath(gp);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
functionsAdded: Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))),
|
|
107
|
-
functionsRemoved: Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp)))
|
|
108
|
-
});
|
|
93
|
+
yield* logFileChangeIndented("Modified", path.join(convexDirectory, relativeModulePath));
|
|
94
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsAdded, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionAddedIndented);
|
|
95
|
+
yield* Effect.forEach(Array.fromIterable(HashSet.filter(functionsRemoved, (fp) => Equal.equals(fp.groupPath, gp))), logFunctionRemovedIndented);
|
|
109
96
|
}));
|
|
110
97
|
yield* Ref.set(functionPathsRef, current);
|
|
111
|
-
return Option.some(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
...changedChanges
|
|
115
|
-
]);
|
|
116
|
-
})), Effect.catchTag("SpecImportFailedError", () => logFailed("Spec import failed").pipe(Effect.as(Option.none()))), Effect.catchTag("SpecFileDoesNotExportSpecError", () => logFailed("Spec file does not default export a spec").pipe(Effect.as(Option.none())))),
|
|
117
|
-
onFalse: () => Effect.succeed(Option.some([]))
|
|
98
|
+
return Option.some(void 0);
|
|
99
|
+
})), Effect.catchTag("SpecImportFailedError", () => logFailure("Spec import failed").pipe(Effect.as(Option.none()))), Effect.catchTag("SpecFileDoesNotExportSpecError", () => logFailure("Spec file does not default export a Convex spec").pipe(Effect.as(Option.none()))), Effect.catchTag("NodeSpecFileDoesNotExportSpecError", () => logFailure("Node spec file does not default export a Node spec").pipe(Effect.as(Option.none())))),
|
|
100
|
+
onFalse: () => Effect.succeed(Option.some(void 0))
|
|
118
101
|
});
|
|
119
|
-
const specChanges = Option.getOrElse(specResult, () => []);
|
|
120
102
|
const dirtyOptionalFiles = [
|
|
121
103
|
...pending.httpDirty ? [syncOptionalFile(generateHttp, "http.ts")] : [],
|
|
122
104
|
...pending.appDirty ? [syncOptionalFile(generateConvexConfig, "convex.config.ts")] : [],
|
|
123
105
|
...pending.cronsDirty ? [syncOptionalFile(generateCrons, "crons.ts")] : [],
|
|
124
106
|
...pending.authDirty ? [syncOptionalFile(generateAuthConfig, "auth.config.ts")] : []
|
|
125
107
|
];
|
|
126
|
-
|
|
127
|
-
yield* Ref.update(changesRef, (prev) => [
|
|
128
|
-
...prev,
|
|
129
|
-
...specChanges,
|
|
130
|
-
...optionalChanges
|
|
131
|
-
]);
|
|
108
|
+
yield* Array.isNonEmptyReadonlyArray(dirtyOptionalFiles) ? Effect.all(dirtyOptionalFiles, { concurrency: "unbounded" }) : Effect.void;
|
|
132
109
|
yield* Option.match(specResult, {
|
|
133
|
-
onSome: () =>
|
|
134
|
-
|
|
135
|
-
yield* Effect.when(Effect.gen(function* () {
|
|
136
|
-
yield* logChangeReport(yield* Ref.getAndSet(changesRef, []));
|
|
137
|
-
}), () => pendingSize === 0);
|
|
138
|
-
}),
|
|
139
|
-
onNone: () => Ref.set(changesRef, [])
|
|
110
|
+
onSome: () => logSuccess("Generated files are up-to-date"),
|
|
111
|
+
onNone: () => Effect.void
|
|
140
112
|
});
|
|
141
113
|
}));
|
|
142
114
|
});
|
|
143
115
|
const loadSpec = Effect.gen(function* () {
|
|
144
|
-
const
|
|
116
|
+
const fs = yield* FileSystem.FileSystem;
|
|
117
|
+
const path = yield* Path.Path;
|
|
118
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
119
|
+
const specPathUrl = yield* path.toFileUrl(yield* getSpecPath);
|
|
145
120
|
const spec = (yield* Effect.tryPromise({
|
|
146
121
|
try: () => tsx.tsImport(specPathUrl.href, import.meta.url),
|
|
147
122
|
catch: (error) => new SpecImportFailedError({ error })
|
|
148
123
|
})).default;
|
|
149
|
-
if (Spec.
|
|
150
|
-
|
|
124
|
+
if (!Spec.isConvexSpec(spec)) return yield* new SpecFileDoesNotExportSpecError();
|
|
125
|
+
const nodeImplPath = path.join(confectDirectory, "nodeImpl.ts");
|
|
126
|
+
const nodeImplExists = yield* fs.exists(nodeImplPath);
|
|
127
|
+
const nodeSpecOption = yield* loadNodeSpec;
|
|
128
|
+
return Option.match(nodeSpecOption, {
|
|
129
|
+
onNone: () => spec,
|
|
130
|
+
onSome: (nodeSpec) => nodeImplExists ? Spec.merge(spec, nodeSpec) : spec
|
|
131
|
+
});
|
|
151
132
|
});
|
|
152
133
|
const getSpecPath = Effect.gen(function* () {
|
|
153
134
|
const path = yield* Path.Path;
|
|
154
135
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
155
136
|
return path.join(confectDirectory, "spec.ts");
|
|
156
137
|
});
|
|
157
|
-
const
|
|
138
|
+
const getNodeSpecPath = Effect.gen(function* () {
|
|
139
|
+
const path = yield* Path.Path;
|
|
140
|
+
const confectDirectory = yield* ConfectDirectory.get;
|
|
141
|
+
return path.join(confectDirectory, "nodeSpec.ts");
|
|
142
|
+
});
|
|
143
|
+
const loadNodeSpec = Effect.gen(function* () {
|
|
144
|
+
const fs = yield* FileSystem.FileSystem;
|
|
145
|
+
const path = yield* Path.Path;
|
|
146
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
147
|
+
if (!(yield* fs.exists(nodeSpecPath))) return Option.none();
|
|
148
|
+
const nodeSpecPathUrl = yield* path.toFileUrl(nodeSpecPath);
|
|
149
|
+
const nodeSpec = (yield* Effect.tryPromise({
|
|
150
|
+
try: () => tsx.tsImport(nodeSpecPathUrl.href, import.meta.url),
|
|
151
|
+
catch: (error) => new SpecImportFailedError({ error })
|
|
152
|
+
})).default;
|
|
153
|
+
if (!Spec.isNodeSpec(nodeSpec)) return yield* new NodeSpecFileDoesNotExportSpecError();
|
|
154
|
+
return Option.some(nodeSpec);
|
|
155
|
+
});
|
|
156
|
+
const esbuildOptions = (entryPoint) => ({
|
|
157
|
+
entryPoints: [entryPoint],
|
|
158
|
+
bundle: true,
|
|
159
|
+
write: false,
|
|
160
|
+
metafile: true,
|
|
161
|
+
platform: "node",
|
|
162
|
+
format: "esm",
|
|
163
|
+
logLevel: "silent",
|
|
164
|
+
external: [
|
|
165
|
+
"@confect/core",
|
|
166
|
+
"@confect/server",
|
|
167
|
+
"effect",
|
|
168
|
+
"@effect/*"
|
|
169
|
+
],
|
|
170
|
+
plugins: [{
|
|
171
|
+
name: "notify-rebuild",
|
|
172
|
+
setup(build) {
|
|
173
|
+
build.onEnd((result) => {
|
|
174
|
+
if (result.errors.length === 0) build._emit?.();
|
|
175
|
+
else Effect.runPromise(Effect.gen(function* () {
|
|
176
|
+
const formattedMessages = yield* Effect.promise(() => esbuild.formatMessages(result.errors, {
|
|
177
|
+
kind: "error",
|
|
178
|
+
color: true,
|
|
179
|
+
terminalWidth: 80
|
|
180
|
+
}));
|
|
181
|
+
const output = formatBuildErrors(result.errors, formattedMessages);
|
|
182
|
+
yield* Console.error("\n" + output + "\n");
|
|
183
|
+
yield* logFailure("Build errors found");
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}]
|
|
188
|
+
});
|
|
189
|
+
const createSpecWatcher = (entryPoint) => Stream.asyncPush((emit) => Effect.acquireRelease(Effect.promise(async () => {
|
|
190
|
+
const opts = esbuildOptions(entryPoint);
|
|
191
|
+
const plugin = opts.plugins[0];
|
|
192
|
+
const originalSetup = plugin.setup;
|
|
193
|
+
plugin.setup = (build) => {
|
|
194
|
+
build._emit = () => emit.single();
|
|
195
|
+
return originalSetup(build);
|
|
196
|
+
};
|
|
197
|
+
const ctx = await esbuild.context({
|
|
198
|
+
...opts,
|
|
199
|
+
plugins: [plugin]
|
|
200
|
+
});
|
|
201
|
+
await ctx.watch();
|
|
202
|
+
return ctx;
|
|
203
|
+
}), (ctx) => Effect.promise(() => ctx.dispose()).pipe(Effect.tap(() => Effect.logDebug("esbuild watcher disposed")))), {
|
|
204
|
+
bufferSize: 1,
|
|
205
|
+
strategy: "sliding"
|
|
206
|
+
});
|
|
207
|
+
const specFileWatcher = (signal, pendingRef, specWatcherRestartQueue) => Effect.forever(Effect.gen(function* () {
|
|
208
|
+
const fs = yield* FileSystem.FileSystem;
|
|
158
209
|
const specPath = yield* getSpecPath;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
format: "esm",
|
|
167
|
-
logLevel: "silent",
|
|
168
|
-
external: [
|
|
169
|
-
"@confect/core",
|
|
170
|
-
"@confect/server",
|
|
171
|
-
"effect",
|
|
172
|
-
"@effect/*"
|
|
173
|
-
],
|
|
174
|
-
plugins: [{
|
|
175
|
-
name: "notify-rebuild",
|
|
176
|
-
setup(build) {
|
|
177
|
-
build.onEnd((result) => {
|
|
178
|
-
if (result.errors.length === 0) emit.single();
|
|
179
|
-
else Effect.runPromise(Effect.gen(function* () {
|
|
180
|
-
yield* logFailed("Build errors");
|
|
181
|
-
const formattedMessages = yield* Effect.promise(() => esbuild.formatMessages(result.errors, {
|
|
182
|
-
kind: "error",
|
|
183
|
-
color: true,
|
|
184
|
-
terminalWidth: 80
|
|
185
|
-
}));
|
|
186
|
-
const output = formatBuildErrors(result.errors, formattedMessages);
|
|
187
|
-
yield* Console.error("\n" + output + "\n");
|
|
188
|
-
}));
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}]
|
|
192
|
-
});
|
|
193
|
-
await ctx.watch();
|
|
194
|
-
return ctx;
|
|
195
|
-
}), (ctx) => Effect.promise(() => ctx.dispose()).pipe(Effect.tap(() => Effect.logDebug("esbuild watcher disposed")))), {
|
|
196
|
-
bufferSize: 1,
|
|
197
|
-
strategy: "sliding"
|
|
198
|
-
}), Stream.debounce(Duration.millis(200)), Stream.runForEach(() => Ref.update(pendingRef, (pending) => ({
|
|
210
|
+
const nodeSpecPath = yield* getNodeSpecPath;
|
|
211
|
+
const nodeSpecExists = yield* fs.exists(nodeSpecPath);
|
|
212
|
+
const specWatcher = createSpecWatcher(specPath);
|
|
213
|
+
const nodeSpecWatcher = nodeSpecExists ? createSpecWatcher(nodeSpecPath) : Stream.empty;
|
|
214
|
+
const specChanges = pipe(Stream.merge(specWatcher, nodeSpecWatcher), Stream.map(() => "change"));
|
|
215
|
+
const restartStream = pipe(Stream.fromQueue(specWatcherRestartQueue), Stream.map(() => "restart"));
|
|
216
|
+
yield* pipe(Stream.merge(specChanges, restartStream), Stream.debounce(Duration.millis(200)), Stream.takeUntil((event) => event === "restart"), Stream.runForEach((event) => event === "change" ? Ref.update(pendingRef, (pending) => ({
|
|
199
217
|
...pending,
|
|
200
218
|
specDirty: true
|
|
201
|
-
})).pipe(Effect.andThen(Queue.offer(signal, void 0)))));
|
|
202
|
-
});
|
|
219
|
+
})).pipe(Effect.andThen(Queue.offer(signal, void 0))) : Effect.void));
|
|
220
|
+
}));
|
|
203
221
|
const formatBuildError = (error, formattedMessage) => {
|
|
204
222
|
const lines = String.split(formattedMessage, "\n");
|
|
205
223
|
const redErrorText = pipe(AnsiDoc.text(error?.text ?? ""), AnsiDoc.annotate(Ansi.red), AnsiDoc.render({ style: "pretty" }));
|
|
206
224
|
return pipe(pipe(Array.findFirstIndex(lines, (l) => pipe(l, String.trim, String.isNonEmpty)), Option.match({
|
|
207
225
|
onNone: () => lines,
|
|
208
|
-
onSome: (
|
|
209
|
-
})), Array.
|
|
226
|
+
onSome: (index) => Array.modify(lines, index, () => redErrorText)
|
|
227
|
+
})), Array.join("\n"));
|
|
210
228
|
};
|
|
211
229
|
const formatBuildErrors = (errors, formattedMessages) => pipe(formattedMessages, Array.map((message, i) => formatBuildError(errors[i], message)), Array.join(""), String.trimEnd);
|
|
212
|
-
var SpecFileDoesNotExportSpecError = class extends Schema.TaggedError(
|
|
213
|
-
var
|
|
230
|
+
var SpecFileDoesNotExportSpecError = class extends Schema.TaggedError()("SpecFileDoesNotExportSpecError", {}) {};
|
|
231
|
+
var NodeSpecFileDoesNotExportSpecError = class extends Schema.TaggedError()("NodeSpecFileDoesNotExportSpecError", {}) {};
|
|
232
|
+
var SpecImportFailedError = class extends Schema.TaggedError()("SpecImportFailedError", { error: Schema.Unknown }) {};
|
|
214
233
|
const syncOptionalFile = (generate, convexFile) => pipe(generate, Effect.andThen(Option.match({
|
|
215
|
-
onSome: ({ change, convexFilePath }) => Match.value(change).pipe(Match.when("Unchanged", () => Effect.
|
|
216
|
-
change: addedOrModified,
|
|
217
|
-
filePath: convexFilePath
|
|
218
|
-
})))), Match.exhaustive),
|
|
234
|
+
onSome: ({ change, convexFilePath }) => Match.value(change).pipe(Match.when("Unchanged", () => Effect.void), Match.whenOr("Added", "Modified", (addedOrModified) => logFileChangeIndented(addedOrModified, convexFilePath)), Match.exhaustive),
|
|
219
235
|
onNone: () => Effect.gen(function* () {
|
|
220
236
|
const fs = yield* FileSystem.FileSystem;
|
|
221
237
|
const path = yield* Path.Path;
|
|
@@ -223,29 +239,38 @@ const syncOptionalFile = (generate, convexFile) => pipe(generate, Effect.andThen
|
|
|
223
239
|
const convexFilePath = path.join(convexDirectory, convexFile);
|
|
224
240
|
if (yield* fs.exists(convexFilePath)) {
|
|
225
241
|
yield* fs.remove(convexFilePath);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
filePath: convexFilePath
|
|
229
|
-
}));
|
|
230
|
-
} else return Option.none();
|
|
242
|
+
yield* logFileChangeIndented("Removed", convexFilePath);
|
|
243
|
+
}
|
|
231
244
|
})
|
|
232
245
|
})));
|
|
233
246
|
const optionalConfectFiles = {
|
|
234
247
|
"http.ts": "httpDirty",
|
|
235
248
|
"app.ts": "appDirty",
|
|
236
249
|
"crons.ts": "cronsDirty",
|
|
237
|
-
"auth.ts": "authDirty"
|
|
250
|
+
"auth.ts": "authDirty",
|
|
251
|
+
"nodeSpec.ts": "specDirty",
|
|
252
|
+
"nodeImpl.ts": "nodeImplDirty"
|
|
238
253
|
};
|
|
239
|
-
const confectDirectoryWatcher = (signal, pendingRef) => Effect.gen(function* () {
|
|
254
|
+
const confectDirectoryWatcher = (signal, pendingRef, specWatcherRestartQueue) => Effect.gen(function* () {
|
|
240
255
|
const fs = yield* FileSystem.FileSystem;
|
|
256
|
+
const path = yield* Path.Path;
|
|
241
257
|
const confectDirectory = yield* ConfectDirectory.get;
|
|
242
|
-
yield* pipe(fs.watch(confectDirectory), Stream.runForEach((event) =>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
258
|
+
yield* pipe(fs.watch(confectDirectory), Stream.runForEach((event) => {
|
|
259
|
+
const basename = path.basename(event.path);
|
|
260
|
+
const pendingKey = optionalConfectFiles[basename];
|
|
261
|
+
if (pendingKey !== void 0) return pipe(pendingRef, Ref.update((pending) => {
|
|
262
|
+
const next = {
|
|
263
|
+
...pending,
|
|
264
|
+
[pendingKey]: true
|
|
265
|
+
};
|
|
266
|
+
if (basename === "nodeImpl.ts") return {
|
|
267
|
+
...next,
|
|
268
|
+
specDirty: true
|
|
269
|
+
};
|
|
270
|
+
return next;
|
|
271
|
+
}), Effect.andThen(Queue.offer(signal, void 0)), Effect.andThen(basename === "nodeSpec.ts" ? Queue.offer(specWatcherRestartQueue, void 0) : Effect.void));
|
|
272
|
+
return Effect.void;
|
|
273
|
+
}));
|
|
249
274
|
});
|
|
250
275
|
|
|
251
276
|
//#endregion
|