@huukhanhnguyen/model / schema/components
schema/components
FlatComponentSource
FlatComponentSource = {
key:string;operations: (Operation|Group)[];parameters?: (Operation|Group)[]; }
key
key:
string
operations
parameters?
FlatLaneExtras
FlatLaneExtras = {
imageUrlOf?: (name) =>string;listAnnotationStyles?: () =>AnnotationStyle[];listTextStyles?: () =>TextStyle[];onStepError?: (failure) =>void;resolveMaterial?: (name) =>unknown;resolvePlacedComponentBody?: (key,argsOverride?) => {data:ObjectData;flat:boolean;opening:BrepData[]; };resolvePlacedNesting?: (parts,stock,spacing,seed,stockLength,kerfWidth) =>ObjectData|undefined;resolvePlacedTable?: (key) =>ObjectData|undefined;resolvePlacedView?: (key) =>ObjectData|undefined;resolveTable?: (key) =>unknown; }
Extra scope hooks an isolated evaluation may need beyond resolveComponent (the by-key lookup passed as a plain function argument) — viewObject's resolvePlacedView, tableEntity's resolvePlacedTable, imageData's imageUrlOf, Table.get()'s resolveTable, Material.get()'s resolveMaterial (settings-functions §B.2 — same wire as Table.get), and the TWO placeComponent hooks: resolvePlacedComponent (FLAT-mode — splices a gated, flattened result; wired for a truly-flat scope: sheets/rasterize) and resolvePlacedComponentBody (3D-mode — raw untransformed body+opening, no flatness gate; wired for the ROOT scope and a component's own "component"-lane scope). All Model-owned — absent when the caller has none (e.g. a standalone test), in which case each generator fails soft to empty/passthrough, and a bare Table.get(...) / Material.get(...) reference simply isn't defined (the same ReferenceError it always was before this hook existed).
imageUrlOf?
optionalimageUrlOf?: (name) =>string
Parameters
name
string
Returns
string
listAnnotationStyles?
optionallistAnnotationStyles?: () =>AnnotationStyle[]
Returns
listTextStyles?
optionallistTextStyles?: () =>TextStyle[]
The two style lanes, RESOLVED — a drafting mark authored inside a component body or a sheet's own operations names a textStyles[] / annotationStyles[] record, and reaches it only through here (the root scope's own listTextStyles/listAnnotationStyles is unreachable from an isolated scope). Wired like resolveMaterial, and for the same reason it is legitimate in a component: a named shared record travels WITH the document, so the definition still renders identically after export — unlike resolveTable, which is host state.
Returns
onStepError?
optionalonStepError?: (failure) =>void
Called once per step whose fold FAILED, after the lane has run. DataNode._stepFailed is fail-soft by design — it records the error on the node, logs it, and passes the input through — so without this hook the only trace outside the node is a console line, and a caller (a sheet) cannot tell a placement that produced nothing from one that was never there. Reporting only; it must not change the fold.
Parameters
failure
Returns
void
resolveMaterial?
optionalresolveMaterial?: (name) =>unknown
Material.get(name) — resolved materials[] record by name (fail-soft null). Wired like resolveTable so component/flat isolated scopes register a materials-lane dependency edge (settings-functions §B.2).
Parameters
name
string
Returns
unknown
resolvePlacedComponentBody?
optionalresolvePlacedComponentBody?: (key,argsOverride?) => {data:ObjectData;flat:boolean;opening:BrepData[]; }
3D-mode placeComponent hook (2026-07-17) — raw (untransformed) body + opening volumes, NO flatness gate: valid to place a flat component in a 3D chain. Wired at the ROOT scope (Model's constructor) AND a component's own isolated "component"-lane scope (nested 3D placement) — never at a truly-flat scope, where placeComponent goes through the FLAT-mode resolver instead: a declared-flat component splices (title-block furniture), a 3D one is refused because paper places a VIEW of it (see DataNode's dispatch, which checks owner.lane === "flat" OR the chain-level flat declaration). flat (the component's own Component.flat) rides along so a flat-declared CHAIN reaching this hook from a 3D lane can still splice the declared 2D representation (see DataNode._resolvePlacedComponentFlat).
Parameters
key
string
argsOverride?
Record<string, string>
Returns
{ data: ObjectData; flat: boolean; opening: BrepData[]; }
data
data:
ObjectData
flat
flat:
boolean
opening
opening:
BrepData[]
resolvePlacedNesting?
optionalresolvePlacedNesting?: (parts,stock,spacing,seed,stockLength,kerfWidth) =>ObjectData|undefined
nesting's hook — a whole-scene-scan-capable flat-lane producer. Deliberately still NEVER wired onto the root scope, nor a component's own scope (a component's placed output can itself join the scene this would scan — same self-reference risk as at root) — UNLIKE resolvePlacedView/Table (see their own docs, and Model.ts's sceneFrame fold-depth guard), nesting's whole-scene scan has no per-key identity to name a cycle by (it reads the WHOLE scene unconditionally, never one keyed entry), so a blanket lane-placement ban stays the simplest correct rule here — not yet worth the same detection machinery. Post VIEW-REFACTOR the parts keys name components[] entries (their attributes.pattern content is what gets nested — see Model._partPatternOf). Args already coerced by the calling DataNode (parts array of {key,quantity}, stock object, spacing/seed numbers).
Parameters
parts
{ key: string; quantity: number; }[]
stock
height
number
width
number
spacing
number
seed
number
stockLength
number
kerfWidth
number
Returns
ObjectData | undefined
resolvePlacedTable?
optionalresolvePlacedTable?: (key) =>ObjectData|undefined
Parameters
key
string
Returns
ObjectData | undefined
resolvePlacedView?
optionalresolvePlacedView?: (key) =>ObjectData|undefined
Parameters
key
string
Returns
ObjectData | undefined
resolveTable?
optionalresolveTable?: (key) =>unknown
Parameters
key
string
Returns
unknown
IsolatedScopeOwner
IsolatedScopeOwner = {
nodes:NodeCollectionHost;registry:RegistryHost; }
nodes
nodes:
NodeCollectionHost
registry
registry:
RegistryHost
StepFailure
StepFailure = {
method:string;reason:string;step:string; }
One step whose fold FAILED, and why. step is the operation key (placedView, a table placement, …); method is what it tried to run; reason is that step's own error message.
Declared here, at the producer (reportStepErrors in lanes/components/components.ts), because the fold is what fails — the consumer that collects them into a partial sheet is one reader among possible others. It was SheetWarning in schema/sheets.ts, byte-identical to the inline shape onStepError already spelled: one shape, two names, one of them named after a consumer.
method
method:
string
reason
reason:
string
step
step:
string