@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,408 @@
|
|
|
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
|
+
* Path-B runtime evaluator.
|
|
6
|
+
*
|
|
7
|
+
* Applies a list of `FilterRule`s to one or more `IfcDataStore`s without
|
|
8
|
+
* touching DuckDB. Three optimisations make this safe on huge (4M-entity)
|
|
9
|
+
* models without a Worker:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Index prefilter (AND + op:in only).** When the rule list contains
|
|
12
|
+
* any `ifcType` or `storey` `op:'in'` rule under an AND combinator,
|
|
13
|
+
* the iteration source is derived from `entityIndex.byType` /
|
|
14
|
+
* `spatialHierarchy.byStorey` — typically 100× narrowing. Per-entity
|
|
15
|
+
* rule evaluation still re-checks every rule for correctness, so
|
|
16
|
+
* picking one prefilter (the smallest bucket) is enough; we don't
|
|
17
|
+
* need to intersect. `notIn` and `OR` skip the prefilter and fall
|
|
18
|
+
* back to the full column scan.
|
|
19
|
+
*
|
|
20
|
+
* 2. **Cheap-first per-entity ordering.** Rules are sorted by cost at
|
|
21
|
+
* evaluation time so column-only checks (`ifcType`, `name`, `storey`,
|
|
22
|
+
* `predefinedType`) run before `property` / `quantity` rules that
|
|
23
|
+
* trigger on-demand source-buffer parses. Combined with AND/OR
|
|
24
|
+
* short-circuit, this avoids the AGENTS.md §2 "never call
|
|
25
|
+
* extractPropertiesOnDemand in a large loop" trap — a single
|
|
26
|
+
* ifcType rule excluding 99% of entities skips 99% of the parses.
|
|
27
|
+
*
|
|
28
|
+
* 3. **Async chunked yielding (federated entry).** The federated entry
|
|
29
|
+
* is async and yields to the event loop every `chunkSize` rows
|
|
30
|
+
* (default 20_000, same as `buildTier1Index`). `AbortSignal` is
|
|
31
|
+
* honoured at chunk boundaries; an `onProgress(scanned, total)`
|
|
32
|
+
* callback fires once per chunk. The synchronous single-model
|
|
33
|
+
* entry remains for tests and small candidate sets.
|
|
34
|
+
*/
|
|
35
|
+
import { extractTypePropertiesOnDemand, extractAllMaterialsOnDemand, extractClassificationsOnDemand, mergeInheritedPropertySets, } from '@ifc-lite/parser';
|
|
36
|
+
import { ownPropertySetsFor, typePropertySetsFor, quantitySetsFor, attributesFor, mutatedAttributeValue } from './filter-evaluate-mutations.js';
|
|
37
|
+
import { RelationshipType } from '@ifc-lite/data';
|
|
38
|
+
import { combineRuleResults, } from './filter-rules.js';
|
|
39
|
+
import { setOpMatches, globalIdOpMatches, stringOpMatches, matchStringAnyNone, numericOpMatches, } from './filter-ops.js';
|
|
40
|
+
import { isNumericArrayLike, materialiseNumericIterable, toNumericIterable, } from './filter-iteration.js';
|
|
41
|
+
import { selectIterationSource, orderRulesByCost } from './filter-iteration-source.js';
|
|
42
|
+
import { buildFilterResult, effectiveFilterFields } from './effective-filter-fields.js';
|
|
43
|
+
import { throwAbort, yieldToEventLoop } from './filter-evaluate-yield.js';
|
|
44
|
+
import { modelPrunedUnderAnd, modelScopedRuleMatches, isModelScopedRule, NO_MODEL_TAGS, } from './filter-evaluate-model-tag.js';
|
|
45
|
+
import { flattenPsets, flattenQtys, stringifyValue, matchPropertyRule, matchQuantityRule, matchAttributeRule, defaultStoreyName, storeyMatchesRefs, materialNamesOf, materialMatchCandidates, matchClassificationRule, matchParentRule, elevationOf, } from './filter-match.js';
|
|
46
|
+
import { resolveEntityPredefinedType } from './entity-predefined-type.js';
|
|
47
|
+
import { matchGroupRule } from './filter-group-rule.js';
|
|
48
|
+
import { readsThroughSubject } from './subject-read-options.js';
|
|
49
|
+
import { matchRuleThroughSubject } from './subject-match.js';
|
|
50
|
+
const DEFAULT_LIMIT = 5_000;
|
|
51
|
+
const DEFAULT_CHUNK_SIZE = 20_000;
|
|
52
|
+
// ── Sync entry (small candidate sets, tests) ─────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Evaluate `rules` against one model synchronously. Suitable for tests
|
|
55
|
+
* and small candidate sets where the chunked async path's overhead
|
|
56
|
+
* isn't justified. For real UI flows (huge models, cancellable runs),
|
|
57
|
+
* use `evaluateFilterRulesFederated` (async).
|
|
58
|
+
*/
|
|
59
|
+
export function evaluateFilterRules(modelId, store, rules, combinator, options = {}) {
|
|
60
|
+
if (rules.length === 0)
|
|
61
|
+
return [];
|
|
62
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
63
|
+
const orderedRules = orderRulesByCost(rules);
|
|
64
|
+
const iterIds = toNumericIterable(selectIterationSource(store, rules, combinator, options.candidateExpressIds, modelId));
|
|
65
|
+
const out = [];
|
|
66
|
+
const ctx = {
|
|
67
|
+
store,
|
|
68
|
+
modelId,
|
|
69
|
+
scope: {
|
|
70
|
+
filterIdentity: options.modelFilterIdentity ?? modelId,
|
|
71
|
+
tagIds: options.modelTagIds,
|
|
72
|
+
definedModelTagIds: options.definedModelTagIds ?? NO_MODEL_TAGS,
|
|
73
|
+
},
|
|
74
|
+
table: store.entities,
|
|
75
|
+
options,
|
|
76
|
+
hasPropertyRule: orderedRules.some((r) => r.kind === 'property'),
|
|
77
|
+
hasQuantityRule: orderedRules.some((r) => r.kind === 'quantity'),
|
|
78
|
+
hasMaterialRule: orderedRules.some((r) => r.kind === 'material'),
|
|
79
|
+
hasClassificationRule: orderedRules.some((r) => r.kind === 'classification'),
|
|
80
|
+
hasAttributeRule: orderedRules.some((r) => r.kind === 'attribute'),
|
|
81
|
+
typePsetCache: new Map(),
|
|
82
|
+
};
|
|
83
|
+
for (const expressId of iterIds) {
|
|
84
|
+
if (out.length >= limit)
|
|
85
|
+
break;
|
|
86
|
+
// Skip empty rows from the raw expressId column. ArrayLike sources
|
|
87
|
+
// (the full-table fast-path) include zero-padded slots; bucket
|
|
88
|
+
// sources (byType / byStorey) never do, so this is a no-op there.
|
|
89
|
+
if (!expressId)
|
|
90
|
+
continue;
|
|
91
|
+
const fields = evaluateOneEntity(ctx, expressId, orderedRules, combinator);
|
|
92
|
+
if (!fields)
|
|
93
|
+
continue;
|
|
94
|
+
out.push(buildFilterResult(modelId, expressId, fields));
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
export async function evaluateFilterRulesFederated(models, rules, combinator, options = {}) {
|
|
99
|
+
if (rules.length === 0)
|
|
100
|
+
return [];
|
|
101
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
102
|
+
const chunkSize = options.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
103
|
+
const signal = options.signal;
|
|
104
|
+
const orderedRules = orderRulesByCost(rules);
|
|
105
|
+
const out = [];
|
|
106
|
+
// Pre-compute per-model iteration plans + a global total so the
|
|
107
|
+
// progress callback can render a single bar across the federation.
|
|
108
|
+
const definedModelTagIds = options.definedModelTagIds ?? NO_MODEL_TAGS;
|
|
109
|
+
const plans = [];
|
|
110
|
+
let grandTotal = 0;
|
|
111
|
+
let totalKnown = true;
|
|
112
|
+
for (const m of models) {
|
|
113
|
+
if (!m.store)
|
|
114
|
+
continue;
|
|
115
|
+
const scope = { filterIdentity: m.filterIdentity ?? m.id, tagIds: m.tagIds, definedModelTagIds };
|
|
116
|
+
// Whole-model prune, AND only: under OR a model failing its model-scoped
|
|
117
|
+
// rules still contributes entities the other rules admit (#4215).
|
|
118
|
+
if (combinator === 'AND' && modelPrunedUnderAnd(orderedRules, scope))
|
|
119
|
+
continue;
|
|
120
|
+
const candidates = options.candidateExpressIdsByModel?.get(m.id);
|
|
121
|
+
const source = candidates ?? selectIterationSource(m.store, rules, combinator, undefined, m.id, m.mutationView);
|
|
122
|
+
const arr = materialiseNumericIterable(source);
|
|
123
|
+
if (arr === null) {
|
|
124
|
+
totalKnown = false;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
grandTotal += arr.length;
|
|
128
|
+
}
|
|
129
|
+
plans.push({
|
|
130
|
+
modelId: m.id,
|
|
131
|
+
scope,
|
|
132
|
+
store: m.store, mutationView: m.mutationView,
|
|
133
|
+
iter: arr ?? source,
|
|
134
|
+
total: arr ? arr.length : -1,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
let scanned = 0;
|
|
138
|
+
options.onProgress?.(0, totalKnown ? grandTotal : -1);
|
|
139
|
+
for (const plan of plans) {
|
|
140
|
+
if (out.length >= limit)
|
|
141
|
+
break;
|
|
142
|
+
if (signal?.aborted)
|
|
143
|
+
throwAbort(signal);
|
|
144
|
+
const ctx = {
|
|
145
|
+
store: plan.store,
|
|
146
|
+
modelId: plan.modelId,
|
|
147
|
+
scope: plan.scope, mutationView: plan.mutationView,
|
|
148
|
+
table: plan.store.entities,
|
|
149
|
+
options,
|
|
150
|
+
hasPropertyRule: orderedRules.some((r) => r.kind === 'property'),
|
|
151
|
+
hasQuantityRule: orderedRules.some((r) => r.kind === 'quantity'),
|
|
152
|
+
hasMaterialRule: orderedRules.some((r) => r.kind === 'material'),
|
|
153
|
+
hasClassificationRule: orderedRules.some((r) => r.kind === 'classification'),
|
|
154
|
+
hasAttributeRule: orderedRules.some((r) => r.kind === 'attribute'),
|
|
155
|
+
typePsetCache: new Map(),
|
|
156
|
+
};
|
|
157
|
+
// Walk the per-model iter in chunkSize-sized strides, yielding the
|
|
158
|
+
// event loop between chunks. ArrayLike fast-path uses index access;
|
|
159
|
+
// the fallback path drains an iterator into chunks.
|
|
160
|
+
if (Array.isArray(plan.iter) || isNumericArrayLike(plan.iter)) {
|
|
161
|
+
const arr = plan.iter;
|
|
162
|
+
for (let i = 0; i < arr.length && out.length < limit; i += chunkSize) {
|
|
163
|
+
if (signal?.aborted)
|
|
164
|
+
throwAbort(signal);
|
|
165
|
+
const end = Math.min(i + chunkSize, arr.length);
|
|
166
|
+
for (let j = i; j < end; j++) {
|
|
167
|
+
const expressId = arr[j];
|
|
168
|
+
if (!expressId)
|
|
169
|
+
continue;
|
|
170
|
+
const fields = evaluateOneEntity(ctx, expressId, orderedRules, combinator);
|
|
171
|
+
if (!fields)
|
|
172
|
+
continue;
|
|
173
|
+
out.push(buildFilterResult(plan.modelId, expressId, fields));
|
|
174
|
+
if (out.length >= limit)
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
scanned += end - i;
|
|
178
|
+
options.onProgress?.(scanned, totalKnown ? grandTotal : -1);
|
|
179
|
+
if (end < arr.length && out.length < limit)
|
|
180
|
+
await yieldToEventLoop();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
let buffered = 0;
|
|
185
|
+
for (const expressId of plan.iter) {
|
|
186
|
+
if (out.length >= limit)
|
|
187
|
+
break;
|
|
188
|
+
if (!expressId)
|
|
189
|
+
continue;
|
|
190
|
+
const fields = evaluateOneEntity(ctx, expressId, orderedRules, combinator);
|
|
191
|
+
if (fields) {
|
|
192
|
+
out.push(buildFilterResult(plan.modelId, expressId, fields));
|
|
193
|
+
}
|
|
194
|
+
buffered++;
|
|
195
|
+
scanned++;
|
|
196
|
+
if (buffered >= chunkSize) {
|
|
197
|
+
buffered = 0;
|
|
198
|
+
if (signal?.aborted)
|
|
199
|
+
throwAbort(signal);
|
|
200
|
+
options.onProgress?.(scanned, totalKnown ? grandTotal : -1);
|
|
201
|
+
await yieldToEventLoop();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Final progress tick for the residual.
|
|
205
|
+
options.onProgress?.(scanned, totalKnown ? grandTotal : -1);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
function evaluateOneEntity(ctx, expressId, orderedRules, combinator) {
|
|
211
|
+
if (ctx.mutationView?.isDeleted(expressId))
|
|
212
|
+
return null;
|
|
213
|
+
const fields = effectiveFilterFields(ctx.store, ctx.mutationView, expressId);
|
|
214
|
+
// Lazy pset/qto reads — only invoked when an ordered rule for that
|
|
215
|
+
// family actually needs the data. Cheap-first ordering means cheap
|
|
216
|
+
// rules check first; AND short-circuit on a cheap miss skips the
|
|
217
|
+
// parse entirely.
|
|
218
|
+
let psetCache = null;
|
|
219
|
+
let qtyCache = null;
|
|
220
|
+
let matCache = null;
|
|
221
|
+
let classCache = null;
|
|
222
|
+
let attrCache = null;
|
|
223
|
+
const psetsFor = () => {
|
|
224
|
+
if (!psetCache) {
|
|
225
|
+
const ownSets = ownPropertySetsFor(ctx.store, expressId, ctx.mutationView); // #4946, mutation-aware
|
|
226
|
+
const typeSets = getInheritedTypePsets(ctx, expressId);
|
|
227
|
+
// IFC inheritance is per-PROPERTY, not per-set, and the occurrence's
|
|
228
|
+
// own value wins on a name collision — same rule the IDS bridge
|
|
229
|
+
// already applies (`mergeInheritedPropertySets`, packages/parser).
|
|
230
|
+
// A type-only pset (nothing on the instance) is appended as-is, so
|
|
231
|
+
// `isSet`/`isNotSet` now also see properties that exist ONLY on the
|
|
232
|
+
// type — a deliberate presence-semantics change (was instance-only).
|
|
233
|
+
psetCache = flattenPsets(mergeInheritedPropertySets(ownSets, typeSets));
|
|
234
|
+
}
|
|
235
|
+
return psetCache;
|
|
236
|
+
};
|
|
237
|
+
const qtysFor = () => {
|
|
238
|
+
if (!qtyCache)
|
|
239
|
+
qtyCache = flattenQtys(quantitySetsFor(ctx.store, expressId, ctx.mutationView));
|
|
240
|
+
return qtyCache;
|
|
241
|
+
};
|
|
242
|
+
const matNamesFor = () => {
|
|
243
|
+
if (!matCache) {
|
|
244
|
+
// Union across ALL associations so a material rule matches an element
|
|
245
|
+
// whose second IfcRelAssociatesMaterial carries the queried name.
|
|
246
|
+
const seen = new Set();
|
|
247
|
+
for (const info of extractAllMaterialsOnDemand(ctx.store, expressId)) {
|
|
248
|
+
for (const n of materialMatchCandidates(info))
|
|
249
|
+
seen.add(n);
|
|
250
|
+
}
|
|
251
|
+
matCache = [...seen];
|
|
252
|
+
}
|
|
253
|
+
return matCache;
|
|
254
|
+
};
|
|
255
|
+
const classFor = () => {
|
|
256
|
+
if (!classCache)
|
|
257
|
+
classCache = extractClassificationsOnDemand(ctx.store, expressId);
|
|
258
|
+
return classCache;
|
|
259
|
+
};
|
|
260
|
+
const attrsFor = () => {
|
|
261
|
+
if (!attrCache)
|
|
262
|
+
attrCache = attributesFor(ctx.store, expressId, ctx.mutationView);
|
|
263
|
+
return attrCache;
|
|
264
|
+
};
|
|
265
|
+
const ruleResults = [];
|
|
266
|
+
for (const rule of orderedRules) {
|
|
267
|
+
const result = evaluateRule(rule, ctx, expressId, ctx.hasPropertyRule ? psetsFor : null, ctx.hasQuantityRule ? qtysFor : null, ctx.hasMaterialRule ? matNamesFor : null, ctx.hasClassificationRule ? classFor : null, ctx.hasAttributeRule ? attrsFor : null, fields);
|
|
268
|
+
ruleResults.push(result);
|
|
269
|
+
if (combinator === 'AND' && !result)
|
|
270
|
+
return null;
|
|
271
|
+
if (combinator === 'OR' && result)
|
|
272
|
+
return fields;
|
|
273
|
+
}
|
|
274
|
+
return combineRuleResults(combinator, ruleResults) ? fields : null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Resolve `expressId`'s TYPE-level property sets (e.g. `IfcWallType`'s
|
|
278
|
+
* `Pset_WallCommon`) via `IfcRelDefinesByType`, caching the parse per
|
|
279
|
+
* TYPE (`ctx.typePsetCache`) rather than per instance. Many occurrences
|
|
280
|
+
* share one type, so this is O(distinct types) source-buffer parses per
|
|
281
|
+
* filter run, not O(entities) — see the AGENTS.md §2 warning this module
|
|
282
|
+
* already guards for instance psets.
|
|
283
|
+
*
|
|
284
|
+
* Mirrors `packages/ids/src/bridge/properties.ts`'s `inheritedPropertySets`
|
|
285
|
+
* / `typePropertySetsFromTable` split: `extractTypePropertiesOnDemand` only
|
|
286
|
+
* resolves from the source buffer, so on a server-parsed store (no
|
|
287
|
+
* `source`, e.g. after collab/session load) it always returns null — the
|
|
288
|
+
* type's psets there are keyed under the type's own expressId in the
|
|
289
|
+
* pre-built `PropertyTable` (`store.properties.getForEntity(typeId)`,
|
|
290
|
+
* issue #1787's server-path fallback).
|
|
291
|
+
*/
|
|
292
|
+
function getInheritedTypePsets(ctx, expressId) {
|
|
293
|
+
if (!ctx.store.relationships)
|
|
294
|
+
return [];
|
|
295
|
+
const typeIds = ctx.store.relationships.getRelated(expressId, RelationshipType.DefinesByType, 'inverse');
|
|
296
|
+
if (typeIds.length === 0)
|
|
297
|
+
return [];
|
|
298
|
+
const typeId = typeIds[0];
|
|
299
|
+
// Only the BASE read is cached per type (review finding: `mutationView` is
|
|
300
|
+
// live/mutable, edited possibly mid-run between chunk yields — caching the
|
|
301
|
+
// mutation-APPLIED result by typeId would keep answering pre-edit psets).
|
|
302
|
+
// The overlay is cheap and applied fresh on every call.
|
|
303
|
+
let base = ctx.typePsetCache.get(typeId);
|
|
304
|
+
if (base === undefined) {
|
|
305
|
+
base = ctx.store.source && ctx.store.source.length > 0
|
|
306
|
+
? extractTypePropertiesOnDemand(ctx.store, expressId)?.properties ?? []
|
|
307
|
+
: (ctx.store.properties?.getForEntity?.(typeId) ?? []);
|
|
308
|
+
ctx.typePsetCache.set(typeId, base);
|
|
309
|
+
}
|
|
310
|
+
return typePropertySetsFor(base, typeId, ctx.mutationView); // #4946, mutation-aware
|
|
311
|
+
}
|
|
312
|
+
function evaluateRule(rule, ctx, expressId, psetsFor, qtysFor, matNamesFor, classFor, attrsFor, fields) {
|
|
313
|
+
if (isModelScopedRule(rule))
|
|
314
|
+
return modelScopedRuleMatches(rule, ctx.scope);
|
|
315
|
+
switch (rule.kind) {
|
|
316
|
+
case 'storey': {
|
|
317
|
+
// Exact-identity mode (refs present): Name isn't unique.
|
|
318
|
+
if (rule.refs) {
|
|
319
|
+
const isMatch = storeyMatchesRefs(ctx.store, expressId, ctx.modelId, rule);
|
|
320
|
+
return rule.op === 'in' ? isMatch : !isMatch;
|
|
321
|
+
}
|
|
322
|
+
const storeyName = ctx.options.storeyNameOf?.(expressId)
|
|
323
|
+
?? defaultStoreyName(ctx.store, expressId);
|
|
324
|
+
return setOpMatches(rule.op, storeyName, rule.values);
|
|
325
|
+
}
|
|
326
|
+
case 'ifcType':
|
|
327
|
+
return setOpMatches(rule.op, fields.ifcType, rule.values);
|
|
328
|
+
case 'predefinedType': {
|
|
329
|
+
// No columnar accessor - resolve from the source buffer, per-store (#1462). A live edit (#4946) wins.
|
|
330
|
+
const pt = mutatedAttributeValue(ctx.mutationView, expressId, 'PredefinedType')
|
|
331
|
+
?? ctx.options.predefinedTypeOf?.(expressId)
|
|
332
|
+
?? resolveEntityPredefinedType(ctx.store, expressId)
|
|
333
|
+
?? '';
|
|
334
|
+
return setOpMatches(rule.op, pt, rule.values);
|
|
335
|
+
}
|
|
336
|
+
case 'name': {
|
|
337
|
+
// getNameOrUndefined: absent must reach as undefined, not '' (#4930). A live edit (#4946) wins.
|
|
338
|
+
return stringOpMatches(rule.op, fields.name, rule.value, rule.valueKind);
|
|
339
|
+
}
|
|
340
|
+
case 'globalId':
|
|
341
|
+
return globalIdOpMatches(rule.op, fields.globalId, rule.values);
|
|
342
|
+
case 'attribute': {
|
|
343
|
+
if (!attrsFor)
|
|
344
|
+
return false;
|
|
345
|
+
return matchAttributeRule(rule, attrsFor());
|
|
346
|
+
}
|
|
347
|
+
case 'property':
|
|
348
|
+
if (readsThroughSubject(rule))
|
|
349
|
+
return matchRuleThroughSubject(rule, ctx.store, expressId);
|
|
350
|
+
return psetsFor ? matchPropertyRule(rule, psetsFor()) : false;
|
|
351
|
+
case 'quantity':
|
|
352
|
+
if (readsThroughSubject(rule))
|
|
353
|
+
return matchRuleThroughSubject(rule, ctx.store, expressId);
|
|
354
|
+
return qtysFor ? matchQuantityRule(rule, qtysFor()) : false;
|
|
355
|
+
case 'material': {
|
|
356
|
+
if (!matNamesFor)
|
|
357
|
+
return false;
|
|
358
|
+
return matchStringAnyNone(rule.op, matNamesFor(), rule.value, rule.valueKind);
|
|
359
|
+
}
|
|
360
|
+
case 'classification': {
|
|
361
|
+
if (!classFor)
|
|
362
|
+
return false;
|
|
363
|
+
return matchClassificationRule(rule, classFor());
|
|
364
|
+
}
|
|
365
|
+
case 'elevation': {
|
|
366
|
+
const elev = elevationOf(ctx.store, expressId);
|
|
367
|
+
if (elev === null)
|
|
368
|
+
return false;
|
|
369
|
+
return numericOpMatches(rule.op, elev, rule.value);
|
|
370
|
+
}
|
|
371
|
+
case 'type': {
|
|
372
|
+
const typeName = relatingTypeNameOf(ctx, expressId);
|
|
373
|
+
if (typeName === null)
|
|
374
|
+
return false;
|
|
375
|
+
return stringOpMatches(rule.op, typeName, rule.value, rule.valueKind);
|
|
376
|
+
}
|
|
377
|
+
case 'parent': return matchParentRule(rule, ctx.store, expressId);
|
|
378
|
+
case 'group': return matchGroupRule(rule, ctx.store, expressId);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* The Name of `expressId`'s RELATING TYPE via `IfcRelDefinesByType` (#4094).
|
|
383
|
+
* `null` = no such relation (must never match). `undefined` = the related
|
|
384
|
+
* `IfcTypeObject` has no Name (#4930) — distinct from an empty one.
|
|
385
|
+
*/
|
|
386
|
+
function relatingTypeNameOf(ctx, expressId) {
|
|
387
|
+
if (!ctx.store.relationships)
|
|
388
|
+
return null;
|
|
389
|
+
const typeIds = ctx.store.relationships.getRelated(expressId, RelationshipType.DefinesByType, 'inverse');
|
|
390
|
+
if (typeIds.length === 0)
|
|
391
|
+
return null;
|
|
392
|
+
return ctx.table.getNameOrUndefined(typeIds[0]);
|
|
393
|
+
}
|
|
394
|
+
// ── Exposed for tests ────────────────────────────────────────────────────────
|
|
395
|
+
export const __internal = {
|
|
396
|
+
flattenPsets,
|
|
397
|
+
flattenQtys,
|
|
398
|
+
stringifyValue,
|
|
399
|
+
matchPropertyRule,
|
|
400
|
+
matchQuantityRule,
|
|
401
|
+
matchAttributeRule,
|
|
402
|
+
materialNamesOf,
|
|
403
|
+
matchClassificationRule,
|
|
404
|
+
elevationOf,
|
|
405
|
+
orderRulesByCost,
|
|
406
|
+
selectIterationSource,
|
|
407
|
+
};
|
|
408
|
+
//# sourceMappingURL=filter-evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-evaluate.js","sourceRoot":"","sources":["../../src/filter/filter-evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type IfcDataStore } from '@ifc-lite/parser';
|
|
2
|
+
import type { ClassificationOp, TextKind } from './filter-rules.js';
|
|
3
|
+
export interface GroupRule {
|
|
4
|
+
kind: 'group';
|
|
5
|
+
/** Only groups of this IFC class or a subclass, e.g. `IfcSystem`. Absent = any `IfcGroup`. */
|
|
6
|
+
groupClass?: string;
|
|
7
|
+
op: ClassificationOp;
|
|
8
|
+
/** Matched against each group's Name. Ignored for `isSet` / `isNotSet`. */
|
|
9
|
+
value: string;
|
|
10
|
+
/** How `value` reads. Only consulted by the `matches` / `notMatches` ops. */
|
|
11
|
+
valueKind?: TextKind;
|
|
12
|
+
}
|
|
13
|
+
export declare function groupRule(op: ClassificationOp, value: string, groupClass?: string, valueKind?: TextKind): GroupRule;
|
|
14
|
+
/**
|
|
15
|
+
* The groups `expressId` is assigned to (inverse `IfcRelAssignsToGroup`),
|
|
16
|
+
* narrowed to `groupClass` when given. The exact declared class is read,
|
|
17
|
+
* not the coalesced one, so a subclass check is a real subclass check.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assignedGroupIds(store: IfcDataStore, expressId: number, groupClass?: string): number[];
|
|
20
|
+
/** The Names of those groups; `undefined` for a group with no Name. */
|
|
21
|
+
export declare function assignedGroupNames(store: IfcDataStore, expressId: number, groupClass?: string): (string | undefined)[];
|
|
22
|
+
export declare function matchGroupRule(rule: GroupRule, store: IfcDataStore, expressId: number): boolean;
|
|
23
|
+
//# sourceMappingURL=filter-group-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-group-rule.d.ts","sourceRoot":"","sources":["../../src/filter/filter-group-rule.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,gBAAgB,CAAC;IACrB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,SAAS,CAAC,EAAE,QAAQ,CAAC;CACtB;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,QAAQ,GACnB,SAAS,CAQX;AAeD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAOtG;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAEtH;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAK/F"}
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
* `group` — membership in an `IfcGroup` through `IfcRelAssignsToGroup`
|
|
6
|
+
* (#5226): "every AHU is assigned to a system". The one vocabulary entry
|
|
7
|
+
* both search/applicability and validation requirements read, like every
|
|
8
|
+
* other `FilterRule` kind. Own module because `filter-rules.ts` sits at the
|
|
9
|
+
* module-size cap.
|
|
10
|
+
*
|
|
11
|
+
* An element's candidates are the Names of every group it is assigned to,
|
|
12
|
+
* optionally only groups of one IFC class (`groupClass`, subclasses
|
|
13
|
+
* included: `IfcSystem` also takes `IfcDistributionSystem` and
|
|
14
|
+
* `IfcBuildingSystem`). `isSet` / `isNotSet` ask whether there is any such
|
|
15
|
+
* group at all, named or not. Value ops match ANY group Name for a positive
|
|
16
|
+
* op and NONE for a negative one, the convention `material` and `parent`
|
|
17
|
+
* already use.
|
|
18
|
+
*/
|
|
19
|
+
import { exactTypeName, RelationshipType } from '@ifc-lite/data';
|
|
20
|
+
import { expandTypes } from '@ifc-lite/parser';
|
|
21
|
+
import { matchStringAnyNone } from './filter-ops.js';
|
|
22
|
+
export function groupRule(op, value, groupClass, valueKind) {
|
|
23
|
+
return {
|
|
24
|
+
kind: 'group',
|
|
25
|
+
...(groupClass ? { groupClass } : {}),
|
|
26
|
+
op,
|
|
27
|
+
value,
|
|
28
|
+
...(valueKind ? { valueKind } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const classSetCache = new Map();
|
|
32
|
+
/** `groupClass` plus every subclass, upper-cased, for the store's schema. */
|
|
33
|
+
function classSet(groupClass, schemaVersion) {
|
|
34
|
+
const key = `${schemaVersion ?? ''}|${groupClass.toUpperCase()}`;
|
|
35
|
+
let set = classSetCache.get(key);
|
|
36
|
+
if (!set) {
|
|
37
|
+
set = new Set(expandTypes([groupClass], schemaVersion).map((t) => t.toUpperCase()));
|
|
38
|
+
classSetCache.set(key, set);
|
|
39
|
+
}
|
|
40
|
+
return set;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The groups `expressId` is assigned to (inverse `IfcRelAssignsToGroup`),
|
|
44
|
+
* narrowed to `groupClass` when given. The exact declared class is read,
|
|
45
|
+
* not the coalesced one, so a subclass check is a real subclass check.
|
|
46
|
+
*/
|
|
47
|
+
export function assignedGroupIds(store, expressId, groupClass) {
|
|
48
|
+
if (!store.relationships)
|
|
49
|
+
return [];
|
|
50
|
+
const ids = store.relationships.getRelated(expressId, RelationshipType.AssignsToGroup, 'inverse');
|
|
51
|
+
const wanted = groupClass?.trim();
|
|
52
|
+
if (!wanted)
|
|
53
|
+
return ids;
|
|
54
|
+
const classes = classSet(wanted, store.schemaVersion);
|
|
55
|
+
return ids.filter((id) => classes.has(exactTypeName(store.entities, id).toUpperCase()));
|
|
56
|
+
}
|
|
57
|
+
/** The Names of those groups; `undefined` for a group with no Name. */
|
|
58
|
+
export function assignedGroupNames(store, expressId, groupClass) {
|
|
59
|
+
return assignedGroupIds(store, expressId, groupClass).map((id) => store.entities.getNameOrUndefined(id));
|
|
60
|
+
}
|
|
61
|
+
export function matchGroupRule(rule, store, expressId) {
|
|
62
|
+
const names = assignedGroupNames(store, expressId, rule.groupClass);
|
|
63
|
+
if (rule.op === 'isSet')
|
|
64
|
+
return names.length > 0;
|
|
65
|
+
if (rule.op === 'isNotSet')
|
|
66
|
+
return names.length === 0;
|
|
67
|
+
return matchStringAnyNone(rule.op, names, rule.value, rule.valueKind);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=filter-group-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-group-rule.js","sourceRoot":"","sources":["../../src/filter/filter-group-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `FilterGroup` — one AND-combined (or OR-combined, per its own
|
|
3
|
+
* `combinator`) list of `FilterRule`s. A `SearchFilterStateValue` (and a
|
|
4
|
+
* saved filter, #4904) carries an ARRAY of these; groups themselves are
|
|
5
|
+
* always OR'd together, mirroring the selector grammar's `+` union
|
|
6
|
+
* (`IfcSlab, material=concrete + IfcDoor` → two groups).
|
|
7
|
+
*
|
|
8
|
+
* Kept in its own file (not folded into `filter-rules.ts`, already near the
|
|
9
|
+
* module-size cap) so both the evaluator and the serialization layer can
|
|
10
|
+
* import it without pulling in the whole rule taxonomy's JSON guards.
|
|
11
|
+
*/
|
|
12
|
+
import { type Combinator, type FilterRule } from './filter-rules.js';
|
|
13
|
+
export interface FilterGroup {
|
|
14
|
+
rules: FilterRule[];
|
|
15
|
+
combinator: Combinator;
|
|
16
|
+
}
|
|
17
|
+
/** A fresh, empty AND group — what a brand-new filter (or a brand-new
|
|
18
|
+
* group added in the builder) starts from. */
|
|
19
|
+
export declare function emptyFilterGroup(): FilterGroup;
|
|
20
|
+
export declare function isFilterGroup(value: unknown): value is FilterGroup;
|
|
21
|
+
/**
|
|
22
|
+
* Render `groups` back as selector-ish text — NOT a full inverse of
|
|
23
|
+
* `parseSelector`/`selectorToFilterRules` (most rule kinds have no single
|
|
24
|
+
* canonical spelling; a regex `Name` rule and a typed-in `contains` rule
|
|
25
|
+
* both become `Rule.name`, and only one of those round-trips through text).
|
|
26
|
+
* What this DOES round-trip exactly is the shape the selector's own union
|
|
27
|
+
* syntax cares about: class names (`IfcWall`, `IfcDoor`, …) and GlobalIds,
|
|
28
|
+
* `+`-joined across groups. Used by the Selector field to echo back what
|
|
29
|
+
* the CURRENT filter state reads as, so adding a second group in the
|
|
30
|
+
* builder is visible as a second `+`-joined clause without leaving the
|
|
31
|
+
* builder (#4904).
|
|
32
|
+
*
|
|
33
|
+
* All-or-nothing: an empty group, or a group whose rules do not reduce to
|
|
34
|
+
* exactly ONE renderable clause, makes the WHOLE echo `''` rather than a
|
|
35
|
+
* partial rendering — review (PR #4987) caught that joining per-group
|
|
36
|
+
* fragments with `+` regardless produced text that read as a DIFFERENT
|
|
37
|
+
* query than what evaluation actually runs: an empty group left a
|
|
38
|
+
* dangling ` + `, and several `ifcType`/`globalId` rules AND'd within one
|
|
39
|
+
* group rendered as comma-separated union terms (selector-text unions use
|
|
40
|
+
* `,` to ADD classes, not narrow them), so a two-rule AND group echoed as
|
|
41
|
+
* something the evaluator would read as broader than what it actually
|
|
42
|
+
* matches. Silently showing a narrower or broader query back to the user
|
|
43
|
+
* is the same "matched nothing, said nothing" defect class #4091 exists to
|
|
44
|
+
* avoid, so this omits the echo entirely rather than guess.
|
|
45
|
+
*/
|
|
46
|
+
export declare function groupsToSelectorText(groups: readonly FilterGroup[]): string;
|
|
47
|
+
/** The rules of `groups[activeIndex]`, clamped into range — what the
|
|
48
|
+
* builder's active-group actions (`addFilterRule` etc., `searchSlice.
|
|
49
|
+
* filterGroups.ts`) operate on. Callers outside the store (HierarchyPanel's
|
|
50
|
+
* upsert-by-kind) read this instead of reimplementing the clamp. */
|
|
51
|
+
export declare function activeGroupRules(groups: readonly FilterGroup[], activeIndex: number): FilterRule[];
|
|
52
|
+
/** Total rule count across every group — what "empty filter" checks and rule
|
|
53
|
+
* count badges read, since a `groups.length === 1` filter with zero rules
|
|
54
|
+
* in that one group must still read as empty. */
|
|
55
|
+
export declare function totalRuleCount(groups: readonly FilterGroup[]): number;
|
|
56
|
+
/**
|
|
57
|
+
* Parse a persisted `groups` array, refusing (returning `null`) the WHOLE
|
|
58
|
+
* query rather than silently dropping a group this build cannot read. A
|
|
59
|
+
* saved filter with an unreadable group is exactly the "matched nothing,
|
|
60
|
+
* said nothing" defect class #4091 exists to avoid — narrowing it to the
|
|
61
|
+
* readable groups would change which elements a `+` union matches without
|
|
62
|
+
* telling anyone.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseFilterGroups(raw: unknown): FilterGroup[] | null;
|
|
65
|
+
//# sourceMappingURL=filter-groups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-groups.d.ts","sourceRoot":"","sources":["../../src/filter/filter-groups.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAgB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEnF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;+CAC+C;AAC/C,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAQlE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAU3E;AAiBD;;;qEAGqE;AACrE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,EAAE,CAIlG;AAED;;kDAEkD;AAClD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAIrE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,EAAE,GAAG,IAAI,CAmBpE"}
|