@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/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export * from './types.js';
|
|
11
11
|
export { matchesSelector } from './selectors.js';
|
|
12
|
+
export { clashMemberKey, clashMemberSet, inClashSet } from './members.js';
|
|
12
13
|
export { DISCIPLINES, CLASH_RULE_PRESETS, inferClashSeverity, disciplineMatrixRules, rulesFromPresets, type Discipline, type DisciplineInfo, type ClashRulePreset, } from './disciplines.js';
|
|
13
14
|
export { createClashEngine, type ClashEngine, type ClashBackend, type CreateClashEngineOptions } from './engine.js';
|
|
14
15
|
export { makeExclusionSet, isExcluded, pairKey, qualifiedKey } from './exclude.js';
|
|
@@ -17,7 +18,8 @@ export { groupClashes, isClusterGroupingIneffective, type GroupOptions } from '.
|
|
|
17
18
|
export { groupDuplicateSets } from './duplicate-sets.js';
|
|
18
19
|
export { clashReviewKey, aggregateReviewStatus, reviewStatusToBcfTopicStatus, } from './review.js';
|
|
19
20
|
export { compareClashRuns, type ClashRevisionDiff } from './lifecycle.js';
|
|
20
|
-
export {
|
|
21
|
+
export { compareClashRevisions, type ClashRevisionSide, type ClashRevisionComparison, type ClashRevisionReasons, } from './revision.js';
|
|
22
|
+
export { SEVERITY_RANK, TOUCHING_EPSILON, penetrationDepth, isTouching, sortClashes, summarizeClashes, ruleHadNoMatch, classifyRuleCoverage, describeEmptyRuleSides, type ClashSortBy, type RuleCoverageOutcome, } from './analysis.js';
|
|
21
23
|
export { findDuplicates, DUPLICATES_RULE, type DuplicateOptions, } from './duplicates.js';
|
|
22
24
|
/**
|
|
23
25
|
* Per-triangle mesh analysis, re-exported for consumers outside this package
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,KAAK,WAAW,EAChB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB;;;;;;;GAOG;AACH,OAAO,EACL,YAAY,EACZ,KAAK,QAAQ,GACd,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB;;;;;;;GAOG;AACH,OAAO,EACL,YAAY,EACZ,KAAK,QAAQ,GACd,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export * from './types.js';
|
|
14
14
|
export { matchesSelector } from './selectors.js';
|
|
15
|
+
export { clashMemberKey, clashMemberSet, inClashSet } from './members.js';
|
|
15
16
|
export { DISCIPLINES, CLASH_RULE_PRESETS, inferClashSeverity, disciplineMatrixRules, rulesFromPresets, } from './disciplines.js';
|
|
16
17
|
export { createClashEngine } from './engine.js';
|
|
17
18
|
export { makeExclusionSet, isExcluded, pairKey, qualifiedKey } from './exclude.js';
|
|
@@ -20,7 +21,8 @@ export { groupClashes, isClusterGroupingIneffective } from './grouping.js';
|
|
|
20
21
|
export { groupDuplicateSets } from './duplicate-sets.js';
|
|
21
22
|
export { clashReviewKey, aggregateReviewStatus, reviewStatusToBcfTopicStatus, } from './review.js';
|
|
22
23
|
export { compareClashRuns } from './lifecycle.js';
|
|
23
|
-
export {
|
|
24
|
+
export { compareClashRevisions, } from './revision.js';
|
|
25
|
+
export { SEVERITY_RANK, TOUCHING_EPSILON, penetrationDepth, isTouching, sortClashes, summarizeClashes, ruleHadNoMatch, classifyRuleCoverage, describeEmptyRuleSides, } from './analysis.js';
|
|
24
26
|
export { findDuplicates, DUPLICATES_RULE, } from './duplicates.js';
|
|
25
27
|
/**
|
|
26
28
|
* Per-triangle mesh analysis, re-exported for consumers outside this package
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAsE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAqB,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAA0B,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;GAQG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAsE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAqB,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAA0B,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EACL,qBAAqB,GAItB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,GAGvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,eAAe,GAEhB,MAAM,iBAAiB,CAAC;AACzB;;;;;;;GAOG;AACH,OAAO,EACL,YAAY,GAEb,MAAM,uBAAuB,CAAC"}
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clash lifecycle across model revisions (Phase 5).
|
|
3
|
-
*
|
|
4
|
-
* Compares two clash runs and partitions their clashes into added / resolved /
|
|
5
|
-
* persistent buckets. Matching is by the stable `clash.id`, which is durable
|
|
6
|
-
* across revisions because it derives from the elements' durable keys
|
|
7
|
-
* (IfcGUID / USD prim path) plus the rule id — not from runtime refs that
|
|
8
|
-
* change between loads. This makes the diff stable: a clash that survives a
|
|
9
|
-
* revision keeps its id and is reported as `persistent` rather than as a
|
|
10
|
-
* resolve-plus-add churn.
|
|
11
|
-
*/
|
|
12
1
|
import type { Clash, ClashResult } from './types.js';
|
|
13
2
|
/**
|
|
14
3
|
* The result of comparing a previous clash run to a later ("next") one.
|
|
@@ -17,6 +6,9 @@ import type { Clash, ClashResult } from './types.js';
|
|
|
17
6
|
* - `persistent` clashes present in both runs (still open; the `next` Clash)
|
|
18
7
|
* - `resolved` clashes present in `previous` but not in `next` (fixed/removed)
|
|
19
8
|
*
|
|
9
|
+
* "Present in" counts occurrences, not just review keys: two clashes sharing a
|
|
10
|
+
* review key in one run need a counterpart each to both be `persistent`.
|
|
11
|
+
*
|
|
20
12
|
* Each array is sorted by `clash.id` for deterministic, diff-friendly output.
|
|
21
13
|
*/
|
|
22
14
|
export interface ClashRevisionDiff {
|
package/dist/lifecycle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE;AAsID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,iBAAiB,CA8B5F"}
|
package/dist/lifecycle.js
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Clash lifecycle across model revisions (Phase 5).
|
|
6
|
+
*
|
|
7
|
+
* Compares two clash runs and partitions their clashes into added / resolved /
|
|
8
|
+
* persistent buckets. Matching is by `clashReviewKey` (review.ts) — the rule id
|
|
9
|
+
* plus the two elements' durable keys (IfcGUID / USD prim path), order-
|
|
10
|
+
* independent — NOT by the raw `clash.id`. `clash.id` (`engine-ts/orchestrator.
|
|
11
|
+
* ts`'s `clashId()`) also folds in `ClashElement.model`, which review.ts
|
|
12
|
+
* documents as "an ephemeral per-load id in the viewer": two loads of the
|
|
13
|
+
* identical geometry — exactly the "revision" scenario this module exists to
|
|
14
|
+
* diff — get two different `model` values and therefore two different
|
|
15
|
+
* `clash.id`s for the same real-world clash. Matching on the review key keeps
|
|
16
|
+
* the diff stable across loads: a clash that survives a revision is reported
|
|
17
|
+
* as `persistent` rather than as a resolve-plus-add churn.
|
|
18
|
+
*
|
|
19
|
+
* The review key is NOT unique within a run, and the matching below is built
|
|
20
|
+
* around that. Dropping `model` is what makes the key durable, but the engine
|
|
21
|
+
* treats `(model, key)` as element identity — `orchestrator.ts` skips a pair
|
|
22
|
+
* only when `elA.key === elB.key && elA.model === elB.model` — and
|
|
23
|
+
* `adapters/ifcx.ts` keys on the bare USD prim path while `adapters/step.ts`
|
|
24
|
+
* keys on the bare IfcGUID (only its `syntheticKey` fallback folds in the
|
|
25
|
+
* model id). A federated run gathers every loaded model, so one run can
|
|
26
|
+
* legitimately hold several DISTINCT clashes under one review key: `/Duct` in
|
|
27
|
+
* layer-a and `/Duct` in layer-b each hitting the same wall. Matching by key
|
|
28
|
+
* membership alone would collapse those, silently swallowing a resolved clash
|
|
29
|
+
* and reporting a genuinely new one as pre-existing, so occurrences are
|
|
30
|
+
* grouped per key and paired (see `pairGroup`) instead.
|
|
31
|
+
*/
|
|
32
|
+
import { clashReviewKey } from './review.js';
|
|
4
33
|
/** Stable string compare for ids (ASCII/Unicode code-point order). */
|
|
5
34
|
function byId(a, b) {
|
|
6
35
|
if (a.id < b.id)
|
|
@@ -10,19 +39,108 @@ function byId(a, b) {
|
|
|
10
39
|
return 0;
|
|
11
40
|
}
|
|
12
41
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
42
|
+
* Group a run's clashes by their durable review key (`clashReviewKey`, not
|
|
43
|
+
* `clash.id` — see the module docstring), keeping EVERY occurrence rather than
|
|
44
|
+
* the last one. The key is deliberately not unique within a run (module
|
|
45
|
+
* docstring), so the group length is the multiplicity that `pairGroup` needs
|
|
46
|
+
* in order to tell "the same clash, seen again" from "a second, different
|
|
47
|
+
* clash that happens to share a review key".
|
|
19
48
|
*/
|
|
20
|
-
function
|
|
21
|
-
const
|
|
49
|
+
function groupByReviewKey(run) {
|
|
50
|
+
const groups = new Map();
|
|
51
|
+
for (const clash of run.clashes) {
|
|
52
|
+
const key = clashReviewKey(clash);
|
|
53
|
+
const group = groups.get(key);
|
|
54
|
+
if (group)
|
|
55
|
+
group.push(clash);
|
|
56
|
+
else
|
|
57
|
+
groups.set(key, [clash]);
|
|
58
|
+
}
|
|
59
|
+
return groups;
|
|
60
|
+
}
|
|
61
|
+
/** Every `model` id that appears on any clash in a run. `toRef`
|
|
62
|
+
* (`engine-ts/orchestrator.ts`) carries `model` onto both of a `Clash`'s
|
|
63
|
+
* element refs, so this is readable from a `ClashResult` alone. A model that
|
|
64
|
+
* produced no clash at all in the run is invisible here — see `pairGroup`. */
|
|
65
|
+
function modelsInRun(run) {
|
|
66
|
+
const models = new Set();
|
|
22
67
|
for (const clash of run.clashes) {
|
|
23
|
-
|
|
68
|
+
models.add(clash.a.model);
|
|
69
|
+
models.add(clash.b.model);
|
|
70
|
+
}
|
|
71
|
+
return models;
|
|
72
|
+
}
|
|
73
|
+
/** True when both of a clash's elements sit in models the other run also
|
|
74
|
+
* clashed in, i.e. that clash's `clash.id` was still mintable there. */
|
|
75
|
+
function bothModelsIn(clash, models) {
|
|
76
|
+
return models.has(clash.a.model) && models.has(clash.b.model);
|
|
77
|
+
}
|
|
78
|
+
/** Split into [matching, rest], preserving run order in both. */
|
|
79
|
+
function partition(clashes, keep) {
|
|
80
|
+
const yes = [];
|
|
81
|
+
const no = [];
|
|
82
|
+
for (const clash of clashes)
|
|
83
|
+
(keep(clash) ? yes : no).push(clash);
|
|
84
|
+
return [yes, no];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Pair one review key's previous-run occurrences against its next-run ones.
|
|
88
|
+
*
|
|
89
|
+
* Equal `clash.id`s are paired first. `clashId()` folds both elements' `model`
|
|
90
|
+
* into the id, so an id match is the same clash between the same two loaded
|
|
91
|
+
* models — which covers the whole of the "federated session that did not
|
|
92
|
+
* reload" case, pairing every surviving clash with ITSELF.
|
|
93
|
+
*
|
|
94
|
+
* A leftover is the same real-world clash seen again only if `model` was
|
|
95
|
+
* re-minted between the runs, and the data says whether it was: a previous-run
|
|
96
|
+
* leftover whose two models BOTH still clash somewhere in the next run was not
|
|
97
|
+
* re-minted, so had that clash survived it would have produced the same id and
|
|
98
|
+
* paired above — it is genuinely `resolved`. The mirror of that is genuinely
|
|
99
|
+
* `added`. Only leftovers whose models the other run no longer shows — the
|
|
100
|
+
* re-load this whole module exists to diff — are paired with each other, in
|
|
101
|
+
* run order, and the surplus on either side is `added` / `resolved`. Without
|
|
102
|
+
* that model test, two runs of one federated session in which the wall stops
|
|
103
|
+
* hitting `/Duct` in layer-a and starts hitting `/Duct` in layer-b would pair
|
|
104
|
+
* on count alone: the fixed clash would vanish from `resolved` and the new one
|
|
105
|
+
* would be reported as pre-existing.
|
|
106
|
+
*
|
|
107
|
+
* The model ids are read off the two runs' clashes, so a model that produced
|
|
108
|
+
* no clash at all in a run is invisible to the test and its clashes count as
|
|
109
|
+
* re-minted. That errs towards pairing, i.e. towards `persistent`: the
|
|
110
|
+
* churn-free reading, not a claim that something was fixed.
|
|
111
|
+
*
|
|
112
|
+
* `persistent` always receives the NEXT run's Clash (current geometry).
|
|
113
|
+
*/
|
|
114
|
+
function pairGroup(previous, next, models, out) {
|
|
115
|
+
const prevIndicesById = new Map();
|
|
116
|
+
previous.forEach((clash, i) => {
|
|
117
|
+
const slot = prevIndicesById.get(clash.id);
|
|
118
|
+
if (slot)
|
|
119
|
+
slot.push(i);
|
|
120
|
+
else
|
|
121
|
+
prevIndicesById.set(clash.id, [i]);
|
|
122
|
+
});
|
|
123
|
+
const matchedPrev = new Array(previous.length).fill(false);
|
|
124
|
+
const unmatchedNext = [];
|
|
125
|
+
for (const clash of next) {
|
|
126
|
+
const index = prevIndicesById.get(clash.id)?.shift();
|
|
127
|
+
if (index === undefined) {
|
|
128
|
+
unmatchedNext.push(clash);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
matchedPrev[index] = true;
|
|
132
|
+
out.persistent.push(clash);
|
|
133
|
+
}
|
|
24
134
|
}
|
|
25
|
-
|
|
135
|
+
const unmatchedPrev = previous.filter((_, i) => !matchedPrev[i]);
|
|
136
|
+
const [reloadedPrev, stillLivePrev] = partition(unmatchedPrev, (clash) => !bothModelsIn(clash, models.next));
|
|
137
|
+
const [reloadedNext, stillLiveNext] = partition(unmatchedNext, (clash) => !bothModelsIn(clash, models.previous));
|
|
138
|
+
out.resolved.push(...stillLivePrev);
|
|
139
|
+
out.added.push(...stillLiveNext);
|
|
140
|
+
const paired = Math.min(reloadedPrev.length, reloadedNext.length);
|
|
141
|
+
out.persistent.push(...reloadedNext.slice(0, paired));
|
|
142
|
+
out.added.push(...reloadedNext.slice(paired));
|
|
143
|
+
out.resolved.push(...reloadedPrev.slice(paired));
|
|
26
144
|
}
|
|
27
145
|
/**
|
|
28
146
|
* Compare two clash runs and partition their clashes by lifecycle state.
|
|
@@ -33,26 +151,18 @@ function indexById(run) {
|
|
|
33
151
|
* caller can render the up-to-date state. Each array is sorted by id.
|
|
34
152
|
*/
|
|
35
153
|
export function compareClashRuns(previous, next) {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
if (prevById.has(clash.id)) {
|
|
43
|
-
// Present in both runs: still open. Report the next run's Clash so the
|
|
44
|
-
// caller sees current geometry, not the stale previous-revision copy.
|
|
45
|
-
persistent.push(clash);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
added.push(clash);
|
|
49
|
-
}
|
|
154
|
+
const prevGroups = groupByReviewKey(previous);
|
|
155
|
+
const nextGroups = groupByReviewKey(next);
|
|
156
|
+
const models = { previous: modelsInRun(previous), next: modelsInRun(next) };
|
|
157
|
+
const buckets = { added: [], persistent: [], resolved: [] };
|
|
158
|
+
for (const [key, nextGroup] of nextGroups) {
|
|
159
|
+
pairGroup(prevGroups.get(key) ?? [], nextGroup, models, buckets);
|
|
50
160
|
}
|
|
51
|
-
for (const
|
|
52
|
-
if (!
|
|
53
|
-
resolved.push(
|
|
54
|
-
}
|
|
161
|
+
for (const [key, prevGroup] of prevGroups) {
|
|
162
|
+
if (!nextGroups.has(key))
|
|
163
|
+
buckets.resolved.push(...prevGroup);
|
|
55
164
|
}
|
|
165
|
+
const { added, persistent, resolved } = buckets;
|
|
56
166
|
added.sort(byId);
|
|
57
167
|
persistent.sort(byId);
|
|
58
168
|
resolved.sort(byId);
|
package/dist/lifecycle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;+DAE+D;
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClashElement } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The membership identity of one element: its model plus its `ref`, encoded
|
|
4
|
+
* with the engine's existing model-qualified scheme (`qualifiedKey`) so there
|
|
5
|
+
* is one such encoding in this package rather than two.
|
|
6
|
+
*/
|
|
7
|
+
export declare function clashMemberKey(model: string, ref: number): string;
|
|
8
|
+
/** Index a rule's member list; `null` when the side has no explicit members. */
|
|
9
|
+
export declare function clashMemberSet(members: readonly string[] | undefined): ReadonlySet<string> | null;
|
|
10
|
+
/** Whether one element belongs to a rule side, by membership when the side has
|
|
11
|
+
* an explicit member set and by type selector otherwise. */
|
|
12
|
+
export declare function inClashSet(element: Pick<ClashElement, 'model' | 'ref' | 'tag'>, selector: string, members: ReadonlySet<string> | null): boolean;
|
|
13
|
+
//# sourceMappingURL=members.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACrC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAE5B;AAED;6DAC6D;AAC7D,wBAAgB,UAAU,CACxB,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC,EACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,GAClC,OAAO,CAGT"}
|
package/dist/members.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
* Explicit MEMBERSHIP for a rule's A / B set.
|
|
6
|
+
*
|
|
7
|
+
* `ClashRule.a` / `.b` are type-name selectors, and a `ClashElement` carries
|
|
8
|
+
* nothing but its type (`tag`), name and storey — so a selector cannot express
|
|
9
|
+
* "walls whose `Pset_WallCommon.IsExternal` is true". A caller that DOES have
|
|
10
|
+
* the model (the viewer resolves its advanced filter against the parsed store)
|
|
11
|
+
* resolves such a set to element identities and hands them over as
|
|
12
|
+
* `membersA` / `membersB`; the engine then partitions by membership instead of
|
|
13
|
+
* by the selector, and everything downstream — severity, exclusions, dedup,
|
|
14
|
+
* coverage, both kernels — is untouched.
|
|
15
|
+
*
|
|
16
|
+
* The identity is `(model, ref)`, not `key`. `ref` is what a caller holding a
|
|
17
|
+
* `(modelId, expressId)` pair can compute directly, while `key` is built inside
|
|
18
|
+
* the adapter out of the stored GlobalId plus an occurrence suffix and cannot
|
|
19
|
+
* be reconstructed from the store alone. Two GPU-instanced occurrences of one
|
|
20
|
+
* entity share a `ref` and both land in the set, which is the intended reading
|
|
21
|
+
* of "this entity is in set A".
|
|
22
|
+
*
|
|
23
|
+
* An EMPTY member list is not an absent one — see `ClashRule.membersA`.
|
|
24
|
+
*/
|
|
25
|
+
import { qualifiedKey } from './exclude.js';
|
|
26
|
+
import { matchesSelector } from './selectors.js';
|
|
27
|
+
/**
|
|
28
|
+
* The membership identity of one element: its model plus its `ref`, encoded
|
|
29
|
+
* with the engine's existing model-qualified scheme (`qualifiedKey`) so there
|
|
30
|
+
* is one such encoding in this package rather than two.
|
|
31
|
+
*/
|
|
32
|
+
export function clashMemberKey(model, ref) {
|
|
33
|
+
return qualifiedKey(model, String(ref));
|
|
34
|
+
}
|
|
35
|
+
/** Index a rule's member list; `null` when the side has no explicit members. */
|
|
36
|
+
export function clashMemberSet(members) {
|
|
37
|
+
return members ? new Set(members) : null;
|
|
38
|
+
}
|
|
39
|
+
/** Whether one element belongs to a rule side, by membership when the side has
|
|
40
|
+
* an explicit member set and by type selector otherwise. */
|
|
41
|
+
export function inClashSet(element, selector, members) {
|
|
42
|
+
if (members)
|
|
43
|
+
return members.has(clashMemberKey(element.model, element.ref));
|
|
44
|
+
return matchesSelector(element.tag, selector);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.js","sourceRoot":"","sources":["../src/members.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,GAAW;IACvD,OAAO,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAC5B,OAAsC;IAEtC,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED;6DAC6D;AAC7D,MAAM,UAAU,UAAU,CACxB,OAAoD,EACpD,QAAgB,EAChB,OAAmC;IAEnC,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,OAAO,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Clash, ClashResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* One side of a revision comparison: a completed run plus the durable
|
|
4
|
+
* identity of every model it drew elements from.
|
|
5
|
+
*
|
|
6
|
+
* `ClashElementRef.model` (carried on `Clash.a`/`Clash.b`) is the federation's
|
|
7
|
+
* per-LOAD id — `crypto.randomUUID()` in the viewer — so it is deliberately
|
|
8
|
+
* useless for asking "is this model still part of the comparison". `modelNames`
|
|
9
|
+
* is the caller-supplied bridge: a map from that ephemeral id, AS IT APPEARS ON
|
|
10
|
+
* THIS RESULT'S OWN CLASHES, to a durable identity (the model's display name /
|
|
11
|
+
* filename in the viewer). Two different `model` ids that map to the same name
|
|
12
|
+
* are treated as the same model reloaded; a name present in `previous` but
|
|
13
|
+
* absent from `next` is treated as a model the comparison lost entirely.
|
|
14
|
+
*
|
|
15
|
+
* This is a heuristic, not a proof: renaming a model between runs makes it
|
|
16
|
+
* look "missing" (its old name has no counterpart), and two distinctly loaded
|
|
17
|
+
* files that happen to share a display name look like one. Both failure modes
|
|
18
|
+
* point the same way — toward `unretested` rather than a wrongly-confident
|
|
19
|
+
* `resolved` — which is the direction this module exists to be safe in.
|
|
20
|
+
*/
|
|
21
|
+
export interface ClashRevisionSide {
|
|
22
|
+
result: ClashResult;
|
|
23
|
+
/** Ephemeral `ClashElementRef.model` id → durable display identity. */
|
|
24
|
+
modelNames: Readonly<Record<string, string>>;
|
|
25
|
+
}
|
|
26
|
+
export interface ClashRevisionReasons {
|
|
27
|
+
/** Rule ids the baseline ran that the current run's `rulesRun` omits entirely. */
|
|
28
|
+
skippedRuleIds: string[];
|
|
29
|
+
/** Rule ids the current run ran but whose coverage matched 0 elements on a
|
|
30
|
+
* side (`ruleHadNoMatch`) — it ran, but compared nothing. */
|
|
31
|
+
noMatchRuleIds: string[];
|
|
32
|
+
/** Durable model names present in the baseline that have no counterpart
|
|
33
|
+
* (by name) among the current run's models. */
|
|
34
|
+
missingModelNames: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface ClashRevisionComparison {
|
|
37
|
+
/** In the current run, not the baseline: new issues. */
|
|
38
|
+
added: Clash[];
|
|
39
|
+
/** In both runs: still open. Carries the current run's `Clash`. */
|
|
40
|
+
persistent: Clash[];
|
|
41
|
+
/** In the baseline, not the current run, AND safe to call fixed: every rule
|
|
42
|
+
* and model the clash depended on was genuinely re-checked. */
|
|
43
|
+
resolved: Clash[];
|
|
44
|
+
/** In the baseline, not the current run, but NOT safe to call fixed: the
|
|
45
|
+
* current run could not have found it even if it still existed (a skipped
|
|
46
|
+
* rule, an empty-match rule, or a model no longer in the comparison). Never
|
|
47
|
+
* silently folded into `resolved`. */
|
|
48
|
+
unretested: Clash[];
|
|
49
|
+
/** Why each `unretested` clash landed there, for a coordinator's UI banner. */
|
|
50
|
+
reasons: ClashRevisionReasons;
|
|
51
|
+
summary: {
|
|
52
|
+
added: number;
|
|
53
|
+
persistent: number;
|
|
54
|
+
resolved: number;
|
|
55
|
+
unretested: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Compare a saved baseline run to a current run, safely.
|
|
60
|
+
*
|
|
61
|
+
* Pure and deterministic: depends only on the two inputs. `resolved` only
|
|
62
|
+
* receives a clash whose rule ran (with real matches on both sides) in the
|
|
63
|
+
* current run AND whose two models both still have a same-named counterpart
|
|
64
|
+
* there — everything else that `compareClashRuns` would have called
|
|
65
|
+
* `resolved` moves to `unretested` instead.
|
|
66
|
+
*/
|
|
67
|
+
export declare function compareClashRevisions(previous: ClashRevisionSide, next: ClashRevisionSide): ClashRevisionComparison;
|
|
68
|
+
//# sourceMappingURL=revision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision.d.ts","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,uEAAuE;IACvE,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;kEAC8D;IAC9D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;oDACgD;IAChD,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,wDAAwD;IACxD,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,mEAAmE;IACnE,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB;oEACgE;IAChE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB;;;2CAGuC;IACvC,UAAU,EAAE,KAAK,EAAE,CAAC;IACpB,+EAA+E;IAC/E,OAAO,EAAE,oBAAoB,CAAC;IAC9B,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CACtF;AAkGD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,iBAAiB,GACtB,uBAAuB,CAoEzB"}
|