brepjs-bim 0.3.1 → 0.4.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.
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
20
20
  value: mod,
21
21
  enumerable: true
22
22
  }) : target, mod));
@@ -27,7 +27,7 @@ web_ifc = __toESM(web_ifc, 1);
27
27
  //#region src/identity/ifcGuid.ts
28
28
  var IFC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
29
29
  function newIfcGuid() {
30
- const bytes = crypto.getRandomValues(new Uint8Array(16));
30
+ const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
31
31
  bytes[6] = (bytes[6] ?? 0) & 15 | 64;
32
32
  bytes[8] = (bytes[8] ?? 0) & 63 | 128;
33
33
  return encodeIfcGuid(bytes);
@@ -69,7 +69,7 @@ function fnv1a(text) {
69
69
  }
70
70
  function digest16(stableKey) {
71
71
  const seed = `${NAMESPACE}::${stableKey}`;
72
- const bytes = new Uint8Array(16);
72
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
73
73
  for (let block = 0; block < 4; block++) {
74
74
  const h = fnv1a(`b${block}:${seed}`);
75
75
  bytes[block * 4 + 0] = h >>> 24 & 255;
@@ -206,7 +206,7 @@ function fromBrepError(inner, code, message) {
206
206
  };
207
207
  }
208
208
  //#endregion
209
- //#region \0@oxc-project+runtime@0.133.0/helpers/esm/usingCtx.js
209
+ //#region \0@oxc-project+runtime@0.143.0/helpers/esm/usingCtx.js
210
210
  function _usingCtx() {
211
211
  var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
212
212
  var n = Error();
@@ -293,7 +293,8 @@ function wallToSolid(spec) {
293
293
  ]
294
294
  ]);
295
295
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "WALL_PROFILE_FAILED", "Failed to create wall profile"));
296
- const solidResult = (0, brepjs.extrude)(_usingCtx$19.u(profileResult.value), [
296
+ const profile = _usingCtx$19.u(profileResult.value);
297
+ const solidResult = (0, brepjs.extrude)(profile, [
297
298
  length,
298
299
  0,
299
300
  0
@@ -343,7 +344,8 @@ function slabToSolid(spec) {
343
344
  ]
344
345
  ]);
345
346
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_PROFILE_FAILED", "Failed to create slab profile"));
346
- const solidResult = (0, brepjs.extrude)(_usingCtx$18.u(profileResult.value), [
347
+ const profile = _usingCtx$18.u(profileResult.value);
348
+ const solidResult = (0, brepjs.extrude)(profile, [
347
349
  0,
348
350
  0,
349
351
  thickness
@@ -437,7 +439,6 @@ function cached(getter) {
437
439
  Object.defineProperty(this, "value", { value });
438
440
  return value;
439
441
  }
440
- throw new Error("cached value already set");
441
442
  } };
442
443
  }
443
444
  function nullish(input) {
@@ -483,7 +484,10 @@ function assignProp(target, prop, value) {
483
484
  }
484
485
  function mergeDefs(...defs) {
485
486
  const mergedDescriptors = {};
486
- for (const def of defs) Object.assign(mergedDescriptors, Object.getOwnPropertyDescriptors(def));
487
+ for (const def of defs) {
488
+ const descriptors = Object.getOwnPropertyDescriptors(def);
489
+ Object.assign(mergedDescriptors, descriptors);
490
+ }
487
491
  return Object.defineProperties({}, mergedDescriptors);
488
492
  }
489
493
  function esc(str) {
@@ -805,7 +809,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
805
809
  }, ctx);
806
810
  if (result instanceof Promise) throw new $ZodAsyncError();
807
811
  if (result.issues.length) {
808
- const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
812
+ const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
809
813
  captureStackTrace(e, _params?.callee);
810
814
  throw e;
811
815
  }
@@ -822,7 +826,7 @@ var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
822
826
  }, ctx);
823
827
  if (result instanceof Promise) result = await result;
824
828
  if (result.issues.length) {
825
- const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
829
+ const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
826
830
  captureStackTrace(e, params?.callee);
827
831
  throw e;
828
832
  }
@@ -989,8 +993,10 @@ var $ZodCheckLessThan = /*@__PURE__*/ $constructor("$ZodCheckLessThan", (inst, d
989
993
  inst._zod.onattach.push((inst) => {
990
994
  const bag = inst._zod.bag;
991
995
  const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY;
992
- if (def.value < curr) if (def.inclusive) bag.maximum = def.value;
993
- else bag.exclusiveMaximum = def.value;
996
+ if (def.value < curr) {
997
+ if (def.inclusive) bag.maximum = def.value;
998
+ else bag.exclusiveMaximum = def.value;
999
+ }
994
1000
  });
995
1001
  inst._zod.check = (payload) => {
996
1002
  if (def.inclusive ? payload.value <= def.value : payload.value < def.value) return;
@@ -1011,8 +1017,10 @@ var $ZodCheckGreaterThan = /*@__PURE__*/ $constructor("$ZodCheckGreaterThan", (i
1011
1017
  inst._zod.onattach.push((inst) => {
1012
1018
  const bag = inst._zod.bag;
1013
1019
  const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY;
1014
- if (def.value > curr) if (def.inclusive) bag.minimum = def.value;
1015
- else bag.exclusiveMinimum = def.value;
1020
+ if (def.value > curr) {
1021
+ if (def.inclusive) bag.minimum = def.value;
1022
+ else bag.exclusiveMinimum = def.value;
1023
+ }
1016
1024
  });
1017
1025
  inst._zod.check = (payload) => {
1018
1026
  if (def.inclusive ? payload.value >= def.value : payload.value > def.value) return;
@@ -2545,7 +2553,7 @@ var $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => {
2545
2553
  inst._zod.optin = "optional";
2546
2554
  inst._zod.optout = "optional";
2547
2555
  defineLazy(inst._zod, "values", () => {
2548
- return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0;
2556
+ return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0;
2549
2557
  });
2550
2558
  defineLazy(inst._zod, "pattern", () => {
2551
2559
  const pattern = def.innerType._zod.pattern;
@@ -2579,7 +2587,7 @@ var $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => {
2579
2587
  return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0;
2580
2588
  });
2581
2589
  defineLazy(inst._zod, "values", () => {
2582
- return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0;
2590
+ return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0;
2583
2591
  });
2584
2592
  inst._zod.parse = (payload, ctx) => {
2585
2593
  if (payload.value === null) return payload;
@@ -3513,8 +3521,10 @@ function finalize$1(ctx, schema) {
3513
3521
  defs[seen.defId] = seen.def;
3514
3522
  }
3515
3523
  }
3516
- if (ctx.external) {} else if (Object.keys(defs).length > 0) if (ctx.target === "draft-2020-12") result.$defs = defs;
3517
- else result.definitions = defs;
3524
+ if (ctx.external) {} else if (Object.keys(defs).length > 0) {
3525
+ if (ctx.target === "draft-2020-12") result.$defs = defs;
3526
+ else result.definitions = defs;
3527
+ }
3518
3528
  try {
3519
3529
  const finalized = JSON.parse(JSON.stringify(result));
3520
3530
  Object.defineProperty(finalized, "~standard", {
@@ -3627,16 +3637,18 @@ var numberProcessor = (schema, ctx, _json, _params) => {
3627
3637
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
3628
3638
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
3629
3639
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
3630
- if (exMin) if (legacy) {
3631
- json.minimum = exclusiveMinimum;
3632
- json.exclusiveMinimum = true;
3633
- } else json.exclusiveMinimum = exclusiveMinimum;
3634
- else if (typeof minimum === "number") json.minimum = minimum;
3635
- if (exMax) if (legacy) {
3636
- json.maximum = exclusiveMaximum;
3637
- json.exclusiveMaximum = true;
3638
- } else json.exclusiveMaximum = exclusiveMaximum;
3639
- else if (typeof maximum === "number") json.maximum = maximum;
3640
+ if (exMin) {
3641
+ if (legacy) {
3642
+ json.minimum = exclusiveMinimum;
3643
+ json.exclusiveMinimum = true;
3644
+ } else json.exclusiveMinimum = exclusiveMinimum;
3645
+ } else if (typeof minimum === "number") json.minimum = minimum;
3646
+ if (exMax) {
3647
+ if (legacy) {
3648
+ json.maximum = exclusiveMaximum;
3649
+ json.exclusiveMaximum = true;
3650
+ } else json.exclusiveMaximum = exclusiveMaximum;
3651
+ } else if (typeof maximum === "number") json.maximum = maximum;
3640
3652
  if (typeof multipleOf === "number") json.multipleOf = multipleOf;
3641
3653
  };
3642
3654
  var booleanProcessor = (_schema, _ctx, json, _params) => {
@@ -3657,9 +3669,10 @@ var literalProcessor = (schema, ctx, json, _params) => {
3657
3669
  const vals = [];
3658
3670
  for (const val of def.values) if (val === void 0) {
3659
3671
  if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
3660
- } else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
3661
- else vals.push(Number(val));
3662
- else vals.push(val);
3672
+ } else if (typeof val === "bigint") {
3673
+ if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
3674
+ else vals.push(Number(val));
3675
+ } else vals.push(val);
3663
3676
  if (vals.length === 0) {} else if (vals.length === 1) {
3664
3677
  const val = vals[0];
3665
3678
  json.type = val === null ? "null" : typeof val;
@@ -5074,7 +5087,7 @@ function extendedProfileToFace(profile) {
5074
5087
  }
5075
5088
  //#endregion
5076
5089
  //#region src/specs/profile.ts
5077
- var EXTENDED_PROFILE_KIND_SET = new Set([
5090
+ var EXTENDED_PROFILE_KIND_SET = /* @__PURE__ */ new Set([
5078
5091
  "L_SHAPE",
5079
5092
  "T_SHAPE",
5080
5093
  "U_SHAPE",
@@ -5298,7 +5311,7 @@ function profileToPolygon(profile, circleSegments = 32) {
5298
5311
  case "RECTANGULAR": {
5299
5312
  const halfW = profile.width / 2;
5300
5313
  const halfH = profile.height / 2;
5301
- return (0, brepjs.ok)([
5314
+ const pts = [
5302
5315
  [
5303
5316
  -halfW,
5304
5317
  -halfH,
@@ -5319,7 +5332,8 @@ function profileToPolygon(profile, circleSegments = 32) {
5319
5332
  halfH,
5320
5333
  0
5321
5334
  ]
5322
- ]);
5335
+ ];
5336
+ return (0, brepjs.ok)(pts);
5323
5337
  }
5324
5338
  case "CIRCULAR": {
5325
5339
  if (circleSegments < 3) return (0, brepjs.err)(specError("PROFILE_CIRCLE_SEGMENTS", `profileToPolygon: circleSegments must be >= 3, got ${circleSegments}`));
@@ -5354,7 +5368,7 @@ function profileToPolygon(profile, circleSegments = 32) {
5354
5368
  [-halfW, -flangeInnerY]
5355
5369
  ];
5356
5370
  const r = profile.filletRadius ?? 0;
5357
- const rootCorners = new Set([
5371
+ const rootCorners = /* @__PURE__ */ new Set([
5358
5372
  3,
5359
5373
  4,
5360
5374
  9,
@@ -5396,13 +5410,15 @@ function beamToSolid(spec) {
5396
5410
  var _usingCtx3 = _usingCtx();
5397
5411
  const faceResult = extendedProfileToFace(spec.profile);
5398
5412
  if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
5399
- const prismResult = (0, brepjs.extrude)(_usingCtx3.u(faceResult.value), [
5413
+ const face = _usingCtx3.u(faceResult.value);
5414
+ const prismResult = (0, brepjs.extrude)(face, [
5400
5415
  0,
5401
5416
  0,
5402
5417
  spec.length
5403
5418
  ]);
5404
5419
  if (!prismResult.ok) return (0, brepjs.err)(fromBrepError(prismResult.error, "BEAM_EXTRUDE_FAILED", "Failed to extrude beam profile"));
5405
- const solid = (0, brepjs.rotate)(_usingCtx3.u(prismResult.value), 90, { axis: [
5420
+ const prism = _usingCtx3.u(prismResult.value);
5421
+ const solid = (0, brepjs.rotate)(prism, 90, { axis: [
5406
5422
  0,
5407
5423
  1,
5408
5424
  0
@@ -5419,13 +5435,15 @@ function beamToSolid(spec) {
5419
5435
  }
5420
5436
  const profilePtsResult = profileToPolygon(spec.profile);
5421
5437
  if (!profilePtsResult.ok) return (0, brepjs.err)(profilePtsResult.error);
5422
- const profileResult = (0, brepjs.polygon)(profilePtsResult.value.map(([px, py]) => [
5438
+ const profilePts = profilePtsResult.value.map(([px, py]) => [
5423
5439
  0,
5424
5440
  px,
5425
5441
  py
5426
- ]));
5442
+ ]);
5443
+ const profileResult = (0, brepjs.polygon)(profilePts);
5427
5444
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "BEAM_PROFILE_FAILED", "Failed to create beam profile"));
5428
- const solidResult = (0, brepjs.extrude)(_usingCtx$16.u(profileResult.value), [
5445
+ const profile = _usingCtx$16.u(profileResult.value);
5446
+ const solidResult = (0, brepjs.extrude)(profile, [
5429
5447
  spec.length,
5430
5448
  0,
5431
5449
  0
@@ -5453,7 +5471,8 @@ function columnToSolid(spec) {
5453
5471
  var _usingCtx3 = _usingCtx();
5454
5472
  const faceResult = extendedProfileToFace(spec.profile);
5455
5473
  if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
5456
- const extResult = (0, brepjs.extrude)(_usingCtx3.u(faceResult.value), [
5474
+ const face = _usingCtx3.u(faceResult.value);
5475
+ const extResult = (0, brepjs.extrude)(face, [
5457
5476
  0,
5458
5477
  0,
5459
5478
  spec.height
@@ -5475,7 +5494,8 @@ function columnToSolid(spec) {
5475
5494
  const profilePts = profilePtsResult.value;
5476
5495
  const profileResult = (0, brepjs.polygon)(profilePts);
5477
5496
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COLUMN_PROFILE_FAILED", "Failed to create column profile"));
5478
- const solidResult = (0, brepjs.extrude)(_usingCtx$15.u(profileResult.value), [
5497
+ const profile = _usingCtx$15.u(profileResult.value);
5498
+ const solidResult = (0, brepjs.extrude)(profile, [
5479
5499
  0,
5480
5500
  0,
5481
5501
  spec.height
@@ -5495,7 +5515,7 @@ function columnToSolid(spec) {
5495
5515
  }
5496
5516
  //#endregion
5497
5517
  //#region src/elementFns/openingFns.ts
5498
- var EPSILON_MM$1 = 1;
5518
+ var EPSILON_MM = 1;
5499
5519
  function openingToSolid(spec, wallThickness) {
5500
5520
  try {
5501
5521
  var _usingCtx$14 = _usingCtx();
@@ -5504,7 +5524,7 @@ function openingToSolid(spec, wallThickness) {
5504
5524
  if (wallThickness <= 0) return (0, brepjs.err)(specError("OPENING_ZERO_WALL_THICKNESS", "Wall thickness must be positive"));
5505
5525
  const x0 = spec.offsetAlongWall;
5506
5526
  const yLow = -1;
5507
- const yHigh = wallThickness + EPSILON_MM$1;
5527
+ const yHigh = wallThickness + EPSILON_MM;
5508
5528
  const zLow = spec.offsetFromFloor;
5509
5529
  const zHigh = spec.offsetFromFloor + spec.height;
5510
5530
  const profileResult = (0, brepjs.polygon)([
@@ -5530,7 +5550,8 @@ function openingToSolid(spec, wallThickness) {
5530
5550
  ]
5531
5551
  ]);
5532
5552
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "OPENING_PROFILE_FAILED", "Failed to create opening profile"));
5533
- const solidResult = (0, brepjs.extrude)(_usingCtx$14.u(profileResult.value), [
5553
+ const profile = _usingCtx$14.u(profileResult.value);
5554
+ const solidResult = (0, brepjs.extrude)(profile, [
5534
5555
  spec.width,
5535
5556
  0,
5536
5557
  0
@@ -5550,7 +5571,6 @@ function openingToSolid(spec, wallThickness) {
5550
5571
  }
5551
5572
  //#endregion
5552
5573
  //#region src/elementFns/slabOpeningFns.ts
5553
- var EPSILON_MM = 1;
5554
5574
  function slabOpeningToSolid(spec, slabThickness) {
5555
5575
  try {
5556
5576
  var _usingCtx$13 = _usingCtx();
@@ -5585,10 +5605,11 @@ function slabOpeningToSolid(spec, slabThickness) {
5585
5605
  ]
5586
5606
  ]);
5587
5607
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SLAB_OPENING_PROFILE_FAILED", "Failed to create slab opening profile"));
5588
- const solidResult = (0, brepjs.extrude)(_usingCtx$13.u(profileResult.value), [
5608
+ const profile = _usingCtx$13.u(profileResult.value);
5609
+ const solidResult = (0, brepjs.extrude)(profile, [
5589
5610
  0,
5590
5611
  0,
5591
- slabThickness + 2 * EPSILON_MM
5612
+ slabThickness + 2
5592
5613
  ]);
5593
5614
  if (!solidResult.ok) return (0, brepjs.err)(fromBrepError(solidResult.error, "SLAB_OPENING_EXTRUDE_FAILED", "Failed to extrude slab opening profile"));
5594
5615
  const solid = solidResult.value;
@@ -5635,7 +5656,8 @@ function spaceToSolid(spec) {
5635
5656
  ]
5636
5657
  ]);
5637
5658
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "SPACE_PROFILE_FAILED", "Failed to create space footprint"));
5638
- const solidResult = (0, brepjs.extrude)(_usingCtx$12.u(profileResult.value), [
5659
+ const profile = _usingCtx$12.u(profileResult.value);
5660
+ const solidResult = (0, brepjs.extrude)(profile, [
5639
5661
  0,
5640
5662
  0,
5641
5663
  height
@@ -5690,7 +5712,8 @@ function flatRoof(spec) {
5690
5712
  ]
5691
5713
  ]);
5692
5714
  if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create roof profile"));
5693
- const solid = (0, brepjs.extrude)(_usingCtx$11.u(face.value), [
5715
+ const profile = _usingCtx$11.u(face.value);
5716
+ const solid = (0, brepjs.extrude)(profile, [
5694
5717
  0,
5695
5718
  0,
5696
5719
  thickness
@@ -5731,7 +5754,8 @@ function shedRoof(spec, pitch) {
5731
5754
  ]
5732
5755
  ]);
5733
5756
  if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create shed profile"));
5734
- const solid = (0, brepjs.extrude)(_usingCtx3.u(face.value), [
5757
+ const profile = _usingCtx3.u(face.value);
5758
+ const solid = (0, brepjs.extrude)(profile, [
5735
5759
  length,
5736
5760
  0,
5737
5761
  0
@@ -5777,7 +5801,8 @@ function gableRoof(spec, pitch) {
5777
5801
  ]
5778
5802
  ]);
5779
5803
  if (!face.ok) return (0, brepjs.err)(fromBrepError(face.error, "ROOF_PROFILE_FAILED", "Failed to create gable profile"));
5780
- const solid = (0, brepjs.extrude)(_usingCtx4.u(face.value), [
5804
+ const profile = _usingCtx4.u(face.value);
5805
+ const solid = (0, brepjs.extrude)(profile, [
5781
5806
  length,
5782
5807
  0,
5783
5808
  0
@@ -5918,7 +5943,8 @@ function boxSolid(sizeX, sizeY, sizeZ) {
5918
5943
  ]
5919
5944
  ]);
5920
5945
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "CURTAIN_WALL_PROFILE_FAILED", "Failed to create component profile"));
5921
- const solidResult = (0, brepjs.extrude)(_usingCtx$10.u(profileResult.value), [
5946
+ const profile = _usingCtx$10.u(profileResult.value);
5947
+ const solidResult = (0, brepjs.extrude)(profile, [
5922
5948
  0,
5923
5949
  0,
5924
5950
  sizeZ
@@ -6060,7 +6086,8 @@ function footingToSolid(spec) {
6060
6086
  ]
6061
6087
  ]);
6062
6088
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "FOOTING_PROFILE_FAILED", "Failed to create footing profile"));
6063
- const solidResult = (0, brepjs.extrude)(_usingCtx$9.u(profileResult.value), [
6089
+ const profile = _usingCtx$9.u(profileResult.value);
6090
+ const solidResult = (0, brepjs.extrude)(profile, [
6064
6091
  0,
6065
6092
  0,
6066
6093
  thickness
@@ -6086,7 +6113,8 @@ function pileToSolid(spec) {
6086
6113
  var _usingCtx4 = _usingCtx();
6087
6114
  const faceResult = extendedProfileToFace(spec.profile);
6088
6115
  if (!faceResult.ok) return (0, brepjs.err)(faceResult.error);
6089
- const extResult = (0, brepjs.extrude)(_usingCtx4.u(faceResult.value), [
6116
+ const face = _usingCtx4.u(faceResult.value);
6117
+ const extResult = (0, brepjs.extrude)(face, [
6090
6118
  0,
6091
6119
  0,
6092
6120
  spec.length
@@ -6108,7 +6136,8 @@ function pileToSolid(spec) {
6108
6136
  const profilePts = profilePtsResult.value;
6109
6137
  const profileResult = (0, brepjs.polygon)(profilePts);
6110
6138
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "PILE_PROFILE_FAILED", "Failed to create pile profile"));
6111
- const solidResult = (0, brepjs.extrude)(_usingCtx3.u(profileResult.value), [
6139
+ const profile = _usingCtx3.u(profileResult.value);
6140
+ const solidResult = (0, brepjs.extrude)(profile, [
6112
6141
  0,
6113
6142
  0,
6114
6143
  spec.length
@@ -6155,7 +6184,8 @@ function panelRailing(spec) {
6155
6184
  ]
6156
6185
  ]);
6157
6186
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAILING_PROFILE_FAILED", "Failed to create railing profile"));
6158
- const solidResult = (0, brepjs.extrude)(_usingCtx$8.u(profileResult.value), [
6187
+ const profile = _usingCtx$8.u(profileResult.value);
6188
+ const solidResult = (0, brepjs.extrude)(profile, [
6159
6189
  length,
6160
6190
  0,
6161
6191
  0
@@ -6261,7 +6291,8 @@ function coveringToSolid(spec) {
6261
6291
  ]
6262
6292
  ]);
6263
6293
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "COVERING_PROFILE_FAILED", "Failed to create covering profile"));
6264
- const solidResult = (0, brepjs.extrude)(_usingCtx$7.u(profileResult.value), [
6294
+ const profile = _usingCtx$7.u(profileResult.value);
6295
+ const solidResult = (0, brepjs.extrude)(profile, [
6265
6296
  0,
6266
6297
  0,
6267
6298
  thickness
@@ -6288,6 +6319,7 @@ var BimModel = class {
6288
6319
  #counter = makeLocalIdCounter();
6289
6320
  #projectId = null;
6290
6321
  #modelScope = "";
6322
+ #usedStableKeys = /* @__PURE__ */ new Set();
6291
6323
  init(spec) {
6292
6324
  if (this.#projectId !== null) return (0, brepjs.err)(specError("DUPLICATE_PROJECT", "BimModel.init() called twice — only one project per model"));
6293
6325
  this.#modelScope = spec.projectId ?? `${spec.name}::${spec.description ?? ""}`;
@@ -6305,24 +6337,35 @@ var BimModel = class {
6305
6337
  addSite(spec) {
6306
6338
  return this.#makeElement("SITE", spec, null);
6307
6339
  }
6308
- addBuilding(spec) {
6309
- return this.#makeElement("BUILDING", spec, null);
6340
+ addBuilding(spec, options) {
6341
+ return this.#makeElement("BUILDING", spec, null, options?.stableKey);
6310
6342
  }
6311
- addStorey(spec) {
6312
- return this.#makeElement("STOREY", spec, null);
6343
+ addStorey(spec, options) {
6344
+ return this.#makeElement("STOREY", spec, null, options?.stableKey);
6313
6345
  }
6314
- addWall(spec) {
6346
+ /** Reject a duplicate stableKey BEFORE any geometry is built, so the
6347
+ * Result-returning adders never allocate a solid they cannot store. */
6348
+ #checkStableKey(options) {
6349
+ const key = options?.stableKey;
6350
+ if (key !== void 0 && this.#usedStableKeys.has(key)) return (0, brepjs.err)(specError("DUPLICATE_STABLE_KEY", `BimModel: duplicate stableKey '${key}'`));
6351
+ return (0, brepjs.ok)(void 0);
6352
+ }
6353
+ addWall(spec, options) {
6354
+ const keyCheck = this.#checkStableKey(options);
6355
+ if (!keyCheck.ok) return keyCheck;
6315
6356
  const geomResult = wallToSolid(spec);
6316
6357
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6317
- const id = this.#makeElement("WALL", spec, geomResult.value);
6358
+ const id = this.#makeElement("WALL", spec, geomResult.value, options?.stableKey);
6318
6359
  this.#associateMaterial(id, spec);
6319
6360
  this.#associateClassification(id, spec);
6320
6361
  return (0, brepjs.ok)(id);
6321
6362
  }
6322
- addSlab(spec) {
6363
+ addSlab(spec, options) {
6364
+ const keyCheck = this.#checkStableKey(options);
6365
+ if (!keyCheck.ok) return keyCheck;
6323
6366
  const geomResult = slabToSolid(spec);
6324
6367
  if (!geomResult.ok) return (0, brepjs.err)(geomResult.error);
6325
- const id = this.#makeElement("SLAB", spec, geomResult.value);
6368
+ const id = this.#makeElement("SLAB", spec, geomResult.value, options?.stableKey);
6326
6369
  this.#associateMaterial(id, spec);
6327
6370
  this.#associateClassification(id, spec);
6328
6371
  return (0, brepjs.ok)(id);
@@ -6941,10 +6984,14 @@ var BimModel = class {
6941
6984
  getAllRelationships() {
6942
6985
  return [...this.#relationships.values()];
6943
6986
  }
6944
- #makeElement(category, spec, geometry) {
6987
+ #makeElement(category, spec, geometry, stableKey) {
6945
6988
  const localId = this.#counter.next();
6989
+ if (stableKey !== void 0) {
6990
+ if (this.#usedStableKeys.has(stableKey)) throw new Error(`BimModel: duplicate stableKey '${stableKey}'`);
6991
+ this.#usedStableKeys.add(stableKey);
6992
+ }
6946
6993
  const el = {
6947
- guid: deriveIfcGuidSync(makeElementKey(this.#modelScope, category, localId)),
6994
+ guid: deriveIfcGuidSync(stableKey !== void 0 ? `elem:${this.#modelScope}:${stableKey}` : makeElementKey(this.#modelScope, category, localId)),
6948
6995
  localId,
6949
6996
  category,
6950
6997
  spec,
@@ -7191,9 +7238,11 @@ function stairFlightToSolid(spec) {
7191
7238
  if (spec.riserHeight <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_RISER", "Stair flight riserHeight must be positive"));
7192
7239
  if (spec.treadLength <= 0) return (0, brepjs.err)(specError("STAIR_FLIGHT_ZERO_TREAD", "Stair flight treadLength must be positive"));
7193
7240
  if (!Number.isInteger(spec.numberOfRisers) || spec.numberOfRisers < 1) return (0, brepjs.err)(specError("STAIR_FLIGHT_BAD_RISERS", "Stair flight numberOfRisers must be a positive integer"));
7194
- const profileResult = (0, brepjs.polygon)(buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength));
7241
+ const silhouette = buildSilhouette$1(spec.numberOfRisers, spec.riserHeight, spec.treadLength);
7242
+ const profileResult = (0, brepjs.polygon)(silhouette);
7195
7243
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "STAIR_FLIGHT_PROFILE_FAILED", "Failed to create stair flight silhouette profile"));
7196
- const solidResult = (0, brepjs.extrude)(_usingCtx$5.u(profileResult.value), [
7244
+ const profile = _usingCtx$5.u(profileResult.value);
7245
+ const solidResult = (0, brepjs.extrude)(profile, [
7197
7246
  0,
7198
7247
  spec.width,
7199
7248
  0
@@ -7349,7 +7398,7 @@ function isIfcSchema(value) {
7349
7398
  * linear-infrastructure entities). Entities absent from every per-schema set are
7350
7399
  * treated as schema-agnostic and supported everywhere (open-world default).
7351
7400
  */
7352
- var IFC4X3_ONLY_ENTITIES = new Set([
7401
+ var IFC4X3_ONLY_ENTITIES = /* @__PURE__ */ new Set([
7353
7402
  "IfcAlignment",
7354
7403
  "IfcAlignmentHorizontal",
7355
7404
  "IfcAlignmentVertical",
@@ -7429,7 +7478,8 @@ var IfcWriter = class IfcWriter {
7429
7478
  try {
7430
7479
  const api = new web_ifc.IfcAPI();
7431
7480
  await initIfcApi(api);
7432
- return (0, brepjs.ok)(new IfcWriter(api, api.CreateModel({ schema: fileSchemaString(ifcSchema) }), mvdViewDefinition, header));
7481
+ const modelId = api.CreateModel({ schema: fileSchemaString(ifcSchema) });
7482
+ return (0, brepjs.ok)(new IfcWriter(api, modelId, mvdViewDefinition, header));
7433
7483
  } catch (e) {
7434
7484
  return (0, brepjs.err)(ifcError("IFC_INIT_FAILED", "Failed to initialize web-ifc", e));
7435
7485
  }
@@ -7483,8 +7533,10 @@ var IfcWriter = class IfcWriter {
7483
7533
  let head = new TextDecoder().decode(bytes.subarray(0, HEADER_SCAN));
7484
7534
  if (FILE_NAME_RE.test(head)) head = head.replace(FILE_NAME_RE, (_m, prefix, systems) => `${prefix}(${stepString(this.#author)}),(${stepString(this.#organization)}),${systems},${stepString("")})`);
7485
7535
  else console.warn("IfcWriter: FILE_NAME null-field pattern not found; author/organization/authorization left unpatched");
7486
- if (this.#mvdViewDefinition.length > 0) if (VIEW_DEFINITION_RE.test(head)) head = head.replace(VIEW_DEFINITION_RE, `ViewDefinition [${this.#mvdViewDefinition}]`);
7487
- else console.warn(`IfcWriter: FILE_DESCRIPTION ViewDefinition not found; MVD "${this.#mvdViewDefinition}" not declared`);
7536
+ if (this.#mvdViewDefinition.length > 0) {
7537
+ if (VIEW_DEFINITION_RE.test(head)) head = head.replace(VIEW_DEFINITION_RE, `ViewDefinition [${this.#mvdViewDefinition}]`);
7538
+ else console.warn(`IfcWriter: FILE_DESCRIPTION ViewDefinition not found; MVD "${this.#mvdViewDefinition}" not declared`);
7539
+ }
7488
7540
  const patchedHeadBytes = new TextEncoder().encode(head);
7489
7541
  const tail = bytes.subarray(HEADER_SCAN);
7490
7542
  const out = new Uint8Array(patchedHeadBytes.byteLength + tail.byteLength);
@@ -9403,9 +9455,11 @@ function rampFlightToSolid(spec) {
9403
9455
  if (spec.slope <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_SLOPE", "Ramp flight slope must be positive"));
9404
9456
  if (spec.thickness <= 0) return (0, brepjs.err)(specError("RAMP_FLIGHT_ZERO_THICKNESS", "Ramp flight thickness must be positive"));
9405
9457
  const rise = spec.length * spec.slope;
9406
- const profileResult = (0, brepjs.polygon)(buildSilhouette(spec.length, rise, spec.thickness));
9458
+ const silhouette = buildSilhouette(spec.length, rise, spec.thickness);
9459
+ const profileResult = (0, brepjs.polygon)(silhouette);
9407
9460
  if (!profileResult.ok) return (0, brepjs.err)(fromBrepError(profileResult.error, "RAMP_FLIGHT_PROFILE_FAILED", "Failed to create ramp flight silhouette profile"));
9408
- const solidResult = (0, brepjs.extrude)(_usingCtx$3.u(profileResult.value), [
9461
+ const profile = _usingCtx$3.u(profileResult.value);
9462
+ const solidResult = (0, brepjs.extrude)(profile, [
9409
9463
  0,
9410
9464
  spec.width,
9411
9465
  0
@@ -11731,7 +11785,7 @@ function isSlabOpening(spec) {
11731
11785
  * instead, and OPENINGs are tied to their host through VOIDS rels — neither
11732
11786
  * participates in containment, so excluding them here avoids false orphans.
11733
11787
  */
11734
- var CONTAINABLE_CATEGORIES = new Set([
11788
+ var CONTAINABLE_CATEGORIES = /* @__PURE__ */ new Set([
11735
11789
  "WALL",
11736
11790
  "SLAB",
11737
11791
  "BEAM",
@@ -12528,14 +12582,15 @@ async function toIfcValidated(model, meta) {
12528
12582
  const geometry = collectGeometryIssues(model);
12529
12583
  const schema = await checkSchema(bytes);
12530
12584
  const roundTrip = await checkRoundTrip(bytes);
12585
+ const report = { issues: [
12586
+ ...integrity.issues,
12587
+ ...geometry.issues,
12588
+ ...schema.issues,
12589
+ ...roundTrip.issues
12590
+ ] };
12531
12591
  return (0, brepjs.ok)({
12532
12592
  bytes,
12533
- report: { issues: [
12534
- ...integrity.issues,
12535
- ...geometry.issues,
12536
- ...schema.issues,
12537
- ...roundTrip.issues
12538
- ] }
12593
+ report
12539
12594
  });
12540
12595
  }
12541
12596
  /**
@@ -12756,7 +12811,7 @@ var SpfReader = class SpfReader {
12756
12811
  };
12757
12812
  //#endregion
12758
12813
  //#region src/import/spatialTree.ts
12759
- var CATEGORY_BY_TYPE = new Map([
12814
+ var CATEGORY_BY_TYPE = /* @__PURE__ */ new Map([
12760
12815
  [web_ifc.IFCPROJECT, "PROJECT"],
12761
12816
  [web_ifc.IFCSITE, "SITE"],
12762
12817
  [web_ifc.IFCBUILDING, "BUILDING"],
@@ -12938,7 +12993,8 @@ function reconstructExtrusion(reader, extrusionId, scale, worldTransform, diagno
12938
12993
  const solidResult = (() => {
12939
12994
  try {
12940
12995
  var _usingCtx$1 = _usingCtx();
12941
- return (0, brepjs.extrude)(_usingCtx$1.u(faceResult.value), extrudeVec);
12996
+ const face = _usingCtx$1.u(faceResult.value);
12997
+ return (0, brepjs.extrude)(face, extrudeVec);
12942
12998
  } catch (_) {
12943
12999
  _usingCtx$1.e = _;
12944
13000
  } finally {
@@ -12991,10 +13047,12 @@ function reconstructRevolution(reader, revolutionId, scale, worldTransform, diag
12991
13047
  const revolved = (() => {
12992
13048
  try {
12993
13049
  var _usingCtx3 = _usingCtx();
12994
- return (0, brepjs.revolve)(_usingCtx3.u(faceResult.value), {
13050
+ const face = _usingCtx3.u(faceResult.value);
13051
+ const angleDeg = angleRaw * readPlaneAngleScale(reader) * (180 / Math.PI);
13052
+ return (0, brepjs.revolve)(face, {
12995
13053
  at: center,
12996
13054
  axis: direction,
12997
- angle: angleRaw * readPlaneAngleScale(reader) * (180 / Math.PI)
13055
+ angle: angleDeg
12998
13056
  });
12999
13057
  } catch (_) {
13000
13058
  _usingCtx3.e = _;
@@ -13109,7 +13167,7 @@ function packBinaryStl(vertices, indices, scaleToMm) {
13109
13167
  }
13110
13168
  return new Uint8Array(buffer);
13111
13169
  }
13112
- var PARAMETRIC_PROFILE_BUILDERS = new Map([
13170
+ var PARAMETRIC_PROFILE_BUILDERS = /* @__PURE__ */ new Map([
13113
13171
  [web_ifc.IFCRECTANGLEPROFILEDEF, (f) => ({
13114
13172
  kind: "RECTANGULAR",
13115
13173
  width: f("XDim"),
@@ -13877,14 +13935,15 @@ async function fromIfc(bytes, options = {}) {
13877
13935
  }
13878
13936
  const report = appendIssues(emptyReport(), diagnostics);
13879
13937
  const applicationName = readApplicationName(reader);
13880
- return (0, brepjs.ok)({
13938
+ const model = {
13881
13939
  schema: reader.schema,
13882
13940
  spatialTree: spatialRoot === null ? null : mapSpatialNode(spatialRoot),
13883
13941
  elements,
13884
13942
  byExpressId,
13885
13943
  diagnostics: report,
13886
13944
  ...applicationName !== void 0 ? { applicationName } : {}
13887
- });
13945
+ };
13946
+ return (0, brepjs.ok)(model);
13888
13947
  } catch (e) {
13889
13948
  return (0, brepjs.err)(importError("IMPORT_FAILED", "Unexpected failure during IFC import", e));
13890
13949
  } finally {
@@ -14911,7 +14970,7 @@ function parseSlabOpeningInput(input) {
14911
14970
  * containers (PROJECT/SITE/BUILDING/STOREY), abstract groupings, and the SPACE
14912
14971
  * category (which maps to the Space sheet, not Component) are excluded.
14913
14972
  */
14914
- var COMPONENT_CATEGORIES = new Set([
14973
+ var COMPONENT_CATEGORIES = /* @__PURE__ */ new Set([
14915
14974
  "WALL",
14916
14975
  "SLAB",
14917
14976
  "BEAM",
@@ -15536,9 +15595,10 @@ function parseIdsXml(xml) {
15536
15595
  const title = info ? firstChild(info, "title")?.text ?? "" : "";
15537
15596
  const specsContainer = firstChild(root, "specifications");
15538
15597
  if (specsContainer === void 0) return (0, brepjs.err)(idsError("IDS_INVALID_SCHEMA", "IDS document has no <specifications> element"));
15598
+ const specifications = childrenNamed(specsContainer, "specification").map(parseSpecification);
15539
15599
  return (0, brepjs.ok)({
15540
15600
  title,
15541
- specifications: childrenNamed(specsContainer, "specification").map(parseSpecification)
15601
+ specifications
15542
15602
  });
15543
15603
  }
15544
15604
  function parseSpecification(el) {
@@ -15895,10 +15955,7 @@ function restrictionsOf(facet) {
15895
15955
  push(facet.system);
15896
15956
  push(facet.value);
15897
15957
  break;
15898
- case "Material":
15899
- push(facet.value);
15900
- break;
15901
- case "PartOf": break;
15958
+ case "Material": push(facet.value);
15902
15959
  }
15903
15960
  return out;
15904
15961
  }
@@ -16298,7 +16355,8 @@ function parseBcfFiles(files) {
16298
16355
  topics
16299
16356
  });
16300
16357
  } catch (cause) {
16301
- return (0, brepjs.err)(bcfError("BCF_PARSE_FAILED", `Failed to parse BCF container: ${cause instanceof Error ? cause.message : String(cause)}`, cause));
16358
+ const message = cause instanceof Error ? cause.message : String(cause);
16359
+ return (0, brepjs.err)(bcfError("BCF_PARSE_FAILED", `Failed to parse BCF container: ${message}`, cause));
16302
16360
  }
16303
16361
  }
16304
16362
  function parseVersion(xml) {
@@ -16413,6 +16471,138 @@ function assignNum(target, key, value) {
16413
16471
  if (value !== void 0) target[key] = Number(value);
16414
16472
  }
16415
16473
  //#endregion
16474
+ //#region src/familiesAdapter.ts
16475
+ /**
16476
+ * brepjs-families -> BimModel adapter. Consumes a resolved element tree and
16477
+ * feeds each element's PRE-DESUGARED props into the parametric specs — the
16478
+ * spec path stays authoritative for IFC (IfcExtrudedAreaSolid + placement),
16479
+ * while the IR path serves the viewport and dedup. GlobalIds derive from
16480
+ * families key paths (stable under reordering), not insertion order.
16481
+ *
16482
+ * v1 scope: Storey containers and Wall/Slab elements. Openings, fills, and
16483
+ * relationship wiring (IfcRelVoidsElement) follow with the opening writer.
16484
+ */
16485
+ var SPEC_DEFAULTS = {
16486
+ origin: [
16487
+ 0,
16488
+ 0,
16489
+ 0
16490
+ ],
16491
+ axisX: [
16492
+ 1,
16493
+ 0,
16494
+ 0
16495
+ ],
16496
+ axisZ: [
16497
+ 0,
16498
+ 0,
16499
+ 1
16500
+ ],
16501
+ materialName: "Default"
16502
+ };
16503
+ var GEOMETRY_PROPS = /* @__PURE__ */ new Set([
16504
+ "voids",
16505
+ "fuse",
16506
+ "transform",
16507
+ "psets"
16508
+ ]);
16509
+ /** Fold the resolved geometry's OUTER literal translate chain into the spec
16510
+ * placement origin, so IfcLocalPlacement matches the IR world frame no
16511
+ * matter where the transform came from (family-internal or prop-level).
16512
+ * Parameter-driven translations cannot fold and keep the default origin. */
16513
+ function composedOrigin(el) {
16514
+ const out = [...el.props["origin"] ?? [
16515
+ 0,
16516
+ 0,
16517
+ 0
16518
+ ]];
16519
+ let moved = false;
16520
+ let node = el.geometry;
16521
+ while (node.kind === "Translate") {
16522
+ const v = node.vector;
16523
+ if (v.kind !== "Vec3Lit") break;
16524
+ out[0] += v.value[0];
16525
+ out[1] += v.value[1];
16526
+ out[2] += v.value[2];
16527
+ moved = true;
16528
+ node = node.target;
16529
+ }
16530
+ return moved || el.props["origin"] !== void 0 ? out : void 0;
16531
+ }
16532
+ function specInput(el) {
16533
+ const fromProps = {};
16534
+ for (const [k, v] of Object.entries(el.props)) if (!GEOMETRY_PROPS.has(k)) fromProps[k] = v;
16535
+ const origin = composedOrigin(el);
16536
+ return {
16537
+ ...SPEC_DEFAULTS,
16538
+ ...fromProps,
16539
+ ...origin ? { origin } : {},
16540
+ ...collectSpecProps(el)
16541
+ };
16542
+ }
16543
+ function collectSpecProps(el) {
16544
+ const psets = el.attributes["psets"];
16545
+ const out = {};
16546
+ if (psets && typeof psets === "object") {
16547
+ const common = psets["Pset_WallCommon"];
16548
+ if (common && typeof common === "object") {
16549
+ const c = common;
16550
+ if (typeof c["IsExternal"] === "boolean") out["isExternal"] = c["IsExternal"];
16551
+ if (typeof c["FireRating"] === "string") out["fireRating"] = c["FireRating"];
16552
+ }
16553
+ }
16554
+ delete out["psets"];
16555
+ return out;
16556
+ }
16557
+ /**
16558
+ * Project a resolved families tree into an eager BimModel. The caller owns
16559
+ * the returned model (`using`); families stays domain-neutral — this adapter
16560
+ * is where families types meet the IFC vocabulary.
16561
+ */
16562
+ function familiesToBim(root, options) {
16563
+ const model = new BimModel();
16564
+ const initResult = model.init(options.project);
16565
+ if (!initResult.ok) return initResult;
16566
+ const siteId = model.addSite({ name: options.siteName ?? "Site" });
16567
+ const buildingId = model.addBuilding({ name: options.buildingName ?? "Building" });
16568
+ model.aggregate(siteId, buildingId);
16569
+ const idByKeyPath = /* @__PURE__ */ new Map();
16570
+ const walk = (el, storeyId) => {
16571
+ let containerId = storeyId;
16572
+ if (el.type === "Storey") {
16573
+ const id = model.addStorey({
16574
+ name: el.attributes["name"] ?? el.keyPath,
16575
+ elevation: el.props["elevation"] ?? 0
16576
+ }, { stableKey: el.keyPath });
16577
+ model.aggregate(buildingId, id);
16578
+ idByKeyPath.set(el.keyPath, id);
16579
+ containerId = id;
16580
+ } else if (el.type === "Wall" || el.type === "Slab") {
16581
+ const parsed = el.type === "Wall" ? parseWallSpec(specInput(el)) : parseSlabSpec(specInput(el));
16582
+ if (!parsed.ok) return parsed;
16583
+ const added = el.type === "Wall" ? model.addWall(parsed.value, { stableKey: el.keyPath }) : model.addSlab(parsed.value, { stableKey: el.keyPath });
16584
+ if (!added.ok) return added;
16585
+ idByKeyPath.set(el.keyPath, added.value);
16586
+ if (containerId === null) return (0, brepjs.err)(specError("FAMILIES_NO_STOREY", `familiesToBim: '${el.keyPath}' has no Storey ancestor — IFC elements need spatial containment`));
16587
+ model.placeIn(added.value, containerId);
16588
+ } else if (el.type !== "Opening" && el.type !== "Group" && el.geometry.kind !== "Empty") return (0, brepjs.err)(specError("FAMILIES_UNSUPPORTED_TYPE", `familiesToBim: no spec mapping for element type '${el.type}' at '${el.keyPath}'`));
16589
+ for (const child of el.children) {
16590
+ const r = walk(child, containerId);
16591
+ if (!r.ok) return r;
16592
+ }
16593
+ return (0, brepjs.ok)(void 0);
16594
+ };
16595
+ const walked = walk(root, null);
16596
+ if (!walked.ok) {
16597
+ model[Symbol.dispose]();
16598
+ return walked;
16599
+ }
16600
+ return (0, brepjs.ok)({
16601
+ model,
16602
+ idByKeyPath
16603
+ });
16604
+ }
16605
+ //#endregion
16416
16606
  exports.BimModel = BimModel;
16417
16607
  exports.DEFAULT_IFC_SCHEMA = DEFAULT_IFC_SCHEMA;
16418
16608
  exports.DEFAULT_UNITS = DEFAULT_UNITS;
@@ -16436,6 +16626,7 @@ exports.emptyReport = emptyReport;
16436
16626
  exports.exportCobie = deriveCobieModel;
16437
16627
  exports.extendedProfileArea = extendedProfileArea;
16438
16628
  exports.extendedProfileToFace = extendedProfileToFace;
16629
+ exports.familiesToBim = familiesToBim;
16439
16630
  exports.fileSchemaString = fileSchemaString;
16440
16631
  exports.fromBrepError = fromBrepError;
16441
16632
  exports.fromIfc = fromIfc;