brepjs-bim 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,7 +43,7 @@ export.
43
43
  | Spatial structure | project → site → building → storey aggregation; `placeIn` to assign elements to a storey |
44
44
  | Property sets | IFC pset templates + measure types; quantity sets for takeoff |
45
45
  | Data layers | materials (layer/profile/simple sets), classification refs, surface styles, zones/systems |
46
- | IFC export | `toIfc` → IFC-SPF (`Uint8Array`); IFC2X3 / IFC4 schema selection; owner history |
46
+ | IFC export | `toIfc` → IFC-SPF (`Uint8Array`); IFC4 / IFC4X3 schema selection; owner history |
47
47
  | IFC import | `fromIfc` / `SpfReader` → `ImportedModel` (elements, geometry, psets, materials, spatial tree) |
48
48
  | Validation | referential integrity, schema check, geometry validity, IFC round-trip report |
49
49
  | Interop | COBie 2.4 export (CSV/JSON), IDS 1.0 checking, BCF 3.0 read/write |
@@ -57,8 +57,9 @@ validator and generates geometry for every product. See [VALIDATION.md](./VALIDA
57
57
  to reproduce, and `examples/sampleBuilding.mjs` for the model it validates.
58
58
 
59
59
  > **Not yet:** the official buildingSMART Validation Service and desktop-tool
60
- > interop (Revit / ArchiCAD / Solibri) are unverified. This is an early-stage
61
- > (`0.1.x`) experimental package and the API will change.
60
+ > interop (Revit / Solibri) are unverified the fixtures and per-tool
61
+ > checklists are ready in [VALIDATION.md](./VALIDATION.md). This is an
62
+ > experimental pre-1.0 package and the API may change.
62
63
 
63
64
  ## Usage
64
65
 
@@ -66,15 +67,16 @@ Author a small model and export IFC:
66
67
 
67
68
  ```ts
68
69
  import { BimModel, toIfc } from 'brepjs-bim';
70
+ import { unwrap } from 'brepjs';
69
71
 
70
72
  const model = new BimModel();
71
73
  model.init({ name: 'Example' });
72
74
 
73
75
  // Spatial structure: project → site → building → storey.
74
76
  const project = model.getProject();
75
- const siteId = model.addSite({ name: 'Site' });
76
- const buildingId = model.addBuilding({ name: 'Building' });
77
- const storeyId = model.addStorey({ name: 'Level 1', elevation: 0 });
77
+ const siteId = unwrap(model.addSite({ name: 'Site' }));
78
+ const buildingId = unwrap(model.addBuilding({ name: 'Building' }));
79
+ const storeyId = unwrap(model.addStorey({ name: 'Level 1', elevation: 0 }));
78
80
  if (project) model.aggregate(project.localId, siteId);
79
81
  model.aggregate(siteId, buildingId);
80
82
  model.aggregate(buildingId, storeyId);
@@ -6334,14 +6334,20 @@ var BimModel = class {
6334
6334
  for (const mullion of el.geometry.mullions) mullion.solid[Symbol.dispose]();
6335
6335
  }
6336
6336
  }
6337
- addSite(spec) {
6338
- return this.#makeElement("SITE", spec, null);
6337
+ addSite(spec, options) {
6338
+ const keyCheck = this.#checkStableKey(options);
6339
+ if (!keyCheck.ok) return keyCheck;
6340
+ return (0, brepjs.ok)(this.#makeElement("SITE", spec, null, options?.stableKey));
6339
6341
  }
6340
6342
  addBuilding(spec, options) {
6341
- return this.#makeElement("BUILDING", spec, null, options?.stableKey);
6343
+ const keyCheck = this.#checkStableKey(options);
6344
+ if (!keyCheck.ok) return keyCheck;
6345
+ return (0, brepjs.ok)(this.#makeElement("BUILDING", spec, null, options?.stableKey));
6342
6346
  }
6343
6347
  addStorey(spec, options) {
6344
- return this.#makeElement("STOREY", spec, null, options?.stableKey);
6348
+ const keyCheck = this.#checkStableKey(options);
6349
+ if (!keyCheck.ok) return keyCheck;
6350
+ return (0, brepjs.ok)(this.#makeElement("STOREY", spec, null, options?.stableKey));
6345
6351
  }
6346
6352
  /** Reject a duplicate stableKey BEFORE any geometry is built, so the
6347
6353
  * Result-returning adders never allocate a solid they cannot store. */
@@ -6398,10 +6404,12 @@ var BimModel = class {
6398
6404
  this.#associateClassification(id, spec);
6399
6405
  return (0, brepjs.ok)(id);
6400
6406
  }
6401
- addSpace(spec) {
6407
+ addSpace(spec, options) {
6408
+ const keyCheck = this.#checkStableKey(options);
6409
+ if (!keyCheck.ok) return keyCheck;
6402
6410
  const geomResult = spaceToSolid(spec);
6403
6411
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6404
- const id = this.#makeElement("SPACE", spec, geomResult.value);
6412
+ const id = this.#makeElement("SPACE", spec, geomResult.value, options?.stableKey);
6405
6413
  this.#associateMaterial(id, spec);
6406
6414
  this.#associateClassification(id, spec);
6407
6415
  return (0, brepjs.ok)(id);
@@ -6416,26 +6424,32 @@ var BimModel = class {
6416
6424
  this.#associateClassification(id, spec);
6417
6425
  return (0, brepjs.ok)(id);
6418
6426
  }
6419
- addCurtainWall(spec) {
6427
+ addCurtainWall(spec, options) {
6428
+ const keyCheck = this.#checkStableKey(options);
6429
+ if (!keyCheck.ok) return keyCheck;
6420
6430
  const gridResult = curtainWallToGrid(spec);
6421
6431
  if (!gridResult.ok) return (0, brepjs.err)(gridResult.error);
6422
- const id = this.#makeElement("CURTAIN_WALL", spec, gridResult.value);
6432
+ const id = this.#makeElement("CURTAIN_WALL", spec, gridResult.value, options?.stableKey);
6423
6433
  this.#associateMaterial(id, spec);
6424
6434
  this.#associateClassification(id, spec);
6425
6435
  return (0, brepjs.ok)(id);
6426
6436
  }
6427
- addFooting(spec) {
6437
+ addFooting(spec, options) {
6438
+ const keyCheck = this.#checkStableKey(options);
6439
+ if (!keyCheck.ok) return keyCheck;
6428
6440
  const geomResult = footingToSolid(spec);
6429
6441
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6430
- const id = this.#makeElement("FOOTING", spec, geomResult.value);
6442
+ const id = this.#makeElement("FOOTING", spec, geomResult.value, options?.stableKey);
6431
6443
  this.#associateMaterial(id, spec);
6432
6444
  this.#associateClassification(id, spec);
6433
6445
  return (0, brepjs.ok)(id);
6434
6446
  }
6435
- addPile(spec) {
6447
+ addPile(spec, options) {
6448
+ const keyCheck = this.#checkStableKey(options);
6449
+ if (!keyCheck.ok) return keyCheck;
6436
6450
  const geomResult = pileToSolid(spec);
6437
6451
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6438
- const id = this.#makeElement("PILE", spec, geomResult.value);
6452
+ const id = this.#makeElement("PILE", spec, geomResult.value, options?.stableKey);
6439
6453
  this.#associateMaterial(id, spec);
6440
6454
  this.#associateClassification(id, spec);
6441
6455
  return (0, brepjs.ok)(id);
@@ -6465,10 +6479,12 @@ var BimModel = class {
6465
6479
  this.#associateClassification(id, spec);
6466
6480
  return (0, brepjs.ok)(id);
6467
6481
  }
6468
- addRailing(spec) {
6482
+ addRailing(spec, options) {
6483
+ const keyCheck = this.#checkStableKey(options);
6484
+ if (!keyCheck.ok) return keyCheck;
6469
6485
  const geomResult = railingToSolid(spec);
6470
6486
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6471
- const id = this.#makeElement("RAILING", spec, geomResult.value);
6487
+ const id = this.#makeElement("RAILING", spec, geomResult.value, options?.stableKey);
6472
6488
  this.#associateMaterial(id, spec);
6473
6489
  this.#associateClassification(id, spec);
6474
6490
  return (0, brepjs.ok)(id);
@@ -6478,10 +6494,12 @@ var BimModel = class {
6478
6494
  * IfcRelCoversBldgElements linking the covering to its host (e.g. a slab it
6479
6495
  * finishes) is recorded for export.
6480
6496
  */
6481
- addCovering(spec, hostLocalId) {
6497
+ addCovering(spec, hostLocalId, options) {
6498
+ const keyCheck = this.#checkStableKey(options);
6499
+ if (!keyCheck.ok) return keyCheck;
6482
6500
  const geomResult = coveringToSolid(spec);
6483
6501
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6484
- const id = this.#makeElement("COVERING", spec, geomResult.value);
6502
+ const id = this.#makeElement("COVERING", spec, geomResult.value, options?.stableKey);
6485
6503
  this.#associateMaterial(id, spec);
6486
6504
  this.#associateClassification(id, spec);
6487
6505
  if (hostLocalId !== void 0) this.#makeRel({
@@ -6496,24 +6514,30 @@ var BimModel = class {
6496
6514
  * attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
6497
6515
  * (IfcRelNests, order-preserving). Returns the assembly's localId.
6498
6516
  */
6499
- addElementAssembly(spec) {
6500
- return this.#makeElement("ELEMENT_ASSEMBLY", spec, null);
6517
+ addElementAssembly(spec, options) {
6518
+ const keyCheck = this.#checkStableKey(options);
6519
+ if (!keyCheck.ok) return keyCheck;
6520
+ return (0, brepjs.ok)(this.#makeElement("ELEMENT_ASSEMBLY", spec, null, options?.stableKey));
6501
6521
  }
6502
6522
  /**
6503
6523
  * Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
6504
6524
  * carries no geometry; attach members (spaces or other elements) with
6505
- * {@link assignToGroup}. Returns the zone's localId.
6525
+ * {@link assignToGroup}. Returns the zone's localId as a Result.
6506
6526
  */
6507
- addZone(spec) {
6508
- return this.#makeElement("ZONE", spec, null);
6527
+ addZone(spec, options) {
6528
+ const keyCheck = this.#checkStableKey(options);
6529
+ if (!keyCheck.ok) return keyCheck;
6530
+ return (0, brepjs.ok)(this.#makeElement("ZONE", spec, null, options?.stableKey));
6509
6531
  }
6510
6532
  /**
6511
6533
  * Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
6512
6534
  * system carries no geometry; attach members with {@link assignToGroup}.
6513
- * Returns the system's localId.
6535
+ * Returns the system's localId as a Result.
6514
6536
  */
6515
- addSystem(spec) {
6516
- return this.#makeElement("SYSTEM", spec, null);
6537
+ addSystem(spec, options) {
6538
+ const keyCheck = this.#checkStableKey(options);
6539
+ if (!keyCheck.ok) return keyCheck;
6540
+ return (0, brepjs.ok)(this.#makeElement("SYSTEM", spec, null, options?.stableKey));
6517
6541
  }
6518
6542
  /**
6519
6543
  * Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
@@ -6649,9 +6673,11 @@ var BimModel = class {
6649
6673
  * and disposes it on model disposal; the caller must not dispose it (see
6650
6674
  * {@link ProxySpec.solid}).
6651
6675
  */
6652
- addProxy(spec) {
6676
+ addProxy(spec, options) {
6677
+ const keyCheck = this.#checkStableKey(options);
6678
+ if (!keyCheck.ok) return keyCheck;
6653
6679
  if (spec.solid === null || spec.solid === void 0) return (0, brepjs.err)(specError("PROXY_NO_GEOMETRY", "ProxySpec.solid is required"));
6654
- const id = this.#makeElement("PROXY", spec, spec.solid);
6680
+ const id = this.#makeElement("PROXY", spec, spec.solid, options?.stableKey);
6655
6681
  if (spec.materialName !== void 0) this.#makeRel({
6656
6682
  kind: "ASSOCIATES_MATERIAL",
6657
6683
  materialName: spec.materialName,
@@ -16733,9 +16759,18 @@ function familiesToBim(root, options) {
16733
16759
  const model = new BimModel();
16734
16760
  const initResult = model.init(options.project);
16735
16761
  if (!initResult.ok) return initResult;
16736
- const siteId = model.addSite({ name: options.siteName ?? "Site" });
16737
- const buildingId = model.addBuilding({ name: options.buildingName ?? "Building" });
16738
- model.aggregate(siteId, buildingId);
16762
+ const siteResult = model.addSite({ name: options.siteName ?? "Site" });
16763
+ if (!siteResult.ok) {
16764
+ model[Symbol.dispose]();
16765
+ return siteResult;
16766
+ }
16767
+ const buildingResult = model.addBuilding({ name: options.buildingName ?? "Building" });
16768
+ if (!buildingResult.ok) {
16769
+ model[Symbol.dispose]();
16770
+ return buildingResult;
16771
+ }
16772
+ const buildingId = buildingResult.value;
16773
+ model.aggregate(siteResult.value, buildingId);
16739
16774
  const idByKeyPath = /* @__PURE__ */ new Map();
16740
16775
  const walk = (el, storeyId) => {
16741
16776
  let containerId = storeyId;
@@ -16743,13 +16778,14 @@ function familiesToBim(root, options) {
16743
16778
  if (el.type === "Storey") {
16744
16779
  const keyed = requireKeyed(el);
16745
16780
  if (!keyed.ok) return keyed;
16746
- const id = model.addStorey({
16781
+ const storeyResult = model.addStorey({
16747
16782
  name: el.attributes["name"] ?? el.keyPath,
16748
16783
  elevation: el.props["elevation"] ?? 0
16749
16784
  }, { stableKey: el.keyPath });
16750
- model.aggregate(buildingId, id);
16751
- idByKeyPath.set(el.keyPath, id);
16752
- containerId = id;
16785
+ if (!storeyResult.ok) return storeyResult;
16786
+ model.aggregate(buildingId, storeyResult.value);
16787
+ idByKeyPath.set(el.keyPath, storeyResult.value);
16788
+ containerId = storeyResult.value;
16753
16789
  } else if (route !== void 0) {
16754
16790
  const keyed = requireKeyed(el);
16755
16791
  if (!keyed.ok) return keyed;
@@ -6311,14 +6311,20 @@ var BimModel = class {
6311
6311
  for (const mullion of el.geometry.mullions) mullion.solid[Symbol.dispose]();
6312
6312
  }
6313
6313
  }
6314
- addSite(spec) {
6315
- return this.#makeElement("SITE", spec, null);
6314
+ addSite(spec, options) {
6315
+ const keyCheck = this.#checkStableKey(options);
6316
+ if (!keyCheck.ok) return keyCheck;
6317
+ return ok(this.#makeElement("SITE", spec, null, options?.stableKey));
6316
6318
  }
6317
6319
  addBuilding(spec, options) {
6318
- return this.#makeElement("BUILDING", spec, null, options?.stableKey);
6320
+ const keyCheck = this.#checkStableKey(options);
6321
+ if (!keyCheck.ok) return keyCheck;
6322
+ return ok(this.#makeElement("BUILDING", spec, null, options?.stableKey));
6319
6323
  }
6320
6324
  addStorey(spec, options) {
6321
- return this.#makeElement("STOREY", spec, null, options?.stableKey);
6325
+ const keyCheck = this.#checkStableKey(options);
6326
+ if (!keyCheck.ok) return keyCheck;
6327
+ return ok(this.#makeElement("STOREY", spec, null, options?.stableKey));
6322
6328
  }
6323
6329
  /** Reject a duplicate stableKey BEFORE any geometry is built, so the
6324
6330
  * Result-returning adders never allocate a solid they cannot store. */
@@ -6375,10 +6381,12 @@ var BimModel = class {
6375
6381
  this.#associateClassification(id, spec);
6376
6382
  return ok(id);
6377
6383
  }
6378
- addSpace(spec) {
6384
+ addSpace(spec, options) {
6385
+ const keyCheck = this.#checkStableKey(options);
6386
+ if (!keyCheck.ok) return keyCheck;
6379
6387
  const geomResult = spaceToSolid(spec);
6380
6388
  if (!geomResult.ok) return err(geomResult.error);
6381
- const id = this.#makeElement("SPACE", spec, geomResult.value);
6389
+ const id = this.#makeElement("SPACE", spec, geomResult.value, options?.stableKey);
6382
6390
  this.#associateMaterial(id, spec);
6383
6391
  this.#associateClassification(id, spec);
6384
6392
  return ok(id);
@@ -6393,26 +6401,32 @@ var BimModel = class {
6393
6401
  this.#associateClassification(id, spec);
6394
6402
  return ok(id);
6395
6403
  }
6396
- addCurtainWall(spec) {
6404
+ addCurtainWall(spec, options) {
6405
+ const keyCheck = this.#checkStableKey(options);
6406
+ if (!keyCheck.ok) return keyCheck;
6397
6407
  const gridResult = curtainWallToGrid(spec);
6398
6408
  if (!gridResult.ok) return err(gridResult.error);
6399
- const id = this.#makeElement("CURTAIN_WALL", spec, gridResult.value);
6409
+ const id = this.#makeElement("CURTAIN_WALL", spec, gridResult.value, options?.stableKey);
6400
6410
  this.#associateMaterial(id, spec);
6401
6411
  this.#associateClassification(id, spec);
6402
6412
  return ok(id);
6403
6413
  }
6404
- addFooting(spec) {
6414
+ addFooting(spec, options) {
6415
+ const keyCheck = this.#checkStableKey(options);
6416
+ if (!keyCheck.ok) return keyCheck;
6405
6417
  const geomResult = footingToSolid(spec);
6406
6418
  if (!geomResult.ok) return err(geomResult.error);
6407
- const id = this.#makeElement("FOOTING", spec, geomResult.value);
6419
+ const id = this.#makeElement("FOOTING", spec, geomResult.value, options?.stableKey);
6408
6420
  this.#associateMaterial(id, spec);
6409
6421
  this.#associateClassification(id, spec);
6410
6422
  return ok(id);
6411
6423
  }
6412
- addPile(spec) {
6424
+ addPile(spec, options) {
6425
+ const keyCheck = this.#checkStableKey(options);
6426
+ if (!keyCheck.ok) return keyCheck;
6413
6427
  const geomResult = pileToSolid(spec);
6414
6428
  if (!geomResult.ok) return err(geomResult.error);
6415
- const id = this.#makeElement("PILE", spec, geomResult.value);
6429
+ const id = this.#makeElement("PILE", spec, geomResult.value, options?.stableKey);
6416
6430
  this.#associateMaterial(id, spec);
6417
6431
  this.#associateClassification(id, spec);
6418
6432
  return ok(id);
@@ -6442,10 +6456,12 @@ var BimModel = class {
6442
6456
  this.#associateClassification(id, spec);
6443
6457
  return ok(id);
6444
6458
  }
6445
- addRailing(spec) {
6459
+ addRailing(spec, options) {
6460
+ const keyCheck = this.#checkStableKey(options);
6461
+ if (!keyCheck.ok) return keyCheck;
6446
6462
  const geomResult = railingToSolid(spec);
6447
6463
  if (!geomResult.ok) return err(geomResult.error);
6448
- const id = this.#makeElement("RAILING", spec, geomResult.value);
6464
+ const id = this.#makeElement("RAILING", spec, geomResult.value, options?.stableKey);
6449
6465
  this.#associateMaterial(id, spec);
6450
6466
  this.#associateClassification(id, spec);
6451
6467
  return ok(id);
@@ -6455,10 +6471,12 @@ var BimModel = class {
6455
6471
  * IfcRelCoversBldgElements linking the covering to its host (e.g. a slab it
6456
6472
  * finishes) is recorded for export.
6457
6473
  */
6458
- addCovering(spec, hostLocalId) {
6474
+ addCovering(spec, hostLocalId, options) {
6475
+ const keyCheck = this.#checkStableKey(options);
6476
+ if (!keyCheck.ok) return keyCheck;
6459
6477
  const geomResult = coveringToSolid(spec);
6460
6478
  if (!geomResult.ok) return err(geomResult.error);
6461
- const id = this.#makeElement("COVERING", spec, geomResult.value);
6479
+ const id = this.#makeElement("COVERING", spec, geomResult.value, options?.stableKey);
6462
6480
  this.#associateMaterial(id, spec);
6463
6481
  this.#associateClassification(id, spec);
6464
6482
  if (hostLocalId !== void 0) this.#makeRel({
@@ -6473,24 +6491,30 @@ var BimModel = class {
6473
6491
  * attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
6474
6492
  * (IfcRelNests, order-preserving). Returns the assembly's localId.
6475
6493
  */
6476
- addElementAssembly(spec) {
6477
- return this.#makeElement("ELEMENT_ASSEMBLY", spec, null);
6494
+ addElementAssembly(spec, options) {
6495
+ const keyCheck = this.#checkStableKey(options);
6496
+ if (!keyCheck.ok) return keyCheck;
6497
+ return ok(this.#makeElement("ELEMENT_ASSEMBLY", spec, null, options?.stableKey));
6478
6498
  }
6479
6499
  /**
6480
6500
  * Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
6481
6501
  * carries no geometry; attach members (spaces or other elements) with
6482
- * {@link assignToGroup}. Returns the zone's localId.
6502
+ * {@link assignToGroup}. Returns the zone's localId as a Result.
6483
6503
  */
6484
- addZone(spec) {
6485
- return this.#makeElement("ZONE", spec, null);
6504
+ addZone(spec, options) {
6505
+ const keyCheck = this.#checkStableKey(options);
6506
+ if (!keyCheck.ok) return keyCheck;
6507
+ return ok(this.#makeElement("ZONE", spec, null, options?.stableKey));
6486
6508
  }
6487
6509
  /**
6488
6510
  * Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
6489
6511
  * system carries no geometry; attach members with {@link assignToGroup}.
6490
- * Returns the system's localId.
6512
+ * Returns the system's localId as a Result.
6491
6513
  */
6492
- addSystem(spec) {
6493
- return this.#makeElement("SYSTEM", spec, null);
6514
+ addSystem(spec, options) {
6515
+ const keyCheck = this.#checkStableKey(options);
6516
+ if (!keyCheck.ok) return keyCheck;
6517
+ return ok(this.#makeElement("SYSTEM", spec, null, options?.stableKey));
6494
6518
  }
6495
6519
  /**
6496
6520
  * Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
@@ -6626,9 +6650,11 @@ var BimModel = class {
6626
6650
  * and disposes it on model disposal; the caller must not dispose it (see
6627
6651
  * {@link ProxySpec.solid}).
6628
6652
  */
6629
- addProxy(spec) {
6653
+ addProxy(spec, options) {
6654
+ const keyCheck = this.#checkStableKey(options);
6655
+ if (!keyCheck.ok) return keyCheck;
6630
6656
  if (spec.solid === null || spec.solid === void 0) return err(specError("PROXY_NO_GEOMETRY", "ProxySpec.solid is required"));
6631
- const id = this.#makeElement("PROXY", spec, spec.solid);
6657
+ const id = this.#makeElement("PROXY", spec, spec.solid, options?.stableKey);
6632
6658
  if (spec.materialName !== void 0) this.#makeRel({
6633
6659
  kind: "ASSOCIATES_MATERIAL",
6634
6660
  materialName: spec.materialName,
@@ -16710,9 +16736,18 @@ function familiesToBim(root, options) {
16710
16736
  const model = new BimModel();
16711
16737
  const initResult = model.init(options.project);
16712
16738
  if (!initResult.ok) return initResult;
16713
- const siteId = model.addSite({ name: options.siteName ?? "Site" });
16714
- const buildingId = model.addBuilding({ name: options.buildingName ?? "Building" });
16715
- model.aggregate(siteId, buildingId);
16739
+ const siteResult = model.addSite({ name: options.siteName ?? "Site" });
16740
+ if (!siteResult.ok) {
16741
+ model[Symbol.dispose]();
16742
+ return siteResult;
16743
+ }
16744
+ const buildingResult = model.addBuilding({ name: options.buildingName ?? "Building" });
16745
+ if (!buildingResult.ok) {
16746
+ model[Symbol.dispose]();
16747
+ return buildingResult;
16748
+ }
16749
+ const buildingId = buildingResult.value;
16750
+ model.aggregate(siteResult.value, buildingId);
16716
16751
  const idByKeyPath = /* @__PURE__ */ new Map();
16717
16752
  const walk = (el, storeyId) => {
16718
16753
  let containerId = storeyId;
@@ -16720,13 +16755,14 @@ function familiesToBim(root, options) {
16720
16755
  if (el.type === "Storey") {
16721
16756
  const keyed = requireKeyed(el);
16722
16757
  if (!keyed.ok) return keyed;
16723
- const id = model.addStorey({
16758
+ const storeyResult = model.addStorey({
16724
16759
  name: el.attributes["name"] ?? el.keyPath,
16725
16760
  elevation: el.props["elevation"] ?? 0
16726
16761
  }, { stableKey: el.keyPath });
16727
- model.aggregate(buildingId, id);
16728
- idByKeyPath.set(el.keyPath, id);
16729
- containerId = id;
16762
+ if (!storeyResult.ok) return storeyResult;
16763
+ model.aggregate(buildingId, storeyResult.value);
16764
+ idByKeyPath.set(el.keyPath, storeyResult.value);
16765
+ containerId = storeyResult.value;
16730
16766
  } else if (route !== void 0) {
16731
16767
  const keyed = requireKeyed(el);
16732
16768
  if (!keyed.ok) return keyed;
@@ -37,18 +37,18 @@ export declare class BimModel {
37
37
  #private;
38
38
  init(spec: ProjectSpec): Result<LocalId, BimError>;
39
39
  [Symbol.dispose](): void;
40
- addSite(spec: SiteSpec): LocalId;
41
- addBuilding(spec: BuildingSpec, options?: ElementIdentityOptions): LocalId;
42
- addStorey(spec: StoreySpec, options?: ElementIdentityOptions): LocalId;
40
+ addSite(spec: SiteSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
41
+ addBuilding(spec: BuildingSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
42
+ addStorey(spec: StoreySpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
43
43
  addWall(spec: WallSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
44
44
  addSlab(spec: SlabSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
45
45
  addBeam(spec: BeamSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
46
46
  addColumn(spec: ColumnSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
47
- addSpace(spec: SpaceSpec): Result<LocalId, BimError>;
47
+ addSpace(spec: SpaceSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
48
48
  addRoof(spec: RoofSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
49
- addCurtainWall(spec: CurtainWallSpec): Result<LocalId, BimError>;
50
- addFooting(spec: FootingSpec): Result<LocalId, BimError>;
51
- addPile(spec: PileSpec): Result<LocalId, BimError>;
49
+ addCurtainWall(spec: CurtainWallSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
50
+ addFooting(spec: FootingSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
51
+ addPile(spec: PileSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
52
52
  /**
53
53
  * Adds an IfcStair assembly. Geometry for each flight is built and written by
54
54
  * the IFC layer from `spec.flights`; the STAIR element itself carries no solid
@@ -60,31 +60,31 @@ export declare class BimModel {
60
60
  * IFC layer from `spec.flights`; the RAMP element carries no solid of its own.
61
61
  */
62
62
  addRamp(spec: RampSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
63
- addRailing(spec: RailingSpec): Result<LocalId, BimError>;
63
+ addRailing(spec: RailingSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
64
64
  /**
65
65
  * Adds an IfcCovering. When `hostLocalId` is supplied, an
66
66
  * IfcRelCoversBldgElements linking the covering to its host (e.g. a slab it
67
67
  * finishes) is recorded for export.
68
68
  */
69
- addCovering(spec: CoveringSpec, hostLocalId?: LocalId): Result<LocalId, BimError>;
69
+ addCovering(spec: CoveringSpec, hostLocalId?: LocalId, options?: ElementIdentityOptions): Result<LocalId, BimError>;
70
70
  /**
71
71
  * Adds an IfcElementAssembly grouping container. The assembly has no geometry;
72
72
  * attach parts with {@link aggregate} (IfcRelAggregates) or {@link nest}
73
73
  * (IfcRelNests, order-preserving). Returns the assembly's localId.
74
74
  */
75
- addElementAssembly(spec: ElementAssemblySpec): LocalId;
75
+ addElementAssembly(spec: ElementAssemblySpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
76
76
  /**
77
77
  * Adds an IfcZone grouping object (a thermal/fire/occupancy zone). The zone
78
78
  * carries no geometry; attach members (spaces or other elements) with
79
- * {@link assignToGroup}. Returns the zone's localId.
79
+ * {@link assignToGroup}. Returns the zone's localId as a Result.
80
80
  */
81
- addZone(spec: ZoneSpec): LocalId;
81
+ addZone(spec: ZoneSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
82
82
  /**
83
83
  * Adds an IfcSystem grouping object (an HVAC/electrical/plumbing system). The
84
84
  * system carries no geometry; attach members with {@link assignToGroup}.
85
- * Returns the system's localId.
85
+ * Returns the system's localId as a Result.
86
86
  */
87
- addSystem(spec: SystemSpec): LocalId;
87
+ addSystem(spec: SystemSpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
88
88
  /**
89
89
  * Assigns members to a zone or system via IfcRelAssignsToGroup. Repeated calls
90
90
  * for the same group extend the single relationship in call order. Returns the
@@ -130,7 +130,7 @@ export declare class BimModel {
130
130
  * and disposes it on model disposal; the caller must not dispose it (see
131
131
  * {@link ProxySpec.solid}).
132
132
  */
133
- addProxy(spec: ProxySpec): Result<LocalId, BimError>;
133
+ addProxy(spec: ProxySpec, options?: ElementIdentityOptions): Result<LocalId, BimError>;
134
134
  addDoor(spec: DoorSpec, options?: OpeningIdentityOptions): Result<LocalId, BimError>;
135
135
  addWindow(spec: WindowSpec, options?: OpeningIdentityOptions): Result<LocalId, BimError>;
136
136
  addSlabOpening(input: SlabOpeningInput, options?: ElementIdentityOptions): Result<LocalId, BimError>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs-bim",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "BIM layer for brepjs — IFC4-aligned parametric building elements",
5
5
  "keywords": [
6
6
  "bim",