From bae4a3d388412e387514ce11416f4e6cbddecd28 Mon Sep 17 00:00:00 2001 From: Dylan Piercey Date: Mon, 12 Oct 2020 10:24:03 -0700 Subject: [PATCH] fix: dynamic tag html attr normalize --- packages/babel-utils/src/tags.js | 4 + .../translator-default/src/tag/custom-tag.js | 4 +- .../translator-default/src/tag/dynamic-tag.js | 143 +---------------- packages/translator-default/src/tag/index.js | 146 +++++++++++++++++- .../translator-default/src/tag/native-tag.js | 6 +- .../src/tag/native-tag[html]/index.js | 3 +- .../src/tag/native-tag[vdom]/index.js | 3 +- .../snapshots/cjs-expected.js | 53 +++++-- .../snapshots/generated-expected.marko | 34 ++-- .../snapshots/html-expected.js | 52 +++++-- .../snapshots/htmlProduction-expected.js | 52 +++++-- .../snapshots/vdom-expected.js | 84 ++++++++-- .../snapshots/vdomProduction-expected.js | 84 ++++++++-- .../fixtures/dynamic-tag-name/template.marko | 34 ++-- 14 files changed, 431 insertions(+), 271 deletions(-) diff --git a/packages/babel-utils/src/tags.js b/packages/babel-utils/src/tags.js index 05ea8176d..68cf1279e 100644 --- a/packages/babel-utils/src/tags.js +++ b/packages/babel-utils/src/tags.js @@ -4,6 +4,10 @@ const TRANSPARENT_TAGS = new Set(["for", "while", "if", "else", "_no-update"]); const MACROS = new WeakMap(); export function isNativeTag(path) { + if (path.node._isDynamicString) { + return true; + } + const tagDef = getTagDef(path); return ( tagDef && diff --git a/packages/translator-default/src/tag/custom-tag.js b/packages/translator-default/src/tag/custom-tag.js index 51eb73f9e..6bda2dcbc 100644 --- a/packages/translator-default/src/tag/custom-tag.js +++ b/packages/translator-default/src/tag/custom-tag.js @@ -12,13 +12,13 @@ import withPreviousLocation from "../util/with-previous-location"; // TODO: support transform and other entries. const TAG_FILE_ENTRIES = ["template", "renderer"]; -export default function(path) { +export default function(path, isNullable) { const { hub: { file }, node } = path; const { metadata, markoOpts } = file; - const { name, key, isNullable } = node; + const { name, key } = node; assertNoArgs(path); diff --git a/packages/translator-default/src/tag/dynamic-tag.js b/packages/translator-default/src/tag/dynamic-tag.js index 97ced0a9f..220a94c12 100644 --- a/packages/translator-default/src/tag/dynamic-tag.js +++ b/packages/translator-default/src/tag/dynamic-tag.js @@ -1,12 +1,7 @@ -import nodePath from "path"; import { types as t } from "@marko/babel-types"; import { importDefault } from "@marko/babel-utils"; import { getAttrs, buildEventHandlerArray } from "./util"; import withPreviousLocation from "../util/with-previous-location"; -import nativeTag from "./native-tag"; -import customTag from "./custom-tag"; - -const HANDLE_BINDINGS = ["module", "var", "let", "const"]; export default function(path) { const { @@ -15,35 +10,6 @@ export default function(path) { } = path; const { key, arguments: args, properties: tagProperties } = node; - const name = path.get("name"); - const types = findTypes(name); - - if (types && !(types.string && types.component)) { - let tagIdentifier; - if (name.isIdentifier()) { - tagIdentifier = name; - } else { - tagIdentifier = path.scope.generateUidIdentifier(`tagName`); - path.insertBefore( - t.variableDeclaration("const", [ - t.variableDeclarator(tagIdentifier, name.node) - ]) - ); - - name.replaceWith(tagIdentifier); - } - - path.set("isNullable", types.empty); - - if (types.string) { - nativeTag(path); - } else { - customTag(path); - } - - return; - } - const foundAttrs = getAttrs(path, true); let renderBodyProp; let attrsLen = t.isNullLiteral(foundAttrs) ? 0 : 1; @@ -70,7 +36,7 @@ export default function(path) { ), [ t.identifier("out"), - name.node, + node.name, attrsLen ? t.arrowFunctionExpression([], foundAttrs) : t.nullLiteral(), renderBodyProp ? renderBodyProp.value : t.nullLiteral(), args && args.length ? t.arrayExpression(args) : t.nullLiteral(), @@ -85,110 +51,3 @@ export default function(path) { path.replaceWith(withPreviousLocation(dynamicTagRenderCall, node)); } - -function findTypes(root) { - const pending = [root]; - const types = { - string: false, - empty: false, - component: false - }; - - let path; - while ((path = pending.pop())) { - switch (path.type) { - case "ConditionalExpression": - pending.push(path.get("consequent")); - - if (path.get("alternate").node) { - pending.push(path.get("alternate")); - } - break; - - case "LogicalExpression": - if (path.get("operator").node === "||") { - pending.push(path.get("left")); - } else { - types.empty = true; - } - - pending.push(path.get("right")); - break; - - case "AssignmentExpression": - pending.push(path.get("right")); - break; - - case "BinaryExpression": - if (path.get("operator").node !== "+") { - return false; - } - - types.string = true; - break; - - case "StringLiteral": - case "TemplateLiteral": - types.string = true; - break; - - case "NullLiteral": - types.empty = true; - break; - - case "Identifier": - if (path.get("name").node === "undefined") { - types.empty = true; - } else { - const binding = path.scope.getBinding(path.node.name); - - if (!binding || !HANDLE_BINDINGS.includes(binding.kind)) { - return false; - } - - if (binding.kind === "module") { - const importSourcePath = binding.path.parentPath.get("source"); - if ( - importSourcePath.isStringLiteral() && - isMarkoFile(importSourcePath.get("value").node) - ) { - types.component = true; - } else { - return false; - } - } else { - const initialValue = binding.path.get("init"); - if (initialValue.node) { - pending.push(initialValue); - } else { - types.empty = true; - } - - const assignments = binding.constantViolations; - if (assignments && assignments.length) { - for (const assignment of assignments) { - const operator = assignment.get("operator").node; - if (operator === "=") { - pending.push(assignment.get("right")); - } else if (operator === "+=") { - types.string = true; - } else { - return false; - } - } - } - } - } - break; - - default: - return false; - } - } - - return types; -} - -function isMarkoFile(request) { - return nodePath.extname(request) === ".marko" || /^<.*>$/.test(request); -} diff --git a/packages/translator-default/src/tag/index.js b/packages/translator-default/src/tag/index.js index 5563c9169..883a46645 100644 --- a/packages/translator-default/src/tag/index.js +++ b/packages/translator-default/src/tag/index.js @@ -1,3 +1,4 @@ +import nodePath from "path"; import { types as t } from "@marko/babel-types"; import { getTagDef, @@ -61,6 +62,31 @@ export default { getKeyManager(path).resolveKey(path); }, exit(path) { + let isUnknownDynamic = false; + let isDynamicNullable = false; + + if (isDynamicTag(path)) { + const name = path.get("name"); + const types = findDynamicTagTypes(name); + if (types && !(types.string && types.component)) { + if (!name.isIdentifier()) { + const tagIdentifier = path.scope.generateUidIdentifier(`tagName`); + path.insertBefore( + t.variableDeclaration("const", [ + t.variableDeclarator(tagIdentifier, name.node) + ]) + ); + + name.replaceWith(tagIdentifier); + } + + isDynamicNullable = types.empty; + path.node._isDynamicString = types.string; + } else { + isUnknownDynamic = true; + } + } + for (const attr of path.get("attributes")) { if (attr.isMarkoAttribute()) { const { node } = path; @@ -71,7 +97,7 @@ export default { } } - if (isDynamicTag(path)) { + if (isUnknownDynamic) { return dynamicTag(path); } @@ -94,12 +120,120 @@ export default { if (path.node !== node) { return; } - - if (isNativeTag(path)) { - return nativeTag(path); - } } - customTag(path); + if (isNativeTag(path)) { + return nativeTag(path, isDynamicNullable); + } else { + return customTag(path, isDynamicNullable); + } } }; + +const HANDLE_BINDINGS = ["module", "var", "let", "const"]; +function findDynamicTagTypes(root) { + const pending = [root]; + const types = { + string: false, + empty: false, + component: false + }; + + let path; + while ((path = pending.pop())) { + switch (path.type) { + case "ConditionalExpression": + pending.push(path.get("consequent")); + + if (path.get("alternate").node) { + pending.push(path.get("alternate")); + } + break; + + case "LogicalExpression": + if (path.get("operator").node === "||") { + pending.push(path.get("left")); + } else { + types.empty = true; + } + + pending.push(path.get("right")); + break; + + case "AssignmentExpression": + pending.push(path.get("right")); + break; + + case "BinaryExpression": + if (path.get("operator").node !== "+") { + return false; + } + + types.string = true; + break; + + case "StringLiteral": + case "TemplateLiteral": + types.string = true; + break; + + case "NullLiteral": + types.empty = true; + break; + + case "Identifier": + if (path.get("name").node === "undefined") { + types.empty = true; + } else { + const binding = path.scope.getBinding(path.node.name); + + if (!binding || !HANDLE_BINDINGS.includes(binding.kind)) { + return false; + } + + if (binding.kind === "module") { + const importSourcePath = binding.path.parentPath.get("source"); + if ( + importSourcePath.isStringLiteral() && + isMarkoFile(importSourcePath.get("value").node) + ) { + types.component = true; + } else { + return false; + } + } else { + const initialValue = binding.path.get("init"); + if (initialValue.node) { + pending.push(initialValue); + } else { + types.empty = true; + } + + const assignments = binding.constantViolations; + if (assignments && assignments.length) { + for (const assignment of assignments) { + const operator = assignment.get("operator").node; + if (operator === "=") { + pending.push(assignment.get("right")); + } else if (operator === "+=") { + types.string = true; + } else { + return false; + } + } + } + } + } + break; + + default: + return false; + } + } + + return types; +} + +function isMarkoFile(request) { + return nodePath.extname(request) === ".marko" || /^<.*>$/.test(request); +} diff --git a/packages/translator-default/src/tag/native-tag.js b/packages/translator-default/src/tag/native-tag.js index 785faa520..b23ba6ae6 100644 --- a/packages/translator-default/src/tag/native-tag.js +++ b/packages/translator-default/src/tag/native-tag.js @@ -6,7 +6,7 @@ import { assertNoArgs } from "@marko/babel-utils"; -export default function(path) { +export default function(path, isNullable) { const { hub: { file } } = path; @@ -19,8 +19,8 @@ export default function(path) { } if (markoOpts.output === "html") { - nativeTagHtml(path); + nativeTagHtml(path, isNullable); } else { - nativeTagVdom(path); + nativeTagVdom(path, isNullable); } } diff --git a/packages/translator-default/src/tag/native-tag[html]/index.js b/packages/translator-default/src/tag/native-tag[html]/index.js index c28caf607..fe2e7aff6 100644 --- a/packages/translator-default/src/tag/native-tag[html]/index.js +++ b/packages/translator-default/src/tag/native-tag[html]/index.js @@ -17,7 +17,7 @@ const EMPTY_OBJECT = {}; /** * Translates the html streaming version of a standard html element. */ -export default function(path) { +export default function(path, isNullable) { const { hub: { file }, node @@ -26,7 +26,6 @@ export default function(path) { key, name, body: { body }, - isNullable, properties, handlers } = node; diff --git a/packages/translator-default/src/tag/native-tag[vdom]/index.js b/packages/translator-default/src/tag/native-tag[vdom]/index.js index 2cecc673d..0077ea214 100644 --- a/packages/translator-default/src/tag/native-tag[vdom]/index.js +++ b/packages/translator-default/src/tag/native-tag[vdom]/index.js @@ -22,7 +22,7 @@ const MAYBE_SVG = { /** * Translates the html streaming version of a standard html element. */ -export default function(path) { +export default function(path, isNullable) { const { hub: { file }, node, @@ -32,7 +32,6 @@ export default function(path) { name, key, body: { body }, - isNullable, properties, handlers } = node; diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/cjs-expected.js b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/cjs-expected.js index a4488d10c..d7c4e1d38 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/cjs-expected.js +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/cjs-expected.js @@ -9,6 +9,8 @@ var _index2 = _interopRequireDefault(require("./components/tag-b/index.marko")); var _dynamicTag = _interopRequireDefault(require("marko/src/runtime/helpers/dynamic-tag")); +var _attr = _interopRequireDefault(require("marko/src/runtime/html/helpers/attr")); + var _renderTag = _interopRequireDefault(require("marko/src/runtime/helpers/render-tag")); var _renderer = _interopRequireDefault(require("marko/src/runtime/components/renderer")); @@ -24,28 +26,42 @@ exports.default = _default; const _marko_componentType = "packages/translator-default/test/fixtures/dynamic-tag-name/template.marko", _marko_component = {}; _marko_template._ = (0, _renderer.default)(function (input, out, _component, component, state) { - (0, _dynamicTag.default)(out, input, null, null, null, null, _component, "0"); - (0, _dynamicTag.default)(out, input.x, null, null, null, null, _component, "1"); + (0, _dynamicTag.default)(out, input, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "0"); + (0, _dynamicTag.default)(out, input.x, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "1"); const _tagName = input.show ? "div" : null; - if (_tagName) out.w(`<${_tagName}>`);else out.bf("f_2", component); + if (_tagName) out.w(`<${_tagName} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_2", component); const _tagName2 = input.show && "div"; - if (_tagName2) out.w(`<${_tagName2}>`);else out.bf("f_3", component); + if (_tagName2) out.w(`<${_tagName2} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_3", component); const _tagName3 = input.large ? "h1" : "h2"; - out.w(`<${_tagName3}>`); + out.w(`<${_tagName3} class="a b"${(0, _attr.default)("other", input.other)}>`); const _tagName4 = input.showTagA ? _index.default : _index2.default; - (0, _renderTag.default)(_tagName4, {}, out, _component, "5"); + (0, _renderTag.default)(_tagName4, { + "class": ["a", "b"], + "other": input.other, + "class": ["a", "b"], + "other": input.other + }, out, _component, "5"); const _tagName5 = input.showTagA && _index.default; - if (_tagName5) (0, _renderTag.default)(_tagName5, {}, out, _component, "6"); + if (_tagName5) (0, _renderTag.default)(_tagName5, { + "class": ["a", "b"], + "other": input.other + }, out, _component, "6"); const _tagName6 = input.showTagA && _index.default; @@ -54,33 +70,38 @@ _marko_template._ = (0, _renderer.default)(function (input, out, _component, com }; if (_tagName6) (0, _renderTag.default)(_tagName6, { + "class": ["a", "b"], + "other": input.other, "renderBody": _renderBody }, out, _component, "7");else _renderBody(out); - (0, _dynamicTag.default)(out, input.tag || _index.default, null, null, null, null, _component, "8"); + (0, _dynamicTag.default)(out, input.tag || _index.default, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "8"); const largeHeading = input.isLarge && "h1"; const _tagName7 = largeHeading || "h2"; - if (_tagName7) out.w(`<${_tagName7}>`);else out.bf("f_9", component); + if (_tagName7) out.w(`<${_tagName7} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_9", component); const _tagName8 = global.x = "a" + "b"; - out.w(`<${_tagName8}>`); + out.w(`<${_tagName8} class="a b"${(0, _attr.default)("other", input.other)}>`); const _tagName9 = "h" + input.level; - out.w(`<${_tagName9}>`); + out.w(`<${_tagName9} class="a b"${(0, _attr.default)("other", input.other)}>`); const _tagName10 = `h${input.level}`; - out.w(`<${_tagName10}>`); + out.w(`<${_tagName10} class="a b"${(0, _attr.default)("other", input.other)}>`); const tagConstA = "a"; - out.w(`<${tagConstA}>`); + out.w(`<${tagConstA} class="a b"${(0, _attr.default)("other", input.other)}>`); const tagConstB = input.show ? "div" : null; - if (tagConstB) out.w(`<${tagConstB}>`);else out.bf("f_14", component); + if (tagConstB) out.w(`<${tagConstB} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_14", component); let tagLazyAssign; tagLazyAssign = "a"; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_15", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_15", component); tagLazyAssign = input.show ? "div" : null; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_16", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${(0, _attr.default)("other", input.other)}>`);else out.bf("f_16", component); }, { t: _marko_componentType, i: true diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/generated-expected.marko b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/generated-expected.marko index 0d3c551cf..d50efd1b6 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/generated-expected.marko +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/generated-expected.marko @@ -1,27 +1,27 @@ import tagA from "./components/tag-a/index.marko"; import tagB from "./components/tag-b/index.marko"; -<${input}/> -<${input.x}/> -<${input.show ? "div" : null}/> -<${input.show && "div"}/> -<${input.large ? "h1" : "h2"}/> -<${input.showTagA ? tagA : tagB}/> -<${input.showTagA && tagA}/> -<${input.showTagA && tagA}> +<${input} class=["a", "b"] other=input.other/> +<${input.x} class=["a", "b"] other=input.other/> +<${input.show ? "div" : null} class=["a", "b"] other=input.other/> +<${input.show && "div"} class=["a", "b"] other=input.other/> +<${input.large ? "h1" : "h2"} class=["a", "b"] other=input.other/> +<${input.showTagA ? tagA : tagB} class=["a", "b"] other=input.other class=["a", "b"] other=input.other/> +<${input.showTagA && tagA} class=["a", "b"] other=input.other/> +<${input.showTagA && tagA} class=["a", "b"] other=input.other> Body content -<${input.tag || tagA}/> +<${input.tag || tagA} class=["a", "b"] other=input.other/> $ const largeHeading = input.isLarge && "h1"; -<${largeHeading || "h2"}/> -<${global.x = "a" + "b"}/> -<${"h" + input.level}/> -<${`h${input.level}`}/> +<${largeHeading || "h2"} class=["a", "b"] other=input.other/> +<${global.x = "a" + "b"} class=["a", "b"] other=input.other/> +<${"h" + input.level} class=["a", "b"] other=input.other/> +<${`h${input.level}`} class=["a", "b"] other=input.other/> $ const tagConstA = "a"; -<${tagConstA}/> +<${tagConstA} class=["a", "b"] other=input.other/> $ const tagConstB = input.show ? "div" : null; -<${tagConstB}/> +<${tagConstB} class=["a", "b"] other=input.other/> $ let tagLazyAssign; $ tagLazyAssign = "a"; -<${tagLazyAssign}/> +<${tagLazyAssign} class=["a", "b"] other=input.other/> $ tagLazyAssign = input.show ? "div" : null; -<${tagLazyAssign}/> \ No newline at end of file +<${tagLazyAssign} class=["a", "b"] other=input.other/> \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/html-expected.js b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/html-expected.js index c8a2c3b7d..283207cec 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/html-expected.js +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/html-expected.js @@ -4,35 +4,50 @@ export default _marko_template; import tagA from "./components/tag-a/index.marko"; import tagB from "./components/tag-b/index.marko"; import _marko_dynamic_tag from "marko/src/runtime/helpers/dynamic-tag"; +import _marko_attr from "marko/src/runtime/html/helpers/attr"; import _marko_tag from "marko/src/runtime/helpers/render-tag"; import _marko_renderer from "marko/src/runtime/components/renderer"; import { t as _t } from "marko/src/runtime/html"; const _marko_componentType = "packages/translator-default/test/fixtures/dynamic-tag-name/template.marko", _marko_component = {}; _marko_template._ = _marko_renderer(function (input, out, _component, component, state) { - _marko_dynamic_tag(out, input, null, null, null, null, _component, "0"); + _marko_dynamic_tag(out, input, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "0"); - _marko_dynamic_tag(out, input.x, null, null, null, null, _component, "1"); + _marko_dynamic_tag(out, input.x, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "1"); const _tagName = input.show ? "div" : null; - if (_tagName) out.w(`<${_tagName}>`);else out.bf("f_2", component); + if (_tagName) out.w(`<${_tagName} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_2", component); const _tagName2 = input.show && "div"; - if (_tagName2) out.w(`<${_tagName2}>`);else out.bf("f_3", component); + if (_tagName2) out.w(`<${_tagName2} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_3", component); const _tagName3 = input.large ? "h1" : "h2"; - out.w(`<${_tagName3}>`); + out.w(`<${_tagName3} class="a b"${_marko_attr("other", input.other)}>`); const _tagName4 = input.showTagA ? tagA : tagB; - _marko_tag(_tagName4, {}, out, _component, "5"); + _marko_tag(_tagName4, { + "class": ["a", "b"], + "other": input.other, + "class": ["a", "b"], + "other": input.other + }, out, _component, "5"); const _tagName5 = input.showTagA && tagA; - if (_tagName5) _marko_tag(_tagName5, {}, out, _component, "6"); + if (_tagName5) _marko_tag(_tagName5, { + "class": ["a", "b"], + "other": input.other + }, out, _component, "6"); const _tagName6 = input.showTagA && tagA; @@ -41,35 +56,40 @@ _marko_template._ = _marko_renderer(function (input, out, _component, component, }; if (_tagName6) _marko_tag(_tagName6, { + "class": ["a", "b"], + "other": input.other, "renderBody": _renderBody }, out, _component, "7");else _renderBody(out); - _marko_dynamic_tag(out, input.tag || tagA, null, null, null, null, _component, "8"); + _marko_dynamic_tag(out, input.tag || tagA, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "8"); const largeHeading = input.isLarge && "h1"; const _tagName7 = largeHeading || "h2"; - if (_tagName7) out.w(`<${_tagName7}>`);else out.bf("f_9", component); + if (_tagName7) out.w(`<${_tagName7} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_9", component); const _tagName8 = global.x = "a" + "b"; - out.w(`<${_tagName8}>`); + out.w(`<${_tagName8} class="a b"${_marko_attr("other", input.other)}>`); const _tagName9 = "h" + input.level; - out.w(`<${_tagName9}>`); + out.w(`<${_tagName9} class="a b"${_marko_attr("other", input.other)}>`); const _tagName10 = `h${input.level}`; - out.w(`<${_tagName10}>`); + out.w(`<${_tagName10} class="a b"${_marko_attr("other", input.other)}>`); const tagConstA = "a"; - out.w(`<${tagConstA}>`); + out.w(`<${tagConstA} class="a b"${_marko_attr("other", input.other)}>`); const tagConstB = input.show ? "div" : null; - if (tagConstB) out.w(`<${tagConstB}>`);else out.bf("f_14", component); + if (tagConstB) out.w(`<${tagConstB} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_14", component); let tagLazyAssign; tagLazyAssign = "a"; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_15", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_15", component); tagLazyAssign = input.show ? "div" : null; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_16", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_16", component); }, { t: _marko_componentType, i: true diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/htmlProduction-expected.js b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/htmlProduction-expected.js index e07c4f2fa..fe3e9d019 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/htmlProduction-expected.js +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/htmlProduction-expected.js @@ -4,35 +4,50 @@ export default _marko_template; import tagA from "./components/tag-a/index.marko"; import tagB from "./components/tag-b/index.marko"; import _marko_dynamic_tag from "marko/dist/runtime/helpers/dynamic-tag"; +import _marko_attr from "marko/dist/runtime/html/helpers/attr"; import _marko_tag from "marko/dist/runtime/helpers/render-tag"; import _marko_renderer from "marko/dist/runtime/components/renderer"; import { t as _t } from "marko/dist/runtime/html"; const _marko_componentType = "FiPq+pCl", _marko_component = {}; _marko_template._ = _marko_renderer(function (input, out, _component, component, state) { - _marko_dynamic_tag(out, input, null, null, null, null, _component, "0"); + _marko_dynamic_tag(out, input, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "0"); - _marko_dynamic_tag(out, input.x, null, null, null, null, _component, "1"); + _marko_dynamic_tag(out, input.x, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "1"); const _tagName = input.show ? "div" : null; - if (_tagName) out.w(`<${_tagName}>`);else out.bf("f_2", component); + if (_tagName) out.w(`<${_tagName} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_2", component); const _tagName2 = input.show && "div"; - if (_tagName2) out.w(`<${_tagName2}>`);else out.bf("f_3", component); + if (_tagName2) out.w(`<${_tagName2} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_3", component); const _tagName3 = input.large ? "h1" : "h2"; - out.w(`<${_tagName3}>`); + out.w(`<${_tagName3} class="a b"${_marko_attr("other", input.other)}>`); const _tagName4 = input.showTagA ? tagA : tagB; - _marko_tag(_tagName4, {}, out, _component, "5"); + _marko_tag(_tagName4, { + "class": ["a", "b"], + "other": input.other, + "class": ["a", "b"], + "other": input.other + }, out, _component, "5"); const _tagName5 = input.showTagA && tagA; - if (_tagName5) _marko_tag(_tagName5, {}, out, _component, "6"); + if (_tagName5) _marko_tag(_tagName5, { + "class": ["a", "b"], + "other": input.other + }, out, _component, "6"); const _tagName6 = input.showTagA && tagA; @@ -41,35 +56,40 @@ _marko_template._ = _marko_renderer(function (input, out, _component, component, }; if (_tagName6) _marko_tag(_tagName6, { + "class": ["a", "b"], + "other": input.other, "renderBody": _renderBody }, out, _component, "7");else _renderBody(out); - _marko_dynamic_tag(out, input.tag || tagA, null, null, null, null, _component, "8"); + _marko_dynamic_tag(out, input.tag || tagA, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "8"); const largeHeading = input.isLarge && "h1"; const _tagName7 = largeHeading || "h2"; - if (_tagName7) out.w(`<${_tagName7}>`);else out.bf("f_9", component); + if (_tagName7) out.w(`<${_tagName7} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_9", component); const _tagName8 = global.x = "a" + "b"; - out.w(`<${_tagName8}>`); + out.w(`<${_tagName8} class="a b"${_marko_attr("other", input.other)}>`); const _tagName9 = "h" + input.level; - out.w(`<${_tagName9}>`); + out.w(`<${_tagName9} class="a b"${_marko_attr("other", input.other)}>`); const _tagName10 = `h${input.level}`; - out.w(`<${_tagName10}>`); + out.w(`<${_tagName10} class="a b"${_marko_attr("other", input.other)}>`); const tagConstA = "a"; - out.w(`<${tagConstA}>`); + out.w(`<${tagConstA} class="a b"${_marko_attr("other", input.other)}>`); const tagConstB = input.show ? "div" : null; - if (tagConstB) out.w(`<${tagConstB}>`);else out.bf("f_14", component); + if (tagConstB) out.w(`<${tagConstB} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_14", component); let tagLazyAssign; tagLazyAssign = "a"; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_15", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_15", component); tagLazyAssign = input.show ? "div" : null; - if (tagLazyAssign) out.w(`<${tagLazyAssign}>`);else out.bf("f_16", component); + if (tagLazyAssign) out.w(`<${tagLazyAssign} class="a b"${_marko_attr("other", input.other)}>`);else out.bf("f_16", component); }, { t: _marko_componentType, i: true diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdom-expected.js b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdom-expected.js index 47b71e23b..5bb432d5c 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdom-expected.js +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdom-expected.js @@ -13,29 +13,52 @@ const _marko_componentType = _marko_registerComponent("packages/translator-defau _marko_component = {}; _marko_template._ = _marko_renderer(function (input, out, _component, component, state) { - _marko_dynamic_tag(out, input, null, null, null, null, _component, "0"); + _marko_dynamic_tag(out, input, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "0"); - _marko_dynamic_tag(out, input.x, null, null, null, null, _component, "1"); + _marko_dynamic_tag(out, input.x, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "1"); const _tagName = input.show ? "div" : null; - if (_tagName) out.e(_tagName, null, "2", component, 0, 0);else out.bf("f_2", component); + if (_tagName) out.e(_tagName, { + "class": "a b", + "other": input.other + }, "2", component, 0, 0);else out.bf("f_2", component); const _tagName2 = input.show && "div"; - if (_tagName2) out.e(_tagName2, null, "3", component, 0, 0);else out.bf("f_3", component); + if (_tagName2) out.e(_tagName2, { + "class": "a b", + "other": input.other + }, "3", component, 0, 0);else out.bf("f_3", component); const _tagName3 = input.large ? "h1" : "h2"; - out.e(_tagName3, null, "4", component, 0, 0); + out.e(_tagName3, { + "class": "a b", + "other": input.other + }, "4", component, 0, 0); const _tagName4 = input.showTagA ? tagA : tagB; - _marko_tag(_tagName4, {}, out, _component, "5"); + _marko_tag(_tagName4, { + "class": ["a", "b"], + "other": input.other, + "class": ["a", "b"], + "other": input.other + }, out, _component, "5"); const _tagName5 = input.showTagA && tagA; - if (_tagName5) _marko_tag(_tagName5, {}, out, _component, "6"); + if (_tagName5) _marko_tag(_tagName5, { + "class": ["a", "b"], + "other": input.other + }, out, _component, "6"); const _tagName6 = input.showTagA && tagA; @@ -44,35 +67,64 @@ _marko_template._ = _marko_renderer(function (input, out, _component, component, }; if (_tagName6) _marko_tag(_tagName6, { + "class": ["a", "b"], + "other": input.other, "renderBody": _renderBody }, out, _component, "7");else _renderBody(out); - _marko_dynamic_tag(out, input.tag || tagA, null, null, null, null, _component, "8"); + _marko_dynamic_tag(out, input.tag || tagA, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "8"); const largeHeading = input.isLarge && "h1"; const _tagName7 = largeHeading || "h2"; - if (_tagName7) out.e(_tagName7, null, "9", component, 0, 0);else out.bf("f_9", component); + if (_tagName7) out.e(_tagName7, { + "class": "a b", + "other": input.other + }, "9", component, 0, 0);else out.bf("f_9", component); const _tagName8 = global.x = "a" + "b"; - out.e(_tagName8, null, "10", component, 0, 0); + out.e(_tagName8, { + "class": "a b", + "other": input.other + }, "10", component, 0, 0); const _tagName9 = "h" + input.level; - out.e(_tagName9, null, "11", component, 0, 0); + out.e(_tagName9, { + "class": "a b", + "other": input.other + }, "11", component, 0, 0); const _tagName10 = `h${input.level}`; - out.e(_tagName10, null, "12", component, 0, 0); + out.e(_tagName10, { + "class": "a b", + "other": input.other + }, "12", component, 0, 0); const tagConstA = "a"; - out.e(tagConstA, null, "13", component, 0, 0); + out.e(tagConstA, { + "class": "a b", + "other": input.other + }, "13", component, 0, 0); const tagConstB = input.show ? "div" : null; - if (tagConstB) out.e(tagConstB, null, "14", component, 0, 0);else out.bf("f_14", component); + if (tagConstB) out.e(tagConstB, { + "class": "a b", + "other": input.other + }, "14", component, 0, 0);else out.bf("f_14", component); let tagLazyAssign; tagLazyAssign = "a"; - if (tagLazyAssign) out.e(tagLazyAssign, null, "15", component, 0, 0);else out.bf("f_15", component); + if (tagLazyAssign) out.e(tagLazyAssign, { + "class": "a b", + "other": input.other + }, "15", component, 0, 0);else out.bf("f_15", component); tagLazyAssign = input.show ? "div" : null; - if (tagLazyAssign) out.e(tagLazyAssign, null, "16", component, 0, 0);else out.bf("f_16", component); + if (tagLazyAssign) out.e(tagLazyAssign, { + "class": "a b", + "other": input.other + }, "16", component, 0, 0);else out.bf("f_16", component); }, { t: _marko_componentType, i: true diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdomProduction-expected.js b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdomProduction-expected.js index 06a5c9434..d507fc89a 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdomProduction-expected.js +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/vdomProduction-expected.js @@ -13,29 +13,52 @@ const _marko_componentType = _marko_registerComponent("FiPq+pCl", () => _marko_t _marko_component = {}; _marko_template._ = _marko_renderer(function (input, out, _component, component, state) { - _marko_dynamic_tag(out, input, null, null, null, null, _component, "0"); + _marko_dynamic_tag(out, input, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "0"); - _marko_dynamic_tag(out, input.x, null, null, null, null, _component, "1"); + _marko_dynamic_tag(out, input.x, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "1"); const _tagName = input.show ? "div" : null; - if (_tagName) out.e(_tagName, null, "2", component, 0, 0);else out.bf("f_2", component); + if (_tagName) out.e(_tagName, { + "class": "a b", + "other": input.other + }, "2", component, 0, 0);else out.bf("f_2", component); const _tagName2 = input.show && "div"; - if (_tagName2) out.e(_tagName2, null, "3", component, 0, 0);else out.bf("f_3", component); + if (_tagName2) out.e(_tagName2, { + "class": "a b", + "other": input.other + }, "3", component, 0, 0);else out.bf("f_3", component); const _tagName3 = input.large ? "h1" : "h2"; - out.e(_tagName3, null, "4", component, 0, 0); + out.e(_tagName3, { + "class": "a b", + "other": input.other + }, "4", component, 0, 0); const _tagName4 = input.showTagA ? tagA : tagB; - _marko_tag(_tagName4, {}, out, _component, "5"); + _marko_tag(_tagName4, { + "class": ["a", "b"], + "other": input.other, + "class": ["a", "b"], + "other": input.other + }, out, _component, "5"); const _tagName5 = input.showTagA && tagA; - if (_tagName5) _marko_tag(_tagName5, {}, out, _component, "6"); + if (_tagName5) _marko_tag(_tagName5, { + "class": ["a", "b"], + "other": input.other + }, out, _component, "6"); const _tagName6 = input.showTagA && tagA; @@ -44,35 +67,64 @@ _marko_template._ = _marko_renderer(function (input, out, _component, component, }; if (_tagName6) _marko_tag(_tagName6, { + "class": ["a", "b"], + "other": input.other, "renderBody": _renderBody }, out, _component, "7");else _renderBody(out); - _marko_dynamic_tag(out, input.tag || tagA, null, null, null, null, _component, "8"); + _marko_dynamic_tag(out, input.tag || tagA, () => ({ + "class": ["a", "b"], + "other": input.other + }), null, null, null, _component, "8"); const largeHeading = input.isLarge && "h1"; const _tagName7 = largeHeading || "h2"; - if (_tagName7) out.e(_tagName7, null, "9", component, 0, 0);else out.bf("f_9", component); + if (_tagName7) out.e(_tagName7, { + "class": "a b", + "other": input.other + }, "9", component, 0, 0);else out.bf("f_9", component); const _tagName8 = global.x = "a" + "b"; - out.e(_tagName8, null, "10", component, 0, 0); + out.e(_tagName8, { + "class": "a b", + "other": input.other + }, "10", component, 0, 0); const _tagName9 = "h" + input.level; - out.e(_tagName9, null, "11", component, 0, 0); + out.e(_tagName9, { + "class": "a b", + "other": input.other + }, "11", component, 0, 0); const _tagName10 = `h${input.level}`; - out.e(_tagName10, null, "12", component, 0, 0); + out.e(_tagName10, { + "class": "a b", + "other": input.other + }, "12", component, 0, 0); const tagConstA = "a"; - out.e(tagConstA, null, "13", component, 0, 0); + out.e(tagConstA, { + "class": "a b", + "other": input.other + }, "13", component, 0, 0); const tagConstB = input.show ? "div" : null; - if (tagConstB) out.e(tagConstB, null, "14", component, 0, 0);else out.bf("f_14", component); + if (tagConstB) out.e(tagConstB, { + "class": "a b", + "other": input.other + }, "14", component, 0, 0);else out.bf("f_14", component); let tagLazyAssign; tagLazyAssign = "a"; - if (tagLazyAssign) out.e(tagLazyAssign, null, "15", component, 0, 0);else out.bf("f_15", component); + if (tagLazyAssign) out.e(tagLazyAssign, { + "class": "a b", + "other": input.other + }, "15", component, 0, 0);else out.bf("f_15", component); tagLazyAssign = input.show ? "div" : null; - if (tagLazyAssign) out.e(tagLazyAssign, null, "16", component, 0, 0);else out.bf("f_16", component); + if (tagLazyAssign) out.e(tagLazyAssign, { + "class": "a b", + "other": input.other + }, "16", component, 0, 0);else out.bf("f_16", component); }, { t: _marko_componentType, i: true diff --git a/packages/translator-default/test/fixtures/dynamic-tag-name/template.marko b/packages/translator-default/test/fixtures/dynamic-tag-name/template.marko index cfe2f66f1..845a50534 100644 --- a/packages/translator-default/test/fixtures/dynamic-tag-name/template.marko +++ b/packages/translator-default/test/fixtures/dynamic-tag-name/template.marko @@ -1,39 +1,39 @@ import tagA from "./components/tag-a/index.marko"; import tagB from "./components/tag-b/index.marko"; -<${input}/> -<${input.x}/> +<${input} class=["a", "b"] other=input.other/> +<${input.x} class=["a", "b"] other=input.other/> -<${input.show ? "div" : null}/> -<${input.show && "div"}/> +<${input.show ? "div" : null} class=["a", "b"] other=input.other/> +<${input.show && "div"} class=["a", "b"] other=input.other/> -<${input.large ? "h1" : "h2"}/> +<${input.large ? "h1" : "h2"} class=["a", "b"] other=input.other/> -<${input.showTagA ? tagA : tagB}/> -<${input.showTagA && tagA}/> -<${input.showTagA && tagA}> +<${input.showTagA ? tagA : tagB} class=["a", "b"] other=input.other class=["a", "b"] other=input.other/> +<${input.showTagA && tagA} class=["a", "b"] other=input.other/> +<${input.showTagA && tagA} class=["a", "b"] other=input.other> Body content -<${input.tag || tagA}/> +<${input.tag || tagA} class=["a", "b"] other=input.other/> $ const largeHeading = input.isLarge && "h1"; -<${largeHeading || "h2"}/> +<${largeHeading || "h2"} class=["a", "b"] other=input.other/> -<${global.x = "a" + "b"}/> -<${"h" + input.level}/> -<${`h${input.level}`}/> +<${global.x = "a" + "b"} class=["a", "b"] other=input.other/> +<${"h" + input.level} class=["a", "b"] other=input.other/> +<${`h${input.level}`} class=["a", "b"] other=input.other/> $ const tagConstA = "a"; -<${tagConstA}/> +<${tagConstA} class=["a", "b"] other=input.other/> $ const tagConstB = input.show ? "div" : null; -<${tagConstB}/> +<${tagConstB} class=["a", "b"] other=input.other/> $ let tagLazyAssign; $ tagLazyAssign = "a"; -<${tagLazyAssign}/> +<${tagLazyAssign} class=["a", "b"] other=input.other/> $ tagLazyAssign = input.show ? "div" : null; -<${tagLazyAssign}/> +<${tagLazyAssign} class=["a", "b"] other=input.other/>