@confect/cli 8.0.0 → 9.0.0-next.1

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/src/log.ts CHANGED
@@ -5,6 +5,27 @@ import type * as FunctionPath from "./FunctionPath";
5
5
  import * as GroupPath from "./GroupPath";
6
6
  import { ProjectRoot } from "./ProjectRoot";
7
7
 
8
+ // --- Path styling ---
9
+
10
+ /**
11
+ * Render a relative path as an AnsiDoc with the directory portion
12
+ * dimmed (`Ansi.blackBright`) and the file leaf rendered in the
13
+ * default terminal color. Used inline anywhere a file path appears
14
+ * in a CLI message.
15
+ */
16
+ export const formatPathDoc = (relativePath: string): AnsiDoc.AnsiDoc => {
17
+ const lastSep = Math.max(
18
+ relativePath.lastIndexOf("/"),
19
+ relativePath.lastIndexOf("\\"),
20
+ );
21
+ const dir = lastSep < 0 ? "" : relativePath.slice(0, lastSep + 1);
22
+ const leaf = lastSep < 0 ? relativePath : relativePath.slice(lastSep + 1);
23
+ return AnsiDoc.hcat([
24
+ pipe(AnsiDoc.text(dir), AnsiDoc.annotate(Ansi.blackBright)),
25
+ AnsiDoc.text(leaf),
26
+ ]);
27
+ };
28
+
8
29
  // --- File operation logs ---
9
30
 
10
31
  const logFile = (char: string, color: Ansi.Ansi) => (fullPath: string) =>
package/src/templates.ts CHANGED
@@ -1,42 +1,36 @@
1
- import type { Options as CodeBlockWriterOptions } from "code-block-writer";
2
- import CodeBlockWriter_ from "code-block-writer";
3
- import { Array, Effect } from "effect";
4
- import type * as GroupPath from "./GroupPath";
1
+ import { Array, Effect, Option } from "effect";
2
+ import { CodeBlockWriter } from "./CodeBlockWriter";
3
+ import {
4
+ collectImportBindings,
5
+ type SpecAssemblyNode,
6
+ } from "./SpecAssemblyNode";
5
7
 
6
8
  export const functions = ({
7
- groupPath,
8
9
  functionNames,
9
10
  registeredFunctionsImportPath,
10
- registeredFunctionsVariableName = "registeredFunctions",
11
- registeredFunctionsLookupPath,
12
11
  useNode = false,
13
12
  }: {
14
- groupPath: GroupPath.GroupPath;
15
13
  functionNames: string[];
16
14
  registeredFunctionsImportPath: string;
17
- registeredFunctionsVariableName?: string;
18
- registeredFunctionsLookupPath?: readonly string[];
19
15
  useNode?: boolean;
20
16
  }) =>
21
17
  Effect.gen(function* () {
22
18
  const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
23
19
 
24
- const lookupPath = registeredFunctionsLookupPath ?? groupPath.pathSegments;
25
-
26
20
  if (useNode) {
27
21
  yield* cbw.writeLine(`"use node";`);
28
22
  yield* cbw.blankLine();
29
23
  }
30
24
 
31
25
  yield* cbw.writeLine(
32
- `import ${registeredFunctionsVariableName} from "${registeredFunctionsImportPath}";`,
26
+ `import registeredFunctions from "${registeredFunctionsImportPath}";`,
33
27
  );
34
28
  yield* cbw.newLine();
35
- for (const functionName of functionNames) {
36
- yield* cbw.writeLine(
37
- `export const ${functionName} = ${registeredFunctionsVariableName}.${Array.join([...lookupPath, functionName], ".")};`,
38
- );
39
- }
29
+ yield* Effect.forEach(functionNames, (functionName) =>
30
+ cbw.writeLine(
31
+ `export const ${functionName} = registeredFunctions.${functionName};`,
32
+ ),
33
+ );
40
34
 
41
35
  return yield* cbw.toString();
42
36
  });
@@ -92,21 +86,24 @@ export const refs = ({
92
86
  nodeSpecImportPath,
93
87
  }: {
94
88
  specImportPath: string;
95
- nodeSpecImportPath?: string;
89
+ nodeSpecImportPath: Option.Option<string>;
96
90
  }) =>
97
91
  Effect.gen(function* () {
98
92
  const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
99
93
 
100
94
  yield* cbw.writeLine(`import { Refs } from "@confect/core";`);
101
95
  yield* cbw.writeLine(`import spec from "${specImportPath}";`);
102
- if (nodeSpecImportPath !== undefined) {
103
- yield* cbw.writeLine(`import nodeSpec from "${nodeSpecImportPath}";`);
104
- }
96
+ yield* Option.match(nodeSpecImportPath, {
97
+ onNone: () => Effect.void,
98
+ onSome: (nodeSpecImportPath_) =>
99
+ cbw.writeLine(`import nodeSpec from "${nodeSpecImportPath_}";`),
100
+ });
105
101
  yield* cbw.blankLine();
106
102
  yield* cbw.writeLine(
107
- nodeSpecImportPath !== undefined
108
- ? `export default Refs.make(spec, nodeSpec);`
109
- : `export default Refs.make(spec);`,
103
+ Option.match(nodeSpecImportPath, {
104
+ onSome: () => `export default Refs.make(spec, nodeSpec);`,
105
+ onNone: () => `export default Refs.make(spec);`,
106
+ }),
110
107
  );
111
108
 
112
109
  return yield* cbw.toString();
@@ -151,45 +148,43 @@ export const nodeApi = ({
151
148
  return yield* cbw.toString();
152
149
  });
153
150
 
154
- export const registeredFunctions = ({
151
+ export const registeredFunctionsForGroup = ({
152
+ apiImportPath,
153
+ groupPathDot,
155
154
  implImportPath,
155
+ layerExportName,
156
+ useNode = false,
156
157
  }: {
158
+ apiImportPath: string;
159
+ groupPathDot: string;
157
160
  implImportPath: string;
161
+ layerExportName: string;
162
+ useNode?: boolean;
158
163
  }) =>
159
164
  Effect.gen(function* () {
160
165
  const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
161
166
 
162
- yield* cbw.writeLine(
163
- `import { RegisteredConvexFunction, RegisteredFunctions } from "@confect/server";`,
164
- );
165
- yield* cbw.writeLine(`import impl from "${implImportPath}";`);
166
- yield* cbw.blankLine();
167
- yield* cbw.writeLine(
168
- `export default RegisteredFunctions.make(impl, RegisteredConvexFunction.make);`,
169
- );
170
-
171
- return yield* cbw.toString();
172
- });
173
-
174
- export const nodeRegisteredFunctions = ({
175
- nodeImplImportPath,
176
- }: {
177
- nodeImplImportPath: string;
178
- }) =>
179
- Effect.gen(function* () {
180
- const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
167
+ if (useNode) {
168
+ yield* cbw.writeLine(
169
+ `import { RegisteredFunctions } from "@confect/server";`,
170
+ );
171
+ yield* cbw.writeLine(
172
+ `import { RegisteredNodeFunction } from "@confect/server/node";`,
173
+ );
174
+ } else {
175
+ yield* cbw.writeLine(
176
+ `import { RegisteredConvexFunction, RegisteredFunctions } from "@confect/server";`,
177
+ );
178
+ }
181
179
 
182
- yield* cbw.writeLine(
183
- `import { RegisteredFunctions } from "@confect/server";`,
184
- );
185
- yield* cbw.writeLine(
186
- `import { RegisteredNodeFunction } from "@confect/server/node";`,
187
- );
188
- yield* cbw.blankLine();
189
- yield* cbw.writeLine(`import nodeImpl from "${nodeImplImportPath}";`);
180
+ yield* cbw.writeLine(`import api from "${apiImportPath}";`);
181
+ yield* cbw.writeLine(`import ${layerExportName} from "${implImportPath}";`);
190
182
  yield* cbw.blankLine();
183
+ const quotedGroupPath = `"${groupPathDot.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
191
184
  yield* cbw.writeLine(
192
- `export default RegisteredFunctions.make(nodeImpl, RegisteredNodeFunction.make);`,
185
+ useNode
186
+ ? `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredNodeFunction.make);`
187
+ : `export default RegisteredFunctions.buildForGroup(api, ${quotedGroupPath}, ${layerExportName}, RegisteredConvexFunction.make);`,
193
188
  );
194
189
 
195
190
  return yield* cbw.toString();
@@ -382,64 +377,106 @@ export const services = ({ schemaImportPath }: { schemaImportPath: string }) =>
382
377
  return yield* cbw.toString();
383
378
  });
384
379
 
385
- class CodeBlockWriter {
386
- private readonly writer: CodeBlockWriter_;
387
-
388
- constructor(opts?: Partial<CodeBlockWriterOptions>) {
389
- this.writer = new CodeBlockWriter_(opts);
390
- }
391
-
392
- indent<E = never, R = never>(
393
- eff: Effect.Effect<void, E, R>,
394
- ): Effect.Effect<void, E, R> {
395
- return Effect.gen(this, function* () {
396
- const indentationLevel = this.writer.getIndentationLevel();
397
- this.writer.setIndentationLevel(indentationLevel + 1);
398
- yield* eff;
399
- this.writer.setIndentationLevel(indentationLevel);
400
- });
401
- }
380
+ const writeChildAddGroupAt = (
381
+ cbw: CodeBlockWriter,
382
+ child: SpecAssemblyNode,
383
+ groupFactory: string,
384
+ ): Effect.Effect<void> =>
385
+ Effect.gen(function* () {
386
+ yield* cbw.write(".addGroupAt(");
387
+ yield* cbw.quote(child.segment);
388
+ yield* cbw.write(", ");
389
+ yield* writeGroupAssembly(cbw, child, groupFactory);
390
+ yield* cbw.write(")");
391
+ });
402
392
 
403
- writeLine<E = never, R = never>(line: string): Effect.Effect<void, E, R> {
404
- return Effect.sync(() => {
405
- this.writer.writeLine(line);
406
- });
407
- }
393
+ const writeGroupFactoryCall = (
394
+ cbw: CodeBlockWriter,
395
+ node: SpecAssemblyNode,
396
+ groupFactory: string,
397
+ ): Effect.Effect<void> =>
398
+ Effect.gen(function* () {
399
+ yield* cbw.write(groupFactory);
400
+ yield* cbw.write("(");
401
+ yield* cbw.quote(node.segment);
402
+ yield* cbw.write(")");
408
403
 
409
- write<E = never, R = never>(text: string): Effect.Effect<void, E, R> {
410
- return Effect.sync(() => {
411
- this.writer.write(text);
412
- });
413
- }
404
+ yield* Effect.forEach(node.children, (child) =>
405
+ writeChildAddGroupAt(cbw, child, groupFactory),
406
+ );
407
+ });
414
408
 
415
- quote<E = never, R = never>(text: string): Effect.Effect<void, E, R> {
416
- return Effect.sync(() => {
417
- this.writer.quote(text);
418
- });
419
- }
420
-
421
- conditionalWriteLine<E = never, R = never>(
422
- condition: boolean,
423
- text: string,
424
- ): Effect.Effect<void, E, R> {
425
- return Effect.sync(() => {
426
- this.writer.conditionalWriteLine(condition, text);
427
- });
428
- }
409
+ const writeGroupAssembly: (
410
+ cbw: CodeBlockWriter,
411
+ node: SpecAssemblyNode,
412
+ groupFactory: string,
413
+ ) => Effect.Effect<void> = (cbw, node, groupFactory) =>
414
+ Option.match(node.importBinding, {
415
+ onNone: () => writeGroupFactoryCall(cbw, node, groupFactory),
416
+ onSome: (binding) =>
417
+ Effect.gen(function* () {
418
+ yield* cbw.write(binding.exportName);
419
+ yield* Effect.forEach(node.children, (child) =>
420
+ writeChildAddGroupAt(cbw, child, groupFactory),
421
+ );
422
+ }),
423
+ });
429
424
 
430
- newLine<E = never, R = never>(): Effect.Effect<void, E, R> {
431
- return Effect.sync(() => {
432
- this.writer.newLine();
433
- });
434
- }
425
+ const writeRootAddAt = (
426
+ cbw: CodeBlockWriter,
427
+ node: SpecAssemblyNode,
428
+ groupFactory: string,
429
+ ): Effect.Effect<void> =>
430
+ Effect.gen(function* () {
431
+ yield* cbw.write(".addAt(");
432
+ yield* cbw.quote(node.segment);
433
+ yield* cbw.write(", ");
435
434
 
436
- blankLine<E = never, R = never>(): Effect.Effect<void, E, R> {
437
- return Effect.sync(() => {
438
- this.writer.blankLine();
439
- });
440
- }
435
+ yield* writeGroupAssembly(cbw, node, groupFactory);
436
+
437
+ yield* cbw.write(")");
438
+ });
441
439
 
442
- toString<E = never, R = never>(): Effect.Effect<string, E, R> {
443
- return Effect.sync(() => this.writer.toString());
444
- }
445
- }
440
+ export const assembledSpec = ({
441
+ nodes,
442
+ runtime,
443
+ }: {
444
+ nodes: ReadonlyArray<SpecAssemblyNode>;
445
+ runtime: "Convex" | "Node";
446
+ }) =>
447
+ Effect.gen(function* () {
448
+ const cbw = new CodeBlockWriter({ indentNumberOfSpaces: 2 });
449
+
450
+ const nodeRequiresGroupFactory = (node: SpecAssemblyNode): boolean =>
451
+ Option.isNone(node.importBinding) ||
452
+ Array.some(node.children, nodeRequiresGroupFactory);
453
+
454
+ const needsGroupSpec = Array.some(nodes, nodeRequiresGroupFactory);
455
+ yield* cbw.writeLine(
456
+ needsGroupSpec
457
+ ? `import { GroupSpec, Spec } from "@confect/core";`
458
+ : `import { Spec } from "@confect/core";`,
459
+ );
460
+
461
+ yield* Effect.forEach(collectImportBindings(nodes), (binding) =>
462
+ cbw.writeLine(
463
+ `import ${binding.exportName} from "${binding.importPath}";`,
464
+ ),
465
+ );
466
+
467
+ yield* cbw.blankLine();
468
+
469
+ const specFactory =
470
+ runtime === "Convex" ? "Spec.make()" : "Spec.makeNode()";
471
+ const groupFactory =
472
+ runtime === "Convex" ? "GroupSpec.makeAt" : "GroupSpec.makeNodeAt";
473
+
474
+ yield* cbw.write(`export default ${specFactory}`);
475
+ yield* Effect.forEach(nodes, (node) =>
476
+ writeRootAddAt(cbw, node, groupFactory),
477
+ );
478
+ yield* cbw.write(";");
479
+ yield* cbw.newLine();
480
+
481
+ return yield* cbw.toString();
482
+ });