toml_path_equals
Query a structured document with a JSONPath expression and assert every match deep-equals the supplied value.
Semantics:
- Multiple matches — every match must equal the expected value.
- Zero matches — counts as a violation (the key the rule is enforcing doesn't exist).
- Unparseable files — one violation per file (not silently skipped).
- Numbers compare by value, in every format and at any depth:
equals: 1matches a document's1.0(or1e0), andequals: 1.0matches1. The comparison is exact: an integer equals a float only when the float is a whole number of exactly that value, so9007199254740993does not equal9007199254740992.0even though both round to the same 64-bit float. There is no other coercion: a string"1"never equals the number1. (New in v0.18; this supersedes the HCL whole-number caveat above.)
XML mapping applies to every XML surface: xml_path_*, json_schema_passes format: xml, and the xml: extract used by cross_file / file_graph / registry_paths_resolve. XML is mapped to the queryable tree with the xmltodict-style convention so the JSONPath reads like the XML — the document is { <root-element>: … } ($.Project…, $.project…); attributes are @name keys (['@Version'], in bracket notation, since .@Version is not valid JSONPath); a leaf element collapses to its text (<TargetFramework>net8.0</TargetFramework> → "net8.0"); namespaces flatten to the local name (Maven's default pom.xml namespace just works). Two properties of XML's data model to keep in mind:
- Every XML leaf value is a string. Quote expected values (
equals: "4.0.0", notequals: 4.0.0), reach for*_path_matches, and in ajson_schema_passesschema type XML fields asstringwith apattern—type: integer/boolean/numberalways fail against XML (every leaf is a string);type: array/objectadditionally depend on cardinality (next point). - Cardinality is data-dependent. A single
<dependency>is an object (a string for a leaf element); two or more become an array. A[*]wildcard therefore does not normalize cardinality —dependency[*]reads nothing for one element but every element for many, and a leaf query flips the same way (an attribute such as MSBuild'sCondition=also turns a would-be leaf string into a{ "@Condition": …, "#text": … }object). When a rule must handle both one and many, use recursive descent:$.Project.ItemGroup.ProjectReference..['@Include']reads the@Includeof one or many. Scope the..under a parent element so it does not over-match a same-named key elsewhere.
Full rationale and edge cases: docs/design/v0.10/xml_path.md.
Options
Section titled "Options"| Option | Type | Required | Default | Description |
|---|---|---|---|---|
equals | any value | yes | Expected value. Any JSON type (string, number, boolean, null, array, object). | |
if_present | boolean | false | When true, a query returning zero matches is silently OK - only real matches that fail the op produce violations. | |
path | string | yes | JSONPath expression rooted at $. Supports dot-access ($.foo.bar), array index ($.deps[0]), wildcards ($.deps[*]), filters, and every other RFC 9535 construct. |
Plus the common paths, level, id, when, and expect_matches fields. This table is generated from the JSON Schema; option types and defaults are authoritative.
Example
Section titled "Example"A crate pinned to an older Rust edition
Section titled "A crate pinned to an older Rust edition"The rule fires on this repository:
- crates/
- crates/bad/
- crates/bad/Cargo.toml
⚠ warning rust-edition-2024
value at path does not equal expected: expected "2024", got "2021"
- crates/ok/
- crates/ok/Cargo.toml✓
[package]name = "bad"edition = "2021"[package]name = "ok"edition = "2024"With this .alint.yml:
version: 1rules: - id: rust-edition-2024 kind: toml_path_equals paths: "crates/*/Cargo.toml" path: "$.package.edition" equals: "2024" level: warningalint check reports:
--- crates/bad/Cargo.toml ------------------------------------------------------ ! warning rust-edition-2024 value at path does not equal expected: expected "2024", got "2021"
Summary (1 violation): ! 1 warning 0 passing * 1 failingEvery crate targets the 2024 edition
Section titled "Every crate targets the 2024 edition"This repository is compliant:
- crates/
- crates/a/
- crates/a/Cargo.toml✓
- crates/b/
- crates/b/Cargo.toml✓
[package]name = "a"edition = "2024"[package]name = "b"edition = "2024"With this .alint.yml:
version: 1rules: - id: rust-edition-2024 kind: toml_path_equals paths: "crates/*/Cargo.toml" path: "$.package.edition" equals: "2024" level: warningalint check reports:
v All 1 rule(s) passed.