diff --git a/CHANGELOG.md b/CHANGELOG.md index e993292..8a5de87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ## Change Log -### 1.6.3 (2015/04/13 18:03 +00:00) +### v1.7.0 (2015/04/18 00:24 +00:00) +- [#133](https://github.com/linkedin/dustjs-helpers/pull/133) Don't require a key for `{@select}` (@sethkinast) +- [#129](https://github.com/linkedin/dustjs-helpers/pull/129) Refactor for 1.7 (@sethkinast) +- [#132](https://github.com/linkedin/dustjs-helpers/pull/132) Drop 0.8 support and bump dust core dependency (@sethkinast) + +### v1.6.3 (2015/04/13 18:03 +00:00) - [#131](https://github.com/linkedin/dustjs-helpers/pull/131) Explicitly check context.stack.tail.head to make sure it is defined (@sethkinast, @rragan) - [#130](https://github.com/linkedin/dustjs-helpers/pull/130) Move to Travis CI Container builds (@sethkinast) - [#127](https://github.com/linkedin/dustjs-helpers/pull/127) Add grunt-github-changes plugin to automatically update changelog before releases (@sethkinast) diff --git a/README.md b/README.md index c4c010a..943d752 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,9 @@ It's possible to write your own helpers and extend the functionality of Dust's t The helpers we provide as part of this repository fulfill some of the most common use cases encountered while using Dust. We provide official support for these helpers as part of the core Dust library. -Read the wiki for more information: - ## Getting Started -The helpers depend on and augment Dust.js.If you need a refresher, read a [quick tutorial on using Dust](https://github.com/linkedin/dustjs/wiki/Dust-Tutorial). +The helpers depend on and augment Dust.js. If you need a refresher, read a [quick tutorial on using Dust](http://www.dustjs.com/guides/getting-started/). -You can look at a [list of the helpers](https://github.com/linkedin/dustjs-helpers/wiki/Helpers) contained in this package, along with usage examples, on the wiki. +You can look at a [list of the helpers](http://www.dustjs.com/guides/dust-helpers/) contained in this package, along with usage examples, on the website. The [changelog](https://github.com/linkedin/dustjs-helpers/blob/master/CHANGELOG.md) documents all added, deprecated, and removed functionality. diff --git a/bower.json b/bower.json index 68e75d8..d430a7f 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "dustjs-helpers", - "version": "1.6.3", + "version": "1.7.0", "homepage": "https://github.com/linkedin/dustjs-helpers", "authors": [ "Veena Basavaraj ", diff --git a/dist/dust-helpers.js b/dist/dust-helpers.js index 580a4d2..e6f0847 100644 --- a/dist/dust-helpers.js +++ b/dist/dust-helpers.js @@ -1,5 +1,5 @@ -/*! dustjs-helpers - v1.6.3 -* https://github.com/linkedin/dustjs-helpers +/*! dustjs-helpers - v1.7.0 +* http://dustjs.com/ * Copyright (c) 2015 Aleksander Williams; Released under the MIT License */ (function(root, factory) { if (typeof define === 'function' && define.amd && define.amd.dust === true) { @@ -11,18 +11,17 @@ } }(this, function(dust) { -// Use dust's built-in logging when available -var _log = dust.log ? function(helper, msg, level) { +function log(helper, msg, level) { level = level || "INFO"; helper = helper ? '{@' + helper + '}: ' : ''; dust.log(helper + msg, level); -} : function() {}; +} var _deprecatedCache = {}; function _deprecated(target) { if(_deprecatedCache[target]) { return; } - _log(target, "Deprecation warning: " + target + " is deprecated and will be removed in a future version of dustjs-helpers", "WARN"); - _log(null, "For help and a deprecation timeline, see https://github.com/linkedin/dustjs-helpers/wiki/Deprecated-Features#" + target.replace(/\W+/g, ""), "WARN"); + log(target, "Deprecation warning: " + target + " is deprecated and will be removed in a future version of dustjs-helpers", "WARN"); + log(null, "For help and a deprecation timeline, see https://github.com/linkedin/dustjs-helpers/wiki/Deprecated-Features#" + target.replace(/\W+/g, ""), "WARN"); _deprecatedCache[target] = true; } @@ -36,101 +35,125 @@ function getSelectState(context) { return isSelect(context) && context.get('__select__'); } -function addSelectState(context, key) { +/** + * Adds a special __select__ key behind the head of the context stack. Used to maintain the state + * of {@select} blocks + * @param context {Context} add state to this Context + * @param opts {Object} add these properties to the state (`key` and `type`) + */ +function addSelectState(context, opts) { var head = context.stack.head, - newContext = context.rebase(); + newContext = context.rebase(), + key; if(context.stack && context.stack.tail) { newContext.stack = context.stack.tail; } + var state = { + isResolved: false, + isDeferredComplete: false, + deferreds: [] + }; + + for(key in opts) { + state[key] = opts[key]; + } + return newContext - .push({ "__select__": { - isResolved: false, - isDefaulted: false, - isDeferredComplete: false, - deferreds: [], - key: key - } - }) + .push({ "__select__": state }) .push(head, context.stack.index, context.stack.of); } -// Utility method : toString() equivalent for functions +/** + * After a {@select} or {@math} block is complete, they invoke this function + */ +function resolveSelectDeferreds(state) { + var x, len; + if(state.deferreds.length) { + state.isDeferredComplete = true; + for(x=0, len=state.deferreds.length; x [] is evaluated to false and empty object -> {} and non-empty object are evaluated to true - The type of the return value is string ( since we concatenate to support interpolated references - - if value does not exist in JSON and the input is a single reference: {x} - dust render emits empty string, and we then return false - - if values does not exist in JSON and the input is interpolated references : {x} < {y} - dust render emits < and we return the partial output - - */ + // uses native Dust Context#resolve (available since Dust 2.6.2) "tap": function(input, chunk, context) { // deprecated for removal in 1.8 _deprecated("tap"); - - // return given input if there is no dust reference to resolve - // dust compiles a string/reference such as {foo} to a function - if (typeof input !== "function") { - return input; - } - - var dustBodyOutput = '', - returnValue; - - //use chunk render to evaluate output. For simple functions result will be returned from render call, - //for dust body functions result will be output via callback function - returnValue = chunk.tap(function(data) { - dustBodyOutput += data; - return ''; - }).render(input, context); - - chunk.untap(); - - //assume it's a simple function call if return result is not a chunk - if (returnValue.constructor !== chunk.constructor) { - //use returnValue as a result of tap - return returnValue; - } else if (dustBodyOutput === '') { - return false; - } else { - return dustBodyOutput; - } + return context.resolve(input); }, "sep": function(chunk, context, bodies) { @@ -215,266 +196,158 @@ var helpers = { }, /** - * contextDump helper - * @param key specifies how much to dump. - * "current" dumps current context. "full" dumps the full context stack. - * @param to specifies where to write dump output. - * Values can be "console" or "output". Default is output. + * {@contextDump} + * @param key {String} set to "full" to the full context stack, otherwise the current context is dumped + * @param to {String} set to "console" to log to console, otherwise outputs to the chunk */ "contextDump": function(chunk, context, bodies, params) { - var p = params || {}, - to = p.to || 'output', - key = p.key || 'current', - dump; - to = dust.helpers.tap(to, chunk, context); - key = dust.helpers.tap(key, chunk, context); - if (key === 'full') { - dump = JSON.stringify(context.stack, jsonFilter, 2); - } - else { - dump = JSON.stringify(context.stack.head, jsonFilter, 2); - } - if (to === 'console') { - _log('contextDump', dump); - return chunk; + var to = context.resolve(params.to), + key = context.resolve(params.key), + target, output; + switch(key) { + case 'full': + target = context.stack; + break; + default: + target = context.stack.head; } - else { - // encode opening brackets when outputting to html - dump = dump.replace(/ |s - @param cond, either a string literal value or a dust reference - a string literal value, is enclosed in double quotes, e.g. cond="2>3" - a dust reference is also enclosed in double quotes, e.g. cond="'{val}'' > 3" - cond argument should evaluate to a valid javascript expression - **/ /** - * math helper - * @param key is the value to perform math against - * @param method is the math method, is a valid string supported by math helper like mod, add, subtract - * @param operand is the second value needed for operations like mod, add, subtract, etc. - * @param round is a flag to assure that an integer is returned + * {@math} + * @param key first value + * @param method {String} operation to perform + * @param operand second value (not required for operations like `abs`) + * @param round if truthy, round() the result */ - "math": function ( chunk, context, bodies, params ) { - //key and method are required for further processing - if( params && typeof params.key !== "undefined" && params.method ){ - var key = params.key, - method = params.method, - // operand can be null for "abs", ceil and floor - operand = params.operand, - round = params.round, - mathOut = null; - - key = parseFloat(dust.helpers.tap(key, chunk, context)); - operand = parseFloat(dust.helpers.tap(operand, chunk, context)); - // TODO: handle and tests for negatives and floats in all math operations - switch(method) { - case "mod": - if(operand === 0 || operand === -0) { - _log("math", "Division by 0", "ERROR"); - } - mathOut = key % operand; - break; - case "add": - mathOut = key + operand; - break; - case "subtract": - mathOut = key - operand; - break; - case "multiply": - mathOut = key * operand; - break; - case "divide": - if(operand === 0 || operand === -0) { - _log("math", "Division by 0", "ERROR"); - } - mathOut = key / operand; - break; - case "ceil": - mathOut = Math.ceil(key); - break; - case "floor": - mathOut = Math.floor(key); - break; - case "round": - mathOut = Math.round(key); - break; - case "abs": - mathOut = Math.abs(key); - break; - case "toint": - mathOut = parseInt(key, 10); - break; - default: - _log("math", "Method `" + method + "` is not supported", "ERROR"); - } - - if (mathOut !== null){ - if (round) { - mathOut = Math.round(mathOut); + "math": function (chunk, context, bodies, params) { + var key = params.key, + method = params.method, + operand = params.operand, + round = params.round, + output, state, x, len; + + if(!params.hasOwnProperty('key') || !params.method) { + log("math", "`key` or `method` was not provided", "ERROR"); + return chunk; + } + + key = parseFloat(context.resolve(key)); + operand = parseFloat(context.resolve(operand)); + + switch(method) { + case "mod": + if(operand === 0) { + log("math", "Division by 0", "ERROR"); } - if (bodies && bodies.block) { - // with bodies act like the select helper with mathOut as the key - // like the select helper bodies['else'] is meaningless and is ignored - context = addSelectState(context, mathOut); - return chunk.render(bodies.block, context); - } else { - // self closing math helper will return the calculated output - return chunk.write(mathOut); + output = key % operand; + break; + case "add": + output = key + operand; + break; + case "subtract": + output = key - operand; + break; + case "multiply": + output = key * operand; + break; + case "divide": + if(operand === 0) { + log("math", "Division by 0", "ERROR"); } - } else { - return chunk; - } - } - // no key parameter and no method - else { - _log("math", "`key` or `method` was not provided", "ERROR"); + output = key / operand; + break; + case "ceil": + case "floor": + case "round": + case "abs": + output = Math[method](key); + break; + case "toint": + output = parseInt(key, 10); + break; + default: + log("math", "Method `" + method + "` is not supported", "ERROR"); } - return chunk; - }, - /** - select helper works with one of the eq/ne/gt/gte/lt/lte/default providing the functionality - of branching conditions - @param key, ( required ) either a string literal value or a dust reference - a string literal value, is enclosed in double quotes, e.g. key="foo" - a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid - @param type (optional), supported types are number, boolean, string, date, context, defaults to string - **/ - "select": function(chunk, context, bodies, params) { - var body = bodies.block, - state, key, len, x; - - if (params.hasOwnProperty("key")) { - key = dust.helpers.tap(params.key, chunk, context); - // bodies['else'] is meaningless and is ignored - if (body) { - context = addSelectState(context, key); - state = getSelectState(context); - chunk = chunk.render(body, context); - // Resolve any deferred blocks (currently just {@any} blocks) - if(state.deferreds.length) { - state.isDeferredComplete = true; - for(x=0, len=state.deferreds.length; x expected; }); - }, - - /** - gte helper, compares the given key is greater than or equal to the expected value - It can be used standalone or in conjunction with select for multiple branching - @param key, The actual key to be compared ( optional when helper used in conjunction with select) - either a string literal value or a dust reference - a string literal value, is enclosed in double quotes, e.g. key="foo" - a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid - @param value, The expected value to compare to, when helper is used standalone or in conjunction with select - @param type (optional), supported types are number, boolean, string, date, context, defaults to string - Note : use type="number" when comparing numeric - **/ - "gte": function(chunk, context, bodies, params) { - params.filterOpType = "gte"; - return filter(chunk, context, bodies, params, function(expected, actual) { return actual >= expected; }); - }, + * Truth test helpers + * @param key a value or reference to use as the left-hand side of comparisons + * @param value a value or reference to use as the right-hand side of comparisons + * @param type if specified, `key` and `value` will be forcibly cast to this type + */ + "eq": truthTest('eq', function(left, right) { + return left === right; + }), + "ne": truthTest('ne', function(left, right) { + return left !== right; + }), + "lt": truthTest('lt', function(left, right) { + return left < right; + }), + "lte": truthTest('lte', function(left, right) { + return left <= right; + }), + "gt": truthTest('gt', function(left, right) { + return left > right; + }), + "gte": truthTest('gte', function(left, right) { + return left >= right; + }), /** * {@any} @@ -486,14 +359,14 @@ var helpers = { var selectState = getSelectState(context); if(!selectState) { - _log("any", "Must be used inside a {@select} block", "ERROR"); + log("any", "Must be used inside a {@select} block", "ERROR"); } else { if(selectState.isDeferredComplete) { - _log("any", "Must not be nested inside {@any} or {@none} block", "ERROR"); + log("any", "Must not be nested inside {@any} or {@none} block", "ERROR"); } else { chunk = chunk.map(function(chunk) { selectState.deferreds.push(function() { - if(selectState.isResolved && !selectState.isDefaulted) { + if(selectState.isResolved) { chunk = chunk.render(bodies.block, context); } chunk.end(); @@ -514,10 +387,10 @@ var helpers = { var selectState = getSelectState(context); if(!selectState) { - _log("none", "Must be used inside a {@select} block", "ERROR"); + log("none", "Must be used inside a {@select} block", "ERROR"); } else { if(selectState.isDeferredComplete) { - _log("none", "Must not be nested inside {@any} or {@none} block", "ERROR"); + log("none", "Must not be nested inside {@any} or {@none} block", "ERROR"); } else { chunk = chunk.map(function(chunk) { selectState.deferreds.push(function() { @@ -533,62 +406,46 @@ var helpers = { }, /** - * {@default} - * Outputs if no truth test inside a {@select} has passed. - * Must be contained inside a {@select} block. - */ - "default": function(chunk, context, bodies, params) { - params.filterOpType = "default"; - // Deprecated for removal in 1.7 - _deprecated("default"); - if(!isSelect(context)) { - _log("default", "Must be used inside a {@select} block", "ERROR"); - return chunk; - } - return filter(chunk, context, bodies, params, function() { return true; }); - }, - - /** - * size helper prints the size of the given key - * Note : size helper is self closing and does not support bodies - * @param key, the element whose size is returned + * {@size} + * Write the size of the target to the chunk + * Falsy values and true have size 0 + * Numbers are returned as-is + * Arrays and Strings have size equal to their length + * Objects have size equal to the number of keys they contain + * Dust bodies are evaluated and the length of the string is returned + * Functions are evaluated and the length of their return value is evaluated + * @param key find the size of this value or reference */ - "size": function( chunk, context, bodies, params ) { - var key, value=0, nr, k; - params = params || {}; - key = params.key; - if (!key || key === true) { //undefined, null, "", 0 + "size": function(chunk, context, bodies, params) { + var key = params.key, + value, k; + + key = context.resolve(params.key); + if (!key || key === true) { value = 0; - } - else if(dust.isArray(key)) { //array + } else if(dust.isArray(key)) { value = key.length; - } - else if (!isNaN(parseFloat(key)) && isFinite(key)) { //numeric values + } else if (!isNaN(parseFloat(key)) && isFinite(key)) { value = key; - } - else if (typeof key === "object") { //object test - //objects, null and array all have typeof ojbect... - //null and array are already tested so typeof is sufficient http://jsperf.com/isobject-tests - nr = 0; + } else if (typeof key === "object") { + value = 0; for(k in key){ - if(Object.hasOwnProperty.call(key,k)){ - nr++; + if(key.hasOwnProperty(k)){ + value++; } } - value = nr; } else { - value = (key + '').length; //any other value (strings etc.) + value = (key + '').length; } return chunk.write(value); } - }; - for(var key in helpers) { - dust.helpers[key] = helpers[key]; - } +for(var key in helpers) { + dust.helpers[key] = helpers[key]; +} - return dust; +return dust; })); diff --git a/dist/dust-helpers.min.js b/dist/dust-helpers.min.js index 7c317dc..2c897e6 100644 --- a/dist/dust-helpers.min.js +++ b/dist/dust-helpers.min.js @@ -1,4 +1,4 @@ -/*! dustjs-helpers - v1.6.3 -* https://github.com/linkedin/dustjs-helpers +/*! dustjs-helpers - v1.7.0 +* http://dustjs.com/ * Copyright (c) 2015 Aleksander Williams; Released under the MIT License */ -!function(a,b){"function"==typeof define&&define.amd&&define.amd.dust===!0?define(["dust.core"],b):"object"==typeof exports?module.exports=b(require("dustjs-linkedin")):b(a.dust)}(this,function(dust){function a(a){i[a]||(h(a,"Deprecation warning: "+a+" is deprecated and will be removed in a future version of dustjs-helpers","WARN"),h(null,"For help and a deprecation timeline, see https://github.com/linkedin/dustjs-helpers/wiki/Deprecated-Features#"+a.replace(/\W+/g,""),"WARN"),i[a]=!0)}function b(a){return a.stack.tail&&a.stack.tail.head&&"undefined"!=typeof a.stack.tail.head.__select__}function c(a){return b(a)&&a.get("__select__")}function d(a,b){var c=a.stack.head,d=a.rebase();return a.stack&&a.stack.tail&&(d.stack=a.stack.tail),d.push({__select__:{isResolved:!1,isDefaulted:!1,isDeferredComplete:!1,deferreds:[],key:b}}).push(c,a.stack.index,a.stack.of)}function e(a,b){return"function"==typeof b?b.toString().replace(/(^\s+|\s+$)/gm,"").replace(/\n/gm,"").replace(/,\s*/gm,", ").replace(/\)\{/gm,") {"):b}function f(a,b,d,e,f){e=e||{};var i,j,k=d.block,l=c(b),m=e.filterOpType||"";if(e.hasOwnProperty("key"))i=dust.helpers.tap(e.key,a,b);else{if(!l)return h(m,"No key specified","WARN"),a;i=l.key,l.isResolved&&(f=function(){return!1})}return j=dust.helpers.tap(e.value,a,b),f(g(j,e.type,b),g(i,e.type,b))?(l&&("default"===m&&(l.isDefaulted=!0),l.isResolved=!0),k?a.render(k,b):a):d["else"]?a.render(d["else"],b):a}function g(a,b,c){if("undefined"!=typeof a)switch(b||typeof a){case"number":return+a;case"string":return String(a);case"boolean":return a="false"===a?!1:a,Boolean(a);case"date":return new Date(a);case"context":return c.get(a)}return a}var h=dust.log?function(a,b,c){c=c||"INFO",a=a?"{@"+a+"}: ":"",dust.log(a+b,c)}:function(){},i={},j={tap:function(b,c,d){if(a("tap"),"function"!=typeof b)return b;var e,f="";return e=c.tap(function(a){return f+=a,""}).render(b,d),c.untap(),e.constructor!==c.constructor?e:""===f?!1:f},sep:function(a,b,c){var d=c.block;return b.stack.index===b.stack.of-1?a:d?d(a,b):a},first:function(a,b,c){return 0===b.stack.index?c.block(a,b):a},last:function(a,b,c){return b.stack.index===b.stack.of-1?c.block(a,b):a},contextDump:function(a,b,c,d){var f,g=d||{},i=g.to||"output",j=g.key||"current";return i=dust.helpers.tap(i,a,b),j=dust.helpers.tap(j,a,b),f="full"===j?JSON.stringify(b.stack,e,2):JSON.stringify(b.stack.head,e,2),"console"===i?(h("contextDump",f),a):(f=f.replace(/k;k++)g.deferreds[k]()}else h("select","Missing body block","WARN");else h("select","`key` is required","ERROR");return a},eq:function(a,b,c,d){return d.filterOpType="eq",f(a,b,c,d,function(a,b){return b===a})},ne:function(a,b,c,d){return d.filterOpType="ne",f(a,b,c,d,function(a,b){return b!==a})},lt:function(a,b,c,d){return d.filterOpType="lt",f(a,b,c,d,function(a,b){return a>b})},lte:function(a,b,c,d){return d.filterOpType="lte",f(a,b,c,d,function(a,b){return a>=b})},gt:function(a,b,c,d){return d.filterOpType="gt",f(a,b,c,d,function(a,b){return b>a})},gte:function(a,b,c,d){return d.filterOpType="gte",f(a,b,c,d,function(a,b){return b>=a})},any:function(a,b,d,e){var f=c(b);return f?f.isDeferredComplete?h("any","Must not be nested inside {@any} or {@none} block","ERROR"):a=a.map(function(a){f.deferreds.push(function(){f.isResolved&&!f.isDefaulted&&(a=a.render(d.block,b)),a.end()})}):h("any","Must be used inside a {@select} block","ERROR"),a},none:function(a,b,d,e){var f=c(b);return f?f.isDeferredComplete?h("none","Must not be nested inside {@any} or {@none} block","ERROR"):a=a.map(function(a){f.deferreds.push(function(){f.isResolved||(a=a.render(d.block,b)),a.end()})}):h("none","Must be used inside a {@select} block","ERROR"),a},"default":function(c,d,e,g){return g.filterOpType="default",a("default"),b(d)?f(c,d,e,g,function(){return!0}):(h("default","Must be used inside a {@select} block","ERROR"),c)},size:function(a,b,c,d){var e,f,g,h=0;if(d=d||{},e=d.key,e&&e!==!0)if(dust.isArray(e))h=e.length;else if(!isNaN(parseFloat(e))&&isFinite(e))h=e;else if("object"==typeof e){f=0;for(g in e)Object.hasOwnProperty.call(e,g)&&f++;h=f}else h=(e+"").length;else h=0;return a.write(h)}};for(var k in j)dust.helpers[k]=j[k];return dust}); \ No newline at end of file +!function(a,b){"function"==typeof define&&define.amd&&define.amd.dust===!0?define(["dust.core"],b):"object"==typeof exports?module.exports=b(require("dustjs-linkedin")):b(a.dust)}(this,function(dust){function a(a,b,c){c=c||"INFO",a=a?"{@"+a+"}: ":"",dust.log(a+b,c)}function b(b){k[b]||(a(b,"Deprecation warning: "+b+" is deprecated and will be removed in a future version of dustjs-helpers","WARN"),a(null,"For help and a deprecation timeline, see https://github.com/linkedin/dustjs-helpers/wiki/Deprecated-Features#"+b.replace(/\W+/g,""),"WARN"),k[b]=!0)}function c(a){return a.stack.tail&&a.stack.tail.head&&"undefined"!=typeof a.stack.tail.head.__select__}function d(a){return c(a)&&a.get("__select__")}function e(a,b){var c,d=a.stack.head,e=a.rebase();a.stack&&a.stack.tail&&(e.stack=a.stack.tail);var f={isResolved:!1,isDeferredComplete:!1,deferreds:[]};for(c in b)f[c]=b[c];return e.push({__select__:f}).push(d,a.stack.index,a.stack.of)}function f(a){var b,c;if(a.deferreds.length)for(a.isDeferredComplete=!0,b=0,c=a.deferreds.length;c>b;b++)a.deferreds[b]()}function g(a,b){return"function"==typeof b?b.toString().replace(/(^\s+|\s+$)/gm,"").replace(/\n/gm,"").replace(/,\s*/gm,", ").replace(/\)\{/gm,") {"):b}function h(a,b){return function(c,d,e,f){return i(c,d,e,f,a,b)}}function i(b,c,e,f,g,h){var i,k,l,m=e.block,n=e["else"],o=d(c)||{};if(o.isResolved)return b;if(f.hasOwnProperty("key"))i=f.key;else{if(!o.hasOwnProperty("key"))return a(g,"No key specified","WARN"),b;i=o.key}if(l=f.type||o.type,i=j(c.resolve(i),l),k=j(c.resolve(f.value),l),h(i,k)){if(o&&(o.isResolved=!0),m)return b.render(m,c)}else if(n)return b.render(n,c);return b}function j(a,b){switch(b&&(b=b.toLowerCase()),b){case"number":return+a;case"string":return String(a);case"boolean":return a="false"===a?!1:a,Boolean(a);case"date":return new Date(a)}return a}var k={},l={tap:function(a,c,d){return b("tap"),d.resolve(a)},sep:function(a,b,c){var d=c.block;return b.stack.index===b.stack.of-1?a:d?d(a,b):a},first:function(a,b,c){return 0===b.stack.index?c.block(a,b):a},last:function(a,b,c){return b.stack.index===b.stack.of-1?c.block(a,b):a},contextDump:function(b,c,d,e){var f,h,i=c.resolve(e.to),j=c.resolve(e.key);switch(j){case"full":f=c.stack;break;default:f=c.stack.head}switch(h=JSON.stringify(f,g,2),i){case"console":a("contextDump",h);break;default:h=h.replace(/a}),lte:h("lte",function(a,b){return b>=a}),gt:h("gt",function(a,b){return a>b}),gte:h("gte",function(a,b){return a>=b}),any:function(b,c,e,f){var g=d(c);return g?g.isDeferredComplete?a("any","Must not be nested inside {@any} or {@none} block","ERROR"):b=b.map(function(a){g.deferreds.push(function(){g.isResolved&&(a=a.render(e.block,c)),a.end()})}):a("any","Must be used inside a {@select} block","ERROR"),b},none:function(b,c,e,f){var g=d(c);return g?g.isDeferredComplete?a("none","Must not be nested inside {@any} or {@none} block","ERROR"):b=b.map(function(a){g.deferreds.push(function(){g.isResolved||(a=a.render(e.block,c)),a.end()})}):a("none","Must be used inside a {@select} block","ERROR"),b},size:function(a,b,c,d){var e,f,g=d.key;if(g=b.resolve(d.key),g&&g!==!0)if(dust.isArray(g))e=g.length;else if(!isNaN(parseFloat(g))&&isFinite(g))e=g;else if("object"==typeof g){e=0;for(f in g)g.hasOwnProperty(f)&&e++}else e=(g+"").length;else e=0;return a.write(e)}};for(var m in l)dust.helpers[m]=l[m];return dust}); \ No newline at end of file diff --git a/gruntfile.js b/gruntfile.js index 4b4cae2..adf95ed 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -196,7 +196,7 @@ module.exports = function (grunt) { options: { owner: "linkedin", repository: "dustjs-helpers", - tagName: "<%= pkg.version %>", + tagName: "v<%= pkg.version %>", onlyPulls: true, useCommitBody: true, auth: true diff --git a/package.json b/package.json index 67aacca..8f0d1aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dustjs-helpers", - "version": "1.6.3", + "version": "1.7.0", "author": { "name": "Aleksander Williams", "url": "http://akdubya.github.com/dustjs"