diff --git a/packages/babel-plugin-jsx-dom-expressions/src/shared/component.js b/packages/babel-plugin-jsx-dom-expressions/src/shared/component.js index 3762b868..df813d94 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/shared/component.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/shared/component.js @@ -7,7 +7,8 @@ import { filterChildren, trimWhitespace, transformCondition, - convertJSXIdentifier + convertJSXIdentifier, + hasStaticMarker } from "./utils"; import { transformNode, getCreateTemplate } from "./transform"; @@ -172,13 +173,7 @@ export default function transformComponent(path) { runningObject.push(t.objectMethod("get", id, [], body, !t.isValidIdentifier(key))); } else { runningObject.push( - t.objectMethod( - "get", - id, - [], - t.blockStatement([t.returnStatement(value.expression)]), - !t.isValidIdentifier(key) - ) + transformObjectGetter(id, !t.isValidIdentifier(key), value.expression, path) ); } } else runningObject.push(t.objectProperty(id, value.expression)); @@ -279,3 +274,62 @@ function transformComponentChildren(children, config) { } return [transformedChildren, dynamic]; } + +function transformObjectGetter(key, isComputed, value, path) { + if (t.isObjectExpression(value)) { + // is object recurse + + if ( + !hasStaticMarker(value, path) && + value.properties.some( + prop => + (t.isSpreadElement(prop) || (prop.computed && t.isMemberExpression(prop.key))) && + !hasStaticMarker(prop, path) && + !hasStaticMarker(prop.value, path) + ) + ) { + return t.objectMethod( + "get", + key, + [], + t.blockStatement([t.returnStatement(transformObjectGetterRecurse(value, path))]), + isComputed + ); + } + + return t.objectProperty(key, transformObjectGetterRecurse(value, path), isComputed); + } + + // is not object, do not recurse + + if (hasStaticMarker(value, path)) { + return t.objectProperty(key, value, isComputed); + } + + return t.objectMethod("get", key, [], t.blockStatement([t.returnStatement(value)]), isComputed); +} + +function transformObjectGetterRecurse(object, path) { + const properties = object.properties.map(prop => { + const key = prop.key; + const value = prop.value; + + if (!t.isObjectProperty(prop)) { + return prop; + } + + if ( + t.isStringLiteral(value) || + t.isNumericLiteral(value) || + t.isBooleanLiteral(value) || + t.isNullLiteral(value) || + t.isIdentifier(value) + ) { + return prop; + } + + return transformObjectGetter(key, !t.isValidIdentifier(key.name), value, path); + }); + + return t.objectExpression(properties); +} diff --git a/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js b/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js index 2bde30ef..e4f551b9 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js @@ -77,6 +77,17 @@ export function isComponent(tagName) { ); } +export function hasStaticMarker(object, path) { + if (!object) return false; + if ( + object.leadingComments && + object.leadingComments[0] && + object.leadingComments[0].value.trim() === getConfig(path).staticMarker + ) + return true; + if (object.expression) return hasStaticMarker(object.expression, path); +} + export function isDynamic(path, { checkMember, checkTags, checkCallExpressions = true, native }) { const config = getConfig(path); if (config.generate === "ssr" && native) { diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/code.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/code.js index fcd9b249..cb435ce2 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/code.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_fixtures__/attributeExpressions/code.js @@ -264,3 +264,130 @@ const template80 =
const template81 = const template82 = x= +const template84 = + +const template85 = + + + +const template86 = + +const template87 = +const template87a1 = +const template87a2 = + +const template88 = + +const template89 = + +const template90 = \ No newline at end of file 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 f7165362..941a10bc 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 @@ -1,5 +1,6 @@ import { template as _$template } from "r-dom"; import { delegateEvents as _$delegateEvents } from "r-dom"; +import { createComponent as _$createComponent } from "r-dom"; import { setBoolAttribute as _$setBoolAttribute } from "r-dom"; import { insert as _$insert } from "r-dom"; import { memo as _$memo } from "r-dom"; @@ -575,4 +576,179 @@ const template80 = (() => { })(); const template81 = _tmpl$52(); const template82 = _tmpl$53(); +const template84 = _$createComponent(Comp, { + inputProps: { + quack, + get title() { + return title(); + }, + get name() { + return name(); + }, + quack: "best cat", + get store() { + return store.access; + }, + static_: { + get store() { + return store.access; + }, + quack: "best cat", + get team() { + return uy(); + }, + store + }, + get spread() { + return { + ...store + }; + } + } +}); +const template85 = _$createComponent(Comp, { + get inputProps() { + return { + quack, + get title() { + return title(); + }, + get name() { + return name(); + }, + quack: "best cat", + get store() { + return store.access; + }, + static_: { + get store() { + return store.access; + }, + quack: "best cat", + get team() { + return uy(); + }, + store + }, + ...store + }; + } +}); +const template86 = _$createComponent(Comp, { + get inputProps() { + return { + [quack]: "meaw", + get title() { + return title(); + }, + get name() { + return name(); + }, + quack: "best cat", + get store() { + return store.access; + }, + static_: { + get store() { + return store.access; + }, + quack: "best cat", + get team() { + return uy(); + }, + store + }, + ...store + }; + } +}); +const template87 = _$createComponent(Comp, { + get inputProps() { + return { + [quack]: "meaw", + [store.key]: "ha" + }; + } +}); +const template87a1 = _$createComponent(Comp, { + inputProps: { + [quack]: "meaw", + [store]: "ha" + } +}); +const template87a2 = _$createComponent(Comp, { + get inputProps() { + return { + [quack.key]: "meaw", + [store.key]: "ha" + }; + } +}); +const template88 = _$createComponent(Comp, { + inputProps: { + [quack]: /* @once */ "meaw", + get title() { + return title(); + }, + name: /* @once */ name(), + quack: "best cat", + get store() { + return store.access; + }, + static_: { + store: /* @once */ store.access, + quack: "best cat", + team: /* @once */ uy(), + /* @once */ store + }, + /* @once */ ...store + } +}); +const template89 = _$createComponent(Comp, { + get inputProps() { + return { + [quack]: /* @once */ "meaw", + get title() { + return title(); + }, + name: /* @once */ name(), + quack: "best cat", + get store() { + return store.access; + }, + static_: { + store: /* @once */ store.access, + quack: "best cat", + team: /* @once */ uy(), + /* @once */ store + }, + /* @once */ ...store, + ...store + }; + } +}); +const template90 = _$createComponent(Comp, { + get inputProps() { + return { + [quack]: /* @once */ "meaw", + get title() { + return title(); + }, + name: /* @once */ name(), + quack: "best cat", + get store() { + return store.access; + }, + static_: { + store: /* @once */ store.access, + quack: "best cat", + team: /* @once */ uy(), + /* @once */ store, + ...store + }, + /* @once */ ...store, + ...store + }; + } +}); _$delegateEvents(["click", "input"]);