added all files to project

This commit is contained in:
2022-03-10 10:36:59 +01:00
parent 09dd957b33
commit 46a936d7de
25351 changed files with 3883356 additions and 0 deletions
+736
View File
@@ -0,0 +1,736 @@
Changelog
=========
3.2.3 (Feb 15 2021)
-------------------
* Add support for nested attributes on
[`sort` filter](https://mozilla.github.io/nunjucks/templating.html#sort-arr-reverse-casesens-attr);
respect `throwOnUndefined` if sort attribute is undefined.
* Add `base` arg to
[`int` filter](https://mozilla.github.io/nunjucks/templating.html#int).
* Move `chokidar` to `peerDependencies` and mark it `optional` in `peerDependenciesMeta`.
* Fix prototype pollution issue for template variables. Merge of
[#1330](https://github.com/mozilla/nunjucks/pull/1330); fixes
[#1331](https://github.com/mozilla/nunjucks/issues/1331). Thanks
[ChenKS12138](https://github.com/ChenKS12138)!
3.2.2 (Jul 20 2020)
-------------------
* Add [`select`](https://mozilla.github.io/nunjucks/templating.html#select) and
[`reject`](https://mozilla.github.io/nunjucks/templating.html#reject) filters.
Merge of [#1278](https://github.com/mozilla/nunjucks/pull/1278) and
[#1279](https://github.com/mozilla/nunjucks/pull/1279); fixes
[#282](https://github.com/mozilla/nunjucks/issues/282). Thanks
[ogonkov](https://github.com/ogonkovv)!
* Fix precompile binary script `TypeError: name.replace is not a function`.
Fixes [#1295](https://github.com/mozilla/nunjucks/issues/1295).
* Add support for nested attributes on
[`groupby` filter](https://mozilla.github.io/nunjucks/templating.html#groupby);
respect `throwOnUndefined` option, if the groupby attribute is undefined.
Merge of [#1276](https://github.com/mozilla/nunjucks/pull/1276); fixes
[#1198](https://github.com/mozilla/nunjucks/issues/1198). Thanks
[ogonkov](https://github.com/ogonkovv)!
* Fix bug that prevented errors in included templates from being raised when
rendering templates synchronously. Fixes
[#1272](https://github.com/mozilla/nunjucks/issues/1272).
* The `indent` filter no longer appends an additional newline. Fixes
[#1231](https://github.com/mozilla/nunjucks/issues/1231).
3.2.1 (Mar 17 2020)
-------------------
* Replace yargs with commander to reduce number of dependencies. Merge of
[#1253](https://github.com/mozilla/nunjucks/pull/1253). Thanks
[AlynxZhou](@AlynxZhou).
* Update optional dependency chokidar from `^2.0.0` to `^3.3.0`. Merge of
[#1254](https://github.com/mozilla/nunjucks/pull/1254). Thanks
[eklingen](@eklingen).
* Prevent optional dependency Chokidar from loading when not watching. Merge
of [#1250](https://github.com/mozilla/nunjucks/pull/1250). Thanks
[eklingen](@eklingen).
3.2.0 (Mar 5 2019)
------------------
* Adds [`NodeResolveLoader`](http://mozilla.github.io/nunjucks/api.html#noderesolveloader),
a Loader that loads templates using node's
[`require.resolve`](https://nodejs.org/api/modules.html#modules_all_together).
Fixes [#1175](https://github.com/mozilla/nunjucks/issues/1175).
* Emit 'load' events on `Environment` instances, to allow runtime dependency
tracking. Fixes [#1153](https://github.com/mozilla/nunjucks/issues/1153).
3.1.7 (Jan 12 2019)
------------------
* Fix bug where exceptions were silently swallowed with synchronous render.
Fixes [#678](https://github.com/mozilla/nunjucks/issues/678),
[#1116](https://github.com/mozilla/nunjucks/issues/1116),
[#1127](https://github.com/mozilla/nunjucks/issues/1127), and
[#1164](https://github.com/mozilla/nunjucks/issues/1164)
* Removes deprecated postinstall-build package in favor of
[npm prepare](https://docs.npmjs.com/misc/scripts#prepublish-and-prepare).
Merge of [#1172](https://github.com/mozilla/nunjucks/pull/1172).
Fixes [#1167](https://github.com/mozilla/nunjucks/issues/1167).
- Note: this means that npm@5 or later is required to install nunjucks
directly from github.
3.1.6 (Dec 13 2018)
-------------------
No code changes; fixed npm packaging issue.
3.1.5 (Dec 13 2018)
-------------------
* Fix engine dependency version for Node versions > 11.1.0;
Fixes [#1168](https://github.com/mozilla/nunjucks/issues/1168).
3.1.4 (Nov 9 2018)
------------------
* Fix engine version for Node v11.1.0
* Fix "Unexpected token" error for U+2028 unicode newline. Fixes [#126](https://github.com/mozilla/nunjucks/issues/126) and [#736](https://github.com/mozilla/nunjucks/issues/736)
3.1.3 (May 19 2018)
-------------------
* Add `forceescape` filter. Fixes [#782](https://github.com/mozilla/nunjucks/issues/782)
* Fix regression that prevented template errors from reporting line and column number.
Fixes [#1087](https://github.com/mozilla/nunjucks/issues/1087) and
[#1095](https://github.com/mozilla/nunjucks/issues/1095).
* Fix "Invalid type: Is" error for `{% if value is defined %}`. Fixes
[#1110](https://github.com/mozilla/nunjucks/issues/1110)
* Formally drop support for node v4 (the upgrade to babel 7 in 3.1.0 made the
build process incompatible with node < 6.9.0).
3.1.2 (Feb 23 2018)
-------------------
* Fix regression to make `chokidar` an optional dependency again. Fixes
[#1073](https://github.com/mozilla/nunjucks/issues/1073)
* Fix issue when running `npm install nunjucks` with the `--no-bin-links` flag
* Fix regression that broke template caching. Fixes
[#1074](https://github.com/mozilla/nunjucks/issues/1074)
3.1.0 (Feb 19 2018)
-------------------
* Support nunjucks.installJinjaCompat() with slim build. Fixes
[#1019](https://github.com/mozilla/nunjucks/issues/1019)
* Fix calling render callback twice when a conditional import throws an error.
Solves [#1029](https://github.com/mozilla/nunjucks/issues/1029)
* Support objects created with Object.create(null). fixes [#468](https://github.com/mozilla/nunjucks/issues/468)
* Support ESNext iterators, using Array.from. Merge of
[#1058](https://github.com/mozilla/nunjucks/pull/1058)
3.0.1 (May 24 2017)
-------------------
* Fix handling methods and attributes of static arrays, objects and primitives.
Solves the issue [#937](https://github.com/mozilla/nunjucks/issues/937)
* Add support for python-style array slices with Jinja compat enabled.
Fixes [#188](https://github.com/mozilla/nunjucks/issues/188); merge of
[#976](https://github.com/mozilla/nunjucks/pull/976).
* Fix call blocks having access to their parent scope. Fixes
[#906](https://github.com/mozilla/nunjucks/issues/906); merge of
[#994](https://github.com/mozilla/nunjucks/pull/994).
* Fix a bug that caused capturing block tags (e.g. set/endset,
filter/endfilter) to write to the global buffer rather than capturing
their contents. Fixes
[#914](https://github.com/mozilla/nunjucks/issues/914) and
[#972](https://github.com/mozilla/nunjucks/issues/972); merge of
[#990](https://github.com/mozilla/nunjucks/pull/990). Thanks [Noah
Lange](@noahlange).
3.0.0 (Nov 5 2016)
----------------
* Allow including many templates without reaching recursion limits. Merge of
[#787](https://github.com/mozilla/nunjucks/pull/787). Thanks Gleb Khudyakov.
* Allow explicitly setting `null` (aka `none`) as the value of a variable;
don't ignore that value and look on up the frame stack or context. Fixes
[#478](https://github.com/mozilla/nunjucks/issues/478). Thanks Jonny Gerig
Meyer for the report.
* Execute blocks in a child frame that can't write to its parent. This means
that vars set inside blocks will not leak outside of the block, base
templates can no longer see vars set in templates that inherit them, and
`super()` can no longer set vars in its calling scope. Fixes the inheritance
portion of [#561](https://github.com/mozilla/nunjucks/issues/561), which
fully closes that issue. Thanks legutierr for the report.
* Prevent macros from seeing or affecting their calling scope. Merge of
[#667](https://github.com/mozilla/nunjucks/pull/667).
* Fix handling of macro arg with default value which shares a name with another
macro. Merge of [#791](https://github.com/mozilla/nunjucks/pull/791).
* Add support for the spaces parameter in the dump template filter.
Merge of [#868](https://github.com/mozilla/nunjucks/pull/868).
Thanks Jesse Eikema
* Add `verbatim` as an alias of `raw` for compatibility with Twig.
Merge of [#874](https://github.com/mozilla/nunjucks/pull/874).
* Add new `nl2br` filter. Thanks Marc-Aurèle Darche
* Add support for python's `list.append` with Jinja compat enabled. Thanks
Conor Flannigan.
* Add variables whitespace control.
2.5.2 (Sep 14 2016)
----------------
* Call `.toString` in safe filter.
Merge of [#849](https://github.com/mozilla/nunjucks/pull/849).
2.5.1 (Sep 13 2016)
----------------
* Fix `undefined` and `null` behavior in escape and safe filter.
Merge of [#843](https://github.com/mozilla/nunjucks/pull/843).
2.5.0 (Sep 7 2016)
----------------
* Add `elseif` as an alias of `elif` for parity with Twig. Thanks kswedberg.
Merge of [#826](https://github.com/mozilla/nunjucks/pull/826).
* Add nunjucks env to express app settings as `nunjucksEnv`.
Merge of [#829](https://github.com/mozilla/nunjucks/pull/829).
* Add support for finding an object's "length" in length filter.
Merge of [#813](https://github.com/mozilla/nunjucks/pull/813).
* Ensure that precompiling on Windows still outputs POSIX-style path
separators. Merge of [#761](https://github.com/mozilla/nunjucks/pull/761).
* Add support for strict type check comparisons (=== and !==). Thanks
oughter. Merge of [#746](https://github.com/mozilla/nunjucks/pull/746).
* Allow full expressions (incl. filters) in import and from tags. Thanks legutierr.
Merge of [#710](https://github.com/mozilla/nunjucks/pull/710).
* OS agnostic file paths in precompile. Merge of [#825](https://github.com/mozilla/nunjucks/pull/825).
2.4.3 (Sep 7 2016)
----------------
* Fix potential cast-related XSS vulnerability in autoescape mode, and with `escape` filter.
Thanks Matt Austin for the report and Thomas Hunkapiller for the fix.
[#836](https://github.com/mozilla/nunjucks/pull/836)
2.4.2 (Apr 15 2016)
-------------------
* Fix use of `in` operator with strings. Fixes
[#714](https://github.com/mozilla/nunjucks/issues/714). Thanks Zubrik for the
report.
* Support ES2015 Map and Set in `length` filter. Merge of
[#705](https://github.com/mozilla/nunjucks/pull/705). Thanks ricordisamoa.
* Remove truncation of long function names in error messages. Thanks Daniel
Bendavid. Merge of [#702](https://github.com/mozilla/nunjucks/pull/702).
2.4.1 (Mar 17 2016)
-------------------
* Don't double-escape. Thanks legutierr. Merge of
[#701](https://github.com/mozilla/nunjucks/pull/701).
* Prevent filter.escape from escaping SafeString. Thanks atian25. Merge of
[#623](https://github.com/mozilla/nunjucks/pull/623).
* Throw an error if a block is defined multiple times. Refs
[#696](https://github.com/mozilla/nunjucks/issues/696).
* Officially recommend the `.njk` extension. Thanks David Kebler. Merge of
[#691](https://github.com/mozilla/nunjucks/pull/691).
* Allow block-set to wrap an inheritance block. Unreported; fixed as a side
effect of the fix for [#576](https://github.com/mozilla/nunjucks/issues/576).
* Fix `filter` tag with non-trivial contents. Thanks Stefan Cruz and Fabien
Franzen for report and investigation, Jan Oopkaup for failing tests. Fixes
[#576](https://github.com/mozilla/nunjucks/issues/576).
2.4.0 (Mar 10 2016)
-------------------
* Allow retrieving boolean-false as a global. Thanks Marius Büscher. Merge of
[#694](https://github.com/mozilla/nunjucks/pull/694).
* Don't automatically convert any for-loop that has an include statement into
an async loop. Reverts
[7d4716f4fd](https://github.com/mozilla/nunjucks/commit/7d4716f4fd), re-opens
[#372](https://github.com/mozilla/nunjucks/issues/372), fixes
[#527](https://github.com/mozilla/nunjucks/issues/527). Thanks Tom Delmas for
the report.
* Switch from Optimist to Yargs for argument-parsing. Thanks Bogdan
Chadkin. Merge of [#672](https://github.com/mozilla/nunjucks/pull/672).
* Prevent includes from writing to their including scope. Merge of
[#667](https://github.com/mozilla/nunjucks/pull/667) (only partially
backported to 2.x; macro var visibility not backported).
* Fix handling of `dev` environment option, to get full tracebacks on errors
(including nunjucks internals). Thanks Tobias Petry and Chandrasekhar Ambula
V for the report, Aleksandr Motsjonov for draft patch.
* Support using `in` operator to search in both arrays and objects,
and it will throw an error for other data types.
Fix [#659](https://github.com/mozilla/nunjucks/pull/659).
Thanks Alex Mayfield for report and test, Ouyang Yadong for fix.
Merge of [#661](https://github.com/mozilla/nunjucks/pull/661).
* Add support for `{% set %}` block assignments as in jinja2. Thanks Daniele
Rapagnani. Merge of [#656](https://github.com/mozilla/nunjucks/pull/656)
* Fix `{% set %}` scoping within macros.
Fixes [#577](https://github.com/mozilla/nunjucks/issues/577) and
the macro portion of [#561](https://github.com/mozilla/nunjucks/issues/561).
Thanks Ouyang Yadong. Merge of [#653](https://github.com/mozilla/nunjucks/pull/653).
* Add support for named `endblock` (e.g. `{% endblock foo %}`). Thanks
ricordisamoa. Merge of [#641](https://github.com/mozilla/nunjucks/pull/641).
* Fix `range` global with zero as stop-value. Thanks Thomas Hunkapiller. Merge
of [#638](https://github.com/mozilla/nunjucks/pull/638).
* Fix a bug in urlize that collapsed whitespace. Thanks Paulo Bu. Merge of
[#637](https://github.com/mozilla/nunjucks/pull/637).
* Add `sum` filter. Thanks Pablo Matías Lazo. Merge of
[#629](https://github.com/mozilla/nunjucks/pull/629).
* Don't suppress errors inside {% if %} tags. Thanks Artemy Tregubenko for
report and test, Ouyang Yadong for fix. Merge of
[#634](https://github.com/mozilla/nunjucks/pull/634).
* Allow whitespace control on comment blocks, too. Thanks Ouyang Yadong. Merge
of [#632](https://github.com/mozilla/nunjucks/pull/632).
* Fix whitespace control around nested tags/variables/comments. Thanks Ouyang
Yadong. Merge of [#631](https://github.com/mozilla/nunjucks/pull/631).
v2.3.0 (Jan 6 2016)
-------------------
* Return `null` from `WebLoader` on missing template instead of throwing an
error, for consistency with other loaders. This allows `WebLoader` to support
the new `ignore missing` flag on the `include` tag. If `ignore missing` is
not set, a generic "template not found" error will still be thrown, just like
for any other loader. Ajax errors other than 404 will still cause `WebLoader`
to throw an error directly.
* Add preserve-linebreaks option to `striptags` filter. Thanks Ivan
Kleshnin. Merge of [#619](https://github.com/mozilla/nunjucks/pull/619).
v2.2.0 (Nov 23 2015)
--------------------
* Add `striptags` filter. Thanks Anthony Giniers. Merge of
[#589](https://github.com/mozilla/nunjucks/pull/589).
* Allow compiled templates to be imported, included and extended. Thanks Luis
Gutierrez-Sheris. Merge of
[#581](https://github.com/mozilla/nunjucks/pull/581).
* Fix issue with different nunjucks environments sharing same globals. Each
environment is now independent. Thanks Paul Pechin. Merge of
[#574](https://github.com/mozilla/nunjucks/pull/574).
* Add negative steps support for range function. Thanks Nikita Mostovoy. Merge
of [#575](https://github.com/mozilla/nunjucks/pull/575).
* Remove deprecation warning when using the `default` filter without specifying
a third argument. Merge of
[#567](https://github.com/mozilla/nunjucks/pull/567).
* Add support for chaining of addGlobal, addFilter, etc. Thanks Rob Graeber. Merge of
[#537](https://github.com/mozilla/nunjucks/pull/537)
* Fix error propagation. Thanks Tom Delmas. Merge of
[#534](https://github.com/mozilla/nunjucks/pull/534).
* trimBlocks now also trims windows style line endings. Thanks Magnus Tovslid. Merge of
[#548](https://github.com/mozilla/nunjucks/pull/548)
* `include` now supports an option to suppress errors if the template does not
exist. Thanks Mathias Nestler. Merge of
[#559](https://github.com/mozilla/nunjucks/pull/559)
v2.1.0 (Sep 21 2015)
--------------------
* Fix creating `WebLoader` without `opts`. Merge of
[#524](https://github.com/mozilla/nunjucks/pull/524).
* Add `hasExtension` and `removeExtension` methods to `Environment`. Merge of
[#512](https://github.com/mozilla/nunjucks/pull/512).
* Add support for kwargs in `sort` filter. Merge of
[#510](https://github.com/mozilla/nunjucks/pull/510).
* Add `none` as a lexed constant evaluating to `null`. Merge of
[#480](https://github.com/mozilla/nunjucks/pull/480).
* Fix rendering of multiple `raw` blocks. Thanks Aaron O'Mullan. Merge of
[#503](https://github.com/mozilla/nunjucks/pull/503).
* Avoid crashing on async loader error. Thanks Samy Pessé. Merge of
[#504](https://github.com/mozilla/nunjucks/pull/504).
* Add support for keyword arguments for sort filter. Thanks Andres Pardini. Merge of
[#510](https://github.com/mozilla/nunjucks/pull/510)
v2.0.0 (Aug 30 2015)
--------------------
Most of the changes can be summed up in the
[issues tagged 2.0](https://github.com/mozilla/nunjucks/issues?q=is%3Aissue+milestone%3A2.0+is%3Aclosed).
Or you can
[see all commits](https://github.com/mozilla/nunjucks/compare/v1.3.4...f8aabccefc31a9ffaccdc6797938b5187e07ea87).
Most important changes:
* **autoescape is now on by default.** You need to explicitly pass `{
autoescape: false }` in the options to turn it off.
* **watch is off by default.** You need to explicitly pass `{ watch: true }` to
start the watcher.
* The `default` filter has changed. It will show the default value only if the
argument is **undefined**. Any other value, even false-y values like `false`
and `null`, will be returned. You can get back the old behavior by passing
`true` as a 3rd argument to activate the loose-y behavior: `foo |
default("bar", true)`. In 2.0 if you don't pass the 3rd argument, a warning
will be displayed about this change in behavior. In 2.1 this warning will be
removed.
* [New filter tag](http://mozilla.github.io/nunjucks/templating.html#filter)
* Lots of other bug fixes and small features, view the above issue list!
v1.3.4 (Apr 27 2015)
--------------------
This is an extremely minor release that only adds an .npmignore so that the
bench, tests, and docs folders do not get published to npm. Nunjucks should
download a lot faster now.
v1.3.3 (Apr 3 2015)
-------------------
This is exactly the same as v1.3.1, just fixing a typo in the git version tag.
v1.3.2 (Apr 3 2015)
-------------------
(no notes)
v1.3.1 (Apr 3 2015)
-------------------
We added strict mode to all the files, but that broke running nunjucks in the
browser. Should work now with this small fix.
v1.3.0 (Apr 3 2015)
-------------------
* Relative templates: you can now load a template relatively by starting the
path with ., like ./foo.html
* FileSystemLoader now takes a noCache option, if true will disable caching
entirely
* Additional lstripBlocks and trimBlocks available to clean output
automatically
* New selectattr and rejectattr filters
* Small fixes to the watcher
* Several bug fixes
v1.2.0 (Feb 4 2015)
-------------------
* The special non-line-breaking space is considered whitespace now
* The in operator has a lower precedence now. This is potentially a breaking
change, thus the minor version bump. See
[#336](https://github.com/mozilla/nunjucks/pull/336)
* import with context now implemented:
[#319](https://github.com/mozilla/nunjucks/pull/319)
* async rendering doesn't throw compile errors
v1.1.0 (Sep 30 2014)
--------------------
User visible changes:
* Fix a bug in urlize that would remove periods
* custom tag syntax (like {% and %}) was made Environment-specific
internally. Previously they were global even though you set them through the
Environment.
* Remove aggressive optimization that only emitted loop variables when uses. It
introduced several bugs and didn't really improve perf.
* Support the regular expression syntax like /foo/g.
* The replace filter can take a regex as the first argument
* The call tag was implemented
* for tags can now take an else clause
* The cycler object now exposes the current item as the current property
* The chokidar library was updated and should fix various issues
Dev changes:
* Test coverage now available via istanbul. Will automatically display after
running tests.
v1.0.7 (Aug 15 2014)
--------------------
Mixed up a few things in the 1.0.6 release, so another small bump. This merges
in one thing:
* The length filter will not throw an error is used on an undefined
variable. It will return 0 if the variable is undefined.
v1.0.6 (Aug 15 2014)
--------------------
* Added the addGlobal method to the Environment object
* import/extends/include now can take an arbitrary expression
* fix bugs in set
* improve express integration (allows rendering templates without an extension)
v1.0.5 (May 1 2014)
-------------------
* Added support for browserify
* Added option to specify template output path when precompiling templates
* Keep version comment in browser minified files
* Speed up SafeString implementation
* Handle null and non-matching cases for word count filter
* Added support for node-webkit
* Other various minor bugfixes
chokidar repo fix - v1.0.4 (Apr 4 2014)
---------------------------------------
* The chokidar dependency moved repos, and though the git URL should have been
forwarded some people were having issues. This fixed the repo and
version.
(v1.0.3 is skipped because it was published with a bad URL, quickly fixed with
another version bump)
Bug fixes - v1.0.2 (Mar 25 2014)
--------------------------------
* Use chokidar for watching file changes. This should fix a lot of problems on
OS X machines.
* Always use / in paths when precompiling templates
* Fix bug where async filters hang indefinitely inside if statements
* Extensions now can override autoescaping with an autoescape property
* Other various minor bugfixes
v1.0.1 (Dec 16, 2013)
---------------------
(no notes)
We've reached 1.0! Better APIs, asynchronous control, and more (Oct 24, 2013)
-----------------------------------------------------------------------------
* An asynchronous API is now available, and async filters, extensions, and
loaders is supported. The async API is optional and if you don't do anything
async (the default), nothing changes for you. You can read more about this
[here](http://jlongster.github.io/nunjucks/api.html#asynchronous-support). (fixes
[#41](https://github.com/mozilla/nunjucks/issues/41))
* Much simpler higher-level API for initiating/configuring nunjucks is
available. Read more
[here](http://jlongster.github.io/nunjucks/api.html#simple-api).
* An official grunt plugin is available for precompiling templates:
[grunt-nunjucks](https://github.com/jlongster/grunt-nunjucks)
* **The browser files have been renamed.** nunjucks.js is now the full library
with compiler, and nunjucks-slim.js is the small version that only works with
precompiled templates
* urlencode filter has been added
* The express integration has been refactored and isn't a kludge
anymore. Should avoid some bugs and be more future-proof;
* The order in which variables are lookup up in the context and frame lookup
has been reversed. It will now look in the frame first, and then the
context. This means that if a for loop introduces a new var, like {% for name
in names %}, and if you have name in the context as well, it will properly
reference name from the for loop inside the loop. (fixes
[#122](https://github.com/mozilla/nunjucks/pull/122) and
[#119](https://github.com/mozilla/nunjucks/issues/119))
v0.1.10 (Aug 9 2013)
--------------------
(no notes)
v0.1.9 (May 30 2013)
--------------------
(no notes)
v0.1.8 - whitespace controls, unpacking, better errors, and more! (Feb 6 2013)
------------------------------------------------------------------------------
There are lots of cool new features in this release, as well as many critical
bug fixes.
Full list of changes:
* Whitespace control is implemented. Use {%- and -%} to strip whitespace before/after the block.
* `for` loops implement Python-style array unpacking. This is a really nice
feature which lets you do this:
{% for x, y, z in [[2, 2, 2], [3, 3, 3]] %}
--{{ x }} {{ y }} {{ z }}--
{% endfor %}
The above would output: --2 2 2----3 3 3--
You can pass any number of variable names to for and it will destructure each
array in the list to the variables.
This makes the syntax between arrays and objects more
consistent. Additionally, it allows us to implement the `dictsort` filter
which sorts an object by keys or values. Technically, it returns an array of
2-value arrays and the unpacking takes care of it. Example:
{% for k, v in { b: 2, a: 1 } %}
--{{ k }}: {{ v }}--
{% endfor %}
Output: `--b: 2----a: 1--` (note: the order could actually be anything
because it uses javascript’s `for k in obj` syntax to iterate, and ordering
depends on the js implementation)
{% for k, v in { b: 2, a: 1} | dictsort %}
--{{ k }}: {{ v }}--
{% endfor %}
Output: `--a: 1----b: 2--`
The above output will always be ordered that way. See the documentation for
more details.
Thanks to novocaine for this!
* Much better error handling with at runtime (shows template/line/col information for attempting to call undefined values, etc)
* Fixed a regression which broke the {% raw %} block
* Fix some edge cases with variable lookups
* Fix a regression with loading precompiled templates
* Tweaks to allow usage with YUICompressor
* Use the same error handling as normal when precompiling (shows proper errors)
* Fix template loading on Windows machines
* Fix int/float filters
* Fix regression with super()
v0.1.7 - helpful errors, many bug fixes (Dec 12 2012)
-----------------------------------------------------
The biggest change in v0.1.7 comes from devoidfury (thanks!) which implements
consistent and helpful error messages. The errors are still simply raw text,
and not pretty HTML, but they at least contain all the necessary information to
track down an error, such as template names, line and column numbers, and the
inheritance stack. So if an error happens in a child template, it will print
out all the templates that it inherits. In the future, we will most likely
display the actual line causing an error.
Full list of changes:
* Consistent and helpful error messages
* Expressions are more consistent now. Previously, there were several places
that wouldn’t accept an arbitrary expression that should. For example, you
can now do {% include templateNames['foo'] %}, whereas previously you could
only give it a simply variable name.
* app.locals is fixed with express 2.5
* Method calls on objects now have correct scope for this. Version 0.1.6 broke
this and this was referencing the global scope.
* A check was added to enforce loading of templates within the correct
path. Previously you could load a file outside of the template with something
like ../../crazyPrivateFile.txt
You can
[view all the code changes here](https://github.com/jlongster/nunjucks/compare/v0.1.6...v0.1.7). Please
[file an issue](https://github.com/jlongster/nunjucks/issues?page=1&state=open)
if something breaks!
v0.1.6 - undefined handling, bugfixes (Nov 13, 2012)
----------------------------------------------------
This is mostly a bugfix release, but there are a few small tweaks based on
feedback:
* In some cases, backslashes in the template would not appear in the
output. This has been fixed.
* An error is thrown if a filter is not found
* Old versions of express are now supported (2.5.11 was tested)
* References on undefined objects are now suppressed. For example, {{ foo }},
{{ foo.bar }}, {{ foo.bar.baz }} all output nothing if foo is
undefined. Previously only the first form would be suppressed, and a cryptic
error thrown for the latter 2 references. Note: I believe this is a departure
from jinja, which throws errors when referencing undefined objects. I feel
that this is a good and non-breaking addition though. (thanks to devoidfury)
* A bug in set where you couldn’t not reference other variables is fixed
(thanks chriso and panta)
* Other various small bugfixes
You can view
[all the code changes here](https://github.com/jlongster/nunjucks/compare/v0.1.5...v0.1.6). As
always, [file an issue](https://github.com/jlongster/nunjucks/issues) if
something breaks!
v0.1.5 - macros, keyword arguments, bugfixes (Oct 11 2012)
----------------------------------------------------------
v0.1.5 has been pushed to npm, and it’s a big one. Please file any issues you
find, and I’ll fix them as soon as possible!
* The node data structure has been completely refactored to reduce redundancy
and make it easier to add more types in the future.
* Thanks to Brent Hagany, macros now have been implemented. They should act
exactly the way jinja2 macros do.
* A calling convention which implements keyword arguments now exists. All
keyword args are converted into a hash and passed as the last
argument. Macros needed this to implement keyword/default arguments.
* Function and filter calls apply the new keyword argument calling convention
* The “set” block now appropriately only sets a variable for the current scope.
* Many other bugfixes.
I’m watching this release carefully because of the large amount of code that
has changed, so please
[file an issue](https://github.com/jlongster/nunjucks/issues) if you have a
problem with it.
+26
View File
@@ -0,0 +1,26 @@
Copyright (c) 2012-2015, James Long
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+58
View File
@@ -0,0 +1,58 @@
# Nunjucks
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Linux Build][github-actions-image]][github-actions-url]
[![Windows Build][appveyor-image]][appveyor-url]
[![Test Codecov][codecov-image]][codecov-url]
[Nunjucks](https://mozilla.github.io/nunjucks/) is a full featured
templating engine for javascript. It is heavily inspired by
[jinja2](http://jinja.pocoo.org/). View the docs
[here](https://mozilla.github.io/nunjucks/).
## Installation
`npm install nunjucks`
To use the file watcher built-in to Nunjucks, Chokidar must be installed separately.
`npm install nunjucks chokidar`
(View the [CHANGELOG](https://github.com/mozilla/nunjucks/releases))
## Documentation
See [here](https://mozilla.github.io/nunjucks/).
## Browser Support
Supported in all modern browsers. For IE8 support, use [es5-shim](https://github.com/es-shims/es5-shim).
## Tests
Run the tests with `npm test`.
Watch `master` branch's [tests running in the browser](https://mozilla.github.io/nunjucks/files/tests/browser/).
## Mailing List
Join our mailing list and get help with and issues you have:
https://groups.google.com/forum/?fromgroups#!forum/nunjucks
## Want to help?
Contributions are always welcome! Before you submit an issue or pull request, please read our [contribution guidelines](CONTRIBUTING.md).
[Contributors](https://github.com/mozilla/nunjucks/graphs/contributors)
[npm-image]: https://img.shields.io/npm/v/nunjucks.svg
[npm-url]: https://npmjs.org/package/nunjucks
[downloads-image]: https://img.shields.io/npm/dm/nunjucks.svg
[downloads-url]: https://npmjs.org/package/nunjucks
[github-actions-image]: https://img.shields.io/github/workflow/status/mozilla/nunjucks/Tests/master.svg?label=linux
[github-actions-url]: https://github.com/mozilla/nunjucks/actions
[appveyor-image]: https://img.shields.io/appveyor/ci/fdintino/nunjucks/master.svg?label=windows
[appveyor-url]: https://ci.appveyor.com/project/fdintino/nunjucks
[codecov-image]: https://img.shields.io/codecov/c/gh/mozilla/nunjucks.svg
[codecov-url]: https://codecov.io/gh/mozilla/nunjucks/branch/master
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env node
var {program} = require('commander');
var precompile = require('../src/precompile').precompile;
var Environment = require('../src/environment').Environment;
var lib = require('../src/lib');
var cmdpath = null;
program
.storeOptionsAsProperties(false)
.passCommandToAction(false);
program
.name('precompile')
.usage('[-f|--force] [-a|--filters <filters>] [-n|--name <name>] [-i|--include <regex>] [-x|--exclude <regex>] [-w|--wrapper <wrapper>] <path>')
.arguments('<path>')
.helpOption('-?, -h, --help', 'Display this help message')
.option('-f, --force', 'Force compilation to continue on error')
.option('-a, --filters <filters>', 'Give the compiler a comma-delimited list of asynchronous filters, required for correctly generating code')
.option('-n, --name <name>', 'Specify the template name when compiling a single file')
.option('-i, --include <regex>', 'Include a file or folder which match the regex but would otherwise be excluded. You can use this flag multiple times', concat, ['\\.html$', '\\.jinja$'])
.option('-x, --exclude <regex>', 'Exclude a file or folder which match the regex but would otherwise be included. You can use this flag multiple times', concat, [])
.option('-w, --wrapper <wrapper>', 'Load a external plugin to change the output format of the precompiled templates (for example, "-w custom" will load a module named "nunjucks-custom")')
.action(function (path) {
cmdpath = path;
})
.parse(process.argv);
function concat(value, previous) {
return previous.concat(value);
}
if (cmdpath == null) {
program.outputHelp();
console.error('\nerror: no path given');
process.exit(1);
}
var env = new Environment([]);
const opts = program.opts();
lib.each([].concat(opts.filters).join(',').split(','), function (name) {
env.addFilter(name.trim(), function () {}, true);
});
if (opts.wrapper) {
opts.wrapper = require('nunjucks-' + opts.wrapper).wrapper;
}
console.log(precompile(cmdpath, {
env : env,
force : opts.force,
name : opts.name,
wrapper: opts.wrapper,
include : [].concat(opts.include),
exclude : [].concat(opts.exclude)
}));
+5
View File
@@ -0,0 +1,5 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\precompile" %*
) ELSE (
node "%~dp0\precompile" %*
)
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8423
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+103
View File
@@ -0,0 +1,103 @@
'use strict';
var lib = require('./src/lib');
var _require = require('./src/environment'),
Environment = _require.Environment,
Template = _require.Template;
var Loader = require('./src/loader');
var loaders = require('./src/loaders');
var precompile = require('./src/precompile');
var compiler = require('./src/compiler');
var parser = require('./src/parser');
var lexer = require('./src/lexer');
var runtime = require('./src/runtime');
var nodes = require('./src/nodes');
var installJinjaCompat = require('./src/jinja-compat'); // A single instance of an environment, since this is so commonly used
var e;
function configure(templatesPath, opts) {
opts = opts || {};
if (lib.isObject(templatesPath)) {
opts = templatesPath;
templatesPath = null;
}
var TemplateLoader;
if (loaders.FileSystemLoader) {
TemplateLoader = new loaders.FileSystemLoader(templatesPath, {
watch: opts.watch,
noCache: opts.noCache
});
} else if (loaders.WebLoader) {
TemplateLoader = new loaders.WebLoader(templatesPath, {
useCache: opts.web && opts.web.useCache,
async: opts.web && opts.web.async
});
}
e = new Environment(TemplateLoader, opts);
if (opts && opts.express) {
e.express(opts.express);
}
return e;
}
module.exports = {
Environment: Environment,
Template: Template,
Loader: Loader,
FileSystemLoader: loaders.FileSystemLoader,
NodeResolveLoader: loaders.NodeResolveLoader,
PrecompiledLoader: loaders.PrecompiledLoader,
WebLoader: loaders.WebLoader,
compiler: compiler,
parser: parser,
lexer: lexer,
runtime: runtime,
lib: lib,
nodes: nodes,
installJinjaCompat: installJinjaCompat,
configure: configure,
reset: function reset() {
e = undefined;
},
compile: function compile(src, env, path, eagerCompile) {
if (!e) {
configure();
}
return new Template(src, env, path, eagerCompile);
},
render: function render(name, ctx, cb) {
if (!e) {
configure();
}
return e.render(name, ctx, cb);
},
renderString: function renderString(src, ctx, cb) {
if (!e) {
configure();
}
return e.renderString(src, ctx, cb);
},
precompile: precompile ? precompile.precompile : undefined,
precompileString: precompile ? precompile.precompileString : undefined
};
+144
View File
@@ -0,0 +1,144 @@
{
"_args": [
[
"nunjucks@3.2.3",
"/home/pi/Desktop/smartMirrorTestEnvironment/MagicMirror/vendor"
]
],
"_from": "nunjucks@3.2.3",
"_id": "nunjucks@3.2.3",
"_inBundle": false,
"_integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
"_location": "/nunjucks",
"_moduleAliases": {
"babel-register": "@babel/register"
},
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "nunjucks@3.2.3",
"name": "nunjucks",
"escapedName": "nunjucks",
"rawSpec": "3.2.3",
"saveSpec": null,
"fetchSpec": "3.2.3"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz",
"_spec": "3.2.3",
"_where": "/home/pi/Desktop/smartMirrorTestEnvironment/MagicMirror/vendor",
"author": {
"name": "James Long",
"email": "longster@gmail.com"
},
"bin": {
"nunjucks-precompile": "./bin/precompile"
},
"browser": "./browser/nunjucks.js",
"bugs": {
"url": "https://github.com/mozilla/nunjucks/issues"
},
"buildDependencies": {
"@babel/cli": "^7.0.0-beta.38",
"@babel/core": "^7.0.0-beta.38",
"@babel/preset-env": "^7.0.0-beta.38",
"@babel/register": "^7.0.0-beta.38",
"babel-loader": "^8.0.0-beta.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-module-resolver": "3.0.0-beta.5",
"core-js": "^2.5.3",
"module-alias": "^2.0.3",
"node-libs-browser": "^0.7.0",
"uglify-js": "^2.8.29",
"uglifyjs-webpack-plugin": "^1.1.6",
"webpack": "^3.10.0"
},
"dependencies": {
"a-sync-waterfall": "^1.0.0",
"asap": "^2.0.3",
"commander": "^5.1.0"
},
"description": "A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)",
"devDependencies": {
"@babel/cli": "^7.0.0-beta.38",
"@babel/core": "^7.0.0-beta.38",
"@babel/preset-env": "^7.0.0-beta.38",
"@babel/register": "^7.0.0-beta.38",
"babel-loader": "^8.0.0-beta.0",
"babel-plugin-istanbul": "^4.1.5",
"babel-plugin-module-resolver": "3.0.0-beta.5",
"connect": "^3.6.5",
"core-js": "^2.5.3",
"cross-env": "^5.1.3",
"eslint": "^4.13.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0",
"expect.js": "*",
"express": "4.x",
"fs-extra": "^5.0.0",
"get-port": "^3.2.0",
"mocha": "< 8.x",
"mocha-phantomjs-core": "^2.1.2",
"mocha-phantomjs-istanbul": "0.0.2",
"module-alias": "^2.0.3",
"node-libs-browser": "^0.7.0",
"nyc": "^11.4.1",
"phantomjs-prebuilt": "^2.1.16",
"serve-static": "^1.13.1",
"supertest": "*",
"uglify-js": "^2.8.29",
"uglifyjs-webpack-plugin": "^1.1.6",
"webpack": "^3.10.0"
},
"engines": {
"node": ">= 6.9.0"
},
"files": [
"bin/**",
"browser/**",
"src/**"
],
"homepage": "https://github.com/mozilla/nunjucks#readme",
"keywords": [
"template",
"templating"
],
"license": "BSD-2-Clause",
"main": "index.js",
"name": "nunjucks",
"nyc": {
"require": [
"babel-register"
],
"sourceMap": false,
"instrument": false
},
"peerDependencies": {
"chokidar": "^3.3.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/mozilla/nunjucks.git"
},
"scripts": {
"build": "npm run build:transpile && npm run build:bundle",
"build:bundle": "node scripts/bundle.js",
"build:transpile": "babel nunjucks --out-dir .",
"codecov": "codecov",
"lint": "eslint nunjucks scripts tests",
"mocha": "mocha -R spec tests",
"prepare": "npm run build",
"test": "npm run lint && npm run test:instrument && npm run test:runner",
"test:instrument": "cross-env NODE_ENV=test scripts/bundle.js",
"test:runner": "cross-env NODE_ENV=test NODE_PATH=tests/test-node-pkgs scripts/testrunner.js"
},
"version": "3.2.3"
}
+1449
View File
File diff suppressed because it is too large Load Diff
+659
View File
@@ -0,0 +1,659 @@
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var asap = require('asap');
var _waterfall = require('a-sync-waterfall');
var lib = require('./lib');
var compiler = require('./compiler');
var filters = require('./filters');
var _require = require('./loaders'),
FileSystemLoader = _require.FileSystemLoader,
WebLoader = _require.WebLoader,
PrecompiledLoader = _require.PrecompiledLoader;
var tests = require('./tests');
var globals = require('./globals');
var _require2 = require('./object'),
Obj = _require2.Obj,
EmitterObj = _require2.EmitterObj;
var globalRuntime = require('./runtime');
var handleError = globalRuntime.handleError,
Frame = globalRuntime.Frame;
var expressApp = require('./express-app'); // If the user is using the async API, *always* call it
// asynchronously even if the template was synchronous.
function callbackAsap(cb, err, res) {
asap(function () {
cb(err, res);
});
}
/**
* A no-op template, for use with {% include ignore missing %}
*/
var noopTmplSrc = {
type: 'code',
obj: {
root: function root(env, context, frame, runtime, cb) {
try {
cb(null, '');
} catch (e) {
cb(handleError(e, null, null));
}
}
}
};
var Environment = /*#__PURE__*/function (_EmitterObj) {
_inheritsLoose(Environment, _EmitterObj);
function Environment() {
return _EmitterObj.apply(this, arguments) || this;
}
var _proto = Environment.prototype;
_proto.init = function init(loaders, opts) {
var _this = this;
// The dev flag determines the trace that'll be shown on errors.
// If set to true, returns the full trace from the error point,
// otherwise will return trace starting from Template.render
// (the full trace from within nunjucks may confuse developers using
// the library)
// defaults to false
opts = this.opts = opts || {};
this.opts.dev = !!opts.dev; // The autoescape flag sets global autoescaping. If true,
// every string variable will be escaped by default.
// If false, strings can be manually escaped using the `escape` filter.
// defaults to true
this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true; // If true, this will make the system throw errors if trying
// to output a null or undefined value
this.opts.throwOnUndefined = !!opts.throwOnUndefined;
this.opts.trimBlocks = !!opts.trimBlocks;
this.opts.lstripBlocks = !!opts.lstripBlocks;
this.loaders = [];
if (!loaders) {
// The filesystem loader is only available server-side
if (FileSystemLoader) {
this.loaders = [new FileSystemLoader('views')];
} else if (WebLoader) {
this.loaders = [new WebLoader('/views')];
}
} else {
this.loaders = lib.isArray(loaders) ? loaders : [loaders];
} // It's easy to use precompiled templates: just include them
// before you configure nunjucks and this will automatically
// pick it up and use it
if (typeof window !== 'undefined' && window.nunjucksPrecompiled) {
this.loaders.unshift(new PrecompiledLoader(window.nunjucksPrecompiled));
}
this._initLoaders();
this.globals = globals();
this.filters = {};
this.tests = {};
this.asyncFilters = [];
this.extensions = {};
this.extensionsList = [];
lib._entries(filters).forEach(function (_ref) {
var name = _ref[0],
filter = _ref[1];
return _this.addFilter(name, filter);
});
lib._entries(tests).forEach(function (_ref2) {
var name = _ref2[0],
test = _ref2[1];
return _this.addTest(name, test);
});
};
_proto._initLoaders = function _initLoaders() {
var _this2 = this;
this.loaders.forEach(function (loader) {
// Caching and cache busting
loader.cache = {};
if (typeof loader.on === 'function') {
loader.on('update', function (name, fullname) {
loader.cache[name] = null;
_this2.emit('update', name, fullname, loader);
});
loader.on('load', function (name, source) {
_this2.emit('load', name, source, loader);
});
}
});
};
_proto.invalidateCache = function invalidateCache() {
this.loaders.forEach(function (loader) {
loader.cache = {};
});
};
_proto.addExtension = function addExtension(name, extension) {
extension.__name = name;
this.extensions[name] = extension;
this.extensionsList.push(extension);
return this;
};
_proto.removeExtension = function removeExtension(name) {
var extension = this.getExtension(name);
if (!extension) {
return;
}
this.extensionsList = lib.without(this.extensionsList, extension);
delete this.extensions[name];
};
_proto.getExtension = function getExtension(name) {
return this.extensions[name];
};
_proto.hasExtension = function hasExtension(name) {
return !!this.extensions[name];
};
_proto.addGlobal = function addGlobal(name, value) {
this.globals[name] = value;
return this;
};
_proto.getGlobal = function getGlobal(name) {
if (typeof this.globals[name] === 'undefined') {
throw new Error('global not found: ' + name);
}
return this.globals[name];
};
_proto.addFilter = function addFilter(name, func, async) {
var wrapped = func;
if (async) {
this.asyncFilters.push(name);
}
this.filters[name] = wrapped;
return this;
};
_proto.getFilter = function getFilter(name) {
if (!this.filters[name]) {
throw new Error('filter not found: ' + name);
}
return this.filters[name];
};
_proto.addTest = function addTest(name, func) {
this.tests[name] = func;
return this;
};
_proto.getTest = function getTest(name) {
if (!this.tests[name]) {
throw new Error('test not found: ' + name);
}
return this.tests[name];
};
_proto.resolveTemplate = function resolveTemplate(loader, parentName, filename) {
var isRelative = loader.isRelative && parentName ? loader.isRelative(filename) : false;
return isRelative && loader.resolve ? loader.resolve(parentName, filename) : filename;
};
_proto.getTemplate = function getTemplate(name, eagerCompile, parentName, ignoreMissing, cb) {
var _this3 = this;
var that = this;
var tmpl = null;
if (name && name.raw) {
// this fixes autoescape for templates referenced in symbols
name = name.raw;
}
if (lib.isFunction(parentName)) {
cb = parentName;
parentName = null;
eagerCompile = eagerCompile || false;
}
if (lib.isFunction(eagerCompile)) {
cb = eagerCompile;
eagerCompile = false;
}
if (name instanceof Template) {
tmpl = name;
} else if (typeof name !== 'string') {
throw new Error('template names must be a string: ' + name);
} else {
for (var i = 0; i < this.loaders.length; i++) {
var loader = this.loaders[i];
tmpl = loader.cache[this.resolveTemplate(loader, parentName, name)];
if (tmpl) {
break;
}
}
}
if (tmpl) {
if (eagerCompile) {
tmpl.compile();
}
if (cb) {
cb(null, tmpl);
return undefined;
} else {
return tmpl;
}
}
var syncResult;
var createTemplate = function createTemplate(err, info) {
if (!info && !err && !ignoreMissing) {
err = new Error('template not found: ' + name);
}
if (err) {
if (cb) {
cb(err);
return;
} else {
throw err;
}
}
var newTmpl;
if (!info) {
newTmpl = new Template(noopTmplSrc, _this3, '', eagerCompile);
} else {
newTmpl = new Template(info.src, _this3, info.path, eagerCompile);
if (!info.noCache) {
info.loader.cache[name] = newTmpl;
}
}
if (cb) {
cb(null, newTmpl);
} else {
syncResult = newTmpl;
}
};
lib.asyncIter(this.loaders, function (loader, i, next, done) {
function handle(err, src) {
if (err) {
done(err);
} else if (src) {
src.loader = loader;
done(null, src);
} else {
next();
}
} // Resolve name relative to parentName
name = that.resolveTemplate(loader, parentName, name);
if (loader.async) {
loader.getSource(name, handle);
} else {
handle(null, loader.getSource(name));
}
}, createTemplate);
return syncResult;
};
_proto.express = function express(app) {
return expressApp(this, app);
};
_proto.render = function render(name, ctx, cb) {
if (lib.isFunction(ctx)) {
cb = ctx;
ctx = null;
} // We support a synchronous API to make it easier to migrate
// existing code to async. This works because if you don't do
// anything async work, the whole thing is actually run
// synchronously.
var syncResult = null;
this.getTemplate(name, function (err, tmpl) {
if (err && cb) {
callbackAsap(cb, err);
} else if (err) {
throw err;
} else {
syncResult = tmpl.render(ctx, cb);
}
});
return syncResult;
};
_proto.renderString = function renderString(src, ctx, opts, cb) {
if (lib.isFunction(opts)) {
cb = opts;
opts = {};
}
opts = opts || {};
var tmpl = new Template(src, this, opts.path);
return tmpl.render(ctx, cb);
};
_proto.waterfall = function waterfall(tasks, callback, forceAsync) {
return _waterfall(tasks, callback, forceAsync);
};
return Environment;
}(EmitterObj);
var Context = /*#__PURE__*/function (_Obj) {
_inheritsLoose(Context, _Obj);
function Context() {
return _Obj.apply(this, arguments) || this;
}
var _proto2 = Context.prototype;
_proto2.init = function init(ctx, blocks, env) {
var _this4 = this;
// Has to be tied to an environment so we can tap into its globals.
this.env = env || new Environment(); // Make a duplicate of ctx
this.ctx = lib.extend({}, ctx);
this.blocks = {};
this.exported = [];
lib.keys(blocks).forEach(function (name) {
_this4.addBlock(name, blocks[name]);
});
};
_proto2.lookup = function lookup(name) {
// This is one of the most called functions, so optimize for
// the typical case where the name isn't in the globals
if (name in this.env.globals && !(name in this.ctx)) {
return this.env.globals[name];
} else {
return this.ctx[name];
}
};
_proto2.setVariable = function setVariable(name, val) {
this.ctx[name] = val;
};
_proto2.getVariables = function getVariables() {
return this.ctx;
};
_proto2.addBlock = function addBlock(name, block) {
this.blocks[name] = this.blocks[name] || [];
this.blocks[name].push(block);
return this;
};
_proto2.getBlock = function getBlock(name) {
if (!this.blocks[name]) {
throw new Error('unknown block "' + name + '"');
}
return this.blocks[name][0];
};
_proto2.getSuper = function getSuper(env, name, block, frame, runtime, cb) {
var idx = lib.indexOf(this.blocks[name] || [], block);
var blk = this.blocks[name][idx + 1];
var context = this;
if (idx === -1 || !blk) {
throw new Error('no super block available for "' + name + '"');
}
blk(env, context, frame, runtime, cb);
};
_proto2.addExport = function addExport(name) {
this.exported.push(name);
};
_proto2.getExported = function getExported() {
var _this5 = this;
var exported = {};
this.exported.forEach(function (name) {
exported[name] = _this5.ctx[name];
});
return exported;
};
return Context;
}(Obj);
var Template = /*#__PURE__*/function (_Obj2) {
_inheritsLoose(Template, _Obj2);
function Template() {
return _Obj2.apply(this, arguments) || this;
}
var _proto3 = Template.prototype;
_proto3.init = function init(src, env, path, eagerCompile) {
this.env = env || new Environment();
if (lib.isObject(src)) {
switch (src.type) {
case 'code':
this.tmplProps = src.obj;
break;
case 'string':
this.tmplStr = src.obj;
break;
default:
throw new Error("Unexpected template object type " + src.type + "; expected 'code', or 'string'");
}
} else if (lib.isString(src)) {
this.tmplStr = src;
} else {
throw new Error('src must be a string or an object describing the source');
}
this.path = path;
if (eagerCompile) {
try {
this._compile();
} catch (err) {
throw lib._prettifyError(this.path, this.env.opts.dev, err);
}
} else {
this.compiled = false;
}
};
_proto3.render = function render(ctx, parentFrame, cb) {
var _this6 = this;
if (typeof ctx === 'function') {
cb = ctx;
ctx = {};
} else if (typeof parentFrame === 'function') {
cb = parentFrame;
parentFrame = null;
} // If there is a parent frame, we are being called from internal
// code of another template, and the internal system
// depends on the sync/async nature of the parent template
// to be inherited, so force an async callback
var forceAsync = !parentFrame; // Catch compile errors for async rendering
try {
this.compile();
} catch (e) {
var err = lib._prettifyError(this.path, this.env.opts.dev, e);
if (cb) {
return callbackAsap(cb, err);
} else {
throw err;
}
}
var context = new Context(ctx || {}, this.blocks, this.env);
var frame = parentFrame ? parentFrame.push(true) : new Frame();
frame.topLevel = true;
var syncResult = null;
var didError = false;
this.rootRenderFunc(this.env, context, frame, globalRuntime, function (err, res) {
// TODO: this is actually a bug in the compiled template (because waterfall
// tasks are both not passing errors up the chain of callbacks AND are not
// causing a return from the top-most render function). But fixing that
// will require a more substantial change to the compiler.
if (didError && cb && typeof res !== 'undefined') {
// prevent multiple calls to cb
return;
}
if (err) {
err = lib._prettifyError(_this6.path, _this6.env.opts.dev, err);
didError = true;
}
if (cb) {
if (forceAsync) {
callbackAsap(cb, err, res);
} else {
cb(err, res);
}
} else {
if (err) {
throw err;
}
syncResult = res;
}
});
return syncResult;
};
_proto3.getExported = function getExported(ctx, parentFrame, cb) {
// eslint-disable-line consistent-return
if (typeof ctx === 'function') {
cb = ctx;
ctx = {};
}
if (typeof parentFrame === 'function') {
cb = parentFrame;
parentFrame = null;
} // Catch compile errors for async rendering
try {
this.compile();
} catch (e) {
if (cb) {
return cb(e);
} else {
throw e;
}
}
var frame = parentFrame ? parentFrame.push() : new Frame();
frame.topLevel = true; // Run the rootRenderFunc to populate the context with exported vars
var context = new Context(ctx || {}, this.blocks, this.env);
this.rootRenderFunc(this.env, context, frame, globalRuntime, function (err) {
if (err) {
cb(err, null);
} else {
cb(null, context.getExported());
}
});
};
_proto3.compile = function compile() {
if (!this.compiled) {
this._compile();
}
};
_proto3._compile = function _compile() {
var props;
if (this.tmplProps) {
props = this.tmplProps;
} else {
var source = compiler.compile(this.tmplStr, this.env.asyncFilters, this.env.extensionsList, this.path, this.env.opts);
var func = new Function(source); // eslint-disable-line no-new-func
props = func();
}
this.blocks = this._getBlocks(props);
this.rootRenderFunc = props.root;
this.compiled = true;
};
_proto3._getBlocks = function _getBlocks(props) {
var blocks = {};
lib.keys(props).forEach(function (k) {
if (k.slice(0, 2) === 'b_') {
blocks[k.slice(2)] = props[k];
}
});
return blocks;
};
return Template;
}(Obj);
module.exports = {
Environment: Environment,
Template: Template
};
+28
View File
@@ -0,0 +1,28 @@
"use strict";
var path = require('path');
module.exports = function express(env, app) {
function NunjucksView(name, opts) {
this.name = name;
this.path = name;
this.defaultEngine = opts.defaultEngine;
this.ext = path.extname(name);
if (!this.ext && !this.defaultEngine) {
throw new Error('No default engine was specified and no extension was provided.');
}
if (!this.ext) {
this.name += this.ext = (this.defaultEngine[0] !== '.' ? '.' : '') + this.defaultEngine;
}
}
NunjucksView.prototype.render = function render(opts, cb) {
env.render(this.name, opts, cb);
};
app.set('view', NunjucksView);
app.set('nunjucksEnv', env);
return env;
};
+680
View File
@@ -0,0 +1,680 @@
'use strict';
var lib = require('./lib');
var r = require('./runtime');
var _exports = module.exports = {};
function normalize(value, defaultValue) {
if (value === null || value === undefined || value === false) {
return defaultValue;
}
return value;
}
_exports.abs = Math.abs;
function isNaN(num) {
return num !== num; // eslint-disable-line no-self-compare
}
function batch(arr, linecount, fillWith) {
var i;
var res = [];
var tmp = [];
for (i = 0; i < arr.length; i++) {
if (i % linecount === 0 && tmp.length) {
res.push(tmp);
tmp = [];
}
tmp.push(arr[i]);
}
if (tmp.length) {
if (fillWith) {
for (i = tmp.length; i < linecount; i++) {
tmp.push(fillWith);
}
}
res.push(tmp);
}
return res;
}
_exports.batch = batch;
function capitalize(str) {
str = normalize(str, '');
var ret = str.toLowerCase();
return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1));
}
_exports.capitalize = capitalize;
function center(str, width) {
str = normalize(str, '');
width = width || 80;
if (str.length >= width) {
return str;
}
var spaces = width - str.length;
var pre = lib.repeat(' ', spaces / 2 - spaces % 2);
var post = lib.repeat(' ', spaces / 2);
return r.copySafeness(str, pre + str + post);
}
_exports.center = center;
function default_(val, def, bool) {
if (bool) {
return val || def;
} else {
return val !== undefined ? val : def;
}
} // TODO: it is confusing to export something called 'default'
_exports['default'] = default_; // eslint-disable-line dot-notation
function dictsort(val, caseSensitive, by) {
if (!lib.isObject(val)) {
throw new lib.TemplateError('dictsort filter: val must be an object');
}
var array = []; // deliberately include properties from the object's prototype
for (var k in val) {
// eslint-disable-line guard-for-in, no-restricted-syntax
array.push([k, val[k]]);
}
var si;
if (by === undefined || by === 'key') {
si = 0;
} else if (by === 'value') {
si = 1;
} else {
throw new lib.TemplateError('dictsort filter: You can only sort by either key or value');
}
array.sort(function (t1, t2) {
var a = t1[si];
var b = t2[si];
if (!caseSensitive) {
if (lib.isString(a)) {
a = a.toUpperCase();
}
if (lib.isString(b)) {
b = b.toUpperCase();
}
}
return a > b ? 1 : a === b ? 0 : -1; // eslint-disable-line no-nested-ternary
});
return array;
}
_exports.dictsort = dictsort;
function dump(obj, spaces) {
return JSON.stringify(obj, null, spaces);
}
_exports.dump = dump;
function escape(str) {
if (str instanceof r.SafeString) {
return str;
}
str = str === null || str === undefined ? '' : str;
return r.markSafe(lib.escape(str.toString()));
}
_exports.escape = escape;
function safe(str) {
if (str instanceof r.SafeString) {
return str;
}
str = str === null || str === undefined ? '' : str;
return r.markSafe(str.toString());
}
_exports.safe = safe;
function first(arr) {
return arr[0];
}
_exports.first = first;
function forceescape(str) {
str = str === null || str === undefined ? '' : str;
return r.markSafe(lib.escape(str.toString()));
}
_exports.forceescape = forceescape;
function groupby(arr, attr) {
return lib.groupBy(arr, attr, this.env.opts.throwOnUndefined);
}
_exports.groupby = groupby;
function indent(str, width, indentfirst) {
str = normalize(str, '');
if (str === '') {
return '';
}
width = width || 4; // let res = '';
var lines = str.split('\n');
var sp = lib.repeat(' ', width);
var res = lines.map(function (l, i) {
return i === 0 && !indentfirst ? l : "" + sp + l;
}).join('\n');
return r.copySafeness(str, res);
}
_exports.indent = indent;
function join(arr, del, attr) {
del = del || '';
if (attr) {
arr = lib.map(arr, function (v) {
return v[attr];
});
}
return arr.join(del);
}
_exports.join = join;
function last(arr) {
return arr[arr.length - 1];
}
_exports.last = last;
function lengthFilter(val) {
var value = normalize(val, '');
if (value !== undefined) {
if (typeof Map === 'function' && value instanceof Map || typeof Set === 'function' && value instanceof Set) {
// ECMAScript 2015 Maps and Sets
return value.size;
}
if (lib.isObject(value) && !(value instanceof r.SafeString)) {
// Objects (besides SafeStrings), non-primative Arrays
return lib.keys(value).length;
}
return value.length;
}
return 0;
}
_exports.length = lengthFilter;
function list(val) {
if (lib.isString(val)) {
return val.split('');
} else if (lib.isObject(val)) {
return lib._entries(val || {}).map(function (_ref) {
var key = _ref[0],
value = _ref[1];
return {
key: key,
value: value
};
});
} else if (lib.isArray(val)) {
return val;
} else {
throw new lib.TemplateError('list filter: type not iterable');
}
}
_exports.list = list;
function lower(str) {
str = normalize(str, '');
return str.toLowerCase();
}
_exports.lower = lower;
function nl2br(str) {
if (str === null || str === undefined) {
return '';
}
return r.copySafeness(str, str.replace(/\r\n|\n/g, '<br />\n'));
}
_exports.nl2br = nl2br;
function random(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
_exports.random = random;
/**
* Construct select or reject filter
*
* @param {boolean} expectedTestResult
* @returns {function(array, string, *): array}
*/
function getSelectOrReject(expectedTestResult) {
function filter(arr, testName, secondArg) {
if (testName === void 0) {
testName = 'truthy';
}
var context = this;
var test = context.env.getTest(testName);
return lib.toArray(arr).filter(function examineTestResult(item) {
return test.call(context, item, secondArg) === expectedTestResult;
});
}
return filter;
}
_exports.reject = getSelectOrReject(false);
function rejectattr(arr, attr) {
return arr.filter(function (item) {
return !item[attr];
});
}
_exports.rejectattr = rejectattr;
_exports.select = getSelectOrReject(true);
function selectattr(arr, attr) {
return arr.filter(function (item) {
return !!item[attr];
});
}
_exports.selectattr = selectattr;
function replace(str, old, new_, maxCount) {
var originalStr = str;
if (old instanceof RegExp) {
return str.replace(old, new_);
}
if (typeof maxCount === 'undefined') {
maxCount = -1;
}
var res = ''; // Output
// Cast Numbers in the search term to string
if (typeof old === 'number') {
old = '' + old;
} else if (typeof old !== 'string') {
// If it is something other than number or string,
// return the original string
return str;
} // Cast numbers in the replacement to string
if (typeof str === 'number') {
str = '' + str;
} // If by now, we don't have a string, throw it back
if (typeof str !== 'string' && !(str instanceof r.SafeString)) {
return str;
} // ShortCircuits
if (old === '') {
// Mimic the python behaviour: empty string is replaced
// by replacement e.g. "abc"|replace("", ".") -> .a.b.c.
res = new_ + str.split('').join(new_) + new_;
return r.copySafeness(str, res);
}
var nextIndex = str.indexOf(old); // if # of replacements to perform is 0, or the string to does
// not contain the old value, return the string
if (maxCount === 0 || nextIndex === -1) {
return str;
}
var pos = 0;
var count = 0; // # of replacements made
while (nextIndex > -1 && (maxCount === -1 || count < maxCount)) {
// Grab the next chunk of src string and add it with the
// replacement, to the result
res += str.substring(pos, nextIndex) + new_; // Increment our pointer in the src string
pos = nextIndex + old.length;
count++; // See if there are any more replacements to be made
nextIndex = str.indexOf(old, pos);
} // We've either reached the end, or done the max # of
// replacements, tack on any remaining string
if (pos < str.length) {
res += str.substring(pos);
}
return r.copySafeness(originalStr, res);
}
_exports.replace = replace;
function reverse(val) {
var arr;
if (lib.isString(val)) {
arr = list(val);
} else {
// Copy it
arr = lib.map(val, function (v) {
return v;
});
}
arr.reverse();
if (lib.isString(val)) {
return r.copySafeness(val, arr.join(''));
}
return arr;
}
_exports.reverse = reverse;
function round(val, precision, method) {
precision = precision || 0;
var factor = Math.pow(10, precision);
var rounder;
if (method === 'ceil') {
rounder = Math.ceil;
} else if (method === 'floor') {
rounder = Math.floor;
} else {
rounder = Math.round;
}
return rounder(val * factor) / factor;
}
_exports.round = round;
function slice(arr, slices, fillWith) {
var sliceLength = Math.floor(arr.length / slices);
var extra = arr.length % slices;
var res = [];
var offset = 0;
for (var i = 0; i < slices; i++) {
var start = offset + i * sliceLength;
if (i < extra) {
offset++;
}
var end = offset + (i + 1) * sliceLength;
var currSlice = arr.slice(start, end);
if (fillWith && i >= extra) {
currSlice.push(fillWith);
}
res.push(currSlice);
}
return res;
}
_exports.slice = slice;
function sum(arr, attr, start) {
if (start === void 0) {
start = 0;
}
if (attr) {
arr = lib.map(arr, function (v) {
return v[attr];
});
}
return start + arr.reduce(function (a, b) {
return a + b;
}, 0);
}
_exports.sum = sum;
_exports.sort = r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], function sortFilter(arr, reversed, caseSens, attr) {
var _this = this;
// Copy it
var array = lib.map(arr, function (v) {
return v;
});
var getAttribute = lib.getAttrGetter(attr);
array.sort(function (a, b) {
var x = attr ? getAttribute(a) : a;
var y = attr ? getAttribute(b) : b;
if (_this.env.opts.throwOnUndefined && attr && (x === undefined || y === undefined)) {
throw new TypeError("sort: attribute \"" + attr + "\" resolved to undefined");
}
if (!caseSens && lib.isString(x) && lib.isString(y)) {
x = x.toLowerCase();
y = y.toLowerCase();
}
if (x < y) {
return reversed ? 1 : -1;
} else if (x > y) {
return reversed ? -1 : 1;
} else {
return 0;
}
});
return array;
});
function string(obj) {
return r.copySafeness(obj, obj);
}
_exports.string = string;
function striptags(input, preserveLinebreaks) {
input = normalize(input, '');
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|<!--[\s\S]*?-->/gi;
var trimmedInput = trim(input.replace(tags, ''));
var res = '';
if (preserveLinebreaks) {
res = trimmedInput.replace(/^ +| +$/gm, '') // remove leading and trailing spaces
.replace(/ +/g, ' ') // squash adjacent spaces
.replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF)
.replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks
} else {
res = trimmedInput.replace(/\s+/gi, ' ');
}
return r.copySafeness(input, res);
}
_exports.striptags = striptags;
function title(str) {
str = normalize(str, '');
var words = str.split(' ').map(function (word) {
return capitalize(word);
});
return r.copySafeness(str, words.join(' '));
}
_exports.title = title;
function trim(str) {
return r.copySafeness(str, str.replace(/^\s*|\s*$/g, ''));
}
_exports.trim = trim;
function truncate(input, length, killwords, end) {
var orig = input;
input = normalize(input, '');
length = length || 255;
if (input.length <= length) {
return input;
}
if (killwords) {
input = input.substring(0, length);
} else {
var idx = input.lastIndexOf(' ', length);
if (idx === -1) {
idx = length;
}
input = input.substring(0, idx);
}
input += end !== undefined && end !== null ? end : '...';
return r.copySafeness(orig, input);
}
_exports.truncate = truncate;
function upper(str) {
str = normalize(str, '');
return str.toUpperCase();
}
_exports.upper = upper;
function urlencode(obj) {
var enc = encodeURIComponent;
if (lib.isString(obj)) {
return enc(obj);
} else {
var keyvals = lib.isArray(obj) ? obj : lib._entries(obj);
return keyvals.map(function (_ref2) {
var k = _ref2[0],
v = _ref2[1];
return enc(k) + "=" + enc(v);
}).join('&');
}
}
_exports.urlencode = urlencode; // For the jinja regexp, see
// https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23
var puncRe = /^(?:\(|<|&lt;)?(.*?)(?:\.|,|\)|\n|&gt;)?$/; // from http://blog.gerv.net/2011/05/html5_email_address_regexp/
var emailRe = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i;
var httpHttpsRe = /^https?:\/\/.*$/;
var wwwRe = /^www\./;
var tldRe = /\.(?:org|net|com)(?:\:|\/|$)/;
function urlize(str, length, nofollow) {
if (isNaN(length)) {
length = Infinity;
}
var noFollowAttr = nofollow === true ? ' rel="nofollow"' : '';
var words = str.split(/(\s+)/).filter(function (word) {
// If the word has no length, bail. This can happen for str with
// trailing whitespace.
return word && word.length;
}).map(function (word) {
var matches = word.match(puncRe);
var possibleUrl = matches ? matches[1] : word;
var shortUrl = possibleUrl.substr(0, length); // url that starts with http or https
if (httpHttpsRe.test(possibleUrl)) {
return "<a href=\"" + possibleUrl + "\"" + noFollowAttr + ">" + shortUrl + "</a>";
} // url that starts with www.
if (wwwRe.test(possibleUrl)) {
return "<a href=\"http://" + possibleUrl + "\"" + noFollowAttr + ">" + shortUrl + "</a>";
} // an email address of the form username@domain.tld
if (emailRe.test(possibleUrl)) {
return "<a href=\"mailto:" + possibleUrl + "\">" + possibleUrl + "</a>";
} // url that ends in .com, .org or .net that is not an email address
if (tldRe.test(possibleUrl)) {
return "<a href=\"http://" + possibleUrl + "\"" + noFollowAttr + ">" + shortUrl + "</a>";
}
return word;
});
return words.join('');
}
_exports.urlize = urlize;
function wordcount(str) {
str = normalize(str, '');
var words = str ? str.match(/\w+/g) : null;
return words ? words.length : null;
}
_exports.wordcount = wordcount;
function float(val, def) {
var res = parseFloat(val);
return isNaN(res) ? def : res;
}
_exports.float = float;
var intFilter = r.makeMacro(['value', 'default', 'base'], [], function doInt(value, defaultValue, base) {
if (base === void 0) {
base = 10;
}
var res = parseInt(value, base);
return isNaN(res) ? defaultValue : res;
});
_exports.int = intFilter; // Aliases
_exports.d = _exports.default;
_exports.e = _exports.escape;
+72
View File
@@ -0,0 +1,72 @@
'use strict';
function _cycler(items) {
var index = -1;
return {
current: null,
reset: function reset() {
index = -1;
this.current = null;
},
next: function next() {
index++;
if (index >= items.length) {
index = 0;
}
this.current = items[index];
return this.current;
}
};
}
function _joiner(sep) {
sep = sep || ',';
var first = true;
return function () {
var val = first ? '' : sep;
first = false;
return val;
};
} // Making this a function instead so it returns a new object
// each time it's called. That way, if something like an environment
// uses it, they will each have their own copy.
function globals() {
return {
range: function range(start, stop, step) {
if (typeof stop === 'undefined') {
stop = start;
start = 0;
step = 1;
} else if (!step) {
step = 1;
}
var arr = [];
if (step > 0) {
for (var i = start; i < stop; i += step) {
arr.push(i);
}
} else {
for (var _i = start; _i > stop; _i += step) {
// eslint-disable-line for-direction
arr.push(_i);
}
}
return arr;
},
cycler: function cycler() {
return _cycler(Array.prototype.slice.call(arguments));
},
joiner: function joiner(sep) {
return _joiner(sep);
}
};
}
module.exports = globals;
+358
View File
@@ -0,0 +1,358 @@
"use strict";
function installCompat() {
'use strict';
/* eslint-disable camelcase */
// This must be called like `nunjucks.installCompat` so that `this`
// references the nunjucks instance
var runtime = this.runtime;
var lib = this.lib; // Handle slim case where these 'modules' are excluded from the built source
var Compiler = this.compiler.Compiler;
var Parser = this.parser.Parser;
var nodes = this.nodes;
var lexer = this.lexer;
var orig_contextOrFrameLookup = runtime.contextOrFrameLookup;
var orig_memberLookup = runtime.memberLookup;
var orig_Compiler_assertType;
var orig_Parser_parseAggregate;
if (Compiler) {
orig_Compiler_assertType = Compiler.prototype.assertType;
}
if (Parser) {
orig_Parser_parseAggregate = Parser.prototype.parseAggregate;
}
function uninstall() {
runtime.contextOrFrameLookup = orig_contextOrFrameLookup;
runtime.memberLookup = orig_memberLookup;
if (Compiler) {
Compiler.prototype.assertType = orig_Compiler_assertType;
}
if (Parser) {
Parser.prototype.parseAggregate = orig_Parser_parseAggregate;
}
}
runtime.contextOrFrameLookup = function contextOrFrameLookup(context, frame, key) {
var val = orig_contextOrFrameLookup.apply(this, arguments);
if (val !== undefined) {
return val;
}
switch (key) {
case 'True':
return true;
case 'False':
return false;
case 'None':
return null;
default:
return undefined;
}
};
function getTokensState(tokens) {
return {
index: tokens.index,
lineno: tokens.lineno,
colno: tokens.colno
};
}
if (process.env.BUILD_TYPE !== 'SLIM' && nodes && Compiler && Parser) {
// i.e., not slim mode
var Slice = nodes.Node.extend('Slice', {
fields: ['start', 'stop', 'step'],
init: function init(lineno, colno, start, stop, step) {
start = start || new nodes.Literal(lineno, colno, null);
stop = stop || new nodes.Literal(lineno, colno, null);
step = step || new nodes.Literal(lineno, colno, 1);
this.parent(lineno, colno, start, stop, step);
}
});
Compiler.prototype.assertType = function assertType(node) {
if (node instanceof Slice) {
return;
}
orig_Compiler_assertType.apply(this, arguments);
};
Compiler.prototype.compileSlice = function compileSlice(node, frame) {
this._emit('(');
this._compileExpression(node.start, frame);
this._emit('),(');
this._compileExpression(node.stop, frame);
this._emit('),(');
this._compileExpression(node.step, frame);
this._emit(')');
};
Parser.prototype.parseAggregate = function parseAggregate() {
var _this = this;
var origState = getTokensState(this.tokens); // Set back one accounting for opening bracket/parens
origState.colno--;
origState.index--;
try {
return orig_Parser_parseAggregate.apply(this);
} catch (e) {
var errState = getTokensState(this.tokens);
var rethrow = function rethrow() {
lib._assign(_this.tokens, errState);
return e;
}; // Reset to state before original parseAggregate called
lib._assign(this.tokens, origState);
this.peeked = false;
var tok = this.peekToken();
if (tok.type !== lexer.TOKEN_LEFT_BRACKET) {
throw rethrow();
} else {
this.nextToken();
}
var node = new Slice(tok.lineno, tok.colno); // If we don't encounter a colon while parsing, this is not a slice,
// so re-raise the original exception.
var isSlice = false;
for (var i = 0; i <= node.fields.length; i++) {
if (this.skip(lexer.TOKEN_RIGHT_BRACKET)) {
break;
}
if (i === node.fields.length) {
if (isSlice) {
this.fail('parseSlice: too many slice components', tok.lineno, tok.colno);
} else {
break;
}
}
if (this.skip(lexer.TOKEN_COLON)) {
isSlice = true;
} else {
var field = node.fields[i];
node[field] = this.parseExpression();
isSlice = this.skip(lexer.TOKEN_COLON) || isSlice;
}
}
if (!isSlice) {
throw rethrow();
}
return new nodes.Array(tok.lineno, tok.colno, [node]);
}
};
}
function sliceLookup(obj, start, stop, step) {
obj = obj || [];
if (start === null) {
start = step < 0 ? obj.length - 1 : 0;
}
if (stop === null) {
stop = step < 0 ? -1 : obj.length;
} else if (stop < 0) {
stop += obj.length;
}
if (start < 0) {
start += obj.length;
}
var results = [];
for (var i = start;; i += step) {
if (i < 0 || i > obj.length) {
break;
}
if (step > 0 && i >= stop) {
break;
}
if (step < 0 && i <= stop) {
break;
}
results.push(runtime.memberLookup(obj, i));
}
return results;
}
function hasOwnProp(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
var ARRAY_MEMBERS = {
pop: function pop(index) {
if (index === undefined) {
return this.pop();
}
if (index >= this.length || index < 0) {
throw new Error('KeyError');
}
return this.splice(index, 1);
},
append: function append(element) {
return this.push(element);
},
remove: function remove(element) {
for (var i = 0; i < this.length; i++) {
if (this[i] === element) {
return this.splice(i, 1);
}
}
throw new Error('ValueError');
},
count: function count(element) {
var count = 0;
for (var i = 0; i < this.length; i++) {
if (this[i] === element) {
count++;
}
}
return count;
},
index: function index(element) {
var i;
if ((i = this.indexOf(element)) === -1) {
throw new Error('ValueError');
}
return i;
},
find: function find(element) {
return this.indexOf(element);
},
insert: function insert(index, elem) {
return this.splice(index, 0, elem);
}
};
var OBJECT_MEMBERS = {
items: function items() {
return lib._entries(this);
},
values: function values() {
return lib._values(this);
},
keys: function keys() {
return lib.keys(this);
},
get: function get(key, def) {
var output = this[key];
if (output === undefined) {
output = def;
}
return output;
},
has_key: function has_key(key) {
return hasOwnProp(this, key);
},
pop: function pop(key, def) {
var output = this[key];
if (output === undefined && def !== undefined) {
output = def;
} else if (output === undefined) {
throw new Error('KeyError');
} else {
delete this[key];
}
return output;
},
popitem: function popitem() {
var keys = lib.keys(this);
if (!keys.length) {
throw new Error('KeyError');
}
var k = keys[0];
var val = this[k];
delete this[k];
return [k, val];
},
setdefault: function setdefault(key, def) {
if (def === void 0) {
def = null;
}
if (!(key in this)) {
this[key] = def;
}
return this[key];
},
update: function update(kwargs) {
lib._assign(this, kwargs);
return null; // Always returns None
}
};
OBJECT_MEMBERS.iteritems = OBJECT_MEMBERS.items;
OBJECT_MEMBERS.itervalues = OBJECT_MEMBERS.values;
OBJECT_MEMBERS.iterkeys = OBJECT_MEMBERS.keys;
runtime.memberLookup = function memberLookup(obj, val, autoescape) {
if (arguments.length === 4) {
return sliceLookup.apply(this, arguments);
}
obj = obj || {}; // If the object is an object, return any of the methods that Python would
// otherwise provide.
if (lib.isArray(obj) && hasOwnProp(ARRAY_MEMBERS, val)) {
return ARRAY_MEMBERS[val].bind(obj);
}
if (lib.isObject(obj) && hasOwnProp(OBJECT_MEMBERS, val)) {
return OBJECT_MEMBERS[val].bind(obj);
}
return orig_memberLookup.apply(this, arguments);
};
return uninstall;
}
module.exports = installCompat;
+542
View File
@@ -0,0 +1,542 @@
'use strict';
var lib = require('./lib');
var whitespaceChars = " \n\t\r\xA0";
var delimChars = '()[]{}%*-+~/#,:|.<>=!';
var intChars = '0123456789';
var BLOCK_START = '{%';
var BLOCK_END = '%}';
var VARIABLE_START = '{{';
var VARIABLE_END = '}}';
var COMMENT_START = '{#';
var COMMENT_END = '#}';
var TOKEN_STRING = 'string';
var TOKEN_WHITESPACE = 'whitespace';
var TOKEN_DATA = 'data';
var TOKEN_BLOCK_START = 'block-start';
var TOKEN_BLOCK_END = 'block-end';
var TOKEN_VARIABLE_START = 'variable-start';
var TOKEN_VARIABLE_END = 'variable-end';
var TOKEN_COMMENT = 'comment';
var TOKEN_LEFT_PAREN = 'left-paren';
var TOKEN_RIGHT_PAREN = 'right-paren';
var TOKEN_LEFT_BRACKET = 'left-bracket';
var TOKEN_RIGHT_BRACKET = 'right-bracket';
var TOKEN_LEFT_CURLY = 'left-curly';
var TOKEN_RIGHT_CURLY = 'right-curly';
var TOKEN_OPERATOR = 'operator';
var TOKEN_COMMA = 'comma';
var TOKEN_COLON = 'colon';
var TOKEN_TILDE = 'tilde';
var TOKEN_PIPE = 'pipe';
var TOKEN_INT = 'int';
var TOKEN_FLOAT = 'float';
var TOKEN_BOOLEAN = 'boolean';
var TOKEN_NONE = 'none';
var TOKEN_SYMBOL = 'symbol';
var TOKEN_SPECIAL = 'special';
var TOKEN_REGEX = 'regex';
function token(type, value, lineno, colno) {
return {
type: type,
value: value,
lineno: lineno,
colno: colno
};
}
var Tokenizer = /*#__PURE__*/function () {
function Tokenizer(str, opts) {
this.str = str;
this.index = 0;
this.len = str.length;
this.lineno = 0;
this.colno = 0;
this.in_code = false;
opts = opts || {};
var tags = opts.tags || {};
this.tags = {
BLOCK_START: tags.blockStart || BLOCK_START,
BLOCK_END: tags.blockEnd || BLOCK_END,
VARIABLE_START: tags.variableStart || VARIABLE_START,
VARIABLE_END: tags.variableEnd || VARIABLE_END,
COMMENT_START: tags.commentStart || COMMENT_START,
COMMENT_END: tags.commentEnd || COMMENT_END
};
this.trimBlocks = !!opts.trimBlocks;
this.lstripBlocks = !!opts.lstripBlocks;
}
var _proto = Tokenizer.prototype;
_proto.nextToken = function nextToken() {
var lineno = this.lineno;
var colno = this.colno;
var tok;
if (this.in_code) {
// Otherwise, if we are in a block parse it as code
var cur = this.current();
if (this.isFinished()) {
// We have nothing else to parse
return null;
} else if (cur === '"' || cur === '\'') {
// We've hit a string
return token(TOKEN_STRING, this._parseString(cur), lineno, colno);
} else if (tok = this._extract(whitespaceChars)) {
// We hit some whitespace
return token(TOKEN_WHITESPACE, tok, lineno, colno);
} else if ((tok = this._extractString(this.tags.BLOCK_END)) || (tok = this._extractString('-' + this.tags.BLOCK_END))) {
// Special check for the block end tag
//
// It is a requirement that start and end tags are composed of
// delimiter characters (%{}[] etc), and our code always
// breaks on delimiters so we can assume the token parsing
// doesn't consume these elsewhere
this.in_code = false;
if (this.trimBlocks) {
cur = this.current();
if (cur === '\n') {
// Skip newline
this.forward();
} else if (cur === '\r') {
// Skip CRLF newline
this.forward();
cur = this.current();
if (cur === '\n') {
this.forward();
} else {
// Was not a CRLF, so go back
this.back();
}
}
}
return token(TOKEN_BLOCK_END, tok, lineno, colno);
} else if ((tok = this._extractString(this.tags.VARIABLE_END)) || (tok = this._extractString('-' + this.tags.VARIABLE_END))) {
// Special check for variable end tag (see above)
this.in_code = false;
return token(TOKEN_VARIABLE_END, tok, lineno, colno);
} else if (cur === 'r' && this.str.charAt(this.index + 1) === '/') {
// Skip past 'r/'.
this.forwardN(2); // Extract until the end of the regex -- / ends it, \/ does not.
var regexBody = '';
while (!this.isFinished()) {
if (this.current() === '/' && this.previous() !== '\\') {
this.forward();
break;
} else {
regexBody += this.current();
this.forward();
}
} // Check for flags.
// The possible flags are according to https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
var POSSIBLE_FLAGS = ['g', 'i', 'm', 'y'];
var regexFlags = '';
while (!this.isFinished()) {
var isCurrentAFlag = POSSIBLE_FLAGS.indexOf(this.current()) !== -1;
if (isCurrentAFlag) {
regexFlags += this.current();
this.forward();
} else {
break;
}
}
return token(TOKEN_REGEX, {
body: regexBody,
flags: regexFlags
}, lineno, colno);
} else if (delimChars.indexOf(cur) !== -1) {
// We've hit a delimiter (a special char like a bracket)
this.forward();
var complexOps = ['==', '===', '!=', '!==', '<=', '>=', '//', '**'];
var curComplex = cur + this.current();
var type;
if (lib.indexOf(complexOps, curComplex) !== -1) {
this.forward();
cur = curComplex; // See if this is a strict equality/inequality comparator
if (lib.indexOf(complexOps, curComplex + this.current()) !== -1) {
cur = curComplex + this.current();
this.forward();
}
}
switch (cur) {
case '(':
type = TOKEN_LEFT_PAREN;
break;
case ')':
type = TOKEN_RIGHT_PAREN;
break;
case '[':
type = TOKEN_LEFT_BRACKET;
break;
case ']':
type = TOKEN_RIGHT_BRACKET;
break;
case '{':
type = TOKEN_LEFT_CURLY;
break;
case '}':
type = TOKEN_RIGHT_CURLY;
break;
case ',':
type = TOKEN_COMMA;
break;
case ':':
type = TOKEN_COLON;
break;
case '~':
type = TOKEN_TILDE;
break;
case '|':
type = TOKEN_PIPE;
break;
default:
type = TOKEN_OPERATOR;
}
return token(type, cur, lineno, colno);
} else {
// We are not at whitespace or a delimiter, so extract the
// text and parse it
tok = this._extractUntil(whitespaceChars + delimChars);
if (tok.match(/^[-+]?[0-9]+$/)) {
if (this.current() === '.') {
this.forward();
var dec = this._extract(intChars);
return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno);
} else {
return token(TOKEN_INT, tok, lineno, colno);
}
} else if (tok.match(/^(true|false)$/)) {
return token(TOKEN_BOOLEAN, tok, lineno, colno);
} else if (tok === 'none') {
return token(TOKEN_NONE, tok, lineno, colno);
/*
* Added to make the test `null is null` evaluate truthily.
* Otherwise, Nunjucks will look up null in the context and
* return `undefined`, which is not what we want. This *may* have
* consequences is someone is using null in their templates as a
* variable.
*/
} else if (tok === 'null') {
return token(TOKEN_NONE, tok, lineno, colno);
} else if (tok) {
return token(TOKEN_SYMBOL, tok, lineno, colno);
} else {
throw new Error('Unexpected value while parsing: ' + tok);
}
}
} else {
// Parse out the template text, breaking on tag
// delimiters because we need to look for block/variable start
// tags (don't use the full delimChars for optimization)
var beginChars = this.tags.BLOCK_START.charAt(0) + this.tags.VARIABLE_START.charAt(0) + this.tags.COMMENT_START.charAt(0) + this.tags.COMMENT_END.charAt(0);
if (this.isFinished()) {
return null;
} else if ((tok = this._extractString(this.tags.BLOCK_START + '-')) || (tok = this._extractString(this.tags.BLOCK_START))) {
this.in_code = true;
return token(TOKEN_BLOCK_START, tok, lineno, colno);
} else if ((tok = this._extractString(this.tags.VARIABLE_START + '-')) || (tok = this._extractString(this.tags.VARIABLE_START))) {
this.in_code = true;
return token(TOKEN_VARIABLE_START, tok, lineno, colno);
} else {
tok = '';
var data;
var inComment = false;
if (this._matches(this.tags.COMMENT_START)) {
inComment = true;
tok = this._extractString(this.tags.COMMENT_START);
} // Continually consume text, breaking on the tag delimiter
// characters and checking to see if it's a start tag.
//
// We could hit the end of the template in the middle of
// our looping, so check for the null return value from
// _extractUntil
while ((data = this._extractUntil(beginChars)) !== null) {
tok += data;
if ((this._matches(this.tags.BLOCK_START) || this._matches(this.tags.VARIABLE_START) || this._matches(this.tags.COMMENT_START)) && !inComment) {
if (this.lstripBlocks && this._matches(this.tags.BLOCK_START) && this.colno > 0 && this.colno <= tok.length) {
var lastLine = tok.slice(-this.colno);
if (/^\s+$/.test(lastLine)) {
// Remove block leading whitespace from beginning of the string
tok = tok.slice(0, -this.colno);
if (!tok.length) {
// All data removed, collapse to avoid unnecessary nodes
// by returning next token (block start)
return this.nextToken();
}
}
} // If it is a start tag, stop looping
break;
} else if (this._matches(this.tags.COMMENT_END)) {
if (!inComment) {
throw new Error('unexpected end of comment');
}
tok += this._extractString(this.tags.COMMENT_END);
break;
} else {
// It does not match any tag, so add the character and
// carry on
tok += this.current();
this.forward();
}
}
if (data === null && inComment) {
throw new Error('expected end of comment, got end of file');
}
return token(inComment ? TOKEN_COMMENT : TOKEN_DATA, tok, lineno, colno);
}
}
};
_proto._parseString = function _parseString(delimiter) {
this.forward();
var str = '';
while (!this.isFinished() && this.current() !== delimiter) {
var cur = this.current();
if (cur === '\\') {
this.forward();
switch (this.current()) {
case 'n':
str += '\n';
break;
case 't':
str += '\t';
break;
case 'r':
str += '\r';
break;
default:
str += this.current();
}
this.forward();
} else {
str += cur;
this.forward();
}
}
this.forward();
return str;
};
_proto._matches = function _matches(str) {
if (this.index + str.length > this.len) {
return null;
}
var m = this.str.slice(this.index, this.index + str.length);
return m === str;
};
_proto._extractString = function _extractString(str) {
if (this._matches(str)) {
this.forwardN(str.length);
return str;
}
return null;
};
_proto._extractUntil = function _extractUntil(charString) {
// Extract all non-matching chars, with the default matching set
// to everything
return this._extractMatching(true, charString || '');
};
_proto._extract = function _extract(charString) {
// Extract all matching chars (no default, so charString must be
// explicit)
return this._extractMatching(false, charString);
};
_proto._extractMatching = function _extractMatching(breakOnMatch, charString) {
// Pull out characters until a breaking char is hit.
// If breakOnMatch is false, a non-matching char stops it.
// If breakOnMatch is true, a matching char stops it.
if (this.isFinished()) {
return null;
}
var first = charString.indexOf(this.current()); // Only proceed if the first character doesn't meet our condition
if (breakOnMatch && first === -1 || !breakOnMatch && first !== -1) {
var t = this.current();
this.forward(); // And pull out all the chars one at a time until we hit a
// breaking char
var idx = charString.indexOf(this.current());
while ((breakOnMatch && idx === -1 || !breakOnMatch && idx !== -1) && !this.isFinished()) {
t += this.current();
this.forward();
idx = charString.indexOf(this.current());
}
return t;
}
return '';
};
_proto._extractRegex = function _extractRegex(regex) {
var matches = this.currentStr().match(regex);
if (!matches) {
return null;
} // Move forward whatever was matched
this.forwardN(matches[0].length);
return matches;
};
_proto.isFinished = function isFinished() {
return this.index >= this.len;
};
_proto.forwardN = function forwardN(n) {
for (var i = 0; i < n; i++) {
this.forward();
}
};
_proto.forward = function forward() {
this.index++;
if (this.previous() === '\n') {
this.lineno++;
this.colno = 0;
} else {
this.colno++;
}
};
_proto.backN = function backN(n) {
for (var i = 0; i < n; i++) {
this.back();
}
};
_proto.back = function back() {
this.index--;
if (this.current() === '\n') {
this.lineno--;
var idx = this.src.lastIndexOf('\n', this.index - 1);
if (idx === -1) {
this.colno = this.index;
} else {
this.colno = this.index - idx;
}
} else {
this.colno--;
}
} // current returns current character
;
_proto.current = function current() {
if (!this.isFinished()) {
return this.str.charAt(this.index);
}
return '';
} // currentStr returns what's left of the unparsed string
;
_proto.currentStr = function currentStr() {
if (!this.isFinished()) {
return this.str.substr(this.index);
}
return '';
};
_proto.previous = function previous() {
return this.str.charAt(this.index - 1);
};
return Tokenizer;
}();
module.exports = {
lex: function lex(src, opts) {
return new Tokenizer(src, opts);
},
TOKEN_STRING: TOKEN_STRING,
TOKEN_WHITESPACE: TOKEN_WHITESPACE,
TOKEN_DATA: TOKEN_DATA,
TOKEN_BLOCK_START: TOKEN_BLOCK_START,
TOKEN_BLOCK_END: TOKEN_BLOCK_END,
TOKEN_VARIABLE_START: TOKEN_VARIABLE_START,
TOKEN_VARIABLE_END: TOKEN_VARIABLE_END,
TOKEN_COMMENT: TOKEN_COMMENT,
TOKEN_LEFT_PAREN: TOKEN_LEFT_PAREN,
TOKEN_RIGHT_PAREN: TOKEN_RIGHT_PAREN,
TOKEN_LEFT_BRACKET: TOKEN_LEFT_BRACKET,
TOKEN_RIGHT_BRACKET: TOKEN_RIGHT_BRACKET,
TOKEN_LEFT_CURLY: TOKEN_LEFT_CURLY,
TOKEN_RIGHT_CURLY: TOKEN_RIGHT_CURLY,
TOKEN_OPERATOR: TOKEN_OPERATOR,
TOKEN_COMMA: TOKEN_COMMA,
TOKEN_COLON: TOKEN_COLON,
TOKEN_TILDE: TOKEN_TILDE,
TOKEN_PIPE: TOKEN_PIPE,
TOKEN_INT: TOKEN_INT,
TOKEN_FLOAT: TOKEN_FLOAT,
TOKEN_BOOLEAN: TOKEN_BOOLEAN,
TOKEN_NONE: TOKEN_NONE,
TOKEN_SYMBOL: TOKEN_SYMBOL,
TOKEN_SPECIAL: TOKEN_SPECIAL,
TOKEN_REGEX: TOKEN_REGEX
};
+417
View File
@@ -0,0 +1,417 @@
'use strict';
var ArrayProto = Array.prototype;
var ObjProto = Object.prototype;
var escapeMap = {
'&': '&amp;',
'"': '&quot;',
'\'': '&#39;',
'<': '&lt;',
'>': '&gt;'
};
var escapeRegex = /[&"'<>]/g;
var _exports = module.exports = {};
function hasOwnProp(obj, k) {
return ObjProto.hasOwnProperty.call(obj, k);
}
_exports.hasOwnProp = hasOwnProp;
function lookupEscape(ch) {
return escapeMap[ch];
}
function _prettifyError(path, withInternals, err) {
if (!err.Update) {
// not one of ours, cast it
err = new _exports.TemplateError(err);
}
err.Update(path); // Unless they marked the dev flag, show them a trace from here
if (!withInternals) {
var old = err;
err = new Error(old.message);
err.name = old.name;
}
return err;
}
_exports._prettifyError = _prettifyError;
function TemplateError(message, lineno, colno) {
var err;
var cause;
if (message instanceof Error) {
cause = message;
message = cause.name + ": " + cause.message;
}
if (Object.setPrototypeOf) {
err = new Error(message);
Object.setPrototypeOf(err, TemplateError.prototype);
} else {
err = this;
Object.defineProperty(err, 'message', {
enumerable: false,
writable: true,
value: message
});
}
Object.defineProperty(err, 'name', {
value: 'Template render error'
});
if (Error.captureStackTrace) {
Error.captureStackTrace(err, this.constructor);
}
var getStack;
if (cause) {
var stackDescriptor = Object.getOwnPropertyDescriptor(cause, 'stack');
getStack = stackDescriptor && (stackDescriptor.get || function () {
return stackDescriptor.value;
});
if (!getStack) {
getStack = function getStack() {
return cause.stack;
};
}
} else {
var stack = new Error(message).stack;
getStack = function getStack() {
return stack;
};
}
Object.defineProperty(err, 'stack', {
get: function get() {
return getStack.call(err);
}
});
Object.defineProperty(err, 'cause', {
value: cause
});
err.lineno = lineno;
err.colno = colno;
err.firstUpdate = true;
err.Update = function Update(path) {
var msg = '(' + (path || 'unknown path') + ')'; // only show lineno + colno next to path of template
// where error occurred
if (this.firstUpdate) {
if (this.lineno && this.colno) {
msg += " [Line " + this.lineno + ", Column " + this.colno + "]";
} else if (this.lineno) {
msg += " [Line " + this.lineno + "]";
}
}
msg += '\n ';
if (this.firstUpdate) {
msg += ' ';
}
this.message = msg + (this.message || '');
this.firstUpdate = false;
return this;
};
return err;
}
if (Object.setPrototypeOf) {
Object.setPrototypeOf(TemplateError.prototype, Error.prototype);
} else {
TemplateError.prototype = Object.create(Error.prototype, {
constructor: {
value: TemplateError
}
});
}
_exports.TemplateError = TemplateError;
function escape(val) {
return val.replace(escapeRegex, lookupEscape);
}
_exports.escape = escape;
function isFunction(obj) {
return ObjProto.toString.call(obj) === '[object Function]';
}
_exports.isFunction = isFunction;
function isArray(obj) {
return ObjProto.toString.call(obj) === '[object Array]';
}
_exports.isArray = isArray;
function isString(obj) {
return ObjProto.toString.call(obj) === '[object String]';
}
_exports.isString = isString;
function isObject(obj) {
return ObjProto.toString.call(obj) === '[object Object]';
}
_exports.isObject = isObject;
/**
* @param {string|number} attr
* @returns {(string|number)[]}
* @private
*/
function _prepareAttributeParts(attr) {
if (!attr) {
return [];
}
if (typeof attr === 'string') {
return attr.split('.');
}
return [attr];
}
/**
* @param {string} attribute Attribute value. Dots allowed.
* @returns {function(Object): *}
*/
function getAttrGetter(attribute) {
var parts = _prepareAttributeParts(attribute);
return function attrGetter(item) {
var _item = item;
for (var i = 0; i < parts.length; i++) {
var part = parts[i]; // If item is not an object, and we still got parts to handle, it means
// that something goes wrong. Just roll out to undefined in that case.
if (hasOwnProp(_item, part)) {
_item = _item[part];
} else {
return undefined;
}
}
return _item;
};
}
_exports.getAttrGetter = getAttrGetter;
function groupBy(obj, val, throwOnUndefined) {
var result = {};
var iterator = isFunction(val) ? val : getAttrGetter(val);
for (var i = 0; i < obj.length; i++) {
var value = obj[i];
var key = iterator(value, i);
if (key === undefined && throwOnUndefined === true) {
throw new TypeError("groupby: attribute \"" + val + "\" resolved to undefined");
}
(result[key] || (result[key] = [])).push(value);
}
return result;
}
_exports.groupBy = groupBy;
function toArray(obj) {
return Array.prototype.slice.call(obj);
}
_exports.toArray = toArray;
function without(array) {
var result = [];
if (!array) {
return result;
}
var length = array.length;
var contains = toArray(arguments).slice(1);
var index = -1;
while (++index < length) {
if (indexOf(contains, array[index]) === -1) {
result.push(array[index]);
}
}
return result;
}
_exports.without = without;
function repeat(char_, n) {
var str = '';
for (var i = 0; i < n; i++) {
str += char_;
}
return str;
}
_exports.repeat = repeat;
function each(obj, func, context) {
if (obj == null) {
return;
}
if (ArrayProto.forEach && obj.forEach === ArrayProto.forEach) {
obj.forEach(func, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
func.call(context, obj[i], i, obj);
}
}
}
_exports.each = each;
function map(obj, func) {
var results = [];
if (obj == null) {
return results;
}
if (ArrayProto.map && obj.map === ArrayProto.map) {
return obj.map(func);
}
for (var i = 0; i < obj.length; i++) {
results[results.length] = func(obj[i], i);
}
if (obj.length === +obj.length) {
results.length = obj.length;
}
return results;
}
_exports.map = map;
function asyncIter(arr, iter, cb) {
var i = -1;
function next() {
i++;
if (i < arr.length) {
iter(arr[i], i, next, cb);
} else {
cb();
}
}
next();
}
_exports.asyncIter = asyncIter;
function asyncFor(obj, iter, cb) {
var keys = keys_(obj || {});
var len = keys.length;
var i = -1;
function next() {
i++;
var k = keys[i];
if (i < len) {
iter(k, obj[k], i, len, next);
} else {
cb();
}
}
next();
}
_exports.asyncFor = asyncFor;
function indexOf(arr, searchElement, fromIndex) {
return Array.prototype.indexOf.call(arr || [], searchElement, fromIndex);
}
_exports.indexOf = indexOf;
function keys_(obj) {
/* eslint-disable no-restricted-syntax */
var arr = [];
for (var k in obj) {
if (hasOwnProp(obj, k)) {
arr.push(k);
}
}
return arr;
}
_exports.keys = keys_;
function _entries(obj) {
return keys_(obj).map(function (k) {
return [k, obj[k]];
});
}
_exports._entries = _entries;
function _values(obj) {
return keys_(obj).map(function (k) {
return obj[k];
});
}
_exports._values = _values;
function extend(obj1, obj2) {
obj1 = obj1 || {};
keys_(obj2).forEach(function (k) {
obj1[k] = obj2[k];
});
return obj1;
}
_exports._assign = _exports.extend = extend;
function inOperator(key, val) {
if (isArray(val) || isString(val)) {
return val.indexOf(key) !== -1;
} else if (isObject(val)) {
return key in val;
}
throw new Error('Cannot use "in" operator to search for "' + key + '" in unexpected types.');
}
_exports.inOperator = inOperator;
+30
View File
@@ -0,0 +1,30 @@
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var path = require('path');
var _require = require('./object'),
EmitterObj = _require.EmitterObj;
module.exports = /*#__PURE__*/function (_EmitterObj) {
_inheritsLoose(Loader, _EmitterObj);
function Loader() {
return _EmitterObj.apply(this, arguments) || this;
}
var _proto = Loader.prototype;
_proto.resolve = function resolve(from, to) {
return path.resolve(path.dirname(from), to);
};
_proto.isRelative = function isRelative(filename) {
return filename.indexOf('./') === 0 || filename.indexOf('../') === 0;
};
return Loader;
}(EmitterObj);
+5
View File
@@ -0,0 +1,5 @@
"use strict";
// This file will automatically be rewired to web-loader.js when
// building for the browser
module.exports = require('./node-loaders');
+177
View File
@@ -0,0 +1,177 @@
/* eslint-disable no-console */
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var fs = require('fs');
var path = require('path');
var Loader = require('./loader');
var _require = require('./precompiled-loader.js'),
PrecompiledLoader = _require.PrecompiledLoader;
var chokidar;
var FileSystemLoader = /*#__PURE__*/function (_Loader) {
_inheritsLoose(FileSystemLoader, _Loader);
function FileSystemLoader(searchPaths, opts) {
var _this;
_this = _Loader.call(this) || this;
if (typeof opts === 'boolean') {
console.log('[nunjucks] Warning: you passed a boolean as the second ' + 'argument to FileSystemLoader, but it now takes an options ' + 'object. See http://mozilla.github.io/nunjucks/api.html#filesystemloader');
}
opts = opts || {};
_this.pathsToNames = {};
_this.noCache = !!opts.noCache;
if (searchPaths) {
searchPaths = Array.isArray(searchPaths) ? searchPaths : [searchPaths]; // For windows, convert to forward slashes
_this.searchPaths = searchPaths.map(path.normalize);
} else {
_this.searchPaths = ['.'];
}
if (opts.watch) {
// Watch all the templates in the paths and fire an event when
// they change
try {
chokidar = require('chokidar'); // eslint-disable-line global-require
} catch (e) {
throw new Error('watch requires chokidar to be installed');
}
var paths = _this.searchPaths.filter(fs.existsSync);
var watcher = chokidar.watch(paths);
watcher.on('all', function (event, fullname) {
fullname = path.resolve(fullname);
if (event === 'change' && fullname in _this.pathsToNames) {
_this.emit('update', _this.pathsToNames[fullname], fullname);
}
});
watcher.on('error', function (error) {
console.log('Watcher error: ' + error);
});
}
return _this;
}
var _proto = FileSystemLoader.prototype;
_proto.getSource = function getSource(name) {
var fullpath = null;
var paths = this.searchPaths;
for (var i = 0; i < paths.length; i++) {
var basePath = path.resolve(paths[i]);
var p = path.resolve(paths[i], name); // Only allow the current directory and anything
// underneath it to be searched
if (p.indexOf(basePath) === 0 && fs.existsSync(p)) {
fullpath = p;
break;
}
}
if (!fullpath) {
return null;
}
this.pathsToNames[fullpath] = name;
var source = {
src: fs.readFileSync(fullpath, 'utf-8'),
path: fullpath,
noCache: this.noCache
};
this.emit('load', name, source);
return source;
};
return FileSystemLoader;
}(Loader);
var NodeResolveLoader = /*#__PURE__*/function (_Loader2) {
_inheritsLoose(NodeResolveLoader, _Loader2);
function NodeResolveLoader(opts) {
var _this2;
_this2 = _Loader2.call(this) || this;
opts = opts || {};
_this2.pathsToNames = {};
_this2.noCache = !!opts.noCache;
if (opts.watch) {
try {
chokidar = require('chokidar'); // eslint-disable-line global-require
} catch (e) {
throw new Error('watch requires chokidar to be installed');
}
_this2.watcher = chokidar.watch();
_this2.watcher.on('change', function (fullname) {
_this2.emit('update', _this2.pathsToNames[fullname], fullname);
});
_this2.watcher.on('error', function (error) {
console.log('Watcher error: ' + error);
});
_this2.on('load', function (name, source) {
_this2.watcher.add(source.path);
});
}
return _this2;
}
var _proto2 = NodeResolveLoader.prototype;
_proto2.getSource = function getSource(name) {
// Don't allow file-system traversal
if (/^\.?\.?(\/|\\)/.test(name)) {
return null;
}
if (/^[A-Z]:/.test(name)) {
return null;
}
var fullpath;
try {
fullpath = require.resolve(name);
} catch (e) {
return null;
}
this.pathsToNames[fullpath] = name;
var source = {
src: fs.readFileSync(fullpath, 'utf-8'),
path: fullpath,
noCache: this.noCache
};
this.emit('load', name, source);
return source;
};
return NodeResolveLoader;
}(Loader);
module.exports = {
FileSystemLoader: FileSystemLoader,
PrecompiledLoader: PrecompiledLoader,
NodeResolveLoader: NodeResolveLoader
};
+394
View File
@@ -0,0 +1,394 @@
'use strict';
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var _require = require('./object'),
Obj = _require.Obj;
function traverseAndCheck(obj, type, results) {
if (obj instanceof type) {
results.push(obj);
}
if (obj instanceof Node) {
obj.findAll(type, results);
}
}
var Node = /*#__PURE__*/function (_Obj) {
_inheritsLoose(Node, _Obj);
function Node() {
return _Obj.apply(this, arguments) || this;
}
var _proto = Node.prototype;
_proto.init = function init(lineno, colno) {
var _arguments = arguments,
_this = this;
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
args[_key - 2] = arguments[_key];
}
this.lineno = lineno;
this.colno = colno;
this.fields.forEach(function (field, i) {
// The first two args are line/col numbers, so offset by 2
var val = _arguments[i + 2]; // Fields should never be undefined, but null. It makes
// testing easier to normalize values.
if (val === undefined) {
val = null;
}
_this[field] = val;
});
};
_proto.findAll = function findAll(type, results) {
var _this2 = this;
results = results || [];
if (this instanceof NodeList) {
this.children.forEach(function (child) {
return traverseAndCheck(child, type, results);
});
} else {
this.fields.forEach(function (field) {
return traverseAndCheck(_this2[field], type, results);
});
}
return results;
};
_proto.iterFields = function iterFields(func) {
var _this3 = this;
this.fields.forEach(function (field) {
func(_this3[field], field);
});
};
return Node;
}(Obj); // Abstract nodes
var Value = /*#__PURE__*/function (_Node) {
_inheritsLoose(Value, _Node);
function Value() {
return _Node.apply(this, arguments) || this;
}
_createClass(Value, [{
key: "typename",
get: function get() {
return 'Value';
}
}, {
key: "fields",
get: function get() {
return ['value'];
}
}]);
return Value;
}(Node); // Concrete nodes
var NodeList = /*#__PURE__*/function (_Node2) {
_inheritsLoose(NodeList, _Node2);
function NodeList() {
return _Node2.apply(this, arguments) || this;
}
var _proto2 = NodeList.prototype;
_proto2.init = function init(lineno, colno, nodes) {
_Node2.prototype.init.call(this, lineno, colno, nodes || []);
};
_proto2.addChild = function addChild(node) {
this.children.push(node);
};
_createClass(NodeList, [{
key: "typename",
get: function get() {
return 'NodeList';
}
}, {
key: "fields",
get: function get() {
return ['children'];
}
}]);
return NodeList;
}(Node);
var Root = NodeList.extend('Root');
var Literal = Value.extend('Literal');
var Symbol = Value.extend('Symbol');
var Group = NodeList.extend('Group');
var ArrayNode = NodeList.extend('Array');
var Pair = Node.extend('Pair', {
fields: ['key', 'value']
});
var Dict = NodeList.extend('Dict');
var LookupVal = Node.extend('LookupVal', {
fields: ['target', 'val']
});
var If = Node.extend('If', {
fields: ['cond', 'body', 'else_']
});
var IfAsync = If.extend('IfAsync');
var InlineIf = Node.extend('InlineIf', {
fields: ['cond', 'body', 'else_']
});
var For = Node.extend('For', {
fields: ['arr', 'name', 'body', 'else_']
});
var AsyncEach = For.extend('AsyncEach');
var AsyncAll = For.extend('AsyncAll');
var Macro = Node.extend('Macro', {
fields: ['name', 'args', 'body']
});
var Caller = Macro.extend('Caller');
var Import = Node.extend('Import', {
fields: ['template', 'target', 'withContext']
});
var FromImport = /*#__PURE__*/function (_Node3) {
_inheritsLoose(FromImport, _Node3);
function FromImport() {
return _Node3.apply(this, arguments) || this;
}
var _proto3 = FromImport.prototype;
_proto3.init = function init(lineno, colno, template, names, withContext) {
_Node3.prototype.init.call(this, lineno, colno, template, names || new NodeList(), withContext);
};
_createClass(FromImport, [{
key: "typename",
get: function get() {
return 'FromImport';
}
}, {
key: "fields",
get: function get() {
return ['template', 'names', 'withContext'];
}
}]);
return FromImport;
}(Node);
var FunCall = Node.extend('FunCall', {
fields: ['name', 'args']
});
var Filter = FunCall.extend('Filter');
var FilterAsync = Filter.extend('FilterAsync', {
fields: ['name', 'args', 'symbol']
});
var KeywordArgs = Dict.extend('KeywordArgs');
var Block = Node.extend('Block', {
fields: ['name', 'body']
});
var Super = Node.extend('Super', {
fields: ['blockName', 'symbol']
});
var TemplateRef = Node.extend('TemplateRef', {
fields: ['template']
});
var Extends = TemplateRef.extend('Extends');
var Include = Node.extend('Include', {
fields: ['template', 'ignoreMissing']
});
var Set = Node.extend('Set', {
fields: ['targets', 'value']
});
var Switch = Node.extend('Switch', {
fields: ['expr', 'cases', 'default']
});
var Case = Node.extend('Case', {
fields: ['cond', 'body']
});
var Output = NodeList.extend('Output');
var Capture = Node.extend('Capture', {
fields: ['body']
});
var TemplateData = Literal.extend('TemplateData');
var UnaryOp = Node.extend('UnaryOp', {
fields: ['target']
});
var BinOp = Node.extend('BinOp', {
fields: ['left', 'right']
});
var In = BinOp.extend('In');
var Is = BinOp.extend('Is');
var Or = BinOp.extend('Or');
var And = BinOp.extend('And');
var Not = UnaryOp.extend('Not');
var Add = BinOp.extend('Add');
var Concat = BinOp.extend('Concat');
var Sub = BinOp.extend('Sub');
var Mul = BinOp.extend('Mul');
var Div = BinOp.extend('Div');
var FloorDiv = BinOp.extend('FloorDiv');
var Mod = BinOp.extend('Mod');
var Pow = BinOp.extend('Pow');
var Neg = UnaryOp.extend('Neg');
var Pos = UnaryOp.extend('Pos');
var Compare = Node.extend('Compare', {
fields: ['expr', 'ops']
});
var CompareOperand = Node.extend('CompareOperand', {
fields: ['expr', 'type']
});
var CallExtension = Node.extend('CallExtension', {
init: function init(ext, prop, args, contentArgs) {
this.parent();
this.extName = ext.__name || ext;
this.prop = prop;
this.args = args || new NodeList();
this.contentArgs = contentArgs || [];
this.autoescape = ext.autoescape;
},
fields: ['extName', 'prop', 'args', 'contentArgs']
});
var CallExtensionAsync = CallExtension.extend('CallExtensionAsync'); // This is hacky, but this is just a debugging function anyway
function print(str, indent, inline) {
var lines = str.split('\n');
lines.forEach(function (line, i) {
if (line && (inline && i > 0 || !inline)) {
process.stdout.write(' '.repeat(indent));
}
var nl = i === lines.length - 1 ? '' : '\n';
process.stdout.write("" + line + nl);
});
} // Print the AST in a nicely formatted tree format for debuggin
function printNodes(node, indent) {
indent = indent || 0;
print(node.typename + ': ', indent);
if (node instanceof NodeList) {
print('\n');
node.children.forEach(function (n) {
printNodes(n, indent + 2);
});
} else if (node instanceof CallExtension) {
print(node.extName + "." + node.prop + "\n");
if (node.args) {
printNodes(node.args, indent + 2);
}
if (node.contentArgs) {
node.contentArgs.forEach(function (n) {
printNodes(n, indent + 2);
});
}
} else {
var nodes = [];
var props = null;
node.iterFields(function (val, fieldName) {
if (val instanceof Node) {
nodes.push([fieldName, val]);
} else {
props = props || {};
props[fieldName] = val;
}
});
if (props) {
print(JSON.stringify(props, null, 2) + '\n', null, true);
} else {
print('\n');
}
nodes.forEach(function (_ref) {
var fieldName = _ref[0],
n = _ref[1];
print("[" + fieldName + "] =>", indent + 2);
printNodes(n, indent + 4);
});
}
}
module.exports = {
Node: Node,
Root: Root,
NodeList: NodeList,
Value: Value,
Literal: Literal,
Symbol: Symbol,
Group: Group,
Array: ArrayNode,
Pair: Pair,
Dict: Dict,
Output: Output,
Capture: Capture,
TemplateData: TemplateData,
If: If,
IfAsync: IfAsync,
InlineIf: InlineIf,
For: For,
AsyncEach: AsyncEach,
AsyncAll: AsyncAll,
Macro: Macro,
Caller: Caller,
Import: Import,
FromImport: FromImport,
FunCall: FunCall,
Filter: Filter,
FilterAsync: FilterAsync,
KeywordArgs: KeywordArgs,
Block: Block,
Super: Super,
Extends: Extends,
Include: Include,
Set: Set,
Switch: Switch,
Case: Case,
LookupVal: LookupVal,
BinOp: BinOp,
In: In,
Is: Is,
Or: Or,
And: And,
Not: Not,
Add: Add,
Concat: Concat,
Sub: Sub,
Mul: Mul,
Div: Div,
FloorDiv: FloorDiv,
Mod: Mod,
Pow: Pow,
Neg: Neg,
Pos: Pos,
Compare: Compare,
CompareOperand: CompareOperand,
CallExtension: CallExtension,
CallExtensionAsync: CallExtensionAsync,
printNodes: printNodes
};
+129
View File
@@ -0,0 +1,129 @@
'use strict'; // A simple class system, more documentation to come
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var EventEmitter = require('events');
var lib = require('./lib');
function parentWrap(parent, prop) {
if (typeof parent !== 'function' || typeof prop !== 'function') {
return prop;
}
return function wrap() {
// Save the current parent method
var tmp = this.parent; // Set parent to the previous method, call, and restore
this.parent = parent;
var res = prop.apply(this, arguments);
this.parent = tmp;
return res;
};
}
function extendClass(cls, name, props) {
props = props || {};
lib.keys(props).forEach(function (k) {
props[k] = parentWrap(cls.prototype[k], props[k]);
});
var subclass = /*#__PURE__*/function (_cls) {
_inheritsLoose(subclass, _cls);
function subclass() {
return _cls.apply(this, arguments) || this;
}
_createClass(subclass, [{
key: "typename",
get: function get() {
return name;
}
}]);
return subclass;
}(cls);
lib._assign(subclass.prototype, props);
return subclass;
}
var Obj = /*#__PURE__*/function () {
function Obj() {
// Unfortunately necessary for backwards compatibility
this.init.apply(this, arguments);
}
var _proto = Obj.prototype;
_proto.init = function init() {};
Obj.extend = function extend(name, props) {
if (typeof name === 'object') {
props = name;
name = 'anonymous';
}
return extendClass(this, name, props);
};
_createClass(Obj, [{
key: "typename",
get: function get() {
return this.constructor.name;
}
}]);
return Obj;
}();
var EmitterObj = /*#__PURE__*/function (_EventEmitter) {
_inheritsLoose(EmitterObj, _EventEmitter);
function EmitterObj() {
var _this2;
var _this;
_this = _EventEmitter.call(this) || this; // Unfortunately necessary for backwards compatibility
(_this2 = _this).init.apply(_this2, arguments);
return _this;
}
var _proto2 = EmitterObj.prototype;
_proto2.init = function init() {};
EmitterObj.extend = function extend(name, props) {
if (typeof name === 'object') {
props = name;
name = 'anonymous';
}
return extendClass(this, name, props);
};
_createClass(EmitterObj, [{
key: "typename",
get: function get() {
return this.constructor.name;
}
}]);
return EmitterObj;
}(EventEmitter);
module.exports = {
Obj: Obj,
EmitterObj: EmitterObj
};
+1267
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
'use strict';
function precompileGlobal(templates, opts) {
var out = '';
opts = opts || {};
for (var i = 0; i < templates.length; i++) {
var name = JSON.stringify(templates[i].name);
var template = templates[i].template;
out += '(function() {' + '(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})' + '[' + name + '] = (function() {\n' + template + '\n})();\n';
if (opts.asFunction) {
out += 'return function(ctx, cb) { return nunjucks.render(' + name + ', ctx, cb); }\n';
}
out += '})();\n';
}
return out;
}
module.exports = precompileGlobal;
+131
View File
@@ -0,0 +1,131 @@
'use strict';
var fs = require('fs');
var path = require('path');
var _require = require('./lib'),
_prettifyError = _require._prettifyError;
var compiler = require('./compiler');
var _require2 = require('./environment'),
Environment = _require2.Environment;
var precompileGlobal = require('./precompile-global');
function match(filename, patterns) {
if (!Array.isArray(patterns)) {
return false;
}
return patterns.some(function (pattern) {
return filename.match(pattern);
});
}
function precompileString(str, opts) {
opts = opts || {};
opts.isString = true;
var env = opts.env || new Environment([]);
var wrapper = opts.wrapper || precompileGlobal;
if (!opts.name) {
throw new Error('the "name" option is required when compiling a string');
}
return wrapper([_precompile(str, opts.name, env)], opts);
}
function precompile(input, opts) {
// The following options are available:
//
// * name: name of the template (auto-generated when compiling a directory)
// * isString: input is a string, not a file path
// * asFunction: generate a callable function
// * force: keep compiling on error
// * env: the Environment to use (gets extensions and async filters from it)
// * include: which file/folders to include (folders are auto-included, files are auto-excluded)
// * exclude: which file/folders to exclude (folders are auto-included, files are auto-excluded)
// * wrapper: function(templates, opts) {...}
// Customize the output format to store the compiled template.
// By default, templates are stored in a global variable used by the runtime.
// A custom loader will be necessary to load your custom wrapper.
opts = opts || {};
var env = opts.env || new Environment([]);
var wrapper = opts.wrapper || precompileGlobal;
if (opts.isString) {
return precompileString(input, opts);
}
var pathStats = fs.existsSync(input) && fs.statSync(input);
var precompiled = [];
var templates = [];
function addTemplates(dir) {
fs.readdirSync(dir).forEach(function (file) {
var filepath = path.join(dir, file);
var subpath = filepath.substr(path.join(input, '/').length);
var stat = fs.statSync(filepath);
if (stat && stat.isDirectory()) {
subpath += '/';
if (!match(subpath, opts.exclude)) {
addTemplates(filepath);
}
} else if (match(subpath, opts.include)) {
templates.push(filepath);
}
});
}
if (pathStats.isFile()) {
precompiled.push(_precompile(fs.readFileSync(input, 'utf-8'), opts.name || input, env));
} else if (pathStats.isDirectory()) {
addTemplates(input);
for (var i = 0; i < templates.length; i++) {
var name = templates[i].replace(path.join(input, '/'), '');
try {
precompiled.push(_precompile(fs.readFileSync(templates[i], 'utf-8'), name, env));
} catch (e) {
if (opts.force) {
// Don't stop generating the output if we're
// forcing compilation.
console.error(e); // eslint-disable-line no-console
} else {
throw e;
}
}
}
}
return wrapper(precompiled, opts);
}
function _precompile(str, name, env) {
env = env || new Environment([]);
var asyncFilters = env.asyncFilters;
var extensions = env.extensionsList;
var template;
name = name.replace(/\\/g, '/');
try {
template = compiler.compile(str, asyncFilters, extensions, name, env.opts);
} catch (err) {
throw _prettifyError(name, false, err);
}
return {
name: name,
template: template
};
}
module.exports = {
precompile: precompile,
precompileString: precompileString
};
+41
View File
@@ -0,0 +1,41 @@
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var Loader = require('./loader');
var PrecompiledLoader = /*#__PURE__*/function (_Loader) {
_inheritsLoose(PrecompiledLoader, _Loader);
function PrecompiledLoader(compiledTemplates) {
var _this;
_this = _Loader.call(this) || this;
_this.precompiled = compiledTemplates || {};
return _this;
}
var _proto = PrecompiledLoader.prototype;
_proto.getSource = function getSource(name) {
if (this.precompiled[name]) {
return {
src: {
type: 'code',
obj: this.precompiled[name]
},
path: name
};
}
return null;
};
return PrecompiledLoader;
}(Loader);
module.exports = {
PrecompiledLoader: PrecompiledLoader
};
+405
View File
@@ -0,0 +1,405 @@
'use strict';
var lib = require('./lib');
var arrayFrom = Array.from;
var supportsIterators = typeof Symbol === 'function' && Symbol.iterator && typeof arrayFrom === 'function'; // Frames keep track of scoping both at compile-time and run-time so
// we know how to access variables. Block tags can introduce special
// variables, for example.
var Frame = /*#__PURE__*/function () {
function Frame(parent, isolateWrites) {
this.variables = Object.create(null);
this.parent = parent;
this.topLevel = false; // if this is true, writes (set) should never propagate upwards past
// this frame to its parent (though reads may).
this.isolateWrites = isolateWrites;
}
var _proto = Frame.prototype;
_proto.set = function set(name, val, resolveUp) {
// Allow variables with dots by automatically creating the
// nested structure
var parts = name.split('.');
var obj = this.variables;
var frame = this;
if (resolveUp) {
if (frame = this.resolve(parts[0], true)) {
frame.set(name, val);
return;
}
}
for (var i = 0; i < parts.length - 1; i++) {
var id = parts[i];
if (!obj[id]) {
obj[id] = {};
}
obj = obj[id];
}
obj[parts[parts.length - 1]] = val;
};
_proto.get = function get(name) {
var val = this.variables[name];
if (val !== undefined) {
return val;
}
return null;
};
_proto.lookup = function lookup(name) {
var p = this.parent;
var val = this.variables[name];
if (val !== undefined) {
return val;
}
return p && p.lookup(name);
};
_proto.resolve = function resolve(name, forWrite) {
var p = forWrite && this.isolateWrites ? undefined : this.parent;
var val = this.variables[name];
if (val !== undefined) {
return this;
}
return p && p.resolve(name);
};
_proto.push = function push(isolateWrites) {
return new Frame(this, isolateWrites);
};
_proto.pop = function pop() {
return this.parent;
};
return Frame;
}();
function makeMacro(argNames, kwargNames, func) {
return function macro() {
for (var _len = arguments.length, macroArgs = new Array(_len), _key = 0; _key < _len; _key++) {
macroArgs[_key] = arguments[_key];
}
var argCount = numArgs(macroArgs);
var args;
var kwargs = getKeywordArgs(macroArgs);
if (argCount > argNames.length) {
args = macroArgs.slice(0, argNames.length); // Positional arguments that should be passed in as
// keyword arguments (essentially default values)
macroArgs.slice(args.length, argCount).forEach(function (val, i) {
if (i < kwargNames.length) {
kwargs[kwargNames[i]] = val;
}
});
args.push(kwargs);
} else if (argCount < argNames.length) {
args = macroArgs.slice(0, argCount);
for (var i = argCount; i < argNames.length; i++) {
var arg = argNames[i]; // Keyword arguments that should be passed as
// positional arguments, i.e. the caller explicitly
// used the name of a positional arg
args.push(kwargs[arg]);
delete kwargs[arg];
}
args.push(kwargs);
} else {
args = macroArgs;
}
return func.apply(this, args);
};
}
function makeKeywordArgs(obj) {
obj.__keywords = true;
return obj;
}
function isKeywordArgs(obj) {
return obj && Object.prototype.hasOwnProperty.call(obj, '__keywords');
}
function getKeywordArgs(args) {
var len = args.length;
if (len) {
var lastArg = args[len - 1];
if (isKeywordArgs(lastArg)) {
return lastArg;
}
}
return {};
}
function numArgs(args) {
var len = args.length;
if (len === 0) {
return 0;
}
var lastArg = args[len - 1];
if (isKeywordArgs(lastArg)) {
return len - 1;
} else {
return len;
}
} // A SafeString object indicates that the string should not be
// autoescaped. This happens magically because autoescaping only
// occurs on primitive string objects.
function SafeString(val) {
if (typeof val !== 'string') {
return val;
}
this.val = val;
this.length = val.length;
}
SafeString.prototype = Object.create(String.prototype, {
length: {
writable: true,
configurable: true,
value: 0
}
});
SafeString.prototype.valueOf = function valueOf() {
return this.val;
};
SafeString.prototype.toString = function toString() {
return this.val;
};
function copySafeness(dest, target) {
if (dest instanceof SafeString) {
return new SafeString(target);
}
return target.toString();
}
function markSafe(val) {
var type = typeof val;
if (type === 'string') {
return new SafeString(val);
} else if (type !== 'function') {
return val;
} else {
return function wrapSafe(args) {
var ret = val.apply(this, arguments);
if (typeof ret === 'string') {
return new SafeString(ret);
}
return ret;
};
}
}
function suppressValue(val, autoescape) {
val = val !== undefined && val !== null ? val : '';
if (autoescape && !(val instanceof SafeString)) {
val = lib.escape(val.toString());
}
return val;
}
function ensureDefined(val, lineno, colno) {
if (val === null || val === undefined) {
throw new lib.TemplateError('attempted to output null or undefined value', lineno + 1, colno + 1);
}
return val;
}
function memberLookup(obj, val) {
if (obj === undefined || obj === null) {
return undefined;
}
if (typeof obj[val] === 'function') {
return function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return obj[val].apply(obj, args);
};
}
return obj[val];
}
function callWrap(obj, name, context, args) {
if (!obj) {
throw new Error('Unable to call `' + name + '`, which is undefined or falsey');
} else if (typeof obj !== 'function') {
throw new Error('Unable to call `' + name + '`, which is not a function');
}
return obj.apply(context, args);
}
function contextOrFrameLookup(context, frame, name) {
var val = frame.lookup(name);
return val !== undefined ? val : context.lookup(name);
}
function handleError(error, lineno, colno) {
if (error.lineno) {
return error;
} else {
return new lib.TemplateError(error, lineno, colno);
}
}
function asyncEach(arr, dimen, iter, cb) {
if (lib.isArray(arr)) {
var len = arr.length;
lib.asyncIter(arr, function iterCallback(item, i, next) {
switch (dimen) {
case 1:
iter(item, i, len, next);
break;
case 2:
iter(item[0], item[1], i, len, next);
break;
case 3:
iter(item[0], item[1], item[2], i, len, next);
break;
default:
item.push(i, len, next);
iter.apply(this, item);
}
}, cb);
} else {
lib.asyncFor(arr, function iterCallback(key, val, i, len, next) {
iter(key, val, i, len, next);
}, cb);
}
}
function asyncAll(arr, dimen, func, cb) {
var finished = 0;
var len;
var outputArr;
function done(i, output) {
finished++;
outputArr[i] = output;
if (finished === len) {
cb(null, outputArr.join(''));
}
}
if (lib.isArray(arr)) {
len = arr.length;
outputArr = new Array(len);
if (len === 0) {
cb(null, '');
} else {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
switch (dimen) {
case 1:
func(item, i, len, done);
break;
case 2:
func(item[0], item[1], i, len, done);
break;
case 3:
func(item[0], item[1], item[2], i, len, done);
break;
default:
item.push(i, len, done);
func.apply(this, item);
}
}
}
} else {
var keys = lib.keys(arr || {});
len = keys.length;
outputArr = new Array(len);
if (len === 0) {
cb(null, '');
} else {
for (var _i = 0; _i < keys.length; _i++) {
var k = keys[_i];
func(k, arr[k], _i, len, done);
}
}
}
}
function fromIterator(arr) {
if (typeof arr !== 'object' || arr === null || lib.isArray(arr)) {
return arr;
} else if (supportsIterators && Symbol.iterator in arr) {
return arrayFrom(arr);
} else {
return arr;
}
}
module.exports = {
Frame: Frame,
makeMacro: makeMacro,
makeKeywordArgs: makeKeywordArgs,
numArgs: numArgs,
suppressValue: suppressValue,
ensureDefined: ensureDefined,
memberLookup: memberLookup,
contextOrFrameLookup: contextOrFrameLookup,
callWrap: callWrap,
handleError: handleError,
isArray: lib.isArray,
keys: lib.keys,
SafeString: SafeString,
copySafeness: copySafeness,
markSafe: markSafe,
asyncEach: asyncEach,
asyncAll: asyncAll,
inOperator: lib.inOperator,
fromIterator: fromIterator
};
+286
View File
@@ -0,0 +1,286 @@
'use strict';
var SafeString = require('./runtime').SafeString;
/**
* Returns `true` if the object is a function, otherwise `false`.
* @param { any } value
* @returns { boolean }
*/
function callable(value) {
return typeof value === 'function';
}
exports.callable = callable;
/**
* Returns `true` if the object is strictly not `undefined`.
* @param { any } value
* @returns { boolean }
*/
function defined(value) {
return value !== undefined;
}
exports.defined = defined;
/**
* Returns `true` if the operand (one) is divisble by the test's argument
* (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function divisibleby(one, two) {
return one % two === 0;
}
exports.divisibleby = divisibleby;
/**
* Returns true if the string has been escaped (i.e., is a SafeString).
* @param { any } value
* @returns { boolean }
*/
function escaped(value) {
return value instanceof SafeString;
}
exports.escaped = escaped;
/**
* Returns `true` if the arguments are strictly equal.
* @param { any } one
* @param { any } two
*/
function equalto(one, two) {
return one === two;
}
exports.equalto = equalto; // Aliases
exports.eq = exports.equalto;
exports.sameas = exports.equalto;
/**
* Returns `true` if the value is evenly divisible by 2.
* @param { number } value
* @returns { boolean }
*/
function even(value) {
return value % 2 === 0;
}
exports.even = even;
/**
* Returns `true` if the value is falsy - if I recall correctly, '', 0, false,
* undefined, NaN or null. I don't know if we should stick to the default JS
* behavior or attempt to replicate what Python believes should be falsy (i.e.,
* empty arrays, empty dicts, not 0...).
* @param { any } value
* @returns { boolean }
*/
function falsy(value) {
return !value;
}
exports.falsy = falsy;
/**
* Returns `true` if the operand (one) is greater or equal to the test's
* argument (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function ge(one, two) {
return one >= two;
}
exports.ge = ge;
/**
* Returns `true` if the operand (one) is greater than the test's argument
* (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function greaterthan(one, two) {
return one > two;
}
exports.greaterthan = greaterthan; // alias
exports.gt = exports.greaterthan;
/**
* Returns `true` if the operand (one) is less than or equal to the test's
* argument (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function le(one, two) {
return one <= two;
}
exports.le = le;
/**
* Returns `true` if the operand (one) is less than the test's passed argument
* (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function lessthan(one, two) {
return one < two;
}
exports.lessthan = lessthan; // alias
exports.lt = exports.lessthan;
/**
* Returns `true` if the string is lowercased.
* @param { string } value
* @returns { boolean }
*/
function lower(value) {
return value.toLowerCase() === value;
}
exports.lower = lower;
/**
* Returns `true` if the operand (one) is less than or equal to the test's
* argument (two).
* @param { number } one
* @param { number } two
* @returns { boolean }
*/
function ne(one, two) {
return one !== two;
}
exports.ne = ne;
/**
* Returns true if the value is strictly equal to `null`.
* @param { any }
* @returns { boolean }
*/
function nullTest(value) {
return value === null;
}
exports.null = nullTest;
/**
* Returns true if value is a number.
* @param { any }
* @returns { boolean }
*/
function number(value) {
return typeof value === 'number';
}
exports.number = number;
/**
* Returns `true` if the value is *not* evenly divisible by 2.
* @param { number } value
* @returns { boolean }
*/
function odd(value) {
return value % 2 === 1;
}
exports.odd = odd;
/**
* Returns `true` if the value is a string, `false` if not.
* @param { any } value
* @returns { boolean }
*/
function string(value) {
return typeof value === 'string';
}
exports.string = string;
/**
* Returns `true` if the value is not in the list of things considered falsy:
* '', null, undefined, 0, NaN and false.
* @param { any } value
* @returns { boolean }
*/
function truthy(value) {
return !!value;
}
exports.truthy = truthy;
/**
* Returns `true` if the value is undefined.
* @param { any } value
* @returns { boolean }
*/
function undefinedTest(value) {
return value === undefined;
}
exports.undefined = undefinedTest;
/**
* Returns `true` if the string is uppercased.
* @param { string } value
* @returns { boolean }
*/
function upper(value) {
return value.toUpperCase() === value;
}
exports.upper = upper;
/**
* If ES6 features are available, returns `true` if the value implements the
* `Symbol.iterator` method. If not, it's a string or Array.
*
* Could potentially cause issues if a browser exists that has Set and Map but
* not Symbol.
*
* @param { any } value
* @returns { boolean }
*/
function iterable(value) {
if (typeof Symbol !== 'undefined') {
return !!value[Symbol.iterator];
} else {
return Array.isArray(value) || typeof value === 'string';
}
}
exports.iterable = iterable;
/**
* If ES6 features are available, returns `true` if the value is an object hash
* or an ES6 Map. Otherwise just return if it's an object hash.
* @param { any } value
* @returns { boolean }
*/
function mapping(value) {
// only maps and object hashes
var bool = value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
if (Set) {
return bool && !(value instanceof Set);
} else {
return bool;
}
}
exports.mapping = mapping;
+197
View File
@@ -0,0 +1,197 @@
'use strict';
var nodes = require('./nodes');
var lib = require('./lib');
var sym = 0;
function gensym() {
return 'hole_' + sym++;
} // copy-on-write version of map
function mapCOW(arr, func) {
var res = null;
for (var i = 0; i < arr.length; i++) {
var item = func(arr[i]);
if (item !== arr[i]) {
if (!res) {
res = arr.slice();
}
res[i] = item;
}
}
return res || arr;
}
function walk(ast, func, depthFirst) {
if (!(ast instanceof nodes.Node)) {
return ast;
}
if (!depthFirst) {
var astT = func(ast);
if (astT && astT !== ast) {
return astT;
}
}
if (ast instanceof nodes.NodeList) {
var children = mapCOW(ast.children, function (node) {
return walk(node, func, depthFirst);
});
if (children !== ast.children) {
ast = new nodes[ast.typename](ast.lineno, ast.colno, children);
}
} else if (ast instanceof nodes.CallExtension) {
var args = walk(ast.args, func, depthFirst);
var contentArgs = mapCOW(ast.contentArgs, function (node) {
return walk(node, func, depthFirst);
});
if (args !== ast.args || contentArgs !== ast.contentArgs) {
ast = new nodes[ast.typename](ast.extName, ast.prop, args, contentArgs);
}
} else {
var props = ast.fields.map(function (field) {
return ast[field];
});
var propsT = mapCOW(props, function (prop) {
return walk(prop, func, depthFirst);
});
if (propsT !== props) {
ast = new nodes[ast.typename](ast.lineno, ast.colno);
propsT.forEach(function (prop, i) {
ast[ast.fields[i]] = prop;
});
}
}
return depthFirst ? func(ast) || ast : ast;
}
function depthWalk(ast, func) {
return walk(ast, func, true);
}
function _liftFilters(node, asyncFilters, prop) {
var children = [];
var walked = depthWalk(prop ? node[prop] : node, function (descNode) {
var symbol;
if (descNode instanceof nodes.Block) {
return descNode;
} else if (descNode instanceof nodes.Filter && lib.indexOf(asyncFilters, descNode.name.value) !== -1 || descNode instanceof nodes.CallExtensionAsync) {
symbol = new nodes.Symbol(descNode.lineno, descNode.colno, gensym());
children.push(new nodes.FilterAsync(descNode.lineno, descNode.colno, descNode.name, descNode.args, symbol));
}
return symbol;
});
if (prop) {
node[prop] = walked;
} else {
node = walked;
}
if (children.length) {
children.push(node);
return new nodes.NodeList(node.lineno, node.colno, children);
} else {
return node;
}
}
function liftFilters(ast, asyncFilters) {
return depthWalk(ast, function (node) {
if (node instanceof nodes.Output) {
return _liftFilters(node, asyncFilters);
} else if (node instanceof nodes.Set) {
return _liftFilters(node, asyncFilters, 'value');
} else if (node instanceof nodes.For) {
return _liftFilters(node, asyncFilters, 'arr');
} else if (node instanceof nodes.If) {
return _liftFilters(node, asyncFilters, 'cond');
} else if (node instanceof nodes.CallExtension) {
return _liftFilters(node, asyncFilters, 'args');
} else {
return undefined;
}
});
}
function liftSuper(ast) {
return walk(ast, function (blockNode) {
if (!(blockNode instanceof nodes.Block)) {
return;
}
var hasSuper = false;
var symbol = gensym();
blockNode.body = walk(blockNode.body, function (node) {
// eslint-disable-line consistent-return
if (node instanceof nodes.FunCall && node.name.value === 'super') {
hasSuper = true;
return new nodes.Symbol(node.lineno, node.colno, symbol);
}
});
if (hasSuper) {
blockNode.body.children.unshift(new nodes.Super(0, 0, blockNode.name, new nodes.Symbol(0, 0, symbol)));
}
});
}
function convertStatements(ast) {
return depthWalk(ast, function (node) {
if (!(node instanceof nodes.If) && !(node instanceof nodes.For)) {
return undefined;
}
var async = false;
walk(node, function (child) {
if (child instanceof nodes.FilterAsync || child instanceof nodes.IfAsync || child instanceof nodes.AsyncEach || child instanceof nodes.AsyncAll || child instanceof nodes.CallExtensionAsync) {
async = true; // Stop iterating by returning the node
return child;
}
return undefined;
});
if (async) {
if (node instanceof nodes.If) {
return new nodes.IfAsync(node.lineno, node.colno, node.cond, node.body, node.else_);
} else if (node instanceof nodes.For && !(node instanceof nodes.AsyncAll)) {
return new nodes.AsyncEach(node.lineno, node.colno, node.arr, node.name, node.body, node.else_);
}
}
return undefined;
});
}
function cps(ast, asyncFilters) {
return convertStatements(liftSuper(liftFilters(ast, asyncFilters)));
}
function transform(ast, asyncFilters) {
return cps(ast, asyncFilters || []);
} // var parser = require('./parser');
// var src = 'hello {% foo %}{% endfoo %} end';
// var ast = transform(parser.parse(src, [new FooExtension()]), ['bar']);
// nodes.printNodes(ast);
module.exports = {
transform: transform
};
+110
View File
@@ -0,0 +1,110 @@
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var Loader = require('./loader');
var _require = require('./precompiled-loader.js'),
PrecompiledLoader = _require.PrecompiledLoader;
var WebLoader = /*#__PURE__*/function (_Loader) {
_inheritsLoose(WebLoader, _Loader);
function WebLoader(baseURL, opts) {
var _this;
_this = _Loader.call(this) || this;
_this.baseURL = baseURL || '.';
opts = opts || {}; // By default, the cache is turned off because there's no way
// to "watch" templates over HTTP, so they are re-downloaded
// and compiled each time. (Remember, PRECOMPILE YOUR
// TEMPLATES in production!)
_this.useCache = !!opts.useCache; // We default `async` to false so that the simple synchronous
// API can be used when you aren't doing anything async in
// your templates (which is most of the time). This performs a
// sync ajax request, but that's ok because it should *only*
// happen in development. PRECOMPILE YOUR TEMPLATES.
_this.async = !!opts.async;
return _this;
}
var _proto = WebLoader.prototype;
_proto.resolve = function resolve(from, to) {
throw new Error('relative templates not support in the browser yet');
};
_proto.getSource = function getSource(name, cb) {
var _this2 = this;
var useCache = this.useCache;
var result;
this.fetch(this.baseURL + '/' + name, function (err, src) {
if (err) {
if (cb) {
cb(err.content);
} else if (err.status === 404) {
result = null;
} else {
throw err.content;
}
} else {
result = {
src: src,
path: name,
noCache: !useCache
};
_this2.emit('load', name, result);
if (cb) {
cb(null, result);
}
}
}); // if this WebLoader isn't running asynchronously, the
// fetch above would actually run sync and we'll have a
// result here
return result;
};
_proto.fetch = function fetch(url, cb) {
// Only in the browser please
if (typeof window === 'undefined') {
throw new Error('WebLoader can only by used in a browser');
}
var ajax = new XMLHttpRequest();
var loading = true;
ajax.onreadystatechange = function () {
if (ajax.readyState === 4 && loading) {
loading = false;
if (ajax.status === 0 || ajax.status === 200) {
cb(null, ajax.responseText);
} else {
cb({
status: ajax.status,
content: ajax.responseText
});
}
}
};
url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' + new Date().getTime();
ajax.open('GET', url, this.async);
ajax.send();
};
return WebLoader;
}(Loader);
module.exports = {
WebLoader: WebLoader,
PrecompiledLoader: PrecompiledLoader
};