@ifc-lite/create 2.6.0 → 2.7.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.
Files changed (35) hide show
  1. package/README.md +8 -0
  2. package/dist/cost-authoring-rules.d.ts +70 -0
  3. package/dist/cost-authoring-rules.d.ts.map +1 -0
  4. package/dist/cost-authoring-rules.js +118 -0
  5. package/dist/cost-authoring-rules.js.map +1 -0
  6. package/dist/ifc-creator-cost.d.ts +3 -14
  7. package/dist/ifc-creator-cost.d.ts.map +1 -1
  8. package/dist/ifc-creator-cost.js +4 -62
  9. package/dist/ifc-creator-cost.js.map +1 -1
  10. package/dist/in-store/cost-nesting-cycle.d.ts +8 -0
  11. package/dist/in-store/cost-nesting-cycle.d.ts.map +1 -0
  12. package/dist/in-store/cost-nesting-cycle.js +28 -0
  13. package/dist/in-store/cost-nesting-cycle.js.map +1 -0
  14. package/dist/in-store/cost-reference-validation.d.ts +13 -0
  15. package/dist/in-store/cost-reference-validation.d.ts.map +1 -0
  16. package/dist/in-store/cost-reference-validation.js +49 -0
  17. package/dist/in-store/cost-reference-validation.js.map +1 -0
  18. package/dist/in-store/cost-removal.d.ts +40 -0
  19. package/dist/in-store/cost-removal.d.ts.map +1 -0
  20. package/dist/in-store/cost-removal.js +107 -0
  21. package/dist/in-store/cost-removal.js.map +1 -0
  22. package/dist/in-store/cost.d.ts +109 -0
  23. package/dist/in-store/cost.d.ts.map +1 -0
  24. package/dist/in-store/cost.js +323 -0
  25. package/dist/in-store/cost.js.map +1 -0
  26. package/dist/in-store/resolve-source.d.ts.map +1 -1
  27. package/dist/in-store/resolve-source.js +11 -8
  28. package/dist/in-store/resolve-source.js.map +1 -1
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/types-cost.d.ts +2 -2
  34. package/dist/types-cost.d.ts.map +1 -1
  35. package/package.json +5 -4
@@ -0,0 +1,107 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { assertCostSchema } from '../cost-authoring-rules.js';
5
+ import { requireEntityTypeOneOf, requireMatchingCostSchema } from './cost-reference-validation.js';
6
+ const REMOVABLE_COST_ENTITY_TYPES = new Set(['IFCCOSTSCHEDULE', 'IFCCOSTITEM', 'IFCCOSTVALUE']);
7
+ /**
8
+ * Safe-delete an `IfcCostSchedule` / `IfcCostItem` / `IfcCostValue`, refusing
9
+ * live value references unless `detach` explicitly requests their rewrite.
10
+ */
11
+ export function removeCostEntityInStore(editor, anchor, expressId, referrers, options = {}) {
12
+ assertCostSchema(requireMatchingCostSchema(editor, anchor.schema), 'removeCostEntity');
13
+ requireEntityTypeOneOf(editor, expressId, REMOVABLE_COST_ENTITY_TYPES, 'expressId', 'removeCostEntity');
14
+ const blockers = [];
15
+ for (const [itemId, values] of referrers.itemCostValues ?? []) {
16
+ if (values.includes(expressId))
17
+ blockers.push(`IfcCostItem #${itemId}.CostValues`);
18
+ }
19
+ for (const [valueId, components] of referrers.valueComponents ?? []) {
20
+ if (components.includes(expressId))
21
+ blockers.push(`IfcCostValue #${valueId}.Components`);
22
+ }
23
+ for (const [valueId, ref] of referrers.valueAppliedValueRef ?? []) {
24
+ if (ref === expressId)
25
+ blockers.push(`IfcCostValue #${valueId}.AppliedValue (AppliedValueRef)`);
26
+ }
27
+ for (const ref of referrers.otherRelationshipLists ?? []) {
28
+ if (ref.relatedIds.includes(expressId))
29
+ blockers.push(`relationship #${ref.relId}`);
30
+ }
31
+ for (const relId of referrers.otherRelationships ?? [])
32
+ blockers.push(`relationship #${relId}`);
33
+ for (const ref of referrers.optionalScalarReferrers ?? []) {
34
+ blockers.push(`entity #${ref.entityId} attribute ${ref.attributeIndex}`);
35
+ }
36
+ for (const ref of referrers.optionalListReferrers ?? []) {
37
+ if (ref.referencedIds.includes(expressId)) {
38
+ blockers.push(`entity #${ref.entityId} attribute ${ref.attributeIndex}`);
39
+ }
40
+ }
41
+ if (blockers.length > 0 && !options.detach) {
42
+ throw new Error(`removeCostEntity: #${expressId} is still referenced by ${blockers.join(', ')}. `
43
+ + 'Pass { detach: true } to rewrite those lists first.');
44
+ }
45
+ if (blockers.length > 0) {
46
+ for (const [itemId, values] of referrers.itemCostValues ?? []) {
47
+ if (!values.includes(expressId))
48
+ continue;
49
+ const remaining = values.filter(id => id !== expressId);
50
+ editor.setPositionalAttribute(itemId, 7, remaining.length === 0 ? null : remaining.map(id => `#${id}`));
51
+ }
52
+ for (const [valueId, components] of referrers.valueComponents ?? []) {
53
+ if (!components.includes(expressId))
54
+ continue;
55
+ const remaining = components.filter(id => id !== expressId);
56
+ editor.setPositionalAttribute(valueId, 9, remaining.length === 0 ? null : remaining.map(id => `#${id}`));
57
+ }
58
+ for (const [valueId, ref] of referrers.valueAppliedValueRef ?? []) {
59
+ if (ref === expressId)
60
+ editor.setPositionalAttribute(valueId, 2, null);
61
+ }
62
+ for (const ref of referrers.otherRelationshipLists ?? []) {
63
+ if (!ref.relatedIds.includes(expressId))
64
+ continue;
65
+ const remaining = ref.relatedIds.filter(id => id !== expressId);
66
+ if (remaining.length === 0)
67
+ editor.removeEntity(ref.relId);
68
+ else
69
+ editor.setPositionalAttribute(ref.relId, ref.attributeIndex, remaining.map(id => `#${id}`));
70
+ }
71
+ for (const relId of referrers.otherRelationships ?? [])
72
+ editor.removeEntity(relId);
73
+ for (const ref of referrers.optionalScalarReferrers ?? []) {
74
+ editor.setPositionalAttribute(ref.entityId, ref.attributeIndex, null);
75
+ }
76
+ for (const ref of referrers.optionalListReferrers ?? []) {
77
+ if (!ref.referencedIds.includes(expressId))
78
+ continue;
79
+ const remaining = ref.referencedIds.filter(id => id !== expressId);
80
+ editor.setPositionalAttribute(ref.entityId, ref.attributeIndex, remaining.length === 0 ? null : remaining.map(id => `#${id}`));
81
+ }
82
+ }
83
+ for (const [relId, related] of referrers.nestRelatedObjects ?? []) {
84
+ if (!related.includes(expressId))
85
+ continue;
86
+ const remaining = related.filter(id => id !== expressId);
87
+ if (remaining.length === 0)
88
+ editor.removeEntity(relId);
89
+ else
90
+ editor.setPositionalAttribute(relId, 5, remaining.map(id => `#${id}`));
91
+ }
92
+ for (const [relId, related] of referrers.assignmentRelatedObjects ?? []) {
93
+ if (!related.includes(expressId))
94
+ continue;
95
+ const remaining = related.filter(id => id !== expressId);
96
+ if (remaining.length === 0)
97
+ editor.removeEntity(relId);
98
+ else
99
+ editor.setPositionalAttribute(relId, 4, remaining.map(id => `#${id}`));
100
+ }
101
+ for (const relId of referrers.nestsAsParent ?? [])
102
+ editor.removeEntity(relId);
103
+ for (const relId of referrers.assignmentsAsControl ?? [])
104
+ editor.removeEntity(relId);
105
+ editor.removeEntity(expressId);
106
+ }
107
+ //# sourceMappingURL=cost-removal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-removal.js","sourceRoot":"","sources":["../../src/in-store/cost-removal.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAK/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAGnG,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,iBAAiB,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;AAgChG;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAmB,EACnB,MAAkB,EAClB,SAAiB,EACjB,SAA+B,EAC/B,UAAgC,EAAE;IAElC,gBAAgB,CAAC,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACvF,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,2BAA2B,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;IACxG,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;QAC9D,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,MAAM,aAAa,CAAC,CAAC;IACrF,CAAC;IACD,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,SAAS,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QACpE,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,OAAO,aAAa,CAAC,CAAC;IAC3F,CAAC;IACD,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC,oBAAoB,IAAI,EAAE,EAAE,CAAC;QAClE,IAAI,GAAG,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,OAAO,iCAAiC,CAAC,CAAC;IAClG,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,sBAAsB,IAAI,EAAE,EAAE,CAAC;QACzD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,kBAAkB,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC;IAChG,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,uBAAuB,IAAI,EAAE,EAAE,CAAC;QAC1D,QAAQ,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,QAAQ,cAAc,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,qBAAqB,IAAI,EAAE,EAAE,CAAC;QACxD,IAAI,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,QAAQ,cAAc,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,sBAAsB,SAAS,2BAA2B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;cAC/E,qDAAqD,CACxD,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;YAC9D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,SAAS;YAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;YACxD,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1G,CAAC;QACD,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,SAAS,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;YACpE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,SAAS;YAC9C,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;YAC5D,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC3G,CAAC;QACD,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC,oBAAoB,IAAI,EAAE,EAAE,CAAC;YAClE,IAAI,GAAG,KAAK,SAAS;gBAAE,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACzE,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,sBAAsB,IAAI,EAAE,EAAE,CAAC;YACzD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,SAAS;YAClD,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;YAChE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;;gBACtD,MAAM,CAAC,sBAAsB,CAChC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAC7D,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,kBAAkB,IAAI,EAAE;YAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACnF,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,uBAAuB,IAAI,EAAE,EAAE,CAAC;YAC1D,MAAM,CAAC,sBAAsB,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QACxE,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,qBAAqB,IAAI,EAAE,EAAE,CAAC;YACxD,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,SAAS;YACrD,MAAM,SAAS,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;YACnE,MAAM,CAAC,sBAAsB,CAC3B,GAAG,CAAC,QAAQ,EACZ,GAAG,CAAC,cAAc,EAClB,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,SAAS,CAAC,kBAAkB,IAAI,EAAE,EAAE,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAS;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACzD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;;YAClD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,SAAS,CAAC,wBAAwB,IAAI,EAAE,EAAE,CAAC;QACxE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAS;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACzD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;;YAClD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,aAAa,IAAI,EAAE;QAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9E,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,oBAAoB,IAAI,EAAE;QAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACrF,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Loaded-model cost authoring (#4857 PR A) — `bim.store.addCost*` / `nestCostItems`
3
+ * / `assignCostItemsToSchedule` / `assignToCostItem` / `setCostItemValues` /
4
+ * `removeCostEntity`. The counterpart of `ifc-creator-cost.ts` for a model
5
+ * that is already parsed and loaded rather than being built from scratch:
6
+ * same validation (`cost-authoring-rules.ts`, shared so a value illegal from
7
+ * one entry point is illegal from the other), different serialization —
8
+ * `StoreEditor.addEntity` takes a typed attribute array, not raw STEP text.
9
+ *
10
+ * Pure: no I/O, no parser access, no read of the store's OWN existing graph.
11
+ * `nestCostItemsInStore` (reparenting) and `removeCostEntityInStore`
12
+ * (safe-delete / cascade) both need to know what ALREADY references an
13
+ * entity, which only a graph READ can answer — the caller resolves referrers
14
+ * first and hands them in. The editor is the only mutable thing touched.
15
+ */
16
+ import { type RandomSource } from '@ifc-lite/encoding';
17
+ import type { StoreEditor } from '@ifc-lite/mutations';
18
+ import { type CostSchema } from '../cost-authoring-rules.js';
19
+ import type { CostItemParams, CostQuantityParams, CostScheduleParams, CostValueParams } from '../types-cost.js';
20
+ /** What `nestCostItemsInStore` / `assign*InStore` / `removeCostEntityInStore` need to
21
+ * reparent or detach cleanly — the model's owner history and target schema. */
22
+ export interface CostAnchor {
23
+ /** IfcOwnerHistory expressId, or null when the model has none (written as `$`). */
24
+ ownerHistoryId: number | null;
25
+ /** Target schema; IFC2X3 is refused (see `assertCostSchema`). */
26
+ schema: CostSchema;
27
+ /** Optional seeded randomness for authored GlobalIds — see `SpatialAnchor.guidRandom`. */
28
+ guidRandom?: RandomSource;
29
+ }
30
+ /**
31
+ * Emit an `IfcCostSchedule` into the loaded model's overlay.
32
+ *
33
+ * [0] GlobalId, [1] OwnerHistory, [2] Name, [3] Description, [4] ObjectType,
34
+ * [5] Identification, [6] PredefinedType, [7] Status, [8] SubmittedOn,
35
+ * [9] UpdateDate — same IFC4 layout `emitCostSchedule` writes; refused for
36
+ * IFC2X3 (different layout, see `assertCostSchema`).
37
+ */
38
+ export declare function addCostScheduleToStore(editor: StoreEditor, anchor: CostAnchor, params: CostScheduleParams): number;
39
+ /**
40
+ * Emit an `IfcCostItem`. [0] GlobalId, [1] OwnerHistory, [2] Name,
41
+ * [3] Description, [4] ObjectType, [5] Identification, [6] PredefinedType,
42
+ * [7] CostValues, [8] CostQuantities — an empty `CostValues`/`CostQuantities`
43
+ * array is refused (EXPRESS `[1:?]`); use `attachCostValuesToItemInStore` to
44
+ * attach them after the fact instead.
45
+ */
46
+ export declare function addCostItemToStore(editor: StoreEditor, anchor: CostAnchor, params: CostItemParams): number;
47
+ /**
48
+ * Emit an `IfcCostValue`. [0] Name, [1] Description, [2] AppliedValue,
49
+ * [3] UnitBasis, [4] ApplicableDate, [5] FixedUntilDate, [6] Category,
50
+ * [7] Condition, [8] ArithmeticOperator, [9] Components.
51
+ *
52
+ * `AppliedValue` and `AppliedValueRef` are the two branches of one SELECT —
53
+ * at most one may be given (mirrors `emitCostValue`).
54
+ */
55
+ export declare function addCostValueToStore(editor: StoreEditor, anchor: CostAnchor, params: CostValueParams): number;
56
+ /**
57
+ * Emit an `IfcPhysicalSimpleQuantity` (the same subtypes `emitPhysicalQuantity`
58
+ * writes), for `IfcCostItem.CostQuantities`. [0] Name, [1] Description,
59
+ * [2] Unit, [3] `<Kind>Value`, [4] Formula.
60
+ */
61
+ export declare function addCostQuantityToStore(editor: StoreEditor, anchor: CostAnchor, params: CostQuantityParams): number;
62
+ /** One relationship the caller already found referencing an id, so the builders below
63
+ * never need to scan the store themselves — see the module header. */
64
+ export interface ExistingRelatedList {
65
+ relId: number;
66
+ /** The relationship's RelatingObject, when the caller is supplying a nesting graph. */
67
+ relatingId?: number;
68
+ /** The relationship's current RelatedObjects (or Components), in file order. */
69
+ relatedIds: readonly number[];
70
+ /**
71
+ * When a controller legally has MORE THAN ONE relationship of this kind
72
+ * (e.g. two separate `IfcRelAssignsToControl` records for the same
73
+ * schedule), every member across ALL of them — used only to decide which
74
+ * requested ids are genuinely new, never as the list written back. Writing
75
+ * this union into `relId`'s own slot would copy a secondary relationship's
76
+ * members into the primary one, duplicating membership while leaving the
77
+ * secondary relationship untouched. Defaults to `relatedIds` when absent
78
+ * (the single-relationship case, where the two are the same set).
79
+ */
80
+ allMemberIds?: readonly number[];
81
+ }
82
+ /**
83
+ * Nest `childIds` under `parentId` as `IfcRelNests.RelatedObjects` (slot 5),
84
+ * `RelatingObject` = parent.
85
+ *
86
+ * A child already nested under one or more DIFFERENT `IfcRelNests` is
87
+ * reparented: it is removed from EVERY one of those rels' `RelatedObjects`
88
+ * first (a file may legally list a child under more than one nest —
89
+ * `MULTIPLE_NESTING_PARENTS` is a diagnostic, not a refusal — so detaching
90
+ * from only the first one found would leave it still nested under the rest),
91
+ * tombstoning a rel if that empties it (`RelatedObjects` is `[1:?]`, so an
92
+ * emptied list cannot be left as `()`), then added to (or its own new) the
93
+ * target rel.
94
+ */
95
+ export declare function nestCostItemsInStore(editor: StoreEditor, anchor: CostAnchor, parentId: number, childIds: number[], existingNestByChild: ReadonlyMap<number, readonly ExistingRelatedList[]>, existingTargetNest?: ExistingRelatedList): number;
96
+ /** Assign `itemIds` (IfcCostItem) to `scheduleId` (IfcCostSchedule) as its controlled objects. */
97
+ export declare function assignCostItemsToScheduleInStore(editor: StoreEditor, anchor: CostAnchor, scheduleId: number, itemIds: number[], existingAssignment?: ExistingRelatedList): number;
98
+ /**
99
+ * Assign IFC objects (products, tasks, resources, etc.) to a cost item.
100
+ * The controlling item itself is not a legal related member.
101
+ */
102
+ export declare function assignObjectsToCostItemInStore(editor: StoreEditor, anchor: CostAnchor, costItemId: number, objectIds: number[], existingAssignment?: ExistingRelatedList): number;
103
+ /**
104
+ * Set (replace) `itemId`'s `IfcCostItem.CostValues` (slot 7). `valueIds` is
105
+ * REQUIRED, not optional: an empty array is how a caller CLEARS the list,
106
+ * written as `$` — never `()`, which `[1:?]` forbids.
107
+ */
108
+ export declare function attachCostValuesToItemInStore(editor: StoreEditor, anchor: CostAnchor, itemId: number, valueIds: readonly number[]): void;
109
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/in-store/cost.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAM1E,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,eAAe,EACxE,MAAM,kBAAkB,CAAC;AAG1B;gFACgF;AAChF,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iEAAiE;IACjE,MAAM,EAAE,UAAU,CAAC;IACnB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B;AAeD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAmBlH;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CA0B1G;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAiC5G;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA6BlH;AAED;uEACuE;AACvE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,mBAAmB,EAAE,CAAC,EACxE,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,MAAM,CA6CR;AA4DD,kGAAkG;AAClG,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAC9E,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,MAAM,CAIR;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAChF,kBAAkB,CAAC,EAAE,mBAAmB,GACvC,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAcN"}
@@ -0,0 +1,323 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Loaded-model cost authoring (#4857 PR A) — `bim.store.addCost*` / `nestCostItems`
6
+ * / `assignCostItemsToSchedule` / `assignToCostItem` / `setCostItemValues` /
7
+ * `removeCostEntity`. The counterpart of `ifc-creator-cost.ts` for a model
8
+ * that is already parsed and loaded rather than being built from scratch:
9
+ * same validation (`cost-authoring-rules.ts`, shared so a value illegal from
10
+ * one entry point is illegal from the other), different serialization —
11
+ * `StoreEditor.addEntity` takes a typed attribute array, not raw STEP text.
12
+ *
13
+ * Pure: no I/O, no parser access, no read of the store's OWN existing graph.
14
+ * `nestCostItemsInStore` (reparenting) and `removeCostEntityInStore`
15
+ * (safe-delete / cascade) both need to know what ALREADY references an
16
+ * entity, which only a graph READ can answer — the caller resolves referrers
17
+ * first and hands them in. The editor is the only mutable thing touched.
18
+ */
19
+ import { generateIfcGuid } from '@ifc-lite/encoding';
20
+ import { ownerHistoryRef } from './_emit-helpers.js';
21
+ import { requireAssignableIfcObjectDefinition, requireEntitySubtype, requireEntityType, requireEntityTypeOneOf, requireMatchingCostSchema, } from './cost-reference-validation.js';
22
+ import { COST_ITEM_TYPES, COST_SCHEDULE_TYPES, QUANTITY_KINDS, assertCostSchema, assertOneOf, requireRef, validateArithmeticOperator, validateRefList, validateTypedValue, } from '../cost-authoring-rules.js';
23
+ import { assertNoNestingCycle } from './cost-nesting-cycle.js';
24
+ /** `IfcCostValue.Components` / `IfcAppliedValueSelect`'s entity branches: another cost/applied value. */
25
+ const APPLIED_VALUE_ENTITY_TYPES = new Set(['IFCCOSTVALUE', 'IFCAPPLIEDVALUE']);
26
+ /** The entity branches of IFC4/IFC4X3 IfcAppliedValueSelect. */
27
+ const APPLIED_VALUE_REF_TYPES = new Set(['IFCMEASUREWITHUNIT', 'IFCREFERENCE']);
28
+ function typedAttrValue(value, schema, context) {
29
+ validateTypedValue(value, schema, context);
30
+ return { typed: { type: value.Type, value: value.Value } };
31
+ }
32
+ function refListAttr(ids) {
33
+ return ids === undefined ? null : ids.map(id => `#${id}`);
34
+ }
35
+ /**
36
+ * Emit an `IfcCostSchedule` into the loaded model's overlay.
37
+ *
38
+ * [0] GlobalId, [1] OwnerHistory, [2] Name, [3] Description, [4] ObjectType,
39
+ * [5] Identification, [6] PredefinedType, [7] Status, [8] SubmittedOn,
40
+ * [9] UpdateDate — same IFC4 layout `emitCostSchedule` writes; refused for
41
+ * IFC2X3 (different layout, see `assertCostSchema`).
42
+ */
43
+ export function addCostScheduleToStore(editor, anchor, params) {
44
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
45
+ assertCostSchema(schema, 'addCostSchedule');
46
+ if (typeof params.Name !== 'string' || params.Name.length === 0) {
47
+ throw new Error('addCostSchedule: Name is required');
48
+ }
49
+ assertOneOf(params.PredefinedType, COST_SCHEDULE_TYPES, 'PredefinedType', 'addCostSchedule');
50
+ return editor.addEntity('IfcCostSchedule', [
51
+ generateIfcGuid(anchor.guidRandom),
52
+ ownerHistoryRef(anchor.ownerHistoryId),
53
+ params.Name,
54
+ params.Description ?? null,
55
+ params.ObjectType ?? null,
56
+ params.Identification ?? null,
57
+ params.PredefinedType ? `.${params.PredefinedType}.` : null,
58
+ params.Status ?? null,
59
+ params.SubmittedOn ?? null,
60
+ params.UpdateDate ?? null,
61
+ ]).expressId;
62
+ }
63
+ /**
64
+ * Emit an `IfcCostItem`. [0] GlobalId, [1] OwnerHistory, [2] Name,
65
+ * [3] Description, [4] ObjectType, [5] Identification, [6] PredefinedType,
66
+ * [7] CostValues, [8] CostQuantities — an empty `CostValues`/`CostQuantities`
67
+ * array is refused (EXPRESS `[1:?]`); use `attachCostValuesToItemInStore` to
68
+ * attach them after the fact instead.
69
+ */
70
+ export function addCostItemToStore(editor, anchor, params) {
71
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
72
+ const costValues = params.CostValues === undefined ? undefined : [...new Set(params.CostValues)];
73
+ const costQuantities = params.CostQuantities === undefined ? undefined : [...new Set(params.CostQuantities)];
74
+ assertCostSchema(schema, 'addCostItem');
75
+ if (typeof params.Name !== 'string' || params.Name.length === 0) {
76
+ throw new Error('addCostItem: Name is required');
77
+ }
78
+ assertOneOf(params.PredefinedType, COST_ITEM_TYPES, 'PredefinedType', 'addCostItem');
79
+ validateRefList(costValues, 'CostValues', 'addCostItem');
80
+ validateRefList(costQuantities, 'CostQuantities', 'addCostItem');
81
+ for (const id of costValues ?? [])
82
+ requireEntityType(editor, id, 'IfcCostValue', 'CostValues', 'addCostItem');
83
+ for (const id of costQuantities ?? []) {
84
+ requireEntitySubtype(editor, id, 'IfcPhysicalQuantity', 'CostQuantities', 'addCostItem');
85
+ }
86
+ return editor.addEntity('IfcCostItem', [
87
+ generateIfcGuid(anchor.guidRandom),
88
+ ownerHistoryRef(anchor.ownerHistoryId),
89
+ params.Name,
90
+ params.Description ?? null,
91
+ params.ObjectType ?? null,
92
+ params.Identification ?? null,
93
+ params.PredefinedType ? `.${params.PredefinedType}.` : null,
94
+ refListAttr(costValues),
95
+ refListAttr(costQuantities),
96
+ ]).expressId;
97
+ }
98
+ /**
99
+ * Emit an `IfcCostValue`. [0] Name, [1] Description, [2] AppliedValue,
100
+ * [3] UnitBasis, [4] ApplicableDate, [5] FixedUntilDate, [6] Category,
101
+ * [7] Condition, [8] ArithmeticOperator, [9] Components.
102
+ *
103
+ * `AppliedValue` and `AppliedValueRef` are the two branches of one SELECT —
104
+ * at most one may be given (mirrors `emitCostValue`).
105
+ */
106
+ export function addCostValueToStore(editor, anchor, params) {
107
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
108
+ assertCostSchema(schema, 'addCostValue');
109
+ if (params.AppliedValue !== undefined && params.AppliedValueRef !== undefined) {
110
+ throw new Error('addCostValue: AppliedValue and AppliedValueRef are the two branches of one SELECT — give at most one');
111
+ }
112
+ validateArithmeticOperator(params.ArithmeticOperator, schema, 'addCostValue');
113
+ let applied = null;
114
+ if (params.AppliedValue !== undefined) {
115
+ applied = typedAttrValue(params.AppliedValue, schema, 'addCostValue');
116
+ }
117
+ else if (params.AppliedValueRef !== undefined) {
118
+ requireRef(params.AppliedValueRef, 'AppliedValueRef', 'addCostValue');
119
+ requireEntityTypeOneOf(editor, params.AppliedValueRef, APPLIED_VALUE_REF_TYPES, 'AppliedValueRef', 'addCostValue');
120
+ applied = `#${params.AppliedValueRef}`;
121
+ }
122
+ if (params.UnitBasis !== undefined) {
123
+ requireRef(params.UnitBasis, 'UnitBasis', 'addCostValue');
124
+ requireEntityType(editor, params.UnitBasis, 'IfcMeasureWithUnit', 'UnitBasis', 'addCostValue');
125
+ }
126
+ validateRefList(params.Components, 'Components', 'addCostValue');
127
+ for (const id of params.Components ?? [])
128
+ requireEntityTypeOneOf(editor, id, APPLIED_VALUE_ENTITY_TYPES, 'Components', 'addCostValue');
129
+ return editor.addEntity('IfcCostValue', [
130
+ params.Name ?? null,
131
+ params.Description ?? null,
132
+ applied,
133
+ params.UnitBasis === undefined ? null : `#${params.UnitBasis}`,
134
+ params.ApplicableDate ?? null,
135
+ params.FixedUntilDate ?? null,
136
+ params.Category ?? null,
137
+ params.Condition ?? null,
138
+ params.ArithmeticOperator ? `.${params.ArithmeticOperator}.` : null,
139
+ refListAttr(params.Components),
140
+ ]).expressId;
141
+ }
142
+ /**
143
+ * Emit an `IfcPhysicalSimpleQuantity` (the same subtypes `emitPhysicalQuantity`
144
+ * writes), for `IfcCostItem.CostQuantities`. [0] Name, [1] Description,
145
+ * [2] Unit, [3] `<Kind>Value`, [4] Formula.
146
+ */
147
+ export function addCostQuantityToStore(editor, anchor, params) {
148
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
149
+ assertCostSchema(schema, 'addCostQuantity');
150
+ if (typeof params.Name !== 'string' || params.Name.length === 0) {
151
+ throw new Error('addCostQuantity: Name is required');
152
+ }
153
+ assertOneOf(params.Kind, QUANTITY_KINDS, 'Kind', 'addCostQuantity');
154
+ if (!Number.isFinite(params.Value))
155
+ throw new Error(`addCostQuantity: ${params.Kind} value must be a finite number`);
156
+ if (params.Kind === 'IfcQuantityNumber' && schema !== 'IFC4X3') {
157
+ throw new Error(`addCostQuantity: ${params.Kind} does not exist in ${schema}; requires Schema "IFC4X3"`);
158
+ }
159
+ if (params.Kind !== 'IfcQuantityNumber' && params.Value < 0) {
160
+ throw new Error(`addCostQuantity: ${params.Kind} value must be non-negative, got ${params.Value}`);
161
+ }
162
+ if (params.Unit !== undefined) {
163
+ requireRef(params.Unit, 'Unit', 'addCostQuantity');
164
+ requireEntitySubtype(editor, params.Unit, 'IfcNamedUnit', 'Unit', 'addCostQuantity');
165
+ }
166
+ const isInteger = params.Kind === 'IfcQuantityCount' && schema === 'IFC4X3';
167
+ if (isInteger && !Number.isInteger(params.Value)) {
168
+ throw new Error(`addCostQuantity: ${params.Kind} value must be a finite integer in IFC4X3`);
169
+ }
170
+ return editor.addEntity(params.Kind, [
171
+ params.Name,
172
+ params.Description ?? null,
173
+ params.Unit === undefined ? null : `#${params.Unit}`,
174
+ isInteger ? params.Value : { real: params.Value },
175
+ params.Formula ?? null,
176
+ ]).expressId;
177
+ }
178
+ /**
179
+ * Nest `childIds` under `parentId` as `IfcRelNests.RelatedObjects` (slot 5),
180
+ * `RelatingObject` = parent.
181
+ *
182
+ * A child already nested under one or more DIFFERENT `IfcRelNests` is
183
+ * reparented: it is removed from EVERY one of those rels' `RelatedObjects`
184
+ * first (a file may legally list a child under more than one nest —
185
+ * `MULTIPLE_NESTING_PARENTS` is a diagnostic, not a refusal — so detaching
186
+ * from only the first one found would leave it still nested under the rest),
187
+ * tombstoning a rel if that empties it (`RelatedObjects` is `[1:?]`, so an
188
+ * emptied list cannot be left as `()`), then added to (or its own new) the
189
+ * target rel.
190
+ */
191
+ export function nestCostItemsInStore(editor, anchor, parentId, childIds, existingNestByChild, existingTargetNest) {
192
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
193
+ assertCostSchema(schema, 'nestCostItems');
194
+ validateRefList(childIds, 'childIds', 'nestCostItems');
195
+ requireRef(parentId, 'parentId', 'nestCostItems');
196
+ if (childIds.includes(parentId)) {
197
+ throw new Error(`nestCostItems: parentId #${parentId} cannot also be one of childIds (an item cannot nest itself)`);
198
+ }
199
+ requireEntityType(editor, parentId, 'IfcCostItem', 'parentId', 'nestCostItems');
200
+ // De-duplicated once: every use below (the reparent scan, the merge, the
201
+ // freshly-created rel's own RelatedObjects) reads from this, not childIds
202
+ // — a repeated id in the caller's list must not write a repeated #N into a
203
+ // list IFC readers count members of.
204
+ const uniqueChildIds = [...new Set(childIds)];
205
+ for (const childId of uniqueChildIds)
206
+ requireEntityType(editor, childId, 'IfcCostItem', 'childId', 'nestCostItems');
207
+ // The SDK supplies relatingId so the helper can reject indirect cycles.
208
+ assertNoNestingCycle(parentId, uniqueChildIds, existingNestByChild);
209
+ // Detach every child of THIS call from every old rel it is a member of, one
210
+ // rewrite per (rel, not per (rel, child)): two children reparented out of
211
+ // the same old IfcRelNests in one call must both leave it, and re-filtering
212
+ // the ORIGINAL (unchanged) relatedIds on each iteration would make the
213
+ // second child's rewrite silently undo the first child's removal.
214
+ const detachedRelIds = new Set();
215
+ for (const childId of uniqueChildIds) {
216
+ for (const existing of existingNestByChild.get(childId) ?? []) {
217
+ if (existing.relId === existingTargetNest?.relId || detachedRelIds.has(existing.relId))
218
+ continue;
219
+ detachedRelIds.add(existing.relId);
220
+ const remaining = existing.relatedIds.filter(id => !uniqueChildIds.includes(id));
221
+ if (remaining.length === 0)
222
+ editor.removeEntity(existing.relId);
223
+ else
224
+ editor.setPositionalAttribute(existing.relId, 5, remaining.map(id => `#${id}`));
225
+ }
226
+ }
227
+ if (existingTargetNest) {
228
+ const merged = [...new Set([...existingTargetNest.relatedIds, ...uniqueChildIds])];
229
+ editor.setPositionalAttribute(existingTargetNest.relId, 5, merged.map(id => `#${id}`));
230
+ return existingTargetNest.relId;
231
+ }
232
+ return editor.addEntity('IfcRelNests', [
233
+ generateIfcGuid(anchor.guidRandom),
234
+ ownerHistoryRef(anchor.ownerHistoryId),
235
+ null,
236
+ null,
237
+ `#${parentId}`,
238
+ uniqueChildIds.map(id => `#${id}`),
239
+ ]).expressId;
240
+ }
241
+ /**
242
+ * Shared `IfcRelAssignsToControl` writer behind
243
+ * `assignCostItemsToScheduleInStore` / `assignObjectsToCostItemInStore`:
244
+ * [0] GlobalId, [1] OwnerHistory, [2] Name, [3] Description,
245
+ * [4] RelatedObjects, [5] RelatedObjectsType, [6] RelatingControl. Appends to
246
+ * `existingAssignment` when the controlling entity already has one, rather
247
+ * than creating a second relationship for the same control.
248
+ */
249
+ function assignToControlInStore(editor, anchor, relatingControlId, relatedObjectIds, existingAssignment, context, controlType, relatedType) {
250
+ const schema = requireMatchingCostSchema(editor, anchor.schema);
251
+ assertCostSchema(schema, context);
252
+ validateRefList(relatedObjectIds, 'relatedObjectIds', context);
253
+ requireRef(relatingControlId, 'relatingControlId', context);
254
+ requireEntityType(editor, relatingControlId, controlType, 'relatingControlId', context);
255
+ // De-duplicated once so a repeated id in the caller's list can't write a
256
+ // repeated #N into RelatedObjects — a caller-visible malformed member list.
257
+ const uniqueRelated = [...new Set(relatedObjectIds)];
258
+ for (const id of uniqueRelated) {
259
+ if (relatedType === 'IfcObjectDefinition') {
260
+ requireAssignableIfcObjectDefinition(editor, id, relatingControlId, context);
261
+ }
262
+ else if (relatedType) {
263
+ requireEntityType(editor, id, relatedType, 'relatedObjectIds', context);
264
+ }
265
+ else if (!editor.hasEntity(id)) {
266
+ throw new Error(`${context}: relatedObjectIds #${id} does not exist in this model`);
267
+ }
268
+ }
269
+ if (existingAssignment) {
270
+ // Filter against the union across every relationship for this control
271
+ // (a member of a DIFFERENT one is not re-added), but merge only into
272
+ // THIS rel's own list — never the union itself, which would copy a
273
+ // secondary relationship's members into the primary one.
274
+ const alreadyMember = new Set(existingAssignment.allMemberIds ?? existingAssignment.relatedIds);
275
+ const toAdd = uniqueRelated.filter(id => !alreadyMember.has(id));
276
+ if (toAdd.length === 0)
277
+ return existingAssignment.relId;
278
+ const merged = [...existingAssignment.relatedIds, ...toAdd];
279
+ editor.setPositionalAttribute(existingAssignment.relId, 4, merged.map(id => `#${id}`));
280
+ return existingAssignment.relId;
281
+ }
282
+ return editor.addEntity('IfcRelAssignsToControl', [
283
+ generateIfcGuid(anchor.guidRandom),
284
+ ownerHistoryRef(anchor.ownerHistoryId),
285
+ null,
286
+ null,
287
+ uniqueRelated.map(id => `#${id}`),
288
+ null,
289
+ `#${relatingControlId}`,
290
+ ]).expressId;
291
+ }
292
+ /** Assign `itemIds` (IfcCostItem) to `scheduleId` (IfcCostSchedule) as its controlled objects. */
293
+ export function assignCostItemsToScheduleInStore(editor, anchor, scheduleId, itemIds, existingAssignment) {
294
+ return assignToControlInStore(editor, anchor, scheduleId, itemIds, existingAssignment, 'assignCostItemsToSchedule', 'IfcCostSchedule', 'IfcCostItem');
295
+ }
296
+ /**
297
+ * Assign IFC objects (products, tasks, resources, etc.) to a cost item.
298
+ * The controlling item itself is not a legal related member.
299
+ */
300
+ export function assignObjectsToCostItemInStore(editor, anchor, costItemId, objectIds, existingAssignment) {
301
+ return assignToControlInStore(editor, anchor, costItemId, objectIds, existingAssignment, 'assignToCostItem', 'IfcCostItem', 'IfcObjectDefinition');
302
+ }
303
+ /**
304
+ * Set (replace) `itemId`'s `IfcCostItem.CostValues` (slot 7). `valueIds` is
305
+ * REQUIRED, not optional: an empty array is how a caller CLEARS the list,
306
+ * written as `$` — never `()`, which `[1:?]` forbids.
307
+ */
308
+ export function attachCostValuesToItemInStore(editor, anchor, itemId, valueIds) {
309
+ assertCostSchema(requireMatchingCostSchema(editor, anchor.schema), 'setCostItemValues');
310
+ requireEntityType(editor, itemId, 'IfcCostItem', 'itemId', 'setCostItemValues');
311
+ for (const id of valueIds) {
312
+ requireRef(id, 'CostValues', 'setCostItemValues');
313
+ requireEntityType(editor, id, 'IfcCostValue', 'CostValues', 'setCostItemValues');
314
+ }
315
+ // De-duplicated (SET semantics, first occurrence kept), like every other
316
+ // list writer here (nestCostItemsInStore's childIds, assignToControlInStore's
317
+ // relatedObjectIds, …) — a repeated id must not write a repeated #N into a
318
+ // list the evaluator sums over (setCostItemValues([v, v]) would otherwise
319
+ // double-count that value).
320
+ const uniqueValueIds = [...new Set(valueIds)];
321
+ editor.setPositionalAttribute(itemId, 7, uniqueValueIds.length === 0 ? null : uniqueValueIds.map(id => `#${id}`));
322
+ }
323
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/in-store/cost.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-source.d.ts","sourceRoot":"","sources":["../../src/in-store/resolve-source.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAA2B,MAAM,gBAAgB,CAAC;AA0ChF;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,eAAe,EAAE,MAAM,GACtB,gBAAgB,CA0GlB"}
1
+ {"version":3,"file":"resolve-source.d.ts","sourceRoot":"","sources":["../../src/in-store/resolve-source.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGtE,OAAO,KAAK,EAAE,gBAAgB,EAA2B,MAAM,gBAAgB,CAAC;AA0ChF;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,eAAe,EAAE,MAAM,GACtB,gBAAgB,CA+GlB"}
@@ -12,6 +12,7 @@
12
12
  * backend layer can call it without needing parser internals.
13
13
  */
14
14
  import { EntityExtractor } from '@ifc-lite/parser';
15
+ import { resolvedTypeName } from '@ifc-lite/data';
15
16
  import { safeLengthUnitScale } from './length-unit-scale.js';
16
17
  /**
17
18
  * Rel types whose `RelatedObjects` list is replayed against a
@@ -130,11 +131,13 @@ export function resolveDuplicateSource(store, sourceExpressId) {
130
131
  // duplicate flow convert its metre offset onto the native-unit
131
132
  // sourceLocation. Falls back to 1 (metres) on extraction failure.
132
133
  const lengthUnitScale = safeLengthUnitScale(store.source, store.entityIndex, 'resolveDuplicateSource') ?? 1.0;
134
+ // Canonical PascalCase, or the raw STEP type as parsed (#4933).
135
+ const type = resolvedTypeName(store.entities, sourceExpressId) ?? sourceEntity.type;
136
+ if (!type) {
137
+ throw new Error(`resolveDuplicateSource: #${sourceExpressId} has no resolvable IFC type — cannot duplicate`);
138
+ }
133
139
  return {
134
- // Canonical PascalCase (e.g. "IfcWall"); falls back to the raw
135
- // extractor type when the entity table doesn't recognise the id
136
- // (vendor extensions etc).
137
- type: store.entities.getTypeName(sourceExpressId) || sourceEntity.type,
140
+ type,
138
141
  attributes: attrs,
139
142
  placementExpressId: placementId,
140
143
  parentPlacementId,
@@ -191,10 +194,10 @@ function collectSourceAssociations(store, extractor, sourceId) {
191
194
  continue;
192
195
  const name = typeof entity.attributes[2] === 'string' ? entity.attributes[2] : null;
193
196
  const description = typeof entity.attributes[3] === 'string' ? entity.attributes[3] : null;
194
- // Use the entity table's canonical name so the duplicate replays
195
- // a PascalCase type into the editor (e.g. "IfcRelDefinesByProperties"),
196
- // not the byType map's UPPERCASE storage key.
197
- const canonicalRelType = store.entities.getTypeName(relId) || relType;
197
+ // Canonical PascalCase when the table has it; association rels are
198
+ // usually categorised out of the `EntityTable` entirely, so `relType`
199
+ // (the constant this loop is already iterating by) is the fallback.
200
+ const canonicalRelType = resolvedTypeName(store.entities, relId) ?? relType;
198
201
  out.push({
199
202
  relType: canonicalRelType,
200
203
  ownerHistoryId,