address architecture review findings and add review document
Fixes from architecture review (4 critical, 10 warnings):
Critical:
- Fix selectNode/setNode docs to accurately describe prop-key
navigation behavior including array support and prop-key writes
- Document RenderContext/Density exported types in host-config
- Resolve ADR dual status ambiguity with clarifying note in README
(frontmatter status = editorial, body Status = decision)
- Effect types already addressed in prior commit
Warnings addressed:
- Add Fragment re-export note to jsx-runtime section in
build-distribution
- Document childCtx/transformCtx helper functions in transforms.md
- Document render() accepting non-root UNode in host-config
- Add Value.Hash re-entrancy constraint to reconciler.md
- Add true-passthrough constraint and h('root') special case
to element-factory constraints
- Add _idCounter bundling caveat note
Review document added at docs/reviews/architecture-review-2026-05-18.md
with full findings, source verification table, and recommendations.
This commit is contained in:
@@ -141,10 +141,11 @@ This is documented in the schema architecture ([schema.md](schema.md) — Known
|
||||
## Constraints
|
||||
|
||||
- **`h()` is pure** — no side effects beyond the `_idCounter` increment in `createRoot()`. It does not call hosts, subscribe to signals, or mutate external state.
|
||||
- **Children are always flat** — `flat(Infinity)` + filter means consumers never receive nested arrays or null/false children from factory output. Hosts and transforms can assume `element.children` is a flat `UNode[]` with no null slots.
|
||||
- **`h("root", ...)` is a special case** — the string `"root"` is effectively a reserved type string. When `type === "root"`, `h()` produces a `URoot` (discriminated union with `type: "root"`), not a `UElement`. This is not a host tag — no host will ever receive `"root"` as a `createInstance` tag.
|
||||
- **Children are always flat** — `flat(Infinity)` + filter means consumers never receive nested arrays or null/false children from factory output. Hosts and transforms can assume `element.children` is a flat `UNode[]` with no null slots. Note that `true` values are NOT filtered — `{condition}` where `condition` is `true` produces a `true` `UPrimitive` child. Hosts that want `true` to render as nothing should filter it in their `createTextInstance`.
|
||||
- **Props are not deep-cloned** — `h()` spreads props shallowly. Nested objects are shared references. Consumers must not mutate element.props and expect isolation.
|
||||
- **`Fragment` produces arrays, not elements** — hosts and transforms must handle `UNode[]` return values from component renders. A Fragment does not appear in the tree.
|
||||
- **`_idCounter` is module-scoped** — each module instance has its own counter. If multiple copies of UJSX are loaded (e.g., different package versions), roots from different copies may collide on `id` values.
|
||||
- **`_idCounter` is module-scoped** — each module instance has its own counter. If multiple copies of UJSX are loaded (e.g., different package versions), roots from different copies may collide on `id` values. Bundle deduplication behavior determines whether copies share the counter.
|
||||
- **JSX aliases are identical** — `jsx`, `jsxs`, and `jsxDEV` are the same function. UJSX does not differentiate between them. Dev-mode only features (e.g., source location) are not currently supported.
|
||||
|
||||
## References
|
||||
|
||||
Reference in New Issue
Block a user