Skip to content

Commit

Permalink
[FIX] blockdom: fix t-set-slot causing context capture with xml
Browse files Browse the repository at this point in the history
This is a commit message.
  • Loading branch information
sdegueldre committed Jan 10, 2024
1 parent 70101e4 commit 3975a96
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 94 deletions.
9 changes: 5 additions & 4 deletions src/compiler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { BDom } from "../runtime/blockdom";
import { CodeGenerator, Config } from "./code_generator";
import { parse } from "./parser";
import { OwlError } from "../common/owl_error";
import { parseXML } from "../common/utils";

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

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

// some work
const hasSafeContext =
template instanceof Node
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
: !template.includes("t-set") && !template.includes("t-call");
const hasSafeContext = template.querySelector("[t-set], [t-call]") === null;

// code generation
const codeGenerator = new CodeGenerator(ast, { ...options, hasSafeContext });
Expand Down
7 changes: 1 addition & 6 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { OwlError } from "../common/owl_error";
import { parseXML } from "../common/utils";

// -----------------------------------------------------------------------------
// AST Type definition
Expand Down Expand Up @@ -198,11 +197,7 @@ export type AST =
// -----------------------------------------------------------------------------
const cache: WeakMap<Element, AST> = new WeakMap();

export function parse(xml: string | Element): AST {
if (typeof xml === "string") {
const elem = parseXML(`<t>${xml}</t>`).firstChild as Element;
return _parse(elem);
}
export function parse(xml: Element): AST {
let ast = cache.get(xml);
if (!ast) {
// we clone here the xml to prevent modifying it in place
Expand Down
5 changes: 4 additions & 1 deletion tests/compiler/parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ASTType, parse } from "../../src/compiler/parser";
import { parseXML } from "../../src/common/utils";
import { ASTType, parse as _parse } from "../../src/compiler/parser";

const parse = (template: string) => _parse(parseXML(`<t>${template}</t>`).firstChild as Element);

describe("qweb parser", () => {
// ---------------------------------------------------------------------------
Expand Down
5 changes: 2 additions & 3 deletions tests/components/__snapshots__/refs.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ exports[`refs refs are properly bound in slots 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { capture, markRaw } = helpers;
let { markRaw } = helpers;
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
let block1 = createBlock(\`<div><span class=\\"counter\\"><block-text-0/></span><block-child-0/></div>\`);
Expand All @@ -113,8 +113,7 @@ exports[`refs refs are properly bound in slots 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].val;
const ctx1 = capture(ctx);
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
return block1([txt1], [b3]);
}
}"
Expand Down
149 changes: 76 additions & 73 deletions tests/components/__snapshots__/slots.test.ts.snap

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions tests/components/__snapshots__/t_foreach.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ exports[`list of components order is correct when slots are not of same type 1`]
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { capture, markRaw } = helpers;
let { markRaw } = helpers;
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
let block2 = createBlock(\`<div>A</div>\`);
Expand All @@ -175,8 +175,7 @@ exports[`list of components order is correct when slots are not of same type 1`]
}
return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
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);
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);
}
}"
`;
Expand Down
5 changes: 2 additions & 3 deletions tests/components/__snapshots__/t_on.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ exports[`t-on t-on on t-set-slots 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { capture, createCatcher, markRaw } = helpers;
let { createCatcher, markRaw } = helpers;
const catcher1 = createCatcher({\\"click\\":0});
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
Expand All @@ -405,8 +405,7 @@ exports[`t-on t-on on t-set-slots 1`] = `
const b2 = text(\` [\`);
const b3 = text(ctx['state'].count);
const b4 = text(\`] \`);
const ctx1 = capture(ctx);
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
return multi([b2, b3, b4, b8]);
}
}"
Expand Down
24 changes: 23 additions & 1 deletion tests/components/slots.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { App, Component, mount, onMounted, useState, xml } from "../../src/index";
import { App, Component, mount, onMounted, onRendered, useState, xml } from "../../src/index";
import { children, makeTestFixture, nextAppError, nextTick, snapshotEverything } from "../helpers";

snapshotEverything();
Expand Down Expand Up @@ -62,6 +62,28 @@ describe("slots", () => {
expect(fixture.innerHTML).toBe("some other text");
});

test("t-set-slot doesn't cause context to be captured", async () => {
class Child extends Component {
static template = xml`<t t-slot="default"/>`;
}

class Parent extends Component {
static template = xml`<Child>
<t t-set-slot="default"><t t-esc="someVal"/></t>
</Child>`;
static components = { Child };
someVal = "some text";
setup() {
onRendered(() => {
this.someVal = "some other text";
});
}
}
await mount(Parent, fixture);

expect(fixture.textContent).toBe("some other text");
});

test("simple slot with slot scope", async () => {
let child: any;
class Child extends Component {
Expand Down

0 comments on commit 3975a96

Please sign in to comment.