@huukhanhnguyen/model / schema/lanes
schema/lanes
LaneBodyFieldName
LaneBodyFieldName = typeof
LANE_BODY_FIELDS[number]
LaneCarrier
LaneCarrier =
Record<string,unknown>
Anything shaped like a document — a stored ModelJSON, or a live ModelScope paired with the Model fields. Indexed loosely on purpose: this is the one place lane names are read as data, and every caller has a different static type for the same arrays.
LaneChain
LaneChain = {
columns?:unknown[];entities?:unknown[];lane:LaneName;opening?:unknown[];operations?:unknown[];parameters?:unknown[]; }
One lane entry reduced to the node lists a doc-wide walk must visit, plus the lane it came from. A node-entry lane yields the entry itself as a one-element operations list, so a consumer never special-cases it.
columns?
optionalcolumns?:unknown[]
entities?
optionalentities?:unknown[]
NOT a node list — Component.entities is baked geometry (the static-geometry door for importers/AI). Carried here because a geometry migration has to reach it; a NODE walk ignores it.
lane
lane:
LaneName
opening?
optionalopening?:unknown[]
operations?
optionaloperations?:unknown[]
parameters?
optionalparameters?:unknown[]
LaneDescriptor
LaneDescriptor = {
base:string;clearEmptyArgs?:true;collection?:true;entry:"chain"|"node";identity:"key"|"name";references?: {arg:string;method:string; }[];scope:LaneScope;space:"model"|"paper";stepLane:boolean;storage:"scope"|"model"; }
base
base:
string
Base string for a minted identity ("view" → view1, view2…).
clearEmptyArgs?
optionalclearEmptyArgs?:true
Empty arg input CLEARS the arg instead of storing "" (the cameras authoring convention).
collection?
optionalcollection?:true
Has a CollectionNode — its MEMBERSHIP is pullable as a dependency, separate from any entry's body. Wired only where a reader exists.
entry
entry:
"chain"|"node"
chain — the entry is a mini-document (parameters/operations/…). node — the entry IS one authored node (a material, a camera).
identity
identity:
"key"|"name"
key field, or a quoted string literal in a name arg.
references?
optionalreferences?: {arg:string;method:string; }[]
The by-name consumers that block a delete and are rewritten on rename. A LIST, because one lane can be named from more than one carrier: patterns is named by a hatch AND by a material's cut / surface pattern, and a single-carrier field silently ignored the other two.
arg
arg:
string
method
method:
string
scope
scope:
LaneScope
space
space:
"model"|"paper"
Which SPACE the lengths inside this lane live in.
model follows the document's display unit — switch mm→m and its literals are rewritten. paper is physical sheet millimetres and must NEVER be rescaled: an A3 sheet is 420 mm wide whether the model is measured in millimetres, metres or inches.
stepLane
stepLane:
boolean
A STEP lane: every step in an entry's body returns exactly the lane's own singular type (material, view…), so RETURN_LANE_OF can map that return back to this lane.
false marks a lane whose entries are NOT step chains and never will be: components is a lite MODEL (own parameters + a data-stream body) and sheets is a flat WORKSPACE chain (it places views/tables by key AND carries ad hoc flat content drawn straight on the paper). Neither has a return: "<singular>" node.
Required, not optional, on purpose: adding a lane must not silently inherit either answer.
storage
storage:
"scope"|"model"
Which object owns the array. The FIELD NAME always equals the lane name, so a consumer resolves it as scope[lane] / model[lane].
LaneName
LaneName = typeof
LANE_NAMES[number]
LaneScope
LaneScope =
"porous"|"isolated"
How deep a name resolves from inside the lane's body. See the long form in references.ts — porous climbs owner.parent to the model root, so the whole model shares one namespace; isolated has that link cut, so the lane is a FUNCTION whose own parameters are the only names its body sees.
LANE_BODY_FIELDS
constLANE_BODY_FIELDS: readonly ["parameters","operations","opening","columns"]
The body fields a lane entry may carry — what an offline transform or a doc-wide walk has to visit. A node-entry lane has none: the entry itself is the node.
LANE_NAMES
constLANE_NAMES: readonly ["materials","layers","patterns","styles","textStyles","annotationStyles","cameras","animations","components","textures","tables","views","sheets"]
Every lane of a ModelJSON document. The two PSEUDO-lanes (parameters and scene, the root header and body) are deliberately absent: they are not arrays of entries, they are the root collection itself. references.ts adds them where an edge table needs to name them.
LANES
constLANES:Record<LaneName,LaneDescriptor>
Missing a key here is a COMPILE error, which is the whole point: the descriptor cannot drift from the lane list it describes.
MODEL_SPACE_LANES
constMODEL_SPACE_LANES: ("patterns"|"animations"|"materials"|"layers"|"styles"|"textStyles"|"annotationStyles"|"cameras"|"views"|"components"|"textures"|"tables"|"sheets")[]
The lanes whose lengths follow the model's display unit.
STEP_LANES
constSTEP_LANES: ("patterns"|"animations"|"materials"|"layers"|"styles"|"textStyles"|"annotationStyles"|"cameras"|"views"|"components"|"textures"|"tables"|"sheets")[]
The lanes whose entries are step chains — see LaneDescriptor.stepLane.
laneChains()
laneChains(
carrier,filter?):LaneChain[]
Every lane entry of a document, as node lists to walk. THE replacement for the hand-written [doc.components, doc.sheets, doc.textures, …] arrays that each offline transform used to carry — those are exactly the lists that fall behind when a lane is added.
filter narrows by descriptor (e.g. unit conversion takes only space === "model"), so a consumer states its RULE instead of its list.
Parameters
carrier
filter?
(descriptor, lane) => boolean