UNPKG

create-unibest

Version:

快速创建 unibest 项目的脚手架工具

1,518 lines (1,494 loc) 58.6 kB
#!/usr/bin/env node // src/index.ts import process6 from "process"; import { green as green5, yellow as yellow4 } from "kolorist"; import minimist from "minimist"; // package.json var version = "4.0.16"; var package_default = { name: "create-unibest", type: "module", version, updateTime: "2026-04-25", packageManager: "pnpm@10.10.0", description: "\u5FEB\u901F\u521B\u5EFA unibest \u9879\u76EE\u7684\u811A\u624B\u67B6\u5DE5\u5177", author: "feige996", license: "MIT", homepage: "https://unibest.tech", bin: { best: "bin/index.js", "create-unibest": "bin/index.js", unibest: "bin/index.js" }, files: [ "bin", "dist", "features" ], scripts: { dev: "cross-env NODE_ENV=development tsup --watch", build: "cross-env NODE_ENV=production tsup", prepare: "pnpm build", start: "cross-env NODE_ENV=development node bin/index.js" }, dependencies: { "@clack/prompts": "^1.0.0", dayjs: "^1.11.18", ejs: "^4.0.0", "fs-extra": "^11.3.0", kolorist: "^1.8.0", minimist: "^1.2.8", "node-fetch": "^3.3.2" }, devDependencies: { "@types/ejs": "^3.1.5", "@types/fs-extra": "^11.0.4", "@types/minimist": "^1.2.5", "@types/node": "^24.5.0", "cross-env": "^7.0.3", tsup: "^8.5.0", typescript: "^5.9.0" } }; // src/commands/add.ts import fs4 from "fs"; import path3 from "path"; import process2 from "process"; import { cancel, intro, isCancel, log as log2, multiselect } from "@clack/prompts"; import { bold as bold2, green } from "kolorist"; // src/features/interface.ts var AVAILABLE_FEATURES = [ { name: "i18n", description: "\u591A\u8BED\u8A00\u652F\u6301", dependencies: { "vue-i18n": "^9.0.0", "dayjs": "^1.11.0" } }, { name: "login", description: "\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09", dependencies: {} }, { name: "lime-echart", description: "lime-echart \u56FE\u8868\u5E93", dependencies: { "echarts": "^5.4.1", "lodash-es": "^4.17.21" } }, { name: "ucharts", description: "uCharts \u56FE\u8868\u5E93", dependencies: { "@qiun/ucharts": "2.5.0-20230101" } } ]; function getFeatureByName(name) { return AVAILABLE_FEATURES.find((f) => f.name === name); } function getSelectedFeatures(options) { const features = []; if (options.i18n) { const feature = getFeatureByName("i18n"); if (feature) features.push(feature); } if (options.loginStrategy) { const feature = getFeatureByName("login"); if (feature) features.push(feature); } for (const library of options.chartLibraries || []) { const feature = getFeatureByName(library); if (feature) features.push(feature); } return features; } // src/features/loader.ts import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; var __filename = fileURLToPath(import.meta.url); var __dirname = path.dirname(__filename); var FEATURES_DIR = path.resolve(__dirname, "..", "features"); async function loadFeatureHooks(featureName) { const hooksPath = path.join(FEATURES_DIR, featureName, "hooks.js"); if (!fs.existsSync(hooksPath)) { return null; } const module = await import(hooksPath); return module; } function getAvailableFeatureNames() { if (!fs.existsSync(FEATURES_DIR)) { return []; } const entries = fs.readdirSync(FEATURES_DIR, { withFileTypes: true }); return entries.filter((e) => e.isDirectory() && fs.existsSync(path.join(FEATURES_DIR, e.name, "files"))).map((e) => e.name); } // src/utils/injector.ts import fs2 from "fs"; import path2, { dirname } from "path"; import { fileURLToPath as fileURLToPath2 } from "url"; var __filename2 = fileURLToPath2(import.meta.url); var __dirname2 = dirname(__filename2); var FEATURES_PATH = path2.join(__dirname2, "..", "features"); var FeatureInjector = class { constructor(projectPath) { this.projectPath = projectPath; } injectFile(targetPath, featureCode, placeholder) { const fullPath = path2.join(this.projectPath, targetPath); if (!fs2.existsSync(fullPath)) { return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` }; } const content = fs2.readFileSync(fullPath, "utf-8"); if (!content.includes(placeholder)) { return { success: false, message: `\u5360\u4F4D\u7B26\u4E0D\u5B58\u5728: ${placeholder}` }; } const newContent = content.replace(placeholder, featureCode); fs2.writeFileSync(fullPath, newContent); return { success: true, message: `\u6CE8\u5165\u6210\u529F: ${targetPath}` }; } replaceFile(targetPath, featureFilePath) { const targetFullPath = path2.join(this.projectPath, targetPath); const featureFullPath = path2.join(FEATURES_PATH, featureFilePath); if (!fs2.existsSync(featureFullPath)) { return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` }; } const featureContent = fs2.readFileSync(featureFullPath, "utf-8"); fs2.writeFileSync(targetFullPath, featureContent); return { success: true, message: `\u66FF\u6362\u6210\u529F: ${targetPath}` }; } createFile(relativePath, featureFilePath) { const targetFullPath = path2.join(this.projectPath, relativePath); const featureFullPath = path2.join(FEATURES_PATH, featureFilePath); if (!fs2.existsSync(featureFullPath)) { return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` }; } const dir = path2.dirname(targetFullPath); if (!fs2.existsSync(dir)) { fs2.mkdirSync(dir, { recursive: true }); } const featureContent = fs2.readFileSync(featureFullPath, "utf-8"); fs2.writeFileSync(targetFullPath, featureContent); return { success: true, message: `\u521B\u5EFA\u6210\u529F: ${relativePath}` }; } appendAfter(targetPath, marker, code) { const fullPath = path2.join(this.projectPath, targetPath); if (!fs2.existsSync(fullPath)) { return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` }; } const content = fs2.readFileSync(fullPath, "utf-8"); if (!content.includes(marker)) { return { success: false, message: `\u6807\u8BB0\u4E0D\u5B58\u5728: ${marker}` }; } const newContent = content.replace(marker, `${marker} ${code}`); fs2.writeFileSync(fullPath, newContent); return { success: true, message: `\u8FFD\u52A0\u6210\u529F: ${targetPath}` }; } }; async function injectI18n(projectPath) { const results = []; const injector = new FeatureInjector(projectPath); results.push( injector.appendAfter( "src/main.ts", `import 'virtual:uno.css'`, `import i18n from './locale/index'` ) ); results.push( injector.appendAfter( "src/main.ts", ` app.use(requestInterceptor)`, ` app.use(i18n)` ) ); results.push( injector.replaceFile( "src/tabbar/config.ts", "i18n/files/src/tabbar/config.ts" ) ); results.push( injector.replaceFile( "src/tabbar/index.vue", "i18n/files/src/tabbar/index.vue" ) ); results.push( injector.replaceFile( "src/tabbar/TabbarItem.vue", "i18n/files/src/tabbar/TabbarItem.vue" ) ); results.push( injector.replaceFile("src/utils/index.ts", "i18n/files/src/utils/index.ts") ); results.push( injector.replaceFile("src/store/token.ts", "i18n/files/src/store/token.ts") ); const i18nFiles = [ "src/locale/index.ts", "src/locale/en.json", "src/locale/zh-Hans.json", "src/locale/README.md", "src/utils/i18n.ts", "src/types/i18n.d.ts", "src/tabbar/i18n.ts", "src/pages/i18n/index.vue" ]; for (const file of i18nFiles) { const featurePath = `i18n/files/${file}`; results.push(injector.createFile(file, featurePath)); } return results; } async function injectLogin(projectPath) { const results = []; const injector = new FeatureInjector(projectPath); results.push( injector.replaceFile( "src/router/interceptor.ts", "login/files/src/router/interceptor.ts" ) ); results.push( injector.replaceFile( "src/router/config.ts", "login/files/src/router/config.ts" ) ); results.push( injector.replaceFile("src/pages/me/me.vue", "login/files/src/pages/me.vue") ); const loginFiles = [ "src/pages/auth/login.vue", "src/pages/auth/register.vue", "src/pages/auth/README.md" ]; for (const file of loginFiles) { const featurePath = `login/files/${file}`; results.push(injector.createFile(file, featurePath)); } return results; } function ensurePagesDemoSubPackage(projectPath) { const configPath = path2.join(projectPath, "pages.config.ts"); if (!fs2.existsSync(configPath)) { return { success: false, message: "\u6587\u4EF6\u4E0D\u5B58\u5728: pages.config.ts" }; } let content = fs2.readFileSync(configPath, "utf-8"); if (content.includes("root: 'pages-demo'") || content.includes('root: "pages-demo"')) { return { success: true, message: "pages-demo \u5DF2\u5B58\u5728" }; } const entry = `{ root: 'pages-demo', pages: [], }`; if (/subPackages:\s*\[\s*\]/.test(content)) { content = content.replace( /subPackages:\s*\[\s*\]/, `subPackages: [${entry}]` ); } else if (/subPackages:\s*\[/.test(content)) { content = content.replace( /subPackages:\s*\[/, `subPackages: [ ${entry},` ); } else { if (content.includes("tabBar:")) { content = content.replace( /\n\s*tabBar:\s*/, ` subPackages: [${entry}], tabBar: ` ); } else if (content.includes("defineUniPages({")) { content = content.replace( /\n\}\)\s*$/, ` subPackages: [${entry}], })` ); } else { return { success: false, message: "\u672A\u627E\u5230 defineUniPages \u914D\u7F6E" }; } } fs2.writeFileSync(configPath, content); return { success: true, message: "\u5DF2\u66F4\u65B0 pages.config.ts \u7684 pages-demo \u914D\u7F6E" }; } async function injectLimeEchart(projectPath) { const results = []; const injector = new FeatureInjector(projectPath); results.push(ensurePagesDemoSubPackage(projectPath)); const limeFiles = [ "src/uni_modules/lime-echart/package.json", "src/uni_modules/lime-echart/static/uvue.html", "src/uni_modules/lime-echart/static/echarts.min.js", "src/uni_modules/lime-echart/static/ecStat.min.js", "src/uni_modules/lime-echart/static/uni.webview.1.5.5.js", "src/uni_modules/lime-echart/components/lime-echart/lime-echart.vue", "src/uni_modules/lime-echart/components/lime-echart/lime-echart.nvue", "src/uni_modules/lime-echart/components/lime-echart/lime-echart.uvue", "src/uni_modules/lime-echart/components/l-echart/utils.js", "src/uni_modules/lime-echart/components/l-echart/uvue.uts", "src/uni_modules/lime-echart/components/l-echart/nvue.js", "src/uni_modules/lime-echart/components/l-echart/l-echart.vue", "src/uni_modules/lime-echart/components/l-echart/canvas.js", "src/uni_modules/lime-echart/components/l-echart/l-echart.uvue", "src/pages-demo/hooks/useEcharts.ts", "src/pages-demo/lime-echarts/index.vue", "src/pages-demo/lime-echarts/index2.vue", "src/pages-demo/lime-echarts/index2.ts" ]; for (const file of limeFiles) { const featurePath = `lime-echart/files/${file}`; results.push(injector.createFile(file, featurePath)); } return results; } async function injectUcharts(projectPath) { const results = []; const injector = new FeatureInjector(projectPath); results.push(ensurePagesDemoSubPackage(projectPath)); const uchartsFiles = [ "src/components/qiun-data-charts/config-ucharts.js", "src/components/qiun-data-charts/config-echarts.js", "src/components/qiun-data-charts/qiun-data-charts.vue", "src/components/qiun-data-charts/u-charts.js", "src/components/qiun-error/qiun-error.vue", "src/components/qiun-loading/loading1.vue", "src/components/qiun-loading/loading2.vue", "src/components/qiun-loading/loading3.vue", "src/components/qiun-loading/loading4.vue", "src/components/qiun-loading/loading5.vue", "src/components/qiun-loading/qiun-loading.vue", "src/components/qiun-title-bar/qiun-title-bar.vue", "src/pages-demo/ucharts/index.vue", "src/pages-demo/ucharts/data.json" ]; for (const file of uchartsFiles) { const featurePath = `ucharts/files/${file}`; results.push(injector.createFile(file, featurePath)); } return results; } // src/utils/logger.ts import { log, spinner } from "@clack/prompts"; import { bold, red } from "kolorist"; var logger = { /** 普通信息日志 */ info: (message) => { log.info(bold(message)); }, /** 成功日志 */ success: (message) => { log.success(bold(message)); }, /** 错误日志 */ error: (message) => { log.error(bold(message)); }, /** 警告日志 */ warn: (message) => { log.warn(bold(message)); }, /** 提示日志 */ tip: (message) => { log.info(bold(message)); }, /** 开始一个带有 spinner 的任务 */ start: (message) => { const s = spinner(); s.start(bold(message)); return { stop: (msg) => s.stop(msg ? bold(msg) : void 0), fail: (msg) => s.stop(msg ? bold(red(msg)) : void 0) }; } }; // src/utils/readPackageJson.ts import fs3 from "fs"; function readPackageJson(pkgPath) { if (!fs3.existsSync(pkgPath)) { throw new Error(`package.json not found: ${pkgPath}`); } const content = fs3.readFileSync(pkgPath, "utf-8"); return JSON.parse(content); } function writePackageJson(pkgPath, pkg) { fs3.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)} `); } // src/commands/add.ts function getFeatureStatusFromPackageJson(pkgPath) { try { const pkg = readPackageJson(pkgPath); return { "i18n": pkg.unibest?.i18n === true, "login": pkg.unibest?.loginStrategy === true, "lime-echart": pkg.unibest?.charts?.limeEchart === true, "ucharts": pkg.unibest?.charts?.ucharts === true }; } catch { return { "i18n": false, "login": false, "lime-echart": false, "ucharts": false }; } } function updatePackageJsonForFeature(pkgPath, featureName) { const pkg = readPackageJson(pkgPath); if (!pkg.unibest) { pkg.unibest = {}; } switch (featureName) { case "i18n": pkg.unibest.i18n = true; break; case "login": pkg.unibest.loginStrategy = true; break; case "lime-echart": pkg.unibest.charts = { ...pkg.unibest.charts, limeEchart: true }; break; case "ucharts": pkg.unibest.charts = { ...pkg.unibest.charts, ucharts: true }; break; } writePackageJson(pkgPath, pkg); } async function checkFeatureStatus(projectPath) { const pkgPath = path3.join(projectPath, "package.json"); const statusFromPkg = getFeatureStatusFromPackageJson(pkgPath); return [ { name: "i18n", enabled: statusFromPkg.i18n }, { name: "login", enabled: statusFromPkg.login }, { name: "lime-echart", enabled: statusFromPkg["lime-echart"] }, { name: "ucharts", enabled: statusFromPkg.ucharts } ]; } async function addFeature(featureName, projectPath, options = {}) { const feature = getFeatureByName(featureName); if (!feature) { logger.error(`\u672A\u77E5\u7684 Feature: ${featureName}`); return false; } const pkgPath = path3.join(projectPath, "package.json"); const pkg = readPackageJson(pkgPath); let alreadyAdded = false; if (featureName === "i18n" && pkg.unibest?.i18n === true) { alreadyAdded = true; } else if (featureName === "login" && pkg.unibest?.loginStrategy === true) { alreadyAdded = true; } else if (featureName === "lime-echart" && pkg.unibest?.charts?.limeEchart === true) { alreadyAdded = true; } else if (featureName === "ucharts" && pkg.unibest?.charts?.ucharts === true) { alreadyAdded = true; } if (alreadyAdded && !options.force) { logger.warn(`Feature ${featureName} \u5DF2\u6DFB\u52A0\u8FC7\uFF0C\u5982\u9700\u91CD\u65B0\u6CE8\u5165\u8BF7\u4F7F\u7528 --force \u53C2\u6570`); return true; } log2.info(`\u6B63\u5728\u6DFB\u52A0 Feature: ${green(featureName)} - ${feature.description}`); try { let results; switch (featureName) { case "i18n": results = await injectI18n(projectPath); break; case "login": results = await injectLogin(projectPath); break; case "lime-echart": results = await injectLimeEchart(projectPath); break; case "ucharts": results = await injectUcharts(projectPath); break; default: logger.error(`\u4E0D\u652F\u6301\u7684 Feature: ${featureName}`); return false; } for (const result of results) { if (result.success) { logger.success(result.message); } else { logger.warn(result.message); } } const hooks = await loadFeatureHooks(featureName); if (hooks?.postApply) { await hooks.postApply({ options: { projectName: "", platforms: [], uiLibrary: "none", i18n: true, loginStrategy: true }, projectPath, featureName }); } updatePackageJsonForFeature(pkgPath, featureName); logger.success(`\u5DF2\u66F4\u65B0 package.json \u7684 unibest \u914D\u7F6E`); if (feature.dependencies && Object.keys(feature.dependencies).length > 0) { logger.info(`\u5B89\u88C5\u4F9D\u8D56: ${Object.keys(feature.dependencies).join(", ")}`); } logger.success(`Feature ${featureName} \u6DFB\u52A0\u6210\u529F\uFF01`); return true; } catch (error) { logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`); return false; } } async function addCommand(args) { const options = { path: args.path || args.p || ".", feature: args._[1] || args.feature || args.f, force: args.force || args.f }; intro(bold2(green(`create-unibest@v${version} \u6DFB\u52A0 Feature`))); const projectPath = path3.isAbsolute(options.path) ? options.path : path3.join(process2.cwd(), options.path); const pkgPath = path3.join(projectPath, "package.json"); if (!fs4.existsSync(pkgPath)) { logger.error(`\u9879\u76EE\u4E0D\u5B58\u5728: ${projectPath}`); process2.exit(1); } const pkg = readPackageJson(pkgPath); if (pkg.name !== "unibest") { logger.warn(`\u5F53\u524D\u9879\u76EE\u53EF\u80FD\u4E0D\u662F unibest \u9879\u76EE: ${pkg.name}`); } const availableFeatures = getAvailableFeatureNames(); try { if (!options.feature) { const detected = await checkFeatureStatus(projectPath); const available = availableFeatures.filter((f) => !detected.find((d) => d.name === f && d.enabled)); if (available.length === 0) { logger.info("\u6240\u6709\u53EF\u7528 Feature \u5DF2\u542F\u7528"); return; } const selectedFeatures = await multiselect({ message: `\u8BF7\u9009\u62E9\u8981\u6DFB\u52A0\u7684 Feature`, options: available.map((name) => { const feature = getFeatureByName(name); return { value: name, label: feature?.name || name, hint: feature?.description || "" }; }), required: false }); if (isCancel(selectedFeatures)) { cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88"); process2.exit(0); } if (!Array.isArray(selectedFeatures) || selectedFeatures.length === 0) { logger.info("\u672A\u9009\u62E9\u4EFB\u4F55 Feature"); return; } for (const featureName of selectedFeatures) { await addFeature(featureName, projectPath, options); } } else { const features = Array.isArray(options.feature) ? options.feature : [options.feature]; for (const featureName of features) { await addFeature(featureName, projectPath, options); } } } catch (error) { logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`); process2.exit(1); } } // src/commands/create.ts import { intro as intro2, log as log5 } from "@clack/prompts"; import { bold as bold3, green as green3, yellow as yellow2 } from "kolorist"; // src/utils/beacon.ts import crypto from "crypto"; import os2 from "os"; import dayjs from "dayjs"; import fetch2 from "node-fetch"; // src/utils/debug.ts import { magenta } from "kolorist"; function debug(...args) { const isDev = process.env.NODE_ENV === "development"; if (isDev) { const debugPrefix = magenta("[debug]"); console.log(debugPrefix, ...args); } } // src/utils/unibestVersion.ts import { promises as fs5 } from "fs"; import os from "os"; import { join } from "path"; import fetch from "node-fetch"; async function getUnibestVersionFromGitee() { try { const apiUrl = `https://gitee.com/api/v5/repos/feige996/unibest/contents/package.json?ref=main`; const response = await fetch(apiUrl, { method: "GET", headers: { "Content-Type": "application/json" } }); if (response.ok) { const data = await response.json(); const { content, encoding } = data; if (encoding === "base64") { const decodedContent = Buffer.from(content, "base64").toString("utf8"); const packageJson = JSON.parse(decodedContent); return packageJson.version || null; } else { return null; } } else { return null; } } catch (error) { return null; } } // src/utils/beacon.ts async function beacon(options) { try { const unibestVersion = await getUnibestVersionFromGitee(); const deviceIdentifier = generateDeviceIdentifier(); await fetch2("https://ukw0y1.laf.run/create-unibest-v3/beacon", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...options, version: unibestVersion, cbVersion: package_default.version, createAt: dayjs().format("YYYY-MM-DD HH:mm:ss"), nodeVersion: process.version, osPlatform: process.platform, cpuModel: os2.cpus()[0]?.model || "unknown", osRelease: os2.release(), totalMem: Math.round(os2.totalmem() / (1024 * 1024 * 1024)), // 四舍五入为整数 GB cpuArch: process.arch, uuid: deviceIdentifier // 添加设备唯一标识符 }) }); debug("Beacon sent successfully"); } catch (error) { } } function generateDeviceIdentifier() { const deviceInfo = [os2.cpus()[0]?.model || "", os2.totalmem().toString(), os2.platform(), os2.userInfo().username].join( "|" ); const hash = crypto.createHash("sha256").update(deviceInfo).digest("hex"); return hash; } // src/utils/validate.ts import { existsSync } from "fs"; import { join as join2 } from "path"; import { yellow } from "kolorist"; function validateProjectName(name) { const reg = /^[\w-]+$/; if (!reg.test(name)) { return false; } if (name.startsWith("-") || name.endsWith("-")) { return false; } return true; } function checkProjectNameExistAndValidate(_projectName) { const projectName = _projectName.trim(); if (existsSync(join2(process.cwd(), projectName))) { return `\u76EE\u5F55 ${yellow(projectName)} \u5DF2\u5B58\u5728\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u540D\u79F0`; } if (!validateProjectName(projectName)) { return `\u9879\u76EE\u540D\u79F0 ${yellow(projectName)} \u4E0D\u7B26\u5408\u89C4\u8303\uFF0C\u8BF7\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u8FDE\u5B57\u7B26\u6216\u4E0B\u5212\u7EBF`; } return ""; } // src/commands/create/generate.ts import path4 from "path"; import process4 from "process"; import { log as log4 } from "@clack/prompts"; // src/utils/cloneRepo.ts import { exec } from "child_process"; import { promises as fsPromises } from "fs"; import { join as join4 } from "path"; import process3 from "process"; import { log as log3 } from "@clack/prompts"; import { red as red2 } from "kolorist"; // src/utils/replacePackageJson.ts import { readFileSync, writeFileSync } from "fs"; import { join as join3 } from "path"; import dayjs2 from "dayjs"; function replaceContent(filePath, projectName, version2, options) { const fileContent = JSON.parse(readFileSync(filePath, "utf8")); const unibestVersion = fileContent["unibest-version"]; const unibestUpdateTime = fileContent["unibest-update-time"]; delete fileContent["unibest-version"]; delete fileContent["unibest-update-time"]; delete fileContent.metadata; delete fileContent.name; delete fileContent.version; const { projectName: _, ...restOptions } = options; const selectedFeatures = getSelectedFeatures(options); const featureDeps = {}; for (const feature of selectedFeatures) { if (feature.dependencies) { Object.assign(featureDeps, feature.dependencies); } } if (!fileContent.dependencies) { fileContent.dependencies = {}; } for (const [pkg, ver] of Object.entries(featureDeps)) { if (!fileContent.dependencies[pkg]) { fileContent.dependencies[pkg] = ver; } } const newContent = { name: projectName, type: fileContent.type, // 保持 type 在前(如果存在) version: version2, unibest: { ...restOptions, cliVersion: version, unibestVersion, unibestUpdateTime, createdAt: dayjs2().format("YYYY-MM-DD HH:mm:ss") }, ...fileContent // 剩余字段 }; writeFileSync(filePath, JSON.stringify(newContent, null, 2)); } function replacePackageJson(root2, name, version2, options) { const projectName = name.toLocaleLowerCase().replace(/\s/g, "-"); const pkgPath = join3(root2, "package.json"); replaceContent(pkgPath, projectName, version2, options); } // src/utils/cloneRepo.ts var REPO_URL = "https://gitee.com/feige996/unibest.git"; async function removeGitFolder(localPath) { const gitFolderPath = join4(localPath, ".git"); await fsPromises.rm(gitFolderPath, { recursive: true, force: true }); } async function cloneRepo(projectName, branch) { log3.info("\u4ECE Git \u514B\u9686\u57FA\u7840\u6A21\u677F..."); await new Promise((resolve, reject) => { const execStr = `git clone --depth=1 -b ${branch} ${REPO_URL} "${projectName}"`; exec(execStr, async (error) => { if (error) { log3.error(`${red2("\u514B\u9686\u6A21\u677F\u5931\u8D25:")} ${error}`); reject(error); return; } try { await removeGitFolder(projectName); resolve(); } catch (error2) { log3.error(`${red2("\u79FB\u9664 .git \u6587\u4EF6\u5939\u5931\u8D25:")} ${error2}`); reject(error2); } }); }); } async function cloneRepoByBranch(root2, name, branch, options) { try { await cloneRepo(name, "base"); } catch (error) { log3.error(`${red2(`\u6A21\u677F\u4E0B\u8F7D\u5931\u8D25\uFF01`)} ${error}`); process3.exit(1); } const projectPath = join4(root2, name); replacePackageJson(projectPath, name, "1.0.0", options); } // src/utils/uiLibrary.ts import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs"; import { join as join5 } from "path"; var UI_LIBRARY_CONFIGS = { "none": null, "wot-ui": { packageName: "wot-design-uni", easycom: { pattern: "^wd-(.*)", path: "wot-design-uni/components/wd-$1/wd-$1.vue" }, types: ["wot-design-uni/global.d.ts"] }, /** Wot UI v2,npm 包 @wot-ui/ui,见 https://wot-ui.cn/guide/quick-use.html */ "wot-ui-v2": { packageName: "@wot-ui/ui", devDependencies: { sass: "latest" }, easycom: { pattern: "^wd-(.*)", path: "@wot-ui/ui/components/wd-$1/wd-$1.vue" }, types: ["@wot-ui/ui/global"] }, "sard-uniapp": { packageName: "sard-uniapp", easycom: { pattern: "^sar-(.*)", path: "sard-uniapp/components/$1/$1.vue" }, types: ["sard-uniapp/global"], appVueImport: "@import 'sard-uniapp/index.scss';" }, "uview-pro": { packageName: "uview-pro", easycom: { pattern: "^u-(.*)", path: "uview-pro/components/u-$1/u-$1.vue" }, needMainImport: true, mainImport: "import uViewPro from 'uview-pro';", needUniScss: true, uniScssImport: "@import 'uview-pro/theme.scss';", needAppVue: true, appVueImport: "@import 'uview-pro/index.scss';" }, "uv-ui": { packageName: "@climblee/uv-ui", easycom: { pattern: "^uv-(.*)", path: "@climblee/uv-ui/components/uv-$1/uv-$1.vue" }, types: ["@ttou/uv-typings/shim", "@ttou/uv-typings/v2"] }, "uview-plus": { packageName: "uview-plus", // uview-plus 需要多个 easycom 配置 easycom: { pattern: "^u--(.*)", path: "uview-plus/components/u-$1/u-$1.vue" }, types: ["uview-plus/types"], needUniScss: true, uniScssImport: "@import 'uview-plus/theme.scss'; // /* \u884C\u4E3A\u76F8\u5173\u989C\u8272 */" }, "tdesign": { packageName: "@tdesign/uniapp", easycom: { pattern: "^t-(.*)", path: "@tdesign/uniapp/$1/$1.vue" }, mainImport: "import '@tdesign/uniapp/common/style/theme/index.css';", types: ["@tdesign/uniapp/global.d.ts"] } }; function getUILibraryConfig(uiLibrary) { return UI_LIBRARY_CONFIGS[uiLibrary]; } async function applyUILibraryConfig(projectPath, uiLibrary) { if (uiLibrary === "none") { return; } const config = getUILibraryConfig(uiLibrary); if (!config) { return; } await updatePackageJson(projectPath, config.packageName, config.devDependencies); if (config.easycom) { await updatePagesConfig(projectPath, config.easycom); if (uiLibrary === "uview-plus") { await updatePagesConfig(projectPath, { pattern: "^up-(.*)", path: "uview-plus/components/u-$1/u-$1.vue" }); await updatePagesConfig(projectPath, { pattern: "^u-([^-].*)", path: "uview-plus/components/u-$1/u-$1.vue" }); } } if (config.types && config.types.length > 0) { await updateTsConfig(projectPath, config.types); } if (config.needMainImport && config.mainImport) { await updateMainTs(projectPath, config.mainImport); } if (config.needUniScss && config.uniScssImport) { await updateUniScss(projectPath, config.uniScssImport); } if (config.needAppVue && config.appVueImport) { await updateAppVue(projectPath, config.appVueImport); } if (uiLibrary === "wot-ui-v2") { await ensureWotUiV2Resolver(projectPath); } } var WOT_UI_V2_RESOLVER_FILENAME = "wot-ui-resolver.ts"; var WOT_UI_V2_RESOLVER_CONTENT = `import type { ComponentResolver } from '@uni-helper/vite-plugin-uni-components' import { kebabCase } from '@uni-helper/vite-plugin-uni-components' /** * npm \u5B89\u88C5\u7684 Wot UI \u7EC4\u4EF6\u5728 H5 \u7AEF\u9700\u901A\u8FC7 vite-plugin-uni-components \u89E3\u6790\uFF0C * \u624D\u80FD\u6B63\u786E\u6302\u8F7D\u7EC4\u4EF6\u6837\u5F0F\u3002 */ export function WotResolver(): ComponentResolver { return { type: 'component', resolve: (name: string) => { if (name.match(/^Wd[A-Z]/)) { const compName = kebabCase(name) return { name, from: \`@wot-ui/ui/components/\${compName}/\${compName}.vue\`, } } if (name.startsWith('wd-')) { return { name, from: \`@wot-ui/ui/components/\${name}/\${name}.vue\`, } } }, } } `; async function ensureWotUiV2Resolver(projectPath) { const resolverPath = join5(projectPath, WOT_UI_V2_RESOLVER_FILENAME); const viteConfigPath = join5(projectPath, "vite.config.ts"); if (!existsSync2(resolverPath)) { writeFileSync2(resolverPath, WOT_UI_V2_RESOLVER_CONTENT); } if (existsSync2(viteConfigPath)) { updateViteConfigForWotUiV2(viteConfigPath); } } function updateViteConfigForWotUiV2(viteConfigPath) { const original = readFileSync2(viteConfigPath, "utf8"); let content = original; if (!content.includes(`from './${WOT_UI_V2_RESOLVER_FILENAME.replace(".ts", "")}'`)) { const importTarget = `import { WotResolver } from './${WOT_UI_V2_RESOLVER_FILENAME.replace(".ts", "")}'`; const uniPagesImportRegex = /(import\s+UniPages\s+from\s+['"]@uni-helper\/vite-plugin-uni-pages['"]\s*\n)/; if (uniPagesImportRegex.test(content)) { content = content.replace(uniPagesImportRegex, `$1${importTarget} `); } else { content = `${importTarget} ${content}`; } } const uniComponentsRegex = /UniComponents\(\{[\s\S]*?\}\)/; const matched = content.match(uniComponentsRegex); if (matched && !matched[0].includes("resolvers:")) { const block = matched[0]; const updatedBlock = block.replace(/\}\)$/, ` resolvers: [WotResolver()], })`); content = content.replace(block, updatedBlock); } if (content !== original) { writeFileSync2(viteConfigPath, ensureTrailingNewline(content)); } } async function updatePackageJson(projectPath, packageName, devDependencies) { const packageJsonPath = join5(projectPath, "package.json"); if (!existsSync2(packageJsonPath)) { return; } const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8")); if (!packageJson.dependencies) { packageJson.dependencies = {}; } if (!packageJson.dependencies[packageName]) { packageJson.dependencies[packageName] = "latest"; } if (devDependencies && Object.keys(devDependencies).length > 0) { if (!packageJson.devDependencies) { packageJson.devDependencies = {}; } for (const [name, version2] of Object.entries(devDependencies)) { if (!packageJson.devDependencies[name]) { packageJson.devDependencies[name] = version2; } } } writeFileSync2(packageJsonPath, `${JSON.stringify(packageJson, null, 2)} `); } async function updatePagesConfig(projectPath, easycom) { const pagesConfigPath = join5(projectPath, "pages.config.ts"); if (!existsSync2(pagesConfigPath)) { return; } const originalContent = readFileSync2(pagesConfigPath, "utf8"); let content = originalContent; const patternLiteral = escapeSingleQuotes(easycom.pattern); const pathLiteral = escapeSingleQuotes(easycom.path); const existingEntryRegex = new RegExp( `["']${escapeForRegExp(patternLiteral)}["']\\s*:\\s*["']${escapeForRegExp(pathLiteral)}["']` ); if (existingEntryRegex.test(content)) { return; } const entry = { pattern: patternLiteral, path: pathLiteral }; content = addToExistingCustomBlock(content, entry) ?? addCustomBlock(content, entry) ?? addEasycomBlock(content, entry) ?? appendEasycomBlock(content, entry); if (content !== originalContent) { writeFileSync2(pagesConfigPath, ensureTrailingNewline(content)); } } async function updateTsConfig(projectPath, types) { const tsConfigPath = join5(projectPath, "tsconfig.json"); if (!existsSync2(tsConfigPath)) { return; } const tsConfig = JSON.parse(readFileSync2(tsConfigPath, "utf8")); if (!tsConfig.compilerOptions) { tsConfig.compilerOptions = {}; } if (!tsConfig.compilerOptions.types) { tsConfig.compilerOptions.types = []; } const existingTypes = tsConfig.compilerOptions.types; for (const type of types) { if (!existingTypes.includes(type)) { existingTypes.push(type); } } writeFileSync2(tsConfigPath, `${JSON.stringify(tsConfig, null, 2)} `); } async function updateMainTs(projectPath, importCode) { const mainTsPath = join5(projectPath, "src", "main.ts"); if (!existsSync2(mainTsPath)) { return; } let content = readFileSync2(mainTsPath, "utf8"); const firstLine = importCode.split("\n")[0]; if (content.includes(firstLine)) { return; } const vueImportRegex = /(import\s+(?:\S.*)?from\s+['"]vue['"];?\s*\n)/; const match = content.match(vueImportRegex); if (match) { content = content.replace(vueImportRegex, `$1${importCode} `); } else { content = `${importCode} ${content}`; } if (importCode.includes("uview-pro")) { const appUseRegex = /(const\s+app\s*=\s*createSSRApp\(App\);?\s*\n)/; const appUseMatch = content.match(appUseRegex); if (appUseMatch && !content.includes("app.use(uViewPro)")) { content = content.replace(appUseRegex, `$1 app.use(uViewPro); `); } } writeFileSync2(mainTsPath, content); } async function updateUniScss(projectPath, importCode) { const uniScssPath = join5(projectPath, "src", "uni.scss"); if (!existsSync2(uniScssPath)) { const altPath = join5(projectPath, "uni.scss"); if (existsSync2(altPath)) { await updateScssFile(altPath, importCode); } return; } await updateScssFile(uniScssPath, importCode); } async function updateScssFile(filePath, importCode) { let content = readFileSync2(filePath, "utf8"); if (content.includes(importCode)) { return; } content = `${content.trim()} ${importCode} `; writeFileSync2(filePath, content); } async function updateAppVue(projectPath, importCode) { const appVuePath = join5(projectPath, "src", "App.vue"); if (!existsSync2(appVuePath)) { return; } let content = readFileSync2(appVuePath, "utf8"); if (content.includes(importCode)) { return; } const styleRegex = /(<style[^>]*>)/; const match = content.match(styleRegex); if (match) { content = content.replace(styleRegex, `$1 ${importCode}`); } else { content = `${content} <style lang="scss"> ${importCode}</style>`; } writeFileSync2(appVuePath, content); } function addToExistingCustomBlock(content, entry) { const customIndex = content.indexOf("custom:"); if (customIndex === -1) { return null; } const braceIndex = content.indexOf("{", customIndex); if (braceIndex === -1) { return null; } const closingIndex = findMatchingBrace(content, braceIndex); if (closingIndex === -1) { return null; } const inside = content.slice(braceIndex + 1, closingIndex); const hasEntries = inside.trim().length > 0; const entryIndent = `${getLineIndent(content, braceIndex)} `; const entryLine = `${entryIndent}'${entry.pattern}': '${entry.path}',`; if (!hasEntries) { const closingIndent = getLineIndent(content, closingIndex); return `${content.slice(0, braceIndex + 1)} ${entryLine} ${closingIndent}${content.slice(closingIndex)}`; } const beforeRaw = content.slice(0, closingIndex).replace(/\s*$/, ""); const separator = beforeRaw.endsWith("\n") ? "" : "\n"; const after = content.slice(closingIndex); return `${beforeRaw}${separator}${entryLine} ${after}`; } function addCustomBlock(content, entry) { const easycomIndex = content.indexOf("easycom:"); if (easycomIndex === -1) { return null; } const braceIndex = content.indexOf("{", easycomIndex); if (braceIndex === -1) { return null; } const closingIndex = findMatchingBrace(content, braceIndex); if (closingIndex === -1) { return null; } const easycomIndent = getLineIndent(content, braceIndex); const customIndent = `${easycomIndent} `; const entryIndent = `${customIndent} `; const customBlock = `${customIndent}custom: { ${entryIndent}'${entry.pattern}': '${entry.path}', ${customIndent}},`; const beforeRaw = content.slice(0, closingIndex).replace(/\s*$/, ""); const separator = beforeRaw.endsWith("\n") ? "" : "\n"; const after = content.slice(closingIndex); return `${beforeRaw}${separator}${customBlock} ${after}`; } function addEasycomBlock(content, entry) { const exportIndex = content.indexOf("export default"); if (exportIndex === -1) { return null; } const braceIndex = content.indexOf("{", exportIndex); if (braceIndex === -1) { return null; } const closingIndex = findMatchingBrace(content, braceIndex); if (closingIndex === -1) { return null; } const blockIndent = `${getLineIndent(content, braceIndex)} `; const entryIndent = `${blockIndent} `; const block = `${blockIndent}easycom: { ${blockIndent} autoscan: true, ${blockIndent} custom: { ${entryIndent}'${entry.pattern}': '${entry.path}', ${blockIndent} }, ${blockIndent}},`; const before = content.slice(0, braceIndex + 1); const after = content.slice(braceIndex + 1); const prefix = before.endsWith("\n") ? before : `${before} `; return `${prefix}${block} ${after}`; } function appendEasycomBlock(content, entry) { const block = ` export const easycom = { autoscan: true, custom: { '${entry.pattern}': '${entry.path}', }, } `; return `${content}${block}`; } function findMatchingBrace(content, startIndex) { let depth = 0; for (let i = startIndex; i < content.length; i += 1) { const char = content[i]; if (char === "{") { depth += 1; } else if (char === "}") { depth -= 1; if (depth === 0) { return i; } } } return -1; } function getLineIndent(content, index) { const lineStart = content.lastIndexOf("\n", index) + 1; const line = content.slice(lineStart, index); const match = line.match(/^\s*/); return match ? match[0] : ""; } function escapeSingleQuotes(value) { return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); } function escapeForRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function ensureTrailingNewline(value) { return value.endsWith("\n") ? value : `${value} `; } // src/commands/create/generate.ts var root = process4.cwd(); async function generateProject(options) { debug("generateProject options", options); const { projectName, platforms, uiLibrary, loginStrategy, i18n, chartLibraries } = options; const projectPath = path4.join(root, projectName); debug("\u62C9\u53D6 base \u5206\u652F"); await cloneRepoByBranch(root, projectName, "base", options); if (i18n) { debug("\u6CE8\u5165 i18n feature"); const results = await injectI18n(projectPath); for (const result of results) { if (result.success) { debug(result.message); } else { logger.warn(result.message); } } } if (loginStrategy) { debug("\u6CE8\u5165 login feature"); const results = await injectLogin(projectPath); for (const result of results) { if (result.success) { debug(result.message); } else { logger.warn(result.message); } } } for (const chartLibrary of chartLibraries || []) { if (chartLibrary === "lime-echart") { debug("\u6CE8\u5165 lime-echart feature"); const results = await injectLimeEchart(projectPath); for (const result of results) { if (result.success) { debug(result.message); } else { logger.warn(result.message); } } } if (chartLibrary === "ucharts") { debug("\u6CE8\u5165 ucharts feature"); const results = await injectUcharts(projectPath); for (const result of results) { if (result.success) { debug(result.message); } else { logger.warn(result.message); } } } } if (uiLibrary === "none") { debug("\u4E0D\u5F15\u5165\u4EFB\u4F55UI\u5E93"); } else { debug(`\u914D\u7F6E UI \u5E93: ${uiLibrary}`); try { await applyUILibraryConfig(projectPath, uiLibrary); logger.success(`UI \u5E93 ${uiLibrary} \u914D\u7F6E\u5B8C\u6210`); } catch (error) { logger.warn(`UI \u5E93 ${uiLibrary} \u914D\u7F6E\u5931\u8D25: ${error.message}`); logger.info("\u60A8\u53EF\u4EE5\u5728\u9879\u76EE\u521B\u5EFA\u540E\u624B\u52A8\u914D\u7F6E UI \u5E93"); } } const selectedFeatures = getSelectedFeatures(options); const allDeps = {}; for (const feature of selectedFeatures) { if (feature.dependencies) { Object.assign(allDeps, feature.dependencies); } } if (Object.keys(allDeps).length > 0) { log4.info(`Feature \u4F9D\u8D56: ${Object.keys(allDeps).join(", ")}`); } try { log4.success(`\u9879\u76EE${projectName}\u521B\u5EFA\u6210\u529F\uFF01`); logger.info("\u4E0B\u4E00\u6B65:"); logger.info(` cd ${projectName}`); logger.info(" pnpm i"); logger.info(" pnpm dev"); logger.info(" \u8FD0\u884C\u5B8C\u4EE5\u4E0A\u547D\u4EE4\u540E\uFF0C\u518D\u8FD0\u884C\u5176\u4ED6\u5E73\u53F0"); logger.info(" \u5982\uFF1Apnpm dev:mp, pnpm dev:app \u7B49"); } catch (error) { logger.error(`\u751F\u6210\u9879\u76EE\u5931\u8D25: ${error.message}`); throw error; } } // src/commands/create/prompts.ts import process5 from "process"; import { cancel as cancel2, confirm, isCancel as isCancel2, multiselect as multiselect2, select, text } from "@clack/prompts"; import { green as green2, red as red3 } from "kolorist"; var VALID_PLATFORMS = ["h5", "mp-weixin", "app", "mp-alipay", "mp-toutiao"]; var VALID_UI_LIBRARIES = ["none", "wot-ui-v2", "wot-ui", "uview-pro", "sard-uniapp", "uv-ui", "uview-plus", "tdesign"]; var VALID_CHART_LIBRARIES = ["lime-echart", "ucharts"]; async function promptUser(projectName, argv = {}) { let platforms; let uiLibrary; let loginStrategy; let i18n; let chartLibraries; const platformArg = argv.p || argv.platform; if (platformArg) { let parsedPlatforms = []; if (Array.isArray(platformArg)) { parsedPlatforms = platformArg; } else if (typeof platformArg === "string") { parsedPlatforms = platformArg.split(","); } const invalidPlatforms = parsedPlatforms.filter((p) => !VALID_PLATFORMS.includes(p)); if (invalidPlatforms.length > 0) { console.error(red3(`\u65E0\u6548\u7684\u5E73\u53F0\u53C2\u6570: ${invalidPlatforms.join(", ")}`)); console.error(red3(`\u53EF\u9009\u503C: ${VALID_PLATFORMS.join(", ")}`)); process5.exit(1); } platforms = parsedPlatforms; } const uiArg = argv.u || argv.ui; if (uiArg) { if (!VALID_UI_LIBRARIES.includes(uiArg)) { console.error(red3(`\u65E0\u6548\u7684UI\u5E93\u53C2\u6570: ${uiArg}`)); console.error(red3(`\u53EF\u9009\u503C: ${VALID_UI_LIBRARIES.join(", ")}`)); process5.exit(1); } uiLibrary = uiArg; } const loginArg = argv.l ?? argv.login; if (loginArg === true || loginArg === "true") { loginStrategy = true; } else if (loginArg === false || loginArg === "false") { loginStrategy = false; } const i18nArg = argv.i ?? argv.i18n; if (i18nArg === true || i18nArg === "true") { i18n = true; } else if (i18nArg === false || i18nArg === "false") { i18n = false; } const chartArgs = []; if (argv["lime-echart"] === true || argv["lime-echart"] === "true") { chartArgs.push("lime-echart"); } if (argv.ucharts === true || argv.ucharts === "true" || argv.uchart === true || argv.uchart === "true") { chartArgs.push("ucharts"); } if (chartArgs.length > 0) { const invalidCharts = chartArgs.filter((c) => !VALID_CHART_LIBRARIES.includes(c)); if (invalidCharts.length > 0) { console.error(red3(`\u65E0\u6548\u7684\u56FE\u8868\u5E93\u53C2\u6570: ${invalidCharts.join(", ")}`)); console.error(red3(`\u53EF\u9009\u503C: ${VALID_CHART_LIBRARIES.join(", ")}`)); process5.exit(1); } chartLibraries = Array.from(new Set(chartArgs)); } try { if (!projectName) { const inputProjectName = await text({ message: `\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0${green2("[\u9879\u76EE\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u77ED\u6A2A\u7EBF\uFF0C\u5343\u4E07\u522B\u5199\u4E2D\u6587]")}`, initialValue: "", validate: (value) => { if (!value?.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A"; const errorMessage = checkProjectNameExistAndValidate(value); if (errorMessage) return errorMessage; return; } }); if (isCancel2(inputProjectName)) { cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88"); process5.exit(0); } projectName = inputProjectName; } if (!platforms) { const selectedPlatforms = await multiselect2({ message: `\u8BF7\u9009\u62E9\u9700\u8981\u652F\u6301\u7684\u5E73\u53F0\uFF08\u591A\u9009\uFF09${green2("[\u811A\u624B\u67B6\u5C06\u6839\u636E\u6240\u9009\u5E73\u53F0\u751F\u6210\u5BF9\u5E94\u7684\u5E73\u53F0\u4EE3\u7801\uFF0C\u8BF7\u6839\u636E\u5B9E\u9645\u60C5\u51B5\u9009\u62E9]")}`, options: [ { value: "h5", label: "H5" }, { value: "mp-weixin", label: "\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F" }, { value: "app", label: "APP" }, { value: "mp-alipay", label: "\u652F\u4ED8\u5B9D\u5C0F\u7A0B\u5E8F\uFF08\u5305\u542B\u9489\u9489\uFF09" }, { value: "mp-toutiao", label: "\u6296\u97F3\u5C0F\u7A0B\u5E8F" } ], initialValues: ["h5"], // 默认选择 H5 required: true }); if (isCancel2(selectedPlatforms)) { cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88"); process5.exit(0); } platforms = selectedPlatforms; } if (!uiLibrary) { const selectedUiLibrary = await select({ message: "\u8BF7\u9009\u62E9UI\u5E93", options: [ { value: "none", label: "\u65E0UI\u5E93" }, { value: "wot-ui-v2", label: "wot-ui V2\uFF08@wot-ui/ui\uFF09" }, { value: "wot-ui", label: "wot-ui\uFF08v1 / wot-design-uni\uFF09" }, { value: "uview-pro", label: "uview-pro" }, { value: "sard-uniapp", label: "sard-uniapp" }, { value: "uv-ui", label: "uv-ui" }, { value: "uview-plus", label: "uview-plus" }, { value: "tdesign", label: "tdesign" } ], initialValue: "none" }); if (isCancel2(selectedUiLibrary)) { cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88"); process5.exit(0); } uiLibrary = selectedUiLibrary; } if (loginStrategy === void 0) { const selectedLoginStrategy = await confirm({ message: `\u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09\uFF1F${green2("[\u6682\u4E0D\u77E5\u9053\u7684\uFF0C\u900