mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[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:
committed by
Géry Debongnie
parent
7b7a6de373
commit
11e4e67599
@@ -82,6 +82,14 @@ function isProp(tag: string, key: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a template literal that evaluates to str. You can add interpolation
|
||||
* sigils into the string if required
|
||||
*/
|
||||
function toStringExpression(str: string) {
|
||||
return `\`${str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/, "\\${")}\``;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BlockDescription
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -311,14 +319,13 @@ export class CodeGenerator {
|
||||
mainCode.push(``);
|
||||
for (let block of this.blocks) {
|
||||
if (block.dom) {
|
||||
let xmlString = block.asXmlString();
|
||||
xmlString = xmlString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
|
||||
let xmlString = toStringExpression(block.asXmlString());
|
||||
if (block.dynamicTagName) {
|
||||
xmlString = xmlString.replace(/^<\w+/, `<\${tag || '${block.dom.nodeName}'}`);
|
||||
xmlString = xmlString.replace(/\w+>$/, `\${tag || '${block.dom.nodeName}'}>`);
|
||||
mainCode.push(`let ${block.blockName} = tag => createBlock(\`${xmlString}\`);`);
|
||||
xmlString = xmlString.replace(/^`<\w+/, `\`<\${tag || '${block.dom.nodeName}'}`);
|
||||
xmlString = xmlString.replace(/\w+>`$/, `\${tag || '${block.dom.nodeName}'}>\``);
|
||||
mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);
|
||||
} else {
|
||||
mainCode.push(`let ${block.blockName} = createBlock(\`${xmlString}\`);`);
|
||||
mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,7 +522,7 @@ export class CodeGenerator {
|
||||
const isNewBlock = !block || forceNewBlock;
|
||||
if (isNewBlock) {
|
||||
block = this.createBlock(block, "comment", ctx);
|
||||
this.insertBlock(`comment(\`${ast.value}\`)`, block, {
|
||||
this.insertBlock(`comment(${toStringExpression(ast.value)})`, block, {
|
||||
...ctx,
|
||||
forceNewBlock: forceNewBlock && !block,
|
||||
});
|
||||
@@ -539,7 +546,7 @@ export class CodeGenerator {
|
||||
|
||||
if (!block || forceNewBlock) {
|
||||
block = this.createBlock(block, "text", ctx);
|
||||
this.insertBlock(`text(\`${value}\`)`, block, {
|
||||
this.insertBlock(`text(${toStringExpression(value)})`, block, {
|
||||
...ctx,
|
||||
forceNewBlock: forceNewBlock && !block,
|
||||
});
|
||||
@@ -774,7 +781,8 @@ export class CodeGenerator {
|
||||
expr = compileExpr(ast.expr);
|
||||
if (ast.defaultValue) {
|
||||
this.helpers.add("withDefault");
|
||||
expr = `withDefault(${expr}, \`${ast.defaultValue}\`)`;
|
||||
// FIXME: defaultValue is not translated
|
||||
expr = `withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;
|
||||
}
|
||||
}
|
||||
if (!block || forceNewBlock) {
|
||||
@@ -1039,7 +1047,7 @@ export class CodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
const key = `key + \`${this.generateComponentKey()}\``;
|
||||
const key = this.generateComponentKey();
|
||||
if (isDynamic) {
|
||||
const templateVar = generateId("template");
|
||||
if (!this.staticDefs.find((d) => d.id === "call")) {
|
||||
@@ -1091,11 +1099,13 @@ export class CodeGenerator {
|
||||
} else {
|
||||
let value: string;
|
||||
if (ast.defaultValue) {
|
||||
const defaultValue = ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue;
|
||||
const defaultValue = toStringExpression(
|
||||
ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue
|
||||
);
|
||||
if (ast.value) {
|
||||
value = `withDefault(${expr}, \`${defaultValue}\`)`;
|
||||
value = `withDefault(${expr}, ${defaultValue})`;
|
||||
} else {
|
||||
value = `\`${defaultValue}\``;
|
||||
value = defaultValue;
|
||||
}
|
||||
} else {
|
||||
value = expr;
|
||||
@@ -1106,12 +1116,12 @@ export class CodeGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
generateComponentKey() {
|
||||
generateComponentKey(currentKey: string = "key") {
|
||||
const parts = [generateId("__")];
|
||||
for (let i = 0; i < this.target.loopLevel; i++) {
|
||||
parts.push(`\${key${i + 1}}`);
|
||||
}
|
||||
return parts.join("__");
|
||||
return `${currentKey} + \`${parts.join("__")}\``;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1214,7 +1224,6 @@ export class CodeGenerator {
|
||||
}
|
||||
|
||||
// cmap key
|
||||
const key = this.generateComponentKey();
|
||||
let expr: string;
|
||||
if (ast.isDynamic) {
|
||||
expr = generateId("Comp");
|
||||
@@ -1232,7 +1241,7 @@ export class CodeGenerator {
|
||||
this.insertAnchor(block);
|
||||
}
|
||||
|
||||
let keyArg = `key + \`${key}\``;
|
||||
let keyArg = this.generateComponentKey();
|
||||
if (ctx.tKeyExpr) {
|
||||
keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
|
||||
}
|
||||
@@ -1311,7 +1320,7 @@ export class CodeGenerator {
|
||||
}
|
||||
let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
|
||||
if (isMultiple) {
|
||||
key = `${key} + \`${this.generateComponentKey()}\``;
|
||||
key = this.generateComponentKey(key);
|
||||
}
|
||||
|
||||
const props = ast.attrs ? this.formatPropObject(ast.attrs) : [];
|
||||
@@ -1354,7 +1363,6 @@ export class CodeGenerator {
|
||||
|
||||
let { block } = ctx;
|
||||
const name = this.compileInNewTarget("slot", ast.content, ctx);
|
||||
const key = this.generateComponentKey();
|
||||
let ctxStr = "ctx";
|
||||
if (this.target.loopLevel || !this.hasSafeContext) {
|
||||
ctxStr = generateId("ctx");
|
||||
@@ -1368,7 +1376,8 @@ export class CodeGenerator {
|
||||
});
|
||||
|
||||
const target = compileExpr(ast.target);
|
||||
const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx, Portal)`;
|
||||
const key = this.generateComponentKey();
|
||||
const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;
|
||||
if (block) {
|
||||
this.insertAnchor(block);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user