add cache

This commit is contained in:
danhanson committed 2026-09-07 15:20:21 -05:00
1 parent 7e71c5e3ae
commit 709a33f52d
8 files changed
+40910 -35539

No files matched your search

+6 -1
View File
@@ -106,7 +106,7 @@ which Django itself enforces while it parses the template ("add requires 2 argum
### First-party libraries ### First-party libraries
Django ships `i18n`, `l10n`, `static`, `cache` and `tz` as libraries rather than builtins. Their tags are Django ships `i18n`, `l10n`, `static`, `cache` and `tz` as libraries rather than builtins. Their tags are
modelled as ordinary tags (so far: `static`, `l10n`, `tz`), and the grammar **never requires the `{% load %}`**, because modelled as ordinary tags (so far: `static`, `l10n`, `tz`, `cache`), and the grammar **never requires the `{% load %}`**, because
an engine can preload a library through `OPTIONS: {"builtins": [...]}`, which makes `{% static "a" %}` valid an engine can preload a library through `OPTIONS: {"builtins": [...]}`, which makes `{% static "a" %}` valid
with no load at all. with no load at all.
@@ -205,5 +205,10 @@ documentation or memory. Both checks are worth repeating whenever tags, filters
bits from the end, so `{% static "a" junk %}` and `{% static "a" as u v %}` are accepted there and bits from the end, so `{% static "a" junk %}` and `{% static "a" as u v %}` are accepted there and
rejected here, and `PrefixNode.handle_token` raises `IndexError` rather than `TemplateSyntaxError` on rejected here, and `PrefixNode.handle_token` raises `IndexError` rather than `TemplateSyntaxError` on
`{% get_static_prefix as %}`. `{% get_static_prefix as %}`.
- Django's `{% cache %}` takes its fragment name as the raw word in that position and finds the cache to
use by testing whether the last word starts with `using=`, and only when something precedes it. So
`{% cache 500 sidebar.name %}` names a fragment there, `{% cache 500 using="c" %}` names a fragment
called `using="c"` rather than choosing a cache, and `{% cache 500 sidebar using= %}` takes an empty
name. All three are errors here.
- `partial`/`partialdef` are Django builtins as of Django 6; `elif`/`else`/`empty` are modelled as parts of - `partial`/`partialdef` are Django builtins as of Django 6; `elif`/`else`/`empty` are modelled as parts of
their enclosing tag rather than as separate tags. their enclosing tag rather than as separate tags.
+14
View File
@@ -247,6 +247,7 @@ const NAMES_INSIDE_A_TAG_GROUP = [
"empty", "empty",
"endautoescape", "endautoescape",
"endblock", "endblock",
"endcache",
"endcomment", "endcomment",
"endfilter", "endfilter",
"endfor", "endfor",
@@ -378,6 +379,7 @@ const django = grammar({
choice( choice(
$.autoescape_group, $.autoescape_group,
$.block_group, $.block_group,
$.cache_group,
$.comment_group, $.comment_group,
$.csp_nonce_attr, $.csp_nonce_attr,
$.csrf_token, $.csrf_token,
@@ -461,6 +463,18 @@ const django = grammar({
optional($.template), optional($.template),
block("endblock", $.pop_block), block("endblock", $.pop_block),
), ),
cache_group: ($) =>
seq(
block(
"cache",
part($.filtered_value),
part(choice($.identifier, $.string)),
repeat(part($.filtered_value)),
optional(part(seq("using=", $.filtered_value))),
),
optional($.template),
block("endcache"),
),
comment_group: ($) => comment_group: ($) =>
seq( seq(
block("comment", optional(part($.string))), block("comment", optional(part($.string))),
+2
View File
@@ -50,6 +50,8 @@ tag: [
("endautoescape") ("endautoescape")
("block") ("block")
("endblock") ("endblock")
("cache")
("endcache")
("comment") ("comment")
("endcomment") ("endcomment")
("csp_nonce_attr") ("csp_nonce_attr")
+3
View File
@@ -24,6 +24,9 @@
(get_media_prefix (get_media_prefix
tag: ("get_media_prefix") @library.static) tag: ("get_media_prefix") @library.static)
(cache_group
tag: ("cache") @library.cache)
(localize_group (localize_group
tag: ("localize") @library.l10n) tag: ("localize") @library.l10n)
+196
View File
@@ -542,6 +542,10 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "block_group" "name": "block_group"
}, },
{
"type": "SYMBOL",
"name": "cache_group"
},
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "comment_group" "name": "comment_group"
@@ -1293,6 +1297,194 @@
} }
] ]
}, },
"cache_group": {
"type": "SEQ",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "{%"
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "tag",
"content": {
"type": "STRING",
"value": "cache"
}
},
{
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "SYMBOL",
"name": "filtered_value"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "string"
}
]
}
]
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "SYMBOL",
"name": "filtered_value"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "using="
},
{
"type": "SYMBOL",
"name": "filtered_value"
}
]
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "%}"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "template"
},
{
"type": "BLANK"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "{%"
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "tag",
"content": {
"type": "STRING",
"value": "endcache"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[ \\t\\r\\n]+"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "%}"
}
]
}
]
},
"comment_group": { "comment_group": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
@@ -5423,6 +5615,10 @@
"type": "STRING", "type": "STRING",
"value": "endblock" "value": "endblock"
}, },
{
"type": "STRING",
"value": "endcache"
},
{ {
"type": "STRING", "type": "STRING",
"value": "endcomment" "value": "endcomment"
+58
View File
@@ -11,6 +11,10 @@
"type": "block_group", "type": "block_group",
"named": true "named": true
}, },
{
"type": "cache_group",
"named": true
},
{ {
"type": "comment_group", "type": "comment_group",
"named": true "named": true
@@ -246,6 +250,48 @@
] ]
} }
}, },
{
"type": "cache_group",
"named": true,
"fields": {
"tag": {
"multiple": true,
"required": true,
"types": [
{
"type": "cache",
"named": false
},
{
"type": "endcache",
"named": false
}
]
}
},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "filtered_value",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "string",
"named": true
},
{
"type": "template",
"named": true
}
]
}
},
{ {
"type": "comment_group", "type": "comment_group",
"named": true, "named": true,
@@ -1928,6 +1974,10 @@
"type": "by", "type": "by",
"named": false "named": false
}, },
{
"type": "cache",
"named": false
},
{ {
"type": "capfirst", "type": "capfirst",
"named": false "named": false
@@ -2028,6 +2078,10 @@
"type": "endblock", "type": "endblock",
"named": false "named": false
}, },
{
"type": "endcache",
"named": false
},
{ {
"type": "endcomment", "type": "endcomment",
"named": false "named": false
@@ -2448,6 +2502,10 @@
"type": "urlizetrunc", "type": "urlizetrunc",
"named": false "named": false
}, },
{
"type": "using=",
"named": false
},
{ {
"type": "utc", "type": "utc",
"named": false "named": false
+40396 -35538
View File
File diff suppressed because it is too large. Load diff
+235
View File
@@ -0,0 +1,235 @@
==================
Cache
==================
{% cache 500 sidebar %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(identifier)
(template
(content)))
(content))
==================
Cache With A Variable Timeout
==================
{% cache t sidebar %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(variable_attribute
(identifier))))
(identifier)
(template
(content)))
(content))
==================
Cache With A Filtered Timeout
==================
{% cache 500|add:1 sidebar %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number)))
(filter_expression
(filter
argument: (value
(literal
(number))))))
(identifier)
(template
(content)))
(content))
==================
Cache With A Quoted Fragment Name
==================
{% cache 500 "sidebar" %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(string)
(template
(content)))
(content))
==================
Cache Varying On Arguments
==================
{% cache 500 sidebar a b %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(filtered_value
(value
(variable_attribute
(identifier))))
(template
(content)))
(content))
==================
Cache Varying On A Filtered Argument
==================
{% cache 500 sidebar a|upper %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(variable_attribute
(identifier)))
(filter_expression
(filter)))
(template
(content)))
(content))
==================
Cache Using A Named Cache
==================
{% cache 500 sidebar using="c" %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(literal
(string))))
(template
(content)))
(content))
==================
Cache Using An Unquoted Cache Name
==================
{% cache 500 sidebar using=c %}x{% endcache %}
---
(template
(content)
(cache_group
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(template
(content)))
(content))
==================
Cache Without A Fragment Name
:error
==================
{% cache 500 %}x{% endcache %}
---
==================
Cache With Anything After Using
:error
==================
{% cache 500 sidebar using="c" extra %}x{% endcache %}
---
==================
Cache With An Empty Using
:error
==================
{% cache 500 sidebar using= %}x{% endcache %}
---
==================
Cache With An Attribute Fragment Name
:error
==================
{% cache 500 sidebar.name %}x{% endcache %}
---
==================
Cache With Using As Its Fragment Name
:error
==================
{% cache 500 using="c" %}x{% endcache %}
---