import research docs from prior conversation and scattered sources

This commit is contained in:
2026-04-29 15:11:46 +00:00
parent 9915be2ca6
commit b256fc7eb5
9 changed files with 4274 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
# TypeBox Module & ValuePointer: Core Patterns for UJSX
Source: `/workspace/@alkdev/typebox` (npm: `@alkdev/typebox`)
## TModule: The Schema Registry
`Type.Module()` creates a `TModule` whose `$defs` property is a live `string → TSchema` map. This IS the type registry UJSX needs — no separate registry required.
### Core Operations
```typescript
const UJSX = Type.Module({
Props: Type.Object({ id: Type.Optional(Type.String()) }, { additionalProperties: Type.Unknown() }),
Element: Type.Object({
type: Type.String(),
props: Type.Ref("Props"),
children: Type.Array(Type.Ref("Node")),
}),
Node: Type.Union([Type.String(), Type.Number(), Type.Null(), Type.Ref("Element")]),
})
```
### Read schemas by name
```typescript
import { ValuePointer } from "@alkdev/typebox/value";
ValuePointer.Get(UJSX, "$defs/Props") // TSchema with $id: "Props"
ValuePointer.Get(UJSX, "$defs/Element") // TSchema with $id: "Element"
```
### Add schemas at runtime
```typescript
ValuePointer.Set(UJSX, "$defs/Heading", Type.Object({
type: Type.Literal("heading"),
depth: Type.Number(),
children: Type.Array(Type.Ref("Node")),
}))
// Now UJSX.$defs.Heading exists and Type.Ref("Heading") resolves
```
### Import: Resolved schemas for validation
```typescript
const Element = UJSX.Import("Element")
// Creates TImport with: { [Kind]: 'Import', $defs: { all module defs inlined }, $ref: "Element" }
Value.Check(Element, someData) // Works! All $refs resolved via inlined $defs
```
### Static type inference
```typescript
type UE = Static<typeof Element>
// UE = { type: string; props: { id?: string; [k: string]: unknown }; children: UE[] }
```
The Module's type-level inference handles cycles through `TRef` — no `Type.Recursive` needed.
## How Import Works (from source)
Module source: `/workspace/@alkdev/typebox/src/type/module/index.ts`
```typescript
public Import<Key>(key: Key, options?: SchemaOptions): TImport {
const $defs = { ...this.$defs, [key]: CreateType(this.$defs[key], options) }
return CreateType({ [Kind]: 'Import', $defs, $ref: key })
}
```
Creates a `TImport` schema with:
- `[Kind]: 'Import'` — uniquely identifies as module import
- `$defs` — ALL module definitions copied in (so $refs resolve)
- `$ref: key` — which definition to use as root
## ComputeModuleProperties
Called during Module construction. Walks every property and:
1. Resolves `Type.Ref("X")` → dereferences to actual type at `moduleProperties[X]`
2. Recursively processes: `Type.Array(Type.Ref("Node"))``Type.Array(ResolvedNode)`
3. Handles all TypeBox combinators: Object, Union, Intersect, Function, Record, etc.
4. Adds `$id` to each definition via `WithIdentifiers`
## Function Types in Modules
```typescript
Type.Function([Type.Ref("Props")], Type.Ref("Node"))
```
Creates a JavaScript-extended schema type `{ type: "Function", parameters: [...], returns: {...} }`. Not standard JSON Schema but valid TypeBox. `Value.Check` validates that the value is a function at runtime.
This means component functions CAN be represented in the schema. For serialization, resolve function components to string identifiers before going to mdast/other targets.
## Implications for UJSX v2
1. **No separate type registry needed**`TModule` IS the registry
2. **Schemas ARE types AND tool parameter schemas** — one definition, triple duty
3. **Bi-directional transforms can be schema-driven**`Value.Check(ruleSchema, node)` instead of string matching
4. **Node definitions can be added at runtime** — plugins can extend the IR via `ValuePointer.Set()`
5. **`Import` creates self-contained schemas** — perfect for tool definitions or validation contexts
6. **Function components are first-class in schema** — separate runtime vs serializable representations
7. **No `Type.Recursive` needed in Module** — cycles handle through `TRef` + type-level inference