@ifc-lite/clash 1.9.2 → 2.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 +6 -1
- package/dist/analysis.d.ts +9 -1
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +19 -0
- package/dist/analysis.js.map +1 -1
- package/dist/bcf-bridge.js.map +1 -1
- package/dist/contact/aabb.d.ts +17 -1
- package/dist/contact/aabb.d.ts.map +1 -1
- package/dist/contact/aabb.js +41 -3
- package/dist/contact/aabb.js.map +1 -1
- package/dist/deterministic-uuid.d.ts +14 -5
- package/dist/deterministic-uuid.d.ts.map +1 -1
- package/dist/deterministic-uuid.js +13 -79
- package/dist/deterministic-uuid.js.map +1 -1
- package/dist/duplicates.js +1 -1
- package/dist/duplicates.js.map +1 -1
- package/dist/engine-ts/orchestrator.d.ts.map +1 -1
- package/dist/engine-ts/orchestrator.js +42 -6
- package/dist/engine-ts/orchestrator.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +3 -11
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +138 -28
- package/dist/lifecycle.js.map +1 -1
- package/dist/members.d.ts +13 -0
- package/dist/members.d.ts.map +1 -0
- package/dist/members.js +46 -0
- package/dist/members.js.map +1 -0
- package/dist/revision.d.ts +68 -0
- package/dist/revision.d.ts.map +1 -0
- package/dist/revision.js +208 -0
- package/dist/revision.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -9
package/dist/revision.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* The safety layer around `compareClashRuns` for a coordinator-facing
|
|
6
|
+
* "compare this run to a saved baseline" feature (#3928).
|
|
7
|
+
*
|
|
8
|
+
* `compareClashRuns` (lifecycle.ts) answers one narrow question — given two
|
|
9
|
+
* `ClashResult`s, which review keys appear in which — and it answers it well
|
|
10
|
+
* (see its own module doc for the model-re-mint handling). It does NOT know
|
|
11
|
+
* anything about the run's *conditions*: whether the same rules were run,
|
|
12
|
+
* whether a rule's selectors matched anything, or whether every model the
|
|
13
|
+
* baseline drew clashes from is still part of the comparison. A caller that
|
|
14
|
+
* feeds it two runs blindly can turn any of those into a false "resolved":
|
|
15
|
+
*
|
|
16
|
+
* - Drop a rule from the matrix between runs (a scope change) and every one of
|
|
17
|
+
* its previous clashes reads as fixed — nobody re-checked them, the rule
|
|
18
|
+
* simply didn't run.
|
|
19
|
+
* - A rule whose selector now matches zero elements on one side (renamed
|
|
20
|
+
* discipline, wrong model loaded) "ran" but compared nothing, so its
|
|
21
|
+
* previous clashes read as fixed for the same reason.
|
|
22
|
+
* - Unload one of the two models a clash spans and its elements vanish from
|
|
23
|
+
* `next.clashes` entirely — indistinguishable, at the `ClashResult` level,
|
|
24
|
+
* from the clash having been genuinely fixed.
|
|
25
|
+
*
|
|
26
|
+
* `compareClashRevisions` wraps `compareClashRuns` and reclassifies any
|
|
27
|
+
* `resolved` clash caught by one of those three conditions into a fourth
|
|
28
|
+
* bucket, `unretested`, so a coordinator is told "we don't know" instead of
|
|
29
|
+
* "fixed". Only `resolved` is at risk — `added` and `persistent` both assert
|
|
30
|
+
* a clash EXISTS in `next`, which the geometry backs directly; `resolved`
|
|
31
|
+
* asserts an ABSENCE, which a run can manufacture for reasons that have
|
|
32
|
+
* nothing to do with the model getting better.
|
|
33
|
+
*
|
|
34
|
+
* The condition-level checks above reason at RULE/MODEL granularity, but
|
|
35
|
+
* clash identity is per-ELEMENT. A rule can keep matching non-zero elements
|
|
36
|
+
* on both sides while silently dropping the ONE element a specific baseline
|
|
37
|
+
* clash depended on (a narrowed selector, or a re-scoped `membersA`/`membersB`
|
|
38
|
+
* filter) — invisible to a count-only coverage check. And a durable key can
|
|
39
|
+
* vanish entirely between exports (a re-minted GlobalId) — `compareClashRuns`
|
|
40
|
+
* correctly can't match old to new, so it reports a `resolved` half and an
|
|
41
|
+
* `added` half for what is really one still-live clash. Both cases are the
|
|
42
|
+
* SAME question in disguise: "was this clash's specific element actually
|
|
43
|
+
* re-examined in `next`, under this same rule?" — so `elementsReexamined`
|
|
44
|
+
* below answers that directly from `ruleCoverage[].matchedKeysA/B` (the
|
|
45
|
+
* durable keys the current run's rule actually matched), rather than from the
|
|
46
|
+
* coarser rule/model conditions. A rule with no tracked keys (an older result,
|
|
47
|
+
* or a hand-built fixture) cannot be verified and is treated as unsafe — the
|
|
48
|
+
* fail-safe direction this whole module exists to take.
|
|
49
|
+
*/
|
|
50
|
+
import { ruleHadNoMatch } from './analysis.js';
|
|
51
|
+
import { compareClashRuns } from './lifecycle.js';
|
|
52
|
+
function ruleIdSet(result) {
|
|
53
|
+
return new Set(result.rulesRun.map((rule) => rule.id));
|
|
54
|
+
}
|
|
55
|
+
/** Rule ids in `result.ruleCoverage` whose selectors matched 0 elements on a
|
|
56
|
+
* side — the rule ran but compared nothing. Absent coverage (a result from
|
|
57
|
+
* before #… or a hand-built fixture) yields an empty set, never a crash. */
|
|
58
|
+
function noMatchRuleIdSet(result) {
|
|
59
|
+
const ids = new Set();
|
|
60
|
+
for (const coverage of result.ruleCoverage ?? []) {
|
|
61
|
+
if (ruleHadNoMatch(coverage))
|
|
62
|
+
ids.add(coverage.rule);
|
|
63
|
+
}
|
|
64
|
+
return ids;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Per rule id, the sets of durable keys the CURRENT run's rule actually
|
|
68
|
+
* matched, one set per side — element-level membership, not a count. A rule
|
|
69
|
+
* id is deliberately absent from the returned map (rather than mapped to an
|
|
70
|
+
* empty set) whenever it cannot be verified: the rule didn't run this time
|
|
71
|
+
* (dropped from `ruleCoverage` entirely), or the coverage entry predates
|
|
72
|
+
* key-tracking (`matchedKeysA` undefined — an older result or a hand-built
|
|
73
|
+
* fixture). Callers must read "absent" as "unknown", never as "matched
|
|
74
|
+
* nothing" — see `elementsReexamined`.
|
|
75
|
+
*/
|
|
76
|
+
function ruleMatchedKeys(result) {
|
|
77
|
+
const map = new Map();
|
|
78
|
+
for (const coverage of result.ruleCoverage ?? []) {
|
|
79
|
+
if (coverage.matchedKeysA === undefined)
|
|
80
|
+
continue; // untracked: leave unmapped, not empty
|
|
81
|
+
const sideA = new Set(coverage.matchedKeysA);
|
|
82
|
+
const sideB = coverage.matchedKeysB === null ? null : new Set(coverage.matchedKeysB);
|
|
83
|
+
map.set(coverage.rule, { sideA, sideB });
|
|
84
|
+
}
|
|
85
|
+
return map;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether a clash's two elements are confirmed, by durable key, to still be
|
|
89
|
+
* matched by this SAME rule in the current run, in the roles the ORCHESTRATOR
|
|
90
|
+
* (`engine-ts/orchestrator.ts`) actually assigns them.
|
|
91
|
+
*
|
|
92
|
+
* Role-qualified, not order-independent, for a two-sided rule: `groupA`/
|
|
93
|
+
* `groupB` there are resolved once from `rule.a`/`membersA` and `rule.b`/
|
|
94
|
+
* `membersB`, and the broad phase only ever pairs `groupA[i] x groupB[j]` — a
|
|
95
|
+
* `NarrowRecord`'s `a` is always a global index drawn from `groupA`, `b`
|
|
96
|
+
* always from `groupB` (`broad.ts`). So `clash.a` is always "the element that
|
|
97
|
+
* matched side A" and `clash.b` always "the element that matched side B" for
|
|
98
|
+
* that rule, even when the two member sets overlap (the same physical element
|
|
99
|
+
* can appear as `a` in one clash instance and `b` in another, but never both
|
|
100
|
+
* within ONE clash record). Requiring the opposite assignment to also count
|
|
101
|
+
* would let a wall that moved from role A to role B alone — with its actual
|
|
102
|
+
* former partner never re-paired against it — read as "still matched",
|
|
103
|
+
* exactly the false `resolved` this module exists to prevent (the
|
|
104
|
+
* `matchedKeysA`/`matchedKeysB` union this replaces made precisely that
|
|
105
|
+
* mistake).
|
|
106
|
+
*
|
|
107
|
+
* `clashReviewKey` (review.ts) is order-independent, but that is a statement
|
|
108
|
+
* about MATCHING two `Clash` records across runs as "the same real-world
|
|
109
|
+
* clash" (so a and b can be seen in either order there without losing the
|
|
110
|
+
* pairing) — it says nothing about whether a role SWAP within one clash
|
|
111
|
+
* instance is safe to treat as "re-examined". It is not, here: the roles are
|
|
112
|
+
* fixed by the rule's own selector/membership resolution, not interchangeable.
|
|
113
|
+
*
|
|
114
|
+
* For a self-clash rule (`sideB === null`, no `b` side at all: `a` and `b` on
|
|
115
|
+
* such a clash are just two members of the one group, symmetric by
|
|
116
|
+
* construction), both elements are checked against the single set.
|
|
117
|
+
*/
|
|
118
|
+
function elementsReexamined(clash, matchedKeys) {
|
|
119
|
+
const keys = matchedKeys.get(clash.rule);
|
|
120
|
+
if (!keys)
|
|
121
|
+
return false;
|
|
122
|
+
if (keys.sideB === null)
|
|
123
|
+
return keys.sideA.has(clash.a.key) && keys.sideA.has(clash.b.key);
|
|
124
|
+
return keys.sideA.has(clash.a.key) && keys.sideB.has(clash.b.key);
|
|
125
|
+
}
|
|
126
|
+
/** How many distinct model ids share each display name — a plain `Set` of
|
|
127
|
+
* names cannot tell "this name still has a model" from "this name has a
|
|
128
|
+
* DIFFERENT model than before", which is exactly what two same-named models
|
|
129
|
+
* (a common federation setup: several disciplines all exported as
|
|
130
|
+
* `mep.ifc`-style filenames) needs. */
|
|
131
|
+
function nameCounts(modelNames) {
|
|
132
|
+
const counts = new Map();
|
|
133
|
+
for (const name of Object.values(modelNames))
|
|
134
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
135
|
+
return counts;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Compare a saved baseline run to a current run, safely.
|
|
139
|
+
*
|
|
140
|
+
* Pure and deterministic: depends only on the two inputs. `resolved` only
|
|
141
|
+
* receives a clash whose rule ran (with real matches on both sides) in the
|
|
142
|
+
* current run AND whose two models both still have a same-named counterpart
|
|
143
|
+
* there — everything else that `compareClashRuns` would have called
|
|
144
|
+
* `resolved` moves to `unretested` instead.
|
|
145
|
+
*/
|
|
146
|
+
export function compareClashRevisions(previous, next) {
|
|
147
|
+
const diff = compareClashRuns(previous.result, next.result);
|
|
148
|
+
const previousRuleIds = ruleIdSet(previous.result);
|
|
149
|
+
const nextRuleIds = ruleIdSet(next.result);
|
|
150
|
+
const skippedRuleIds = [...previousRuleIds].filter((id) => !nextRuleIds.has(id)).sort();
|
|
151
|
+
const noMatch = noMatchRuleIdSet(next.result);
|
|
152
|
+
const matchedKeys = ruleMatchedKeys(next.result);
|
|
153
|
+
// A name's count DROPPING between runs means at least one model under it is
|
|
154
|
+
// genuinely gone, and — because two models sharing a name are otherwise
|
|
155
|
+
// indistinguishable by anything this module is given — WHICH one cannot be
|
|
156
|
+
// known. Every previous model under that name is therefore treated as lost,
|
|
157
|
+
// which over-flags the survivor(s) too (a false `unretested`, the safe
|
|
158
|
+
// direction) rather than risk crediting a genuinely-gone model's clash as
|
|
159
|
+
// `resolved` (a false confirmation, the direction this module exists to
|
|
160
|
+
// prevent). A name whose count held steady or grew is NOT flagged: every
|
|
161
|
+
// previous model under it still has as many same-named counterparts as
|
|
162
|
+
// before, which is the best this heuristic can say without a firmer signal
|
|
163
|
+
// (content or size — see #3945's federation matcher for that fuller sense
|
|
164
|
+
// of "identity", not available here from a bare id→name map).
|
|
165
|
+
const previousCounts = nameCounts(previous.modelNames);
|
|
166
|
+
const nextCounts = nameCounts(next.modelNames);
|
|
167
|
+
const missingModelNames = [...previousCounts.keys()]
|
|
168
|
+
.filter((name) => (nextCounts.get(name) ?? 0) < (previousCounts.get(name) ?? 0))
|
|
169
|
+
.sort();
|
|
170
|
+
const missing = new Set(missingModelNames);
|
|
171
|
+
/** A previous-run model id is "lost" if it maps to a name whose count
|
|
172
|
+
* dropped in the current run. An id `previous.modelNames` never named is
|
|
173
|
+
* not lost — it just means the caller gave us nothing to say about it, and
|
|
174
|
+
* "unknown" must never manufacture a false confirmation either, so such a
|
|
175
|
+
* clash is left to the element-level check below. */
|
|
176
|
+
const modelLost = (modelId) => {
|
|
177
|
+
const name = previous.modelNames[modelId];
|
|
178
|
+
return name !== undefined && missing.has(name);
|
|
179
|
+
};
|
|
180
|
+
const resolved = [];
|
|
181
|
+
const unretested = [];
|
|
182
|
+
for (const clash of diff.resolved) {
|
|
183
|
+
const unsafe = skippedRuleIds.includes(clash.rule) ||
|
|
184
|
+
noMatch.has(clash.rule) ||
|
|
185
|
+
modelLost(clash.a.model) ||
|
|
186
|
+
modelLost(clash.b.model) ||
|
|
187
|
+
!elementsReexamined(clash, matchedKeys);
|
|
188
|
+
(unsafe ? unretested : resolved).push(clash);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
added: diff.added,
|
|
192
|
+
persistent: diff.persistent,
|
|
193
|
+
resolved,
|
|
194
|
+
unretested,
|
|
195
|
+
reasons: {
|
|
196
|
+
skippedRuleIds,
|
|
197
|
+
noMatchRuleIds: [...noMatch].sort(),
|
|
198
|
+
missingModelNames,
|
|
199
|
+
},
|
|
200
|
+
summary: {
|
|
201
|
+
added: diff.added.length,
|
|
202
|
+
persistent: diff.persistent.length,
|
|
203
|
+
resolved: resolved.length,
|
|
204
|
+
unretested: unretested.length,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=revision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision.js","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -51,6 +51,16 @@ export interface ClashRule {
|
|
|
51
51
|
a: string;
|
|
52
52
|
/** Selector for set B. Omitted ⇒ self-clash within A. */
|
|
53
53
|
b?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Explicit membership for set A — `clashMemberKey(model, ref)` strings. When
|
|
56
|
+
* present it REPLACES the `a` selector, so a caller that can resolve a richer
|
|
57
|
+
* filter than a type name (properties, attributes, storeys) against the model
|
|
58
|
+
* can express it. An empty array means "matched nothing", never "everything".
|
|
59
|
+
* See `members.ts`.
|
|
60
|
+
*/
|
|
61
|
+
membersA?: readonly string[];
|
|
62
|
+
/** Explicit membership for set B, replacing the `b` selector. See `membersA`. */
|
|
63
|
+
membersB?: readonly string[];
|
|
54
64
|
mode: ClashMode;
|
|
55
65
|
/** Touching band (m). Defaults to the run-level tolerance. */
|
|
56
66
|
tolerance?: number;
|
|
@@ -200,6 +210,30 @@ export interface ClashRuleCoverage {
|
|
|
200
210
|
rule: string;
|
|
201
211
|
matchedA: number;
|
|
202
212
|
matchedB: number | null;
|
|
213
|
+
/**
|
|
214
|
+
* Whether each side was resolved from explicit membership (`membersA` /
|
|
215
|
+
* `membersB`) rather than from its type selector. A caller explaining an
|
|
216
|
+
* empty side needs it and cannot recover it from `rulesRun`, which
|
|
217
|
+
* deliberately drops the resolved member lists. Absent on a result recorded
|
|
218
|
+
* before this existed — which is the same thing as "by selector".
|
|
219
|
+
*/
|
|
220
|
+
fromMembersA?: boolean;
|
|
221
|
+
fromMembersB?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* The durable `key` (IfcGUID / USD prim path) of every element THIS rule
|
|
224
|
+
* matched on each side, deduplicated and sorted for determinism — not just
|
|
225
|
+
* a count. `compareClashRevisions` (revision.ts) needs this to ask "was
|
|
226
|
+
* this SPECIFIC element re-examined?", which `matchedA`/`matchedB` (counts
|
|
227
|
+
* only) cannot answer: a narrowed selector that drops one previously-
|
|
228
|
+
* matched element while keeping the total count non-zero is invisible to a
|
|
229
|
+
* count-only check. `matchedKeysB` mirrors `matchedB`'s `null` for a
|
|
230
|
+
* self-clash rule (no `b` side). Absent (not just empty) on a result
|
|
231
|
+
* recorded before this existed, or from a hand-built fixture — callers
|
|
232
|
+
* MUST treat an absent `matchedKeysA` as "cannot verify", never as "matched
|
|
233
|
+
* nothing".
|
|
234
|
+
*/
|
|
235
|
+
matchedKeysA?: readonly string[];
|
|
236
|
+
matchedKeysB?: readonly string[] | null;
|
|
203
237
|
}
|
|
204
238
|
export interface ClashResult {
|
|
205
239
|
clashes: Clash[];
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;+DAE+D;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAyM/D,sEAAsE;AACtE,MAAM,CAAC,MAAM,qBAAqB,GAAiC,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAEpG,iEAAiE;AACjE,MAAM,CAAC,MAAM,2BAA2B,GAAsB,MAAM,CAAC;AAsFrE,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,KAAK;IAChB,oBAAoB,EAAE,IAAI;CAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/clash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Clash detection for IFC-Lite — representation-agnostic core engine + source adapters",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,17 +33,18 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ifc-lite/
|
|
37
|
-
"@ifc-lite/geometry": "^4.
|
|
38
|
-
"@ifc-lite/
|
|
39
|
-
"@ifc-lite/
|
|
40
|
-
"@ifc-lite/parser": "^
|
|
41
|
-
"@ifc-lite/
|
|
42
|
-
"@ifc-lite/
|
|
36
|
+
"@ifc-lite/bcf": "^3.0.0",
|
|
37
|
+
"@ifc-lite/geometry": "^4.2.0",
|
|
38
|
+
"@ifc-lite/ifcx": "^4.0.0",
|
|
39
|
+
"@ifc-lite/encoding": "^2.2.0",
|
|
40
|
+
"@ifc-lite/parser": "^5.1.0",
|
|
41
|
+
"@ifc-lite/query": "^2.1.0",
|
|
42
|
+
"@ifc-lite/spatial": "^1.14.16",
|
|
43
|
+
"@ifc-lite/wasm": "^6.3.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"typescript": "^6.0.3",
|
|
46
|
-
"vitest": "^4.1.
|
|
47
|
+
"vitest": "^4.1.11",
|
|
47
48
|
"@ifc-lite/world-frame-fixtures": "^0.1.1"
|
|
48
49
|
},
|
|
49
50
|
"license": "MPL-2.0",
|