@rhinostone/swig-jinja2 2.5.1 → 2.5.2

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.
package/lib/parser.js CHANGED
@@ -548,6 +548,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
548
548
  var line = 1;
549
549
  var stack = [];
550
550
  var parent = null;
551
+ var parentExpr = null;
551
552
  var tokens = [];
552
553
  var blocks = {};
553
554
  var inRaw = false;
@@ -698,6 +699,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
698
699
  if (token) {
699
700
  if (token.name === 'extends') {
700
701
  parent = token.args.length ? String(token.args[0]) : null;
702
+ parentExpr = token.irExpr && token.irExpr.file;
701
703
  } else if (token.block && !stack.length) {
702
704
  blocks[token.args.join('')] = token;
703
705
  }
@@ -757,6 +759,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
757
759
  return {
758
760
  name: opts.filename,
759
761
  parent: parent,
762
+ parentExpr: parentExpr,
760
763
  tokens: tokens,
761
764
  blocks: blocks
762
765
  };
@@ -3,21 +3,27 @@
3
3
  *
4
4
  * Declares a parent template for inheritance:
5
5
  *
6
- * {% extends "layout.html" %}
6
+ * {% extends "layout.html" %} (static — compile-time)
7
+ * {% extends parent_var %} (dynamic — render-time)
8
+ * {% extends full if cond else partial %} (dynamic)
7
9
  *
8
- * Only static string paths are supported here. Dynamic extends
9
- * (`{% extends some_var %}`) is rejected at parse time: the engine's
10
- * parent-chain resolution (`engine.getParents` + `remapBlocks` +
11
- * `importNonBlocks`) walks the chain statically at compile time, so a
12
- * runtime-valued parent cannot be resolved on the sync path. Dynamic
13
- * extends is the async-codegen path's concern, tracked separately.
10
+ * A static string-literal path is pushed as the single `token.args`
11
+ * element; the parser's splitter lifts it onto `template.parent`, and the
12
+ * engine's parent-chain resolution (`engine.getParents` + `remapBlocks` +
13
+ * `importNonBlocks`) walks the chain statically at compile time.
14
14
  *
15
- * The parser's splitter reads `token.args[0]` and stashes it on
16
- * `template.parent`. This tag must push the *unquoted* path as the single
17
- * `token.args` element.
15
+ * A dynamic path is lowered through `parser.parseExpr` into an IRExpr and
16
+ * stashed on `token.irExpr.file`; the splitter lifts it onto the sibling
17
+ * `template.parentExpr` slot, which the async codegen path
18
+ * (`buildExtendsDeferred`) prefers over the string literal and resolves at
19
+ * render time via `_swig.getTemplate`. Dynamic extends therefore requires
20
+ * an async loader (`renderFile` with a callback); on the synchronous
21
+ * render path a runtime-valued parent is unresolvable. Mirrors the
22
+ * dynamic-path lowering in `include.js`.
18
23
  *
19
24
  * Compile emits nothing — `extends` is a parse-time declaration carried via
20
- * `template.parent` metadata; no runtime code is generated for the tag.
25
+ * `template.parent` / `template.parentExpr` metadata; no runtime code is
26
+ * generated for the tag.
21
27
  */
22
28
 
23
29
  var utils = require('@rhinostone/swig-core/lib/utils');
@@ -28,20 +34,26 @@ exports.ends = false;
28
34
  exports.block = true;
29
35
 
30
36
  /**
31
- * Parse the `{% extends %}` tag body. Extracts the STRING literal path,
32
- * strips surrounding quotes, and stashes the result as `token.args[0]`.
33
- * Rejects anything other than a single STRING token.
37
+ * Parse the `{% extends %}` tag body.
38
+ *
39
+ * A single STRING literal is stashed (quotes stripped) as `token.args[0]`
40
+ * for the splitter to lift onto `template.parent`. Any other expression
41
+ * (VAR, member access, inline-if, ...) is a dynamic path: it is lowered
42
+ * through `parser.parseExpr` into an IRExpr on `token.irExpr.file` (the
43
+ * splitter lifts it onto `template.parentExpr`) and the raw source text is
44
+ * kept on `token.args[0]` so the sync `template.parent` string stays
45
+ * truthy. Mirrors `include.js`.
34
46
  *
35
47
  * @param {string} str Tag body.
36
48
  * @param {number} line Source line of the opening `{%`.
37
- * @param {object} parser The Jinja2 parser module (unused — path is a
38
- * bare string literal).
49
+ * @param {object} parser The Jinja2 parser module (exposes `parseExpr`).
39
50
  * @param {object} types Jinja2 lexer token-type enum.
40
51
  * @param {Array} stack Open-tag stack (unused — extends has no body).
41
52
  * @param {object} opts Per-call options (honors `opts.filename`).
42
53
  * @param {object} swig Swig instance (unused).
43
- * @param {object} token In-progress TagToken. `token.args` gets the
44
- * unquoted parent path as its single element.
54
+ * @param {object} token In-progress TagToken. Gets `token.args` (raw or
55
+ * unquoted path) and, for a dynamic path,
56
+ * `token.irExpr.file` (the lowered IRExpr).
45
57
  * @return {boolean} Always `true` on success. Throws otherwise.
46
58
  */
47
59
  exports.parse = function (str, line, parser, types, stack, opts, swig, token) {
@@ -53,17 +65,23 @@ exports.parse = function (str, line, parser, types, stack, opts, swig, token) {
53
65
  if (!pathTok) {
54
66
  utils.throwError('Expected parent template path in "extends" tag', line, opts.filename);
55
67
  }
56
- if (pathTok.type !== types.STRING) {
57
- utils.throwError('Dynamic "extends" is not supported — parent path must be a string literal', line, opts.filename);
58
- }
59
68
 
60
- pos += 1;
61
- while (pos < tokens.length && tokens[pos].type === types.WHITESPACE) { pos += 1; }
62
- if (pos < tokens.length) {
63
- utils.throwError('Unexpected token "' + tokens[pos].match + '" after parent path in "extends" tag', line, opts.filename);
69
+ if (pathTok.type === types.STRING) {
70
+ pos += 1;
71
+ while (pos < tokens.length && tokens[pos].type === types.WHITESPACE) { pos += 1; }
72
+ if (pos < tokens.length) {
73
+ utils.throwError('Unexpected token "' + tokens[pos].match + '" after parent path in "extends" tag', line, opts.filename);
74
+ }
75
+ token.args = [pathTok.match.replace(/^['"]|['"]$/g, '')];
76
+ return true;
64
77
  }
65
78
 
66
- token.args = [pathTok.match.replace(/^['"]|['"]$/g, '')];
79
+ // Dynamic path: lower to an IRExpr so it resolves at render time on the
80
+ // async codegen path. The raw source is kept on token.args[0] so the
81
+ // sync template.parent string stays truthy (the async dispatch guard
82
+ // keys on it); buildExtendsDeferred prefers template.parentExpr.
83
+ token.irExpr = { file: parser.parseExpr(tokens) };
84
+ token.args = [utils.strip(str)];
67
85
  return true;
68
86
  };
69
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhinostone/swig-jinja2",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "Jinja2-syntax frontend for the @rhinostone/swig-core template engine. Part of the @rhinostone/swig multi-flavor family.",
5
5
  "keywords": [
6
6
  "template",
@@ -23,7 +23,7 @@
23
23
  "node": ">=12"
24
24
  },
25
25
  "peerDependencies": {
26
- "@rhinostone/swig-core": "2.5.1"
26
+ "@rhinostone/swig-core": "2.5.2"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"