UNPKG

@builder.io/mitosis

Version:

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

219 lines (216 loc) 9.38 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.processAngularCode = exports.traverseAndCheckIfInnerHTMLIsUsed = exports.getTemplateFormat = exports.traverseToGetAllDynamicComponents = exports.generateNgModule = exports.preprocessCssAsJson = exports.hasFirstChildKeyAttribute = exports.transformState = exports.getDefaultProps = exports.getAppropriateTemplateFunctionKeys = exports.HELPER_FUNCTIONS = void 0; const blocks_1 = require("../../../generators/angular/classic/blocks"); const indent_1 = require("../../../helpers/indent"); const is_mitosis_node_1 = require("../../../helpers/is-mitosis-node"); const replace_identifiers_1 = require("../../../helpers/replace-identifiers"); const strip_state_and_props_refs_1 = require("../../../helpers/strip-state-and-props-refs"); const helpers_1 = require("../../../helpers/styles/helpers"); const babel = __importStar(require("@babel/core")); const function_1 = require("fp-ts/function"); const legacy_1 = __importDefault(require("neotraverse/legacy")); const HELPER_FUNCTIONS = (isTs) => ({ useObjectWrapper: `useObjectWrapper(...args${isTs ? ': any[]' : ''}) { let obj = {} args.forEach((arg) => { obj = { ...obj, ...arg }; }); return obj; }`, useObjectDotValues: `useObjectDotValues(obj${isTs ? ': any' : ''})${isTs ? ': any[]' : ''}) { return Object.values(obj); }`, useTypeOf: `useTypeOf(obj${isTs ? ': any' : ''})${isTs ? ': string' : ''}) { return typeof obj; }`, useJsonStringify: `useJsonStringify(...args${isTs ? ': any' : ''})${isTs ? ': string' : ''}) { return JSON.stringify(...args); }`, setAttributes: `setAttributes(el${isTs ? ': HTMLElement' : ''}, value${isTs ? ': any' : ''}, changes${isTs ? '?: any' : ''}) { if (!el) { return; } const target = typeof changes === 'undefined' ? value : changes; Object.keys(target).forEach((key) => { if (key.startsWith('on')) { if (this._listenerFns.has(key)) { this._listenerFns.get(key)${isTs ? '!' : ''}(); } this._listenerFns.set(key, this.renderer.listen( el, key.replace('on', '').toLowerCase(), target[key] )); } else { this.renderer.setAttribute(el, key.toLowerCase(), target[key] ?? ''); } }); }`, }); exports.HELPER_FUNCTIONS = HELPER_FUNCTIONS; const getAppropriateTemplateFunctionKeys = (code) => Object.keys((0, exports.HELPER_FUNCTIONS)()).filter((key) => code.includes(key)); exports.getAppropriateTemplateFunctionKeys = getAppropriateTemplateFunctionKeys; const getDefaultProps = ({ defaultProps }) => { if (!defaultProps) return ''; const defalutPropsString = Object.keys(defaultProps) .map((prop) => { var _a; const value = defaultProps.hasOwnProperty(prop) ? (_a = defaultProps[prop]) === null || _a === void 0 ? void 0 : _a.code : 'undefined'; return `${prop}: ${value}`; }) .join(','); return `const defaultProps: any = {${defalutPropsString}};\n`; }; exports.getDefaultProps = getDefaultProps; /** * if any state "property" is trying to access state.* or props.* * then we need to move them to onInit where they can be accessed * @param json The MitosisComponent. */ const transformState = (json) => { Object.entries(json.state) .reverse() .forEach(([key, value]) => { var _a; if ((value === null || value === void 0 ? void 0 : value.type) === 'property') { if (value.code && (value.code.includes('state.') || value.code.includes('props.'))) { const code = (0, strip_state_and_props_refs_1.stripStateAndPropsRefs)(value.code, { replaceWith: 'this' }); json.state[key].code = 'null'; if (!((_a = json.hooks.onInit) === null || _a === void 0 ? void 0 : _a.code)) { json.hooks.onInit = { code: '' }; } json.hooks.onInit.code = `\nthis.${key} = ${code};\n${json.hooks.onInit.code}`; } } }); }; exports.transformState = transformState; /** * Checks if the first child has a "key" attribute - used for "For" elements * @param node The node which should be "For" */ const hasFirstChildKeyAttribute = (node) => { var _a; if (!node.children || node.children.length === 0) { return false; } const firstChildBinding = node.children[0].bindings; return Boolean(firstChildBinding && ((_a = firstChildBinding.key) === null || _a === void 0 ? void 0 : _a.code)); }; exports.hasFirstChildKeyAttribute = hasFirstChildKeyAttribute; const preprocessCssAsJson = (json) => { (0, legacy_1.default)(json).forEach((item) => { var _a, _b; if ((0, is_mitosis_node_1.isMitosisNode)(item)) { if ((0, helpers_1.nodeHasCss)(item)) { if ((_b = (_a = item.bindings.css) === null || _a === void 0 ? void 0 : _a.code) === null || _b === void 0 ? void 0 : _b.includes('&quot;')) { item.bindings.css.code = item.bindings.css.code.replace(/&quot;/g, '"'); } } } }); }; exports.preprocessCssAsJson = preprocessCssAsJson; const generateNgModule = (content, name, componentsUsed, component, bootstrapMapper) => { return `import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; ${content} @NgModule({ declarations: [${name}], imports: [CommonModule${componentsUsed.length ? ', ' + componentsUsed.map((comp) => `${comp}Module`).join(', ') : ''}], exports: [${name}], ${bootstrapMapper ? bootstrapMapper(name, componentsUsed, component) : ''} }) export class ${name}Module {}`; }; exports.generateNgModule = generateNgModule; const traverseToGetAllDynamicComponents = (json, options, blockOptions) => { const components = new Set(); let dynamicTemplate = ''; (0, legacy_1.default)(json).forEach((item) => { if ((0, is_mitosis_node_1.isMitosisNode)(item) && item.name.includes('.') && item.name.split('.').length === 2) { const children = item.children .map((child) => (0, blocks_1.blockToAngular)({ root: json, json: child, options, blockOptions })) .join('\n'); dynamicTemplate = `<ng-template #${item.name.split('.')[1].toLowerCase() + 'Template'}>${children}</ng-template>`; components.add(item.name); } }); return { components, dynamicTemplate, }; }; exports.traverseToGetAllDynamicComponents = traverseToGetAllDynamicComponents; const getTemplateFormat = (template) => (0, indent_1.indent)(template, 8).replace(/`/g, '\\`').replace(/\$\{/g, '\\${'); exports.getTemplateFormat = getTemplateFormat; const traverseAndCheckIfInnerHTMLIsUsed = (json) => { let innerHTMLIsUsed = false; (0, legacy_1.default)(json).forEach((item) => { if ((0, is_mitosis_node_1.isMitosisNode)(item)) { Object.keys(item.bindings).forEach((key) => { if (key === 'innerHTML') { innerHTMLIsUsed = true; return; } }); } }); return innerHTMLIsUsed; }; exports.traverseAndCheckIfInnerHTMLIsUsed = traverseAndCheckIfInnerHTMLIsUsed; const { types } = babel; /** * Prefixes state identifiers with this. * e.g. state.foo --> this.foo */ const prefixState = (code) => { return (0, replace_identifiers_1.replaceNodes)({ code, nodeMaps: [ { from: types.identifier('state'), to: types.thisExpression(), }, ], }).trim(); }; const processAngularCode = ({ contextVars, outputVars, domRefs, replaceWith, }) => (code) => (0, function_1.pipe)((0, strip_state_and_props_refs_1.DO_NOT_USE_VARS_TRANSFORMS)(code, { contextVars, domRefs, outputVars, }), /** * Only prefix state that is in the Angular class component. * Do not prefix state referenced in the template */ replaceWith === 'this' ? prefixState : (x) => x, (newCode) => (0, strip_state_and_props_refs_1.stripStateAndPropsRefs)(newCode, { replaceWith })); exports.processAngularCode = processAngularCode;