39 lines
2.2 KiB
Markdown
39 lines
2.2 KiB
Markdown
# tree-sitter-django
|
|
|
|
A [tree-sitter](https://tree-sitter.github.io/tree-sitter/) grammar for the Django Template Language (DTL) — the `{% %}` tags and `{{ }}` variables used in Django templates.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
npm install
|
|
npm run parser-generate # regenerate the parser from grammar.js
|
|
npm run parser-test # run the corpus tests in test/corpus
|
|
npm run parser-build # build the WASM binary
|
|
npm run playground # interactively explore the grammar
|
|
```
|
|
|
|
## Divergences from Django
|
|
|
|
The grammar aims to accept what Django accepts, with one deliberate exception. Where Django takes an
|
|
input without complaint but the input is almost certainly a mistake — it parses, and then silently
|
|
renders nothing or quietly ignores half of what was written — the grammar reports an error instead.
|
|
Every case below is input Django itself accepts:
|
|
|
|
- **Number-shaped names.** Django has no number token: a word is a literal if `int()` or `float()` parses
|
|
it and a variable lookup otherwise, so `0x1f`, `1a`, `1.`, `1.2.3` and `1__0` look up a variable of that
|
|
name and render nothing.
|
|
- **An attribute of `True`, `False` or `None`.** Every Django context is seeded with those three names, so
|
|
`{{ True.x }}` is an ordinary two-part lookup that can never resolve.
|
|
- **A keyword argument written twice.** `{% with a=1 a=2 %}`, and the same in `{% include %}` and
|
|
`{% blocktranslate %}`, where Django builds a dict and lets the last value win.
|
|
- **Anything after a `{% static %}` path.** `StaticNode.handle_token` looks for `as` two words from the end
|
|
and ignores the rest, so `{% static "a" junk %}` and `{% static "a" as url junk %}` render as if the
|
|
extra words were not there.
|
|
- **A `{% cache %}` argument meant as something other than the fragment name.** Django takes the raw word
|
|
in that position, so `{% cache 500 using="c" %}` names a fragment called `using="c"` rather than choosing
|
|
a cache, and `{% cache 500 sidebar.name %}` names one with a dot in it.
|
|
|
|
In the other direction the grammar is more permissive only where it cannot know better: the names a
|
|
`{% load %}` brings in live in Python, so `{{ x|lenght }}` cannot be told from a filter some library
|
|
registered, and an unknown tag's arguments are assumed to have the shape `simple_tag` gives them.
|