openmanual 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/bin.js +733 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +186 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/bin.ts","../src/cli/commands/build.ts","../src/core/config/loader.ts","../src/core/config/schema.ts","../src/core/generator/index.ts","../src/core/generator/global-css.ts","../src/core/generator/layout.ts","../src/core/generator/lib-source.ts","../src/core/generator/next-config.ts","../src/core/generator/package-json.ts","../src/core/generator/page.ts","../src/core/generator/postcss-config.ts","../src/core/generator/provider.ts","../src/core/generator/source-config.ts","../src/core/generator/tsconfig.ts","../src/utils/install-deps.ts","../src/utils/logger.ts","../src/utils/temp-dir.ts","../src/cli/commands/dev.ts","../src/cli/commands/preview.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { buildCommand } from './commands/build.js';\nimport { devCommand } from './commands/dev.js';\nimport { previewCommand } from './commands/preview.js';\n\nconst program = new Command();\n\nprogram.name('openmanual').description('AI 友好的开源文档系统框架').version('0.1.0');\n\nprogram.addCommand(devCommand);\nprogram.addCommand(buildCommand);\nprogram.addCommand(previewCommand);\n\nprogram.parse();\n","import { spawn } from 'node:child_process';\nimport { cp, mkdir } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { Command } from 'commander';\nimport { loadConfig } from '../../core/config/loader.js';\nimport { generateAll } from '../../core/generator/index.js';\nimport { installDeps } from '../../utils/install-deps.js';\nimport { logger } from '../../utils/logger.js';\nimport { cleanTempDir, createSymlink, ensureTempDir, getAppDir } from '../../utils/temp-dir.js';\n\nexport const buildCommand = new Command('build').description('构建静态站点').action(async () => {\n const cwd = process.cwd();\n\n try {\n logger.step('读取配置文件...');\n const config = await loadConfig(cwd);\n\n logger.step('生成临时应用...');\n const appDir = getAppDir(cwd);\n const contentDir = resolve(cwd, config.contentDir ?? 'content');\n\n await ensureTempDir(cwd);\n\n const ctx = {\n config,\n projectDir: cwd,\n appDir,\n contentDir: config.contentDir ?? 'content',\n };\n\n await generateAll(ctx);\n\n // Symlink content directory\n await createSymlink(contentDir, resolve(appDir, 'content'));\n\n // Symlink public directory if exists\n const publicDir = resolve(cwd, 'public');\n try {\n const { stat } = await import('node:fs/promises');\n await stat(publicDir);\n await createSymlink(publicDir, resolve(appDir, 'public'));\n } catch {\n // no public dir, that's fine\n }\n\n logger.step('安装依赖...');\n await installDeps(appDir);\n\n logger.step('构建静态站点...');\n const buildResult = spawn('npx', ['next', 'build'], {\n cwd: appDir,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n await new Promise<void>((resolve, reject) => {\n buildResult.on('error', reject);\n buildResult.on('exit', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Build failed with code ${code}`));\n }\n });\n });\n\n // Copy output to user's output dir\n const outputDir = resolve(cwd, config.outputDir ?? 'dist');\n await mkdir(outputDir, { recursive: true });\n\n const nextOutput = resolve(appDir, 'out');\n try {\n await cp(nextOutput, outputDir, { recursive: true });\n logger.success(`静态站点已输出到: ${outputDir}`);\n } catch {\n // If no 'out' dir, check .next/static\n logger.warn('未找到静态导出产物,请检查 next.config.mjs 中 output: \"export\" 配置');\n }\n\n logger.step('清理临时文件...');\n await cleanTempDir(cwd);\n\n logger.success('构建完成!');\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger.error(message);\n process.exit(1);\n }\n});\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { type OpenManualConfig, OpenManualConfigSchema } from './schema.js';\n\nconst DEFAULT_CONFIG: Partial<OpenManualConfig> = {\n contentDir: 'content',\n outputDir: 'dist',\n locale: 'zh',\n navbar: {},\n footer: {},\n theme: {\n primaryHue: 220,\n darkMode: true,\n },\n search: {\n enabled: true,\n },\n mdx: {},\n};\n\nexport async function loadConfig(cwd: string = process.cwd()): Promise<OpenManualConfig> {\n const configPath = join(cwd, 'openmanual.json');\n\n let rawJson: string;\n try {\n rawJson = await readFile(configPath, 'utf-8');\n } catch {\n throw new Error(`openmanual.json not found in ${cwd}. Please create one.`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawJson);\n } catch {\n throw new Error('openmanual.json is not valid JSON.');\n }\n\n const result = OpenManualConfigSchema.safeParse(parsed);\n if (!result.success) {\n const errors = result.error.issues\n .map((i) => ` - ${i.path.join('.')}: ${i.message}`)\n .join('\\n');\n throw new Error(`openmanual.json validation failed:\\n${errors}`);\n }\n\n return mergeDefaults(result.data);\n}\n\nfunction mergeDefaults(config: OpenManualConfig): OpenManualConfig {\n return {\n ...config,\n contentDir: config.contentDir ?? DEFAULT_CONFIG.contentDir ?? 'content',\n outputDir: config.outputDir ?? DEFAULT_CONFIG.outputDir ?? 'dist',\n locale: config.locale ?? DEFAULT_CONFIG.locale ?? 'zh',\n navbar: {\n ...DEFAULT_CONFIG.navbar,\n ...config.navbar,\n logo: config.navbar?.logo ?? config.name,\n },\n footer: {\n ...DEFAULT_CONFIG.footer,\n ...config.footer,\n text: config.footer?.text ?? `MIT ${new Date().getFullYear()} © ${config.name}.`,\n },\n theme: {\n ...DEFAULT_CONFIG.theme,\n ...config.theme,\n },\n search: {\n ...DEFAULT_CONFIG.search,\n ...config.search,\n },\n mdx: {\n ...DEFAULT_CONFIG.mdx,\n ...config.mdx,\n },\n };\n}\n","import { z } from 'zod';\n\nexport const NavbarSchema = z.object({\n logo: z.string().optional(),\n github: z.string().url().optional(),\n links: z\n .array(\n z.object({\n label: z.string(),\n href: z.string(),\n })\n )\n .optional(),\n});\n\nexport const FooterSchema = z.object({\n text: z.string().optional(),\n});\n\nexport const SidebarPageSchema = z.object({\n slug: z.string(),\n title: z.string(),\n icon: z.string().optional(),\n});\n\nexport const SidebarGroupSchema = z.object({\n group: z.string(),\n icon: z.string().optional(),\n collapsed: z.boolean().optional(),\n pages: z.array(SidebarPageSchema),\n});\n\nexport const ThemeSchema = z.object({\n primaryHue: z.number().min(0).max(360).optional(),\n darkMode: z.boolean().optional(),\n});\n\nexport const SearchSchema = z.object({\n enabled: z.boolean().optional(),\n});\n\nexport const MdxSchema = z.object({\n latex: z.boolean().optional(),\n});\n\nexport const OpenManualConfigSchema = z.object({\n name: z.string().min(1),\n description: z.string().optional(),\n contentDir: z.string().optional(),\n outputDir: z.string().optional(),\n siteUrl: z.string().url().optional(),\n locale: z.string().optional(),\n navbar: NavbarSchema.optional(),\n footer: FooterSchema.optional(),\n sidebar: z.array(SidebarGroupSchema).optional(),\n theme: ThemeSchema.optional(),\n search: SearchSchema.optional(),\n mdx: MdxSchema.optional(),\n});\n\nexport type OpenManualConfig = z.infer<typeof OpenManualConfigSchema>;\nexport type NavbarConfig = z.infer<typeof NavbarSchema>;\nexport type FooterConfig = z.infer<typeof FooterSchema>;\nexport type SidebarGroup = z.infer<typeof SidebarGroupSchema>;\nexport type SidebarPage = z.infer<typeof SidebarPageSchema>;\nexport type ThemeConfig = z.infer<typeof ThemeSchema>;\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { OpenManualConfig } from '../config/schema.js';\nimport { generateGlobalCss } from './global-css.js';\nimport { generateLayout } from './layout.js';\nimport { generateLibSource } from './lib-source.js';\nimport { generateNextConfig } from './next-config.js';\nimport { generatePackageJson } from './package-json.js';\nimport { generatePage } from './page.js';\nimport { generatePostcssConfig } from './postcss-config.js';\nimport { generateProvider } from './provider.js';\nimport { generateSourceConfig } from './source-config.js';\nimport { generateTsconfig } from './tsconfig.js';\n\nexport interface GenerateContext {\n config: OpenManualConfig;\n /** Absolute path to user's project root */\n projectDir: string;\n /** Absolute path to .openmanual/app */\n appDir: string;\n /** Content directory relative to project root */\n contentDir: string;\n}\n\nexport async function generateAll(ctx: GenerateContext): Promise<void> {\n const files: Array<{ path: string; content: string }> = [\n {\n path: 'source.config.ts',\n content: generateSourceConfig(ctx),\n },\n {\n path: 'next.config.mjs',\n content: generateNextConfig(ctx),\n },\n {\n path: 'global.css',\n content: generateGlobalCss(ctx),\n },\n {\n path: 'package.json',\n content: generatePackageJson(ctx),\n },\n {\n path: 'tsconfig.json',\n content: generateTsconfig(),\n },\n {\n path: 'postcss.config.mjs',\n content: generatePostcssConfig(),\n },\n {\n path: 'lib/source.ts',\n content: generateLibSource(),\n },\n {\n path: 'lib/layout.ts',\n content: generateLayout(ctx),\n },\n {\n path: 'app/layout.tsx',\n content: generateRootLayout(),\n },\n {\n path: 'app/provider.tsx',\n content: generateProvider(ctx),\n },\n {\n path: 'app/[[...slug]]/layout.tsx',\n content: generateDocsLayout(ctx),\n },\n {\n path: 'app/[[...slug]]/page.tsx',\n content: generatePage(ctx),\n },\n ];\n\n for (const file of files) {\n const fullPath = join(ctx.appDir, file.path);\n const dir = join(fullPath, '..');\n await mkdir(dir, { recursive: true });\n await writeFile(fullPath, file.content, 'utf-8');\n }\n}\n\nfunction generateRootLayout(): string {\n return `import { Provider } from './provider';\nimport type { ReactNode } from 'react';\nimport '../global.css';\n\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return (\n <html lang=\"zh\" suppressHydrationWarning>\n <body className=\"flex flex-col min-h-screen\">\n <Provider>{children}</Provider>\n </body>\n </html>\n );\n}\n`;\n}\n\nfunction generateDocsLayout(ctx: GenerateContext): string {\n const { config } = ctx;\n const githubLink = config.navbar?.github ?? '';\n const navLinks = config.navbar?.links ?? [];\n const footerText = config.footer?.text ?? '';\n\n const linksArray = navLinks.map((l) => ({\n text: l.label,\n url: l.href,\n external: true,\n }));\n\n const githubLine = githubLink ? `\\n github: '${githubLink}',` : '';\n\n const linksLine = linksArray.length > 0 ? `\\n links: ${JSON.stringify(linksArray)},` : '';\n\n const footerLine = footerText\n ? `\\n footer: { children: '${footerText.replace(/'/g, \"\\\\'\")}' },`\n : '';\n\n return `import { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { baseOptions } from '@/lib/layout';\nimport { source } from '@/lib/source';\nimport type { ReactNode } from 'react';\n\nconst docsOptions = {\n ...baseOptions(),\n tree: source.getPageTree(),${githubLine}${linksLine}${footerLine}\n};\n\nexport default function DocsLayoutWrapper({ children }: { children: ReactNode }) {\n return (\n <DocsLayout {...docsOptions}>\n {children}\n </DocsLayout>\n );\n}\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generateGlobalCss(ctx: { config: OpenManualConfig }): string {\n const { config } = ctx;\n const primaryHue = config.theme?.primaryHue ?? 220;\n\n return `@import 'tailwindcss';\n@import 'fumadocs-ui/style.css';\n\n:root {\n --primary-hue: ${primaryHue};\n}\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generateLayout(ctx: { config: OpenManualConfig }): string {\n const { config } = ctx;\n const navTitle = config.navbar?.logo ?? config.name;\n\n return `import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\n\nexport function baseOptions(): BaseLayoutProps {\n return {\n nav: {\n title: '${navTitle}',\n },\n };\n}\n`;\n}\n","export function generateLibSource(): string {\n return `import { docs } from '@/.source/server';\nimport { loader } from 'fumadocs-core/source';\n\nexport const source = loader({\n baseUrl: '/',\n source: docs.toFumadocsSource(),\n});\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generateNextConfig(ctx: { config: OpenManualConfig }): string {\n const { config } = ctx;\n const siteUrl = config.siteUrl ?? '';\n\n return `import { createMDX } from 'fumadocs-mdx/next';\n\nconst withMDX = createMDX();\n\n/** @type {import('next').NextConfig} */\nconst config = {\n reactStrictMode: true,${siteUrl ? `\\n output: 'export',` : ''}\n images: {\n unoptimized: true,\n },\n};\n\nexport default withMDX(config);\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generatePackageJson(_ctx: {\n config: OpenManualConfig;\n projectDir: string;\n}): string {\n const pkg = {\n name: 'openmanual-app',\n type: 'module',\n private: true,\n scripts: {\n dev: 'next dev',\n build: 'next build',\n start: 'next start',\n },\n dependencies: {\n '@tailwindcss/postcss': '^4.1.15',\n 'fumadocs-core': '^16.7.7',\n 'fumadocs-mdx': '^14.2.11',\n 'fumadocs-ui': '^16.7.7',\n next: '^16.2.1',\n postcss: '^8.5.8',\n react: '^19.1.0',\n 'react-dom': '^19.1.0',\n tailwindcss: '^4.1.15',\n },\n };\n\n return `${JSON.stringify(pkg, null, 2)}\\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generatePage(_ctx: { config: OpenManualConfig }): string {\n return `import { source } from '@/lib/source';\nimport { notFound } from 'next/navigation';\nimport { DocsPage, DocsBody, DocsTitle, DocsDescription } from 'fumadocs-ui/page';\nimport defaultMdxComponents from 'fumadocs-ui/mdx';\n\nexport default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {\n const { slug } = await params;\n const page = source.getPage(slug);\n\n if (!page) {\n notFound();\n }\n\n const MDX = page.data.body;\n\n return (\n <DocsPage toc={page.data.toc}>\n <DocsTitle>{page.data.title}</DocsTitle>\n {page.data.description && (\n <DocsDescription>{page.data.description}</DocsDescription>\n )}\n <DocsBody>\n <MDX components={{ ...defaultMdxComponents }} />\n </DocsBody>\n </DocsPage>\n );\n}\n\nexport function generateStaticParams() {\n return source.generateParams();\n}\n`;\n}\n","export function generatePostcssConfig(): string {\n return `/** @type {import('postcss-load-config').Config} */\nconst config = {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n};\n\nexport default config;\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generateProvider(ctx: { config: OpenManualConfig }): string {\n const searchEnabled = ctx.config.search?.enabled !== false;\n\n return `'use client';\n\nimport { RootProvider } from 'fumadocs-ui/provider/next';\nimport type { ReactNode } from 'react';\n\nexport function Provider({ children }: { children: ReactNode }) {\n return (\n <RootProvider\n search={{\n enabled: ${searchEnabled},\n }}\n >\n {children}\n </RootProvider>\n );\n}\n`;\n}\n","import type { OpenManualConfig } from '../config/schema.js';\n\nexport function generateSourceConfig(_ctx: { config: OpenManualConfig }): string {\n return `import { defineDocs, defineConfig } from 'fumadocs-mdx/config';\n\nexport const docs = defineDocs({\n dir: 'content',\n});\n\nexport default defineConfig();\n`;\n}\n","export function generateTsconfig(): string {\n return `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n lib: ['dom', 'dom.iterable', 'esnext'],\n module: 'ESNext',\n moduleResolution: 'Bundler',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n jsx: 'react-jsx',\n noEmit: true,\n allowJs: true,\n resolveJsonModule: true,\n isolatedModules: true,\n incremental: true,\n plugins: [{ name: 'next' }],\n paths: {\n '@/*': ['./*'],\n },\n },\n include: ['**/*.ts', '**/*.tsx', 'next-env.d.ts', '.next/types/**/*.ts', '.next/dev/types/**/*.ts'],\n exclude: ['node_modules'],\n },\n null,\n 2\n )}\\n`;\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nexport async function installDeps(appDir: string): Promise<void> {\n const nodeModules = resolve(appDir, 'node_modules');\n\n // Skip install if node_modules already exists\n if (existsSync(nodeModules)) {\n return;\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn('pnpm', ['install', '--no-frozen-lockfile'], {\n cwd: appDir,\n stdio: 'pipe',\n env: { ...process.env },\n });\n\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('error', reject);\n child.on('exit', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`pnpm install failed: ${stderr}`));\n }\n });\n });\n}\n","const COLORS = {\n reset: '\\x1b[0m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m',\n} as const;\n\nfunction timestamp(): string {\n return new Date().toLocaleTimeString('zh-CN', { hour12: false });\n}\n\nexport const logger = {\n info(msg: string): void {\n console.log(\n `${COLORS.gray}[${timestamp()}]${COLORS.reset} ${COLORS.cyan}info${COLORS.reset} ${msg}`\n );\n },\n\n success(msg: string): void {\n console.log(\n `${COLORS.gray}[${timestamp()}]${COLORS.reset} ${COLORS.green}done${COLORS.reset} ${msg}`\n );\n },\n\n warn(msg: string): void {\n console.warn(\n `${COLORS.gray}[${timestamp()}]${COLORS.reset} ${COLORS.yellow}warn${COLORS.reset} ${msg}`\n );\n },\n\n error(msg: string): void {\n console.error(\n `${COLORS.gray}[${timestamp()}]${COLORS.reset} ${COLORS.red}error${COLORS.reset} ${msg}`\n );\n },\n\n step(msg: string): void {\n console.log(\n `${COLORS.gray}[${timestamp()}]${COLORS.reset} ${COLORS.bold}→${COLORS.reset} ${msg}`\n );\n },\n};\n","import { existsSync } from 'node:fs';\nimport { lstat, mkdir, rm, symlink } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nconst TEMP_DIR_NAME = '.openmanual';\n\nexport function getTempDir(cwd: string): string {\n return join(cwd, TEMP_DIR_NAME);\n}\n\nexport function getAppDir(cwd: string): string {\n return join(getTempDir(cwd), 'app');\n}\n\nexport async function ensureTempDir(cwd: string): Promise<string> {\n const tempDir = getTempDir(cwd);\n const appDir = getAppDir(cwd);\n\n await mkdir(tempDir, { recursive: true });\n await mkdir(join(appDir, 'app'), { recursive: true });\n\n return tempDir;\n}\n\nexport async function cleanTempDir(cwd: string): Promise<void> {\n const tempDir = getTempDir(cwd);\n if (existsSync(tempDir)) {\n await rm(tempDir, { recursive: true, force: true });\n }\n}\n\nexport async function createSymlink(target: string, linkPath: string): Promise<void> {\n const resolvedTarget = resolve(target);\n const resolvedLink = resolve(linkPath);\n\n try {\n await lstat(resolvedLink);\n // Remove existing symlink or directory\n await rm(resolvedLink, { recursive: true, force: true });\n } catch {\n // link doesn't exist, that's fine\n }\n\n await symlink(resolvedTarget, resolvedLink, 'junction');\n}\n","import { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\nimport { Command } from 'commander';\nimport { loadConfig } from '../../core/config/loader.js';\nimport { generateAll } from '../../core/generator/index.js';\nimport { installDeps } from '../../utils/install-deps.js';\nimport { logger } from '../../utils/logger.js';\nimport { createSymlink, ensureTempDir, getAppDir } from '../../utils/temp-dir.js';\n\nexport const devCommand = new Command('dev')\n .description('启动开发服务器')\n .option('-p, --port <port>', '端口号', '3000')\n .action(async (options) => {\n const cwd = process.cwd();\n\n try {\n logger.step('读取配置文件...');\n const config = await loadConfig(cwd);\n\n logger.step('生成临时应用...');\n const tempDir = await ensureTempDir(cwd);\n const appDir = getAppDir(cwd);\n const contentDir = resolve(cwd, config.contentDir ?? 'content');\n\n const ctx = {\n config,\n projectDir: cwd,\n appDir,\n contentDir: config.contentDir ?? 'content',\n };\n\n await generateAll(ctx);\n\n // Symlink content directory\n await createSymlink(contentDir, resolve(appDir, 'content'));\n\n // Symlink public directory if exists\n const publicDir = resolve(cwd, 'public');\n try {\n const { stat } = await import('node:fs/promises');\n await stat(publicDir);\n await createSymlink(publicDir, resolve(appDir, 'public'));\n } catch {\n // no public dir, that's fine\n }\n\n logger.step('安装依赖...');\n await installDeps(appDir);\n\n logger.success(`开发服务器启动中...`);\n logger.info(`内容目录: ${contentDir}`);\n logger.info(`临时目录: ${tempDir}`);\n logger.info(`端口: ${options.port}`);\n\n const child = spawn('npx', ['next', 'dev', '--port', options.port], {\n cwd: appDir,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n child.on('error', (err) => {\n logger.error(`启动失败: ${err.message}`);\n process.exit(1);\n });\n\n child.on('exit', (code) => {\n if (code !== 0 && code !== null) {\n process.exit(code);\n }\n });\n\n // Handle graceful shutdown\n const cleanup = () => {\n child.kill();\n process.exit(0);\n };\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger.error(message);\n process.exit(1);\n }\n });\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Command } from 'commander';\nimport { loadConfig } from '../../core/config/loader.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const previewCommand = new Command('preview')\n .description('预览构建产物')\n .option('-p, --port <port>', '端口号', '8080')\n .option('-d, --dir <dir>', '产物目录')\n .action(async (options) => {\n const cwd = process.cwd();\n\n try {\n let outputDir = options.dir;\n if (!outputDir) {\n const config = await loadConfig(cwd);\n outputDir = resolve(cwd, config.outputDir ?? 'dist');\n }\n\n if (!existsSync(outputDir)) {\n logger.error(`产物目录不存在: ${outputDir}`);\n logger.info('请先运行 openmanual build');\n process.exit(1);\n }\n\n logger.info(`预览目录: ${outputDir}`);\n logger.info(`预览地址: http://localhost:${options.port}`);\n\n const child = spawn('npx', ['serve', outputDir, '-p', options.port], {\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n child.on('error', (err) => {\n logger.error(`启动失败: ${err.message}`);\n process.exit(1);\n });\n\n const cleanup = () => {\n child.kill();\n process.exit(0);\n };\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger.error(message);\n process.exit(1);\n }\n });\n"],"mappings":";;;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,SAAAC,cAAa;AACtB,SAAS,IAAI,SAAAC,cAAa;AAC1B,SAAS,WAAAC,gBAAe;AACxB,SAAS,eAAe;;;ACHxB,SAAS,gBAAgB;AACzB,SAAS,YAAY;;;ACDrB,SAAS,SAAS;AAEX,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAClC,OAAO,EACJ;AAAA,IACC,EAAE,OAAO;AAAA,MACP,OAAO,EAAE,OAAO;AAAA,MAChB,MAAM,EAAE,OAAO;AAAA,IACjB,CAAC;AAAA,EACH,EACC,SAAS;AACd,CAAC;AAEM,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,WAAW,EAAE,QAAQ,EAAE,SAAS;AAAA,EAChC,OAAO,EAAE,MAAM,iBAAiB;AAClC,CAAC;AAEM,IAAM,cAAc,EAAE,OAAO;AAAA,EAClC,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAChD,UAAU,EAAE,QAAQ,EAAE,SAAS;AACjC,CAAC;AAEM,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,SAAS,EAAE,QAAQ,EAAE,SAAS;AAChC,CAAC;AAEM,IAAM,YAAY,EAAE,OAAO;AAAA,EAChC,OAAO,EAAE,QAAQ,EAAE,SAAS;AAC9B,CAAC;AAEM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACnC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,QAAQ,aAAa,SAAS;AAAA,EAC9B,QAAQ,aAAa,SAAS;AAAA,EAC9B,SAAS,EAAE,MAAM,kBAAkB,EAAE,SAAS;AAAA,EAC9C,OAAO,YAAY,SAAS;AAAA,EAC5B,QAAQ,aAAa,SAAS;AAAA,EAC9B,KAAK,UAAU,SAAS;AAC1B,CAAC;;;ADtDD,IAAM,iBAA4C;AAAA,EAChD,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ,CAAC;AAAA,EACT,QAAQ,CAAC;AAAA,EACT,OAAO;AAAA,IACL,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,KAAK,CAAC;AACR;AAEA,eAAsB,WAAW,MAAc,QAAQ,IAAI,GAA8B;AACvF,QAAM,aAAa,KAAK,KAAK,iBAAiB;AAE9C,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,YAAY,OAAO;AAAA,EAC9C,QAAQ;AACN,UAAM,IAAI,MAAM,gCAAgC,GAAG,sBAAsB;AAAA,EAC3E;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;AAAA,EAC7B,QAAQ;AACN,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AAEA,QAAM,SAAS,uBAAuB,UAAU,MAAM;AACtD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OACzB,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAClD,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM;AAAA,EAAuC,MAAM,EAAE;AAAA,EACjE;AAEA,SAAO,cAAc,OAAO,IAAI;AAClC;AAEA,SAAS,cAAc,QAA4C;AACjE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY,OAAO,cAAc,eAAe,cAAc;AAAA,IAC9D,WAAW,OAAO,aAAa,eAAe,aAAa;AAAA,IAC3D,QAAQ,OAAO,UAAU,eAAe,UAAU;AAAA,IAClD,QAAQ;AAAA,MACN,GAAG,eAAe;AAAA,MAClB,GAAG,OAAO;AAAA,MACV,MAAM,OAAO,QAAQ,QAAQ,OAAO;AAAA,IACtC;AAAA,IACA,QAAQ;AAAA,MACN,GAAG,eAAe;AAAA,MAClB,GAAG,OAAO;AAAA,MACV,MAAM,OAAO,QAAQ,QAAQ,QAAO,oBAAI,KAAK,GAAE,YAAY,CAAC,SAAM,OAAO,IAAI;AAAA,IAC/E;AAAA,IACA,OAAO;AAAA,MACL,GAAG,eAAe;AAAA,MAClB,GAAG,OAAO;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN,GAAG,eAAe;AAAA,MAClB,GAAG,OAAO;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,GAAG,eAAe;AAAA,MAClB,GAAG,OAAO;AAAA,IACZ;AAAA,EACF;AACF;;;AE7EA,SAAS,OAAO,iBAAiB;AACjC,SAAS,QAAAC,aAAY;;;ACCd,SAAS,kBAAkB,KAA2C;AAC3E,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,aAAa,OAAO,OAAO,cAAc;AAE/C,SAAO;AAAA;AAAA;AAAA;AAAA,mBAIU,UAAU;AAAA;AAAA;AAG7B;;;ACXO,SAAS,eAAe,KAA2C;AACxE,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAW,OAAO,QAAQ,QAAQ,OAAO;AAE/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAKxB;;;AChBO,SAAS,oBAA4B;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQT;;;ACPO,SAAS,mBAAmB,KAA2C;AAC5E,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,UAAU,OAAO,WAAW;AAElC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAMiB,UAAU;AAAA,uBAA0B,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQhE;;;AClBO,SAAS,oBAAoB,MAGzB;AACT,QAAM,MAAM;AAAA,IACV,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,cAAc;AAAA,MACZ,wBAAwB;AAAA,MACxB,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA;AACxC;;;AC3BO,SAAS,aAAa,MAA4C;AACvE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCT;;;ACnCO,SAAS,wBAAgC;AAC9C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAST;;;ACRO,SAAS,iBAAiB,KAA2C;AAC1E,QAAM,gBAAgB,IAAI,OAAO,QAAQ,YAAY;AAErD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBASU,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQhC;;;ACpBO,SAAS,qBAAqB,MAA4C;AAC/E,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQT;;;ACXO,SAAS,mBAA2B;AACzC,SAAO,GAAG,KAAK;AAAA,IACb;AAAA,MACE,iBAAiB;AAAA,QACf,QAAQ;AAAA,QACR,KAAK,CAAC,OAAO,gBAAgB,QAAQ;AAAA,QACrC,QAAQ;AAAA,QACR,kBAAkB;AAAA,QAClB,QAAQ;AAAA,QACR,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,QAC1B,OAAO;AAAA,UACL,OAAO,CAAC,KAAK;AAAA,QACf;AAAA,MACF;AAAA,MACA,SAAS,CAAC,WAAW,YAAY,iBAAiB,uBAAuB,yBAAyB;AAAA,MAClG,SAAS,CAAC,cAAc;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA;AACH;;;AVJA,eAAsB,YAAY,KAAqC;AACrE,QAAM,QAAkD;AAAA,IACtD;AAAA,MACE,MAAM;AAAA,MACN,SAAS,qBAAqB,GAAG;AAAA,IACnC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,mBAAmB,GAAG;AAAA,IACjC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,kBAAkB,GAAG;AAAA,IAChC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,oBAAoB,GAAG;AAAA,IAClC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,iBAAiB;AAAA,IAC5B;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,sBAAsB;AAAA,IACjC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,kBAAkB;AAAA,IAC7B;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,eAAe,GAAG;AAAA,IAC7B;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,mBAAmB;AAAA,IAC9B;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,iBAAiB,GAAG;AAAA,IAC/B;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,mBAAmB,GAAG;AAAA,IACjC;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,aAAa,GAAG;AAAA,IAC3B;AAAA,EACF;AAEA,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAWC,MAAK,IAAI,QAAQ,KAAK,IAAI;AAC3C,UAAM,MAAMA,MAAK,UAAU,IAAI;AAC/B,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,UAAU,UAAU,KAAK,SAAS,OAAO;AAAA,EACjD;AACF;AAEA,SAAS,qBAA6B;AACpC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcT;AAEA,SAAS,mBAAmB,KAA8B;AACxD,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,aAAa,OAAO,QAAQ,UAAU;AAC5C,QAAM,WAAW,OAAO,QAAQ,SAAS,CAAC;AAC1C,QAAM,aAAa,OAAO,QAAQ,QAAQ;AAE1C,QAAM,aAAa,SAAS,IAAI,CAAC,OAAO;AAAA,IACtC,MAAM,EAAE;AAAA,IACR,KAAK,EAAE;AAAA,IACP,UAAU;AAAA,EACZ,EAAE;AAEF,QAAM,aAAa,aAAa;AAAA,eAAkB,UAAU,OAAO;AAEnE,QAAM,YAAY,WAAW,SAAS,IAAI;AAAA,aAAgB,KAAK,UAAU,UAAU,CAAC,MAAM;AAE1F,QAAM,aAAa,aACf;AAAA,yBAA4B,WAAW,QAAQ,MAAM,KAAK,CAAC,SAC3D;AAEJ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAOsB,UAAU,GAAG,SAAS,GAAG,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWlE;;;AW3IA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AAExB,eAAsB,YAAY,QAA+B;AAC/D,QAAM,cAAc,QAAQ,QAAQ,cAAc;AAGlD,MAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,EACF;AAEA,SAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,QAAQ,CAAC,WAAW,sBAAsB,GAAG;AAAA,MAC/D,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAED,QAAI,SAAS;AACb,UAAM,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AACzC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,SAAS,GAAG;AACd,QAAAA,SAAQ;AAAA,MACV,OAAO;AACL,eAAO,IAAI,MAAM,wBAAwB,MAAM,EAAE,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;;;ACjCA,IAAM,SAAS;AAAA,EACb,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAEA,SAAS,YAAoB;AAC3B,UAAO,oBAAI,KAAK,GAAE,mBAAmB,SAAS,EAAE,QAAQ,MAAM,CAAC;AACjE;AAEO,IAAM,SAAS;AAAA,EACpB,KAAK,KAAmB;AACtB,YAAQ;AAAA,MACN,GAAG,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,KAAK,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,IAAI,GAAG;AAAA,IACxF;AAAA,EACF;AAAA,EAEA,QAAQ,KAAmB;AACzB,YAAQ;AAAA,MACN,GAAG,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,KAAK,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK,IAAI,GAAG;AAAA,IACzF;AAAA,EACF;AAAA,EAEA,KAAK,KAAmB;AACtB,YAAQ;AAAA,MACN,GAAG,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,KAAK,IAAI,OAAO,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;AAAA,IAC1F;AAAA,EACF;AAAA,EAEA,MAAM,KAAmB;AACvB,YAAQ;AAAA,MACN,GAAG,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,KAAK,IAAI,OAAO,GAAG,QAAQ,OAAO,KAAK,IAAI,GAAG;AAAA,IACxF;AAAA,EACF;AAAA,EAEA,KAAK,KAAmB;AACtB,YAAQ;AAAA,MACN,GAAG,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,KAAK,IAAI,OAAO,IAAI,SAAI,OAAO,KAAK,IAAI,GAAG;AAAA,IACrF;AAAA,EACF;AACF;;;AC5CA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,OAAO,SAAAC,QAAO,IAAI,eAAe;AAC1C,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AAE9B,IAAM,gBAAgB;AAEf,SAAS,WAAW,KAAqB;AAC9C,SAAOD,MAAK,KAAK,aAAa;AAChC;AAEO,SAAS,UAAU,KAAqB;AAC7C,SAAOA,MAAK,WAAW,GAAG,GAAG,KAAK;AACpC;AAEA,eAAsB,cAAc,KAA8B;AAChE,QAAM,UAAU,WAAW,GAAG;AAC9B,QAAM,SAAS,UAAU,GAAG;AAE5B,QAAMD,OAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,QAAMA,OAAMC,MAAK,QAAQ,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AAEpD,SAAO;AACT;AAEA,eAAsB,aAAa,KAA4B;AAC7D,QAAM,UAAU,WAAW,GAAG;AAC9B,MAAIF,YAAW,OAAO,GAAG;AACvB,UAAM,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACpD;AACF;AAEA,eAAsB,cAAc,QAAgB,UAAiC;AACnF,QAAM,iBAAiBG,SAAQ,MAAM;AACrC,QAAM,eAAeA,SAAQ,QAAQ;AAErC,MAAI;AACF,UAAM,MAAM,YAAY;AAExB,UAAM,GAAG,cAAc,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACzD,QAAQ;AAAA,EAER;AAEA,QAAM,QAAQ,gBAAgB,cAAc,UAAU;AACxD;;;AhBlCO,IAAM,eAAe,IAAI,QAAQ,OAAO,EAAE,YAAY,sCAAQ,EAAE,OAAO,YAAY;AACxF,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI;AACF,WAAO,KAAK,yCAAW;AACvB,UAAM,SAAS,MAAM,WAAW,GAAG;AAEnC,WAAO,KAAK,yCAAW;AACvB,UAAM,SAAS,UAAU,GAAG;AAC5B,UAAM,aAAaC,SAAQ,KAAK,OAAO,cAAc,SAAS;AAE9D,UAAM,cAAc,GAAG;AAEvB,UAAM,MAAM;AAAA,MACV;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,YAAY,OAAO,cAAc;AAAA,IACnC;AAEA,UAAM,YAAY,GAAG;AAGrB,UAAM,cAAc,YAAYA,SAAQ,QAAQ,SAAS,CAAC;AAG1D,UAAM,YAAYA,SAAQ,KAAK,QAAQ;AACvC,QAAI;AACF,YAAM,EAAE,KAAK,IAAI,MAAM,OAAO,aAAkB;AAChD,YAAM,KAAK,SAAS;AACpB,YAAM,cAAc,WAAWA,SAAQ,QAAQ,QAAQ,CAAC;AAAA,IAC1D,QAAQ;AAAA,IAER;AAEA,WAAO,KAAK,6BAAS;AACrB,UAAM,YAAY,MAAM;AAExB,WAAO,KAAK,yCAAW;AACvB,UAAM,cAAcC,OAAM,OAAO,CAAC,QAAQ,OAAO,GAAG;AAAA,MAClD,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAED,UAAM,IAAI,QAAc,CAACD,UAAS,WAAW;AAC3C,kBAAY,GAAG,SAAS,MAAM;AAC9B,kBAAY,GAAG,QAAQ,CAAC,SAAS;AAC/B,YAAI,SAAS,GAAG;AACd,UAAAA,SAAQ;AAAA,QACV,OAAO;AACL,iBAAO,IAAI,MAAM,0BAA0B,IAAI,EAAE,CAAC;AAAA,QACpD;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAGD,UAAM,YAAYA,SAAQ,KAAK,OAAO,aAAa,MAAM;AACzD,UAAME,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAE1C,UAAM,aAAaF,SAAQ,QAAQ,KAAK;AACxC,QAAI;AACF,YAAM,GAAG,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AACnD,aAAO,QAAQ,qDAAa,SAAS,EAAE;AAAA,IACzC,QAAQ;AAEN,aAAO,KAAK,qIAAqD;AAAA,IACnE;AAEA,WAAO,KAAK,yCAAW;AACvB,UAAM,aAAa,GAAG;AAEtB,WAAO,QAAQ,gCAAO;AAAA,EACxB,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,MAAM,OAAO;AACpB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;;;AiBxFD,SAAS,SAAAG,cAAa;AACtB,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAAC,gBAAe;AAOjB,IAAM,aAAa,IAAIC,SAAQ,KAAK,EACxC,YAAY,4CAAS,EACrB,OAAO,qBAAqB,sBAAO,MAAM,EACzC,OAAO,OAAO,YAAY;AACzB,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI;AACF,WAAO,KAAK,yCAAW;AACvB,UAAM,SAAS,MAAM,WAAW,GAAG;AAEnC,WAAO,KAAK,yCAAW;AACvB,UAAM,UAAU,MAAM,cAAc,GAAG;AACvC,UAAM,SAAS,UAAU,GAAG;AAC5B,UAAM,aAAaC,SAAQ,KAAK,OAAO,cAAc,SAAS;AAE9D,UAAM,MAAM;AAAA,MACV;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,YAAY,OAAO,cAAc;AAAA,IACnC;AAEA,UAAM,YAAY,GAAG;AAGrB,UAAM,cAAc,YAAYA,SAAQ,QAAQ,SAAS,CAAC;AAG1D,UAAM,YAAYA,SAAQ,KAAK,QAAQ;AACvC,QAAI;AACF,YAAM,EAAE,KAAK,IAAI,MAAM,OAAO,aAAkB;AAChD,YAAM,KAAK,SAAS;AACpB,YAAM,cAAc,WAAWA,SAAQ,QAAQ,QAAQ,CAAC;AAAA,IAC1D,QAAQ;AAAA,IAER;AAEA,WAAO,KAAK,6BAAS;AACrB,UAAM,YAAY,MAAM;AAExB,WAAO,QAAQ,qDAAa;AAC5B,WAAO,KAAK,6BAAS,UAAU,EAAE;AACjC,WAAO,KAAK,6BAAS,OAAO,EAAE;AAC9B,WAAO,KAAK,iBAAO,QAAQ,IAAI,EAAE;AAEjC,UAAM,QAAQC,OAAM,OAAO,CAAC,QAAQ,OAAO,UAAU,QAAQ,IAAI,GAAG;AAAA,MAClE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,aAAO,MAAM,6BAAS,IAAI,OAAO,EAAE;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,SAAS,KAAK,SAAS,MAAM;AAC/B,gBAAQ,KAAK,IAAI;AAAA,MACnB;AAAA,IACF,CAAC;AAGD,UAAM,UAAU,MAAM;AACpB,YAAM,KAAK;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,GAAG,UAAU,OAAO;AAC5B,YAAQ,GAAG,WAAW,OAAO;AAAA,EAC/B,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,MAAM,OAAO;AACpB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;;;ACnFH,SAAS,SAAAC,cAAa;AACtB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAAC,gBAAe;AAIjB,IAAM,iBAAiB,IAAIC,SAAQ,SAAS,EAChD,YAAY,sCAAQ,EACpB,OAAO,qBAAqB,sBAAO,MAAM,EACzC,OAAO,mBAAmB,0BAAM,EAChC,OAAO,OAAO,YAAY;AACzB,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI;AACF,QAAI,YAAY,QAAQ;AACxB,QAAI,CAAC,WAAW;AACd,YAAM,SAAS,MAAM,WAAW,GAAG;AACnC,kBAAYC,SAAQ,KAAK,OAAO,aAAa,MAAM;AAAA,IACrD;AAEA,QAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,aAAO,MAAM,+CAAY,SAAS,EAAE;AACpC,aAAO,KAAK,2CAAuB;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,WAAO,KAAK,6BAAS,SAAS,EAAE;AAChC,WAAO,KAAK,8CAA0B,QAAQ,IAAI,EAAE;AAEpD,UAAM,QAAQC,OAAM,OAAO,CAAC,SAAS,WAAW,MAAM,QAAQ,IAAI,GAAG;AAAA,MACnE,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACxB,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,aAAO,MAAM,6BAAS,IAAI,OAAO,EAAE;AACnC,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAED,UAAM,UAAU,MAAM;AACpB,YAAM,KAAK;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,GAAG,UAAU,OAAO;AAC5B,YAAQ,GAAG,WAAW,OAAO;AAAA,EAC/B,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,MAAM,OAAO;AACpB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;;;AnB9CH,IAAM,UAAU,IAAIC,SAAQ;AAE5B,QAAQ,KAAK,YAAY,EAAE,YAAY,uEAAgB,EAAE,QAAQ,OAAO;AAExE,QAAQ,WAAW,UAAU;AAC7B,QAAQ,WAAW,YAAY;AAC/B,QAAQ,WAAW,cAAc;AAEjC,QAAQ,MAAM;","names":["Command","spawn","mkdir","resolve","join","join","resolve","existsSync","mkdir","join","resolve","resolve","spawn","mkdir","spawn","resolve","Command","Command","resolve","spawn","spawn","existsSync","resolve","Command","Command","resolve","existsSync","spawn","Command"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const OpenManualConfigSchema: z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
description: z.ZodOptional<z.ZodString>;
|
|
6
|
+
contentDir: z.ZodOptional<z.ZodString>;
|
|
7
|
+
outputDir: z.ZodOptional<z.ZodString>;
|
|
8
|
+
siteUrl: z.ZodOptional<z.ZodString>;
|
|
9
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
10
|
+
navbar: z.ZodOptional<z.ZodObject<{
|
|
11
|
+
logo: z.ZodOptional<z.ZodString>;
|
|
12
|
+
github: z.ZodOptional<z.ZodString>;
|
|
13
|
+
links: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
14
|
+
label: z.ZodString;
|
|
15
|
+
href: z.ZodString;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
label: string;
|
|
18
|
+
href: string;
|
|
19
|
+
}, {
|
|
20
|
+
label: string;
|
|
21
|
+
href: string;
|
|
22
|
+
}>, "many">>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
logo?: string | undefined;
|
|
25
|
+
github?: string | undefined;
|
|
26
|
+
links?: {
|
|
27
|
+
label: string;
|
|
28
|
+
href: string;
|
|
29
|
+
}[] | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
logo?: string | undefined;
|
|
32
|
+
github?: string | undefined;
|
|
33
|
+
links?: {
|
|
34
|
+
label: string;
|
|
35
|
+
href: string;
|
|
36
|
+
}[] | undefined;
|
|
37
|
+
}>>;
|
|
38
|
+
footer: z.ZodOptional<z.ZodObject<{
|
|
39
|
+
text: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
text?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
text?: string | undefined;
|
|
44
|
+
}>>;
|
|
45
|
+
sidebar: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
46
|
+
group: z.ZodString;
|
|
47
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
48
|
+
collapsed: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
pages: z.ZodArray<z.ZodObject<{
|
|
50
|
+
slug: z.ZodString;
|
|
51
|
+
title: z.ZodString;
|
|
52
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, "strip", z.ZodTypeAny, {
|
|
54
|
+
slug: string;
|
|
55
|
+
title: string;
|
|
56
|
+
icon?: string | undefined;
|
|
57
|
+
}, {
|
|
58
|
+
slug: string;
|
|
59
|
+
title: string;
|
|
60
|
+
icon?: string | undefined;
|
|
61
|
+
}>, "many">;
|
|
62
|
+
}, "strip", z.ZodTypeAny, {
|
|
63
|
+
group: string;
|
|
64
|
+
pages: {
|
|
65
|
+
slug: string;
|
|
66
|
+
title: string;
|
|
67
|
+
icon?: string | undefined;
|
|
68
|
+
}[];
|
|
69
|
+
icon?: string | undefined;
|
|
70
|
+
collapsed?: boolean | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
group: string;
|
|
73
|
+
pages: {
|
|
74
|
+
slug: string;
|
|
75
|
+
title: string;
|
|
76
|
+
icon?: string | undefined;
|
|
77
|
+
}[];
|
|
78
|
+
icon?: string | undefined;
|
|
79
|
+
collapsed?: boolean | undefined;
|
|
80
|
+
}>, "many">>;
|
|
81
|
+
theme: z.ZodOptional<z.ZodObject<{
|
|
82
|
+
primaryHue: z.ZodOptional<z.ZodNumber>;
|
|
83
|
+
darkMode: z.ZodOptional<z.ZodBoolean>;
|
|
84
|
+
}, "strip", z.ZodTypeAny, {
|
|
85
|
+
primaryHue?: number | undefined;
|
|
86
|
+
darkMode?: boolean | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
primaryHue?: number | undefined;
|
|
89
|
+
darkMode?: boolean | undefined;
|
|
90
|
+
}>>;
|
|
91
|
+
search: z.ZodOptional<z.ZodObject<{
|
|
92
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
93
|
+
}, "strip", z.ZodTypeAny, {
|
|
94
|
+
enabled?: boolean | undefined;
|
|
95
|
+
}, {
|
|
96
|
+
enabled?: boolean | undefined;
|
|
97
|
+
}>>;
|
|
98
|
+
mdx: z.ZodOptional<z.ZodObject<{
|
|
99
|
+
latex: z.ZodOptional<z.ZodBoolean>;
|
|
100
|
+
}, "strip", z.ZodTypeAny, {
|
|
101
|
+
latex?: boolean | undefined;
|
|
102
|
+
}, {
|
|
103
|
+
latex?: boolean | undefined;
|
|
104
|
+
}>>;
|
|
105
|
+
}, "strip", z.ZodTypeAny, {
|
|
106
|
+
name: string;
|
|
107
|
+
description?: string | undefined;
|
|
108
|
+
contentDir?: string | undefined;
|
|
109
|
+
outputDir?: string | undefined;
|
|
110
|
+
siteUrl?: string | undefined;
|
|
111
|
+
locale?: string | undefined;
|
|
112
|
+
navbar?: {
|
|
113
|
+
logo?: string | undefined;
|
|
114
|
+
github?: string | undefined;
|
|
115
|
+
links?: {
|
|
116
|
+
label: string;
|
|
117
|
+
href: string;
|
|
118
|
+
}[] | undefined;
|
|
119
|
+
} | undefined;
|
|
120
|
+
footer?: {
|
|
121
|
+
text?: string | undefined;
|
|
122
|
+
} | undefined;
|
|
123
|
+
sidebar?: {
|
|
124
|
+
group: string;
|
|
125
|
+
pages: {
|
|
126
|
+
slug: string;
|
|
127
|
+
title: string;
|
|
128
|
+
icon?: string | undefined;
|
|
129
|
+
}[];
|
|
130
|
+
icon?: string | undefined;
|
|
131
|
+
collapsed?: boolean | undefined;
|
|
132
|
+
}[] | undefined;
|
|
133
|
+
theme?: {
|
|
134
|
+
primaryHue?: number | undefined;
|
|
135
|
+
darkMode?: boolean | undefined;
|
|
136
|
+
} | undefined;
|
|
137
|
+
search?: {
|
|
138
|
+
enabled?: boolean | undefined;
|
|
139
|
+
} | undefined;
|
|
140
|
+
mdx?: {
|
|
141
|
+
latex?: boolean | undefined;
|
|
142
|
+
} | undefined;
|
|
143
|
+
}, {
|
|
144
|
+
name: string;
|
|
145
|
+
description?: string | undefined;
|
|
146
|
+
contentDir?: string | undefined;
|
|
147
|
+
outputDir?: string | undefined;
|
|
148
|
+
siteUrl?: string | undefined;
|
|
149
|
+
locale?: string | undefined;
|
|
150
|
+
navbar?: {
|
|
151
|
+
logo?: string | undefined;
|
|
152
|
+
github?: string | undefined;
|
|
153
|
+
links?: {
|
|
154
|
+
label: string;
|
|
155
|
+
href: string;
|
|
156
|
+
}[] | undefined;
|
|
157
|
+
} | undefined;
|
|
158
|
+
footer?: {
|
|
159
|
+
text?: string | undefined;
|
|
160
|
+
} | undefined;
|
|
161
|
+
sidebar?: {
|
|
162
|
+
group: string;
|
|
163
|
+
pages: {
|
|
164
|
+
slug: string;
|
|
165
|
+
title: string;
|
|
166
|
+
icon?: string | undefined;
|
|
167
|
+
}[];
|
|
168
|
+
icon?: string | undefined;
|
|
169
|
+
collapsed?: boolean | undefined;
|
|
170
|
+
}[] | undefined;
|
|
171
|
+
theme?: {
|
|
172
|
+
primaryHue?: number | undefined;
|
|
173
|
+
darkMode?: boolean | undefined;
|
|
174
|
+
} | undefined;
|
|
175
|
+
search?: {
|
|
176
|
+
enabled?: boolean | undefined;
|
|
177
|
+
} | undefined;
|
|
178
|
+
mdx?: {
|
|
179
|
+
latex?: boolean | undefined;
|
|
180
|
+
} | undefined;
|
|
181
|
+
}>;
|
|
182
|
+
type OpenManualConfig = z.infer<typeof OpenManualConfigSchema>;
|
|
183
|
+
|
|
184
|
+
declare function loadConfig(cwd?: string): Promise<OpenManualConfig>;
|
|
185
|
+
|
|
186
|
+
export { type OpenManualConfig, loadConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// src/core/config/loader.ts
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
// src/core/config/schema.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var NavbarSchema = z.object({
|
|
8
|
+
logo: z.string().optional(),
|
|
9
|
+
github: z.string().url().optional(),
|
|
10
|
+
links: z.array(
|
|
11
|
+
z.object({
|
|
12
|
+
label: z.string(),
|
|
13
|
+
href: z.string()
|
|
14
|
+
})
|
|
15
|
+
).optional()
|
|
16
|
+
});
|
|
17
|
+
var FooterSchema = z.object({
|
|
18
|
+
text: z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
var SidebarPageSchema = z.object({
|
|
21
|
+
slug: z.string(),
|
|
22
|
+
title: z.string(),
|
|
23
|
+
icon: z.string().optional()
|
|
24
|
+
});
|
|
25
|
+
var SidebarGroupSchema = z.object({
|
|
26
|
+
group: z.string(),
|
|
27
|
+
icon: z.string().optional(),
|
|
28
|
+
collapsed: z.boolean().optional(),
|
|
29
|
+
pages: z.array(SidebarPageSchema)
|
|
30
|
+
});
|
|
31
|
+
var ThemeSchema = z.object({
|
|
32
|
+
primaryHue: z.number().min(0).max(360).optional(),
|
|
33
|
+
darkMode: z.boolean().optional()
|
|
34
|
+
});
|
|
35
|
+
var SearchSchema = z.object({
|
|
36
|
+
enabled: z.boolean().optional()
|
|
37
|
+
});
|
|
38
|
+
var MdxSchema = z.object({
|
|
39
|
+
latex: z.boolean().optional()
|
|
40
|
+
});
|
|
41
|
+
var OpenManualConfigSchema = z.object({
|
|
42
|
+
name: z.string().min(1),
|
|
43
|
+
description: z.string().optional(),
|
|
44
|
+
contentDir: z.string().optional(),
|
|
45
|
+
outputDir: z.string().optional(),
|
|
46
|
+
siteUrl: z.string().url().optional(),
|
|
47
|
+
locale: z.string().optional(),
|
|
48
|
+
navbar: NavbarSchema.optional(),
|
|
49
|
+
footer: FooterSchema.optional(),
|
|
50
|
+
sidebar: z.array(SidebarGroupSchema).optional(),
|
|
51
|
+
theme: ThemeSchema.optional(),
|
|
52
|
+
search: SearchSchema.optional(),
|
|
53
|
+
mdx: MdxSchema.optional()
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// src/core/config/loader.ts
|
|
57
|
+
var DEFAULT_CONFIG = {
|
|
58
|
+
contentDir: "content",
|
|
59
|
+
outputDir: "dist",
|
|
60
|
+
locale: "zh",
|
|
61
|
+
navbar: {},
|
|
62
|
+
footer: {},
|
|
63
|
+
theme: {
|
|
64
|
+
primaryHue: 220,
|
|
65
|
+
darkMode: true
|
|
66
|
+
},
|
|
67
|
+
search: {
|
|
68
|
+
enabled: true
|
|
69
|
+
},
|
|
70
|
+
mdx: {}
|
|
71
|
+
};
|
|
72
|
+
async function loadConfig(cwd = process.cwd()) {
|
|
73
|
+
const configPath = join(cwd, "openmanual.json");
|
|
74
|
+
let rawJson;
|
|
75
|
+
try {
|
|
76
|
+
rawJson = await readFile(configPath, "utf-8");
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error(`openmanual.json not found in ${cwd}. Please create one.`);
|
|
79
|
+
}
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(rawJson);
|
|
83
|
+
} catch {
|
|
84
|
+
throw new Error("openmanual.json is not valid JSON.");
|
|
85
|
+
}
|
|
86
|
+
const result = OpenManualConfigSchema.safeParse(parsed);
|
|
87
|
+
if (!result.success) {
|
|
88
|
+
const errors = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
89
|
+
throw new Error(`openmanual.json validation failed:
|
|
90
|
+
${errors}`);
|
|
91
|
+
}
|
|
92
|
+
return mergeDefaults(result.data);
|
|
93
|
+
}
|
|
94
|
+
function mergeDefaults(config) {
|
|
95
|
+
return {
|
|
96
|
+
...config,
|
|
97
|
+
contentDir: config.contentDir ?? DEFAULT_CONFIG.contentDir ?? "content",
|
|
98
|
+
outputDir: config.outputDir ?? DEFAULT_CONFIG.outputDir ?? "dist",
|
|
99
|
+
locale: config.locale ?? DEFAULT_CONFIG.locale ?? "zh",
|
|
100
|
+
navbar: {
|
|
101
|
+
...DEFAULT_CONFIG.navbar,
|
|
102
|
+
...config.navbar,
|
|
103
|
+
logo: config.navbar?.logo ?? config.name
|
|
104
|
+
},
|
|
105
|
+
footer: {
|
|
106
|
+
...DEFAULT_CONFIG.footer,
|
|
107
|
+
...config.footer,
|
|
108
|
+
text: config.footer?.text ?? `MIT ${(/* @__PURE__ */ new Date()).getFullYear()} \xA9 ${config.name}.`
|
|
109
|
+
},
|
|
110
|
+
theme: {
|
|
111
|
+
...DEFAULT_CONFIG.theme,
|
|
112
|
+
...config.theme
|
|
113
|
+
},
|
|
114
|
+
search: {
|
|
115
|
+
...DEFAULT_CONFIG.search,
|
|
116
|
+
...config.search
|
|
117
|
+
},
|
|
118
|
+
mdx: {
|
|
119
|
+
...DEFAULT_CONFIG.mdx,
|
|
120
|
+
...config.mdx
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
loadConfig
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config/loader.ts","../src/core/config/schema.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { type OpenManualConfig, OpenManualConfigSchema } from './schema.js';\n\nconst DEFAULT_CONFIG: Partial<OpenManualConfig> = {\n contentDir: 'content',\n outputDir: 'dist',\n locale: 'zh',\n navbar: {},\n footer: {},\n theme: {\n primaryHue: 220,\n darkMode: true,\n },\n search: {\n enabled: true,\n },\n mdx: {},\n};\n\nexport async function loadConfig(cwd: string = process.cwd()): Promise<OpenManualConfig> {\n const configPath = join(cwd, 'openmanual.json');\n\n let rawJson: string;\n try {\n rawJson = await readFile(configPath, 'utf-8');\n } catch {\n throw new Error(`openmanual.json not found in ${cwd}. Please create one.`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawJson);\n } catch {\n throw new Error('openmanual.json is not valid JSON.');\n }\n\n const result = OpenManualConfigSchema.safeParse(parsed);\n if (!result.success) {\n const errors = result.error.issues\n .map((i) => ` - ${i.path.join('.')}: ${i.message}`)\n .join('\\n');\n throw new Error(`openmanual.json validation failed:\\n${errors}`);\n }\n\n return mergeDefaults(result.data);\n}\n\nfunction mergeDefaults(config: OpenManualConfig): OpenManualConfig {\n return {\n ...config,\n contentDir: config.contentDir ?? DEFAULT_CONFIG.contentDir ?? 'content',\n outputDir: config.outputDir ?? DEFAULT_CONFIG.outputDir ?? 'dist',\n locale: config.locale ?? DEFAULT_CONFIG.locale ?? 'zh',\n navbar: {\n ...DEFAULT_CONFIG.navbar,\n ...config.navbar,\n logo: config.navbar?.logo ?? config.name,\n },\n footer: {\n ...DEFAULT_CONFIG.footer,\n ...config.footer,\n text: config.footer?.text ?? `MIT ${new Date().getFullYear()} © ${config.name}.`,\n },\n theme: {\n ...DEFAULT_CONFIG.theme,\n ...config.theme,\n },\n search: {\n ...DEFAULT_CONFIG.search,\n ...config.search,\n },\n mdx: {\n ...DEFAULT_CONFIG.mdx,\n ...config.mdx,\n },\n };\n}\n","import { z } from 'zod';\n\nexport const NavbarSchema = z.object({\n logo: z.string().optional(),\n github: z.string().url().optional(),\n links: z\n .array(\n z.object({\n label: z.string(),\n href: z.string(),\n })\n )\n .optional(),\n});\n\nexport const FooterSchema = z.object({\n text: z.string().optional(),\n});\n\nexport const SidebarPageSchema = z.object({\n slug: z.string(),\n title: z.string(),\n icon: z.string().optional(),\n});\n\nexport const SidebarGroupSchema = z.object({\n group: z.string(),\n icon: z.string().optional(),\n collapsed: z.boolean().optional(),\n pages: z.array(SidebarPageSchema),\n});\n\nexport const ThemeSchema = z.object({\n primaryHue: z.number().min(0).max(360).optional(),\n darkMode: z.boolean().optional(),\n});\n\nexport const SearchSchema = z.object({\n enabled: z.boolean().optional(),\n});\n\nexport const MdxSchema = z.object({\n latex: z.boolean().optional(),\n});\n\nexport const OpenManualConfigSchema = z.object({\n name: z.string().min(1),\n description: z.string().optional(),\n contentDir: z.string().optional(),\n outputDir: z.string().optional(),\n siteUrl: z.string().url().optional(),\n locale: z.string().optional(),\n navbar: NavbarSchema.optional(),\n footer: FooterSchema.optional(),\n sidebar: z.array(SidebarGroupSchema).optional(),\n theme: ThemeSchema.optional(),\n search: SearchSchema.optional(),\n mdx: MdxSchema.optional(),\n});\n\nexport type OpenManualConfig = z.infer<typeof OpenManualConfigSchema>;\nexport type NavbarConfig = z.infer<typeof NavbarSchema>;\nexport type FooterConfig = z.infer<typeof FooterSchema>;\nexport type SidebarGroup = z.infer<typeof SidebarGroupSchema>;\nexport type SidebarPage = z.infer<typeof SidebarPageSchema>;\nexport type ThemeConfig = z.infer<typeof ThemeSchema>;\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openmanual",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI 友好的开源文档系统框架",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"openmanual": "./dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"templates"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.0.0",
|
|
23
|
+
"pnpm": ">=10.0.0"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"documentation",
|
|
27
|
+
"mdx",
|
|
28
|
+
"fumadocs",
|
|
29
|
+
"nextjs",
|
|
30
|
+
"openmanual"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/shenjingnan/openmanual.git"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"commander": "^14.0.3",
|
|
39
|
+
"fast-glob": "^3.3.3",
|
|
40
|
+
"fumadocs-core": "^16.7.7",
|
|
41
|
+
"fumadocs-mdx": "^14.2.11",
|
|
42
|
+
"fumadocs-ui": "^16.7.7",
|
|
43
|
+
"gray-matter": "^4.0.3",
|
|
44
|
+
"next": "^16.2.1",
|
|
45
|
+
"react": "^19.1.0",
|
|
46
|
+
"react-dom": "^19.1.0",
|
|
47
|
+
"zod": "^3.25.28"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@biomejs/biome": "^2.4.9",
|
|
51
|
+
"@release-it/conventional-changelog": "^9.0.4",
|
|
52
|
+
"@types/node": "^25.5.0",
|
|
53
|
+
"@types/react": "^19.1.6",
|
|
54
|
+
"@types/react-dom": "^19.1.6",
|
|
55
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
56
|
+
"cspell": "^9.7.0",
|
|
57
|
+
"husky": "^9.1.7",
|
|
58
|
+
"lint-staged": "^16.4.0",
|
|
59
|
+
"release-it": "^17.10.0",
|
|
60
|
+
"tsup": "^8.3.5",
|
|
61
|
+
"tsx": "^4.19.2",
|
|
62
|
+
"typescript": "^6.0.2",
|
|
63
|
+
"vitest": "^2.1.8"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "tsup",
|
|
67
|
+
"dev": "tsx watch src/cli/bin.ts",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"test:watch": "vitest",
|
|
70
|
+
"test:coverage": "vitest run --coverage",
|
|
71
|
+
"lint": "biome check .",
|
|
72
|
+
"lint:fix": "biome check --write .",
|
|
73
|
+
"format": "biome format --write .",
|
|
74
|
+
"typecheck": "tsc --noEmit",
|
|
75
|
+
"check": "pnpm run typecheck && pnpm run lint",
|
|
76
|
+
"check:fix": "pnpm run typecheck && pnpm run lint:fix && pnpm run format",
|
|
77
|
+
"spellcheck": "cspell \"**/*.ts\" \"**/*.md\"",
|
|
78
|
+
"release": "release-it"
|
|
79
|
+
}
|
|
80
|
+
}
|