import research docs from prior conversation and scattered sources
This commit is contained in:
101
docs/research/typebox-module-valuepointer.md
Normal file
101
docs/research/typebox-module-valuepointer.md
Normal 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
|
||||
Reference in New Issue
Block a user