1/*! dustjs-helpers - v1.2.0 2* https://github.com/linkedin/dustjs-helpers 3* Copyright (c) 2014 Aleksander Williams; Released under the MIT License */ 4(function(dust){ 5 6 // Note: all error conditions are logged to console and failed silently 7 8 /* make a safe version of console if it is not available 9 * currently supporting: 10 * _console.log 11 * */ 12 var _console = (typeof console !== 'undefined')? console: { 13 log: function(){ 14 /* a noop*/ 15 } 16 }; 17 18 function isSelect(context) { 19 var value = context.current(); 20 return typeof value === "object" && value.isSelect === true; 21 } 22 23 // Utility method : toString() equivalent for functions 24 function jsonFilter(key, value) { 25 if (typeof value === "function") { 26 //to make sure all environments format functions the same way 27 return value.toString() 28 //remove all leading and trailing whitespace 29 .replace(/(^\s+|\s+$)/mg, '') 30 //remove new line characters 31 .replace(/\n/mg, '') 32 //replace , and 0 or more spaces with ", " 33 .replace(/,\s*/mg, ', ') 34 //insert space between ){ 35 .replace(/\)\{/mg, ') {') 36 ; 37 } 38 return value; 39 } 40 41 // Utility method: to invoke the given filter operation such as eq/gt etc 42 function filter(chunk, context, bodies, params, filterOp) { 43 params = params || {}; 44 var body = bodies.block, 45 actualKey, 46 expectedValue, 47 filterOpType = params.filterOpType || ''; 48 // when @eq, @lt etc are used as standalone helpers, key is required and hence check for defined 49 if ( typeof params.key !== "undefined") { 50 actualKey = dust.helpers.tap(params.key, chunk, context); 51 } 52 else if (isSelect(context)) { 53 actualKey = context.current().selectKey; 54 // supports only one of the blocks in the select to be selected 55 if (context.current().isResolved) { 56 filterOp = function() { return false; }; 57 } 58 } 59 else { 60 _console.log ("No key specified for filter in:" + filterOpType + " helper "); 61 return chunk; 62 } 63 expectedValue = dust.helpers.tap(params.value, chunk, context); 64 // coerce both the actualKey and expectedValue to the same type for equality and non-equality compares 65 if (filterOp(coerce(expectedValue, params.type, context), coerce(actualKey, params.type, context))) { 66 if (isSelect(context)) { 67 context.current().isResolved = true; 68 } 69 // we want helpers without bodies to fail gracefully so check it first 70 if(body) { 71 return chunk.render(body, context); 72 } 73 else { 74 _console.log( "Missing body block in the " + filterOpType + " helper "); 75 return chunk; 76 } 77 } 78 else if (bodies['else']) { 79 return chunk.render(bodies['else'], context); 80 } 81 return chunk; 82 } 83 84 function coerce (value, type, context) { 85 if (value) { 86 switch (type || typeof(value)) { 87 case 'number': return +value; 88 case 'string': return String(value); 89 case 'boolean': { 90 value = (value === 'false' ? false : value); 91 return Boolean(value); 92 } 93 case 'date': return new Date(value); 94 case 'context': return context.get(value); 95 } 96 } 97 98 return value; 99 } 100 101 var helpers = { 102 103 // Utility helping to resolve dust references in the given chunk 104 // uses the Chunk.render method to resolve value 105 /* 106 Reference resolution rules: 107 if value exists in JSON: 108 "" or '' will evaluate to false, boolean false, null, or undefined will evaluate to false, 109 numeric 0 evaluates to true, so does, string "0", string "null", string "undefined" and string "false". 110 Also note that empty array ->
110 [] is evaluated to false and empty object -> {} and non-empty object are evaluated to true 111 The type of the return value is string ( since we concatenate to support interpolated references 112 113 if value does not exist in JSON and the input is a single reference: {x} 114 dust render emits empty string, and we then return false 115 116 if values does not exist in JSON and the input is interpolated references : {x} < {y} 117 dust render emits < and we return the partial output 118 119 */ 120 "tap": function(input, chunk, context) { 121 // return given input if there is no dust reference to resolve 122 // dust compiles a string/reference such as {foo} to a function 123 if (typeof input !== "function") { 124 return input; 125 } 126 127 var dustBodyOutput = '', 128 returnValue; 129 130 //use chunk render to evaluate output. For simple functions result will be returned from render call, 131 //for dust body functions result will be output via callback function 132 returnValue = chunk.tap(function(data) { 133 dustBodyOutput += data; 134 return ''; 135 }).render(input, context); 136 137 chunk.untap(); 138 139 //assume it's a simple function call if return result is not a chunk 140 if (returnValue.constructor !== chunk.constructor) { 141 //use returnValue as a result of tap 142 return returnValue; 143 } else if (dustBodyOutput === '') { 144 return false; 145 } else { 146 return dustBodyOutput; 147 } 148 }, 149 150 "sep": function(chunk, context, bodies) { 151 var body = bodies.block; 152 if (context.stack.index === context.stack.of - 1) { 153 return chunk; 154 } 155 if(body) { 156 return bodies.block(chunk, context); 157 } 158 else { 159 return chunk; 160 } 161 }, 162 163 "idx": function(chunk, context, bodies) { 164 var body = bodies.block; 165 if(body) { 166 return bodies.block(chunk, context.push(context.stack.index)); 167 } 168 else { 169 return chunk; 170 } 171 }, 172 173 /** 174 * contextDump helper 175 * @param key specifies how much to dump. 176 * "current" dumps current context. "full" dumps the full context stack. 177 * @param to specifies where to write dump output. 178 * Values can be "console" or "output". Default is output. 179 */ 180 "contextDump": function(chunk, context, bodies, params) { 181 var p = params || {}, 182 to = p.to || 'output', 183 key = p.key || 'current', 184 dump; 185 to = dust.helpers.tap(to, chunk, context); 186 key = dust.helpers.tap(key, chunk, context); 187 if (key === 'full') { 188 dump = JSON.stringify(context.stack, jsonFilter, 2); 189 } 190 else { 191 dump = JSON.stringify(context.stack.head, jsonFilter, 2); 192 } 193 if (to === 'console') { 194 _console.log(dump); 195 return chunk; 196 } 197 else { 198 return chunk.write(dump); 199 } 200 }, 201 /** 202 if helper for complex evaluation complex logic expressions. 203 Note : #1 if helper fails gracefully when there is no body block nor else block 204 #2 Undefined values and false values in the JSON need to be handled specially with .length check 205 for e.g @if cond=" '{a}'.length && '{b}'.length" is advised when there are chances of the a and b been 206 undefined or false in the context 207 #3 Use only when the default ? and ^ dust operators and the select fall short in addressing the given logic, 208 since eval executes in the global scope 209 #4 All dust references are default escaped as they are resolved, hence eval will block malicious scripts in the context 210 Be mindful of evaluating a expression that is passed through the unescape filter -> |s 211 @param cond, either a string literal value or a dust reference 212 a string literal value, is enclosed in double quotes, e.g. cond="2>3" 213 a dust reference is also enclosed in double quotes, e.g. cond="'{val}'' > 3" 214 cond argument should evaluate to a valid javascript expression 215 **/ 216 217 "if": function( chunk, context, bodies, params ){ 218 var body = bodies.block, 219 skip = bodies['else']; 220 if( params && params.cond){ 221 var cond = params.cond; 222 cond = dust.helpers.tap(cond, chunk, context); 223 // eval expressions with given dust references 224 if(eval(cond)){ 225 if(body) { 226 return chunk.render( bodies.block, context ); 227 } 228 else { 229 _console.log( "Missing body block in the if helper!" ); 230 return chunk; 231 } 232 } 233 if(skip){ 234 return chunk.render( bodies['else'], context ); 235 } 236 } 237 // no condition 238 else { 239 _console.log( "No condition given in the if helper!" ); 240 } 241 return chunk; 242 }, 243 244 /** 245 * math helper 246 * @param key is the value to perform math against 247 * @param method is the math method, is a valid string supported by math helper like mod, add, subtract 248 * @param operand is the second value needed for operations like mod, add, subtract, etc. 249 * @param round is a flag to assure that an integer is returned 250 */ 251 "math": function ( chunk, context, bodies, params ) { 252 //key and method are required for further processing 253 if( params && typeof params.key !== "undefined" && params.method ){ 254 var key = params.key, 255 method = params.method, 256 // operand can be null for "abs", ceil and floor 257 operand = params.operand, 258 round = params.round, 259 mathOut = null, 260 operError = function(){_console.log("operand is required for this math method"); return null;}; 261 key = dust.helpers.tap(key, chunk, context); 262 operand = dust.helpers.tap(operand, chunk, context); 263 // TODO: handle and tests for negatives and floats in all math operations
264 switch(method) { 265 case "mod": 266 if(operand === 0 || operand === -0) { 267 _console.log("operand for divide operation is 0/-0: expect Nan!"); 268 } 269 mathOut = parseFloat(key) % parseFloat(operand); 270 break; 271 case "add": 272 mathOut = parseFloat(key) + parseFloat(operand); 273 break; 274 case "subtract": 275 mathOut = parseFloat(key) - parseFloat(operand); 276 break; 277 case "multiply": 278 mathOut = parseFloat(key) * parseFloat(operand); 279 break; 280 case "divide": 281 if(operand === 0 || operand === -0) { 282 _console.log("operand for divide operation is 0/-0: expect Nan/Infinity!"); 283 } 284 mathOut = parseFloat(key) / parseFloat(operand); 285 break; 286 case "ceil": 287 mathOut = Math.ceil(parseFloat(key)); 288 break; 289 case "floor": 290 mathOut = Math.floor(parseFloat(key)); 291 break; 292 case "round": 293 mathOut = Math.round(parseFloat(key)); 294 break; 295 case "abs": 296 mathOut = Math.abs(parseFloat(key)); 297 break; 298 default: 299 _console.log( "method passed is not supported" ); 300 } 301 302 if (mathOut !== null){ 303 if (round) { 304 mathOut = Math.round(mathOut); 305 } 306 if (bodies && bodies.block) { 307 // with bodies act like the select helper with mathOut as the key 308 // like the select helper bodies['else'] is meaningless and is ignored 309 return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: mathOut })); 310 } else { 311 // self closing math helper will return the calculated output 312 return chunk.write(mathOut); 313 } 314 } else { 315 return chunk; 316 } 317 } 318 // no key parameter and no method 319 else { 320 _console.log( "Key is a required parameter for math helper along with method/operand!" ); 321 } 322 return chunk; 323 }, 324 /** 325 select helper works with one of the eq/ne/gt/gte/lt/lte/default providing the functionality 326 of branching conditions 327 @param key, ( required ) either a string literal value or a dust reference 328 a string literal value, is enclosed in double quotes, e.g. key="foo" 329 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 330 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 331 **/ 332 "select": function(chunk, context, bodies, params) { 333 var body = bodies.block; 334 // key is required for processing, hence check for defined 335 if( params && typeof params.key !== "undefined"){ 336 // returns given input as output, if the input is not a dust reference, else does a context lookup 337 var key = dust.helpers.tap(params.key, chunk, context); 338 // bodies['else'] is meaningless and is ignored 339 if( body ) { 340 return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: key })); 341 } 342 else { 343 _console.log( "Missing body block in the select helper "); 344 return chunk; 345 } 346 } 347 // no key 348 else { 349 _console.log( "No key given in the select helper!" ); 350 } 351 return chunk; 352 }, 353 354 /** 355 eq helper compares the given key is same as the expected value 356 It can be used standalone or in conjunction with select for multiple branching 357 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 358 either a string literal value or a dust reference 359 a string literal value, is enclosed in double quotes, e.g. key="foo" 360 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 361 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 362 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 363 Note : use type="number" when comparing numeric 364 **/ 365 "eq": function(chunk, context, bodies, params) { 366 if(params) { 367 params.filterOpType = "eq"; 368 } 369 return filter(chunk, context, bodies, params, function(expected, actual) { return actual === expected; }); 370 }, 371 372 /** 373 ne helper compares the given key is not the same as the expected value 374 It can be used standalone or in conjunction with select for multiple branching 375 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 376 either a string literal value or a dust reference 377 a string literal value, is enclosed in double quotes, e.g. key="foo" 378 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 379 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 380 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 381 Note : use type="number" when comparing numeric 382 **/ 383 "ne": function(chunk, context, bodies, params) { 384 if(params) { 385 params.filterOpType = "ne"; 386 return filter(chunk, context, bodies, params, function(expected, actual) { return actual !== expected; }); 387 } 388 return chunk; 389 }, 390 391 /** 392 lt helper compares the given key is less than the expected value 393 It can be used standalone or in conjunction with select for multiple branching 394 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 395 either a string literal value or a dust reference 396 a string literal value, is enclosed in double quotes, e.g. key="foo" 397 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 398 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 399 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 400 Note : use type="number" when comparing numeric 401 **/ 402 "lt": function(chunk, context, bodies, params) { 403 if(params) { 404 params.filterOpType = "lt"; 405 return filter(chunk, context, bodies, params, function(expected, actual) { return actual < expected; }); 406 } 407 }, 408 409 /** 410 lte helper compares the given key is less or equal to the expected value 411 It can be used standalone or in conjunction with select for multiple branching 412 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 413 either a string literal value or a dust reference 414 a string literal value, is enclosed in double quotes, e.g. key="foo" 415 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 416 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 417 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 418 Note : use type="number" when comparing numeric 419 **/ 420 "lte": function(chunk, context, bodies, params) { 421 if(params) { 422 params.filterOpType = "lte"; 423 return filter(chunk, context, bodies, params, function(expected, actual) { return actual <= expected; }); 424 } 425 return chunk; 426 }, 427 428 429 /** 430 gt helper compares the given key is greater than the expected value 431 It can be used standalone or in conjunction with select for multiple branching 432 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 433 either a string literal value or a dust reference 434 a string literal value, is enclosed in double quotes, e.g. key="foo" 435 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 436 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 437 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 438 Note : use type="number" when comparing numeric 439 **/ 440 "gt": function(chunk, context, bodies, params) { 441 // if no params do no go further 442 if(params) { 443 params.filterOpType = "gt"; 444 return filter(chunk, context, bodies, params, function(expected, actual) { return actual > expected; }); 445 } 446 return chunk; 447 }, 448 449 /** 450 gte helper, compares the given key is greater than or equal to the expected value 451 It can be used standalone or in conjunction with select for multiple branching 452 @param key, The actual key to be compared ( optional when helper used in conjunction with select) 453 either a string literal value or a dust reference 454 a string literal value, is enclosed in double quotes, e.g. key="foo" 455 a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid 456 @param value, The expected value to compare to, when helper is used standalone or in conjunction with select 457 @param type (optional), supported types are number, boolean, string, date, context, defaults to string 458 Note : use type="number" when comparing numeric 459 **/ 460 "gte": function(chunk, context, bodies, params) { 461 if(params) { 462 params.filterOpType = "gte"; 463 return filter(chunk, context, bodies, params, function(expected, actual) { return actual >= expected; }); 464 } 465 return chunk; 466 }, 467 468 // to be used in conjunction with the select helper
469 // TODO: fix the helper to do nothing when used standalone 470 "default": function(chunk, context, bodies, params) { 471 // does not require any params 472 if(params) { 473 params.filterOpType = "default"; 474 } 475 return filter(chunk, context, bodies, params, function(expected, actual) { return true; }); 476 }, 477 478 /** 479 * size helper prints the size of the given key 480 * Note : size helper is self closing and does not support bodies 481 * @param key, the element whose size is returned 482 */ 483 "size": function( chunk, context, bodies, params ) { 484 var key, value=0, nr, k; 485 params = params || {}; 486 key = params.key; 487 if (!key || key === true) { //undefined, null, "", 0 488 value = 0; 489 } 490 else if(dust.isArray(key)) { //array 491 value = key.length; 492 } 493 else if (!isNaN(parseFloat(key)) && isFinite(key)) { //numeric values 494 value = key; 495 } 496 else if (typeof key === "object") { //object test 497 //objects, null and array all have typeof ojbect... 498 //null and array are already tested so typeof is sufficient http://jsperf.com/isobject-tests 499 nr = 0; 500 for(k in key){ 501 if(Object.hasOwnProperty.call(key,k)){ 502 nr++; 503 } 504 } 505 value = nr; 506 } else { 507 value = (key + '').length; //any other value (strings etc.) 508 } 509 return chunk.write(value); 510 } 511 512 513 }; 514 515 dust.helpers = helpers; 516 517 })(typeof exports !== 'undefined' ? module.exports = require('dustjs-linkedin') : dust); 518
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.