@ifc-lite/rules 0.2.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/LICENSE +373 -0
- package/README.md +45 -0
- package/dist/engine/rule-engine-chunk.d.ts +25 -0
- package/dist/engine/rule-engine-chunk.d.ts.map +1 -0
- package/dist/engine/rule-engine-chunk.js +43 -0
- package/dist/engine/rule-engine-chunk.js.map +1 -0
- package/dist/engine/rule-engine-compare.d.ts +17 -0
- package/dist/engine/rule-engine-compare.d.ts.map +1 -0
- package/dist/engine/rule-engine-compare.js +69 -0
- package/dist/engine/rule-engine-compare.js.map +1 -0
- package/dist/engine/rule-engine-requirements.d.ts +37 -0
- package/dist/engine/rule-engine-requirements.d.ts.map +1 -0
- package/dist/engine/rule-engine-requirements.js +293 -0
- package/dist/engine/rule-engine-requirements.js.map +1 -0
- package/dist/engine/rule-engine-sets.d.ts +46 -0
- package/dist/engine/rule-engine-sets.d.ts.map +1 -0
- package/dist/engine/rule-engine-sets.js +298 -0
- package/dist/engine/rule-engine-sets.js.map +1 -0
- package/dist/engine/rule-engine-unit.d.ts +23 -0
- package/dist/engine/rule-engine-unit.d.ts.map +1 -0
- package/dist/engine/rule-engine-unit.js +64 -0
- package/dist/engine/rule-engine-unit.js.map +1 -0
- package/dist/engine/rule-engine.d.ts +29 -0
- package/dist/engine/rule-engine.d.ts.map +1 -0
- package/dist/engine/rule-engine.js +244 -0
- package/dist/engine/rule-engine.js.map +1 -0
- package/dist/filter/effective-filter-fields.d.ts +13 -0
- package/dist/filter/effective-filter-fields.d.ts.map +1 -0
- package/dist/filter/effective-filter-fields.js +44 -0
- package/dist/filter/effective-filter-fields.js.map +1 -0
- package/dist/filter/entity-predefined-type.d.ts +24 -0
- package/dist/filter/entity-predefined-type.d.ts.map +1 -0
- package/dist/filter/entity-predefined-type.js +34 -0
- package/dist/filter/entity-predefined-type.js.map +1 -0
- package/dist/filter/filter-evaluate-groups.d.ts +36 -0
- package/dist/filter/filter-evaluate-groups.d.ts.map +1 -0
- package/dist/filter/filter-evaluate-groups.js +111 -0
- package/dist/filter/filter-evaluate-groups.js.map +1 -0
- package/dist/filter/filter-evaluate-model-tag.d.ts +22 -0
- package/dist/filter/filter-evaluate-model-tag.d.ts.map +1 -0
- package/dist/filter/filter-evaluate-model-tag.js +35 -0
- package/dist/filter/filter-evaluate-model-tag.js.map +1 -0
- package/dist/filter/filter-evaluate-mutations.d.ts +51 -0
- package/dist/filter/filter-evaluate-mutations.d.ts.map +1 -0
- package/dist/filter/filter-evaluate-mutations.js +111 -0
- package/dist/filter/filter-evaluate-mutations.js.map +1 -0
- package/dist/filter/filter-evaluate-yield.d.ts +9 -0
- package/dist/filter/filter-evaluate-yield.d.ts.map +1 -0
- package/dist/filter/filter-evaluate-yield.js +32 -0
- package/dist/filter/filter-evaluate-yield.js.map +1 -0
- package/dist/filter/filter-evaluate.d.ts +120 -0
- package/dist/filter/filter-evaluate.d.ts.map +1 -0
- package/dist/filter/filter-evaluate.js +408 -0
- package/dist/filter/filter-evaluate.js.map +1 -0
- package/dist/filter/filter-group-rule.d.ts +23 -0
- package/dist/filter/filter-group-rule.d.ts.map +1 -0
- package/dist/filter/filter-group-rule.js +69 -0
- package/dist/filter/filter-group-rule.js.map +1 -0
- package/dist/filter/filter-groups.d.ts +65 -0
- package/dist/filter/filter-groups.d.ts.map +1 -0
- package/dist/filter/filter-groups.js +136 -0
- package/dist/filter/filter-groups.js.map +1 -0
- package/dist/filter/filter-iteration-source.d.ts +26 -0
- package/dist/filter/filter-iteration-source.d.ts.map +1 -0
- package/dist/filter/filter-iteration-source.js +154 -0
- package/dist/filter/filter-iteration-source.js.map +1 -0
- package/dist/filter/filter-iteration.d.ts +5 -0
- package/dist/filter/filter-iteration.d.ts.map +1 -0
- package/dist/filter/filter-iteration.js +25 -0
- package/dist/filter/filter-iteration.js.map +1 -0
- package/dist/filter/filter-match.d.ts +114 -0
- package/dist/filter/filter-match.d.ts.map +1 -0
- package/dist/filter/filter-match.js +302 -0
- package/dist/filter/filter-match.js.map +1 -0
- package/dist/filter/filter-ops.d.ts +90 -0
- package/dist/filter/filter-ops.d.ts.map +1 -0
- package/dist/filter/filter-ops.js +202 -0
- package/dist/filter/filter-ops.js.map +1 -0
- package/dist/filter/filter-rule-guards.d.ts +4 -0
- package/dist/filter/filter-rule-guards.d.ts.map +1 -0
- package/dist/filter/filter-rule-guards.js +74 -0
- package/dist/filter/filter-rule-guards.js.map +1 -0
- package/dist/filter/filter-rules.d.ts +275 -0
- package/dist/filter/filter-rules.d.ts.map +1 -0
- package/dist/filter/filter-rules.js +68 -0
- package/dist/filter/filter-rules.js.map +1 -0
- package/dist/filter/lens-material-names.d.ts +13 -0
- package/dist/filter/lens-material-names.d.ts.map +1 -0
- package/dist/filter/lens-material-names.js +36 -0
- package/dist/filter/lens-material-names.js.map +1 -0
- package/dist/filter/measure-units.d.ts +29 -0
- package/dist/filter/measure-units.d.ts.map +1 -0
- package/dist/filter/measure-units.js +72 -0
- package/dist/filter/measure-units.js.map +1 -0
- package/dist/filter/model-tag.d.ts +65 -0
- package/dist/filter/model-tag.d.ts.map +1 -0
- package/dist/filter/model-tag.js +57 -0
- package/dist/filter/model-tag.js.map +1 -0
- package/dist/filter/read-measure-subject.d.ts +28 -0
- package/dist/filter/read-measure-subject.d.ts.map +1 -0
- package/dist/filter/read-measure-subject.js +116 -0
- package/dist/filter/read-measure-subject.js.map +1 -0
- package/dist/filter/read-subject.d.ts +72 -0
- package/dist/filter/read-subject.d.ts.map +1 -0
- package/dist/filter/read-subject.js +128 -0
- package/dist/filter/read-subject.js.map +1 -0
- package/dist/filter/subject-match.d.ts +27 -0
- package/dist/filter/subject-match.d.ts.map +1 -0
- package/dist/filter/subject-match.js +52 -0
- package/dist/filter/subject-match.js.map +1 -0
- package/dist/filter/subject-read-options.d.ts +33 -0
- package/dist/filter/subject-read-options.d.ts.map +1 -0
- package/dist/filter/subject-read-options.js +8 -0
- package/dist/filter/subject-read-options.js.map +1 -0
- package/dist/ids/ids-facet-to-rules.d.ts +20 -0
- package/dist/ids/ids-facet-to-rules.d.ts.map +1 -0
- package/dist/ids/ids-facet-to-rules.js +230 -0
- package/dist/ids/ids-facet-to-rules.js.map +1 -0
- package/dist/ids/ids-regex.d.ts +44 -0
- package/dist/ids/ids-regex.d.ts.map +1 -0
- package/dist/ids/ids-regex.js +334 -0
- package/dist/ids/ids-regex.js.map +1 -0
- package/dist/ids/ids-to-rule-set.d.ts +39 -0
- package/dist/ids/ids-to-rule-set.d.ts.map +1 -0
- package/dist/ids/ids-to-rule-set.js +103 -0
- package/dist/ids/ids-to-rule-set.js.map +1 -0
- package/dist/ids/ids-xml-writer.d.ts +11 -0
- package/dist/ids/ids-xml-writer.d.ts.map +1 -0
- package/dist/ids/ids-xml-writer.js +172 -0
- package/dist/ids/ids-xml-writer.js.map +1 -0
- package/dist/ids/rule-set-to-ids.d.ts +45 -0
- package/dist/ids/rule-set-to-ids.d.ts.map +1 -0
- package/dist/ids/rule-set-to-ids.js +140 -0
- package/dist/ids/rule-set-to-ids.js.map +1 -0
- package/dist/ids/rule-to-ids-facets.d.ts +52 -0
- package/dist/ids/rule-to-ids-facets.d.ts.map +1 -0
- package/dist/ids/rule-to-ids-facets.js +291 -0
- package/dist/ids/rule-to-ids-facets.js.map +1 -0
- package/dist/ids/stored-unit-scale.d.ts +15 -0
- package/dist/ids/stored-unit-scale.d.ts.map +1 -0
- package/dist/ids/stored-unit-scale.js +64 -0
- package/dist/ids/stored-unit-scale.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/rule-set/between-chip.d.ts +54 -0
- package/dist/rule-set/between-chip.d.ts.map +1 -0
- package/dist/rule-set/between-chip.js +95 -0
- package/dist/rule-set/between-chip.js.map +1 -0
- package/dist/rule-set/requirement-invariants.d.ts +25 -0
- package/dist/rule-set/requirement-invariants.d.ts.map +1 -0
- package/dist/rule-set/requirement-invariants.js +29 -0
- package/dist/rule-set/requirement-invariants.js.map +1 -0
- package/dist/rule-set/requirement-text.d.ts +20 -0
- package/dist/rule-set/requirement-text.d.ts.map +1 -0
- package/dist/rule-set/requirement-text.js +179 -0
- package/dist/rule-set/requirement-text.js.map +1 -0
- package/dist/rule-set/rule-set-io-requirement.d.ts +22 -0
- package/dist/rule-set/rule-set-io-requirement.d.ts.map +1 -0
- package/dist/rule-set/rule-set-io-requirement.js +140 -0
- package/dist/rule-set/rule-set-io-requirement.js.map +1 -0
- package/dist/rule-set/rule-set-io-shared.d.ts +24 -0
- package/dist/rule-set/rule-set-io-shared.d.ts.map +1 -0
- package/dist/rule-set/rule-set-io-shared.js +48 -0
- package/dist/rule-set/rule-set-io-shared.js.map +1 -0
- package/dist/rule-set/rule-set-io-subject.d.ts +10 -0
- package/dist/rule-set/rule-set-io-subject.d.ts.map +1 -0
- package/dist/rule-set/rule-set-io-subject.js +67 -0
- package/dist/rule-set/rule-set-io-subject.js.map +1 -0
- package/dist/rule-set/rule-set-io.d.ts +37 -0
- package/dist/rule-set/rule-set-io.d.ts.map +1 -0
- package/dist/rule-set/rule-set-io.js +142 -0
- package/dist/rule-set/rule-set-io.js.map +1 -0
- package/dist/rule-set/rule-set.d.ts +109 -0
- package/dist/rule-set/rule-set.d.ts.map +1 -0
- package/dist/rule-set/rule-set.js +5 -0
- package/dist/rule-set/rule-set.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,298 @@
|
|
|
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 { collectSpatialAncestors } from '@ifc-lite/data';
|
|
5
|
+
import { numericOpMatches } from '../filter/filter-ops.js';
|
|
6
|
+
import { evaluateFilterGroupsFederated } from '../filter/filter-evaluate-groups.js';
|
|
7
|
+
import { readSubject } from '../filter/read-subject.js';
|
|
8
|
+
import { OP_LABEL } from './rule-engine-requirements.js';
|
|
9
|
+
import { maybeYieldChunk, finalProgress } from './rule-engine-chunk.js';
|
|
10
|
+
const SET_RESULT_CAP = 1_000;
|
|
11
|
+
/** Shared with `rule-engine-compare.ts` (same `Subject` label rendering). */
|
|
12
|
+
export function describeSubject(subject) {
|
|
13
|
+
switch (subject.kind) {
|
|
14
|
+
case 'property': return `${subject.setName}.${subject.propertyName}`;
|
|
15
|
+
case 'quantity': return `${subject.setName}.${subject.quantityName}`;
|
|
16
|
+
case 'attribute': return subject.name;
|
|
17
|
+
case 'classification': return subject.system ? `Classification[${subject.system}]` : 'Classification';
|
|
18
|
+
case 'group': return subject.groupClass ? `Group[${subject.groupClass}]` : 'Group';
|
|
19
|
+
default: return subject.kind;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fold a raw subject value into a bucket/group key. `globalId` is NEVER
|
|
24
|
+
* case-folded, `caseSensitive` or not — review finding: same rule
|
|
25
|
+
* `filter-ops.ts`'s `globalIdOpMatches` already applies (a GlobalId is a
|
|
26
|
+
* 22-char base64 GUID where case IS the identity; folding it would merge
|
|
27
|
+
* two genuinely different elements' ids, e.g. `abc`/`ABC`, into one
|
|
28
|
+
* "duplicate").
|
|
29
|
+
*/
|
|
30
|
+
function foldKey(value, subjectKind, caseSensitive) {
|
|
31
|
+
if (subjectKind === 'globalId')
|
|
32
|
+
return value;
|
|
33
|
+
return caseSensitive ? value : value.toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
/** Shared with `rule-engine-compare.ts`. */
|
|
36
|
+
export function baseRow(el, passed, result) {
|
|
37
|
+
return {
|
|
38
|
+
expressId: el.expressId,
|
|
39
|
+
modelId: el.modelId,
|
|
40
|
+
entityType: el.ifcType,
|
|
41
|
+
entityName: el.name || undefined,
|
|
42
|
+
globalId: el.globalId,
|
|
43
|
+
passed,
|
|
44
|
+
requirementResults: [result],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export async function checkUnique(requirementId, requirement, applicable, storesById, opts, ruleIndex, signal, onProgress) {
|
|
48
|
+
const label = `unique(${describeSubject(requirement.subject)})`;
|
|
49
|
+
const perModel = requirement.scope === 'perModel';
|
|
50
|
+
const entityResults = [];
|
|
51
|
+
// scope key ('' for federation, else modelId) -> folded value -> members.
|
|
52
|
+
const buckets = new Map();
|
|
53
|
+
for (let i = 0; i < applicable.length; i++) {
|
|
54
|
+
const el = applicable[i];
|
|
55
|
+
const store = storesById.get(el.modelId);
|
|
56
|
+
if (store) {
|
|
57
|
+
const subject = readSubject(requirement.subject, { store, expressId: el.expressId });
|
|
58
|
+
if (!subject.present) {
|
|
59
|
+
entityResults.push(baseRow(el, false, {
|
|
60
|
+
requirement: { id: requirementId, label, optionality: 'required' },
|
|
61
|
+
status: 'fail', facetType: 'unique', checkedDescription: label,
|
|
62
|
+
failureReason: 'absent', actualValue: '""', expectedValue: 'unique',
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const scopeKey = perModel ? el.modelId : '';
|
|
67
|
+
let scoped = buckets.get(scopeKey);
|
|
68
|
+
if (!scoped)
|
|
69
|
+
buckets.set(scopeKey, (scoped = new Map()));
|
|
70
|
+
for (const raw of subject.values) {
|
|
71
|
+
const s = String(raw);
|
|
72
|
+
if (s.trim().length === 0)
|
|
73
|
+
continue;
|
|
74
|
+
const key = foldKey(s, requirement.subject.kind, opts.caseSensitive);
|
|
75
|
+
let bucket = scoped.get(key);
|
|
76
|
+
if (!bucket)
|
|
77
|
+
scoped.set(key, (bucket = []));
|
|
78
|
+
bucket.push({ el, value: s });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
await maybeYieldChunk(i + 1, applicable.length, ruleIndex, signal, onProgress);
|
|
83
|
+
}
|
|
84
|
+
finalProgress(applicable.length, ruleIndex, signal, onProgress);
|
|
85
|
+
const dupGroups = [];
|
|
86
|
+
for (const scoped of buckets.values()) {
|
|
87
|
+
for (const members of scoped.values()) {
|
|
88
|
+
if (members.length > 1)
|
|
89
|
+
dupGroups.push({ value: members[0].value, members });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
dupGroups.sort((a, b) => b.members.length - a.members.length);
|
|
93
|
+
for (const g of dupGroups) {
|
|
94
|
+
const actual = `${g.value} (${g.members.length}×)`;
|
|
95
|
+
for (const m of g.members) {
|
|
96
|
+
entityResults.push(baseRow(m.el, false, {
|
|
97
|
+
requirement: { id: requirementId, label, optionality: 'required' },
|
|
98
|
+
status: 'fail', facetType: 'unique', checkedDescription: label,
|
|
99
|
+
failureReason: 'duplicate', actualValue: actual, expectedValue: 'unique',
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const setResultsTruncated = dupGroups.length > SET_RESULT_CAP;
|
|
104
|
+
const setResults = dupGroups.slice(0, SET_RESULT_CAP).map((g) => ({
|
|
105
|
+
kind: 'duplicate',
|
|
106
|
+
label: g.value,
|
|
107
|
+
actual: `${g.value} (${g.members.length}×)`,
|
|
108
|
+
expected: 'unique',
|
|
109
|
+
passed: false,
|
|
110
|
+
failureReason: 'duplicate',
|
|
111
|
+
members: g.members.map((m) => ({ modelId: m.el.modelId, expressId: m.el.expressId })),
|
|
112
|
+
}));
|
|
113
|
+
return { setResults, setResultsTruncated, entityResults };
|
|
114
|
+
}
|
|
115
|
+
function newAccumulator(keyLabel) {
|
|
116
|
+
return { count: 0, sum: 0, min: Infinity, max: -Infinity, units: new Set(), skipped: 0, keyLabel, members: [] };
|
|
117
|
+
}
|
|
118
|
+
/** The DIRECT (nearest) spatial parent — `collectSpatialAncestors`'s BFS
|
|
119
|
+
* walk yields nearest-first, so its first entry is exactly that; plan
|
|
120
|
+
* §4.6 asks for the direct parent's identity, not the whole ancestor
|
|
121
|
+
* chain `parent=` (search) matches against. */
|
|
122
|
+
function directParentOf(store, expressId) {
|
|
123
|
+
if (!store.relationships)
|
|
124
|
+
return undefined;
|
|
125
|
+
return collectSpatialAncestors(store.relationships, expressId)[0];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Every group key `el` contributes to — plural, per plan §3: "an element
|
|
129
|
+
* contributes to every key it carries", so a multi-valued `groupBy` subject
|
|
130
|
+
* (`material`, `classification`) lands the same element in EVERY matching
|
|
131
|
+
* group, not just its first value. `parent` stays single-valued (an element
|
|
132
|
+
* has exactly one direct spatial parent); everything else de-dupes an
|
|
133
|
+
* element's own repeated values so one element can't double-count itself
|
|
134
|
+
* into the SAME group twice.
|
|
135
|
+
*/
|
|
136
|
+
function groupKeysOf(requirement, el, store, caseSensitive) {
|
|
137
|
+
if (!requirement.groupBy)
|
|
138
|
+
return [{ key: '*', label: '' }];
|
|
139
|
+
if (requirement.groupBy.subject.kind === 'parent') {
|
|
140
|
+
const parentId = directParentOf(store, el.expressId);
|
|
141
|
+
if (parentId === undefined)
|
|
142
|
+
return [];
|
|
143
|
+
return [{ key: `${el.modelId}:${parentId}`, label: store.entities.getName(parentId) }];
|
|
144
|
+
}
|
|
145
|
+
const subject = readSubject(requirement.groupBy.subject, { store, expressId: el.expressId });
|
|
146
|
+
if (!subject.present)
|
|
147
|
+
return [];
|
|
148
|
+
const out = [];
|
|
149
|
+
const seen = new Set();
|
|
150
|
+
for (const raw of subject.values) {
|
|
151
|
+
const s = String(raw);
|
|
152
|
+
if (s.trim().length === 0)
|
|
153
|
+
continue;
|
|
154
|
+
const key = foldKey(s, requirement.groupBy.subject.kind, caseSensitive);
|
|
155
|
+
if (seen.has(key))
|
|
156
|
+
continue;
|
|
157
|
+
seen.add(key);
|
|
158
|
+
out.push({ key, label: s });
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
/** Seed every group the `universe` block defines with an EMPTY accumulator,
|
|
163
|
+
* so a group with zero contributing members (e.g. an `IfcElementAssembly`
|
|
164
|
+
* with no `IfcPlate`) still produces a `count 0` set result that can fail —
|
|
165
|
+
* without this, that key never appears at all (plan §4.6, §11 risk). */
|
|
166
|
+
async function seedUniverse(requirement, models, storesById, caseSensitive, groups) {
|
|
167
|
+
const universe = requirement.groupBy?.universe;
|
|
168
|
+
if (!universe)
|
|
169
|
+
return;
|
|
170
|
+
const universeEls = await evaluateFilterGroupsFederated(models, universe.groups, { limit: Number.MAX_SAFE_INTEGER });
|
|
171
|
+
for (const uel of universeEls) {
|
|
172
|
+
const store = storesById.get(uel.modelId);
|
|
173
|
+
if (!store)
|
|
174
|
+
continue;
|
|
175
|
+
if (requirement.groupBy?.subject.kind === 'parent') {
|
|
176
|
+
const key = `${uel.modelId}:${uel.expressId}`;
|
|
177
|
+
if (!groups.has(key))
|
|
178
|
+
groups.set(key, newAccumulator(store.entities.getName(uel.expressId)));
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!requirement.groupBy)
|
|
182
|
+
continue;
|
|
183
|
+
const subject = readSubject(requirement.groupBy.subject, { store, expressId: uel.expressId });
|
|
184
|
+
for (const raw of subject.values) {
|
|
185
|
+
const s = String(raw);
|
|
186
|
+
if (s.trim().length === 0)
|
|
187
|
+
continue;
|
|
188
|
+
const key = foldKey(s, requirement.groupBy.subject.kind, caseSensitive);
|
|
189
|
+
if (!groups.has(key))
|
|
190
|
+
groups.set(key, newAccumulator(s));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export async function checkAggregate(requirementId, requirement, applicable, storesById, models, opts, ruleIndex, signal, onProgress) {
|
|
195
|
+
const label = `${requirement.fn}(${requirement.subject ? describeSubject(requirement.subject) : ''})`;
|
|
196
|
+
const groups = new Map();
|
|
197
|
+
await seedUniverse(requirement, models, storesById, opts.caseSensitive, groups);
|
|
198
|
+
const entityResults = [];
|
|
199
|
+
const excludedRow = (el, reason) => baseRow(el, false, {
|
|
200
|
+
requirement: { id: requirementId, label, optionality: 'required' },
|
|
201
|
+
status: 'fail', facetType: 'aggregate', checkedDescription: label,
|
|
202
|
+
failureReason: reason, actualValue: reason === 'absent' ? '""' : '(non-numeric)', expectedValue: 'numeric',
|
|
203
|
+
});
|
|
204
|
+
const accFor = (key, groupLabel) => {
|
|
205
|
+
let acc = groups.get(key);
|
|
206
|
+
if (!acc)
|
|
207
|
+
groups.set(key, (acc = newAccumulator(groupLabel)));
|
|
208
|
+
return acc;
|
|
209
|
+
};
|
|
210
|
+
for (let i = 0; i < applicable.length; i++) {
|
|
211
|
+
const el = applicable[i];
|
|
212
|
+
const store = storesById.get(el.modelId);
|
|
213
|
+
if (store) {
|
|
214
|
+
const groupKeys = groupKeysOf(requirement, el, store, opts.caseSensitive);
|
|
215
|
+
if (groupKeys.length > 0) {
|
|
216
|
+
if (requirement.fn === 'count') {
|
|
217
|
+
for (const gk of groupKeys) {
|
|
218
|
+
const acc = accFor(gk.key, gk.label);
|
|
219
|
+
acc.members.push({ modelId: el.modelId, expressId: el.expressId });
|
|
220
|
+
acc.count++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const subject = readSubject(requirement.subject, { store, expressId: el.expressId });
|
|
225
|
+
const nums = subject.present ? subject.values.map(Number).filter(Number.isFinite) : [];
|
|
226
|
+
const reason = !subject.present ? 'absent' : nums.length === 0 ? 'notNumeric' : undefined;
|
|
227
|
+
for (const gk of groupKeys) {
|
|
228
|
+
const acc = accFor(gk.key, gk.label);
|
|
229
|
+
acc.members.push({ modelId: el.modelId, expressId: el.expressId });
|
|
230
|
+
if (reason) {
|
|
231
|
+
acc.skipped++;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
acc.count++;
|
|
235
|
+
for (const n of nums) {
|
|
236
|
+
acc.sum += n;
|
|
237
|
+
if (n < acc.min)
|
|
238
|
+
acc.min = n;
|
|
239
|
+
if (n > acc.max)
|
|
240
|
+
acc.max = n;
|
|
241
|
+
}
|
|
242
|
+
if (subject.unit)
|
|
243
|
+
acc.units.add(subject.unit);
|
|
244
|
+
}
|
|
245
|
+
// One entity row per excluded ELEMENT (not per group it belongs to).
|
|
246
|
+
if (reason)
|
|
247
|
+
entityResults.push(excludedRow(el, reason));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
await maybeYieldChunk(i + 1, applicable.length, ruleIndex, signal, onProgress);
|
|
252
|
+
}
|
|
253
|
+
finalProgress(applicable.length, ruleIndex, signal, onProgress);
|
|
254
|
+
const setResults = [];
|
|
255
|
+
for (const acc of groups.values()) {
|
|
256
|
+
const value = requirement.fn === 'count' ? acc.count
|
|
257
|
+
: requirement.fn === 'sum' ? acc.sum
|
|
258
|
+
: requirement.fn === 'min' ? (acc.count > 0 ? acc.min : 0)
|
|
259
|
+
: requirement.fn === 'max' ? (acc.count > 0 ? acc.max : 0)
|
|
260
|
+
: (acc.count > 0 ? acc.sum / acc.count : 0); // avg
|
|
261
|
+
const unitMismatch = acc.units.size > 1;
|
|
262
|
+
const unitSuffix = acc.units.size === 1 ? ` ${[...acc.units][0]}` : '';
|
|
263
|
+
const passed = !unitMismatch && numericOpMatches(requirement.op, value, requirement.value, opts);
|
|
264
|
+
setResults.push({
|
|
265
|
+
kind: 'aggregate',
|
|
266
|
+
label,
|
|
267
|
+
groupKey: requirement.groupBy ? acc.keyLabel : undefined,
|
|
268
|
+
actual: unitMismatch ? `mixed units: ${[...acc.units].join(', ')}` : `${value}${unitSuffix}`,
|
|
269
|
+
expected: `${OP_LABEL[requirement.op]} ${requirement.value}`,
|
|
270
|
+
passed,
|
|
271
|
+
failureReason: passed ? undefined : (unitMismatch ? 'mismatch' : 'aggregate'),
|
|
272
|
+
skipped: acc.skipped > 0 ? acc.skipped : undefined,
|
|
273
|
+
members: acc.members,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// Counted on the FULL (pre-cap) list — see `failedElementCount`'s doc. A
|
|
277
|
+
// key set, because an element can sit in several groups (groupBy material).
|
|
278
|
+
const failedElements = new Set(entityResults.map((r) => `${r.modelId}:${r.expressId}`));
|
|
279
|
+
for (const set of setResults) {
|
|
280
|
+
if (set.passed)
|
|
281
|
+
continue;
|
|
282
|
+
for (const m of set.members)
|
|
283
|
+
failedElements.add(`${m.modelId}:${m.expressId}`);
|
|
284
|
+
}
|
|
285
|
+
orderSetResultsForCap(setResults);
|
|
286
|
+
const setResultsTruncated = setResults.length > SET_RESULT_CAP;
|
|
287
|
+
return {
|
|
288
|
+
setResults: setResults.slice(0, SET_RESULT_CAP), setResultsTruncated, entityResults,
|
|
289
|
+
failedElementCount: failedElements.size,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/** Failing groups first, then largest first. The cap slices from the front,
|
|
293
|
+
* so a failing group must never sit behind 1 000 passing ones — otherwise the
|
|
294
|
+
* truncated list is all-pass and the rule reads `pass` (review on #5160). */
|
|
295
|
+
export function orderSetResultsForCap(results) {
|
|
296
|
+
results.sort((a, b) => Number(a.passed) - Number(b.passed) || b.members.length - a.members.length);
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=rule-engine-sets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-engine-sets.js","sourceRoot":"","sources":["../../src/engine/rule-engine-sets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `unit` requirement checking (#5300): "Width is recorded in mm". Per
|
|
3
|
+
* element, like `compare`. `readSubject` reports the unit every value of a
|
|
4
|
+
* property/quantity subject is recorded in (its explicit `Unit`, else the
|
|
5
|
+
* project unit for its measure type); an element passes when the subject
|
|
6
|
+
* is present and EVERY value is recorded in the required unit.
|
|
7
|
+
*
|
|
8
|
+
* Units compare by display symbol, the one spelling the viewer shows for a
|
|
9
|
+
* unit (`mm`, `m²`), after folding the ASCII exponent spellings a person
|
|
10
|
+
* types (`m2`, `m^2`) onto the superscripts the resolver emits. Nothing
|
|
11
|
+
* else is folded: `mm` and `Mm` are different units.
|
|
12
|
+
*/
|
|
13
|
+
import type { IfcDataStore } from '@ifc-lite/parser';
|
|
14
|
+
import type { EntityResult } from '@ifc-lite/ids';
|
|
15
|
+
import type { FilteredElement } from '../filter/filter-evaluate.js';
|
|
16
|
+
import type { UnitRequirement } from '../rule-set/rule-set.js';
|
|
17
|
+
import { type RuleEngineProgress } from './rule-engine-chunk.js';
|
|
18
|
+
/** `m2` / `m^2` / `m²` all read as `m²`; everything else is compared as typed. */
|
|
19
|
+
export declare function normalizeUnitSymbol(symbol: string): string;
|
|
20
|
+
export declare function checkUnit(requirementId: string, requirement: UnitRequirement, applicable: readonly FilteredElement[], storesById: ReadonlyMap<string, IfcDataStore>, ruleIndex: number, signal: AbortSignal | undefined, onProgress: ((p: RuleEngineProgress) => void) | undefined): Promise<{
|
|
21
|
+
entityResults: EntityResult[];
|
|
22
|
+
}>;
|
|
23
|
+
//# sourceMappingURL=rule-engine-unit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-engine-unit.d.ts","sourceRoot":"","sources":["../../src/engine/rule-engine-unit.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAkC,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAIjG,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAOD,wBAAsB,SAAS,CAC7B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,eAAe,EAC5B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAAG,SAAS,GACxD,OAAO,CAAC;IAAE,aAAa,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CA6C5C"}
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { readSubject } from '../filter/read-subject.js';
|
|
5
|
+
import { baseRow, describeSubject } from './rule-engine-sets.js';
|
|
6
|
+
import { maybeYieldChunk, finalProgress } from './rule-engine-chunk.js';
|
|
7
|
+
const SUPERSCRIPT = { '2': '²', '3': '³' };
|
|
8
|
+
/** `m2` / `m^2` / `m²` all read as `m²`; everything else is compared as typed. */
|
|
9
|
+
export function normalizeUnitSymbol(symbol) {
|
|
10
|
+
return symbol.trim().replace(/([A-Za-zµ])\^?([23])(?![0-9])/g, (_, base, exp) => `${base}${SUPERSCRIPT[exp]}`);
|
|
11
|
+
}
|
|
12
|
+
/** What a value's unit reads as in a failure message. */
|
|
13
|
+
function unitLabel(unit) {
|
|
14
|
+
return unit ?? 'no unit';
|
|
15
|
+
}
|
|
16
|
+
export async function checkUnit(requirementId, requirement, applicable, storesById, ruleIndex, signal, onProgress) {
|
|
17
|
+
const wanted = normalizeUnitSymbol(requirement.unit);
|
|
18
|
+
// A blank unit is an unfinished rule, not a check every element fails:
|
|
19
|
+
// report it as the rule's error (`rule-engine.ts`'s per-rule guard).
|
|
20
|
+
if (wanted.length === 0)
|
|
21
|
+
throw new Error('the unit requirement names no unit');
|
|
22
|
+
const label = `${describeSubject(requirement.subject)} recorded in ${wanted}`;
|
|
23
|
+
const facetType = requirement.subject.kind;
|
|
24
|
+
const entityResults = [];
|
|
25
|
+
for (let i = 0; i < applicable.length; i++) {
|
|
26
|
+
const el = applicable[i];
|
|
27
|
+
const store = storesById.get(el.modelId);
|
|
28
|
+
if (!store) {
|
|
29
|
+
await maybeYieldChunk(i + 1, applicable.length, ruleIndex, signal, onProgress);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const subject = readSubject(requirement.subject, { store, expressId: el.expressId });
|
|
33
|
+
let passed = false;
|
|
34
|
+
let reason;
|
|
35
|
+
let actual = '""';
|
|
36
|
+
if (subject.present) {
|
|
37
|
+
// Only the values that are actually there: an explicitly empty label
|
|
38
|
+
// next to a real one is not a second, unit-less recording.
|
|
39
|
+
const recorded = subject.values
|
|
40
|
+
.map((value, index) => ({ value: String(value), unit: subject.valueUnits?.[index] }))
|
|
41
|
+
.filter((v) => v.value.trim().length > 0);
|
|
42
|
+
actual = recorded.map((v) => `${v.value} ${unitLabel(v.unit)}`).join('; ');
|
|
43
|
+
passed = recorded.length > 0
|
|
44
|
+
&& recorded.every((v) => v.unit !== undefined && normalizeUnitSymbol(v.unit) === wanted);
|
|
45
|
+
reason = passed ? undefined : 'mismatch';
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
reason = 'absent';
|
|
49
|
+
}
|
|
50
|
+
entityResults.push(baseRow(el, passed, {
|
|
51
|
+
requirement: { id: requirementId, label, optionality: 'required' },
|
|
52
|
+
status: passed ? 'pass' : 'fail',
|
|
53
|
+
facetType,
|
|
54
|
+
checkedDescription: label,
|
|
55
|
+
failureReason: reason,
|
|
56
|
+
actualValue: actual,
|
|
57
|
+
expectedValue: wanted,
|
|
58
|
+
}));
|
|
59
|
+
await maybeYieldChunk(i + 1, applicable.length, ruleIndex, signal, onProgress);
|
|
60
|
+
}
|
|
61
|
+
finalProgress(applicable.length, ruleIndex, signal, onProgress);
|
|
62
|
+
return { entityResults };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=rule-engine-unit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-engine-unit.js","sourceRoot":"","sources":["../../src/engine/rule-engine-unit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ValidationReport } from '@ifc-lite/ids';
|
|
2
|
+
import type { EvaluatorModel } from '../filter/filter-evaluate.js';
|
|
3
|
+
import type { RuleSetFile, RuleSetTargets } from '../rule-set/rule-set.js';
|
|
4
|
+
import { type RuleEngineProgress } from './rule-engine-chunk.js';
|
|
5
|
+
export type { RuleEngineProgress };
|
|
6
|
+
export interface RunRuleSetOptions {
|
|
7
|
+
ruleSet: RuleSetFile;
|
|
8
|
+
/** Every currently-loaded model as the evaluator sees it (#5138 PR 7a: the
|
|
9
|
+
* caller — the viewer's `evaluatorModelsFromState` or the CLI's
|
|
10
|
+
* `loadModelForDelivery` — builds this list; the engine no longer knows
|
|
11
|
+
* about a "model tag state" shape). */
|
|
12
|
+
models: ReadonlyArray<EvaluatorModel>;
|
|
13
|
+
/** Every tag id that currently exists, for `modelTag` rule resolution
|
|
14
|
+
* (plan: a rule naming a since-deleted tag is UNRESOLVED, never silently
|
|
15
|
+
* broad). Omit when the caller has no tag concept (e.g. the CLI). */
|
|
16
|
+
definedModelTagIds?: ReadonlySet<string>;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
onProgress?: (progress: RuleEngineProgress) => void;
|
|
19
|
+
}
|
|
20
|
+
/** `targets` narrows the loaded-model list to the rule set's declared
|
|
21
|
+
* default targets (plan §3: never a local model id; both lists OR'd;
|
|
22
|
+
* empty/absent = every loaded model). */
|
|
23
|
+
export declare function resolveTargetModels(models: ReadonlyArray<EvaluatorModel>, targets: RuleSetTargets | undefined): EvaluatorModel[];
|
|
24
|
+
/** Run every rule in `ruleSet` against the targeted models and return one
|
|
25
|
+
* `ValidationReport`. Rejects with `AbortError` on cancellation; the report
|
|
26
|
+
* object is constructed only after the loop completes, so a caller can
|
|
27
|
+
* never observe a partial one. */
|
|
28
|
+
export declare function runRuleSet(options: RunRuleSetOptions): Promise<ValidationReport>;
|
|
29
|
+
//# sourceMappingURL=rule-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-engine.d.ts","sourceRoot":"","sources":["../../src/engine/rule-engine.ts"],"names":[],"mappings":"AAkBA,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAKvB,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,8BAA8B,CAAC;AAGpF,OAAO,KAAK,EAA8B,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAKvG,OAAO,EAAkC,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjG,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,WAAW,CAAC;IACrB;;;4CAGwC;IACxC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACtC;;0EAEsE;IACtE,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACrD;AAED;;0CAE0C;AAC1C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,SAAS,GAAG,cAAc,EAAE,CAWhI;AA2JD;;;mCAGmC;AACnC,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuFtF"}
|