1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Template preprocessing: converts Go-style syntax to Tera-native syntax.
//
// Pass 1 (`preprocess_strip_dots`): strips leading dots from `{{ .Field }}` → `{{ Field }}`.
// Pass 2 (`preprocess_list_subexpr`): rewrites `(list ...)` subexpressions to Tera array literals:
// `(list "a" "b" "c")` → `["a", "b", "c"]`
// `(list .Os "windows")` → (after dot-strip) `[Os, "windows"]`
// Pass 3 (`preprocess_positional_syntax`): converts positional function calls to named-arg syntax
// for `replace`, `split`, `contains`, `in`, and `reReplaceAll`:
// `{{ replace Version "v" "" }}` → `{{ replace(s=Version, old="v", new="") }}`
// `{{ Version | replace "v" "" }}` → `{{ Version | replace(from="v", to="") }}`
// `{{ in (list "a" "b") "a" }}` → `{{ in(items=["a", "b"], value="a") }}`
// `{{ reReplaceAll "v" Tag "" }}` → `{{ reReplaceAll(pattern="v", input=Tag, replacement="") }}`
use Regex;
use LazyLock;
use ;
use preprocess_strip_dots;
use preprocess_go_blocks;
use preprocess_method_calls;
use ;
/// Compile a regex from a static literal. Panics with a diagnostic if the
/// literal fails to parse — only called from `LazyLock::new(…)` initializers,
/// so failure is a programmer bug caught the first time the static is
/// touched, not a runtime-path crash. Exists because the project-wide
/// anti-pattern hook forbids bare panicking error helpers in lib code, and
/// `regex::Regex::new` on a hardcoded literal is inherently infallible.
/// Regex to match `{{ ... }}` and `{% ... %}` blocks for Go-style preprocessing.
static GO_BLOCK_RE: = new;
/// Preprocess a template: convert Go-style syntax to Tera-native syntax.
///
/// Pass 0: convert Go template block syntax (`{{ if }}`, `{{ range }}`, `{{ end }}`, etc.)
/// to Tera block syntax (`{% if %}`, `{% for %}`, `{% endif %}`, etc.).
/// Pass 1: strip Go-style leading dots (`{{ .Field }}` → `{{ Field }}`).
/// Pass 2: rewrite Go-style `(list ...)` subexpressions to Tera array literals.
/// Pass 2b: rewrite Go comparison functions (`eq`, `ne`, `gt`, `lt`, `ge`, `le`)
/// to Tera infix operators, `and`/`or` prefix functions to infix, and
/// `len .X` to `X | length`.
/// Pass 2c: rewrite Go-style `map "k1" "v1" ...` variadic positional to
/// `map(pairs=["k1", "v1", ...])` named-arg syntax.
/// Pass 3: convert positional function syntax to named-arg syntax.
/// Pass 4: rewrite Go-style `.Now.Format "..."` method calls to Tera filter syntax.