Skip to content

Commit 3975a96

Browse files
committed
[FIX] blockdom: fix t-set-slot causing context capture with xml
This is a commit message.
1 parent 70101e4 commit 3975a96

File tree

8 files changed

+115
-94
lines changed

8 files changed

+115
-94
lines changed

src/compiler/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { BDom } from "../runtime/blockdom";
33
import { CodeGenerator, Config } from "./code_generator";
44
import { parse } from "./parser";
55
import { OwlError } from "../common/owl_error";
6+
import { parseXML } from "../common/utils";
67

78
export type Template = (context: any, vnode: any, key?: string) => BDom;
89

@@ -16,13 +17,13 @@ export function compile(
1617
options: CompileOptions = {}
1718
): TemplateFunction {
1819
// parsing
20+
if (typeof template === "string") {
21+
template = parseXML(`<t>${template}</t>`).firstChild as Element;
22+
}
1923
const ast = parse(template);
2024

2125
// some work
22-
const hasSafeContext =
23-
template instanceof Node
24-
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
25-
: !template.includes("t-set") && !template.includes("t-call");
26+
const hasSafeContext = template.querySelector("[t-set], [t-call]") === null;
2627

2728
// code generation
2829
const codeGenerator = new CodeGenerator(ast, { ...options, hasSafeContext });

src/compiler/parser.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { OwlError } from "../common/owl_error";
2-
import { parseXML } from "../common/utils";
32

43
// -----------------------------------------------------------------------------
54
// AST Type definition
@@ -198,11 +197,7 @@ export type AST =
198197
// -----------------------------------------------------------------------------
199198
const cache: WeakMap<Element, AST> = new WeakMap();
200199

201-
export function parse(xml: string | Element): AST {
202-
if (typeof xml === "string") {
203-
const elem = parseXML(`<t>${xml}</t>`).firstChild as Element;
204-
return _parse(elem);
205-
}
200+
export function parse(xml: Element): AST {
206201
let ast = cache.get(xml);
207202
if (!ast) {
208203
// we clone here the xml to prevent modifying it in place

tests/compiler/parser.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { ASTType, parse } from "../../src/compiler/parser";
1+
import { parseXML } from "../../src/common/utils";
2+
import { ASTType, parse as _parse } from "../../src/compiler/parser";
3+
4+
const parse = (template: string) => _parse(parseXML(`<t>${template}</t>`).firstChild as Element);
25

36
describe("qweb parser", () => {
47
// ---------------------------------------------------------------------------

tests/components/__snapshots__/refs.test.ts.snap

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ exports[`refs refs are properly bound in slots 1`] = `
9999
"function anonymous(app, bdom, helpers
100100
) {
101101
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
102-
let { capture, markRaw } = helpers;
102+
let { markRaw } = helpers;
103103
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
104104
105105
let block1 = createBlock(\`<div><span class=\\"counter\\"><block-text-0/></span><block-child-0/></div>\`);
@@ -113,8 +113,7 @@ exports[`refs refs are properly bound in slots 1`] = `
113113
114114
return function template(ctx, node, key = \\"\\") {
115115
let txt1 = ctx['state'].val;
116-
const ctx1 = capture(ctx);
117-
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
116+
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
118117
return block1([txt1], [b3]);
119118
}
120119
}"

tests/components/__snapshots__/slots.test.ts.snap

Lines changed: 76 additions & 73 deletions
Large diffs are not rendered by default.

tests/components/__snapshots__/t_foreach.test.ts.snap

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ exports[`list of components order is correct when slots are not of same type 1`]
153153
"function anonymous(app, bdom, helpers
154154
) {
155155
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
156-
let { capture, markRaw } = helpers;
156+
let { markRaw } = helpers;
157157
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
158158
159159
let block2 = createBlock(\`<div>A</div>\`);
@@ -175,8 +175,7 @@ exports[`list of components order is correct when slots are not of same type 1`]
175175
}
176176
177177
return function template(ctx, node, key = \\"\\") {
178-
const ctx1 = capture(ctx);
179-
return comp1({slots: markRaw({'a': {__render: slot1.bind(this), __ctx: ctx1, active: !ctx['state'].active}, 'b': {__render: slot2.bind(this), __ctx: ctx1, active: true}, 'c': {__render: slot3.bind(this), __ctx: ctx1, active: ctx['state'].active}})}, key + \`__1\`, node, this, null);
178+
return comp1({slots: markRaw({'a': {__render: slot1.bind(this), __ctx: ctx, active: !ctx['state'].active}, 'b': {__render: slot2.bind(this), __ctx: ctx, active: true}, 'c': {__render: slot3.bind(this), __ctx: ctx, active: ctx['state'].active}})}, key + \`__1\`, node, this, null);
180179
}
181180
}"
182181
`;

tests/components/__snapshots__/t_on.test.ts.snap

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ exports[`t-on t-on on t-set-slots 1`] = `
386386
"function anonymous(app, bdom, helpers
387387
) {
388388
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
389-
let { capture, createCatcher, markRaw } = helpers;
389+
let { createCatcher, markRaw } = helpers;
390390
const catcher1 = createCatcher({\\"click\\":0});
391391
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
392392
@@ -405,8 +405,7 @@ exports[`t-on t-on on t-set-slots 1`] = `
405405
const b2 = text(\` [\`);
406406
const b3 = text(ctx['state'].count);
407407
const b4 = text(\`] \`);
408-
const ctx1 = capture(ctx);
409-
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
408+
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
410409
return multi([b2, b3, b4, b8]);
411410
}
412411
}"

tests/components/slots.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { App, Component, mount, onMounted, useState, xml } from "../../src/index";
1+
import { App, Component, mount, onMounted, onRendered, useState, xml } from "../../src/index";
22
import { children, makeTestFixture, nextAppError, nextTick, snapshotEverything } from "../helpers";
33

44
snapshotEverything();
@@ -62,6 +62,28 @@ describe("slots", () => {
6262
expect(fixture.innerHTML).toBe("some other text");
6363
});
6464

65+
test("t-set-slot doesn't cause context to be captured", async () => {
66+
class Child extends Component {
67+
static template = xml`<t t-slot="default"/>`;
68+
}
69+
70+
class Parent extends Component {
71+
static template = xml`<Child>
72+
<t t-set-slot="default"><t t-esc="someVal"/></t>
73+
</Child>`;
74+
static components = { Child };
75+
someVal = "some text";
76+
setup() {
77+
onRendered(() => {
78+
this.someVal = "some other text";
79+
});
80+
}
81+
}
82+
await mount(Parent, fixture);
83+
84+
expect(fixture.textContent).toBe("some other text");
85+
});
86+
6587
test("simple slot with slot scope", async () => {
6688
let child: any;
6789
class Child extends Component {

0 commit comments

Comments
 (0)