Skip to content

Commit

Permalink
Support Map for iteration and nested paths
Browse files Browse the repository at this point in the history
  • Loading branch information
karlvr committed Apr 16, 2020
1 parent 3789a30 commit 2f61200
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 10 deletions.
23 changes: 13 additions & 10 deletions lib/handlebars/helpers/each.js
Expand Up @@ -33,7 +33,7 @@ export default function(instance) {
data = createFrame(options.data);
}

function execIteration(field, index, last) {
function execIteration(field, value, index, last) {
if (data) {
data.key = field;
data.index = index;
Expand All @@ -47,22 +47,25 @@ export default function(instance) {

ret =
ret +
fn(context[field], {
fn(value, {
data: data,
blockParams: blockParams(
[context[field], field],
[contextPath + field, null]
)
blockParams: blockParams([value, field], [contextPath + field, null])
});
}

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);
execIteration(i, context[i], i, i === context.length - 1);
}
}
} else if (context instanceof Map) {
const j = context.size - 1;
for (const [key, value] of context) {
execIteration(key, value, i, i === j);
i++;
}
} else if (global.Symbol && context[global.Symbol.iterator]) {
const newContext = [];
const iterator = context[global.Symbol.iterator]();
Expand All @@ -71,7 +74,7 @@ export default function(instance) {
}
context = newContext;
for (let j = context.length; i < j; i++) {
execIteration(i, i, i === context.length - 1);
execIteration(i, context[i], i, i === context.length - 1);
}
} else {
let priorKey;
Expand All @@ -81,13 +84,13 @@ export default function(instance) {
// the last iteration without have to scan the object twice and create
// an itermediate keys array.
if (priorKey !== undefined) {
execIteration(priorKey, i - 1);
execIteration(priorKey, context[priorKey], i - 1);
}
priorKey = key;
i++;
});
if (priorKey !== undefined) {
execIteration(priorKey, i - 1, true);
execIteration(priorKey, context[priorKey], i - 1, true);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/handlebars/runtime.js
Expand Up @@ -127,6 +127,9 @@ export function template(templateSpec, env) {
return obj[name];
},
lookupProperty: function(parent, propertyName) {
if (parent instanceof Map) {
return parent.get(propertyName);
}
let result = parent[propertyName];
if (result == null) {
return result;
Expand Down
11 changes: 11 additions & 0 deletions spec/basic.js
Expand Up @@ -394,6 +394,17 @@ describe('basic context', function() {
);
});

it('nested paths with Map', function() {
var map = new Map();
map.set('expression', 'beautiful');
shouldCompileTo(
'Goodbye {{foo/expression}} world!',
{ foo: map },
'Goodbye beautiful world!',
'Nested paths access nested objects'
);
});

it('nested paths with empty string value', function() {
shouldCompileTo(
'Goodbye {{alan/expression}} world!',
Expand Down
23 changes: 23 additions & 0 deletions spec/builtins.js
Expand Up @@ -551,6 +551,29 @@ describe('builtin helpers', function() {
);
});
}

it('each on Map and @key', function() {
var goodbyes = new Map();
goodbyes.set('first', 'goodbye');
goodbyes.set('second', 'Goodbye');
goodbyes.set('last', 'GOODBYE');
var goodbyesEmpty = new Map();
var string =
'{{#each goodbyes}}{{@key}}. {{.}}! {{/each}}cruel {{world}}!';
var hash = { goodbyes: goodbyes, world: 'world' };
shouldCompileTo(
string,
hash,
'first. goodbye! second. Goodbye! last. GOODBYE! cruel world!',
'each with map argument iterates over entries when not empty'
);
shouldCompileTo(
string,
{ goodbyes: goodbyesEmpty, world: 'world' },
'cruel world!',
'each with map argument ignores the contents when empty'
);
});
});

describe('#log', function() {
Expand Down

0 comments on commit 2f61200

Please sign in to comment.