From c01a8dbc58ecaf308e6dde26c59be901efbab1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=B6=E7=91=BE?= <74231782+sj817@users.noreply.github.com> Date: Fri, 17 Jan 2025 00:44:51 +0800 Subject: [PATCH] chore: update configuration files and enhance CLI commands --- .prettierrc | 4 +- eslint.config.mjs | 27 +++++----- packages/core/exports/cli/index.ts | 45 +++-------------- packages/core/exports/cli/init.ts | 59 ++++++++++++++-------- packages/core/exports/cli/start.ts | 81 ++---------------------------- packages/core/tsconfig.json | 6 +-- 6 files changed, 67 insertions(+), 155 deletions(-) diff --git a/.prettierrc b/.prettierrc index 660fe156..485f888b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,5 +5,7 @@ "singleQuote": true, "trailingComma": "all", "bracketSpacing": true, - "semi": false + "semi": false, + "arrowParens": "avoid", + "noUnusedLocals": true } diff --git a/eslint.config.mjs b/eslint.config.mjs index 120fecbb..7eba60aa 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,21 +1,15 @@ import neostandard from 'neostandard' -import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import prettier from 'eslint-plugin-prettier' /** 尾随逗号 */ -const commaDangle = (val) => { - if (val?.rules?.['@stylistic/comma-dangle']?.[0] === 'warn') { - val.rules['@stylistic/comma-dangle'] = [ - 'warn', - { - arrays: 'always-multiline', - enums: 'always-multiline', - exports: 'always-multiline', - imports: 'always-multiline', - objects: 'always-multiline', - }, - ] - return val +const commaDangle = val => { + if (typeof val?.rules?.['@stylistic/comma-dangle']?.[1] === 'object') { + val.rules['@stylistic/comma-dangle'][0] = 'off' + Object.keys(val?.rules?.['@stylistic/comma-dangle']?.[1]).forEach(key => { + val.rules['@stylistic/comma-dangle'][1][key] = 'always-multiline' + }) } + return val } @@ -35,7 +29,10 @@ const options = neostandard({ ignores, globals: ['logger'], plugins: { - ...eslintPluginPrettierRecommended.plugins, + prettier, + }, + rules: { + 'prettier/prettier': 'error', }, }).map(commaDangle) diff --git a/packages/core/exports/cli/index.ts b/packages/core/exports/cli/index.ts index 1b7b5147..b0290782 100644 --- a/packages/core/exports/cli/index.ts +++ b/packages/core/exports/cli/index.ts @@ -4,7 +4,7 @@ import fs from 'node:fs' import { fileURLToPath } from 'node:url' import { pm2 } from './pm2' import { init } from './init' -import { dev, start, tsStart, tsWatch } from './start' +import { start } from './start' import { updateAll } from './update' import { program } from 'commander' import type { Command } from 'commander' @@ -43,45 +43,12 @@ program.command('log').description('查看日志').action(pm2.log) program.command('up').description('更新插件').action(updateAll) program.command('init').description('初始化项目').action(init) -addEnvOption(program.command('.').description('前台启动')) - .action((options: { env: string | undefined }) => start(options.env)) -addEnvOption(program.command('app').description('前台启动')) - .action((options: { env: string | undefined }) => start(options.env)) -addEnvOption(program.command('start').description('前台启动')) - .action((options: { env: string | undefined }) => start(options.env)) -addEnvOption(program.command('dev').description('JavaScript开发模式')) - .action((options: { env: string | undefined }) => dev(options.env)) -addEnvOption( - program.command('ts') - .description('TypeScript开发模式') - .addHelpText('after', ` -示例: - $ karin ts # 使用默认 .env 文件启动 - $ karin ts -e .env.dev # 使用指定的环境变量文件启动 - $ karin ts -e .env.dev,.env.local # 使用多个环境变量文件启动 -`) +addEnvOption(program.command('.').description('前台启动')).action( + (options: { env: string | undefined }) => start(options.env), ) - .action((options: { env: string | undefined }) => tsStart(options.env)) - -addEnvOption( - program.command('watch') - .description('TypeScript监视模式') - .option('--include ', '添加要监视的文件/目录,多个用逗号分隔') - .option('--exclude ', '排除要监视的文件/目录,多个用逗号分隔') - .option('--clear-screen', '重新运行时是否清屏', true) - .addHelpText('after', ` -示例: - $ karin watch # 默认监视模式 - $ karin watch --include src # 监视 src 目录 - $ karin watch --exclude node_modules,dist # 排除指定目录 - $ karin watch --no-clear-screen # 禁用清屏 -`) +addEnvOption(program.command('app').description('前台启动')).action( + (options: { env: string | undefined }) => start(options.env), ) - .action((options: { - env: string | undefined - include?: string - exclude?: string - clearScreen: boolean - }) => tsWatch(options)) +addEnvOption(program.command('start').description('前台启动')) program.parse(process.argv) diff --git a/packages/core/exports/cli/init.ts b/packages/core/exports/cli/init.ts index f185cf37..e65d3c3b 100644 --- a/packages/core/exports/cli/init.ts +++ b/packages/core/exports/cli/init.ts @@ -1,27 +1,49 @@ import fs from 'node:fs' import path from 'node:path' -import { URL, fileURLToPath } from 'node:url' - import { execSync } from './exec.js' +import { URL, fileURLToPath } from 'node:url' +let isDev = false const dir = process.env.INIT_CWD || process.cwd() const pkgDir = fileURLToPath(new URL('../..', import.meta.url)) +/** + * 判断是否处于插件开发环境 + */ +const isPluginDev = () => { + /** + * 规则如下 + * 1. 根目录的package.json中karin字段存在 + * 2. 存在src目录 + * 3. 存在tsconfig.json文件 + * 4. 存在.prettierrc文件 + * 5. 存在eslint.config.mjs文件 + */ + const pkg = fs.readFileSync(path.join(dir, 'package.json'), 'utf-8') + const data = JSON.parse(pkg) + if (data?.karin) return true + if (fs.existsSync(path.join(dir, 'src'))) return true + if (fs.existsSync(path.join(dir, 'tsconfig.json'))) return true + if (fs.existsSync(path.join(dir, '.prettierrc'))) return true + if (fs.existsSync(path.join(dir, 'eslint.config.mjs'))) return true + return false +} + /** * 创建基本目录 */ export const createDir = () => { const list = [ - path.join(dir, 'plugins', 'karin-plugin-example'), path.join(dir, '@karinjs', 'logs'), path.join(dir, '@karinjs', 'config'), path.join(dir, '@karinjs', 'data'), + path.join(dir, '@karinjs', 'resource'), path.join(dir, '@karinjs', 'temp', 'console'), path.join(dir, '@karinjs', 'temp', 'html'), - path.join(dir, '@karinjs', 'resource'), ] - list.forEach((item) => { + isDev && list.push(path.join(dir, 'plugins', 'karin-plugin-example')) + list.forEach(item => { if (!fs.existsSync(item)) fs.mkdirSync(item, { recursive: true }) }) } @@ -37,8 +59,8 @@ const createPnpmFile = (dir: string) => { const content = [ '// 清空对等依赖中的node-karin', 'function readPackage (pkg, context) {', - ' if (pkg?.[\'peerDependencies\']?.[\'node-karin\'] && pkg[\'peerDependencies\'][\'node-karin\'] !== \'file:./lib\') {', - ' delete pkg[\'peerDependencies\'][\'node-karin\']', + " if (pkg?.['peerDependencies']?.['node-karin'] && pkg['peerDependencies']['node-karin'] !== 'file:./lib') {", + " delete pkg['peerDependencies']['node-karin']", ' }', ' return pkg', '}', @@ -108,7 +130,9 @@ const createOrUpdateEnv = (dir: string) => { /** 生成随机6位字母key */ const generateRandomKey = () => { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' - return Array.from({ length: 6 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('') + return Array.from({ length: 6 }, () => + chars.charAt(Math.floor(Math.random() * chars.length)), + ).join('') } const envData = [ @@ -174,7 +198,7 @@ const createWorkspace = (dir: string) => { const workspace = path.join(dir, 'pnpm-workspace.yaml') if (fs.existsSync(workspace)) return - const content = 'packages:\n - \'plugins/**\'\n' + const content = "packages:\n - 'plugins/**'\n" fs.writeFileSync(workspace, content) } @@ -182,8 +206,8 @@ const createWorkspace = (dir: string) => { * 生成一些其他文件 */ export const createOtherFile = async () => { - createPnpmFile(dir) - createWorkspace(dir) + isDev && createPnpmFile(dir) + isDev && createWorkspace(dir) if (!shouldSkipNpmrc()) { createOrUpdateNpmrc(dir) @@ -199,7 +223,7 @@ export const createConfig = () => { const defCfg = path.join(pkgDir, 'default', 'config') /** 读取默认目录下的所有json文件 遍历复制到目标目录 */ const files = fs.readdirSync(defCfg) - files.forEach((file) => { + files.forEach(file => { /** 忽略非json文件 */ if (!file.endsWith('.json')) return /** 默认配置文件路径 */ @@ -234,15 +258,7 @@ export const modifyPackageJson = () => { if (!data.scripts) data.scripts = {} data.scripts.karin = 'karin' - const list = [ - 'app', - 'start', - 'pm2', - 'stop', - 'rs', - 'log', - ] - + const list = ['app', 'start', 'pm2', 'stop', 'rs', 'log'] list.forEach(v => { data.scripts[v] = `karin ${v}` }) @@ -255,6 +271,7 @@ export const modifyPackageJson = () => { * 入口函数 */ export const init = async () => { + isDev = isPluginDev() createDir() await createOtherFile() createConfig() diff --git a/packages/core/exports/cli/start.ts b/packages/core/exports/cli/start.ts index a4e881c0..e7c3acc6 100644 --- a/packages/core/exports/cli/start.ts +++ b/packages/core/exports/cli/start.ts @@ -1,7 +1,7 @@ import fs from 'node:fs' import dotenv from 'dotenv' import { pathToFileURL } from 'node:url' -import { fork, spawn } from 'node:child_process' +import { fork } from 'node:child_process' /** * 解析环境变量文件列表 @@ -26,7 +26,7 @@ const loadEnv = (env?: string) => { files.unshift('.env') } - files.forEach((file) => { + files.forEach(file => { if (!fs.existsSync(`${dir}/${file}`)) { if (file === '.env') { console.error(`未找到${file}文件,请使用 npx karin init 进行初始化项目`) @@ -37,7 +37,7 @@ const loadEnv = (env?: string) => { } }) - const paths = files.map((file) => `${dir}/${file}`) + const paths = files.map(file => `${dir}/${file}`) dotenv.config({ path: paths, override: true }) } @@ -51,7 +51,7 @@ export const start = async (env?: string) => { const { karinMain } = await import(index) const child = fork(karinMain) - child.on('message', (message) => { + child.on('message', message => { if (message === 'restart') { child.kill() child.removeAllListeners() @@ -59,7 +59,7 @@ export const start = async (env?: string) => { } }) - child.on('exit', (code) => process.exit(code)) + child.on('exit', code => process.exit(code)) } /** @@ -73,74 +73,3 @@ export const dev = async (env?: string) => { const { karinMain } = await import(index) await import(pathToFileURL(karinMain).toString()) } - -/** - * TypeScript 开发模式 - * @param env - 环境变量文件名称,可以是单个文件名或用逗号分隔的多个文件名 - */ -export const tsStart = async (env?: string) => { - loadEnv(env) - process.env.RUNTIME = 'tsx' - process.env.NODE_ENV = 'development' - - const index = '../root.js' - const { karinMain } = await import(index) - - const child = spawn('npx', ['tsx', karinMain], { - stdio: 'inherit', - shell: true, - }) - - child.on('exit', (code) => process.exit(code ?? 0)) -} - -/** - * TypeScript 监视模式 - * @param options - 配置选项 - * @param options.env - 环境变量文件名称,可以是单个文件名或用逗号分隔的多个文件名 - * @param options.include - 要监视的额外文件/目录,多个用逗号分隔 - * @param options.exclude - 要排除监视的文件/目录,多个用逗号分隔 - * @param options.clearScreen - 重新运行时是否清屏 - */ -export const tsWatch = async (options: { - env?: string - include?: string - exclude?: string - clearScreen: boolean -}) => { - loadEnv(options.env) - process.env.NODE_ENV = 'development' - - const index = '../root.js' - const { karinMain } = await import(index) - - const args = ['tsx', 'watch'] - - if (options.include) { - options.include.split(',').forEach(pattern => { - args.push('--include', pattern.trim()) - }) - } - - if (options.exclude) { - options.exclude.split(',').forEach(pattern => { - args.push('--exclude', pattern.trim()) - }) - } - - if (!options.clearScreen) { - args.push('--clear-screen=false') - } - - args.push(karinMain) - - process.env.RUNTIME = 'tsx' - process.env.TSX_WATCH = 'true' - - const child = spawn('npx', args, { - stdio: 'inherit', - shell: true, - }) - - child.on('exit', (code) => process.exit(code ?? 0)) -} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index b96398d5..b99bb748 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,6 +4,7 @@ "alwaysStrict": true, "baseUrl": ".", "declaration": true, + "declarationDir": "./lib/types", "declarationMap": true, "esModuleInterop": true, "module": "ES2022", @@ -26,8 +27,7 @@ "target": "ES2022", "types": [ "@types/node" - ], - "declarationDir": "./lib/types" + ] }, "exclude": [ "@karinjs", @@ -45,4 +45,4 @@ "resolveFullExtension": ".js", "resolveFullPaths": true } -} \ No newline at end of file +}