[FIX] prevent crash in case with t-foreach and t-out with components

The t-out directive is compiled internally into a LazyValue, which
represents a value that may or may not be created sometimes in the
future.  It can also be reused more than once, and this is where there
may be an issue: if a component is contained in the lazyvalue, it needs
a unique key (coming from the t-foreach) to be properly indexed in the
parent children map.  However, the LazyValue does not keep the key
information, so it is not able to provide it to its content.

The fix is then quite clear: the LazyValue class should store the key
information, and provides it to its content.  This allows the LazyValue
to be used multiple times, in any place in a template.

closes #1270
This commit is contained in:
Géry Debongnie
2022-09-28 09:34:30 +02:00
committed by Sam Degueldre
parent 669fd622ec
commit 7ab34c5ca5
9 changed files with 110 additions and 27 deletions
@@ -126,7 +126,7 @@ exports[`t-esc t-esc is escaped 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`var\`] = new LazyValue(value1, ctx, this, node);
ctx[\`var\`] = new LazyValue(value1, ctx, this, node, key);
let txt1 = ctx['var'];
return block1([txt1]);
}
@@ -161,7 +161,7 @@ exports[`t-out t-out bdom 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`var\`] = new LazyValue(value1, ctx, this, node);
ctx[\`var\`] = new LazyValue(value1, ctx, this, node, key);
const b3 = safeOutput(ctx['var']);
return block1([], [b3]);
}
@@ -310,7 +310,7 @@ exports[`t-out t-out switch markup on bdom 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
let b3,b5;
ctx[\`bdom\`] = new LazyValue(value1, ctx, this, node);
ctx[\`bdom\`] = new LazyValue(value1, ctx, this, node, key);
if (ctx['hasBdom']) {
const b4 = safeOutput(ctx['bdom']);
b3 = block3([], [b4]);
@@ -106,7 +106,7 @@ exports[`t-set set from body literal (with t-if/t-else 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`value\`] = new LazyValue(value1, ctx, this, node);
ctx[\`value\`] = new LazyValue(value1, ctx, this, node, key);
return text(ctx['value']);
}
}"
@@ -142,7 +142,7 @@ exports[`t-set set from body lookup 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`stuff\`] = new LazyValue(value1, ctx, this, node);
ctx[\`stuff\`] = new LazyValue(value1, ctx, this, node, key);
let txt1 = ctx['stuff'];
return block1([txt1]);
}
@@ -206,7 +206,7 @@ exports[`t-set t-set body is evaluated immediately 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"v1\\", 'before');
ctx[\`v2\`] = new LazyValue(value1, ctx, this, node);
ctx[\`v2\`] = new LazyValue(value1, ctx, this, node, key);
setContextValue(ctx, \\"v1\\", 'after');
const b3 = safeOutput(ctx['v2']);
return block1([], [b3]);
@@ -471,7 +471,7 @@ exports[`t-set t-set with content and sub t-esc 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`setvar\`] = new LazyValue(value1, ctx, this, node);
ctx[\`setvar\`] = new LazyValue(value1, ctx, this, node, key);
let txt1 = ctx['setvar'];
return block1([txt1]);
}
@@ -497,7 +497,7 @@ exports[`t-set t-set with t-value (falsy) and body 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"v3\\", false);
setContextValue(ctx, \\"v1\\", 'before');
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, this, node));
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, this, node, key));
setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", true);
const b3 = safeOutput(ctx['v2']);
@@ -525,7 +525,7 @@ exports[`t-set t-set with t-value (truthy) and body 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"v3\\", 'Truthy');
setContextValue(ctx, \\"v1\\", 'before');
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, this, node));
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, this, node, key));
setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", false);
const b3 = safeOutput(ctx['v2']);
@@ -638,7 +638,7 @@ exports[`t-set value priority (with non text body 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`value\`] = withDefault(1, new LazyValue(value1, ctx, this, node));
ctx[\`value\`] = withDefault(1, new LazyValue(value1, ctx, this, node, key));
let txt1 = ctx['value'];
return block1([txt1]);
}