/** * StoreEditor — high-level facade for editing a parsed `IfcDataStore` via the * `MutablePropertyView` overlay. * * Implements the `store.addEntity()` / `store.removeEntity()` / * `store.setPositionalAttribute()` API requested in LTplus-AG/ifc-lite#592. * * The underlying store buffer and entity index are never mutated. Changes * accumulate in the overlay and materialise during * `StepExporter.export({ applyMutations })`. Overlay-created entities are * visible via `getNewEntity()` / `getNewEntities()`; they are intentionally * NOT inserted into `store.entityIndex.byId`, because that index may be a * `CompactEntityIndex` whose backing typed arrays are immutable. */ import type { MutablePropertyView } from './mutable-property-view.js'; import type { IfcAttributeValue, MutationEntityRef as EntityRef, MutationStoreShape as IfcDataStore, NewEntity } from './types.js'; /** Sentinel byteOffset that flags an `EntityRef` as overlay-only (no source bytes). */ export declare const OVERLAY_BYTE_OFFSET = -1; /** Quantity kinds accepted by {@link StoreEditor.addQuantitySet}. */ export type QuantityKind = 'LENGTH' | 'AREA' | 'VOLUME' | 'COUNT' | 'WEIGHT' | 'TIME'; /** Property value kinds accepted by {@link StoreEditor.addPropertySet}. */ export type PropertyKind = 'TEXT' | 'LABEL' | 'REAL' | 'INTEGER' | 'BOOLEAN'; /** * Schema-aware normaliser injected from outside the package. * * `@ifc-lite/mutations` cannot import `@ifc-lite/parser` (cycle), so * the canonical-name registry isn't reachable here. The SDK / viewer * boundary calls `setEntityTypeNormalizer` once at startup with the * parser's `normalizeIfcTypeName` helper, and from then on every * `addEntity()` call resolves to canonical PascalCase before forwarding * to the overlay. Direct callers that don't wire a normalizer fall * back to the lightweight regex check below — typos still surface, * just without registry-grade rejection. */ export type EntityTypeNormalizer = (type: string) => string; /** * Register the canonical-name resolver. Pass `null` to clear it (used * by tests). Calling repeatedly is fine — last write wins. */ export declare function setEntityTypeNormalizer(fn: EntityTypeNormalizer | null): void; export declare class StoreEditor { private store; private view; private maxExistingId; constructor(store: IfcDataStore, view: MutablePropertyView); /** * Re-scan the store and bump the express-id watermark if the store has * grown since construction (e.g. after lazy index hydration or * federating in another model). Cheap to call — `MutablePropertyView` * keeps the high watermark, so re-seeding with a stale value is a * no-op. */ refreshWatermark(): void; /** * Add a new entity to the store overlay. Returns a synthetic `EntityRef` * with a freshly-allocated expressId; pass it back to other APIs (other * `addEntity` calls, `setPositionalAttribute`, exporters) to reference * the new record. * * Pass `type` as the canonical IFC EXPRESS PascalCase name * (e.g. `'IfcRectangleProfileDef'`). UPPERCASE STEP tokens are also * accepted — both are normalized to the same internal form. * * Attribute conventions (mirrors `EntityExtractor.extractEntity()` output): * - numbers → STEP integer / REAL literal * - `"#42"` → STEP entity reference * - `"'literal'"` or any plain string → quoted STEP string * - `".AREA."` (dot-wrapped) → enum * - `null` / `undefined` → `$` * - arrays → STEP list `(a,b,c)` */ addEntity(type: string, attributes: IfcAttributeValue[]): EntityRef; /** * Remove an entity. Existing entities are tombstoned and skipped during * export; overlay-only entities are forgotten. Returns false if the id is * not known to the store or the overlay. */ removeEntity(expressId: number): boolean; /** * Edit a positional STEP argument on any entity by zero-based index. * Use this for non-IfcRoot edits like `IfcRectangleProfileDef.XDim` * where the attribute has no symbolic name. */ setPositionalAttribute(expressId: number, index: number, value: IfcAttributeValue): void; /** Edit a named root attribute (Name, Description, ObjectType, …). */ setAttribute(expressId: number, attrName: string, value: string): void; /** * Change an entity's IFC class in place ("retype" / reassign class). * * The entity keeps its expressId, so its geometry, placement, representation * and every `IfcRel*` reference (all keyed by `#id`) carry over unchanged. * The STEP exporter re-lays-out the entity's attributes BY NAME against the * target class's declared layout — mirroring IfcOpenShell's * `reassign_class`. Best suited to compatible reassignments such as the * building-element subtypes (`IfcBuildingElementProxy` ↔ `IfcColumn` / * `IfcBeam` / `IfcMember` / `IfcPlate` / `IfcWall`) which share the * IfcElement attribute layout. * * Returns false if the id is not known to the store or the overlay. * * @param newType Target IFC class. PascalCase (`IfcColumn`) or the all-caps * STEP form (`IFCCOLUMN`) — both normalize to canonical PascalCase. * @param options.predefinedType Optional PredefinedType for the target class. */ setEntityType(expressId: number, newType: string, options?: { predefinedType?: string | null; }): boolean; /** Look up the overlay record for a freshly-added entity. */ getNewEntity(expressId: number): NewEntity | null; /** All overlay-created entities, in insertion order. */ getNewEntities(): NewEntity[]; /** * Attach a quantity set to an entity via the property view, so it surfaces in * the properties panel (`getQuantitiesForEntity`) AND exports to * IfcElementQuantity — the single source the rest of the app reads. Prefer * this over emitting raw quantity / element-quantity entities, which the * panel doesn't resolve. */ addQuantitySet(entityId: number, qsetName: string, quantities: Array<{ name: string; value: number; quantityType: QuantityKind; unit?: string; }>): void; /** * Attach a property set to an entity via the property view, so it surfaces in * the properties panel AND exports to IfcPropertySet — the single source the * rest of the app reads (the panel doesn't resolve raw overlay entities). */ addPropertySet(entityId: number, psetName: string, properties: Array<{ name: string; value: string | number | boolean; type: PropertyKind; unit?: string; }>): void; private computeMaxExistingId; } //# sourceMappingURL=store-editor.d.ts.map