@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.
Files changed (179) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +45 -0
  3. package/dist/engine/rule-engine-chunk.d.ts +25 -0
  4. package/dist/engine/rule-engine-chunk.d.ts.map +1 -0
  5. package/dist/engine/rule-engine-chunk.js +43 -0
  6. package/dist/engine/rule-engine-chunk.js.map +1 -0
  7. package/dist/engine/rule-engine-compare.d.ts +17 -0
  8. package/dist/engine/rule-engine-compare.d.ts.map +1 -0
  9. package/dist/engine/rule-engine-compare.js +69 -0
  10. package/dist/engine/rule-engine-compare.js.map +1 -0
  11. package/dist/engine/rule-engine-requirements.d.ts +37 -0
  12. package/dist/engine/rule-engine-requirements.d.ts.map +1 -0
  13. package/dist/engine/rule-engine-requirements.js +293 -0
  14. package/dist/engine/rule-engine-requirements.js.map +1 -0
  15. package/dist/engine/rule-engine-sets.d.ts +46 -0
  16. package/dist/engine/rule-engine-sets.d.ts.map +1 -0
  17. package/dist/engine/rule-engine-sets.js +298 -0
  18. package/dist/engine/rule-engine-sets.js.map +1 -0
  19. package/dist/engine/rule-engine-unit.d.ts +23 -0
  20. package/dist/engine/rule-engine-unit.d.ts.map +1 -0
  21. package/dist/engine/rule-engine-unit.js +64 -0
  22. package/dist/engine/rule-engine-unit.js.map +1 -0
  23. package/dist/engine/rule-engine.d.ts +29 -0
  24. package/dist/engine/rule-engine.d.ts.map +1 -0
  25. package/dist/engine/rule-engine.js +244 -0
  26. package/dist/engine/rule-engine.js.map +1 -0
  27. package/dist/filter/effective-filter-fields.d.ts +13 -0
  28. package/dist/filter/effective-filter-fields.d.ts.map +1 -0
  29. package/dist/filter/effective-filter-fields.js +44 -0
  30. package/dist/filter/effective-filter-fields.js.map +1 -0
  31. package/dist/filter/entity-predefined-type.d.ts +24 -0
  32. package/dist/filter/entity-predefined-type.d.ts.map +1 -0
  33. package/dist/filter/entity-predefined-type.js +34 -0
  34. package/dist/filter/entity-predefined-type.js.map +1 -0
  35. package/dist/filter/filter-evaluate-groups.d.ts +36 -0
  36. package/dist/filter/filter-evaluate-groups.d.ts.map +1 -0
  37. package/dist/filter/filter-evaluate-groups.js +111 -0
  38. package/dist/filter/filter-evaluate-groups.js.map +1 -0
  39. package/dist/filter/filter-evaluate-model-tag.d.ts +22 -0
  40. package/dist/filter/filter-evaluate-model-tag.d.ts.map +1 -0
  41. package/dist/filter/filter-evaluate-model-tag.js +35 -0
  42. package/dist/filter/filter-evaluate-model-tag.js.map +1 -0
  43. package/dist/filter/filter-evaluate-mutations.d.ts +51 -0
  44. package/dist/filter/filter-evaluate-mutations.d.ts.map +1 -0
  45. package/dist/filter/filter-evaluate-mutations.js +111 -0
  46. package/dist/filter/filter-evaluate-mutations.js.map +1 -0
  47. package/dist/filter/filter-evaluate-yield.d.ts +9 -0
  48. package/dist/filter/filter-evaluate-yield.d.ts.map +1 -0
  49. package/dist/filter/filter-evaluate-yield.js +32 -0
  50. package/dist/filter/filter-evaluate-yield.js.map +1 -0
  51. package/dist/filter/filter-evaluate.d.ts +120 -0
  52. package/dist/filter/filter-evaluate.d.ts.map +1 -0
  53. package/dist/filter/filter-evaluate.js +408 -0
  54. package/dist/filter/filter-evaluate.js.map +1 -0
  55. package/dist/filter/filter-group-rule.d.ts +23 -0
  56. package/dist/filter/filter-group-rule.d.ts.map +1 -0
  57. package/dist/filter/filter-group-rule.js +69 -0
  58. package/dist/filter/filter-group-rule.js.map +1 -0
  59. package/dist/filter/filter-groups.d.ts +65 -0
  60. package/dist/filter/filter-groups.d.ts.map +1 -0
  61. package/dist/filter/filter-groups.js +136 -0
  62. package/dist/filter/filter-groups.js.map +1 -0
  63. package/dist/filter/filter-iteration-source.d.ts +26 -0
  64. package/dist/filter/filter-iteration-source.d.ts.map +1 -0
  65. package/dist/filter/filter-iteration-source.js +154 -0
  66. package/dist/filter/filter-iteration-source.js.map +1 -0
  67. package/dist/filter/filter-iteration.d.ts +5 -0
  68. package/dist/filter/filter-iteration.d.ts.map +1 -0
  69. package/dist/filter/filter-iteration.js +25 -0
  70. package/dist/filter/filter-iteration.js.map +1 -0
  71. package/dist/filter/filter-match.d.ts +114 -0
  72. package/dist/filter/filter-match.d.ts.map +1 -0
  73. package/dist/filter/filter-match.js +302 -0
  74. package/dist/filter/filter-match.js.map +1 -0
  75. package/dist/filter/filter-ops.d.ts +90 -0
  76. package/dist/filter/filter-ops.d.ts.map +1 -0
  77. package/dist/filter/filter-ops.js +202 -0
  78. package/dist/filter/filter-ops.js.map +1 -0
  79. package/dist/filter/filter-rule-guards.d.ts +4 -0
  80. package/dist/filter/filter-rule-guards.d.ts.map +1 -0
  81. package/dist/filter/filter-rule-guards.js +74 -0
  82. package/dist/filter/filter-rule-guards.js.map +1 -0
  83. package/dist/filter/filter-rules.d.ts +275 -0
  84. package/dist/filter/filter-rules.d.ts.map +1 -0
  85. package/dist/filter/filter-rules.js +68 -0
  86. package/dist/filter/filter-rules.js.map +1 -0
  87. package/dist/filter/lens-material-names.d.ts +13 -0
  88. package/dist/filter/lens-material-names.d.ts.map +1 -0
  89. package/dist/filter/lens-material-names.js +36 -0
  90. package/dist/filter/lens-material-names.js.map +1 -0
  91. package/dist/filter/measure-units.d.ts +29 -0
  92. package/dist/filter/measure-units.d.ts.map +1 -0
  93. package/dist/filter/measure-units.js +72 -0
  94. package/dist/filter/measure-units.js.map +1 -0
  95. package/dist/filter/model-tag.d.ts +65 -0
  96. package/dist/filter/model-tag.d.ts.map +1 -0
  97. package/dist/filter/model-tag.js +57 -0
  98. package/dist/filter/model-tag.js.map +1 -0
  99. package/dist/filter/read-measure-subject.d.ts +28 -0
  100. package/dist/filter/read-measure-subject.d.ts.map +1 -0
  101. package/dist/filter/read-measure-subject.js +116 -0
  102. package/dist/filter/read-measure-subject.js.map +1 -0
  103. package/dist/filter/read-subject.d.ts +72 -0
  104. package/dist/filter/read-subject.d.ts.map +1 -0
  105. package/dist/filter/read-subject.js +128 -0
  106. package/dist/filter/read-subject.js.map +1 -0
  107. package/dist/filter/subject-match.d.ts +27 -0
  108. package/dist/filter/subject-match.d.ts.map +1 -0
  109. package/dist/filter/subject-match.js +52 -0
  110. package/dist/filter/subject-match.js.map +1 -0
  111. package/dist/filter/subject-read-options.d.ts +33 -0
  112. package/dist/filter/subject-read-options.d.ts.map +1 -0
  113. package/dist/filter/subject-read-options.js +8 -0
  114. package/dist/filter/subject-read-options.js.map +1 -0
  115. package/dist/ids/ids-facet-to-rules.d.ts +20 -0
  116. package/dist/ids/ids-facet-to-rules.d.ts.map +1 -0
  117. package/dist/ids/ids-facet-to-rules.js +230 -0
  118. package/dist/ids/ids-facet-to-rules.js.map +1 -0
  119. package/dist/ids/ids-regex.d.ts +44 -0
  120. package/dist/ids/ids-regex.d.ts.map +1 -0
  121. package/dist/ids/ids-regex.js +334 -0
  122. package/dist/ids/ids-regex.js.map +1 -0
  123. package/dist/ids/ids-to-rule-set.d.ts +39 -0
  124. package/dist/ids/ids-to-rule-set.d.ts.map +1 -0
  125. package/dist/ids/ids-to-rule-set.js +103 -0
  126. package/dist/ids/ids-to-rule-set.js.map +1 -0
  127. package/dist/ids/ids-xml-writer.d.ts +11 -0
  128. package/dist/ids/ids-xml-writer.d.ts.map +1 -0
  129. package/dist/ids/ids-xml-writer.js +172 -0
  130. package/dist/ids/ids-xml-writer.js.map +1 -0
  131. package/dist/ids/rule-set-to-ids.d.ts +45 -0
  132. package/dist/ids/rule-set-to-ids.d.ts.map +1 -0
  133. package/dist/ids/rule-set-to-ids.js +140 -0
  134. package/dist/ids/rule-set-to-ids.js.map +1 -0
  135. package/dist/ids/rule-to-ids-facets.d.ts +52 -0
  136. package/dist/ids/rule-to-ids-facets.d.ts.map +1 -0
  137. package/dist/ids/rule-to-ids-facets.js +291 -0
  138. package/dist/ids/rule-to-ids-facets.js.map +1 -0
  139. package/dist/ids/stored-unit-scale.d.ts +15 -0
  140. package/dist/ids/stored-unit-scale.d.ts.map +1 -0
  141. package/dist/ids/stored-unit-scale.js +64 -0
  142. package/dist/ids/stored-unit-scale.js.map +1 -0
  143. package/dist/index.d.ts +39 -0
  144. package/dist/index.d.ts.map +1 -0
  145. package/dist/index.js +46 -0
  146. package/dist/index.js.map +1 -0
  147. package/dist/rule-set/between-chip.d.ts +54 -0
  148. package/dist/rule-set/between-chip.d.ts.map +1 -0
  149. package/dist/rule-set/between-chip.js +95 -0
  150. package/dist/rule-set/between-chip.js.map +1 -0
  151. package/dist/rule-set/requirement-invariants.d.ts +25 -0
  152. package/dist/rule-set/requirement-invariants.d.ts.map +1 -0
  153. package/dist/rule-set/requirement-invariants.js +29 -0
  154. package/dist/rule-set/requirement-invariants.js.map +1 -0
  155. package/dist/rule-set/requirement-text.d.ts +20 -0
  156. package/dist/rule-set/requirement-text.d.ts.map +1 -0
  157. package/dist/rule-set/requirement-text.js +179 -0
  158. package/dist/rule-set/requirement-text.js.map +1 -0
  159. package/dist/rule-set/rule-set-io-requirement.d.ts +22 -0
  160. package/dist/rule-set/rule-set-io-requirement.d.ts.map +1 -0
  161. package/dist/rule-set/rule-set-io-requirement.js +140 -0
  162. package/dist/rule-set/rule-set-io-requirement.js.map +1 -0
  163. package/dist/rule-set/rule-set-io-shared.d.ts +24 -0
  164. package/dist/rule-set/rule-set-io-shared.d.ts.map +1 -0
  165. package/dist/rule-set/rule-set-io-shared.js +48 -0
  166. package/dist/rule-set/rule-set-io-shared.js.map +1 -0
  167. package/dist/rule-set/rule-set-io-subject.d.ts +10 -0
  168. package/dist/rule-set/rule-set-io-subject.d.ts.map +1 -0
  169. package/dist/rule-set/rule-set-io-subject.js +67 -0
  170. package/dist/rule-set/rule-set-io-subject.js.map +1 -0
  171. package/dist/rule-set/rule-set-io.d.ts +37 -0
  172. package/dist/rule-set/rule-set-io.d.ts.map +1 -0
  173. package/dist/rule-set/rule-set-io.js +142 -0
  174. package/dist/rule-set/rule-set-io.js.map +1 -0
  175. package/dist/rule-set/rule-set.d.ts +109 -0
  176. package/dist/rule-set/rule-set.d.ts.map +1 -0
  177. package/dist/rule-set/rule-set.js +5 -0
  178. package/dist/rule-set/rule-set.js.map +1 -0
  179. package/package.json +59 -0
@@ -0,0 +1,293 @@
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 { combineRuleResults, } from '../filter/filter-rules.js';
5
+ import { readSubject } from '../filter/read-subject.js';
6
+ import { toSiValues } from '../filter/subject-match.js';
7
+ import { matchStringAnyNone, numericOpMatches, setOpMatches, stringOpMatches, valueOpMatches, } from '../filter/filter-ops.js';
8
+ /** Shared with `rule-engine-sets.ts` (compare/aggregate render the same
9
+ * `op` vocabulary). */
10
+ export const OP_LABEL = {
11
+ eq: '=', ne: '!=', gt: '>', gte: '>=', lt: '<', lte: '<=',
12
+ contains: 'contains', notContains: 'not contains', startsWith: 'starts with',
13
+ matches: 'matches', notMatches: 'not matches',
14
+ };
15
+ function actualOf(subject) {
16
+ // `present === false` covers BOTH a genuinely empty `values` array and one
17
+ // whose only entries are `''`/whitespace (plan §4.2's "empty string is
18
+ // absent" — an explicitly empty `IFCLABEL` renders the same `'""'` an
19
+ // outright-missing property does, not a blank string).
20
+ if (!subject.present)
21
+ return '""';
22
+ const joined = subject.values.map(String).join('; ');
23
+ return subject.unit ? `${joined} ${subject.unit}` : joined;
24
+ }
25
+ function subjectLabel(rule) {
26
+ switch (rule.kind) {
27
+ case 'property': return `${rule.setName}.${rule.propertyName}`;
28
+ case 'quantity': return `${rule.setName}.${rule.quantityName}`;
29
+ case 'attribute': return rule.name;
30
+ case 'name': return 'Name';
31
+ case 'type': return 'Type';
32
+ case 'parent': return 'Parent';
33
+ case 'material': return 'Material';
34
+ case 'classification': return rule.system ? `Classification[${rule.system}]` : 'Classification';
35
+ case 'group': return rule.groupClass ? `Group[${rule.groupClass}]` : 'Group';
36
+ case 'ifcType': return 'IfcType';
37
+ case 'predefinedType': return 'PredefinedType';
38
+ default: return rule.kind;
39
+ }
40
+ }
41
+ /** Maps a `FilterRule` kind onto the closed `CheckKind` reporting vocabulary
42
+ * (plan §5). Several kinds have no dedicated IDS facet type; the closest
43
+ * fit is used and documented here rather than invented silently:
44
+ * `attribute`/`name`/`type`/`globalId` → `attribute` (all read an IFC
45
+ * attribute), `parent` → `partOf` (bSI's containment/aggregation facet),
46
+ * `ifcType`/`predefinedType` → `entity` (bSI's entity facet covers both),
47
+ * `storey` → `spatial` (a `CheckKind`-only addition with no facet analogue). */
48
+ function checkKindOf(kind) {
49
+ switch (kind) {
50
+ case 'property': return 'property';
51
+ case 'quantity': return 'quantity';
52
+ case 'attribute':
53
+ case 'name':
54
+ case 'type':
55
+ case 'globalId':
56
+ return 'attribute';
57
+ case 'material': return 'material';
58
+ case 'classification': return 'classification';
59
+ case 'parent':
60
+ case 'group':
61
+ return 'partOf';
62
+ case 'ifcType':
63
+ case 'predefinedType':
64
+ return 'entity';
65
+ case 'storey': return 'spatial';
66
+ default: return 'attribute';
67
+ }
68
+ }
69
+ function renderExpected(rule) {
70
+ switch (rule.kind) {
71
+ case 'quantity':
72
+ return `${OP_LABEL[rule.op]} ${rule.value}`;
73
+ case 'property':
74
+ case 'attribute':
75
+ case 'name':
76
+ case 'type':
77
+ case 'parent':
78
+ case 'material':
79
+ case 'classification':
80
+ case 'group':
81
+ return `${OP_LABEL[rule.op] ?? rule.op} ${'value' in rule ? rule.value : ''}`;
82
+ case 'ifcType':
83
+ case 'predefinedType':
84
+ return `${rule.op === 'in' ? 'in' : 'not in'} [${rule.values.join(', ')}]`;
85
+ default:
86
+ return 'op' in rule ? String(rule.op) : '';
87
+ }
88
+ }
89
+ function isElementRule(rule) {
90
+ switch (rule.kind) {
91
+ case 'property':
92
+ case 'quantity':
93
+ case 'attribute':
94
+ case 'name':
95
+ case 'type':
96
+ case 'parent':
97
+ case 'material':
98
+ case 'classification':
99
+ case 'ifcType':
100
+ case 'predefinedType':
101
+ case 'group':
102
+ return true;
103
+ default:
104
+ return false;
105
+ }
106
+ }
107
+ function checkFilterRule(rule, ctx, opts) {
108
+ // `valueUnit: 'si'` (#5225): compare SI values, the same reading search uses.
109
+ const subject = (rule.kind === 'property' || rule.kind === 'quantity') && rule.valueUnit === 'si'
110
+ ? toSiValues(readSubject(rule, ctx))
111
+ : readSubject(rule, ctx);
112
+ const facetType = checkKindOf(rule.kind);
113
+ const label = subjectLabel(rule);
114
+ const actual = actualOf(subject);
115
+ if (rule.op === 'isSet' || rule.op === 'isNotSet') {
116
+ const passed = rule.op === 'isSet' ? subject.present : !subject.present;
117
+ const expected = rule.op === 'isSet' ? 'is set' : 'is not set';
118
+ return { passed, reason: passed ? undefined : 'absent', actual, expected, facetType, checkedDescription: `${label} ${expected}` };
119
+ }
120
+ const expected = renderExpected(rule);
121
+ const checkedDescription = `${label} ${expected}`;
122
+ if (!subject.present) {
123
+ return { passed: false, reason: 'absent', actual, expected, facetType, checkedDescription };
124
+ }
125
+ switch (rule.kind) {
126
+ case 'quantity': {
127
+ const nums = subject.values.map(Number).filter(Number.isFinite);
128
+ if (nums.length === 0)
129
+ return { passed: false, reason: 'notNumeric', actual, expected, facetType, checkedDescription };
130
+ const passed = nums.some((v) => numericOpMatches(rule.op, v, rule.value, opts));
131
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
132
+ }
133
+ case 'property':
134
+ case 'attribute':
135
+ return checkValueOp(rule, subject, opts, facetType, actual, expected, checkedDescription);
136
+ case 'ifcType':
137
+ case 'predefinedType': {
138
+ const candidate = String(subject.values[0] ?? '');
139
+ const passed = setOpMatches(rule.op, candidate, rule.values, opts);
140
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
141
+ }
142
+ default: {
143
+ // name | type | parent | material | classification | group — StringOp (or the
144
+ // StringOp-compatible subset of ClassificationOp); multi-valued
145
+ // subjects (parent/material) match ANY for a positive op, NONE for a
146
+ // negative one, via the same convention search already uses.
147
+ const candidates = subject.values.map(String);
148
+ const passed = matchStringAnyNone(rule.op, candidates, rule.value, rule.valueKind, opts);
149
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
150
+ }
151
+ }
152
+ }
153
+ function checkValueOp(rule, subject, opts, facetType, actual, expected, checkedDescription) {
154
+ const strVals = subject.values.map(String);
155
+ const op = rule.op;
156
+ if (op === 'gt' || op === 'gte' || op === 'lt' || op === 'lte') {
157
+ // Strict `Number(...)`, not `Number.parseFloat` — plan §4 item 4 requires
158
+ // a "finite f64", and `parseFloat('2HR')` (== 2) would silently accept a
159
+ // fire-rating STRING as a number instead of reporting `notNumeric`.
160
+ const rv = Number(rule.value);
161
+ const nums = strVals.map((v) => Number(v)).filter(Number.isFinite);
162
+ if (!Number.isFinite(rv) || nums.length === 0) {
163
+ return { passed: false, reason: 'notNumeric', actual, expected, facetType, checkedDescription };
164
+ }
165
+ const passed = nums.some((cv) => numericOpMatches(op, cv, rv, opts));
166
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
167
+ }
168
+ if (op === 'eq' || op === 'ne') {
169
+ const rv = Number(rule.value);
170
+ const nums = strVals.map((v) => Number(v));
171
+ const allFinite = Number.isFinite(rv) && nums.length > 0 && nums.every(Number.isFinite);
172
+ const matchAny = allFinite
173
+ ? nums.some((cv) => numericOpMatches('eq', cv, rv, opts))
174
+ : strVals.some((v) => stringOpMatches('eq', v, rule.value, undefined, opts));
175
+ const passed = op === 'eq' ? matchAny : !matchAny;
176
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
177
+ }
178
+ // contains / notContains / matches / notMatches
179
+ const posOp = op === 'notContains' ? 'contains' : op === 'notMatches' ? 'matches' : op;
180
+ const anyPositive = strVals.some((v) => valueOpMatches(posOp, v, rule.value, rule.valueKind, opts));
181
+ const passed = posOp === op ? anyPositive : !anyPositive;
182
+ return { passed, reason: passed ? undefined : 'mismatch', actual, expected, facetType, checkedDescription };
183
+ }
184
+ function subjectKey(rule) {
185
+ switch (rule.kind) {
186
+ case 'quantity': return `quantity:${rule.setName}:${rule.quantityName}`;
187
+ case 'property': return `property:${rule.setName}:${rule.propertyName}`;
188
+ case 'attribute': return `attribute:${rule.name}`;
189
+ default: return null;
190
+ }
191
+ }
192
+ function foldBetweenPairs(rules) {
193
+ const used = new Set();
194
+ const out = [];
195
+ for (let i = 0; i < rules.length; i++) {
196
+ if (used.has(i))
197
+ continue;
198
+ const a = rules[i];
199
+ const keyA = subjectKey(a);
200
+ const opA = 'op' in a ? a.op : undefined;
201
+ if (keyA && (opA === 'gte' || opA === 'lte')) {
202
+ for (let j = i + 1; j < rules.length; j++) {
203
+ if (used.has(j))
204
+ continue;
205
+ const b = rules[j];
206
+ if (subjectKey(b) !== keyA)
207
+ continue;
208
+ const opB = 'op' in b ? b.op : undefined;
209
+ if ((opA === 'gte' && opB === 'lte') || (opA === 'lte' && opB === 'gte')) {
210
+ used.add(i);
211
+ used.add(j);
212
+ out.push({ kind: 'between', low: opA === 'gte' ? a : b, high: opA === 'lte' ? a : b });
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ for (let i = 0; i < rules.length; i++)
219
+ if (!used.has(i))
220
+ out.push(rules[i]);
221
+ return out;
222
+ }
223
+ function evaluateBetween(pair, ctx, opts) {
224
+ const low = checkFilterRule(pair.low, ctx, opts);
225
+ const high = checkFilterRule(pair.high, ctx, opts);
226
+ const passed = low.passed && high.passed;
227
+ const label = subjectLabel(pair.low);
228
+ const lowVal = 'value' in pair.low ? pair.low.value : '';
229
+ const highVal = 'value' in pair.high ? pair.high.value : '';
230
+ const expected = `>= ${lowVal} and <= ${highVal}`;
231
+ return {
232
+ passed,
233
+ reason: passed ? undefined : (low.reason ?? high.reason),
234
+ actual: low.actual,
235
+ expected,
236
+ facetType: low.facetType,
237
+ checkedDescription: `${label} ${expected}`,
238
+ };
239
+ }
240
+ function evaluateGroup(group, ctx, opts) {
241
+ const elementRules = group.rules.filter(isElementRule);
242
+ if (elementRules.length !== group.rules.length) {
243
+ throw new Error(`rule-engine: applicability-only rule kind used in an element requirement (group has ${group.rules.length - elementRules.length} such rule(s))`);
244
+ }
245
+ // `between` is a gte+lte pair AND'd on the identical subject (plan §5's
246
+ // operator table) — only a shorthand within an AND group. In an OR group
247
+ // the two rules are independent alternatives (`Width >= 0.25` OR `Width
248
+ // <= 0.35` — 0.20 satisfies the second on its own), so folding them would
249
+ // silently require BOTH, changing what the group matches (review finding).
250
+ const items = group.combinator === 'AND' ? foldBetweenPairs(elementRules) : elementRules;
251
+ const outcomes = items.map((item) => 'kind' in item && item.kind === 'between' ? evaluateBetween(item, ctx, opts) : checkFilterRule(item, ctx, opts));
252
+ if (outcomes.length === 0)
253
+ return { passed: false, failingCount: 0, representative: { passed: false, actual: '', expected: '', facetType: 'attribute', checkedDescription: 'empty group' } };
254
+ const passed = combineRuleResults(group.combinator, outcomes.map((o) => o.passed));
255
+ const failingCount = outcomes.filter((o) => !o.passed).length;
256
+ const representative = outcomes.find((o) => !o.passed) ?? outcomes[0];
257
+ return { passed, failingCount, representative };
258
+ }
259
+ /**
260
+ * Check one applicable element against `block` (plan §4.4). `requirementId`/
261
+ * `requirementLabel` seed the singular `requirementResults[0]` every entity
262
+ * row carries — the rule's own id/name, since one `InformationRule`'s
263
+ * `element` requirement is ONE requirement, not one per underlying
264
+ * `FilterRule` (a `between` pair, or several AND'd rules in a group, are
265
+ * still a single pass/fail question).
266
+ */
267
+ export function checkElementForEntity(requirementId, block, el, store, opts) {
268
+ const ctx = { store, expressId: el.expressId };
269
+ const groupOutcomes = block.groups.map((g) => evaluateGroup(g, ctx, opts));
270
+ const passedGroup = groupOutcomes.find((g) => g.passed);
271
+ const chosen = passedGroup
272
+ ?? groupOutcomes.reduce((best, g) => (g.failingCount < best.failingCount ? g : best), groupOutcomes[0]);
273
+ const passed = !!passedGroup;
274
+ const requirementResult = {
275
+ requirement: { id: requirementId, label: chosen.representative.checkedDescription, optionality: 'required' },
276
+ status: passed ? 'pass' : 'fail',
277
+ facetType: chosen.representative.facetType,
278
+ checkedDescription: chosen.representative.checkedDescription,
279
+ failureReason: passed ? undefined : chosen.representative.reason,
280
+ actualValue: chosen.representative.actual,
281
+ expectedValue: chosen.representative.expected,
282
+ };
283
+ return {
284
+ expressId: el.expressId,
285
+ modelId: el.modelId,
286
+ entityType: el.ifcType,
287
+ entityName: el.name || undefined,
288
+ globalId: el.globalId,
289
+ passed,
290
+ requirementResults: [requirementResult],
291
+ };
292
+ }
293
+ //# sourceMappingURL=rule-engine-requirements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-engine-requirements.js","sourceRoot":"","sources":["../../src/engine/rule-engine-requirements.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Set-level requirement checking (#5138 PR 3) — `unique` (plan §4.5) and
3
+ * `aggregate` (§4.6). Unlike `element` (per-entity, `rule-engine-
4
+ * requirements.ts`), these produce `SetResult`s describing a GROUP of
5
+ * entities. `compare` (§4.7) is per-entity like `element`, not a set kind —
6
+ * it lives in `rule-engine-compare.ts` (split out once this file crossed the
7
+ * module-size budget), reusing `describeSubject`/`baseRow` from here.
8
+ */
9
+ import type { IfcDataStore } from '@ifc-lite/parser';
10
+ import type { EntityResult, RequirementResult, SetResult } from '@ifc-lite/ids';
11
+ import type { FilteredElement, EvaluatorModel } from '../filter/filter-evaluate.js';
12
+ import type { Subject, UniqueRequirement, AggregateRequirement } from '../rule-set/rule-set.js';
13
+ import { type ValidationOpts } from './rule-engine-requirements.js';
14
+ import { type RuleEngineProgress } from './rule-engine-chunk.js';
15
+ /** Shared with `rule-engine-compare.ts` (same `Subject` label rendering). */
16
+ export declare function describeSubject(subject: Subject): string;
17
+ /** Shared with `rule-engine-compare.ts`. */
18
+ export declare function baseRow(el: FilteredElement, passed: boolean, result: RequirementResult): EntityResult;
19
+ /** The shape every requirement-kind checker returns, folded by
20
+ * `rule-engine.ts`'s `finalizeSpecification`. `setResults`/
21
+ * `setResultsTruncated` are optional — `element`/`compare` never populate
22
+ * them (they are per-entity kinds, not set kinds). */
23
+ export interface SetCheckOutcome {
24
+ entityResults: EntityResult[];
25
+ setResults?: SetResult[];
26
+ setResultsTruncated?: boolean;
27
+ /**
28
+ * `aggregate` only (#5177): the number of DISTINCT applicable elements that
29
+ * fail the rule, i.e. every element excluded for an absent/non-numeric
30
+ * subject plus every member of a group whose aggregate fails — the same
31
+ * attribution `checkUnique` makes by giving every duplicate member a
32
+ * failing row. `checkAggregate` does not emit a row per failing-group
33
+ * member (a whole federation's worth of rows for no reporting value), so
34
+ * `entityResults` alone under-counts; this is the count it would have had.
35
+ * Taken on the full, pre-cap `setResults`, so it stays exact when
36
+ * `setResultsTruncated` is true.
37
+ */
38
+ failedElementCount?: number;
39
+ }
40
+ export declare function checkUnique(requirementId: string, requirement: UniqueRequirement, applicable: readonly FilteredElement[], storesById: ReadonlyMap<string, IfcDataStore>, opts: ValidationOpts, ruleIndex: number, signal: AbortSignal | undefined, onProgress: ((p: RuleEngineProgress) => void) | undefined): Promise<SetCheckOutcome>;
41
+ export declare function checkAggregate(requirementId: string, requirement: AggregateRequirement, applicable: readonly FilteredElement[], storesById: ReadonlyMap<string, IfcDataStore>, models: ReadonlyArray<EvaluatorModel>, opts: ValidationOpts, ruleIndex: number, signal: AbortSignal | undefined, onProgress: ((p: RuleEngineProgress) => void) | undefined): Promise<SetCheckOutcome>;
42
+ /** Failing groups first, then largest first. The cap slices from the front,
43
+ * so a failing group must never sit behind 1 000 passing ones — otherwise the
44
+ * truncated list is all-pass and the rule reads `pass` (review on #5160). */
45
+ export declare function orderSetResultsForCap(results: SetResult[]): void;
46
+ //# sourceMappingURL=rule-engine-sets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-engine-sets.d.ts","sourceRoot":"","sources":["../../src/engine/rule-engine-sets.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAqB,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAInG,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEpF,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAkC,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAIjG,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CASxD;AAeD,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAUrG;AAID;;;uDAGuD;AACvD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,iBAAiB,EAC9B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7C,IAAI,EAAE,cAAc,EACpB,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,eAAe,CAAC,CAmE1B;AAiGD,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,oBAAoB,EACjC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7C,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,IAAI,EAAE,cAAc,EACpB,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,eAAe,CAAC,CAqF1B;AAED;;8EAE8E;AAC9E,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAEhE"}