PassiveScan::Matcher
Constants
A token that can match \n: \s, a negated class, \n itself, …
Constructs that make a whole-file gate unsound: absolute anchors
(\A \z \Z \G) hold only at the file's edges, not each line's,
and a (*VERB) can change newline handling or matching outright. A
pattern carrying one gets no gate and is left to the per-line loop.
Lookarounds, atomic groups and possessive quantifiers keep the plain
gate: at a line edge they see the \n where the per-line match sees
the end of the string, which only differs for a construct that
reaches across the newline — and treating them as gate-less made a
gitleaks-style (?<![A-Za-z0-9])…(?![A-Za-z0-9]) rule set walk every
line of every file.
Constructs Regex.union changes the meaning of. The union renumbers
capture groups, so a \1, \g{1}, (?1) or (?(1)…) in any pattern
but the first points at the wrong group; and under (?x) a #
comment runs to the end of the joined source and swallows the union's
closing parens, so the whole rule failed to compile. Over-matching
here (an escaped \\1) only costs the union fast path.
Constructors
Class methods
True when pattern has an unescaped ^ or $ outside a character
class. A misread here only costs a MULTILINE gate, which still accepts
every line the pattern can match.
True when a negative lookaround in pattern can match a newline. At a
line's end the per-line match sees end-of-string where the whole-file
gate sees \n and the next line, so key(?!\s*=\s*null) fires on the
line key but the gate rejects key\n= null and the rule never runs.
Over-matching here only costs the gate.
Instance methods
or: the single union every pattern is folded into, or nil when the
patterns cannot share one (see UNION_UNSAFE) and are matched one by
one through compiled_regexes instead.
or: the single union every pattern is folded into, or nil when the
patterns cannot share one (see UNION_UNSAFE) and are matched one by
one through compiled_regexes instead.
One compiled regex per pattern, under either condition.
True when this matcher's regexes failed to compile. detect.cr checks it to short-circuit instead of retrying the (already-broken) compilation on every line.
Why this matcher's regexes failed to compile, or nil when they
compiled. Held as the message rather than a bare flag so the
loader can name the pattern in the warning it prints — the
previous shape wrote the reason straight to Crystal's global
Log, whose default backend is STDOUT, so it landed in the
middle of -f json / -f sarif output and broke every
downstream parser.
Whether a regex matcher fires on content (a line, as detect.cr
calls it). Shared with the false-positive gate so both agree on what
fired.
Whole-file form of regex_match?: false only when no line of
content can satisfy this matcher.
Pre-stringified patterns. detect.cr's hot path used to call
pattern.to_s per (file × line × matcher); the conversion is the
same every call so we do it once at load time.
Pre-stringified patterns. detect.cr's hot path used to call
pattern.to_s per (file × line × matcher); the conversion is the
same every call so we do it once at load time.
word patterns as escaped literal regexes: one union for or,
one regex per pattern for and. A literal regex matches exactly
where String#includes? does, and PCRE2 (with
Noir::TextFile::MATCH_OPTIONS) scans a whole file far faster
than includes?'s rolling hash, which restarts per pattern.