@ifc-lite/export 3.0.1 → 3.1.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 +34 -0
- package/dist/anonymize-export.d.ts +60 -0
- package/dist/anonymize-export.d.ts.map +1 -0
- package/dist/anonymize-export.js +117 -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 +312 -0
- package/dist/anonymize-scrub.js.map +1 -0
- package/dist/anonymize-types.d.ts +212 -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/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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/parquet-exporter.d.ts.map +1 -1
- package/dist/parquet-exporter.js +10 -10
- package/dist/parquet-exporter.js.map +1 -1
- package/dist/reference-collector.d.ts +47 -20
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +88 -89
- 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 +259 -0
- package/dist/related-entities.js.map +1 -0
- package/dist/step-collection.d.ts.map +1 -1
- package/dist/step-collection.js +36 -7
- package/dist/step-collection.js.map +1 -1
- package/dist/step-export-types.d.ts +27 -0
- package/dist/step-export-types.d.ts.map +1 -1
- package/dist/step-export-types.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/subset-entity-reader.d.ts +103 -0
- package/dist/subset-entity-reader.d.ts.map +1 -0
- package/dist/subset-entity-reader.js +102 -0
- package/dist/subset-entity-reader.js.map +1 -0
- package/dist/subset-roots.d.ts +58 -0
- package/dist/subset-roots.d.ts.map +1 -0
- package/dist/subset-roots.js +103 -0
- package/dist/subset-roots.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrub pass for the "anonymized isolated export" feature (#2934, plan A5):
|
|
3
|
+
* deterministic per-type pseudonyms for `Name`/`LongName`/`Description`/`Tag`
|
|
4
|
+
* on every included `IfcRoot`, `GlobalId` regeneration (the old->new map is
|
|
5
|
+
* handed back as `guidMap` rather than written into the file — see
|
|
6
|
+
* `AnonymizeResult.guidMap` on `anonymize-types.ts`), owner-history scrubbing
|
|
7
|
+
* (`IfcPerson`/`IfcOrganization`/`IfcPersonAndOrganization`), and clearing an
|
|
8
|
+
* included `IfcTypeObject`'s `HasPropertySets` slot.
|
|
9
|
+
*
|
|
10
|
+
* Expressed as mutations on a private `MutablePropertyView`, never as a text
|
|
11
|
+
* rewrite — see the plan's "Key mechanism choice": the effective-index
|
|
12
|
+
* closure walk (`effective-index.ts`) already reacts to a queued
|
|
13
|
+
* `setAttribute`/`setPositionalAttribute`, so these mutations are visible to
|
|
14
|
+
* `step-collection.ts`'s subset closure the same way any other overlay edit
|
|
15
|
+
* is, with no second code path that could disagree about what got scrubbed.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately does NOT use `store.entities.getTypeName` for the pseudonym
|
|
18
|
+
* label despite the plan sketch spelling it that way: that table only
|
|
19
|
+
* indexes product-ish entities and answers `'Unknown'` for the rest (see its
|
|
20
|
+
* own doc) — including `IfcPropertySet` (an `IfcRoot` descendant this module
|
|
21
|
+
* must be able to pseudonymize under `keepPropertySets`) and every
|
|
22
|
+
* `IfcRel*` relationship (also `IfcRoot` descendants, per `IFC_ROOT_TYPES`).
|
|
23
|
+
* `'Unknown-1'`, `'Unknown-2'`, … colliding across every such class would be
|
|
24
|
+
* both a worse pseudonym AND a residual identifying signal (two entities
|
|
25
|
+
* sharing a label leaks that they were originally the SAME kind of thing).
|
|
26
|
+
* `normalizeIfcTypeName` off the effective index's own class answer has no
|
|
27
|
+
* such gap.
|
|
28
|
+
*/
|
|
29
|
+
import type { IfcSourceBytes } from '@ifc-lite/parser';
|
|
30
|
+
import type { MutablePropertyView } from '@ifc-lite/mutations';
|
|
31
|
+
import type { EffectiveEntityIndex } from './effective-index.js';
|
|
32
|
+
import type { AnonymizeOptions } from './anonymize-types.js';
|
|
33
|
+
/** The subset of `AnonymizeOptions` this pass reads. */
|
|
34
|
+
export type ScrubOptions = Pick<AnonymizeOptions, 'pseudonymizeNames' | 'pseudonymizeAllNames' | 'regenerateGlobalIds' | 'scrubOwnerHistory' | 'neutralizeCurrency' | 'keepPropertySets' | 'guidRandom'>;
|
|
35
|
+
/** What one `applyScrub` call produced. */
|
|
36
|
+
export interface ScrubResult {
|
|
37
|
+
/** Original `GlobalId` -> regenerated `GlobalId`, one entry per
|
|
38
|
+
* `includedIds` `IfcRoot` entity whose GlobalId this pass actually
|
|
39
|
+
* regenerated. Empty when `regenerateGlobalIds` is `false`. */
|
|
40
|
+
guidMap: Map<string, string>;
|
|
41
|
+
/** How many entities this pass wrote at least one mutation for: every
|
|
42
|
+
* scrubbed `includedIds` root, plus every `IfcPerson`/`IfcOrganization`/
|
|
43
|
+
* `IfcPersonAndOrganization` found anywhere in `index` and scrubbed. */
|
|
44
|
+
scrubbedCount: number;
|
|
45
|
+
/** Non-fatal notices — an `includedIds` root this pass could not read (no
|
|
46
|
+
* source bytes, or a record that does not parse) or whose `GlobalId`
|
|
47
|
+
* could not be decoded, left untouched by the affected sub-step. */
|
|
48
|
+
warnings: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Scrub `includedIds`' `IfcRoot` entities plus every owner-history entity in
|
|
52
|
+
* `index`, queuing every change on `view` (never writing into `store`).
|
|
53
|
+
*
|
|
54
|
+
* `index` must be the EFFECTIVE index (`getEffectiveEntityIndex`), not a
|
|
55
|
+
* bare source index — see that module's doc for why an overlay-created or
|
|
56
|
+
* retyped entity answers differently through it. `store` need only expose
|
|
57
|
+
* `source`: `readEntityArgs` reads SOURCE-backed records only, which is the
|
|
58
|
+
* entire domain of what this pass mutates (it creates no entities).
|
|
59
|
+
*/
|
|
60
|
+
export declare function applyScrub(store: {
|
|
61
|
+
readonly source: IfcSourceBytes;
|
|
62
|
+
readonly schemaVersion?: string;
|
|
63
|
+
}, index: EffectiveEntityIndex, includedIds: ReadonlySet<number>, view: MutablePropertyView, opts?: ScrubOptions): ScrubResult;
|
|
64
|
+
//# sourceMappingURL=anonymize-scrub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-scrub.d.ts","sourceRoot":"","sources":["../src/anonymize-scrub.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAuC7D,wDAAwD;AACxD,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,gBAAgB,EACd,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,mBAAmB,GACnB,oBAAoB,GACpB,kBAAkB,GAClB,YAAY,CACf,CAAC;AAEF,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B;;oEAEgE;IAChE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;6EAEyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB;;yEAEqE;IACrE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,EAC3E,KAAK,EAAE,oBAAoB,EAC3B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,IAAI,EAAE,mBAAmB,EACzB,IAAI,GAAE,YAAiB,GACtB,WAAW,CAsIb"}
|
|
@@ -0,0 +1,312 @@
|
|
|
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
|
+
const ROOT_ALL_NAMES_ATTRIBUTES = ['ObjectType', 'Phase'];
|
|
19
|
+
/** Non-`IfcRoot` text fields covered by `pseudonymizeAllNames`. Only a
|
|
20
|
+
* quoted-string token is ever rewritten, so an enum-valued `Name`
|
|
21
|
+
* (`IfcSIUnit.Name = .METRE.`) or a `$` passes through untouched. */
|
|
22
|
+
const NON_ROOT_NAME_ATTRIBUTES = ['Name', 'LongName', 'Description', 'ProfileName', 'LayerSetName'];
|
|
23
|
+
/** Non-root classes whose `Name` is schema semantics rather than authored
|
|
24
|
+
* text, left alone by `pseudonymizeAllNames`: the authoring application
|
|
25
|
+
* (kept by decision — it is debugging signal), and property / quantity
|
|
26
|
+
* names (`FireRating`, `Width`), which are only exported at all under
|
|
27
|
+
* `keepPropertySets` and are what a property-debugging repro needs. */
|
|
28
|
+
function isNonRootNameExempt(typeUpper) {
|
|
29
|
+
return typeUpper === 'IFCAPPLICATION'
|
|
30
|
+
// Owner-history actors are `scrubOwnerHistory`'s job (their whole
|
|
31
|
+
// attribute list, not just Name), and must stay untouched when it is off.
|
|
32
|
+
|| typeUpper === 'IFCPERSON'
|
|
33
|
+
|| typeUpper === 'IFCORGANIZATION'
|
|
34
|
+
|| typeUpper === 'IFCPERSONANDORGANIZATION'
|
|
35
|
+
|| typeUpper.startsWith('IFCPROPERTY')
|
|
36
|
+
|| typeUpper.startsWith('IFCPHYSICAL')
|
|
37
|
+
|| typeUpper.startsWith('IFCQUANTITY');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Scrub `includedIds`' `IfcRoot` entities plus every owner-history entity in
|
|
41
|
+
* `index`, queuing every change on `view` (never writing into `store`).
|
|
42
|
+
*
|
|
43
|
+
* `index` must be the EFFECTIVE index (`getEffectiveEntityIndex`), not a
|
|
44
|
+
* bare source index — see that module's doc for why an overlay-created or
|
|
45
|
+
* retyped entity answers differently through it. `store` need only expose
|
|
46
|
+
* `source`: `readEntityArgs` reads SOURCE-backed records only, which is the
|
|
47
|
+
* entire domain of what this pass mutates (it creates no entities).
|
|
48
|
+
*/
|
|
49
|
+
export function applyScrub(store, index, includedIds, view, opts = {}) {
|
|
50
|
+
// Model's OWN schema (#3309 review finding): the sweeps below walk
|
|
51
|
+
// arbitrary types, and the bundled schemas don't always agree on order.
|
|
52
|
+
const schema = stepSourceSchema(store.schemaVersion);
|
|
53
|
+
const pseudonymizeNames = opts.pseudonymizeNames ?? true;
|
|
54
|
+
const pseudonymizeAllNames = opts.pseudonymizeAllNames ?? true;
|
|
55
|
+
const regenerateGlobalIds = opts.regenerateGlobalIds ?? true;
|
|
56
|
+
const scrubOwnerHistory = opts.scrubOwnerHistory ?? true;
|
|
57
|
+
const neutralizeCurrency = opts.neutralizeCurrency ?? true;
|
|
58
|
+
const keepPropertySets = opts.keepPropertySets ?? false;
|
|
59
|
+
const guidMap = new Map();
|
|
60
|
+
const warnings = [];
|
|
61
|
+
let scrubbedCount = 0;
|
|
62
|
+
// Ascending expressId order, per plan A5 ("per-type counter in ascending
|
|
63
|
+
// expressId order") — determinism depends on this sort, not on Set
|
|
64
|
+
// insertion order, which `includedIds` makes no promise about.
|
|
65
|
+
const rootIds = [...includedIds]
|
|
66
|
+
.filter((id) => IFC_ROOT_TYPES.has(index.typeOf(id) ?? ''))
|
|
67
|
+
.sort((a, b) => a - b);
|
|
68
|
+
const pseudonymCounters = new Map();
|
|
69
|
+
for (const id of rootIds) {
|
|
70
|
+
const type = index.typeOf(id);
|
|
71
|
+
if (type === undefined)
|
|
72
|
+
continue; // gone from the effective model (tombstoned); nothing to scrub
|
|
73
|
+
const record = readEntityArgs(store, index, id);
|
|
74
|
+
if (!record) {
|
|
75
|
+
warnings.push(`Entity #${id} (${normalizeIfcTypeName(type)}): its source record could not be read, `
|
|
76
|
+
+ 'so its name/GlobalId scrub was skipped and it is exported unmodified.');
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
let touched = false;
|
|
80
|
+
if (regenerateGlobalIds) {
|
|
81
|
+
const guidIdx = attrIndex(type, 'GlobalId', schema);
|
|
82
|
+
const oldGuid = guidIdx !== -1 ? decodeQuotedStepString(record.args[guidIdx]) : null;
|
|
83
|
+
if (oldGuid !== null) {
|
|
84
|
+
const newGuid = generateIfcGuid(opts.guidRandom);
|
|
85
|
+
// Positional: `setAttribute` re-resolves the slot by name at
|
|
86
|
+
// serialize time via `step-attribute-mutations.ts`'s own (still
|
|
87
|
+
// pinned-IFC4-first) lookup, undoing `guidIdx` above (#3309).
|
|
88
|
+
view.setPositionalAttribute(id, guidIdx, newGuid);
|
|
89
|
+
guidMap.set(oldGuid, newGuid);
|
|
90
|
+
touched = true;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
warnings.push(`Entity #${id} (${normalizeIfcTypeName(type)}): its GlobalId could not be read, `
|
|
94
|
+
+ 'so it was not regenerated.');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (pseudonymizeNames || pseudonymizeAllNames) {
|
|
98
|
+
const pseudonym = nextPseudonym(pseudonymCounters, type);
|
|
99
|
+
const attrs = [
|
|
100
|
+
...(pseudonymizeNames ? PSEUDONYM_ATTRIBUTES : []),
|
|
101
|
+
...(pseudonymizeAllNames ? ROOT_ALL_NAMES_ATTRIBUTES : []),
|
|
102
|
+
];
|
|
103
|
+
for (const attr of attrs) {
|
|
104
|
+
const idx = attrIndex(type, attr, schema);
|
|
105
|
+
if (idx === -1 || idx >= record.args.length || !isQuotedStepString(record.args[idx]))
|
|
106
|
+
continue;
|
|
107
|
+
view.setPositionalAttribute(id, idx, pseudonym); // positional — see the GlobalId write above
|
|
108
|
+
touched = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!keepPropertySets && isTypeClass(type)) {
|
|
112
|
+
view.setPositionalAttribute(id, HAS_PROPERTY_SETS_SLOT, null);
|
|
113
|
+
touched = true;
|
|
114
|
+
}
|
|
115
|
+
if (touched)
|
|
116
|
+
scrubbedCount += 1;
|
|
117
|
+
}
|
|
118
|
+
if (pseudonymizeAllNames) {
|
|
119
|
+
scrubbedCount += pseudonymizeNonRootNames(store, index, view, pseudonymCounters);
|
|
120
|
+
}
|
|
121
|
+
if (scrubOwnerHistory || neutralizeCurrency) {
|
|
122
|
+
for (const [id, ref] of index) {
|
|
123
|
+
const type = index.typeOf(id) ?? ref.type.toUpperCase();
|
|
124
|
+
if (type === 'IFCMONETARYUNIT') {
|
|
125
|
+
if (neutralizeCurrency && neutralizeMonetaryUnit(store, index, view, id))
|
|
126
|
+
scrubbedCount += 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (!scrubOwnerHistory)
|
|
130
|
+
continue;
|
|
131
|
+
// Below (and IFCMONETARYUNIT above): FIXED literal types, each
|
|
132
|
+
// slot checked directly against all three `ENTITIES_*` tables — no
|
|
133
|
+
// `schema` argument needed (unlike the arbitrary-type sweeps above).
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'IFCPERSON':
|
|
136
|
+
scrubPerson(view, id);
|
|
137
|
+
scrubbedCount += 1;
|
|
138
|
+
break;
|
|
139
|
+
case 'IFCORGANIZATION':
|
|
140
|
+
scrubOrganization(view, id);
|
|
141
|
+
scrubbedCount += 1;
|
|
142
|
+
break;
|
|
143
|
+
case 'IFCPERSONANDORGANIZATION': {
|
|
144
|
+
const rolesIdx = attrIndex('IFCPERSONANDORGANIZATION', 'Roles');
|
|
145
|
+
if (rolesIdx !== -1)
|
|
146
|
+
view.setPositionalAttribute(id, rolesIdx, null);
|
|
147
|
+
scrubbedCount += 1;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case 'IFCOWNERHISTORY': {
|
|
151
|
+
// Dates pin the model to a project timeline: creation -> epoch 0
|
|
152
|
+
// (the attribute is mandatory, an IfcTimeStamp INTEGER), last
|
|
153
|
+
// modification -> $ (optional).
|
|
154
|
+
const createdIdx = attrIndex('IFCOWNERHISTORY', 'CreationDate');
|
|
155
|
+
const modifiedIdx = attrIndex('IFCOWNERHISTORY', 'LastModifiedDate');
|
|
156
|
+
if (createdIdx !== -1)
|
|
157
|
+
view.setPositionalAttribute(id, createdIdx, 0);
|
|
158
|
+
if (modifiedIdx !== -1)
|
|
159
|
+
view.setPositionalAttribute(id, modifiedIdx, null);
|
|
160
|
+
scrubbedCount += 1;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'IFCAPPLICATION': {
|
|
164
|
+
// Keep ApplicationFullName/ApplicationIdentifier (the tool), drop
|
|
165
|
+
// Version (a vendor build string can carry the licence region).
|
|
166
|
+
const versionIdx = attrIndex('IFCAPPLICATION', 'Version');
|
|
167
|
+
if (versionIdx !== -1)
|
|
168
|
+
view.setPositionalAttribute(id, versionIdx, null);
|
|
169
|
+
scrubbedCount += 1;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
default:
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { guidMap, scrubbedCount, warnings };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* `IfcMonetaryUnit.Currency` -> US dollars, in the source file's own spelling:
|
|
181
|
+
* IFC2X3 declares it as the `IfcCurrencyEnum` (`.NOK.`), IFC4+ as an
|
|
182
|
+
* `IfcLabel` (`'NOK'`). Returns whether a mutation was queued.
|
|
183
|
+
*/
|
|
184
|
+
function neutralizeMonetaryUnit(store, index, view, id) {
|
|
185
|
+
const idx = attrIndex('IFCMONETARYUNIT', 'Currency');
|
|
186
|
+
if (idx === -1)
|
|
187
|
+
return false;
|
|
188
|
+
const record = readEntityArgs(store, index, id);
|
|
189
|
+
const token = record?.args[idx];
|
|
190
|
+
if (token === undefined || token === '$')
|
|
191
|
+
return false;
|
|
192
|
+
const usd = token.startsWith('.') ? '.USD.' : 'USD';
|
|
193
|
+
if (token === '.USD.' || token === "'USD'")
|
|
194
|
+
return false;
|
|
195
|
+
view.setPositionalAttribute(id, idx, usd);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
/** Next `<IfcType>-<n>` for `typeUpper`, advancing its per-type counter. */
|
|
199
|
+
function nextPseudonym(counters, typeUpper) {
|
|
200
|
+
const typeName = normalizeIfcTypeName(typeUpper);
|
|
201
|
+
const n = (counters.get(typeName) ?? 0) + 1;
|
|
202
|
+
counters.set(typeName, n);
|
|
203
|
+
return `${typeName}-${n}`;
|
|
204
|
+
}
|
|
205
|
+
function isQuotedStepString(token) {
|
|
206
|
+
return token !== undefined && token.length >= 2 && token[0] === "'" && token[token.length - 1] === "'";
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* `pseudonymizeAllNames` for the non-`IfcRoot` half: walk EVERY entity in
|
|
210
|
+
* `index` (not just `includedIds` — styles, materials, layers and profiles
|
|
211
|
+
* reach the export through the forward closure, which only exists after the
|
|
212
|
+
* exporter runs) and pseudonymize each quoted-string
|
|
213
|
+
* `NON_ROOT_NAME_ATTRIBUTES` slot. A mutation queued on an entity the
|
|
214
|
+
* closure never reaches is simply never serialized, so over-approximating
|
|
215
|
+
* here costs nothing but time, and the per-type slot lookup is cached so the
|
|
216
|
+
* walk touches source bytes only for classes that declare such a slot.
|
|
217
|
+
* Returns how many entities received at least one mutation.
|
|
218
|
+
*/
|
|
219
|
+
function pseudonymizeNonRootNames(store, index, view, counters) {
|
|
220
|
+
// Same schema-aware resolution as `applyScrub`'s root pass: this walks
|
|
221
|
+
// every non-root type (materials, styles, layers, profiles, …), e.g.
|
|
222
|
+
// IFC2X3's `IfcApprovalRelationship.Name` sits at slot 3, IFC4's at 0.
|
|
223
|
+
const schema = stepSourceSchema(store.schemaVersion);
|
|
224
|
+
const slotsByType = new Map();
|
|
225
|
+
const slotsFor = (typeUpper) => {
|
|
226
|
+
let slots = slotsByType.get(typeUpper);
|
|
227
|
+
if (slots === undefined) {
|
|
228
|
+
slots = IFC_ROOT_TYPES.has(typeUpper) || isNonRootNameExempt(typeUpper)
|
|
229
|
+
? []
|
|
230
|
+
: NON_ROOT_NAME_ATTRIBUTES
|
|
231
|
+
.map((name) => [name, attrIndex(typeUpper, name, schema)])
|
|
232
|
+
.filter(([, idx]) => idx !== -1);
|
|
233
|
+
slotsByType.set(typeUpper, slots);
|
|
234
|
+
}
|
|
235
|
+
return slots;
|
|
236
|
+
};
|
|
237
|
+
// Ascending expressId for the same determinism guarantee as the root pass.
|
|
238
|
+
const ids = [];
|
|
239
|
+
for (const [id] of index)
|
|
240
|
+
ids.push(id);
|
|
241
|
+
ids.sort((a, b) => a - b);
|
|
242
|
+
let scrubbed = 0;
|
|
243
|
+
for (const id of ids) {
|
|
244
|
+
const type = index.typeOf(id);
|
|
245
|
+
if (type === undefined)
|
|
246
|
+
continue;
|
|
247
|
+
const slots = slotsFor(type);
|
|
248
|
+
if (slots.length === 0)
|
|
249
|
+
continue;
|
|
250
|
+
const record = readEntityArgs(store, index, id);
|
|
251
|
+
if (!record)
|
|
252
|
+
continue; // overlay-created (e.g. the placement clones) or unreadable: nothing authored to scrub
|
|
253
|
+
let pseudonym = null;
|
|
254
|
+
for (const [, idx] of slots) {
|
|
255
|
+
if (idx >= record.args.length || !isQuotedStepString(record.args[idx]))
|
|
256
|
+
continue;
|
|
257
|
+
pseudonym ??= nextPseudonym(counters, type);
|
|
258
|
+
view.setPositionalAttribute(id, idx, pseudonym); // positional — same reasoning as `applyScrub`'s writes
|
|
259
|
+
}
|
|
260
|
+
if (pseudonym !== null)
|
|
261
|
+
scrubbed += 1;
|
|
262
|
+
}
|
|
263
|
+
return scrubbed;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Decode a raw STEP string-literal token (`'…'`, quotes still attached, as
|
|
267
|
+
* `SubsetEntityArgs.args` holds it — see `subset-entity-reader.ts`) to its
|
|
268
|
+
* Unicode value, or `null` when the token is not a quoted string: `$`, a
|
|
269
|
+
* numeric/enum/reference token, or simply absent because the record's
|
|
270
|
+
* trailing optional arguments were omitted short.
|
|
271
|
+
*/
|
|
272
|
+
function decodeQuotedStepString(token) {
|
|
273
|
+
if (token === undefined || token.length < 2 || token[0] !== "'" || token[token.length - 1] !== "'") {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
return decodeStepStringLiteral(token.slice(1, -1));
|
|
277
|
+
}
|
|
278
|
+
/** `IfcPerson.FamilyName` -> `'Anonymous'`; every other declared attribute
|
|
279
|
+
* (`Identification`, `GivenName`, `MiddleNames`, `PrefixTitles`,
|
|
280
|
+
* `SuffixTitles`, `Roles`, `Addresses`) -> `$`. Per the decision doc the
|
|
281
|
+
* ENTIRE attribute list is identifying fields/Roles/Addresses, but a total
|
|
282
|
+
* wipe emits `IFCPERSON($,$,$,$,$,$,$,$)`, which violates the schema's
|
|
283
|
+
* `IdentifiablePersonName` WHERE rule (`Identification`, `FamilyName`, or
|
|
284
|
+
* `GivenName` must be set) — a validator or strict viewer can then reject
|
|
285
|
+
* the very file this export exists to hand to a maintainer. Keeping one
|
|
286
|
+
* fixed, non-identifying `FamilyName` satisfies the rule without leaking
|
|
287
|
+
* anything. Schema-driven (`getAttributeNamesAcrossSchemas`) rather than a
|
|
288
|
+
* hardcoded slot count, the same way every other positional write in this
|
|
289
|
+
* package resolves slots. */
|
|
290
|
+
function scrubPerson(view, id) {
|
|
291
|
+
const names = getAttributeNamesAcrossSchemas('IFCPERSON');
|
|
292
|
+
const familyNameIdx = names.indexOf('FamilyName');
|
|
293
|
+
for (let i = 0; i < names.length; i++) {
|
|
294
|
+
if (i === familyNameIdx)
|
|
295
|
+
continue;
|
|
296
|
+
view.setPositionalAttribute(id, i, null);
|
|
297
|
+
}
|
|
298
|
+
view.setAttribute(id, 'FamilyName', 'Anonymous');
|
|
299
|
+
}
|
|
300
|
+
/** `IfcOrganization.Name` -> `'Anonymous'`; every other declared attribute
|
|
301
|
+
* (`Identification`, `Description`, `Roles`, `Addresses`) -> `$`. */
|
|
302
|
+
function scrubOrganization(view, id) {
|
|
303
|
+
const names = getAttributeNamesAcrossSchemas('IFCORGANIZATION');
|
|
304
|
+
const nameIdx = names.indexOf('Name');
|
|
305
|
+
for (let i = 0; i < names.length; i++) {
|
|
306
|
+
if (i === nameIdx)
|
|
307
|
+
continue;
|
|
308
|
+
view.setPositionalAttribute(id, i, null);
|
|
309
|
+
}
|
|
310
|
+
view.setAttribute(id, 'Name', 'Anonymous');
|
|
311
|
+
}
|
|
312
|
+
//# 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,212 @@
|
|
|
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
|
+
* and `IfcProject.Phase` on roots, and every quoted-string `Name` /
|
|
121
|
+
* `Description` / `LongName` / `ProfileName` / `LayerSetName` on
|
|
122
|
+
* non-`IfcRoot` entities (`IfcSurfaceStyle`, `IfcMaterial*`,
|
|
123
|
+
* `IfcPresentationLayerAssignment`, `IfcProfileDef`, `IfcColourRgb`, …).
|
|
124
|
+
* A surface style called after the building it belongs to identifies the
|
|
125
|
+
* project as surely as `IfcProject.Name` does. Enum-valued `Name`s
|
|
126
|
+
* (`IfcSIUnit.Name = .METRE.`) are never touched, nor are property /
|
|
127
|
+
* quantity names (schema semantics, only present under `keepPropertySets`)
|
|
128
|
+
* or `IfcApplication`. Default `true`; independent of `pseudonymizeNames`. */
|
|
129
|
+
pseudonymizeAllNames?: boolean;
|
|
130
|
+
/** Keep `IfcPropertySet`/`IfcElementQuantity` entities instead of dropping
|
|
131
|
+
* them. Default `false` (i.e. psets are dropped by default). */
|
|
132
|
+
keepPropertySets?: boolean;
|
|
133
|
+
/** Regenerate every exported `IfcRoot`'s `GlobalId` (the old→new mapping
|
|
134
|
+
* comes back as `AnonymizeResult.guidMap`, never written into the file
|
|
135
|
+
* itself). Default `true`. */
|
|
136
|
+
regenerateGlobalIds?: boolean;
|
|
137
|
+
/** Zero the translation of each root `IfcLocalPlacement`
|
|
138
|
+
* (`PlacementRelTo = $`), preserving `Axis`/`RefDirection` and every child
|
|
139
|
+
* placement untouched. Default `true`. */
|
|
140
|
+
zeroRootPlacement?: boolean;
|
|
141
|
+
/** Remove `IfcMapConversion(Scaled)`/`IfcProjectedCRS` and blank
|
|
142
|
+
* `IfcSite`'s georeferencing/address attributes and
|
|
143
|
+
* `IfcBuilding.BuildingAddress`. Default `true`. */
|
|
144
|
+
removeGeoreferencing?: boolean;
|
|
145
|
+
/** Scrub the owner-history chain: blank `IfcPerson`/`IfcOrganization`
|
|
146
|
+
* identifying fields, zero `IfcOwnerHistory.CreationDate` and blank
|
|
147
|
+
* `LastModifiedDate`, blank `IfcApplication.Version` (a vendor build
|
|
148
|
+
* string such as `26.0.0 NOR FULL` encodes the licence region), and blank
|
|
149
|
+
* the STEP header's `originating_system`. `IfcApplication`'s name and
|
|
150
|
+
* identifier are kept — the authoring tool is debugging signal, its
|
|
151
|
+
* regional build is not. Default `true`. */
|
|
152
|
+
scrubOwnerHistory?: boolean;
|
|
153
|
+
/** Rewrite every `IfcMonetaryUnit.Currency` to US dollars (`.USD.` under
|
|
154
|
+
* IFC2X3's enum, `'USD'` under IFC4+'s label), so a cost-loaded model does
|
|
155
|
+
* not reveal its country. Default `true`. */
|
|
156
|
+
neutralizeCurrency?: boolean;
|
|
157
|
+
/** Seeded randomness for regenerated `GlobalId`s (and any other id this
|
|
158
|
+
* export synthesizes) — omitted means the platform CSPRNG, so two runs of
|
|
159
|
+
* an otherwise-identical anonymization differ in exactly those bytes.
|
|
160
|
+
* Pass the same source across repeat runs for byte-reproducible output. */
|
|
161
|
+
guidRandom?: RandomSource;
|
|
162
|
+
/** Pin the STEP header `FILE_NAME` timestamp (STEP format, e.g.
|
|
163
|
+
* `20240101T000000`). Omitted = the wall clock. */
|
|
164
|
+
timeStamp?: string;
|
|
165
|
+
/** Name recorded in the exported STEP header's `FILE_NAME` field — NOT
|
|
166
|
+
* necessarily the name the caller writes the file to disk under. Default
|
|
167
|
+
* `'anonymized.ifc'`, chosen because it is neutral: a caller that passes
|
|
168
|
+
* the real output path or project name here (e.g. `Acme-Tower.ifc`)
|
|
169
|
+
* defeats the anonymization by writing the identifying name straight back
|
|
170
|
+
* into the header of the file this option exists to scrub it from. */
|
|
171
|
+
filename?: string;
|
|
172
|
+
}
|
|
173
|
+
/** The result of one `exportAnonymizedSubset` call. */
|
|
174
|
+
export interface AnonymizeResult {
|
|
175
|
+
/** The anonymized STEP file content. */
|
|
176
|
+
content: Uint8Array;
|
|
177
|
+
/** Old `GlobalId` → new `GlobalId`, for every regenerated `IfcRoot`. Kept
|
|
178
|
+
* out of the exported file itself — it is exactly the mapping back to the
|
|
179
|
+
* original, identifying model, so it is the caller's responsibility to
|
|
180
|
+
* keep it separate (and typically NOT share it alongside the file). */
|
|
181
|
+
guidMap: Map<string, string>;
|
|
182
|
+
stats: {
|
|
183
|
+
/** Total entities in the exported file. */
|
|
184
|
+
entityCount: number;
|
|
185
|
+
/** How many `IfcRoot` entities from `includedIds` actually made it into
|
|
186
|
+
* the export (after subset-root exclusion and relationship pruning). */
|
|
187
|
+
includedRootEntityCount: number;
|
|
188
|
+
/** ExpressIds of `IfcRel*` entities dropped because their mandatory,
|
|
189
|
+
* single-valued reference named an entity the exclusion left out —
|
|
190
|
+
* `relationshipRefsSurviveExclusion` (`reference-collector.ts`) already
|
|
191
|
+
* decides this for the closure walk; this is that same decision,
|
|
192
|
+
* reported so a caller can see WHICH associations the anonymization
|
|
193
|
+
* cost, not just that some file that changed. */
|
|
194
|
+
prunedRelationshipIds: number[];
|
|
195
|
+
/** Each root `IfcLocalPlacement` this export zeroed, and the translation
|
|
196
|
+
* it zeroed (the ORIGINAL, pre-zero coordinates) — reported because the
|
|
197
|
+
* translation was real coordinate data the caller may still want to log
|
|
198
|
+
* or compare against, even though it is deliberately not in the file. */
|
|
199
|
+
zeroedPlacements: {
|
|
200
|
+
expressId: number;
|
|
201
|
+
translation: number[];
|
|
202
|
+
}[];
|
|
203
|
+
/** Non-fatal notices: a placement chain this export could not safely
|
|
204
|
+
* zero (e.g. an `IfcGridPlacement`/`IfcLinearPlacement` root, left
|
|
205
|
+
* untouched), multiple root placements collapsing onto one origin, or
|
|
206
|
+
* anything else `AnonymizeOptions` asked for that this export could not
|
|
207
|
+
* fully deliver. Same `string[]` shape as
|
|
208
|
+
* `StepExportResult.stats.warnings`. */
|
|
209
|
+
warnings: string[];
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//# 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"}
|