@ifc-lite/export 2.9.4 → 3.0.1

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 (126) hide show
  1. package/dist/csv-cell.d.ts +101 -0
  2. package/dist/csv-cell.d.ts.map +1 -0
  3. package/dist/csv-cell.js +90 -0
  4. package/dist/csv-cell.js.map +1 -0
  5. package/dist/declared-property-type.d.ts +19 -8
  6. package/dist/declared-property-type.d.ts.map +1 -1
  7. package/dist/declared-property-type.js +31 -9
  8. package/dist/declared-property-type.js.map +1 -1
  9. package/dist/demesh-session.d.ts.map +1 -1
  10. package/dist/demesh-session.js +2 -1
  11. package/dist/demesh-session.js.map +1 -1
  12. package/dist/effective-index.js +1 -1
  13. package/dist/index.d.ts +1 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +9 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/lod1-generator.d.ts +0 -2
  18. package/dist/lod1-generator.d.ts.map +1 -1
  19. package/dist/lod1-generator.js +1 -1
  20. package/dist/lod1-generator.js.map +1 -1
  21. package/dist/merged-exporter.d.ts +19 -0
  22. package/dist/merged-exporter.d.ts.map +1 -1
  23. package/dist/merged-exporter.js +23 -41
  24. package/dist/merged-exporter.js.map +1 -1
  25. package/dist/parquet-exporter.d.ts +1 -3
  26. package/dist/parquet-exporter.d.ts.map +1 -1
  27. package/dist/parquet-exporter.js +1 -0
  28. package/dist/parquet-exporter.js.map +1 -1
  29. package/dist/property-value-serialization.d.ts +54 -0
  30. package/dist/property-value-serialization.d.ts.map +1 -0
  31. package/dist/property-value-serialization.js +134 -0
  32. package/dist/property-value-serialization.js.map +1 -0
  33. package/dist/reference-collector.d.ts +20 -0
  34. package/dist/reference-collector.d.ts.map +1 -1
  35. package/dist/reference-collector.js +46 -113
  36. package/dist/reference-collector.js.map +1 -1
  37. package/dist/schema-converter.d.ts.map +1 -1
  38. package/dist/schema-converter.js +46 -96
  39. package/dist/schema-converter.js.map +1 -1
  40. package/dist/source-ref-bounds.d.ts +3 -3
  41. package/dist/source-ref-bounds.js +3 -3
  42. package/dist/step-attribute-mutations.d.ts +49 -0
  43. package/dist/step-attribute-mutations.d.ts.map +1 -0
  44. package/dist/step-attribute-mutations.js +172 -0
  45. package/dist/step-attribute-mutations.js.map +1 -0
  46. package/dist/step-attribute-serializers.d.ts +41 -0
  47. package/dist/step-attribute-serializers.d.ts.map +1 -0
  48. package/dist/step-attribute-serializers.js +74 -0
  49. package/dist/step-attribute-serializers.js.map +1 -0
  50. package/dist/step-collection.d.ts +55 -0
  51. package/dist/step-collection.d.ts.map +1 -0
  52. package/dist/step-collection.js +126 -0
  53. package/dist/step-collection.js.map +1 -0
  54. package/dist/step-export-contexts.d.ts +61 -0
  55. package/dist/step-export-contexts.d.ts.map +1 -0
  56. package/dist/step-export-contexts.js +50 -0
  57. package/dist/step-export-contexts.js.map +1 -0
  58. package/dist/step-export-types.d.ts +262 -0
  59. package/dist/step-export-types.d.ts.map +1 -0
  60. package/dist/step-export-types.js +22 -0
  61. package/dist/step-export-types.js.map +1 -0
  62. package/dist/step-exporter.d.ts +23 -354
  63. package/dist/step-exporter.d.ts.map +1 -1
  64. package/dist/step-exporter.js +76 -1260
  65. package/dist/step-exporter.js.map +1 -1
  66. package/dist/step-geometry-types.d.ts +3 -0
  67. package/dist/step-geometry-types.d.ts.map +1 -0
  68. package/dist/step-geometry-types.js +73 -0
  69. package/dist/step-geometry-types.js.map +1 -0
  70. package/dist/step-georeferencing.d.ts +0 -10
  71. package/dist/step-georeferencing.d.ts.map +1 -1
  72. package/dist/step-georeferencing.js +46 -94
  73. package/dist/step-georeferencing.js.map +1 -1
  74. package/dist/step-header.d.ts +53 -0
  75. package/dist/step-header.d.ts.map +1 -0
  76. package/dist/step-header.js +63 -0
  77. package/dist/step-header.js.map +1 -0
  78. package/dist/step-map-unit.d.ts +90 -0
  79. package/dist/step-map-unit.d.ts.map +1 -0
  80. package/dist/step-map-unit.js +277 -0
  81. package/dist/step-map-unit.js.map +1 -0
  82. package/dist/step-omission-predicates.d.ts +51 -0
  83. package/dist/step-omission-predicates.d.ts.map +1 -0
  84. package/dist/step-omission-predicates.js +268 -0
  85. package/dist/step-omission-predicates.js.map +1 -0
  86. package/dist/step-overlay-attribute-overrides.d.ts +32 -0
  87. package/dist/step-overlay-attribute-overrides.d.ts.map +1 -0
  88. package/dist/step-overlay-attribute-overrides.js +83 -0
  89. package/dist/step-overlay-attribute-overrides.js.map +1 -0
  90. package/dist/step-overlay-entities.d.ts +64 -0
  91. package/dist/step-overlay-entities.d.ts.map +1 -0
  92. package/dist/step-overlay-entities.js +119 -0
  93. package/dist/step-overlay-entities.js.map +1 -0
  94. package/dist/step-pass-builder.d.ts +45 -0
  95. package/dist/step-pass-builder.d.ts.map +1 -0
  96. package/dist/step-pass-builder.js +249 -0
  97. package/dist/step-pass-builder.js.map +1 -0
  98. package/dist/step-property-set-collection.d.ts +24 -0
  99. package/dist/step-property-set-collection.d.ts.map +1 -0
  100. package/dist/step-property-set-collection.js +286 -0
  101. package/dist/step-property-set-collection.js.map +1 -0
  102. package/dist/step-property-set-generators.d.ts +20 -0
  103. package/dist/step-property-set-generators.d.ts.map +1 -0
  104. package/dist/step-property-set-generators.js +98 -0
  105. package/dist/step-property-set-generators.js.map +1 -0
  106. package/dist/step-property-set-index.d.ts +25 -0
  107. package/dist/step-property-set-index.d.ts.map +1 -0
  108. package/dist/step-property-set-index.js +69 -0
  109. package/dist/step-property-set-index.js.map +1 -0
  110. package/dist/step-property-set-readers.d.ts +158 -0
  111. package/dist/step-property-set-readers.d.ts.map +1 -0
  112. package/dist/step-property-set-readers.js +251 -0
  113. package/dist/step-property-set-readers.js.map +1 -0
  114. package/dist/step-property-sets.d.ts +2 -184
  115. package/dist/step-property-sets.d.ts.map +1 -1
  116. package/dist/step-property-sets.js +22 -674
  117. package/dist/step-property-sets.js.map +1 -1
  118. package/dist/step-serialization.d.ts +33 -52
  119. package/dist/step-serialization.d.ts.map +1 -1
  120. package/dist/step-serialization.js +69 -131
  121. package/dist/step-serialization.js.map +1 -1
  122. package/dist/step-source-iteration.d.ts +97 -0
  123. package/dist/step-source-iteration.d.ts.map +1 -0
  124. package/dist/step-source-iteration.js +178 -0
  125. package/dist/step-source-iteration.js.map +1 -0
  126. package/package.json +7 -7
@@ -0,0 +1,49 @@
1
+ import type { MutablePropertyView } from '@ifc-lite/mutations';
2
+ import type { IfcSchemaVersion } from './schema-converter.js';
3
+ import type { SourceLineMutations } from './step-exporter.js';
4
+ /**
5
+ * THE mutation pipeline for a line read out of the source buffer: retype,
6
+ * then named attribute edits, then positional edits.
7
+ *
8
+ * **One implementation, two call sites**, and that is the whole point. Two
9
+ * passes can write the defining line of a source entity — the
10
+ * source-iteration pass, and the type-object `HasPropertySets` rewrite that
11
+ * REPLACES it (`rewrittenEntityIds` makes the source pass skip those ids).
12
+ * The rewrite used to do its own thing (replace slot 5, nothing else), so
13
+ * every other edit to a type object with a type-owned pset edit was dropped
14
+ * in silence: first the renames (#2462 follow-up), and after those were
15
+ * special-cased here, still the retypes and the positional edits. Whatever
16
+ * the source pass applies, the rewrite has to apply too, or the next edit
17
+ * kind added to one site goes missing at the other.
18
+ *
19
+ * The order is load-bearing:
20
+ *
21
+ * - the retype runs FIRST so named attribute edits resolve against the
22
+ * TARGET class's attribute names, and so positional slots are indexed
23
+ * into the retyped argument list;
24
+ * - the `HasPropertySets` replacement (rewrite path only) runs LAST, on
25
+ * the text this returns. Run it first and a positional edit to slot 5 —
26
+ * or a retype's argument-list rebuild — overwrites the resolved pset
27
+ * list with the stale one, which is the same silent drop one slot over.
28
+ *
29
+ * The expressId is unchanged by all of this, so geometry / placement /
30
+ * representation and every IfcRel* reference (keyed by #id) carry over.
31
+ *
32
+ * All three flags report EFFECT, not intent — each is the answer to "did this
33
+ * operation change the line", measured across that operation alone. The count
34
+ * and the ledger are claims about the FILE, so an edit that resolves to the
35
+ * text already there has delivered nothing and must not be reported: retyping
36
+ * an entity to the class it already is, or writing a positional slot the token
37
+ * it already holds, used to count as a modification and reach the ledger as a
38
+ * landed edit, over a byte-identical line. Discarded edits read the same way:
39
+ * `applyAttributeMutations` drops a name its class has no slot for and
40
+ * `retypeStepLine` returns an unparseable line untouched, and neither is a
41
+ * modification of anything.
42
+ *
43
+ * `retyped` / `positional` matter most in a FULL export, which is where the
44
+ * two are nominated (their edits have no earlier nomination site); named
45
+ * attribute edits are nominated by the collection pass and `attributed` only
46
+ * settles their delivery.
47
+ */
48
+ export declare function applySourceLineMutations(mutationView: MutablePropertyView | null, expressId: number, entityText: string, recordType: string, attributeMutations: Map<string, string> | undefined, sourceSchema: IfcSchemaVersion, overlayActive: boolean, onRejected?: (attrName: string, value: string) => void): SourceLineMutations;
49
+ //# sourceMappingURL=step-attribute-mutations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-attribute-mutations.d.ts","sourceRoot":"","sources":["../src/step-attribute-mutations.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,mBAAmB,GAAG,IAAI,EACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,OAAO,EACtB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACrD,mBAAmB,CAmDrB"}
@@ -0,0 +1,172 @@
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
+ * THE source-buffer attribute-mutation pipeline: retype, then named
6
+ * attribute edits, then positional edits, applied to a line read out of the
7
+ * STEP source. Both {@link applySourceLineMutations}'s call sites — the
8
+ * source-iteration pass and the type-object `HasPropertySets` rewrite that
9
+ * REPLACES it — are documented on the function itself.
10
+ *
11
+ * This file used to also hold the overlay-created sibling pipeline and the
12
+ * two per-slot serialize helpers both pipelines share; #3184 split those out
13
+ * along the line this module's own doc already drew — the overlay-created
14
+ * pipeline is now `step-overlay-attribute-overrides.ts`, and the shared
15
+ * serializers are `step-attribute-serializers.ts`.
16
+ */
17
+ import { splitTopLevelArgs } from './step-argument-parser.js';
18
+ import { getRealTypedSlots } from './attribute-real-slots.js';
19
+ import { retypeStepLine } from './retype.js';
20
+ import { getAttributeNamesAcrossSchemas } from '@ifc-lite/parser';
21
+ import { serializeNamedAttribute, serializePositionalOverride } from './step-attribute-serializers.js';
22
+ /**
23
+ * THE mutation pipeline for a line read out of the source buffer: retype,
24
+ * then named attribute edits, then positional edits.
25
+ *
26
+ * **One implementation, two call sites**, and that is the whole point. Two
27
+ * passes can write the defining line of a source entity — the
28
+ * source-iteration pass, and the type-object `HasPropertySets` rewrite that
29
+ * REPLACES it (`rewrittenEntityIds` makes the source pass skip those ids).
30
+ * The rewrite used to do its own thing (replace slot 5, nothing else), so
31
+ * every other edit to a type object with a type-owned pset edit was dropped
32
+ * in silence: first the renames (#2462 follow-up), and after those were
33
+ * special-cased here, still the retypes and the positional edits. Whatever
34
+ * the source pass applies, the rewrite has to apply too, or the next edit
35
+ * kind added to one site goes missing at the other.
36
+ *
37
+ * The order is load-bearing:
38
+ *
39
+ * - the retype runs FIRST so named attribute edits resolve against the
40
+ * TARGET class's attribute names, and so positional slots are indexed
41
+ * into the retyped argument list;
42
+ * - the `HasPropertySets` replacement (rewrite path only) runs LAST, on
43
+ * the text this returns. Run it first and a positional edit to slot 5 —
44
+ * or a retype's argument-list rebuild — overwrites the resolved pset
45
+ * list with the stale one, which is the same silent drop one slot over.
46
+ *
47
+ * The expressId is unchanged by all of this, so geometry / placement /
48
+ * representation and every IfcRel* reference (keyed by #id) carry over.
49
+ *
50
+ * All three flags report EFFECT, not intent — each is the answer to "did this
51
+ * operation change the line", measured across that operation alone. The count
52
+ * and the ledger are claims about the FILE, so an edit that resolves to the
53
+ * text already there has delivered nothing and must not be reported: retyping
54
+ * an entity to the class it already is, or writing a positional slot the token
55
+ * it already holds, used to count as a modification and reach the ledger as a
56
+ * landed edit, over a byte-identical line. Discarded edits read the same way:
57
+ * `applyAttributeMutations` drops a name its class has no slot for and
58
+ * `retypeStepLine` returns an unparseable line untouched, and neither is a
59
+ * modification of anything.
60
+ *
61
+ * `retyped` / `positional` matter most in a FULL export, which is where the
62
+ * two are nominated (their edits have no earlier nomination site); named
63
+ * attribute edits are nominated by the collection pass and `attributed` only
64
+ * settles their delivery.
65
+ */
66
+ export function applySourceLineMutations(mutationView, expressId, entityText, recordType, attributeMutations, sourceSchema, overlayActive, onRejected) {
67
+ let text = entityText;
68
+ let workingType = recordType.toUpperCase();
69
+ const typeMutation = overlayActive && typeof mutationView.getEntityTypeMutation === 'function'
70
+ ? mutationView.getEntityTypeMutation(expressId)
71
+ : null;
72
+ let retyped = false;
73
+ if (typeMutation) {
74
+ const beforeRetype = text;
75
+ text = retypeStepLine(text, recordType, typeMutation.newType, typeMutation.predefinedType ?? null, sourceSchema);
76
+ retyped = text !== beforeRetype;
77
+ // Set even for a no-op retype: the entity IS the target class from here
78
+ // on, so the named and positional edits below must resolve against it.
79
+ workingType = typeMutation.newType.toUpperCase();
80
+ }
81
+ // `applyAttributeMutations` returns its input UNCHANGED when it wrote
82
+ // nothing — no slot resolved for any of the names, or the line does not
83
+ // parse — so comparing is what tells the ledger whether a named attribute
84
+ // edit was really carried, rather than merely attempted.
85
+ let attributed = false;
86
+ if (attributeMutations && attributeMutations.size > 0) {
87
+ const beforeAttributes = text;
88
+ text = applyAttributeMutations(text, workingType, attributeMutations, sourceSchema, onRejected);
89
+ attributed = text !== beforeAttributes;
90
+ }
91
+ const positionals = overlayActive && typeof mutationView.getPositionalMutationsForEntity === 'function'
92
+ ? mutationView.getPositionalMutationsForEntity(expressId)
93
+ : null;
94
+ let positional = false;
95
+ if (positionals && positionals.size > 0) {
96
+ const beforePositionals = text;
97
+ text = applyPositionalMutations(text, positionals, workingType, sourceSchema);
98
+ positional = text !== beforePositionals;
99
+ }
100
+ return { text, attributed, retyped, positional };
101
+ }
102
+ /**
103
+ * Rewrite root IFC attributes directly on the original STEP entity line.
104
+ */
105
+ function applyAttributeMutations(entityText, entityType, attributeMutations, schemaVersion, onRejected) {
106
+ const openParen = entityText.indexOf('(');
107
+ const closeParen = entityText.lastIndexOf(');');
108
+ if (openParen < 0 || closeParen < openParen) {
109
+ return entityText;
110
+ }
111
+ // Cross-schema, not the IFC4 pin: an IFC4X3-only class (IfcCourse, IfcRoad,
112
+ // IfcBridge, …) resolves no slots under the pin, so every named edit on one
113
+ // was silently discarded here too. Identical for the 755 pinned classes
114
+ // that declare attributes — `attribute-slot-types.test.ts` measures that —
115
+ // so no IFC4 export changes; this only stops dropping edits it used to drop.
116
+ const attrNames = getAttributeNamesAcrossSchemas(entityType);
117
+ if (attrNames.length === 0) {
118
+ return entityText;
119
+ }
120
+ const args = splitTopLevelArgs(entityText.slice(openParen + 1, closeParen));
121
+ // A source line NEVER pads (unlike the overlay-created path): a short
122
+ // argument list here means the file speaks a different schema, and growing
123
+ // a record we did not author would corrupt it.
124
+ let changed = false;
125
+ const realSlots = getRealTypedSlots(entityType, schemaVersion);
126
+ for (const [attrName, value] of attributeMutations) {
127
+ const index = attrNames.indexOf(attrName);
128
+ if (index < 0 || index >= args.length)
129
+ continue;
130
+ // The source path shares every `$`-slot hole with the overlay-created
131
+ // path, because a source record has plenty of `$` slots of its own. Both
132
+ // go through the one helper below.
133
+ const serialized = serializeNamedAttribute(entityType, index, value, args[index], realSlots);
134
+ if (serialized === null) {
135
+ // Slot untouched AND reported. Not counted as a change: claiming a
136
+ // modification we did not make is the failure this avoids.
137
+ onRejected?.(attrName, value);
138
+ continue;
139
+ }
140
+ args[index] = serialized;
141
+ changed = true;
142
+ }
143
+ if (!changed) {
144
+ return entityText;
145
+ }
146
+ return `${entityText.slice(0, openParen + 1)}${args.join(',')}${entityText.slice(closeParen)}`;
147
+ }
148
+ /**
149
+ * Apply positional STEP argument overrides to an entity line.
150
+ * Used for non-IfcRoot edits (e.g. profile dimensions) where attributes
151
+ * have no symbolic names. Indexes that fall outside the existing arg list
152
+ * are silently ignored.
153
+ */
154
+ function applyPositionalMutations(entityText, positionals, entityType, schemaVersion) {
155
+ const openParen = entityText.indexOf('(');
156
+ const closeParen = entityText.lastIndexOf(');');
157
+ if (openParen < 0 || closeParen < openParen)
158
+ return entityText;
159
+ const args = splitTopLevelArgs(entityText.slice(openParen + 1, closeParen));
160
+ const realSlots = getRealTypedSlots(entityType, schemaVersion);
161
+ let changed = false;
162
+ for (const [index, value] of positionals) {
163
+ if (index < 0 || index >= args.length)
164
+ continue;
165
+ args[index] = serializePositionalOverride(entityType, index, value, args[index], realSlots, schemaVersion);
166
+ changed = true;
167
+ }
168
+ if (!changed)
169
+ return entityText;
170
+ return `${entityText.slice(0, openParen + 1)}${args.join(',')}${entityText.slice(closeParen)}`;
171
+ }
172
+ //# sourceMappingURL=step-attribute-mutations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-attribute-mutations.js","sourceRoot":"","sources":["../src/step-attribute-mutations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The two per-slot serialize helpers `step-attribute-mutations.ts`'s
3
+ * source-buffer pipeline and `step-overlay-attribute-overrides.ts`'s
4
+ * overlay-created pipeline both go through — the single point where a named
5
+ * or positional override becomes a STEP token. Split out of
6
+ * `step-attribute-mutations.ts` (#3184).
7
+ */
8
+ import type { IfcAttributeValue } from '@ifc-lite/parser';
9
+ import type { IfcSchemaVersion } from './schema-converter.js';
10
+ /**
11
+ * Serialize one NAMED attribute override into its slot — the single point
12
+ * both the source-buffer rewrite and the overlay-created rewrite go through.
13
+ *
14
+ * `serializeAttributeValue` decides the STEP form by reading the token being
15
+ * replaced, which is sound only while that token carries type information. A
16
+ * `$` slot carries none, and both paths have plenty: a source record's
17
+ * optional attributes are `$`, and overlay-created records pad missing slots
18
+ * with `$`. So the declared type decides first, and inference is the fallback
19
+ * for slots the schema does not classify (references, SELECTs, numerics),
20
+ * where reading the old token is exactly the right heuristic.
21
+ *
22
+ * Before this REAL check existed, "the declared type decides first" was true
23
+ * for enum/string slots only — a REAL-backed slot (`IfcMapConversion.
24
+ * OrthogonalHeight`, any other `IfcLengthMeasure`/`IfcReal`-typed attribute)
25
+ * fell straight to `serializeAttributeValue`'s token inference, which quotes
26
+ * anything it cannot recognize as numeric. A schema-legal `$` placeholder
27
+ * carries no digits to recognize, so setting such a field for the first time
28
+ * wrote `'12345'` in a slot ISO 10303-21 requires to be an unquoted REAL —
29
+ * silently invalid output (#2724, LTplus-AG/ifc-lite#2475).
30
+ */
31
+ export declare function serializeNamedAttribute(entityType: string, index: number, value: string, currentToken: string, realSlots: ReadonlySet<number>): string | null;
32
+ /**
33
+ * Serialize one positional override, composing the schema-aware passes:
34
+ * explicit `{ real }`/`{ typed }` marker → SELECT auto-qualification
35
+ * (`IFCBOOLEAN(.T.)`) → REAL forcing. For REAL forcing the current source
36
+ * token is a secondary signal: replacing a value that was already a REAL
37
+ * (`0.4`, `1.5E-7`) keeps it REAL even for entities the XSD index doesn't
38
+ * cover, so a whole-number edit can't silently downgrade the slot.
39
+ */
40
+ export declare function serializePositionalOverride(entityType: string, index: number, value: IfcAttributeValue, currentToken: string, realSlots: ReadonlySet<number>, schemaVersion: IfcSchemaVersion): string;
41
+ //# sourceMappingURL=step-attribute-serializers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-attribute-serializers.d.ts","sourceRoot":"","sources":["../src/step-attribute-serializers.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAU1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAC7B,MAAM,GAAG,IAAI,CAuBf;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,iBAAiB,EACxB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAC9B,aAAa,EAAE,gBAAgB,GAC9B,MAAM,CAMR"}
@@ -0,0 +1,74 @@
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 { getEnumTypedSlots, getStringTypedSlots, serializeEnumToken, serializeStringSlot } from './attribute-slot-types.js';
5
+ import { isTypedMarker } from './attribute-real-slots.js';
6
+ import { serializeQualifiedSelectSlot } from './select-qualification.js';
7
+ import { toStepReal, serializeAttributeValue, serializeStepValue, tokenIsRealLiteral, } from './step-serialization.js';
8
+ /**
9
+ * Serialize one NAMED attribute override into its slot — the single point
10
+ * both the source-buffer rewrite and the overlay-created rewrite go through.
11
+ *
12
+ * `serializeAttributeValue` decides the STEP form by reading the token being
13
+ * replaced, which is sound only while that token carries type information. A
14
+ * `$` slot carries none, and both paths have plenty: a source record's
15
+ * optional attributes are `$`, and overlay-created records pad missing slots
16
+ * with `$`. So the declared type decides first, and inference is the fallback
17
+ * for slots the schema does not classify (references, SELECTs, numerics),
18
+ * where reading the old token is exactly the right heuristic.
19
+ *
20
+ * Before this REAL check existed, "the declared type decides first" was true
21
+ * for enum/string slots only — a REAL-backed slot (`IfcMapConversion.
22
+ * OrthogonalHeight`, any other `IfcLengthMeasure`/`IfcReal`-typed attribute)
23
+ * fell straight to `serializeAttributeValue`'s token inference, which quotes
24
+ * anything it cannot recognize as numeric. A schema-legal `$` placeholder
25
+ * carries no digits to recognize, so setting such a field for the first time
26
+ * wrote `'12345'` in a slot ISO 10303-21 requires to be an unquoted REAL —
27
+ * silently invalid output (#2724, LTplus-AG/ifc-lite#2475).
28
+ */
29
+ export function serializeNamedAttribute(entityType, index, value, currentToken, realSlots) {
30
+ if (getEnumTypedSlots(entityType).has(index))
31
+ return serializeEnumToken(value);
32
+ if (getStringTypedSlots(entityType).has(index))
33
+ return serializeStringSlot(value);
34
+ if (realSlots.has(index)) {
35
+ const trimmed = value.trim();
36
+ if (trimmed === '')
37
+ return '$';
38
+ const numberValue = Number(trimmed);
39
+ if (Number.isFinite(numberValue))
40
+ return toStepReal(numberValue);
41
+ // A non-numeric value in a REAL slot used to fall through and be QUOTED,
42
+ // producing the same ISO 10303-21 violation #2725 exists to prevent
43
+ // (#2741). `StoreEditor.setAttribute` takes a string, so any UI text
44
+ // field bound to a georeferencing REAL can deliver one; it does not need
45
+ // a corrupt file.
46
+ //
47
+ // `null` means "leave the slot as the file had it". Simply returning
48
+ // `currentToken` here would stop the invalid output but SILENTLY DISCARD
49
+ // the edit - the exporter would then claim a modification it did not
50
+ // carry, which is the exact misreport #2723/#2724/#2726 were written to
51
+ // pin. The caller turns this into a warning, so a dropped edit is visible
52
+ // rather than inferred from absence.
53
+ return null;
54
+ }
55
+ return serializeAttributeValue(value, currentToken);
56
+ }
57
+ /**
58
+ * Serialize one positional override, composing the schema-aware passes:
59
+ * explicit `{ real }`/`{ typed }` marker → SELECT auto-qualification
60
+ * (`IFCBOOLEAN(.T.)`) → REAL forcing. For REAL forcing the current source
61
+ * token is a secondary signal: replacing a value that was already a REAL
62
+ * (`0.4`, `1.5E-7`) keeps it REAL even for entities the XSD index doesn't
63
+ * cover, so a whole-number edit can't silently downgrade the slot.
64
+ */
65
+ export function serializePositionalOverride(entityType, index, value, currentToken, realSlots, schemaVersion) {
66
+ if (isTypedMarker(value))
67
+ return serializeStepValue(value);
68
+ const qualified = serializeQualifiedSelectSlot(entityType, index, value);
69
+ if (qualified !== null)
70
+ return qualified;
71
+ const forceReal = realSlots.has(index) || tokenIsRealLiteral(currentToken);
72
+ return serializeStepValue(value, forceReal);
73
+ }
74
+ //# sourceMappingURL=step-attribute-serializers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-attribute-serializers.js","sourceRoot":"","sources":["../src/step-attribute-serializers.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAW/D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAC5H,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EACL,UAAU,EACV,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAkB,EAClB,KAAa,EACb,KAAa,EACb,YAAoB,EACpB,SAA8B;IAE9B,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC/E,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAClF,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,GAAG,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,UAAU,CAAC,WAAW,CAAC,CAAC;QACjE,yEAAyE;QACzE,oEAAoE;QACpE,qEAAqE;QACrE,yEAAyE;QACzE,kBAAkB;QAClB,EAAE;QACF,qEAAqE;QACrE,yEAAyE;QACzE,qEAAqE;QACrE,wEAAwE;QACxE,0EAA0E;QAC1E,qCAAqC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,uBAAuB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAAkB,EAClB,KAAa,EACb,KAAwB,EACxB,YAAoB,EACpB,SAA8B,EAC9B,aAA+B;IAE/B,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,4BAA4B,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzE,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC3E,OAAO,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The collection phase of `StepExporter.export()` (#2475, the collection
3
+ * block): builds the visible-only closure (`pass.allowedEntityIds` /
4
+ * `hiddenProductIds`), groups the overlay's mutation history by entity and
5
+ * kind, and applies the georeferencing edits. Nothing here WRITES a STEP
6
+ * line — every write happens in a later phase (`step-source-iteration.ts`,
7
+ * `step-property-sets.ts`, `step-georeferencing.ts`'s own new-entity lines,
8
+ * `step-overlay-entities.ts`) that reads what this phase left on `pass`.
9
+ *
10
+ * `PropertyMutationGroups` (`step-property-set-collection.ts`) already names the
11
+ * boundary this module sits behind: "the mutation groupings `export()`
12
+ * builds before the collection phase runs." This is that builder, plus the
13
+ * two collection calls (`buildRelDefinesByPropertiesIndex` /
14
+ * `collectPropertyAndQuantitySetMutations`) it was already handing them to.
15
+ *
16
+ * `hasAnyUnreadableSourceRef` and the `mayNameOmittedRefs` /
17
+ * `isOmittedFromOutput` predicates it feeds do NOT live here: they read
18
+ * `pass.effective` and this phase's OUTPUT (`allowedEntityIds`,
19
+ * `overlayActive`), but nothing in THIS module reads them back, so moving them
20
+ * here would not shrink a dependency, only relocate it. That argument was
21
+ * always about this module specifically. They live in
22
+ * `step-omission-predicates.ts`, called from `export()` immediately after this
23
+ * phase returns (#2475).
24
+ */
25
+ import type { IfcDataStore } from '@ifc-lite/parser';
26
+ import type { MutablePropertyView } from '@ifc-lite/mutations';
27
+ import { type PropertySetContext } from './step-property-set-readers.js';
28
+ import { type GeorefContext } from './step-georeferencing.js';
29
+ import type { ExportPass, StepExportOptions } from './step-exporter.js';
30
+ /**
31
+ * The exporter state this phase cannot read off the pass.
32
+ *
33
+ * `propertySetContext` and `georefContext` are thunks, not values, matching
34
+ * every other call site of theirs in `export()`: this phase calls
35
+ * `propertySetContext()` twice (once for `buildRelDefinesByPropertiesIndex`,
36
+ * once for `collectPropertyAndQuantitySetMutations`) and moving that call
37
+ * out from under the two sites — deriving one value up front instead —
38
+ * would be a behaviour change nothing here asked for.
39
+ */
40
+ export interface CollectionContext {
41
+ readonly dataStore: IfcDataStore;
42
+ readonly mutationView: MutablePropertyView | null;
43
+ readonly propertySetContext: () => PropertySetContext;
44
+ readonly georefContext: (deltaOnly: boolean) => GeorefContext;
45
+ }
46
+ /**
47
+ * Populate `pass` with everything the overlay's edits and `options` imply,
48
+ * in place. The caller owns three gates and this phase does not re-derive
49
+ * any of them: `applyMutations` (`options.applyMutations !== false`, read
50
+ * once in `export()` — see the "read ONCE" comment there for why a second
51
+ * read would be a bug, not a style choice), `options.visibleOnly`, and
52
+ * `options.georefMutations`.
53
+ */
54
+ export declare function collectModifications(pass: ExportPass, options: StepExportOptions, applyMutations: boolean, ctx: CollectionContext): void;
55
+ //# sourceMappingURL=step-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-collection.d.ts","sourceRoot":"","sources":["../src/step-collection.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAgC,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,aAAa,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,iBAAiB,EAC1B,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,iBAAiB,GACrB,IAAI,CAsIN"}
@@ -0,0 +1,126 @@
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 { collectReferencedEntityIds, getVisibleEntityIds, collectStyleEntities } from './reference-collector.js';
5
+ import { buildRelDefinesByPropertiesIndex } from './step-property-set-index.js';
6
+ import { collectPropertyAndQuantitySetMutations } from './step-property-set-collection.js';
7
+ import { applyGeoreferencingMutations } from './step-georeferencing.js';
8
+ /**
9
+ * Populate `pass` with everything the overlay's edits and `options` imply,
10
+ * in place. The caller owns three gates and this phase does not re-derive
11
+ * any of them: `applyMutations` (`options.applyMutations !== false`, read
12
+ * once in `export()` — see the "read ONCE" comment there for why a second
13
+ * read would be a bug, not a style choice), `options.visibleOnly`, and
14
+ * `options.georefMutations`.
15
+ */
16
+ export function collectModifications(pass, options, applyMutations, ctx) {
17
+ if (options.visibleOnly && ctx.dataStore.source) {
18
+ const visible = getVisibleEntityIds(ctx.dataStore, options.hiddenEntityIds ?? new Set(), options.isolatedEntityIds ?? null, pass.effective);
19
+ pass.hiddenProductIds = visible.hiddenProductIds;
20
+ pass.allowedEntityIds = collectReferencedEntityIds(visible.roots, ctx.dataStore.source, pass.effective, visible.hiddenProductIds, pass.isRefExcludedDuringClosureWalk);
21
+ // Second pass: collect IFCSTYLEDITEM entities that reference included
22
+ // geometry. Styled items reference geometry items but nothing references
23
+ // them back, so the forward closure misses them.
24
+ collectStyleEntities(pass.allowedEntityIds, ctx.dataStore.source, { byId: pass.effective, byType: pass.effective.byType });
25
+ }
26
+ // Process mutations if we have a mutation view
27
+ if (ctx.mutationView && applyMutations) {
28
+ const mutationView = ctx.mutationView;
29
+ const mutations = mutationView.getMutations();
30
+ // Attribute values come from the *overlay*, never from the mutation
31
+ // history. The history is append-only and undo writes its reverse edit
32
+ // with `skipHistory: true`, so a superseded UPDATE_ATTRIBUTE record keeps
33
+ // its stale `newValue` forever — replaying it resurrects edits the user
34
+ // undid (#1957). The overlay is what the editor shows, and it is already
35
+ // the source for psets, quantities, positional attributes and retypes
36
+ // below, so attributes were the sole outlier.
37
+ for (const [entityId, attrs] of mutationView.getAttributeMutationsByEntity()) {
38
+ pass.modifiedEntities.add(entityId);
39
+ let target = pass.modifiedAttributes.get(entityId);
40
+ if (!target) {
41
+ target = new Map();
42
+ pass.modifiedAttributes.set(entityId, target);
43
+ }
44
+ for (const [name, value] of attrs)
45
+ target.set(name, value);
46
+ }
47
+ // Group mutations by entity, separating property vs quantity mutations
48
+ const entityPropMutations = new Map();
49
+ const entityQuantMutations = new Map();
50
+ for (const mutation of mutations) {
51
+ // Handled above, off the overlay. Skipped explicitly because an
52
+ // UPDATE_ATTRIBUTE record can also carry a `psetName` (georef fields
53
+ // encode their target entity there) and must not be mistaken for a
54
+ // property-set edit.
55
+ if (mutation.type === 'UPDATE_ATTRIBUTE')
56
+ continue;
57
+ if (!mutation.psetName)
58
+ continue;
59
+ const isQuantity = mutation.type === 'CREATE_QUANTITY' || mutation.type === 'UPDATE_QUANTITY'
60
+ || mutation.type === 'DELETE_QUANTITY' || mutation.type === 'DELETE_QUANTITY_SET';
61
+ const targetMap = isQuantity ? entityQuantMutations : entityPropMutations;
62
+ if (!targetMap.has(mutation.entityId)) {
63
+ targetMap.set(mutation.entityId, new Set());
64
+ }
65
+ targetMap.get(mutation.entityId).add(mutation.psetName);
66
+ }
67
+ // Build a reverse index of IfcRelDefinesByProperties → (relId, psetId)
68
+ // pairs keyed on each related entity. The two property/quantity loops
69
+ // below previously walked every entity in `entityIndex.byId` per
70
+ // modified entity (O(E·N)); the index keeps the per-entity step
71
+ // O(K) where K is the number of rels referencing that entity.
72
+ const { byEntity: relDefinesByEntity, relatedByRel } = buildRelDefinesByPropertiesIndex(ctx.propertySetContext());
73
+ // A source IfcRelDefinesByProperties whose EVERY related object the
74
+ // session deleted has nothing left to relate, and emitting it leaves a
75
+ // `#id` pointing at a record the export skipped. Dropped only when all of
76
+ // them are gone: a rel that still names a live entity is that entity's
77
+ // only link to its psets, and nothing here rewrites a RelatedObjects list.
78
+ for (const [relId, related] of relatedByRel) {
79
+ if (related.length > 0 && related.every((id) => pass.effective.isDeleted(id))) {
80
+ pass.skipRelationshipIds.add(relId);
81
+ }
82
+ }
83
+ collectPropertyAndQuantitySetMutations(pass, options, { entityPropMutations, entityQuantMutations, relDefinesByEntity }, ctx.propertySetContext());
84
+ for (const [entityId] of pass.modifiedAttributes) {
85
+ // An overlay-CREATED entity carrying attribute edits is emitted once,
86
+ // by the new-entities pass, and already counted in `newEntityCount`.
87
+ // Counting it here too made the header claim two affected entities for
88
+ // one created-then-renamed wall.
89
+ if (pass.isOverlayCreated(entityId))
90
+ continue;
91
+ // A source entity with no bytes never gets its line rewritten (the
92
+ // source-iteration pass skips it), so an attribute edit against it
93
+ // must not inflate the count either.
94
+ if (!pass.hasEmittableHostBytes(entityId))
95
+ continue;
96
+ // Under `deltaOnly` this only NOMINATES the host's ATTRIBUTE edits:
97
+ // nothing writes an in-place attribute edit into a delta except the
98
+ // type-object line rewrite, so the ledger drops it at settle time
99
+ // unless that pass reports having carried it (#2462). That nomination
100
+ // is deliberately made at INTENT: the per-kind warning exists to NAME
101
+ // an edit the delta could not carry, and an undeliverable edit is
102
+ // exactly the one that must still be named.
103
+ //
104
+ // A FULL export has no such warning, so an edit that resolved to
105
+ // nothing has nothing to say and nothing to claim — it waits for the
106
+ // rewrite instead. `setAttribute` to the value already in the slot, and
107
+ // `setAttribute` naming a slot the class does not declare, both leave
108
+ // the line byte-identical and used to count anyway (#2483).
109
+ //
110
+ // Recorded unconditionally. It used to be skipped for a host that also
111
+ // had a pset or qset edit, because the count was per entity and the
112
+ // other loop had already nominated it — which is exactly what let a
113
+ // pset emission mark the rename delivered and suppress its warning. The
114
+ // ledger de-duplicates the COUNT per entity now, so the two edits can
115
+ // and must be nominated separately.
116
+ pass.inPlaceNominees.attribute.add(entityId);
117
+ if (options.deltaOnly === true)
118
+ pass.modifications.nominate(entityId, 'attribute');
119
+ }
120
+ }
121
+ // Process georeferencing mutations (only when applyMutations is enabled)
122
+ if (applyMutations && options.georefMutations) {
123
+ applyGeoreferencingMutations(pass, options.georefMutations, ctx.georefContext(options.deltaOnly === true));
124
+ }
125
+ }
126
+ //# sourceMappingURL=step-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-collection.js","sourceRoot":"","sources":["../src/step-collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The per-phase contexts that do NOT allocate express ids.
3
+ *
4
+ * Split out of `StepExporter` for #2475. These two are pure forwarders: they
5
+ * assemble what a phase cannot read off the pass, out of values handed to
6
+ * them, and touch no exporter state of their own.
7
+ *
8
+ * WHY ONLY THESE TWO. `georefContext` and `propertySetContext` stay methods on
9
+ * `StepExporter`, and `collectionContext` stays with them because it forwards
10
+ * to both. Those two are the only places that mint express ids, via
11
+ * `allocateExpressId: () => this.nextExpressId++` — two closures over ONE
12
+ * instance counter. Moving them would mean re-establishing that shared
13
+ * identity through a parameter, and capturing the counter's value instead of
14
+ * its closure gives each builder its own sequence, silently emitting two
15
+ * entities with the same `#N` — well-formed STEP in which every reference
16
+ * still resolves, and two different entities.
17
+ *
18
+ * That failure used to be invisible: `findDanglingRefs` collects defined ids
19
+ * into a `Set`, which absorbs a duplicate rather than reporting it. It is now
20
+ * caught — `step-georeferencing.test.ts`'s "mints distinct ids for generated
21
+ * psets and for created georeferencing" drives both allocating paths in one
22
+ * export and asserts no id is defined twice. Freezing both closures fails that
23
+ * test and only that test.
24
+ *
25
+ * So the reason this module holds two functions rather than five is written
26
+ * down here AND checkable, which is the only reason it is safe to leave the
27
+ * other three where they are.
28
+ */
29
+ import type { IfcDataStore } from '@ifc-lite/parser';
30
+ import type { MutablePropertyView } from '@ifc-lite/mutations';
31
+ import type { SourceIterationContext } from './step-source-iteration.js';
32
+ import type { OverlayEntitiesContext } from './step-overlay-entities.js';
33
+ import type { PropertySetContext } from './step-property-set-readers.js';
34
+ /**
35
+ * The state `step-source-iteration.ts` cannot read off the pass (#2475 2d).
36
+ *
37
+ * No `allocateExpressId`: that phase never allocates an id, it only rewrites
38
+ * lines that already have one. `applySourceLineMutations` (a free function in
39
+ * `step-attribute-mutations.ts`, closed over `mutationView` here) and
40
+ * `isGeometryEntity` are injected rather than read off the pass because each
41
+ * has readers outside this phase — the mutation pipeline is shared with the
42
+ * type-object `HasPropertySets` rewrite (see `StepExporter`'s
43
+ * `propertySetContext`, which stays a method because it mints express ids) and
44
+ * with the overlay-created-entities block in `export()`; `isGeometryEntity`
45
+ * with the visible-only setup closure and that same block.
46
+ *
47
+ * `propertySetContext` arrives as a THUNK, not a value: the phase calls it
48
+ * per use and the original method rebuilt it per call, which is the behaviour
49
+ * being preserved.
50
+ */
51
+ export declare function buildSourceIterationContext(dataStore: IfcDataStore, mutationView: MutablePropertyView | null, propertySetContext: () => PropertySetContext): SourceIterationContext;
52
+ /**
53
+ * The state `step-overlay-entities.ts` cannot read off the pass (#2475
54
+ * step 2e). `applyOverlayEntityOverrides` is the free function
55
+ * `step-overlay-attribute-overrides.ts` exports; `isGeometryEntity` and
56
+ * `relationshipWithheldWarning` are the same shared readers
57
+ * {@link buildSourceIterationContext} already injects into the other output
58
+ * pass.
59
+ */
60
+ export declare function buildOverlayEntitiesContext(mutationView: MutablePropertyView | null): OverlayEntitiesContext;
61
+ //# sourceMappingURL=step-export-contexts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-export-contexts.d.ts","sourceRoot":"","sources":["../src/step-export-contexts.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAK/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,YAAY,EACvB,YAAY,EAAE,mBAAmB,GAAG,IAAI,EACxC,kBAAkB,EAAE,MAAM,kBAAkB,GAC3C,sBAAsB,CASxB;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,mBAAmB,GAAG,IAAI,GACvC,sBAAsB,CAOxB"}