diff --git a/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js b/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js index 26153bd5..866d7387 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js @@ -297,6 +297,31 @@ function transformAttributes(path, results) { ); //NOTE: can't be checked at compile time so add to compiled output hasHydratableEvent = true; + } else { + /** + * Spreads already de-duplicate attributes. + * + * This handles the case when attributes are duplicated without the presence of a spread. Such: + * `
;` + */ + const seenAttributes = {}; + const duplicates = []; + path + .get("openingElement") + .get("attributes") + .forEach(attr => { + const key = t.isJSXNamespacedName(attr.node.name) + ? `${attr.node.name.namespace.name}:${attr.node.name.name.name}` + : attr.node.name.name; + + if (!key.startsWith("use:") && key !== "ref" && seenAttributes[key]) { + duplicates.push(seenAttributes[key]); + } + seenAttributes[key] = attr; + }); + for (const duplicate of duplicates) { + duplicate.remove(); + } } /** @@ -1171,12 +1196,7 @@ function processSpreads(path, attributes, { elem, isSVG, hasChildren, wrapCondit : node.argument; spreadArgs.push(isStatic ? t.objectExpression([t.spreadElement(s)]) : s); - } else if ( - (firstSpread || - (t.isJSXExpressionContainer(node.value) && - isDynamic(attribute.get("value").get("expression"), { checkMember: true }))) && - canNativeSpread(key, { checkNameSpaces: true }) - ) { + } else if (key && !key.startsWith("use:") && key !== "ref") { const isContainer = t.isJSXExpressionContainer(node.value); const dynamic = isContainer && isDynamic(attribute.get("value").get("expression"), { checkMember: true }); diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js index 7425e869..a8b28d3b 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js @@ -325,3 +325,5 @@ const template88 = ( {count()} ); + +const template89 =
diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/output.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/output.js index 6702b7f9..fcf5c151 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/output.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/output.js @@ -11,9 +11,7 @@ import { className as _$className } from "r-dom"; import { use as _$use } from "r-dom"; import { spread as _$spread } from "r-dom"; import { mergeProps as _$mergeProps } from "r-dom"; -var _tmpl$ = /*#__PURE__*/ _$template( - `` - ), +var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome

`), _tmpl$2 = /*#__PURE__*/ _$template(`
`), _tmpl$3 = /*#__PURE__*/ _$template(`
`), _tmpl$4 = /*#__PURE__*/ _$template(`
`), @@ -29,7 +27,7 @@ var _tmpl$ = /*#__PURE__*/ _$template( _tmpl$14 = /*#__PURE__*/ _$template(`
`), _tmpl$15 = /*#__PURE__*/ _$template(``), _tmpl$16 = /*#__PURE__*/ _$template(`
`), - _tmpl$17 = /*#__PURE__*/ _$template(`
Hi
`), + _tmpl$17 = /*#__PURE__*/ _$template(`
Hi
`), _tmpl$18 = /*#__PURE__*/ _$template(``), _tmpl$19 = /*#__PURE__*/ _$template( `
` @@ -72,7 +70,8 @@ var _tmpl$ = /*#__PURE__*/ _$template( _tmpl$43 = /*#__PURE__*/ _$template(``), _tmpl$44 = /*#__PURE__*/ _$template(`
`), _tmpl$45 = /*#__PURE__*/ _$template(`
`), - _tmpl$46 = /*#__PURE__*/ _$template(``); + _tmpl$46 = /*#__PURE__*/ _$template(``), + _tmpl$47 = /*#__PURE__*/ _$template(`
`); import * as styles from "./styles.module.css"; import { binding } from "somewhere"; function refFn() {} @@ -86,41 +85,53 @@ const template = (() => { _el$3 = _el$2.firstChild; _$spread( _el$, - _$mergeProps(results, { - class: { - selected: unknown + _$mergeProps( + { + id: "main" }, - style: { - color + results, + { + class: { + selected: unknown + }, + style: { + color + } } - }), + ), false, true ); _$spread( _el$2, - _$mergeProps(results, { - foo: "", - disabled: "", - get title() { - return welcoming(); - }, - get style() { - return { - "background-color": color(), - "margin-right": "40px" - }; + _$mergeProps( + { + id: id }, - get ["class"]() { - return [ - "base", - { - dynamic: dynamic(), - selected - } - ]; + results, + { + foo: "", + disabled: "", + get title() { + return welcoming(); + }, + get style() { + return { + "background-color": color(), + "margin-right": "40px" + }; + }, + get ["class"]() { + return [ + "base", + { + dynamic: dynamic(), + selected + } + ]; + } } - }), + ), false, true ); @@ -385,8 +396,18 @@ const template25 = (() => { })(); const template26 = (() => { var _el$35 = _tmpl$17(); - _$setAttribute(_el$35, "middle", middle); - _$spread(_el$35, spread, false, true); + _$spread( + _el$35, + _$mergeProps( + { + start: "Hi", + middle: middle + }, + spread + ), + false, + true + ); return _el$35; })(); const template27 = (() => { @@ -394,6 +415,9 @@ const template27 = (() => { _$spread( _el$36, _$mergeProps( + { + start: "Hi" + }, first, { middle: middle @@ -820,4 +844,5 @@ const template88 = (() => { }); return _el$107; })(); +const template89 = _tmpl$47(); _$delegateEvents(["click", "input"]); diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/output.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/output.js index 1f999181..66c332aa 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/output.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/output.js @@ -11,7 +11,7 @@ import { className as _$className } from "r-dom"; import { use as _$use } from "r-dom"; import { spread as _$spread } from "r-dom"; import { mergeProps as _$mergeProps } from "r-dom"; -var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), +var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), _tmpl$2 = /*#__PURE__*/ _$template(`
`), _tmpl$3 = /*#__PURE__*/ _$template(`
`), _tmpl$4 = /*#__PURE__*/ _$template(`
`), @@ -27,7 +27,7 @@ var _tmpl$ = /*#__PURE__*/ _$template(`

Welco _tmpl$14 = /*#__PURE__*/ _$template(`
`), _tmpl$15 = /*#__PURE__*/ _$template(``), _tmpl$16 = /*#__PURE__*/ _$template(`
`), - _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), + _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), _tmpl$18 = /*#__PURE__*/ _$template(`
`), _tmpl$19 = /*#__PURE__*/ _$template( `
` @@ -74,41 +74,53 @@ const template = (() => { _el$3 = _el$2.firstChild; _$spread( _el$, - _$mergeProps(results, { - class: { - selected: unknown + _$mergeProps( + { + id: "main" }, - style: { - color + results, + { + class: { + selected: unknown + }, + style: { + color + } } - }), + ), false, true ); _$spread( _el$2, - _$mergeProps(results, { - foo: "", - disabled: "", - get title() { - return welcoming(); - }, - get style() { - return { - "background-color": color(), - "margin-right": "40px" - }; + _$mergeProps( + { + id: id }, - get ["class"]() { - return [ - "base", - { - dynamic: dynamic(), - selected - } - ]; + results, + { + foo: "", + disabled: "", + get title() { + return welcoming(); + }, + get style() { + return { + "background-color": color(), + "margin-right": "40px" + }; + }, + get ["class"]() { + return [ + "base", + { + dynamic: dynamic(), + selected + } + ]; + } } - }), + ), false, true ); @@ -373,8 +385,18 @@ const template25 = (() => { })(); const template26 = (() => { var _el$35 = _tmpl$17(); - _$setAttribute(_el$35, "middle", middle); - _$spread(_el$35, spread, false, true); + _$spread( + _el$35, + _$mergeProps( + { + start: "Hi", + middle: middle + }, + spread + ), + false, + true + ); return _el$35; })(); const template27 = (() => { @@ -382,6 +404,9 @@ const template27 = (() => { _$spread( _el$36, _$mergeProps( + { + start: "Hi" + }, first, { middle: middle @@ -808,4 +833,4 @@ const template88 = (() => { }); return _el$107; })(); -_$delegateEvents(["click", "input"]); +_$delegateEvents(["click", "input"]); \ No newline at end of file diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_hydratable_fixtures__/attributeExpressions/output.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_hydratable_fixtures__/attributeExpressions/output.js index bad8f034..6fa2c20b 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_hydratable_fixtures__/attributeExpressions/output.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_hydratable_fixtures__/attributeExpressions/output.js @@ -15,7 +15,7 @@ import { className as _$className } from "r-dom"; import { use as _$use } from "r-dom"; import { spread as _$spread } from "r-dom"; import { mergeProps as _$mergeProps } from "r-dom"; -var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), +var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), _tmpl$2 = /*#__PURE__*/ _$template(`
`), _tmpl$3 = /*#__PURE__*/ _$template(`
`), _tmpl$4 = /*#__PURE__*/ _$template(`
`), @@ -31,7 +31,7 @@ var _tmpl$ = /*#__PURE__*/ _$template(`

Welco _tmpl$14 = /*#__PURE__*/ _$template(`
`), _tmpl$15 = /*#__PURE__*/ _$template(``), _tmpl$16 = /*#__PURE__*/ _$template(`
`), - _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), + _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), _tmpl$18 = /*#__PURE__*/ _$template(`
`), _tmpl$19 = /*#__PURE__*/ _$template( `
` @@ -78,41 +78,53 @@ const template = (() => { _el$3 = _el$2.firstChild; _$spread( _el$, - _$mergeProps(results, { - class: { - selected: unknown + _$mergeProps( + { + id: "main" }, - style: { - color + results, + { + class: { + selected: unknown + }, + style: { + color + } } - }), + ), false, true ); _$spread( _el$2, - _$mergeProps(results, { - foo: "", - disabled: "", - get title() { - return welcoming(); - }, - get style() { - return { - "background-color": color(), - "margin-right": "40px" - }; + _$mergeProps( + { + id: id }, - get ["class"]() { - return [ - "base", - { - dynamic: dynamic(), - selected - } - ]; + results, + { + foo: "", + disabled: "", + get title() { + return welcoming(); + }, + get style() { + return { + "background-color": color(), + "margin-right": "40px" + }; + }, + get ["class"]() { + return [ + "base", + { + dynamic: dynamic(), + selected + } + ]; + } } - }), + ), false, true ); @@ -386,8 +398,18 @@ const template25 = (() => { })(); const template26 = (() => { var _el$37 = _$getNextElement(_tmpl$17); - _$setAttribute(_el$37, "middle", middle); - _$spread(_el$37, spread, false, true); + _$spread( + _el$37, + _$mergeProps( + { + start: "Hi", + middle: middle + }, + spread + ), + false, + true + ); _$runHydrationEvents(); return _el$37; })(); @@ -396,6 +418,9 @@ const template27 = (() => { _$spread( _el$38, _$mergeProps( + { + start: "Hi" + }, first, { middle: middle @@ -832,4 +857,4 @@ const template88 = (() => { }); return _el$111; })(); -_$delegateEvents(["click", "input"]); +_$delegateEvents(["click", "input"]); \ No newline at end of file diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dynamic_fixtures__/attributeExpressions/output.js b/packages/babel-plugin-jsx-dom-expressions/test/__dynamic_fixtures__/attributeExpressions/output.js index 2e53cd8e..2ea900c7 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dynamic_fixtures__/attributeExpressions/output.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dynamic_fixtures__/attributeExpressions/output.js @@ -15,7 +15,7 @@ import { className as _$className } from "r-dom"; import { use as _$use } from "r-dom"; import { spread as _$spread } from "r-dom"; import { mergeProps as _$mergeProps } from "r-custom"; -var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), +var _tmpl$ = /*#__PURE__*/ _$template(`

Welcome`), _tmpl$2 = /*#__PURE__*/ _$template(`
`), _tmpl$3 = /*#__PURE__*/ _$template(`
`), _tmpl$4 = /*#__PURE__*/ _$template(`
`), @@ -31,7 +31,7 @@ var _tmpl$ = /*#__PURE__*/ _$template(`

Welco _tmpl$14 = /*#__PURE__*/ _$template(`
`), _tmpl$15 = /*#__PURE__*/ _$template(``), _tmpl$16 = /*#__PURE__*/ _$template(`
`), - _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), + _tmpl$17 = /*#__PURE__*/ _$template(`
Hi`), _tmpl$18 = /*#__PURE__*/ _$template(`