README
¶
tree-sitter-cisco-ios-jinja2
A tree-sitter grammar for Cisco IOS configuration files with Jinja2 templating support — parse real running-config files or Jinja2-templated ones (for ciscoconfparse, nornir, Ansible, …) into a structured AST.
Installation
Node / npm
npm install tree-sitter-cisco-ios-jinja2
Python
pip install tree-sitter-cisco-ios-jinja2
Go
go get github.com/dgethings/tree-sitter-cisco-ios-jinja2
C (build from source)
make && make install # installs libtree-sitter-cisco-ios-jinja2.{a,so} + headers + .pc
Usage
Node
import Parser from "tree-sitter";
import CiscoIosJinja2 from "tree-sitter-cisco-ios-jinja2";
const parser = new Parser();
parser.setLanguage(CiscoIosJinja2);
const tree = parser.parse(
"interface GigabitEthernet0/0\n description uplink\n speed 1000\n!\n",
);
console.log(tree.rootNode.toString());
(config
(interface_section
(interface_header
name: (interface_name))
(description_statement
text: (value))
(speed_statement
value: (value))
(eos)))
Python
from tree_sitter import Language, Parser
import tree_sitter_cisco_ios_jinja2
parser = Parser(Language(tree_sitter_cisco_ios_jinja2.language()))
tree = parser.parse(
b"interface GigabitEthernet0/0\n"
b" description uplink\n"
b" speed 1000\n"
b"!\n"
)
print(tree.root_node.sexp())
Supported syntax
- IOS sections (bodies terminated by
!):interface <name>…!→interface_sectionrouter <ospf|bgp> <id>…!→router_section
- Generic command lines — every word-leading line parses to a
command_linenode (identifier+repeat(arg)); multi-word command identity (e.g.ip address) is resolved downstream by the LSP againstdata/commands.json, not by the AST. - Rich families (override the generic backbone where fields matter):
- interface —
description,shutdown,speed,duplex,mtu - router / address-family —
address-family,neighbor,network,redistribute,passive-interface,router-id,exit-address-family,metric-style,graceful-restart,queue-depth,compatible,auto-cost,aggregate-address,af-interface,autonomous-system,maximum-prefix,summary-prefix,default-information,distribute-list - global —
snmp-server,scheduler,hw-module,memory,rtr,exception,subscriber,mac-address-table,kerberos,boot,tacacs-server,parser - line —
login,password,transport,exec-timeout,access-class,terminal-type,length,width,editing,motd-banner,escape-character,activation-character,databits,parity,padding,stopbits - access-list (ACE) —
permit,deny(generic across the five ACL/mACL sub-modes) - misc —
match,set,class(multi-mode generics),remote-span,private-vlan(vlan),police,priority,drop,random-detect(policy-map-class),auto-sync(redundancy),continue(route-map) - service / timestamps / hostname / version — the earliest rich rules; see
test/corpus/service.txt
- interface —
- Generic
nonegation —no <command>wraps any line or section header as anegated_statement. - Jinja2 templating:
- Control:
{% for %}/{% endfor %}(with optional{% else %}),{% if %}/{% elif %}/{% else %}/{% endif %},{% set %}/{% endset %},{% block %}/{% endblock %},{% macro %}/{% endmacro %},{% call %},{% filter %},{% with %}/{% endwith %},{% extends %},{% include %},{% import %},{% raw %} - Output:
{{ expr }} - Comments:
{# ... #}
- Control:
Development
Prerequisites
- Node.js + a C compiler (for
node-gypbuildingsrc/parser.c) tree-sitter-cli— provided as an npm devDependency (npm installbrings it)- Go ≥ 1.23
- Python ≥ 3.10 +
uv
Running tests
make test # runs tests in tests/corpus
npm install && npm test # node binding
go test ./bindings/go # go binding
Development loop
Add test(s) to test/corpus, either by adding to an existing file or by creating a new file.
Run the tests using make test. Only your added test should fail.
Update grammer.js to implement the parser and generate the AST.
Rerun the test using make test. All tests should pass.
Thanks
Obvious thanks go to the Treesitter folks for the project.
The Jinja2 part of the parser is heavily inspired by geigerzaehler/tree-sitter-jinja2. There is/was no license in that repo, so I hope this is ok.
Click to show internal directories.
Click to hide internal directories.