UNPKG

@szzbmy/lowcode-cli

Version:

🐇 lowcode-cli is an efficient cli tool for Rabbitpre plugin component secondary development. ❤️

259 lines (258 loc) 11.6 kB
"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;