@barefootjs/rust 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +194 -0
  2. package/dist/adapter/analysis/component-tree.d.ts +26 -0
  3. package/dist/adapter/analysis/component-tree.d.ts.map +1 -0
  4. package/dist/adapter/boolean-result.d.ts +85 -0
  5. package/dist/adapter/boolean-result.d.ts.map +1 -0
  6. package/dist/adapter/emit-context.d.ts +107 -0
  7. package/dist/adapter/emit-context.d.ts.map +1 -0
  8. package/dist/adapter/expr/array-method.d.ts +75 -0
  9. package/dist/adapter/expr/array-method.d.ts.map +1 -0
  10. package/dist/adapter/expr/emitters.d.ts +143 -0
  11. package/dist/adapter/expr/emitters.d.ts.map +1 -0
  12. package/dist/adapter/index.d.ts +6 -0
  13. package/dist/adapter/index.d.ts.map +1 -0
  14. package/dist/adapter/index.js +189091 -0
  15. package/dist/adapter/lib/constants.d.ts +25 -0
  16. package/dist/adapter/lib/constants.d.ts.map +1 -0
  17. package/dist/adapter/lib/ir-scope.d.ts +50 -0
  18. package/dist/adapter/lib/ir-scope.d.ts.map +1 -0
  19. package/dist/adapter/lib/minijinja-naming.d.ts +64 -0
  20. package/dist/adapter/lib/minijinja-naming.d.ts.map +1 -0
  21. package/dist/adapter/lib/types.d.ts +32 -0
  22. package/dist/adapter/lib/types.d.ts.map +1 -0
  23. package/dist/adapter/memo/seed.d.ts +84 -0
  24. package/dist/adapter/memo/seed.d.ts.map +1 -0
  25. package/dist/adapter/minijinja-adapter.d.ts +421 -0
  26. package/dist/adapter/minijinja-adapter.d.ts.map +1 -0
  27. package/dist/adapter/props/prop-classes.d.ts +33 -0
  28. package/dist/adapter/props/prop-classes.d.ts.map +1 -0
  29. package/dist/adapter/spread/spread-codegen.d.ts +63 -0
  30. package/dist/adapter/spread/spread-codegen.d.ts.map +1 -0
  31. package/dist/adapter/value/parsed-literal.d.ts +28 -0
  32. package/dist/adapter/value/parsed-literal.d.ts.map +1 -0
  33. package/dist/build.d.ts +29 -0
  34. package/dist/build.d.ts.map +1 -0
  35. package/dist/build.js +189111 -0
  36. package/dist/conformance-pins.d.ts +13 -0
  37. package/dist/conformance-pins.d.ts.map +1 -0
  38. package/dist/index.d.ts +12 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +189112 -0
  41. package/package.json +67 -0
  42. package/runtime/Cargo.lock +124 -0
  43. package/runtime/Cargo.toml +21 -0
  44. package/runtime/src/backend_minijinja.rs +176 -0
  45. package/runtime/src/bin/bf-render.rs +147 -0
  46. package/runtime/src/evaluator.rs +770 -0
  47. package/runtime/src/lib.rs +19 -0
  48. package/runtime/src/manifest.rs +258 -0
  49. package/runtime/src/num.rs +558 -0
  50. package/runtime/src/runtime.rs +1548 -0
  51. package/runtime/src/search_params.rs +173 -0
  52. package/runtime/tests/eval_vectors.rs +94 -0
  53. package/runtime/tests/evaluator.rs +407 -0
  54. package/runtime/tests/helper_vectors.rs +348 -0
  55. package/runtime/tests/manifest.rs +169 -0
  56. package/runtime/tests/omit.rs +79 -0
  57. package/runtime/tests/props_attr.rs +75 -0
  58. package/runtime/tests/query.rs +50 -0
  59. package/runtime/tests/render_child.rs +210 -0
  60. package/runtime/tests/search_params.rs +68 -0
  61. package/runtime/tests/spread_attrs.rs +94 -0
  62. package/runtime/tests/template_primitives.rs +376 -0
  63. package/runtime/tests/vector-divergences.json +33 -0
  64. package/src/__tests__/minijinja-adapter-unit.test.ts +392 -0
  65. package/src/__tests__/minijinja-adapter.test.ts +58 -0
  66. package/src/__tests__/minijinja-counter.test.ts +61 -0
  67. package/src/__tests__/minijinja-query-href.test.ts +101 -0
  68. package/src/__tests__/minijinja-spread-attrs.test.ts +227 -0
  69. package/src/adapter/analysis/component-tree.ts +119 -0
  70. package/src/adapter/boolean-result.ts +177 -0
  71. package/src/adapter/emit-context.ts +119 -0
  72. package/src/adapter/expr/array-method.ts +346 -0
  73. package/src/adapter/expr/emitters.ts +608 -0
  74. package/src/adapter/index.ts +6 -0
  75. package/src/adapter/lib/constants.ts +37 -0
  76. package/src/adapter/lib/ir-scope.ts +95 -0
  77. package/src/adapter/lib/minijinja-naming.ts +85 -0
  78. package/src/adapter/lib/types.ts +35 -0
  79. package/src/adapter/memo/seed.ts +135 -0
  80. package/src/adapter/minijinja-adapter.ts +1796 -0
  81. package/src/adapter/props/prop-classes.ts +65 -0
  82. package/src/adapter/spread/spread-codegen.ts +168 -0
  83. package/src/adapter/value/parsed-literal.ts +76 -0
  84. package/src/build.ts +38 -0
  85. package/src/conformance-pins.ts +101 -0
  86. package/src/index.ts +12 -0
  87. package/src/test-render.ts +680 -0
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # @barefootjs/rust
2
+
3
+ minijinja (Rust) adapter for BarefootJS: compiles the BarefootJS IR (JSX →
4
+ IR, see `spec/compiler.md`) into `.j2` template files plus the client JS
5
+ bundle every other adapter produces, and ships a Rust rendering runtime
6
+ (`runtime/`, crate `barefootjs`) that renders those templates through a
7
+ plain [`minijinja::Environment`](https://docs.rs/minijinja) — no framework
8
+ is required (axum, actix-web, warp, bare `hyper`, etc. all work the same
9
+ way).
10
+
11
+ Near-verbatim port of `@barefootjs/jinja` (the Jinja2/Python adapter) to the
12
+ `minijinja` Rust crate. **The emitted template syntax is IDENTICAL** to
13
+ `@barefootjs/jinja`'s output — minijinja 2.21 is Jinja2-compatible for
14
+ everything this adapter emits (verified by an orchestrator spike; see the
15
+ Environment contract below). Only identity fields differ (`name: 'minijinja'`,
16
+ `extension: '.j2'`, class `MinijinjaAdapter`) plus the render engine that
17
+ interprets the syntax at request time (a Rust `minijinja::Environment`
18
+ instead of Python's `jinja2.Environment`). See
19
+ `src/adapter/minijinja-adapter.ts`'s header comment for the full
20
+ Kolon↔Jinja2 syntax-mapping table (inherited unchanged from `@barefootjs/jinja`)
21
+ and the JS-semantics divergences this port handles uniformly (truthiness,
22
+ stringification, reserved-word identifier mangling, and the
23
+ evaluator-only higher-order-callback lowering since Jinja has no lambda
24
+ expression).
25
+
26
+ ## Template output shape
27
+
28
+ - `name: 'minijinja'`, `extension: '.j2'`, `templatesPerComponent: true` —
29
+ one `.j2` file per component, named by snake-casing the PascalCase
30
+ component name (`UserCard` → `user_card.j2`).
31
+ - Hydration markers (`bf-s`, `bf-h`/`bf-m`/`bf-r`, `bf-p`, slot/conditional
32
+ comment markers, loop boundary comments) use the SAME runtime method
33
+ names as every other adapter's `bf.*` calls (`bf.scope_attr()`,
34
+ `bf.hydration_attrs()`, `bf.text_start`/`text_end`, `bf.comment(...)`,
35
+ …) — see `spec/template-helpers.md` for the shared helper contract.
36
+ - Every text/attribute interpolation of a possibly-non-string value is
37
+ routed through `bf.string(...)` (or `bf.bool_str(...)` for
38
+ boolean-shaped values); every non-comparison condition position is
39
+ routed through `bf.truthy(...)`. Both are pure Rust-runtime helpers —
40
+ see the Rust runtime pointer below.
41
+
42
+ ## The minijinja Environment contract
43
+
44
+ This adapter's output assumes an `Environment` constructed exactly as
45
+ follows (see `runtime/src/backend_minijinja.rs`):
46
+
47
+ ```rust
48
+ let mut env = Environment::new();
49
+ env.set_loader(minijinja::path_loader(templates_dir)); // .j2 files
50
+ env.set_undefined_behavior(UndefinedBehavior::Chainable); // == Jinja2's ChainableUndefined; `missing.deep` renders '' — verified
51
+ env.set_trim_blocks(true);
52
+ env.set_lstrip_blocks(true);
53
+ env.set_auto_escape_callback(|_| AutoEscape::Html); // REQUIRED: .j2 is not auto-escaped by default in minijinja
54
+ env.set_formatter(<custom formatter>);
55
+ ```
56
+
57
+ `trim_blocks`/`lstrip_blocks` are required because this adapter places
58
+ `{% … %}` control tags on their own source line; without them every such
59
+ line would leak a stray newline/indentation into the rendered HTML.
60
+
61
+ The **custom formatter** is the uniform emit policy that absorbs the
62
+ remaining JS/minijinja semantic differences (no per-fixture hacks anywhere —
63
+ all divergence-absorption lives here plus in the `bf` runtime helpers):
64
+
65
+ - `undefined`/`none` → print nothing
66
+ - safe values → raw passthrough
67
+ - strings → escape with MarkupSafe-compatible entities: `&` → `&amp;`, `<` →
68
+ `&lt;`, `>` → `&gt;`, `"` → `&quot;`, `'` → `&#39;` — **not** minijinja's
69
+ own default `&#x27;`; the conformance fixtures pin `&#39;` (matching
70
+ Python's MarkupSafe, which `@barefootjs/jinja`'s output also relies on)
71
+ - numbers → JS `String(n)` formatting (`1.0` → `1`) via the centralized
72
+ `format_js_number` — this is a **fallback**; templates normally already
73
+ route a value through `bf.string(...)` before it reaches the formatter
74
+ - bools → `true`/`false`
75
+
76
+ ### minijinja↔Jinja2 divergence record (orchestrator spike, minijinja 2.21.0)
77
+
78
+ Verified compatible before committing to the near-verbatim port strategy:
79
+
80
+ - `{{ missing }}` → `''`; `{% if missing.deep %}` → falsy, renders `''`
81
+ under `UndefinedBehavior::Chainable`
82
+ - `(x if (x is defined and x is not none) else 'FB')` → `'FB'` for both
83
+ undefined AND `none`, the value otherwise ⇒ `@barefootjs/jinja`'s `??`
84
+ lowering ports verbatim
85
+ - `{% set cap %}…{% endset %}` works; dict literals, `elif`, `loop.index0`,
86
+ `{% set %}` inside `{% for %}`, `~` concat, `| safe` all work identically
87
+ to Python's Jinja2
88
+ - method calls on a custom `Object` (`bf.to_str(42)`) work via
89
+ `Object::call_method`
90
+ - minijinja truthiness is Python-like (empty list/map/str are falsy) — same
91
+ as Python's Jinja2, and the reason JS truthiness MUST go through
92
+ `bf.truthy(...)` (the adapter already emits this, unchanged from the
93
+ Jinja2 port)
94
+
95
+ No divergence found that required a per-fixture special case; every
96
+ absorption point above is uniform (formatter, `bf` helper, or adapter emit
97
+ rule).
98
+
99
+ ## Rust runtime
100
+
101
+ `runtime/` is a self-contained Rust crate (`barefootjs`, deps: `minijinja`,
102
+ `serde`, `serde_json`) implementing the engine-agnostic `bf` object every
103
+ emitted template calls into: hydration markers, context propagation
104
+ (`provide_context`/`use_context`), child-component rendering
105
+ (`render_child`), script registration, and the JS-compatible helper library
106
+ (`string`, `bool_str`, `truthy`, `number`, `floor`/`ceil`/`round`,
107
+ array/string helpers, the `*_eval` evaluator helpers, `spread_attrs`,
108
+ `query`, …). It mirrors the layering of `packages/adapter-jinja/python/barefootjs/`
109
+ (an engine-agnostic core plus a thin per-engine backend) — see
110
+ `spec/template-helpers.md` for the semantic contract each helper must
111
+ satisfy, and the crate's own tests under `runtime/tests/`.
112
+
113
+ The crate also ships a `bf-render` binary — a conformance renderer that
114
+ reads a JSON payload (`templates_dir`, `entry`, `scope_id`, `vars`,
115
+ `search_params?`, `children[]`) and writes the rendered HTML to stdout. It
116
+ is what `src/test-render.ts` builds (once, memoized — `cargo build
117
+ --manifest-path runtime/Cargo.toml --bin bf-render`) and spawns per
118
+ conformance fixture; a production host would instead link the `barefootjs`
119
+ library crate directly (see the axum sketch below) rather than shelling out
120
+ to the binary.
121
+
122
+ ## Usage
123
+
124
+ ```ts
125
+ // barefoot.config.ts
126
+ import { createConfig } from '@barefootjs/rust/build'
127
+
128
+ export default createConfig({
129
+ components: ['./src/components'],
130
+ outDir: './dist',
131
+ })
132
+ ```
133
+
134
+ `bf build` then emits `.j2` templates + client JS under `outDir`. A Rust
135
+ host renders a component by constructing a `minijinja::Environment` (per
136
+ the contract above) over `minijinja::path_loader` pointed at the emitted
137
+ templates, wiring in the `barefootjs` crate's `backend_minijinja` module as
138
+ the render backend:
139
+
140
+ ```rust
141
+ use axum::{routing::get, Router};
142
+ use barefootjs::{backend_minijinja::render_named, BarefootJS};
143
+
144
+ async fn user_card() -> axum::response::Html<String> {
145
+ let mut bf = BarefootJS::new();
146
+ let html = render_named("user_card", &mut bf, /* vars */ Default::default());
147
+ axum::response::Html(html)
148
+ }
149
+
150
+ #[tokio::main]
151
+ async fn main() {
152
+ let app = Router::new().route("/", get(user_card));
153
+ let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
154
+ axum::serve(listener, app).await.unwrap();
155
+ }
156
+ ```
157
+
158
+ ## Divergences from `@barefootjs/jinja`
159
+
160
+ Beyond the identity fields (`name`, `extension`, class name) and the render
161
+ engine itself, this is a near-verbatim port. One divergence DOES reach the
162
+ emitted template syntax:
163
+
164
+ - **Record/map lookup with a default.** Jinja2's dict has a `.get(k, d)`
165
+ method; `@barefootjs/jinja` emits `{'a': 'x', ...}.get(key, '')` for a
166
+ `Record<K, string>[key]` template-literal lookup. minijinja maps have no
167
+ `.get` method (`unknown method: map has no method named get`, verified).
168
+ This adapter instead emits `({'a': 'x', ...}[key] | default(''))`: a
169
+ missing-key index on a minijinja map returns `undefined` under
170
+ `UndefinedBehavior::Chainable`, and the builtin `default` filter supplies
171
+ the fallback inline (verified: `{{ {'a':'x'}[k] | default('DD') }}` →
172
+ `'DD'` on miss, `'x'` on hit, including nested in call args/string
173
+ concat). See `convertTemplateLiteralPartsToJinja`'s `lookup` branch in
174
+ `src/adapter/minijinja-adapter.ts`.
175
+
176
+ The remaining divergences are all in the TypeScript side's places the
177
+ conformance harness could not port byte-for-byte from `@barefootjs/jinja`,
178
+ confined to `src/test-render.ts` (the conformance-render harness, not the
179
+ adapter itself — the emitted template syntax is unaffected beyond the point
180
+ above):
181
+
182
+ - **Render invocation.** `@barefootjs/jinja` generates a throwaway Python
183
+ *script* per fixture (inline Python source building a props dict +
184
+ per-child renderer closures) and shells out to `python3`. This adapter
185
+ instead serializes the same information to a JSON *payload* and spawns
186
+ one long-lived compiled `bf-render` binary, built once per test run.
187
+ - **Non-finite numbers.** JSON cannot represent `NaN`/`Infinity`/`-Infinity`
188
+ — the TS side recursively encodes them as `{"__bf_special": "nan" | "inf"
189
+ | "-inf"}` before `JSON.stringify`; `bf-render` decodes the sentinel back
190
+ to the corresponding `f64` after parsing.
191
+ - **`vars` keys are unmangled.** Like `@barefootjs/jinja`'s Python props
192
+ dict, the JSON payload's `vars` keys are the RAW prop/signal/memo names;
193
+ reserved-word mangling happens in ONE place backend-side (the Rust
194
+ runtime's `render_named`, mirroring the Python runtime's `render_named`).
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Component-tree analysis for the minijinja template adapter.
3
+ *
4
+ * Ported from `packages/adapter-xslate/src/adapter/analysis/component-tree.ts`.
5
+ * Pure functions over the IR — they read no adapter instance state.
6
+ * `collectImportedLoopChildComponentErrors` returns its diagnostics instead
7
+ * of pushing onto the adapter's error list, so the adapter stays the sole
8
+ * owner of `errors`.
9
+ */
10
+ import type { ComponentIR, CompilerError } from '@barefootjs/jsx';
11
+ /**
12
+ * Whether the component needs the client runtime — it owns reactive state
13
+ * (signals / effects / onMount) or the analyzer flagged it as needing init.
14
+ */
15
+ export declare function hasClientInteractivity(ir: ComponentIR): boolean;
16
+ /**
17
+ * Build a `BF103` diagnostic for every component reference inside a loop body
18
+ * whose name is imported from a relative-path module. Mirror of the Go /
19
+ * Xslate / Jinja2 adapter's check — this adapter has the same
20
+ * cross-template-registration constraint at request time (each `.j2`
21
+ * component file must be registered with the shared `minijinja::Environment`
22
+ * loader alongside the parent). Returns the diagnostics so the caller pushes
23
+ * them onto its own error list.
24
+ */
25
+ export declare function collectImportedLoopChildComponentErrors(ir: ComponentIR, componentName: string): CompilerError[];
26
+ //# sourceMappingURL=component-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-tree.d.ts","sourceRoot":"","sources":["../../../src/adapter/analysis/component-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,WAAW,EAUX,aAAa,EACd,MAAM,iBAAiB,CAAA;AAExB;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAO/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,EAAE,EAAE,WAAW,EACf,aAAa,EAAE,MAAM,GACpB,aAAa,EAAE,CAqEjB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Structural classifier for JS expressions whose result is a boolean value
3
+ * (or unambiguously stringifies to "true"/"false" in JS).
4
+ *
5
+ * Near-verbatim port of `packages/adapter-jinja/src/adapter/boolean-result.ts`
6
+ * (itself ported from `packages/adapter-xslate/src/adapter/boolean-result.ts`,
7
+ * which was ported from the Mojo adapter's `bf->bool_str` classifier). Used
8
+ * by this adapter for TWO purposes — one inherited from Xslate, one new:
9
+ *
10
+ * 1. **Attribute/text stringification** (inherited): route a boolean-shaped
11
+ * reactive binding through the runtime `bf.bool_str` helper so the
12
+ * serialised value matches JS `String(boolean)` ("true"/"false"). Python
13
+ * has a real `bool` type (unlike Perl's `1`/`''`), but Python's own
14
+ * `str(True)` == `"True"` (capitalised) — still wrong for HTML output —
15
+ * so the same explicit routing is required.
16
+ * 2. **Condition-position truthy wrapping** (new — `isBooleanResultParsed` is
17
+ * exported, not just the string-based `isBooleanResultExpr`): Python
18
+ * truthiness diverges from JS specifically on empty containers (`[]` /
19
+ * `{}` are JS-truthy, Python-falsy). Perl doesn't have this problem — a
20
+ * Perl array/hash REFERENCE is always true, matching JS objects/arrays
21
+ * being unconditionally truthy — which is why Xslate never needed a
22
+ * truthy-routing layer for `if`/ternary/`&&`/`||` conditions. The Jinja
23
+ * adapter's condition-emission call sites (see `minijinja-adapter.ts`'s
24
+ * `convertConditionToJinja`) reuse this SAME structural classifier: a
25
+ * condition that is already unambiguously boolean-shaped emits directly;
26
+ * everything else is wrapped in `bf.truthy(...)` (a JS-faithful
27
+ * `ToBoolean`) before being used as an `{% if %}` / ternary test.
28
+ *
29
+ * The classifier walks a `ParsedExpr` produced by
30
+ * `@barefootjs/jsx::parseExpression` — same AST the filter / loop lowerings
31
+ * already use — so detection is structural rather than regex-text-matching.
32
+ * Wrapped expression text is left to the caller's existing
33
+ * `convertExpressionToJinja` pipeline; this module only decides whether to
34
+ * wrap.
35
+ *
36
+ * Detected shapes:
37
+ * - `binary` with a comparison operator (`<`, `>`, `<=`, `>=`, `==`, `===`,
38
+ * `!=`, `!==`)
39
+ * - `unary` with logical `!`
40
+ * - `literal` with `literalType: 'boolean'`
41
+ * - `logical` (`&&` / `||` / `??`) when both sides are themselves
42
+ * boolean-result (catches `x > 0 && y < 10`; intentionally does NOT
43
+ * catch `x() || 'fallback'` whose right side stringifies as a regular
44
+ * value)
45
+ * - `conditional` (`?:`) when both branches are themselves boolean-result
46
+ *
47
+ * Anything else returns `false` — including bare identifiers (`accepted`)
48
+ * and call expressions (`accepted()`) whose return type the adapter has no
49
+ * way to infer from source text alone.
50
+ */
51
+ import { type ParsedExpr } from '@barefootjs/jsx';
52
+ /**
53
+ * Structural boolean-result check over an already-parsed `ParsedExpr` tree.
54
+ * Exported (unlike Xslate's private equivalent) so the condition-position
55
+ * truthy-wrapping call sites can reuse it without a stringify → re-parse
56
+ * round-trip.
57
+ */
58
+ export declare function isBooleanResultParsed(node: ParsedExpr): boolean;
59
+ export declare function isBooleanResultExpr(expr: string): boolean;
60
+ /**
61
+ * True when `expr`'s top-level shape is an explicit JS `String(x)` call
62
+ * (the `EVAL_BUILTIN_IDENTS` builtin the compiler recognizes structurally —
63
+ * `packages/jsx/src/expression-parser.ts`'s `EVAL_BUILTIN_IDENTS`; lowered
64
+ * by this adapter's `String` template primitive to `bf.string(x)`, see
65
+ * `lib/constants.ts`).
66
+ *
67
+ * Guards the `isAriaBooleanAttr`-driven `bf.bool_str(...)` override in
68
+ * `minijinja-adapter.ts`'s `elementAttrEmitter`: `bf.string` and `bf.bool_str`
69
+ * produce IDENTICAL text for a real Python `bool` (both are `"true"` /
70
+ * `"false"`), so applying `bf.bool_str` to `String(x)`'s ALREADY-STRINGIFIED
71
+ * result is not a no-op — it is a Python-truthiness test over that STRING
72
+ * ("false" is a non-empty Python string, hence truthy, so
73
+ * `bf.bool_str(bf.string(false))` would wrongly render `"true"`). The Kolon
74
+ * port has the identical double-wrap shape and "works" only by an
75
+ * unrelated accident (`JSON::PP::Boolean` stringifies to `"0"`/`"1"`, and
76
+ * Perl specifically treats the STRING `"0"` as falsy) that doesn't hold in
77
+ * Python. An author who explicitly writes `String(...)` has already opted
78
+ * into JS `String()` semantics — `bf.string(x)` alone (which DOES special-
79
+ * case booleans, see `runtime.js_string`) is the complete, correct
80
+ * lowering; no attribute-name-driven override should run again on top of
81
+ * it.
82
+ */
83
+ export declare function isExplicitStringCall(expr: string): boolean;
84
+ export declare function isAriaBooleanAttr(name: string): boolean;
85
+ //# sourceMappingURL=boolean-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boolean-result.d.ts","sourceRoot":"","sources":["../../src/adapter/boolean-result.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAalE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAuB/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS1D;AAyCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The contract the extracted expression-emitter modules depend on instead of
3
+ * the concrete `MinijinjaAdapter`.
4
+ *
5
+ * Near-verbatim port of `packages/adapter-jinja/src/adapter/emit-context.ts`
6
+ * (itself ported from `packages/adapter-xslate/src/adapter/emit-context.ts`).
7
+ * This adapter's top-level expression lowering is mutually recursive with
8
+ * the adapter's own const/record resolution and its filter-predicate
9
+ * emitter, so the extracted `JinjaTopLevelEmitter` still needs to call back
10
+ * into shared per-compile state and recursive entry points.
11
+ * `JinjaEmitContext` is that seam: the emitter takes a `JinjaEmitContext`
12
+ * built by the adapter's private `emitCtx` getter (the adapter does NOT
13
+ * `implements` this interface, so the wrapped members stay private and off
14
+ * its exported public type). The emitter depends on this narrow interface
15
+ * rather than the full class, so the coupling is explicit and it's
16
+ * unit-testable against a stub.
17
+ *
18
+ * Keep this surface minimal: add a member only when an extracted module
19
+ * genuinely needs it, so the seam documents the real cross-module coupling
20
+ * rather than re-exposing the whole adapter.
21
+ */
22
+ import type { ParsedExpr, CompilerError, IRMetadata } from '@barefootjs/jsx';
23
+ export interface JinjaEmitContext {
24
+ /**
25
+ * (#1922) Local binding names the request-scoped `searchParams()` env signal
26
+ * is imported under. Non-empty enables the env-signal method-call lowering.
27
+ */
28
+ readonly _searchParamsLocals: Set<string>;
29
+ /**
30
+ * Inline a module-scope pure string-literal const by name as the resolved
31
+ * literal value, or null when the name is not such a const.
32
+ */
33
+ _resolveModuleStringConst(name: string): string | null;
34
+ /** Resolve a literal const (`const totalPages = 5`) to its Jinja value, or null. */
35
+ _resolveLiteralConst(name: string): string | null;
36
+ /**
37
+ * Resolve a static property access on a module object-literal const
38
+ * (`variantClasses.ghost`) to its Jinja value at compile time, or null.
39
+ */
40
+ _resolveStaticRecordLiteral(objectName: string, key: string): string | null;
41
+ /** Record a BF101 unsupported-expression diagnostic. */
42
+ _recordExprBF101(message: string, reason?: string): void;
43
+ /** Lower a filter/predicate body to its Jinja form, bound to `param`. */
44
+ _renderJinjaFilterExprPublic(expr: ParsedExpr, param: string): string;
45
+ }
46
+ /**
47
+ * The contract the extracted object-literal / conditional-spread lowering
48
+ * (`spread/spread-codegen.ts`) depends on. Declared separately from
49
+ * `JinjaEmitContext` so each extracted module's real coupling is documented
50
+ * precisely. Mirror of the Xslate adapter's `XslateSpreadContext`.
51
+ */
52
+ export interface JinjaSpreadContext {
53
+ /** Component name, for diagnostic source locations. */
54
+ readonly componentName: string;
55
+ /** Per-compile diagnostic list the spread lowering appends to. */
56
+ readonly errors: CompilerError[];
57
+ /** Local-constant metadata, for resolving `Record[key]` spread values. */
58
+ readonly localConstants: IRMetadata['localConstants'];
59
+ /** Prop params, for classifying a bare-identifier index as a prop. */
60
+ readonly propsParams: {
61
+ name: string;
62
+ }[];
63
+ /**
64
+ * Lower a JS expression to its Jinja form (the core recursive entry).
65
+ *
66
+ * When the IR already carries a structured `ParsedExpr` tree, pass it as
67
+ * `preParsed` so the converter threads it straight through instead of
68
+ * re-parsing `expr`. With `preParsed` set, `expr` is unused for parsing
69
+ * (the converter derives any diagnostic text from the tree), so callers
70
+ * may pass `''`.
71
+ */
72
+ convertExpressionToJinja(expr: string, preParsed?: ParsedExpr): string;
73
+ /**
74
+ * Lower a JS expression to a Jinja CONDITION (routes through `bf.truthy`
75
+ * unless the expression is structurally already boolean-shaped — see
76
+ * `boolean-result.ts`). Used for the conditional-spread ternary's test,
77
+ * which is a condition position, not a value position. Same `preParsed`
78
+ * contract as `convertExpressionToJinja`.
79
+ */
80
+ convertConditionToJinja(expr: string, preParsed?: ParsedExpr): string;
81
+ }
82
+ /**
83
+ * The contract the extracted in-template memo / context seeding
84
+ * (`memo/seed.ts`) depends on. The seed lowering recurses into the core
85
+ * expression lowering to compute a derived signal/memo value or a context
86
+ * default; that recursive entry is its only adapter coupling.
87
+ */
88
+ export interface JinjaMemoContext {
89
+ /**
90
+ * Lower a JS expression to its Jinja form (the core recursive entry). See
91
+ * `JinjaSpreadContext.convertExpressionToJinja` for the `preParsed` contract.
92
+ */
93
+ convertExpressionToJinja(expr: string, preParsed?: ParsedExpr): string;
94
+ /**
95
+ * Per-compile diagnostic list `convertExpressionToJinja` appends to on an
96
+ * unsupported shape (`_recordExprBF101`). `memo/seed.ts`'s
97
+ * `generateDerivedMemoSeed` is a SPECULATIVE "try this in-template
98
+ * recomputation, else fall back to the static ssrDefault seed" attempt per
99
+ * plan step — unlike every other `convertExpressionToJinja` call site, a
100
+ * failure here must NOT become a hard compile error, so it snapshots this
101
+ * array's length before calling in and truncates back to it on failure
102
+ * (discarding whatever `_recordExprBF101` appended) rather than letting
103
+ * the error escape.
104
+ */
105
+ readonly errors: CompilerError[];
106
+ }
107
+ //# sourceMappingURL=emit-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-context.d.ts","sourceRoot":"","sources":["../../src/adapter/emit-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5E,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEzC;;;OAGG;IACH,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEtD,oFAAoF;IACpF,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEjD;;;OAGG;IACH,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE3E,wDAAwD;IACxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAExD,yEAAyE;IACzE,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAE9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAA;IAEhC,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAErD,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAExC;;;;;;;;OAQG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;IAEtE;;;;;;OAMG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;IAEtE;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CACjC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Array / string method lowering for the minijinja template adapter.
3
+ *
4
+ * Ported from `packages/adapter-xslate/src/adapter/expr/array-method.ts`.
5
+ * Pure free functions shared by both the filter-context emitter and the
6
+ * top-level emitter — they take an `emit` callback for receiver / argument
7
+ * recursion and read no adapter instance state.
8
+ *
9
+ * The receiver/array helpers are the same runtime methods the Xslate adapter
10
+ * calls, invoked as `bf.NAME(...)` (bare, no `$` sigil) instead of
11
+ * `$bf.NAME(...)`.
12
+ */
13
+ import type { ParsedExpr, ArrayMethod, SortComparator, FlatDepth } from '@barefootjs/jsx';
14
+ export declare function renderArrayMethod(method: ArrayMethod, object: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
15
+ /**
16
+ * Emit a `.sort(cmp)` / `.toSorted(cmp)` via the runtime evaluator (#2018):
17
+ * the comparator body travels as serialized-ParsedExpr JSON, evaluated per
18
+ * comparison against `{paramA, paramB, …captured}`. Returns null when the
19
+ * body is outside the evaluator surface (e.g. a `localeCompare` comparator —
20
+ * `serializeParsedExpr` refuses it), so the caller falls back to the
21
+ * structured `bf.sort`. `params` are the comparator arrow's two params
22
+ * (`[paramA, paramB]`).
23
+ */
24
+ export declare function renderSortEval(recv: string, body: ParsedExpr, params: string[], emit: (e: ParsedExpr) => string): string | null;
25
+ /**
26
+ * Emit a `.reduce(fn, init)` / `.reduceRight(fn, init)` via the runtime
27
+ * evaluator (#2018): the reducer body travels as serialized-ParsedExpr JSON,
28
+ * folded over the receiver from `init` in `direction` order. `params` are the
29
+ * reducer arrow's params (`[paramAcc, paramItem]`); `init` is the initial-value
30
+ * `ParsedExpr` from the call's trailing argument. Returns null when the body is
31
+ * outside the evaluator surface, or when `init` is not a literal string/number
32
+ * (→ caller refuses with BF101). A numeric seed passes through as a bare
33
+ * Jinja number; a string seed as a single-quoted literal.
34
+ */
35
+ export declare function renderReduceEval(recv: string, body: ParsedExpr, params: string[], init: ParsedExpr, direction: 'left' | 'right', emit: (e: ParsedExpr) => string): string | null;
36
+ /**
37
+ * Emit a higher-order predicate call via the runtime evaluator (#2018, P2):
38
+ * `bf.filter_eval` / `bf.every_eval` / `bf.some_eval` / `bf.find_eval` /
39
+ * `bf.find_index_eval`, carrying the serialized predicate body + captured env
40
+ * dict. Generalizes the lambda lowering to the same JS-faithful evaluator
41
+ * the Go/Xslate adapters use. Returns null when the predicate is outside the
42
+ * evaluator surface (e.g. a method-call predicate — `serializeParsedExpr`
43
+ * refuses it), so the caller falls back to the lambda form. `forward`
44
+ * (find / findIndex family only) selects the search direction — `false` =
45
+ * findLast / findLastIndex.
46
+ */
47
+ export declare function renderPredicateEval(funcName: string, recv: string, predicate: ParsedExpr, param: string, emit: (e: ParsedExpr) => string, forward?: boolean): string | null;
48
+ /**
49
+ * Emit a `.flatMap(proj)` via the runtime evaluator (#2018, P3): the projection
50
+ * body serializes to JSON and `bf.flat_map_eval` projects + flattens one
51
+ * level. `param` is the projection arrow's single param. Returns null when the
52
+ * projection is outside the evaluator surface (→ caller refuses with BF101).
53
+ */
54
+ export declare function renderFlatMapEval(recv: string, body: ParsedExpr, param: string, emit: (e: ParsedExpr) => string): string | null;
55
+ /**
56
+ * Emit a value-producing `.map(cb)` via the runtime evaluator (#2073): the
57
+ * projection body serializes to JSON and `bf.map_eval` projects each element,
58
+ * one result per element (no flatten — the JS `.map` contract). Composes
59
+ * through the array-method chain (`.map(cb).join(' ')`). Returns null when
60
+ * the projection is outside the evaluator surface (→ caller refuses with
61
+ * BF101). The JSX-returning `.map` is an IRLoop upstream and never reaches
62
+ * this emit.
63
+ */
64
+ export declare function renderMapEval(recv: string, body: ParsedExpr, param: string, emit: (e: ParsedExpr) => string): string | null;
65
+ /**
66
+ * Shared Jinja emit for `.sort(cmp)` / `.toSorted(cmp)`. Used by both the
67
+ * filter-context emitter and the top-level emitter, plus the loop-array
68
+ * wrap in `renderLoop`. The runtime `bf.sort` accepts an opts dict and
69
+ * returns a fresh list.
70
+ */
71
+ export declare function renderSortMethod(recv: string, c: SortComparator): string;
72
+ export declare function renderFlatMethod(recv: string, depth: FlatDepth | {
73
+ expr: ParsedExpr;
74
+ }, emit: (e: ParsedExpr) => string): string;
75
+ //# sourceMappingURL=array-method.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array-method.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/array-method.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAA;AAGxB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CA6HR;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAUf;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,GAAG,OAAO,EAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAkBf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,EAC/B,OAAO,CAAC,EAAE,OAAO,GAChB,MAAM,GAAG,IAAI,CAMf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CASxE;AAGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,EACvC,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAmBR"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * ParsedExpr → Jinja2 emitters for the minijinja template adapter.
3
+ *
4
+ * Ported from `packages/adapter-xslate/src/adapter/expr/emitters.ts`
5
+ * (`XslateFilterEmitter` / `XslateTopLevelEmitter`). Two `ParsedExprEmitter`
6
+ * implementations:
7
+ *
8
+ * - `JinjaFilterEmitter` — filter/predicate context (loop param + local
9
+ * aliases + bare identifier signal fallback); self-contained, reads no
10
+ * adapter state.
11
+ * - `JinjaTopLevelEmitter` — top-level / per-render-var context; depends on
12
+ * the adapter only through the narrow `JinjaEmitContext` seam.
13
+ *
14
+ * Two deliberate divergences from the Kolon port, both documented at their
15
+ * definition site below:
16
+ *
17
+ * 1. **JS-truthy condition wrapping** (`truthyTest`) — Python truthiness
18
+ * diverges from JS on empty containers; Perl doesn't have this problem
19
+ * (a Perl ref is always true), so Kolon never needed this. Every
20
+ * condition-TEST position (`!x`, the left operand of `&&`/`||`, a
21
+ * ternary's test) routes through the shared `bf.truthy(...)` runtime
22
+ * helper unless the operand is structurally already boolean-shaped
23
+ * (`isBooleanResultParsed`). `&&`/`||` still return the ORIGINAL
24
+ * operand VALUE (not a coerced bool) on the taken branch — matching JS
25
+ * `a || b` returning `a` itself, not `true` — only the BRANCH TEST uses
26
+ * `bf.truthy`. Because Jinja's `if/else` ternary has no way to reuse an
27
+ * already-computed test value for both the test and (conditionally) the
28
+ * result, the left operand's rendered text is emitted TWICE (once as
29
+ * the test, once as the value) — safe because every operand reaching
30
+ * this pipeline is a pure, side-effect-free read (a signal/prop lookup
31
+ * or a call into a pure runtime helper), never a stateful expression.
32
+ * 2. **No Jinja lambda for the predicate-callback fallback.** Kolon's
33
+ * `-> $x { … }` lambda is the Xslate top-level emitter's fallback when a
34
+ * `.filter`/`.every`/`.some`/`.find*` predicate can't be serialized to
35
+ * the runtime evaluator's JSON form (e.g. a nested method-call
36
+ * predicate). Jinja has no lambda-expression syntax at all, so there is
37
+ * no equivalent fallback to port. `JinjaTopLevelEmitter` therefore uses
38
+ * ONE mechanism for every higher-order callback: the evaluator-JSON
39
+ * `*_eval` payload (`bf.filter_eval`, `bf.sort_eval`, …). When
40
+ * `serializeParsedExpr` refuses the body, the call surfaces `BF101`
41
+ * instead of silently degrading — `.sort`/`.toSorted` is the one
42
+ * exception, whose non-lambda STRUCTURED fallback (`bf.sort` with a
43
+ * `{keys: […]}` descriptor, no callback body at all) survives the port
44
+ * unchanged since it was never lambda-shaped to begin with.
45
+ * `JinjaFilterEmitter` (the loop `.filter().map()` INLINE predicate,
46
+ * rendered as a plain boolean expression, never a lambda) is otherwise
47
+ * unaffected and still used for that path plus the filter-predicate
48
+ * entry point `_renderJinjaFilterExprPublic`.
49
+ */
50
+ import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
51
+ import type { JinjaEmitContext } from '../emit-context.ts';
52
+ /**
53
+ * Route a condition-TEST position through `bf.truthy(...)` unless the node
54
+ * is structurally already boolean-shaped. See the file header (divergence
55
+ * 1). Shared by both emitters below and reused by the adapter's top-level
56
+ * `convertConditionToJinja` for IR-level `if` / loop-filter conditions.
57
+ */
58
+ export declare function truthyTest(node: ParsedExpr, rendered: string): string;
59
+ /**
60
+ * Lowering for the predicate body of a filter / every / some / find, plus the
61
+ * same shape used by the loop-hoist `.filter().map()` inline condition.
62
+ * Higher-order predicates are emitted using Jinja's own scalar comparison
63
+ * operators.
64
+ *
65
+ * NOTE: Jinja has no `[x for x in … if …]`-as-expression form usable inline
66
+ * here (a comprehension is a value producer, not a boolean test), so a
67
+ * nested higher-order call (`x.tags.filter(...)`, `other.some(...)`) inside
68
+ * a predicate has no faithful scalar lowering here either — same BF101
69
+ * surfacing as Kolon (#2038) instead of silently degrading to the
70
+ * callback's receiver.
71
+ */
72
+ export declare class JinjaFilterEmitter implements ParsedExprEmitter {
73
+ private readonly param;
74
+ private readonly localVarMap;
75
+ private readonly isStringName;
76
+ private readonly onUnsupported?;
77
+ constructor(param: string, localVarMap: Map<string, string>, isStringName?: (n: string) => boolean, onUnsupported?: ((message: string, reason?: string) => void) | undefined);
78
+ identifier(name: string): string;
79
+ literal(value: string | number | boolean | null, literalType: LiteralType): string;
80
+ member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string;
81
+ indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string;
82
+ call(callee: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
83
+ unary(op: string, argument: ParsedExpr, emit: (e: ParsedExpr) => string): string;
84
+ binary(op: string, left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string;
85
+ logical(op: '&&' | '||' | '??', left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string;
86
+ callbackMethod(method: string, object: ParsedExpr, _arrow: Extract<ParsedExpr, {
87
+ kind: 'arrow';
88
+ }>, _restArgs: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
89
+ arrayLiteral(elements: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
90
+ arrayMethod(method: ArrayMethod, object: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
91
+ flatMethod(object: ParsedExpr, depth: FlatDepth | {
92
+ expr: ParsedExpr;
93
+ }, emit: (e: ParsedExpr) => string): string;
94
+ conditional(_test: ParsedExpr, _consequent: ParsedExpr, _alternate: ParsedExpr): string;
95
+ templateLiteral(_parts: TemplatePart[]): string;
96
+ arrow(_params: string[], _body: ParsedExpr): string;
97
+ regex(_raw: string): string;
98
+ unsupported(_raw: string, _reason: string): string;
99
+ objectLiteral(_properties: ObjectLiteralProperty[], _raw: string, _emit: (e: ParsedExpr) => string): string;
100
+ }
101
+ /**
102
+ * Lowering for top-level expressions whose identifiers resolve against the
103
+ * Jinja template's per-render context vars (signals, props, locals
104
+ * introduced by `{% set x = … %}`). Differs from the filter emitter mainly
105
+ * in
106
+ * - `conditional` is supported (filter predicates can't return ternaries),
107
+ * - higher-order methods route through `bf.*` array/evaluator helpers,
108
+ * - no lambda fallback exists (see the file header, divergence 2).
109
+ */
110
+ export declare class JinjaTopLevelEmitter implements ParsedExprEmitter {
111
+ private readonly ctx;
112
+ constructor(ctx: JinjaEmitContext);
113
+ identifier(name: string): string;
114
+ literal(value: string | number | boolean | null, literalType: LiteralType): string;
115
+ member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string;
116
+ indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string;
117
+ call(callee: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
118
+ unary(op: string, argument: ParsedExpr, emit: (e: ParsedExpr) => string): string;
119
+ binary(op: string, left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string;
120
+ logical(op: '&&' | '||' | '??', left: ParsedExpr, right: ParsedExpr, emit: (e: ParsedExpr) => string): string;
121
+ callbackMethod(method: string, object: ParsedExpr, arrow: Extract<ParsedExpr, {
122
+ kind: 'arrow';
123
+ }>, restArgs: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
124
+ /**
125
+ * Lower a boolean-predicate callback (`filter` / `find*` / `every` /
126
+ * `some`). See the file header, divergence 2: Jinja has no lambda
127
+ * expression, so — unlike Kolon — there is no non-evaluator fallback here.
128
+ * A predicate the evaluator can't model surfaces `BF101`.
129
+ */
130
+ private _emitPredicateCallback;
131
+ arrayLiteral(elements: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
132
+ arrayMethod(method: ArrayMethod, object: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
133
+ flatMethod(object: ParsedExpr, depth: FlatDepth | {
134
+ expr: ParsedExpr;
135
+ }, emit: (e: ParsedExpr) => string): string;
136
+ conditional(test: ParsedExpr, consequent: ParsedExpr, alternate: ParsedExpr, emit: (e: ParsedExpr) => string): string;
137
+ templateLiteral(parts: TemplatePart[], emit: (e: ParsedExpr) => string): string;
138
+ arrow(_params: string[], _body: ParsedExpr): string;
139
+ regex(_raw: string): string;
140
+ unsupported(_raw: string, _reason: string): string;
141
+ objectLiteral(properties: ObjectLiteralProperty[], _raw: string, _emit: (e: ParsedExpr) => string): string;
142
+ }
143
+ //# sourceMappingURL=emitters.d.ts.map