@builder.io/mitosis
Version:
Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io
131 lines (130 loc) • 6.31 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.convertTypeScriptToJS = exports.babelTransformExpression = exports.babelTransformCode = void 0;
const babel = __importStar(require("@babel/core"));
const plugin_syntax_decorators_1 = __importDefault(require("@babel/plugin-syntax-decorators"));
const plugin_syntax_typescript_1 = __importDefault(require("@babel/plugin-syntax-typescript"));
const preset_typescript_1 = __importDefault(require("@babel/preset-typescript"));
const function_1 = require("fp-ts/lib/function");
const patterns_1 = require("./patterns");
const handleErrorOrExpression = ({ code, useCode, result, visitor, stripTypes, }) => {
try {
// If it can't, e.g. this is an expression or code fragment, modify the code below and try again
// Detect method fragments. These get passed sometimes and otherwise
// generate compile errors. They are of the form `foo() { ... }`
const isMethod = Boolean(!code.trim().startsWith('function') && code.trim().match(/^[a-z0-9_]+\s*\([^\)]*\)\s*[\{:]/i));
const isGetter = (0, patterns_1.checkIsGetter)(code);
const isMethodOrGetter = isMethod || isGetter;
if (isMethodOrGetter) {
useCode = `function ${useCode}`;
}
result = (0, function_1.pipe)(
// Parse the code as an expression (instead of the default, a block) by giving it a fake variable assignment
// e.g. if the code parsed is { ... } babel will treat that as a block by deafult, unless processed as an expression
// that is an object
`let _ = ${useCode}`, (code) => (0, exports.babelTransformCode)(code, visitor, stripTypes), trimSemicolons,
// Remove our fake variable assignment
(str) => str.replace(/let _ =\s/, ''));
if (isMethodOrGetter) {
return result.replace('function', '');
}
return result;
}
catch (err) {
console.error('Error parsing code:\n', { code, result, useCode });
throw err;
}
};
const babelTransform = ({ code, visitor, stripTypes, }) => {
return babel.transform(code, {
sourceFileName: 'file.tsx',
configFile: false,
babelrc: false,
parserOpts: { allowReturnOutsideFunction: true },
...(stripTypes ? { presets: [[preset_typescript_1.default, { isTSX: true, allExtensions: true }]] } : {}),
plugins: [
[plugin_syntax_typescript_1.default, { isTSX: true }],
[plugin_syntax_decorators_1.default, { legacy: true }],
...(visitor ? [() => ({ visitor })] : []),
],
});
};
const babelTransformCode = (code, visitor, stripTypes = false) => { var _a; return ((_a = babelTransform({ code, visitor, stripTypes })) === null || _a === void 0 ? void 0 : _a.code) || ''; };
exports.babelTransformCode = babelTransformCode;
// Babel adds trailing semicolons, but for expressions we need those gone
// TODO: maybe detect if the original code ended with one, and keep it if so, for the case
// of appending several fragements
const trimSemicolons = (code) => code.replace(/;$/, '');
const trimExpression = (type) => (code) => {
switch (type) {
case 'functionBody':
return code.replace(/^function\s*\(\)\s*\{/, '').replace(/\};?$/, '');
default:
return trimSemicolons(code);
}
};
const getType = (code, initialType) => {
// match for object literal like { foo: ... }
if (initialType === 'unknown' && code.trim().match(/^\s*{\s*[a-z0-9]+:/i)) {
return 'expression';
}
// For Builder content
if (initialType === 'unknown' &&
(code.includes('return _virtual_index') || code.trim().startsWith('return ')) &&
!code.trim().startsWith('function')) {
return 'functionBody';
}
return initialType;
};
const babelTransformExpression = (code, visitor, initialType = 'unknown', stripTypes = false) => {
if (!code) {
return '';
}
const isGetter = code.trim().startsWith('get ');
return (0, function_1.pipe)(code, isGetter ? patterns_1.replaceGetterWithFunction : function_1.identity, (code) => {
const type = getType(code, initialType);
const useCode = type === 'functionBody' ? `function(){${code}}` : code;
return { type, useCode };
}, ({ type, useCode }) => {
if (type !== 'expression') {
try {
return (0, function_1.pipe)((0, exports.babelTransformCode)(useCode, visitor, stripTypes), trimExpression(type));
}
catch (error) {
return handleErrorOrExpression({ code, useCode, result: null, visitor, stripTypes });
}
}
else {
return handleErrorOrExpression({ code, useCode, result: null, visitor, stripTypes });
}
}, isGetter ? patterns_1.replaceFunctionWithGetter : function_1.identity);
};
exports.babelTransformExpression = babelTransformExpression;
const convertTypeScriptToJS = (code) => (0, exports.babelTransformExpression)(code, {}, 'unknown', true);
exports.convertTypeScriptToJS = convertTypeScriptToJS;
;