@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.
- package/dist/csv-cell.d.ts +101 -0
- package/dist/csv-cell.d.ts.map +1 -0
- package/dist/csv-cell.js +90 -0
- package/dist/csv-cell.js.map +1 -0
- package/dist/declared-property-type.d.ts +19 -8
- package/dist/declared-property-type.d.ts.map +1 -1
- package/dist/declared-property-type.js +31 -9
- package/dist/declared-property-type.js.map +1 -1
- package/dist/demesh-session.d.ts.map +1 -1
- package/dist/demesh-session.js +2 -1
- package/dist/demesh-session.js.map +1 -1
- package/dist/effective-index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/lod1-generator.d.ts +0 -2
- package/dist/lod1-generator.d.ts.map +1 -1
- package/dist/lod1-generator.js +1 -1
- package/dist/lod1-generator.js.map +1 -1
- package/dist/merged-exporter.d.ts +19 -0
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +23 -41
- package/dist/merged-exporter.js.map +1 -1
- package/dist/parquet-exporter.d.ts +1 -3
- package/dist/parquet-exporter.d.ts.map +1 -1
- package/dist/parquet-exporter.js +1 -0
- package/dist/parquet-exporter.js.map +1 -1
- package/dist/property-value-serialization.d.ts +54 -0
- package/dist/property-value-serialization.d.ts.map +1 -0
- package/dist/property-value-serialization.js +134 -0
- package/dist/property-value-serialization.js.map +1 -0
- package/dist/reference-collector.d.ts +20 -0
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +46 -113
- package/dist/reference-collector.js.map +1 -1
- package/dist/schema-converter.d.ts.map +1 -1
- package/dist/schema-converter.js +46 -96
- package/dist/schema-converter.js.map +1 -1
- package/dist/source-ref-bounds.d.ts +3 -3
- package/dist/source-ref-bounds.js +3 -3
- package/dist/step-attribute-mutations.d.ts +49 -0
- package/dist/step-attribute-mutations.d.ts.map +1 -0
- package/dist/step-attribute-mutations.js +172 -0
- package/dist/step-attribute-mutations.js.map +1 -0
- package/dist/step-attribute-serializers.d.ts +41 -0
- package/dist/step-attribute-serializers.d.ts.map +1 -0
- package/dist/step-attribute-serializers.js +74 -0
- package/dist/step-attribute-serializers.js.map +1 -0
- package/dist/step-collection.d.ts +55 -0
- package/dist/step-collection.d.ts.map +1 -0
- package/dist/step-collection.js +126 -0
- package/dist/step-collection.js.map +1 -0
- package/dist/step-export-contexts.d.ts +61 -0
- package/dist/step-export-contexts.d.ts.map +1 -0
- package/dist/step-export-contexts.js +50 -0
- package/dist/step-export-contexts.js.map +1 -0
- package/dist/step-export-types.d.ts +262 -0
- package/dist/step-export-types.d.ts.map +1 -0
- package/dist/step-export-types.js +22 -0
- package/dist/step-export-types.js.map +1 -0
- package/dist/step-exporter.d.ts +23 -354
- package/dist/step-exporter.d.ts.map +1 -1
- package/dist/step-exporter.js +76 -1260
- package/dist/step-exporter.js.map +1 -1
- package/dist/step-geometry-types.d.ts +3 -0
- package/dist/step-geometry-types.d.ts.map +1 -0
- package/dist/step-geometry-types.js +73 -0
- package/dist/step-geometry-types.js.map +1 -0
- package/dist/step-georeferencing.d.ts +0 -10
- package/dist/step-georeferencing.d.ts.map +1 -1
- package/dist/step-georeferencing.js +46 -94
- package/dist/step-georeferencing.js.map +1 -1
- package/dist/step-header.d.ts +53 -0
- package/dist/step-header.d.ts.map +1 -0
- package/dist/step-header.js +63 -0
- package/dist/step-header.js.map +1 -0
- package/dist/step-map-unit.d.ts +90 -0
- package/dist/step-map-unit.d.ts.map +1 -0
- package/dist/step-map-unit.js +277 -0
- package/dist/step-map-unit.js.map +1 -0
- package/dist/step-omission-predicates.d.ts +51 -0
- package/dist/step-omission-predicates.d.ts.map +1 -0
- package/dist/step-omission-predicates.js +268 -0
- package/dist/step-omission-predicates.js.map +1 -0
- package/dist/step-overlay-attribute-overrides.d.ts +32 -0
- package/dist/step-overlay-attribute-overrides.d.ts.map +1 -0
- package/dist/step-overlay-attribute-overrides.js +83 -0
- package/dist/step-overlay-attribute-overrides.js.map +1 -0
- package/dist/step-overlay-entities.d.ts +64 -0
- package/dist/step-overlay-entities.d.ts.map +1 -0
- package/dist/step-overlay-entities.js +119 -0
- package/dist/step-overlay-entities.js.map +1 -0
- package/dist/step-pass-builder.d.ts +45 -0
- package/dist/step-pass-builder.d.ts.map +1 -0
- package/dist/step-pass-builder.js +249 -0
- package/dist/step-pass-builder.js.map +1 -0
- package/dist/step-property-set-collection.d.ts +24 -0
- package/dist/step-property-set-collection.d.ts.map +1 -0
- package/dist/step-property-set-collection.js +286 -0
- package/dist/step-property-set-collection.js.map +1 -0
- package/dist/step-property-set-generators.d.ts +20 -0
- package/dist/step-property-set-generators.d.ts.map +1 -0
- package/dist/step-property-set-generators.js +98 -0
- package/dist/step-property-set-generators.js.map +1 -0
- package/dist/step-property-set-index.d.ts +25 -0
- package/dist/step-property-set-index.d.ts.map +1 -0
- package/dist/step-property-set-index.js +69 -0
- package/dist/step-property-set-index.js.map +1 -0
- package/dist/step-property-set-readers.d.ts +158 -0
- package/dist/step-property-set-readers.d.ts.map +1 -0
- package/dist/step-property-set-readers.js +251 -0
- package/dist/step-property-set-readers.js.map +1 -0
- package/dist/step-property-sets.d.ts +2 -184
- package/dist/step-property-sets.d.ts.map +1 -1
- package/dist/step-property-sets.js +22 -674
- package/dist/step-property-sets.js.map +1 -1
- package/dist/step-serialization.d.ts +33 -52
- package/dist/step-serialization.d.ts.map +1 -1
- package/dist/step-serialization.js +69 -131
- package/dist/step-serialization.js.map +1 -1
- package/dist/step-source-iteration.d.ts +97 -0
- package/dist/step-source-iteration.d.ts.map +1 -0
- package/dist/step-source-iteration.js +178 -0
- package/dist/step-source-iteration.js.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
export function evaluateOmissionPredicates(pass, options, applyMutations, excludeGeometry, mutationView) {
|
|
5
|
+
/**
|
|
6
|
+
* "Does this model hold a record whose bytes this export cannot read?" —
|
|
7
|
+
* the one disjunct of {@link mayNameOmittedRefs} that is not already a
|
|
8
|
+
* value in hand, so it is a function and called last, behind `||`.
|
|
9
|
+
*
|
|
10
|
+
* Scans the EFFECTIVE index, and that is a requirement rather than an
|
|
11
|
+
* implementation detail: it has to cover the id space
|
|
12
|
+
* `isOmittedFromOutput` answers over, and an unreadable record can live in
|
|
13
|
+
* `deferredEntityIndex` — the secondary index `getCompleteEntityIndex`
|
|
14
|
+
* exists to merge — and nowhere in `entityIndex.byId`. Scanning `byId`,
|
|
15
|
+
* the obvious cheaper source, was measured to leave the gate false and
|
|
16
|
+
* ship the dangling ref; `relationship-filter-gate.test.ts` pins the
|
|
17
|
+
* merged scan behaviourally so that shortcut cannot come back as an
|
|
18
|
+
* optimisation.
|
|
19
|
+
*
|
|
20
|
+
* Reads the ref ITERATION yields — what the source-iteration pass's own
|
|
21
|
+
* skip reads — rather than re-asking `effective.get(id)` per id as
|
|
22
|
+
* `willBeEmitted` does, which on the largest files would cost a binary
|
|
23
|
+
* search and an allocation per entity and defeat the point of the gate.
|
|
24
|
+
* Every index here keeps the two in step by construction:
|
|
25
|
+
* `CompactEntityIndex` serves `get`, `has` and iteration from one pair of
|
|
26
|
+
* `Uint32Array`s, a `Map` trivially agrees, the merged deferred view is
|
|
27
|
+
* `byId.get ?? deferred.get` over `yield* byId; yield* deferred`, and
|
|
28
|
+
* `OverlayIndex` filters both by one tombstone set. An index whose `has`
|
|
29
|
+
* accepted an id its iteration never yields would defeat this — and would
|
|
30
|
+
* equally defeat the source-iteration pass's skip, so that file is broken
|
|
31
|
+
* either way; nothing in the repo builds one.
|
|
32
|
+
*
|
|
33
|
+
* Not short-circuited on `overlayActive`: an overlay-created record carries
|
|
34
|
+
* `(OVERLAY_BYTE_OFFSET, 0)` and so counts as unreadable here, which would
|
|
35
|
+
* make this always answer true once an overlay exists. Harmless —
|
|
36
|
+
* `overlayActive` is an earlier disjunct, so this never runs then — and
|
|
37
|
+
* correct if it ever did.
|
|
38
|
+
*
|
|
39
|
+
* ## Why a standalone pass rather than a value off the index
|
|
40
|
+
*
|
|
41
|
+
* Measured: 12.0 ms of a 470 ms export at 714,485 entities (2.55%), one
|
|
42
|
+
* call, whole index walked because a well-formed model gives it nothing to
|
|
43
|
+
* short-circuit on. The cheaper shape was prototyped and is 13x faster —
|
|
44
|
+
* `min(byteLength)` and `max(byteOffset + byteLength)` over
|
|
45
|
+
* `CompactEntityIndex`'s own `Uint32Array`s answer "is every ref readable
|
|
46
|
+
* within `extent`" exactly and allocation-free in 0.74 ms — and was not
|
|
47
|
+
* taken, because 11 ms does not buy what it costs.
|
|
48
|
+
*
|
|
49
|
+
* It could only stand in FRONT of this loop, never replace it:
|
|
50
|
+
* `EntityByIdIndex` is a structural type and plain `Map`s satisfy it
|
|
51
|
+
* (`synthetic-data-store.ts` builds one), so the walk stays for those. That
|
|
52
|
+
* makes it a second implementation of one predicate across a package
|
|
53
|
+
* boundary — the defect class #2637, #2668 and this gate are all instances
|
|
54
|
+
* of. And storing it at construction is the invariant
|
|
55
|
+
* `source-ref-bounds.ts` exists to delete: `CompactEntityIndex` is built by
|
|
56
|
+
* its builder, by `compactEntityIndexFromColumns` in the transport, and by
|
|
57
|
+
* embedders, so a value one producer writes is a value the next can skip,
|
|
58
|
+
* whereas testing the ref where it is READ cannot be bypassed. If 2.5% ever
|
|
59
|
+
* has to go, the safe shape is a memoized derivation the index computes
|
|
60
|
+
* from its own arrays on demand — not a field set at build time.
|
|
61
|
+
*/
|
|
62
|
+
const hasAnyUnreadableSourceRef = () => {
|
|
63
|
+
for (const [, ref] of pass.effective) {
|
|
64
|
+
if (!pass.isReadableSourceRef(ref))
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
};
|
|
69
|
+
// If delta only, only export modified entities. Overlay-created entities
|
|
70
|
+
// also count — without this, `createEntity()`-only edits would silently
|
|
71
|
+
// drop out of delta exports.
|
|
72
|
+
const overlayNewEntityCount = (mutationView
|
|
73
|
+
&& applyMutations
|
|
74
|
+
&& typeof mutationView.getNewEntities === 'function') ? mutationView.getNewEntities().length : 0;
|
|
75
|
+
// Georef-only deltas (newGeorefLines populated but no entity changes) must
|
|
76
|
+
// still produce a non-empty DATA section.
|
|
77
|
+
if (
|
|
78
|
+
// `=== true`, matching `step-pass-builder.ts`'s two reads of the same
|
|
79
|
+
// option. A plain-JS caller passing `deltaOnly: 1` would otherwise have
|
|
80
|
+
// this module call the export a delta while the predicates there call it
|
|
81
|
+
// a full export -- the same divergence this file argues against for
|
|
82
|
+
// `visibleOnly` a few paragraphs down.
|
|
83
|
+
options.deltaOnly === true
|
|
84
|
+
&& pass.modifiedEntities.size === 0
|
|
85
|
+
&& overlayNewEntityCount === 0
|
|
86
|
+
&& pass.newGeorefLines.length === 0) {
|
|
87
|
+
const emptyContent = new TextEncoder().encode(pass.buildHeader(0) + 'DATA;\nENDSEC;\nEND-ISO-10303-21;\n');
|
|
88
|
+
return {
|
|
89
|
+
kind: 'short-circuit',
|
|
90
|
+
result: {
|
|
91
|
+
content: emptyContent,
|
|
92
|
+
stats: {
|
|
93
|
+
entityCount: 0,
|
|
94
|
+
newEntityCount: 0,
|
|
95
|
+
modifiedEntityCount: 0,
|
|
96
|
+
fileSize: emptyContent.byteLength,
|
|
97
|
+
warnings: pass.warnings,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* "May a line this export writes name `#id`?" — the single predicate both
|
|
104
|
+
* relationship-line filter sites consume, derived from `willBeEmitted`
|
|
105
|
+
* rather than from a second list kept in step with it by hand.
|
|
106
|
+
*
|
|
107
|
+
* DERIVED, not identical, and the gaps are named below rather than glossed:
|
|
108
|
+
* a scope qualifier for ids the file never had, and `deltaOnly`, where
|
|
109
|
+
* `willBeEmitted` answers `true` for a source record whose line this export
|
|
110
|
+
* does not write at all (the source-iteration pass is skipped wholesale in
|
|
111
|
+
* that mode). Nor does this make the CLOSURE WALK agree with either: the
|
|
112
|
+
* walk keeps `isRefExcludedDuringClosureWalk` and diverges from this
|
|
113
|
+
* predicate for an unreadable source ref — see the note on that predicate,
|
|
114
|
+
* and the "walk and output predicates diverge" test.
|
|
115
|
+
*
|
|
116
|
+
* The hand-kept second list is the bug this replaces. `willBeEmitted` recognises
|
|
117
|
+
* seven reasons a line never lands — outside the closure, hidden product,
|
|
118
|
+
* tombstoned, never existed, unreadable source ref (#2491), geometry
|
|
119
|
+
* excluded by options, and the `deltaOnly` carve-out — while the filter
|
|
120
|
+
* used to consume `(hiddenProductIds !== null && hiddenProductIds.has(id))
|
|
121
|
+
* || effective.isDeleted(id)`, which answered for two: hidden product, and
|
|
122
|
+
* tombstoned. Notably NOT "never existed" — that one is deliberately out of
|
|
123
|
+
* scope for the filter even now, for the reason under the qualifier heading
|
|
124
|
+
* below. The gap was live: on a PLAIN full export, with no `visibleOnly`,
|
|
125
|
+
* no deletions and no overlay, an unreadable ref made the source-iteration
|
|
126
|
+
* pass skip an entity's line while an `IFCREL*` naming it shipped verbatim,
|
|
127
|
+
* dangling.
|
|
128
|
+
*
|
|
129
|
+
* Deriving the filter from `willBeEmitted` is also what fixed the
|
|
130
|
+
* `mayNameExcludedRefs` gate that stands in front of both call sites. That
|
|
131
|
+
* gate used to be a SECOND, shorter enumeration of the same reasons
|
|
132
|
+
* (hidden products exist, or an overlay is active) and answered `false` for
|
|
133
|
+
* exactly the unreadable-ref export above, so the filter never ran at all.
|
|
134
|
+
* It is now {@link mayNameOmittedRefs} — see there for why a gate is kept
|
|
135
|
+
* at all (running the filter on every `IFCREL*` line costs +13% of a
|
|
136
|
+
* 714k-entity export) and for the enumeration it has to cover.
|
|
137
|
+
*
|
|
138
|
+
* ## The one qualifier on top of `willBeEmitted`
|
|
139
|
+
*
|
|
140
|
+
* `willBeEmitted` answers NO for an id neither the file nor the session
|
|
141
|
+
* ever had, which is right for its own job — nothing GENERATED may name an
|
|
142
|
+
* id that does not exist. It is the wrong answer for rewriting a SOURCE
|
|
143
|
+
* line, and the difference is whose bug it is. A `#999` already sitting in
|
|
144
|
+
* a relationship's `OwnerHistory` slot in the input file is a dangling ref
|
|
145
|
+
* this export did not create and cannot repair; `filterHiddenRefsFromRelationshipLine`
|
|
146
|
+
* withholds a whole relationship when an excluded id is in a bare scalar,
|
|
147
|
+
* so treating it as an exclusion would DELETE a visible element's pset over
|
|
148
|
+
* somebody else's corrupt file. That is the harm #2637 was about, and
|
|
149
|
+
* `step-exporter.test.ts` states the position out loud: a pre-existing
|
|
150
|
+
* dangling ref is out of scope and ships as it arrived.
|
|
151
|
+
*
|
|
152
|
+
* So the filter asks the narrower question: is `#id` an entity this model
|
|
153
|
+
* HAS, that this export is nonetheless not writing? `effective.has` is
|
|
154
|
+
* false for a tombstone, hence the explicit `isDeleted` arm — deleting an
|
|
155
|
+
* entity IS this session's doing and must be filtered.
|
|
156
|
+
*
|
|
157
|
+
* This is a scope qualifier, not a second enumeration of omission reasons:
|
|
158
|
+
* an eighth reason added to `willBeEmitted` still reaches the filter with
|
|
159
|
+
* no edit here.
|
|
160
|
+
*
|
|
161
|
+
* ## What the filter can and cannot reach
|
|
162
|
+
*
|
|
163
|
+
* Only `IFCREL*` lines. A `#N` named from a product's `Representation` or
|
|
164
|
+
* `ObjectPlacement` slot is not touched, so `includeGeometry:false` — a
|
|
165
|
+
* reason `willBeEmitted` does answer for — produces the same dangling refs
|
|
166
|
+
* with this predicate as without it. Measured on `tests/models/AB22.ifc`:
|
|
167
|
+
* 80 dangling refs before and after, output byte-identical but for the
|
|
168
|
+
* header timestamp.
|
|
169
|
+
*
|
|
170
|
+
* ## Withholding is not free
|
|
171
|
+
*
|
|
172
|
+
* When the omitted id sits in a single-valued slot, or is a set's only
|
|
173
|
+
* member, `filterHiddenRefsFromRelationshipLine` withholds the WHOLE
|
|
174
|
+
* relationship — so an entity that relationship also named loses the
|
|
175
|
+
* association, on a plain full export with no options set. That is why the
|
|
176
|
+
* call sites push {@link relationshipWithheldWarning}.
|
|
177
|
+
*
|
|
178
|
+
* See `unreadable-ref-dangling.test.ts` for the reproduction. #2637 is the
|
|
179
|
+
* prior instance of this class, which took seven rounds because the same
|
|
180
|
+
* decision was recomputed per call site.
|
|
181
|
+
*/
|
|
182
|
+
const isOmittedFromOutput = (id) => (pass.effective.has(id) || pass.effective.isDeleted(id)) && !pass.willBeEmitted(id);
|
|
183
|
+
/**
|
|
184
|
+
* "Can ANY id be omitted from this export at all?" — the precondition both
|
|
185
|
+
* `IFCREL*` filter sites are gated on, so the common export pays nothing.
|
|
186
|
+
*
|
|
187
|
+
* ## Why a gate exists
|
|
188
|
+
*
|
|
189
|
+
* Running `filterHiddenRefsFromRelationshipLine` on every `IFCREL*` line
|
|
190
|
+
* costs a re-parse of that line's attribute list, and a large model is
|
|
191
|
+
* mostly relationships. Measured on `tests/models/ara3d/schependomlaan.ifc`
|
|
192
|
+
* (714,485 entities, 21 interleaved reps in randomised order): 463 ms
|
|
193
|
+
* median with this gate false versus 523 ms filtering unconditionally,
|
|
194
|
+
* **+13%**. That is a real price paid on every export to protect a state
|
|
195
|
+
* most exports are not in. With the gate, the same export is 475 ms, +2.7%,
|
|
196
|
+
* all of it the fourth disjunct's one pass.
|
|
197
|
+
*
|
|
198
|
+
* ## Why THIS gate, and not the one that shipped before
|
|
199
|
+
*
|
|
200
|
+
* The gate this replaces was a second, hand-kept enumeration of "reasons an
|
|
201
|
+
* entity might be excluded", and it went stale exactly as such lists do: it
|
|
202
|
+
* named hidden products and the overlay and knew nothing about an unreadable
|
|
203
|
+
* source ref, so the bug this branch fixes reached the output with the
|
|
204
|
+
* filter switched off. A cheap gate is safe only as an OVER-APPROXIMATION of
|
|
205
|
+
* `isOmittedFromOutput` that can be checked against `willBeEmitted` branch
|
|
206
|
+
* by branch — so every branch is listed, with the disjunct that covers it:
|
|
207
|
+
*
|
|
208
|
+
* | `willBeEmitted` answers NO at | covered by |
|
|
209
|
+
* |----------------------------------------------|-------------------------------|
|
|
210
|
+
* | `allowedEntityIds !== null && !has(id)` | `allowedEntityIds !== null` |
|
|
211
|
+
* | `!ref`, because the overlay tombstoned `id` | `overlayActive` |
|
|
212
|
+
* | overlay-created, geometry excluded | `overlayActive` |
|
|
213
|
+
* | `!isReadableSourceRef(ref)` | `hasAnyUnreadableSourceRef()` |
|
|
214
|
+
* | source-backed, geometry excluded | `excludeGeometry` |
|
|
215
|
+
* | `!ref`, because `id` never existed | out of scope (below) |
|
|
216
|
+
* | `!ref` while `has(id)` is TRUE | nothing (below) |
|
|
217
|
+
*
|
|
218
|
+
* "Never existed" needs no disjunct: `isOmittedFromOutput`'s own
|
|
219
|
+
* `(has || isDeleted)` qualifier already drops it, deliberately — a
|
|
220
|
+
* pre-existing dangling ref in somebody else's file is not this export's to
|
|
221
|
+
* repair (see that predicate's note).
|
|
222
|
+
*
|
|
223
|
+
* The last row is a real hole and is stated rather than hidden: an index
|
|
224
|
+
* that answers `has(id)` for an id its iteration never yields makes
|
|
225
|
+
* `isOmittedFromOutput` true with no disjunct true. It needs an index whose
|
|
226
|
+
* `has`, `get` and iteration disagree, which nothing in the repo builds and
|
|
227
|
+
* which would already break the source-iteration pass's own skip — see
|
|
228
|
+
* {@link hasAnyUnreadableSourceRef}, which rests on the same agreement.
|
|
229
|
+
*
|
|
230
|
+
* Three of the four disjuncts are reads of values this export already
|
|
231
|
+
* computed. Only the fourth costs anything, and it short-circuits: `||`
|
|
232
|
+
* evaluates it solely when the other three are false, i.e. only for an
|
|
233
|
+
* export that has nothing else to filter for.
|
|
234
|
+
*
|
|
235
|
+
* ## The two spellings that are deliberately NOT the obvious ones
|
|
236
|
+
*
|
|
237
|
+
* `allowedEntityIds !== null`, not `options.visibleOnly === true`. Not the
|
|
238
|
+
* same test: the closure is built under `if (options.visibleOnly &&
|
|
239
|
+
* ctx.dataStore.source)` in `step-collection.ts` — quoted rather than cited
|
|
240
|
+
* by line, because the line moved by three in the very commit that added
|
|
241
|
+
* this reference — which is TRUTHY rather than `=== true`, and which
|
|
242
|
+
* is a SECOND read of the caller's object. A plain-JS caller of this
|
|
243
|
+
* published package passing `visibleOnly: 1` — or a `get visibleOnly()` that
|
|
244
|
+
* answers `true` once — built the closure while the gate read false and
|
|
245
|
+
* shipped a relationship naming an entity outside it. Executed, not
|
|
246
|
+
* reasoned: 192 of an 800-case sweep over `visibleOnly`/`hidden`/`isolated`
|
|
247
|
+
* combinations shipped a dangling ref against the `=== true` spelling, 0
|
|
248
|
+
* against this one. Reading the state the walk PRODUCED cannot disagree with
|
|
249
|
+
* the walk, whatever `options` says afterwards.
|
|
250
|
+
*
|
|
251
|
+
* It is also wider than the `hiddenProductIds.size > 0` the old gate used: a
|
|
252
|
+
* closure exists whenever `visibleOnly` was requested, even with nothing
|
|
253
|
+
* hidden, and can exclude an entity the roots simply never reach. No fixture
|
|
254
|
+
* has produced that case, so the widening is defensive — but a gate that is
|
|
255
|
+
* true too often costs speed on a rare path, while one that is false too
|
|
256
|
+
* rarely ships a corrupt file, and this one costs nothing.
|
|
257
|
+
*
|
|
258
|
+
* `overlayActive` and `excludeGeometry` are the SAME consts the effective
|
|
259
|
+
* index and `isGeometryExcluded` are built from — one read of `options` per
|
|
260
|
+
* question, shared — so those two cannot disagree with the predicate either.
|
|
261
|
+
*/
|
|
262
|
+
const mayNameOmittedRefs = pass.allowedEntityIds !== null
|
|
263
|
+
|| pass.overlayActive
|
|
264
|
+
|| excludeGeometry
|
|
265
|
+
|| hasAnyUnreadableSourceRef();
|
|
266
|
+
return { kind: 'continue', isOmittedFromOutput, mayNameOmittedRefs };
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=step-omission-predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-omission-predicates.js","sourceRoot":"","sources":["../src/step-omission-predicates.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAqD/D,MAAM,UAAU,0BAA0B,CACxC,IAAgB,EAChB,OAA0B,EAC1B,cAAuB,EACvB,eAAwB,EACxB,YAAwC;IAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwDG;IACH,MAAM,yBAAyB,GAAG,GAAY,EAAE;QAC9C,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;QAClD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,yEAAyE;IACzE,wEAAwE;IACxE,6BAA6B;IAC7B,MAAM,qBAAqB,GAAG,CAC5B,YAAY;WACT,cAAc;WACd,OAAO,YAAY,CAAC,cAAc,KAAK,UAAU,CACrD,CAAC,CAAC,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,2EAA2E;IAC3E,0CAA0C;IAC1C;IACE,sEAAsE;IACtE,wEAAwE;IACxE,yEAAyE;IACzE,oEAAoE;IACpE,uCAAuC;IACvC,OAAO,CAAC,SAAS,KAAK,IAAI;WACvB,IAAI,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC;WAChC,qBAAqB,KAAK,CAAC;WAC3B,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EACnC,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,qCAAqC,CAAC,CAAC;QAC3G,OAAO;YACL,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE;gBACN,OAAO,EAAE,YAAY;gBACrB,KAAK,EAAE;oBACL,WAAW,EAAE,CAAC;oBACd,cAAc,EAAE,CAAC;oBACjB,mBAAmB,EAAE,CAAC;oBACtB,QAAQ,EAAE,YAAY,CAAC,UAAU;oBACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB;aACF;SACF,CAAC;IACJ,CAAC;IAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+EG;IACH,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAW,EAAE,CAClD,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8EG;IACH,MAAM,kBAAkB,GACtB,IAAI,CAAC,gBAAgB,KAAK,IAAI;WAC3B,IAAI,CAAC,aAAa;WAClB,eAAe;WACf,yBAAyB,EAAE,CAAC;IACjC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply overlay attribute + positional overrides to an OVERLAY-CREATED
|
|
3
|
+
* entity's argument list (#2006) — the sibling of `step-attribute-
|
|
4
|
+
* mutations.ts`'s source-buffer pipeline that shares its two serialize
|
|
5
|
+
* helpers (`step-attribute-serializers.ts`). 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
|
+
* Apply overlay attribute + positional overrides to an OVERLAY-CREATED
|
|
12
|
+
* entity's argument list (#2006).
|
|
13
|
+
*
|
|
14
|
+
* Distinct from {@link applyAttributeMutations} / {@link applyPositionalMutations},
|
|
15
|
+
* which rewrite a line read out of the source buffer. Here the whole line is
|
|
16
|
+
* ours: it was serialized moments ago from the creation payload, so the
|
|
17
|
+
* argument list is the authoring payload's, not the file's. That difference
|
|
18
|
+
* is why this PADS — `entity_create` takes whatever positional list the
|
|
19
|
+
* caller passes, so a wall authored with three arguments still has a real
|
|
20
|
+
* `Tag` slot at index 7, and dropping the edit because the payload was short
|
|
21
|
+
* would be the very data loss this fixes. The source-buffer path must not
|
|
22
|
+
* pad: there a short line means a different schema, and growing a record we
|
|
23
|
+
* did not author would corrupt it.
|
|
24
|
+
*
|
|
25
|
+
* Named and positional overrides resolve to a slot index up front and share
|
|
26
|
+
* ONE padding rule. Two padding rules on one record is how the next bug
|
|
27
|
+
* starts, and the argument for padding — the class is fixed at creation time,
|
|
28
|
+
* so a short payload is partial authoring — never depended on which of the
|
|
29
|
+
* two APIs queued the edit.
|
|
30
|
+
*/
|
|
31
|
+
export declare function applyOverlayEntityOverrides(argsText: string, entityType: string, attributeOverrides: Map<string, string> | null, positionalOverrides: Map<number, IfcAttributeValue> | null, schemaVersion: IfcSchemaVersion, onRejected?: (attrName: string, value: string) => void): string;
|
|
32
|
+
//# sourceMappingURL=step-overlay-attribute-overrides.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-overlay-attribute-overrides.d.ts","sourceRoot":"","sources":["../src/step-overlay-attribute-overrides.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAK1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EAC9C,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,EAC1D,aAAa,EAAE,gBAAgB,EAC/B,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACrD,MAAM,CAoER"}
|
|
@@ -0,0 +1,83 @@
|
|
|
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 { getAttributeNamesAcrossSchemas } from '@ifc-lite/parser';
|
|
5
|
+
import { splitTopLevelArgs } from './step-argument-parser.js';
|
|
6
|
+
import { getRealTypedSlots } from './attribute-real-slots.js';
|
|
7
|
+
import { serializeNamedAttribute, serializePositionalOverride } from './step-attribute-serializers.js';
|
|
8
|
+
/**
|
|
9
|
+
* Apply overlay attribute + positional overrides to an OVERLAY-CREATED
|
|
10
|
+
* entity's argument list (#2006).
|
|
11
|
+
*
|
|
12
|
+
* Distinct from {@link applyAttributeMutations} / {@link applyPositionalMutations},
|
|
13
|
+
* which rewrite a line read out of the source buffer. Here the whole line is
|
|
14
|
+
* ours: it was serialized moments ago from the creation payload, so the
|
|
15
|
+
* argument list is the authoring payload's, not the file's. That difference
|
|
16
|
+
* is why this PADS — `entity_create` takes whatever positional list the
|
|
17
|
+
* caller passes, so a wall authored with three arguments still has a real
|
|
18
|
+
* `Tag` slot at index 7, and dropping the edit because the payload was short
|
|
19
|
+
* would be the very data loss this fixes. The source-buffer path must not
|
|
20
|
+
* pad: there a short line means a different schema, and growing a record we
|
|
21
|
+
* did not author would corrupt it.
|
|
22
|
+
*
|
|
23
|
+
* Named and positional overrides resolve to a slot index up front and share
|
|
24
|
+
* ONE padding rule. Two padding rules on one record is how the next bug
|
|
25
|
+
* starts, and the argument for padding — the class is fixed at creation time,
|
|
26
|
+
* so a short payload is partial authoring — never depended on which of the
|
|
27
|
+
* two APIs queued the edit.
|
|
28
|
+
*/
|
|
29
|
+
export function applyOverlayEntityOverrides(argsText, entityType, attributeOverrides, positionalOverrides, schemaVersion, onRejected) {
|
|
30
|
+
const args = argsText.length > 0 ? splitTopLevelArgs(argsText) : [];
|
|
31
|
+
const attrNames = getAttributeNamesAcrossSchemas(entityType);
|
|
32
|
+
const named = [];
|
|
33
|
+
for (const [attrName, value] of attributeOverrides ?? []) {
|
|
34
|
+
const index = attrNames.indexOf(attrName);
|
|
35
|
+
if (index >= 0)
|
|
36
|
+
named.push([index, value]);
|
|
37
|
+
}
|
|
38
|
+
// Grow to the class's FULL declared arity as soon as any override names a
|
|
39
|
+
// declared slot the creation payload never reached. Growing only as far as
|
|
40
|
+
// the edited slot would emit eight arguments for an IfcWall that declares
|
|
41
|
+
// nine: this parser tolerates the truncated record, a schema-validating
|
|
42
|
+
// consumer rejects the file.
|
|
43
|
+
//
|
|
44
|
+
// An index PAST the declared layout is not a slot at all, so it cannot
|
|
45
|
+
// justify growing the record and stays dropped — as does any override on a
|
|
46
|
+
// class neither schema source knows, where there is no arity to grow to.
|
|
47
|
+
let needsPad = named.some(([index]) => index >= args.length);
|
|
48
|
+
if (!needsPad && positionalOverrides) {
|
|
49
|
+
for (const [index] of positionalOverrides) {
|
|
50
|
+
if (index >= args.length && index < attrNames.length) {
|
|
51
|
+
needsPad = true;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (needsPad) {
|
|
57
|
+
while (args.length < attrNames.length)
|
|
58
|
+
args.push('$');
|
|
59
|
+
}
|
|
60
|
+
// Every `named` index is < attrNames.length by construction, and padding
|
|
61
|
+
// has taken args.length to at least that, so each one lands.
|
|
62
|
+
const realSlots = getRealTypedSlots(entityType, schemaVersion);
|
|
63
|
+
for (const [index, value] of named) {
|
|
64
|
+
const serialized = serializeNamedAttribute(entityType, index, value, args[index], realSlots);
|
|
65
|
+
// Overlay-created entities take the same rejection: a non-numeric REAL is
|
|
66
|
+
// invalid STEP whoever authored the record. The slot keeps the `$` this
|
|
67
|
+
// path padded it with, rather than gaining a quoted string.
|
|
68
|
+
if (serialized === null) {
|
|
69
|
+
onRejected?.(attrNames[index] ?? `#${index}`, value);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
args[index] = serialized;
|
|
73
|
+
}
|
|
74
|
+
if (positionalOverrides && positionalOverrides.size > 0) {
|
|
75
|
+
for (const [index, value] of positionalOverrides) {
|
|
76
|
+
if (index < 0 || index >= args.length)
|
|
77
|
+
continue;
|
|
78
|
+
args[index] = serializePositionalOverride(entityType, index, value, args[index], realSlots, schemaVersion);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return args.join(',');
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=step-overlay-attribute-overrides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-overlay-attribute-overrides.js","sourceRoot":"","sources":["../src/step-overlay-attribute-overrides.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAW/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAGvG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAgB,EAChB,UAAkB,EAClB,kBAA8C,EAC9C,mBAA0D,EAC1D,aAA+B,EAC/B,UAAsD;IAEtD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,MAAM,SAAS,GAAG,8BAA8B,CAAC,UAAU,CAAC,CAAC;IAE7D,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,kBAAkB,IAAI,EAAE,EAAE,CAAC;QACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,KAAK,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,0EAA0E;IAC1E,2EAA2E;IAC3E,0EAA0E;IAC1E,wEAAwE;IACxE,6BAA6B;IAC7B,EAAE;IACF,uEAAuE;IACvE,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,CAAC,QAAQ,IAAI,mBAAmB,EAAE,CAAC;QACrC,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,mBAAmB,EAAE,CAAC;YAC1C,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;gBACrD,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,yEAAyE;IACzE,6DAA6D;IAC7D,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAC/D,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QACnC,MAAM,UAAU,GAAG,uBAAuB,CACxC,UAAU,EACV,KAAK,EACL,KAAK,EACL,IAAI,CAAC,KAAK,CAAC,EACX,SAAS,CACV,CAAC;QACF,0EAA0E;QAC1E,wEAAwE;QACxE,4DAA4D;QAC5D,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,UAAU,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC;IAC3B,CAAC;IAED,IAAI,mBAAmB,IAAI,mBAAmB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACxD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,mBAAmB,EAAE,CAAC;YACjD,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;gBAAE,SAAS;YAChD,IAAI,CAAC,KAAK,CAAC,GAAG,2BAA2B,CACvC,UAAU,EACV,KAAK,EACL,KAAK,EACL,IAAI,CAAC,KAAK,CAAC,EACX,SAAS,EACT,aAAa,CACd,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay-created-entities phase of `StepExporter.export()` (#2475 step
|
|
3
|
+
* 2e): the pass that writes one line per entity the OVERLAY created
|
|
4
|
+
* (`store.addEntity` / `mutationView.createEntity`), as opposed to
|
|
5
|
+
* `step-source-iteration.ts`, which writes lines for records the SOURCE file
|
|
6
|
+
* already holds.
|
|
7
|
+
*
|
|
8
|
+
* It runs last among the four output passes — after georeferencing
|
|
9
|
+
* (`step-georeferencing.ts`), property/quantity-set generation
|
|
10
|
+
* (`step-property-sets.ts`) and source iteration — and reads what two of them
|
|
11
|
+
* wrote: `pass.modifiedAttributes` (attribute-collection phase, applied here
|
|
12
|
+
* as an overlay-created entity's post-create edits) and
|
|
13
|
+
* `pass.overlayTypeOwnedPsets` (`step-property-sets.ts`, a created TYPE
|
|
14
|
+
* object's generated pset ids, arriving as one more positional override).
|
|
15
|
+
* Nothing downstream of this phase reads anything it writes except the
|
|
16
|
+
* settle/assemble tail, so it moves cleanly.
|
|
17
|
+
*
|
|
18
|
+
* What is injected rather than read off the pass, and why: `isGeometryEntity`
|
|
19
|
+
* is shared with the setup closure and with `step-source-iteration.ts`.
|
|
20
|
+
* `relationshipWithheldWarning` is the same pure string formatter
|
|
21
|
+
* `step-source-iteration.ts` already injects, not duplicated here.
|
|
22
|
+
* `applyOverlayEntityOverrides` is injected as `OverlayEntitiesContext`'s
|
|
23
|
+
* field even though, since #2475's "remaining private helpers" step, it is
|
|
24
|
+
* an ordinary export of `step-overlay-attribute-overrides.ts` this file could
|
|
25
|
+
* import directly — kept as an injected field for symmetry with the other two and
|
|
26
|
+
* because `StepExporter.overlayEntitiesContext()` is still the one
|
|
27
|
+
* construction site for this context, exactly as before that step.
|
|
28
|
+
*
|
|
29
|
+
* `mutationView` is passed through as-is (not narrowed to an interface of the
|
|
30
|
+
* three optional methods this phase calls) because the original code guards
|
|
31
|
+
* every one of them with its own `typeof x === 'function'` check rather than
|
|
32
|
+
* assuming the shape — a real-store `MutablePropertyView` versus a bare mock
|
|
33
|
+
* used by some tests. Narrowing the type here would not remove those checks
|
|
34
|
+
* without also changing what a test double is allowed to omit.
|
|
35
|
+
*/
|
|
36
|
+
import type { IfcAttributeValue } from '@ifc-lite/parser';
|
|
37
|
+
import type { MutablePropertyView } from '@ifc-lite/mutations';
|
|
38
|
+
import type { ExportPass, StepExportOptions } from './step-exporter.js';
|
|
39
|
+
/**
|
|
40
|
+
* The exporter state this phase cannot read off the {@link ExportPass}.
|
|
41
|
+
*/
|
|
42
|
+
export interface OverlayEntitiesContext {
|
|
43
|
+
readonly mutationView: MutablePropertyView | null;
|
|
44
|
+
/** `step-overlay-attribute-overrides.ts`'s `applyOverlayEntityOverrides`: resolves
|
|
45
|
+
* named/positional overrides against the overlay-created entity's
|
|
46
|
+
* EFFECTIVE class. */
|
|
47
|
+
readonly applyOverlayEntityOverrides: (argsText: string, entityType: string, attributeOverrides: Map<string, string> | null, positionalOverrides: Map<number, IfcAttributeValue> | null, schemaVersion: ExportPass['sourceSchema'], onRejected?: (attrName: string, value: string) => void) => string;
|
|
48
|
+
/** `isGeometryEntity` (`step-geometry-types.ts`), also read by the setup closure and by
|
|
49
|
+
* `step-source-iteration.ts`. */
|
|
50
|
+
readonly isGeometryEntity: (type: string) => boolean;
|
|
51
|
+
/** The `relationshipWithheldWarning` message builder (`step-exporter.ts`):
|
|
52
|
+
* a pure string formatter with no pass dependency, injected here as it is
|
|
53
|
+
* into `step-source-iteration.ts`. */
|
|
54
|
+
readonly relationshipWithheldWarning: (expressId: number, type: string) => string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Add overlay-created entities (store.addEntity / mutationView.createEntity).
|
|
58
|
+
* Apply the same filters as the source-iteration pass so newly-created
|
|
59
|
+
* beams/slabs don't smuggle their geometry helpers (IfcCartesianPoint,
|
|
60
|
+
* IfcExtrudedAreaSolid, etc.) past `includeGeometry:false` /
|
|
61
|
+
* `exportPropertiesOnly()` modes.
|
|
62
|
+
*/
|
|
63
|
+
export declare function writeOverlayCreatedEntities(pass: ExportPass, options: StepExportOptions, excludeGeometry: boolean, applyMutations: boolean, mayNameOmittedRefs: boolean, isOmittedFromOutput: (id: number) => boolean, ctx: OverlayEntitiesContext): void;
|
|
64
|
+
//# sourceMappingURL=step-overlay-entities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-overlay-entities.d.ts","sourceRoot":"","sources":["../src/step-overlay-entities.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAM/D,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAClD;;2BAEuB;IACvB,QAAQ,CAAC,2BAA2B,EAAE,CACpC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EAC9C,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,EAC1D,aAAa,EAAE,UAAU,CAAC,cAAc,CAAC,EACzC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,KACnD,MAAM,CAAC;IACZ;sCACkC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD;;2CAEuC;IACvC,QAAQ,CAAC,2BAA2B,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnF;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,iBAAiB,EAC1B,eAAe,EAAE,OAAO,EACxB,cAAc,EAAE,OAAO,EACvB,kBAAkB,EAAE,OAAO,EAC3B,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,EAC5C,GAAG,EAAE,sBAAsB,GAC1B,IAAI,CA4HN"}
|
|
@@ -0,0 +1,119 @@
|
|
|
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 { filterHiddenRefsFromRelationshipLine } from './reference-collector.js';
|
|
5
|
+
import { convertStepLine } from './schema-converter.js';
|
|
6
|
+
import { retypeArgTokens } from './retype.js';
|
|
7
|
+
import { HAS_PROPERTY_SETS_SLOT } from './type-owned-psets.js';
|
|
8
|
+
import { serializeEntityArgs, serializeAttributeSlot } from './attribute-real-slots.js';
|
|
9
|
+
/**
|
|
10
|
+
* Add overlay-created entities (store.addEntity / mutationView.createEntity).
|
|
11
|
+
* Apply the same filters as the source-iteration pass so newly-created
|
|
12
|
+
* beams/slabs don't smuggle their geometry helpers (IfcCartesianPoint,
|
|
13
|
+
* IfcExtrudedAreaSolid, etc.) past `includeGeometry:false` /
|
|
14
|
+
* `exportPropertiesOnly()` modes.
|
|
15
|
+
*/
|
|
16
|
+
export function writeOverlayCreatedEntities(pass, options, excludeGeometry, applyMutations, mayNameOmittedRefs, isOmittedFromOutput, ctx) {
|
|
17
|
+
if (!ctx.mutationView
|
|
18
|
+
|| !applyMutations
|
|
19
|
+
|| typeof ctx.mutationView.getNewEntities !== 'function') {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const getTypeMut = typeof ctx.mutationView.getEntityTypeMutation === 'function'
|
|
23
|
+
? ctx.mutationView.getEntityTypeMutation.bind(ctx.mutationView)
|
|
24
|
+
: null;
|
|
25
|
+
for (const entity of ctx.mutationView.getNewEntities()) {
|
|
26
|
+
// A retyped overlay entity keeps its AUTHORED type on `entity.type`
|
|
27
|
+
// (the overlay typeMutation is the source of truth for the effective
|
|
28
|
+
// class). Resolve the effective class, then re-lay-out the authored
|
|
29
|
+
// attributes from the authored layout up to it.
|
|
30
|
+
const typeMut = getTypeMut ? getTypeMut(entity.expressId) : null;
|
|
31
|
+
const effectiveType = typeMut?.newType ?? entity.type;
|
|
32
|
+
// STEP requires UPPERCASE entity type tokens; the upper-case happens
|
|
33
|
+
// here at the file-format boundary.
|
|
34
|
+
const upperType = effectiveType.toUpperCase();
|
|
35
|
+
if (excludeGeometry && ctx.isGeometryEntity(upperType)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (pass.allowedEntityIds !== null && !pass.allowedEntityIds.has(entity.expressId)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Re-lay-out by name against the effective class (identity for
|
|
42
|
+
// compatible layouts). Runs whenever a retype intent exists — even a
|
|
43
|
+
// same-class retype, which carries a PredefinedType override
|
|
44
|
+
// (e.g. setEntityType(id, 'IfcColumn', 'PILASTER')).
|
|
45
|
+
let argsText;
|
|
46
|
+
if (typeMut) {
|
|
47
|
+
// Serialize against the AUTHORED layout (`entity.type`); retypeArgTokens
|
|
48
|
+
// then re-lays the tokens out by name up to the effective class.
|
|
49
|
+
const srcTokens = entity.attributes.map((value, i) => serializeAttributeSlot(entity.type, i, value, pass.sourceSchema));
|
|
50
|
+
const { tokens } = retypeArgTokens(srcTokens, entity.type, effectiveType, typeMut.predefinedType ?? null, pass.sourceSchema);
|
|
51
|
+
argsText = tokens.join(',');
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
argsText = serializeEntityArgs(entity.type, entity.attributes, pass.sourceSchema);
|
|
55
|
+
}
|
|
56
|
+
// Edits made AFTER the create live in the overlay, never in the
|
|
57
|
+
// authored payload (#2006). The source-iteration pass applies them to
|
|
58
|
+
// source records via applyAttributeMutations / applyPositionalMutations;
|
|
59
|
+
// an overlay-created entity has no source record, so without this it was
|
|
60
|
+
// written from its creation payload alone and every later
|
|
61
|
+
// `setAttribute` / `setPositionalAttribute` was silently dropped on
|
|
62
|
+
// save — data loss with no error and no warning.
|
|
63
|
+
//
|
|
64
|
+
// Order mirrors the source pass: retype (above) -> named attributes ->
|
|
65
|
+
// positional overrides, all resolved against the EFFECTIVE class.
|
|
66
|
+
const attributeOverrides = pass.modifiedAttributes.get(entity.expressId) ?? null;
|
|
67
|
+
const queuedPositional = typeof ctx.mutationView.getPositionalMutationsForEntity === 'function'
|
|
68
|
+
? ctx.mutationView.getPositionalMutationsForEntity(entity.expressId)
|
|
69
|
+
: null;
|
|
70
|
+
// A created TYPE object owns its psets through HasPropertySets, and the
|
|
71
|
+
// ids of the psets this export generated are only known now — so they
|
|
72
|
+
// arrive as one more slot override rather than through the overlay.
|
|
73
|
+
// `has`, not `??`, for the same reason `overlaySlotValue` gives: the
|
|
74
|
+
// stored value is deliberately null when the resolved list is empty.
|
|
75
|
+
const positionalOverrides = pass.overlayTypeOwnedPsets.has(entity.expressId)
|
|
76
|
+
? new Map(queuedPositional).set(HAS_PROPERTY_SETS_SLOT, pass.overlayTypeOwnedPsets.get(entity.expressId) ?? null)
|
|
77
|
+
: queuedPositional;
|
|
78
|
+
if ((attributeOverrides && attributeOverrides.size > 0)
|
|
79
|
+
|| (positionalOverrides && positionalOverrides.size > 0)) {
|
|
80
|
+
argsText = ctx.applyOverlayEntityOverrides(argsText, upperType, attributeOverrides, positionalOverrides, pass.sourceSchema,
|
|
81
|
+
// Overlay-created entities report a rejected REAL edit exactly as
|
|
82
|
+
// source-backed ones do. Without this the slot was kept and NOTHING
|
|
83
|
+
// was said - the silent discard this whole change exists to
|
|
84
|
+
// prevent, surviving in the one path that had no test.
|
|
85
|
+
(attr, value) => pass.warnings.push(`entity #${entity.expressId}: attribute ${attr} not written - ` +
|
|
86
|
+
`${JSON.stringify(value)} is not a number and the slot is REAL-typed`));
|
|
87
|
+
}
|
|
88
|
+
let line = `#${entity.expressId}=${upperType}(${argsText});`;
|
|
89
|
+
// Same gap as the source-iteration pass, for an overlay-authored
|
|
90
|
+
// relationship instead of a parsed one (#2398).
|
|
91
|
+
//
|
|
92
|
+
// `mayNameOmittedRefs` is provably TRUE wherever this line executes:
|
|
93
|
+
// the block enclosing this pass requires `ctx.mutationView` and
|
|
94
|
+
// `applyMutations`, which is `pass.overlayActive`, which is one of the
|
|
95
|
+
// gate's own disjuncts. Spelled out anyway so both filter sites read the
|
|
96
|
+
// same — the previous gate's failure was one site's condition drifting
|
|
97
|
+
// from what the filter needed, and a pass reachable without an overlay
|
|
98
|
+
// would otherwise silently need the gate re-derived here.
|
|
99
|
+
if (mayNameOmittedRefs && upperType.startsWith('IFCREL')) {
|
|
100
|
+
line = filterHiddenRefsFromRelationshipLine(line, isOmittedFromOutput);
|
|
101
|
+
if (line === null) {
|
|
102
|
+
pass.warnings.push(ctx.relationshipWithheldWarning(entity.expressId, upperType));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (pass.converting) {
|
|
107
|
+
const converted = convertStepLine(line, pass.sourceSchema, pass.schema, options.guidRandom);
|
|
108
|
+
if (converted !== null) {
|
|
109
|
+
pass.entities.push(converted);
|
|
110
|
+
pass.newEntityCount++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
pass.entities.push(line);
|
|
115
|
+
pass.newEntityCount++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=step-overlay-entities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-overlay-entities.js","sourceRoot":"","sources":["../src/step-overlay-entities.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAwC/D,OAAO,EAAE,oCAAoC,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AA4BxF;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAgB,EAChB,OAA0B,EAC1B,eAAwB,EACxB,cAAuB,EACvB,kBAA2B,EAC3B,mBAA4C,EAC5C,GAA2B;IAE3B,IACE,CAAC,GAAG,CAAC,YAAY;WACd,CAAC,cAAc;WACf,OAAO,GAAG,CAAC,YAAY,CAAC,cAAc,KAAK,UAAU,EACxD,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,GAAG,CAAC,YAAY,CAAC,qBAAqB,KAAK,UAAU;QAC7E,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;QAC/D,CAAC,CAAC,IAAI,CAAC;IACT,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,CAAC;QACvD,oEAAoE;QACpE,qEAAqE;QACrE,oEAAoE;QACpE,gDAAgD;QAChD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,MAAM,aAAa,GAAG,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC;QACtD,qEAAqE;QACrE,oCAAoC;QACpC,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;QAC9C,IAAI,eAAe,IAAI,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;YACvD,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACnF,SAAS;QACX,CAAC;QACD,+DAA+D;QAC/D,qEAAqE;QACrE,6DAA6D;QAC7D,qDAAqD;QACrD,IAAI,QAAgB,CAAC;QACrB,IAAI,OAAO,EAAE,CAAC;YACZ,yEAAyE;YACzE,iEAAiE;YACjE,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CACrC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAC/E,CAAC;YACF,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,CAChC,SAAS,EACT,MAAM,CAAC,IAAI,EACX,aAAa,EACb,OAAO,CAAC,cAAc,IAAI,IAAI,EAC9B,IAAI,CAAC,YAAY,CAClB,CAAC;YACF,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACpF,CAAC;QACD,gEAAgE;QAChE,sEAAsE;QACtE,yEAAyE;QACzE,yEAAyE;QACzE,0DAA0D;QAC1D,oEAAoE;QACpE,iDAAiD;QACjD,EAAE;QACF,uEAAuE;QACvE,kEAAkE;QAClE,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;QACjF,MAAM,gBAAgB,GAAG,OAAO,GAAG,CAAC,YAAY,CAAC,+BAA+B,KAAK,UAAU;YAC7F,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,+BAA+B,CAAC,MAAM,CAAC,SAAS,CAAC;YACpE,CAAC,CAAC,IAAI,CAAC;QACT,wEAAwE;QACxE,sEAAsE;QACtE,oEAAoE;QACpE,qEAAqE;QACrE,qEAAqE;QACrE,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;YAC1E,CAAC,CAAC,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAC3B,sBAAsB,EACtB,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CACzD;YACH,CAAC,CAAC,gBAAgB,CAAC;QACrB,IACE,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,IAAI,GAAG,CAAC,CAAC;eAChD,CAAC,mBAAmB,IAAI,mBAAmB,CAAC,IAAI,GAAG,CAAC,CAAC,EACxD,CAAC;YACD,QAAQ,GAAG,GAAG,CAAC,2BAA2B,CACxC,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,IAAI,CAAC,YAAY;YACjB,kEAAkE;YAClE,oEAAoE;YACpE,4DAA4D;YAC5D,uDAAuD;YACvD,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACd,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChB,WAAW,MAAM,CAAC,SAAS,eAAe,IAAI,iBAAiB;gBAC7D,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,6CAA6C,CACxE,CACJ,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,GAAkB,IAAI,MAAM,CAAC,SAAS,IAAI,SAAS,IAAI,QAAQ,IAAI,CAAC;QAC5E,iEAAiE;QACjE,gDAAgD;QAChD,EAAE;QACF,qEAAqE;QACrE,gEAAgE;QAChE,uEAAuE;QACvE,yEAAyE;QACzE,uEAAuE;QACvE,uEAAuE;QACvE,0DAA0D;QAC1D,IAAI,kBAAkB,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,IAAI,GAAG,oCAAoC,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;YACvE,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;gBACjF,SAAS;YACX,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5F,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;AACH,CAAC"}
|