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 2adf606
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 11 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
29 changes: 29 additions & 0 deletions tests/components/__snapshots__/slots.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2875,6 +2875,35 @@ exports[`slots t-set t-value in a slot 2`] = `
}"
`;

exports[`slots t-set-slot doesn't cause context to be captured 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { markRaw } = helpers;
const comp1 = app.createComponent(\`Child\`, true, true, false, []);

function slot1(ctx, node, key = \\"\\") {
return text(ctx['someVal']);
}

return function template(ctx, node, key = \\"\\") {
return comp1({slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
}
}"
`;

exports[`slots t-set-slot doesn't cause context to be captured 2`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { callSlot } = helpers;

return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, {});
}
}"
`;

exports[`slots t-set-slot=default has priority over rest of the content 1`] = `
"function anonymous(app, bdom, helpers
) {
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.only("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 2adf606

Please sign in to comment.