Skip to content

Commit

Permalink
chore: update configuration files and enhance CLI commands
Browse files Browse the repository at this point in the history
  • Loading branch information
sj817 committed Jan 16, 2025
1 parent baa34b3 commit c01a8db
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 155 deletions.
4 changes: 3 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"semi": false
"semi": false,
"arrowParens": "avoid",
"noUnusedLocals": true
}
27 changes: 12 additions & 15 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -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
}

Expand All @@ -35,7 +29,10 @@ const options = neostandard({
ignores,
globals: ['logger'],
plugins: {
...eslintPluginPrettierRecommended.plugins,
prettier,
},
rules: {
'prettier/prettier': 'error',
},
}).map(commaDangle)

Expand Down
45 changes: 6 additions & 39 deletions packages/core/exports/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 <patterns>', '添加要监视的文件/目录,多个用逗号分隔')
.option('--exclude <patterns>', '排除要监视的文件/目录,多个用逗号分隔')
.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)
59 changes: 38 additions & 21 deletions packages/core/exports/cli/init.ts
Original file line number Diff line number Diff line change
@@ -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 })
})
}
Expand All @@ -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',
'}',
Expand Down Expand Up @@ -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 = [
Expand Down Expand Up @@ -174,16 +198,16 @@ 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)
}

/**
* 生成一些其他文件
*/
export const createOtherFile = async () => {
createPnpmFile(dir)
createWorkspace(dir)
isDev && createPnpmFile(dir)
isDev && createWorkspace(dir)

if (!shouldSkipNpmrc()) {
createOrUpdateNpmrc(dir)
Expand All @@ -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
/** 默认配置文件路径 */
Expand Down Expand Up @@ -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}`
})
Expand All @@ -255,6 +271,7 @@ export const modifyPackageJson = () => {
* 入口函数
*/
export const init = async () => {
isDev = isPluginDev()
createDir()
await createOtherFile()
createConfig()
Expand Down
81 changes: 5 additions & 76 deletions packages/core/exports/cli/start.ts
Original file line number Diff line number Diff line change
@@ -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'

/**
* 解析环境变量文件列表
Expand All @@ -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 进行初始化项目`)
Expand All @@ -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 })
}

Expand All @@ -51,15 +51,15 @@ 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()
start(env)
}
})

child.on('exit', (code) => process.exit(code))
child.on('exit', code => process.exit(code))
}

/**
Expand All @@ -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))
}
6 changes: 3 additions & 3 deletions packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"alwaysStrict": true,
"baseUrl": ".",
"declaration": true,
"declarationDir": "./lib/types",
"declarationMap": true,
"esModuleInterop": true,
"module": "ES2022",
Expand All @@ -26,8 +27,7 @@
"target": "ES2022",
"types": [
"@types/node"
],
"declarationDir": "./lib/types"
]
},
"exclude": [
"@karinjs",
Expand All @@ -45,4 +45,4 @@
"resolveFullExtension": ".js",
"resolveFullPaths": true
}
}
}

0 comments on commit c01a8db

Please sign in to comment.