@mark1russell7/render-node 0.0.0-stage → 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["hasOwn"],"sources":["../src/equality.ts","../src/ops.ts","../src/engine.ts","../src/writes.ts","../src/toposort.ts"],"sourcesContent":["/**\n * Structural equality for node values.\n *\n * With reference equality only, each expression that makes an object is always dirty: each evaluation\n * gives a new object, and each epoch propagates it. Node values are plain data, thus the default is structural:\n *\n * - `Object.is` for primitives, thus `NaN` is equal to `NaN`.\n * - Element by element for arrays, own key by own key for plain objects.\n * - An exotic object (a class instance, a function, a React element) is equal only to itself.\n * - Below `MAX_DEPTH` levels, two values are not equal. This limit also stops a cyclic value.\n */\n\nconst MAX_DEPTH = 32;\n\nconst hasOwn = (o: object, key: string): boolean => Object.prototype.hasOwnProperty.call(o, key);\n\n/** This function tells if a value is a plain object: its prototype is `Object.prototype` or `null`. */\nexport const isPlainObject = (v: unknown): v is Record<string, unknown> => {\n if (v === null || typeof v !== \"object\") return false;\n const proto: unknown = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n};\n\nconst eq = (a: unknown, b: unknown, depth: number): boolean => {\n if (Object.is(a, b)) return true;\n if (depth >= MAX_DEPTH) return false;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!eq(a[i], b[i], depth + 1)) return false;\n }\n return true;\n }\n\n if (!isPlainObject(a) || !isPlainObject(b)) return false;\n const keysA = Object.keys(a);\n if (keysA.length !== Object.keys(b).length) return false;\n for (const k of keysA) {\n if (!hasOwn(b, k) || !eq(a[k], b[k], depth + 1)) return false;\n }\n return true;\n};\n\n/** This function compares two node values structurally. The module comment gives the rules. */\nexport const valueEquals = (a: unknown, b: unknown): boolean => eq(a, b, 0);\n","import { some, none, isSome } from \"@mark1russell7/render-optional\";\nimport type { DerefFn, FlowFn, Node, NodeOps, SplashFn, TargetsFn } from \"./types.ts\";\nimport { valueEquals } from \"./equality.ts\";\n\nconst hasOwn = (o: object, key: string): boolean => Object.prototype.hasOwnProperty.call(o, key);\n\n/**\n * The default write. It keeps the old value when the new result is structurally equal, thus an equal\n * object keeps its old reference. A change from a value to `none`, or from `none` to a value, is a change.\n */\nexport const defaultSplash: SplashFn = (value, target) => {\n const prev = target.value;\n if (isSome(prev) ? isSome(value) && valueEquals(prev.value, value.value) : !isSome(value)) return false;\n target.value = value;\n return true;\n};\n\n/** The default propagation. A change of a node makes its value readers dirty. */\nexport const defaultFlow: FlowFn = (target) => target.seats;\n\n/**\n * The default resolution. It goes through slots as far as they exist, then through the own fields of the value.\n * A path that ends on a node gives the value of that node. For a container, this value is the record of its slots.\n * A path that stops at a container before its end reads a missing slot, thus it gives `none`.\n */\nexport const defaultDeref: DerefFn = (root, path, store) => {\n let current = root;\n let i = 0;\n while (i < path.length) {\n const slotId = current.slots.get(path[i]!);\n if (slotId === undefined) break;\n const next = store.nodes.get(slotId);\n if (!next) break;\n current = next;\n i++;\n }\n if (i < path.length && current.slots.size > 0) return none;\n if (!isSome(current.value)) return none;\n let value: unknown = current.value.value;\n for (; i < path.length; i++) {\n const segment = path[i]!;\n if (value === null || typeof value !== \"object\" || !hasOwn(value, segment)) return none;\n value = (value as Record<string, unknown>)[segment];\n }\n return some(value);\n};\n\n/**\n * The default dependencies of a path, which agree with `defaultDeref`. The nodes that the path goes through are\n * structural targets, and the node where it ends is the terminal. A path that stops at a container before its end\n * reads a missing slot: it has no terminal, and the container is a structural target.\n */\nexport const defaultTargets: TargetsFn = (root, path, store) => {\n const through: Node[] = [];\n let current = root;\n let i = 0;\n for (; i < path.length; i++) {\n const slotId = current.slots.get(path[i]!);\n const next = slotId === undefined ? undefined : store.nodes.get(slotId);\n if (!next) break;\n through.push(current);\n current = next;\n }\n if (i < path.length && current.slots.size > 0) return { through: [...through, current], terminal: undefined };\n return { through, terminal: current };\n};\n\n/** The default semantics of a store. */\nexport const defaultOps: NodeOps = {\n splash: defaultSplash,\n flow: defaultFlow,\n deref: defaultDeref,\n targets: defaultTargets,\n};\n","/**\n * The internal state of a store and the epoch machine. The public operations are in `writes.ts`.\n *\n * Each write changes the structure at once and marks the nodes that it touched. A flush then rewires\n * the touched nodes and starts one epoch over them. Outside a batch, each write flushes at its end.\n */\nimport type { DepPath, Expr, Ops, Resolver } from \"@mark1russell7/render-dsl\";\nimport { deps, evaluate, lit, ref } from \"@mark1russell7/render-dsl\";\nimport type { Optional } from \"@mark1russell7/render-optional\";\nimport { isSome, none, some } from \"@mark1russell7/render-optional\";\nimport type { EpochStats, Node, NodeId, NodeOps, NodeStore } from \"./types.ts\";\nimport { isPlainObject } from \"./equality.ts\";\n\n/** The mutable form of a node. Only the engine sees it. */\nexport type MutableNode = {\n readonly id: NodeId;\n expr: Expr;\n value: Optional<unknown>;\n reads: readonly DepPath[];\n readonly seats: Set<NodeId>;\n readonly seatsStructural: Set<NodeId>;\n readonly seatedOn: Set<NodeId>;\n parent: NodeId | undefined;\n readonly heldBy: Set<NodeId>;\n readonly slots: Map<string, NodeId>;\n /** True when a read of this node waits in `dangling`. */\n dangles: boolean;\n // The scratch fields of the epoch machine. They are valid only when `mark` is the current epoch.\n mark: number;\n dirty: number;\n index: number;\n low: number;\n onStack: boolean;\n next: MutableNode[] | null;\n};\n\n/** The work that the next flush does. */\ntype Pending = {\n /** The nodes to rewire and to evaluate. */\n readonly touched: Set<NodeId>;\n /** The containers whose record expression to make again from their slots. */\n readonly records: Set<NodeId>;\n /** The nodes to expand after the epoch, because a batch asked for an expansion of a value that was not settled. */\n readonly expansions: Set<NodeId>;\n};\n\n/** The full state of a store. `nodeStore` makes it, and the public type `NodeStore` shows a part of it. */\nexport type StoreState = {\n readonly nodes: Map<NodeId, MutableNode>;\n readonly nodeOps: NodeOps;\n readonly ops: Ops;\n epochStats: EpochStats | null;\n nextId: number;\n /** For each node ID that is not in the store: the readers whose path starts at it. */\n readonly dangling: Map<NodeId, Set<NodeId>>;\n pending: Pending | null;\n batchDepth: number;\n /** The counter of epochs. The scratch fields of a node use it as a stamp. */\n epoch: number;\n};\n\n/** This function gives the internal state of a store. All stores come from `makeState`. */\nexport const state = (store: NodeStore): StoreState => store as unknown as StoreState;\n\n/** This function gives the public view of a state. */\nexport const publicStore = (s: StoreState): NodeStore => s;\n\n/** This function makes the state of an empty store. */\nexport const makeState = (nodeOps: NodeOps, ops: Ops): StoreState => ({\n nodes: new Map(),\n nodeOps,\n ops,\n epochStats: null,\n nextId: 0,\n dangling: new Map(),\n pending: null,\n batchDepth: 0,\n epoch: 0,\n});\n\n/** This function makes a node that is not in a store yet. */\nexport const makeNode = (id: NodeId, expr: Expr): MutableNode => ({\n id,\n expr,\n value: none,\n reads: deps(expr),\n seats: new Set(),\n seatsStructural: new Set(),\n seatedOn: new Set(),\n parent: undefined,\n heldBy: new Set(),\n slots: new Map(),\n dangles: false,\n mark: 0,\n dirty: 0,\n index: -1,\n low: -1,\n onStack: false,\n next: null,\n});\n\n/**\n * This function gives an ID that no node of the store has. It uses the hint when the hint is free.\n * Without a hint, the IDs have the form `n_<number>`, with a counter for each store.\n */\nexport const freshId = (s: StoreState, hint?: string): NodeId => {\n if (hint !== undefined && !s.nodes.has(hint)) return hint;\n const base = hint ?? \"n\";\n for (;;) {\n const id = `${base}${hint === undefined ? \"_\" : \"~\"}${String(s.nextId++)}`;\n if (!s.nodes.has(id)) return id;\n }\n};\n\n/** This function makes the `record` expression of a container: one field for each slot. */\nexport const recordOf = (n: MutableNode): Expr => {\n const args: Expr[] = [];\n for (const name of n.slots.keys()) args.push(lit(name), ref(n.id, name));\n return { tag: \"app\", op: \"record\", args };\n};\n\n/** This function tells if the expression of a container is the record of its current slots. */\nconst isRecordOf = (n: MutableNode): boolean => {\n const e = n.expr;\n if (e.tag !== \"app\" || e.op !== \"record\" || e.args.length !== 2 * n.slots.size) return false;\n let i = 0;\n for (const name of n.slots.keys()) {\n const k = e.args[i++]!;\n const r = e.args[i++]!;\n if (k.tag !== \"lit\" || k.value !== name) return false;\n if (r.tag !== \"ref\" || r.path.length !== 2 || r.path[0] !== n.id || r.path[1] !== name) return false;\n }\n return true;\n};\n\n// === Slots ===\n\n/** This function points a slot at a node and records the container in `heldBy` of the node. */\nexport const linkSlot = (container: MutableNode, name: string, child: MutableNode): void => {\n container.slots.set(name, child.id);\n child.heldBy.add(container.id);\n};\n\n/** This function removes a slot. The target forgets the container when no other slot of the container points at it. */\nexport const unlinkSlot = (s: StoreState, container: MutableNode, name: string): void => {\n const target = container.slots.get(name);\n container.slots.delete(name);\n if (target === undefined) return;\n for (const other of container.slots.values()) if (other === target) return;\n s.nodes.get(target)?.heldBy.delete(container.id);\n};\n\n// === Wiring ===\n\n/**\n * This function gives the chain of nodes that a read path goes through. The chain starts at the root\n * (`path[0]`, a node ID) and follows slots as far as they exist. The last node is the terminal: the path\n * reads its value. The function gives an empty chain when the root is not in the store.\n */\nexport const readTargets = (nodes: ReadonlyMap<NodeId, Node>, path: DepPath): Node[] => {\n const rootId = path[0];\n const root = rootId === undefined ? undefined : nodes.get(rootId);\n if (!root) return [];\n const out: Node[] = [root];\n let current = root;\n for (let i = 1; i < path.length; i++) {\n const slotId = current.slots.get(path[i]!);\n const next = slotId === undefined ? undefined : nodes.get(slotId);\n if (!next) break;\n current = next;\n out.push(current);\n }\n return out;\n};\n\n/**\n * This function seats a node on the targets of its reads (the `targets` op of the store). The terminal gets a\n * value seat, and each node that the path goes through gets a structural seat. A read whose root is not in the\n * store waits in `dangling`. A missing slot of a container has no terminal. Thus a container cannot be on a\n * false cycle with a reader of one of its missing slots.\n */\nexport const wireNode = (s: StoreState, n: MutableNode): void => {\n for (const path of n.reads) {\n const rootId = path[0];\n const root = rootId === undefined ? undefined : s.nodes.get(rootId);\n if (!root) {\n if (rootId !== undefined) {\n let waiting = s.dangling.get(rootId);\n if (!waiting) s.dangling.set(rootId, (waiting = new Set()));\n waiting.add(n.id);\n n.dangles = true;\n }\n continue;\n }\n const targets = s.nodeOps.targets(root, path.slice(1), publicStore(s));\n for (const t of targets.through) {\n const m = s.nodes.get(t.id);\n if (!m || m === n) continue;\n m.seatsStructural.add(n.id);\n n.seatedOn.add(m.id);\n }\n const terminal = targets.terminal === undefined ? undefined : s.nodes.get(targets.terminal.id);\n if (terminal && terminal !== n) {\n terminal.seats.add(n.id);\n n.seatedOn.add(terminal.id);\n }\n }\n};\n\n/** This function removes a node from each seat set that holds it, and from `dangling`. */\nexport const unwireNode = (s: StoreState, n: MutableNode): void => {\n if (n.seatedOn.size > 0) {\n for (const otherId of n.seatedOn) {\n const other = s.nodes.get(otherId);\n if (other) {\n other.seats.delete(n.id);\n other.seatsStructural.delete(n.id);\n }\n }\n n.seatedOn.clear();\n }\n if (n.dangles) {\n for (const path of n.reads) {\n const head = path[0];\n const waiting = head === undefined ? undefined : s.dangling.get(head);\n if (waiting) {\n waiting.delete(n.id);\n if (waiting.size === 0) s.dangling.delete(head!);\n }\n }\n n.dangles = false;\n }\n};\n\n/** This function changes the expression of a node and keeps its reads correct. The caller touches the node. */\nexport const replaceExpr = (s: StoreState, n: MutableNode, expr: Expr): void => {\n unwireNode(s, n);\n n.expr = expr;\n n.reads = deps(expr);\n};\n\n// === Pending work, batches and the flush ===\n\nconst pending = (s: StoreState): Pending =>\n (s.pending ??= { touched: new Set(), records: new Set(), expansions: new Set() });\n\n/** This function marks a node for the next flush: rewire and evaluate. */\nexport const touch = (s: StoreState, id: NodeId): void => {\n pending(s).touched.add(id);\n};\n\n/** This function marks a container: the next flush makes its record expression again. */\nexport const touchRecord = (s: StoreState, id: NodeId): void => {\n pending(s).records.add(id);\n};\n\n/** This function marks a node for an expansion after the next epoch, when its value is settled. */\nexport const touchExpansion = (s: StoreState, id: NodeId): void => {\n pending(s).expansions.add(id);\n};\n\n/** This function adds a node to the store. Readers that waited for its ID get rewired. */\nexport const insertNode = (s: StoreState, n: MutableNode): void => {\n s.nodes.set(n.id, n);\n touch(s, n.id);\n const waiting = s.dangling.get(n.id);\n if (waiting) {\n for (const r of waiting) touch(s, r);\n s.dangling.delete(n.id);\n }\n};\n\n/**\n * This function expands a node with a settled value. Each field of a plain object becomes an owned\n * slot, and a field that is a plain object becomes a container in turn. A field that holds one of its own\n * ancestors stays a leaf, thus a cyclic object gives a finite tree. The caller flushes.\n * The build uses its own stack, not the call stack, thus a deep value does not overflow it.\n */\nexport const expandNow = (s: StoreState, id: NodeId): void => {\n const n = s.nodes.get(id);\n const value = n && isSome(n.value) ? n.value.value : undefined;\n if (!n || n.slots.size > 0 || !isPlainObject(value)) return;\n type Frame = { readonly owner: MutableNode; readonly value: object; readonly fields: [string, unknown][]; next: number };\n // The objects on the path from the root to the current field\n const ancestors = new Set<object>([value]);\n const frames: Frame[] = [{ owner: n, value, fields: Object.entries(value), next: 0 }];\n for (let frame = frames.at(-1); frame !== undefined; frame = frames.at(-1)) {\n const field = frame.fields[frame.next++];\n if (field === undefined) {\n frames.pop();\n ancestors.delete(frame.value);\n // A container gets its record after its fields, thus the records go from the leaves to the root\n if (frame.owner !== n) touchRecord(s, frame.owner.id);\n continue;\n }\n const [key, fieldValue] = field;\n const sub = makeNode(freshId(s, `${frame.owner.id}.${key}`), lit(fieldValue));\n sub.parent = frame.owner.id;\n sub.value = some(fieldValue);\n insertNode(s, sub);\n linkSlot(frame.owner, key, sub);\n if (isPlainObject(fieldValue) && !ancestors.has(fieldValue)) {\n ancestors.add(fieldValue);\n frames.push({ owner: sub, value: fieldValue, fields: Object.entries(fieldValue), next: 0 });\n }\n }\n touchRecord(s, n.id);\n for (const r of n.seats) touch(s, r);\n for (const r of n.seatsStructural) touch(s, r);\n};\n\n/** This function does the pending work at once, except inside a batch. */\nexport const flushUnlessBatched = (s: StoreState): void => {\n if (s.batchDepth === 0) flush(s);\n};\n\n/**\n * This function makes `fn` one transaction: the pending work of all its writes becomes one epoch at the end.\n * When `fn` throws, the flush still does the pending work, and the error of `fn` is the error of the batch.\n */\nexport const runBatch = <T>(s: StoreState, fn: () => T): T => {\n s.batchDepth++;\n let result: T;\n try {\n result = fn();\n } catch (error) {\n s.batchDepth--;\n if (s.batchDepth === 0) {\n try {\n flush(s);\n } catch {\n // The error of fn is the cause. An error of the flush comes after it, thus the batch keeps the first one.\n }\n }\n throw error;\n }\n s.batchDepth--;\n if (s.batchDepth === 0) flush(s);\n return result;\n};\n\n/** The limit of follow-up epochs in one flush. Only a custom op that writes on each epoch reaches it. */\nconst MAX_FOLLOW_UPS = 1000;\n\n/** The error of an op during an epoch, with the dirty nodes that the epoch did not evaluate. */\nclass EpochFailure {\n readonly retry: ReadonlySet<NodeId>;\n readonly cause: unknown;\n constructor(retry: ReadonlySet<NodeId>, cause: unknown) {\n this.retry = retry;\n this.cause = cause;\n }\n}\n\n/**\n * This function does the pending work. A custom op can write during an epoch. That write does not go into\n * the epoch: it becomes pending, and the flush does it in a follow-up epoch. The stats join all epochs.\n *\n * When an op throws, the dirty nodes that the epoch did not evaluate stay pending. The next flush evaluates them,\n * and the error goes to the caller. A throw before the evaluation, for example of a custom `targets` or `flow`\n * op, keeps all the work of the round pending.\n */\nconst flush = (s: StoreState): void => {\n let stats: { evaluated: Set<NodeId>; changed: Set<NodeId>; cyclic: Set<NodeId> } | null = null;\n s.batchDepth++;\n try {\n for (let round = 0; s.pending; round++) {\n if (round > MAX_FOLLOW_UPS) {\n s.pending = null;\n throw new Error(`The epochs did not settle after ${String(MAX_FOLLOW_UPS)} follow-ups: an op writes on each epoch.`);\n }\n const p = s.pending;\n s.pending = null;\n let epoch: { evaluated: Set<NodeId>; changed: Set<NodeId>; cyclic: Set<NodeId> };\n try {\n for (const id of p.records) {\n const n = s.nodes.get(id);\n if (!n) continue;\n if (!isRecordOf(n)) replaceExpr(s, n, recordOf(n));\n p.touched.add(id);\n }\n for (const id of p.touched) {\n const n = s.nodes.get(id);\n if (!n) continue;\n unwireNode(s, n);\n wireNode(s, n);\n }\n epoch = runEpoch(s, p.touched);\n } catch (failure) {\n if (failure instanceof EpochFailure) {\n for (const id of failure.retry) touch(s, id);\n for (const id of p.expansions) touchExpansion(s, id);\n throw failure.cause;\n }\n // The wiring or the closure failed, thus no node evaluated: the full round stays pending\n for (const id of p.records) touchRecord(s, id);\n for (const id of p.touched) touch(s, id);\n for (const id of p.expansions) touchExpansion(s, id);\n throw failure;\n }\n if (!stats) stats = epoch;\n else {\n for (const id of epoch.evaluated) stats.evaluated.add(id);\n for (const id of epoch.changed) stats.changed.add(id);\n for (const id of epoch.cyclic) stats.cyclic.add(id);\n }\n // An expansion inside a batch waits for the settled value. It makes new pending work: a follow-up epoch.\n for (const id of p.expansions) expandNow(s, id);\n }\n } finally {\n s.batchDepth--;\n }\n s.epochStats = {\n evaluated: stats?.evaluated ?? new Set(),\n changed: stats?.changed ?? new Set(),\n cyclic: stats?.cyclic ?? new Set(),\n total: s.nodes.size,\n };\n};\n\n// === The epoch ===\n\n/** This function makes the resolver that the expressions of a store use: `path[0]` is a node ID. */\nexport const resolverOf = (store: NodeStore): Resolver => (path) => {\n const rootId = path[0];\n const root = rootId === undefined ? undefined : store.nodes.get(rootId);\n return root ? store.nodeOps.deref(root, path.length === 1 ? [] : path.slice(1), store) : none;\n};\n\n/**\n * The limit of the rounds of a cycle in one epoch. Like the iterative calculation of a spreadsheet, the members\n * of a cycle evaluate again until their values are stable, or until this limit.\n */\nexport const MAX_CYCLE_ROUNDS = 100;\n\n/**\n * This function gives the strongly connected components of the closure (Tarjan, without recursion).\n * Tarjan gives each component after all components that it reaches. Thus the reverse list is a topological\n * order of the components, and each node comes after its inputs.\n */\nconst components = (closure: readonly MutableNode[]): MutableNode[][] => {\n const out: MutableNode[][] = [];\n const stack: MutableNode[] = [];\n let counter = 0;\n for (const start of closure) {\n if (start.index !== -1) continue;\n const frames: { readonly node: MutableNode; next: number }[] = [];\n const open = (v: MutableNode): void => {\n v.index = v.low = counter++;\n v.onStack = true;\n stack.push(v);\n frames.push({ node: v, next: 0 });\n };\n open(start);\n while (frames.length > 0) {\n const frame = frames[frames.length - 1]!;\n const v = frame.node;\n const successors = v.next!;\n if (frame.next < successors.length) {\n const w = successors[frame.next++]!;\n if (w.index === -1) open(w);\n else if (w.onStack) v.low = Math.min(v.low, w.index);\n continue;\n }\n frames.pop();\n const parent = frames[frames.length - 1];\n if (parent) parent.node.low = Math.min(parent.node.low, v.low);\n if (v.low === v.index) {\n const component: MutableNode[] = [];\n let w: MutableNode;\n do {\n w = stack.pop()!;\n w.onStack = false;\n component.push(w);\n } while (w !== v);\n out.push(component);\n }\n }\n }\n return out.toReversed();\n};\n\n/**\n * One epoch. The engine finds the closure of the frontier through `flow`, and it orders the strongly connected\n * components of the closure topologically. Then it evaluates each dirty node in that order, thus each node\n * reads settled values. A node is dirty when it is in the frontier or when one of its inputs changed.\n *\n * A node outside a cycle evaluates at most one time. The members of a cycle (a component with more than one\n * node) evaluate again while one of them changes, up to `MAX_CYCLE_ROUNDS` rounds. The stats report them.\n * The machine keeps its state in the scratch fields of the nodes, with the epoch number as a stamp.\n */\nconst runEpoch = (\n s: StoreState,\n frontier: ReadonlySet<NodeId>,\n): { evaluated: Set<NodeId>; changed: Set<NodeId>; cyclic: Set<NodeId> } => {\n const store = publicStore(s);\n const epoch = ++s.epoch;\n\n // 1. The closure: the nodes that the frontier can reach. Each node gets its successors one time.\n const closure: MutableNode[] = [];\n const stack: MutableNode[] = [];\n const enter = (n: MutableNode): void => {\n n.mark = epoch;\n n.index = -1;\n n.low = -1;\n n.onStack = false;\n n.next = null;\n stack.push(n);\n };\n for (const id of frontier) {\n const n = s.nodes.get(id);\n if (n && n.mark !== epoch) {\n enter(n);\n n.dirty = epoch;\n }\n }\n while (stack.length > 0) {\n const n = stack.pop()!;\n closure.push(n);\n const next: MutableNode[] = [];\n for (const id of s.nodeOps.flow(n, store)) {\n const m = s.nodes.get(id);\n if (!m || m === n) continue;\n next.push(m);\n if (m.mark !== epoch) enter(m);\n }\n n.next = next;\n }\n\n // 2. The order: the components, with each component after its inputs\n const order = components(closure);\n\n // 3. The evaluation of the dirty nodes, in order\n const resolver = resolverOf(store);\n const evaluated = new Set<NodeId>();\n const changed = new Set<NodeId>();\n const cyclic = new Set<NodeId>();\n const evaluateNode = (n: MutableNode): boolean => {\n n.dirty = 0;\n evaluated.add(n.id);\n if (!s.nodeOps.splash(evaluate(n.expr, resolver, s.ops), n, store)) return false;\n changed.add(n.id);\n for (const m of n.next!) m.dirty = epoch;\n return true;\n };\n let position = 0;\n try {\n for (; position < order.length; position++) {\n const component = order[position]!;\n if (component.length === 1) {\n const n = component[0]!;\n if (n.dirty === epoch) evaluateNode(n);\n continue;\n }\n for (const n of component) cyclic.add(n.id);\n for (let round = 0; round < MAX_CYCLE_ROUNDS; round++) {\n let any = false;\n for (const n of component) if (n.dirty === epoch && evaluateNode(n)) any = true;\n if (!any) break;\n }\n }\n } catch (cause) {\n const retry = new Set<NodeId>();\n for (let i = position; i < order.length; i++) {\n for (const n of order[i]!) if (n.dirty === epoch || i === position) retry.add(n.id);\n }\n for (const n of closure) n.next = null;\n throw new EpochFailure(retry, cause);\n }\n for (const n of closure) n.next = null;\n return { evaluated, changed, cyclic };\n};\n","/**\n * The public operations of a store. Each operation keeps the store consistent. At the end of the operation, or after\n * the end of the enclosing batch, the value of each node agrees with its expression.\n * The seats agree with the reads too. `store.epochStats` records the epoch of the last operation.\n */\nimport type { Expr, ExprDocument } from \"@mark1russell7/render-dsl\";\nimport { asExpr, lit } from \"@mark1russell7/render-dsl\";\nimport type { Optional } from \"@mark1russell7/render-optional\";\nimport { none } from \"@mark1russell7/render-optional\";\nimport type { Node, NodeId, NodeStore, StoreOptions } from \"./types.ts\";\nimport type { MutableNode, StoreState } from \"./engine.ts\";\nimport {\n expandNow, flushUnlessBatched, freshId, insertNode, linkSlot, makeNode, makeState, publicStore, replaceExpr,\n runBatch, state, touch, touchExpansion, touchRecord, unlinkSlot, unwireNode,\n} from \"./engine.ts\";\nimport { defaultOps } from \"./ops.ts\";\n\n/** This function makes an empty store. The options give its reactive semantics and its op registry. */\nexport const nodeStore = (options: StoreOptions = {}): NodeStore =>\n publicStore(makeState(options.nodeOps ?? defaultOps, options.ops ?? {}));\n\n/**\n * This function gives an independent copy of a store: the same nodes, values, slots and seats, and the same\n * counters. A write to one store does not change the other. The expressions and the values are immutable,\n * thus the copy shares them. The options replace the semantics or the op registry of the copy, for example the\n * class semantics of a copied biblo. The function throws inside a batch, because a batch has pending work.\n */\nexport const forkStore = (store: NodeStore, options: StoreOptions = {}): NodeStore => {\n const s = state(store);\n if (s.pending !== null || s.batchDepth > 0) throw new Error(\"forkStore: the store is in a batch\");\n const copy: StoreState = {\n nodes: new Map(),\n nodeOps: options.nodeOps ?? s.nodeOps,\n ops: options.ops ?? s.ops,\n epochStats: s.epochStats,\n nextId: s.nextId,\n dangling: new Map([...s.dangling].map(([id, readers]) => [id, new Set(readers)])),\n pending: null,\n batchDepth: 0,\n epoch: s.epoch,\n };\n for (const [id, n] of s.nodes) {\n const node: MutableNode = {\n ...n,\n seats: new Set(n.seats),\n seatsStructural: new Set(n.seatsStructural),\n seatedOn: new Set(n.seatedOn),\n heldBy: new Set(n.heldBy),\n slots: new Map(n.slots),\n // The scratch fields of the epoch machine start again: no epoch is in progress\n mark: 0,\n dirty: 0,\n index: -1,\n low: -1,\n onStack: false,\n next: null,\n };\n copy.nodes.set(id, node);\n }\n return publicStore(copy);\n};\n\n/** This function gives a node of the store, or `undefined`. */\nexport const getNode = (store: NodeStore, id: NodeId): Node | undefined => store.nodes.get(id);\n\n/** This function gives the value of a node, or `none` when the store has no such node. */\nexport const readValue = (store: NodeStore, id: NodeId): Optional<unknown> => store.nodes.get(id)?.value ?? none;\n\n/**\n * This function makes `fn` one transaction. The writes in `fn` change the structure at once, and one epoch\n * at the end evaluates all their effects. A batch inside a batch joins the outer batch.\n */\nexport const batch = <T>(store: NodeStore, fn: () => T): T => runBatch(state(store), fn);\n\n/**\n * This function adds a node with an expression and evaluates it. It gives the ID of the node.\n * The ID is the hint when no node has it, otherwise a fresh ID. A reader that waited for this ID gets rewired.\n * The expression can be a document (`ExprDocument`): the node keeps its tree of the IR (`asExpr`).\n */\nexport const addNode = (store: NodeStore, expr: Expr | ExprDocument, idHint?: string): NodeId => {\n const s = state(store);\n const n = makeNode(freshId(s, idHint), asExpr(expr));\n insertNode(s, n);\n flushUnlessBatched(s);\n return n.id;\n};\n\n/**\n * This function sets the expression of a node. This is the fundamental write.\n * The engine rewires the reads of the node, evaluates it and propagates the change.\n * A write to a container collapses it first: its own slots are removed, and the expression replaces the record.\n * The expression can be a document (`ExprDocument`): the node keeps its tree of the IR (`asExpr`).\n */\nexport const setExpr = (store: NodeStore, id: NodeId, expr: Expr | ExprDocument): void => {\n const s = state(store);\n const n = s.nodes.get(id);\n if (n) {\n if (n.slots.size > 0) collapse(s, n);\n replaceExpr(s, n, asExpr(expr));\n touch(s, id);\n }\n flushUnlessBatched(s);\n};\n\n/**\n * This function writes a literal value: it is `setExpr` with `lit(value)`.\n * A write to a derived node makes it an input node, like a value that a person types over a formula.\n */\nexport const setValue = (store: NodeStore, id: NodeId, value: unknown): void => {\n setExpr(store, id, lit(value));\n};\n\n/** This function writes many literal values in one batch, thus in one epoch. */\nexport const fillMany = (store: NodeStore, writes: Iterable<readonly [NodeId, unknown]>): void => {\n batch(store, () => {\n for (const [id, value] of writes) setValue(store, id, value);\n });\n};\n\n/** The options of `setSlot`. */\nexport type SlotOptions = {\n /**\n * With `own`, the container becomes the owner of the child when the child has no owner. The removal of the\n * owner removes the child, and so does a slot change that drops the child. Without `own`, the child is shared.\n */\n readonly own?: boolean;\n};\n\n/**\n * This function points a slot of a container at a node, or removes the slot when `childId` is `undefined`.\n * This is the structural write: the container gets a new record expression, and each reader whose path goes\n * through the container resolves its path again. A node that the container owns and drops is removed.\n * The function does nothing when a node is missing or when the child is the container itself.\n */\nexport const setSlot = (\n store: NodeStore,\n parentId: NodeId,\n name: string,\n childId: NodeId | undefined,\n options: SlotOptions = {},\n): void => {\n const s = state(store);\n const parent = s.nodes.get(parentId);\n const child = childId === undefined ? undefined : s.nodes.get(childId);\n if (parent && (childId === undefined || (child && childId !== parentId)) && parent.slots.get(name) !== childId) {\n const previous = parent.slots.get(name);\n if (previous !== undefined) unlinkSlot(s, parent, name);\n if (child) {\n linkSlot(parent, name, child);\n if (options.own === true && (child.parent === undefined || !s.nodes.has(child.parent))) child.parent = parent.id;\n }\n if (previous !== undefined) dropIfOwned(s, parent, previous);\n touchRecord(s, parent.id);\n for (const r of parent.seatsStructural) touch(s, r);\n for (const r of parent.seats) touch(s, r);\n }\n flushUnlessBatched(s);\n};\n\n/**\n * This function expands a node whose value is a plain object. Each field becomes a slot, and\n * a field that is a plain object becomes a container in turn. The node becomes a container, and its slots\n * are from then on the source of truth of its fields. A reader of a field gets a seat on the field node,\n * thus an edit of one field makes only its own readers dirty. An expansion of a derived node keeps the current fields.\n *\n * Inside a batch, the expansion waits for the epoch of the batch, thus it uses the settled value.\n * The function does nothing for a container or for a value that is not a plain object.\n */\nexport const expandNode = (store: NodeStore, id: NodeId): void => {\n const s = state(store);\n if (s.batchDepth > 0) touchExpansion(s, id);\n else expandNow(s, id);\n flushUnlessBatched(s);\n};\n\n/**\n * This function removes a node and the slots that it owns. The containers that hold it lose the slot.\n * Its readers resolve their paths again: a path to a removed node gives `none`. If a node with the same ID\n * comes back later, the readers find it.\n */\nexport const removeNode = (store: NodeStore, id: NodeId): void => {\n const s = state(store);\n const n = s.nodes.get(id);\n if (n) removeOwned(s, n);\n flushUnlessBatched(s);\n};\n\n/**\n * This function evaluates the full store again. It rewires each node, makes each record expression again,\n * and starts one epoch in which each node evaluates one time in topological order. The operations keep the\n * store consistent, thus this function is a repair tool. It does not revert a write.\n */\nexport const resolveAll = (store: NodeStore): void => {\n const s = state(store);\n for (const n of s.nodes.values()) {\n touch(s, n.id);\n if (n.slots.size > 0) touchRecord(s, n.id);\n }\n flushUnlessBatched(s);\n};\n\n// === Internal ===\n\n/** A node that the container owns and no longer holds is removed: it was a part of the container. */\nconst dropIfOwned = (s: StoreState, container: MutableNode, childId: NodeId): void => {\n const former = s.nodes.get(childId);\n if (!former || former.parent !== container.id) return;\n for (const target of container.slots.values()) if (target === childId) return;\n removeOwned(s, former);\n};\n\n/** A container gives up its slots: the owned slot nodes are removed, and the shared ones are only released. */\nconst collapse = (s: StoreState, n: MutableNode): void => {\n const slots = [...n.slots.values()];\n for (const name of Array.from(n.slots.keys())) unlinkSlot(s, n, name);\n for (const childId of slots) {\n const child = s.nodes.get(childId);\n if (child && child.parent === n.id) removeOwned(s, child);\n }\n for (const r of n.seatsStructural) touch(s, r);\n};\n\n/** This function removes a node and its owned slot subtree, and touches each reader that stays. */\nconst removeOwned = (s: StoreState, root: MutableNode): void => {\n const doomed: MutableNode[] = [];\n const doomedIds = new Set<NodeId>();\n // The owned subtree, with a stack of its own: a deep tree does not overflow the call stack\n for (const todo = [root]; todo.length > 0;) {\n const n = todo.pop();\n if (n === undefined || doomedIds.has(n.id)) continue;\n doomedIds.add(n.id);\n doomed.push(n);\n for (const childId of n.slots.values()) {\n const child = s.nodes.get(childId);\n if (child && child.parent === n.id) todo.push(child);\n }\n }\n\n // The owner and each container that shares a removed node lose the slot\n for (const n of doomed) {\n for (const r of n.seatsStructural) touch(s, r);\n for (const r of n.seats) touch(s, r);\n for (const holderId of Array.from(n.heldBy)) {\n const holder = doomedIds.has(holderId) ? undefined : s.nodes.get(holderId);\n if (!holder) continue;\n for (const [name, target] of Array.from(holder.slots)) {\n if (target === n.id) unlinkSlot(s, holder, name);\n }\n touchRecord(s, holder.id);\n for (const r of holder.seatsStructural) touch(s, r);\n }\n }\n // A removed container no longer holds the nodes that it shares\n for (const n of doomed) {\n for (const target of n.slots.values()) if (!doomedIds.has(target)) s.nodes.get(target)?.heldBy.delete(n.id);\n }\n\n for (const n of doomed) {\n for (const readerId of n.seats) s.nodes.get(readerId)?.seatedOn.delete(n.id);\n for (const readerId of n.seatsStructural) s.nodes.get(readerId)?.seatedOn.delete(n.id);\n n.seats.clear();\n n.seatsStructural.clear();\n }\n for (const n of doomed) {\n unwireNode(s, n);\n s.nodes.delete(n.id);\n }\n};\n","import type { NodeId, NodeStore } from \"./types.ts\";\n\n\n/**\n * This function sorts the nodes of a store by their static dependencies (Kahn's algorithm).\n *\n * The edges come from the `targets` op of the store, like the seat wiring.\n * A reader depends on the terminal of each path and on each node that the path goes through.\n * A path to a node that is not in the store adds no edge.\n *\n * The result has the dependencies before their readers. A node on a cycle of two or more nodes is not in the\n * result. A reference of a node to itself adds no edge. The epochs of the engine use the edges of `flow`\n * instead, thus this function is a tool for analysis.\n */\nexport const toposort = (store: NodeStore): NodeId[] => {\n const dependedBy = new Map<NodeId, Set<NodeId>>();\n const inDegree = new Map<NodeId, number>();\n for (const id of store.nodes.keys()) {\n dependedBy.set(id, new Set());\n inDegree.set(id, 0);\n }\n for (const [id, n] of store.nodes) {\n for (const path of n.reads) {\n const root = path[0] === undefined ? undefined : store.nodes.get(path[0]);\n if (!root) continue;\n const { through, terminal } = store.nodeOps.targets(root, path.slice(1), store);\n for (const target of terminal === undefined ? through : [...through, terminal]) {\n const readers = dependedBy.get(target.id)!;\n if (target.id === id || readers.has(id)) continue;\n readers.add(id);\n inDegree.set(id, inDegree.get(id)! + 1);\n }\n }\n }\n\n const order: NodeId[] = [];\n for (const [id, d] of inDegree) if (d === 0) order.push(id);\n for (let head = 0; head < order.length; head++) {\n for (const readerId of dependedBy.get(order[head]!)!) {\n const d = inDegree.get(readerId)! - 1;\n inDegree.set(readerId, d);\n if (d === 0) order.push(readerId);\n }\n }\n return order;\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,69 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package",
2
3
  "name": "@mark1russell7/render-node",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
4
+ "version": "0.1.1",
5
+ "description": "The reactive node store of render: seats, slots, ordered flow epochs and the NodeOps extension points.",
6
+ "keywords": [
7
+ "reactive",
8
+ "reactive-programming",
9
+ "dataflow",
10
+ "dependency-graph",
11
+ "incremental-computation",
12
+ "signals",
13
+ "spreadsheet",
14
+ "typescript"
15
+ ],
16
+ "homepage": "https://mark1russell7.github.io/render/",
17
+ "bugs": {
18
+ "url": "https://github.com/mark1russell7/render/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/mark1russell7/render.git",
23
+ "directory": "packages/node"
24
+ },
25
+ "license": "MIT",
26
+ "author": "Mark Russell (https://github.com/mark1russell7)",
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "main": "./build/index.js",
30
+ "types": "./build/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./build/index.d.ts",
34
+ "default": "./build/index.js"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "files": [
39
+ "build",
40
+ "src",
41
+ "!src/**/*.test.ts",
42
+ "!src/**/*.test.tsx",
43
+ "!src/main.tsx",
44
+ "!src/page.css"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "engines": {
50
+ "node": ">=22.12"
51
+ },
52
+ "dependencies": {
53
+ "@mark1russell7/render-dsl": "0.1.1",
54
+ "@mark1russell7/render-optional": "0.1.0"
55
+ },
56
+ "devDependencies": {
57
+ "@mark1russell7/cue": "github:mark1russell7/cue",
58
+ "@types/node": "^26.6.4",
59
+ "tsdown": "^0.23.1",
60
+ "typescript": "^7.0.2",
61
+ "vitest": "^5.0.3"
62
+ },
63
+ "scripts": {
64
+ "build": "tsdown",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
67
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.test.json"
68
+ }
6
69
  }