Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/docs/api-codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ Verification follows the repository-wide rule below: `check:codegen` detects sta

## Generated Style codec

`api/style-codec.json` and `api/schemas/style-codec.schema.json` are the maintained versioned model for the 41 public Style input fields, their canonical order, their encoding categories, their referenced numeric families, and their public descriptions. The compiler resolves numeric-family references and derives field indexes and the presence-map width once. Neither target keeps a handwritten second field inventory.
`api/style-codec.json` and `api/schemas/style-codec.schema.json` are the maintained versioned model for the 42 public Style input fields, their canonical order, their encoding categories, their referenced numeric families, and their public descriptions. The compiler resolves numeric-family references and derives field indexes and the presence-map width once. Neither target keeps a handwritten second field inventory.

The TypeScript emitter writes `packages/taffyjs-node/src/style-input.ts`, which owns the public `StyleInput` and `StyleUpdate` declarations and a straight-line encoder that reads each known property once in canonical order. The Rust emitter writes `crates/taffyjs_binding/src/style_input.rs`, which applies the matching fields in the same order through `decode_into`. Handwritten `style-codec.ts` and `style_codec.rs` own only the closed category encodings, validation primitives, buffer mechanics, and Taffy-specific conversion used by those generated call sites.

The wire version is distinct from the maintained input format version. A change that only extends generator metadata without changing bytes need not change the wire version; a change that reinterprets existing private bytes must. The current format, buffer lifetime, format choice, and mutation rules are recorded in [Compact Style codec](style-codec.md).

## Generated Layout codec

The complete public `Layout` field tree and its fixed 21-number private transport have one versioned description in `api/layout-codec.json`. Input order is the public property and slot order. The compiler validates the supported scalar and geometry shapes, resolves JavaScript and Rust field paths, assigns every slot once, and derives the 168-byte buffer size.
The complete public `Layout` field tree and its fixed 23-number private transport have one versioned description in `api/layout-codec.json`. Input order is the public property and slot order. The compiler validates the supported scalar and geometry shapes, resolves JavaScript and Rust field paths, assigns every slot once, and derives the 184-byte buffer size.

The TypeScript emitter owns the public `Layout` declaration, slot constants, and straight-line reconstruction of fresh ordinary objects. The Rust emitter owns the same slot constants and the straight-line writer from Taffy's stored `Layout`. The authored tree wrapper owns one module-local `Float64Array` scratch buffer built over an explicit `ArrayBuffer`; the private binding writers synchronously fill it and never retain a pointer to it. The explicit `ArrayBuffer` is required because JavaScriptCore materializes the backing buffer of a length-constructed typed array lazily and Bun loses the first pointer write into any such buffer. Native targets fill the buffer through the borrowed slice; the Wasm target fills the same slots through `napi_set_element`, because a Wasm module cannot receive a pointer into the JavaScript heap. Both targets share one public method name, so the wrapper and the generated decoder never branch on the runtime.

Expand Down
34 changes: 17 additions & 17 deletions .agents/docs/binding-cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The feedback loop is: apply the current rules to concrete upstream behavior; dis

Direct reads still materialize complete snapshots. The measured callback path now preserves the same complete Style capability through on-demand `getStyle()` delivery as recorded in the [read boundary](architecture.md#read-boundary); selective reads remain separate work under the [performance TODO](api-alignment-todos.md#performance).

The evidence baseline for this case is Taffy at revision [`55cda62a`](https://github.com/DioxusLabs/taffy/commit/55cda62a5df9a5d04c0023be6f6dd607b1474fe9), napi 3.12.0, napi-derive 3.6.2, and @napi-rs/cli 3.8.2.
The evidence baseline for this case is Taffy at revision [`8d13fdc8`](https://github.com/DioxusLabs/taffy/commit/8d13fdc88468c83f01b13b36fadc0349950c6f51), napi 3.12.0, napi-derive 3.6.2, and @napi-rs/cli 3.8.2.

## Case 1: TaffyTree layout state and node identities

Expand Down Expand Up @@ -91,23 +91,23 @@ This case is closed as an API mapping exercise. It fixes the outer state owner,

### Evidence

- [TaffyTree and NodeData implementation](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/taffy_tree.rs)
- [NodeId implementation](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/node.rs)
- [Layout implementation](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/layout.rs)
- [TaffyTree and NodeData implementation](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/taffy_tree.rs)
- [NodeId implementation](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/node.rs)
- [Layout implementation](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/layout.rs)
- [ECMAScript Map objects](https://tc39.es/ecma262/multipage/keyed-collections.html#sec-map-objects)
- [ECMAScript SameValueZero comparison](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero)

## Case 2: Style values and conversion boundaries

This case maps the complete Style value that JavaScript supplies to node creation and replacement and the owned readonly Style value returned by direct reads or a measure callback's `getStyle()`. It is intended to establish reusable value-mapping rules, not merely settle the spelling of one Style field.

This case is complete as an API-alignment example. Its reference value is that the selected container and value-family rules are sufficient to classify every currently known Style field without reviewing all 41 fields individually. The exhaustive inventory is intentionally outside the example because repeating already covered categories would add no new alignment reasoning.
This case is complete as an API-alignment example. Its reference value is that the selected container and value-family rules are sufficient to classify every currently exposed Style field without reviewing the complete inventory individually. The exhaustive inventory is intentionally outside the example because repeating already covered categories would add no new alignment reasoning.

### Rust behavior

`Style<DefaultCheapStr>` is one complete owned value. `new_leaf` moves a Style into the new node. `set_style` replaces the node's entire Style and then marks the node dirty; it does not merge the supplied value with the previous Style. `style` returns a borrowed reference to the complete stored Style, and `compute_layout_with_measure` passes a borrowed reference to that same complete value during measurement.

Taffy's examples normally construct a small set of fields and use `..Default::default()` for the rest. Under the repository's pinned default feature set, Style has 41 semantic fields after excluding its Rust-only phantom field. Their transitive types cover booleans, numeric values, optional values, closed keywords, alignment records, generic `Point`, `Size`, `Rect`, and `Line` records, semantic length variants, nested grid collections, custom grid identifiers, and integer counts and indices.
Taffy's examples normally construct a small set of fields and use `..Default::default()` for the rest. The binding currently exposes 42 semantic Style fields after excluding Taffy's Rust-only phantom field and the separately open `flex_line_count` surface. Their transitive types cover booleans, numeric values, optional values, closed keywords and finite containment flags, alignment records, generic `Point`, `Size`, `Rect`, and `Line` records, semantic length variants, nested grid collections, custom grid identifiers, and integer counts and indices.

The `calc` feature is enabled by Taffy's default features, which this repository keeps enabled, but its public length types represent calc values through opaque pointers. The high-level `TaffyTree` implementation resolves every calc pointer to `0.0`; it does not expose an application resolver. Raw calc pointers therefore cannot define a JavaScript Style value, so the selected public high-level Style vocabulary excludes calc.

Expand Down Expand Up @@ -176,7 +176,7 @@ The earlier rich-object implementation was justified by a focused end-to-end nat
| ------------------------------------------------------------ | ------------------------: | ------------: | ------------------------: |
| One retained scalar; replace one scalar | 3.83 µs | 3.89 µs | Effectively equal |
| 13 retained sparse fields; replace one scalar | 11.8 µs | 3.89 µs | `updateStyle` 3.0× faster |
| Complete 41-field `getStyle` snapshot; replace one scalar | 23.1 µs | 3.97 µs | `updateStyle` 5.8× faster |
| Complete `getStyle` snapshot; replace one scalar | 23.1 µs | 3.97 µs | `updateStyle` 5.8× faster |
| 1,000 retained `gridAutoRows`; replace one scalar | 428 µs | 4.60 µs | `updateStyle` 93× faster |
| Replace 1,000 `gridAutoRows` | 446 µs | 448 µs | Effectively equal |
| 1,000 retained nested string grid values; replace one scalar | 139 µs | 64.3 µs | `updateStyle` 2.2× faster |
Expand Down Expand Up @@ -582,15 +582,15 @@ The shared definition and stable codes that this case originally left open are n

### Evidence

- [Taffy Style definition and defaults](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/style/mod.rs)
- [Taffy semantic length types](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/style/dimension.rs)
- [Taffy alignment types](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/style/alignment.rs)
- [Taffy Style definition and defaults](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/style/mod.rs)
- [Taffy semantic length types](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/style/dimension.rs)
- [Taffy alignment types](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/style/alignment.rs)
- [CSS Box Alignment overflow-position values](https://www.w3.org/TR/css-align-3/#overflow-values)
- [Taffy geometry types](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/geometry.rs)
- [Taffy grid Style types](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/style/grid.rs)
- [Taffy geometry types](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/geometry.rs)
- [Taffy grid Style types](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/style/grid.rs)
- [Yoga 3.2.1 JavaScript wrapper](https://github.com/facebook/yoga/blob/v3.2.1/javascript/src/wrapAssembly.ts)
- [Yoga 3.2.1 native Style normalization](https://github.com/facebook/yoga/blob/v3.2.1/yoga/style/Style.h)
- [TaffyTree Style operations and measurement](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/taffy_tree.rs)
- [TaffyTree Style operations and measurement](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/taffy_tree.rs)
- [napi-rs object conversion](https://napi.rs/docs/concepts/type-conversions)
- [napi-rs enum conversion](https://napi.rs/docs/concepts/enum)
- [TypeScript enum objects and const-enum publication pitfalls](https://www.typescriptlang.org/docs/handbook/enums)
Expand Down Expand Up @@ -686,10 +686,10 @@ Retaining a callback's owned `getStyle` provider remains supported and does not

### Evidence

- [TaffyTree context, dirty-state, and compute operations](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/taffy_tree.rs)
- [Taffy root and cached layout computation](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/compute/mod.rs)
- [Taffy leaf measurement](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/compute/leaf.rs)
- [Taffy per-node cache behavior](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/cache.rs)
- [TaffyTree context, dirty-state, and compute operations](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/taffy_tree.rs)
- [Taffy root and cached layout computation](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/compute/mod.rs)
- [Taffy leaf measurement](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/compute/leaf.rs)
- [Taffy per-node cache behavior](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/cache.rs)
- [napi-rs scoped function calls and pending-exception capture](https://github.com/napi-rs/napi-rs/blob/napi-v3.12.0/crates/napi/src/bindgen_runtime/js_values/function.rs)
- [napi-rs JavaScript exception retention](https://github.com/napi-rs/napi-rs/blob/napi-v3.12.0/crates/napi/src/error.rs)
- [Yoga 3.2.1 JavaScript measure wrapper](https://github.com/facebook/yoga/blob/v3.2.1/javascript/src/wrapAssembly.ts)
Expand Down
6 changes: 5 additions & 1 deletion .agents/docs/binding-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is the current reference for Rust/JavaScript conversion and safety in `@taffyjs/node`. It describes the implemented Taffy boundary. Product choices that should constrain future work are recorded in [@taffyjs/node decisions](taffyjs-node-decisions.md).

Recheck version-sensitive behavior whenever Taffy, napi-rs, Node.js, or TypeScript changes. The primary upstream references are [TaffyTree](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/tree/taffy_tree.rs), [Style](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/style/mod.rs), [geometry](https://github.com/DioxusLabs/taffy/blob/55cda62a5df9a5d04c0023be6f6dd607b1474fe9/src/geometry.rs), and [napi-rs conversions](https://napi.rs/docs/concepts/type-conversions).
Recheck version-sensitive behavior whenever Taffy, napi-rs, Node.js, or TypeScript changes. The primary upstream references are [TaffyTree](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/tree/taffy_tree.rs), [Style](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/style/mod.rs), [geometry](https://github.com/DioxusLabs/taffy/blob/8d13fdc88468c83f01b13b36fadc0349950c6f51/src/geometry.rs), and [napi-rs conversions](https://napi.rs/docs/concepts/type-conversions).

## Scope and ownership

Expand Down Expand Up @@ -58,6 +58,8 @@ Indices and Rust integer payloads must be finite exact integers in their public

Fieldless families such as `Display`, `Overflow`, and `AlignItems` use stable numeric literal members exposed through frozen PascalCase objects. Public code should use the names, while an exact valid raw code remains accepted. Rust conversion checks exact family membership and does not derive codes from Rust declaration order.

`Contain` uses the same finite numeric-family boundary for the four combinations Taffy can store: `None`, `Layout`, `Paint`, and `Content` (`Layout | Paint`). This exposes Taffy's layout-affecting containment flags without importing CSS parsing or accepting unknown bits.

### Lengths, available space, and other tagged values

Length inputs accept a direct number as shorthand for an absolute length. The complete tagged form remains supported through values such as `Dimension.Length(20)`, `Dimension.Percent(50)`, and `Dimension.Auto`, and tagged length outputs remain valid later inputs. Percent helpers use user-facing percentages, so `50` maps to Taffy's `0.5`. CSS strings are not length values.
Expand All @@ -82,6 +84,8 @@ Non-Style scalar and fixed-object inputs use concrete napi-rs types where their

Borrowed Rust values never escape. Direct Style reads, Layout, child arrays, detailed Grid data, available space, and nested records are copied into complete detached JavaScript values. A measure callback's Style is first cloned into an owned Rust snapshot and is converted into a complete detached JavaScript value only when its `getStyle()` function is called.

Layout snapshots expose Taffy's `scrollable_overflow_rect` as `scrollableOverflowRect`; `right` and `bottom` are the reachable content extents formerly represented by `contentSize`, while negative `left` and `top` preserve start-side overflow that the old size could not express. Detailed Grid track snapshots expose per-track `positions` and resolved `lineNames`, replacing the old derived `sizes` and `gutters` arrays and preserving content-alignment offsets and logical RTL order.

Binding-produced records and arrays are recursively readonly in TypeScript because mutation cannot update Taffy. Runtime objects remain ordinary mutable, unfrozen objects, and each read or callback `getStyle()` call returns an independent snapshot. There are no live native views, output caches, lazy properties, selectors, prepared queries, or batch snapshots; the callback function is an explicit on-demand operation rather than a property that hides an already materialized object.

Public TypeScript declarations and JSDoc live in `packages/taffyjs-node/src` and are emitted by `vp pack` into `index.d.ts`. The private native declarations remain napi-rs-generated.
Expand Down
Loading