[FIX] compiler: correctly escape special characters in template literals

Previously, there were a few places where the compiler would create
strings from template content and emit them as template literals, but
didn't properly escape characters or character sequences with special
meanings, in particular: backslashes, backticks, and interpolation
sigils.

This commit fixes this in:
- block creation (interpolation sigils were not escaped)
- text node creation (no escaping was performed)
- comment not creation (no escaping was performed)
- default values for t-esc (no escaping was performed)
- body of a t-set (no escaping was performed)
This commit is contained in:
Samuel Degueldre
2024-05-08 13:02:26 +02:00
committed by Géry Debongnie
parent 7b7a6de373
commit 11e4e67599
9 changed files with 236 additions and 20 deletions
@@ -1,5 +1,38 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`comments comment node with backslash at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return comment(\` \\\\\\\\ \`);
}
}"
`;
exports[`comments comment node with backtick at top-level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return comment(\` \\\\\` \`);
}
}"
`;
exports[`comments comment node with interpolation sigil at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return comment(\` \\\\\${very cool} \`);
}
}"
`;
exports[`comments only a comment 1`] = `
"function anonymous(app, bdom, helpers
) {
@@ -341,6 +341,39 @@ exports[`simple templates, mostly static template with t tag with multiple conte
}"
`;
exports[`simple templates, mostly static text node with backslash at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`\\\\\\\\\`);
}
}"
`;
exports[`simple templates, mostly static text node with backtick at top-level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`\\\\\`\`);
}
}"
`;
exports[`simple templates, mostly static text node with interpolation sigil at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`\\\\\${very cool}\`);
}
}"
`;
exports[`simple templates, mostly static two t-escs next to each other 1`] = `
"function anonymous(app, bdom, helpers
) {
@@ -1,5 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`t-esc default with backslash at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { withDefault } = helpers;
return function template(ctx, node, key = \\"\\") {
return text(withDefault(undefined, \`\\\\\\\\\`));
}
}"
`;
exports[`t-esc default with backtick at top-level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { withDefault } = helpers;
return function template(ctx, node, key = \\"\\") {
return text(withDefault(undefined, \`\\\\\`\`));
}
}"
`;
exports[`t-esc default with interpolation sigil at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { withDefault } = helpers;
return function template(ctx, node, key = \\"\\") {
return text(withDefault(undefined, \`\\\\\${very cool}\`));
}
}"
`;
exports[`t-esc div with falsy values 1`] = `
"function anonymous(app, bdom, helpers
) {
@@ -1,5 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`t-set body with backslash at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { isBoundary, withDefault, setContextValue } = helpers;
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"value\\", \`\\\\\\\\\`);
return text(ctx['value']);
}
}"
`;
exports[`t-set body with backtick at top-level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { isBoundary, withDefault, setContextValue } = helpers;
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"value\\", \`\\\\\`\`);
return text(ctx['value']);
}
}"
`;
exports[`t-set body with interpolation sigil at top level 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { isBoundary, withDefault, setContextValue } = helpers;
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"value\\", \`\\\\\${very cool}\`);
return text(ctx['value']);
}
}"
`;
exports[`t-set evaluate value expression 1`] = `
"function anonymous(app, bdom, helpers
) {
+15
View File
@@ -26,4 +26,19 @@ describe("comments", () => {
</div>`;
expect(renderToString(template)).toBe("<div><span>true</span></div>");
});
test("comment node with backslash at top level", () => {
const template = "<!-- \\ -->";
expect(renderToString(template)).toBe("<!-- \\ -->");
});
test("comment node with backtick at top-level", () => {
const template = "<!-- ` -->";
expect(renderToString(template)).toBe("<!-- ` -->");
});
test("comment node with interpolation sigil at top level", () => {
const template = "<!-- ${very cool} -->";
expect(renderToString(template)).toBe("<!-- ${very cool} -->");
});
});
+15
View File
@@ -154,4 +154,19 @@ describe("simple templates, mostly static", () => {
</div>`;
expect(renderToString(template, { a: "a", b: "b", c: "c" })).toBe("<div>abLoadingc</div>");
});
test("text node with backslash at top level", () => {
const template = "\\";
expect(renderToString(template)).toBe("\\");
});
test("text node with backtick at top-level", () => {
const template = "`";
expect(renderToString(template)).toBe("`");
});
test("text node with interpolation sigil at top level", () => {
const template = "${very cool}";
expect(renderToString(template)).toBe("${very cool}");
});
});
+15
View File
@@ -121,4 +121,19 @@ describe("t-esc", () => {
mount(bdom, fixture);
expect(fixture.querySelector("span")!.textContent).toBe("<p>escaped</p>");
});
test("default with backslash at top level", () => {
const template = '<t t-esc="undefined">\\</t>';
expect(renderToString(template)).toBe("\\");
});
test("default with backtick at top-level", () => {
const template = '<t t-esc="undefined">`</t>';
expect(renderToString(template)).toBe("`");
});
test("default with interpolation sigil at top level", () => {
const template = '<t t-esc="undefined">${very cool}</t>';
expect(renderToString(template)).toBe("${very cool}");
});
});
+15
View File
@@ -54,6 +54,21 @@ describe("t-set", () => {
expect(renderToString(template)).toBe("ok");
});
test("body with backslash at top level", () => {
const template = '<t t-set="value">\\</t><t t-esc="value"/>';
expect(renderToString(template)).toBe("\\");
});
test("body with backtick at top-level", () => {
const template = '<t t-set="value">`</t><t t-esc="value"/>';
expect(renderToString(template)).toBe("`");
});
test("body with interpolation sigil at top level", () => {
const template = '<t t-set="value">${very cool}</t><t t-esc="value"/>';
expect(renderToString(template)).toBe("${very cool}");
});
test("set from body literal (with t-if/t-else", () => {
const template = `
<t>