@rhinostone/swig-twig 2.5.1 → 2.5.3
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 +3 -0
- package/lib/tags/extends.js +43 -32
- package/package.json +2 -2
package/lib/parser.js
CHANGED
|
@@ -529,6 +529,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
|
|
|
529
529
|
var line = 1;
|
|
530
530
|
var stack = [];
|
|
531
531
|
var parent = null;
|
|
532
|
+
var parentExpr = null;
|
|
532
533
|
var tokens = [];
|
|
533
534
|
var blocks = {};
|
|
534
535
|
var inVerbatim = false;
|
|
@@ -674,6 +675,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
|
|
|
674
675
|
if (token) {
|
|
675
676
|
if (token.name === 'extends') {
|
|
676
677
|
parent = token.args.length ? String(token.args[0]) : null;
|
|
678
|
+
parentExpr = token.irExpr && token.irExpr.file;
|
|
677
679
|
} else if (token.block && !stack.length) {
|
|
678
680
|
blocks[token.args.join('')] = token;
|
|
679
681
|
}
|
|
@@ -733,6 +735,7 @@ exports.parse = function (swig, source, opts, tags, filters) {
|
|
|
733
735
|
return {
|
|
734
736
|
name: opts.filename,
|
|
735
737
|
parent: parent,
|
|
738
|
+
parentExpr: parentExpr,
|
|
736
739
|
tokens: tokens,
|
|
737
740
|
blocks: blocks
|
|
738
741
|
};
|
package/lib/tags/extends.js
CHANGED
|
@@ -3,26 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Declares a parent template for inheritance:
|
|
5
5
|
*
|
|
6
|
-
* {% extends "layout.twig" %}
|
|
6
|
+
* {% extends "layout.twig" %} (static — resolved at compile time)
|
|
7
|
+
* {% extends some_var %} (dynamic — resolved at render time)
|
|
8
|
+
* {% extends a ? "x" : "y" %} (dynamic)
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* chain
|
|
12
|
-
* `importNonBlocks`) walks the chain statically at compile time, so a
|
|
13
|
-
* runtime-valued parent cannot be resolved without reworking the engine.
|
|
14
|
-
* Dynamic extends is tracked for a later session; the rejection is
|
|
15
|
-
* deliberate, not an oversight.
|
|
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.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `
|
|
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`.
|
|
21
23
|
*
|
|
22
24
|
* Compile emits nothing — `extends.compile` returns undefined. The
|
|
23
25
|
* backend's emit loop skips undefined returns. Extends is a parse-time
|
|
24
|
-
* declaration carried via `template.parent`
|
|
25
|
-
* is generated for the `{% extends %}` tag itself.
|
|
26
|
+
* declaration carried via `template.parent` / `template.parentExpr`
|
|
27
|
+
* metadata; no runtime code is generated for the `{% extends %}` tag itself.
|
|
26
28
|
*/
|
|
27
29
|
|
|
28
30
|
var utils = require('@rhinostone/swig-core/lib/utils');
|
|
@@ -34,23 +36,26 @@ exports.ends = false;
|
|
|
34
36
|
exports.block = true;
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
|
-
* Parse the `{% extends %}` tag body.
|
|
38
|
-
* strips surrounding quotes, and stashes the result as `token.args[0]`
|
|
39
|
-
* for the parser's splitter to pick up.
|
|
39
|
+
* Parse the `{% extends %}` tag body.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* A single STRING literal is stashed (quotes stripped) as `token.args[0]`
|
|
42
|
+
* for the splitter to lift onto `template.parent`. Any other expression
|
|
43
|
+
* (VAR, member access, ternary, ...) is a dynamic path: it is lowered
|
|
44
|
+
* through `parser.parseExpr` into an IRExpr on `token.irExpr.file` (the
|
|
45
|
+
* splitter lifts it onto `template.parentExpr`) and the raw source text is
|
|
46
|
+
* kept on `token.args[0]` so the sync `template.parent` string stays
|
|
47
|
+
* truthy. Mirrors `include.js`.
|
|
43
48
|
*
|
|
44
49
|
* @param {string} str Tag body.
|
|
45
50
|
* @param {number} line Source line of the opening `{%`.
|
|
46
|
-
* @param {object} parser The Twig parser module (
|
|
47
|
-
* bare string literal).
|
|
51
|
+
* @param {object} parser The Twig parser module (exposes `parseExpr`).
|
|
48
52
|
* @param {object} types Twig lexer token-type enum.
|
|
49
53
|
* @param {Array} stack Open-tag stack (unused — extends has no body).
|
|
50
54
|
* @param {object} opts Per-call options (honors `opts.filename`).
|
|
51
55
|
* @param {object} swig Swig instance (unused).
|
|
52
|
-
* @param {object} token In-progress TagToken. `token.args`
|
|
53
|
-
* unquoted
|
|
56
|
+
* @param {object} token In-progress TagToken. Gets `token.args` (raw or
|
|
57
|
+
* unquoted path) and, for a dynamic path,
|
|
58
|
+
* `token.irExpr.file` (the lowered IRExpr).
|
|
54
59
|
* @return {boolean} Always `true` on success. Throws otherwise.
|
|
55
60
|
*/
|
|
56
61
|
exports.parse = function (str, line, parser, types, stack, opts, swig, token) {
|
|
@@ -62,17 +67,23 @@ exports.parse = function (str, line, parser, types, stack, opts, swig, token) {
|
|
|
62
67
|
if (!pathTok) {
|
|
63
68
|
utils.throwError('Expected parent template path in "extends" tag', line, opts.filename);
|
|
64
69
|
}
|
|
65
|
-
if (pathTok.type !== types.STRING) {
|
|
66
|
-
utils.throwError('Dynamic "extends" is not supported — parent path must be a string literal', line, opts.filename);
|
|
67
|
-
}
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
if (pathTok.type === types.STRING) {
|
|
72
|
+
pos += 1;
|
|
73
|
+
while (pos < tokens.length && tokens[pos].type === types.WHITESPACE) { pos += 1; }
|
|
74
|
+
if (pos < tokens.length) {
|
|
75
|
+
utils.throwError('Unexpected token "' + tokens[pos].match + '" after parent path in "extends" tag', line, opts.filename);
|
|
76
|
+
}
|
|
77
|
+
token.args = [pathTok.match.replace(/^['"]|['"]$/g, '')];
|
|
78
|
+
return true;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
// Dynamic path: lower to an IRExpr so it resolves at render time on the
|
|
82
|
+
// async codegen path. The raw source is kept on token.args[0] so the
|
|
83
|
+
// sync template.parent string stays truthy (the async dispatch guard
|
|
84
|
+
// keys on it); buildExtendsDeferred prefers template.parentExpr.
|
|
85
|
+
token.irExpr = { file: parser.parseExpr(tokens) };
|
|
86
|
+
token.args = [utils.strip(str)];
|
|
76
87
|
return true;
|
|
77
88
|
};
|
|
78
89
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rhinostone/swig-twig",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.3",
|
|
4
4
|
"description": "Twig-syntax frontend for the @rhinostone/swig-core template engine. Part of the @rhinostone/swig multi-flavor family.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"template",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"node": ">=12"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@rhinostone/swig-core": "2.5.
|
|
25
|
+
"@rhinostone/swig-core": "2.5.3"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|