@szzbmy/lowcode-cli
Version:
🐇 lowcode-cli is an efficient cli tool for Rabbitpre plugin component secondary development. ❤️
259 lines (258 loc) • 11.6 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (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 });
/*
* @Author: chubiao Ni
* @Date: 2022-02-11 14:04:29
* @Last Modified by: chubiao Ni
* @Last Modified time: 2022-02-17 14:47:39
*/
const fs_1 = require("fs");
const path_1 = require("path");
const shelljs_1 = __importDefault(require("shelljs"));
const react_1 = __importStar(require("react"));
const ink_1 = require("ink");
const components_1 = require("../../../components");
const interactive_1 = require("../../../components/interactive");
const create_code_1 = require("../../../apis/create-code");
const shell_1 = require("../../../utils/shell");
const utils_1 = require("../utils");
const config_1 = __importDefault(require("../../../config"));
const fs_2 = require("../../../config/fs");
const SELECT_LIST_LIMIT = 20;
function Loading(props) {
return (react_1.default.createElement(ink_1.Text, null,
react_1.default.createElement(ink_1.Text, { color: "green" },
react_1.default.createElement(components_1.Spinner, { type: "dots" })),
props.text));
}
var CREATE_STEP;
(function (CREATE_STEP) {
CREATE_STEP[CREATE_STEP["INIT"] = 0] = "INIT";
CREATE_STEP[CREATE_STEP["FETCH_CMPS"] = 1] = "FETCH_CMPS";
CREATE_STEP[CREATE_STEP["FETCH_TEMPLATES"] = 2] = "FETCH_TEMPLATES";
CREATE_STEP[CREATE_STEP["PULL_TEMPLATE"] = 3] = "PULL_TEMPLATE";
CREATE_STEP[CREATE_STEP["INTERACTIVE"] = 4] = "INTERACTIVE";
CREATE_STEP[CREATE_STEP["FINISHED"] = 5] = "FINISHED";
CREATE_STEP[CREATE_STEP["ERROR"] = 6] = "ERROR";
})(CREATE_STEP || (CREATE_STEP = {}));
var INTERACTIVES;
(function (INTERACTIVES) {
INTERACTIVES[INTERACTIVES["SELECT_CMP"] = 0] = "SELECT_CMP";
INTERACTIVES[INTERACTIVES["SELECT_TEMPLATE"] = 1] = "SELECT_TEMPLATE";
INTERACTIVES[INTERACTIVES["INPUT_NAME"] = 2] = "INPUT_NAME";
})(INTERACTIVES || (INTERACTIVES = {}));
function CreateCmp() {
const [folderName, setFolderName] = (0, react_1.useState)('');
const [selectedCmpInfo, setSelectedCmpInfo] = (0, react_1.useState)({});
const [selectedTemplateInfo, setSelectedTemplateInfo] = (0, react_1.useState)({});
const [stepState, setStepStateOriginal] = (0, react_1.useState)({
step: CREATE_STEP.INIT,
options: {},
});
const [cmpList, setCmpList] = (0, react_1.useState)([]);
const [templateList, setTemplateList] = (0, react_1.useState)([]);
const setStepState = (0, react_1.useCallback)((step, options) => {
setStepStateOriginal({ step, options });
}, []);
// 处理选择的组件
const onHandleSelectCmps = (0, react_1.useCallback)(cmpInfo => {
// 存储使用 component 数据, 作 config.jsonc 字段替换使用
setSelectedCmpInfo(cmpInfo);
// 选择模板
setStepState(CREATE_STEP.FETCH_TEMPLATES);
}, [setStepState, setSelectedCmpInfo]);
// 处理选择的模板
const onHandleSelectTemplate = (0, react_1.useCallback)(templateInfo => {
setSelectedTemplateInfo(templateInfo);
// 进入目录填写交互
setStepState(CREATE_STEP.INTERACTIVE, {
step: INTERACTIVES.INPUT_NAME,
msg: '模板导出目录: ',
});
}, [setStepState, setSelectedTemplateInfo]);
// 命名模板下载目录
const onHandleRename = (0, react_1.useCallback)(value => {
if ((0, fs_1.existsSync)((0, path_1.resolve)(value))) {
// 仍存在项目目录, 继续重写目录名
setStepState(CREATE_STEP.INTERACTIVE, {
step: INTERACTIVES.INPUT_NAME,
msg: '已存在目录, 请重新输入: ',
});
}
else {
// 目录名确定, 进入拉取模板流程
setFolderName(value);
setStepState(CREATE_STEP.PULL_TEMPLATE);
}
}, [setStepState]);
const init = (0, react_1.useCallback)(async () => {
setStepState(CREATE_STEP.FETCH_CMPS);
}, [setStepState]);
const fetchComponentList = (0, react_1.useCallback)(async () => {
try {
const cmpList = await (0, create_code_1.getCmpList)();
const formatedCmpList = (0, utils_1.formatCmpList)(cmpList);
if (formatedCmpList.length === 0) {
throw new Error('当前组件列表为空, 请先在低代码平台添加组件');
}
setCmpList(formatedCmpList);
setStepState(CREATE_STEP.INTERACTIVE, {
step: INTERACTIVES.SELECT_CMP,
});
}
catch (err) {
setStepState(CREATE_STEP.ERROR, {
msg: `获取组件列表失败: ${err.message}`,
});
}
}, [setStepState]);
// 从 gitlab 获取模版项目列表供选择
const fetchTemplateList = (0, react_1.useCallback)(async () => {
try {
const templateList = await (0, create_code_1.getTemplateList)();
const formatedTemplateList = (0, utils_1.formatTemplateList)(templateList);
if (formatedTemplateList.length === 0) {
throw new Error('无可用模板');
}
setTemplateList(formatedTemplateList);
setStepState(CREATE_STEP.INTERACTIVE, {
step: INTERACTIVES.SELECT_TEMPLATE,
});
}
catch (err) {
setStepState(CREATE_STEP.ERROR, {
msg: `获取模板列表失败: ${err.message}`,
});
}
}, [setStepState]);
// 从 gitlab 拉取模板项目
const pullingTemplate = (0, react_1.useCallback)(async () => {
try {
const { accessTokenName, accessToken, psdTemplatesRegistryUrl } = config_1.default.gitlab;
const { path } = selectedTemplateInfo;
await (0, shell_1.execCommandPromise)({
cmd: `git clone https://${accessTokenName}:${accessToken}@${psdTemplatesRegistryUrl} ${folderName}` +
` && cd ${folderName}` +
/** fix filter-branch可能失败: https://stackoverflow.com/questions/30325758/git-conversion-of-a-subdirectory-to-a-submodule/35937708 */
` && git filter-branch --subdirectory-filter ${path}/`,
silent: true,
});
// 清理 .git
await shelljs_1.default.rm('-rf', (0, path_1.resolve)(folderName, '.git'));
const { id, name, title } = selectedCmpInfo;
// 更新 config.jsonc 字段
(0, fs_2.updateComponentConfig)({
id,
name,
title,
isTemplate: false,
env: config_1.default.env,
appid: '',
shortUrl: '',
}, folderName);
setStepState(CREATE_STEP.FINISHED, { msg: '模板下载成功' });
}
catch (err) {
setStepState(CREATE_STEP.ERROR, {
msg: `下载模板代码失败: ${err.message}`,
});
}
}, [folderName, setStepState, selectedCmpInfo, selectedTemplateInfo]);
const finish = (0, react_1.useCallback)(() => {
process.exit(0);
}, []);
const error = (0, react_1.useCallback)(() => {
process.exit(1);
}, []);
(0, react_1.useEffect)(() => {
const func = {
[CREATE_STEP.INIT]: init,
[CREATE_STEP.FETCH_CMPS]: fetchComponentList,
[CREATE_STEP.FETCH_TEMPLATES]: fetchTemplateList,
[CREATE_STEP.PULL_TEMPLATE]: pullingTemplate,
[CREATE_STEP.FINISHED]: finish,
[CREATE_STEP.ERROR]: error,
}[stepState.step];
func && func();
}, [
init,
fetchComponentList,
fetchTemplateList,
pullingTemplate,
finish,
error,
stepState.step,
]);
let renderer = null;
switch (stepState.step) {
case CREATE_STEP.FETCH_CMPS:
renderer = react_1.default.createElement(Loading, { text: "\u6B63\u5728\u62C9\u53D6\u4E8C\u5F00\u7EC4\u4EF6\u5217\u8868" });
break;
case CREATE_STEP.FETCH_TEMPLATES:
renderer = react_1.default.createElement(Loading, { text: "\u6B63\u5728\u62C9\u53D6\u6A21\u677F\u5217\u8868" });
break;
case CREATE_STEP.PULL_TEMPLATE:
renderer = react_1.default.createElement(Loading, { text: "\u6B63\u5728\u4E0B\u8F7D\u6A21\u677F" });
break;
case CREATE_STEP.INTERACTIVE:
if (stepState.options?.step === INTERACTIVES.SELECT_CMP) {
renderer = (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(ink_1.Text, { color: "green" },
"\u9009\u62E9\u6A21\u677F(\u5171",
cmpList.length,
"\u4E2A):"),
react_1.default.createElement(ink_1.Box, { borderStyle: "single" },
react_1.default.createElement(components_1.SelectInput, { items: cmpList, limit: SELECT_LIST_LIMIT, onSelect: onHandleSelectCmps }))));
}
else if (stepState.options?.step === INTERACTIVES.SELECT_TEMPLATE) {
renderer = (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(ink_1.Text, { color: "green" },
"\u9009\u62E9\u6A21\u677F(\u5171",
templateList.length,
"\u4E2A):"),
react_1.default.createElement(ink_1.Box, { borderStyle: "single" },
react_1.default.createElement(components_1.SelectInput, { items: templateList, limit: SELECT_LIST_LIMIT, onSelect: onHandleSelectTemplate }))));
}
else if (stepState.options?.step === INTERACTIVES.INPUT_NAME) {
renderer = (react_1.default.createElement(interactive_1.InteractiveGenerator, { type: interactive_1.GENERATOR_TYPE.TEXT_INPUT, options: {
title: stepState.options?.msg,
props: {
onSubmit: onHandleRename,
},
} }));
}
break;
case CREATE_STEP.FINISHED:
renderer = react_1.default.createElement(ink_1.Text, { color: "green" }, stepState.options?.msg);
break;
case CREATE_STEP.ERROR:
renderer = react_1.default.createElement(ink_1.Text, { color: "red" }, stepState.options?.msg);
break;
default:
renderer = null;
}
return renderer;
}
exports.default = CreateCmp;