pub struct RuleSpec {
pub index: usize,
pub id: RuleId,
pub languages: Vec<String>,
pub severity: Severity,
pub card: RuleCard,
pub queries: BTreeMap<String, String>,
pub gates: Gates,
pub timeout: Option<Duration>,
pub has_reduce: bool,
pub component: Option<ComponentRule>,
}Expand description
A rule as the config declares it.
Fields§
§index: usizeZero-based position in the config’s rules array.
This is how the engine reaches the handler: the rule object lives in the loaded config, and indexing into it is what lets a function cross the boundary without ever being extracted as a value.
It is the position in the config and the position in the entry module’s array, and
those have to stay one number. A component-backed rule has no entry in that array —
its handlers are not JavaScript — so json::rules_module emits a null placeholder to
hold its place rather than closing the gap. Numbering the array separately would leave
every rule after a component pointing at its neighbor’s handler: the call succeeds, and
the violations are attributed to the wrong rule.
It is therefore not a position in Config::rules, and is not unique across it. A
component hosts a list of rules, so one entry in the config’s array — one placeholder —
can produce several RuleSpecs, and every one of them carries the position of the
reference. Which of the component’s own rules a spec is lives on
ComponentRule::index, and the two numberings answer different questions: this one
names a slot in the entry module, that one names a rule inside a compiled program.
id: RuleIdNamespaced identifier.
languages: Vec<String>Which languages’ grammars the query compiles against, and which files the rule runs on.
A rule runs on a file only when the file’s own language is one of these, and it is
then parsed with that grammar. Running every rule against every file with a single
declared grammar is what used to turn a .tsx file into a tree of ERROR nodes —
silently, since a query simply matches nothing inside one.
severity: SeveritySeverity as the rule declares it, before config overrides.
card: RuleCardThe rule card.
queries: BTreeMap<String, String>Language id → query source, one entry per language the rule targets.
The exact cover — every declared language present, nothing extra — is enforced by
build_rule; the engine compiles each entry against that language’s grammar.
gates: GatesPre-parse gates.
timeout: Option<Duration>A per-invocation budget overriding the default.
has_reduce: boolWhether the rule has a reduce phase.
component: Option<ComponentRule>The compiled component this rule’s handlers live in, or None for a TypeScript rule.
This is what sends a rule to one engine or the other. lanekeep-engine runs a rule
with None through lanekeep-js and a rule with Some through lanekeep-wasm, in the
same run over the same corpus — the decision is a property of the rule and is made here,
where a rule is described, rather than by the engine guessing from anything else.
Every other field of a component-backed rule is the component’s own answer to
metadata, read once here at config load. There is no config syntax carrying an id, a
query or a card beside a .wasm reference, and there deliberately never was: a second
description of a rule is drift that has to be kept in step with the first.
Trait Implementations§
impl Eq for RuleSpec
impl StructuralPartialEq for RuleSpec
Auto Trait Implementations§
impl Freeze for RuleSpec
impl RefUnwindSafe for RuleSpec
impl Send for RuleSpec
impl Sync for RuleSpec
impl Unpin for RuleSpec
impl UnsafeUnpin for RuleSpec
impl UnwindSafe for RuleSpec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more