1import { 2 appendContextPath, 3 blockParams, 4 createFrame, 5 isArray, 6 isFunction 7} from '../utils'; 8import Exception from '../exception'; 9 10export default function(instance) { 11 instance.registerHelper('each', function(context, options) { 12 if (!options) { 13 throw new Exception('Must pass iterator to #each'); 14 } 15 16 let fn = options.fn, 17 inverse = options.inverse, 18 i = 0, 19 ret = '', 20 data, 21 contextPath; 22 23 if (options.data && options.ids) { 24 contextPath = 25 appendContextPath(options.data.contextPath, options.ids[0]) + '.'; 26 } 27 28 if (isFunction(context)) { 29 context = context.call(this); 30 } 31 32 if (options.data) { 33 data = createFrame(options.data); 34 } 35 36 function execIteration(field, index, last) { 37 if (data) { 38 data.key = field; 39 data.index = index; 40 data.first = index === 0; 41 data.last = !!last; 42 43 if (contextPath) { 44 data.contextPath = contextPath + field; 45 } 46 } 47 48 ret = 49 ret + 50 fn(context[field], { 51 data: data, 52 blockParams: blockParams( 53 [context[field], field], 54 [contextPath + field, null] 55 ) 56 }); 57 } 58 59 if (context && typeof context === 'object') { 60 if (isArray(context)) { 61 for (let j = context.length; i < j; i++) { 62 if (i in context) { 63 execIteration(i, i, i === context.length - 1); 64 } 65 } 66 } else if (typeof Symbol === 'function' && context[Symbol.iterator]) { 67 const newContext = []; 68 const iterator = context[Symbol.iterator](); 69 for (let it = iterator.next(); !it.done; it = iterator.next()) { 70 newContext.push(it.value); 71 } 72 context = newContext; 73 for (let j = context.length; i < j; i++) { 74 execIteration(i, i, i === context.length - 1); 75 } 76 } else { 77 let priorKey; 78 79 Object.keys(context).forEach(key => { 80 // We're running the iterations one step out of sync so we can detect 81 // the last iteration without have to scan the object twice and create 82 // an itermediate keys array. 83 if (priorKey !== undefined) { 84 execIteration(priorKey, i - 1); 85 } 86 priorKey = key; 87 i++; 88 }); 89 if (priorKey !== undefined) { 90 execIteration(priorKey, i - 1, true); 91 } 92 } 93 } 94 95 if (i === 0) { 96 ret = inverse(this); 97 } 98 99 return ret; 100 }); 101} 102