@rhinostone/swig 2.7.3 → 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 CHANGED
@@ -1,3 +1,18 @@
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
+
1
16
  [2.7.3](https://github.com/gina-io/swig/tree/v2.7.3) / 2026-06-10
2
17
  -----------------------------------------------------------------
3
18
 
package/README.md CHANGED
@@ -3,11 +3,11 @@ Swig
3
3
 
4
4
  [![CI](https://github.com/gina-io/swig/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/gina-io/swig/actions/workflows/ci.yml) [![NPM version](https://img.shields.io/npm/v/@rhinostone/swig.svg?style=flat)](https://www.npmjs.com/package/@rhinostone/swig) [![NPM Downloads](https://img.shields.io/npm/dm/@rhinostone/swig.svg?style=flat)](https://www.npmjs.com/package/@rhinostone/swig) [![Socket Badge](https://socket.dev/api/badge/npm/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 [paularmstrong/swig](https://github.com/paularmstrong/swig) (last released 2014) and is now a standalone project. Security and bug fixes ship here.
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](http://expressjs.com/) compatible.
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,20 @@ _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
+
24
33
  ### v2.7.3 (June 2026)
25
34
 
26
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).
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
- output = 'module.exports = {\n' + parts.join(',\n') + '\n};\n';
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.7.3 | 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/ocrybit/DateZ/blob/master/LISENCE */
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() {
@@ -4176,6 +4176,9 @@
4176
4176
  basepath = basepath ? path.normalize(basepath) : null;
4177
4177
  ret.resolve = function(to, from) {
4178
4178
  if (basepath) {
4179
+ if (/^\.\.([\\/]|$)/.test(path.normalize(to))) {
4180
+ utils.throwError('Template "' + to + '" resolves outside the loader root "' + basepath + '".');
4181
+ }
4179
4182
  from = basepath;
4180
4183
  } else {
4181
4184
  from = from ? path.dirname(from) : "/";
@@ -4376,7 +4379,7 @@
4376
4379
  return;
4377
4380
  }
4378
4381
  if (engineCache === "memory") {
4379
- return memoryStore[key];
4382
+ return Object.prototype.hasOwnProperty.call(memoryStore, key) ? memoryStore[key] : void 0;
4380
4383
  }
4381
4384
  return engineCache.get(key);
4382
4385
  };
@@ -4475,7 +4478,10 @@
4475
4478
  }
4476
4479
  parentFile = parentFile || options.filename;
4477
4480
  parentFile = deps.resolve(parentName, parentFile);
4478
- parent = deps.cacheGet(parentFile, options) || deps.parseFile(parentFile, utils.extend({}, options, { filename: parentFile }));
4481
+ parent = deps.cacheGet(parentFile, options);
4482
+ if (!parent || !parent.tokens) {
4483
+ parent = deps.parseFile(parentFile, utils.extend({}, options, { filename: parentFile }));
4484
+ }
4479
4485
  parentName = parent.parent;
4480
4486
  if (parentFiles.indexOf(parentFile) !== -1) {
4481
4487
  throw new Error('Illegal circular extends of "' + parentFile + '".');
@@ -4526,6 +4532,52 @@
4526
4532
  self.cache = {};
4527
4533
  }
4528
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
+ };
4529
4581
  self.setFilter = function(name, method) {
4530
4582
  if (typeof method !== "function") {
4531
4583
  throw new Error('Filter "' + name + '" is not a valid function.');
@@ -4739,7 +4791,7 @@
4739
4791
  self.run = function(tpl, locals, filepath) {
4740
4792
  var context = getLocals({ locals });
4741
4793
  if (filepath) {
4742
- cacheSet(filepath, {}, tpl);
4794
+ cacheSet(self.options.loader.resolve(filepath), {}, buildRegistered(tpl));
4743
4795
  }
4744
4796
  return tpl(self, context, filters, utils, efn);
4745
4797
  };
@@ -4758,7 +4810,7 @@
4758
4810
  var loaders = require_loaders2();
4759
4811
  var preWalker = require_pre_walker();
4760
4812
  var engine = require_engine();
4761
- exports.version = "2.7.3";
4813
+ exports.version = "2.8.0";
4762
4814
  var defaultOptions = {
4763
4815
  autoescape: true,
4764
4816
  varControls: ["{{", "}}"],
@@ -4963,6 +5015,8 @@
4963
5015
  exports.renderFile = defaultInstance.renderFile;
4964
5016
  exports.renderFileAsync = defaultInstance.renderFileAsync;
4965
5017
  exports.run = defaultInstance.run;
5018
+ exports.register = defaultInstance.register;
5019
+ exports.registerBundle = defaultInstance.registerBundle;
4966
5020
  exports.invalidateCache = defaultInstance.invalidateCache;
4967
5021
  exports.loaders = loaders;
4968
5022
  }
@@ -5126,6 +5180,17 @@
5126
5180
  * chunk, returning the trimmed tag body (e.g. `extends "x.html"`).
5127
5181
  * @private
5128
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
+ */
5129
5194
  /*!
5130
5195
  * Export methods publicly
5131
5196
  */