@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
JavaScript
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('"')) {
item.bindings.css.code = item.bindings.css.code.replace(/"/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;
;