@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,244 @@
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 { exactTypeName } from '@ifc-lite/data';
5
+ import { calculateSummary, } from '@ifc-lite/ids';
6
+ import { setOpMatches } from '../filter/filter-ops.js';
7
+ import { evaluateFilterGroupsFederated } from '../filter/filter-evaluate-groups.js';
8
+ import { throwAbort } from '../filter/filter-evaluate-yield.js';
9
+ import { checkElementForEntity } from './rule-engine-requirements.js';
10
+ import { checkAggregate, checkUnique } from './rule-engine-sets.js';
11
+ import { checkCompare } from './rule-engine-compare.js';
12
+ import { checkUnit } from './rule-engine-unit.js';
13
+ import { maybeYieldChunk, finalProgress } from './rule-engine-chunk.js';
14
+ /** `targets` narrows the loaded-model list to the rule set's declared
15
+ * default targets (plan §3: never a local model id; both lists OR'd;
16
+ * empty/absent = every loaded model). */
17
+ export function resolveTargetModels(models, targets) {
18
+ const fingerprints = targets?.modelFingerprints ?? [];
19
+ const tagIds = targets?.modelTagIds ?? [];
20
+ if (fingerprints.length === 0 && tagIds.length === 0)
21
+ return [...models];
22
+ const fpSet = new Set(fingerprints);
23
+ const tagSet = new Set(tagIds);
24
+ return models.filter((m) => {
25
+ if (fpSet.size > 0 && m.filterIdentity !== undefined && fpSet.has(m.filterIdentity))
26
+ return true;
27
+ if (tagSet.size > 0 && m.tagIds)
28
+ for (const t of m.tagIds)
29
+ if (tagSet.has(t))
30
+ return true;
31
+ return false;
32
+ });
33
+ }
34
+ function buildModelInfo(models) {
35
+ const out = [];
36
+ for (const m of models) {
37
+ if (!m.store)
38
+ continue;
39
+ out.push({
40
+ modelId: m.id,
41
+ schemaVersion: m.store.schemaVersion || 'IFC4',
42
+ entityCount: m.store.entityCount || m.store.entities.count,
43
+ });
44
+ }
45
+ return out;
46
+ }
47
+ /** Every `exactClass`-flagged `ifcType` rule in an applicability block (plan
48
+ * §2 row "Class inheritance", §4 item 1 last sentence). Scoped to the WHOLE
49
+ * block rather than per-`FilterGroup` — a rule authoring `exactClass` on one
50
+ * OR-branch and not another is not a shape the editor (PR 5) offers, so a
51
+ * whole-rule post-filter is the closest correct reading, not a narrowing of
52
+ * an actually-supported shape (documented here per the brief's "closest
53
+ * correct thing" instruction rather than left unhandled). */
54
+ function exactClassRulesOf(block) {
55
+ const out = [];
56
+ for (const group of block.groups) {
57
+ for (const rule of group.rules) {
58
+ if (rule.kind === 'ifcType' && rule.exactClass)
59
+ out.push(rule);
60
+ }
61
+ }
62
+ return out;
63
+ }
64
+ function applyExactClassFilter(elements, rules, storesById, opts) {
65
+ if (rules.length === 0)
66
+ return [...elements];
67
+ return elements.filter((el) => {
68
+ const store = storesById.get(el.modelId);
69
+ if (!store)
70
+ return false;
71
+ const exact = exactTypeName(store.entities, el.expressId);
72
+ return rules.some((r) => setOpMatches(r.op, exact, r.values, opts));
73
+ });
74
+ }
75
+ function checkCardinality(cardinality, count) {
76
+ if (!cardinality || (cardinality.minApplicable === undefined && cardinality.maxApplicable === undefined)) {
77
+ return undefined;
78
+ }
79
+ const messages = [];
80
+ let passed = true;
81
+ if (cardinality.minApplicable !== undefined && count < cardinality.minApplicable) {
82
+ passed = false;
83
+ messages.push(`expected at least ${cardinality.minApplicable}, found ${count}`);
84
+ }
85
+ if (cardinality.maxApplicable !== undefined && count > cardinality.maxApplicable) {
86
+ passed = false;
87
+ messages.push(`expected at most ${cardinality.maxApplicable}, found ${count}`);
88
+ }
89
+ return {
90
+ passed,
91
+ actualCount: count,
92
+ minExpected: cardinality.minApplicable,
93
+ maxExpected: cardinality.maxApplicable,
94
+ message: messages.length > 0 ? messages.join('; ') : 'Cardinality satisfied',
95
+ };
96
+ }
97
+ async function runElementRequirement(ruleId, block, applicable, storesById, opts, ruleIndex, signal, onProgress) {
98
+ const out = [];
99
+ for (let i = 0; i < applicable.length; i++) {
100
+ const el = applicable[i];
101
+ const store = storesById.get(el.modelId);
102
+ if (store)
103
+ out.push(checkElementForEntity(ruleId, block, el, store, opts));
104
+ await maybeYieldChunk(i + 1, applicable.length, ruleIndex, signal, onProgress);
105
+ }
106
+ finalProgress(applicable.length, ruleIndex, signal, onProgress);
107
+ return out;
108
+ }
109
+ function finalizeSpecification(rule, applicableCount, cardinalityResult, outcome, error) {
110
+ const specification = { id: rule.id, name: rule.name, description: rule.description };
111
+ if (error !== undefined) {
112
+ // Existing IDS convention (`packages/ids/src/report-types.ts`'s
113
+ // `SpecificationResult.error` doc): an unevaluable rule is `status:
114
+ // 'fail'` with `error` set, never silently folded into `pass`.
115
+ return {
116
+ specification, status: 'fail', applicableCount, passedCount: 0, failedCount: 0, passRate: 0,
117
+ entityResults: [], error,
118
+ };
119
+ }
120
+ const failedEntities = outcome.entityResults.filter((e) => !e.passed).length;
121
+ const passedEntities = outcome.entityResults.filter((e) => e.passed).length;
122
+ const setsFail = (outcome.setResults ?? []).some((s) => !s.passed);
123
+ // `element`/`compare`/`unit` report every applicable entity (pass and fail), so
124
+ // their counts read straight off `entityResults`. `unique`/`aggregate`
125
+ // only ever construct FAILING rows (plan §4.5/§4.6 — a whole federation's
126
+ // worth of passing rows would dwarf the report for no reporting value),
127
+ // so their `passedCount` is the complement against `applicableCount`.
128
+ //
129
+ // `aggregate` is the exception to "rows are complete for failures": it
130
+ // emits no row for a member of a group that fails on its aggregate value
131
+ // (none at all for `fn: 'count'`), so it reports the distinct failing
132
+ // element count alongside (#5177). Reading `failedEntities` there left a
133
+ // failing aggregate rule at `failedCount: 0` / `passRate: 100`.
134
+ const isPerElementKind = rule.requirement.kind === 'element' || rule.requirement.kind === 'compare'
135
+ || rule.requirement.kind === 'unit';
136
+ const failedCount = outcome.failedElementCount ?? failedEntities;
137
+ const passedCount = isPerElementKind ? passedEntities : Math.max(0, applicableCount - failedCount);
138
+ const anyFail = failedCount > 0 || setsFail || cardinalityResult?.passed === false;
139
+ // With zero applicable elements a `universe`-seeded aggregate group can
140
+ // still fail (every assembly has 0 plates), so `setsFail` counts here too.
141
+ const status = applicableCount === 0
142
+ ? (cardinalityResult?.passed === false || setsFail ? 'fail' : cardinalityResult?.passed === true ? 'pass' : 'not_applicable')
143
+ : (anyFail ? 'fail' : 'pass');
144
+ // A failure no applicable element carries — an unmet/exceeded cardinality,
145
+ // or an aggregate group seeded by `universe` with zero members — leaves the
146
+ // element arithmetic at 100 (or has nothing to rate). `status` and
147
+ // `passRate` must never disagree, so a failing spec never reads 100: the
148
+ // same rule `@ifc-lite/ids`'s `validateSpecification` applies (#5212).
149
+ const elementRate = applicableCount > 0 ? Math.floor((passedCount / applicableCount) * 100) : 100;
150
+ const passRate = status === 'fail' && elementRate === 100 ? 0 : elementRate;
151
+ return {
152
+ specification, status, applicableCount, passedCount, failedCount, passRate,
153
+ entityResults: outcome.entityResults,
154
+ cardinalityResult,
155
+ setResults: outcome.setResults,
156
+ setResultsTruncated: outcome.setResultsTruncated,
157
+ };
158
+ }
159
+ /** Run every rule in `ruleSet` against the targeted models and return one
160
+ * `ValidationReport`. Rejects with `AbortError` on cancellation; the report
161
+ * object is constructed only after the loop completes, so a caller can
162
+ * never observe a partial one. */
163
+ export async function runRuleSet(options) {
164
+ const { ruleSet, models, definedModelTagIds, signal, onProgress } = options;
165
+ const targetModels = resolveTargetModels(models, ruleSet.targets);
166
+ const storesById = new Map();
167
+ for (const m of targetModels)
168
+ if (m.store)
169
+ storesById.set(m.id, m.store);
170
+ const modelInfo = buildModelInfo(targetModels);
171
+ // A rule set that DECLARES targets (`modelFingerprints`/`modelTagIds`) but
172
+ // resolves to zero loaded models is a MISMATCH, not an empty applicable
173
+ // set (#5138 PR 7b review): every model tag id or fingerprint is opaque
174
+ // and unresolved-by-construction (`Subject` §3), so this is exactly as
175
+ // likely to mean "the caller's `filterIdentity`/tag set doesn't match
176
+ // what the rule set was authored against" as "no targeted model happens
177
+ // to be loaded right now" — and a silent `not_applicable` pass reads as
178
+ // a clean report either way. Every rule is unevaluable, not vacuously
179
+ // satisfied, so every rule reports `error`, the same convention
180
+ // `finalizeSpecification` already uses for an exception mid-evaluation.
181
+ const targetsDeclared = (ruleSet.targets?.modelFingerprints?.length ?? 0) > 0 || (ruleSet.targets?.modelTagIds?.length ?? 0) > 0;
182
+ const targetsUnresolved = targetsDeclared && targetModels.length === 0;
183
+ const specificationResults = [];
184
+ for (let ruleIndex = 0; ruleIndex < ruleSet.rules.length; ruleIndex++) {
185
+ if (signal?.aborted)
186
+ throwAbort(signal);
187
+ const rule = ruleSet.rules[ruleIndex];
188
+ const opts = { caseSensitive: rule.caseSensitive ?? true, tolerance: rule.tolerance ?? 1e-6 };
189
+ if (targetsUnresolved) {
190
+ specificationResults.push(finalizeSpecification(rule, 0, undefined, { entityResults: [] }, 'no loaded model matches the rule set targets'));
191
+ continue;
192
+ }
193
+ // Tracked outside the `try` so the `catch` can report the REAL applicable
194
+ // count when applicability itself succeeded and only the requirement
195
+ // check threw — `0` is reserved for when applicability never resolved.
196
+ let applicableCount = 0;
197
+ try {
198
+ const applicableRaw = await evaluateFilterGroupsFederated(targetModels, rule.applicability.groups, {
199
+ limit: Number.MAX_SAFE_INTEGER,
200
+ signal,
201
+ definedModelTagIds,
202
+ onProgress: (done, total) => onProgress?.({ ruleIndex, phase: 'applicability', done, total }),
203
+ });
204
+ const applicable = applyExactClassFilter(applicableRaw, exactClassRulesOf(rule.applicability), storesById, opts);
205
+ applicableCount = applicable.length;
206
+ const cardinalityResult = checkCardinality(rule.cardinality, applicableCount);
207
+ let outcome;
208
+ switch (rule.requirement.kind) {
209
+ case 'element': {
210
+ const entityResults = await runElementRequirement(rule.id, rule.requirement.block, applicable, storesById, opts, ruleIndex, signal, onProgress);
211
+ outcome = { entityResults };
212
+ break;
213
+ }
214
+ case 'unique':
215
+ outcome = await checkUnique(rule.id, rule.requirement, applicable, storesById, opts, ruleIndex, signal, onProgress);
216
+ break;
217
+ case 'aggregate':
218
+ outcome = await checkAggregate(rule.id, rule.requirement, applicable, storesById, targetModels, opts, ruleIndex, signal, onProgress);
219
+ break;
220
+ case 'compare':
221
+ outcome = await checkCompare(rule.id, rule.requirement, applicable, storesById, opts, ruleIndex, signal, onProgress);
222
+ break;
223
+ case 'unit':
224
+ outcome = await checkUnit(rule.id, rule.requirement, applicable, storesById, ruleIndex, signal, onProgress);
225
+ break;
226
+ }
227
+ specificationResults.push(finalizeSpecification(rule, applicableCount, cardinalityResult, outcome));
228
+ }
229
+ catch (err) {
230
+ if (err instanceof DOMException && err.name === 'AbortError')
231
+ throw err;
232
+ const message = err instanceof Error ? err.message : String(err);
233
+ specificationResults.push(finalizeSpecification(rule, applicableCount, undefined, { entityResults: [] }, message));
234
+ }
235
+ }
236
+ return {
237
+ source: { kind: 'rules', ruleSet: { name: ruleSet.name, description: ruleSet.description } },
238
+ modelInfo,
239
+ timestamp: new Date(),
240
+ summary: calculateSummary(specificationResults),
241
+ specificationResults,
242
+ };
243
+ }
244
+ //# sourceMappingURL=rule-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-engine.js","sourceRoot":"","sources":["../../src/engine/rule-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type EffectiveEntityRecord, type IfcDataStore } from '@ifc-lite/parser';
2
+ import type { MutablePropertyView } from '@ifc-lite/mutations';
3
+ import type { FilteredElement } from './filter-evaluate.js';
4
+ export interface EffectiveFilterFields {
5
+ ifcType: string;
6
+ name: string | undefined;
7
+ globalId: string;
8
+ }
9
+ export declare function createdFilterRecord(store: IfcDataStore, view: MutablePropertyView | undefined, expressId: number): EffectiveEntityRecord | null;
10
+ /** The same class and root values export will write for a live filter result. */
11
+ export declare function effectiveFilterFields(store: IfcDataStore, view: MutablePropertyView | undefined, expressId: number): EffectiveFilterFields;
12
+ export declare function buildFilterResult(modelId: string, expressId: number, fields: EffectiveFilterFields): FilteredElement;
13
+ //# sourceMappingURL=effective-filter-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-filter-fields.d.ts","sourceRoot":"","sources":["../../src/filter/effective-filter-fields.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsD,KAAK,qBAAqB,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrI,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,mBAAmB,GAAG,SAAS,EACrC,SAAS,EAAE,MAAM,GAChB,qBAAqB,GAAG,IAAI,CAQ9B;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,mBAAmB,GAAG,SAAS,EACrC,SAAS,EAAE,MAAM,GAChB,qBAAqB,CAmBvB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAQpH"}
@@ -0,0 +1,44 @@
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 { normalizeIfcTypeName, resolveEffectiveEntityRecord } from '@ifc-lite/parser';
5
+ export function createdFilterRecord(store, view, expressId) {
6
+ const created = view?.getNewEntity(expressId);
7
+ if (!created || !view)
8
+ return null;
9
+ return resolveEffectiveEntityRecord(created, {
10
+ retype: view.getEntityTypeMutation(expressId)?.newType,
11
+ named: view.getAttributeMutationsForEntity(expressId).map(({ name, value }) => [name, value]),
12
+ positional: view.getPositionalMutationsForEntity(expressId) ?? [],
13
+ }, store.schemaVersion);
14
+ }
15
+ /** The same class and root values export will write for a live filter result. */
16
+ export function effectiveFilterFields(store, view, expressId) {
17
+ const record = createdFilterRecord(store, view, expressId);
18
+ if (record) {
19
+ const value = (name) => {
20
+ const index = record.names.indexOf(name);
21
+ const raw = index < 0 ? undefined : record.attributes[index];
22
+ return typeof raw === 'string' && raw !== '$' ? raw : undefined;
23
+ };
24
+ return { ifcType: record.type, name: value('Name'), globalId: value('GlobalId') ?? '' };
25
+ }
26
+ const retype = view?.getEntityTypeMutation(expressId)?.newType;
27
+ const edits = view?.getAttributeMutationsForEntity(expressId);
28
+ const edited = (name) => edits?.find((entry) => entry.name === name)?.value;
29
+ return {
30
+ ifcType: retype ? normalizeIfcTypeName(retype) : store.entities.getTypeName(expressId),
31
+ name: edited('Name') ?? store.entities.getNameOrUndefined(expressId),
32
+ globalId: edited('GlobalId') ?? store.entities.getGlobalId(expressId),
33
+ };
34
+ }
35
+ export function buildFilterResult(modelId, expressId, fields) {
36
+ return {
37
+ modelId,
38
+ expressId,
39
+ ifcType: fields.ifcType,
40
+ name: fields.name ?? '',
41
+ globalId: fields.globalId,
42
+ };
43
+ }
44
+ //# sourceMappingURL=effective-filter-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-filter-fields.js","sourceRoot":"","sources":["../../src/filter/effective-filter-fields.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAiD,MAAM,kBAAkB,CAAC;AAUrI,MAAM,UAAU,mBAAmB,CACjC,KAAmB,EACnB,IAAqC,EACrC,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,4BAA4B,CAAC,OAAO,EAAE;QAC3C,MAAM,EAAE,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,OAAO;QACtD,KAAK,EAAE,IAAI,CAAC,8BAA8B,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC;QACtG,UAAU,EAAE,IAAI,CAAC,+BAA+B,CAAC,SAAS,CAAC,IAAI,EAAE;KAClE,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;AAC1B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,qBAAqB,CACnC,KAAmB,EACnB,IAAqC,EACrC,SAAiB;IAEjB,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3D,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,CAAC,IAAY,EAAsB,EAAE;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC7D,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QAClE,CAAC,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;IAC1F,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,CAAC,IAAY,EAAsB,EAAE,CAClD,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,CAAC;IACrD,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC;QACtF,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,SAAS,CAAC;QACpE,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC;KACtE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,SAAiB,EAAE,MAA6B;IACjG,OAAO;QACL,OAAO;QACP,SAAS;QACT,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type IfcDataStore } from '@ifc-lite/parser';
2
+ /**
3
+ * Pick the `PredefinedType` value out of the schema-named attribute pairs
4
+ * returned by {@link extractAllEntityAttributes}. The extractor already strips
5
+ * the STEP enum markers (`.FLOOR.` → `FLOOR`), so this returns the display
6
+ * token (e.g. `"FLOOR"`, `"FLOORING"`, `"USERDEFINED"`, `"NOTDEFINED"`).
7
+ * Returns `undefined` when the slot is absent or empty so callers can ghost /
8
+ * skip elements that carry no PredefinedType.
9
+ */
10
+ export declare function pickPredefinedType(attrs: ReadonlyArray<{
11
+ name: string;
12
+ value: string | number | boolean;
13
+ }>): string | undefined;
14
+ /**
15
+ * Resolve an entity's IFC `PredefinedType` (e.g. `IfcSlab.FLOOR`,
16
+ * `IfcCovering.FLOORING`) from the source buffer. Schema-driven, so it works
17
+ * for any product type whose attribute layout the registry knows. (#1364)
18
+ *
19
+ * Like `Tag` and the property / quantity auto-color sources, this re-parses
20
+ * the entity on demand — there is no columnar PredefinedType accessor — which
21
+ * is the same cost class as those existing per-entity attribute reads.
22
+ */
23
+ export declare function resolveEntityPredefinedType(store: IfcDataStore, expressId: number): string | undefined;
24
+ //# sourceMappingURL=entity-predefined-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-predefined-type.d.ts","sourceRoot":"","sources":["../../src/filter/entity-predefined-type.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,GACvE,MAAM,GAAG,SAAS,CAKpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAGpB"}
@@ -0,0 +1,34 @@
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 { extractAllEntityAttributes } from '@ifc-lite/parser';
5
+ /**
6
+ * Pick the `PredefinedType` value out of the schema-named attribute pairs
7
+ * returned by {@link extractAllEntityAttributes}. The extractor already strips
8
+ * the STEP enum markers (`.FLOOR.` → `FLOOR`), so this returns the display
9
+ * token (e.g. `"FLOOR"`, `"FLOORING"`, `"USERDEFINED"`, `"NOTDEFINED"`).
10
+ * Returns `undefined` when the slot is absent or empty so callers can ghost /
11
+ * skip elements that carry no PredefinedType.
12
+ */
13
+ export function pickPredefinedType(attrs) {
14
+ const entry = attrs.find((a) => a.name === 'PredefinedType');
15
+ if (!entry)
16
+ return undefined;
17
+ const value = String(entry.value).trim();
18
+ return value.length > 0 ? value : undefined;
19
+ }
20
+ /**
21
+ * Resolve an entity's IFC `PredefinedType` (e.g. `IfcSlab.FLOOR`,
22
+ * `IfcCovering.FLOORING`) from the source buffer. Schema-driven, so it works
23
+ * for any product type whose attribute layout the registry knows. (#1364)
24
+ *
25
+ * Like `Tag` and the property / quantity auto-color sources, this re-parses
26
+ * the entity on demand — there is no columnar PredefinedType accessor — which
27
+ * is the same cost class as those existing per-entity attribute reads.
28
+ */
29
+ export function resolveEntityPredefinedType(store, expressId) {
30
+ if (!(store.source?.length > 0) || !store.entityIndex)
31
+ return undefined;
32
+ return pickPredefinedType(extractAllEntityAttributes(store, expressId));
33
+ }
34
+ //# sourceMappingURL=entity-predefined-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-predefined-type.js","sourceRoot":"","sources":["../../src/filter/entity-predefined-type.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EAAE,0BAA0B,EAAqB,MAAM,kBAAkB,CAAC;AAEjF;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAwE;IAExE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAAmB,EACnB,SAAiB;IAEjB,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW;QAAE,OAAO,SAAS,CAAC;IACxE,OAAO,kBAAkB,CAAC,0BAA0B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Group evaluation (OR-of-AND-groups, #4904).
3
+ *
4
+ * Split out of `filter-evaluate.ts` (allowlisted at 583 lines,
5
+ * `scripts/module-size-allowlist.txt`) rather than grown in place — the
6
+ * ratchet forbids a listed file growing, and this needs its own home
7
+ * regardless: it's the one seam where "groups" become a second concern
8
+ * layered on top of the single-list evaluator, not a change to it.
9
+ *
10
+ * A `FilterGroup[]` ORs its groups together; within each group, the group's
11
+ * own `combinator` still governs (mirrors the selector's `+`: AND within a
12
+ * group, OR across groups). Rather than desugar this into a full-scan pass
13
+ * over some merged rule list — a second matching path that could not answer
14
+ * "why did this match" per-group, and could not be saved — each group is run
15
+ * through the EXACT SAME per-entity evaluator as a single-group query
16
+ * (`evaluateFilterRules(Federated)`), one call per group, unioned by
17
+ * (modelId, expressId). A single group (the overwhelmingly common case,
18
+ * and every query before #4904) takes this function's fast path straight
19
+ * through to the existing single-list evaluator with zero extra overhead.
20
+ *
21
+ * This also means the AND+`op:in` index prefilter is NOT lost for
22
+ * multi-group queries: each group still gets its own prefilter via
23
+ * `selectIterationSource`, same as it would running alone. Measured on
24
+ * `tests/models/buildingsmart/Building-Architecture.ifc` (the largest
25
+ * fixture available on this host; see the PR body for the exact numbers) —
26
+ * a two-group union costs about the sum of the two single-group runs, not a
27
+ * full-scan multiple of it.
28
+ */
29
+ import type { IfcDataStore } from '@ifc-lite/parser';
30
+ import type { FilterGroup } from './filter-groups.js';
31
+ import { type EvaluateOptions, type FederatedEvaluateOptions, type FilteredElement, type EvaluatorModel } from './filter-evaluate.js';
32
+ /** Sync entry — small candidate sets, tests. Mirrors `evaluateFilterRules`. */
33
+ export declare function evaluateFilterGroups(modelId: string, store: IfcDataStore, groups: readonly FilterGroup[], options?: EvaluateOptions): FilteredElement[];
34
+ /** Async federated entry — production UI path. Mirrors `evaluateFilterRulesFederated`. */
35
+ export declare function evaluateFilterGroupsFederated(models: ReadonlyArray<EvaluatorModel>, groups: readonly FilterGroup[], options?: FederatedEvaluateOptions): Promise<FilteredElement[]>;
36
+ //# sourceMappingURL=filter-evaluate-groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-evaluate-groups.d.ts","sourceRoot":"","sources":["../../src/filter/filter-evaluate-groups.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAQ9B,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,GAAE,eAAoB,GAC5B,eAAe,EAAE,CAkCnB;AAED,0FAA0F;AAC1F,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,eAAe,EAAE,CAAC,CAsD5B"}
@@ -0,0 +1,111 @@
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 { evaluateFilterRules, evaluateFilterRulesFederated, } from './filter-evaluate.js';
5
+ const DEFAULT_LIMIT = 5_000;
6
+ function groupKey(el) {
7
+ return `${el.modelId}:${el.expressId}`;
8
+ }
9
+ /** Sync entry — small candidate sets, tests. Mirrors `evaluateFilterRules`. */
10
+ export function evaluateFilterGroups(modelId, store, groups, options = {}) {
11
+ if (groups.length === 0)
12
+ return [];
13
+ if (groups.length === 1) {
14
+ return evaluateFilterRules(modelId, store, groups[0].rules, groups[0].combinator, options);
15
+ }
16
+ const limit = options.limit ?? DEFAULT_LIMIT;
17
+ const seen = new Set();
18
+ const out = [];
19
+ for (const group of groups) {
20
+ if (out.length >= limit)
21
+ break;
22
+ if (group.rules.length === 0)
23
+ continue;
24
+ // Each group's OWN cap is the full `limit`, not `limit - out.length` —
25
+ // review (PR #4987) caught that a shrinking per-group cap can underfill
26
+ // the union: if THIS group's first N matches all duplicate ones an
27
+ // earlier group already returned, capping it at the (small) remaining
28
+ // budget stops the scan before its later, actually-unique matches are
29
+ // ever reached. The outer `out.length >= limit` check above still skips
30
+ // whole groups once the union is already full, and the inner loop below
31
+ // still stops appending once it is; the only change is that a later
32
+ // group may now be asked to find more candidates than strictly remain,
33
+ // which costs some extra scanning but never drops a real match.
34
+ const groupOut = evaluateFilterRules(modelId, store, group.rules, group.combinator, {
35
+ ...options,
36
+ limit,
37
+ });
38
+ for (const el of groupOut) {
39
+ const key = groupKey(el);
40
+ if (seen.has(key))
41
+ continue;
42
+ seen.add(key);
43
+ out.push(el);
44
+ if (out.length >= limit)
45
+ break;
46
+ }
47
+ }
48
+ return out;
49
+ }
50
+ /** Async federated entry — production UI path. Mirrors `evaluateFilterRulesFederated`. */
51
+ export async function evaluateFilterGroupsFederated(models, groups, options = {}) {
52
+ if (groups.length === 0)
53
+ return [];
54
+ if (groups.length === 1) {
55
+ return evaluateFilterRulesFederated(models, groups[0].rules, groups[0].combinator, options);
56
+ }
57
+ const limit = options.limit ?? DEFAULT_LIMIT;
58
+ const seen = new Set();
59
+ const out = [];
60
+ // A single-use candidate iterable (a generator, say) would be exhausted
61
+ // by the first group's call and come back empty for every later one —
62
+ // review (PR #4987). Materialize each model's candidates ONCE, up front,
63
+ // so every group's `evaluateFilterRulesFederated` call gets its own fresh
64
+ // pass over the same (now-array) candidate set.
65
+ const candidatesByModel = options.candidateExpressIdsByModel
66
+ ? new Map([...options.candidateExpressIdsByModel].map(([id, c]) => [id, [...c]]))
67
+ : undefined;
68
+ // Accumulate `scanned` ACROSS groups rather than handing each group's raw
69
+ // per-group progress straight through — review (PR #4987) caught that
70
+ // without this, a multi-group run's progress bar reached 100% at the end
71
+ // of group 1 and then reset to 0% when group 2 started. `total` is
72
+ // reported as -1 (unknown) for the whole multi-group run: the UI's own
73
+ // progress renderer already has an unknown-total mode (a plain "scanned
74
+ // N" count, no bar) for exactly this case, rather than a bar this
75
+ // function would otherwise have to guess a cross-group total for.
76
+ let scannedSoFar = 0;
77
+ for (const group of groups) {
78
+ if (out.length >= limit)
79
+ break;
80
+ if (group.rules.length === 0)
81
+ continue;
82
+ let lastGroupScanned = 0;
83
+ // See the sync entry above (`evaluateFilterGroups`) for why this is
84
+ // `limit`, not `limit - out.length`: a shrinking per-group cap can
85
+ // underfill the union when a later group's early matches duplicate an
86
+ // earlier group's.
87
+ const groupOut = await evaluateFilterRulesFederated(models, group.rules, group.combinator, {
88
+ ...options,
89
+ candidateExpressIdsByModel: candidatesByModel,
90
+ limit,
91
+ onProgress: options.onProgress
92
+ ? (scanned) => {
93
+ lastGroupScanned = scanned;
94
+ options.onProgress(scannedSoFar + scanned, -1);
95
+ }
96
+ : undefined,
97
+ });
98
+ scannedSoFar += lastGroupScanned;
99
+ for (const el of groupOut) {
100
+ const key = groupKey(el);
101
+ if (seen.has(key))
102
+ continue;
103
+ seen.add(key);
104
+ out.push(el);
105
+ if (out.length >= limit)
106
+ break;
107
+ }
108
+ }
109
+ return out;
110
+ }
111
+ //# sourceMappingURL=filter-evaluate-groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-evaluate-groups.js","sourceRoot":"","sources":["../../src/filter/filter-evaluate-groups.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { FilterRule, ModelRule, ModelTagRule } from './filter-rules.js';
2
+ /** What a model-scoped rule needs to know about one model. */
3
+ export interface ModelScope {
4
+ /** Stable source identity compared by `ModelRule` (`sourceFingerprint`, else the id). */
5
+ filterIdentity: string;
6
+ /** The model's tag ids; absent = untagged. */
7
+ tagIds?: ReadonlySet<string>;
8
+ /** Every tag id that currently exists — a rule naming any other id is unresolved. */
9
+ definedModelTagIds: ReadonlySet<string>;
10
+ }
11
+ export type ModelScopedRule = ModelRule | ModelTagRule;
12
+ export declare function isModelScopedRule(rule: FilterRule): rule is ModelScopedRule;
13
+ export declare function modelScopedRuleMatches(rule: ModelScopedRule, scope: ModelScope): boolean;
14
+ /**
15
+ * Under AND, may this model be skipped outright? True when some model-scoped
16
+ * rule fails for it. Under OR the answer is always `false`: the entity-level
17
+ * rules on the other side of the OR can still admit its entities.
18
+ */
19
+ export declare function modelPrunedUnderAnd(rules: readonly FilterRule[], scope: ModelScope): boolean;
20
+ /** Empty set for callers that know of no tags (single-model tests, adapters without a tag store). */
21
+ export declare const NO_MODEL_TAGS: ReadonlySet<string>;
22
+ //# sourceMappingURL=filter-evaluate-model-tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-evaluate-model-tag.d.ts","sourceRoot":"","sources":["../../src/filter/filter-evaluate-model-tag.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7E,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,qFAAqF;IACrF,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,YAAY,CAAC;AAEvD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,IAAI,eAAe,CAE3E;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAGxF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAE5F;AAED,qGAAqG;AACrG,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAAa,CAAC"}
@@ -0,0 +1,35 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * The MODEL-SCOPED rule arm of the evaluator (`filter-evaluate.ts`): `model`
6
+ * and `modelTag` (#4215) are decided by the owning model alone, never by the
7
+ * entity, so one answer per model serves every entity in it.
8
+ *
9
+ * Used twice, by design: as the per-entity arm (so OR keeps its boolean
10
+ * meaning — a model failing the tag condition still contributes entities that
11
+ * pass the other side of the OR) and as the whole-model prune under AND (a
12
+ * model that fails any model-scoped rule can contribute no entity, so its scan
13
+ * is skipped). Same function both times, so the two cannot disagree.
14
+ */
15
+ import { modelTagRuleMatches } from './model-tag.js';
16
+ import { setOpMatches } from './filter-ops.js';
17
+ export function isModelScopedRule(rule) {
18
+ return rule.kind === 'model' || rule.kind === 'modelTag';
19
+ }
20
+ export function modelScopedRuleMatches(rule, scope) {
21
+ if (rule.kind === 'model')
22
+ return setOpMatches(rule.op, scope.filterIdentity, rule.values);
23
+ return modelTagRuleMatches(rule.op, rule.tagIds, scope.tagIds, scope.definedModelTagIds);
24
+ }
25
+ /**
26
+ * Under AND, may this model be skipped outright? True when some model-scoped
27
+ * rule fails for it. Under OR the answer is always `false`: the entity-level
28
+ * rules on the other side of the OR can still admit its entities.
29
+ */
30
+ export function modelPrunedUnderAnd(rules, scope) {
31
+ return rules.some((rule) => isModelScopedRule(rule) && !modelScopedRuleMatches(rule, scope));
32
+ }
33
+ /** Empty set for callers that know of no tags (single-model tests, adapters without a tag store). */
34
+ export const NO_MODEL_TAGS = new Set();
35
+ //# sourceMappingURL=filter-evaluate-model-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-evaluate-model-tag.js","sourceRoot":"","sources":["../../src/filter/filter-evaluate-model-tag.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe/C,MAAM,UAAU,iBAAiB,CAAC,IAAgB;IAChD,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAqB,EAAE,KAAiB;IAC7E,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3F,OAAO,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;AAC3F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA4B,EAAE,KAAiB;IACjF,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,qGAAqG;AACrG,MAAM,CAAC,MAAM,aAAa,GAAwB,IAAI,GAAG,EAAE,CAAC"}