Skip to content

Commit acdd378

Browse files
authored
Refactor builder API into a factory + separate types for interface (#1217)
* initial step of refactoring builder API to be created by a factory + the interface in builder/interface * let's just go back to `any` here, this is wonky * builder/interface.ts and builder/schema-to-ts.ts are now together entirely self contained! * lots of types fixes for previous change * more type fixes * remove this syntax for now * remove extraneous parameter for createBuilder * add back ability to set schema with cell/opaqueRef * fix more tests * export opaqueRef directly still, for internal use outside of recipes * partially fix test * import type with `type` annotation * interface is now truly just the public interface. users should only import one or the other * separated imports in other places * fix misaligned exports * removed Mutable from interface * change all recipes to import from /interface. * redo use of SchemaWithoutCell in the right places, this fixed the tests * need Mutable<> after all, so duplicating here to keep interface.ts and schema-tot-ts.ts together standalone * recipe also needs SchemaWithoutCell * and recipe needs that also for the recipe function! * fix recipes * move getRecipeEnvironment to public environment * also exports constants via builder!
1 parent 7519e2c commit acdd378

40 files changed

+952
-610
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ The instructions in this document apply to the entire repository.
3333
- Prefer named exports over default exports.
3434
- Use package names for internal imports.
3535
- Destructure when importing multiple names from the same module.
36+
- Import either from `@commontools/builder` (internal API) or
37+
`@commontools/builder/interface` (external API), but not both.
3638

3739
### Error Handling
3840

packages/builder/deno.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
22
"name": "@commontools/builder",
3-
"exports": "./src/index.ts",
3+
"exports": {
4+
".": "./src/index.ts",
5+
"./interface": "./src/interface.ts"
6+
},
47
"tasks": {
58
"test": "deno test --allow-env"
69
}

packages/builder/src/built-in.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { createNodeFactory, lift } from "./module.ts";
2-
import { type Cell } from "@commontools/runner";
3-
import type { JSONSchema, NodeFactory, Opaque, OpaqueRef } from "./types.ts";
4-
import type { Schema } from "./schema-to-ts.ts";
2+
import type {
3+
Cell,
4+
JSONSchema,
5+
NodeFactory,
6+
Opaque,
7+
OpaqueRef,
8+
Schema,
9+
} from "./types.ts";
510

611
export interface BuiltInLLMParams {
712
messages?: string[];

packages/builder/src/factory.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* Factory function to create builder functions with runtime dependency injection
3+
*/
4+
5+
import type {
6+
BuilderFunctionsAndConstants,
7+
Cell,
8+
CreateCellFunction,
9+
JSONSchema,
10+
} from "./types.ts";
11+
import { AuthSchema, ID, ID_FIELD, NAME, schema, TYPE, UI } from "./types.ts";
12+
import { opaqueRef, stream } from "./opaque-ref.ts";
13+
import { getTopFrame, recipe } from "./recipe.ts";
14+
import { byRef, compute, derive, handler, lift, render } from "./module.ts";
15+
import {
16+
compileAndRun,
17+
fetchData,
18+
ifElse,
19+
llm,
20+
navigateTo,
21+
str,
22+
streamData,
23+
} from "./built-in.ts";
24+
import { getCellLinkOrThrow, type Runtime } from "@commontools/runner";
25+
import { getRecipeEnvironment } from "./env.ts";
26+
27+
/**
28+
* Creates a set of builder functions with the given runtime
29+
* @param runtime - The runtime instance to use for cell creation
30+
* @returns An object containing all builder functions
31+
*/
32+
export const createBuilder = (
33+
runtime: Runtime,
34+
): BuilderFunctionsAndConstants => {
35+
// Implementation of createCell moved from runner/harness
36+
const createCell: CreateCellFunction = function createCell<T = any>(
37+
schema?: JSONSchema,
38+
name?: string,
39+
value?: T,
40+
): Cell<T> {
41+
const frame = getTopFrame();
42+
// This is a rather hacky way to get the context, based on the
43+
// unsafe_binding pattern. Once we replace that mechanism, let's add nicer
44+
// abstractions for context here as well.
45+
const cellLink = frame?.unsafe_binding?.materialize([]);
46+
if (!frame || !frame.cause || !cellLink) {
47+
throw new Error(
48+
"Can't invoke createCell outside of a lifted function or handler",
49+
);
50+
}
51+
if (!getCellLinkOrThrow) {
52+
throw new Error(
53+
"getCellLinkOrThrow function not provided to createBuilder",
54+
);
55+
}
56+
const space = getCellLinkOrThrow(cellLink).cell.space;
57+
58+
const cause = { parent: frame.cause } as Record<string, any>;
59+
if (name) cause.name = name;
60+
else cause.number = frame.generatedIdCounter++;
61+
62+
// Cast to Cell<T> is necessary to cast to interface-only Cell type
63+
const cell = runtime.getCell<T>(space, cause, schema) as Cell<T>;
64+
65+
if (value !== undefined) cell.set(value);
66+
67+
return cell;
68+
} as CreateCellFunction;
69+
70+
return {
71+
// Recipe creation
72+
recipe,
73+
74+
// Module creation
75+
lift,
76+
handler,
77+
derive,
78+
compute,
79+
render,
80+
81+
// Built-in modules
82+
str,
83+
ifElse,
84+
llm,
85+
fetchData,
86+
streamData,
87+
compileAndRun,
88+
navigateTo,
89+
90+
// Cell creation
91+
createCell,
92+
cell: opaqueRef,
93+
stream,
94+
95+
// Utility
96+
byRef,
97+
98+
// Environment
99+
getRecipeEnvironment,
100+
101+
// Constants
102+
ID,
103+
ID_FIELD,
104+
TYPE,
105+
NAME,
106+
UI,
107+
108+
// Schema utilities
109+
schema,
110+
AuthSchema,
111+
};
112+
};

packages/builder/src/index.ts

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
export { opaqueRef as cell, stream } from "./opaque-ref.ts";
2-
export { $, event, select, Spell } from "./spell.ts";
3-
export {
4-
byRef,
5-
compute,
6-
createNodeFactory,
7-
derive,
8-
handler,
9-
lift,
10-
render,
11-
} from "./module.ts";
1+
// Export the factory function
2+
export { createBuilder } from "./factory.ts";
3+
export type {
4+
BuilderFunctionsAndConstants as BuilderFunctions,
5+
BuilderRuntime,
6+
} from "./types.ts";
7+
8+
// Internal functions and exports needed by other packages
129
export {
1310
getRecipeEnvironment,
1411
type RecipeEnvironment,
@@ -19,26 +16,14 @@ export {
1916
popFrame,
2017
pushFrame,
2118
pushFrameFromCause,
22-
recipe,
2319
recipeFromFrame,
2420
} from "./recipe.ts";
25-
export {
26-
type BuiltInCompileAndRunParams,
27-
type BuiltInCompileAndRunState,
28-
type BuiltInLLMParams,
29-
type BuiltInLLMState,
30-
compileAndRun,
31-
type createCell,
32-
fetchData,
33-
ifElse,
34-
llm,
35-
navigateTo,
36-
str,
37-
streamData,
38-
} from "./built-in.ts";
3921
export {
4022
type Alias,
23+
AuthSchema,
24+
type Cell,
4125
type Frame,
26+
type HandlerFactory,
4227
ID,
4328
ID_FIELD,
4429
isAlias,
@@ -54,16 +39,17 @@ export {
5439
markAsStatic,
5540
type Module,
5641
type ModuleFactory,
57-
type Mutable,
5842
NAME,
59-
type Node,
6043
type NodeFactory,
6144
type Opaque,
6245
type OpaqueRef,
6346
type OpaqueRefMethods,
6447
type Recipe,
6548
type RecipeFactory,
66-
type Static,
49+
type Schema,
50+
schema,
51+
type SchemaWithoutCell,
52+
type Stream,
6753
type StreamAlias,
6854
type toJSON,
6955
toOpaqueRef,
@@ -74,8 +60,9 @@ export {
7460
unsafe_parentRecipe,
7561
type UnsafeBinding,
7662
} from "./types.ts";
77-
export { type Schema, schema } from "./schema-to-ts.ts";
78-
export { AuthSchema } from "./schema-lib.ts";
63+
export { createNodeFactory } from "./module.ts";
64+
export { opaqueRef as cell } from "./opaque-ref.ts";
65+
export type { Mutable } from "@commontools/utils/types";
7966

8067
// This should be a separate package, but for now it's easier to keep it here.
8168
export {

0 commit comments

Comments
 (0)