Skip to content

Commit

Permalink
Refactor: Vue bindings (BuilderIO#996)
Browse files Browse the repository at this point in the history
* tidy

* more cleanup

* refactor

* fix

fix

* fix
  • Loading branch information
samijaber authored Jan 24, 2023
1 parent cf67d76 commit 3a6768e
Showing 1 changed file with 64 additions and 54 deletions.
118 changes: 64 additions & 54 deletions packages/core/src/generators/vue/blocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { pipe } from 'fp-ts/lib/function';
import { pipe, identity } from 'fp-ts/lib/function';
import { filter } from 'lodash';
import { Dictionary } from '../../helpers/typescript';
import { filterEmptyTextNodes } from '../../helpers/filter-empty-text-nodes';
import isChildren from '../../helpers/is-children';
import { isMitosisNode } from '../../helpers/is-mitosis-node';
Expand All @@ -21,6 +22,9 @@ const SPECIAL_PROPERTIES = {
V_FOR: 'v-for',
V_ELSE: 'v-else',
V_ELSE_IF: 'v-else-if',
V_ON: 'v-on',
V_ON_AT: '@',
V_BIND: 'v-bind',
} as const;

type BlockRenderer = (json: MitosisNode, options: ToVueOptions, scope?: Scope) => string;
Expand Down Expand Up @@ -283,11 +287,11 @@ const NODE_MAPPERS: {

const stringifyBinding =
(node: MitosisNode) =>
([key, value]: [string, Binding | undefined]) => {
if (node.bindings[key]?.type === 'spread') {
([key, value]: [string, Binding]) => {
if (value.type === 'spread') {
return ''; // we handle this after
} else if (key === 'class') {
return ` :class="_classStringToObject(${value?.code})" `;
return `:class="_classStringToObject(${value?.code})"`;
// TODO: support dynamic classes as objects somehow like Vue requires
// https://vuejs.org/v2/guide/class-and-style.html
} else {
Expand All @@ -301,29 +305,66 @@ const stringifyBinding =
event = 'input';
}
const isAssignmentExpression = useValue.includes('=');
const valueWRenamedEvent = replaceIdentifiers({
code: useValue,
from: cusArgs[0],
to: '$event',
});

// TODO: proper babel transform to replace. Util for this
if (isAssignmentExpression) {
return ` @${event}="${encodeQuotes(removeSurroundingBlock(valueWRenamedEvent))}" `;
} else {
return ` @${event}="${encodeQuotes(
removeSurroundingBlock(removeSurroundingBlock(valueWRenamedEvent)),
)}" `;
}

const eventHandlerValue = pipe(
replaceIdentifiers({
code: useValue,
from: cusArgs[0],
to: '$event',
}),
isAssignmentExpression ? identity : removeSurroundingBlock,
removeSurroundingBlock,
encodeQuotes,
);

const eventHandlerKey = `${SPECIAL_PROPERTIES.V_ON_AT}${event}`;

return `${eventHandlerKey}="${eventHandlerValue}"`;
} else if (key === 'ref') {
return ` ref="${encodeQuotes(useValue)}" `;
return `ref="${encodeQuotes(useValue)}"`;
} else if (BINDING_MAPPERS[key]) {
return ` ${BINDING_MAPPERS[key]}="${encodeQuotes(useValue.replace(/"/g, "\\'"))}" `;
return `${BINDING_MAPPERS[key]}="${encodeQuotes(useValue.replace(/"/g, "\\'"))}"`;
} else {
return ` :${key}="${encodeQuotes(useValue)}" `;
return `:${key}="${encodeQuotes(useValue)}"`;
}
}
};

const stringifySpreads = (node: MitosisNode) => {
let spreads = filter(node.bindings, (binding) => binding?.type === 'spread').map((value) =>
value!.code === 'props' ? '$props' : value!.code,
);

if (spreads.length === 0) {
return '';
}

const stringifiedValue =
spreads.length > 1 ? `{${spreads.map((spread) => `...${spread}`).join(', ')}}` : spreads[0];

return ` ${SPECIAL_PROPERTIES.V_BIND}="${encodeQuotes(stringifiedValue)}" `;
};

const getBlockBindings = (node: MitosisNode) => {
const stringifiedProperties = Object.entries(node.properties)
.map(([key, value]) => {
if (key === 'className') {
return '';
} else if (key === SPECIAL_PROPERTIES.V_ELSE) {
return `${key}`;
} else if (typeof value === 'string') {
return `${key}="${encodeQuotes(value)}"`;
}
})
.join(' ');

const stringifiedBindings = Object.entries(node.bindings as Dictionary<Binding>)
.map(stringifyBinding(node))
.join(' ');

return [stringifiedProperties, stringifiedBindings, stringifySpreads(node)].join(' ');
};

export const blockToVue: BlockRenderer = (node, options, scope) => {
const nodeMapper = NODE_MAPPERS[node.name];
if (nodeMapper) {
Expand Down Expand Up @@ -353,40 +394,9 @@ export const blockToVue: BlockRenderer = (node, options, scope) => {
return `{{${textCode}}}`;
}

let str = '';

str += `<${node.name} `;

for (const key in node.properties) {
const value = node.properties[key];

if (key === 'className') {
continue;
} else if (key === SPECIAL_PROPERTIES.V_ELSE) {
str += ` ${key} `;
} else if (typeof value === 'string') {
str += ` ${key}="${encodeQuotes(value)}" `;
}
}

const stringifiedBindings = Object.entries(node.bindings).map(stringifyBinding(node)).join('');
let str = `<${node.name} `;

str += stringifiedBindings;

// spreads

let spreads = filter(node.bindings, (binding) => binding?.type === 'spread').map((value) =>
value?.code === 'props' ? '$props' : value?.code,
);

if (spreads?.length) {
if (spreads.length > 1) {
let spreadsString = `{...${spreads.join(', ...')}}`;
str += ` v-bind="${encodeQuotes(spreadsString)}"`;
} else {
str += ` v-bind="${encodeQuotes(spreads.join(''))}"`;
}
}
str += getBlockBindings(node);

if (selfClosingTags.has(node.name)) {
return str + ' />';
Expand Down

0 comments on commit 3a6768e

Please sign in to comment.