同步操作将从 Fantastic-admin/basic 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#!/usr/bin/env nodeimport { spawn } from 'node:child_process'import fs from 'node:fs'import path from 'node:path'import process from 'node:process'import { fileURLToPath } from 'node:url'import * as p from '@clack/prompts'interface PackageJson {name: stringdescription?: stringscripts?: Record<string, string>}interface WorkspaceEntry {name: stringpackageJsonPath: string}interface AppInfo {name: stringpackageName: stringdescription: stringscripts: string[]}interface RunMessageContext {app: AppInfoscript: string}interface ModeConfig {action: Modeintro: stringnoAppsMessage: stringappSelectMessage: stringscriptMatcher: (scriptName: string) => booleanselectionMode: 'single' | 'multiple'completionMessage?: stringgetRunMessage?: (context: RunMessageContext) => stringshowRunMessageWhenSingleApp?: boolean}type Mode = 'build' | 'dev' | 'serve'const currentDir = path.dirname(fileURLToPath(import.meta.url))const rootDir = path.resolve(currentDir, '..')const isWindows = process.platform === 'win32'const validModes: Mode[] = ['build', 'dev', 'serve']const modeConfigs: Record<Mode, ModeConfig> = {build: {action: 'build',intro: 'Select apps to build',noAppsMessage: 'No apps found with build script',appSelectMessage: 'Which apps do you want to build?',scriptMatcher: isBuildScript,selectionMode: 'multiple',completionMessage: 'Build complete!',getRunMessage: ({ app, script }) => `Building "${app.name}" with script "${script}"...`,},dev: {action: 'dev',intro: 'Select an app to run',noAppsMessage: 'No apps found with dev script',appSelectMessage: 'Which app do you want to run?',scriptMatcher: isDevScript,selectionMode: 'single',getRunMessage: ({ app }) => `Starting ${app.packageName}...`,},serve: {action: 'serve',intro: 'Select an app to serve',noAppsMessage: 'No apps found with serve script',appSelectMessage: 'Which app do you want to serve?',scriptMatcher: isServeScript,selectionMode: 'single',getRunMessage: ({ app, script }) => `Serving "${app.name}" with script "${script}"...`,},}let childProcess: ReturnType<typeof spawn> | null = nullprocess.on('SIGINT', () => {childProcess?.kill('SIGINT')})function isBuildScript(scriptName: string): boolean {return scriptName === 'build' || scriptName.startsWith('build:')}function isDevScript(scriptName: string): boolean {return scriptName === 'dev' || scriptName.startsWith('dev:')}function isServeScript(scriptName: string): boolean {return scriptName === 'serve' || scriptName.startsWith('serve:')}function getWorkspaceEntries(): WorkspaceEntry[] {const entries: WorkspaceEntry[] = []const appsDir = path.resolve(rootDir, 'apps')if (fs.existsSync(appsDir)) {const apps = fs.readdirSync(appsDir, { withFileTypes: true })for (const app of apps) {if (!app.isDirectory()) {continue}const packageJsonPath = path.join(appsDir, app.name, 'package.json')if (!fs.existsSync(packageJsonPath)) {continue}entries.push({name: app.name,packageJsonPath,})}}const docsPackageJsonPath = path.resolve(rootDir, 'docs', 'package.json')if (fs.existsSync(docsPackageJsonPath)) {entries.push({name: 'docs',packageJsonPath: docsPackageJsonPath,})}return entries}function readPackageJson(packageJsonPath: string): PackageJson {return JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as PackageJson}function getApps(scriptMatcher: (scriptName: string) => boolean): AppInfo[] {const apps: AppInfo[] = []for (const entry of getWorkspaceEntries()) {const packageJson = readPackageJson(entry.packageJsonPath)const scripts = Object.keys(packageJson.scripts ?? {}).filter(scriptMatcher)if (scripts.length === 0) {continue}apps.push({name: entry.name,packageName: packageJson.name,description: packageJson.description || '',scripts,})}return apps}function getAppChoices(apps: AppInfo[]): Array<{ value: string, label: string, hint: string }> {return apps.map(app => ({value: app.packageName,label: app.name,hint: app.description,}))}function getAppByPackageName(apps: AppInfo[], packageName: string): AppInfo {const app = apps.find(item => item.packageName === packageName)if (!app) {throw new Error(`App not found: ${packageName}`)}return app}function resolvePromptValue<T>(value: T | symbol): T {if (p.isCancel(value)) {p.cancel('Operation cancelled')process.exit(0)}return value}async function selectScript(app: AppInfo, action: Mode): Promise<string> {if (app.scripts.length === 1) {return app.scripts[0]}const script = await p.select({message: `Select ${action} script for "${app.name}":`,options: app.scripts.map(name => ({value: name,label: name,})),})return resolvePromptValue(script)}async function runPackageScript(packageName: string, script: string): Promise<void> {return new Promise((resolve, reject) => {childProcess = spawn('pnpm', ['--filter', packageName, 'run', script], {stdio: 'inherit',cwd: rootDir,shell: isWindows,})childProcess.on('close', (code) => {childProcess = nullif (code === 0 || code === null) {resolve()return}reject(new Error(`Process exited with code ${code}`))})childProcess.on('error', (error) => {childProcess = nullreject(error)})})}async function selectApps(apps: AppInfo[], message: string, selectionMode: ModeConfig['selectionMode']): Promise<AppInfo[]> {if (selectionMode === 'multiple') {const selectedPackageNames = resolvePromptValue(await p.multiselect({message,options: getAppChoices(apps),required: true,}))return selectedPackageNames.map(packageName => getAppByPackageName(apps, packageName))}const selectedPackageName = resolvePromptValue(await p.select({message,options: getAppChoices(apps),}))return [getAppByPackageName(apps, selectedPackageName)]}async function runSelectedApps(apps: AppInfo[], config: ModeConfig, showRunMessage: boolean): Promise<void> {for (const app of apps) {const script = await selectScript(app, config.action)if (showRunMessage) {const runMessage = config.getRunMessage?.({app,script,})if (runMessage) {p.log.info(runMessage)}}await runPackageScript(app.packageName, script)}}async function runMode(config: ModeConfig): Promise<void> {p.intro(config.intro)const apps = getApps(config.scriptMatcher)if (apps.length === 0) {p.log.error(config.noAppsMessage)process.exit(1)}if (apps.length === 1) {p.log.info(`Only one app found: ${apps[0].name}`)await runSelectedApps([apps[0]], config, config.showRunMessageWhenSingleApp ?? false)if (config.completionMessage) {p.outro(config.completionMessage)}return}const selectedApps = await selectApps(apps, config.appSelectMessage, config.selectionMode)await runSelectedApps(selectedApps, config, true)if (config.completionMessage) {p.outro(config.completionMessage)}}function parseModeArg(argv: string[]): string | undefined {for (let index = 0; index < argv.length; index += 1) {const arg = argv[index]if (arg === '--mode' || arg === '-m') {return argv[index + 1]}if (arg.startsWith('--mode=')) {return arg.slice('--mode='.length)}if (arg.startsWith('-m=')) {return arg.slice('-m='.length)}}return undefined}function hasHelpArg(argv: string[]): boolean {return argv.includes('--help') || argv.includes('-h')}function isMode(value: string | undefined): value is Mode {return value !== undefined && validModes.includes(value as Mode)}function printHelp(): void {console.log(`Usage: tsx scripts/cli.ts --mode=<${validModes.join('|')}>`)console.log('Examples:')console.log(' pnpm dev')console.log(' pnpm build')console.log(' pnpm serve')console.log(' pnpm cli -- --mode=dev')}async function main(): Promise<void> {const argv = process.argv.slice(2)const modeArg = parseModeArg(argv)if (hasHelpArg(argv)) {printHelp()return}if (!isMode(modeArg)) {p.log.error(`Invalid or missing mode. Expected one of: ${validModes.join(', ')}`)printHelp()process.exit(1)}await runMode(modeConfigs[modeArg])}main().catch((error: Error) => {p.log.error(error.message)process.exit(1)})
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。