From 2145fca826742aa22ea80bf1d9c5b68eefb0dff9 Mon Sep 17 00:00:00 2001 From: xion Date: Fri, 29 Nov 2024 13:32:58 +0800 Subject: [PATCH] add envision-cli 0.0.6 --- .npmrc | 4 +- package.json | 14 +++---- src/command/config.ts | 76 ++++++++++++++++++++++++++++++++++-- src/command/publish.ts | 89 +++++++++++++++++++++++++++++++++++++----- src/module/query.ts | 11 +++++- 5 files changed, 171 insertions(+), 23 deletions(-) diff --git a/.npmrc b/.npmrc index fc4e12a..a4d9caf 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,3 @@ +//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} @abearxiong:registry=https://npm.pkg.github.com -//registry.npmjs.org/:_authToken=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 -@kevisual:registry=https://npm.xiongxiao.me +//registry.npmjs.org/:_authToken=${NPM_TOKEN} \ No newline at end of file diff --git a/package.json b/package.json index 55fca4a..04d8e58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/envision-cli", - "version": "0.0.5", + "version": "0.0.6", "description": "envision command tools", "main": "dist/index.js", "type": "module", @@ -29,7 +29,7 @@ "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-typescript": "^12.1.1", - "@types/node": "^22.8.6", + "@types/node": "^22.10.1", "chalk": "^5.3.0", "commander": "^12.1.0", "fast-glob": "^3.3.2", @@ -37,14 +37,14 @@ "form-data": "^4.0.1", "glob": "^11.0.0", "ignore": "^6.0.2", - "inquirer": "^12.0.1", + "inquirer": "^12.1.0", "rimraf": "^6.0.1", - "rollup": "^4.24.3", + "rollup": "^4.27.4", "rollup-plugin-dts": "^6.1.1", "rollup-plugin-esbuild": "^6.1.1", "tar": "^7.4.3", "tslib": "^2.8.1", - "typescript": "^5.6.3" + "typescript": "^5.7.2" }, "resolutions": { "picomatch": "^4" @@ -56,10 +56,10 @@ "access": "public" }, "dependencies": { - "@kevisual/router": "^0.0.3", + "@kevisual/router": "^0.0.5", "pg-hstore": "^2.3.4", "sequelize": "^6.37.5", "sqlite3": "^5.1.7", - "vite": "^5.4.10" + "vite": "^6.0.1" } } diff --git a/src/command/config.ts b/src/command/config.ts index bcdb15b..23a7f49 100644 --- a/src/command/config.ts +++ b/src/command/config.ts @@ -5,6 +5,45 @@ import fs from 'fs'; import { chalk } from '@/module/chalk.ts'; import inquirer from 'inquirer'; +// 设置工作目录 +const setWorkdir = async (options: { workdir: string }) => { + const execPath = process.cwd(); + let flag = false; + let config = getConfig(); + const workdir = options.workdir; + if (workdir) { + let finalPath: string; + if (workdir.startsWith('/')) { + // 如果以 / 开头,处理为绝对路径 + finalPath = workdir; + } else { + // 否则,处理为相对路径 + finalPath = path.join(execPath, workdir); + } + if (!checkFileExists(finalPath)) { + console.log('路径不存在'); + fs.mkdirSync(finalPath, { recursive: true }); + } + const answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'confirm', + message: `Are you sure you want to set the workdir to: ${finalPath}?`, + default: false, + }, + ]); + if (answers.confirm) { + flag = true; + config.workdir = finalPath; + console.log(chalk.green(`set workdir success:`, finalPath)); + } else { + console.log('Cancel set workdir'); + } + } + if (flag) { + writeConfig(config); + } +}; const command = new Command('config') .description('') .option('-d, --dev ', 'Specify dev') @@ -14,7 +53,7 @@ const command = new Command('config') .option('-v --value ', 'value') .option('-w --workdir ', 'web config') .action(async (options) => { - const { dev, list, workdir } = options || {}; + const { dev, workdir } = options || {}; let config = getConfig(); let flag = false; const execPath = process.cwd(); @@ -107,11 +146,29 @@ const setCommand = new Command('set') when: () => value === 'not_input', }, ]); + if (answer.value === 'not_input') { + value = ''; + } value = answer.value || value; + if (key === 'workdir') { + await setWorkdir({ workdir: value }); + return; + } if (key && value) { flag = true; - console.log(chalk.green(`set ${key} success:`, value)); - config[key] = value; + if (key === 'dev') { + if (value === 'true') { + config.dev = true; + } else { + config.dev = false; + } + } else { + config[key] = value; + } + console.log(chalk.green(`set ${key} success:`, config.key)); + } else if (key) { + flag = true; + delete config[key]; } if (flag) { writeConfig(config); @@ -144,6 +201,19 @@ const getCommand = new Command('get') }); command.addCommand(getCommand); +const removeCommand = new Command('remove') + .argument('') + .description('remove config') + .action(async (key) => { + const config = getConfig(); + if (key) { + delete config[key]; + writeConfig(config); + console.log(chalk.green(`remove ${key} success`)); + } + }); +command.addCommand(removeCommand); + const list = new Command('list').action(async () => { const config = getConfig(); console.log(chalk.green('config', JSON.stringify(config, null, 2))); diff --git a/src/command/publish.ts b/src/command/publish.ts index 92b25c5..122c45e 100644 --- a/src/command/publish.ts +++ b/src/command/publish.ts @@ -1,22 +1,23 @@ -import fs from 'fs/promises'; +import fs, { createReadStream } from 'fs'; import path from 'path'; import * as tar from 'tar'; import glob from 'fast-glob'; import { program, Command } from '@/program.ts'; -import { getConfig } from '@/module/index.ts'; +import { getBaseURL, getConfig } from '@/module/index.ts'; import { fileIsExist } from '@/uitls/file.ts'; import ignore from 'ignore'; +import FormData from 'form-data'; // 查找文件(忽略大小写) async function findFileInsensitive(targetFile: string): Promise { - const files = await fs.readdir('.'); + const files = fs.readdirSync('.'); const matchedFile = files.find((file) => file.toLowerCase() === targetFile.toLowerCase()); return matchedFile || null; } // 递归收集文件信息 async function collectFileInfo(filePath: string, baseDir = '.'): Promise { - const stats = await fs.stat(filePath); + const stats = fs.statSync(filePath); const relativePath = path.relative(baseDir, filePath); if (stats.isFile()) { @@ -24,7 +25,7 @@ async function collectFileInfo(filePath: string, baseDir = '.'): Promise } if (stats.isDirectory()) { - const files = await fs.readdir(filePath); + const files = fs.readdirSync(filePath); const results = await Promise.all(files.map((file) => collectFileInfo(path.join(filePath, file), baseDir))); return results.flat(); } @@ -37,7 +38,7 @@ async function loadNpmIgnore(cwd: string): Promise { const ig = ignore.default(); try { - const content = await fs.readFile(npmIgnorePath, 'utf-8'); + const content = fs.readFileSync(npmIgnorePath, 'utf-8'); ig.add(content); } catch (err) { console.warn('.npmignore not found, using default ignore rules'); @@ -68,14 +69,14 @@ const pack = async () => { const cwd = process.cwd(); const collection: Record = {}; const packageJsonPath = path.join(cwd, 'package.json'); - if (!(await fileIsExist(packageJsonPath))) { + if (!fileIsExist(packageJsonPath)) { console.error('package.json not found'); return; } let packageJson; try { - const packageContent = await fs.readFile(packageJsonPath, 'utf-8'); + const packageContent = fs.readFileSync(packageJsonPath, 'utf-8'); packageJson = JSON.parse(packageContent); } catch (error) { console.error('Invalid package.json:', error); @@ -139,6 +140,11 @@ const pack = async () => { } catch (error) { console.error('Error creating tarball:', error); } + const readme = await findFileInsensitive('README.md'); + if (readme) { + const readmeContent = fs.readFileSync(readme, 'utf-8'); + collection.readme = readmeContent; + } return { collection, outputFilePath }; }; const packByIgnore = async () => { @@ -148,7 +154,7 @@ const packByIgnore = async () => { const packageJsonPath = path.join(cwd, 'package.json'); let packageJson; try { - const packageContent = await fs.readFile(packageJsonPath, 'utf-8'); + const packageContent = fs.readFileSync(packageJsonPath, 'utf-8'); packageJson = JSON.parse(packageContent); } catch (error) { console.error('Invalid package.json:', error); @@ -195,6 +201,11 @@ const packByIgnore = async () => { } catch (error) { console.error('Error creating tarball:', error); } + const readme = await findFileInsensitive('README.md'); + if (readme) { + const readmeContent = fs.readFileSync(readme, 'utf-8'); + collection.readme = readmeContent; + } return { collection, outputFilePath }; }; const publishCommand = new Command('publish') @@ -204,13 +215,66 @@ const publishCommand = new Command('publish') .action(async (options) => { const { key, version } = options; const config = await getConfig(); - const form = new FormData(); console.log('发布逻辑实现', { key, version, config }); }); +const uploadFiles = async (filePath: string, collection: any): Promise => { + const config = await getConfig(); + const form = new FormData(); + const filename = path.basename(filePath); + try { + console.log('upload file', filePath); + form.append('file', createReadStream(filePath)); + } catch (error) { + console.error('Error reading file:', error); + return; + } + form.append('collection', JSON.stringify(collection)); + console.log('upload file', filename); + return await new Promise((resolve) => { + const _baseURL = getBaseURL(); + const url = new URL(_baseURL); + console.log('upload url', url.hostname, url.protocol, url.port); + form.submit( + { + path: '/api/micro-app/upload', + host: url.hostname, + protocol: url.protocol as any, + port: url.port, + method: 'POST', + headers: { + Authorization: 'Bearer ' + config.token, + ...form.getHeaders(), + }, + }, + (err, res) => { + if (err) { + console.error('Error uploading file:', err.message); + return; + } + console.log('upload success'); + // 处理服务器响应 + let body = ''; + res.on('data', (chunk) => { + body += chunk; + }); + res.on('end', () => { + try { + const res = JSON.parse(body); + console.log('upload success', res); + resolve(res); + } catch (e) { + resolve({ code: 500, message: body }); + } + }); + }, + ); + }); +}; const packCommand = new Command('pack') .description('打包应用, 默认使用 package.json 中的 files 字段') .option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段') + .option('-p, --publish', '打包并发布') .action(async (opts) => { let value: { collection: Record; outputFilePath: string }; if (opts.ignore) { @@ -218,6 +282,11 @@ const packCommand = new Command('pack') } else { value = await pack(); } + if (opts.publish && value?.collection) { + console.log('\n\npublish'); + const { collection, outputFilePath } = value; + await uploadFiles(outputFilePath, collection); + } // }); diff --git a/src/module/query.ts b/src/module/query.ts index dddcc80..51180fc 100644 --- a/src/module/query.ts +++ b/src/module/query.ts @@ -3,7 +3,16 @@ import { getConfig } from './get-config.ts'; const config = getConfig(); export const baseURL = config?.baseURL || 'https://envision.xiongxiao.me'; export const getBaseURL = () => { - if (config?.dev) { + if (typeof config?.dev === 'undefined') { + return baseURL; + } + if (typeof config?.dev === 'string') { + if (config?.dev === 'true') { + return 'http://localhost:4002'; + } + return baseURL; + } + if (config?.dev === true) { return 'http://localhost:4002'; } return baseURL;