UNPKG

@builder.io/mitosis

Version:

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

265 lines (259 loc) 12.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.componentToSolid = void 0; const bindings_1 = require("../../helpers/bindings"); const create_mitosis_node_1 = require("../../helpers/create-mitosis-node"); const dedent_1 = require("../../helpers/dedent"); const fast_clone_1 = require("../../helpers/fast-clone"); const filter_empty_text_nodes_1 = require("../../helpers/filter-empty-text-nodes"); const get_components_used_1 = require("../../helpers/get-components-used"); const get_refs_1 = require("../../helpers/get-refs"); const get_state_object_string_1 = require("../../helpers/get-state-object-string"); const is_mitosis_node_1 = require("../../helpers/is-mitosis-node"); const is_root_text_node_1 = require("../../helpers/is-root-text-node"); const merge_options_1 = require("../../helpers/merge-options"); const nullable_1 = require("../../helpers/nullable"); const on_event_1 = require("../../helpers/on-event"); const process_code_1 = require("../../helpers/plugins/process-code"); const render_imports_1 = require("../../helpers/render-imports"); const strip_meta_properties_1 = require("../../helpers/strip-meta-properties"); const collect_css_1 = require("../../helpers/styles/collect-css"); const helpers_1 = require("../../helpers/styles/helpers"); const Array_1 = require("fp-ts/lib/Array"); const S = __importStar(require("fp-ts/string")); const hash_sum_1 = __importDefault(require("hash-sum")); const legacy_1 = __importDefault(require("neotraverse/legacy")); const standalone_1 = require("prettier/standalone"); const plugins_1 = require("../../modules/plugins"); const context_1 = require("../helpers/context"); const blocks_1 = require("./blocks"); const state_1 = require("./state"); const helpers_2 = require("./state/helpers"); // Transform <foo.bar key={value} /> to <Dynamic compnent={foo.bar} key={value} /> function processDynamicComponents(json, options) { let found = false; (0, legacy_1.default)(json).forEach((node) => { if ((0, is_mitosis_node_1.isMitosisNode)(node)) { if (node.name.includes('.') && !node.name.endsWith('.Provider')) { node.bindings.component = (0, bindings_1.createSingleBinding)({ code: node.name }); node.name = 'Dynamic'; found = true; } } }); return found; } function getContextString(component, options) { let str = ''; for (const key in component.context.get) { str += ` const ${key} = useContext(${component.context.get[key].name}); `; } return str; } const getRefsString = (json, options) => Array.from((0, get_refs_1.getRefs)(json)) .map((ref) => { var _a; // fix prettier issue when encounter `let props.ref` // Prettier playground: https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAzArlMMCW0AEAsgJ4DCEAtgA7QIwAUVAThFQM5ICGUxAlPsAA6UfPgA2cGPmas2AOhxQq6GACU4qANzDRTSeiYj6O0fgA8i5VPx7UAXmAz2CpSvWoAhAF9RAegB8JqK8wl7CcAAeNExSACYanOhiUiTk1LSwmiAANCCsuNBsyKCcTCwA7gAKpQhFKJxi5ZzERbkARkycYADWkgDKnBRwADKKcMioDWxw7Z09-VRdigDmyDBM6DMg0xQ4axtbkVRwTDhDsA0AKidQpThwdZNi07lsKxIAiugQ8BNTWwArNgRPrvOBfH7jJBPF4gACO33glRY7GQIE4bAAtFA4HB4rEciB1pwcGIVmkKJw0Q0xIS3lBlhIAIIwdY4NoqOCVE6jHF-Z5bAAWMAoYgA6oKcPA2IswHA+rUpTgAG5S4hosBsVogZWbACSUHisD6YFOVBgTMNfRgxAk-NhMmmYs6VDRzAeJ2V41yimmMWRnGWlPtW0WTD9aJtxzYppw5sJzEUMDFOFiMEFyAAHAAGXJ6BE4PQBoNU6H-XIwThtFNpjNIABMuXQ00uVce5ZAcAobTx+OG3GW6EDcAAYhAmJTWStqSoICAvF4gA if (ref.includes('.')) return ''; const typeParameter = (options.typescript && ((_a = json['refs'][ref]) === null || _a === void 0 ? void 0 : _a.typeParameter)) || ''; return `let ${ref}${typeParameter ? ': ' + typeParameter : ''};`; }) .join('\n'); function addProviderComponents(json, options) { for (const key in json.context.set) { const { name, value, ref } = json.context.set[key]; const bindingValue = value ? (0, bindings_1.createSingleBinding)({ code: (0, get_state_object_string_1.stringifyContextValue)(value) }) : ref ? (0, bindings_1.createSingleBinding)({ code: ref }) : undefined; json.children = [ (0, create_mitosis_node_1.createMitosisNode)({ name: `${name}.Provider`, children: json.children, ...(bindingValue && { bindings: { value: bindingValue } }), }), ]; } } const DEFAULT_OPTIONS = { state: 'signals', stylesType: 'style-tag', }; const componentToSolid = (passedOptions) => ({ component }) => { var _a, _b, _c, _d, _e, _f, _g; let json = (0, fast_clone_1.fastClone)(component); const options = (0, merge_options_1.initializeOptions)({ target: 'solid', component, defaults: DEFAULT_OPTIONS, userOptions: passedOptions, }); options.plugins = [ ...(options.plugins || []), (0, on_event_1.processOnEventHooksPlugin)(), (0, process_code_1.CODE_PROCESSOR_PLUGIN)((codeType) => { switch (codeType) { case 'state': case 'context-set': case 'dynamic-jsx-elements': case 'types': return (c) => c; case 'bindings': case 'hooks': case 'hooks-deps': case 'hooks-deps-array': case 'properties': return (0, helpers_2.updateStateCode)({ component: json, options, updateSetters: codeType === 'properties' ? false : true, }); } }), ]; if (options.plugins) { json = (0, plugins_1.runPreJsonPlugins)({ json, plugins: options.plugins }); } addProviderComponents(json, options); const componentHasStyles = (0, helpers_1.hasCss)(json); const hasCustomStyles = !!((_a = json.style) === null || _a === void 0 ? void 0 : _a.length); const shouldInjectCustomStyles = hasCustomStyles && options.stylesType === 'styled-components'; const addWrapper = json.children.filter(filter_empty_text_nodes_1.filterEmptyTextNodes).length !== 1 || options.stylesType === 'style-tag' || shouldInjectCustomStyles || (0, is_root_text_node_1.isRootTextNode)(json); // we need to run this before we run the code processor plugin, so the dynamic component variables are transformed const foundDynamicComponents = processDynamicComponents(json, options); if (options.plugins) { json = (0, plugins_1.runPostJsonPlugins)({ json, plugins: options.plugins }); } (0, strip_meta_properties_1.stripMetaProperties)(json); const css = options.stylesType === 'style-tag' && (0, collect_css_1.collectCss)(json, { prefix: (0, hash_sum_1.default)(json) }); const state = (0, state_1.getState)({ json, options }); const componentsUsed = (0, get_components_used_1.getComponentsUsed)(json); const hasShowComponent = componentsUsed.has('Show'); const hasForComponent = componentsUsed.has('For'); const solidJSImports = (0, Array_1.uniq)(S.Eq)([ (0, context_1.hasGetContext)(json) ? 'useContext' : undefined, hasShowComponent ? 'Show' : undefined, hasForComponent ? 'For' : undefined, json.hooks.onMount.length ? 'onMount' : undefined, ...(((_b = json.hooks.onUpdate) === null || _b === void 0 ? void 0 : _b.length) ? ['on', 'createEffect', 'createMemo'] : []), ...((_c = state === null || state === void 0 ? void 0 : state.import.solidjs) !== null && _c !== void 0 ? _c : []), ].filter(nullable_1.checkIsDefined)); const storeImports = (_d = state === null || state === void 0 ? void 0 : state.import.store) !== null && _d !== void 0 ? _d : []; const propType = json.propsTypeRef || 'any'; const propsArgs = `props${options.typescript ? `:${propType}` : ''}`; let str = (0, dedent_1.dedent) ` ${solidJSImports.length > 0 ? `import { ${solidJSImports.join(', ')} } from 'solid-js';` : ''} ${!foundDynamicComponents ? '' : `import { Dynamic } from 'solid-js/web';`} ${storeImports.length > 0 ? `import { ${storeImports.join(', ')} } from 'solid-js/store';` : ''} ${componentHasStyles && options.stylesType === 'styled-components' ? 'import { css } from "solid-styled-components";' : ``} ${json.types && options.typescript ? json.types.join('\n') : ''} ${(0, render_imports_1.renderPreComponent)({ explicitImportFileExtension: options.explicitImportFileExtension, component: json, target: 'solid', })} function ${json.name}(${propsArgs}) { ${(_e = state === null || state === void 0 ? void 0 : state.str) !== null && _e !== void 0 ? _e : ''} ${getRefsString(json, options)} ${getContextString(json, options)} ${(_g = (_f = json.hooks.onInit) === null || _f === void 0 ? void 0 : _f.code) !== null && _g !== void 0 ? _g : ''} ${json.hooks.onMount.map((hook) => `onMount(() => { ${hook.code} })`).join('\n')} ${json.hooks.onUpdate ? json.hooks.onUpdate .map((hook, index) => { // TO-DO: support `onUpdate` without `deps` if (!hook.deps) return ''; const hookName = `onUpdateFn_${index}`; const depsArray = hook.deps .slice(1, hook.deps.length - 1) .split(',') .map((x) => x.trim()); const getReactiveDepName = (dep) => { const newLocal = dep.replace(/(\.|\?|\(|\)|\[|\])/g, '_'); return `${hookName}_${newLocal}`; }; const needsMemo = (dep) => true; const reactiveDepsWorkaround = depsArray .filter(needsMemo) .map((dep) => `const ${getReactiveDepName(dep)} = createMemo(() => ${dep});`) .join('\n'); const depsArrayStr = depsArray .map((x) => (needsMemo(x) ? `${getReactiveDepName(x)}()` : x)) .join(', '); return ` ${reactiveDepsWorkaround} function ${hookName}() { ${hook.code} }; createEffect(on(() => [${depsArrayStr}], ${hookName})); `; }) .join('\n') : ''} return (${addWrapper ? '<>' : ''} ${json.children .filter(filter_empty_text_nodes_1.filterEmptyTextNodes) .map((item) => (0, blocks_1.blockToSolid)(item, component, options, addWrapper)) .join('\n')} ${options.stylesType === 'style-tag' && css && css.trim().length > 4 ? `<style>{\`${css}\`}</style>` : ''} ${shouldInjectCustomStyles ? `<style>{\`${json.style}\`}</style>` : ''} ${addWrapper ? '</>' : ''}) } export default ${json.name}; `; if (options.plugins) { str = (0, plugins_1.runPreCodePlugins)({ json, code: str, plugins: options.plugins }); } if (options.prettier !== false) { str = (0, standalone_1.format)(str, { parser: 'typescript', plugins: [require('prettier/parser-typescript'), require('prettier/parser-postcss')], }); } if (options.plugins) { str = (0, plugins_1.runPostCodePlugins)({ json, code: str, plugins: options.plugins }); } return str; }; exports.componentToSolid = componentToSolid; __exportStar(require("./types"), exports);