diff --git a/src/app/template_helpers.ts b/src/app/template_helpers.ts index fe055377..e97d8707 100644 --- a/src/app/template_helpers.ts +++ b/src/app/template_helpers.ts @@ -27,14 +27,14 @@ function callSlot( if (__scope) { slotScope[__scope] = extra || {}; } - const slotBDom = __render ? __render(slotScope, parent, key) : null; + const slotBDom = __render ? __render.call(__ctx.__owl__.component, slotScope, parent, key) : null; if (defaultContent) { let child1: BDom | undefined = undefined; let child2: BDom | undefined = undefined; if (slotBDom) { child1 = dynamic ? toggler(name, slotBDom) : slotBDom; } else { - child2 = defaultContent(ctx, parent, key); + child2 = defaultContent.call(ctx.__owl__.component, ctx, parent, key); } return multi([child1, child2]); } diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index f77360f7..33927ccd 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -137,7 +137,6 @@ function createContext(parentCtx: Context, params?: Partial) { class CodeTarget { name: string; - signature: string = ""; indentLevel = 0; loopLevel = 0; code: string[] = []; @@ -334,7 +333,7 @@ export class CodeGenerator { generateFunctions(fn: CodeTarget) { this.addLine(""); - this.addLine(`const ${fn.name} = ${fn.signature}`); + this.addLine(`function ${fn.name}(ctx, node, key) {`); if (fn.hasCache) { this.addLine(`let cache = ctx.cache || {};`); this.addLine(`let nextCache = ctx.cache = {};`); @@ -988,7 +987,6 @@ export class CodeGenerator { for (let slotName in ast.slots) { let name = this.generateId("slot"); const slot = new CodeTarget(name); - slot.signature = "(ctx, node, key) => {"; this.functions.push(slot); this.target = slot; const subCtx: Context = createContext(ctx); @@ -1097,7 +1095,6 @@ export class CodeGenerator { if (ast.defaultContent) { let name = this.generateId("defaultContent"); const slot = new CodeTarget(name); - slot.signature = "(ctx, node, key) => {"; this.functions.push(slot); const initialTarget = this.target; const subCtx: Context = createContext(ctx); diff --git a/tests/components/__snapshots__/error_handling.test.ts.snap b/tests/components/__snapshots__/error_handling.test.ts.snap index 745a9d6b..478a6cb2 100644 --- a/tests/components/__snapshots__/error_handling.test.ts.snap +++ b/tests/components/__snapshots__/error_handling.test.ts.snap @@ -120,7 +120,7 @@ exports[`can catch errors can catch an error in a component render function 3`] let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {flag: ctx['state'].flag}, key + \`__2\`, node, ctx); } @@ -221,7 +221,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3 = component(\`ClassicCompoent\`, {}, key + \`__2\`, node, ctx); let b4 = component(\`ErrorComponent\`, {}, key + \`__3\`, node, ctx); return multi([b3, b4]); @@ -242,7 +242,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); } @@ -296,7 +296,7 @@ exports[`can catch errors can catch an error in the initial call of a component let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); } @@ -350,7 +350,7 @@ exports[`can catch errors can catch an error in the initial call of a component let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); } @@ -406,7 +406,7 @@ exports[`can catch errors can catch an error in the mounted call 3`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); } @@ -460,7 +460,7 @@ exports[`can catch errors can catch an error in the willPatch call 3`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {message: ctx['state'].message}, key + \`__2\`, node, ctx); } @@ -514,7 +514,7 @@ exports[`can catch errors can catch an error in the willStart call 3`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); } @@ -581,7 +581,7 @@ exports[`can catch errors can catch an error origination from a child's willStar let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3 = component(\`ClassicCompoent\`, {}, key + \`__2\`, node, ctx); let b4 = component(\`ErrorComponent\`, {}, key + \`__3\`, node, ctx); return multi([b3, b4]); diff --git a/tests/components/__snapshots__/refs.test.ts.snap b/tests/components/__snapshots__/refs.test.ts.snap index 29af2931..bfebc361 100644 --- a/tests/components/__snapshots__/refs.test.ts.snap +++ b/tests/components/__snapshots__/refs.test.ts.snap @@ -40,7 +40,7 @@ exports[`refs refs are properly bound in slots 2`] = ` let block1 = createBlock(\`
\`); let block2 = createBlock(\`\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { const refs = ctx.__owl__.refs let d2 = [ctx['doSomething'], ctx]; let d3 = (el) => refs[\`myButton\`] = el; diff --git a/tests/components/__snapshots__/slots.test.ts.snap b/tests/components/__snapshots__/slots.test.ts.snap index 60f49e18..50a8f771 100644 --- a/tests/components/__snapshots__/slots.test.ts.snap +++ b/tests/components/__snapshots__/slots.test.ts.snap @@ -1,5 +1,39 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`slots can define a default content 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + let block1 = createBlock(\`\`); + + function defaultContent1(ctx, node, key) { + return text(\`default content\`); + } + + return function template(ctx, node, key = \\"\\") { + let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1); + return block1([], [b3]); + } +}" +`; + +exports[`slots can define a default content 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + let block1 = createBlock(\`
\`); + + return function template(ctx, node, key = \\"\\") { + let b2 = component(\`Dialog\`, {}, key + \`__1\`, node, ctx); + return block1([], [b2]); + } +}" +`; + exports[`slots can define and call slots 1`] = ` "function anonymous(bdom, helpers ) { @@ -26,11 +60,11 @@ exports[`slots can define and call slots 2`] = ` let block2 = createBlock(\`header\`); let block3 = createBlock(\`footer\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return block2(); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { return block3(); } @@ -70,11 +104,11 @@ exports[`slots can define and call slots with params 2`] = ` let block2 = createBlock(\`header\`); let block3 = createBlock(\`footer\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return block2(); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { return block3(); } @@ -106,7 +140,7 @@ exports[`slots can render node with t-ref and Component in same slot 2`] = ` let block2 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { const refs = ctx.__owl__.refs let d1 = (el) => refs[\`div\`] = el; let b2 = block2([d1]); @@ -151,7 +185,7 @@ exports[`slots can use component in default-content of t-slot 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return component(\`GrandChild\`, {}, key + \`__2\`, node, ctx); } @@ -192,7 +226,7 @@ exports[`slots can use t-call in default-content of t-slot 2`] = ` let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; const callTemplate_3 = getTemplate(\`__template__9\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return callTemplate_3.call(this, ctx, node, key + \`__2\`); } @@ -234,7 +268,7 @@ exports[`slots content is the default slot (variation) 2`] = ` let block1 = createBlock(\`sts rocks\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block1(); } @@ -268,7 +302,7 @@ exports[`slots content is the default slot 2`] = ` let block1 = createBlock(\`
\`); let block2 = createBlock(\`sts rocks\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -279,40 +313,6 @@ exports[`slots content is the default slot 2`] = ` }" `; -exports[`slots dafault slots can define a default content 1`] = ` -"function anonymous(bdom, helpers -) { - let { text, createBlock, list, multi, html, toggler, component } = bdom; - let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - - let block1 = createBlock(\`\`); - - const defaultContent1 = (ctx, node, key) => { - return text(\`default content\`); - } - - return function template(ctx, node, key = \\"\\") { - let b3 = callSlot(ctx, node, key, 'default', false, {}, defaultContent1); - return block1([], [b3]); - } -}" -`; - -exports[`slots dafault slots can define a default content 2`] = ` -"function anonymous(bdom, helpers -) { - let { text, createBlock, list, multi, html, toggler, component } = bdom; - let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - - let block1 = createBlock(\`
\`); - - return function template(ctx, node, key = \\"\\") { - let b2 = component(\`Dialog\`, {}, key + \`__1\`, node, ctx); - return block1([], [b2]); - } -}" -`; - exports[`slots default content is not rendered if named slot is provided 1`] = ` "function anonymous(bdom, helpers ) { @@ -321,7 +321,7 @@ exports[`slots default content is not rendered if named slot is provided 1`] = ` let block1 = createBlock(\`\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\`default content\`); } @@ -340,7 +340,7 @@ exports[`slots default content is not rendered if named slot is provided 2`] = ` let block1 = createBlock(\`
\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(\`hey\`); } @@ -360,7 +360,7 @@ exports[`slots default content is not rendered if slot is provided 1`] = ` let block1 = createBlock(\`\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\`default content\`); } @@ -379,7 +379,7 @@ exports[`slots default content is not rendered if slot is provided 2`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`hey\`); } @@ -398,11 +398,11 @@ exports[`slots default slot next to named slot, with default content 1`] = ` let block1 = createBlock(\`
\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\` Default content \`); } - const defaultContent2 = (ctx, node, key) => { + function defaultContent2(ctx, node, key) { return text(\` Default footer \`); } @@ -422,7 +422,7 @@ exports[`slots default slot next to named slot, with default content 2`] = ` let block1 = createBlock(\`
\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(\` Overridden footer \`); } @@ -452,7 +452,7 @@ exports[`slots default slot work with text nodes (variation) 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`sts rocks\`); } @@ -485,7 +485,7 @@ exports[`slots default slot work with text nodes 2`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`sts rocks\`); } @@ -524,13 +524,13 @@ exports[`slots dynamic t-slot call 2`] = ` let block4 = createBlock(\`content\`); let block5 = createBlock(\`

slot2

\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b3 = block3(); let b4 = block4(); return multi([b3, b4]); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { return block5(); } @@ -550,7 +550,7 @@ exports[`slots dynamic t-slot call with default 1`] = ` let block1 = createBlock(\`\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\` owl \`); } @@ -573,13 +573,13 @@ exports[`slots dynamic t-slot call with default 2`] = ` let block4 = createBlock(\`content\`); let block5 = createBlock(\`

slot2

\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b3 = block3(); let b4 = block4(); return multi([b3, b4]); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { return block5(); } @@ -611,7 +611,7 @@ exports[`slots fun: two calls to the same slot 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`some text\`); } @@ -677,7 +677,7 @@ exports[`slots multiple roots are allowed in a default slot 2`] = ` let block3 = createBlock(\`sts\`); let block4 = createBlock(\`rocks\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3 = block3(); let b4 = block4(); return multi([b3, b4]); @@ -715,7 +715,7 @@ exports[`slots multiple roots are allowed in a named slot 2`] = ` let block3 = createBlock(\`sts\`); let block4 = createBlock(\`rocks\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b3 = block3(); let b4 = block4(); return multi([b3, b4]); @@ -766,11 +766,11 @@ exports[`slots multiple slots containing components 3`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return component(\`C\`, {val: 1}, key + \`__3\`, node, ctx); } - const slot4 = (ctx, node, key) => { + function slot4(ctx, node, key) { return component(\`C\`, {val: 2}, key + \`__5\`, node, ctx); } @@ -807,17 +807,17 @@ exports[`slots named slot inside slot 2`] = ` let block2 = createBlock(\`

A

\`); let block3 = createBlock(\`

B

\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d1 = ctx['value']; return block2([d1]); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { const ctx4 = capture(ctx); return component(\`Child\`, {slots: {'brol': {__render: slot5, __ctx: ctx4}}}, key + \`__6\`, node, ctx); } - const slot5 = (ctx, node, key) => { + function slot5(ctx, node, key) { let d2 = ctx['value']; return block3([d2]); } @@ -856,17 +856,17 @@ exports[`slots named slot inside slot, part 3 2`] = ` let block2 = createBlock(\`

A

\`); let block3 = createBlock(\`

B

\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d1 = ctx['value']; return block2([d1]); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { const ctx4 = capture(ctx); return component(\`Child\`, {slots: {'brol': {__render: slot5, __ctx: ctx4}}}, key + \`__6\`, node, ctx); } - const slot5 = (ctx, node, key) => { + function slot5(ctx, node, key) { let d2 = ctx['value']; return block3([d2]); } @@ -887,7 +887,7 @@ exports[`slots named slots can define a default content 1`] = ` let block1 = createBlock(\`\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\`default content\`); } @@ -921,11 +921,11 @@ exports[`slots named slots inside slot, again 1`] = ` let block1 = createBlock(\`\`); - const defaultContent1 = (ctx, node, key) => { + function defaultContent1(ctx, node, key) { return text(\`default1\`); } - const defaultContent2 = (ctx, node, key) => { + function defaultContent2(ctx, node, key) { return text(\`default2\`); } @@ -948,17 +948,17 @@ exports[`slots named slots inside slot, again 2`] = ` let block2 = createBlock(\`

A

\`); let block3 = createBlock(\`

B

\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d1 = ctx['value']; return block2([d1]); } - const slot3 = (ctx, node, key) => { + function slot3(ctx, node, key) { const ctx4 = capture(ctx); return component(\`Child\`, {slots: {'brol2': {__render: slot5, __ctx: ctx4}}}, key + \`__6\`, node, ctx); } - const slot5 = (ctx, node, key) => { + function slot5(ctx, node, key) { let d2 = ctx['value']; return block3([d2]); } @@ -1023,11 +1023,11 @@ exports[`slots nested slots in same template 4`] = ` let block1 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child2\`, {slots: {'default': {__render: slot2, __ctx: ctx}}}, key + \`__4\`, node, ctx); } - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return component(\`Child3\`, {}, key + \`__3\`, node, ctx); } @@ -1074,7 +1074,7 @@ exports[`slots nested slots: evaluation context and parented relationship 3`] = let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return callSlot(ctx, node, key, 'default', false, {}); } @@ -1090,7 +1090,7 @@ exports[`slots nested slots: evaluation context and parented relationship 4`] = let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Slot\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); } @@ -1148,7 +1148,7 @@ exports[`slots simple default slot 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`some text\`); } @@ -1179,7 +1179,7 @@ exports[`slots simple default slot with params 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b2,b3; if (ctx['slotScope'].bool) { b2 = text(\`some text\`); @@ -1217,7 +1217,7 @@ exports[`slots simple default slot with params 4`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b2,b3; if (ctx['slotScope'].bool) { b2 = text(\`some text\`); @@ -1251,7 +1251,7 @@ exports[`slots simple default slot, variation 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`some text\`); } @@ -1299,7 +1299,7 @@ exports[`slots slot and (inline) t-call 3`] = ` let block1 = createBlock(\`
\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return callTemplate_4.call(this, ctx, node, key + \`__3\`); } @@ -1349,7 +1349,7 @@ exports[`slots slot and t-call 3`] = ` let block1 = createBlock(\`
\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return callTemplate_4.call(this, ctx, node, key + \`__3\`); } @@ -1384,7 +1384,7 @@ exports[`slots slot and t-esc 2`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text('toph'); } @@ -1433,7 +1433,7 @@ exports[`slots slot are properly rendered if inner props are changed 3`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`SomeComponent\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); } @@ -1446,6 +1446,44 @@ exports[`slots slot are properly rendered if inner props are changed 3`] = ` }" `; +exports[`slots slot content is bound to caller (variation) 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + let block1 = createBlock(\`\`); + + return function template(ctx, node, key = \\"\\") { + let b2 = callSlot(ctx, node, key, 'default', false, {}); + return block1([], [b2]); + } +}" +`; + +exports[`slots slot content is bound to caller (variation) 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + let block1 = createBlock(\`\`); + + function slot2(ctx, node, key) { + setContextValue(ctx, \\"var\\", 1); + let d1 = [()=>this.inc(), ctx]; + return block1([d1]); + } + + return function template(ctx, node, key = \\"\\") { + ctx = Object.create(ctx); + ctx[isBoundary] = 1 + const ctx1 = capture(ctx); + return component(\`Child\`, {slots: {'default': {__render: slot2, __ctx: ctx1}}}, key + \`__3\`, node, ctx); + } +}" +`; + exports[`slots slot content is bound to caller 1`] = ` "function anonymous(bdom, helpers ) { @@ -1469,7 +1507,7 @@ exports[`slots slot content is bound to caller 2`] = ` let block1 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let d1 = [ctx['inc'], ctx]; return block1([d1]); } @@ -1512,7 +1550,7 @@ exports[`slots slot preserves properly parented relationship 3`] = ` let block1 = createBlock(\`
\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`GrandChild\`, {}, key + \`__2\`, node, ctx); } @@ -1568,7 +1606,7 @@ exports[`slots slot preserves properly parented relationship, even through t-cal let block1 = createBlock(\`
\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return callTemplate_4.call(this, ctx, node, key + \`__3\`); } @@ -1601,7 +1639,7 @@ exports[`slots slots and wrapper components 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(\`hey\`); } @@ -1611,6 +1649,41 @@ exports[`slots slots and wrapper components 2`] = ` }" `; +exports[`slots slots are properly bound to correct component 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + let block1 = createBlock(\`\`); + + function defaultContent1(ctx, node, key) { + setContextValue(ctx, \\"var\\", 1); + let d1 = [()=>this.increment(), ctx]; + let d2 = ctx['state'].value; + return block1([d1, d2]); + } + + return function template(ctx, node, key = \\"\\") { + ctx = Object.create(ctx); + ctx[isBoundary] = 1 + return callSlot(ctx, node, key, 'default', false, {}, defaultContent1); + } +}" +`; + +exports[`slots slots are properly bound to correct component 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return component(\`Child\`, {}, key + \`__1\`, node, ctx); + } +}" +`; + exports[`slots slots are rendered with proper context 1`] = ` "function anonymous(bdom, helpers ) { @@ -1635,7 +1708,7 @@ exports[`slots slots are rendered with proper context 2`] = ` let block1 = createBlock(\`
\`); let block2 = createBlock(\`\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d2 = [ctx['doSomething'], ctx]; return block2([d2]); } @@ -1674,7 +1747,7 @@ exports[`slots slots are rendered with proper context, part 2 2`] = ` let block1 = createBlock(\`
\`); let block3 = createBlock(\`
  • \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b5 = text(\`User \`); let b6 = text(ctx['user'].name); return multi([b5, b6]); @@ -1721,7 +1794,7 @@ exports[`slots slots are rendered with proper context, part 3 2`] = ` let block1 = createBlock(\`
    \`); let block3 = createBlock(\`
  • \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(ctx['userdescr']); } @@ -1768,7 +1841,7 @@ exports[`slots slots are rendered with proper context, part 4 2`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(ctx['userdescr']); } @@ -1806,7 +1879,7 @@ exports[`slots slots in slots, with vars 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return callSlot(ctx, node, key, 'default', false, {}); } @@ -1826,7 +1899,7 @@ exports[`slots slots in slots, with vars 3`] = ` let block1 = createBlock(\`
    \`); let block2 = createBlock(\`

    hey

    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d1 = ctx['test']; return block2([d1]); } @@ -1866,7 +1939,7 @@ exports[`slots slots in t-foreach and re-rendering 2`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(ctx['n_index']); } @@ -1912,7 +1985,7 @@ exports[`slots slots in t-foreach in t-foreach 2`] = ` let block5 = createBlock(\`\`); let block7 = createBlock(\`
  • \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let d2 = ctx['node1'].value; return block7([d2]); } @@ -1968,7 +2041,7 @@ exports[`slots slots in t-foreach with t-set and re-rendering 2`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return text(ctx['dummy']); } @@ -2014,7 +2087,7 @@ exports[`slots t-debug on a t-set-slot (defining a slot) 2`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { debugger; return text(\`abc\`); } @@ -2050,7 +2123,7 @@ exports[`slots t-set t-value in a slot 2`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { setContextValue(ctx, \\"rainbow\\", 'dash'); return text(ctx['rainbow']); } @@ -2087,7 +2160,7 @@ exports[`slots t-slot in recursive templates 2`] = ` let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; const callTemplate_4 = getTemplate(\`_test_recursive_template\`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { let b2 = text(ctx['name']); ctx = Object.create(ctx); const [k_block3, v_block3, l_block3, c_block3] = prepareList(ctx['items']); @@ -2177,11 +2250,11 @@ exports[`slots t-slot nested within another slot 4`] = ` let block1 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Portal\`, {slots: {'default': {__render: slot2, __ctx: ctx}}}, key + \`__3\`, node, ctx); } - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return callSlot(ctx, node, key, 'default', false, {}); } @@ -2200,7 +2273,7 @@ exports[`slots t-slot nested within another slot 5`] = ` let block1 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child3\`, {}, key + \`__2\`, node, ctx); } @@ -2231,7 +2304,7 @@ exports[`slots t-slot scope context 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let d1 = [ctx['onClick'], ctx]; let b2 = callSlot(ctx, node, key, 'default', false, {}); return block1([d1], [b2]); @@ -2251,7 +2324,7 @@ exports[`slots t-slot scope context 3`] = ` let block1 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block1(); } @@ -2313,7 +2386,7 @@ exports[`slots t-slot within dynamic t-call 4`] = ` let block1 = createBlock(\`
    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { const template4 = (ctx['tcallTemplate']); return call(template4, ctx, node, key + \`__3\`); } @@ -2361,7 +2434,7 @@ exports[`slots template can just return a slot 3`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {value: ctx['state'].value}, key + \`__2\`, node, ctx); } diff --git a/tests/components/__snapshots__/t_set.test.ts.snap b/tests/components/__snapshots__/t_set.test.ts.snap index 7f88be91..9fc3837d 100644 --- a/tests/components/__snapshots__/t_set.test.ts.snap +++ b/tests/components/__snapshots__/t_set.test.ts.snap @@ -27,7 +27,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 2`] = ` let block1 = createBlock(\`

    \`); - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { setContextValue(ctx, \\"iter\\", 'inCall'); } diff --git a/tests/components/slots.test.ts b/tests/components/slots.test.ts index 7301e2e7..d38445e3 100644 --- a/tests/components/slots.test.ts +++ b/tests/components/slots.test.ts @@ -124,6 +124,33 @@ describe("slots", () => { expect(parent.state.value).toBe(1); }); + test("slot content is bound to caller (variation)", async () => { + class Child extends Component { + static template = xml``; + } + + class Parent extends Component { + // t-set t-value in template is to force compiler to protect the scope + // which in turns means that the ctx propagated to the slot is a sub object + static template = xml` + + + + `; + static components = { Child }; + state = useState({ value: 0 }); + inc() { + expect(this).toBe(parent); + this.state.value++; + } + } + const parent = await mount(Parent, fixture); + + expect(parent.state.value).toBe(0); + fixture.querySelector("button")!.click(); + expect(parent.state.value).toBe(1); + }); + test("can define and call slots", async () => { class Dialog extends Component { static template = xml` @@ -208,7 +235,7 @@ describe("slots", () => { expect(fixture.innerHTML).toBe("
    default content
    "); }); - test("dafault slots can define a default content", async () => { + test("can define a default content", async () => { class Dialog extends Component { static template = xml` @@ -256,6 +283,42 @@ describe("slots", () => { expect(fixture.innerHTML).toBe("
    hey
    "); }); + test("slots are properly bound to correct component", async () => { + let child: any = null; + class Child extends Component { + // t-set t-value in template is to force compiler to protect the scope + // which in turns means that the ctx propagated to the slot is a sub object + static template = xml` + + + + `; + + state = useState({ value: 1 }); + setup() { + child = this; + } + increment() { + expect(this).toBe(child); + this.state.value++; + } + } + + class Parent extends Component { + static template = xml``; + static components = { Child }; + } + await mount(Parent, fixture); + + expect(fixture.innerHTML).toBe(""); + + fixture.querySelector("button")!.click(); + await nextTick(); + expect(fixture.innerHTML).toBe(""); + }); + test("slots are rendered with proper context", async () => { class Dialog extends Component { static template = xml``; diff --git a/tests/misc/__snapshots__/memo.test.ts.snap b/tests/misc/__snapshots__/memo.test.ts.snap index 12b1eba7..6dc1ca23 100644 --- a/tests/misc/__snapshots__/memo.test.ts.snap +++ b/tests/misc/__snapshots__/memo.test.ts.snap @@ -18,7 +18,7 @@ exports[`Memo if no prop change, prevent renderings from above 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b6 = text(ctx['state'].a); let b7 = text(ctx['state'].b); let b8 = text(ctx['state'].c); @@ -53,7 +53,7 @@ exports[`Memo if no props, prevent renderings from above 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot2 = (ctx, node, key) => { + function slot2(ctx, node, key) { return component(\`Child\`, {value: ctx['state'].value}, key + \`__3\`, node, ctx); } @@ -71,7 +71,7 @@ exports[`Memo if no props, prevent renderings from above (work with simple html) let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text(ctx['state'].value); } diff --git a/tests/misc/__snapshots__/portal.test.ts.snap b/tests/misc/__snapshots__/portal.test.ts.snap index 6c6a468c..af0572f4 100644 --- a/tests/misc/__snapshots__/portal.test.ts.snap +++ b/tests/misc/__snapshots__/portal.test.ts.snap @@ -21,7 +21,7 @@ exports[`Portal Portal composed with t-slot 2`] = ` let { text, createBlock, list, multi, html, toggler, component } = bdom; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return callSlot(ctx, node, key, 'default', false, {}); } @@ -39,7 +39,7 @@ exports[`Portal Portal composed with t-slot 3`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child2\`, {customHandler: ctx['_handled']}, key + \`__2\`, node, ctx); } @@ -59,7 +59,7 @@ exports[`Portal basic use of portal 1`] = ` let block1 = createBlock(\`
    1
    \`); let block2 = createBlock(\`

    2

    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -93,7 +93,7 @@ exports[`Portal conditional use of Portal (with sub Component) 2`] = ` let block2 = createBlock(\`1\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); } @@ -117,7 +117,7 @@ exports[`Portal conditional use of Portal 1`] = ` let block2 = createBlock(\`1\`); let block3 = createBlock(\`

    2

    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block3(); } @@ -155,7 +155,7 @@ exports[`Portal lifecycle hooks of portal sub component are properly called 2`] let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); } @@ -178,7 +178,7 @@ exports[`Portal portal could have dynamically no content 1`] = ` let block1 = createBlock(\`
    \`); let block3 = createBlock(\`\`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3; if (ctx['state'].val) { let d1 = ctx['state'].val; @@ -217,7 +217,7 @@ exports[`Portal portal destroys on crash 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {error: ctx['state'].error}, key + \`__2\`, node, ctx); } @@ -251,7 +251,7 @@ exports[`Portal portal with child and props 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); } @@ -272,7 +272,7 @@ exports[`Portal portal with dynamic body 1`] = ` let block3 = createBlock(\`\`); let block4 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3,b4; if (ctx['state'].val) { let d1 = ctx['state'].val; @@ -300,7 +300,7 @@ exports[`Portal portal with many children 1`] = ` let block3 = createBlock(\`
    1
    \`); let block4 = createBlock(\`

    2

    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3 = block3(); let b4 = block4(); return multi([b3, b4]); @@ -321,7 +321,7 @@ exports[`Portal portal with no content 1`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { let b3; if (false) { b3 = text('ABC'); @@ -344,7 +344,7 @@ exports[`Portal portal with only text as content 1`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return text('only text'); } @@ -364,7 +364,7 @@ exports[`Portal portal with target not in dom 1`] = ` let block1 = createBlock(\`
    \`); let block2 = createBlock(\`
    2
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -397,7 +397,7 @@ exports[`Portal portal's parent's env is not polluted 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {}, key + \`__2\`, node, ctx); } @@ -417,7 +417,7 @@ exports[`Portal with target in template (after portal) 1`] = ` let block1 = createBlock(\`
    1
    \`); let block2 = createBlock(\`

    2

    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -437,7 +437,7 @@ exports[`Portal with target in template (before portal) 1`] = ` let block1 = createBlock(\`
    1
    \`); let block2 = createBlock(\`

    2

    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -457,7 +457,7 @@ exports[`Portal: Props validation target is mandatory 1`] = ` let block1 = createBlock(\`
    \`); let block2 = createBlock(\`
    2
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -477,7 +477,7 @@ exports[`Portal: Props validation target is not list 1`] = ` let block1 = createBlock(\`
    \`); let block2 = createBlock(\`
    2
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return block2(); } @@ -511,7 +511,7 @@ exports[`Portal: UI/UX focus is kept across re-renders 2`] = ` let block1 = createBlock(\`
    \`); - const slot1 = (ctx, node, key) => { + function slot1(ctx, node, key) { return component(\`Child\`, {val: ctx['state'].val}, key + \`__2\`, node, ctx); }