| name | add-shellspec-rule |
| description | Add a new ShellSpec grammar rule with tests, following project conventions |
Add ShellSpec Rule
Follow these steps to add a new ShellSpec construct to the grammar:
Arguments
rule_name (required): Name of the ShellSpec construct (e.g., "Tag", "Filter")
type (required): One of block (needs End terminator), statement (single-line), directive (% prefixed)
Steps
-
Research the construct in ShellSpec documentation. Understand its syntax, variants, and where it appears in real spec files.
-
Add the rule to grammar.js:
- Prefix the rule name with
shellspec_ (e.g., shellspec_tag_statement)
- For blocks: use
prec.right() with seq(keyword, ..., repeat($._terminated_statement), "End")
- For statements: use
seq(keyword, ...args)
- For directives: use
seq("%" + name, ...args)
- Use
field() for named parts (e.g., field("description", ...))
-
Register in _statement_not_subshell: Add the new rule to the choice array in _statement_not_subshell.
-
Create corpus tests in the appropriate test/corpus/*.txt file:
- Include basic usage, all variants, and edge cases
- Follow the corpus format:
=== header, code, --- separator, S-expression AST
- Aim for 3-5 test cases minimum
-
Update queries/highlights.scm: Add highlighting patterns for any new keywords.
-
Verify:
- Run
npm run generate — check for new conflicts (minimize them)
- Run
npm test — all tests must pass
- Run spec file check:
for f in test/spec/*.sh; do tree-sitter parse "$f" 2>&1 | grep -c ERROR; done
-
Update documentation:
- Update the rule list in CLAUDE.md
- Update the ShellSpec Language Support section in README.md
Grammar Gotchas (from CLAUDE.md)
- Don't use compound keyword tokens (e.g.,
"Data:raw") — they force tokenizer behavior globally
prec(N) on simple alternatives can beat prec.right(M) on blocks at the initial ambiguity point
[ ... ] is $.test_command in tree-sitter-bash, not literal bracket tokens