From 144c352863b75b75d513c8f080b8b19881e5dbde Mon Sep 17 00:00:00 2001 From: Dylan Piercey Date: Fri, 3 Apr 2020 11:36:27 -0700 Subject: [PATCH] fix: regression with nullish values in partial string attribute values (#1537) (cherry picked from commit a469e020cc60089bae73bf1a311a8e6919bc0ce0) --- .../marko/src/runtime/html/AsyncStream.js | 8 +++-- .../marko/src/runtime/html/StringWriter.js | 3 +- .../marko/src/runtime/html/helpers/attr.js | 6 ++-- .../src/runtime/html/helpers/data-marko.js | 6 ++-- .../src/runtime/html/helpers/escape-quotes.js | 35 +++++++++++++++++++ .../src/runtime/html/helpers/escape-xml.js | 32 +++-------------- .../src/runtime/html/helpers/props-script.js | 2 +- .../attr-value-partial-string/expected.html | 1 + .../attr-value-partial-string/template.marko | 2 ++ .../attr-value-partial-string/test.js | 1 + .../vdom-expected.html | 2 ++ .../src/tag/native-tag[html]/attributes.js | 20 +++-------- 12 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 packages/marko/src/runtime/html/helpers/escape-quotes.js create mode 100644 packages/marko/test/render/fixtures/attr-value-partial-string/expected.html create mode 100644 packages/marko/test/render/fixtures/attr-value-partial-string/template.marko create mode 100644 packages/marko/test/render/fixtures/attr-value-partial-string/test.js create mode 100644 packages/marko/test/render/fixtures/attr-value-partial-string/vdom-expected.html diff --git a/packages/marko/src/runtime/html/AsyncStream.js b/packages/marko/src/runtime/html/AsyncStream.js index 46e1a48575..383597bd6d 100644 --- a/packages/marko/src/runtime/html/AsyncStream.js +++ b/packages/marko/src/runtime/html/AsyncStream.js @@ -6,7 +6,9 @@ var defaultDocument = typeof document != "undefined" && document; var RenderResult = require("../RenderResult"); var attrsHelper = require("./helpers/attrs"); var markoAttr = require("./helpers/data-marko"); -var escapeXml = require("./helpers/escape-xml").x; +var escapeXmlHelper = require("./helpers/escape-xml"); +var escapeXmlOrNullish = escapeXmlHelper.x; +var escapeXmlString = escapeXmlHelper.___escapeXML; var selfClosingTags = require("self-closing-tags"); var voidWriter = { write: function() {} }; @@ -551,12 +553,12 @@ var proto = (AsyncStream.prototype = { }, text: function(str) { - this.write(escapeXml(str)); + this.write(escapeXmlOrNullish(str)); }, ___beginFragment: function(key, component, preserve) { if (preserve) { - this.write(""); + this.write(""); } if (this._elStack) { this._elStack.push(preserve); diff --git a/packages/marko/src/runtime/html/StringWriter.js b/packages/marko/src/runtime/html/StringWriter.js index 7cb6beec2c..92a4f947d3 100644 --- a/packages/marko/src/runtime/html/StringWriter.js +++ b/packages/marko/src/runtime/html/StringWriter.js @@ -1,6 +1,7 @@ "use strict"; -var escapeDoubleQuotes = require("./helpers/escape-xml").d; +var escapeDoubleQuotes = require("./helpers/escape-quotes") + .___escapeDoubleQuotes; function StringWriter() { this._content = ""; diff --git a/packages/marko/src/runtime/html/helpers/attr.js b/packages/marko/src/runtime/html/helpers/attr.js index ab429417ec..a8c41f49fa 100644 --- a/packages/marko/src/runtime/html/helpers/attr.js +++ b/packages/marko/src/runtime/html/helpers/attr.js @@ -1,8 +1,8 @@ "use strict"; -var escape = require("./escape-xml"); -var escapeDoubleQuotes = escape.d; -var escapeSingleQuotes = escape.s; +var escapeQuoteHelpers = require("./escape-quotes"); +var escapeDoubleQuotes = escapeQuoteHelpers.___escapeDoubleQuotes; +var escapeSingleQuotes = escapeQuoteHelpers.___escapeSingleQuotes; module.exports = function attr(name, value) { switch (typeof value) { diff --git a/packages/marko/src/runtime/html/helpers/data-marko.js b/packages/marko/src/runtime/html/helpers/data-marko.js index 403ee3fd2b..b87485cd7c 100644 --- a/packages/marko/src/runtime/html/helpers/data-marko.js +++ b/packages/marko/src/runtime/html/helpers/data-marko.js @@ -1,8 +1,8 @@ "use strict"; -var escapeXml = require("./escape-xml"); -var escapeSingleQuotes = escapeXml.s; -var escapeDoubleQuotes = escapeXml.d; +var escapeQuoteHelpers = require("./escape-quotes"); +var escapeSingleQuotes = escapeQuoteHelpers.___escapeSingleQuotes; +var escapeDoubleQuotes = escapeQuoteHelpers.___escapeDoubleQuotes; var FLAG_WILL_RERENDER_IN_BROWSER = 1; // var FLAG_HAS_BODY_EL = 2; // var FLAG_HAS_HEAD_EL = 4; diff --git a/packages/marko/src/runtime/html/helpers/escape-quotes.js b/packages/marko/src/runtime/html/helpers/escape-quotes.js new file mode 100644 index 0000000000..f98d74445c --- /dev/null +++ b/packages/marko/src/runtime/html/helpers/escape-quotes.js @@ -0,0 +1,35 @@ +"use strict"; + +exports.d = function(value) { + return escapeDoubleQuotes(value + ""); +}; + +exports.___escapeDoubleQuotes = escapeDoubleQuotes; + +exports.___escapeSingleQuotes = escapeSingleQuotes; + +function escapeSingleQuotes(value) { + return escapeQuote(value, "'", "'"); +} + +function escapeDoubleQuotes(value) { + return escapeQuote(value, '"', """); +} + +function escapeQuote(str, quote, escaped) { + var result = ""; + var lastPos = 0; + + for (var i = 0, len = str.length; i < len; i++) { + if (str[i] === quote) { + result += str.slice(lastPos, i) + escaped; + lastPos = i + 1; + } + } + + if (lastPos) { + return result + str.slice(lastPos); + } + + return str; +} diff --git a/packages/marko/src/runtime/html/helpers/escape-xml.js b/packages/marko/src/runtime/html/helpers/escape-xml.js index b91d73e091..b20458b355 100644 --- a/packages/marko/src/runtime/html/helpers/escape-xml.js +++ b/packages/marko/src/runtime/html/helpers/escape-xml.js @@ -1,14 +1,6 @@ "use strict"; -exports.d = function(value) { - return escapeQuote(value, '"', """); -}; - -exports.s = function(value) { - return escapeQuote(value, "'", "'"); -}; - -exports.x = function(value) { +module.exports.x = function(value) { if (value == null) { return ""; } @@ -17,28 +9,12 @@ exports.x = function(value) { return value.toHTML(); } - return escapeBody(value + ""); + return escapeXML(value + ""); }; -function escapeQuote(str, quote, escaped) { - var result = ""; - var lastPos = 0; - - for (var i = 0, len = str.length; i < len; i++) { - if (str[i] === quote) { - result += str.slice(lastPos, i) + escaped; - lastPos = i + 1; - } - } - - if (lastPos) { - return result + str.slice(lastPos); - } - - return str; -} +exports.___escapeXML = escapeXML; -function escapeBody(str) { +function escapeXML(str) { var len = str.length; var result = ""; var lastPos = 0; diff --git a/packages/marko/src/runtime/html/helpers/props-script.js b/packages/marko/src/runtime/html/helpers/props-script.js index 9200676162..6b32176a59 100644 --- a/packages/marko/src/runtime/html/helpers/props-script.js +++ b/packages/marko/src/runtime/html/helpers/props-script.js @@ -1,6 +1,6 @@ "use strict"; -var escapeDoubleQuotes = require("./escape-xml").d; +var escapeDoubleQuotes = require("./escape-quotes").___escapeDoubleQuotes; var escapeScript = require("./escape-script-placeholder"); var assignPropsFunction = ` function ap_(p) { diff --git a/packages/marko/test/render/fixtures/attr-value-partial-string/expected.html b/packages/marko/test/render/fixtures/attr-value-partial-string/expected.html new file mode 100644 index 0000000000..0e73ea626f --- /dev/null +++ b/packages/marko/test/render/fixtures/attr-value-partial-string/expected.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/packages/marko/test/render/fixtures/attr-value-partial-string/template.marko b/packages/marko/test/render/fixtures/attr-value-partial-string/template.marko new file mode 100644 index 0000000000..efcfe40b1e --- /dev/null +++ b/packages/marko/test/render/fixtures/attr-value-partial-string/template.marko @@ -0,0 +1,2 @@ +
+
diff --git a/packages/marko/test/render/fixtures/attr-value-partial-string/test.js b/packages/marko/test/render/fixtures/attr-value-partial-string/test.js new file mode 100644 index 0000000000..af716664c4 --- /dev/null +++ b/packages/marko/test/render/fixtures/attr-value-partial-string/test.js @@ -0,0 +1 @@ +exports.templateData = { text: null }; diff --git a/packages/marko/test/render/fixtures/attr-value-partial-string/vdom-expected.html b/packages/marko/test/render/fixtures/attr-value-partial-string/vdom-expected.html new file mode 100644 index 0000000000..35bc16d540 --- /dev/null +++ b/packages/marko/test/render/fixtures/attr-value-partial-string/vdom-expected.html @@ -0,0 +1,2 @@ +
+
diff --git a/packages/translator-default/src/tag/native-tag[html]/attributes.js b/packages/translator-default/src/tag/native-tag[html]/attributes.js index c364bd09b3..74422f4c94 100644 --- a/packages/translator-default/src/tag/native-tag[html]/attributes.js +++ b/packages/translator-default/src/tag/native-tag[html]/attributes.js @@ -1,9 +1,6 @@ import { types as t } from "@marko/babel-types"; import { normalizeTemplateString } from "@marko/babel-utils"; -import { - d as escapeDoubleQuoteAttr, - s as escapeSingleQuoteAttr -} from "marko/src/runtime/html/helpers/escape-xml"; +import attrHelper from "marko/src/runtime/html/helpers/attr"; import { evaluateAttr } from "../util"; export default function(path, attrs) { @@ -40,19 +37,10 @@ export default function(path, attrs) { continue; } - curString += ` ${name}`; - - if (computed === "") { - attrsObject.properties.push( - t.objectProperty(t.stringLiteral(name), t.booleanLiteral(true)) - ); - } else { - curString += - attr.get("value").isObjectExpression() || - attr.get("value").isArrayExpression() - ? `='${escapeSingleQuoteAttr(computed)}'` - : `="${escapeDoubleQuoteAttr(computed)}"`; + const attrString = attrHelper(name, computed); + curString += attrString; + if (attrString) { attrsObject.properties.push( t.objectProperty(t.stringLiteral(name), value) );