UNPKG

@builder.io/mitosis

Version:

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

155 lines (154 loc) 7.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.angularToMitosisComponent = void 0; const compiler_1 = require("@angular/compiler"); const core_1 = require("@babel/core"); const lodash_1 = require("lodash"); const typescript_1 = __importDefault(require("typescript")); const babel_transform_1 = require("../helpers/babel-transform"); const bindings_1 = require("../helpers/bindings"); const capitalize_1 = require("../helpers/capitalize"); const create_mitosis_component_1 = require("../helpers/create-mitosis-component"); const create_mitosis_node_1 = require("../helpers/create-mitosis-node"); const getTsAST = (code) => { return typescript_1.default.createSourceFile('code.ts', code, typescript_1.default.ScriptTarget.Latest, true); }; const transformBinding = (binding, _options) => { return (0, babel_transform_1.babelTransformCode)(binding, { Identifier(path) { const name = path.node.name; if ((core_1.types.isObjectProperty(path.parent) && path.parent.key === path.node) || (core_1.types.isMemberExpression(path.parent) && path.parent.property === path.node)) { return; } if (!(name.startsWith('state.') || name === 'event' || name === '$event')) { path.replaceWith(core_1.types.identifier(`state.${name}`)); } }, }); }; const isElement = (node) => // TODO: theres got to be a better way than this Array.isArray(node.attributes); const isTemplate = (node) => // TODO: theres got to be a better way than this Array.isArray(node.templateAttrs); const isText = (node) => typeof node.value === 'string'; const isBoundText = (node) => typeof node.value === 'object'; const angularTemplateNodeToMitosisNode = (node, options) => { if (isTemplate(node)) { const ngIf = node.templateAttrs.find((item) => item.name === 'ngIf'); if (ngIf) { return (0, create_mitosis_node_1.createMitosisNode)({ name: 'Show', bindings: { when: (0, bindings_1.createSingleBinding)({ code: transformBinding(ngIf.value.source, options), }), }, children: [angularTemplateNodeToMitosisNode((0, lodash_1.omit)(node, 'templateAttrs'), options)], }); } const ngFor = node.templateAttrs.find((item) => item.name === 'ngFor'); if (ngFor) { const value = ngFor.value.source; const split = value.split(/let\s|\sof\s/); const [_let, itemName, _of, expression] = split; return (0, create_mitosis_node_1.createMitosisNode)({ name: 'For', bindings: { each: (0, bindings_1.createSingleBinding)({ code: transformBinding(expression, options) }), }, scope: { forName: itemName, }, children: [angularTemplateNodeToMitosisNode((0, lodash_1.omit)(node, 'templateAttrs'), options)], }); } } if (isElement(node)) { const properties = {}; const bindings = {}; for (const input of node.inputs) { bindings[input.name] = (0, bindings_1.createSingleBinding)({ code: transformBinding(input.value.source, options), }); } for (const output of node.outputs) { bindings['on' + (0, capitalize_1.capitalize)(output.name)] = (0, bindings_1.createSingleBinding)({ code: transformBinding(output.handler .source // TODO: proper reference replace .replace(/\$event/g, 'event'), options), }); } for (const attribute of node.attributes) { properties[attribute.name] = attribute.value; } return (0, create_mitosis_node_1.createMitosisNode)({ name: node.name, properties, bindings: bindings, children: node.children.map((node) => angularTemplateNodeToMitosisNode(node, options)), }); } if (isText(node)) { return (0, create_mitosis_node_1.createMitosisNode)({ properties: { _text: node.value, }, }); } if (isBoundText(node)) { // TODO: handle the bindings return (0, create_mitosis_node_1.createMitosisNode)({ properties: { _text: node.value.source, }, }); } throw new Error(`Element node type {${node}} is not supported`); }; const angularTemplateToMitosisNodes = (template, options) => { const ast = (0, compiler_1.parseTemplate)(template, '.'); const blocks = ast.nodes.map((node) => angularTemplateNodeToMitosisNode(node, options)); return blocks; }; const parseTypescript = (code, options) => { const component = (0, create_mitosis_component_1.createMitosisComponent)(); const ast = getTsAST(code); for (const statement of ast.statements) { if (typescript_1.default.isClassDeclaration(statement)) { const decorators = typescript_1.default.canHaveDecorators(statement) ? typescript_1.default.getDecorators(statement) : undefined; if (decorators) { for (const decorator of decorators) { // TODO: proper reference tracing if (typescript_1.default.isCallExpression(decorator.expression)) if (typescript_1.default.isIdentifier(decorator.expression.expression) && decorator.expression.expression.text === 'Component') { const firstArg = decorator.expression.arguments[0]; if (typescript_1.default.isObjectLiteralExpression(firstArg)) { firstArg.properties.find((item) => { if (typescript_1.default.isPropertyAssignment(item)) { if (typescript_1.default.isIdentifier(item.name) && item.name.text === 'template') { if (typescript_1.default.isTemplateLiteral(item.initializer)) { const template = item.initializer.getText().trim().slice(1, -1); component.children = angularTemplateToMitosisNodes(template, options); } } } }); } } } } } } return component; }; function angularToMitosisComponent(code, options = {}) { return parseTypescript(code, options); } exports.angularToMitosisComponent = angularToMitosisComponent;