@builder.io/mitosis
Version:
Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io
110 lines (109 loc) • 4.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapSignalTypeInTSFile = exports.mapSignalType = exports.getSignalImportName = exports.getSignalMitosisImportForTarget = void 0;
const core_1 = require("@babel/core");
const function_1 = require("fp-ts/lib/function");
const babel_transform_1 = require("../../helpers/babel-transform");
const mitosis_imports_1 = require("../mitosis-imports");
const getSignalMappingForTarget = (target) => {
switch (target) {
case 'svelte':
const importDeclaration = core_1.types.importDeclaration([core_1.types.importSpecifier(core_1.types.identifier('Writable'), core_1.types.identifier('Writable'))], core_1.types.stringLiteral('svelte/store'));
importDeclaration.importKind = 'type';
return {
getTypeReference: (generics = []) => core_1.types.tsTypeReference(core_1.types.identifier('Writable'), core_1.types.tsTypeParameterInstantiation(generics)),
importDeclaration,
};
default:
return undefined;
}
};
const getSignalMitosisImportForTarget = (target) => {
const signalType = getSignalMappingForTarget(target);
if (!signalType) {
return undefined;
}
return (0, mitosis_imports_1.mapImportDeclarationToMitosisImport)(signalType.importDeclaration);
};
exports.getSignalMitosisImportForTarget = getSignalMitosisImportForTarget;
const getSignalImportName = (code) => {
let foundSignalUsage = false;
let signalImportName = undefined;
(0, babel_transform_1.babelTransformExpression)(code, {
ImportSpecifier(path) {
if (core_1.types.isIdentifier(path.node.imported) && path.node.imported.name === 'Signal') {
if (path.parentPath.isImportDeclaration() &&
path.parentPath.node.source.value === '@builder.io/mitosis') {
/**
* in case the import is aliased, we need to use the local name,
* e.g. `import { Signal as MySignal } from '../..'`
*/
signalImportName = path.node.local.name;
path.stop();
}
}
},
});
if (!signalImportName) {
return undefined;
}
(0, babel_transform_1.babelTransformExpression)(code, {
TSTypeReference(path) {
if (core_1.types.isIdentifier(path.node.typeName) && path.node.typeName.name === signalImportName) {
foundSignalUsage = true;
path.stop();
}
},
});
return foundSignalUsage ? signalImportName : undefined;
};
exports.getSignalImportName = getSignalImportName;
const addSignalImport = ({ code, target }) => {
const signalType = getSignalMappingForTarget(target);
if (!signalType) {
return code;
}
return (0, babel_transform_1.babelTransformExpression)(code, {
Program(path) {
path.node.body.unshift(signalType.importDeclaration);
},
});
};
/**
* Finds all `Signal` types and replaces them with the correct type for the given target.
* e.g. `Signal<string>` becomes `Writable<string>` for Svelte.
*/
const mapSignalType = ({ code, target, signalImportName = (0, exports.getSignalImportName)(code), }) => {
const signalType = getSignalMappingForTarget(target);
const map = (path) => {
var _a;
if (core_1.types.isIdentifier(path.node.typeName) && path.node.typeName.name === signalImportName) {
const params = ((_a = path.node.typeParameters) === null || _a === void 0 ? void 0 : _a.params) || [];
const newType = (signalType === null || signalType === void 0 ? void 0 : signalType.getTypeReference)
? signalType.getTypeReference(params)
: // if no mapping exists, drop `Signal` and just use the generic type passed to `Signal` as-is.
params[0];
path.replaceWith(newType);
}
};
return (0, babel_transform_1.babelTransformExpression)(code, {
TSTypeReference(path) {
map(path);
},
});
};
exports.mapSignalType = mapSignalType;
/**
* Processes the `Signal` type usage in a plain TS file:
* - Finds the `Signal` import name
* - Maps the `Signal` type to the target's equivalent
* - Adds the equivalent of the `Signal` import to the file
*/
const mapSignalTypeInTSFile = ({ code, target }) => {
const signalImportName = (0, exports.getSignalImportName)(code);
if (!signalImportName) {
return code;
}
return (0, function_1.pipe)((0, exports.mapSignalType)({ target, code, signalImportName }), (code) => addSignalImport({ code, target }));
};
exports.mapSignalTypeInTSFile = mapSignalTypeInTSFile;
;