Sub-issue of #229.
A spec names other components in two ways, and specs transform currently honours neither when deciding what to build or in what order:
- Nested instances — an element with
instanceOf pointing at a sibling component - Bound primitives — a text, glyph or container element resolved to this platform's designated component (ADR-074)
transform walks components in name order and emits each in isolation. Two failures follow.
1. Output depends on alphabetical order
Primitive resolution originally tested for the target's generated scaffold on disk. A component whose name sorts before its dependency found no scaffold and silently skipped the binding — so an image component processed before the layout component it binds to emitted a host div instead.
Measured on a real catalogue, this silently dropped roughly a third of all bindings: 57 of 86 components bound in React, 54 of 83 in Web Components. A second consecutive run "fixed" different ones.
Worked around for now by testing for the target's api.yaml, which generate writes before any transform runs. That makes correctness order-independent, but it is a sidestep: it proves the dependency exists rather than that it has been built.
2. A scoped run emits references to components it did not build
specs transform --components card transforms exactly one component, while its generated stories import five others — image, favorite button, badge, scrim, paging carousel. The output references components the run never built, and is only usable because a previous unscoped run happened to leave them on disk.
What this asks for
A resolved dependency graph as a first-class step between generate and transform:
- Collect each component's dependencies from
instanceOf references and from the platform's primitive bindings - Transform in dependency order, so a component's dependencies are always emitted before it
- For a scoped run, either pull in the dependency closure or fail naming what is missing — never emit references to components that were not built
- Detect and report cycles rather than looping
Why order matters beyond correctness
Order-independence via api.yaml only permits emitting a reference. A transform that could read an already-built dependency could do more — validating that a prop value is in the target's accepted set, for instance, rather than passing it through and hoping. That is only available once the dependency is guaranteed built.
Acceptance
- Transforming a component whose dependencies are absent either builds them first or fails with a message naming them
- Two consecutive full runs produce byte-identical output
- A scoped run produces no reference to a component outside the built set
Sub-issue of #229.
A spec names other components in two ways, and
specs transformcurrently honours neither when deciding what to build or in what order:instanceOfpointing at a sibling componenttransformwalks components in name order and emits each in isolation. Two failures follow.1. Output depends on alphabetical order
Primitive resolution originally tested for the target's generated scaffold on disk. A component whose name sorts before its dependency found no scaffold and silently skipped the binding — so an image component processed before the layout component it binds to emitted a host
divinstead.Measured on a real catalogue, this silently dropped roughly a third of all bindings: 57 of 86 components bound in React, 54 of 83 in Web Components. A second consecutive run "fixed" different ones.
Worked around for now by testing for the target's
api.yaml, whichgeneratewrites before any transform runs. That makes correctness order-independent, but it is a sidestep: it proves the dependency exists rather than that it has been built.2. A scoped run emits references to components it did not build
specs transform --components cardtransforms exactly one component, while its generated stories import five others — image, favorite button, badge, scrim, paging carousel. The output references components the run never built, and is only usable because a previous unscoped run happened to leave them on disk.What this asks for
A resolved dependency graph as a first-class step between
generateandtransform:instanceOfreferences and from the platform's primitive bindingsWhy order matters beyond correctness
Order-independence via
api.yamlonly permits emitting a reference. A transform that could read an already-built dependency could do more — validating that a prop value is in the target's accepted set, for instance, rather than passing it through and hoping. That is only available once the dependency is guaranteed built.Acceptance