'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 = {}; 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) { var _this = this; return function () { 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 };