summaryrefslogtreecommitdiff
path: root/node_modules/nunjucks/src/environment.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/nunjucks/src/environment.js')
-rw-r--r--node_modules/nunjucks/src/environment.js548
1 files changed, 548 insertions, 0 deletions
diff --git a/node_modules/nunjucks/src/environment.js b/node_modules/nunjucks/src/environment.js
new file mode 100644
index 0000000..326f836
--- /dev/null
+++ b/node_modules/nunjucks/src/environment.js
@@ -0,0 +1,548 @@
+'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 ? Object.setPrototypeOf.bind() : 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
+}; \ No newline at end of file