Regex matching for the matches / notMatches ops, shared by every rule
kind that owns them.
kind is the producer speaking (see TextKind). A declared operand is
a regular-expression SOURCE and the WHOLE string is the pattern, slashes
included — that is what makes the selector Name=//tmp// look for /tmp/
rather than tmp. An operand with no declared kind is free text under the
Lists-panel convention (#1591): a /body/flags literal is a pattern, flags
and all, and anything else is a bare source. That is the spelling the chip
editors ask for, and there the slashes ARE the user's only way to say
"pattern", so reading them is the grammar rather than a guess.
Case-SENSITIVE, unlike every other op here: the selector grammar's /…/ is
a Python regular expression, and those do not fold case. Write JavaScript's
equivalent of (?i) by adding an i flag to a full literal (/wand/i).
An empty operand never matches; a MALFORMED literal (bad regex syntax)
never matches either (compileNameMatcher logs it and falls back to an
exact compare against the literal text, which no property value equals).
An UNSAFE pattern — syntactically valid but rejected by
@ifc-lite/regex-guard as catastrophic-backtracking-shaped or over the
length cap — is different: compileNameMatcher THROWS a plain Error
naming the pattern and reason, once, on the first row that reaches it.
This function does not catch that throw; it propagates out of
stringOpMatches / matchStringAnyNone / valueOpMatches and out of
filter-evaluate.ts's per-entity loop. Every current caller of the
evaluator (SearchModal.filter.tsx's runFilter, resolveClashSetFilter,
query-adapter.ts's entitiesMatchingActiveFilter) already wraps its call
in a try/catch that turns this into a visible, recoverable error rather
than an unhandled exception — see those call sites for how each one
surfaces it. A new caller of evaluateFilterRules /
evaluateFilterRulesFederated MUST do the same.
Regex matching for the
matches/notMatchesops, shared by every rule kind that owns them.kindis the producer speaking (see TextKind). A declared operand is a regular-expression SOURCE and the WHOLE string is the pattern, slashes included — that is what makes the selectorName=//tmp//look for/tmp/rather thantmp. An operand with no declared kind is free text under the Lists-panel convention (#1591): a/body/flagsliteral is a pattern, flags and all, and anything else is a bare source. That is the spelling the chip editors ask for, and there the slashes ARE the user's only way to say "pattern", so reading them is the grammar rather than a guess.Case-SENSITIVE, unlike every other op here: the selector grammar's
/…/is a Python regular expression, and those do not fold case. Write JavaScript's equivalent of(?i)by adding aniflag to a full literal (/wand/i).An empty operand never matches; a MALFORMED literal (bad regex syntax) never matches either (
compileNameMatcherlogs it and falls back to an exact compare against the literal text, which no property value equals).An UNSAFE pattern — syntactically valid but rejected by
@ifc-lite/regex-guardas catastrophic-backtracking-shaped or over the length cap — is different:compileNameMatcherTHROWS a plainErrornaming the pattern and reason, once, on the first row that reaches it. This function does not catch that throw; it propagates out ofstringOpMatches/matchStringAnyNone/valueOpMatchesand out offilter-evaluate.ts's per-entity loop. Every current caller of the evaluator (SearchModal.filter.tsx'srunFilter,resolveClashSetFilter,query-adapter.ts'sentitiesMatchingActiveFilter) already wraps its call in a try/catch that turns this into a visible, recoverable error rather than an unhandled exception — see those call sites for how each one surfaces it. A new caller ofevaluateFilterRules/evaluateFilterRulesFederatedMUST do the same.