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