+121
| 'use strict'; | ||
| const toString = Object.prototype.toString; | ||
| /* Used to match HTML entities and HTML characters. */ | ||
| exports.reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g; | ||
| exports.reUnescapedHtml = /[&<>"'`]/g; | ||
| exports.reHasEscapedHtml = new RegExp(exports.reEscapedHtml.source); | ||
| exports.reHasUnescapedHtml = new RegExp(exports.reUnescapedHtml.source); | ||
| /* Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ | ||
| exports.reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; | ||
| /* Used to match template delimiters. */ | ||
| exports.reEscape = /<%-([\s\S]+?)%>/g; | ||
| exports.reEvaluate = /<%([\s\S]+?)%>/g; | ||
| exports.reInterpolate = /<%=([\s\S]+?)%>/g; | ||
| exports.delimiters = /<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|\$\{([^\\}]*(?:\\.[^\\}]*)*)\}|<%([\s\S]+?)%>$/g; | ||
| /* Used to ensure capturing order of template delimiters. */ | ||
| exports.reNoMatch = /($^)/; | ||
| exports.reUnescapedString = /['\n\r\u2028\u2029\\]/g; | ||
| exports.reEmptyStringLeading = /\b__p \+= '';/g; | ||
| exports.reEmptyStringMiddle = /\b(__p \+=) '' \+/g; | ||
| exports.reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; | ||
| /* Used to map characters to HTML entities. */ | ||
| exports.htmlEscapes = { | ||
| '&': '&', | ||
| '<': '<', | ||
| '>': '>', | ||
| '"': '"', | ||
| "'": ''', | ||
| '`': '`' | ||
| }; | ||
| /* Used to map HTML entities to characters. */ | ||
| exports.htmlUnescapes = { | ||
| '&': '&', | ||
| '<': '<', | ||
| '>': '>', | ||
| '"': '"', | ||
| ''': "'", | ||
| '`': '`' | ||
| }; | ||
| /** | ||
| * Used by `escape` to convert characters to HTML entities. | ||
| * | ||
| * @private | ||
| * @param {string} chr The matched character to escape. | ||
| * @returns {string} Returns the escaped character. | ||
| */ | ||
| exports.escapeHtmlChar = ch => exports.htmlEscapes[ch] || ch; | ||
| /** | ||
| * Returns true if `val` is an object. | ||
| */ | ||
| exports.isObject = val => { | ||
| return typeof val === 'function' || (val && typeof val === 'object' && !Array.isArray(val)); | ||
| }; | ||
| /** | ||
| * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to | ||
| * their corresponding HTML entities. | ||
| * | ||
| * @category String | ||
| * @param {string} [string=''] The string to escape. | ||
| * @returns {string} Returns the escaped string. | ||
| */ | ||
| exports.escape = input => { | ||
| let str = exports.baseToString(input); | ||
| return (str && exports.reHasUnescapedHtml.test(str)) | ||
| ? str.replace(exports.reUnescapedHtml, exports.escapeHtmlChar) | ||
| : str; | ||
| }; | ||
| /** | ||
| * Converts `value` to a string if it's not one. An empty string is returned | ||
| * for `null` or `undefined` values. | ||
| * | ||
| * @private | ||
| * @param {*} value The value to process. | ||
| * @returns {string} Returns the string. | ||
| */ | ||
| exports.baseToString = value => value ? value + '' : ''; | ||
| exports.tryCatch = fn => { | ||
| try { | ||
| return fn(); | ||
| } catch (err) { | ||
| return err; | ||
| } | ||
| }; | ||
| exports.escapeStringChar = ch => { | ||
| return '\\' + ({ | ||
| '\\': '\\', | ||
| "'": "'", | ||
| '\n': 'n', | ||
| '\r': 'r', | ||
| '\u2028': 'u2028', | ||
| '\u2029': 'u2029' | ||
| })[ch]; | ||
| }; | ||
| exports.omit = (obj, keys) => { | ||
| let res = {}; | ||
| if (!obj) return res; | ||
| keys = [].concat(keys || []); | ||
| for (let key of Object.keys(obj)) { | ||
| if (!keys.includes(key)) { | ||
| res[key] = obj[key]; | ||
| } | ||
| } | ||
| return res; | ||
| }; |
+250
-285
| /** | ||
| * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> | ||
| * Copyright (c) 2012-present, The Dojo Foundation .<http://dojofoundation.org/> | ||
| * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> | ||
| * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors | ||
| * Available under MIT license <https://lodash.com/license> | ||
| * Copyright (c) 2015 Jon Schlinkert | ||
| * Copyright (c) 2015-present, Jon Schlinkert. | ||
| */ | ||
@@ -11,3 +11,4 @@ | ||
| var utils = require('./lib/utils'); | ||
| const assign = require('assign-deep'); | ||
| const utils = require('./utils'); | ||
@@ -18,9 +19,5 @@ /** | ||
| * ```js | ||
| * var Engine = require('engine'); | ||
| * var engine = new Engine(); | ||
| * | ||
| * // or | ||
| * var engine = require('engine')(); | ||
| * const Engine = require('engine'); | ||
| * const engine = new Engine(); | ||
| * ``` | ||
| * | ||
| * @param {Object} `options` | ||
@@ -30,317 +27,291 @@ * @api public | ||
| function Engine(options) { | ||
| if (!(this instanceof Engine)) { | ||
| return new Engine(options); | ||
| } | ||
| class Engine { | ||
| constructor(options = {}) { | ||
| this.options = options; | ||
| this.options = options || {}; | ||
| this.init(this.options); | ||
| } | ||
| this.imports = this.options.imports || {}; | ||
| this.options.variable = ''; | ||
| this.settings = {}; | ||
| this.counter = 0; | ||
| this.cache = {}; | ||
| /** | ||
| * Initialize defaults | ||
| */ | ||
| // regex | ||
| this.options.escape = this.options.escape || utils.reEscape; | ||
| this.options.evaluate = this.options.evaluate || utils.reEvaluate; | ||
| this.options.interpolate = this.options.interpolate || utils.reInterpolate; | ||
| Engine.prototype.init = function(opts) { | ||
| this.imports = opts.imports || {}; | ||
| // register helpers | ||
| if (this.options.helpers) { | ||
| this.helpers(this.options.helpers); | ||
| } | ||
| // load data | ||
| if (this.options.data) { | ||
| this.data(this.options.data); | ||
| } | ||
| } | ||
| opts.variable = ''; | ||
| this.settings = {}; | ||
| this.counter = 0; | ||
| this.cache = {}; | ||
| /** | ||
| * Register a template helper. | ||
| * | ||
| * ```js | ||
| * engine.helper('upper', function(str) { | ||
| * return str.toUpperCase(); | ||
| * }); | ||
| * | ||
| * engine.render('<%= upper(user) %>', {user: 'doowb'}); | ||
| * //=> 'DOOWB' | ||
| * ``` | ||
| * @param {String} `prop` | ||
| * @param {Function} `fn` | ||
| * @return {Object} Instance of `Engine` for chaining | ||
| * @api public | ||
| */ | ||
| // regex | ||
| opts.escape = opts.escape || utils.reEscape; | ||
| opts.evaluate = opts.evaluate || utils.reEvaluate; | ||
| opts.interpolate = opts.interpolate || utils.reInterpolate; | ||
| helper(prop, fn) { | ||
| if (utils.isObject(prop)) { | ||
| this.helpers(prop); | ||
| } else { | ||
| this.imports[prop] = fn; | ||
| } | ||
| return this; | ||
| } | ||
| // register helpers | ||
| if (opts.helpers) { | ||
| this.helpers(opts.helpers); | ||
| /** | ||
| * Register an object of template helpers. | ||
| * | ||
| * ```js | ||
| * engine.helpers({ | ||
| * upper: function(str) { | ||
| * return str.toUpperCase(); | ||
| * }, | ||
| * lower: function(str) { | ||
| * return str.toLowerCase(); | ||
| * } | ||
| * }); | ||
| * | ||
| * // Or, just require in `template-helpers` | ||
| * engine.helpers(require('template-helpers')._); | ||
| * ``` | ||
| * @param {Object|Array} `helpers` Object or array of helper objects. | ||
| * @return {Object} Instance of `Engine` for chaining | ||
| * @api public | ||
| */ | ||
| helpers(helpers) { | ||
| if (utils.isObject(helpers)) { | ||
| for (let key of Object.keys(helpers)) { | ||
| this.helper(key, helpers[key]); | ||
| } | ||
| } | ||
| return this; | ||
| } | ||
| // load data | ||
| if (opts.data) { | ||
| this.data(opts.data); | ||
| } | ||
| }; | ||
| /** | ||
| * Register a template helper. | ||
| * | ||
| * ```js | ||
| * engine.helper('upper', function(str) { | ||
| * return str.toUpperCase(); | ||
| * }); | ||
| * | ||
| * engine.render('<%= upper(user) %>', {user: 'doowb'}); | ||
| * //=> 'DOOWB' | ||
| * ``` | ||
| * | ||
| * @param {String} `prop` | ||
| * @param {Function} `fn` | ||
| * @return {Object} Instance of `Engine` for chaining | ||
| * @api public | ||
| */ | ||
| /** | ||
| * Add data to be passed to templates as context. | ||
| * | ||
| * ```js | ||
| * engine.data({first: 'Brian'}); | ||
| * engine.render('<%= last %>, <%= first %>', {last: 'Woodward'}); | ||
| * //=> 'Woodward, Brian' | ||
| * ``` | ||
| * @param {String|Object} `key` Property key, or an object | ||
| * @param {any} `value` If key is a string, this can be any typeof value | ||
| * @return {Object} Engine instance, for chaining | ||
| * @api public | ||
| */ | ||
| Engine.prototype.helper = function(prop, fn) { | ||
| if (typeof prop === 'object') { | ||
| this.helpers(prop); | ||
| } else { | ||
| utils.set(this.imports, prop, fn); | ||
| data(prop, value) { | ||
| if (typeof prop === 'object') { | ||
| if (utils.isObject(prop)) { | ||
| for (let key of Object.keys(prop)) { | ||
| this.data(key, prop[key]); | ||
| } | ||
| } | ||
| } else { | ||
| if (!this.cache.data) this.cache.data = {}; | ||
| this.cache.data[prop] = value; | ||
| } | ||
| return this; | ||
| } | ||
| return this; | ||
| }; | ||
| /** | ||
| * Register an object of template helpers. | ||
| * | ||
| * ```js | ||
| * engine.helpers({ | ||
| * upper: function(str) { | ||
| * return str.toUpperCase(); | ||
| * }, | ||
| * lower: function(str) { | ||
| * return str.toLowerCase(); | ||
| * } | ||
| * }); | ||
| * | ||
| * // Or, just require in `template-helpers` | ||
| * engine.helpers(require('template-helpers')._); | ||
| * ``` | ||
| * @param {Object|Array} `helpers` Object or array of helper objects. | ||
| * @return {Object} Instance of `Engine` for chaining | ||
| * @api public | ||
| */ | ||
| /** | ||
| * Generate the regex to use for matching template variables. | ||
| * @param {Object} `opts` | ||
| * @return {RegExp} | ||
| */ | ||
| Engine.prototype.helpers = function(helpers) { | ||
| return this.visit('helper', helpers); | ||
| }; | ||
| _regex(options) { | ||
| let opts = Object.assign({}, this.options, options); | ||
| if (!opts.interpolate && !opts.regex && !opts.escape && !opts.evaluate) { | ||
| return utils.delimiters; | ||
| } | ||
| /** | ||
| * Add data to be passed to templates as context. | ||
| * | ||
| * ```js | ||
| * engine.data({first: 'Brian'}); | ||
| * engine.render('<%= last %>, <%= first %>', {last: 'Woodward'}); | ||
| * //=> 'Woodward, Brian' | ||
| * ``` | ||
| * | ||
| * @param {String|Object} `key` Property key, or an object | ||
| * @param {any} `value` If key is a string, this can be any typeof value | ||
| * @return {Object} Engine instance, for chaining | ||
| * @api public | ||
| */ | ||
| let interpolate = opts.interpolate || utils.reNoMatch; | ||
| if (opts.regex instanceof RegExp) { | ||
| interpolate = opts.regex; | ||
| } | ||
| Engine.prototype.data = function(prop, value) { | ||
| this.cache.data = this.cache.data || {}; | ||
| if (typeof prop === 'object') { | ||
| this.visit('data', prop); | ||
| } else { | ||
| utils.set(this.cache.data, prop, value); | ||
| let reString = (opts.escape || utils.reNoMatch).source | ||
| + '|' + interpolate.source | ||
| + '|' + (interpolate === utils.reInterpolate ? utils.reEsTemplate : utils.reNoMatch).source | ||
| + '|' + (opts.evaluate || utils.reNoMatch).source; | ||
| return new RegExp(reString + '|$', 'g'); | ||
| } | ||
| return this; | ||
| }; | ||
| /** | ||
| * Generate the regex to use for matching template variables. | ||
| * @param {Object} `opts` | ||
| * @return {RegExp} | ||
| */ | ||
| /** | ||
| * Creates a compiled template function that can interpolate data properties | ||
| * in "interpolate" delimiters, HTML-escape interpolated data properties in | ||
| * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data | ||
| * properties may be accessed as free variables in the template. If a setting | ||
| * object is provided it takes precedence over `engine.settings` values. | ||
| * | ||
| * ```js | ||
| * let fn = engine.compile('Hello, <%= user %>!'); | ||
| * //=> [function] | ||
| * | ||
| * fn({user: 'doowb'}); | ||
| * //=> 'Hello, doowb!' | ||
| * | ||
| * fn({user: 'halle'}); | ||
| * //=> 'Hello, halle!' | ||
| * ``` | ||
| * @param {String} `str` The template string. | ||
| * @param {Object} `options` The options object. | ||
| * @param {RegExp} [options.escape] The HTML "escape" delimiter. | ||
| * @param {RegExp} [options.evaluate] The "evaluate" delimiter. | ||
| * @param {Object} [options.imports] An object to import into the template as free variables. | ||
| * @param {RegExp} [options.interpolate] The "interpolate" delimiter. | ||
| * @param {String} [options.sourceURL] The sourceURL of the template's compiled source. | ||
| * @param {String} [options.variable] The data object variable name. | ||
| * @param {Object} `settings` Engine settings | ||
| * @returns {Function} Returns the compiled template function. | ||
| * @api public | ||
| */ | ||
| Engine.prototype._regex = function (opts) { | ||
| opts = utils.assign({}, this.options, opts); | ||
| if (!opts.interpolate && !opts.regex && !opts.escape && !opts.evaluate) { | ||
| return utils.delimiters; | ||
| } | ||
| compile(input, options = {}, settings) { | ||
| let engine = this; | ||
| var interpolate = opts.interpolate || utils.reNoMatch; | ||
| if (utils.typeOf(opts.regex) === 'regexp') { | ||
| interpolate = opts.regex; | ||
| } | ||
| if (!(this instanceof Engine)) { | ||
| if (!utils.isObject(options)) options = {}; | ||
| engine = new Engine(options); | ||
| } | ||
| var reString = (opts.escape || utils.reNoMatch).source | ||
| + '|' + interpolate.source | ||
| let str = String(input); | ||
| settings = assign({}, engine.settings, options && options.settings, settings); | ||
| let opts = assign({}, engine.options, settings, options); | ||
| + '|' + (interpolate === utils.reInterpolate | ||
| ? utils.reEsTemplate | ||
| : utils.reNoMatch).source | ||
| let imports = assign({}, opts.imports, opts.helpers, settings.imports); | ||
| imports.escape = utils.escape; | ||
| assign(imports, utils.omit(engine.imports, 'engine')); | ||
| assign(imports, utils.omit(engine.cache.data, 'engine')); | ||
| imports.engine = engine; | ||
| + '|' + (opts.evaluate || utils.reNoMatch).source; | ||
| return RegExp(reString + '|$', 'g'); | ||
| }; | ||
| let keys = Object.keys(imports); | ||
| let values = keys.map(key => imports[key]); | ||
| let isEvaluating; | ||
| let isEscaping; | ||
| let source = "__p += '"; | ||
| let idx = 0; | ||
| /** | ||
| * Creates a compiled template function that can interpolate data properties | ||
| * in "interpolate" delimiters, HTML-escape interpolated data properties in | ||
| * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data | ||
| * properties may be accessed as free variables in the template. If a setting | ||
| * object is provided it takes precedence over `engine.settings` values. | ||
| * | ||
| * ```js | ||
| * var fn = engine.compile('Hello, <%= user %>!'); | ||
| * //=> [function] | ||
| * | ||
| * fn({user: 'doowb'}); | ||
| * //=> 'Hello, doowb!' | ||
| * | ||
| * fn({user: 'halle'}); | ||
| * //=> 'Hello, halle!' | ||
| * ``` | ||
| * | ||
| * @param {string} `str` The template string. | ||
| * @param {Object} `opts` The options object. | ||
| * @param {RegExp} [options.escape] The HTML "escape" delimiter. | ||
| * @param {RegExp} [options.evaluate] The "evaluate" delimiter. | ||
| * @param {Object} [options.imports] An object to import into the template as free variables. | ||
| * @param {RegExp} [options.interpolate] The "interpolate" delimiter. | ||
| * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. | ||
| * @param {string} [options.variable] The data object variable name. | ||
| * @param- {Object} [data] Enables the legacy `options` param signature. | ||
| * @returns {Function} Returns the compiled template function. | ||
| * @api public | ||
| */ | ||
| // Use a sourceURL for easier debugging. | ||
| let sourceURL = '//# sourceURL=' | ||
| + ('sourceURL' in opts ? opts.sourceURL : (`engine.templateSources[${(++engine.counter)}]`)) | ||
| + '\n'; | ||
| Engine.prototype.compile = function (str, options, settings) { | ||
| var assign = utils.assign; | ||
| var engine = this; | ||
| // Compile the regexp to match each delimiter. | ||
| let re = engine._regex(opts); | ||
| if (!(this instanceof Engine)) { | ||
| if (utils.typeOf(options) !== 'object') options = {}; | ||
| engine = new Engine(options); | ||
| } | ||
| str.replace(re, (match, esc, interp, es6, evaluate, offset) => { | ||
| if (!interp) interp = es6; | ||
| var opts = options || {}; | ||
| // Escape characters that can't be included in str literals. | ||
| source += str.slice(idx, offset).replace(utils.reUnescapedString, utils.escapeStringChar); | ||
| settings = assign({}, engine.settings, opts.settings, settings); | ||
| opts = assign({}, engine.options, settings, opts); | ||
| str = String(str); | ||
| // Replace delimiters with snippets. | ||
| if (esc) { | ||
| isEscaping = true; | ||
| source += `' +\n__e(${esc}) +\n'`; | ||
| } | ||
| if (evaluate) { | ||
| isEvaluating = true; | ||
| source += `';\n${evaluate};\n__p += '`; | ||
| } | ||
| if (interp) { | ||
| source += `' +\n((__t = (${interp})) == null ? '' : __t) +\n'`; | ||
| } | ||
| var imports = assign({}, opts.imports, opts.helpers, settings.imports); | ||
| idx = offset + match.length; | ||
| imports.escape = utils.escape; | ||
| assign(imports, utils.omit(engine.imports, 'engine')); | ||
| assign(imports, utils.omit(engine.cache.data, 'engine')); | ||
| imports.engine = engine; | ||
| // The JS engine embedded in Adobe products requires returning the `match` | ||
| // str in order to produce the correct `offset` value. | ||
| return match; | ||
| }); | ||
| var keys = Object.keys(imports); | ||
| var values = keys.map(function(key) { | ||
| return imports[key]; | ||
| }); | ||
| source += "';\n"; | ||
| var isEscaping; | ||
| var isEvaluating; | ||
| var idx = 0; | ||
| var source = "__p += '"; | ||
| // If `variable` is not specified wrap a with-statement around the generated | ||
| // code to add the data object to the top of the scope chain. | ||
| let variable = opts.variable; | ||
| if (!variable) { | ||
| source = `with (obj) {\n${source}\n}\n`; | ||
| } | ||
| // Use a sourceURL for easier debugging. | ||
| var sourceURL = '//# sourceURL=' + ('sourceURL' in opts ? opts.sourceURL : ('engine.templateSources[' + (++engine.counter) + ']')) + '\n'; | ||
| // Cleanup code by stripping empty strings. | ||
| source = (isEvaluating ? source.replace(utils.reEmptyStringLeading, '') : source) | ||
| .replace(utils.reEmptyStringMiddle, '$1') | ||
| .replace(utils.reEmptyStringTrailing, '$1;'); | ||
| // Compile the regexp to match each delimiter. | ||
| var re = engine._regex(opts); | ||
| // Frame code as the function body. | ||
| source = 'function(' | ||
| + (variable || 'obj') + ') {\n' | ||
| + (variable ? '' : '(obj || (obj = {}));\n') | ||
| + 'let __t, __p = ""' | ||
| + (isEscaping ? ', __e = escape' : '') | ||
| + (isEvaluating ? ', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, "") }\n' : ';\n') | ||
| + source + 'return __p\n}'; | ||
| str.replace(re, function (match, esc, interp, es6, evaluate, offset) { | ||
| if (!interp) interp = es6; | ||
| let result = utils.tryCatch(function() { | ||
| return Function(keys, sourceURL + `return ${source}`).apply(null, values); | ||
| }); | ||
| // Escape characters that can't be included in str literals. | ||
| source += str.slice(idx, offset).replace(utils.reUnescapedString, utils.escapeStringChar); | ||
| // Provide the compiled function's source by its `toString` method or | ||
| // the `source` property as a convenience for inlining compiled templates. | ||
| result.source = source; | ||
| // Replace delimiters with snippets. | ||
| if (esc) { | ||
| isEscaping = true; | ||
| source += "' +\n__e(" + esc + ") +\n'"; | ||
| if (result instanceof Error) { | ||
| throw result; | ||
| } | ||
| if (evaluate) { | ||
| isEvaluating = true; | ||
| source += "';\n" + evaluate + ";\n__p += '"; | ||
| } | ||
| if (interp) { | ||
| source += "' +\n((__t = (" + interp + ")) == null ? '' : __t) +\n'"; | ||
| } | ||
| idx = offset + match.length; | ||
| // The JS engine embedded in Adobe products requires returning the `match` | ||
| // str in order to produce the correct `offset` value. | ||
| return match; | ||
| }); | ||
| source += "';\n"; | ||
| // If `variable` is not specified wrap a with-statement around the generated | ||
| // code to add the data object to the top of the scope chain. | ||
| var variable = opts.variable; | ||
| if (!variable) { | ||
| source = 'with (obj) {\n' + source + '\n}\n'; | ||
| return result; | ||
| } | ||
| // Cleanup code by stripping empty strings. | ||
| source = (isEvaluating ? source.replace(utils.reEmptyStringLeading, '') : source) | ||
| .replace(utils.reEmptyStringMiddle, '$1') | ||
| .replace(utils.reEmptyStringTrailing, '$1;'); | ||
| /** | ||
| * Renders templates with the given data and returns a string. | ||
| * | ||
| * ```js | ||
| * engine.render('<%= user %>', {user: 'doowb'}); | ||
| * //=> 'doowb' | ||
| * ``` | ||
| * @param {String} `str` | ||
| * @param {Object} `data` | ||
| * @return {String} | ||
| * @api public | ||
| */ | ||
| // Frame code as the function body. | ||
| source = 'function(' | ||
| + (variable || 'obj') + ') {\n' | ||
| + (variable ? '' : '(obj || (obj = {}));\n') | ||
| + 'var __t, __p = ""' | ||
| + (isEscaping ? ', __e = escape' : '') | ||
| + (isEvaluating ? ', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, "") }\n' : ';\n') | ||
| + source + 'return __p\n}'; | ||
| var result = utils.tryCatch(function () { | ||
| return Function(keys, sourceURL + 'return ' + source).apply(null, values); | ||
| }); | ||
| // Provide the compiled function's source by its `toString` method or | ||
| // the `source` property as a convenience for inlining compiled templates. | ||
| result.source = source; | ||
| if (result instanceof Error) { | ||
| throw result; | ||
| render(fn, locals, options) { | ||
| let ctx = Object.assign({}, this.cache.data, locals); | ||
| if (ctx.imports) ctx = Object.assign({}, ctx, ctx.imports); | ||
| if (ctx.helpers) ctx = Object.assign({}, ctx, ctx.helpers); | ||
| if (typeof fn === 'string') { | ||
| fn = this.compile(fn, options); | ||
| } | ||
| return fn(ctx); | ||
| } | ||
| if (this && this.cache && this.cache.data) { | ||
| result = result.bind(this.cache.data); | ||
| static get utils() { | ||
| return utils; | ||
| } | ||
| return result; | ||
| }; | ||
| } | ||
| /** | ||
| * Renders templates with the given data and returns a string. | ||
| * | ||
| * ```js | ||
| * engine.render('<%= user %>', {user: 'doowb'}); | ||
| * //=> 'doowb' | ||
| * ``` | ||
| * @param {String} `str` | ||
| * @param {Object} `data` | ||
| * @return {String} | ||
| * @api public | ||
| */ | ||
| Engine.prototype.render = function(str, data) { | ||
| var ctx = this.cache.data || {}; | ||
| var assign = utils.assign; | ||
| ctx = assign({}, ctx, data); | ||
| ctx = assign({}, ctx, ctx.imports || {}); | ||
| ctx = assign({}, ctx, ctx.helpers || {}); | ||
| if (typeof str === 'function') { | ||
| return str(ctx); | ||
| } | ||
| return this.compile(str)(ctx); | ||
| }; | ||
| /** | ||
| * Visit the given `method` over `val` | ||
| * @param {String} `method` | ||
| * @param {Object|Array} `val` | ||
| */ | ||
| Engine.prototype.visit = function(method, val) { | ||
| utils.visit(this, method, val); | ||
| return this; | ||
| }; | ||
| /** | ||
| * Expose `Engine` | ||
@@ -350,7 +321,1 @@ */ | ||
| module.exports = Engine; | ||
| /** | ||
| * Expose `Engine` | ||
| */ | ||
| module.exports.utils = utils; |
+1
-1
@@ -7,3 +7,3 @@ The MIT License (MIT) | ||
| Available under MIT license <https://lodash.com/license> | ||
| Copyright (c) 2015-2016 Jon Schlinkert | ||
| Copyright (c) 2015-present Jon Schlinkert | ||
@@ -10,0 +10,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
+8
-28
| { | ||
| "name": "engine", | ||
| "description": "Template engine based on Lo-Dash template, but adds features like the ability to register helpers and more easily set data to be used as context in templates.", | ||
| "version": "0.1.12", | ||
| "version": "1.0.0", | ||
| "homepage": "https://github.com/jonschlinkert/engine", | ||
@@ -14,9 +14,7 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
| "index.js", | ||
| "lib", | ||
| "LICENSE", | ||
| "README.md" | ||
| "utils.js" | ||
| ], | ||
| "main": "index.js", | ||
| "engines": { | ||
| "node": ">=0.10.0" | ||
| "node": ">=8" | ||
| }, | ||
@@ -26,22 +24,5 @@ "scripts": { | ||
| }, | ||
| "dependencies": { | ||
| "assign-deep": "^0.4.3", | ||
| "collection-visit": "^0.2.0", | ||
| "get-value": "^1.2.1", | ||
| "kind-of": "^2.0.1", | ||
| "lazy-cache": "^0.2.3", | ||
| "object.omit": "^2.0.0", | ||
| "set-value": "^0.2.0" | ||
| }, | ||
| "devDependencies": { | ||
| "ansi-red": "^0.1.1", | ||
| "extend-shallow": "^2.0.1", | ||
| "for-in": "^0.1.4", | ||
| "gulp-format-md": "^0.1.9", | ||
| "lodash": "^3.10.1", | ||
| "mocha": "*", | ||
| "shallow-clone": "^0.1.1", | ||
| "should": "*", | ||
| "template-helpers": "^0.3.2", | ||
| "time-require": "jonschlinkert/time-require" | ||
| "gulp-format-md": "^1.0.0", | ||
| "mocha": "^5.2.0" | ||
| }, | ||
@@ -80,10 +61,9 @@ "keywords": [ | ||
| }, | ||
| "reflinks": [ | ||
| "verb", | ||
| "verb-generate-readme" | ||
| ], | ||
| "lint": { | ||
| "reflinks": true | ||
| } | ||
| }, | ||
| "dependencies": { | ||
| "assign-deep": "^1.0.0" | ||
| } | ||
| } |
-157
| 'use strict'; | ||
| /** | ||
| * Module dependencies | ||
| */ | ||
| var utils = require('lazy-cache')(require); | ||
| /** | ||
| * Temporarily re-assign `require` to trick browserify and | ||
| * webpack into reconizing lazy dependencies. | ||
| * | ||
| * This tiny bit of ugliness has the huge dual advantage of | ||
| * only loading modules that are actually called at some | ||
| * point in the lifecycle of the application, whilst also | ||
| * allowing browserify and webpack to find modules that | ||
| * are depended on but never actually called. | ||
| */ | ||
| var fn = require; | ||
| require = utils; | ||
| /** | ||
| * Lazily required module dependencies | ||
| */ | ||
| require('set-value', 'set'); | ||
| require('get-value', 'get'); | ||
| require('kind-of', 'typeOf'); | ||
| require('collection-visit', 'visit'); | ||
| require('object.omit', 'omit'); | ||
| require('assign-deep', 'assign'); | ||
| /* Used to match HTML entities and HTML characters. */ | ||
| utils.reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g; | ||
| utils.reUnescapedHtml = /[&<>"'`]/g; | ||
| utils.reHasEscapedHtml = RegExp(utils.reEscapedHtml.source); | ||
| utils.reHasUnescapedHtml = RegExp(utils.reUnescapedHtml.source); | ||
| /* Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ | ||
| utils.reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; | ||
| /* Used to match template delimiters. */ | ||
| utils.reEscape = /<%-([\s\S]+?)%>/g; | ||
| utils.reEvaluate = /<%([\s\S]+?)%>/g; | ||
| utils.reInterpolate = /<%=([\s\S]+?)%>/g; | ||
| utils.delimiters = /<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|\$\{([^\\}]*(?:\\.[^\\}]*)*)\}|<%([\s\S]+?)%>$/g; | ||
| /* Used to ensure capturing order of template delimiters. */ | ||
| utils.reNoMatch = /($^)/; | ||
| utils.reUnescapedString = /['\n\r\u2028\u2029\\]/g; | ||
| utils.reEmptyStringLeading = /\b__p \+= '';/g; | ||
| utils.reEmptyStringMiddle = /\b(__p \+=) '' \+/g; | ||
| utils.reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; | ||
| /* Used to map characters to HTML entities. */ | ||
| utils.htmlEscapes = { | ||
| '&': '&', | ||
| '<': '<', | ||
| '>': '>', | ||
| '"': '"', | ||
| "'": ''', | ||
| '`': '`' | ||
| }; | ||
| /* Used to map HTML entities to characters. */ | ||
| utils.htmlUnescapes = { | ||
| '&': '&', | ||
| '<': '<', | ||
| '>': '>', | ||
| '"': '"', | ||
| ''': "'", | ||
| '`': '`' | ||
| }; | ||
| /** | ||
| * Used by `escape` to convert characters to HTML entities. | ||
| * | ||
| * @private | ||
| * @param {string} chr The matched character to escape. | ||
| * @returns {string} Returns the escaped character. | ||
| */ | ||
| utils.escapeHtmlChar = function escapeHtmlChar(chr) { | ||
| return utils.htmlEscapes[chr]; | ||
| }; | ||
| /** | ||
| * This method returns the first argument provided to it. | ||
| * | ||
| * @param {*} value Any value. | ||
| * @returns {*} Returns `value`. | ||
| */ | ||
| utils.identity = function identity(value) { | ||
| return value; | ||
| }; | ||
| /** | ||
| * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to | ||
| * their corresponding HTML entities. | ||
| * | ||
| * @category String | ||
| * @param {string} [string=''] The string to escape. | ||
| * @returns {string} Returns the escaped string. | ||
| */ | ||
| utils.escape = function escape(str) { | ||
| str = utils.baseToString(str); | ||
| return (str && utils.reHasUnescapedHtml.test(str)) | ||
| ? str.replace(utils.reUnescapedHtml, utils.escapeHtmlChar) | ||
| : str; | ||
| }; | ||
| /** | ||
| * Converts `value` to a string if it's not one. An empty string is returned | ||
| * for `null` or `undefined` values. | ||
| * | ||
| * @private | ||
| * @param {*} value The value to process. | ||
| * @returns {string} Returns the string. | ||
| */ | ||
| utils.baseToString = function baseToString(value) { | ||
| return value == null ? '' : (value + ''); | ||
| }; | ||
| utils.tryCatch = function tryCatch(fn) { | ||
| try { | ||
| return fn.call(); | ||
| } catch (err) { | ||
| return err; | ||
| } | ||
| }; | ||
| utils.escapeStringChar = function escapeStringChar(ch) { | ||
| return '\\' + ({ | ||
| '\\': '\\', | ||
| "'": "'", | ||
| '\n': 'n', | ||
| '\r': 'r', | ||
| '\u2028': 'u2028', | ||
| '\u2029': 'u2029' | ||
| })[ch]; | ||
| }; | ||
| /** | ||
| * Restore `require` | ||
| */ | ||
| require = fn; | ||
| /** | ||
| * Expose `utils` modules | ||
| */ | ||
| module.exports = utils; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1
-85.71%2
-80%0
-100%21647
-5.18%377
-11.92%4
100%2
100%+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated