173 lines
5.1 KiB
JavaScript
173 lines
5.1 KiB
JavaScript
import process from 'node:process'
|
|
import { createInterface } from 'node:readline/promises'
|
|
|
|
import { parseCliArgs, getFlagValue, getFlagValues, hasFlag } from '../core/args.js'
|
|
import {
|
|
loadProjectConfig,
|
|
normalizeParamStyle,
|
|
resolveCwdPath,
|
|
resolveSwaggerSource,
|
|
} from '../core/config.js'
|
|
import { generateApiFiles } from '../core/generate.js'
|
|
|
|
export const runGenerateCommand = async (args) => {
|
|
const context = await resolveGenerateCommandContext(args)
|
|
|
|
if (context.help) {
|
|
printHelp()
|
|
return
|
|
}
|
|
|
|
await generateApiFiles(context.runtimeConfig)
|
|
}
|
|
|
|
export const resolveGenerateCommandContext = async (args) => {
|
|
const parsedArgs = parseCliArgs(args)
|
|
const help = hasFlag(parsedArgs.flags, 'help') || hasFlag(parsedArgs.flags, 'h')
|
|
|
|
if (help) {
|
|
return {
|
|
help: true,
|
|
}
|
|
}
|
|
|
|
const configPath = getFlagValue(parsedArgs.flags, 'config')
|
|
const projectConfig = await loadProjectConfig({
|
|
configPath,
|
|
cwd: process.cwd(),
|
|
})
|
|
const moduleArgs = [
|
|
...parsedArgs.positionals,
|
|
...getFlagValues(parsedArgs.flags, 'modules').flatMap(splitModuleArgs),
|
|
]
|
|
|
|
return {
|
|
help: false,
|
|
projectConfig,
|
|
runtimeConfig: {
|
|
projectRoot: projectConfig.rootDir,
|
|
swaggerUrl: getFlagValue(parsedArgs.flags, 'url')
|
|
? resolveSwaggerSource(process.cwd(), getFlagValue(parsedArgs.flags, 'url'))
|
|
: projectConfig.swaggerUrl,
|
|
swaggerTimeoutMs: resolveSwaggerTimeoutMs(parsedArgs.flags, projectConfig.swaggerTimeoutMs),
|
|
outputDir: getFlagValue(parsedArgs.flags, 'outDir')
|
|
? resolveCwdPath(process.cwd(), getFlagValue(parsedArgs.flags, 'outDir'))
|
|
: projectConfig.outputDir,
|
|
requestImport: getFlagValue(parsedArgs.flags, 'requestImport') || projectConfig.requestImport,
|
|
paramStyle: getFlagValue(parsedArgs.flags, 'paramStyle')
|
|
? normalizeParamStyle(getFlagValue(parsedArgs.flags, 'paramStyle'))
|
|
: projectConfig.paramStyle,
|
|
cleanOutput: hasFlag(parsedArgs.flags, 'clean')
|
|
? Boolean(getFlagValue(parsedArgs.flags, 'clean'))
|
|
: projectConfig.cleanOutput,
|
|
modules: moduleArgs,
|
|
resolveDuplicateExports: createDuplicateExportResolver(),
|
|
},
|
|
}
|
|
}
|
|
|
|
const printHelp = () => {
|
|
console.log(`yx-generate-api generate
|
|
|
|
Usage:
|
|
yx-generate-api generate [moduleName...] [options]
|
|
|
|
Options:
|
|
--config=... Config file path
|
|
--url=... Swagger/OpenAPI JSON URL
|
|
Supports http(s), file://, or a local JSON file path
|
|
--outDir=... Output directory
|
|
--requestImport=... request import path inside generated files
|
|
--modules=... Comma-separated module list
|
|
--paramStyle=... object / positional
|
|
--timeout=... Swagger fetch timeout in milliseconds
|
|
--clean Remove stale auto-generated module files on full generation
|
|
--no-clean Keep previously generated module files
|
|
--help Show help
|
|
|
|
Examples:
|
|
yx-generate-api generate
|
|
yx-generate-api generate Curriculum
|
|
yx-generate-api generate class-assignment Ranking
|
|
yx-generate-api generate --modules=Curriculum,class-assignment
|
|
yx-generate-api generate --config ./yx-generate-api.config.mjs --timeout 10000
|
|
`)
|
|
}
|
|
|
|
const splitModuleArgs = (value) => {
|
|
return String(value || '')
|
|
.split(',')
|
|
.map((item) => item.trim())
|
|
.filter(Boolean)
|
|
}
|
|
|
|
const resolveSwaggerTimeoutMs = (flags, fallbackValue) => {
|
|
const rawValue = getFlagValue(flags, 'timeout') || getFlagValue(flags, 'timeoutMs')
|
|
|
|
if (rawValue === undefined) {
|
|
return fallbackValue
|
|
}
|
|
|
|
const parsedValue = Number.parseInt(String(rawValue), 10)
|
|
|
|
if (!Number.isInteger(parsedValue) || parsedValue <= 0) {
|
|
throw new Error(`--timeout must be a positive integer. Received: ${rawValue}`)
|
|
}
|
|
|
|
return parsedValue
|
|
}
|
|
|
|
const createDuplicateExportResolver = () => {
|
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
return null
|
|
}
|
|
|
|
return async ({ conflicts }) => {
|
|
console.log('')
|
|
console.log('检测到生成后的 API 导出名称冲突:')
|
|
|
|
for (const conflict of conflicts) {
|
|
console.log(`- 冲突函数:${conflict.exportName}`)
|
|
|
|
for (const occurrence of conflict.occurrences) {
|
|
const locationText = occurrence.path ? `URL: ${occurrence.path}` : 'URL: 当前保留的已生成模块'
|
|
console.log(
|
|
` 模块: ${occurrence.moduleName} | 文件: ${occurrence.fileName} | ${locationText}`,
|
|
)
|
|
}
|
|
}
|
|
|
|
console.log('')
|
|
console.log('请选择处理方式:')
|
|
console.log('1. 在冲突函数名后追加模块名,例如 getListEnglishWordApi')
|
|
console.log('2. 退出生成')
|
|
|
|
const readline = createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout,
|
|
})
|
|
|
|
try {
|
|
while (true) {
|
|
const answer = String(await readline.question('请输入 1 或 2: ')).trim()
|
|
|
|
if (answer === '1') {
|
|
return {
|
|
action: 'rename',
|
|
}
|
|
}
|
|
|
|
if (answer === '2') {
|
|
return {
|
|
action: 'abort',
|
|
}
|
|
}
|
|
|
|
console.log('输入无效,请输入 1 或 2。')
|
|
}
|
|
} finally {
|
|
readline.close()
|
|
}
|
|
}
|
|
}
|