add envision-cli 0.0.6

This commit is contained in:
熊潇 2024-11-29 13:32:58 +08:00
parent 35cec990c6
commit 2145fca826
5 changed files with 171 additions and 23 deletions

4
.npmrc
View File

@ -1,3 +1,3 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
@abearxiong:registry=https://npm.pkg.github.com @abearxiong:registry=https://npm.pkg.github.com
//registry.npmjs.org/:_authToken=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 //registry.npmjs.org/:_authToken=${NPM_TOKEN}
@kevisual:registry=https://npm.xiongxiao.me

View File

@ -1,6 +1,6 @@
{ {
"name": "@kevisual/envision-cli", "name": "@kevisual/envision-cli",
"version": "0.0.5", "version": "0.0.6",
"description": "envision command tools", "description": "envision command tools",
"main": "dist/index.js", "main": "dist/index.js",
"type": "module", "type": "module",
@ -29,7 +29,7 @@
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1", "@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^22.8.6", "@types/node": "^22.10.1",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"commander": "^12.1.0", "commander": "^12.1.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
@ -37,14 +37,14 @@
"form-data": "^4.0.1", "form-data": "^4.0.1",
"glob": "^11.0.0", "glob": "^11.0.0",
"ignore": "^6.0.2", "ignore": "^6.0.2",
"inquirer": "^12.0.1", "inquirer": "^12.1.0",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup": "^4.24.3", "rollup": "^4.27.4",
"rollup-plugin-dts": "^6.1.1", "rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.1.1",
"tar": "^7.4.3", "tar": "^7.4.3",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.6.3" "typescript": "^5.7.2"
}, },
"resolutions": { "resolutions": {
"picomatch": "^4" "picomatch": "^4"
@ -56,10 +56,10 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@kevisual/router": "^0.0.3", "@kevisual/router": "^0.0.5",
"pg-hstore": "^2.3.4", "pg-hstore": "^2.3.4",
"sequelize": "^6.37.5", "sequelize": "^6.37.5",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"vite": "^5.4.10" "vite": "^6.0.1"
} }
} }

View File

@ -5,6 +5,45 @@ import fs from 'fs';
import { chalk } from '@/module/chalk.ts'; import { chalk } from '@/module/chalk.ts';
import inquirer from 'inquirer'; 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') const command = new Command('config')
.description('') .description('')
.option('-d, --dev <dev>', 'Specify dev') .option('-d, --dev <dev>', 'Specify dev')
@ -14,7 +53,7 @@ const command = new Command('config')
.option('-v --value <value>', 'value') .option('-v --value <value>', 'value')
.option('-w --workdir <path>', 'web config') .option('-w --workdir <path>', 'web config')
.action(async (options) => { .action(async (options) => {
const { dev, list, workdir } = options || {}; const { dev, workdir } = options || {};
let config = getConfig(); let config = getConfig();
let flag = false; let flag = false;
const execPath = process.cwd(); const execPath = process.cwd();
@ -107,11 +146,29 @@ const setCommand = new Command('set')
when: () => value === 'not_input', when: () => value === 'not_input',
}, },
]); ]);
if (answer.value === 'not_input') {
value = '';
}
value = answer.value || value; value = answer.value || value;
if (key === 'workdir') {
await setWorkdir({ workdir: value });
return;
}
if (key && value) { if (key && value) {
flag = true; flag = true;
console.log(chalk.green(`set ${key} success:`, value)); if (key === 'dev') {
config[key] = value; 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) { if (flag) {
writeConfig(config); writeConfig(config);
@ -144,6 +201,19 @@ const getCommand = new Command('get')
}); });
command.addCommand(getCommand); command.addCommand(getCommand);
const removeCommand = new Command('remove')
.argument('<key>')
.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 list = new Command('list').action(async () => {
const config = getConfig(); const config = getConfig();
console.log(chalk.green('config', JSON.stringify(config, null, 2))); console.log(chalk.green('config', JSON.stringify(config, null, 2)));

View File

@ -1,22 +1,23 @@
import fs from 'fs/promises'; import fs, { createReadStream } from 'fs';
import path from 'path'; import path from 'path';
import * as tar from 'tar'; import * as tar from 'tar';
import glob from 'fast-glob'; import glob from 'fast-glob';
import { program, Command } from '@/program.ts'; 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 { fileIsExist } from '@/uitls/file.ts';
import ignore from 'ignore'; import ignore from 'ignore';
import FormData from 'form-data';
// 查找文件(忽略大小写) // 查找文件(忽略大小写)
async function findFileInsensitive(targetFile: string): Promise<string | null> { async function findFileInsensitive(targetFile: string): Promise<string | null> {
const files = await fs.readdir('.'); const files = fs.readdirSync('.');
const matchedFile = files.find((file) => file.toLowerCase() === targetFile.toLowerCase()); const matchedFile = files.find((file) => file.toLowerCase() === targetFile.toLowerCase());
return matchedFile || null; return matchedFile || null;
} }
// 递归收集文件信息 // 递归收集文件信息
async function collectFileInfo(filePath: string, baseDir = '.'): Promise<any[]> { async function collectFileInfo(filePath: string, baseDir = '.'): Promise<any[]> {
const stats = await fs.stat(filePath); const stats = fs.statSync(filePath);
const relativePath = path.relative(baseDir, filePath); const relativePath = path.relative(baseDir, filePath);
if (stats.isFile()) { if (stats.isFile()) {
@ -24,7 +25,7 @@ async function collectFileInfo(filePath: string, baseDir = '.'): Promise<any[]>
} }
if (stats.isDirectory()) { 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))); const results = await Promise.all(files.map((file) => collectFileInfo(path.join(filePath, file), baseDir)));
return results.flat(); return results.flat();
} }
@ -37,7 +38,7 @@ async function loadNpmIgnore(cwd: string): Promise<ignore.Ignore> {
const ig = ignore.default(); const ig = ignore.default();
try { try {
const content = await fs.readFile(npmIgnorePath, 'utf-8'); const content = fs.readFileSync(npmIgnorePath, 'utf-8');
ig.add(content); ig.add(content);
} catch (err) { } catch (err) {
console.warn('.npmignore not found, using default ignore rules'); console.warn('.npmignore not found, using default ignore rules');
@ -68,14 +69,14 @@ const pack = async () => {
const cwd = process.cwd(); const cwd = process.cwd();
const collection: Record<string, any> = {}; const collection: Record<string, any> = {};
const packageJsonPath = path.join(cwd, 'package.json'); const packageJsonPath = path.join(cwd, 'package.json');
if (!(await fileIsExist(packageJsonPath))) { if (!fileIsExist(packageJsonPath)) {
console.error('package.json not found'); console.error('package.json not found');
return; return;
} }
let packageJson; let packageJson;
try { try {
const packageContent = await fs.readFile(packageJsonPath, 'utf-8'); const packageContent = fs.readFileSync(packageJsonPath, 'utf-8');
packageJson = JSON.parse(packageContent); packageJson = JSON.parse(packageContent);
} catch (error) { } catch (error) {
console.error('Invalid package.json:', error); console.error('Invalid package.json:', error);
@ -139,6 +140,11 @@ const pack = async () => {
} catch (error) { } catch (error) {
console.error('Error creating tarball:', 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 }; return { collection, outputFilePath };
}; };
const packByIgnore = async () => { const packByIgnore = async () => {
@ -148,7 +154,7 @@ const packByIgnore = async () => {
const packageJsonPath = path.join(cwd, 'package.json'); const packageJsonPath = path.join(cwd, 'package.json');
let packageJson; let packageJson;
try { try {
const packageContent = await fs.readFile(packageJsonPath, 'utf-8'); const packageContent = fs.readFileSync(packageJsonPath, 'utf-8');
packageJson = JSON.parse(packageContent); packageJson = JSON.parse(packageContent);
} catch (error) { } catch (error) {
console.error('Invalid package.json:', error); console.error('Invalid package.json:', error);
@ -195,6 +201,11 @@ const packByIgnore = async () => {
} catch (error) { } catch (error) {
console.error('Error creating tarball:', 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 }; return { collection, outputFilePath };
}; };
const publishCommand = new Command('publish') const publishCommand = new Command('publish')
@ -204,13 +215,66 @@ const publishCommand = new Command('publish')
.action(async (options) => { .action(async (options) => {
const { key, version } = options; const { key, version } = options;
const config = await getConfig(); const config = await getConfig();
const form = new FormData();
console.log('发布逻辑实现', { key, version, config }); console.log('发布逻辑实现', { key, version, config });
}); });
const uploadFiles = async (filePath: string, collection: any): Promise<any> => {
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') const packCommand = new Command('pack')
.description('打包应用, 默认使用 package.json 中的 files 字段') .description('打包应用, 默认使用 package.json 中的 files 字段')
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段') .option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
.option('-p, --publish', '打包并发布')
.action(async (opts) => { .action(async (opts) => {
let value: { collection: Record<string, any>; outputFilePath: string }; let value: { collection: Record<string, any>; outputFilePath: string };
if (opts.ignore) { if (opts.ignore) {
@ -218,6 +282,11 @@ const packCommand = new Command('pack')
} else { } else {
value = await pack(); value = await pack();
} }
if (opts.publish && value?.collection) {
console.log('\n\npublish');
const { collection, outputFilePath } = value;
await uploadFiles(outputFilePath, collection);
}
// //
}); });

View File

@ -3,7 +3,16 @@ import { getConfig } from './get-config.ts';
const config = getConfig(); const config = getConfig();
export const baseURL = config?.baseURL || 'https://envision.xiongxiao.me'; export const baseURL = config?.baseURL || 'https://envision.xiongxiao.me';
export const getBaseURL = () => { 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 'http://localhost:4002';
} }
return baseURL; return baseURL;