diff --git a/src/compiler/HtmlJsParser.js b/src/compiler/HtmlJsParser.js index 2a693d84d..c7cd0be33 100644 --- a/src/compiler/HtmlJsParser.js +++ b/src/compiler/HtmlJsParser.js @@ -30,7 +30,10 @@ class HtmlJsParser { if (part.type === "placeholder") { value += "${" + part.value + "}"; } else { - value += part.replace(/`/g, "\\`"); + value += part.replace( + /`|\\|\${/g, + match => "\\" + match + ); } }); event.value = "$nonstandard`" + value + "`"; diff --git a/src/compiler/ast/HtmlElement/vdom/generateCode.js b/src/compiler/ast/HtmlElement/vdom/generateCode.js index 2ad614731..be9529107 100644 --- a/src/compiler/ast/HtmlElement/vdom/generateCode.js +++ b/src/compiler/ast/HtmlElement/vdom/generateCode.js @@ -36,13 +36,19 @@ module.exports = function(node, codegen, vdomUtil) { var body = codegen.generateCode(node.body); var tagName = codegen.generateCode(node.tagNameExpression); var attributes = codegen.generateCode(node.getAttributes()); - var properties = codegen.generateCode(node.getProperties()); var dynamicAttributes = codegen.generateCode(node.dynamicAttributes); - var key = node.key; + var key = codegen.generateCode(node.key); + var properties = node.getProperties(); var isAutoKeyed = node.isAutoKeyed; var runtimeFlags = node.runtimeFlags; var nextConstId = node.nextConstId; + if (properties) { + Object.keys(properties).forEach( + key => (properties[key] = codegen.generateCode(properties[key])) + ); + } + var builder = codegen.builder; var isKeyStatic = vdomUtil.isStaticValue(key); diff --git a/src/compiler/ast/TemplateLiteral.js b/src/compiler/ast/TemplateLiteral.js index 5b585cf1e..bbf1b17a6 100644 --- a/src/compiler/ast/TemplateLiteral.js +++ b/src/compiler/ast/TemplateLiteral.js @@ -38,35 +38,39 @@ class TemplateLiteral extends Node { } writeCode(writer) { - for (let i = 0; i <= this.quasis.length; i++) { - const quasi = this.quasis[i]; - const expr = this.expressions[i]; - if (quasi || i === 0) { - if (i > 0) writer.write("+"); - writer.write(JSON.stringify(quasi)); - } - if (expr) { - writer.write("+"); - writer.write("("); - writer.write(expr); - writer.write(")"); - } - } - writer.write("\n"); - } - - toString() { let code = ""; let quote = this.nonstandard ? '"' : "`"; - let escape = new RegExp(quote, "g"); for (let i = 0; i <= this.quasis.length; i++) { const quasi = this.quasis[i]; const expr = this.expressions[i]; - if (quasi) code += quasi.replace(escape, `\\${quote}`); + if (quasi) code += escapeQuasi(quasi, quote); if (expr) code += "${" + expr.toString() + "}"; } - return quote + code + quote; + writer.write(quote + code + quote); + writer.write("\n"); } } +function escapeQuasi(quasi, quote) { + if (!quasi) return ""; + return quasi.replace(/["`\\\n\r\u2028\u2029]|\${/g, match => { + switch (match) { + case quote: + case "${": + case "\\": + return "\\" + match; + case "\n": + return "\\n"; + case "\r": + return "\\r"; + case "\u2028": + return "\\u2028"; + case "\u2029": + return "\\u2029"; + default: + return match; + } + }); +} + module.exports = TemplateLiteral; diff --git a/src/taglibs/migrate/assign-tag.js b/src/taglibs/migrate/assign-tag.js index 508adb9c0..e44499dc7 100644 --- a/src/taglibs/migrate/assign-tag.js +++ b/src/taglibs/migrate/assign-tag.js @@ -24,7 +24,12 @@ module.exports = function migrator(elNode, context) { value: attr.value == null ? attr.name - : `${attr.name} = ${printJS(attr.value, context)}` + : `${attr.name} = ${printJS( + attr.value, + context, + null, + true + )}` }) ); }); diff --git a/src/taglibs/migrate/util/printJS.js b/src/taglibs/migrate/util/printJS.js index fee69b77e..d5e1a6f89 100644 --- a/src/taglibs/migrate/util/printJS.js +++ b/src/taglibs/migrate/util/printJS.js @@ -1,6 +1,9 @@ const CodeWriter = require("../../../compiler/CodeWriter"); +const CodeGenerator = require("../../../compiler/CodeGenerator"); module.exports = function(node, context, options) { + const codeGenerator = new CodeGenerator(context); + node = codeGenerator.generateCode(node); const writer = new CodeWriter( Object.assign({}, context.options, options), context.builder diff --git a/test/codegen/fixtures/templateLiteral/expected.js b/test/codegen/fixtures/templateLiteral/expected.js new file mode 100644 index 000000000..47e06b67c --- /dev/null +++ b/test/codegen/fixtures/templateLiteral/expected.js @@ -0,0 +1,8 @@ +`hello ${name}` +`hello \${name}` +`hello \\${name}` +`hello "\`"` +"hello ${name}" +"hello \${name}" +"hello \\${name}" +"hello \"`\"" diff --git a/test/codegen/fixtures/templateLiteral/index.js b/test/codegen/fixtures/templateLiteral/index.js new file mode 100644 index 000000000..b656d3a9d --- /dev/null +++ b/test/codegen/fixtures/templateLiteral/index.js @@ -0,0 +1,52 @@ +"use strict"; + +module.exports = function(builder) { + var templateLiteral = builder.templateLiteral( + ["hello ", ""], + [builder.identifier("name")] + ); + var templateLiteralEscape = builder.templateLiteral(["hello ${name}"], []); + var templateLiteralEscape2 = builder.templateLiteral( + ["hello \\", ""], + [builder.identifier("name")] + ); + var templateLiteralEscapeQuotes = builder.templateLiteral( + ['hello "`"'], + [] + ); + + var nsTemplateLiteral = builder.templateLiteral( + ["hello ", ""], + [builder.identifier("name")] + ); + var nsTemplateLiteralEscape = builder.templateLiteral( + ["hello ${name}"], + [] + ); + var nsTemplateLiteralEscape2 = builder.templateLiteral( + ["hello \\", ""], + [builder.identifier("name")] + ); + var nsTemplateLiteralEscapeQuotes = builder.templateLiteral( + ['hello "`"'], + [] + ); + + nsTemplateLiteral.nonstandard = true; + nsTemplateLiteralEscape.nonstandard = true; + nsTemplateLiteralEscape2.nonstandard = true; + nsTemplateLiteralEscapeQuotes.nonstandard = true; + + return [ + templateLiteral, + templateLiteralEscape, + templateLiteralEscape2, + templateLiteralEscapeQuotes, + nsTemplateLiteral, + nsTemplateLiteralEscape, + nsTemplateLiteralEscape2, + nsTemplateLiteralEscapeQuotes + ]; +}; + +module.exports.skipCodegen = true; diff --git a/test/codegen/index.test.js b/test/codegen/index.test.js index 7bb7a6804..624752e6a 100644 --- a/test/codegen/index.test.js +++ b/test/codegen/index.test.js @@ -30,6 +30,7 @@ autotest("fixtures", fixture => { test(done => { var main = require(resolve("index.js")); var generateCodeFunc = main; + var skipCodegen = main.skipCodegen === true; var context = new CompileContext( "dummy", @@ -40,7 +41,7 @@ autotest("fixtures", fixture => { var codeWriter = createCodeWriter(context); var ast = generateCodeFunc(builder, codegen); - var finalAST = codegen.generateCode(ast); + var finalAST = skipCodegen ? ast : codegen.generateCode(ast); codeWriter.write(finalAST);