@rhinostone/swig 2.7.2 → 2.8.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/HISTORY.md +20 -0
- package/README.md +6 -6
- package/ROADMAP.md +14 -0
- package/bin/swig.js +34 -1
- package/dist/swig.js +72 -6
- package/dist/swig.min.js +15 -4
- package/dist/swig.min.js.map +1 -1
- package/dist/swig.runtime.js +1519 -0
- package/dist/swig.runtime.min.js +45 -0
- package/dist/swig.runtime.min.js.map +1 -0
- package/lib/runtime.js +83 -0
- package/lib/swig.js +27 -1
- package/package.json +2 -2
- package/runtime.js +3 -0
package/HISTORY.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
[2.8.0](https://github.com/gina-io/swig/tree/v2.8.0) / 2026-08-02
|
|
2
|
+
-----------------------------------------------------------------
|
|
3
|
+
|
|
4
|
+
* **Added** AOT template registration — swig.register(path, fn) and swig.registerBundle(map) on every flavor store pre-compiled templates in the template cache under loader-normalized keys, wrapped in the locals-binding call shape include expects (priming via swig.run cached the raw template function, which crashed included partials that used variables or filters); swig compile --recursive --register emits a self-registering browser bundle
|
|
5
|
+
|
|
6
|
+
* **Added** Runtime-only browser build — dist/swig.runtime.js and dist/swig.runtime.min.js execute pre-compiled template bundles (register, registerBundle, run, compileFile, renderFile with the native filter catalog and a root-based memory loader) and ship no parser and no new Function, so pages under a strict Content-Security-Policy without unsafe-eval can render AOT-compiled templates; also exposed to Node as require("@rhinostone/swig/runtime")
|
|
7
|
+
|
|
8
|
+
* **Fixed** Updated the stale `/docs/swig` and `/docs/swig/migration` documentation links to their canonical `/docs/templating/swig` and `/docs/templating/swig/migration` paths in `README.md` (4 occurrences) and `CONTRIBUTING.md` (1 occurrence) (2026-06-15 link-health scan, gina-io/gina#39). The old URLs still resolved via the 301 redirects added in the 2026-04-23 Templating umbrella restructure, but were no longer canonical and kept accruing redirect hops. Documentation only; no runtime or API change.
|
|
9
|
+
|
|
10
|
+
* **Fixed** Refreshed two stale external URLs flagged by the 2026-06-22 / 2026-06-29 link-health scans (gina-io/gina#43). `README.md` now links to `https://expressjs.com/` instead of the plain-HTTP `http://expressjs.com/` (the domain 301-redirects HTTP to HTTPS). `browser/comments.js` updates the DateZ `@license` URL from `github.com/ocrybit/DateZ` to `github.com/tomoio/DateZ` — the upstream GitHub user was renamed again (same class as the v2.0.0 `TomoUniversalis` to `ocrybit` rename); the target repo keeps the upstream `LISENCE` spelling. Documentation and comment-only; no runtime or API change.
|
|
11
|
+
|
|
12
|
+
* **Fixed** De-linked the two remaining live references to the archived `paularmstrong/swig` repository (GitHub topic `unmaintained-dont-use`, last released 2014), flagged by the 2026-07-06 link-health scan (gina-io/gina#47). `README.md` no longer links the "abandoned `paularmstrong/swig`" mention to the archived repo root, and `CONTRIBUTING.md` de-links the "Pull Request 273" historical example (a PR on the archived repo, where contributions are disabled) — both references are preserved as plain text for traceability, matching the de-linking house style from the gina-io/gina#18 and #33 link-health fixes. Documentation only; no runtime or API change.
|
|
13
|
+
|
|
14
|
+
* **Fixed** Several template-cache paths failed silently and now report the problem. The memory loader rejects a climbing path when a basepath is set, instead of resolving it to a different template than the one requested — with a root basepath it clamped and rendered the wrong file, mirroring the confinement the filesystem loader already enforces. Passing a filepath to run stores the same locals-binding wrapper, under the same resolved key, that a cache lookup expects, so a template primed that way is usable by a later include rather than crashing on the raw function argument shape. The memory cache no longer reads inherited object members, so an identifier-style loader cannot resolve a name such as constructor to a cache hit. Both minified bundles now point at the source map filename that is actually written.
|
|
15
|
+
|
|
16
|
+
[2.7.3](https://github.com/gina-io/swig/tree/v2.7.3) / 2026-06-10
|
|
17
|
+
-----------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
* **Fixed** Fixed a filter-chain argument leak in the expression parsers — the per-filter argument accumulator was function-scoped and never reset between iterations, so an arg-bearing filter earlier in a chain leaked its arguments onto a later no-arg filter (e.g. `x|default("y")|upper` lowered `upper` with the leaked `["y"]`). Affected nested and parenthesized chains in the shared core parser and all filter chains in the Twig and Jinja2 frontends; the Django frontend shipped the per-iteration reset at carve time.
|
|
20
|
+
|
|
1
21
|
[2.7.2](https://github.com/gina-io/swig/tree/v2.7.2) / 2026-06-09
|
|
2
22
|
-----------------------------------------------------------------
|
|
3
23
|
|
package/README.md
CHANGED
|
@@ -3,11 +3,11 @@ Swig
|
|
|
3
3
|
|
|
4
4
|
[](https://github.com/gina-io/swig/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@rhinostone/swig) [](https://www.npmjs.com/package/@rhinostone/swig) [](https://socket.dev/npm/package/@rhinostone/swig)
|
|
5
5
|
|
|
6
|
-
> **Multi-flavor template engine** for Node.js and browsers — native Swig syntax (Jinja2/Django-inspired), Twig syntax, Python Jinja2 syntax, and Django Template Language syntax via dedicated frontends sharing one IR backend. [gina-io/swig](https://github.com/gina-io/swig) started as a maintained continuation of the abandoned
|
|
6
|
+
> **Multi-flavor template engine** for Node.js and browsers — native Swig syntax (Jinja2/Django-inspired), Twig syntax, Python Jinja2 syntax, and Django Template Language syntax via dedicated frontends sharing one IR backend. [gina-io/swig](https://github.com/gina-io/swig) started as a maintained continuation of the abandoned `paularmstrong/swig` (last released 2014) and is now a standalone project. Security and bug fixes ship here.
|
|
7
7
|
|
|
8
8
|
> **Part of the [Gina](https://github.com/gina-io/gina) ecosystem.** This is the built-in template engine for [Gina](https://gina.io) ([npm](https://www.npmjs.com/package/gina)), a Node.js MVC framework with HTTP/2, multi-bundle architecture, and scope-based data isolation.
|
|
9
9
|
|
|
10
|
-
Swig is a **Jinja2/Django-inspired** template engine for node.js and browsers. The syntax will feel familiar to Jinja2 and Django users, but Swig is **not drop-in compatible** with either — porting templates from an existing project requires a handful of changes. See the [Migration Guide](https://gina.io/docs/swig/migration) for the full parity list and workaround patterns.
|
|
10
|
+
Swig is a **Jinja2/Django-inspired** template engine for node.js and browsers. The syntax will feel familiar to Jinja2 and Django users, but Swig is **not drop-in compatible** with either — porting templates from an existing project requires a handful of changes. See the [Migration Guide](https://gina.io/docs/templating/swig/migration) for the full parity list and workaround patterns.
|
|
11
11
|
|
|
12
12
|
> **Coming from Twig?** Install [@rhinostone/swig-twig](https://www.npmjs.com/package/@rhinostone/swig-twig) instead — a dedicated Twig-syntax frontend with closer parity than working around incompatibilities here.
|
|
13
13
|
|
|
@@ -32,7 +32,7 @@ Features
|
|
|
32
32
|
--------
|
|
33
33
|
|
|
34
34
|
* Available for node.js **and** major web browsers.
|
|
35
|
-
* [Express](
|
|
35
|
+
* [Express](https://expressjs.com/) compatible.
|
|
36
36
|
* Object-Oriented template inheritance.
|
|
37
37
|
* Apply filters and transformations to output in your templates.
|
|
38
38
|
* **Hardened against prototype-pollution** — `__proto__` / `constructor` / `prototype` blocked at parser, tag-side, and IR-emission layers. CVE-2023-25345 fully patched. 11 CVE regression cases under [`tests/regressions.test.js`](./tests/regressions.test.js).
|
|
@@ -56,7 +56,7 @@ Need Help? Have Questions? Comments?
|
|
|
56
56
|
------------------------------------
|
|
57
57
|
|
|
58
58
|
* File an issue at [gina-io/swig/issues](https://github.com/gina-io/swig/issues).
|
|
59
|
-
* Swig v0.x → v1.x migration notes — the original upstream wiki has been deleted; see `HISTORY.md` entries around v1.0.0 for the individual breaking changes. For porting *from Jinja2 or Django* into Swig, see the [Migration Guide](https://gina.io/docs/swig/migration).
|
|
59
|
+
* Swig v0.x → v1.x migration notes — the original upstream wiki has been deleted; see `HISTORY.md` entries around v1.0.0 for the individual breaking changes. For porting *from Jinja2 or Django* into Swig, see the [Migration Guide](https://gina.io/docs/templating/swig/migration).
|
|
60
60
|
|
|
61
61
|
Installation
|
|
62
62
|
------------
|
|
@@ -78,7 +78,7 @@ For Django syntax:
|
|
|
78
78
|
Documentation
|
|
79
79
|
-------------
|
|
80
80
|
|
|
81
|
-
User-facing documentation lives in the Gina Docusaurus site under the [Swig Template Engine](https://gina.io/docs/swig) section, maintained in [gina-io/docs](https://github.com/gina-io/docs) at `docs/templating/swig/`. The JSDoc blocks in `lib/swig.js`, `lib/filters.js`, `lib/tags/`, and `lib/loaders/` remain the canonical source-of-truth for the public API and are mirrored into the Docusaurus pages.
|
|
81
|
+
User-facing documentation lives in the Gina Docusaurus site under the [Swig Template Engine](https://gina.io/docs/templating/swig) section, maintained in [gina-io/docs](https://github.com/gina-io/docs) at `docs/templating/swig/`. The JSDoc blocks in `lib/swig.js`, `lib/filters.js`, `lib/tags/`, and `lib/loaders/` remain the canonical source-of-truth for the public API and are mirrored into the Docusaurus pages.
|
|
82
82
|
|
|
83
83
|
Basic Example
|
|
84
84
|
-------------
|
|
@@ -139,7 +139,7 @@ Swig is *inspired by* Jinja2 and Django, not a drop-in replacement. Common pitfa
|
|
|
139
139
|
* **Method calls require parens** — Django auto-invokes `x.get_absolute_url`; Swig needs `x.get_absolute_url()`.
|
|
140
140
|
* **~25 Jinja2 filters are absent** — `default`, `truncate`, `tojson`, `round`, `int`, `float`, `map`, `select`, `batch`, `trim`, etc. Register them via `swig.setFilter(name, fn)`.
|
|
141
141
|
|
|
142
|
-
Full parity tables and workaround patterns: **[Migration Guide](https://gina.io/docs/swig/migration)**.
|
|
142
|
+
Full parity tables and workaround patterns: **[Migration Guide](https://gina.io/docs/templating/swig/migration)**.
|
|
143
143
|
|
|
144
144
|
How it works
|
|
145
145
|
------------
|
package/ROADMAP.md
CHANGED
|
@@ -16,11 +16,25 @@ _No near-term scheduled items. See [Future (post-2.0)](#future-post-20) for upco
|
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| Planned | Async parse path for the remaining dynamic targets — runtime-resolved `{% import %}` / `{% from %}` paths on the async-codegen branch. Static-target async dispatch shipped in 2.2.0; dynamic `{% extends %}` shipped in 2.5.2 (native + Twig + Jinja2) and dynamic `{% include %}` paths already resolve (the include path has always been an expression). Dynamic `import` / `from` are on hold pending consumer demand. |
|
|
18
18
|
| Planned | Modern browser-test harness. The legacy phantomjs runner was removed; a replacement (e.g. Playwright or JSDOM) has not yet landed, so browser parity is verified in the interim via the production build plus a symbol grep. (The `mocha` → `node:test` runner migration, the `expect.js` → in-repo assertion-shim swap, and the `blanket` → `node:test` built-in coverage migration have all shipped.) |
|
|
19
|
+
| On demand | Runtime-only browser bundles for the Twig, Jinja2, and Django frontends. The shared runtime factory already supports them — each needs its own bundle entry and build target, since filter catalogs are per-flavor. The native `dist/swig.runtime.min.js` shipped in 2.8.0; the flavor bundles land when a consumer needs one. |
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
## Completed
|
|
23
24
|
|
|
25
|
+
### v2.8.0 (August 2026)
|
|
26
|
+
|
|
27
|
+
- Added ahead-of-time template registration: `swig.register(path, fn)` and `swig.registerBundle(map)` place pre-compiled template functions into the template cache under loader-normalized keys, so `include`, `compileFile`, and `renderFile` resolve them without a compiler. Available on all four frontends (native, Twig, Jinja2, Django). `swig compile --recursive --register` emits a bundle that registers itself on load and also exports the template map, so a page needs no per-template wiring.
|
|
28
|
+
- Added a runtime-only browser build — `dist/swig.runtime.js` and `dist/swig.runtime.min.js` (21 KB minified, roughly a quarter of the full bundle). It executes pre-compiled bundles with the full filter catalog but ships no lexer, parser, or code generator, and therefore contains no `new Function`: pages served under a strict Content-Security-Policy without `unsafe-eval` can render AOT-compiled templates. Every compiling entry point throws a clear error naming the CLI workflow instead of failing obscurely. Also available to Node as `require('@rhinostone/swig/runtime')`.
|
|
29
|
+
- Fixed several template-cache paths that failed silently. A registered template no longer shadows a loadable `{% extends %}` parent — the parent's source is still read through the loader, where previously registering a layout could make a child that rendered correctly start rendering an empty string with no error. The memory loader rejects a climbing path when a `basepath` is set rather than resolving it to a different template than the one requested. Passing a filepath to `run` now caches an entry a later `include` can actually use. The memory cache no longer treats inherited object members as cache hits. `register` reports a disabled cache for every falsy `cache` value, and `registerBundle` validates a whole bundle before committing any of it, so a malformed map cannot leave the registry half-populated.
|
|
30
|
+
- Fixed browser integration for the new bundles: a self-registering bundle finds the engine whether it is a bare global or a property of the global object (under AMD there is no bare binding, so every template previously went unregistered in silence) and warns when no engine is present; loading a runtime bundle twice, or after the full build, no longer discards existing registrations or replaces a compiler-capable instance; and the runtime entry no longer assumes `window`, so it loads in a worker. Both minified bundles now reference the source map filename that is actually written.
|
|
31
|
+
- All five packages (`@rhinostone/swig`, `@rhinostone/swig-core`, `@rhinostone/swig-twig`, `@rhinostone/swig-jinja2`, `@rhinostone/swig-django`) released in lockstep at `2.8.0`. Lockstep is now required rather than conventional: the frontends reference modules inside `@rhinostone/swig-core` that exist only from this version forward.
|
|
32
|
+
|
|
33
|
+
### v2.7.3 (June 2026)
|
|
34
|
+
|
|
35
|
+
- Fixed a filter-chain argument leak in the expression parsers: the per-filter argument accumulator was function-scoped and never reset between iterations, so an arg-bearing filter earlier in a chain leaked its arguments onto a later no-arg filter (e.g. `x|default("y")|upper` lowered `upper` with the leaked `["y"]`). Affected nested and parenthesized chains in the shared core parser and all filter chains in the Twig and Jinja2 frontends; the Django frontend already shipped the per-iteration reset. Runtime impact ranged from harmless (filters that ignore extra positional arguments) to wrong output (a no-arg filter consuming a leaked positional argument).
|
|
36
|
+
- All five packages (`@rhinostone/swig`, `@rhinostone/swig-core`, `@rhinostone/swig-twig`, `@rhinostone/swig-jinja2`, `@rhinostone/swig-django`) released in lockstep at `2.7.3`.
|
|
37
|
+
|
|
24
38
|
### v2.7.2 (June 2026)
|
|
25
39
|
|
|
26
40
|
- Fixed a regression in the v2.7.1 CVE-2023-25345 hardening: a **relative** `basepath` (e.g. `swig.loaders.fs('templates')`) wrongly rejected *every* in-root `include` / `extends` / `import` path. The root check compared each resolved template path (always absolute) against a `basepath` that had only been normalized, so a relative root matched nothing and threw `resolves outside the loader root` for legitimate templates. The `basepath` is now resolved to an absolute path before the check; absolute basepaths, the no-`basepath` default, and the directory-traversal rejections are all unchanged. The fix lives in `@rhinostone/swig-core`, so the native, Twig, Jinja2, and Django frontends all inherit it.
|
package/bin/swig.js
CHANGED
|
@@ -27,6 +27,7 @@ var FLAGS = {
|
|
|
27
27
|
'm': { alias: 'minify', boolean: true },
|
|
28
28
|
'r': { alias: 'recursive' },
|
|
29
29
|
'ext': {},
|
|
30
|
+
'register': { boolean: true },
|
|
30
31
|
'filters': {},
|
|
31
32
|
'tags': {},
|
|
32
33
|
'options': {},
|
|
@@ -313,6 +314,10 @@ function validate(argv) {
|
|
|
313
314
|
}
|
|
314
315
|
}
|
|
315
316
|
|
|
317
|
+
if (argv.register && !argv.r) {
|
|
318
|
+
throw new Error('--register requires --recursive; it emits a self-registering bundle of the compiled directory.');
|
|
319
|
+
}
|
|
320
|
+
|
|
316
321
|
if (argv.ext && !argv.r) {
|
|
317
322
|
throw new Error('--ext is only meaningful with --recursive.');
|
|
318
323
|
}
|
|
@@ -344,6 +349,7 @@ function usage() {
|
|
|
344
349
|
' -m, --minify Minify compiled functions with terser',
|
|
345
350
|
' -r, --recursive Recursively compile every template in <dir> into a single AOT bundle module.',
|
|
346
351
|
' --ext Comma-separated list of file extensions to include when using --recursive (e.g. ".html,.swig"). Defaults to no filter.',
|
|
352
|
+
' --register With --recursive: emit a self-registering bundle (calls swig.registerBundle when a global swig is present; also exports the template map).',
|
|
347
353
|
' --filters Custom filters as a CommonJS-style file',
|
|
348
354
|
' --tags Custom tags as a CommonJS-style file',
|
|
349
355
|
' --options Customize Swig\'s Options from a CommonJS-style file',
|
|
@@ -418,6 +424,13 @@ function walkSync(dir) {
|
|
|
418
424
|
* resolution still happens at render time through the consumer's loader. The
|
|
419
425
|
* bundle is not a closed module against inheritance chains.
|
|
420
426
|
*
|
|
427
|
+
* With <code>--register</code> the bundle self-registers instead: it calls
|
|
428
|
+
* <code>swig.registerBundle(map)</code> against a global <code>swig</code>
|
|
429
|
+
* when one is present (a browser page that loaded the swig bundle first),
|
|
430
|
+
* and still exports the raw map for Node-side consumers. Run the command
|
|
431
|
+
* from the template root (<code>swig compile -r . --register</code>) so
|
|
432
|
+
* baked include paths line up with the bundle's registration keys.
|
|
433
|
+
*
|
|
421
434
|
* @param {string} dir Directory to walk.
|
|
422
435
|
* @return {undefined} Writes to stdout or to <code>argv.o</code>.
|
|
423
436
|
* @private
|
|
@@ -452,7 +465,27 @@ function bundleRecursive(dir) {
|
|
|
452
465
|
parts.push(JSON.stringify(key) + ': ' + tpl);
|
|
453
466
|
});
|
|
454
467
|
|
|
455
|
-
|
|
468
|
+
if (argv.register) {
|
|
469
|
+
// The engine may be reachable as a bare global (classic script tag) or
|
|
470
|
+
// only as a property of the global object — under AMD the browser entry
|
|
471
|
+
// registers a named module and never creates the bare binding, so a
|
|
472
|
+
// bare-identifier lookup alone would silently register nothing.
|
|
473
|
+
output = 'var __swigTemplates = {\n' + parts.join(',\n') + '\n};\n' +
|
|
474
|
+
'if (typeof module !== "undefined" && module.exports) {\n' +
|
|
475
|
+
' module.exports = __swigTemplates;\n' +
|
|
476
|
+
'}\n' +
|
|
477
|
+
'var __swigEngine = (typeof swig !== "undefined" && swig) ||\n' +
|
|
478
|
+
' (typeof window !== "undefined" && window.swig) ||\n' +
|
|
479
|
+
' (typeof globalThis !== "undefined" && globalThis.swig) || null;\n' +
|
|
480
|
+
'if (__swigEngine && __swigEngine.registerBundle) {\n' +
|
|
481
|
+
' __swigEngine.registerBundle(__swigTemplates);\n' +
|
|
482
|
+
'} else if (typeof console !== "undefined" && console.warn) {\n' +
|
|
483
|
+
' console.warn("swig: no engine found; ' + parts.length + ' pre-compiled template(s) were not registered. ' +
|
|
484
|
+
'Load swig before this bundle, or call swig.registerBundle(__swigTemplates) yourself.");\n' +
|
|
485
|
+
'}\n';
|
|
486
|
+
} else {
|
|
487
|
+
output = 'module.exports = {\n' + parts.join(',\n') + '\n};\n';
|
|
488
|
+
}
|
|
456
489
|
|
|
457
490
|
if (argv.m) {
|
|
458
491
|
output = loadTerser().minify_sync(output).code;
|
package/dist/swig.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! Swig v2.
|
|
2
|
-
/*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/
|
|
1
|
+
/*! Swig v2.8.0 | https://github.com/gina-io/swig | @license https://github.com/gina-io/swig/blob/master/LICENSE */
|
|
2
|
+
/*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/tomoio/DateZ/blob/master/LISENCE */
|
|
3
3
|
(() => {
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __commonJS = (cb, mod) => function __require() {
|
|
@@ -2689,6 +2689,7 @@
|
|
|
2689
2689
|
bail('Invalid filter "' + fname + '"');
|
|
2690
2690
|
}
|
|
2691
2691
|
var fargs;
|
|
2692
|
+
fargs = void 0;
|
|
2692
2693
|
if (tok.type === _t.FILTER) {
|
|
2693
2694
|
fargs = parseArgList(_t.PARENCLOSE);
|
|
2694
2695
|
}
|
|
@@ -4175,6 +4176,9 @@
|
|
|
4175
4176
|
basepath = basepath ? path.normalize(basepath) : null;
|
|
4176
4177
|
ret.resolve = function(to, from) {
|
|
4177
4178
|
if (basepath) {
|
|
4179
|
+
if (/^\.\.([\\/]|$)/.test(path.normalize(to))) {
|
|
4180
|
+
utils.throwError('Template "' + to + '" resolves outside the loader root "' + basepath + '".');
|
|
4181
|
+
}
|
|
4178
4182
|
from = basepath;
|
|
4179
4183
|
} else {
|
|
4180
4184
|
from = from ? path.dirname(from) : "/";
|
|
@@ -4375,7 +4379,7 @@
|
|
|
4375
4379
|
return;
|
|
4376
4380
|
}
|
|
4377
4381
|
if (engineCache === "memory") {
|
|
4378
|
-
return memoryStore[key];
|
|
4382
|
+
return Object.prototype.hasOwnProperty.call(memoryStore, key) ? memoryStore[key] : void 0;
|
|
4379
4383
|
}
|
|
4380
4384
|
return engineCache.get(key);
|
|
4381
4385
|
};
|
|
@@ -4474,7 +4478,10 @@
|
|
|
4474
4478
|
}
|
|
4475
4479
|
parentFile = parentFile || options.filename;
|
|
4476
4480
|
parentFile = deps.resolve(parentName, parentFile);
|
|
4477
|
-
parent = deps.cacheGet(parentFile, options)
|
|
4481
|
+
parent = deps.cacheGet(parentFile, options);
|
|
4482
|
+
if (!parent || !parent.tokens) {
|
|
4483
|
+
parent = deps.parseFile(parentFile, utils.extend({}, options, { filename: parentFile }));
|
|
4484
|
+
}
|
|
4478
4485
|
parentName = parent.parent;
|
|
4479
4486
|
if (parentFiles.indexOf(parentFile) !== -1) {
|
|
4480
4487
|
throw new Error('Illegal circular extends of "' + parentFile + '".');
|
|
@@ -4525,6 +4532,52 @@
|
|
|
4525
4532
|
self.cache = {};
|
|
4526
4533
|
}
|
|
4527
4534
|
};
|
|
4535
|
+
function buildRegistered(fn) {
|
|
4536
|
+
var context = getLocals(), contextLength = utils.keys(context).length;
|
|
4537
|
+
return function registered(locals, blocks) {
|
|
4538
|
+
var lcls;
|
|
4539
|
+
if (locals && contextLength) {
|
|
4540
|
+
lcls = utils.extend({}, context, locals);
|
|
4541
|
+
} else if (locals && !contextLength) {
|
|
4542
|
+
lcls = locals;
|
|
4543
|
+
} else if (!locals && contextLength) {
|
|
4544
|
+
lcls = context;
|
|
4545
|
+
} else {
|
|
4546
|
+
lcls = {};
|
|
4547
|
+
}
|
|
4548
|
+
return fn(self, lcls, filters, utils, efn, blocks);
|
|
4549
|
+
};
|
|
4550
|
+
}
|
|
4551
|
+
function validateRegistration(path, fn) {
|
|
4552
|
+
if (typeof path !== "string" || !path.length) {
|
|
4553
|
+
throw new Error("Template registration path must be a non-empty string.");
|
|
4554
|
+
}
|
|
4555
|
+
if (typeof fn !== "function") {
|
|
4556
|
+
throw new Error('Registered template for "' + path + '" is not a function. Pass a pre-compiled template function.');
|
|
4557
|
+
}
|
|
4558
|
+
if (!self.options.cache) {
|
|
4559
|
+
throw new Error("Cannot register templates while caching is disabled (cache: " + self.options.cache + "). The registry is the compile cache.");
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
self.register = function(path, fn) {
|
|
4563
|
+
validateRegistration(path, fn);
|
|
4564
|
+
cacheSet(self.options.loader.resolve(path), {}, buildRegistered(fn));
|
|
4565
|
+
return self;
|
|
4566
|
+
};
|
|
4567
|
+
self.registerBundle = function(map) {
|
|
4568
|
+
var entries = [];
|
|
4569
|
+
if (!map || typeof map !== "object") {
|
|
4570
|
+
throw new Error("Template bundle must be an object of { path: templateFn } pairs.");
|
|
4571
|
+
}
|
|
4572
|
+
utils.each(map, function(fn, path) {
|
|
4573
|
+
entries.push([path, fn]);
|
|
4574
|
+
validateRegistration(path, fn);
|
|
4575
|
+
});
|
|
4576
|
+
utils.each(entries, function(entry) {
|
|
4577
|
+
self.register(entry[0], entry[1]);
|
|
4578
|
+
});
|
|
4579
|
+
return self;
|
|
4580
|
+
};
|
|
4528
4581
|
self.setFilter = function(name, method) {
|
|
4529
4582
|
if (typeof method !== "function") {
|
|
4530
4583
|
throw new Error('Filter "' + name + '" is not a valid function.');
|
|
@@ -4738,7 +4791,7 @@
|
|
|
4738
4791
|
self.run = function(tpl, locals, filepath) {
|
|
4739
4792
|
var context = getLocals({ locals });
|
|
4740
4793
|
if (filepath) {
|
|
4741
|
-
cacheSet(filepath, {}, tpl);
|
|
4794
|
+
cacheSet(self.options.loader.resolve(filepath), {}, buildRegistered(tpl));
|
|
4742
4795
|
}
|
|
4743
4796
|
return tpl(self, context, filters, utils, efn);
|
|
4744
4797
|
};
|
|
@@ -4757,7 +4810,7 @@
|
|
|
4757
4810
|
var loaders = require_loaders2();
|
|
4758
4811
|
var preWalker = require_pre_walker();
|
|
4759
4812
|
var engine = require_engine();
|
|
4760
|
-
exports.version = "2.
|
|
4813
|
+
exports.version = "2.8.0";
|
|
4761
4814
|
var defaultOptions = {
|
|
4762
4815
|
autoescape: true,
|
|
4763
4816
|
varControls: ["{{", "}}"],
|
|
@@ -4962,6 +5015,8 @@
|
|
|
4962
5015
|
exports.renderFile = defaultInstance.renderFile;
|
|
4963
5016
|
exports.renderFileAsync = defaultInstance.renderFileAsync;
|
|
4964
5017
|
exports.run = defaultInstance.run;
|
|
5018
|
+
exports.register = defaultInstance.register;
|
|
5019
|
+
exports.registerBundle = defaultInstance.registerBundle;
|
|
4965
5020
|
exports.invalidateCache = defaultInstance.invalidateCache;
|
|
4966
5021
|
exports.loaders = loaders;
|
|
4967
5022
|
}
|
|
@@ -5125,6 +5180,17 @@
|
|
|
5125
5180
|
* chunk, returning the trimmed tag body (e.g. `extends "x.html"`).
|
|
5126
5181
|
* @private
|
|
5127
5182
|
*/
|
|
5183
|
+
/*!
|
|
5184
|
+
* Wrap a pre-compiled template function in the locals-binding call shape
|
|
5185
|
+
* cached entries have — include-emitted code invokes them as
|
|
5186
|
+
* `(context)`, so the raw five-argument function is the wrong shape.
|
|
5187
|
+
* @private
|
|
5188
|
+
*/
|
|
5189
|
+
/*!
|
|
5190
|
+
* Shared argument checks for register / registerBundle, so a bundle can be
|
|
5191
|
+
* validated in full before any entry is committed.
|
|
5192
|
+
* @private
|
|
5193
|
+
*/
|
|
5128
5194
|
/*!
|
|
5129
5195
|
* Export methods publicly
|
|
5130
5196
|
*/
|