diff --git a/dist/leopard.js b/dist/leopard.js index c63533f..6f2ebac 100644 --- a/dist/leopard.js +++ b/dist/leopard.js @@ -1,5 +1,5 @@ /** - * leopard v0.0.1 + * leopard v1.0.0 * (c) 2018 Ryan Liu * @license WTFPL */ @@ -26,6 +26,24 @@ var escapeQuotes = function(str) { return str.replace(/"/g, '\\"') }; +function Leopard() {} +var p = Leopard.prototype; + +/** + * check if there is filters in expressions + * expect format: + * - 'name | capitalize | reverse' + * and this will be compile into: + * - 'reverse(capitalize(name))' + * + * @param {String} line + * @return {String} + */ +var parseFilters = function(line) { + var segments = line.split('|'); + return segments.reduce((accumulator, f) => f.trim() + '(' + accumulator.trim() + ')') +}; + /** * parse the given `tpl` and return Function body string * @@ -33,7 +51,7 @@ var escapeQuotes = function(str) { * @param {Object} data * @return {String} */ -var parser = function(tpl, data) { +p.parse = function(tpl, data) { data = data || {}; var delimeterRE = /<%(.+?)%>/g; var curMatched = null; @@ -59,12 +77,14 @@ var parser = function(tpl, data) { var generate = function(line) { if (line.length > 0) { var type = line.charAt(0); + switch (type) { + // for interpolations we should check filters case '=': - push('escape(' + line.substr(1).trim() + ')'); + push('escape(' + parseFilters(line.substr(1).trim()) + ')'); break case '-': - push(line.substr(1).trim()); + push(parseFilters(line.substr(1).trim())); break default: body += line + '\n'; @@ -99,14 +119,62 @@ var parser = function(tpl, data) { * @param {Object} data * @return {String} */ -var compiler = function(tpl, data) { - var body = parser(tpl, data); - var fun = new Function('escape', body); - return fun.call(this, escape$1) +p.compile = function(tpl, data) { + var body = this.parse(tpl, data); + // 注入过滤器 + var fun = new Function('escape', ...Object.keys(p), body); + return fun.call(p, escape$1, ...Object.values(p)) }; -var leo = compiler; -var src = leo; +var instance = Leopard; + +/** + * util for adding filters to Leopard, + * return Leopard for chaining invoking + * + * @param {String} name + * @param {Function} handler + * @return {Leopard} + */ +function filter(name, handler) { + /* istanbul ignore if */ + if (typeof handler !== 'function') { + throw new TypeError( + 'Leopard: filter requires a function as handler, but got \"' + + typeof handler + '\" in filter \"' + name + '\"' + ) + } + /* istanbul ignore if */ + if (name in this.prototype) { + throw new Error('Leopard: filter \"' + name + '\" has been declared') + } + this.prototype[name] = handler; + return this +} + +var filter_1 = filter; + +var capitalize = function(string) { + return string.charAt(0).toUpperCase() + string.slice(1) +}; + +var reverse = function(string) { + return string.split('').reverse().join('') +}; + +var presets = { capitalize, reverse }; + +// mount `filter` to Leopard as a util +instance.filter = filter_1; + +// mount presets to Leopard.prototype so that every instance can use them +var presetFilters = Object.keys(presets); +for (var i = 0, l = presetFilters.length, name; i < l; i++) { + name = presetFilters[i]; + instance.filter(name, presets[name]); +} + +var src = instance; return src; diff --git a/dist/leopard.min.js b/dist/leopard.min.js index 5ac4665..90fad7d 100644 --- a/dist/leopard.min.js +++ b/dist/leopard.min.js @@ -1 +1 @@ -!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.Leopard=n()}(this,function(){"use strict";var e=function(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")},n=function(e){return e.replace(/"/g,'\\"')};return function(t,r){var i=function(e,t){t=t||{};var r=/<%(.+?)%>/g,i=null,u=null,s="var lines = [];\nvar rst;\nwith("+JSON.stringify(t)+") {\n";function a(e){s+="lines.push("+e+");\n"}for(var c=function(e){if(e.length>0)switch(e.charAt(0)){case"=":a("escape("+e.substr(1).trim()+")");break;case"-":a(e.substr(1).trim());break;default:s+=e+"\n"}};i=r.exec(e);){var l=e.substring(null!==u?u.index+u[0].length:0,i.index);l&&a('"'+n(l)+'"');var o=i[1].trim();o&&c(o),u=i}var f=e.substr(u.index+u[0].length);return f&&a('"'+n(f)+'"'),s+='rst = lines.join("");\n}\nreturn rst;'}(t,r);return new Function("escape",i).call(this,e)}}); +!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):e.Leopard=r()}(this,function(){"use strict";var e=function(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")},r=function(e){return e.replace(/"/g,'\\"')};function t(){}var n=t.prototype,i=function(e){return e.split("|").reduce((e,r)=>r.trim()+"("+e.trim()+")")};n.parse=function(e,t){t=t||{};var n=/<%(.+?)%>/g,o=null,u=null,a="var lines = [];\nvar rst;\nwith("+JSON.stringify(t)+") {\n";function s(e){a+="lines.push("+e+");\n"}for(var c=function(e){if(e.length>0)switch(e.charAt(0)){case"=":s("escape("+i(e.substr(1).trim())+")");break;case"-":s(i(e.substr(1).trim()));break;default:a+=e+"\n"}};o=n.exec(e);){var f=e.substring(null!==u?u.index+u[0].length:0,o.index);f&&s('"'+r(f)+'"');var l=o[1].trim();l&&c(l),u=o}var p=e.substr(u.index+u[0].length);return p&&s('"'+r(p)+'"'),a+='rst = lines.join("");\n}\nreturn rst;'},n.compile=function(r,t){var i=this.parse(r,t);return new Function("escape",...Object.keys(n),i).call(n,e,...Object.values(n))};var o=t;var u=function(e,r){if("function"!=typeof r)throw new TypeError('Leopard: filter requires a function as handler, but got "'+typeof r+'" in filter "'+e+'"');if(e in this.prototype)throw new Error('Leopard: filter "'+e+'" has been declared');return this.prototype[e]=r,this},a={capitalize:function(e){return e.charAt(0).toUpperCase()+e.slice(1)},reverse:function(e){return e.split("").reverse().join("")}};o.filter=u;for(var s,c=Object.keys(a),f=0,l=c.length;f