@prodo/babel-plugin
Version:
Babel plugin for [Prodo](https://prodo.dev). See [documentation](https://docs.prodo.dev/basics/babel-plugin) for more info.
191 lines • 9.78 kB
JavaScript
;
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
var pathLib = require("path");
// Don't consider an action/component if it uses `model` - e.g. `model.createStore`
var MODEL_BLACKLIST = ["model"];
var isModelContextImport = function (importPath) {
return importPath.startsWith(".") &&
/^model(\.ctx)?(\.(j|t)sx?)?$/.test(pathLib.basename(importPath));
};
exports.default = (function (t, type, name, path) {
var universeImports = {
specifiers: {},
};
path.get("body").traverse({
Identifier: function (p) {
// Does it use something from "./model.ctx"
if (p.isReferencedIdentifier()) {
var binding = p.scope.getBinding(p.node.name);
if (binding != null) {
var bindingPath = binding.path;
if (((t.isImportSpecifier(bindingPath.node) &&
!MODEL_BLACKLIST.includes(bindingPath.node.imported.name)) ||
t.isImportNamespaceSpecifier(bindingPath.node) ||
t.isImportDefaultSpecifier(bindingPath.node)) &&
t.isImportDeclaration(bindingPath.parent) &&
isModelContextImport(bindingPath.parent.source.value)) {
universeImports.modelSource = bindingPath.parent.source.value.replace(/(\.ctx)?(?=\.(j|t)sx?)?$/, "");
universeImports.programPath = bindingPath.parentPath
.parentPath;
if (t.isImportSpecifier(bindingPath.node)) {
// import {foo} from "./model.ctx";
universeImports.specifiers[bindingPath.node.imported.name] =
bindingPath.node.local.name;
}
else if (t.isImportNamespaceSpecifier(bindingPath.node)) {
// import * as foo from "./model.ctx";
universeImports.namespace = bindingPath.node.local.name;
}
else if (t.isImportDefaultSpecifier(bindingPath.node)) {
// import foo from "./model.ctx";
universeImports.specifiers.default = bindingPath.node.local.name;
}
}
else if (t.isVariableDeclarator(bindingPath.node) &&
t.isCallExpression(bindingPath.node.init) &&
t.isIdentifier(bindingPath.node.init.callee) &&
bindingPath.node.init.callee.name === "require" &&
bindingPath.node.init.arguments.length === 1 &&
t.isStringLiteral(bindingPath.node.init.arguments[0]) &&
isModelContextImport(bindingPath.node.init.arguments[0]
.value)) {
// const foo = require("./model.ctx");
universeImports.modelSource = bindingPath.node.init
.arguments[0].value.replace(/(\.ctx)?(?=\.(j|t)sx?)?$/, "");
universeImports.programPath = bindingPath.parentPath
.parentPath;
if (t.isIdentifier(bindingPath.node.id)) {
// const foo = require("./model.ctx");
universeImports.namespace = bindingPath.node.id.name;
}
else if (t.isObjectPattern(bindingPath.node.id) &&
!MODEL_BLACKLIST.includes(p.node.name)) {
var property = bindingPath.node.id.properties.find(function (prop) {
return t.isObjectProperty(prop)
? t.isIdentifier(prop.value) &&
prop.value.name === p.node.name
: t.isIdentifier(prop.argument) &&
prop.argument.name === p.node.name;
});
if (property == null) {
throw new Error("You are using require in a way that the transpiler can't understand.");
}
if (t.isObjectProperty(property)) {
// const {foo} = require("./model.ctx");
universeImports.specifiers[property.key.name] = property.value.name;
}
else {
// const {...foo} = require("./model.ctx");
universeImports.specifierRest = property.argument.name;
}
}
}
}
}
},
});
if (universeImports.namespace == null &&
Object.keys(universeImports.specifiers).length === 0 &&
universeImports.specifierRest == null) {
// Doesn't use the universe, so don't change anything.
return;
}
if (universeImports.namespace != null &&
(Object.keys(universeImports.specifiers).length > 0 ||
universeImports.specifierRest != null)) {
throw new Error("Cannot import the context as both a namespace and using named imports.");
}
// Insert `import { model } from "./src/model";
var modelImport;
if (universeImports.programPath != null &&
universeImports.modelSource != null) {
var importDeclarationPath = universeImports.programPath
.get("body")
.find(function (expressionPath) {
return t.isImportDeclaration(expressionPath.node) &&
expressionPath.node.source.value === universeImports.modelSource;
});
if (importDeclarationPath == null) {
var importDeclaration = t.importDeclaration([t.importSpecifier(t.identifier("model"), t.identifier("model"))], t.stringLiteral(universeImports.modelSource));
universeImports.programPath.unshiftContainer("body", importDeclaration);
modelImport = { specifier: "model" };
}
else {
if (importDeclarationPath.node.specifiers.some(function (specifier) { return t.isImportNamespaceSpecifier(specifier); })) {
modelImport = {
namespace: importDeclarationPath.node.specifiers.find(function (specifier) { return t.isImportNamespaceSpecifier(specifier); }).local.name,
};
}
else if (importDeclarationPath.node.specifiers.some(function (specifier) {
return t.isImportSpecifier(specifier) &&
specifier.imported.name === "model";
})) {
modelImport = {
specifier: importDeclarationPath.node.specifiers.find(function (specifier) {
return t.isImportSpecifier(specifier) &&
specifier.imported.name === "model";
}).local.name,
};
}
else {
importDeclarationPath.unshiftContainer("specifiers", t.importSpecifier(t.identifier("model"), t.identifier("model")));
modelImport = { specifier: "model" };
}
}
}
if (modelImport == null) {
throw new Error("Could not import the model.");
}
/*
* If it's a FunctionDeclaration, turn it into a VariableDeclaration
*
* function foo () { ... }
*
* becomes
*
* const foo = function () { ... }
`*/
if (t.isFunctionDeclaration(path.node)) {
path.replaceWith(t.variableDeclaration("const", [
t.variableDeclarator(t.identifier(name), t.functionExpression(null, path.node.params, t.isBlockStatement(path.node.body)
? path.node.body
: t.blockStatement([t.returnStatement(path.node.body)]), path.node.generator, path.node.async)),
]));
path = path.get("declarations")[0].get("init");
}
/*
* Surround in model.action or model.connect
*
* const foo = () => { ... }
*
* becomes
*
* const foo = model.action(({state}) => () => { ... });
*/
path.replaceWith(t.callExpression(t.memberExpression("namespace" in modelImport
? t.memberExpression(t.identifier(modelImport.namespace), t.identifier("model"))
: t.identifier(modelImport.specifier), t.identifier(type === "action" ? "action" : "connect")), [
t.arrowFunctionExpression([
universeImports.namespace != null
? t.identifier(universeImports.namespace)
: t.objectPattern(__spreadArrays(Object.keys(universeImports.specifiers)
.sort()
.map(function (key) {
return t.objectProperty(t.identifier(key), t.identifier(universeImports.specifiers[key]), false, key === universeImports.specifiers[key]);
}), (universeImports.specifierRest != null
? [
t.restElement(t.identifier(universeImports.specifierRest)),
]
: []))),
], path.node),
t.stringLiteral(name),
]));
});
//# sourceMappingURL=inject-universe.js.map