@tobi-or-not/docpress 0.9.0 → 0.10.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/README.md +2 -0
- package/dist/cli.js +297 -256
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../package.json","../src/utils/const.ts","../src/utils/regex.ts","../src/utils/functions.ts","../src/utils/logger.ts","../src/schemas/global.ts","../src/utils/commands.ts","../src/lib/git.ts","../src/lib/gitlab.ts","../src/lib/fetch.ts","../src/commands/global.ts","../src/commands/fetch.ts","../src/commands/build.ts","../src/utils/templates.ts","../src/lib/vitepress.ts","../src/lib/prepare.ts","../src/commands/prepare.ts","../src/cli.ts"],"sourcesContent":["{\n \"name\": \"@tobi-or-not/docpress\",\n \"type\": \"module\",\n \"version\": \"0.9.0\",\n \"packageManager\": \"bun@1.3.14\",\n \"homepage\": \"https://this-is-tobi.com/docpress/introduction\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/this-is-tobi/docpress.git\"\n },\n \"bin\": {\n \"docpress\": \"bin/docpress.js\"\n },\n \"files\": [\n \"bin\",\n \"dist\"\n ],\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"scripts\": {\n \"build\": \"bun run build:clean && bun run build:types && bun run build:vite\",\n \"build:clean\": \"rimraf ./dist ./types ./tsconfig.tsbuildinfo\",\n \"build:docker\": \"docker build --tag tobi-or-not/docpress --target prod .\",\n \"build:types\": \"tsc\",\n \"build:vite\": \"vite build\",\n \"dev\": \"bun ./dev/docpress.ts\",\n \"dev:clean\": \"rimraf ./docpress && bun run dev\",\n \"format\": \"eslint . --fix\",\n \"lint\": \"eslint .\",\n \"prepare\": \"husky\",\n \"start\": \"./bin/docpress.js\",\n \"start:docker\": \"docker run --name docpress --rm -v $(pwd)/docpress:/app/docpress:rw tobi-or-not/docpress\",\n \"stop:docker\": \"docker rm --force docpress\",\n \"test\": \"vitest run\",\n \"test:cov\": \"vitest run --coverage\",\n \"vp:build\": \"vitepress build ./docpress\",\n \"vp:build:docker\": \"docker build --tag tobi-or-not/docs --target prod .\",\n \"vp:dev\": \"vitepress dev ./docpress --port 8080\",\n \"vp:dev:docker\": \"docker run --publish 8080:8080 --name docpress-vp --rm tobi-or-not/docs\",\n \"vp:preview\": \"vitepress preview ./docpress --port 8080\"\n },\n \"dependencies\": {\n \"@octokit/rest\": \"^22.0.1\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^15.0.0\",\n \"rimraf\": \"^6.1.3\",\n \"simple-git\": \"^3.36.0\",\n \"vitepress\": \"^1.6.4\",\n \"vitepress-plugin-mermaid\": \"^2.0.17\",\n \"yaml\": \"^2.9.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@antfu/eslint-config\": \"^9.1.0\",\n \"@commitlint/cli\": \"^21.2.0\",\n \"@commitlint/config-conventional\": \"^21.2.0\",\n \"@octokit/types\": \"^16.0.0\",\n \"@types/node\": \"^26.1.0\",\n \"@vitejs/plugin-vue\": \"^6.0.7\",\n \"@vitest/coverage-v8\": \"^4.1.9\",\n \"eslint\": \"^10.6.0\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^17.0.8\",\n \"typescript\": \"^6.0.3\",\n \"vite\": \"^8.1.3\",\n \"vitest\": \"^4.1.9\",\n \"vue\": \"^3.5.39\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\",\n \"tag\": \"latest\"\n }\n}\n","import { resolve } from 'node:path'\n\n/**\n * Main directory for DocPress files\n */\nexport const DOCPRESS_DIR = resolve(process.cwd(), 'docpress')\n\n/**\n * Directory for documentation files\n */\nexport const DOCS_DIR = resolve(process.cwd(), 'docpress/docs')\n\n/**\n * Path to the main index file\n */\nexport const INDEX_FILE = resolve(process.cwd(), 'docpress/docs/index.md')\n\n/**\n * Path to the forks documentation file\n */\nexport const FORKS_FILE = resolve(process.cwd(), 'docpress/docs/forks.md')\n\n/**\n * Path to VitePress configuration file\n */\nexport const VITEPRESS_CONFIG = resolve(process.cwd(), 'docpress/.vitepress/config.ts')\n\n/**\n * Directory for VitePress theme\n */\nexport const VITEPRESS_THEME = resolve(process.cwd(), 'docpress/.vitepress/theme')\n\n/**\n * Directory for user custom theme files\n */\nexport const VITEPRESS_USER_THEME = resolve(process.cwd(), 'docpress/.vitepress/theme/extras')\n\n/**\n * Path to template theme files\n */\n// eslint-disable-next-line dot-notation\nexport const TEMPLATE_THEME = process.env['NODE_ENV'] === 'development'\n ? resolve(import.meta.dirname, '../../public/templates/theme')\n : resolve(import.meta.dirname, './templates/theme')\n","export const relativePathRegex = /\\[([^\\]]+)\\]\\(\\.\\.\\/([^)]+)\\)/g\nexport const readmePathRegex = /\\[([^\\]]+)\\]\\((?!\\.?\\/docs\\/|docs\\/|http|#)(\\.\\/)?([^/][^)]+)\\)/g\nexport const readmeDocsPathRegex = /\\[([^\\]]+)\\]\\((\\.?\\/docs\\/|docs\\/)([^)]*)\\)/g\nexport const removeIdxRegex = /^\\d{2}-/\n","import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'node:path'\nimport { rimrafSync } from 'rimraf'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport type { EnhancedRepository } from '../lib/fetch.js'\nimport type { getInfos } from '../lib/git.js'\nimport { DOCPRESS_DIR } from './const.js'\nimport { readmeDocsPathRegex, readmePathRegex, relativePathRegex, removeIdxRegex } from './regex.js'\n\n/**\n * Checks the HTTP status code of a URL\n * Redirects are not followed: some providers (e.g. GitLab) redirect to a\n * sign-in page instead of returning 404 for missing resources\n *\n * @param url - URL to check\n * @returns HTTP status code (500 for network errors)\n */\nexport async function checkHttpStatus(url: string): Promise<number> {\n try {\n const response = await fetch(url, { method: 'HEAD', redirect: 'manual' })\n return response.status\n } catch (_error) {\n return 500\n }\n}\n\n/**\n * Options for prettifying strings\n */\ninterface PrettifyOpts {\n mode?: 'capitalize' | 'uppercase' | 'lowercase'\n replaceDash?: boolean\n removeIdx?: boolean\n removeDot?: boolean\n removeExt?: boolean\n}\n\n/**\n * Formats a string based on specified options\n *\n * @param s - Input string to format\n * @param opts - Formatting options\n * @returns Formatted string\n */\nexport function prettify(s: string, opts: PrettifyOpts) {\n let u: string = ''\n\n if (opts?.removeDot) {\n if (s.startsWith('.')) {\n u = s.slice(1)\n } else {\n u = s\n }\n // Replace all remaining dots with dashes to ensure consistency\n u = u.replaceAll('.', '-')\n }\n\n if (opts?.removeIdx) {\n u = (u || s).replace(removeIdxRegex, '')\n }\n\n if (opts?.removeExt) {\n u = (u || s).split('.')[0]\n }\n\n if (opts?.replaceDash) {\n u = (u || s).replaceAll('-', ' ')\n }\n\n if (opts?.mode === 'capitalize') {\n u = (u || s).slice(0, 1).toUpperCase() + (u || s).slice(1).toLowerCase()\n } else if (opts?.mode === 'lowercase') {\n u = (u || s).toLowerCase()\n } else if (opts?.mode === 'uppercase') {\n u = (u || s).toUpperCase()\n }\n\n return u || s\n}\n\n/**\n * Creates a directory, optionally cleaning it first\n *\n * @param directory - Path to the directory to create\n * @param options - Options object\n * @param options.clean - Whether to clean the directory before creating it\n */\nexport function createDir(directory: string, { clean }: { clean?: boolean } = { clean: false }) {\n try {\n if (clean && existsSync(directory)) {\n rimrafSync(`${directory}/*`, { glob: true })\n }\n if (!existsSync(directory)) {\n mkdirSync(directory, { recursive: true })\n }\n } catch (err) {\n console.error(err)\n }\n}\n\n/**\n * Checks if a path is a directory\n *\n * @param path - Path to check\n * @returns True if path is a directory, false otherwise\n */\nexport function isDir(path: string) {\n try {\n return statSync(path).isDirectory()\n } catch (_error) {\n return false\n }\n}\n\n/**\n * Checks if a path is a file\n *\n * @param path - Path to check\n * @returns True if path is a file, false otherwise\n */\nexport function isFile(path: string) {\n try {\n return statSync(path).isFile()\n } catch (_error) {\n return false\n }\n}\n\n/**\n * Extracts a list of file paths from directories and files\n *\n * @param paths - Path or array of paths to extract files from\n * @returns Array of file paths\n */\nexport function extractFiles(paths: string[] | string): string[] {\n return (Array.isArray(paths) ? paths : [paths]).flatMap((path) => {\n if (isFile(path)) {\n return [path]\n }\n if (isDir(path)) {\n return readdirSync(path).sort().flatMap(file => extractFiles(join(path, file)))\n }\n return []\n })\n}\n\n/**\n * Gets all markdown files from specified paths\n *\n * @param path - Array of paths to search for markdown files\n * @returns Array of markdown file paths\n */\nexport function getMdFiles(path: string[]) {\n return extractFiles(path).filter(file => basename(file).endsWith('.md'))\n}\n\n/**\n * Formats an array of strings into a readable comma-separated list\n *\n * @param arr - Array of strings to format\n * @returns Formatted string (e.g., \"a\", \"b\" or \"c\")\n */\nexport function prettifyEnum(arr: readonly string[]) {\n return arr.reduce((acc, cur, idx, arr) => {\n if (!idx) {\n return `\"${cur}\"`\n } else if (idx === arr.length - 1) {\n return `${acc} or \"${cur}\"`\n } else {\n return `${acc}, \"${cur}\"`\n }\n }, '')\n}\n\n/**\n * Gets user information from cached JSON file\n *\n * @param username - GitHub username\n * @returns User information object\n */\nexport function getUserInfos(username: GlobalOpts['usernames'][number]) {\n return JSON.parse(readFileSync(`${DOCPRESS_DIR}/user-${username}.json`).toString()) as Awaited<ReturnType<typeof getInfos>>['user']\n}\n\n/**\n * Gets repository information from cached JSON file\n *\n * @param username - GitHub username\n * @returns Array of enhanced repository objects\n */\nexport function getUserRepos(username: GlobalOpts['usernames'][number]) {\n return JSON.parse(readFileSync(`${DOCPRESS_DIR}/repos-${username}.json`).toString()) as EnhancedRepository[]\n}\n\n/**\n * Deep merges multiple objects\n *\n * @param objects - Objects to merge\n * @returns Merged object\n */\nexport function deepMerge<T extends Record<string, any> | null>(...objects: T[]): T {\n return objects.reduce((acc, obj) => {\n if (obj === null) {\n return acc\n }\n\n Object.keys(obj).forEach((key) => {\n const accValue = acc ? acc[key] : null\n const objValue = obj[key]\n\n if (isObject(accValue) && isObject(objValue)) {\n (acc as Record<string, any>)[key] = deepMerge(accValue, objValue)\n } else {\n (acc as Record<string, any>)[key] = objValue\n }\n })\n return acc\n }, {} as T)\n}\n\n/**\n * Checks if a value is an object (not an array or null)\n *\n * @param val - Value to check\n * @returns True if value is an object, false otherwise\n */\nexport function isObject(val: any): val is object {\n return val && typeof val === 'object' && !Array.isArray(val)\n}\n\n/**\n * Loads and parses a JSON configuration file\n *\n * @param configPath - Path to the configuration file\n * @returns Parsed configuration object, or an empty object when no path is given\n * @throws Error if the file cannot be read or contains invalid JSON\n */\nexport function loadConfigFile(configPath?: string) {\n if (!configPath) {\n return {}\n }\n const fullPath = resolve(process.cwd(), configPath)\n let fileContents: string\n try {\n fileContents = readFileSync(fullPath, 'utf8')\n } catch (_error) {\n throw new Error(`Cannot read config file '${configPath}'.`)\n }\n try {\n return JSON.parse(fileContents)\n } catch (_error) {\n throw new Error(`Invalid JSON in config file '${configPath}'.`)\n }\n}\n\n/**\n * Splits a comma-separated string into an array of strings\n *\n * @param s - Comma-separated string\n * @returns Array of strings\n */\nexport function splitByComma(s: string) {\n return s.split(',')\n}\n\n/**\n * Replaces relative paths in markdown links with absolute URLs\n *\n * @param file - Path to the markdown file to process\n * @param url - Base URL to use for absolute links\n */\nexport function replaceRelativePath(file: string, url: string) {\n const fileContent = readFileSync(file, 'utf8')\n const updatedContent = fileContent.replace(relativePathRegex, (_match, p1, p2) => {\n return `[${p1}](${url}/${p2})`\n })\n writeFileSync(file, updatedContent, 'utf8')\n}\n\n/**\n * Processes README files to fix various link formats\n *\n * @param file - Path to the README file to process\n * @param url - Base URL to use for absolute links\n */\nexport function replaceReadmePath(file: string, url: string) {\n const readmeContent = readFileSync(file, 'utf8')\n const updatedContent = readmeContent\n .replace(readmePathRegex, (_match, p1, _p2, p3) => {\n return `[${p1}](${url}/${p3})`\n })\n .replace(readmeDocsPathRegex, (_match, p1, _p2, p3) => {\n return `[${p1}](${p3})`\n })\n writeFileSync(file, updatedContent, 'utf8')\n}\n","/* eslint-disable dot-notation */\nimport type { ColorName } from 'chalk'\nimport chalk from 'chalk'\n\n/**\n * Log message types\n */\ntype LogType = keyof Pick<Console, 'info' | 'warn' | 'error' | 'debug' | 'trace'> | 'success'\n\n/**\n * Mapping of log types to colors and levels\n */\ntype ColorMap = {\n [K in LogType]: {\n color: ColorName\n level: number\n }\n}\n\n/**\n * Gets the current log level from environment variables\n *\n * @returns Log level number (default: 30)\n */\nfunction getLogLevel() {\n const level = Number(process.env['LOG_LEVEL'])\n return Number.isNaN(level) ? 30 : level\n}\n\n/**\n * Color mapping configuration for different log types\n */\nconst colorMap: ColorMap = {\n error: { color: 'red', level: 10 },\n warn: { color: 'yellow', level: 20 },\n info: { color: 'white', level: 30 },\n success: { color: 'green', level: 30 },\n trace: { color: 'white', level: 40 },\n debug: { color: 'blue', level: 50 },\n}\n\n/**\n * Logs a message with color formatting based on type and level\n *\n * @param msg - Message to log\n * @param type - Type of log message (info, warn, error, debug, trace, success)\n * @param color - Optional specific color to use instead of the default for the type\n */\nexport function log(msg: string, type: LogType = 'info', color?: ColorName) {\n const computedMsg = color ? chalk[color](msg) : chalk[colorMap[type].color](msg)\n const computedType = type === 'success' ? 'info' : type\n\n if (getLogLevel() >= colorMap[type].level) {\n console[computedType](computedMsg)\n }\n}\n","import { z } from 'zod'\nimport { loadConfigFile, prettifyEnum, splitByComma } from '../utils/functions.js'\nimport { log } from '../utils/logger.js'\n\n/**\n * List of supported Git providers\n */\nconst providers = ['github', 'gitlab'] as const\n\n/**\n * Schema for the DocPress configuration file\n * Defines the structure and validation rules for the configuration\n */\nexport const configSchema = z.object({\n // Global\n usernames: z.string()\n .array()\n .describe('List of comma separated Git provider usernames used to collect data.'),\n // Fetch\n branch: z.string()\n .default('main')\n .describe('Branch used to collect Git provider data.'),\n gitProvider: z.enum(providers)\n .default('github')\n .describe(`Git provider used to retrieve data. Values should be ${prettifyEnum(providers)}.`),\n reposFilter: z.string()\n .array()\n .describe('List of comma separated repositories to retrieve from Git provider. Default to all user\\'s public repositories.'),\n // Prepare\n extraHeaderPages: z.string()\n .array()\n .describe('List of comma separated additional files or directories to process Vitepress header pages.'),\n extraPublicContent: z.string()\n .array()\n .describe('List of comma separated additional files or directories to process Vitepress public folder.'),\n extraTheme: z.string()\n .array()\n .describe('List of comma separated additional files or directories to use as Vitepress theme.'),\n forks: z.boolean()\n .default(false)\n .describe('Whether or not to create the dedicated fork page that aggregate external contributions.'),\n vitepressConfig: z.any()\n .optional()\n .describe('Path to the vitepress configuration file.'),\n websiteTitle: z.string()\n .describe('Website title.'),\n websiteTagline: z.string()\n .describe('Website tagline.'),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\n/**\n * CLI schema with transformations applied to handle string-to-array conversions\n * Fields with config defaults are redefined without them, so that values coming\n * from a config file are not overridden by schema defaults\n */\nexport const cliSchema = configSchema\n .partial()\n .extend({\n branch: z.string()\n .optional()\n .describe(configSchema.shape.branch.description || ''),\n gitProvider: z.enum(providers)\n .optional()\n .describe(configSchema.shape.gitProvider.description || ''),\n forks: z.boolean()\n .optional()\n .describe(configSchema.shape.forks.description || ''),\n config: z.string()\n .optional()\n .describe('Path to the docpress configuration file.'),\n token: z.string()\n .optional()\n .describe('Git provider token used to collect data.'),\n usernames: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.usernames.description || ''),\n reposFilter: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.reposFilter.description || ''),\n extraHeaderPages: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraHeaderPages.description || ''),\n extraPublicContent: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraPublicContent.description || ''),\n extraTheme: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraTheme.description || ''),\n vitepressConfig: z.string()\n .optional()\n .describe(configSchema.shape.vitepressConfig.description || ''),\n })\n\nexport type Cli = z.infer<typeof cliSchema>\n\n/**\n * Prepares configuration data by converting string values to arrays when needed\n *\n * @param configData - Raw configuration data to process\n * @returns Processed configuration data with proper array types\n */\nfunction prepareConfigData(configData: any) {\n if (!configData) return {}\n\n const arrayKeys = ['usernames', 'reposFilter', 'extraHeaderPages', 'extraPublicContent', 'extraTheme'] as const\n for (const key of arrayKeys) {\n if (configData[key] && typeof configData[key] === 'string') {\n configData[key] = [configData[key]]\n }\n }\n\n return configData\n}\n\n/**\n * Validates configuration file data against the config schema\n *\n * @param configData - Prepared configuration data to validate\n * @returns The validated configuration data\n * @throws Error if the configuration data is invalid\n */\nfunction validateConfigData(configData: any) {\n const result = configSchema.partial().safeParse(configData)\n if (!result.success) {\n throw new Error(z.prettifyError(result.error))\n }\n return result.data\n}\n\n/**\n * Validates the final merged configuration to ensure required fields are present\n *\n * @param mergedConfig - The merged configuration to validate\n * @returns The validated configuration if it passes validation\n * @throws Error if required fields are missing\n */\nfunction validateFinalConfig(mergedConfig: any) {\n if (!mergedConfig.usernames?.length) {\n throw new Error('The usernames field is required')\n }\n\n return mergedConfig\n}\n\n/**\n * Schema for global options that combines CLI arguments and configuration files\n * Merges config sources with precedence: CLI options > config file > defaults\n */\nexport const globalOptsSchema = cliSchema\n .partial()\n .transform((data) => {\n try {\n const { config, vitepressConfig, token, ...rest } = data\n\n log(`Debug: Schema transform input: ${JSON.stringify(data)}`, 'debug')\n\n // Load and validate configuration from file\n const configData = validateConfigData(prepareConfigData(loadConfigFile(config)))\n\n // Create final config\n const mergedConfig = {\n branch: 'main',\n gitProvider: 'github',\n forks: false,\n ...configData,\n ...rest,\n ...(vitepressConfig\n ? {\n vitepressConfig: {\n ...(configData.vitepressConfig || {}),\n ...(loadConfigFile(vitepressConfig) || {}),\n },\n }\n : {}),\n }\n\n log(`Debug: Final merged config: ${JSON.stringify(mergedConfig)}`, 'debug')\n\n return validateFinalConfig({ ...mergedConfig, token })\n } catch (error) {\n log(` An error occurred while checking configuration.`, 'error')\n if (error instanceof Error) {\n log(` ${error.message}`, 'error')\n } else {\n log(` ${JSON.stringify(error, null, 2)}`, 'error')\n }\n process.exit(1)\n }\n })\n\nexport type GlobalOpts = Required<Pick<z.infer<typeof globalOptsSchema>, 'branch' | 'gitProvider'>>\n & Omit<z.infer<typeof globalOptsSchema>, 'branch' | 'gitProvider'>\n","import type { Command, Option } from 'commander'\nimport { z } from 'zod'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport { globalOptsSchema } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { log } from './logger.js'\n\n/**\n * Type definition for command names\n */\ntype Cmd = 'fetch' | 'prepare' | 'global'\n\n/**\n * Interface mapping command names to their option types\n */\ninterface Options {\n fetch: FetchOpts\n prepare: PrepareOpts\n global: GlobalOpts\n}\n\n/**\n * Parses and validates command options\n * Options are merged with precedence: CLI options > config file > defaults\n *\n * @param cmd - The command name ('fetch', 'prepare' or 'global')\n * @param opts - Raw options from the command line\n * @returns Validated and processed options for the specified command\n */\nexport function parseOptions<T extends Cmd>(cmd: T, opts: Record<string, unknown>): Options[T] {\n log(`Initializing Docpress...`, 'info', 'blue')\n log(`\\n\\n-> Checking for required environment settings and configurations.`, 'info')\n log(` Debug info - opts: ${JSON.stringify(opts)}`, 'debug')\n log(` Debug info - cmd: ${cmd}`, 'debug')\n\n const res = globalOptsSchema.safeParse(opts)\n if (!res.success) {\n log(` An error occurred while checking configuration.\\n ${z.prettifyError(res.error)}`, 'error')\n process.exit(1)\n }\n log(' Setup complete! Ready to process your documentation.', 'info')\n return res.data as Options[T]\n}\n\n/**\n * Extracts options that were explicitly provided by the user, skipping Commander defaults\n * This lets config file values take precedence over CLI defaults\n *\n * @param cmd - The Commander Command instance\n * @param opts - Raw options from the command line\n * @returns Options object containing only user-provided values\n */\nexport function explicitOptions(cmd: Command, opts: Record<string, unknown>) {\n return Object.fromEntries(\n Object.entries(opts).filter(([key]) => cmd.getOptionValueSource(key) !== 'default'),\n )\n}\n\n/**\n * Adds option definitions to a Command instance\n *\n * @param cmd - The Commander Command instance\n * @param opts - Array of option definitions to add\n * @returns The Command instance with options added\n */\nexport function addOptions(cmd: Command, opts: Option[]) {\n for (const opt of opts) {\n cmd.addOption(opt)\n }\n return cmd\n}\n","import { appendFileSync, cpSync, rmSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { Octokit } from '@octokit/rest'\nimport { simpleGit } from 'simple-git'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { createDir } from '../utils/functions.js'\nimport { log } from '../utils/logger.js'\nimport type { EnhancedRepository } from './fetch.js'\n\n/**\n * Octokit logger that stays quiet on 404s, which are handled explicitly\n */\nconst quietOctokitLog = {\n debug: () => {},\n info: () => {},\n warn: (message: string) => {\n if (!message.includes('404')) console.warn(message)\n },\n error: (message: string) => {\n if (!message.includes('404')) console.error(message)\n },\n}\n\n/**\n * Fetches user and repository information from GitHub\n *\n * @param options - Options for retrieving GitHub data\n * @param options.username - GitHub username\n * @param options.token - GitHub API token\n * @param options.branch - Branch to use for documentation\n * @returns Object containing user information, repositories, and branch\n */\nexport async function getInfos({ username, token, branch }: Pick<FetchOpts, 'branch'> & Pick<GlobalOpts, 'token'> & { username: GlobalOpts['usernames'][number] }) {\n log(` Get infos for username '${username}'.`, 'info')\n const octokit = new Octokit({ auth: token, log: quietOctokitLog })\n log(` Get user infos.`, 'debug')\n const { data: user } = await octokit.rest.users.getByUsername({ username })\n .catch((error) => {\n throw error.status === 404 ? new Error(`No GitHub user found for '${username}'.`) : error\n })\n log(` Get repositories infos.`, 'debug')\n const repos = await octokit.paginate(octokit.rest.repos.listForUser, { username, sort: 'full_name', per_page: 100 })\n\n return { user, repos, branch }\n}\n\n/**\n * Gets contributors for a repository\n *\n * @param options - Options for retrieving contributors\n * @param options.repository - Repository information\n * @param options.token - GitHub API token\n * @returns Object with source repository and contributors list\n */\nexport async function getContributors({\n repository,\n token,\n}: {\n repository: EnhancedRepository\n token: GlobalOpts['token']\n}) {\n log(` Get contributors infos for repository '${repository.name}'.`, 'info')\n const octokit = new Octokit({ auth: token, log: quietOctokitLog })\n const { data: repo } = await octokit.rest.repos.get({\n owner: repository.owner.login,\n repo: repository.name,\n })\n if (!repo.source?.owner?.login) {\n return { source: repo.source, contributors: [] }\n }\n const contributors: Array<any> = []\n try {\n for await (const { data } of octokit.paginate.iterator(\n octokit.rest.repos.listContributors,\n {\n owner: repo.source.owner.login,\n repo: repo.parent?.name ?? repo.name,\n per_page: 100,\n },\n )) {\n contributors.push(...data)\n }\n } catch (error) {\n log(\n ` Failed to get contributors infos for repository '${repository.name}'. Error : ${error.message}`,\n 'warn',\n )\n return { source: repo.source, contributors: [] }\n }\n\n return { source: repo.source, contributors }\n}\n\n/**\n * Clones a repository with sparse checkout\n *\n * @param name - Repository name\n * @param url - Repository URL\n * @param projectDir - Directory to clone into\n * @param branch - Branch to clone\n * @param includes - Patterns to include in sparse checkout\n */\nexport async function cloneRepo(name: string, url: string, projectDir: string, branch: string, includes: string[]) {\n createDir(projectDir, { clean: true })\n\n try {\n // Background maintenance is disabled so no git process keeps writing into\n // .git (e.g. commit-graph files) while it is being removed below\n const git = simpleGit({ baseDir: projectDir, config: ['maintenance.auto=false', 'gc.auto=0', 'fetch.writeCommitGraph=false'] })\n await git.init()\n .addConfig('core.sparseCheckout', 'true', true, 'local')\n .addRemote('origin', url)\n\n for (const item of includes) {\n log(` Add '${item}' to '${name}' sparse-checkout file.`, 'debug')\n appendFileSync(resolve(projectDir, '.git/info/sparse-checkout'), `${item}\\n`, 'utf8')\n }\n\n log(` Clone repository '${name}'.`, 'info')\n await git.pull('origin', branch)\n\n if (includes.some(item => item.includes('docs'))) {\n cpSync(resolve(projectDir, 'docs'), projectDir, { recursive: true })\n rmSync(resolve(projectDir, 'docs'), { recursive: true })\n }\n rmSync(resolve(projectDir, '.git'), { recursive: true })\n } catch (error) {\n log(` Error when cloning repository: ${error}.`, 'error')\n }\n}\n","import type { GlobalOpts } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { log } from '../utils/logger.js'\nimport type { getInfos as getGithubInfos } from './git.js'\n\n/**\n * Base URL of the GitLab REST API\n */\nexport const GITLAB_API_URL = 'https://gitlab.com/api/v4'\n\ntype User = Awaited<ReturnType<typeof getGithubInfos>>['user']\ntype Repository = Awaited<ReturnType<typeof getGithubInfos>>['repos'][number]\n\n/**\n * Performs a GET request against the GitLab API\n *\n * @param path - API path starting with '/'\n * @param token - Optional GitLab token\n * @returns Object containing the parsed JSON body and the response headers\n * @throws Error if the request fails\n */\nasync function gitlabGet(path: string, token?: GlobalOpts['token']) {\n const response = await fetch(`${GITLAB_API_URL}${path}`, {\n headers: token ? { 'PRIVATE-TOKEN': token } : {},\n })\n if (!response.ok) {\n throw new Error(`GitLab API request failed for '${path}' (status: ${response.status}).`)\n }\n return { data: await response.json(), headers: response.headers }\n}\n\n/**\n * Fetches all pages of a GitLab API collection\n *\n * @param path - API path starting with '/' (query params allowed)\n * @param token - Optional GitLab token\n * @returns Array containing all items from all pages\n */\nasync function gitlabGetAll(path: string, token?: GlobalOpts['token']) {\n const separator = path.includes('?') ? '&' : '?'\n const items: any[] = []\n let page: string | null = '1'\n\n while (page) {\n const { data, headers } = await gitlabGet(`${path}${separator}per_page=100&page=${page}`, token)\n items.push(...data)\n page = headers.get('x-next-page') || null\n }\n return items\n}\n\n/**\n * Maps a GitLab user or group to the internal user shape\n *\n * @param user - GitLab user or group object\n * @returns User object with the fields used by DocPress\n */\nfunction mapUser(user: any) {\n return {\n login: user.username ?? user.path,\n name: user.name,\n bio: user.bio ?? user.description ?? null,\n avatar_url: user.avatar_url,\n html_url: user.web_url,\n } as unknown as User\n}\n\n/**\n * Maps a GitLab project to the internal repository shape\n *\n * @param project - GitLab project object\n * @param owner - Login of the user or group that owns the project\n * @returns Repository object with the fields used by DocPress\n */\nfunction mapRepository(project: any, owner: string) {\n return {\n name: project.path,\n owner: { login: owner },\n fork: !!project.forked_from_project,\n private: project.visibility !== 'public',\n // An empty repository has no default branch\n size: project.default_branch ? 1 : 0,\n default_branch: project.default_branch,\n clone_url: project.http_url_to_repo,\n html_url: project.web_url,\n description: project.description,\n stargazers_count: project.star_count,\n } as unknown as Repository\n}\n\n/**\n * Fetches user and repository information from GitLab\n * Falls back to the groups API when no user matches the given name\n *\n * @param options - Options for retrieving GitLab data\n * @param options.username - GitLab username or group path\n * @param options.token - GitLab API token\n * @param options.branch - Branch to use for documentation\n * @returns Object containing user information, repositories, and branch\n */\nexport async function getInfos({ username, token, branch }: Pick<FetchOpts, 'branch'> & Pick<GlobalOpts, 'token'> & { username: GlobalOpts['usernames'][number] }) {\n log(` Get infos for username '${username}'.`, 'info')\n\n const { data: users } = await gitlabGet(`/users?username=${encodeURIComponent(username)}`, token)\n\n if (users.length) {\n let user = users[0]\n if (token) {\n // The user detail endpoint requires authentication but provides extra fields (e.g. bio)\n user = await gitlabGet(`/users/${users[0].id}`, token).then(res => res.data).catch(() => users[0])\n }\n log(` Get repositories infos.`, 'debug')\n const projects = await gitlabGetAll(`/users/${users[0].id}/projects`, token)\n return { user: mapUser(user), repos: projects.map(project => mapRepository(project, user.username)), branch }\n }\n\n log(` No GitLab user '${username}' found, trying groups.`, 'debug')\n const group = await gitlabGet(`/groups/${encodeURIComponent(username)}?with_projects=false`, token)\n .then(res => res.data)\n .catch(() => {\n throw new Error(`No GitLab user or group found for '${username}'.`)\n })\n const projects = await gitlabGetAll(`/groups/${encodeURIComponent(username)}/projects`, token)\n return { user: mapUser(group), repos: projects.map(project => mapRepository(project, group.path)), branch }\n}\n","import { resolve } from 'node:path'\nimport { writeFileSync } from 'node:fs'\nimport type { FetchOpts, FetchOptsUser } from '../schemas/fetch.js'\nimport { checkHttpStatus, prettify } from '../utils/functions.js'\nimport { DOCPRESS_DIR, DOCS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { cloneRepo, getInfos } from './git.js'\nimport { getInfos as getGitlabInfos } from './gitlab.js'\n\n/**\n * Enhanced repository type with DocPress-specific metadata\n */\nexport type EnhancedRepository = Awaited<ReturnType<typeof getInfos>>['repos'][number] & {\n docpress: {\n branch: string\n filtered: boolean\n includes: string[]\n projectPath: string\n raw_url: string\n replace_url: string\n }\n}\n\n/**\n * Web URLs of a repository for a given branch, depending on the Git provider\n */\nexport interface ProviderUrls {\n blob_url: string\n tree_url: string\n raw_url: string\n}\n\n/**\n * Builds the web URLs of a repository for a given branch and Git provider\n *\n * @param repo - Repository information\n * @param branch - Branch to build URLs for\n * @param gitProvider - Git provider used to retrieve data\n * @returns Object containing blob, tree and raw base URLs\n */\nexport function getProviderUrls(repo: Awaited<ReturnType<typeof getInfos>>['repos'][number], branch: FetchOpts['branch'], gitProvider?: FetchOpts['gitProvider']): ProviderUrls {\n if (gitProvider === 'gitlab') {\n const base = repo.html_url ?? `https://gitlab.com/${repo.owner.login}/${repo.name}`\n return {\n blob_url: `${base}/-/blob/${branch}`,\n tree_url: `${base}/-/tree/${branch}`,\n raw_url: `${base}/-/raw/${branch}`,\n }\n }\n const base = repo.html_url ?? `https://github.com/${repo.owner.login}/${repo.name}`\n return {\n blob_url: `${base}/blob/${branch}`,\n tree_url: `${base}/tree/${branch}`,\n raw_url: `https://raw.githubusercontent.com/${repo.owner.login}/${repo.name}/${branch}`,\n }\n}\n\n/**\n * Checks for the existence of documentation files in a repository\n *\n * @param urls - Web URLs of the repository for the target branch\n * @returns Object containing HTTP status codes for different documentation paths\n */\nexport async function checkDoc(urls: ProviderUrls) {\n const rootReadmeStatus = await checkHttpStatus(`${urls.blob_url}/README.md`)\n const docsFolderStatus = await checkHttpStatus(`${urls.tree_url}/docs`)\n const docsReadmeStatus = await checkHttpStatus(`${urls.blob_url}/docs/01-readme.md`)\n\n return {\n rootReadmeStatus,\n docsFolderStatus,\n docsReadmeStatus,\n }\n}\n\n/**\n * Fetches documentation from a user's repositories\n *\n * @param options - Options for fetching documentation\n * @param options.username - Git provider username\n * @param options.branch - Branch to use for documentation\n * @param options.reposFilter - Optional filter for repositories\n * @param options.gitProvider - Git provider used to retrieve data\n * @param options.token - Git provider API token\n */\nexport async function fetchDoc({ username, branch, reposFilter, gitProvider, token }: FetchOptsUser) {\n const getProviderInfos = gitProvider === 'gitlab' ? getGitlabInfos : getInfos\n await getProviderInfos({ username, token, branch })\n .then(async ({ user, repos, branch }) => generateInfos(user, repos, branch, reposFilter, gitProvider))\n .then(async ({ repos }) => getDoc(repos, reposFilter))\n}\n\n/**\n * Enhances repository information with DocPress metadata\n *\n * @param repos - List of repositories from Git provider\n * @param branch - Branch to use for documentation\n * @param reposFilter - Optional filter for repositories\n * @returns Array of enhanced repositories with DocPress metadata\n */\nexport async function enhanceRepositories(repos: Awaited<ReturnType<typeof getInfos>>['repos'], branch?: FetchOpts['branch'], reposFilter?: FetchOpts['reposFilter'], gitProvider?: FetchOpts['gitProvider']) {\n const enhancedRepos: EnhancedRepository[] = []\n\n await Promise.all(\n repos.map(async (repo) => {\n const computedBranch = branch ?? repo.default_branch ?? 'main'\n const projectPath = resolve(DOCS_DIR, prettify(repo.name, { removeDot: true }))\n const filtered = isRepoFiltered(repo, reposFilter)\n const urls = getProviderUrls(repo, computedBranch, gitProvider)\n let includes: string[] = []\n\n if (!repo.fork && !repo.private && !filtered) {\n includes = await getSparseCheckout(repo, computedBranch, gitProvider)\n }\n\n enhancedRepos.push({\n ...repo,\n docpress: {\n filtered,\n branch: computedBranch,\n includes,\n projectPath,\n raw_url: urls.raw_url,\n replace_url: urls.tree_url,\n },\n })\n }),\n )\n\n return enhancedRepos\n}\n\n/**\n * Determines which files to include in the sparse checkout based on repository structure\n *\n * @param repo - Repository information\n * @param branch - Branch to check for documentation\n * @param gitProvider - Git provider used to retrieve data\n * @returns Array of file patterns to include in sparse checkout\n */\nexport async function getSparseCheckout(repo: Awaited<ReturnType<typeof getInfos>>['repos'][number], branch: FetchOpts['branch'], gitProvider?: FetchOpts['gitProvider']) {\n const docsStatus = await checkDoc(getProviderUrls(repo, branch, gitProvider))\n\n const includes: string[] = []\n if (Object.values(docsStatus).every(status => status !== 200) || !repo.size) {\n return []\n }\n if (docsStatus.docsFolderStatus === 200) {\n includes.push('docs/*')\n }\n if (docsStatus.docsFolderStatus !== 200 || docsStatus.docsReadmeStatus !== 200) {\n includes.push('README.md', '!*/**/README.md')\n }\n return includes\n}\n\n/**\n * Generates and saves user and repository information\n *\n * @param user - User information from Git provider\n * @param repos - List of repositories from Git provider\n * @param branch - Branch to use for documentation\n * @param reposFilter - Optional filter for repositories\n * @param gitProvider - Git provider used to retrieve data\n * @returns Object containing user and enhanced repository information\n */\nexport async function generateInfos(user: Awaited<ReturnType<typeof getInfos>>['user'], repos: Awaited<ReturnType<typeof getInfos>>['repos'], branch?: FetchOpts['branch'], reposFilter?: FetchOpts['reposFilter'], gitProvider?: FetchOpts['gitProvider']) {\n writeFileSync(`${DOCPRESS_DIR}/user-${user.login}.json`, JSON.stringify(user, null, 2))\n\n const enhancedRepos = await enhanceRepositories(repos, branch, reposFilter, gitProvider)\n writeFileSync(`${DOCPRESS_DIR}/repos-${user.login}.json`, JSON.stringify(enhancedRepos, null, 2))\n\n return { user, repos: enhancedRepos }\n}\n\n/**\n * Fetches documentation from repositories\n *\n * @param repos - List of enhanced repositories\n * @param reposFilter - Optional filter for repositories\n */\nexport async function getDoc(repos?: EnhancedRepository[], reposFilter?: FetchOpts['reposFilter']) {\n if (!repos) {\n log(` No repository respect docpress rules.`, 'warn')\n return\n }\n\n await Promise.all(\n repos\n .filter(repo => !isRepoFiltered(repo, reposFilter))\n .map(async (repo) => {\n await cloneRepo(repo.name, repo.clone_url as string, repo.docpress.projectPath, repo.docpress.branch, repo.docpress.includes)\n }),\n )\n}\n\n/**\n * Determines if a repository should be filtered out based on filter rules\n *\n * @param repo - Repository information\n * @param reposFilter - Optional filter for repositories\n * @returns True if the repository should be filtered out, false otherwise\n */\nexport function isRepoFiltered(repo: EnhancedRepository | Awaited<ReturnType<typeof getInfos>>['repos'][number], reposFilter?: FetchOpts['reposFilter']) {\n const hasOnlyExclusions = reposFilter?.every((filter: string) => filter.startsWith('!'))\n const isExcluded = reposFilter?.filter((filter: string) => filter.startsWith('!'))\n .some((filter: string) => repo.name === filter.substring(1))\n const isIncluded = !reposFilter\n || reposFilter?.filter((filter: string) => !filter.startsWith('!')).includes(repo.name)\n || (repo.fork && !isExcluded)\n || (hasOnlyExclusions && !isExcluded)\n\n const isFiltered = isExcluded || !isIncluded\n\n if ('docpress' in repo && !repo.docpress.includes.length) {\n return true\n }\n\n if (!!repo.clone_url && !repo.private && !isFiltered) {\n return false\n }\n return true\n}\n","import { createOption } from 'commander'\nimport { cliSchema } from '../schemas/global.js'\n\n/**\n * Global command line options shared across all commands\n */\nexport const globalOpts = [\n createOption('-C, --config <string>', cliSchema.shape.config.description),\n createOption('-T, --token <string>', cliSchema.shape.token.description),\n createOption('-U, --usernames <string>', cliSchema.shape.usernames.description),\n]\n","import { createCommand, createOption } from 'commander'\nimport { createDir } from '../utils/functions.js'\nimport { DOCPRESS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { addOptions, explicitOptions, parseOptions } from '../utils/commands.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { fetchDoc } from '../lib/fetch.js'\nimport { configSchema } from '../schemas/global.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Command name for the fetch operation\n */\nconst cmdName = 'fetch'\n\n/**\n * Command line options specific to the fetch command\n */\nexport const fetchOpts = [\n createOption('-b, --branch <string>', configSchema.shape.branch.description)\n .default(configSchema.shape.branch.def.defaultValue),\n createOption('-g, --git-provider <string>', configSchema.shape.gitProvider.description)\n .default(configSchema.shape.gitProvider.def.defaultValue),\n createOption('-r, --repos-filter <string>', configSchema.shape.reposFilter.description),\n]\n\n/**\n * The fetch command definition for Commander\n */\nexport const fetchCmd = addOptions(createCommand(cmdName), [...fetchOpts, ...globalOpts])\n .description('Fetch docs with the given username(s) and git provider.')\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions(cmdName, explicitOptions(cmd, opts))\n await main(parsedOpts)\n })\n\n/**\n * Main function to execute the fetch command\n *\n * @param opts - Validated fetch options\n */\nexport async function main(opts: FetchOpts) {\n const { usernames, reposFilter, token, branch, gitProvider } = opts\n log(`\\n-> Start fetching documentation files. This may take a moment, especially for larger repositories.`, 'info')\n\n createDir(DOCPRESS_DIR, { clean: true })\n for (const username of usernames) {\n // With multiple users, filters are scoped as '<username>/<repo>' or '!<username>/<repo>'\n const finalRF = usernames.length > 1\n ? reposFilter?.filter((rf: string) => rf.replace(/^!/, '').startsWith(`${username}/`)).map((rf: string) => rf.replace(`${username}/`, ''))\n : reposFilter\n await fetchDoc({ username, branch, reposFilter: finalRF, gitProvider, token })\n }\n}\n","import { build as vitepressBuild } from 'vitepress'\nimport type { UserConfig } from 'vitepress'\nimport { withMermaid } from 'vitepress-plugin-mermaid'\nimport { createCommand } from 'commander'\nimport { addOptions } from '../utils/commands.js'\nimport { DOCPRESS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Suppress specific Vue warnings during the build process\n *\n * @param callback - Function to execute while warnings are suppressed\n * @returns The result of the callback function\n */\nexport async function suppressVueWarnings<T>(callback: () => Promise<T>): Promise<T> {\n // Store the original console.warn\n const originalWarn = console.warn\n\n // Override console.warn to suppress specific Vue warnings\n console.warn = function (...args) {\n if (\n args.length > 0\n && typeof args[0] === 'string'\n && (args[0].includes('[Vue warn]: Invalid watch source:')\n || args[0].includes('{ open: false }'))\n ) {\n // Skip this warning\n return\n }\n // Pass other warnings to the original console.warn\n originalWarn.apply(console, args)\n }\n\n try {\n // Execute the callback with warnings suppressed\n return await callback()\n } finally {\n // Restore the original console.warn\n console.warn = originalWarn\n }\n}\n\n/**\n * Command name for the build operation\n */\nconst cmdName = 'build'\n\n/**\n * The build command definition for Commander\n */\nexport const buildCmd = addOptions(createCommand(cmdName), globalOpts)\n .description('Build vitepress website.')\n .action(async (_opts) => {\n await main()\n })\n\n/**\n * Main function to execute the build command\n * Builds the VitePress static site\n */\nexport async function main() {\n log(`\\n-> Start building Vitepress website.\\n\\n`, 'info')\n\n try {\n // Build VitePress with Vue warnings suppressed\n await suppressVueWarnings(async () => {\n await vitepressBuild(DOCPRESS_DIR, {\n onAfterConfigResolve(siteConfig) {\n withMermaid(siteConfig as unknown as UserConfig)\n },\n })\n })\n\n log(`\\n\\nDocpress build succeeded.`, 'success')\n } catch (error) {\n log(`\\n\\nDocpress build failed : ${error}`, 'error')\n process.exit(1)\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createDir } from './functions.js'\n\n/**\n * Generates a file by copying content from source to destination\n *\n * @param src - Path to the source file\n * @param dest - Path to the destination file\n */\nexport function generateFile(src: string, dest: string) {\n const content = readFileSync(src, { encoding: 'utf8' })\n createDir(dirname(dest))\n writeFileSync(dest, content)\n}\n","import type { defineConfig } from 'vitepress'\nimport { deepMerge } from '../utils/functions.js'\nimport type { Page, SidebarProject } from './prepare.js'\n\n/**\n * Default VitePress configuration\n */\nconst defaultVitepressConfig: ReturnType<typeof defineConfig> = {\n base: '/',\n lang: 'en-US',\n vite: {\n publicDir: '../public',\n },\n title: 'Home',\n description: 'Docpress',\n srcDir: './docs',\n cleanUrls: false,\n ignoreDeadLinks: 'localhostLinks',\n themeConfig: {\n outline: [2, 3],\n search: {\n provider: 'local',\n options: {\n translations: {\n button: {\n buttonText: 'Search...',\n buttonAriaLabel: 'Search',\n },\n modal: {\n backButtonTitle: 'erase search',\n displayDetails: 'show details',\n noResultsText: 'No results for : ',\n resetButtonTitle: 'cancel search',\n footer: {\n selectText: 'go to',\n navigateText: 'navigate in results',\n closeText: 'close',\n },\n },\n },\n },\n },\n },\n}\n\n/**\n * Generates VitePress configuration by merging default and custom configs\n *\n * @param sidebar - Sidebar configuration\n * @param nav - Navigation configuration\n * @param vitepressConfig - Optional custom VitePress configuration\n * @returns Merged VitePress configuration\n */\nexport function getVitepressConfig(sidebar: SidebarProject[], nav: Page[], vitepressConfig?: ReturnType<typeof defineConfig>): Partial<ReturnType<typeof defineConfig>> {\n const config = vitepressConfig\n ? deepMerge(defaultVitepressConfig, vitepressConfig, { themeConfig: { sidebar, nav } })\n : deepMerge(defaultVitepressConfig, { themeConfig: { sidebar, nav } })\n return config\n}\n","import { basename, dirname, parse, resolve } from 'node:path'\nimport { appendFileSync, cpSync, existsSync, readdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport YAML from 'yaml'\nimport type { defineConfig } from 'vitepress'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { generateFile } from '../utils/templates.js'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport { createDir, extractFiles, getMdFiles, getUserInfos, getUserRepos, isFile, prettify, replaceReadmePath, replaceRelativePath } from '../utils/functions.js'\nimport { DOCPRESS_DIR, DOCS_DIR, FORKS_FILE, INDEX_FILE, TEMPLATE_THEME, VITEPRESS_CONFIG, VITEPRESS_THEME, VITEPRESS_USER_THEME } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport type { EnhancedRepository } from './fetch.js'\nimport type { getInfos } from './git.js'\nimport { getContributors } from './git.js'\nimport { getVitepressConfig } from './vitepress.js'\n\n/**\n * Represents a navigation page item with text and link\n */\nexport interface Page {\n text: string\n link: string\n}\n\n/**\n * Represents a sidebar project with nested items\n */\nexport interface SidebarProject {\n text: string\n collapsed: boolean\n items: (Page | SidebarProject)[]\n}\n\n/**\n * Represents a feature to display on the index page\n */\nexport interface Feature {\n title: string\n details: string\n link: string\n}\n\n/**\n * Represents the structure of the VitePress index page\n */\nexport interface Index {\n layout: string\n hero: {\n name: string\n tagline?: string\n }\n /** List of features to display */\n features: Feature[]\n}\n\n/**\n * Prepares the documentation structure for a user's repositories\n *\n * @param options - Options for documentation preparation\n * @param options.extraHeaderPages - Array of paths to additional header pages\n * @param options.extraPublicContent - Array of paths to additional public content\n * @param options.extraTheme - Array of paths to additional theme files\n * @param options.vitepressConfig - Path to the VitePress configuration file\n * @param options.forks - Flag to include forked repositories\n * @param options.gitProvider - Git provider used to retrieve data\n * @param options.token - Git provider token for API access\n * @param options.username - Git provider username to fetch repositories for\n * @param options.websiteTitle - Custom title for the documentation website\n * @param options.websiteTagline - Custom tagline for the documentation website\n */\nexport async function prepareDoc({ extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, token, username, websiteTitle, websiteTagline }: Omit<PrepareOpts, 'usernames' | 'branch' | 'reposFilter'> & { username: PrepareOpts['usernames'][number] }) {\n // The forks page relies on matching contributors by login, which the GitLab API does not expose\n const forksEnabled = forks && gitProvider !== 'gitlab'\n if (forks && !forksEnabled) {\n log(` The forks page is not supported with the 'gitlab' provider, skipping.`, 'warn')\n }\n const user = getUserInfos(username)\n const repositories = getUserRepos(username)\n .reduce(({ internals, forks }: { internals: EnhancedRepository[], forks: EnhancedRepository[] }, cur) => {\n const { clone_url, private: privateRepo, fork, docpress } = cur\n if (clone_url && !privateRepo && !docpress.filtered) {\n if (!fork && docpress.includes.length) {\n return { internals: [...internals, cur], forks }\n } else if (fork) {\n return { internals, forks: [...forks, cur] }\n }\n }\n return { internals, forks }\n }, { internals: [], forks: [] })\n\n const websiteInfos = { title: websiteTitle, tagline: websiteTagline }\n const { index, sidebar } = transformDoc(repositories.internals, user, websiteInfos)\n\n let finalSB\n let finalIndex\n if (existsSync(INDEX_FILE) && existsSync(VITEPRESS_CONFIG)) {\n const actualConfig = await parseVitepressConfig(VITEPRESS_CONFIG)\n const actualIndex = await parseVitepressIndex(INDEX_FILE)\n finalSB = [\n ...(actualConfig.themeConfig?.sidebar as SidebarProject[] ?? []),\n ...sidebar,\n ].sort((a, b) => a.text.localeCompare(b.text))\n finalIndex = {\n ...index,\n features: [\n ...actualIndex.features,\n ...index.features,\n ].sort((a, b) => a.title.localeCompare(b.title)),\n }\n } else {\n finalSB = sidebar\n finalIndex = index\n }\n const nav: Page[] = []\n\n if (extraHeaderPages) {\n const pages = addExtraPages(extraHeaderPages)\n if (forksEnabled) {\n nav.push(...pages.filter(p => p.link !== '/forks'))\n } else {\n nav.push(...pages)\n }\n }\n if (extraPublicContent) {\n log(` Add extras Vitepress public folder content.`, 'info')\n addContent(extraPublicContent, resolve(DOCPRESS_DIR, 'public'))\n }\n if (extraTheme) {\n log(` Add extras Vitepress theme files.`, 'info')\n addContent(extraTheme, resolve(VITEPRESS_USER_THEME))\n }\n if (forksEnabled && username.length) {\n log(` Add fork page to display external contributions.`, 'info')\n await processForks(repositories.forks, username, token)\n nav.push({ text: 'Forks', link: '/forks' })\n }\n\n const config = getVitepressConfig(finalSB, nav, vitepressConfig)\n\n generateVitepressFiles(config, finalIndex)\n}\n\n/**\n * Adds a source reference section to a markdown file\n *\n * @param repoUrl - URL of the GitHub repository\n * @param outputPath - Path to the markdown file where sources will be added\n */\nexport function addSources(repoUrl: string, outputPath: string) {\n const fileName = basename(outputPath)\n const title = prettify(fileName, { mode: 'lowercase', removeIdx: true }) === 'readme.md' ? '\\n## Sources' : '# Sources'\n\n const sourcesContent = `${title}\\n\\nTake a look at the [project sources](${repoUrl}).\\n`\n\n appendFileSync(outputPath, sourcesContent, 'utf8')\n}\n\n/**\n * Information about website title and tagline\n */\nexport interface WebsiteInfos {\n title?: string\n tagline?: string\n}\n\n/**\n * Generates the index page content for the documentation site\n *\n * @param features - Array of features to display on the homepage\n * @param user - User information retrieved from GitHub\n * @param websiteInfos - Custom title and tagline information\n * @returns An object with index page configuration\n */\nexport function generateIndex(features: Feature[], user: ReturnType<typeof getUserInfos>, websiteInfos: WebsiteInfos) {\n const { name, login, bio } = user\n const { title, tagline } = websiteInfos\n\n const hero = title\n ? { name: title, tagline }\n : { name: name ? `${name}'s projects` : `${login}'s projects`, tagline: bio ?? 'Robots are everywhere 🤖' }\n\n return {\n layout: 'home',\n hero,\n features,\n }\n}\n\n/**\n * Generates feature cards for the homepage\n *\n * @param repoName - Name of the repository\n * @param description - Description of the repository\n * @param features - Optional existing features to append to\n * @returns Array of feature objects for the homepage\n */\nexport function generateFeatures(repoName: string, description: string, features?: Feature[]) {\n const content = {\n title: prettify(repoName, { mode: 'capitalize', replaceDash: true }),\n details: description,\n link: `/${prettify(repoName, { removeDot: true })}/introduction`,\n }\n\n return features ? [...features, content] : [content]\n}\n\n/**\n * Generates a sidebar project entry for the documentation navigation\n *\n * @param repoName - Name of the repository\n * @param sidebarPages - Array of sidebar pages to include in this project\n * @returns A sidebar project configuration object\n */\nexport function generateSidebarProject(repoName: string, sidebarPages: (SidebarProject | Page)[]) {\n return {\n text: prettify(repoName, { mode: 'capitalize', replaceDash: true }),\n collapsed: true,\n items: sidebarPages,\n }\n}\n\n/**\n * Generates sidebar page entries for the documentation navigation\n *\n * @param repoName - Name of the repository\n * @param fileName - Name of the file\n * @param sidebarPages - Optional existing sidebar pages to append to\n * @returns Array of page objects for the sidebar\n */\nexport function generateSidebarPages(repoName: string, fileName: string, sidebarPages?: Page[]) {\n const content = {\n text: fileName === 'introduction' ? 'Introduction' : prettify(fileName, { mode: 'capitalize', replaceDash: true }),\n link: `/${prettify(repoName, { removeDot: true })}/${fileName}`,\n }\n\n return sidebarPages ? [...sidebarPages, content] : [content]\n}\n\n/**\n * Generates sidebar items from a repository's file structure\n *\n * @param repository - Repository information\n * @param obj - Object representing the file tree structure\n * @returns Array of sidebar items (projects and pages)\n */\nexport function generateSidebarItems(repository: EnhancedRepository, obj: any): (SidebarProject | Page)[] {\n return Object.entries(obj).flatMap(([key, value]): (SidebarProject | Page)[] => {\n if (key === '$') {\n if (Array.isArray(value)) {\n return value.map((element) => {\n const file = resolve(repository.docpress.projectPath, element)\n let filename = prettify(basename(file), { mode: 'lowercase', removeIdx: true })\n if (filename === 'readme.md') {\n filename = 'introduction.md'\n }\n if (filename !== basename(file)) {\n renameSync(file, resolve(dirname(file), filename))\n }\n\n return {\n text: parse(filename).name === 'introduction'\n ? 'Introduction'\n : prettify(filename, { mode: 'capitalize', replaceDash: true, removeExt: true }),\n link: `/${prettify(repository.name, { removeDot: true })}/${parse(filename).name}`,\n } as Page\n })\n }\n return []\n } else if (typeof value === 'object') {\n return [{\n text: prettify(key, { mode: 'capitalize', replaceDash: true }),\n collapsed: true,\n items: generateSidebarItems({ ...repository, name: `${repository.name}/${key}` }, value),\n } as SidebarProject]\n }\n\n return []\n })\n}\n\n/**\n * Builds a tree structure from an array of file paths\n *\n * @param files - Array of file paths to be organized into a tree\n * @returns A nested object representing the directory structure\n */\nexport function buildTree(files: string[]): any {\n return files.reduce((tree, file) => {\n const [first, ...rest] = file.split('/')\n if (!rest.length) {\n // eslint-disable-next-line dot-notation\n tree['$'] = [...(tree['$'] || []), first]\n } else {\n tree[first] = buildTree([\n ...(tree[first] ? flattenTree(tree[first], '') : []),\n rest.join('/'),\n ])\n }\n return tree\n }, {} as Record<string, any>)\n}\n\n/**\n * Flattens a nested tree structure into an array of file paths\n *\n * @param subtree - The tree object to flatten\n * @param prefix - Optional path prefix to prepend to each result\n * @returns An array of file paths\n */\nexport function flattenTree(subtree: any, prefix = ''): string[] {\n return Object.entries(subtree).flatMap(([key, value]) => {\n if (key === '$') {\n if (Array.isArray(value)) {\n return value.map((v: string) => (prefix ? `${prefix}/${v}` : v))\n } else {\n return []\n }\n }\n return flattenTree(value, prefix ? `${prefix}/${key}` : key)\n })\n}\n\n/**\n * Reorders sidebar items to ensure 'Sources' appears last\n *\n * @param arr - Array of sidebar items to reorder\n * @returns Reordered array with 'Sources' as the last item\n */\nfunction moveSourcesLast(arr: (SidebarProject | Page)[]) {\n if (!Array.isArray(arr)) {\n return arr\n }\n const sourcesIdx = arr.findIndex(item => item.text === 'Sources')\n if (sourcesIdx === -1) {\n return arr\n }\n const [sources] = arr.splice(sourcesIdx, 1)\n arr.push(sources)\n return arr\n}\n\n/**\n * Transforms repository data into documentation structure\n *\n * @param repositories - Array of enhanced repositories\n * @param user - User information retrieved from GitHub\n * @param websiteInfos - Custom title and tagline information\n * @returns Object containing sidebar and index page configurations\n */\nexport function transformDoc(repositories: EnhancedRepository[], user: ReturnType<typeof getUserInfos>, websiteInfos: WebsiteInfos) {\n const features: Feature[] = []\n const sidebar: SidebarProject[] = []\n\n for (const repository of repositories) {\n log(` Replace urls for repository '${repository.name}'.`, 'info')\n getMdFiles([repository.docpress.projectPath]).forEach((file) => {\n log(` Processing file '${basename(file)}' for repository '${repository.name}'.`, 'debug')\n replaceRelativePath(file, repository.docpress.replace_url)\n\n if (basename(file).toLowerCase() === 'readme.md') {\n replaceReadmePath(file, repository.docpress.replace_url)\n }\n })\n\n log(` Generate sidebar for repository '${repository.name}'.`, 'info')\n const projectFiles = readdirSync(repository.docpress.projectPath, { recursive: true })\n .filter((file) => {\n const filePath = resolve(repository.docpress.projectPath, file.toString())\n // Name check first, then a stat that tolerates files vanishing between\n // the directory scan and the check (e.g. leftover git lock files)\n return basename(filePath).endsWith('.md') && isFile(filePath)\n })\n .sort() as string[]\n\n log(` Add sources for repository '${repository.name}'.`, 'info')\n let sourceFile\n if (projectFiles.length > 1) {\n sourceFile = resolve(repository.docpress.projectPath, 'sources.md')\n projectFiles.push('sources.md')\n } else if (projectFiles.length === 1) {\n sourceFile = resolve(repository.docpress.projectPath, projectFiles[0])\n }\n if (sourceFile) {\n addSources(repository.html_url, sourceFile)\n } else {\n log(` No markdown files found for repository '${repository.name}', skipping sources.`, 'warn')\n }\n\n const projectTree = buildTree(projectFiles)\n const sidebarItems = moveSourcesLast(generateSidebarItems(repository, projectTree))\n\n sidebar.push(generateSidebarProject(prettify(repository.name, { removeDot: true }), sidebarItems))\n features.push(...generateFeatures(prettify(repository.name, { removeDot: true }), repository.description || ''))\n }\n\n log(` Generate index content.`, 'info')\n const index = generateIndex(features.toSorted((a, b) => a.title.localeCompare(b.title)), user, websiteInfos)\n return {\n sidebar: sidebar.toSorted((a, b) => a.text.localeCompare(b.text)),\n index,\n }\n}\n\n/**\n * Adds extra pages to the documentation from specified paths\n *\n * @param paths - Array of paths to markdown files\n * @returns Array of navigation page objects\n */\nexport function addExtraPages(paths: string[]) {\n const files = getMdFiles(paths)\n const nav: Page[] = []\n\n log(` Add extras Vitepress headers pages.`, 'info')\n for (const file of files) {\n log(` Processing file '${file}'.`, 'debug')\n const src = resolve(process.cwd(), file)\n const dest = resolve(DOCS_DIR, prettify(basename(file), { mode: 'lowercase', removeIdx: true }))\n cpSync(src, dest)\n nav.push({\n text: prettify(parse(src).name, { replaceDash: true, removeIdx: true }),\n link: `/${prettify(parse(src).name, { removeIdx: true, mode: 'lowercase' })}`,\n })\n }\n return nav\n}\n\n/**\n * Adds content from specified paths to a target directory\n *\n * @param paths - String or array of paths to content\n * @param dir - Target directory to copy content to\n * @param fn - Optional callback function to execute for each file\n */\nexport function addContent(paths: string | string[], dir: string, fn?: () => void) {\n for (const path of Array.isArray(paths) ? paths : [paths]) {\n const absolutePath = resolve(process.cwd(), path)\n const files = extractFiles(absolutePath)\n\n for (const file of files) {\n const formattedFile = file.replace(absolutePath, '.')\n log(` Processing file '${formattedFile}' for entry '${path}'.`, 'debug')\n const src = resolve(process.cwd(), file)\n const dest = resolve(dir, formattedFile)\n if (fn) {\n fn()\n }\n cpSync(src, dest)\n }\n }\n}\n\n/**\n * Creates a fork page to display external contributions\n *\n * @param forks - Array of repositories and contribution counts\n */\nexport function addForkPage(forks: { repository: Awaited<ReturnType<typeof getInfos>>['repos'][number], contributions: number }[]) {\n const separator = '---\\n'\n const header = 'layout: fork-page\\nrepoList:\\n'\n const text = '\\n# External contributions\\n\\nThis gallery is a visual representation of the collaborative work done across a variety of open-source projects, each driven by a shared passion for innovation and community growth.\\n\\nEvery tile below represents a unique project where contributions have been made-ranging from code enhancements to documentation improvements. Each project includes a summary of its goals, features, and links to GitHub for direct access.\\n\\nThis page serves as both a portfolio of past work and a resource for revisiting projects that have made a meaningful impact.\\n'\n const frontmatter = forks.map(({ repository, contributions }) => {\n const { name, owner, html_url, description, stargazers_count } = repository\n return { name, owner: owner.login, html_url, description, stargazers_count, contributions }\n })\n log(` Generate forks page.`, 'info')\n writeFileSync(FORKS_FILE, separator + header + YAML.stringify(frontmatter) + separator + text)\n}\n\ntype Source = Required<Awaited<ReturnType<typeof getContributors>>['source']>\n\ntype AdaptedLicense = Omit<NonNullable<Source>['license'], 'spdx_id'> & { spdx_id?: string }\n\ntype AdaptedRepository = Omit<NonNullable<Source>, 'license'> & { license: AdaptedLicense }\n\n/**\n * Processes forked repositories to generate contribution information\n *\n * @param repositories - Array of enhanced repositories\n * @param username - GitHub username\n * @param token - Optional GitHub API token\n */\nexport async function processForks(repositories: EnhancedRepository[], username: GlobalOpts['usernames'][number], token?: GlobalOpts['token']) {\n const forks = await Promise.all(\n repositories.map(async (repository) => {\n const { source, contributors } = await getContributors({ repository, token })\n return {\n contributions: contributors?.find(contributor => contributor.login === username)?.contributions ?? 0,\n repository: source as AdaptedRepository,\n }\n }),\n ).then(f => f.filter(({ repository, contributions }) => !!repository && contributions))\n\n addForkPage(forks)\n}\n\n/**\n * Parses a VitePress configuration file\n *\n * @param path - Path to the VitePress config file\n * @returns The parsed configuration object\n */\nexport async function parseVitepressConfig(path: string): Promise<Partial<ReturnType<typeof defineConfig>>> {\n try {\n const { config } = await import(resolve(process.cwd(), path))\n return config ?? {}\n } catch (error) {\n log(` Unable to load existing Vitepress config '${path}', starting from an empty config. ${error instanceof Error ? error.message : ''}`, 'warn')\n return {}\n }\n}\n\n/**\n * Parses a VitePress index file\n *\n * @param path - Path to the index file\n * @returns The parsed index object\n */\nexport async function parseVitepressIndex(path: string): Promise<Index> {\n const index = (await readFile(resolve(process.cwd(), path))).toString()\n return YAML.parse(index)\n}\n\n/**\n * Generates VitePress configuration and index files\n *\n * @param vitepressConfig - VitePress configuration object\n * @param index - Index page configuration\n * @returns The list of theme files that were generated\n */\nexport function generateVitepressFiles(vitepressConfig: Partial<ReturnType<typeof defineConfig>>, index: Index) {\n const separator = '---\\n'\n createDir(dirname(VITEPRESS_CONFIG))\n\n log(` Generate Vitepress config.`, 'info')\n writeFileSync(VITEPRESS_CONFIG, `export const config = ${JSON.stringify(vitepressConfig, null, 2)}\\n\\nexport default config\\n`)\n log(` Generate index file.`, 'info')\n writeFileSync(INDEX_FILE, separator + YAML.stringify(index))\n log(` Add Docpress theme files.`, 'info')\n return extractFiles(TEMPLATE_THEME).forEach((path) => {\n const relativePath = path.replace(`${TEMPLATE_THEME}/`, '')\n generateFile(path, resolve(VITEPRESS_THEME, relativePath))\n })\n}\n","import { dirname } from 'node:path'\nimport { createCommand, createOption } from 'commander'\nimport { configSchema } from '../schemas/global.js'\nimport { addOptions, explicitOptions, parseOptions } from '../utils/commands.js'\nimport { prepareDoc } from '../lib/prepare.js'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { log } from '../utils/logger.js'\nimport { createDir } from '../utils/functions.js'\nimport { VITEPRESS_CONFIG } from '../utils/const.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Command name for the prepare operation\n */\nconst cmdName = 'prepare'\n\n/**\n * Command line options specific to the prepare command\n */\nexport const prepareOpts = [\n createOption('-c, --extra-public-content <string>', configSchema.shape.extraPublicContent.description),\n createOption('-f, --forks', configSchema.shape.forks.description),\n createOption('-p, --extra-header-pages <string>', configSchema.shape.extraHeaderPages.description),\n createOption('-t, --extra-theme <string>', configSchema.shape.extraTheme.description),\n createOption('-v, --vitepress-config <string>', configSchema.shape.vitepressConfig.description),\n createOption('--website-title <string>', configSchema.shape.websiteTitle.description),\n createOption('--website-tagline <string>', configSchema.shape.websiteTagline.description),\n]\n\n/**\n * The prepare command definition for Commander\n */\nexport const prepareCmd = addOptions(createCommand(cmdName), [...prepareOpts, ...globalOpts])\n .description('Transform doc to the target vitepress format.')\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions(cmdName, explicitOptions(cmd, opts))\n await main(parsedOpts)\n })\n\n/**\n * Main function to execute the prepare command\n *\n * @param opts - Validated prepare options\n */\nexport async function main(opts: PrepareOpts) {\n const { extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, token, usernames, websiteTitle, websiteTagline } = opts\n log(`\\n-> Start transform files to prepare Vitepress build.`, 'info')\n\n createDir(dirname(VITEPRESS_CONFIG), { clean: true })\n for (const username of usernames) {\n await prepareDoc({ extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, token, username, websiteTitle, websiteTagline })\n }\n}\n","import { Command } from 'commander'\nimport pkg from '../package.json' with { type: 'json' }\nimport { fetchCmd, main as fetchFn, fetchOpts } from './commands/fetch.js'\nimport { buildCmd, main as buildFn } from './commands/build.js'\nimport { prepareCmd, main as prepareFn, prepareOpts } from './commands/prepare.js'\nimport { addOptions, explicitOptions, parseOptions } from './utils/commands.js'\nimport { globalOpts } from './commands/global.js'\nimport { log } from './utils/logger.js'\n\n/**\n * Creates and configures the Command Line Interface for DocPress\n *\n * @returns A configured Commander program instance\n */\nexport function getProgram() {\n const pm = new Command()\n .name('docpress')\n .description('Build your doc website faster than light ⚡️⚡️⚡️')\n .version(`${pkg.version}`)\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions('global', explicitOptions(cmd, opts))\n await fetchFn(parsedOpts)\n await prepareFn(parsedOpts)\n await buildFn()\n })\n .configureHelp({\n sortSubcommands: true,\n sortOptions: true,\n showGlobalOptions: true,\n })\n .enablePositionalOptions()\n .passThroughOptions()\n .addCommand(fetchCmd)\n .addCommand(prepareCmd)\n .addCommand(buildCmd)\n\n addOptions(pm, [...fetchOpts, ...prepareOpts, ...globalOpts])\n\n return pm\n}\n\n/**\n * Entry point for the DocPress CLI\n * Initializes and runs the command parser\n */\nexport function main() {\n const pm = getProgram()\n pm.parseAsync(process.argv).catch((error) => {\n log(`\\n${error instanceof Error ? error.message : String(error)}`, 'error')\n process.exit(1)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GCKa,IAAe,EAAQ,QAAQ,IAAI,GAAG,UAAU,GAKhD,IAAW,EAAQ,QAAQ,IAAI,GAAG,eAAe,GAKjD,IAAa,EAAQ,QAAQ,IAAI,GAAG,wBAAwB,GAK5D,KAAa,EAAQ,QAAQ,IAAI,GAAG,wBAAwB,GAK5D,IAAmB,EAAQ,QAAQ,IAAI,GAAG,+BAA+B,GAKzE,KAAkB,EAAQ,QAAQ,IAAI,GAAG,2BAA2B,GAKpE,KAAuB,EAAQ,QAAQ,IAAI,GAAG,kCAAkC,GAMhF,IAAA,QAAA,IAAA,aAA6C,gBACtD,EAAQ,OAAO,KAAK,SAAS,8BAA8B,IAC3D,EAAQ,OAAO,KAAK,SAAS,mBAAmB,GC3CvC,KAAoB,kCACpB,KAAkB,oEAClB,KAAsB,gDACtB,KAAiB;;;ACc9B,eAAsB,EAAgB,GAA8B;CAClE,IAAI;EAEF,QAAO,MADgB,MAAM,GAAK;GAAE,QAAQ;GAAQ,UAAU;EAAS,CAAC,EAAA,CACxD;CAClB,QAAiB;EACf,OAAO;CACT;AACF;AAoBA,SAAgB,EAAS,GAAW,GAAoB;CACtD,IAAI,IAAY;CAgChB,OA9BI,GAAM,cACR,AAGE,IAHE,EAAE,WAAW,GAAG,IACd,EAAE,MAAM,CAAC,IAET,GAGN,IAAI,EAAE,WAAW,KAAK,GAAG,IAGvB,GAAM,cACR,KAAK,KAAK,EAAA,CAAG,QAAQ,IAAgB,EAAE,IAGrC,GAAM,cACR,KAAK,KAAK,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAGtB,GAAM,gBACR,KAAK,KAAK,EAAA,CAAG,WAAW,KAAK,GAAG,IAG9B,GAAM,SAAS,eACjB,KAAK,KAAK,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,KAAK,KAAK,EAAA,CAAG,MAAM,CAAC,CAAC,CAAC,YAAY,IAC9D,GAAM,SAAS,cACxB,KAAK,KAAK,EAAA,CAAG,YAAY,IAChB,GAAM,SAAS,gBACxB,KAAK,KAAK,EAAA,CAAG,YAAY,IAGpB,KAAK;AACd;AASA,SAAgB,EAAU,GAAmB,EAAE,aAA+B,EAAE,OAAO,GAAM,GAAG;CAC9F,IAAI;EAIF,AAHI,KAAS,EAAW,CAAS,KAC/B,EAAW,GAAG,EAAU,KAAK,EAAE,MAAM,GAAK,CAAC,GAExC,EAAW,CAAS,KACvB,EAAU,GAAW,EAAE,WAAW,GAAK,CAAC;CAE5C,SAAS,GAAK;EACZ,QAAQ,MAAM,CAAG;CACnB;AACF;AAQA,SAAgB,GAAM,GAAc;CAClC,IAAI;EACF,OAAO,EAAS,CAAI,CAAC,CAAC,YAAY;CACpC,QAAiB;EACf,OAAO;CACT;AACF;AAQA,SAAgB,EAAO,GAAc;CACnC,IAAI;EACF,OAAO,EAAS,CAAI,CAAC,CAAC,OAAO;CAC/B,QAAiB;EACf,OAAO;CACT;AACF;AAQA,SAAgB,EAAa,GAAoC;CAC/D,QAAQ,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC,CAAK,EAAA,CAAG,SAAS,MACnD,EAAO,CAAI,IACN,CAAC,CAAI,IAEV,GAAM,CAAI,IACL,EAAY,CAAI,CAAC,CAAC,KAAK,CAAC,CAAC,SAAQ,MAAQ,EAAa,EAAK,GAAM,CAAI,CAAC,CAAC,IAEzE,CAAC,CACT;AACH;AAQA,SAAgB,EAAW,GAAgB;CACzC,OAAO,EAAa,CAAI,CAAC,CAAC,QAAO,MAAQ,EAAS,CAAI,CAAC,CAAC,SAAS,KAAK,CAAC;AACzE;AAQA,SAAgB,GAAa,GAAwB;CACnD,OAAO,EAAI,QAAQ,GAAK,GAAK,GAAK,MAC3B,IAEM,MAAQ,EAAI,SAAS,IACvB,GAAG,EAAI,OAAO,EAAI,KAElB,GAAG,EAAI,KAAK,EAAI,KAJhB,IAAI,EAAI,IAMhB,EAAE;AACP;AAQA,SAAgB,GAAa,GAA2C;CACtE,OAAO,KAAK,MAAM,EAAa,GAAG,EAAa,QAAQ,EAAS,MAAM,CAAC,CAAC,SAAS,CAAC;AACpF;AAQA,SAAgB,GAAa,GAA2C;CACtE,OAAO,KAAK,MAAM,EAAa,GAAG,EAAa,SAAS,EAAS,MAAM,CAAC,CAAC,SAAS,CAAC;AACrF;AAQA,SAAgB,EAAgD,GAAG,GAAiB;CAClF,OAAO,EAAQ,QAAQ,GAAK,OACtB,MAAQ,QAIZ,OAAO,KAAK,CAAG,CAAC,CAAC,SAAS,MAAQ;EAChC,IAAM,IAAW,IAAM,EAAI,KAAO,MAC5B,IAAW,EAAI;EAErB,AAAI,EAAS,CAAQ,KAAK,EAAS,CAAQ,IACzC,EAA6B,KAAO,EAAU,GAAU,CAAQ,IAEhE,EAA6B,KAAO;CAExC,CAAC,GAZQ,IAcR,CAAC,CAAM;AACZ;AAQA,SAAgB,EAAS,GAAyB;CAChD,OAAO,KAAO,OAAO,KAAQ,YAAY,CAAC,MAAM,QAAQ,CAAG;AAC7D;AASA,SAAgB,EAAe,GAAqB;CAClD,IAAI,CAAC,GACH,OAAO,CAAC;CAEV,IAAM,IAAW,EAAQ,QAAQ,IAAI,GAAG,CAAU,GAC9C;CACJ,IAAI;EACF,IAAe,EAAa,GAAU,MAAM;CAC9C,QAAiB;EACf,MAAU,MAAM,4BAA4B,EAAW,GAAG;CAC5D;CACA,IAAI;EACF,OAAO,KAAK,MAAM,CAAY;CAChC,QAAiB;EACf,MAAU,MAAM,gCAAgC,EAAW,GAAG;CAChE;AACF;AAQA,SAAgB,EAAa,GAAW;CACtC,OAAO,EAAE,MAAM,GAAG;AACpB;AAQA,SAAgB,GAAoB,GAAc,GAAa;CAK7D,EAAc,GAJM,EAAa,GAAM,MAChB,CAAA,CAAY,QAAQ,KAAoB,GAAQ,GAAI,MAClE,IAAI,EAAG,IAAI,EAAI,GAAG,EAAG,EAEV,GAAgB,MAAM;AAC5C;AAQA,SAAgB,GAAkB,GAAc,GAAa;CAS3D,EAAc,GARQ,EAAa,GAAM,MAClB,CAAA,CACpB,QAAQ,KAAkB,GAAQ,GAAI,GAAK,MACnC,IAAI,EAAG,IAAI,EAAI,GAAG,EAAG,EAC7B,CAAC,CACD,QAAQ,KAAsB,GAAQ,GAAI,GAAK,MACvC,IAAI,EAAG,IAAI,EAAG,EAEL,GAAgB,MAAM;AAC5C;;;AC/QA,SAAS,KAAc;CACrB,IAAM,IAAQ,OAAO,QAAQ,IAAI,SAAY;CAC7C,OAAO,OAAO,MAAM,CAAK,IAAI,KAAK;AACpC;AAKA,IAAM,IAAqB;CACzB,OAAO;EAAE,OAAO;EAAO,OAAO;CAAG;CACjC,MAAM;EAAE,OAAO;EAAU,OAAO;CAAG;CACnC,MAAM;EAAE,OAAO;EAAS,OAAO;CAAG;CAClC,SAAS;EAAE,OAAO;EAAS,OAAO;CAAG;CACrC,OAAO;EAAE,OAAO;EAAS,OAAO;CAAG;CACnC,OAAO;EAAE,OAAO;EAAQ,OAAO;CAAG;AACpC;AASA,SAAgB,EAAI,GAAa,IAAgB,QAAQ,GAAmB;CAC1E,IAAM,IAAc,IAAQ,EAAM,EAAM,CAAC,CAAG,IAAI,EAAM,EAAS,EAAK,CAAC,MAAM,CAAC,CAAG,GACzE,IAAe,MAAS,YAAY,SAAS;CAEnD,AAAI,GAAY,KAAK,EAAS,EAAK,CAAC,SAClC,QAAQ,EAAa,CAAC,CAAW;AAErC;;;AChDA,IAAM,IAAY,CAAC,UAAU,QAAQ,GAMxB,IAAe,EAAE,OAAO;CAEnC,WAAW,EAAE,OAAO,CAAC,CAClB,MAAM,CAAC,CACP,SAAS,sEAAsE;CAElF,QAAQ,EAAE,OAAO,CAAC,CACf,QAAQ,MAAM,CAAC,CACf,SAAS,2CAA2C;CACvD,aAAa,EAAE,KAAK,CAAS,CAAC,CAC3B,QAAQ,QAAQ,CAAC,CACjB,SAAS,wDAAwD,GAAa,CAAS,EAAE,EAAE;CAC9F,aAAa,EAAE,OAAO,CAAC,CACpB,MAAM,CAAC,CACP,SAAS,gHAAiH;CAE7H,kBAAkB,EAAE,OAAO,CAAC,CACzB,MAAM,CAAC,CACP,SAAS,4FAA4F;CACxG,oBAAoB,EAAE,OAAO,CAAC,CAC3B,MAAM,CAAC,CACP,SAAS,6FAA6F;CACzG,YAAY,EAAE,OAAO,CAAC,CACnB,MAAM,CAAC,CACP,SAAS,oFAAoF;CAChG,OAAO,EAAE,QAAQ,CAAC,CACf,QAAQ,EAAK,CAAC,CACd,SAAS,yFAAyF;CACrG,iBAAiB,EAAE,IAAI,CAAC,CACrB,SAAS,CAAC,CACV,SAAS,2CAA2C;CACvD,cAAc,EAAE,OAAO,CAAC,CACrB,SAAS,gBAAgB;CAC5B,gBAAgB,EAAE,OAAO,CAAC,CACvB,SAAS,kBAAkB;AAChC,CAAC,GASY,IAAY,EACtB,QAAQ,CAAC,CACT,OAAO;CACN,QAAQ,EAAE,OAAO,CAAC,CACf,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,OAAO,eAAe,EAAE;CACvD,aAAa,EAAE,KAAK,CAAS,CAAC,CAC3B,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,YAAY,eAAe,EAAE;CAC5D,OAAO,EAAE,QAAQ,CAAC,CACf,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,MAAM,eAAe,EAAE;CACtD,QAAQ,EAAE,OAAO,CAAC,CACf,SAAS,CAAC,CACV,SAAS,0CAA0C;CACtD,OAAO,EAAE,OAAO,CAAC,CACd,SAAS,CAAC,CACV,SAAS,0CAA0C;CACtD,WAAW,EAAE,OAAO,CAAC,CAClB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,UAAU,eAAe,EAAE;CAC1D,aAAa,EAAE,OAAO,CAAC,CACpB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,YAAY,eAAe,EAAE;CAC5D,kBAAkB,EAAE,OAAO,CAAC,CACzB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,iBAAiB,eAAe,EAAE;CACjE,oBAAoB,EAAE,OAAO,CAAC,CAC3B,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,mBAAmB,eAAe,EAAE;CACnE,YAAY,EAAE,OAAO,CAAC,CACnB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,WAAW,eAAe,EAAE;CAC3D,iBAAiB,EAAE,OAAO,CAAC,CACxB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,gBAAgB,eAAe,EAAE;AAClE,CAAC;AAUH,SAAS,GAAkB,GAAiB;CAC1C,IAAI,CAAC,GAAY,OAAO,CAAC;CAGzB,KAAK,IAAM,KAAO;EADC;EAAa;EAAe;EAAoB;EAAsB;CACvE,GAChB,AAAI,EAAW,MAAQ,OAAO,EAAW,MAAS,aAChD,EAAW,KAAO,CAAC,EAAW,EAAI;CAItC,OAAO;AACT;AASA,SAAS,GAAmB,GAAiB;CAC3C,IAAM,IAAS,EAAa,QAAQ,CAAC,CAAC,UAAU,CAAU;CAC1D,IAAI,CAAC,EAAO,SACV,MAAU,MAAM,EAAE,cAAc,EAAO,KAAK,CAAC;CAE/C,OAAO,EAAO;AAChB;AASA,SAAS,GAAoB,GAAmB;CAC9C,IAAI,CAAC,EAAa,WAAW,QAC3B,MAAU,MAAM,iCAAiC;CAGnD,OAAO;AACT;AAMA,IAAa,KAAmB,EAC7B,QAAQ,CAAC,CACT,WAAW,MAAS;CACnB,IAAI;EACF,IAAM,EAAE,WAAQ,oBAAiB,UAAO,GAAG,MAAS;EAEpD,EAAI,kCAAkC,KAAK,UAAU,CAAI,KAAK,OAAO;EAGrE,IAAM,IAAa,GAAmB,GAAkB,EAAe,CAAM,CAAC,CAAC,GAGzE,IAAe;GACnB,QAAQ;GACR,aAAa;GACb,OAAO;GACP,GAAG;GACH,GAAG;GACH,GAAI,IACA,EACE,iBAAiB;IACf,GAAI,EAAW,mBAAmB,CAAC;IACnC,GAAI,EAAe,CAAe,KAAK,CAAC;GAC1C,EACF,IACA,CAAC;EACP;EAIA,OAFA,EAAI,+BAA+B,KAAK,UAAU,CAAY,KAAK,OAAO,GAEnE,GAAoB;GAAE,GAAG;GAAc;EAAM,CAAC;CACvD,SAAS,GAAO;EAOd,AANA,EAAI,sDAAsD,OAAO,GAC7D,aAAiB,QACnB,EAAI,QAAQ,EAAM,WAAW,OAAO,IAEpC,EAAI,QAAQ,KAAK,UAAU,GAAO,MAAM,CAAC,KAAK,OAAO,GAEvD,QAAQ,KAAK,CAAC;CAChB;AACF,CAAC;;;ACrKH,SAAgB,EAA4B,GAAQ,GAA2C;CAI7F,AAHA,EAAI,4BAA4B,QAAQ,MAAM,GAC9C,EAAI,yEAAyE,MAAM,GACnF,EAAI,yBAAyB,KAAK,UAAU,CAAI,KAAK,OAAO,GAC5D,EAAI,wBAAwB,KAAO,OAAO;CAE1C,IAAM,IAAM,GAAiB,UAAU,CAAI;CAM3C,OALK,EAAI,YACP,EAAI,4DAA4D,EAAE,cAAc,EAAI,KAAK,KAAK,OAAO,GACrG,QAAQ,KAAK,CAAC,IAEhB,EAAI,2DAA2D,MAAM,GAC9D,EAAI;AACb;AAUA,SAAgB,EAAgB,GAAc,GAA+B;CAC3E,OAAO,OAAO,YACZ,OAAO,QAAQ,CAAI,CAAC,CAAC,QAAQ,CAAC,OAAS,EAAI,qBAAqB,CAAG,MAAM,SAAS,CACpF;AACF;AASA,SAAgB,EAAW,GAAc,GAAgB;CACvD,KAAK,IAAM,KAAO,GAChB,EAAI,UAAU,CAAG;CAEnB,OAAO;AACT;;;AC1DA,IAAM,IAAkB;CACtB,aAAa,CAAC;CACd,YAAY,CAAC;CACb,OAAO,MAAoB;EACzB,AAAK,EAAQ,SAAS,KAAK,KAAG,QAAQ,KAAK,CAAO;CACpD;CACA,QAAQ,MAAoB;EAC1B,AAAK,EAAQ,SAAS,KAAK,KAAG,QAAQ,MAAM,CAAO;CACrD;AACF;AAWA,eAAsB,GAAS,EAAE,aAAU,UAAO,aAAiH;CACjK,EAAI,8BAA8B,EAAS,KAAK,MAAM;CACtD,IAAM,IAAU,IAAI,EAAQ;EAAE,MAAM;EAAO,KAAK;CAAgB,CAAC;CACjE,EAAI,sBAAsB,OAAO;CACjC,IAAM,EAAE,MAAM,MAAS,MAAM,EAAQ,KAAK,MAAM,cAAc,EAAE,YAAS,CAAC,CAAC,CACxE,OAAO,MAAU;EAChB,MAAM,EAAM,WAAW,MAAM,gBAAI,MAAM,6BAA6B,EAAS,GAAG,IAAI;CACtF,CAAC;CAIH,OAHA,EAAI,8BAA8B,OAAO,GAGlC;EAAE;EAAM,OAAA,MAFK,EAAQ,SAAS,EAAQ,KAAK,MAAM,aAAa;GAAE;GAAU,MAAM;GAAa,UAAU;EAAI,CAAC;EAE7F;CAAO;AAC/B;AAUA,eAAsB,GAAgB,EACpC,eACA,YAIC;CACD,EAAI,6CAA6C,EAAW,KAAK,KAAK,MAAM;CAC5E,IAAM,IAAU,IAAI,EAAQ;EAAE,MAAM;EAAO,KAAK;CAAgB,CAAC,GAC3D,EAAE,MAAM,MAAS,MAAM,EAAQ,KAAK,MAAM,IAAI;EAClD,OAAO,EAAW,MAAM;EACxB,MAAM,EAAW;CACnB,CAAC;CACD,IAAI,CAAC,EAAK,QAAQ,OAAO,OACvB,OAAO;EAAE,QAAQ,EAAK;EAAQ,cAAc,CAAC;CAAE;CAEjD,IAAM,IAA2B,CAAC;CAClC,IAAI;EACF,WAAW,IAAM,EAAE,aAAU,EAAQ,SAAS,SAC5C,EAAQ,KAAK,MAAM,kBACnB;GACE,OAAO,EAAK,OAAO,MAAM;GACzB,MAAM,EAAK,QAAQ,QAAQ,EAAK;GAChC,UAAU;EACZ,CACF,GACE,EAAa,KAAK,GAAG,CAAI;CAE7B,SAAS,GAAO;EAKd,OAJA,EACE,uDAAuD,EAAW,KAAK,aAAa,EAAM,WAC1F,MACF,GACO;GAAE,QAAQ,EAAK;GAAQ,cAAc,CAAC;EAAE;CACjD;CAEA,OAAO;EAAE,QAAQ,EAAK;EAAQ;CAAa;AAC7C;AAWA,eAAsB,GAAU,GAAc,GAAa,GAAoB,GAAgB,GAAoB;CACjH,EAAU,GAAY,EAAE,OAAO,GAAK,CAAC;CAErC,IAAI;EAGF,IAAM,IAAM,GAAU;GAAE,SAAS;GAAY,QAAQ;IAAC;IAA0B;IAAa;GAA8B;EAAE,CAAC;EAC9H,MAAM,EAAI,KAAK,CAAC,CACb,UAAU,uBAAuB,QAAQ,IAAM,OAAO,CAAC,CACvD,UAAU,UAAU,CAAG;EAE1B,KAAK,IAAM,KAAQ,GAEjB,AADA,EAAI,WAAW,EAAK,QAAQ,EAAK,0BAA0B,OAAO,GAClE,EAAe,EAAQ,GAAY,2BAA2B,GAAG,GAAG,EAAK,KAAK,MAAM;EAUtF,AAPA,EAAI,wBAAwB,EAAK,KAAK,MAAM,GAC5C,MAAM,EAAI,KAAK,UAAU,CAAM,GAE3B,EAAS,MAAK,MAAQ,EAAK,SAAS,MAAM,CAAC,MAC7C,EAAO,EAAQ,GAAY,MAAM,GAAG,GAAY,EAAE,WAAW,GAAK,CAAC,GACnE,EAAO,EAAQ,GAAY,MAAM,GAAG,EAAE,WAAW,GAAK,CAAC,IAEzD,EAAO,EAAQ,GAAY,MAAM,GAAG,EAAE,WAAW,GAAK,CAAC;CACzD,SAAS,GAAO;EACd,EAAI,qCAAqC,EAAM,IAAI,OAAO;CAC5D;AACF;;;AC1HA,IAAa,KAAiB;AAa9B,eAAe,EAAU,GAAc,GAA6B;CAClE,IAAM,IAAW,MAAM,MAAM,GAAG,KAAiB,KAAQ,EACvD,SAAS,IAAQ,EAAE,iBAAiB,EAAM,IAAI,CAAC,EACjD,CAAC;CACD,IAAI,CAAC,EAAS,IACZ,MAAU,MAAM,kCAAkC,EAAK,aAAa,EAAS,OAAO,GAAG;CAEzF,OAAO;EAAE,MAAM,MAAM,EAAS,KAAK;EAAG,SAAS,EAAS;CAAQ;AAClE;AASA,eAAe,EAAa,GAAc,GAA6B;CACrE,IAAM,IAAY,EAAK,SAAS,GAAG,IAAI,MAAM,KACvC,IAAe,CAAC,GAClB,IAAsB;CAE1B,OAAO,IAAM;EACX,IAAM,EAAE,SAAM,eAAY,MAAM,EAAU,GAAG,IAAO,EAAU,oBAAoB,KAAQ,CAAK;EAE/F,AADA,EAAM,KAAK,GAAG,CAAI,GAClB,IAAO,EAAQ,IAAI,aAAa,KAAK;CACvC;CACA,OAAO;AACT;AAQA,SAAS,EAAQ,GAAW;CAC1B,OAAO;EACL,OAAO,EAAK,YAAY,EAAK;EAC7B,MAAM,EAAK;EACX,KAAK,EAAK,OAAO,EAAK,eAAe;EACrC,YAAY,EAAK;EACjB,UAAU,EAAK;CACjB;AACF;AASA,SAAS,EAAc,GAAc,GAAe;CAClD,OAAO;EACL,MAAM,EAAQ;EACd,OAAO,EAAE,OAAO,EAAM;EACtB,MAAM,CAAC,CAAC,EAAQ;EAChB,SAAS,EAAQ,eAAe;EAEhC,MAAM,KAAQ;EACd,gBAAgB,EAAQ;EACxB,WAAW,EAAQ;EACnB,UAAU,EAAQ;EAClB,aAAa,EAAQ;EACrB,kBAAkB,EAAQ;CAC5B;AACF;AAYA,eAAsB,GAAS,EAAE,aAAU,UAAO,aAAiH;CACjK,EAAI,8BAA8B,EAAS,KAAK,MAAM;CAEtD,IAAM,EAAE,MAAM,MAAU,MAAM,EAAU,mBAAmB,mBAAmB,CAAQ,KAAK,CAAK;CAEhG,IAAI,EAAM,QAAQ;EAChB,IAAI,IAAO,EAAM;EAKjB,AAJI,MAEF,IAAO,MAAM,EAAU,UAAU,EAAM,EAAE,CAAC,MAAM,CAAK,CAAC,CAAC,MAAK,MAAO,EAAI,IAAI,CAAC,CAAC,YAAY,EAAM,EAAE,IAEnG,EAAI,8BAA8B,OAAO;EACzC,IAAM,IAAW,MAAM,EAAa,UAAU,EAAM,EAAE,CAAC,GAAG,YAAY,CAAK;EAC3E,OAAO;GAAE,MAAM,EAAQ,CAAI;GAAG,OAAO,EAAS,KAAI,MAAW,EAAc,GAAS,EAAK,QAAQ,CAAC;GAAG;EAAO;CAC9G;CAEA,EAAI,sBAAsB,EAAS,0BAA0B,OAAO;CACpE,IAAM,IAAQ,MAAM,EAAU,WAAW,mBAAmB,CAAQ,EAAE,uBAAuB,CAAK,CAAC,CAChG,MAAK,MAAO,EAAI,IAAI,CAAC,CACrB,YAAY;EACX,MAAU,MAAM,sCAAsC,EAAS,GAAG;CACpE,CAAC,GACG,IAAW,MAAM,EAAa,WAAW,mBAAmB,CAAQ,EAAE,YAAY,CAAK;CAC7F,OAAO;EAAE,MAAM,EAAQ,CAAK;EAAG,OAAO,EAAS,KAAI,MAAW,EAAc,GAAS,EAAM,IAAI,CAAC;EAAG;CAAO;AAC5G;;;ACpFA,SAAgB,EAAgB,GAA6D,GAA6B,GAAsD;CAC9K,IAAI,MAAgB,UAAU;EAC5B,IAAM,IAAO,EAAK,YAAY,sBAAsB,EAAK,MAAM,MAAM,GAAG,EAAK;EAC7E,OAAO;GACL,UAAU,GAAG,EAAK,UAAU;GAC5B,UAAU,GAAG,EAAK,UAAU;GAC5B,SAAS,GAAG,EAAK,SAAS;EAC5B;CACF;CACA,IAAM,IAAO,EAAK,YAAY,sBAAsB,EAAK,MAAM,MAAM,GAAG,EAAK;CAC7E,OAAO;EACL,UAAU,GAAG,EAAK,QAAQ;EAC1B,UAAU,GAAG,EAAK,QAAQ;EAC1B,SAAS,qCAAqC,EAAK,MAAM,MAAM,GAAG,EAAK,KAAK,GAAG;CACjF;AACF;AAQA,eAAsB,GAAS,GAAoB;CAKjD,OAAO;EACL,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,WAAW;EAMzE,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,MAAM;EAMpE,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,mBAAmB;CAMnF;AACF;AAYA,eAAsB,GAAS,EAAE,aAAU,WAAQ,gBAAa,gBAAa,YAAwB;CAEnG,OADyB,MAAgB,WAAW,KAAiB,GAAA,CAC9C;EAAE;EAAU;EAAO;CAAO,CAAC,CAAC,CAChD,KAAK,OAAO,EAAE,SAAM,UAAO,gBAAa,GAAc,GAAM,GAAO,GAAQ,GAAa,CAAW,CAAC,CAAC,CACrG,KAAK,OAAO,EAAE,eAAY,GAAO,GAAO,CAAW,CAAC;AACzD;AAUA,eAAsB,GAAoB,GAAsD,GAA8B,GAAwC,GAAwC;CAC5M,IAAM,IAAsC,CAAC;CA4B7C,OA1BA,MAAM,QAAQ,IACZ,EAAM,IAAI,OAAO,MAAS;EACxB,IAAM,IAAiB,KAAU,EAAK,kBAAkB,QAClD,IAAc,EAAQ,GAAU,EAAS,EAAK,MAAM,EAAE,WAAW,GAAK,CAAC,CAAC,GACxE,IAAW,EAAe,GAAM,CAAW,GAC3C,IAAO,EAAgB,GAAM,GAAgB,CAAW,GAC1D,IAAqB,CAAC;EAM1B,AAJI,CAAC,EAAK,QAAQ,CAAC,EAAK,WAAW,CAAC,MAClC,IAAW,MAAM,GAAkB,GAAM,GAAgB,CAAW,IAGtE,EAAc,KAAK;GACjB,GAAG;GACH,UAAU;IACR;IACA,QAAQ;IACR;IACA;IACA,SAAS,EAAK;IACd,aAAa,EAAK;GACpB;EACF,CAAC;CACH,CAAC,CACH,GAEO;AACT;AAUA,eAAsB,GAAkB,GAA6D,GAA6B,GAAwC;CACxK,IAAM,IAAa,MAAM,GAAS,EAAgB,GAAM,GAAQ,CAAW,CAAC,GAEtE,IAAqB,CAAC;CAU5B,OATI,OAAO,OAAO,CAAU,CAAC,CAAC,OAAM,MAAU,MAAW,GAAG,KAAK,CAAC,EAAK,OAC9D,CAAC,KAEN,EAAW,qBAAqB,OAClC,EAAS,KAAK,QAAQ,IAEpB,EAAW,qBAAqB,OAAO,EAAW,qBAAqB,QACzE,EAAS,KAAK,aAAa,iBAAiB,GAEvC;AACT;AAYA,eAAsB,GAAc,GAAoD,GAAsD,GAA8B,GAAwC,GAAwC;CAC1P,EAAc,GAAG,EAAa,QAAQ,EAAK,MAAM,QAAQ,KAAK,UAAU,GAAM,MAAM,CAAC,CAAC;CAEtF,IAAM,IAAgB,MAAM,GAAoB,GAAO,GAAQ,GAAa,CAAW;CAGvF,OAFA,EAAc,GAAG,EAAa,SAAS,EAAK,MAAM,QAAQ,KAAK,UAAU,GAAe,MAAM,CAAC,CAAC,GAEzF;EAAE;EAAM,OAAO;CAAc;AACtC;AAQA,eAAsB,GAAO,GAA8B,GAAwC;CACjG,IAAI,CAAC,GAAO;EACV,EAAI,4CAA4C,MAAM;EACtD;CACF;CAEA,MAAM,QAAQ,IACZ,EACG,QAAO,MAAQ,CAAC,EAAe,GAAM,CAAW,CAAC,CAAC,CAClD,IAAI,OAAO,MAAS;EACnB,MAAM,GAAU,EAAK,MAAM,EAAK,WAAqB,EAAK,SAAS,aAAa,EAAK,SAAS,QAAQ,EAAK,SAAS,QAAQ;CAC9H,CAAC,CACL;AACF;AASA,SAAgB,EAAe,GAAkF,GAAwC;CACvJ,IAAM,IAAoB,GAAa,OAAO,MAAmB,EAAO,WAAW,GAAG,CAAC,GACjF,IAAa,GAAa,QAAQ,MAAmB,EAAO,WAAW,GAAG,CAAC,CAAC,CAC/E,MAAM,MAAmB,EAAK,SAAS,EAAO,UAAU,CAAC,CAAC,GACvD,IAAa,CAAC,KACf,GAAa,QAAQ,MAAmB,CAAC,EAAO,WAAW,GAAG,CAAC,CAAC,CAAC,SAAS,EAAK,IAAI,KAClF,EAAK,QAAQ,CAAC,KACd,KAAqB,CAAC,GAEtB,IAAa,KAAc,CAAC;CASlC,OAPI,cAAc,KAAQ,CAAC,EAAK,SAAS,SAAS,SACzC,KAGT,EAAM,EAAK,aAAa,CAAC,EAAK,WAAW,CAAC;AAI5C;;;ACxNA,IAAa,IAAa;CACxB,EAAa,yBAAyB,EAAU,MAAM,OAAO,WAAW;CACxE,EAAa,wBAAwB,EAAU,MAAM,MAAM,WAAW;CACtE,EAAa,4BAA4B,EAAU,MAAM,UAAU,WAAW;AAChF,GCGM,KAAU,SAKH,KAAY;CACvB,EAAa,yBAAyB,EAAa,MAAM,OAAO,WAAW,CAAC,CACzE,QAAQ,EAAa,MAAM,OAAO,IAAI,YAAY;CACrD,EAAa,+BAA+B,EAAa,MAAM,YAAY,WAAW,CAAC,CACpF,QAAQ,EAAa,MAAM,YAAY,IAAI,YAAY;CAC1D,EAAa,+BAA+B,EAAa,MAAM,YAAY,WAAW;AACxF,GAKa,KAAW,EAAW,EAAc,EAAO,GAAG,CAAC,GAAG,IAAW,GAAG,CAAU,CAAC,CAAC,CACtF,YAAY,yDAAyD,CAAC,CACtE,OAAO,OAAO,GAAM,MAAQ;CAE3B,MAAM,GADa,EAAa,IAAS,EAAgB,GAAK,CAAI,CACvD,CAAU;AACvB,CAAC;AAOH,eAAsB,GAAK,GAAiB;CAC1C,IAAM,EAAE,cAAW,gBAAa,UAAO,WAAQ,mBAAgB;CAG/D,AAFA,EAAI,wGAAwG,MAAM,GAElH,EAAU,GAAc,EAAE,OAAO,GAAK,CAAC;CACvC,KAAK,IAAM,KAAY,GAKrB,MAAM,GAAS;EAAE;EAAU;EAAQ,aAHnB,EAAU,SAAS,IAC/B,GAAa,QAAQ,MAAe,EAAG,QAAQ,MAAM,EAAE,CAAC,CAAC,WAAW,GAAG,EAAS,EAAE,CAAC,CAAC,CAAC,KAAK,MAAe,EAAG,QAAQ,GAAG,EAAS,IAAI,EAAE,CAAC,IACvI;EACqD;EAAa;CAAM,CAAC;AAEjF;;;ACtCA,eAAsB,GAAuB,GAAwC;CAEnF,IAAM,IAAe,QAAQ;CAG7B,QAAQ,OAAO,SAAU,GAAG,GAAM;EAE9B,EAAK,SAAS,KACX,OAAO,EAAK,MAAO,aAClB,EAAK,EAAE,CAAC,SAAS,mCAAmC,KACnD,EAAK,EAAE,CAAC,SAAS,iBAAiB,MAMzC,EAAa,MAAM,SAAS,CAAI;CAClC;CAEA,IAAI;EAEF,OAAO,MAAM,EAAS;CACxB,UAAU;EAER,QAAQ,OAAO;CACjB;AACF;AAUA,IAAa,KAAW,EAAW,EAAc,OAAO,GAAG,CAAU,CAAC,CACnE,YAAY,0BAA0B,CAAC,CACvC,OAAO,OAAO,MAAU;CACvB,MAAM,GAAK;AACb,CAAC;AAMH,eAAsB,KAAO;CAC3B,EAAI,8CAA8C,MAAM;CAExD,IAAI;EAUF,AARA,MAAM,GAAoB,YAAY;GACpC,MAAM,GAAe,GAAc,EACjC,qBAAqB,GAAY;IAC/B,GAAY,CAAmC;GACjD,EACF,CAAC;EACH,CAAC,GAED,EAAI,iCAAiC,SAAS;CAChD,SAAS,GAAO;EAEd,AADA,EAAI,+BAA+B,KAAS,OAAO,GACnD,QAAQ,KAAK,CAAC;CAChB;AACF;;;ACrEA,SAAgB,GAAa,GAAa,GAAc;CACtD,IAAM,IAAU,EAAa,GAAK,EAAE,UAAU,OAAO,CAAC;CAEtD,AADA,EAAU,EAAQ,CAAI,CAAC,GACvB,EAAc,GAAM,CAAO;AAC7B;;;ACPA,IAAM,KAA0D;CAC9D,MAAM;CACN,MAAM;CACN,MAAM,EACJ,WAAW,YACb;CACA,OAAO;CACP,aAAa;CACb,QAAQ;CACR,WAAW;CACX,iBAAiB;CACjB,aAAa;EACX,SAAS,CAAC,GAAG,CAAC;EACd,QAAQ;GACN,UAAU;GACV,SAAS,EACP,cAAc;IACZ,QAAQ;KACN,YAAY;KACZ,iBAAiB;IACnB;IACA,OAAO;KACL,iBAAiB;KACjB,gBAAgB;KAChB,eAAe;KACf,kBAAkB;KAClB,QAAQ;MACN,YAAY;MACZ,cAAc;MACd,WAAW;KACb;IACF;GACF,EACF;EACF;CACF;AACF;AAUA,SAAgB,GAAmB,GAA2B,GAAa,GAA6F;CAItK,OAHe,IACX,EAAU,IAAwB,GAAiB,EAAE,aAAa;EAAE;EAAS;CAAI,EAAE,CAAC,IACpF,EAAU,IAAwB,EAAE,aAAa;EAAE;EAAS;CAAI,EAAE,CAAC;AAEzE;;;ACYA,eAAsB,GAAW,EAAE,qBAAkB,uBAAoB,eAAY,oBAAiB,UAAO,gBAAa,UAAO,aAAU,iBAAc,qBAA8H;CAErR,IAAM,IAAe,KAAS,MAAgB;CAC9C,AAAI,KAAS,CAAC,KACZ,EAAI,4EAA4E,MAAM;CAExF,IAAM,IAAO,GAAa,CAAQ,GAC5B,IAAe,GAAa,CAAQ,CAAC,CACxC,QAAQ,EAAE,cAAW,YAA2E,MAAQ;EACvG,IAAM,EAAE,cAAW,SAAS,GAAa,SAAM,gBAAa;EAC5D,IAAI,KAAa,CAAC,KAAe,CAAC,EAAS,UACzC;OAAI,CAAC,KAAQ,EAAS,SAAS,QAC7B,OAAO;IAAE,WAAW,CAAC,GAAG,GAAW,CAAG;IAAG;GAAM;GAC1C,IAAI,GACT,OAAO;IAAE;IAAW,OAAO,CAAC,GAAG,GAAO,CAAG;GAAE;EAC7C;EAEF,OAAO;GAAE;GAAW;EAAM;CAC5B,GAAG;EAAE,WAAW,CAAC;EAAG,OAAO,CAAC;CAAE,CAAC,GAE3B,IAAe;EAAE,OAAO;EAAc,SAAS;CAAe,GAC9D,EAAE,UAAO,eAAY,GAAa,EAAa,WAAW,GAAM,CAAY,GAE9E,GACA;CACJ,IAAI,EAAW,CAAU,KAAK,EAAW,CAAgB,GAAG;EAC1D,IAAM,IAAe,MAAM,GAAqB,CAAgB,GAC1D,IAAc,MAAM,GAAoB,CAAU;EAKxD,AAJA,IAAU,CACR,GAAI,EAAa,aAAa,WAA+B,CAAC,GAC9D,GAAG,CACL,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,GAC7C,IAAa;GACX,GAAG;GACH,UAAU,CACR,GAAG,EAAY,UACf,GAAG,EAAM,QACX,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;EACjD;CACF,OAEE,AADA,IAAU,GACV,IAAa;CAEf,IAAM,IAAc,CAAC;CAErB,IAAI,GAAkB;EACpB,IAAM,IAAQ,GAAc,CAAgB;EAC5C,AAAI,IACF,EAAI,KAAK,GAAG,EAAM,QAAO,MAAK,EAAE,SAAS,QAAQ,CAAC,IAElD,EAAI,KAAK,GAAG,CAAK;CAErB;CAiBA,AAhBI,MACF,EAAI,kDAAkD,MAAM,GAC5D,GAAW,GAAoB,EAAQ,GAAc,QAAQ,CAAC,IAE5D,MACF,EAAI,wCAAwC,MAAM,GAClD,GAAW,GAAY,EAAQ,EAAoB,CAAC,IAElD,KAAgB,EAAS,WAC3B,EAAI,uDAAuD,MAAM,GACjE,MAAM,GAAa,EAAa,OAAO,GAAU,CAAK,GACtD,EAAI,KAAK;EAAE,MAAM;EAAS,MAAM;CAAS,CAAC,IAK5C,GAFe,GAAmB,GAAS,GAAK,CAEzB,GAAQ,CAAU;AAC3C;AAQA,SAAgB,GAAW,GAAiB,GAAoB;CAM9D,EAAe,GAAY,GAJb,EADG,EAAS,CACH,GAAU;EAAE,MAAM;EAAa,WAAW;CAAK,CAAC,MAAM,cAAc,iBAAiB,YAE5E,2CAA2C,EAAQ,OAExC,MAAM;AACnD;AAkBA,SAAgB,GAAc,GAAqB,GAAuC,GAA4B;CACpH,IAAM,EAAE,SAAM,UAAO,WAAQ,GACvB,EAAE,UAAO,eAAY;CAM3B,OAAO;EACL,QAAQ;EACR,MANW,IACT;GAAE,MAAM;GAAO;EAAQ,IACvB;GAAE,MAAM,IAAO,GAAG,EAAK,eAAe,GAAG,EAAM;GAAc,SAAS,KAAO;EAA2B;EAK1G;CACF;AACF;AAUA,SAAgB,GAAiB,GAAkB,GAAqB,GAAsB;CAC5F,IAAM,IAAU;EACd,OAAO,EAAS,GAAU;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EACnE,SAAS;EACT,MAAM,IAAI,EAAS,GAAU,EAAE,WAAW,GAAK,CAAC,EAAE;CACpD;CAEA,OAAO,IAAW,CAAC,GAAG,GAAU,CAAO,IAAI,CAAC,CAAO;AACrD;AASA,SAAgB,GAAuB,GAAkB,GAAyC;CAChG,OAAO;EACL,MAAM,EAAS,GAAU;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EAClE,WAAW;EACX,OAAO;CACT;AACF;AA0BA,SAAgB,GAAqB,GAAgC,GAAqC;CACxG,OAAO,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,GAAK,OACpC,MAAQ,MACN,MAAM,QAAQ,CAAK,IACd,EAAM,KAAK,MAAY;EAC5B,IAAM,IAAO,EAAQ,EAAW,SAAS,aAAa,CAAO,GACzD,IAAW,EAAS,EAAS,CAAI,GAAG;GAAE,MAAM;GAAa,WAAW;EAAK,CAAC;EAQ9E,OAPI,MAAa,gBACf,IAAW,oBAET,MAAa,EAAS,CAAI,KAC5B,EAAW,GAAM,EAAQ,EAAQ,CAAI,GAAG,CAAQ,CAAC,GAG5C;GACL,MAAM,EAAM,CAAQ,CAAC,CAAC,SAAS,iBAC3B,iBACA,EAAS,GAAU;IAAE,MAAM;IAAc,aAAa;IAAM,WAAW;GAAK,CAAC;GACjF,MAAM,IAAI,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,EAAE,GAAG,EAAM,CAAQ,CAAC,CAAC;EAC9E;CACF,CAAC,IAEI,CAAC,IACC,OAAO,KAAU,WACnB,CAAC;EACN,MAAM,EAAS,GAAK;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EAC7D,WAAW;EACX,OAAO,GAAqB;GAAE,GAAG;GAAY,MAAM,GAAG,EAAW,KAAK,GAAG;EAAM,GAAG,CAAK;CACzF,CAAmB,IAGd,CAAC,CACT;AACH;AAQA,SAAgB,GAAU,GAAsB;CAC9C,OAAO,EAAM,QAAQ,GAAM,MAAS;EAClC,IAAM,CAAC,GAAO,GAAG,KAAQ,EAAK,MAAM,GAAG;EAUvC,OATK,EAAK,SAIR,EAAK,KAAS,GAAU,CACtB,GAAI,EAAK,KAAS,GAAY,EAAK,IAAQ,EAAE,IAAI,CAAC,GAClD,EAAK,KAAK,GAAG,CACf,CAAC,IALD,EAAK,IAAO,CAAC,GAAI,EAAK,KAAQ,CAAC,GAAI,CAAK,GAOnC;CACT,GAAG,CAAC,CAAwB;AAC9B;AASA,SAAgB,GAAY,GAAc,IAAS,IAAc;CAC/D,OAAO,OAAO,QAAQ,CAAO,CAAC,CAAC,SAAS,CAAC,GAAK,OACxC,MAAQ,MACN,MAAM,QAAQ,CAAK,IACd,EAAM,KAAK,MAAe,IAAS,GAAG,EAAO,GAAG,MAAM,CAAE,IAExD,CAAC,IAGL,GAAY,GAAO,IAAS,GAAG,EAAO,GAAG,MAAQ,CAAG,CAC5D;AACH;AAQA,SAAS,GAAgB,GAAgC;CACvD,IAAI,CAAC,MAAM,QAAQ,CAAG,GACpB,OAAO;CAET,IAAM,IAAa,EAAI,WAAU,MAAQ,EAAK,SAAS,SAAS;CAChE,IAAI,MAAe,IACjB,OAAO;CAET,IAAM,CAAC,KAAW,EAAI,OAAO,GAAY,CAAC;CAE1C,OADA,EAAI,KAAK,CAAO,GACT;AACT;AAUA,SAAgB,GAAa,GAAoC,GAAuC,GAA4B;CAClI,IAAM,IAAsB,CAAC,GACvB,IAA4B,CAAC;CAEnC,KAAK,IAAM,KAAc,GAAc;EAWrC,AAVA,EAAI,mCAAmC,EAAW,KAAK,KAAK,MAAM,GAClE,EAAW,CAAC,EAAW,SAAS,WAAW,CAAC,CAAC,CAAC,SAAS,MAAS;GAI9D,AAHA,EAAI,uBAAuB,EAAS,CAAI,EAAE,oBAAoB,EAAW,KAAK,KAAK,OAAO,GAC1F,GAAoB,GAAM,EAAW,SAAS,WAAW,GAErD,EAAS,CAAI,CAAC,CAAC,YAAY,MAAM,eACnC,GAAkB,GAAM,EAAW,SAAS,WAAW;EAE3D,CAAC,GAED,EAAI,uCAAuC,EAAW,KAAK,KAAK,MAAM;EACtE,IAAM,IAAe,EAAY,EAAW,SAAS,aAAa,EAAE,WAAW,GAAK,CAAC,CAAC,CACnF,QAAQ,MAAS;GAChB,IAAM,IAAW,EAAQ,EAAW,SAAS,aAAa,EAAK,SAAS,CAAC;GAGzE,OAAO,EAAS,CAAQ,CAAC,CAAC,SAAS,KAAK,KAAK,EAAO,CAAQ;EAC9D,CAAC,CAAC,CACD,KAAK;EAER,EAAI,kCAAkC,EAAW,KAAK,KAAK,MAAM;EACjE,IAAI;EAOJ,AANI,EAAa,SAAS,KACxB,IAAa,EAAQ,EAAW,SAAS,aAAa,YAAY,GAClE,EAAa,KAAK,YAAY,KACrB,EAAa,WAAW,MACjC,IAAa,EAAQ,EAAW,SAAS,aAAa,EAAa,EAAE,IAEnE,IACF,GAAW,EAAW,UAAU,CAAU,IAE1C,EAAI,8CAA8C,EAAW,KAAK,uBAAuB,MAAM;EAIjG,IAAM,IAAe,GAAgB,GAAqB,GADtC,GAAU,CACwC,CAAW,CAAC;EAGlF,AADA,EAAQ,KAAK,GAAuB,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,GAAG,CAAY,CAAC,GACjG,EAAS,KAAK,GAAG,GAAiB,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,GAAG,EAAW,eAAe,EAAE,CAAC;CACjH;CAEA,EAAI,8BAA8B,MAAM;CACxC,IAAM,IAAQ,GAAc,EAAS,UAAU,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC,GAAG,GAAM,CAAY;CAC3G,OAAO;EACL,SAAS,EAAQ,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;EAChE;CACF;AACF;AAQA,SAAgB,GAAc,GAAiB;CAC7C,IAAM,IAAQ,EAAW,CAAK,GACxB,IAAc,CAAC;CAErB,EAAI,0CAA0C,MAAM;CACpD,KAAK,IAAM,KAAQ,GAAO;EACxB,EAAI,uBAAuB,EAAK,KAAK,OAAO;EAC5C,IAAM,IAAM,EAAQ,QAAQ,IAAI,GAAG,CAAI;EAGvC,AADA,EAAO,GADM,EAAQ,GAAU,EAAS,EAAS,CAAI,GAAG;GAAE,MAAM;GAAa,WAAW;EAAK,CAAC,CAClF,CAAI,GAChB,EAAI,KAAK;GACP,MAAM,EAAS,EAAM,CAAG,CAAC,CAAC,MAAM;IAAE,aAAa;IAAM,WAAW;GAAK,CAAC;GACtE,MAAM,IAAI,EAAS,EAAM,CAAG,CAAC,CAAC,MAAM;IAAE,WAAW;IAAM,MAAM;GAAY,CAAC;EAC5E,CAAC;CACH;CACA,OAAO;AACT;AASA,SAAgB,GAAW,GAA0B,GAAa,GAAiB;CACjF,KAAK,IAAM,KAAQ,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC,CAAK,GAAG;EACzD,IAAM,IAAe,EAAQ,QAAQ,IAAI,GAAG,CAAI,GAC1C,IAAQ,EAAa,CAAY;EAEvC,KAAK,IAAM,KAAQ,GAAO;GACxB,IAAM,IAAgB,EAAK,QAAQ,GAAc,GAAG;GACpD,EAAI,uBAAuB,EAAc,eAAe,EAAK,KAAK,OAAO;GACzE,IAAM,IAAM,EAAQ,QAAQ,IAAI,GAAG,CAAI,GACjC,IAAO,EAAQ,GAAK,CAAa;GAIvC,AAHI,KACF,EAAG,GAEL,EAAO,GAAK,CAAI;EAClB;CACF;AACF;AAOA,SAAgB,GAAY,GAAuG;CAIjI,IAAM,IAAc,EAAM,KAAK,EAAE,eAAY,uBAAoB;EAC/D,IAAM,EAAE,SAAM,UAAO,aAAU,gBAAa,wBAAqB;EACjE,OAAO;GAAE;GAAM,OAAO,EAAM;GAAO;GAAU;GAAa;GAAkB;EAAc;CAC5F,CAAC;CAED,AADA,EAAI,2BAA2B,MAAM,GACrC,EAAc,IAAY,wCAAqB,EAAK,UAAU,CAAW,IAAI,4kBAAgB;AAC/F;AAeA,eAAsB,GAAa,GAAoC,GAA2C,GAA6B;CAW7I,GAAY,MAVQ,QAAQ,IAC1B,EAAa,IAAI,OAAO,MAAe;EACrC,IAAM,EAAE,WAAQ,oBAAiB,MAAM,GAAgB;GAAE;GAAY;EAAM,CAAC;EAC5E,OAAO;GACL,eAAe,GAAc,MAAK,MAAe,EAAY,UAAU,CAAQ,CAAC,EAAE,iBAAiB;GACnG,YAAY;EACd;CACF,CAAC,CACH,CAAC,CAAC,MAAK,MAAK,EAAE,QAAQ,EAAE,eAAY,uBAAoB,CAAC,CAAC,KAAc,CAAa,CAAC,CAErE;AACnB;AAQA,eAAsB,GAAqB,GAAiE;CAC1G,IAAI;EACF,IAAM,EAAE,cAAW,MAAM,OAAO,EAAQ,QAAQ,IAAI,GAAG,CAAI;EAC3D,OAAO,KAAU,CAAC;CACpB,SAAS,GAAO;EAEd,OADA,EAAI,gDAAgD,EAAK,oCAAoC,aAAiB,QAAQ,EAAM,UAAU,MAAM,MAAM,GAC3I,CAAC;CACV;AACF;AAQA,eAAsB,GAAoB,GAA8B;CACtE,IAAM,KAAS,MAAM,GAAS,EAAQ,QAAQ,IAAI,GAAG,CAAI,CAAC,EAAA,CAAG,SAAS;CACtE,OAAO,EAAK,MAAM,CAAK;AACzB;AASA,SAAgB,GAAuB,GAA2D,GAAc;CAS9G,OAPA,EAAU,EAAQ,CAAgB,CAAC,GAEnC,EAAI,iCAAiC,MAAM,GAC3C,EAAc,GAAkB,yBAAyB,KAAK,UAAU,GAAiB,MAAM,CAAC,EAAE,4BAA4B,GAC9H,EAAI,2BAA2B,MAAM,GACrC,EAAc,GAAY,UAAY,EAAK,UAAU,CAAK,CAAC,GAC3D,EAAI,gCAAgC,MAAM,GACnC,EAAa,CAAc,CAAC,CAAC,SAAS,MAAS;EAEpD,GAAa,GAAM,EAAQ,IADN,EAAK,QAAQ,GAAG,EAAe,IAAI,EACZ,CAAY,CAAC;CAC3D,CAAC;AACH;;;ACjhBA,IAAM,KAAU,WAKH,KAAc;CACzB,EAAa,uCAAuC,EAAa,MAAM,mBAAmB,WAAW;CACrG,EAAa,eAAe,EAAa,MAAM,MAAM,WAAW;CAChE,EAAa,qCAAqC,EAAa,MAAM,iBAAiB,WAAW;CACjG,EAAa,8BAA8B,EAAa,MAAM,WAAW,WAAW;CACpF,EAAa,mCAAmC,EAAa,MAAM,gBAAgB,WAAW;CAC9F,EAAa,4BAA4B,EAAa,MAAM,aAAa,WAAW;CACpF,EAAa,8BAA8B,EAAa,MAAM,eAAe,WAAW;AAC1F,GAKa,KAAa,EAAW,EAAc,EAAO,GAAG,CAAC,GAAG,IAAa,GAAG,CAAU,CAAC,CAAC,CAC1F,YAAY,+CAA+C,CAAC,CAC5D,OAAO,OAAO,GAAM,MAAQ;CAE3B,MAAM,GADa,EAAa,IAAS,EAAgB,GAAK,CAAI,CACvD,CAAU;AACvB,CAAC;AAOH,eAAsB,GAAK,GAAmB;CAC5C,IAAM,EAAE,qBAAkB,uBAAoB,eAAY,oBAAiB,UAAO,gBAAa,UAAO,cAAW,iBAAc,sBAAmB;CAGlJ,AAFA,EAAI,0DAA0D,MAAM,GAEpE,EAAU,EAAQ,CAAgB,GAAG,EAAE,OAAO,GAAK,CAAC;CACpD,KAAK,IAAM,KAAY,GACrB,MAAM,GAAW;EAAE;EAAkB;EAAoB;EAAY;EAAiB;EAAO;EAAa;EAAO;EAAU;EAAc;CAAe,CAAC;AAE7J;;;ACtCA,SAAgB,KAAa;CAC3B,IAAM,IAAK,IAAI,EAAQ,CAAC,CACrB,KAAK,UAAU,CAAC,CAChB,YAAY,iDAAiD,CAAC,CAC9D,QAAQ,GAAG,GAAI,SAAS,CAAC,CACzB,OAAO,OAAO,GAAM,MAAQ;EAC3B,IAAM,IAAa,EAAa,UAAU,EAAgB,GAAK,CAAI,CAAC;EAGpE,AAFA,MAAM,GAAQ,CAAU,GACxB,MAAM,GAAU,CAAU,GAC1B,MAAM,GAAQ;CAChB,CAAC,CAAC,CACD,cAAc;EACb,iBAAiB;EACjB,aAAa;EACb,mBAAmB;CACrB,CAAC,CAAC,CACD,wBAAwB,CAAC,CACzB,mBAAmB,CAAC,CACpB,WAAW,EAAQ,CAAC,CACpB,WAAW,EAAU,CAAC,CACtB,WAAW,EAAQ;CAItB,OAFA,EAAW,GAAI;EAAC,GAAG;EAAW,GAAG;EAAa,GAAG;CAAU,CAAC,GAErD;AACT;AAMA,SAAgB,KAAO;CAErB,GAAA,CAAA,CAAG,WAAW,QAAQ,IAAI,CAAC,CAAC,OAAO,MAAU;EAE3C,AADA,EAAI,KAAK,aAAiB,QAAQ,EAAM,UAAU,OAAO,CAAK,KAAK,OAAO,GAC1E,QAAQ,KAAK,CAAC;CAChB,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../package.json","../src/utils/const.ts","../src/utils/regex.ts","../src/utils/functions.ts","../src/utils/logger.ts","../src/schemas/global.ts","../src/utils/commands.ts","../src/lib/git.ts","../src/lib/gitlab.ts","../src/lib/fetch.ts","../src/commands/global.ts","../src/commands/fetch.ts","../src/commands/build.ts","../src/utils/templates.ts","../src/lib/vitepress.ts","../src/lib/prepare.ts","../src/commands/prepare.ts","../src/cli.ts"],"sourcesContent":["{\n \"name\": \"@tobi-or-not/docpress\",\n \"type\": \"module\",\n \"version\": \"0.10.0\",\n \"packageManager\": \"bun@1.3.14\",\n \"homepage\": \"https://this-is-tobi.com/docpress/introduction\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/this-is-tobi/docpress.git\"\n },\n \"bin\": {\n \"docpress\": \"bin/docpress.js\"\n },\n \"files\": [\n \"bin\",\n \"dist\"\n ],\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"scripts\": {\n \"build\": \"bun run build:clean && bun run build:types && bun run build:vite\",\n \"build:clean\": \"rimraf ./dist ./types ./tsconfig.tsbuildinfo\",\n \"build:docker\": \"docker build --tag tobi-or-not/docpress --target prod .\",\n \"build:types\": \"tsc\",\n \"build:vite\": \"vite build\",\n \"dev\": \"bun ./dev/docpress.ts\",\n \"dev:clean\": \"rimraf ./docpress && bun run dev\",\n \"format\": \"eslint . --fix\",\n \"lint\": \"eslint .\",\n \"prepare\": \"husky || true\",\n \"start\": \"./bin/docpress.js\",\n \"start:docker\": \"docker run --name docpress --rm -v $(pwd)/docpress:/app/docpress:rw tobi-or-not/docpress\",\n \"stop:docker\": \"docker rm --force docpress\",\n \"test\": \"vitest run\",\n \"test:cov\": \"vitest run --coverage\",\n \"vp:build\": \"vitepress build ./docpress\",\n \"vp:build:docker\": \"docker build --tag tobi-or-not/docs --target prod .\",\n \"vp:dev\": \"vitepress dev ./docpress --port 8080\",\n \"vp:dev:docker\": \"docker run --publish 8080:8080 --name docpress-vp --rm tobi-or-not/docs\",\n \"vp:preview\": \"vitepress preview ./docpress --port 8080\"\n },\n \"dependencies\": {\n \"@octokit/rest\": \"^22.0.1\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^15.0.0\",\n \"rimraf\": \"^6.1.3\",\n \"simple-git\": \"^3.36.0\",\n \"vitepress\": \"^1.6.4\",\n \"vitepress-plugin-mermaid\": \"^2.0.17\",\n \"yaml\": \"^2.9.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@antfu/eslint-config\": \"^9.1.0\",\n \"@commitlint/cli\": \"^21.2.0\",\n \"@commitlint/config-conventional\": \"^21.2.0\",\n \"@octokit/types\": \"^16.0.0\",\n \"@types/node\": \"^26.1.0\",\n \"@vitejs/plugin-vue\": \"^6.0.7\",\n \"@vitest/coverage-v8\": \"^4.1.9\",\n \"eslint\": \"^10.6.0\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^17.0.8\",\n \"typescript\": \"^6.0.3\",\n \"vite\": \"^8.1.3\",\n \"vitest\": \"^4.1.9\",\n \"vue\": \"^3.5.39\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\",\n \"tag\": \"latest\"\n }\n}\n","import { resolve } from 'node:path'\n\n/**\n * Main directory for DocPress files\n */\nexport const DOCPRESS_DIR = resolve(process.cwd(), 'docpress')\n\n/**\n * Directory for documentation files\n */\nexport const DOCS_DIR = resolve(process.cwd(), 'docpress/docs')\n\n/**\n * Path to the main index file\n */\nexport const INDEX_FILE = resolve(process.cwd(), 'docpress/docs/index.md')\n\n/**\n * Path to the forks documentation file\n */\nexport const FORKS_FILE = resolve(process.cwd(), 'docpress/docs/forks.md')\n\n/**\n * Path to VitePress configuration file\n */\nexport const VITEPRESS_CONFIG = resolve(process.cwd(), 'docpress/.vitepress/config.ts')\n\n/**\n * Directory for VitePress theme\n */\nexport const VITEPRESS_THEME = resolve(process.cwd(), 'docpress/.vitepress/theme')\n\n/**\n * Directory for user custom theme files\n */\nexport const VITEPRESS_USER_THEME = resolve(process.cwd(), 'docpress/.vitepress/theme/extras')\n\n/**\n * Path to template theme files\n */\n// eslint-disable-next-line dot-notation\nexport const TEMPLATE_THEME = process.env['NODE_ENV'] === 'development'\n ? resolve(import.meta.dirname, '../../public/templates/theme')\n : resolve(import.meta.dirname, './templates/theme')\n","export const relativePathRegex = /\\[([^\\]]+)\\]\\(\\.\\.\\/([^)]+)\\)/g\nexport const readmePathRegex = /\\[([^\\]]+)\\]\\((?!\\.?\\/docs\\/|docs\\/|http|#)(\\.\\/)?([^/][^)]+)\\)/g\nexport const readmeDocsPathRegex = /\\[([^\\]]+)\\]\\((\\.?\\/docs\\/|docs\\/)([^)]*)\\)/g\nexport const removeIdxRegex = /^\\d{2}-/\nexport const frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n/\nexport const internalMdLinkRegex = /\\[([^\\]]+)\\]\\((?!https?:|\\/|#|mailto:)([^)#]*\\/)?([^)#/]+\\.md)(#[^)]*)?\\)/g\n","import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'node:path'\nimport { rimrafSync } from 'rimraf'\nimport YAML from 'yaml'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport type { EnhancedRepository } from '../lib/fetch.js'\nimport type { getInfos } from '../lib/git.js'\nimport { DOCPRESS_DIR } from './const.js'\nimport { frontmatterRegex, internalMdLinkRegex, readmeDocsPathRegex, readmePathRegex, relativePathRegex, removeIdxRegex } from './regex.js'\n\n/**\n * Checks the HTTP status code of a URL\n * Redirects are not followed: some providers (e.g. GitLab) redirect to a\n * sign-in page instead of returning 404 for missing resources\n *\n * @param url - URL to check\n * @returns HTTP status code (500 for network errors)\n */\nexport async function checkHttpStatus(url: string): Promise<number> {\n try {\n const response = await fetch(url, { method: 'HEAD', redirect: 'manual' })\n return response.status\n } catch (_error) {\n return 500\n }\n}\n\n/**\n * Options for prettifying strings\n */\ninterface PrettifyOpts {\n mode?: 'capitalize' | 'uppercase' | 'lowercase'\n replaceDash?: boolean\n removeIdx?: boolean\n removeDot?: boolean\n removeExt?: boolean\n}\n\n/**\n * Formats a string based on specified options\n *\n * @param s - Input string to format\n * @param opts - Formatting options\n * @returns Formatted string\n */\nexport function prettify(s: string, opts: PrettifyOpts) {\n let u: string = ''\n\n if (opts?.removeDot) {\n if (s.startsWith('.')) {\n u = s.slice(1)\n } else {\n u = s\n }\n // Replace all remaining dots with dashes to ensure consistency\n u = u.replaceAll('.', '-')\n }\n\n if (opts?.removeIdx) {\n u = (u || s).replace(removeIdxRegex, '')\n }\n\n if (opts?.removeExt) {\n u = (u || s).split('.')[0]\n }\n\n if (opts?.replaceDash) {\n u = (u || s).replaceAll('-', ' ')\n }\n\n if (opts?.mode === 'capitalize') {\n u = (u || s).slice(0, 1).toUpperCase() + (u || s).slice(1).toLowerCase()\n } else if (opts?.mode === 'lowercase') {\n u = (u || s).toLowerCase()\n } else if (opts?.mode === 'uppercase') {\n u = (u || s).toUpperCase()\n }\n\n return u || s\n}\n\n/**\n * Creates a directory, optionally cleaning it first\n *\n * @param directory - Path to the directory to create\n * @param options - Options object\n * @param options.clean - Whether to clean the directory before creating it\n */\nexport function createDir(directory: string, { clean }: { clean?: boolean } = { clean: false }) {\n try {\n if (clean && existsSync(directory)) {\n rimrafSync(`${directory}/*`, { glob: true })\n }\n if (!existsSync(directory)) {\n mkdirSync(directory, { recursive: true })\n }\n } catch (err) {\n console.error(err)\n }\n}\n\n/**\n * Checks if a path is a directory\n *\n * @param path - Path to check\n * @returns True if path is a directory, false otherwise\n */\nexport function isDir(path: string) {\n try {\n return statSync(path).isDirectory()\n } catch (_error) {\n return false\n }\n}\n\n/**\n * Checks if a path is a file\n *\n * @param path - Path to check\n * @returns True if path is a file, false otherwise\n */\nexport function isFile(path: string) {\n try {\n return statSync(path).isFile()\n } catch (_error) {\n return false\n }\n}\n\n/**\n * Extracts a list of file paths from directories and files\n *\n * @param paths - Path or array of paths to extract files from\n * @returns Array of file paths\n */\nexport function extractFiles(paths: string[] | string): string[] {\n return (Array.isArray(paths) ? paths : [paths]).flatMap((path) => {\n if (isFile(path)) {\n return [path]\n }\n if (isDir(path)) {\n return readdirSync(path).filter(file => file !== '.git').sort().flatMap(file => extractFiles(join(path, file)))\n }\n return []\n })\n}\n\n/**\n * Gets all markdown files from specified paths\n *\n * @param path - Array of paths to search for markdown files\n * @returns Array of markdown file paths\n */\nexport function getMdFiles(path: string[]) {\n return extractFiles(path).filter(file => basename(file).endsWith('.md'))\n}\n\n/**\n * Formats an array of strings into a readable comma-separated list\n *\n * @param arr - Array of strings to format\n * @returns Formatted string (e.g., \"a\", \"b\" or \"c\")\n */\nexport function prettifyEnum(arr: readonly string[]) {\n return arr.reduce((acc, cur, idx, arr) => {\n if (!idx) {\n return `\"${cur}\"`\n } else if (idx === arr.length - 1) {\n return `${acc} or \"${cur}\"`\n } else {\n return `${acc}, \"${cur}\"`\n }\n }, '')\n}\n\n/**\n * Gets user information from cached JSON file\n *\n * @param username - GitHub username\n * @returns User information object\n */\nexport function getUserInfos(username: GlobalOpts['usernames'][number]) {\n return JSON.parse(readFileSync(`${DOCPRESS_DIR}/user-${username}.json`).toString()) as Awaited<ReturnType<typeof getInfos>>['user']\n}\n\n/**\n * Gets repository information from cached JSON file\n *\n * @param username - GitHub username\n * @returns Array of enhanced repository objects\n */\nexport function getUserRepos(username: GlobalOpts['usernames'][number]) {\n return JSON.parse(readFileSync(`${DOCPRESS_DIR}/repos-${username}.json`).toString()) as EnhancedRepository[]\n}\n\n/**\n * Deep merges multiple objects\n *\n * @param objects - Objects to merge\n * @returns Merged object\n */\nexport function deepMerge<T extends Record<string, any> | null>(...objects: T[]): T {\n return objects.reduce((acc, obj) => {\n if (obj === null) {\n return acc\n }\n\n Object.keys(obj).forEach((key) => {\n const accValue = acc ? acc[key] : null\n const objValue = obj[key]\n\n if (isObject(accValue) && isObject(objValue)) {\n (acc as Record<string, any>)[key] = deepMerge(accValue, objValue)\n } else {\n (acc as Record<string, any>)[key] = objValue\n }\n })\n return acc\n }, {} as T)\n}\n\n/**\n * Checks if a value is an object (not an array or null)\n *\n * @param val - Value to check\n * @returns True if value is an object, false otherwise\n */\nexport function isObject(val: any): val is object {\n return val && typeof val === 'object' && !Array.isArray(val)\n}\n\n/**\n * Loads and parses a JSON configuration file\n *\n * @param configPath - Path to the configuration file\n * @returns Parsed configuration object, or an empty object when no path is given\n * @throws Error if the file cannot be read or contains invalid JSON\n */\nexport function loadConfigFile(configPath?: string) {\n if (!configPath) {\n return {}\n }\n const fullPath = resolve(process.cwd(), configPath)\n let fileContents: string\n try {\n fileContents = readFileSync(fullPath, 'utf8')\n } catch (_error) {\n throw new Error(`Cannot read config file '${configPath}'.`)\n }\n try {\n return JSON.parse(fileContents)\n } catch (_error) {\n throw new Error(`Invalid JSON in config file '${configPath}'.`)\n }\n}\n\n/**\n * Splits a comma-separated string into an array of strings\n *\n * @param s - Comma-separated string\n * @returns Array of strings\n */\nexport function splitByComma(s: string) {\n return s.split(',')\n}\n\n/**\n * Replaces relative paths in markdown links with absolute URLs\n *\n * @param file - Path to the markdown file to process\n * @param url - Base URL to use for absolute links\n */\nexport function replaceRelativePath(file: string, url: string) {\n const fileContent = readFileSync(file, 'utf8')\n const updatedContent = fileContent.replace(relativePathRegex, (_match, p1, p2) => {\n return `[${p1}](${url}/${p2})`\n })\n writeFileSync(file, updatedContent, 'utf8')\n}\n\n/**\n * Adds or updates the \"lastUpdated\" frontmatter field of a markdown file, preserving\n * any frontmatter already present\n *\n * @param file - Path to the markdown file to update\n * @param date - Datetime to set as the \"lastUpdated\" value\n */\nexport function addLastUpdatedFrontmatter(file: string, date: string) {\n const content = readFileSync(file, 'utf8')\n const match = content.match(frontmatterRegex)\n\n if (match) {\n const data = YAML.parse(match[1]) ?? {}\n data.lastUpdated = date\n writeFileSync(file, content.replace(frontmatterRegex, `---\\n${YAML.stringify(data)}---\\n`), 'utf8')\n } else {\n writeFileSync(file, `---\\nlastUpdated: ${date}\\n---\\n\\n${content}`, 'utf8')\n }\n}\n\n/**\n * Rewrites relative markdown links to match the renamed target files\n * Files are renamed during sidebar generation (index prefix stripped, name lowercased,\n * readme becoming introduction), so in-page links must follow the same convention\n * to avoid pointing to files that no longer exist\n *\n * @param file - Path to the markdown file to process\n */\nexport function replaceInternalMdLinks(file: string) {\n const fileContent = readFileSync(file, 'utf8')\n const updatedContent = fileContent.replace(internalMdLinkRegex, (_match, text, dir, target, anchor) => {\n let filename = prettify(target, { mode: 'lowercase', removeIdx: true })\n if (filename === 'readme.md') {\n filename = 'introduction.md'\n }\n return `[${text}](${dir ?? ''}${filename}${anchor ?? ''})`\n })\n writeFileSync(file, updatedContent, 'utf8')\n}\n\n/**\n * Processes README files to fix various link formats\n *\n * @param file - Path to the README file to process\n * @param url - Base URL to use for absolute links\n */\nexport function replaceReadmePath(file: string, url: string) {\n const readmeContent = readFileSync(file, 'utf8')\n const updatedContent = readmeContent\n .replace(readmePathRegex, (_match, p1, _p2, p3) => {\n return `[${p1}](${url}/${p3})`\n })\n .replace(readmeDocsPathRegex, (_match, p1, _p2, p3) => {\n return `[${p1}](${p3})`\n })\n writeFileSync(file, updatedContent, 'utf8')\n}\n","/* eslint-disable dot-notation */\nimport type { ColorName } from 'chalk'\nimport chalk from 'chalk'\n\n/**\n * Log message types\n */\ntype LogType = keyof Pick<Console, 'info' | 'warn' | 'error' | 'debug' | 'trace'> | 'success'\n\n/**\n * Mapping of log types to colors and levels\n */\ntype ColorMap = {\n [K in LogType]: {\n color: ColorName\n level: number\n }\n}\n\n/**\n * Gets the current log level from environment variables\n *\n * @returns Log level number (default: 30)\n */\nfunction getLogLevel() {\n const level = Number(process.env['LOG_LEVEL'])\n return Number.isNaN(level) ? 30 : level\n}\n\n/**\n * Color mapping configuration for different log types\n */\nconst colorMap: ColorMap = {\n error: { color: 'red', level: 10 },\n warn: { color: 'yellow', level: 20 },\n info: { color: 'white', level: 30 },\n success: { color: 'green', level: 30 },\n trace: { color: 'white', level: 40 },\n debug: { color: 'blue', level: 50 },\n}\n\n/**\n * Logs a message with color formatting based on type and level\n *\n * @param msg - Message to log\n * @param type - Type of log message (info, warn, error, debug, trace, success)\n * @param color - Optional specific color to use instead of the default for the type\n */\nexport function log(msg: string, type: LogType = 'info', color?: ColorName) {\n const computedMsg = color ? chalk[color](msg) : chalk[colorMap[type].color](msg)\n const computedType = type === 'success' ? 'info' : type\n\n if (getLogLevel() >= colorMap[type].level) {\n console[computedType](computedMsg)\n }\n}\n","import { z } from 'zod'\nimport { loadConfigFile, prettifyEnum, splitByComma } from '../utils/functions.js'\nimport { log } from '../utils/logger.js'\n\n/**\n * List of supported Git providers\n */\nconst providers = ['github', 'gitlab'] as const\n\n/**\n * Schema for the DocPress configuration file\n * Defines the structure and validation rules for the configuration\n */\nexport const configSchema = z.object({\n // Global\n usernames: z.string()\n .array()\n .describe('List of comma separated Git provider usernames used to collect data.'),\n // Fetch\n branch: z.string()\n .default('main')\n .describe('Branch used to collect Git provider data.'),\n gitProvider: z.enum(providers)\n .default('github')\n .describe(`Git provider used to retrieve data. Values should be ${prettifyEnum(providers)}.`),\n reposFilter: z.string()\n .array()\n .describe('List of comma separated repositories to retrieve from Git provider. Default to all user\\'s public repositories.'),\n // Prepare\n extraHeaderPages: z.string()\n .array()\n .describe('List of comma separated additional files or directories to process Vitepress header pages.'),\n extraPublicContent: z.string()\n .array()\n .describe('List of comma separated additional files or directories to process Vitepress public folder.'),\n extraTheme: z.string()\n .array()\n .describe('List of comma separated additional files or directories to use as Vitepress theme.'),\n forks: z.boolean()\n .default(false)\n .describe('Whether or not to create the dedicated fork page that aggregate external contributions.'),\n lastUpdated: z.boolean()\n .default(false)\n .describe('Whether or not to inject each page\\'s last Git commit date as Vitepress \"lastUpdated\" frontmatter.'),\n vitepressConfig: z.any()\n .optional()\n .describe('Path to the vitepress configuration file.'),\n websiteTitle: z.string()\n .describe('Website title.'),\n websiteTagline: z.string()\n .describe('Website tagline.'),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\n/**\n * CLI schema with transformations applied to handle string-to-array conversions\n * Fields with config defaults are redefined without them, so that values coming\n * from a config file are not overridden by schema defaults\n */\nexport const cliSchema = configSchema\n .partial()\n .extend({\n branch: z.string()\n .optional()\n .describe(configSchema.shape.branch.description || ''),\n gitProvider: z.enum(providers)\n .optional()\n .describe(configSchema.shape.gitProvider.description || ''),\n forks: z.boolean()\n .optional()\n .describe(configSchema.shape.forks.description || ''),\n lastUpdated: z.boolean()\n .optional()\n .describe(configSchema.shape.lastUpdated.description || ''),\n config: z.string()\n .optional()\n .describe('Path to the docpress configuration file.'),\n token: z.string()\n .optional()\n .describe('Git provider token used to collect data.'),\n usernames: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.usernames.description || ''),\n reposFilter: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.reposFilter.description || ''),\n extraHeaderPages: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraHeaderPages.description || ''),\n extraPublicContent: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraPublicContent.description || ''),\n extraTheme: z.string()\n .transform(splitByComma)\n .optional()\n .describe(configSchema.shape.extraTheme.description || ''),\n vitepressConfig: z.string()\n .optional()\n .describe(configSchema.shape.vitepressConfig.description || ''),\n })\n\nexport type Cli = z.infer<typeof cliSchema>\n\n/**\n * Prepares configuration data by converting string values to arrays when needed\n *\n * @param configData - Raw configuration data to process\n * @returns Processed configuration data with proper array types\n */\nfunction prepareConfigData(configData: any) {\n if (!configData) return {}\n\n const arrayKeys = ['usernames', 'reposFilter', 'extraHeaderPages', 'extraPublicContent', 'extraTheme'] as const\n for (const key of arrayKeys) {\n if (configData[key] && typeof configData[key] === 'string') {\n configData[key] = [configData[key]]\n }\n }\n\n return configData\n}\n\n/**\n * Validates configuration file data against the config schema\n *\n * @param configData - Prepared configuration data to validate\n * @returns The validated configuration data\n * @throws Error if the configuration data is invalid\n */\nfunction validateConfigData(configData: any) {\n const result = configSchema.partial().safeParse(configData)\n if (!result.success) {\n throw new Error(z.prettifyError(result.error))\n }\n return result.data\n}\n\n/**\n * Validates the final merged configuration to ensure required fields are present\n *\n * @param mergedConfig - The merged configuration to validate\n * @returns The validated configuration if it passes validation\n * @throws Error if required fields are missing\n */\nfunction validateFinalConfig(mergedConfig: any) {\n if (!mergedConfig.usernames?.length) {\n throw new Error('The usernames field is required')\n }\n\n return mergedConfig\n}\n\n/**\n * Schema for global options that combines CLI arguments and configuration files\n * Merges config sources with precedence: CLI options > config file > defaults\n */\nexport const globalOptsSchema = cliSchema\n .partial()\n .transform((data) => {\n try {\n const { config, vitepressConfig, token, ...rest } = data\n\n log(`Debug: Schema transform input: ${JSON.stringify(data)}`, 'debug')\n\n // Load and validate configuration from file\n const configData = validateConfigData(prepareConfigData(loadConfigFile(config)))\n\n // Create final config\n const mergedConfig = {\n branch: 'main',\n gitProvider: 'github',\n forks: false,\n lastUpdated: false,\n ...configData,\n ...rest,\n ...(vitepressConfig\n ? {\n vitepressConfig: {\n ...(configData.vitepressConfig || {}),\n ...(loadConfigFile(vitepressConfig) || {}),\n },\n }\n : {}),\n }\n\n log(`Debug: Final merged config: ${JSON.stringify(mergedConfig)}`, 'debug')\n\n return validateFinalConfig({ ...mergedConfig, token })\n } catch (error) {\n log(` An error occurred while checking configuration.`, 'error')\n if (error instanceof Error) {\n log(` ${error.message}`, 'error')\n } else {\n log(` ${JSON.stringify(error, null, 2)}`, 'error')\n }\n process.exit(1)\n }\n })\n\nexport type GlobalOpts = Required<Pick<z.infer<typeof globalOptsSchema>, 'branch' | 'gitProvider'>>\n & Omit<z.infer<typeof globalOptsSchema>, 'branch' | 'gitProvider'>\n","import type { Command, Option } from 'commander'\nimport { z } from 'zod'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport { globalOptsSchema } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { log } from './logger.js'\n\n/**\n * Type definition for command names\n */\ntype Cmd = 'fetch' | 'prepare' | 'global'\n\n/**\n * Interface mapping command names to their option types\n */\ninterface Options {\n fetch: FetchOpts\n prepare: PrepareOpts\n global: GlobalOpts\n}\n\n/**\n * Parses and validates command options\n * Options are merged with precedence: CLI options > config file > defaults\n *\n * @param cmd - The command name ('fetch', 'prepare' or 'global')\n * @param opts - Raw options from the command line\n * @returns Validated and processed options for the specified command\n */\nexport function parseOptions<T extends Cmd>(cmd: T, opts: Record<string, unknown>): Options[T] {\n log(`Initializing Docpress...`, 'info', 'blue')\n log(`\\n\\n-> Checking for required environment settings and configurations.`, 'info')\n log(` Debug info - opts: ${JSON.stringify(opts)}`, 'debug')\n log(` Debug info - cmd: ${cmd}`, 'debug')\n\n const res = globalOptsSchema.safeParse(opts)\n if (!res.success) {\n log(` An error occurred while checking configuration.\\n ${z.prettifyError(res.error)}`, 'error')\n process.exit(1)\n }\n log(' Setup complete! Ready to process your documentation.', 'info')\n return res.data as Options[T]\n}\n\n/**\n * Extracts options that were explicitly provided by the user, skipping Commander defaults\n * This lets config file values take precedence over CLI defaults\n *\n * @param cmd - The Commander Command instance\n * @param opts - Raw options from the command line\n * @returns Options object containing only user-provided values\n */\nexport function explicitOptions(cmd: Command, opts: Record<string, unknown>) {\n return Object.fromEntries(\n Object.entries(opts).filter(([key]) => cmd.getOptionValueSource(key) !== 'default'),\n )\n}\n\n/**\n * Adds option definitions to a Command instance\n *\n * @param cmd - The Commander Command instance\n * @param opts - Array of option definitions to add\n * @returns The Command instance with options added\n */\nexport function addOptions(cmd: Command, opts: Option[]) {\n for (const opt of opts) {\n cmd.addOption(opt)\n }\n return cmd\n}\n","import { appendFileSync, cpSync, rmSync } from 'node:fs'\nimport { relative, resolve } from 'node:path'\nimport { Octokit } from '@octokit/rest'\nimport { simpleGit } from 'simple-git'\nimport type { SimpleGit } from 'simple-git'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { addLastUpdatedFrontmatter, createDir, getMdFiles } from '../utils/functions.js'\nimport { log } from '../utils/logger.js'\nimport type { EnhancedRepository } from './fetch.js'\n\n/**\n * Octokit logger that stays quiet on 404s, which are handled explicitly\n */\nconst quietOctokitLog = {\n debug: () => {},\n info: () => {},\n warn: (message: string) => {\n if (!message.includes('404')) console.warn(message)\n },\n error: (message: string) => {\n if (!message.includes('404')) console.error(message)\n },\n}\n\n/**\n * Fetches user and repository information from GitHub\n *\n * @param options - Options for retrieving GitHub data\n * @param options.username - GitHub username\n * @param options.token - GitHub API token\n * @param options.branch - Branch to use for documentation\n * @returns Object containing user information, repositories, and branch\n */\nexport async function getInfos({ username, token, branch }: Pick<FetchOpts, 'branch'> & Pick<GlobalOpts, 'token'> & { username: GlobalOpts['usernames'][number] }) {\n log(` Get infos for username '${username}'.`, 'info')\n const octokit = new Octokit({ auth: token, log: quietOctokitLog })\n log(` Get user infos.`, 'debug')\n const { data: user } = await octokit.rest.users.getByUsername({ username })\n .catch((error) => {\n throw error.status === 404 ? new Error(`No GitHub user found for '${username}'.`) : error\n })\n log(` Get repositories infos.`, 'debug')\n const repos = await octokit.paginate(octokit.rest.repos.listForUser, { username, sort: 'full_name', per_page: 100 })\n\n return { user, repos, branch }\n}\n\n/**\n * Gets contributors for a repository\n *\n * @param options - Options for retrieving contributors\n * @param options.repository - Repository information\n * @param options.token - GitHub API token\n * @returns Object with source repository and contributors list\n */\nexport async function getContributors({\n repository,\n token,\n}: {\n repository: EnhancedRepository\n token: GlobalOpts['token']\n}) {\n log(` Get contributors infos for repository '${repository.name}'.`, 'info')\n const octokit = new Octokit({ auth: token, log: quietOctokitLog })\n const { data: repo } = await octokit.rest.repos.get({\n owner: repository.owner.login,\n repo: repository.name,\n })\n if (!repo.source?.owner?.login) {\n return { source: repo.source, contributors: [] }\n }\n const contributors: Array<any> = []\n try {\n for await (const { data } of octokit.paginate.iterator(\n octokit.rest.repos.listContributors,\n {\n owner: repo.source.owner.login,\n repo: repo.parent?.name ?? repo.name,\n per_page: 100,\n },\n )) {\n contributors.push(...data)\n }\n } catch (error) {\n log(\n ` Failed to get contributors infos for repository '${repository.name}'. Error : ${error.message}`,\n 'warn',\n )\n return { source: repo.source, contributors: [] }\n }\n\n return { source: repo.source, contributors }\n}\n\n/**\n * Injects each markdown file's last Git commit date as a \"lastUpdated\" frontmatter field\n * Reads the commit history straight from the local clone, so no Git provider API call is\n * needed and no rate limit is spent, regardless of how many files or repositories are processed\n *\n * @param git - Simple-git instance scoped to the cloned repository, with history still intact\n * @param projectDir - Directory containing the cloned repository\n * @param name - Repository name, used for logging\n */\nexport async function applyLastUpdated(git: SimpleGit, projectDir: string, name: string) {\n for (const file of getMdFiles([projectDir])) {\n const filePath = relative(projectDir, file)\n\n try {\n const { latest } = await git.log({ file: filePath, maxCount: 1 })\n if (latest?.date) {\n addLastUpdatedFrontmatter(file, latest.date)\n }\n } catch (error) {\n log(` Unable to get last commit date for '${filePath}' in repository '${name}'. Error : ${error}`, 'warn')\n }\n }\n}\n\n/**\n * Clones a repository with sparse checkout\n *\n * @param name - Repository name\n * @param url - Repository URL\n * @param projectDir - Directory to clone into\n * @param branch - Branch to clone\n * @param includes - Patterns to include in sparse checkout\n * @param lastUpdated - Whether or not to inject each page's last Git commit date as frontmatter\n */\nexport async function cloneRepo(name: string, url: string, projectDir: string, branch: string, includes: string[], lastUpdated?: boolean) {\n createDir(projectDir, { clean: true })\n\n try {\n // Background maintenance is disabled so no git process keeps writing into\n // .git (e.g. commit-graph files) while it is being removed below\n const git = simpleGit({ baseDir: projectDir, config: ['maintenance.auto=false', 'gc.auto=0', 'fetch.writeCommitGraph=false'] })\n await git.init()\n .addConfig('core.sparseCheckout', 'true', true, 'local')\n .addRemote('origin', url)\n\n for (const item of includes) {\n log(` Add '${item}' to '${name}' sparse-checkout file.`, 'debug')\n appendFileSync(resolve(projectDir, '.git/info/sparse-checkout'), `${item}\\n`, 'utf8')\n }\n\n log(` Clone repository '${name}'.`, 'info')\n await git.pull('origin', branch)\n\n if (lastUpdated) {\n await applyLastUpdated(git, projectDir, name)\n }\n\n if (includes.some(item => item.includes('docs'))) {\n cpSync(resolve(projectDir, 'docs'), projectDir, { recursive: true })\n rmSync(resolve(projectDir, 'docs'), { recursive: true })\n }\n rmSync(resolve(projectDir, '.git'), { recursive: true })\n } catch (error) {\n log(` Error when cloning repository: ${error}.`, 'error')\n }\n}\n","import type { GlobalOpts } from '../schemas/global.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { log } from '../utils/logger.js'\nimport type { getInfos as getGithubInfos } from './git.js'\n\n/**\n * Base URL of the GitLab REST API\n */\nexport const GITLAB_API_URL = 'https://gitlab.com/api/v4'\n\ntype User = Awaited<ReturnType<typeof getGithubInfos>>['user']\ntype Repository = Awaited<ReturnType<typeof getGithubInfos>>['repos'][number]\n\n/**\n * Performs a GET request against the GitLab API\n *\n * @param path - API path starting with '/'\n * @param token - Optional GitLab token\n * @returns Object containing the parsed JSON body and the response headers\n * @throws Error if the request fails\n */\nasync function gitlabGet(path: string, token?: GlobalOpts['token']) {\n const response = await fetch(`${GITLAB_API_URL}${path}`, {\n headers: token ? { 'PRIVATE-TOKEN': token } : {},\n })\n if (!response.ok) {\n throw new Error(`GitLab API request failed for '${path}' (status: ${response.status}).`)\n }\n return { data: await response.json(), headers: response.headers }\n}\n\n/**\n * Fetches all pages of a GitLab API collection\n *\n * @param path - API path starting with '/' (query params allowed)\n * @param token - Optional GitLab token\n * @returns Array containing all items from all pages\n */\nasync function gitlabGetAll(path: string, token?: GlobalOpts['token']) {\n const separator = path.includes('?') ? '&' : '?'\n const items: any[] = []\n let page: string | null = '1'\n\n while (page) {\n const { data, headers } = await gitlabGet(`${path}${separator}per_page=100&page=${page}`, token)\n items.push(...data)\n page = headers.get('x-next-page') || null\n }\n return items\n}\n\n/**\n * Maps a GitLab user or group to the internal user shape\n *\n * @param user - GitLab user or group object\n * @returns User object with the fields used by DocPress\n */\nfunction mapUser(user: any) {\n return {\n login: user.username ?? user.path,\n name: user.name,\n bio: user.bio ?? user.description ?? null,\n avatar_url: user.avatar_url,\n html_url: user.web_url,\n } as unknown as User\n}\n\n/**\n * Maps a GitLab project to the internal repository shape\n *\n * @param project - GitLab project object\n * @param owner - Login of the user or group that owns the project\n * @returns Repository object with the fields used by DocPress\n */\nfunction mapRepository(project: any, owner: string) {\n return {\n name: project.path,\n owner: { login: owner },\n fork: !!project.forked_from_project,\n private: project.visibility !== 'public',\n // An empty repository has no default branch\n size: project.default_branch ? 1 : 0,\n default_branch: project.default_branch,\n clone_url: project.http_url_to_repo,\n html_url: project.web_url,\n description: project.description,\n stargazers_count: project.star_count,\n } as unknown as Repository\n}\n\n/**\n * Fetches user and repository information from GitLab\n * Falls back to the groups API when no user matches the given name\n *\n * @param options - Options for retrieving GitLab data\n * @param options.username - GitLab username or group path\n * @param options.token - GitLab API token\n * @param options.branch - Branch to use for documentation\n * @returns Object containing user information, repositories, and branch\n */\nexport async function getInfos({ username, token, branch }: Pick<FetchOpts, 'branch'> & Pick<GlobalOpts, 'token'> & { username: GlobalOpts['usernames'][number] }) {\n log(` Get infos for username '${username}'.`, 'info')\n\n const { data: users } = await gitlabGet(`/users?username=${encodeURIComponent(username)}`, token)\n\n if (users.length) {\n let user = users[0]\n if (token) {\n // The user detail endpoint requires authentication but provides extra fields (e.g. bio)\n user = await gitlabGet(`/users/${users[0].id}`, token).then(res => res.data).catch(() => users[0])\n }\n log(` Get repositories infos.`, 'debug')\n const projects = await gitlabGetAll(`/users/${users[0].id}/projects`, token)\n return { user: mapUser(user), repos: projects.map(project => mapRepository(project, user.username)), branch }\n }\n\n log(` No GitLab user '${username}' found, trying groups.`, 'debug')\n const group = await gitlabGet(`/groups/${encodeURIComponent(username)}?with_projects=false`, token)\n .then(res => res.data)\n .catch(() => {\n throw new Error(`No GitLab user or group found for '${username}'.`)\n })\n const projects = await gitlabGetAll(`/groups/${encodeURIComponent(username)}/projects`, token)\n return { user: mapUser(group), repos: projects.map(project => mapRepository(project, group.path)), branch }\n}\n","import { resolve } from 'node:path'\nimport { writeFileSync } from 'node:fs'\nimport type { FetchOpts, FetchOptsUser } from '../schemas/fetch.js'\nimport { checkHttpStatus, prettify } from '../utils/functions.js'\nimport { DOCPRESS_DIR, DOCS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { cloneRepo, getInfos } from './git.js'\nimport { getInfos as getGitlabInfos } from './gitlab.js'\n\n/**\n * Enhanced repository type with DocPress-specific metadata\n */\nexport type EnhancedRepository = Awaited<ReturnType<typeof getInfos>>['repos'][number] & {\n docpress: {\n branch: string\n filtered: boolean\n includes: string[]\n projectPath: string\n raw_url: string\n replace_url: string\n }\n}\n\n/**\n * Web URLs of a repository for a given branch, depending on the Git provider\n */\nexport interface ProviderUrls {\n blob_url: string\n tree_url: string\n raw_url: string\n}\n\n/**\n * Builds the web URLs of a repository for a given branch and Git provider\n *\n * @param repo - Repository information\n * @param branch - Branch to build URLs for\n * @param gitProvider - Git provider used to retrieve data\n * @returns Object containing blob, tree and raw base URLs\n */\nexport function getProviderUrls(repo: Awaited<ReturnType<typeof getInfos>>['repos'][number], branch: FetchOpts['branch'], gitProvider?: FetchOpts['gitProvider']): ProviderUrls {\n if (gitProvider === 'gitlab') {\n const base = repo.html_url ?? `https://gitlab.com/${repo.owner.login}/${repo.name}`\n return {\n blob_url: `${base}/-/blob/${branch}`,\n tree_url: `${base}/-/tree/${branch}`,\n raw_url: `${base}/-/raw/${branch}`,\n }\n }\n const base = repo.html_url ?? `https://github.com/${repo.owner.login}/${repo.name}`\n return {\n blob_url: `${base}/blob/${branch}`,\n tree_url: `${base}/tree/${branch}`,\n raw_url: `https://raw.githubusercontent.com/${repo.owner.login}/${repo.name}/${branch}`,\n }\n}\n\n/**\n * Checks for the existence of documentation files in a repository\n *\n * @param urls - Web URLs of the repository for the target branch\n * @returns Object containing HTTP status codes for different documentation paths\n */\nexport async function checkDoc(urls: ProviderUrls) {\n const rootReadmeStatus = await checkHttpStatus(`${urls.blob_url}/README.md`)\n const docsFolderStatus = await checkHttpStatus(`${urls.tree_url}/docs`)\n const docsReadmeStatus = await checkHttpStatus(`${urls.blob_url}/docs/01-readme.md`)\n\n return {\n rootReadmeStatus,\n docsFolderStatus,\n docsReadmeStatus,\n }\n}\n\n/**\n * Fetches documentation from a user's repositories\n *\n * @param options - Options for fetching documentation\n * @param options.username - Git provider username\n * @param options.branch - Branch to use for documentation\n * @param options.reposFilter - Optional filter for repositories\n * @param options.gitProvider - Git provider used to retrieve data\n * @param options.token - Git provider API token\n * @param options.lastUpdated - Whether or not to inject each page's last Git commit date as frontmatter\n */\nexport async function fetchDoc({ username, branch, reposFilter, gitProvider, token, lastUpdated }: FetchOptsUser) {\n const getProviderInfos = gitProvider === 'gitlab' ? getGitlabInfos : getInfos\n await getProviderInfos({ username, token, branch })\n .then(async ({ user, repos, branch }) => generateInfos(user, repos, branch, reposFilter, gitProvider))\n .then(async ({ repos }) => getDoc(repos, reposFilter, lastUpdated))\n}\n\n/**\n * Enhances repository information with DocPress metadata\n *\n * @param repos - List of repositories from Git provider\n * @param branch - Branch to use for documentation\n * @param reposFilter - Optional filter for repositories\n * @returns Array of enhanced repositories with DocPress metadata\n */\nexport async function enhanceRepositories(repos: Awaited<ReturnType<typeof getInfos>>['repos'], branch?: FetchOpts['branch'], reposFilter?: FetchOpts['reposFilter'], gitProvider?: FetchOpts['gitProvider']) {\n const enhancedRepos: EnhancedRepository[] = []\n\n await Promise.all(\n repos.map(async (repo) => {\n const computedBranch = branch ?? repo.default_branch ?? 'main'\n const projectPath = resolve(DOCS_DIR, prettify(repo.name, { removeDot: true }))\n const filtered = isRepoFiltered(repo, reposFilter)\n const urls = getProviderUrls(repo, computedBranch, gitProvider)\n let includes: string[] = []\n\n if (!repo.fork && !repo.private && !filtered) {\n includes = await getSparseCheckout(repo, computedBranch, gitProvider)\n }\n\n enhancedRepos.push({\n ...repo,\n docpress: {\n filtered,\n branch: computedBranch,\n includes,\n projectPath,\n raw_url: urls.raw_url,\n replace_url: urls.tree_url,\n },\n })\n }),\n )\n\n return enhancedRepos\n}\n\n/**\n * Determines which files to include in the sparse checkout based on repository structure\n *\n * @param repo - Repository information\n * @param branch - Branch to check for documentation\n * @param gitProvider - Git provider used to retrieve data\n * @returns Array of file patterns to include in sparse checkout\n */\nexport async function getSparseCheckout(repo: Awaited<ReturnType<typeof getInfos>>['repos'][number], branch: FetchOpts['branch'], gitProvider?: FetchOpts['gitProvider']) {\n const docsStatus = await checkDoc(getProviderUrls(repo, branch, gitProvider))\n\n const includes: string[] = []\n if (Object.values(docsStatus).every(status => status !== 200) || !repo.size) {\n return []\n }\n if (docsStatus.docsFolderStatus === 200) {\n includes.push('docs/*')\n }\n if (docsStatus.docsFolderStatus !== 200 || docsStatus.docsReadmeStatus !== 200) {\n includes.push('README.md', '!*/**/README.md')\n }\n return includes\n}\n\n/**\n * Generates and saves user and repository information\n *\n * @param user - User information from Git provider\n * @param repos - List of repositories from Git provider\n * @param branch - Branch to use for documentation\n * @param reposFilter - Optional filter for repositories\n * @param gitProvider - Git provider used to retrieve data\n * @returns Object containing user and enhanced repository information\n */\nexport async function generateInfos(user: Awaited<ReturnType<typeof getInfos>>['user'], repos: Awaited<ReturnType<typeof getInfos>>['repos'], branch?: FetchOpts['branch'], reposFilter?: FetchOpts['reposFilter'], gitProvider?: FetchOpts['gitProvider']) {\n writeFileSync(`${DOCPRESS_DIR}/user-${user.login}.json`, JSON.stringify(user, null, 2))\n\n const enhancedRepos = await enhanceRepositories(repos, branch, reposFilter, gitProvider)\n writeFileSync(`${DOCPRESS_DIR}/repos-${user.login}.json`, JSON.stringify(enhancedRepos, null, 2))\n\n return { user, repos: enhancedRepos }\n}\n\n/**\n * Fetches documentation from repositories\n *\n * @param repos - List of enhanced repositories\n * @param reposFilter - Optional filter for repositories\n * @param lastUpdated - Whether or not to inject each page's last Git commit date as frontmatter\n */\nexport async function getDoc(repos?: EnhancedRepository[], reposFilter?: FetchOpts['reposFilter'], lastUpdated?: boolean) {\n if (!repos) {\n log(` No repository respect docpress rules.`, 'warn')\n return\n }\n\n await Promise.all(\n repos\n .filter(repo => !isRepoFiltered(repo, reposFilter))\n .map(async (repo) => {\n await cloneRepo(repo.name, repo.clone_url as string, repo.docpress.projectPath, repo.docpress.branch, repo.docpress.includes, lastUpdated)\n }),\n )\n}\n\n/**\n * Determines if a repository should be filtered out based on filter rules\n *\n * @param repo - Repository information\n * @param reposFilter - Optional filter for repositories\n * @returns True if the repository should be filtered out, false otherwise\n */\nexport function isRepoFiltered(repo: EnhancedRepository | Awaited<ReturnType<typeof getInfos>>['repos'][number], reposFilter?: FetchOpts['reposFilter']) {\n const hasOnlyExclusions = reposFilter?.every((filter: string) => filter.startsWith('!'))\n const isExcluded = reposFilter?.filter((filter: string) => filter.startsWith('!'))\n .some((filter: string) => repo.name === filter.substring(1))\n const isIncluded = !reposFilter\n || reposFilter?.filter((filter: string) => !filter.startsWith('!')).includes(repo.name)\n || (repo.fork && !isExcluded)\n || (hasOnlyExclusions && !isExcluded)\n\n const isFiltered = isExcluded || !isIncluded\n\n if ('docpress' in repo && !repo.docpress.includes.length) {\n return true\n }\n\n if (!!repo.clone_url && !repo.private && !isFiltered) {\n return false\n }\n return true\n}\n","import { createOption } from 'commander'\nimport { cliSchema } from '../schemas/global.js'\n\n/**\n * Global command line options shared across all commands\n */\nexport const globalOpts = [\n createOption('-C, --config <string>', cliSchema.shape.config.description),\n createOption('-T, --token <string>', cliSchema.shape.token.description),\n createOption('-U, --usernames <string>', cliSchema.shape.usernames.description),\n]\n","import { createCommand, createOption } from 'commander'\nimport { createDir } from '../utils/functions.js'\nimport { DOCPRESS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { addOptions, explicitOptions, parseOptions } from '../utils/commands.js'\nimport type { FetchOpts } from '../schemas/fetch.js'\nimport { fetchDoc } from '../lib/fetch.js'\nimport { configSchema } from '../schemas/global.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Command name for the fetch operation\n */\nconst cmdName = 'fetch'\n\n/**\n * Command line options specific to the fetch command\n */\nexport const fetchOpts = [\n createOption('-b, --branch <string>', configSchema.shape.branch.description)\n .default(configSchema.shape.branch.def.defaultValue),\n createOption('-g, --git-provider <string>', configSchema.shape.gitProvider.description)\n .default(configSchema.shape.gitProvider.def.defaultValue),\n createOption('-l, --last-updated', configSchema.shape.lastUpdated.description),\n createOption('-r, --repos-filter <string>', configSchema.shape.reposFilter.description),\n]\n\n/**\n * The fetch command definition for Commander\n */\nexport const fetchCmd = addOptions(createCommand(cmdName), [...fetchOpts, ...globalOpts])\n .description('Fetch docs with the given username(s) and git provider.')\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions(cmdName, explicitOptions(cmd, opts))\n await main(parsedOpts)\n })\n\n/**\n * Main function to execute the fetch command\n *\n * @param opts - Validated fetch options\n */\nexport async function main(opts: FetchOpts) {\n const { usernames, reposFilter, token, branch, gitProvider, lastUpdated } = opts\n log(`\\n-> Start fetching documentation files. This may take a moment, especially for larger repositories.`, 'info')\n\n createDir(DOCPRESS_DIR, { clean: true })\n for (const username of usernames) {\n // With multiple users, filters are scoped as '<username>/<repo>' or '!<username>/<repo>'\n const finalRF = usernames.length > 1\n ? reposFilter?.filter((rf: string) => rf.replace(/^!/, '').startsWith(`${username}/`)).map((rf: string) => rf.replace(`${username}/`, ''))\n : reposFilter\n await fetchDoc({ username, branch, reposFilter: finalRF, gitProvider, token, lastUpdated })\n }\n}\n","import { build as vitepressBuild } from 'vitepress'\nimport type { UserConfig } from 'vitepress'\nimport { withMermaid } from 'vitepress-plugin-mermaid'\nimport { createCommand } from 'commander'\nimport { addOptions } from '../utils/commands.js'\nimport { DOCPRESS_DIR } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Suppress specific Vue warnings during the build process\n *\n * @param callback - Function to execute while warnings are suppressed\n * @returns The result of the callback function\n */\nexport async function suppressVueWarnings<T>(callback: () => Promise<T>): Promise<T> {\n // Store the original console.warn\n const originalWarn = console.warn\n\n // Override console.warn to suppress specific Vue warnings\n console.warn = function (...args) {\n if (\n args.length > 0\n && typeof args[0] === 'string'\n && (args[0].includes('[Vue warn]: Invalid watch source:')\n || args[0].includes('{ open: false }'))\n ) {\n // Skip this warning\n return\n }\n // Pass other warnings to the original console.warn\n originalWarn.apply(console, args)\n }\n\n try {\n // Execute the callback with warnings suppressed\n return await callback()\n } finally {\n // Restore the original console.warn\n console.warn = originalWarn\n }\n}\n\n/**\n * Command name for the build operation\n */\nconst cmdName = 'build'\n\n/**\n * The build command definition for Commander\n */\nexport const buildCmd = addOptions(createCommand(cmdName), globalOpts)\n .description('Build vitepress website.')\n .action(async (_opts) => {\n await main()\n })\n\n/**\n * Main function to execute the build command\n * Builds the VitePress static site\n */\nexport async function main() {\n log(`\\n-> Start building Vitepress website.\\n\\n`, 'info')\n\n try {\n // Build VitePress with Vue warnings suppressed\n await suppressVueWarnings(async () => {\n await vitepressBuild(DOCPRESS_DIR, {\n onAfterConfigResolve(siteConfig) {\n withMermaid(siteConfig as unknown as UserConfig)\n },\n })\n })\n\n log(`\\n\\nDocpress build succeeded.`, 'success')\n } catch (error) {\n log(`\\n\\nDocpress build failed : ${error}`, 'error')\n process.exit(1)\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createDir } from './functions.js'\n\n/**\n * Generates a file by copying content from source to destination\n *\n * @param src - Path to the source file\n * @param dest - Path to the destination file\n */\nexport function generateFile(src: string, dest: string) {\n const content = readFileSync(src, { encoding: 'utf8' })\n createDir(dirname(dest))\n writeFileSync(dest, content)\n}\n","import type { defineConfig } from 'vitepress'\nimport { deepMerge } from '../utils/functions.js'\nimport type { Page, SidebarProject } from './prepare.js'\n\n/**\n * Default VitePress configuration\n */\nconst defaultVitepressConfig: ReturnType<typeof defineConfig> = {\n base: '/',\n lang: 'en-US',\n vite: {\n publicDir: '../public',\n },\n title: 'Home',\n description: 'Docpress',\n srcDir: './docs',\n cleanUrls: false,\n ignoreDeadLinks: 'localhostLinks',\n themeConfig: {\n outline: [2, 3],\n search: {\n provider: 'local',\n options: {\n translations: {\n button: {\n buttonText: 'Search...',\n buttonAriaLabel: 'Search',\n },\n modal: {\n backButtonTitle: 'erase search',\n displayDetails: 'show details',\n noResultsText: 'No results for : ',\n resetButtonTitle: 'cancel search',\n footer: {\n selectText: 'go to',\n navigateText: 'navigate in results',\n closeText: 'close',\n },\n },\n },\n },\n },\n },\n}\n\n/**\n * Generates VitePress configuration by merging default and custom configs\n *\n * @param sidebar - Sidebar configuration\n * @param nav - Navigation configuration\n * @param vitepressConfig - Optional custom VitePress configuration\n * @returns Merged VitePress configuration\n */\nexport function getVitepressConfig(sidebar: SidebarProject[], nav: Page[], vitepressConfig?: ReturnType<typeof defineConfig>): Partial<ReturnType<typeof defineConfig>> {\n const config = vitepressConfig\n ? deepMerge(defaultVitepressConfig, vitepressConfig, { themeConfig: { sidebar, nav } })\n : deepMerge(defaultVitepressConfig, { themeConfig: { sidebar, nav } })\n return config\n}\n","import { basename, dirname, parse, resolve } from 'node:path'\nimport { appendFileSync, cpSync, existsSync, readdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport YAML from 'yaml'\nimport type { defineConfig } from 'vitepress'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { generateFile } from '../utils/templates.js'\nimport type { GlobalOpts } from '../schemas/global.js'\nimport { createDir, extractFiles, getMdFiles, getUserInfos, getUserRepos, isFile, prettify, replaceInternalMdLinks, replaceReadmePath, replaceRelativePath } from '../utils/functions.js'\nimport { DOCPRESS_DIR, DOCS_DIR, FORKS_FILE, INDEX_FILE, TEMPLATE_THEME, VITEPRESS_CONFIG, VITEPRESS_THEME, VITEPRESS_USER_THEME } from '../utils/const.js'\nimport { log } from '../utils/logger.js'\nimport type { EnhancedRepository } from './fetch.js'\nimport type { getInfos } from './git.js'\nimport { getContributors } from './git.js'\nimport { getVitepressConfig } from './vitepress.js'\n\n/**\n * Represents a navigation page item with text and link\n */\nexport interface Page {\n text: string\n link: string\n}\n\n/**\n * Represents a sidebar project with nested items\n */\nexport interface SidebarProject {\n text: string\n collapsed: boolean\n items: (Page | SidebarProject)[]\n}\n\n/**\n * Represents a feature to display on the index page\n */\nexport interface Feature {\n title: string\n details: string\n link: string\n}\n\n/**\n * Represents the structure of the VitePress index page\n */\nexport interface Index {\n layout: string\n hero: {\n name: string\n tagline?: string\n }\n /** List of features to display */\n features: Feature[]\n}\n\n/**\n * Prepares the documentation structure for a user's repositories\n *\n * @param options - Options for documentation preparation\n * @param options.extraHeaderPages - Array of paths to additional header pages\n * @param options.extraPublicContent - Array of paths to additional public content\n * @param options.extraTheme - Array of paths to additional theme files\n * @param options.vitepressConfig - Path to the VitePress configuration file\n * @param options.forks - Flag to include forked repositories\n * @param options.gitProvider - Git provider used to retrieve data\n * @param options.lastUpdated - Flag to display each page's last Git commit date, computed by the fetch step\n * @param options.token - Git provider token for API access\n * @param options.username - Git provider username to fetch repositories for\n * @param options.websiteTitle - Custom title for the documentation website\n * @param options.websiteTagline - Custom tagline for the documentation website\n */\nexport async function prepareDoc({ extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, lastUpdated, token, username, websiteTitle, websiteTagline }: Omit<PrepareOpts, 'usernames' | 'branch' | 'reposFilter'> & { username: PrepareOpts['usernames'][number] }) {\n // The forks page relies on matching contributors by login, which the GitLab API does not expose\n const forksEnabled = forks && gitProvider !== 'gitlab'\n if (forks && !forksEnabled) {\n log(` The forks page is not supported with the 'gitlab' provider, skipping.`, 'warn')\n }\n const user = getUserInfos(username)\n const repositories = getUserRepos(username)\n .reduce(({ internals, forks }: { internals: EnhancedRepository[], forks: EnhancedRepository[] }, cur) => {\n const { clone_url, private: privateRepo, fork, docpress } = cur\n if (clone_url && !privateRepo && !docpress.filtered) {\n if (!fork && docpress.includes.length) {\n return { internals: [...internals, cur], forks }\n } else if (fork) {\n return { internals, forks: [...forks, cur] }\n }\n }\n return { internals, forks }\n }, { internals: [], forks: [] })\n\n const websiteInfos = { title: websiteTitle, tagline: websiteTagline }\n const { index, sidebar } = transformDoc(repositories.internals, user, websiteInfos)\n\n let finalSB\n let finalIndex\n if (existsSync(INDEX_FILE) && existsSync(VITEPRESS_CONFIG)) {\n const actualConfig = await parseVitepressConfig(VITEPRESS_CONFIG)\n const actualIndex = await parseVitepressIndex(INDEX_FILE)\n finalSB = [\n ...(actualConfig.themeConfig?.sidebar as SidebarProject[] ?? []),\n ...sidebar,\n ].sort((a, b) => a.text.localeCompare(b.text))\n finalIndex = {\n ...index,\n features: [\n ...actualIndex.features,\n ...index.features,\n ].sort((a, b) => a.title.localeCompare(b.title)),\n }\n } else {\n finalSB = sidebar\n finalIndex = index\n }\n const nav: Page[] = []\n\n if (extraHeaderPages) {\n const pages = addExtraPages(extraHeaderPages)\n if (forksEnabled) {\n nav.push(...pages.filter(p => p.link !== '/forks'))\n } else {\n nav.push(...pages)\n }\n }\n if (extraPublicContent) {\n log(` Add extras Vitepress public folder content.`, 'info')\n addContent(extraPublicContent, resolve(DOCPRESS_DIR, 'public'))\n }\n if (extraTheme) {\n log(` Add extras Vitepress theme files.`, 'info')\n addContent(extraTheme, resolve(VITEPRESS_USER_THEME))\n }\n if (forksEnabled && username.length) {\n log(` Add fork page to display external contributions.`, 'info')\n await processForks(repositories.forks, username, token)\n nav.push({ text: 'Forks', link: '/forks' })\n }\n\n // Vitepress only renders the last updated date once its own \"lastUpdated\" flag is on;\n // default it to true when the docpress equivalent is enabled, without overriding an explicit user choice\n const finalVitepressConfig = lastUpdated ? { lastUpdated: true, ...vitepressConfig } : vitepressConfig\n const config = getVitepressConfig(finalSB, nav, finalVitepressConfig)\n\n generateVitepressFiles(config, finalIndex)\n}\n\n/**\n * Adds a source reference section to a markdown file\n *\n * @param repoUrl - URL of the GitHub repository\n * @param outputPath - Path to the markdown file where sources will be added\n */\nexport function addSources(repoUrl: string, outputPath: string) {\n const fileName = basename(outputPath)\n const title = prettify(fileName, { mode: 'lowercase', removeIdx: true }) === 'readme.md' ? '\\n## Sources' : '# Sources'\n\n const sourcesContent = `${title}\\n\\nTake a look at the [project sources](${repoUrl}).\\n`\n\n appendFileSync(outputPath, sourcesContent, 'utf8')\n}\n\n/**\n * Information about website title and tagline\n */\nexport interface WebsiteInfos {\n title?: string\n tagline?: string\n}\n\n/**\n * Generates the index page content for the documentation site\n *\n * @param features - Array of features to display on the homepage\n * @param user - User information retrieved from GitHub\n * @param websiteInfos - Custom title and tagline information\n * @returns An object with index page configuration\n */\nexport function generateIndex(features: Feature[], user: ReturnType<typeof getUserInfos>, websiteInfos: WebsiteInfos) {\n const { name, login, bio } = user\n const { title, tagline } = websiteInfos\n\n const hero = title\n ? { name: title, tagline }\n : { name: name ? `${name}'s projects` : `${login}'s projects`, tagline: bio ?? 'Robots are everywhere 🤖' }\n\n return {\n layout: 'home',\n hero,\n features,\n }\n}\n\n/**\n * Generates feature cards for the homepage\n *\n * @param repoName - Name of the repository\n * @param description - Description of the repository\n * @param features - Optional existing features to append to\n * @returns Array of feature objects for the homepage\n */\nexport function generateFeatures(repoName: string, description: string, features?: Feature[]) {\n const content = {\n title: prettify(repoName, { mode: 'capitalize', replaceDash: true }),\n details: description,\n link: `/${prettify(repoName, { removeDot: true })}/introduction`,\n }\n\n return features ? [...features, content] : [content]\n}\n\n/**\n * Generates a sidebar project entry for the documentation navigation\n *\n * @param repoName - Name of the repository\n * @param sidebarPages - Array of sidebar pages to include in this project\n * @returns A sidebar project configuration object\n */\nexport function generateSidebarProject(repoName: string, sidebarPages: (SidebarProject | Page)[]) {\n return {\n text: prettify(repoName, { mode: 'capitalize', replaceDash: true }),\n collapsed: true,\n items: sidebarPages,\n }\n}\n\n/**\n * Generates sidebar page entries for the documentation navigation\n *\n * @param repoName - Name of the repository\n * @param fileName - Name of the file\n * @param sidebarPages - Optional existing sidebar pages to append to\n * @returns Array of page objects for the sidebar\n */\nexport function generateSidebarPages(repoName: string, fileName: string, sidebarPages?: Page[]) {\n const content = {\n text: fileName === 'introduction' ? 'Introduction' : prettify(fileName, { mode: 'capitalize', replaceDash: true }),\n link: `/${prettify(repoName, { removeDot: true })}/${fileName}`,\n }\n\n return sidebarPages ? [...sidebarPages, content] : [content]\n}\n\n/**\n * Generates sidebar items from a repository's file structure\n *\n * @param repository - Repository information\n * @param obj - Object representing the file tree structure\n * @returns Array of sidebar items (projects and pages)\n */\nexport function generateSidebarItems(repository: EnhancedRepository, obj: any): (SidebarProject | Page)[] {\n return Object.entries(obj).flatMap(([key, value]): (SidebarProject | Page)[] => {\n if (key === '$') {\n if (Array.isArray(value)) {\n return value.map((element) => {\n const file = resolve(repository.docpress.projectPath, element)\n let filename = prettify(basename(file), { mode: 'lowercase', removeIdx: true })\n if (filename === 'readme.md') {\n filename = 'introduction.md'\n }\n if (filename !== basename(file)) {\n renameSync(file, resolve(dirname(file), filename))\n }\n\n return {\n text: parse(filename).name === 'introduction'\n ? 'Introduction'\n : prettify(filename, { mode: 'capitalize', replaceDash: true, removeExt: true }),\n link: `/${prettify(repository.name, { removeDot: true })}/${parse(filename).name}`,\n } as Page\n })\n }\n return []\n } else if (typeof value === 'object') {\n return [{\n text: prettify(key, { mode: 'capitalize', replaceDash: true }),\n collapsed: true,\n items: generateSidebarItems({ ...repository, name: `${repository.name}/${key}` }, value),\n } as SidebarProject]\n }\n\n return []\n })\n}\n\n/**\n * Builds a tree structure from an array of file paths\n *\n * @param files - Array of file paths to be organized into a tree\n * @returns A nested object representing the directory structure\n */\nexport function buildTree(files: string[]): any {\n return files.reduce((tree, file) => {\n const [first, ...rest] = file.split('/')\n if (!rest.length) {\n // eslint-disable-next-line dot-notation\n tree['$'] = [...(tree['$'] || []), first]\n } else {\n tree[first] = buildTree([\n ...(tree[first] ? flattenTree(tree[first], '') : []),\n rest.join('/'),\n ])\n }\n return tree\n }, {} as Record<string, any>)\n}\n\n/**\n * Flattens a nested tree structure into an array of file paths\n *\n * @param subtree - The tree object to flatten\n * @param prefix - Optional path prefix to prepend to each result\n * @returns An array of file paths\n */\nexport function flattenTree(subtree: any, prefix = ''): string[] {\n return Object.entries(subtree).flatMap(([key, value]) => {\n if (key === '$') {\n if (Array.isArray(value)) {\n return value.map((v: string) => (prefix ? `${prefix}/${v}` : v))\n } else {\n return []\n }\n }\n return flattenTree(value, prefix ? `${prefix}/${key}` : key)\n })\n}\n\n/**\n * Reorders sidebar items to ensure 'Sources' appears last\n *\n * @param arr - Array of sidebar items to reorder\n * @returns Reordered array with 'Sources' as the last item\n */\nfunction moveSourcesLast(arr: (SidebarProject | Page)[]) {\n if (!Array.isArray(arr)) {\n return arr\n }\n const sourcesIdx = arr.findIndex(item => item.text === 'Sources')\n if (sourcesIdx === -1) {\n return arr\n }\n const [sources] = arr.splice(sourcesIdx, 1)\n arr.push(sources)\n return arr\n}\n\n/**\n * Transforms repository data into documentation structure\n *\n * @param repositories - Array of enhanced repositories\n * @param user - User information retrieved from GitHub\n * @param websiteInfos - Custom title and tagline information\n * @returns Object containing sidebar and index page configurations\n */\nexport function transformDoc(repositories: EnhancedRepository[], user: ReturnType<typeof getUserInfos>, websiteInfos: WebsiteInfos) {\n const features: Feature[] = []\n const sidebar: SidebarProject[] = []\n\n for (const repository of repositories) {\n log(` Replace urls for repository '${repository.name}'.`, 'info')\n getMdFiles([repository.docpress.projectPath]).forEach((file) => {\n log(` Processing file '${basename(file)}' for repository '${repository.name}'.`, 'debug')\n replaceRelativePath(file, repository.docpress.replace_url)\n\n if (basename(file).toLowerCase() === 'readme.md') {\n replaceReadmePath(file, repository.docpress.replace_url)\n }\n // Runs last so remaining relative links are rewritten to match the\n // renamed files (index prefix stripped, lowercased, readme -> introduction)\n replaceInternalMdLinks(file)\n })\n\n log(` Generate sidebar for repository '${repository.name}'.`, 'info')\n const projectFiles = readdirSync(repository.docpress.projectPath, { recursive: true })\n .filter((file) => {\n const filePath = resolve(repository.docpress.projectPath, file.toString())\n // Name check first, then a stat that tolerates files vanishing between\n // the directory scan and the check (e.g. leftover git lock files)\n return basename(filePath).endsWith('.md') && isFile(filePath)\n })\n .sort() as string[]\n\n log(` Add sources for repository '${repository.name}'.`, 'info')\n let sourceFile\n if (projectFiles.length > 1) {\n sourceFile = resolve(repository.docpress.projectPath, 'sources.md')\n projectFiles.push('sources.md')\n } else if (projectFiles.length === 1) {\n sourceFile = resolve(repository.docpress.projectPath, projectFiles[0])\n }\n if (sourceFile) {\n addSources(repository.html_url, sourceFile)\n } else {\n log(` No markdown files found for repository '${repository.name}', skipping sources.`, 'warn')\n }\n\n const projectTree = buildTree(projectFiles)\n const sidebarItems = moveSourcesLast(generateSidebarItems(repository, projectTree))\n\n sidebar.push(generateSidebarProject(prettify(repository.name, { removeDot: true }), sidebarItems))\n features.push(...generateFeatures(prettify(repository.name, { removeDot: true }), repository.description || ''))\n }\n\n log(` Generate index content.`, 'info')\n const index = generateIndex(features.toSorted((a, b) => a.title.localeCompare(b.title)), user, websiteInfos)\n return {\n sidebar: sidebar.toSorted((a, b) => a.text.localeCompare(b.text)),\n index,\n }\n}\n\n/**\n * Adds extra pages to the documentation from specified paths\n *\n * @param paths - Array of paths to markdown files\n * @returns Array of navigation page objects\n */\nexport function addExtraPages(paths: string[]) {\n const files = getMdFiles(paths)\n const nav: Page[] = []\n\n log(` Add extras Vitepress headers pages.`, 'info')\n for (const file of files) {\n log(` Processing file '${file}'.`, 'debug')\n const src = resolve(process.cwd(), file)\n const dest = resolve(DOCS_DIR, prettify(basename(file), { mode: 'lowercase', removeIdx: true }))\n cpSync(src, dest)\n nav.push({\n text: prettify(parse(src).name, { replaceDash: true, removeIdx: true }),\n link: `/${prettify(parse(src).name, { removeIdx: true, mode: 'lowercase' })}`,\n })\n }\n return nav\n}\n\n/**\n * Adds content from specified paths to a target directory\n *\n * @param paths - String or array of paths to content\n * @param dir - Target directory to copy content to\n * @param fn - Optional callback function to execute for each file\n */\nexport function addContent(paths: string | string[], dir: string, fn?: () => void) {\n for (const path of Array.isArray(paths) ? paths : [paths]) {\n const absolutePath = resolve(process.cwd(), path)\n const files = extractFiles(absolutePath)\n\n for (const file of files) {\n const formattedFile = file.replace(absolutePath, '.')\n log(` Processing file '${formattedFile}' for entry '${path}'.`, 'debug')\n const src = resolve(process.cwd(), file)\n const dest = resolve(dir, formattedFile)\n if (fn) {\n fn()\n }\n cpSync(src, dest)\n }\n }\n}\n\n/**\n * Creates a fork page to display external contributions\n *\n * @param forks - Array of repositories and contribution counts\n */\nexport function addForkPage(forks: { repository: Awaited<ReturnType<typeof getInfos>>['repos'][number], contributions: number }[]) {\n const separator = '---\\n'\n const header = 'layout: fork-page\\nrepoList:\\n'\n const text = '\\n# External contributions\\n\\nThis gallery is a visual representation of the collaborative work done across a variety of open-source projects, each driven by a shared passion for innovation and community growth.\\n\\nEvery tile below represents a unique project where contributions have been made-ranging from code enhancements to documentation improvements. Each project includes a summary of its goals, features, and links to GitHub for direct access.\\n\\nThis page serves as both a portfolio of past work and a resource for revisiting projects that have made a meaningful impact.\\n'\n const frontmatter = forks.map(({ repository, contributions }) => {\n const { name, owner, html_url, description, stargazers_count } = repository\n return { name, owner: owner.login, html_url, description, stargazers_count, contributions }\n })\n log(` Generate forks page.`, 'info')\n writeFileSync(FORKS_FILE, separator + header + YAML.stringify(frontmatter) + separator + text)\n}\n\ntype Source = Required<Awaited<ReturnType<typeof getContributors>>['source']>\n\ntype AdaptedLicense = Omit<NonNullable<Source>['license'], 'spdx_id'> & { spdx_id?: string }\n\ntype AdaptedRepository = Omit<NonNullable<Source>, 'license'> & { license: AdaptedLicense }\n\n/**\n * Processes forked repositories to generate contribution information\n *\n * @param repositories - Array of enhanced repositories\n * @param username - GitHub username\n * @param token - Optional GitHub API token\n */\nexport async function processForks(repositories: EnhancedRepository[], username: GlobalOpts['usernames'][number], token?: GlobalOpts['token']) {\n const forks = await Promise.all(\n repositories.map(async (repository) => {\n const { source, contributors } = await getContributors({ repository, token })\n return {\n contributions: contributors?.find(contributor => contributor.login === username)?.contributions ?? 0,\n repository: source as AdaptedRepository,\n }\n }),\n ).then(f => f.filter(({ repository, contributions }) => !!repository && contributions))\n\n addForkPage(forks)\n}\n\n/**\n * Parses a VitePress configuration file\n *\n * @param path - Path to the VitePress config file\n * @returns The parsed configuration object\n */\nexport async function parseVitepressConfig(path: string): Promise<Partial<ReturnType<typeof defineConfig>>> {\n try {\n const { config } = await import(resolve(process.cwd(), path))\n return config ?? {}\n } catch (error) {\n log(` Unable to load existing Vitepress config '${path}', starting from an empty config. ${error instanceof Error ? error.message : ''}`, 'warn')\n return {}\n }\n}\n\n/**\n * Parses a VitePress index file\n *\n * @param path - Path to the index file\n * @returns The parsed index object\n */\nexport async function parseVitepressIndex(path: string): Promise<Index> {\n const index = (await readFile(resolve(process.cwd(), path))).toString()\n return YAML.parse(index)\n}\n\n/**\n * Generates VitePress configuration and index files\n *\n * @param vitepressConfig - VitePress configuration object\n * @param index - Index page configuration\n * @returns The list of theme files that were generated\n */\nexport function generateVitepressFiles(vitepressConfig: Partial<ReturnType<typeof defineConfig>>, index: Index) {\n const separator = '---\\n'\n createDir(dirname(VITEPRESS_CONFIG))\n\n log(` Generate Vitepress config.`, 'info')\n writeFileSync(VITEPRESS_CONFIG, `export const config = ${JSON.stringify(vitepressConfig, null, 2)}\\n\\nexport default config\\n`)\n log(` Generate index file.`, 'info')\n writeFileSync(INDEX_FILE, separator + YAML.stringify(index))\n log(` Add Docpress theme files.`, 'info')\n return extractFiles(TEMPLATE_THEME).forEach((path) => {\n const relativePath = path.replace(`${TEMPLATE_THEME}/`, '')\n generateFile(path, resolve(VITEPRESS_THEME, relativePath))\n })\n}\n","import { dirname } from 'node:path'\nimport { createCommand, createOption } from 'commander'\nimport { configSchema } from '../schemas/global.js'\nimport { addOptions, explicitOptions, parseOptions } from '../utils/commands.js'\nimport { prepareDoc } from '../lib/prepare.js'\nimport type { PrepareOpts } from '../schemas/prepare.js'\nimport { log } from '../utils/logger.js'\nimport { createDir } from '../utils/functions.js'\nimport { VITEPRESS_CONFIG } from '../utils/const.js'\nimport { globalOpts } from './global.js'\n\n/**\n * Command name for the prepare operation\n */\nconst cmdName = 'prepare'\n\n/**\n * Command line options specific to the prepare command\n */\nexport const prepareOpts = [\n createOption('-c, --extra-public-content <string>', configSchema.shape.extraPublicContent.description),\n createOption('-f, --forks', configSchema.shape.forks.description),\n createOption('-p, --extra-header-pages <string>', configSchema.shape.extraHeaderPages.description),\n createOption('-t, --extra-theme <string>', configSchema.shape.extraTheme.description),\n createOption('-v, --vitepress-config <string>', configSchema.shape.vitepressConfig.description),\n createOption('--website-title <string>', configSchema.shape.websiteTitle.description),\n createOption('--website-tagline <string>', configSchema.shape.websiteTagline.description),\n]\n\n/**\n * The prepare command definition for Commander\n */\nexport const prepareCmd = addOptions(createCommand(cmdName), [...prepareOpts, ...globalOpts])\n .description('Transform doc to the target vitepress format.')\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions(cmdName, explicitOptions(cmd, opts))\n await main(parsedOpts)\n })\n\n/**\n * Main function to execute the prepare command\n *\n * @param opts - Validated prepare options\n */\nexport async function main(opts: PrepareOpts) {\n const { extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, lastUpdated, token, usernames, websiteTitle, websiteTagline } = opts\n log(`\\n-> Start transform files to prepare Vitepress build.`, 'info')\n\n createDir(dirname(VITEPRESS_CONFIG), { clean: true })\n for (const username of usernames) {\n await prepareDoc({ extraHeaderPages, extraPublicContent, extraTheme, vitepressConfig, forks, gitProvider, lastUpdated, token, username, websiteTitle, websiteTagline })\n }\n}\n","import { Command } from 'commander'\nimport pkg from '../package.json' with { type: 'json' }\nimport { fetchCmd, main as fetchFn, fetchOpts } from './commands/fetch.js'\nimport { buildCmd, main as buildFn } from './commands/build.js'\nimport { prepareCmd, main as prepareFn, prepareOpts } from './commands/prepare.js'\nimport { addOptions, explicitOptions, parseOptions } from './utils/commands.js'\nimport { globalOpts } from './commands/global.js'\nimport { log } from './utils/logger.js'\n\n/**\n * Creates and configures the Command Line Interface for DocPress\n *\n * @returns A configured Commander program instance\n */\nexport function getProgram() {\n const pm = new Command()\n .name('docpress')\n .description('Build your doc website faster than light ⚡️⚡️⚡️')\n .version(`${pkg.version}`)\n .action(async (opts, cmd) => {\n const parsedOpts = parseOptions('global', explicitOptions(cmd, opts))\n await fetchFn(parsedOpts)\n await prepareFn(parsedOpts)\n await buildFn()\n })\n .configureHelp({\n sortSubcommands: true,\n sortOptions: true,\n showGlobalOptions: true,\n })\n .enablePositionalOptions()\n .passThroughOptions()\n .addCommand(fetchCmd)\n .addCommand(prepareCmd)\n .addCommand(buildCmd)\n\n addOptions(pm, [...fetchOpts, ...prepareOpts, ...globalOpts])\n\n return pm\n}\n\n/**\n * Entry point for the DocPress CLI\n * Initializes and runs the command parser\n */\nexport function main() {\n const pm = getProgram()\n pm.parseAsync(process.argv).catch((error) => {\n log(`\\n${error instanceof Error ? error.message : String(error)}`, 'error')\n process.exit(1)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GCKa,IAAe,EAAQ,QAAQ,IAAI,GAAG,UAAU,GAKhD,IAAW,EAAQ,QAAQ,IAAI,GAAG,eAAe,GAKjD,IAAa,EAAQ,QAAQ,IAAI,GAAG,wBAAwB,GAK5D,KAAa,EAAQ,QAAQ,IAAI,GAAG,wBAAwB,GAK5D,IAAmB,EAAQ,QAAQ,IAAI,GAAG,+BAA+B,GAKzE,KAAkB,EAAQ,QAAQ,IAAI,GAAG,2BAA2B,GAKpE,KAAuB,EAAQ,QAAQ,IAAI,GAAG,kCAAkC,GAMhF,IAAA,QAAA,IAAA,aAA6C,gBACtD,EAAQ,OAAO,KAAK,SAAS,8BAA8B,IAC3D,EAAQ,OAAO,KAAK,SAAS,mBAAmB,GC3CvC,KAAoB,kCACpB,KAAkB,oEAClB,KAAsB,gDACtB,KAAiB,WACjB,IAAmB,oCACnB,KAAsB;;;ACanC,eAAsB,EAAgB,GAA8B;CAClE,IAAI;EAEF,QAAO,MADgB,MAAM,GAAK;GAAE,QAAQ;GAAQ,UAAU;EAAS,CAAC,EAAA,CACxD;CAClB,QAAiB;EACf,OAAO;CACT;AACF;AAoBA,SAAgB,EAAS,GAAW,GAAoB;CACtD,IAAI,IAAY;CAgChB,OA9BI,GAAM,cACR,AAGE,IAHE,EAAE,WAAW,GAAG,IACd,EAAE,MAAM,CAAC,IAET,GAGN,IAAI,EAAE,WAAW,KAAK,GAAG,IAGvB,GAAM,cACR,KAAK,KAAK,EAAA,CAAG,QAAQ,IAAgB,EAAE,IAGrC,GAAM,cACR,KAAK,KAAK,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,KAGtB,GAAM,gBACR,KAAK,KAAK,EAAA,CAAG,WAAW,KAAK,GAAG,IAG9B,GAAM,SAAS,eACjB,KAAK,KAAK,EAAA,CAAG,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,KAAK,KAAK,EAAA,CAAG,MAAM,CAAC,CAAC,CAAC,YAAY,IAC9D,GAAM,SAAS,cACxB,KAAK,KAAK,EAAA,CAAG,YAAY,IAChB,GAAM,SAAS,gBACxB,KAAK,KAAK,EAAA,CAAG,YAAY,IAGpB,KAAK;AACd;AASA,SAAgB,EAAU,GAAmB,EAAE,aAA+B,EAAE,OAAO,GAAM,GAAG;CAC9F,IAAI;EAIF,AAHI,KAAS,EAAW,CAAS,KAC/B,EAAW,GAAG,EAAU,KAAK,EAAE,MAAM,GAAK,CAAC,GAExC,EAAW,CAAS,KACvB,EAAU,GAAW,EAAE,WAAW,GAAK,CAAC;CAE5C,SAAS,GAAK;EACZ,QAAQ,MAAM,CAAG;CACnB;AACF;AAQA,SAAgB,GAAM,GAAc;CAClC,IAAI;EACF,OAAO,EAAS,CAAI,CAAC,CAAC,YAAY;CACpC,QAAiB;EACf,OAAO;CACT;AACF;AAQA,SAAgB,GAAO,GAAc;CACnC,IAAI;EACF,OAAO,EAAS,CAAI,CAAC,CAAC,OAAO;CAC/B,QAAiB;EACf,OAAO;CACT;AACF;AAQA,SAAgB,EAAa,GAAoC;CAC/D,QAAQ,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC,CAAK,EAAA,CAAG,SAAS,MACnD,GAAO,CAAI,IACN,CAAC,CAAI,IAEV,GAAM,CAAI,IACL,EAAY,CAAI,CAAC,CAAC,QAAO,MAAQ,MAAS,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,SAAQ,MAAQ,EAAa,GAAK,GAAM,CAAI,CAAC,CAAC,IAEzG,CAAC,CACT;AACH;AAQA,SAAgB,EAAW,GAAgB;CACzC,OAAO,EAAa,CAAI,CAAC,CAAC,QAAO,MAAQ,EAAS,CAAI,CAAC,CAAC,SAAS,KAAK,CAAC;AACzE;AAQA,SAAgB,GAAa,GAAwB;CACnD,OAAO,EAAI,QAAQ,GAAK,GAAK,GAAK,MAC3B,IAEM,MAAQ,EAAI,SAAS,IACvB,GAAG,EAAI,OAAO,EAAI,KAElB,GAAG,EAAI,KAAK,EAAI,KAJhB,IAAI,EAAI,IAMhB,EAAE;AACP;AAQA,SAAgB,GAAa,GAA2C;CACtE,OAAO,KAAK,MAAM,EAAa,GAAG,EAAa,QAAQ,EAAS,MAAM,CAAC,CAAC,SAAS,CAAC;AACpF;AAQA,SAAgB,GAAa,GAA2C;CACtE,OAAO,KAAK,MAAM,EAAa,GAAG,EAAa,SAAS,EAAS,MAAM,CAAC,CAAC,SAAS,CAAC;AACrF;AAQA,SAAgB,EAAgD,GAAG,GAAiB;CAClF,OAAO,EAAQ,QAAQ,GAAK,OACtB,MAAQ,QAIZ,OAAO,KAAK,CAAG,CAAC,CAAC,SAAS,MAAQ;EAChC,IAAM,IAAW,IAAM,EAAI,KAAO,MAC5B,IAAW,EAAI;EAErB,AAAI,EAAS,CAAQ,KAAK,EAAS,CAAQ,IACzC,EAA6B,KAAO,EAAU,GAAU,CAAQ,IAEhE,EAA6B,KAAO;CAExC,CAAC,GAZQ,IAcR,CAAC,CAAM;AACZ;AAQA,SAAgB,EAAS,GAAyB;CAChD,OAAO,KAAO,OAAO,KAAQ,YAAY,CAAC,MAAM,QAAQ,CAAG;AAC7D;AASA,SAAgB,EAAe,GAAqB;CAClD,IAAI,CAAC,GACH,OAAO,CAAC;CAEV,IAAM,IAAW,EAAQ,QAAQ,IAAI,GAAG,CAAU,GAC9C;CACJ,IAAI;EACF,IAAe,EAAa,GAAU,MAAM;CAC9C,QAAiB;EACf,MAAU,MAAM,4BAA4B,EAAW,GAAG;CAC5D;CACA,IAAI;EACF,OAAO,KAAK,MAAM,CAAY;CAChC,QAAiB;EACf,MAAU,MAAM,gCAAgC,EAAW,GAAG;CAChE;AACF;AAQA,SAAgB,EAAa,GAAW;CACtC,OAAO,EAAE,MAAM,GAAG;AACpB;AAQA,SAAgB,GAAoB,GAAc,GAAa;CAK7D,EAAc,GAJM,EAAa,GAAM,MAChB,CAAA,CAAY,QAAQ,KAAoB,GAAQ,GAAI,MAClE,IAAI,EAAG,IAAI,EAAI,GAAG,EAAG,EAEV,GAAgB,MAAM;AAC5C;AASA,SAAgB,GAA0B,GAAc,GAAc;CACpE,IAAM,IAAU,EAAa,GAAM,MAAM,GACnC,IAAQ,EAAQ,MAAM,CAAgB;CAE5C,IAAI,GAAO;EACT,IAAM,IAAO,EAAK,MAAM,EAAM,EAAE,KAAK,CAAC;EAEtC,AADA,EAAK,cAAc,GACnB,EAAc,GAAM,EAAQ,QAAQ,GAAkB,QAAQ,EAAK,UAAU,CAAI,EAAE,MAAM,GAAG,MAAM;CACpG,OACE,EAAc,GAAM,qBAAqB,EAAK,WAAW,KAAW,MAAM;AAE9E;AAUA,SAAgB,GAAuB,GAAc;CASnD,EAAc,GARM,EAAa,GAAM,MAChB,CAAA,CAAY,QAAQ,KAAsB,GAAQ,GAAM,GAAK,GAAQ,MAAW;EACrG,IAAI,IAAW,EAAS,GAAQ;GAAE,MAAM;GAAa,WAAW;EAAK,CAAC;EAItE,OAHI,MAAa,gBACf,IAAW,oBAEN,IAAI,EAAK,IAAI,KAAO,KAAK,IAAW,KAAU,GAAG;CAC1D,CACoB,GAAgB,MAAM;AAC5C;AAQA,SAAgB,GAAkB,GAAc,GAAa;CAS3D,EAAc,GARQ,EAAa,GAAM,MAClB,CAAA,CACpB,QAAQ,KAAkB,GAAQ,GAAI,GAAK,MACnC,IAAI,EAAG,IAAI,EAAI,GAAG,EAAG,EAC7B,CAAC,CACD,QAAQ,KAAsB,GAAQ,GAAI,GAAK,MACvC,IAAI,EAAG,IAAI,EAAG,EAEL,GAAgB,MAAM;AAC5C;;;ACxTA,SAAS,KAAc;CACrB,IAAM,IAAQ,OAAO,QAAQ,IAAI,SAAY;CAC7C,OAAO,OAAO,MAAM,CAAK,IAAI,KAAK;AACpC;AAKA,IAAM,KAAqB;CACzB,OAAO;EAAE,OAAO;EAAO,OAAO;CAAG;CACjC,MAAM;EAAE,OAAO;EAAU,OAAO;CAAG;CACnC,MAAM;EAAE,OAAO;EAAS,OAAO;CAAG;CAClC,SAAS;EAAE,OAAO;EAAS,OAAO;CAAG;CACrC,OAAO;EAAE,OAAO;EAAS,OAAO;CAAG;CACnC,OAAO;EAAE,OAAO;EAAQ,OAAO;CAAG;AACpC;AASA,SAAgB,EAAI,GAAa,IAAgB,QAAQ,GAAmB;CAC1E,IAAM,IAAc,IAAQ,EAAM,EAAM,CAAC,CAAG,IAAI,EAAM,GAAS,EAAK,CAAC,MAAM,CAAC,CAAG,GACzE,IAAe,MAAS,YAAY,SAAS;CAEnD,AAAI,GAAY,KAAK,GAAS,EAAK,CAAC,SAClC,QAAQ,EAAa,CAAC,CAAW;AAErC;;;AChDA,IAAM,IAAY,CAAC,UAAU,QAAQ,GAMxB,IAAe,EAAE,OAAO;CAEnC,WAAW,EAAE,OAAO,CAAC,CAClB,MAAM,CAAC,CACP,SAAS,sEAAsE;CAElF,QAAQ,EAAE,OAAO,CAAC,CACf,QAAQ,MAAM,CAAC,CACf,SAAS,2CAA2C;CACvD,aAAa,EAAE,KAAK,CAAS,CAAC,CAC3B,QAAQ,QAAQ,CAAC,CACjB,SAAS,wDAAwD,GAAa,CAAS,EAAE,EAAE;CAC9F,aAAa,EAAE,OAAO,CAAC,CACpB,MAAM,CAAC,CACP,SAAS,gHAAiH;CAE7H,kBAAkB,EAAE,OAAO,CAAC,CACzB,MAAM,CAAC,CACP,SAAS,4FAA4F;CACxG,oBAAoB,EAAE,OAAO,CAAC,CAC3B,MAAM,CAAC,CACP,SAAS,6FAA6F;CACzG,YAAY,EAAE,OAAO,CAAC,CACnB,MAAM,CAAC,CACP,SAAS,oFAAoF;CAChG,OAAO,EAAE,QAAQ,CAAC,CACf,QAAQ,EAAK,CAAC,CACd,SAAS,yFAAyF;CACrG,aAAa,EAAE,QAAQ,CAAC,CACrB,QAAQ,EAAK,CAAC,CACd,SAAS,qGAAoG;CAChH,iBAAiB,EAAE,IAAI,CAAC,CACrB,SAAS,CAAC,CACV,SAAS,2CAA2C;CACvD,cAAc,EAAE,OAAO,CAAC,CACrB,SAAS,gBAAgB;CAC5B,gBAAgB,EAAE,OAAO,CAAC,CACvB,SAAS,kBAAkB;AAChC,CAAC,GASY,IAAY,EACtB,QAAQ,CAAC,CACT,OAAO;CACN,QAAQ,EAAE,OAAO,CAAC,CACf,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,OAAO,eAAe,EAAE;CACvD,aAAa,EAAE,KAAK,CAAS,CAAC,CAC3B,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,YAAY,eAAe,EAAE;CAC5D,OAAO,EAAE,QAAQ,CAAC,CACf,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,MAAM,eAAe,EAAE;CACtD,aAAa,EAAE,QAAQ,CAAC,CACrB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,YAAY,eAAe,EAAE;CAC5D,QAAQ,EAAE,OAAO,CAAC,CACf,SAAS,CAAC,CACV,SAAS,0CAA0C;CACtD,OAAO,EAAE,OAAO,CAAC,CACd,SAAS,CAAC,CACV,SAAS,0CAA0C;CACtD,WAAW,EAAE,OAAO,CAAC,CAClB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,UAAU,eAAe,EAAE;CAC1D,aAAa,EAAE,OAAO,CAAC,CACpB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,YAAY,eAAe,EAAE;CAC5D,kBAAkB,EAAE,OAAO,CAAC,CACzB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,iBAAiB,eAAe,EAAE;CACjE,oBAAoB,EAAE,OAAO,CAAC,CAC3B,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,mBAAmB,eAAe,EAAE;CACnE,YAAY,EAAE,OAAO,CAAC,CACnB,UAAU,CAAY,CAAC,CACvB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,WAAW,eAAe,EAAE;CAC3D,iBAAiB,EAAE,OAAO,CAAC,CACxB,SAAS,CAAC,CACV,SAAS,EAAa,MAAM,gBAAgB,eAAe,EAAE;AAClE,CAAC;AAUH,SAAS,GAAkB,GAAiB;CAC1C,IAAI,CAAC,GAAY,OAAO,CAAC;CAGzB,KAAK,IAAM,KAAO;EADC;EAAa;EAAe;EAAoB;EAAsB;CACvE,GAChB,AAAI,EAAW,MAAQ,OAAO,EAAW,MAAS,aAChD,EAAW,KAAO,CAAC,EAAW,EAAI;CAItC,OAAO;AACT;AASA,SAAS,GAAmB,GAAiB;CAC3C,IAAM,IAAS,EAAa,QAAQ,CAAC,CAAC,UAAU,CAAU;CAC1D,IAAI,CAAC,EAAO,SACV,MAAU,MAAM,EAAE,cAAc,EAAO,KAAK,CAAC;CAE/C,OAAO,EAAO;AAChB;AASA,SAAS,GAAoB,GAAmB;CAC9C,IAAI,CAAC,EAAa,WAAW,QAC3B,MAAU,MAAM,iCAAiC;CAGnD,OAAO;AACT;AAMA,IAAa,KAAmB,EAC7B,QAAQ,CAAC,CACT,WAAW,MAAS;CACnB,IAAI;EACF,IAAM,EAAE,WAAQ,oBAAiB,UAAO,GAAG,MAAS;EAEpD,EAAI,kCAAkC,KAAK,UAAU,CAAI,KAAK,OAAO;EAGrE,IAAM,IAAa,GAAmB,GAAkB,EAAe,CAAM,CAAC,CAAC,GAGzE,IAAe;GACnB,QAAQ;GACR,aAAa;GACb,OAAO;GACP,aAAa;GACb,GAAG;GACH,GAAG;GACH,GAAI,IACA,EACE,iBAAiB;IACf,GAAI,EAAW,mBAAmB,CAAC;IACnC,GAAI,EAAe,CAAe,KAAK,CAAC;GAC1C,EACF,IACA,CAAC;EACP;EAIA,OAFA,EAAI,+BAA+B,KAAK,UAAU,CAAY,KAAK,OAAO,GAEnE,GAAoB;GAAE,GAAG;GAAc;EAAM,CAAC;CACvD,SAAS,GAAO;EAOd,AANA,EAAI,sDAAsD,OAAO,GAC7D,aAAiB,QACnB,EAAI,QAAQ,EAAM,WAAW,OAAO,IAEpC,EAAI,QAAQ,KAAK,UAAU,GAAO,MAAM,CAAC,KAAK,OAAO,GAEvD,QAAQ,KAAK,CAAC;CAChB;AACF,CAAC;;;AC5KH,SAAgB,EAA4B,GAAQ,GAA2C;CAI7F,AAHA,EAAI,4BAA4B,QAAQ,MAAM,GAC9C,EAAI,yEAAyE,MAAM,GACnF,EAAI,yBAAyB,KAAK,UAAU,CAAI,KAAK,OAAO,GAC5D,EAAI,wBAAwB,KAAO,OAAO;CAE1C,IAAM,IAAM,GAAiB,UAAU,CAAI;CAM3C,OALK,EAAI,YACP,EAAI,4DAA4D,EAAE,cAAc,EAAI,KAAK,KAAK,OAAO,GACrG,QAAQ,KAAK,CAAC,IAEhB,EAAI,2DAA2D,MAAM,GAC9D,EAAI;AACb;AAUA,SAAgB,EAAgB,GAAc,GAA+B;CAC3E,OAAO,OAAO,YACZ,OAAO,QAAQ,CAAI,CAAC,CAAC,QAAQ,CAAC,OAAS,EAAI,qBAAqB,CAAG,MAAM,SAAS,CACpF;AACF;AASA,SAAgB,EAAW,GAAc,GAAgB;CACvD,KAAK,IAAM,KAAO,GAChB,EAAI,UAAU,CAAG;CAEnB,OAAO;AACT;;;ACzDA,IAAM,IAAkB;CACtB,aAAa,CAAC;CACd,YAAY,CAAC;CACb,OAAO,MAAoB;EACzB,AAAK,EAAQ,SAAS,KAAK,KAAG,QAAQ,KAAK,CAAO;CACpD;CACA,QAAQ,MAAoB;EAC1B,AAAK,EAAQ,SAAS,KAAK,KAAG,QAAQ,MAAM,CAAO;CACrD;AACF;AAWA,eAAsB,GAAS,EAAE,aAAU,UAAO,aAAiH;CACjK,EAAI,8BAA8B,EAAS,KAAK,MAAM;CACtD,IAAM,IAAU,IAAI,EAAQ;EAAE,MAAM;EAAO,KAAK;CAAgB,CAAC;CACjE,EAAI,sBAAsB,OAAO;CACjC,IAAM,EAAE,MAAM,MAAS,MAAM,EAAQ,KAAK,MAAM,cAAc,EAAE,YAAS,CAAC,CAAC,CACxE,OAAO,MAAU;EAChB,MAAM,EAAM,WAAW,MAAM,gBAAI,MAAM,6BAA6B,EAAS,GAAG,IAAI;CACtF,CAAC;CAIH,OAHA,EAAI,8BAA8B,OAAO,GAGlC;EAAE;EAAM,OAAA,MAFK,EAAQ,SAAS,EAAQ,KAAK,MAAM,aAAa;GAAE;GAAU,MAAM;GAAa,UAAU;EAAI,CAAC;EAE7F;CAAO;AAC/B;AAUA,eAAsB,GAAgB,EACpC,eACA,YAIC;CACD,EAAI,6CAA6C,EAAW,KAAK,KAAK,MAAM;CAC5E,IAAM,IAAU,IAAI,EAAQ;EAAE,MAAM;EAAO,KAAK;CAAgB,CAAC,GAC3D,EAAE,MAAM,MAAS,MAAM,EAAQ,KAAK,MAAM,IAAI;EAClD,OAAO,EAAW,MAAM;EACxB,MAAM,EAAW;CACnB,CAAC;CACD,IAAI,CAAC,EAAK,QAAQ,OAAO,OACvB,OAAO;EAAE,QAAQ,EAAK;EAAQ,cAAc,CAAC;CAAE;CAEjD,IAAM,IAA2B,CAAC;CAClC,IAAI;EACF,WAAW,IAAM,EAAE,aAAU,EAAQ,SAAS,SAC5C,EAAQ,KAAK,MAAM,kBACnB;GACE,OAAO,EAAK,OAAO,MAAM;GACzB,MAAM,EAAK,QAAQ,QAAQ,EAAK;GAChC,UAAU;EACZ,CACF,GACE,EAAa,KAAK,GAAG,CAAI;CAE7B,SAAS,GAAO;EAKd,OAJA,EACE,uDAAuD,EAAW,KAAK,aAAa,EAAM,WAC1F,MACF,GACO;GAAE,QAAQ,EAAK;GAAQ,cAAc,CAAC;EAAE;CACjD;CAEA,OAAO;EAAE,QAAQ,EAAK;EAAQ;CAAa;AAC7C;AAWA,eAAsB,GAAiB,GAAgB,GAAoB,GAAc;CACvF,KAAK,IAAM,KAAQ,EAAW,CAAC,CAAU,CAAC,GAAG;EAC3C,IAAM,IAAW,EAAS,GAAY,CAAI;EAE1C,IAAI;GACF,IAAM,EAAE,cAAW,MAAM,EAAI,IAAI;IAAE,MAAM;IAAU,UAAU;GAAE,CAAC;GAChE,AAAI,GAAQ,QACV,GAA0B,GAAM,EAAO,IAAI;EAE/C,SAAS,GAAO;GACd,EAAI,0CAA0C,EAAS,mBAAmB,EAAK,aAAa,KAAS,MAAM;EAC7G;CACF;AACF;AAYA,eAAsB,GAAU,GAAc,GAAa,GAAoB,GAAgB,GAAoB,GAAuB;CACxI,EAAU,GAAY,EAAE,OAAO,GAAK,CAAC;CAErC,IAAI;EAGF,IAAM,IAAM,GAAU;GAAE,SAAS;GAAY,QAAQ;IAAC;IAA0B;IAAa;GAA8B;EAAE,CAAC;EAC9H,MAAM,EAAI,KAAK,CAAC,CACb,UAAU,uBAAuB,QAAQ,IAAM,OAAO,CAAC,CACvD,UAAU,UAAU,CAAG;EAE1B,KAAK,IAAM,KAAQ,GAEjB,AADA,EAAI,WAAW,EAAK,QAAQ,EAAK,0BAA0B,OAAO,GAClE,EAAe,EAAQ,GAAY,2BAA2B,GAAG,GAAG,EAAK,KAAK,MAAM;EActF,AAXA,EAAI,wBAAwB,EAAK,KAAK,MAAM,GAC5C,MAAM,EAAI,KAAK,UAAU,CAAM,GAE3B,KACF,MAAM,GAAiB,GAAK,GAAY,CAAI,GAG1C,EAAS,MAAK,MAAQ,EAAK,SAAS,MAAM,CAAC,MAC7C,EAAO,EAAQ,GAAY,MAAM,GAAG,GAAY,EAAE,WAAW,GAAK,CAAC,GACnE,EAAO,EAAQ,GAAY,MAAM,GAAG,EAAE,WAAW,GAAK,CAAC,IAEzD,EAAO,EAAQ,GAAY,MAAM,GAAG,EAAE,WAAW,GAAK,CAAC;CACzD,SAAS,GAAO;EACd,EAAI,qCAAqC,EAAM,IAAI,OAAO;CAC5D;AACF;;;ACxJA,IAAa,KAAiB;AAa9B,eAAe,EAAU,GAAc,GAA6B;CAClE,IAAM,IAAW,MAAM,MAAM,GAAG,KAAiB,KAAQ,EACvD,SAAS,IAAQ,EAAE,iBAAiB,EAAM,IAAI,CAAC,EACjD,CAAC;CACD,IAAI,CAAC,EAAS,IACZ,MAAU,MAAM,kCAAkC,EAAK,aAAa,EAAS,OAAO,GAAG;CAEzF,OAAO;EAAE,MAAM,MAAM,EAAS,KAAK;EAAG,SAAS,EAAS;CAAQ;AAClE;AASA,eAAe,EAAa,GAAc,GAA6B;CACrE,IAAM,IAAY,EAAK,SAAS,GAAG,IAAI,MAAM,KACvC,IAAe,CAAC,GAClB,IAAsB;CAE1B,OAAO,IAAM;EACX,IAAM,EAAE,SAAM,eAAY,MAAM,EAAU,GAAG,IAAO,EAAU,oBAAoB,KAAQ,CAAK;EAE/F,AADA,EAAM,KAAK,GAAG,CAAI,GAClB,IAAO,EAAQ,IAAI,aAAa,KAAK;CACvC;CACA,OAAO;AACT;AAQA,SAAS,EAAQ,GAAW;CAC1B,OAAO;EACL,OAAO,EAAK,YAAY,EAAK;EAC7B,MAAM,EAAK;EACX,KAAK,EAAK,OAAO,EAAK,eAAe;EACrC,YAAY,EAAK;EACjB,UAAU,EAAK;CACjB;AACF;AASA,SAAS,EAAc,GAAc,GAAe;CAClD,OAAO;EACL,MAAM,EAAQ;EACd,OAAO,EAAE,OAAO,EAAM;EACtB,MAAM,CAAC,CAAC,EAAQ;EAChB,SAAS,EAAQ,eAAe;EAEhC,MAAM,KAAQ;EACd,gBAAgB,EAAQ;EACxB,WAAW,EAAQ;EACnB,UAAU,EAAQ;EAClB,aAAa,EAAQ;EACrB,kBAAkB,EAAQ;CAC5B;AACF;AAYA,eAAsB,GAAS,EAAE,aAAU,UAAO,aAAiH;CACjK,EAAI,8BAA8B,EAAS,KAAK,MAAM;CAEtD,IAAM,EAAE,MAAM,MAAU,MAAM,EAAU,mBAAmB,mBAAmB,CAAQ,KAAK,CAAK;CAEhG,IAAI,EAAM,QAAQ;EAChB,IAAI,IAAO,EAAM;EAKjB,AAJI,MAEF,IAAO,MAAM,EAAU,UAAU,EAAM,EAAE,CAAC,MAAM,CAAK,CAAC,CAAC,MAAK,MAAO,EAAI,IAAI,CAAC,CAAC,YAAY,EAAM,EAAE,IAEnG,EAAI,8BAA8B,OAAO;EACzC,IAAM,IAAW,MAAM,EAAa,UAAU,EAAM,EAAE,CAAC,GAAG,YAAY,CAAK;EAC3E,OAAO;GAAE,MAAM,EAAQ,CAAI;GAAG,OAAO,EAAS,KAAI,MAAW,EAAc,GAAS,EAAK,QAAQ,CAAC;GAAG;EAAO;CAC9G;CAEA,EAAI,sBAAsB,EAAS,0BAA0B,OAAO;CACpE,IAAM,IAAQ,MAAM,EAAU,WAAW,mBAAmB,CAAQ,EAAE,uBAAuB,CAAK,CAAC,CAChG,MAAK,MAAO,EAAI,IAAI,CAAC,CACrB,YAAY;EACX,MAAU,MAAM,sCAAsC,EAAS,GAAG;CACpE,CAAC,GACG,IAAW,MAAM,EAAa,WAAW,mBAAmB,CAAQ,EAAE,YAAY,CAAK;CAC7F,OAAO;EAAE,MAAM,EAAQ,CAAK;EAAG,OAAO,EAAS,KAAI,MAAW,EAAc,GAAS,EAAM,IAAI,CAAC;EAAG;CAAO;AAC5G;;;ACpFA,SAAgB,EAAgB,GAA6D,GAA6B,GAAsD;CAC9K,IAAI,MAAgB,UAAU;EAC5B,IAAM,IAAO,EAAK,YAAY,sBAAsB,EAAK,MAAM,MAAM,GAAG,EAAK;EAC7E,OAAO;GACL,UAAU,GAAG,EAAK,UAAU;GAC5B,UAAU,GAAG,EAAK,UAAU;GAC5B,SAAS,GAAG,EAAK,SAAS;EAC5B;CACF;CACA,IAAM,IAAO,EAAK,YAAY,sBAAsB,EAAK,MAAM,MAAM,GAAG,EAAK;CAC7E,OAAO;EACL,UAAU,GAAG,EAAK,QAAQ;EAC1B,UAAU,GAAG,EAAK,QAAQ;EAC1B,SAAS,qCAAqC,EAAK,MAAM,MAAM,GAAG,EAAK,KAAK,GAAG;CACjF;AACF;AAQA,eAAsB,GAAS,GAAoB;CAKjD,OAAO;EACL,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,WAAW;EAMzE,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,MAAM;EAMpE,kBAAA,MAL6B,EAAgB,GAAG,EAAK,SAAS,mBAAmB;CAMnF;AACF;AAaA,eAAsB,GAAS,EAAE,aAAU,WAAQ,gBAAa,gBAAa,UAAO,kBAA8B;CAEhH,OADyB,MAAgB,WAAW,KAAiB,GAAA,CAC9C;EAAE;EAAU;EAAO;CAAO,CAAC,CAAC,CAChD,KAAK,OAAO,EAAE,SAAM,UAAO,gBAAa,GAAc,GAAM,GAAO,GAAQ,GAAa,CAAW,CAAC,CAAC,CACrG,KAAK,OAAO,EAAE,eAAY,GAAO,GAAO,GAAa,CAAW,CAAC;AACtE;AAUA,eAAsB,GAAoB,GAAsD,GAA8B,GAAwC,GAAwC;CAC5M,IAAM,IAAsC,CAAC;CA4B7C,OA1BA,MAAM,QAAQ,IACZ,EAAM,IAAI,OAAO,MAAS;EACxB,IAAM,IAAiB,KAAU,EAAK,kBAAkB,QAClD,IAAc,EAAQ,GAAU,EAAS,EAAK,MAAM,EAAE,WAAW,GAAK,CAAC,CAAC,GACxE,IAAW,EAAe,GAAM,CAAW,GAC3C,IAAO,EAAgB,GAAM,GAAgB,CAAW,GAC1D,IAAqB,CAAC;EAM1B,AAJI,CAAC,EAAK,QAAQ,CAAC,EAAK,WAAW,CAAC,MAClC,IAAW,MAAM,GAAkB,GAAM,GAAgB,CAAW,IAGtE,EAAc,KAAK;GACjB,GAAG;GACH,UAAU;IACR;IACA,QAAQ;IACR;IACA;IACA,SAAS,EAAK;IACd,aAAa,EAAK;GACpB;EACF,CAAC;CACH,CAAC,CACH,GAEO;AACT;AAUA,eAAsB,GAAkB,GAA6D,GAA6B,GAAwC;CACxK,IAAM,IAAa,MAAM,GAAS,EAAgB,GAAM,GAAQ,CAAW,CAAC,GAEtE,IAAqB,CAAC;CAU5B,OATI,OAAO,OAAO,CAAU,CAAC,CAAC,OAAM,MAAU,MAAW,GAAG,KAAK,CAAC,EAAK,OAC9D,CAAC,KAEN,EAAW,qBAAqB,OAClC,EAAS,KAAK,QAAQ,IAEpB,EAAW,qBAAqB,OAAO,EAAW,qBAAqB,QACzE,EAAS,KAAK,aAAa,iBAAiB,GAEvC;AACT;AAYA,eAAsB,GAAc,GAAoD,GAAsD,GAA8B,GAAwC,GAAwC;CAC1P,EAAc,GAAG,EAAa,QAAQ,EAAK,MAAM,QAAQ,KAAK,UAAU,GAAM,MAAM,CAAC,CAAC;CAEtF,IAAM,IAAgB,MAAM,GAAoB,GAAO,GAAQ,GAAa,CAAW;CAGvF,OAFA,EAAc,GAAG,EAAa,SAAS,EAAK,MAAM,QAAQ,KAAK,UAAU,GAAe,MAAM,CAAC,CAAC,GAEzF;EAAE;EAAM,OAAO;CAAc;AACtC;AASA,eAAsB,GAAO,GAA8B,GAAwC,GAAuB;CACxH,IAAI,CAAC,GAAO;EACV,EAAI,4CAA4C,MAAM;EACtD;CACF;CAEA,MAAM,QAAQ,IACZ,EACG,QAAO,MAAQ,CAAC,EAAe,GAAM,CAAW,CAAC,CAAC,CAClD,IAAI,OAAO,MAAS;EACnB,MAAM,GAAU,EAAK,MAAM,EAAK,WAAqB,EAAK,SAAS,aAAa,EAAK,SAAS,QAAQ,EAAK,SAAS,UAAU,CAAW;CAC3I,CAAC,CACL;AACF;AASA,SAAgB,EAAe,GAAkF,GAAwC;CACvJ,IAAM,IAAoB,GAAa,OAAO,MAAmB,EAAO,WAAW,GAAG,CAAC,GACjF,IAAa,GAAa,QAAQ,MAAmB,EAAO,WAAW,GAAG,CAAC,CAAC,CAC/E,MAAM,MAAmB,EAAK,SAAS,EAAO,UAAU,CAAC,CAAC,GACvD,IAAa,CAAC,KACf,GAAa,QAAQ,MAAmB,CAAC,EAAO,WAAW,GAAG,CAAC,CAAC,CAAC,SAAS,EAAK,IAAI,KAClF,EAAK,QAAQ,CAAC,KACd,KAAqB,CAAC,GAEtB,IAAa,KAAc,CAAC;CASlC,OAPI,cAAc,KAAQ,CAAC,EAAK,SAAS,SAAS,SACzC,KAGT,EAAM,EAAK,aAAa,CAAC,EAAK,WAAW,CAAC;AAI5C;;;AC1NA,IAAa,IAAa;CACxB,EAAa,yBAAyB,EAAU,MAAM,OAAO,WAAW;CACxE,EAAa,wBAAwB,EAAU,MAAM,MAAM,WAAW;CACtE,EAAa,4BAA4B,EAAU,MAAM,UAAU,WAAW;AAChF,GCGM,KAAU,SAKH,KAAY;CACvB,EAAa,yBAAyB,EAAa,MAAM,OAAO,WAAW,CAAC,CACzE,QAAQ,EAAa,MAAM,OAAO,IAAI,YAAY;CACrD,EAAa,+BAA+B,EAAa,MAAM,YAAY,WAAW,CAAC,CACpF,QAAQ,EAAa,MAAM,YAAY,IAAI,YAAY;CAC1D,EAAa,sBAAsB,EAAa,MAAM,YAAY,WAAW;CAC7E,EAAa,+BAA+B,EAAa,MAAM,YAAY,WAAW;AACxF,GAKa,KAAW,EAAW,EAAc,EAAO,GAAG,CAAC,GAAG,IAAW,GAAG,CAAU,CAAC,CAAC,CACtF,YAAY,yDAAyD,CAAC,CACtE,OAAO,OAAO,GAAM,MAAQ;CAE3B,MAAM,GADa,EAAa,IAAS,EAAgB,GAAK,CAAI,CACvD,CAAU;AACvB,CAAC;AAOH,eAAsB,GAAK,GAAiB;CAC1C,IAAM,EAAE,cAAW,gBAAa,UAAO,WAAQ,gBAAa,mBAAgB;CAG5E,AAFA,EAAI,wGAAwG,MAAM,GAElH,EAAU,GAAc,EAAE,OAAO,GAAK,CAAC;CACvC,KAAK,IAAM,KAAY,GAKrB,MAAM,GAAS;EAAE;EAAU;EAAQ,aAHnB,EAAU,SAAS,IAC/B,GAAa,QAAQ,MAAe,EAAG,QAAQ,MAAM,EAAE,CAAC,CAAC,WAAW,GAAG,EAAS,EAAE,CAAC,CAAC,CAAC,KAAK,MAAe,EAAG,QAAQ,GAAG,EAAS,IAAI,EAAE,CAAC,IACvI;EACqD;EAAa;EAAO;CAAY,CAAC;AAE9F;;;ACvCA,eAAsB,GAAuB,GAAwC;CAEnF,IAAM,IAAe,QAAQ;CAG7B,QAAQ,OAAO,SAAU,GAAG,GAAM;EAE9B,EAAK,SAAS,KACX,OAAO,EAAK,MAAO,aAClB,EAAK,EAAE,CAAC,SAAS,mCAAmC,KACnD,EAAK,EAAE,CAAC,SAAS,iBAAiB,MAMzC,EAAa,MAAM,SAAS,CAAI;CAClC;CAEA,IAAI;EAEF,OAAO,MAAM,EAAS;CACxB,UAAU;EAER,QAAQ,OAAO;CACjB;AACF;AAUA,IAAa,KAAW,EAAW,EAAc,OAAO,GAAG,CAAU,CAAC,CACnE,YAAY,0BAA0B,CAAC,CACvC,OAAO,OAAO,MAAU;CACvB,MAAM,GAAK;AACb,CAAC;AAMH,eAAsB,KAAO;CAC3B,EAAI,8CAA8C,MAAM;CAExD,IAAI;EAUF,AARA,MAAM,GAAoB,YAAY;GACpC,MAAM,GAAe,GAAc,EACjC,qBAAqB,GAAY;IAC/B,GAAY,CAAmC;GACjD,EACF,CAAC;EACH,CAAC,GAED,EAAI,iCAAiC,SAAS;CAChD,SAAS,GAAO;EAEd,AADA,EAAI,+BAA+B,KAAS,OAAO,GACnD,QAAQ,KAAK,CAAC;CAChB;AACF;;;ACrEA,SAAgB,GAAa,GAAa,GAAc;CACtD,IAAM,IAAU,EAAa,GAAK,EAAE,UAAU,OAAO,CAAC;CAEtD,AADA,EAAU,EAAQ,CAAI,CAAC,GACvB,EAAc,GAAM,CAAO;AAC7B;;;ACPA,IAAM,KAA0D;CAC9D,MAAM;CACN,MAAM;CACN,MAAM,EACJ,WAAW,YACb;CACA,OAAO;CACP,aAAa;CACb,QAAQ;CACR,WAAW;CACX,iBAAiB;CACjB,aAAa;EACX,SAAS,CAAC,GAAG,CAAC;EACd,QAAQ;GACN,UAAU;GACV,SAAS,EACP,cAAc;IACZ,QAAQ;KACN,YAAY;KACZ,iBAAiB;IACnB;IACA,OAAO;KACL,iBAAiB;KACjB,gBAAgB;KAChB,eAAe;KACf,kBAAkB;KAClB,QAAQ;MACN,YAAY;MACZ,cAAc;MACd,WAAW;KACb;IACF;GACF,EACF;EACF;CACF;AACF;AAUA,SAAgB,GAAmB,GAA2B,GAAa,GAA6F;CAItK,OAHe,IACX,EAAU,IAAwB,GAAiB,EAAE,aAAa;EAAE;EAAS;CAAI,EAAE,CAAC,IACpF,EAAU,IAAwB,EAAE,aAAa;EAAE;EAAS;CAAI,EAAE,CAAC;AAEzE;;;ACaA,eAAsB,GAAW,EAAE,qBAAkB,uBAAoB,eAAY,oBAAiB,UAAO,gBAAa,gBAAa,UAAO,aAAU,iBAAc,qBAA8H;CAElS,IAAM,IAAe,KAAS,MAAgB;CAC9C,AAAI,KAAS,CAAC,KACZ,EAAI,4EAA4E,MAAM;CAExF,IAAM,IAAO,GAAa,CAAQ,GAC5B,IAAe,GAAa,CAAQ,CAAC,CACxC,QAAQ,EAAE,cAAW,YAA2E,MAAQ;EACvG,IAAM,EAAE,cAAW,SAAS,GAAa,SAAM,gBAAa;EAC5D,IAAI,KAAa,CAAC,KAAe,CAAC,EAAS,UACzC;OAAI,CAAC,KAAQ,EAAS,SAAS,QAC7B,OAAO;IAAE,WAAW,CAAC,GAAG,GAAW,CAAG;IAAG;GAAM;GAC1C,IAAI,GACT,OAAO;IAAE;IAAW,OAAO,CAAC,GAAG,GAAO,CAAG;GAAE;EAC7C;EAEF,OAAO;GAAE;GAAW;EAAM;CAC5B,GAAG;EAAE,WAAW,CAAC;EAAG,OAAO,CAAC;CAAE,CAAC,GAE3B,KAAe;EAAE,OAAO;EAAc,SAAS;CAAe,GAC9D,EAAE,UAAO,eAAY,GAAa,EAAa,WAAW,GAAM,EAAY,GAE9E,GACA;CACJ,IAAI,EAAW,CAAU,KAAK,EAAW,CAAgB,GAAG;EAC1D,IAAM,IAAe,MAAM,GAAqB,CAAgB,GAC1D,IAAc,MAAM,GAAoB,CAAU;EAKxD,AAJA,IAAU,CACR,GAAI,EAAa,aAAa,WAA+B,CAAC,GAC9D,GAAG,CACL,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,GAC7C,IAAa;GACX,GAAG;GACH,UAAU,CACR,GAAG,EAAY,UACf,GAAG,EAAM,QACX,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;EACjD;CACF,OAEE,AADA,IAAU,GACV,IAAa;CAEf,IAAM,IAAc,CAAC;CAErB,IAAI,GAAkB;EACpB,IAAM,IAAQ,GAAc,CAAgB;EAC5C,AAAI,IACF,EAAI,KAAK,GAAG,EAAM,QAAO,MAAK,EAAE,SAAS,QAAQ,CAAC,IAElD,EAAI,KAAK,GAAG,CAAK;CAErB;CASA,AARI,MACF,EAAI,kDAAkD,MAAM,GAC5D,GAAW,GAAoB,EAAQ,GAAc,QAAQ,CAAC,IAE5D,MACF,EAAI,wCAAwC,MAAM,GAClD,GAAW,GAAY,EAAQ,EAAoB,CAAC,IAElD,KAAgB,EAAS,WAC3B,EAAI,uDAAuD,MAAM,GACjE,MAAM,GAAa,EAAa,OAAO,GAAU,CAAK,GACtD,EAAI,KAAK;EAAE,MAAM;EAAS,MAAM;CAAS,CAAC;CAK5C,IAAM,IAAuB,IAAc;EAAE,aAAa;EAAM,GAAG;CAAgB,IAAI;CAGvF,GAFe,GAAmB,GAAS,GAAK,CAEzB,GAAQ,CAAU;AAC3C;AAQA,SAAgB,GAAW,GAAiB,GAAoB;CAM9D,EAAe,GAAY,GAJb,EADG,EAAS,CACH,GAAU;EAAE,MAAM;EAAa,WAAW;CAAK,CAAC,MAAM,cAAc,iBAAiB,YAE5E,2CAA2C,EAAQ,OAExC,MAAM;AACnD;AAkBA,SAAgB,GAAc,GAAqB,GAAuC,GAA4B;CACpH,IAAM,EAAE,SAAM,UAAO,WAAQ,GACvB,EAAE,UAAO,eAAY;CAM3B,OAAO;EACL,QAAQ;EACR,MANW,IACT;GAAE,MAAM;GAAO;EAAQ,IACvB;GAAE,MAAM,IAAO,GAAG,EAAK,eAAe,GAAG,EAAM;GAAc,SAAS,KAAO;EAA2B;EAK1G;CACF;AACF;AAUA,SAAgB,GAAiB,GAAkB,GAAqB,GAAsB;CAC5F,IAAM,IAAU;EACd,OAAO,EAAS,GAAU;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EACnE,SAAS;EACT,MAAM,IAAI,EAAS,GAAU,EAAE,WAAW,GAAK,CAAC,EAAE;CACpD;CAEA,OAAO,IAAW,CAAC,GAAG,GAAU,CAAO,IAAI,CAAC,CAAO;AACrD;AASA,SAAgB,GAAuB,GAAkB,GAAyC;CAChG,OAAO;EACL,MAAM,EAAS,GAAU;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EAClE,WAAW;EACX,OAAO;CACT;AACF;AA0BA,SAAgB,EAAqB,GAAgC,GAAqC;CACxG,OAAO,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,GAAK,OACpC,MAAQ,MACN,MAAM,QAAQ,CAAK,IACd,EAAM,KAAK,MAAY;EAC5B,IAAM,IAAO,EAAQ,EAAW,SAAS,aAAa,CAAO,GACzD,IAAW,EAAS,EAAS,CAAI,GAAG;GAAE,MAAM;GAAa,WAAW;EAAK,CAAC;EAQ9E,OAPI,MAAa,gBACf,IAAW,oBAET,MAAa,EAAS,CAAI,KAC5B,EAAW,GAAM,EAAQ,EAAQ,CAAI,GAAG,CAAQ,CAAC,GAG5C;GACL,MAAM,EAAM,CAAQ,CAAC,CAAC,SAAS,iBAC3B,iBACA,EAAS,GAAU;IAAE,MAAM;IAAc,aAAa;IAAM,WAAW;GAAK,CAAC;GACjF,MAAM,IAAI,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,EAAE,GAAG,EAAM,CAAQ,CAAC,CAAC;EAC9E;CACF,CAAC,IAEI,CAAC,IACC,OAAO,KAAU,WACnB,CAAC;EACN,MAAM,EAAS,GAAK;GAAE,MAAM;GAAc,aAAa;EAAK,CAAC;EAC7D,WAAW;EACX,OAAO,EAAqB;GAAE,GAAG;GAAY,MAAM,GAAG,EAAW,KAAK,GAAG;EAAM,GAAG,CAAK;CACzF,CAAmB,IAGd,CAAC,CACT;AACH;AAQA,SAAgB,GAAU,GAAsB;CAC9C,OAAO,EAAM,QAAQ,GAAM,MAAS;EAClC,IAAM,CAAC,GAAO,GAAG,KAAQ,EAAK,MAAM,GAAG;EAUvC,OATK,EAAK,SAIR,EAAK,KAAS,GAAU,CACtB,GAAI,EAAK,KAAS,GAAY,EAAK,IAAQ,EAAE,IAAI,CAAC,GAClD,EAAK,KAAK,GAAG,CACf,CAAC,IALD,EAAK,IAAO,CAAC,GAAI,EAAK,KAAQ,CAAC,GAAI,CAAK,GAOnC;CACT,GAAG,CAAC,CAAwB;AAC9B;AASA,SAAgB,GAAY,GAAc,IAAS,IAAc;CAC/D,OAAO,OAAO,QAAQ,CAAO,CAAC,CAAC,SAAS,CAAC,GAAK,OACxC,MAAQ,MACN,MAAM,QAAQ,CAAK,IACd,EAAM,KAAK,MAAe,IAAS,GAAG,EAAO,GAAG,MAAM,CAAE,IAExD,CAAC,IAGL,GAAY,GAAO,IAAS,GAAG,EAAO,GAAG,MAAQ,CAAG,CAC5D;AACH;AAQA,SAAS,GAAgB,GAAgC;CACvD,IAAI,CAAC,MAAM,QAAQ,CAAG,GACpB,OAAO;CAET,IAAM,IAAa,EAAI,WAAU,MAAQ,EAAK,SAAS,SAAS;CAChE,IAAI,MAAe,IACjB,OAAO;CAET,IAAM,CAAC,KAAW,EAAI,OAAO,GAAY,CAAC;CAE1C,OADA,EAAI,KAAK,CAAO,GACT;AACT;AAUA,SAAgB,GAAa,GAAoC,GAAuC,GAA4B;CAClI,IAAM,IAAsB,CAAC,GACvB,IAA4B,CAAC;CAEnC,KAAK,IAAM,KAAc,GAAc;EAcrC,AAbA,EAAI,mCAAmC,EAAW,KAAK,KAAK,MAAM,GAClE,EAAW,CAAC,EAAW,SAAS,WAAW,CAAC,CAAC,CAAC,SAAS,MAAS;GAS9D,AARA,EAAI,uBAAuB,EAAS,CAAI,EAAE,oBAAoB,EAAW,KAAK,KAAK,OAAO,GAC1F,GAAoB,GAAM,EAAW,SAAS,WAAW,GAErD,EAAS,CAAI,CAAC,CAAC,YAAY,MAAM,eACnC,GAAkB,GAAM,EAAW,SAAS,WAAW,GAIzD,GAAuB,CAAI;EAC7B,CAAC,GAED,EAAI,uCAAuC,EAAW,KAAK,KAAK,MAAM;EACtE,IAAM,IAAe,EAAY,EAAW,SAAS,aAAa,EAAE,WAAW,GAAK,CAAC,CAAC,CACnF,QAAQ,MAAS;GAChB,IAAM,IAAW,EAAQ,EAAW,SAAS,aAAa,EAAK,SAAS,CAAC;GAGzE,OAAO,EAAS,CAAQ,CAAC,CAAC,SAAS,KAAK,KAAK,GAAO,CAAQ;EAC9D,CAAC,CAAC,CACD,KAAK;EAER,EAAI,kCAAkC,EAAW,KAAK,KAAK,MAAM;EACjE,IAAI;EAOJ,AANI,EAAa,SAAS,KACxB,IAAa,EAAQ,EAAW,SAAS,aAAa,YAAY,GAClE,EAAa,KAAK,YAAY,KACrB,EAAa,WAAW,MACjC,IAAa,EAAQ,EAAW,SAAS,aAAa,EAAa,EAAE,IAEnE,IACF,GAAW,EAAW,UAAU,CAAU,IAE1C,EAAI,8CAA8C,EAAW,KAAK,uBAAuB,MAAM;EAIjG,IAAM,IAAe,GAAgB,EAAqB,GADtC,GAAU,CACwC,CAAW,CAAC;EAGlF,AADA,EAAQ,KAAK,GAAuB,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,GAAG,CAAY,CAAC,GACjG,EAAS,KAAK,GAAG,GAAiB,EAAS,EAAW,MAAM,EAAE,WAAW,GAAK,CAAC,GAAG,EAAW,eAAe,EAAE,CAAC;CACjH;CAEA,EAAI,8BAA8B,MAAM;CACxC,IAAM,IAAQ,GAAc,EAAS,UAAU,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC,GAAG,GAAM,CAAY;CAC3G,OAAO;EACL,SAAS,EAAQ,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;EAChE;CACF;AACF;AAQA,SAAgB,GAAc,GAAiB;CAC7C,IAAM,IAAQ,EAAW,CAAK,GACxB,IAAc,CAAC;CAErB,EAAI,0CAA0C,MAAM;CACpD,KAAK,IAAM,KAAQ,GAAO;EACxB,EAAI,uBAAuB,EAAK,KAAK,OAAO;EAC5C,IAAM,IAAM,EAAQ,QAAQ,IAAI,GAAG,CAAI;EAGvC,AADA,EAAO,GADM,EAAQ,GAAU,EAAS,EAAS,CAAI,GAAG;GAAE,MAAM;GAAa,WAAW;EAAK,CAAC,CAClF,CAAI,GAChB,EAAI,KAAK;GACP,MAAM,EAAS,EAAM,CAAG,CAAC,CAAC,MAAM;IAAE,aAAa;IAAM,WAAW;GAAK,CAAC;GACtE,MAAM,IAAI,EAAS,EAAM,CAAG,CAAC,CAAC,MAAM;IAAE,WAAW;IAAM,MAAM;GAAY,CAAC;EAC5E,CAAC;CACH;CACA,OAAO;AACT;AASA,SAAgB,GAAW,GAA0B,GAAa,GAAiB;CACjF,KAAK,IAAM,KAAQ,MAAM,QAAQ,CAAK,IAAI,IAAQ,CAAC,CAAK,GAAG;EACzD,IAAM,IAAe,EAAQ,QAAQ,IAAI,GAAG,CAAI,GAC1C,IAAQ,EAAa,CAAY;EAEvC,KAAK,IAAM,KAAQ,GAAO;GACxB,IAAM,IAAgB,EAAK,QAAQ,GAAc,GAAG;GACpD,EAAI,uBAAuB,EAAc,eAAe,EAAK,KAAK,OAAO;GACzE,IAAM,IAAM,EAAQ,QAAQ,IAAI,GAAG,CAAI,GACjC,IAAO,EAAQ,GAAK,CAAa;GAIvC,AAHI,KACF,EAAG,GAEL,EAAO,GAAK,CAAI;EAClB;CACF;AACF;AAOA,SAAgB,GAAY,GAAuG;CAIjI,IAAM,IAAc,EAAM,KAAK,EAAE,eAAY,uBAAoB;EAC/D,IAAM,EAAE,SAAM,UAAO,aAAU,gBAAa,wBAAqB;EACjE,OAAO;GAAE;GAAM,OAAO,EAAM;GAAO;GAAU;GAAa;GAAkB;EAAc;CAC5F,CAAC;CAED,AADA,EAAI,2BAA2B,MAAM,GACrC,EAAc,IAAY,wCAAqB,EAAK,UAAU,CAAW,IAAI,4kBAAgB;AAC/F;AAeA,eAAsB,GAAa,GAAoC,GAA2C,GAA6B;CAW7I,GAAY,MAVQ,QAAQ,IAC1B,EAAa,IAAI,OAAO,MAAe;EACrC,IAAM,EAAE,WAAQ,oBAAiB,MAAM,GAAgB;GAAE;GAAY;EAAM,CAAC;EAC5E,OAAO;GACL,eAAe,GAAc,MAAK,MAAe,EAAY,UAAU,CAAQ,CAAC,EAAE,iBAAiB;GACnG,YAAY;EACd;CACF,CAAC,CACH,CAAC,CAAC,MAAK,MAAK,EAAE,QAAQ,EAAE,eAAY,uBAAoB,CAAC,CAAC,KAAc,CAAa,CAAC,CAErE;AACnB;AAQA,eAAsB,GAAqB,GAAiE;CAC1G,IAAI;EACF,IAAM,EAAE,cAAW,MAAM,OAAO,EAAQ,QAAQ,IAAI,GAAG,CAAI;EAC3D,OAAO,KAAU,CAAC;CACpB,SAAS,GAAO;EAEd,OADA,EAAI,gDAAgD,EAAK,oCAAoC,aAAiB,QAAQ,EAAM,UAAU,MAAM,MAAM,GAC3I,CAAC;CACV;AACF;AAQA,eAAsB,GAAoB,GAA8B;CACtE,IAAM,KAAS,MAAM,GAAS,EAAQ,QAAQ,IAAI,GAAG,CAAI,CAAC,EAAA,CAAG,SAAS;CACtE,OAAO,EAAK,MAAM,CAAK;AACzB;AASA,SAAgB,GAAuB,GAA2D,GAAc;CAS9G,OAPA,EAAU,EAAQ,CAAgB,CAAC,GAEnC,EAAI,iCAAiC,MAAM,GAC3C,EAAc,GAAkB,yBAAyB,KAAK,UAAU,GAAiB,MAAM,CAAC,EAAE,4BAA4B,GAC9H,EAAI,2BAA2B,MAAM,GACrC,EAAc,GAAY,UAAY,EAAK,UAAU,CAAK,CAAC,GAC3D,EAAI,gCAAgC,MAAM,GACnC,EAAa,CAAc,CAAC,CAAC,SAAS,MAAS;EAEpD,GAAa,GAAM,EAAQ,IADN,EAAK,QAAQ,GAAG,EAAe,IAAI,EACZ,CAAY,CAAC;CAC3D,CAAC;AACH;;;ACxhBA,IAAM,KAAU,WAKH,KAAc;CACzB,EAAa,uCAAuC,EAAa,MAAM,mBAAmB,WAAW;CACrG,EAAa,eAAe,EAAa,MAAM,MAAM,WAAW;CAChE,EAAa,qCAAqC,EAAa,MAAM,iBAAiB,WAAW;CACjG,EAAa,8BAA8B,EAAa,MAAM,WAAW,WAAW;CACpF,EAAa,mCAAmC,EAAa,MAAM,gBAAgB,WAAW;CAC9F,EAAa,4BAA4B,EAAa,MAAM,aAAa,WAAW;CACpF,EAAa,8BAA8B,EAAa,MAAM,eAAe,WAAW;AAC1F,GAKa,KAAa,EAAW,EAAc,EAAO,GAAG,CAAC,GAAG,IAAa,GAAG,CAAU,CAAC,CAAC,CAC1F,YAAY,+CAA+C,CAAC,CAC5D,OAAO,OAAO,GAAM,MAAQ;CAE3B,MAAM,GADa,EAAa,IAAS,EAAgB,GAAK,CAAI,CACvD,CAAU;AACvB,CAAC;AAOH,eAAsB,GAAK,GAAmB;CAC5C,IAAM,EAAE,qBAAkB,uBAAoB,eAAY,oBAAiB,UAAO,gBAAa,gBAAa,UAAO,cAAW,iBAAc,sBAAmB;CAG/J,AAFA,EAAI,0DAA0D,MAAM,GAEpE,EAAU,EAAQ,CAAgB,GAAG,EAAE,OAAO,GAAK,CAAC;CACpD,KAAK,IAAM,KAAY,GACrB,MAAM,GAAW;EAAE;EAAkB;EAAoB;EAAY;EAAiB;EAAO;EAAa;EAAa;EAAO;EAAU;EAAc;CAAe,CAAC;AAE1K;;;ACtCA,SAAgB,KAAa;CAC3B,IAAM,IAAK,IAAI,EAAQ,CAAC,CACrB,KAAK,UAAU,CAAC,CAChB,YAAY,iDAAiD,CAAC,CAC9D,QAAQ,GAAG,GAAI,SAAS,CAAC,CACzB,OAAO,OAAO,GAAM,MAAQ;EAC3B,IAAM,IAAa,EAAa,UAAU,EAAgB,GAAK,CAAI,CAAC;EAGpE,AAFA,MAAM,GAAQ,CAAU,GACxB,MAAM,GAAU,CAAU,GAC1B,MAAM,GAAQ;CAChB,CAAC,CAAC,CACD,cAAc;EACb,iBAAiB;EACjB,aAAa;EACb,mBAAmB;CACrB,CAAC,CAAC,CACD,wBAAwB,CAAC,CACzB,mBAAmB,CAAC,CACpB,WAAW,EAAQ,CAAC,CACpB,WAAW,EAAU,CAAC,CACtB,WAAW,EAAQ;CAItB,OAFA,EAAW,GAAI;EAAC,GAAG;EAAW,GAAG;EAAa,GAAG;CAAU,CAAC,GAErD;AACT;AAMA,SAAgB,KAAO;CAErB,GAAA,CAAA,CAAG,WAAW,QAAQ,IAAI,CAAC,CAAC,OAAO,MAAU;EAE3C,AADA,EAAI,KAAK,aAAiB,QAAQ,EAAM,UAAU,OAAO,CAAK,KAAK,OAAO,GAC1E,QAAQ,KAAK,CAAC;CAChB,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tobi-or-not/docpress",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"packageManager": "bun@1.3.14",
|
|
6
6
|
"homepage": "https://this-is-tobi.com/docpress/introduction",
|
|
7
7
|
"repository": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dev:clean": "rimraf ./docpress && bun run dev",
|
|
29
29
|
"format": "eslint . --fix",
|
|
30
30
|
"lint": "eslint .",
|
|
31
|
-
"prepare": "husky",
|
|
31
|
+
"prepare": "husky || true",
|
|
32
32
|
"start": "./bin/docpress.js",
|
|
33
33
|
"start:docker": "docker run --name docpress --rm -v $(pwd)/docpress:/app/docpress:rw tobi-or-not/docpress",
|
|
34
34
|
"stop:docker": "docker rm --force docpress",
|