UNPKG

@builder.io/mitosis

Version:

Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io

225 lines (224 loc) 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseElement = void 0; const astring_1 = require("astring"); const lodash_1 = require("lodash"); const children_1 = require("../helpers/children"); const mitosis_node_1 = require("../helpers/mitosis-node"); const string_1 = require("../helpers/string"); const actions_1 = require("./actions"); const bindings_1 = require("../../../helpers/bindings"); const SPECIAL_ELEMENTS = new Set(['svelte:component', 'svelte:element']); function parseElement(json, node) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t; const mitosisNode = (0, mitosis_node_1.createMitosisNode)(); mitosisNode.name = node.name; const useReference = () => { const nodeReference = (0, string_1.uniqueName)(Object.keys(json.refs), node.name); if (!Object.keys(json.refs).includes(nodeReference)) { json.refs[nodeReference] = { argument: '', typeParameter: '' }; mitosisNode.bindings.ref = (0, bindings_1.createSingleBinding)({ code: nodeReference }); } return nodeReference; }; /* Parse special elements such as svelte:component and svelte:element */ if (SPECIAL_ELEMENTS.has(node.name)) { const expression = (0, astring_1.generate)(node.expression || node.tag); let prefix = 'state'; if (json.props[expression]) { prefix = 'props'; } mitosisNode.name = `${prefix}.${expression}`; } if ((_a = node.attributes) === null || _a === void 0 ? void 0 : _a.length) { for (const attribute of node.attributes) { switch (attribute.type) { case 'Attribute': { switch ((_b = attribute.value[0]) === null || _b === void 0 ? void 0 : _b.type) { case 'Text': { const value = attribute.value[0]; // if there are already conditional class declarations // add class names defined here to the bindings code as well if (attribute.name === 'class' && ((_d = (_c = mitosisNode.bindings.class) === null || _c === void 0 ? void 0 : _c.code) === null || _d === void 0 ? void 0 : _d.length)) { mitosisNode.bindings.class.code = (0, string_1.insertAt)(mitosisNode.bindings.class.code, ` ${value.data} `, 1); } else { mitosisNode.properties[attribute.name] = value.data; } break; } case 'MustacheTag': { const value = attribute.value[0]; const expression = value.expression; let code = (0, astring_1.generate)(expression); if (attribute.name === 'class') { code = ((_f = (_e = mitosisNode.bindings.class) === null || _e === void 0 ? void 0 : _e.code) === null || _f === void 0 ? void 0 : _f.length) ? (0, string_1.insertAt)(mitosisNode.bindings.class.code, ' ${' + code + '}', mitosisNode.bindings.class.code.length - 1) : '`${' + code + '}`'; } mitosisNode.bindings[attribute.name] = (0, bindings_1.createSingleBinding)({ code }); break; } case 'AttributeShorthand': { // e.g. <input {value}/> const value = attribute.value[0]; const code = value.expression.name; mitosisNode.bindings[code] = (0, bindings_1.createSingleBinding)({ code }); break; } default: { const name = attribute.name; mitosisNode.bindings[name] = (0, bindings_1.createSingleBinding)({ code: attribute.value.toString(), }); } } break; } case 'Spread': { const expression = attribute.expression; mitosisNode.bindings[expression.name] = { code: expression.name, type: 'spread', spreadType: 'normal', }; break; } case 'EventHandler': { let object = { code: '', arguments: [], }; if (((_g = attribute.expression) === null || _g === void 0 ? void 0 : _g.type) === 'ArrowTypeFunction') { const expression = attribute.expression; let code = (0, astring_1.generate)(expression.body); object = { code, arguments: (_j = (_h = expression.body) === null || _h === void 0 ? void 0 : _h.arguments) === null || _j === void 0 ? void 0 : _j.map((a) => { var _a; return (_a = a.name) !== null && _a !== void 0 ? _a : []; }), }; } else if (attribute.expression) { let code = (0, astring_1.generate)(attribute.expression); if (((_k = attribute.expression.body) === null || _k === void 0 ? void 0 : _k.type) === 'CallExpression') { code = (0, astring_1.generate)(attribute.expression.body); } if (!code.startsWith(')') && !code.endsWith(')')) { code += '()'; } if (!((_l = attribute.expression.arguments) === null || _l === void 0 ? void 0 : _l.length) && !((_o = (_m = attribute.expression.body) === null || _m === void 0 ? void 0 : _m.arguments) === null || _o === void 0 ? void 0 : _o.length)) { code = code.replace(/\(\)/g, '(event)'); } let args = undefined; if (attribute.expression.type === 'ArrowFunctionExpression') { args = (_q = (_p = attribute.expression.params) === null || _p === void 0 ? void 0 : _p.map((arg) => (0, astring_1.generate)(arg))) !== null && _q !== void 0 ? _q : []; } else if (attribute.expression.type === 'CallExpression' && attribute.expression.arguments.length) { args = []; } object = { code, arguments: args, }; } else { object = { code: `props.on${(0, lodash_1.upperFirst)(attribute.name)}(event)`, arguments: ['event'], }; } mitosisNode.bindings[`on${(0, lodash_1.upperFirst)(attribute.name)}`] = (0, bindings_1.createSingleBinding)(object); // add event handlers as props (e.g. props.onClick) json.props = { ...json.props, [`on${(0, lodash_1.upperFirst)(attribute.name)}`]: { default: () => ({}) }, }; break; } case 'Binding': { /* adding onChange handlers for bind:group and bind:property is done during post processing same goes for replacing the group binding with checked see helpers/post-process.ts */ const expression = attribute.expression; const binding = expression.name; let name = attribute.name; // template ref if (attribute.name === 'this') { name = 'ref'; json.refs[binding] = { argument: 'null', typeParameter: 'any', }; if (Object.prototype.hasOwnProperty.call(json.state, binding)) { delete json.state[binding]; } } if (name !== 'ref' && name !== 'group' && name !== 'this') { const onChangeCode = `${binding} = event.target.value`; mitosisNode.bindings['onChange'] = (0, bindings_1.createSingleBinding)({ code: onChangeCode, arguments: ['event'], }); } mitosisNode.bindings[name] = (0, bindings_1.createSingleBinding)({ code: binding, }); break; } case 'Class': { const expression = attribute.expression; // conditional classes (e.g. class:disabled or class:disabled={disabled}) const binding = `${(0, astring_1.generate)(expression)} ? '${attribute.name}' : ''`; let code = ''; // if there are existing class declarations // add them here instead and remove them from properties // to avoid duplicate class declarations in certain frameworks if ((_s = (_r = mitosisNode.properties) === null || _r === void 0 ? void 0 : _r.class) === null || _s === void 0 ? void 0 : _s.length) { code = `${mitosisNode.properties.class} `; delete mitosisNode.properties.class; } // if class code is already defined (meaning there is more than 1 conditional class declaration) // append it to the string instead of assigning it if (mitosisNode.bindings.class && Object.prototype.hasOwnProperty.call(mitosisNode.bindings.class, 'code') && ((_t = mitosisNode.bindings.class) === null || _t === void 0 ? void 0 : _t.code.length)) { code = (0, string_1.insertAt)(mitosisNode.bindings.class.code, ' ${' + binding + '}', mitosisNode.bindings.class.code.length - 1); mitosisNode.bindings.class = (0, bindings_1.createSingleBinding)({ code }); } else { // otherwise just assign code = '`' + code + '${' + binding + '}`'; mitosisNode.bindings.class = (0, bindings_1.createSingleBinding)({ code }); } break; } case 'Action': { (0, actions_1.parseAction)(json, useReference(), attribute); break; } // No default } } } let filteredChildren = []; if (node.children) { filteredChildren = (0, children_1.filterChildren)(node.children); } if (filteredChildren.length === 1 && filteredChildren[0].type === 'RawMustacheTag') { const child = filteredChildren[0]; mitosisNode.children = []; mitosisNode.bindings.innerHTML = (0, bindings_1.createSingleBinding)({ code: (0, astring_1.generate)(child.expression), }); } else { mitosisNode.children = (0, children_1.parseChildren)(json, node); } return mitosisNode; } exports.parseElement = parseElement;