Files
handlebars.js/lib/handlebars/helpers/each.js
T
Chris Garrett 19bdace85a [FEAT] Extract the Handlebars parser (#1713)
Extracts the parser to `@handlebars/parser`, where it can be shared
between different implementations. This means that e.g. Glimmer/Ember
will be able to iterate on new features without forcing Handlebars to
adopt them immediately, and vice versa. All implementors will be able to
absorb changes as it makes sense for them.
2021-02-15 08:56:25 +01:00

83 lines
2.1 KiB
JavaScript

import { Exception } from '@handlebars/parser';
import { createFrame, isArray, isFunction } 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, index, last) {
if (data) {
data.key = field;
data.index = index;
data.first = index === 0;
data.last = !!last;
}
ret =
ret +
fn(context[field], {
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, i, i === context.length - 1);
}
}
} else if (global.Symbol && context[global.Symbol.iterator]) {
const newContext = [];
const iterator = context[global.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, 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 itermediate keys array.
if (priorKey !== undefined) {
execIteration(priorKey, i - 1);
}
priorKey = key;
i++;
});
if (priorKey !== undefined) {
execIteration(priorKey, i - 1, true);
}
}
}
if (i === 0) {
ret = inverse(this);
}
return ret;
});
}