@ifc-lite/export 3.0.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/dist/anonymize-export.d.ts +60 -0
- package/dist/anonymize-export.d.ts.map +1 -0
- package/dist/anonymize-export.js +217 -0
- package/dist/anonymize-export.js.map +1 -0
- package/dist/anonymize-placement.d.ts +71 -0
- package/dist/anonymize-placement.d.ts.map +1 -0
- package/dist/anonymize-placement.js +266 -0
- package/dist/anonymize-placement.js.map +1 -0
- package/dist/anonymize-scrub.d.ts +64 -0
- package/dist/anonymize-scrub.d.ts.map +1 -0
- package/dist/anonymize-scrub.js +315 -0
- package/dist/anonymize-scrub.js.map +1 -0
- package/dist/anonymize-types.d.ts +235 -0
- package/dist/anonymize-types.d.ts.map +1 -0
- package/dist/anonymize-types.js +5 -0
- package/dist/anonymize-types.js.map +1 -0
- package/dist/declared-property-type.d.ts +15 -0
- package/dist/declared-property-type.d.ts.map +1 -1
- package/dist/declared-property-type.js +43 -0
- package/dist/declared-property-type.js.map +1 -1
- package/dist/entity-type-sets.d.ts +47 -0
- package/dist/entity-type-sets.d.ts.map +1 -0
- package/dist/entity-type-sets.js +91 -0
- package/dist/entity-type-sets.js.map +1 -0
- package/dist/georef-closure.d.ts +55 -0
- package/dist/georef-closure.d.ts.map +1 -0
- package/dist/georef-closure.js +95 -0
- package/dist/georef-closure.js.map +1 -0
- package/dist/glb.d.ts.map +1 -1
- package/dist/glb.js +26 -2
- package/dist/glb.js.map +1 -1
- package/dist/ifc5-classification.d.ts +36 -0
- package/dist/ifc5-classification.d.ts.map +1 -0
- package/dist/ifc5-classification.js +46 -0
- package/dist/ifc5-classification.js.map +1 -0
- package/dist/ifc5-export-helpers.d.ts +32 -0
- package/dist/ifc5-export-helpers.d.ts.map +1 -0
- package/dist/ifc5-export-helpers.js +84 -0
- package/dist/ifc5-export-helpers.js.map +1 -0
- package/dist/ifc5-exporter.d.ts.map +1 -1
- package/dist/ifc5-exporter.js +14 -86
- package/dist/ifc5-exporter.js.map +1 -1
- package/dist/ifc5-material.d.ts +38 -0
- package/dist/ifc5-material.d.ts.map +1 -0
- package/dist/ifc5-material.js +32 -0
- package/dist/ifc5-material.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/merged-context.d.ts +100 -0
- package/dist/merged-context.d.ts.map +1 -0
- package/dist/merged-context.js +211 -0
- package/dist/merged-context.js.map +1 -0
- package/dist/merged-empty-containers.d.ts +63 -0
- package/dist/merged-empty-containers.d.ts.map +1 -0
- package/dist/merged-empty-containers.js +354 -0
- package/dist/merged-empty-containers.js.map +1 -0
- package/dist/merged-exporter.d.ts +28 -67
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +134 -258
- package/dist/merged-exporter.js.map +1 -1
- package/dist/merged-guid.d.ts +48 -0
- package/dist/merged-guid.d.ts.map +1 -0
- package/dist/merged-guid.js +128 -0
- package/dist/merged-guid.js.map +1 -0
- package/dist/merged-rel-aggregates.d.ts +63 -0
- package/dist/merged-rel-aggregates.d.ts.map +1 -0
- package/dist/merged-rel-aggregates.js +122 -0
- package/dist/merged-rel-aggregates.js.map +1 -0
- package/dist/merged-remap.d.ts +18 -0
- package/dist/merged-remap.d.ts.map +1 -0
- package/dist/merged-remap.js +66 -0
- package/dist/merged-remap.js.map +1 -0
- package/dist/merged-subcontext.d.ts +41 -0
- package/dist/merged-subcontext.d.ts.map +1 -0
- package/dist/merged-subcontext.js +99 -0
- package/dist/merged-subcontext.js.map +1 -0
- package/dist/parquet-exporter-ondemand.d.ts +34 -0
- package/dist/parquet-exporter-ondemand.d.ts.map +1 -0
- package/dist/parquet-exporter-ondemand.js +89 -0
- package/dist/parquet-exporter-ondemand.js.map +1 -0
- package/dist/parquet-exporter.d.ts +1 -29
- package/dist/parquet-exporter.d.ts.map +1 -1
- package/dist/parquet-exporter.js +68 -90
- package/dist/parquet-exporter.js.map +1 -1
- package/dist/parquet-type-strings.d.ts +11 -0
- package/dist/parquet-type-strings.d.ts.map +1 -0
- package/dist/parquet-type-strings.js +40 -0
- package/dist/parquet-type-strings.js.map +1 -0
- package/dist/parquet-uint32-columns.d.ts +30 -0
- package/dist/parquet-uint32-columns.d.ts.map +1 -0
- package/dist/parquet-uint32-columns.js +38 -0
- package/dist/parquet-uint32-columns.js.map +1 -0
- package/dist/reference-collector.d.ts +47 -51
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +115 -171
- package/dist/reference-collector.js.map +1 -1
- package/dist/related-entities.d.ts +10 -0
- package/dist/related-entities.d.ts.map +1 -0
- package/dist/related-entities.js +274 -0
- package/dist/related-entities.js.map +1 -0
- package/dist/schema-converter-attr-remap.d.ts +53 -0
- package/dist/schema-converter-attr-remap.d.ts.map +1 -0
- package/dist/schema-converter-attr-remap.js +106 -0
- package/dist/schema-converter-attr-remap.js.map +1 -0
- package/dist/schema-converter.d.ts.map +1 -1
- package/dist/schema-converter.js +24 -1
- package/dist/schema-converter.js.map +1 -1
- package/dist/schema-untranslatable.d.ts +35 -0
- package/dist/schema-untranslatable.d.ts.map +1 -0
- package/dist/schema-untranslatable.js +60 -0
- package/dist/schema-untranslatable.js.map +1 -0
- package/dist/step-argument-parser.d.ts.map +1 -1
- package/dist/step-argument-parser.js +11 -1
- package/dist/step-argument-parser.js.map +1 -1
- package/dist/step-attribute-mutations.js +14 -11
- package/dist/step-attribute-mutations.js.map +1 -1
- package/dist/step-collection.d.ts.map +1 -1
- package/dist/step-collection.js +51 -8
- package/dist/step-collection.js.map +1 -1
- package/dist/step-export-types.d.ts +42 -0
- package/dist/step-export-types.d.ts.map +1 -1
- package/dist/step-export-types.js +10 -0
- package/dist/step-export-types.js.map +1 -1
- package/dist/step-exporter.d.ts.map +1 -1
- package/dist/step-exporter.js +9 -1
- package/dist/step-exporter.js.map +1 -1
- package/dist/step-header.d.ts +1 -1
- package/dist/step-header.d.ts.map +1 -1
- package/dist/step-header.js +2 -2
- package/dist/step-header.js.map +1 -1
- package/dist/step-map-unit.d.ts +2 -1
- package/dist/step-map-unit.d.ts.map +1 -1
- package/dist/step-map-unit.js.map +1 -1
- package/dist/step-serialization.d.ts +10 -30
- package/dist/step-serialization.d.ts.map +1 -1
- package/dist/step-serialization.js +10 -60
- package/dist/step-serialization.js.map +1 -1
- package/dist/step-source-iteration.d.ts.map +1 -1
- package/dist/step-source-iteration.js +21 -0
- package/dist/step-source-iteration.js.map +1 -1
- package/dist/style-closure.d.ts +91 -0
- package/dist/style-closure.d.ts.map +1 -0
- package/dist/style-closure.js +164 -0
- package/dist/style-closure.js.map +1 -0
- package/dist/subset-entity-reader.d.ts +104 -0
- package/dist/subset-entity-reader.d.ts.map +1 -0
- package/dist/subset-entity-reader.js +112 -0
- package/dist/subset-entity-reader.js.map +1 -0
- package/dist/subset-roots.d.ts +74 -0
- package/dist/subset-roots.d.ts.map +1 -0
- package/dist/subset-roots.js +168 -0
- package/dist/subset-roots.js.map +1 -0
- package/dist/type-owned-psets.d.ts +19 -0
- package/dist/type-owned-psets.d.ts.map +1 -1
- package/dist/type-owned-psets.js +31 -0
- package/dist/type-owned-psets.js.map +1 -1
- package/dist/unit-normalize.d.ts.map +1 -1
- package/dist/unit-normalize.js +10 -2
- package/dist/unit-normalize.js.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,315 @@
|
|
|
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, normalizeIfcTypeName } from '@ifc-lite/parser';
|
|
5
|
+
import { decodeStepStringLiteral, generateIfcGuid } from '@ifc-lite/encoding';
|
|
6
|
+
import { attrIndex, readEntityArgs, stepSourceSchema } from './subset-entity-reader.js';
|
|
7
|
+
import { IFC_ROOT_TYPES } from './subset-roots.js';
|
|
8
|
+
import { HAS_PROPERTY_SETS_SLOT, isTypeClass } from './type-owned-psets.js';
|
|
9
|
+
/** `Name`/`LongName`/`Description`/`Tag` — the `IfcRoot`-declared text
|
|
10
|
+
* fields a subset export pseudonymizes when the class declares them and
|
|
11
|
+
* the source value is actually set (not already `$`). Per the decision
|
|
12
|
+
* doc: "pseudonymize Name/LongName/Description/Tag on every exported
|
|
13
|
+
* IfcRoot as `<IfcType>-<n>`". */
|
|
14
|
+
const PSEUDONYM_ATTRIBUTES = ['Name', 'LongName', 'Description', 'Tag'];
|
|
15
|
+
/** Extra root-entity text fields covered by `pseudonymizeAllNames`:
|
|
16
|
+
* `IfcObject.ObjectType` (authoring tools put the family/type name there —
|
|
17
|
+
* "Basic Wall: <project> Exterior 300") and `IfcProject.Phase`. */
|
|
18
|
+
// `ElementType` must be HERE, not in NON_ROOT_NAME_ATTRIBUTES: `slotsFor`
|
|
19
|
+
// short-circuits on IFC_ROOT_TYPES, so that list is inert for IfcWallType (#3351).
|
|
20
|
+
const ROOT_ALL_NAMES_ATTRIBUTES = ['ObjectType', 'Phase', 'ElementType', 'ApplicableOccurrence'];
|
|
21
|
+
/** Non-`IfcRoot` text fields covered by `pseudonymizeAllNames`. Only a
|
|
22
|
+
* quoted-string token is ever rewritten, so an enum-valued `Name`
|
|
23
|
+
* (`IfcSIUnit.Name = .METRE.`) or a `$` passes through untouched. */
|
|
24
|
+
// `Category` is authored text in practice ("ACME Acoustic Batt") (#3351).
|
|
25
|
+
const NON_ROOT_NAME_ATTRIBUTES = ['Name', 'LongName', 'Description', 'ProfileName', 'LayerSetName', 'Category'];
|
|
26
|
+
/** Non-root classes whose `Name` is schema semantics rather than authored
|
|
27
|
+
* text, left alone by `pseudonymizeAllNames`: the authoring application
|
|
28
|
+
* (kept by decision — it is debugging signal), and property / quantity
|
|
29
|
+
* names (`FireRating`, `Width`), which are only exported at all under
|
|
30
|
+
* `keepPropertySets` and are what a property-debugging repro needs. */
|
|
31
|
+
function isNonRootNameExempt(typeUpper) {
|
|
32
|
+
return typeUpper === 'IFCAPPLICATION'
|
|
33
|
+
// Owner-history actors are `scrubOwnerHistory`'s job (their whole
|
|
34
|
+
// attribute list, not just Name), and must stay untouched when it is off.
|
|
35
|
+
|| typeUpper === 'IFCPERSON'
|
|
36
|
+
|| typeUpper === 'IFCORGANIZATION'
|
|
37
|
+
|| typeUpper === 'IFCPERSONANDORGANIZATION'
|
|
38
|
+
|| typeUpper.startsWith('IFCPROPERTY')
|
|
39
|
+
|| typeUpper.startsWith('IFCPHYSICAL')
|
|
40
|
+
|| typeUpper.startsWith('IFCQUANTITY');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Scrub `includedIds`' `IfcRoot` entities plus every owner-history entity in
|
|
44
|
+
* `index`, queuing every change on `view` (never writing into `store`).
|
|
45
|
+
*
|
|
46
|
+
* `index` must be the EFFECTIVE index (`getEffectiveEntityIndex`), not a
|
|
47
|
+
* bare source index — see that module's doc for why an overlay-created or
|
|
48
|
+
* retyped entity answers differently through it. `store` need only expose
|
|
49
|
+
* `source`: `readEntityArgs` reads SOURCE-backed records only, which is the
|
|
50
|
+
* entire domain of what this pass mutates (it creates no entities).
|
|
51
|
+
*/
|
|
52
|
+
export function applyScrub(store, index, includedIds, view, opts = {}) {
|
|
53
|
+
// Model's OWN schema (#3309 review finding): the sweeps below walk
|
|
54
|
+
// arbitrary types, and the bundled schemas don't always agree on order.
|
|
55
|
+
const schema = stepSourceSchema(store.schemaVersion);
|
|
56
|
+
const pseudonymizeNames = opts.pseudonymizeNames ?? true;
|
|
57
|
+
const pseudonymizeAllNames = opts.pseudonymizeAllNames ?? true;
|
|
58
|
+
const regenerateGlobalIds = opts.regenerateGlobalIds ?? true;
|
|
59
|
+
const scrubOwnerHistory = opts.scrubOwnerHistory ?? true;
|
|
60
|
+
const neutralizeCurrency = opts.neutralizeCurrency ?? true;
|
|
61
|
+
const keepPropertySets = opts.keepPropertySets ?? false;
|
|
62
|
+
const guidMap = new Map();
|
|
63
|
+
const warnings = [];
|
|
64
|
+
let scrubbedCount = 0;
|
|
65
|
+
// Ascending expressId order, per plan A5 ("per-type counter in ascending
|
|
66
|
+
// expressId order") — determinism depends on this sort, not on Set
|
|
67
|
+
// insertion order, which `includedIds` makes no promise about.
|
|
68
|
+
const rootIds = [...includedIds]
|
|
69
|
+
.filter((id) => IFC_ROOT_TYPES.has(index.typeOf(id) ?? ''))
|
|
70
|
+
.sort((a, b) => a - b);
|
|
71
|
+
const pseudonymCounters = new Map();
|
|
72
|
+
for (const id of rootIds) {
|
|
73
|
+
const type = index.typeOf(id);
|
|
74
|
+
if (type === undefined)
|
|
75
|
+
continue; // gone from the effective model (tombstoned); nothing to scrub
|
|
76
|
+
const record = readEntityArgs(store, index, id);
|
|
77
|
+
if (!record) {
|
|
78
|
+
warnings.push(`Entity #${id} (${normalizeIfcTypeName(type)}): its source record could not be read, `
|
|
79
|
+
+ 'so its name/GlobalId scrub was skipped and it is exported unmodified.');
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
let touched = false;
|
|
83
|
+
if (regenerateGlobalIds) {
|
|
84
|
+
const guidIdx = attrIndex(type, 'GlobalId', schema);
|
|
85
|
+
const oldGuid = guidIdx !== -1 ? decodeQuotedStepString(record.args[guidIdx]) : null;
|
|
86
|
+
if (oldGuid !== null) {
|
|
87
|
+
const newGuid = generateIfcGuid(opts.guidRandom);
|
|
88
|
+
// Positional: `setAttribute` re-resolves the slot by name at
|
|
89
|
+
// serialize time via `step-attribute-mutations.ts`'s own (still
|
|
90
|
+
// pinned-IFC4-first) lookup, undoing `guidIdx` above (#3309).
|
|
91
|
+
view.setPositionalAttribute(id, guidIdx, newGuid);
|
|
92
|
+
guidMap.set(oldGuid, newGuid);
|
|
93
|
+
touched = true;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
warnings.push(`Entity #${id} (${normalizeIfcTypeName(type)}): its GlobalId could not be read, `
|
|
97
|
+
+ 'so it was not regenerated.');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (pseudonymizeNames || pseudonymizeAllNames) {
|
|
101
|
+
const pseudonym = nextPseudonym(pseudonymCounters, type);
|
|
102
|
+
const attrs = [
|
|
103
|
+
...(pseudonymizeNames ? PSEUDONYM_ATTRIBUTES : []),
|
|
104
|
+
...(pseudonymizeAllNames ? ROOT_ALL_NAMES_ATTRIBUTES : []),
|
|
105
|
+
];
|
|
106
|
+
for (const attr of attrs) {
|
|
107
|
+
const idx = attrIndex(type, attr, schema);
|
|
108
|
+
if (idx === -1 || idx >= record.args.length || !isQuotedStepString(record.args[idx]))
|
|
109
|
+
continue;
|
|
110
|
+
view.setPositionalAttribute(id, idx, pseudonym); // positional — see the GlobalId write above
|
|
111
|
+
touched = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (!keepPropertySets && isTypeClass(type)) {
|
|
115
|
+
view.setPositionalAttribute(id, HAS_PROPERTY_SETS_SLOT, null);
|
|
116
|
+
touched = true;
|
|
117
|
+
}
|
|
118
|
+
if (touched)
|
|
119
|
+
scrubbedCount += 1;
|
|
120
|
+
}
|
|
121
|
+
if (pseudonymizeAllNames) {
|
|
122
|
+
scrubbedCount += pseudonymizeNonRootNames(store, index, view, pseudonymCounters);
|
|
123
|
+
}
|
|
124
|
+
if (scrubOwnerHistory || neutralizeCurrency) {
|
|
125
|
+
for (const [id, ref] of index) {
|
|
126
|
+
const type = index.typeOf(id) ?? ref.type.toUpperCase();
|
|
127
|
+
if (type === 'IFCMONETARYUNIT') {
|
|
128
|
+
if (neutralizeCurrency && neutralizeMonetaryUnit(store, index, view, id))
|
|
129
|
+
scrubbedCount += 1;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (!scrubOwnerHistory)
|
|
133
|
+
continue;
|
|
134
|
+
// Below (and IFCMONETARYUNIT above): FIXED literal types, each
|
|
135
|
+
// slot checked directly against all three `ENTITIES_*` tables — no
|
|
136
|
+
// `schema` argument needed (unlike the arbitrary-type sweeps above).
|
|
137
|
+
switch (type) {
|
|
138
|
+
case 'IFCPERSON':
|
|
139
|
+
scrubPerson(view, id);
|
|
140
|
+
scrubbedCount += 1;
|
|
141
|
+
break;
|
|
142
|
+
case 'IFCORGANIZATION':
|
|
143
|
+
scrubOrganization(view, id);
|
|
144
|
+
scrubbedCount += 1;
|
|
145
|
+
break;
|
|
146
|
+
case 'IFCPERSONANDORGANIZATION': {
|
|
147
|
+
const rolesIdx = attrIndex('IFCPERSONANDORGANIZATION', 'Roles');
|
|
148
|
+
if (rolesIdx !== -1)
|
|
149
|
+
view.setPositionalAttribute(id, rolesIdx, null);
|
|
150
|
+
scrubbedCount += 1;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'IFCOWNERHISTORY': {
|
|
154
|
+
// Dates pin the model to a project timeline: creation -> epoch 0
|
|
155
|
+
// (the attribute is mandatory, an IfcTimeStamp INTEGER), last
|
|
156
|
+
// modification -> $ (optional).
|
|
157
|
+
const createdIdx = attrIndex('IFCOWNERHISTORY', 'CreationDate');
|
|
158
|
+
const modifiedIdx = attrIndex('IFCOWNERHISTORY', 'LastModifiedDate');
|
|
159
|
+
if (createdIdx !== -1)
|
|
160
|
+
view.setPositionalAttribute(id, createdIdx, 0);
|
|
161
|
+
if (modifiedIdx !== -1)
|
|
162
|
+
view.setPositionalAttribute(id, modifiedIdx, null);
|
|
163
|
+
scrubbedCount += 1;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'IFCAPPLICATION': {
|
|
167
|
+
// Keep ApplicationFullName/ApplicationIdentifier (the tool), drop
|
|
168
|
+
// Version (a vendor build string can carry the licence region).
|
|
169
|
+
const versionIdx = attrIndex('IFCAPPLICATION', 'Version');
|
|
170
|
+
if (versionIdx !== -1)
|
|
171
|
+
view.setPositionalAttribute(id, versionIdx, null);
|
|
172
|
+
scrubbedCount += 1;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
default:
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { guidMap, scrubbedCount, warnings };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* `IfcMonetaryUnit.Currency` -> US dollars, in the source file's own spelling:
|
|
184
|
+
* IFC2X3 declares it as the `IfcCurrencyEnum` (`.NOK.`), IFC4+ as an
|
|
185
|
+
* `IfcLabel` (`'NOK'`). Returns whether a mutation was queued.
|
|
186
|
+
*/
|
|
187
|
+
function neutralizeMonetaryUnit(store, index, view, id) {
|
|
188
|
+
const idx = attrIndex('IFCMONETARYUNIT', 'Currency');
|
|
189
|
+
if (idx === -1)
|
|
190
|
+
return false;
|
|
191
|
+
const record = readEntityArgs(store, index, id);
|
|
192
|
+
const token = record?.args[idx];
|
|
193
|
+
if (token === undefined || token === '$')
|
|
194
|
+
return false;
|
|
195
|
+
const usd = token.startsWith('.') ? '.USD.' : 'USD';
|
|
196
|
+
if (token === '.USD.' || token === "'USD'")
|
|
197
|
+
return false;
|
|
198
|
+
view.setPositionalAttribute(id, idx, usd);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
/** Next `<IfcType>-<n>` for `typeUpper`, advancing its per-type counter. */
|
|
202
|
+
function nextPseudonym(counters, typeUpper) {
|
|
203
|
+
const typeName = normalizeIfcTypeName(typeUpper);
|
|
204
|
+
const n = (counters.get(typeName) ?? 0) + 1;
|
|
205
|
+
counters.set(typeName, n);
|
|
206
|
+
return `${typeName}-${n}`;
|
|
207
|
+
}
|
|
208
|
+
function isQuotedStepString(token) {
|
|
209
|
+
return token !== undefined && token.length >= 2 && token[0] === "'" && token[token.length - 1] === "'";
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* `pseudonymizeAllNames` for the non-`IfcRoot` half: walk EVERY entity in
|
|
213
|
+
* `index` (not just `includedIds` — styles, materials, layers and profiles
|
|
214
|
+
* reach the export through the forward closure, which only exists after the
|
|
215
|
+
* exporter runs) and pseudonymize each quoted-string
|
|
216
|
+
* `NON_ROOT_NAME_ATTRIBUTES` slot. A mutation queued on an entity the
|
|
217
|
+
* closure never reaches is simply never serialized, so over-approximating
|
|
218
|
+
* here costs nothing but time, and the per-type slot lookup is cached so the
|
|
219
|
+
* walk touches source bytes only for classes that declare such a slot.
|
|
220
|
+
* Returns how many entities received at least one mutation.
|
|
221
|
+
*/
|
|
222
|
+
function pseudonymizeNonRootNames(store, index, view, counters) {
|
|
223
|
+
// Same schema-aware resolution as `applyScrub`'s root pass: this walks
|
|
224
|
+
// every non-root type (materials, styles, layers, profiles, …), e.g.
|
|
225
|
+
// IFC2X3's `IfcApprovalRelationship.Name` sits at slot 3, IFC4's at 0.
|
|
226
|
+
const schema = stepSourceSchema(store.schemaVersion);
|
|
227
|
+
const slotsByType = new Map();
|
|
228
|
+
const slotsFor = (typeUpper) => {
|
|
229
|
+
let slots = slotsByType.get(typeUpper);
|
|
230
|
+
if (slots === undefined) {
|
|
231
|
+
slots = IFC_ROOT_TYPES.has(typeUpper) || isNonRootNameExempt(typeUpper)
|
|
232
|
+
? []
|
|
233
|
+
: NON_ROOT_NAME_ATTRIBUTES
|
|
234
|
+
.map((name) => [name, attrIndex(typeUpper, name, schema)])
|
|
235
|
+
.filter(([, idx]) => idx !== -1);
|
|
236
|
+
slotsByType.set(typeUpper, slots);
|
|
237
|
+
}
|
|
238
|
+
return slots;
|
|
239
|
+
};
|
|
240
|
+
// Ascending expressId for the same determinism guarantee as the root pass.
|
|
241
|
+
const ids = [];
|
|
242
|
+
for (const [id] of index)
|
|
243
|
+
ids.push(id);
|
|
244
|
+
ids.sort((a, b) => a - b);
|
|
245
|
+
let scrubbed = 0;
|
|
246
|
+
for (const id of ids) {
|
|
247
|
+
const type = index.typeOf(id);
|
|
248
|
+
if (type === undefined)
|
|
249
|
+
continue;
|
|
250
|
+
const slots = slotsFor(type);
|
|
251
|
+
if (slots.length === 0)
|
|
252
|
+
continue;
|
|
253
|
+
const record = readEntityArgs(store, index, id);
|
|
254
|
+
if (!record)
|
|
255
|
+
continue; // overlay-created (e.g. the placement clones) or unreadable: nothing authored to scrub
|
|
256
|
+
let pseudonym = null;
|
|
257
|
+
for (const [, idx] of slots) {
|
|
258
|
+
if (idx >= record.args.length || !isQuotedStepString(record.args[idx]))
|
|
259
|
+
continue;
|
|
260
|
+
pseudonym ??= nextPseudonym(counters, type);
|
|
261
|
+
view.setPositionalAttribute(id, idx, pseudonym); // positional — same reasoning as `applyScrub`'s writes
|
|
262
|
+
}
|
|
263
|
+
if (pseudonym !== null)
|
|
264
|
+
scrubbed += 1;
|
|
265
|
+
}
|
|
266
|
+
return scrubbed;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Decode a raw STEP string-literal token (`'…'`, quotes still attached, as
|
|
270
|
+
* `SubsetEntityArgs.args` holds it — see `subset-entity-reader.ts`) to its
|
|
271
|
+
* Unicode value, or `null` when the token is not a quoted string: `$`, a
|
|
272
|
+
* numeric/enum/reference token, or simply absent because the record's
|
|
273
|
+
* trailing optional arguments were omitted short.
|
|
274
|
+
*/
|
|
275
|
+
function decodeQuotedStepString(token) {
|
|
276
|
+
if (token === undefined || token.length < 2 || token[0] !== "'" || token[token.length - 1] !== "'") {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
return decodeStepStringLiteral(token.slice(1, -1));
|
|
280
|
+
}
|
|
281
|
+
/** `IfcPerson.FamilyName` -> `'Anonymous'`; every other declared attribute
|
|
282
|
+
* (`Identification`, `GivenName`, `MiddleNames`, `PrefixTitles`,
|
|
283
|
+
* `SuffixTitles`, `Roles`, `Addresses`) -> `$`. Per the decision doc the
|
|
284
|
+
* ENTIRE attribute list is identifying fields/Roles/Addresses, but a total
|
|
285
|
+
* wipe emits `IFCPERSON($,$,$,$,$,$,$,$)`, which violates the schema's
|
|
286
|
+
* `IdentifiablePersonName` WHERE rule (`Identification`, `FamilyName`, or
|
|
287
|
+
* `GivenName` must be set) — a validator or strict viewer can then reject
|
|
288
|
+
* the very file this export exists to hand to a maintainer. Keeping one
|
|
289
|
+
* fixed, non-identifying `FamilyName` satisfies the rule without leaking
|
|
290
|
+
* anything. Schema-driven (`getAttributeNamesAcrossSchemas`) rather than a
|
|
291
|
+
* hardcoded slot count, the same way every other positional write in this
|
|
292
|
+
* package resolves slots. */
|
|
293
|
+
function scrubPerson(view, id) {
|
|
294
|
+
const names = getAttributeNamesAcrossSchemas('IFCPERSON');
|
|
295
|
+
const familyNameIdx = names.indexOf('FamilyName');
|
|
296
|
+
for (let i = 0; i < names.length; i++) {
|
|
297
|
+
if (i === familyNameIdx)
|
|
298
|
+
continue;
|
|
299
|
+
view.setPositionalAttribute(id, i, null);
|
|
300
|
+
}
|
|
301
|
+
view.setAttribute(id, 'FamilyName', 'Anonymous');
|
|
302
|
+
}
|
|
303
|
+
/** `IfcOrganization.Name` -> `'Anonymous'`; every other declared attribute
|
|
304
|
+
* (`Identification`, `Description`, `Roles`, `Addresses`) -> `$`. */
|
|
305
|
+
function scrubOrganization(view, id) {
|
|
306
|
+
const names = getAttributeNamesAcrossSchemas('IFCORGANIZATION');
|
|
307
|
+
const nameIdx = names.indexOf('Name');
|
|
308
|
+
for (let i = 0; i < names.length; i++) {
|
|
309
|
+
if (i === nameIdx)
|
|
310
|
+
continue;
|
|
311
|
+
view.setPositionalAttribute(id, i, null);
|
|
312
|
+
}
|
|
313
|
+
view.setAttribute(id, 'Name', 'Anonymous');
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=anonymize-scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-scrub.js","sourceRoot":"","sources":["../src/anonymize-scrub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public vocabulary of the "anonymized isolated export" feature (#2934):
|
|
3
|
+
* what a caller passes to `collectRelatedEntities` / `exportAnonymizedSubset`
|
|
4
|
+
* and what it gets back. Declarations only, split out the same way
|
|
5
|
+
* `step-export-types.ts` is split from `step-exporter.ts` — so the two
|
|
6
|
+
* orchestrators (`related-entities.ts`, `anonymize-export.ts`) and every
|
|
7
|
+
* caller (viewer dialog, CLI) share one definition instead of drifting.
|
|
8
|
+
*
|
|
9
|
+
* Keyed by EXPRESS relationship name throughout (`IfcRelVoidsElement`, not
|
|
10
|
+
* `voids`), per this repo's IFC-schema-fidelity rule: these ARE the
|
|
11
|
+
* `IfcRel*` entity types the export walks, not a derived collection that
|
|
12
|
+
* would need its own name.
|
|
13
|
+
*/
|
|
14
|
+
import type { RandomSource } from '@ifc-lite/encoding';
|
|
15
|
+
/**
|
|
16
|
+
* Which relationship kinds `collectRelatedEntities` expands from the seed
|
|
17
|
+
* selection, and how far. Every boolean defaults to what the doc comment
|
|
18
|
+
* says, not to `false` — an omitted `RelatedEntityOptions` (or an omitted
|
|
19
|
+
* field within one) must reproduce the bug the seed exhibits, which usually
|
|
20
|
+
* needs its host/opening/type/material context, not a bare, disconnected
|
|
21
|
+
* element.
|
|
22
|
+
*/
|
|
23
|
+
export interface RelatedEntityOptions {
|
|
24
|
+
/** Openings of an included host element. Default `true`. */
|
|
25
|
+
IfcRelVoidsElement?: boolean;
|
|
26
|
+
/** The filler↔opening↔host chain (a window/door and the wall it sits in).
|
|
27
|
+
* Default `true`. */
|
|
28
|
+
IfcRelFillsElement?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Aggregate parents/children (`IfcRelAggregates`): `'up'` walks to
|
|
31
|
+
* `RelatingObject` only, `'down'` to `RelatedObjects` only, `'both'` walks
|
|
32
|
+
* both directions, `'none'` skips it. Default `'both'`.
|
|
33
|
+
*/
|
|
34
|
+
IfcRelAggregates?: 'up' | 'down' | 'both' | 'none';
|
|
35
|
+
/**
|
|
36
|
+
* Nesting parents/children (`IfcRelNests`) — a separate EXPRESS
|
|
37
|
+
* relationship from `IfcRelAggregates` even though the parser folds both
|
|
38
|
+
* into the same aggregation edge type on `RelationshipGraph`; this option
|
|
39
|
+
* is split out from the one above by REL ENTITY TYPE, not by graph edge,
|
|
40
|
+
* so a caller can toggle them independently. Default `'down'`.
|
|
41
|
+
*/
|
|
42
|
+
IfcRelNests?: 'up' | 'down' | 'both' | 'none';
|
|
43
|
+
/** An included object's `IfcTypeObject` (`IfcRelDefinesByType`). Default `true`. */
|
|
44
|
+
IfcRelDefinesByType?: boolean;
|
|
45
|
+
/** An included object's material assignment (`IfcRelAssociatesMaterial`).
|
|
46
|
+
* Default `true`. */
|
|
47
|
+
IfcRelAssociatesMaterial?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The spatial containment chain (`IfcRelContainedInSpatialStructure`) up to
|
|
50
|
+
* storey/building/site. Default `true`; regardless of this flag,
|
|
51
|
+
* `IfcProject` is ALWAYS included — a STEP file with no project is not a
|
|
52
|
+
* valid reproduction of anything.
|
|
53
|
+
*/
|
|
54
|
+
IfcRelContainedInSpatialStructure?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* An included object's property sets (`IfcRelDefinesByProperties`).
|
|
57
|
+
* Default `false` — psets are the majority of what this feature exists to
|
|
58
|
+
* strip, so expanding them is opt-in, and turning this on still pulls in
|
|
59
|
+
* `ePSet_MapConversion`/`ePSet_ProjectedCRS` style georeferencing psets
|
|
60
|
+
* unless those are separately excluded.
|
|
61
|
+
*/
|
|
62
|
+
IfcRelDefinesByProperties?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* BFS depth (both directions) to walk `IfcRelConnectsPathElements` from an
|
|
65
|
+
* included element — e.g. a wall's structurally-connected neighbour.
|
|
66
|
+
* Default `0` (no expansion).
|
|
67
|
+
*/
|
|
68
|
+
IfcRelConnectsPathElementsDepth?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One relationship kind/direction's contribution to a `collectRelatedEntities`
|
|
72
|
+
* result — e.g. "the openings reached via `IfcRelVoidsElement`, host role".
|
|
73
|
+
*/
|
|
74
|
+
export interface RelatedEntityGroup {
|
|
75
|
+
/** EXPRESS relationship type name, e.g. `IfcRelVoidsElement`. */
|
|
76
|
+
relationship: string;
|
|
77
|
+
/** Which end of the relationship this group walked — e.g. `'opening'` /
|
|
78
|
+
* `'host'` for `IfcRelVoidsElement`, matching the doc at each walker's own
|
|
79
|
+
* call site rather than a fixed enum, since the meaningful roles differ
|
|
80
|
+
* per relationship kind. */
|
|
81
|
+
role: string;
|
|
82
|
+
/** ExpressIds of the related OBJECTS this group reached (never the
|
|
83
|
+
* `IfcRel*` relationship entity itself). */
|
|
84
|
+
expressIds: number[];
|
|
85
|
+
/** ExpressIds of the `IfcRel*` relationship entities that produced this
|
|
86
|
+
* group — these must ALSO be included in the export subset, or the
|
|
87
|
+
* association they represent has nothing naming it. */
|
|
88
|
+
relationshipIds: number[];
|
|
89
|
+
}
|
|
90
|
+
/** The full result of one `collectRelatedEntities` call. */
|
|
91
|
+
export interface RelatedEntities {
|
|
92
|
+
/** The caller's original seed selection, echoed back unfiltered. */
|
|
93
|
+
seeds: number[];
|
|
94
|
+
/** One entry per (relationship, role) that contributed anything, in walk
|
|
95
|
+
* order — the shape a UI groups a related-entity list by. */
|
|
96
|
+
groups: RelatedEntityGroup[];
|
|
97
|
+
/** The union of every id reached: seeds, every group's `expressIds`, and
|
|
98
|
+
* every group's `relationshipIds`. This — not any one group — is what a
|
|
99
|
+
* caller passes as `StepExportOptions.subsetEntityIds`. */
|
|
100
|
+
all: Set<number>;
|
|
101
|
+
/** `true` when the walk's work budget was exhausted before it reached a
|
|
102
|
+
* fixpoint (`Bounding walks over file-supplied references`, AGENTS.md) —
|
|
103
|
+
* the result is a valid, boundable subset of what a complete walk would
|
|
104
|
+
* have found, not the complete answer. */
|
|
105
|
+
truncated: boolean;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* What to scrub, and how, when exporting the `subsetEntityIds` selection as
|
|
109
|
+
* an anonymized STEP file. Every field defaults to the value stated in its
|
|
110
|
+
* own doc comment (all `true`/enabled except where noted) — an anonymized
|
|
111
|
+
* export with no options at all is the maximally-scrubbed one, since the
|
|
112
|
+
* whole point of the feature is that a caller has to opt BACK IN to keep an
|
|
113
|
+
* identifying signal, never opt in to remove one.
|
|
114
|
+
*/
|
|
115
|
+
export interface AnonymizeOptions {
|
|
116
|
+
/** Replace `Name`/`LongName`/`Description`/`Tag` on every exported
|
|
117
|
+
* `IfcRoot` with a `<IfcType>-<n>` pseudonym. Default `true`. */
|
|
118
|
+
pseudonymizeNames?: boolean;
|
|
119
|
+
/** Also pseudonymize names OUTSIDE the `IfcRoot` text fields: `ObjectType`,
|
|
120
|
+
* `IfcTypeObject.ApplicableOccurrence`, `IfcElementType.ElementType` and
|
|
121
|
+
* `IfcProject.Phase` on roots, and every quoted-string `Name` /
|
|
122
|
+
* `Description` / `LongName` / `ProfileName` / `LayerSetName` / `Category`
|
|
123
|
+
* on non-`IfcRoot` entities — `Category` on ANY non-root class declaring it,
|
|
124
|
+
* `IfcMaterialProfile` and `IfcMaterialConstituent` included, not only
|
|
125
|
+
* `IfcMaterial` / `IfcMaterialLayer` —
|
|
126
|
+
* (`IfcSurfaceStyle`, `IfcMaterial*`, `IfcPresentationLayerAssignment`,
|
|
127
|
+
* `IfcProfileDef`, `IfcColourRgb`, …).
|
|
128
|
+
* A surface style called after the building it belongs to identifies the
|
|
129
|
+
* project as surely as `IfcProject.Name` does, and `ElementType` is the
|
|
130
|
+
* type-side twin of `ObjectType`, carrying the same authored text
|
|
131
|
+
* ("Basic Wall: <project> Exterior 300"). Enum-valued `Name`s
|
|
132
|
+
* (`IfcSIUnit.Name = .METRE.`) are never touched, nor are property /
|
|
133
|
+
* quantity names (schema semantics, only present under `keepPropertySets`)
|
|
134
|
+
* or `IfcApplication`. Default `true`; independent of `pseudonymizeNames`. */
|
|
135
|
+
pseudonymizeAllNames?: boolean;
|
|
136
|
+
/** Keep `IfcPropertySet`/`IfcElementQuantity` entities instead of dropping
|
|
137
|
+
* them. Default `false`: `exportAnonymizedSubset` excludes every such id
|
|
138
|
+
* from `includedIds` before export, however it got there (a caller's own
|
|
139
|
+
* `IfcRelDefinesByProperties` walk, or a hand-built id set) — the entity
|
|
140
|
+
* never reaches the output, values included, at any `includedIds` (#3351
|
|
141
|
+
* item 2). Property/quantity VALUES are unscrubbed by design, so setting
|
|
142
|
+
* this `true` keeps them exactly as authored; there is no partial,
|
|
143
|
+
* "kept but scrubbed" state. */
|
|
144
|
+
keepPropertySets?: boolean;
|
|
145
|
+
/** Regenerate every exported `IfcRoot`'s `GlobalId` (the old→new mapping
|
|
146
|
+
* comes back as `AnonymizeResult.guidMap`, never written into the file
|
|
147
|
+
* itself). Default `true`. */
|
|
148
|
+
regenerateGlobalIds?: boolean;
|
|
149
|
+
/** Zero the translation of each root `IfcLocalPlacement`
|
|
150
|
+
* (`PlacementRelTo = $`), preserving `Axis`/`RefDirection` and every child
|
|
151
|
+
* placement untouched. Default `true`. */
|
|
152
|
+
zeroRootPlacement?: boolean;
|
|
153
|
+
/** Remove `IfcMapConversion(Scaled)`/`IfcProjectedCRS` and blank
|
|
154
|
+
* `IfcSite`'s georeferencing/address attributes and
|
|
155
|
+
* `IfcBuilding.BuildingAddress`. Default `true`. */
|
|
156
|
+
removeGeoreferencing?: boolean;
|
|
157
|
+
/** Scrub the owner-history chain: blank `IfcPerson`/`IfcOrganization`
|
|
158
|
+
* identifying fields, zero `IfcOwnerHistory.CreationDate` and blank
|
|
159
|
+
* `LastModifiedDate`, blank `IfcApplication.Version` (a vendor build
|
|
160
|
+
* string such as `26.0.0 NOR FULL` encodes the licence region), and blank
|
|
161
|
+
* the STEP header's `originating_system`. `IfcApplication`'s name and
|
|
162
|
+
* identifier are kept — the authoring tool is debugging signal, its
|
|
163
|
+
* regional build is not. Default `true`. */
|
|
164
|
+
scrubOwnerHistory?: boolean;
|
|
165
|
+
/** Rewrite every `IfcMonetaryUnit.Currency` to US dollars (`.USD.` under
|
|
166
|
+
* IFC2X3's enum, `'USD'` under IFC4+'s label), so a cost-loaded model does
|
|
167
|
+
* not reveal its country. Default `true`. */
|
|
168
|
+
neutralizeCurrency?: boolean;
|
|
169
|
+
/** Seeded randomness for regenerated `GlobalId`s (and any other id this
|
|
170
|
+
* export synthesizes) — omitted means the platform CSPRNG, so two runs of
|
|
171
|
+
* an otherwise-identical anonymization differ in exactly those bytes.
|
|
172
|
+
* Pass the same source across repeat runs for byte-reproducible output. */
|
|
173
|
+
guidRandom?: RandomSource;
|
|
174
|
+
/** Pin the STEP header `FILE_NAME` timestamp (STEP format, e.g.
|
|
175
|
+
* `20240101T000000`). Omitted = the wall clock. */
|
|
176
|
+
timeStamp?: string;
|
|
177
|
+
/** Name recorded in the exported STEP header's `FILE_NAME` field — NOT
|
|
178
|
+
* necessarily the name the caller writes the file to disk under. Default
|
|
179
|
+
* `'anonymized.ifc'`, chosen because it is neutral: a caller that passes
|
|
180
|
+
* the real output path or project name here (e.g. `Acme-Tower.ifc`)
|
|
181
|
+
* defeats the anonymization by writing the identifying name straight back
|
|
182
|
+
* into the header of the file this option exists to scrub it from. */
|
|
183
|
+
filename?: string;
|
|
184
|
+
}
|
|
185
|
+
/** The result of one `exportAnonymizedSubset` call. */
|
|
186
|
+
export interface AnonymizeResult {
|
|
187
|
+
/** The anonymized STEP file content. */
|
|
188
|
+
content: Uint8Array;
|
|
189
|
+
/** Old `GlobalId` → new `GlobalId`, for every regenerated `IfcRoot`. Kept
|
|
190
|
+
* out of the exported file itself — it is exactly the mapping back to the
|
|
191
|
+
* original, identifying model, so it is the caller's responsibility to
|
|
192
|
+
* keep it separate (and typically NOT share it alongside the file). */
|
|
193
|
+
guidMap: Map<string, string>;
|
|
194
|
+
stats: {
|
|
195
|
+
/** Total entities in the exported file. */
|
|
196
|
+
entityCount: number;
|
|
197
|
+
/** How many `IfcRoot` entities from `includedIds` actually made it into
|
|
198
|
+
* the export (after subset-root exclusion and relationship pruning). */
|
|
199
|
+
includedRootEntityCount: number;
|
|
200
|
+
/** ExpressIds of `IfcRel*` entities dropped because their mandatory,
|
|
201
|
+
* single-valued reference named an entity the exclusion left out —
|
|
202
|
+
* `relationshipRefsSurviveExclusion` (`reference-collector.ts`) already
|
|
203
|
+
* decides this for the closure walk; this is that same decision,
|
|
204
|
+
* reported so a caller can see WHICH associations the anonymization
|
|
205
|
+
* cost, not just that some file that changed. */
|
|
206
|
+
prunedRelationshipIds: number[];
|
|
207
|
+
/** ExpressIds of `IfcPropertySet`/`IfcElementQuantity` entities excluded
|
|
208
|
+
* from `includedIds` because `keepPropertySets` was falsy (the
|
|
209
|
+
* default) — reported distinctly, the same way `prunedRelationshipIds`
|
|
210
|
+
* is, so a caller can tell "this id is missing because it is a
|
|
211
|
+
* property set" from any other exclusion reason without grepping
|
|
212
|
+
* `warnings` text. Empty when `keepPropertySets` was `true`. */
|
|
213
|
+
droppedPropertySetIds: number[];
|
|
214
|
+
/** ExpressIds of emitted `IfcPropertyReferenceValue` entities whose
|
|
215
|
+
* optional `PropertyReference` was nulled because it named an entity the
|
|
216
|
+
* subset excluded. */
|
|
217
|
+
droppedPropertyReferenceIds: number[];
|
|
218
|
+
/** Each root `IfcLocalPlacement` this export zeroed, and the translation
|
|
219
|
+
* it zeroed (the ORIGINAL, pre-zero coordinates) — reported because the
|
|
220
|
+
* translation was real coordinate data the caller may still want to log
|
|
221
|
+
* or compare against, even though it is deliberately not in the file. */
|
|
222
|
+
zeroedPlacements: {
|
|
223
|
+
expressId: number;
|
|
224
|
+
translation: number[];
|
|
225
|
+
}[];
|
|
226
|
+
/** Non-fatal notices: a placement chain this export could not safely
|
|
227
|
+
* zero (e.g. an `IfcGridPlacement`/`IfcLinearPlacement` root, left
|
|
228
|
+
* untouched), multiple root placements collapsing onto one origin, or
|
|
229
|
+
* anything else `AnonymizeOptions` asked for that this export could not
|
|
230
|
+
* fully deliver. Same `string[]` shape as
|
|
231
|
+
* `StepExportResult.stats.warnings`. */
|
|
232
|
+
warnings: string[];
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=anonymize-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-types.d.ts","sourceRoot":"","sources":["../src/anonymize-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-types.js","sourceRoot":"","sources":["../src/anonymize-types.ts"],"names":[],"mappings":"AAAA;;+DAE+D"}
|
|
@@ -35,6 +35,21 @@
|
|
|
35
35
|
* both from the same token — the source token is the more specific of the
|
|
36
36
|
* two and wins.
|
|
37
37
|
*
|
|
38
|
+
* **Unless the caller NAMED a member** ({@link NAMED_MEMBERS}, #3715). Gate 2
|
|
39
|
+
* as written could not express `IfcLabel` → `IfcText`: both are STRING, so
|
|
40
|
+
* "the two agree" and the source token won, silently discarding the request.
|
|
41
|
+
* The information it was missing is whether the caller CHOSE the type or
|
|
42
|
+
* merely echoed the shape the extractor derived — and that is already in the
|
|
43
|
+
* `PropertyValueType`, because the two are different members of it.
|
|
44
|
+
* `String` / `Real` are SHAPES, which is all the extractor can produce (it
|
|
45
|
+
* collapses `IFCLABEL`, `IFCTEXT` and `IFCIDENTIFIER` to `String` and keeps
|
|
46
|
+
* the token only in `dataType`); `Label` / `Identifier` / `Text` NAME one
|
|
47
|
+
* `IfcValue` member each and no extraction path produces them, so one of
|
|
48
|
+
* those can only have come from a caller who asked for it. A named member is
|
|
49
|
+
* therefore authoritative over the source token; a shape keeps gate 2's
|
|
50
|
+
* precedence, which is what stops a value-only edit — the UI passes `String`
|
|
51
|
+
* — from rewriting a neighbouring `IFCTEXT` as `IFCLABEL` all over again.
|
|
52
|
+
*
|
|
38
53
|
* 3. **The VALUE must be representable in that base.** `serializeTypedMarker`
|
|
39
54
|
* coerces, so without this an `IFCLENGTHMEASURE` carrying a non-numeric
|
|
40
55
|
* value would be written as `IFCLENGTHMEASURE(NaN)`, where the shape-derived
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declared-property-type.d.ts","sourceRoot":"","sources":["../src/declared-property-type.ts"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"declared-property-type.d.ts","sourceRoot":"","sources":["../src/declared-property-type.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6GG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AA0HnD;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,EAAE,SAAS,MAAM,EAAoC,CAAC;AAqBhG;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAqBf;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,CAIR"}
|