@rhinostone/swig 2.1.0 → 2.2.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.
package/lib/swig.js CHANGED
@@ -10,11 +10,11 @@ var utils = require('./utils'),
10
10
  /**
11
11
  * Swig version number as a string.
12
12
  * @example
13
- * if (swig.version === "2.1.0") { ... }
13
+ * if (swig.version === "2.2.0") { ... }
14
14
  *
15
15
  * @type {String}
16
16
  */
17
- exports.version = "2.1.0";
17
+ exports.version = "2.2.0";
18
18
 
19
19
  /**
20
20
  * Swig Options Object. This object can be passed to many of the API-level Swig methods to control various aspects of the engine. All keys are optional.
@@ -201,6 +201,11 @@ exports.Swig = function (opts) {
201
201
  * pre-resolved and will throw at render time as they would on the sync
202
202
  * path.
203
203
  *
204
+ * @deprecated since 2.2.0 — use {@link Swig#renderFile} with a loader that
205
+ * sets <code>loader.async === true</code>. The async-codegen dispatch
206
+ * handles dynamic include paths the pre-walker cannot. This method will
207
+ * be removed in 3.0.
208
+ *
204
209
  * @example
205
210
  * swig.setDefaults({ loader: myAsyncLoader });
206
211
  * swig.renderFileAsync('page.html', { name: 'world' }, function (err, output) {
@@ -260,6 +265,12 @@ exports.Swig = function (opts) {
260
265
  * temporarily swaps the loader on each call, so subsequent runtime
261
266
  * <var>include</var>s resolve correctly without re-running the pre-walk.
262
267
  *
268
+ * @deprecated since 2.2.0 — use {@link Swig#compileFile} with
269
+ * <code>options.codegenMode === 'async'</code> on a loader that sets
270
+ * <code>loader.async === true</code>. The returned compiled function
271
+ * yields a <code>Promise&lt;{output, exports}&gt;</code> instead of a
272
+ * string. This method will be removed in 3.0.
273
+ *
263
274
  * @example
264
275
  * swig.compileFileAsync('page.html', {}, function (err, fn) {
265
276
  * if (err) { return done(err); }
@@ -1,4 +1,5 @@
1
1
  var utils = require('../utils'),
2
+ ir = require('@rhinostone/swig-core/lib/ir'),
2
3
  backend = require('@rhinostone/swig-core/lib/backend');
3
4
 
4
5
  // CVE-2023-25345: prototype-chain properties that must not be used as import
@@ -26,7 +27,19 @@ var _dangerousProps = require('@rhinostone/swig-core/lib/security').dangerousPro
26
27
  * @param {literal} as Literally, "as".
27
28
  * @param {literal} varname Local-accessible object name to assign the macros to.
28
29
  */
29
- exports.compile = function (compiler, args) {
30
+ exports.compile = function (compiler, args, content, parents, options) {
31
+ // Phase 2 (#T22): async-codegen branch. Parse stashed `[{path}, alias]`
32
+ // (no macro pre-render in async mode); emit IRImportDeferred so the
33
+ // backend's `_swig.getTemplate` + `.exports` bind happens at runtime.
34
+ if (options && options.codegenMode === 'async') {
35
+ var asyncAlias = args[args.length - 1];
36
+ var asyncPath = args[0].path;
37
+ return ir.importDeferred(
38
+ ir.literal('string', asyncPath),
39
+ asyncAlias,
40
+ options.filename || ''
41
+ );
42
+ }
30
43
  var ctx = args.pop(),
31
44
  allMacros = utils.map(args, function (arg) {
32
45
  return arg.name;
@@ -56,37 +69,45 @@ exports.parse = function (str, line, parser, types, stack, opts, swig) {
56
69
  var compiler = require('../parser').compile,
57
70
  parseOpts = { resolveFrom: opts.filename },
58
71
  compileOpts = utils.extend({}, opts, parseOpts),
59
- tokens,
72
+ isAsync = !!(opts && opts.codegenMode === 'async'),
73
+ importPath,
60
74
  ctx;
61
75
 
62
76
  parser.on(types.STRING, function (token) {
63
77
  var self = this;
64
- if (!tokens) {
65
- tokens = swig.parseFile(token.match.replace(/^("|')|("|')$/g, ''), parseOpts).tokens;
66
- utils.each(tokens, function (token) {
67
- var out = '',
68
- macroName;
69
- if (!token || token.name !== 'macro' || !token.compile) {
70
- return;
71
- }
72
- macroName = token.args[0];
73
- // Phase 2 (#T15): macro.compile now returns an IRMacro node
74
- // rather than a JS source string. Render it through the shared
75
- // backend so import.js still gets the JS source it performs
76
- // regex-surgery on for namespace-prefixing. The +'\n' trailing
77
- // newline matches the pre-Phase-2 compile output exactly.
78
- out += backend.compile([token.compile(compiler, token.args, token.content, [], compileOpts)], [], compileOpts) + '\n';
79
- self.out.push({compiled: out, name: macroName});
80
- });
78
+ if (importPath !== undefined) {
79
+ throw new Error('Unexpected string ' + token.match + ' on line ' + line + '.');
80
+ }
81
+ importPath = token.match.replace(/^("|')|("|')$/g, '');
82
+
83
+ if (isAsync) {
84
+ // Async mode: skip the sync parseFile + macro pre-render. Stash
85
+ // just the path; compile() emits IRImportDeferred.
86
+ self.out.push({ path: importPath });
81
87
  return;
82
88
  }
83
89
 
84
- throw new Error('Unexpected string ' + token.match + ' on line ' + line + '.');
90
+ var tokens = swig.parseFile(importPath, parseOpts).tokens;
91
+ utils.each(tokens, function (token) {
92
+ var out = '',
93
+ macroName;
94
+ if (!token || token.name !== 'macro' || !token.compile) {
95
+ return;
96
+ }
97
+ macroName = token.args[0];
98
+ // Phase 2 (#T15): macro.compile now returns an IRMacro node
99
+ // rather than a JS source string. Render it through the shared
100
+ // backend so import.js still gets the JS source it performs
101
+ // regex-surgery on for namespace-prefixing. The +'\n' trailing
102
+ // newline matches the pre-Phase-2 compile output exactly.
103
+ out += backend.compile([token.compile(compiler, token.args, token.content, [], compileOpts)], [], compileOpts) + '\n';
104
+ self.out.push({compiled: out, name: macroName});
105
+ });
85
106
  });
86
107
 
87
108
  parser.on(types.VAR, function (token) {
88
109
  var self = this;
89
- if (!tokens || ctx) {
110
+ if (importPath === undefined || ctx) {
90
111
  throw new Error('Unexpected variable "' + token.match + '" on line ' + line + '.');
91
112
  }
92
113
 
@@ -48,6 +48,10 @@ exports.compile = function (compiler, args, content, parents, options, blockName
48
48
  }
49
49
  }
50
50
 
51
+ if (options && options.codegenMode === 'async') {
52
+ return ir.includeDeferred(file, w || undefined, !!onlyCtx, !!ignoreMissing, parentFile);
53
+ }
54
+
51
55
  return ir.include(file, w || undefined, !!onlyCtx, !!ignoreMissing, parentFile);
52
56
  };
53
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhinostone/swig",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "A simple, powerful, and extendable templating engine for node.js and browsers, similar to Django, Jinja2, and Twig.",
5
5
  "keywords": [
6
6
  "template",
@@ -21,7 +21,7 @@
21
21
  "Rhinostone <contact@gina.io>"
22
22
  ],
23
23
  "dependencies": {
24
- "@rhinostone/swig-core": "2.1.0",
24
+ "@rhinostone/swig-core": "2.2.0",
25
25
  "terser": "^5.46.1",
26
26
  "yargs": "^17.7.2"
27
27
  },