Canonical-emit pretty-printer for %Linx.Netfilter.Ruleset{}.
The inverse of Linx.NFT.Compiler: walks the ruleset value and
emits syntactically valid nft source. The output round-trips
back through Linx.NFT.parse/1 to a structurally equivalent
ruleset (modulo trivia — format/1 makes no attempt to preserve
the comments, blank lines, or original ordering of items it
wasn't itself told about). Trivia-preserving emit is a v2
enhancement; this commit's goal is canonicalisation, not source
fidelity.
Per-construct policy
- Tables are emitted in
{family, name}order. - Inside each table: chains first, then sets, then maps and vmaps. (Element-order across these blocks is independent of original source.)
- Chains emit the full base header (
type hook priority) on one line, thenpolicy Xon the next (if set), a blank line, then one rule per line. - Rules emit as a single space-joined statement sequence,
optionally trailed by
comment "…". - Expressions are paired into match statements (
payload + cmp→tcp dport 22,payload + bitwise + cmp→ CIDR,payload + lookup→tcp dport @ports,payload + __anon_set→tcp dport { 22, 80 },ct + cmp→ct state established,meta + cmp→meta iif "eth0"). Standalone expressions (counter,log,reject, NAT, etc.) emit as their token form.
Limitations
Anything the formatter doesn't yet know how to render emits a
# <unsupported expression: …> comment in line, so the output
remains valid nft (a comment) and the gap is visible. As the
compiler grows (e.g. limit, meta mark set), the formatter
gains the inverse cases alongside.
mix format integration
Implements the Mix.Tasks.Format behaviour: when listed under
:plugins in a project's .formatter.exs, mix format
reflows both inline ~NFT"…" sigil bodies inside .ex
sources AND standalone .nft files. Users wire it up with:
# .formatter.exs
[
plugins: [Linx.NFT.Formatter],
inputs: ["{lib,test}/**/*.{ex,exs}", "**/*.nft"]
]Behaviour:
- Static
~NFTsigil body /.nftfile — parses, runs throughformat/1, returns the canonical single-formatted source. Idempotent. - Interpolation-bearing
~NFTsigil body — left verbatim. AST-aware formatting that preserves#{…}positions while reflowing the surrounding nft syntax is a future enhancement. - Parse error in a
.nftfile — raisesLinx.NFT.ParseError, surfacing visibly so the user fixes the bad file. (For sigils, parse errors leave the body unchanged — the surrounding compile run will report the same error anyway, with better stack context.)
Summary
Functions
Emits %Ruleset{} as nft source. Always returns a binary; never
raises.
Functions
@spec format(Linx.Netfilter.Ruleset.t()) :: String.t()
Emits %Ruleset{} as nft source. Always returns a binary; never
raises.