Skip to content

Commit

Permalink
feat: bring back support for deprecated string literal spread attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Aug 7, 2023
1 parent b2e70bc commit 4bdb32d
Show file tree
Hide file tree
Showing 22 changed files with 318 additions and 234 deletions.
41 changes: 28 additions & 13 deletions packages/marko/src/runtime/html/helpers/merge-attrs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,44 @@ var dynamicAttrHelper = require("./_dynamic-attr");
* Merges attribute objects into a string.
*/
module.exports = function mergeAttrs() {
var result = "";
var i = arguments.length;
var last = arguments[--i];
var seen = new Set();
var result = "";
var attrName;

if (typeof last === "string") {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
complain(
"Passing a string as dynamic attributes ('<div ${string}>' or '<div ...string>') is deprecated, use an object instead."
);
}

for (var i = arguments.length, last = i - 1; i--; ) {
var source = arguments[i];
if (typeof source === "string") {
result += last[0] === " " ? last : " " + last;
} else {
for (attrName in last) {
result += dynamicAttrHelper(attrName, last[attrName]);
seen.add(attrName);
}
}

while (i) {
var arg = arguments[--i];
if (typeof arg === "string") {
// eslint-disable-next-line no-constant-condition
if ("MARKO_DEBUG") {
complain(
"Passing a string as dynamic attributes ('<div ${string}>' or '<div ...string>') is deprecated, use an object instead."
);
}

if (source[0] !== " ") {
result += " " + source;
} else {
result += source;
}
result += arg[0] === " " ? arg : " " + arg;
} else {
for (var k in source) {
if (i === last || !seen.has(k)) {
result += dynamicAttrHelper(k, source[k]);
seen.add(k);
for (attrName in arg) {
if (!seen.has(attrName)) {
result += dynamicAttrHelper(attrName, arg[attrName]);
seen.add(attrName);
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions packages/marko/src/runtime/vdom/helpers/merge-attrs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";

var attrs = require("./attrs");

/**
* Merges attribute objects into a object.
*/
module.exports = function mergeAttrs() {
var len = arguments.length;
var result = {};
for (var i = 0; i < len; i++) {
Object.assign(result, attrs(arguments[i]));
}

return result;
};
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
<div class="foo
bar"></div>
<div class="foo bar"></div>
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
<DIV class="foo
bar">
<DIV class="foo bar">
2 changes: 1 addition & 1 deletion packages/marko/test/render/fixtures/attrs/expected.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div style="background-color: #FF0000; <test>" class=my-div checked data-encoding='"hello"'>Hello World!</div>
<div data-encoding='"hello"' style="background-color: #FF0000; <test>" class=my-div checked>Hello World!</div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div id="dom" class="test"></div>{"hidden":false,"id":"custom","class":"test"}<div id="dom" class="test"></div>
<div class=test id=dom></div>{"hidden":false,"id":"custom","class":"test"}<div class=test id=dom></div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div class="test" id="override">Hello spread</div>
<div id=override class=test>Hello spread</div>
164 changes: 83 additions & 81 deletions packages/translator-default/src/tag/native-tag[html]/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,114 +4,116 @@ import attrHelper from "marko/src/runtime/html/helpers/attr";
import { evaluateAttr } from "../util";

export default function (path, attrs) {
if (!attrs.length) return t.stringLiteral("");

const len = attrs.length;
if (len === 0) return t.stringLiteral("");
if (len === 1 && attrs[0].node.type === "MarkoSpreadAttribute") {
return t.callExpression(
importDefault(
path.hub.file,
"marko/src/runtime/html/helpers/attrs.js",
"marko_attrs"
),
[attrs[0].node.value]
);
}

if (attrs.some((attr) => attr.node.type === "MarkoSpreadAttribute")) {
const attrsObjects = [];
let props;

if (attrs.some((attr) => !attr.node.name)) {
const attrsObject = t.objectExpression([]);
for (let i = 0; i < len; i++) {
const attr = attrs[i];
const {
node: { name, value },
} = attrs[i];
} = attr;

if (name) {
attrsObject.properties.push(
t.objectProperty(t.stringLiteral(name), value)
const computed = evaluateAttr(attr);
const prop = t.objectProperty(
t.stringLiteral(name),
computed?.value !== undefined
? t.stringLiteral(computed.value)
: value
);
if (props) {
props.push(prop);
} else {
attrsObjects.push(t.objectExpression((props = [prop])));
}
} else {
mergeSpread(attrsObject.properties, value);
attrsObjects.push(value);
props = undefined;
}
}

return t.callExpression(
importDefault(
path.hub.file,
"marko/src/runtime/html/helpers/attrs.js",
"marko_attrs"
"marko/src/runtime/html/helpers/merge-attrs.js",
"marko_merge_attrs"
),
[
attrsObject.properties.length === 1 &&
t.isSpreadElement(attrsObject.properties[0])
? attrsObject.properties[0].argument
: attrsObject,
]
attrsObjects
);
} else {
const file = path.hub.file;
const quasis = [];
const expressions = [];
const attrValues = new Map();
let curString = "";
}

// Remove duplicate attrs so last one wins.
for (let i = len; i--; ) {
const attr = attrs[i];
const { name, value } = attr.node;
if (attrValues.has(name)) continue;
const computed = evaluateAttr(attr);
attrValues.set(
name,
computed
? {
confident: true,
computed: computed.value,
value,
}
: {
confident: false,
computed: undefined,
value,
}
);
}
const file = path.hub.file;
const quasis = [];
const expressions = [];
const attrValues = new Map();
let curString = "";

for (const [name, { confident, computed, value }] of [
...attrValues,
].reverse()) {
if (confident) {
if (computed == null || computed === false) {
continue;
}
// Remove duplicate attrs so last one wins.
for (let i = len; i--; ) {
const attr = attrs[i];
const { name, value } = attr.node;
if (attrValues.has(name)) continue;
const computed = evaluateAttr(attr);
attrValues.set(
name,
computed
? {
confident: true,
computed: computed.value,
value,
}
: {
confident: false,
computed: undefined,
value,
}
);
}

curString += attrHelper(name, computed);
} else {
quasis.push(curString);
curString = "";
expressions.push(
t.callExpression(
importDefault(
file,
"marko/src/runtime/html/helpers/attr.js",
"marko_attr"
),
[t.stringLiteral(name), value]
)
);
for (const [name, { confident, computed, value }] of [
...attrValues,
].reverse()) {
if (confident) {
if (computed == null || computed === false) {
continue;
}
}

quasis.push(curString);

if (expressions.length) {
return normalizeTemplateString(quasis, ...expressions);
curString += attrHelper(name, computed);
} else {
return t.stringLiteral(quasis.join(""));
quasis.push(curString);
curString = "";
expressions.push(
t.callExpression(
importDefault(
file,
"marko/src/runtime/html/helpers/attr.js",
"marko_attr"
),
[t.stringLiteral(name), value]
)
);
}
}
}

function mergeSpread(properties, value) {
if (t.isObjectExpression(value)) {
for (const prop of value.properties) {
if (t.isSpreadElement(prop)) {
mergeSpread(properties, prop.argument);
} else {
properties.push(prop);
}
}
quasis.push(curString);

if (expressions.length) {
return normalizeTemplateString(quasis, ...expressions);
} else {
properties.push(t.spreadElement(value));
return t.stringLiteral(quasis.join(""));
}
}
Loading

0 comments on commit 4bdb32d

Please sign in to comment.