Skip to content

Commit e7dfeb0

Browse files
authored
chore(api): Move runtime constant definitions from @commontools/api to @commontools/runner (#2004)
chore(api): Move runtime constant definitions from @commontools/api to @commontools/runner Changed ID, ID_FIELD, TYPE, NAME, and UI from concrete exports to ambient declarations in @commontools/api, getting it closer to being a pure TypeScript interface package. The actual runtime values are now defined in @commontools/runner/src/builder/types.ts, where the runtime environment is created. Type compatibility is maintained by having the runner reference the API's declared types using typeof, ensuring both locations share the same TypeScript symbol types. `schema` and `toSchema` are now being defined in runner as well. `h` is now defined in the `html` package. Non-pattern code like tests or Lit components should import the types from @commontools/runner instead of @commontools/api
1 parent 70e14d6 commit e7dfeb0

File tree

12 files changed

+118
-105
lines changed

12 files changed

+118
-105
lines changed

packages/api/index.ts

Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
* Workspace code should import these types via `@commontools/builder`.
66
*/
77

8-
export const ID: unique symbol = Symbol("ID, unique to the context");
9-
export const ID_FIELD: unique symbol = Symbol(
10-
"ID_FIELD, name of sibling that contains id",
11-
);
8+
// Runtime constants - defined by @commontools/runner/src/builder/types.ts
9+
// These are ambient declarations since the actual values are provided by the runtime environment
10+
export declare const ID: unique symbol;
11+
export declare const ID_FIELD: unique symbol;
1212

1313
// Should be Symbol("UI") or so, but this makes repeat() use these when
1414
// iterating over recipes.
15-
export const TYPE = "$TYPE";
16-
export const NAME = "$NAME";
17-
export const UI = "$UI";
15+
export declare const TYPE: "$TYPE";
16+
export declare const NAME: "$NAME";
17+
export declare const UI: "$UI";
1818

1919
// ============================================================================
2020
// Cell Brand System
@@ -933,6 +933,22 @@ export type CellFunction = <T>(value?: T, schema?: JSONSchema) => OpaqueRef<T>;
933933
export type StreamFunction = <T>(initial?: T) => OpaqueRef<T>;
934934
export type ByRefFunction = <T, R>(ref: string) => ModuleFactory<T, R>;
935935

936+
export type HFunction = {
937+
(
938+
name: string | ((...args: any[]) => VNode),
939+
props: { [key: string]: any } | null,
940+
...children: RenderNode[]
941+
): VNode;
942+
fragment({ children }: { children: RenderNode[] }): VNode;
943+
};
944+
945+
// No-op alternative to `as const as JSONSchema`
946+
export type SchemaFunction = <T extends JSONSchema>(schema: T) => T;
947+
948+
// toSchema is a compile-time transformer that converts TypeScript types to JSONSchema
949+
// The actual implementation is done by the TypeScript transformer
950+
export type ToSchemaFunction = <T>(options?: Partial<JSONSchema>) => JSONSchema;
951+
936952
// Recipe environment types
937953
export interface RecipeEnvironment {
938954
readonly apiUrl: URL;
@@ -965,6 +981,8 @@ export declare const cell: CellFunction;
965981
export declare const stream: StreamFunction;
966982
export declare const byRef: ByRefFunction;
967983
export declare const getRecipeEnvironment: GetRecipeEnvironmentFunction;
984+
export declare const schema: SchemaFunction;
985+
export declare const toSchema: ToSchemaFunction;
968986

969987
/**
970988
* Helper type to recursively remove `readonly` properties from type `T`.
@@ -976,14 +994,6 @@ export type Mutable<T> = T extends ReadonlyArray<infer U> ? Mutable<U>[]
976994
: T extends object ? ({ -readonly [P in keyof T]: Mutable<T[P]> })
977995
: T;
978996

979-
export const schema = <T extends JSONSchema>(schema: T) => schema;
980-
981-
// toSchema is a compile-time transformer that converts TypeScript types to JSONSchema
982-
// The actual implementation is done by the TypeScript transformer
983-
export const toSchema = <T>(_options?: Partial<JSONSchema>): JSONSchema => {
984-
return {} as JSONSchema;
985-
};
986-
987997
// Helper type to transform Cell<T> to Opaque<T> in handler inputs
988998
export type StripCell<T> = T extends Cell<infer U> ? StripCell<U>
989999
: T extends Array<infer U> ? StripCell<U>[]
@@ -1245,42 +1255,6 @@ export type SchemaWithoutCell<
12451255
Depth extends DepthLevel = 9,
12461256
> = SchemaInner<T, Root, Depth, false>;
12471257

1248-
/**
1249-
* Fragment element name used for JSX fragments.
1250-
*/
1251-
const FRAGMENT_ELEMENT = "common-fragment";
1252-
1253-
/**
1254-
* JSX factory function for creating virtual DOM nodes.
1255-
* @param name - The element name or component function
1256-
* @param props - Element properties
1257-
* @param children - Child elements
1258-
* @returns A virtual DOM node
1259-
*/
1260-
export const h = Object.assign(function h(
1261-
name: string | ((...args: any[]) => VNode),
1262-
props: { [key: string]: any } | null,
1263-
...children: RenderNode[]
1264-
): VNode {
1265-
if (typeof name === "function") {
1266-
return name({
1267-
...(props ?? {}),
1268-
children: children.flat(),
1269-
});
1270-
} else {
1271-
return {
1272-
type: "vnode",
1273-
name,
1274-
props: props ?? {},
1275-
children: children.flat(),
1276-
};
1277-
}
1278-
}, {
1279-
fragment({ children }: { children: RenderNode[] }) {
1280-
return h(FRAGMENT_ELEMENT, null, ...children);
1281-
},
1282-
});
1283-
12841258
/**
12851259
* Dynamic properties. Can either be string type (static) or a Mustache
12861260
* variable (dynamic).

packages/html/src/h.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { type HFunction, type RenderNode, type VNode } from "@commontools/api";
2+
3+
/**
4+
* Fragment element name used for JSX fragments.
5+
*/
6+
const FRAGMENT_ELEMENT = "common-fragment";
7+
8+
/**
9+
* JSX factory function for creating virtual DOM nodes.
10+
* @param name - The element name or component function
11+
* @param props - Element properties
12+
* @param children - Child elements
13+
* @returns A virtual DOM node
14+
*/
15+
export const h: HFunction = Object.assign(
16+
function h(
17+
name: string | ((...args: any[]) => VNode),
18+
props: { [key: string]: any } | null,
19+
...children: RenderNode[]
20+
): VNode {
21+
if (typeof name === "function") {
22+
return name({
23+
...(props ?? {}),
24+
children: children.flat(),
25+
});
26+
} else {
27+
return {
28+
type: "vnode",
29+
name,
30+
props: props ?? {},
31+
children: children.flat(),
32+
};
33+
}
34+
},
35+
{
36+
fragment({ children }: { children: RenderNode[] }) {
37+
return h(FRAGMENT_ELEMENT, null, ...children);
38+
},
39+
},
40+
);

packages/html/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export {
88
} from "./render.ts";
99
export { debug, setDebug } from "./logger.ts";
1010
export { isVNode, type VNode } from "./jsx.ts";
11+
export { h } from "./h.ts";

packages/html/src/jsx-dev-runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* @module jsx-dev-runtime
1111
*/
1212

13-
import { h } from "@commontools/api";
13+
import { h } from "./h.ts";
1414
import type { RenderNode, VNode } from "@commontools/api";
1515

1616
/**

packages/html/src/jsx-runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @module jsx-runtime
88
*/
99

10-
import { h } from "@commontools/api";
10+
import { h } from "./h.ts";
1111
import type { RenderNode, VNode } from "@commontools/api";
1212

1313
/**

packages/html/test/html-recipes.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { StorageManager } from "@commontools/runner/storage/cache.deno";
1212
import * as assert from "./assert.ts";
1313
import { Identity } from "@commontools/identity";
14-
import { h } from "@commontools/api";
14+
import { h } from "@commontools/html";
1515

1616
const signer = await Identity.fromPassphrase("test operator");
1717
const space = signer.did();

packages/html/test/render.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { beforeEach, describe, it } from "@std/testing/bdd";
2-
import { h, UI, VNode } from "@commontools/api";
2+
import { UI, VNode } from "@commontools/runner";
33
import { render, renderImpl } from "../src/render.ts";
44
import * as assert from "./assert.ts";
55
import { serializableEvent } from "../src/render.ts";
66
import { MockDoc } from "../src/mock-doc.ts";
7+
import { h } from "../src/h.ts";
78

89
let mock: MockDoc;
910

packages/runner/src/builder/factory.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import type {
66
Cell,
77
CreateCellFunction,
88
JSONSchema,
9+
ToSchemaFunction,
910
} from "./types.ts";
1011
import {
1112
AuthSchema,
12-
h,
1313
ID,
1414
ID_FIELD,
1515
isRecipe,
@@ -18,6 +18,7 @@ import {
1818
TYPE,
1919
UI,
2020
} from "./types.ts";
21+
import { h } from "@commontools/html";
2122
import { opaqueRef, stream } from "./opaque-ref.ts";
2223
import { getTopFrame, recipe } from "./recipe.ts";
2324
import { byRef, compute, derive, handler, lift, render } from "./module.ts";
@@ -40,7 +41,7 @@ import type { IRuntime } from "../runtime.ts";
4041

4142
// Runtime implementation of toSchema - this should never be called
4243
// The TypeScript transformer should replace all calls at compile time
43-
const toSchema = <T>(_options?: Partial<JSONSchema>): JSONSchema => {
44+
const toSchema: ToSchemaFunction = (_options?) => {
4445
throw new Error(
4546
"toSchema() should be transformed at compile time. " +
4647
"Make sure the TypeScript transformer is configured correctly.",

packages/runner/src/builder/types.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import type {
1414
GenerateObjectFunction,
1515
GetRecipeEnvironmentFunction,
1616
HandlerFunction,
17+
HFunction,
18+
ID as IDSymbol,
19+
ID_FIELD as IDFieldSymbol,
1720
IfElseFunction,
1821
JSONSchema,
1922
JSONSchemaObj,
@@ -31,34 +34,35 @@ import type {
3134
RecipeFunction,
3235
RenderFunction,
3336
Schema,
37+
schema as schemaFunction,
3438
StreamDataFunction,
3539
StreamFunction,
3640
StrFunction,
3741
WishFunction,
3842
} from "@commontools/api";
39-
import {
40-
h,
41-
ID,
42-
ID_FIELD,
43-
NAME,
44-
schema,
45-
toSchema,
46-
TYPE,
47-
UI,
48-
} from "@commontools/api";
43+
import { toSchema } from "@commontools/api";
4944
import { AuthSchema } from "./schema-lib.ts";
45+
import {
46+
type IExtendedStorageTransaction,
47+
type MemorySpace,
48+
} from "../storage/interface.ts";
49+
import { type RuntimeProgram } from "../harness/types.ts";
50+
51+
// Define runtime constants here - actual runtime values
52+
export const ID: typeof IDSymbol = Symbol("ID, unique to the context") as any;
53+
export const ID_FIELD: typeof IDFieldSymbol = Symbol(
54+
"ID_FIELD, name of sibling that contains id",
55+
) as any;
56+
57+
// Should be Symbol("UI") or so, but this makes repeat() use these when
58+
// iterating over recipes.
59+
export const TYPE = "$TYPE";
60+
export const NAME = "$NAME";
61+
export const UI = "$UI";
62+
63+
export const schema: typeof schemaFunction = (schema) => schema;
64+
5065
export { AuthSchema } from "./schema-lib.ts";
51-
export {
52-
h,
53-
ID,
54-
ID_FIELD,
55-
NAME,
56-
type Schema,
57-
schema,
58-
toSchema,
59-
TYPE,
60-
UI,
61-
} from "@commontools/api";
6266
export type {
6367
AnyCell,
6468
Cell,
@@ -84,18 +88,15 @@ export type {
8488
Recipe,
8589
RecipeFactory,
8690
RenderNode,
91+
Schema,
8792
SchemaWithoutCell,
8893
Stream,
8994
StripCell,
9095
toJSON,
96+
ToSchemaFunction,
9197
UnwrapCell,
9298
VNode,
9399
} from "@commontools/api";
94-
import {
95-
type IExtendedStorageTransaction,
96-
type MemorySpace,
97-
} from "../storage/interface.ts";
98-
import { type RuntimeProgram } from "../harness/types.ts";
99100

100101
export type JSONSchemaMutable = Mutable<JSONSchemaObj>;
101102

@@ -310,7 +311,7 @@ export interface BuilderFunctionsAndConstants {
310311
AuthSchema: typeof AuthSchema;
311312

312313
// Render utils
313-
h: typeof h;
314+
h: HFunction;
314315
}
315316

316317
// Runtime interface needed by createCell

packages/runner/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ export {
7979
AuthSchema,
8080
type Cell as BuilderCell,
8181
type Frame,
82-
h,
8382
type HandlerFactory,
8483
ID,
8584
ID_FIELD,

0 commit comments

Comments
 (0)