import path from 'path' ; import fs from 'fs-extra' ; import chalk from 'chalk' ; import globby from 'globby' ; import { normalizePath , AliasOptions , UserConfig as ViteConfig , mergeConfig as mergeViteConfig , loadConfigFromFile } from 'vite' ; import { Options as VuePluginOptions } from '@vitejs/plugin-vue' ; import { SiteData , HeadConfig , LocaleConfig , createLangDictionary , DefaultTheme } from './shared' ; import { resolveAliases , DEFAULT_THEME_PATH } from './alias' ; import { MarkdownOptions } from './markdown/markdown' ; import _debug from 'debug' ; export { resolveSiteDataByRoute } from './shared' ; const debug = _debug ( 'vitepress:config' ) ; export type { MarkdownOptions } ; export interface UserConfig < ThemeConfig = any > { extends ? : RawConfigExports < ThemeConfig > ; lang ? : string ; base ? : string ; title ? : string ; description ? : string ; head ? : HeadConfig [ ] ; themeConfig ? : ThemeConfig ; locales ? : Record < string , LocaleConfig > ; markdown ? : MarkdownOptions ; /**
     * Options to pass on to `@vitejs/plugin-vue`
     */ vue ? : VuePluginOptions ; /**
     * Vite config
     */ vite ? : ViteConfig ; srcDir ? : string ; srcExclude ? : string [ ] ; outDir ? : string ; shouldPreload ? : ( link : string , page : string ) => boolean ; /**
     * Configure the scroll offset when the theme has a sticky header.
     * Can be a number or a selector element to get the offset from.
     */ scrollOffset ? : number | string ; experimental mpa ? : boolean ; } export type RawConfigExports < ThemeConfig = any > = UserConfig < ThemeConfig > | Promise < UserConfig < ThemeConfig > > | ( ( ) => UserConfig < ThemeConfig > | Promise < UserConfig < ThemeConfig > > ) ; export interface SiteConfig < ThemeConfig = any > extends Pick < UserConfig , 'markdown' | 'vue' | 'vite' | 'shouldPreload' | 'mpa' > { root : string ; srcDir : string ; site : SiteData < ThemeConfig > ; configPath : string | undefined ; themeDir : string ; outDir : string ; tempDir : string ; alias : AliasOptions ; pages : string [ ] ; } const resolve = ( root , file ) => normalizePath ( path . resolve ( root , `.vitepress` , file ) ) ; /**
 * Type config helper
 */ export function defineConfig ( config ) { return config ; } /**
 * Type config helper for custom theme config
 */ export function defineConfigWithTheme < ThemeConfig > ( config ) { return config ; } export async function resolveConfig ( root = process . cwd ( ) , command = 'serve' , mode = 'development' ) { const [ userConfig , configPath ] = await resolveUserConfig ( root , command , mode ) ; const site = await resolveSiteData ( root , userConfig ) ; const srcDir = path . resolve ( root , userConfig . srcDir || '.' ) ; const outDir = userConfig . outDir ? path . resolve ( root , userConfig . outDir ) : resolve ( root , 'dist' ) ; const userThemeDir = resolve ( root , 'theme' ) ; const themeDir = ( await fs . pathExists ( userThemeDir ) ) ? userThemeDir : DEFAULT_THEME_PATH ; const pages = ( await globby ( [ '**.md' ] , { cwd : srcDir , ignore : [ '**/node_modules' , ... ( userConfig . srcExclude || [ ] ) ] } ) ) . sort ( ) ; const config = { root , srcDir , site , themeDir , pages , configPath , outDir , tempDir : resolve ( root , '.temp' ) , markdown : userConfig . markdown , alias : resolveAliases ( root , themeDir ) , vue : userConfig . vue , vite : userConfig . vite , shouldPreload : userConfig . shouldPreload , mpa : ! ! userConfig . mpa } ; return config ; } const supportedConfigExtensions = [ 'js' , 'ts' , 'mjs' , 'mts' ] ; async function resolveUserConfig ( root , command , mode ) { let configPath ; for ( const ext of supportedConfigExtensions ) { const p = resolve ( root , `config.${ ext }` ) ; if ( await fs . pathExists ( p ) ) { configPath = p ; break ; } } const userConfig = configPath ? ( ( await loadConfigFromFile ( { command , mode } , configPath , root ) ) ?. config as any ) : { } ; if ( configPath ) { debug ( `loaded config at ${ chalk . yellow ( configPath ) }` ) ; } else { debug ( `no config file found.` ) ; } return [ await resolveConfigExtends ( userConfig ) , configPath ] ; } async function resolveConfigExtends ( config ) { const resolved = await ( typeof config === 'function' ? config ( ) : config ) ; if ( resolved . extends ) { const base = await resolveConfigExtends ( resolved . extends ) ; return mergeConfig ( base , resolved ) ; } return resolved ; } function mergeConfig ( a , b , isRoot = true ) { const merged = { ... a } ; for ( const key in b ) { const value = b [ key as keyof UserConfig ] ; if ( value == null ) { continue ; } const existing = merged [ key ] ; if ( Array . isArray ( existing ) && Array . isArray ( value ) ) { merged [ key ] = [ ... existing , ... value ] ; continue ; } if ( isObject ( existing ) && isObject ( value ) ) { if ( isRoot && key === 'vite' ) { merged [ key ] = mergeViteConfig ( existing , value ) ; } else { merged [ key ] = mergeConfig ( existing , value , false ) ; } continue ; } merged [ key ] = value ; } return merged ; } function isObject ( value ) { return Object . prototype . toString . call ( value ) === '[object Object]' ; } export async function resolveSiteData ( root , userConfig ? , command = 'serve' , mode = 'development' ) { userConfig = userConfig || ( await resolveUserConfig ( root , command , mode ) ) [ 0 ] ; return { lang : userConfig . lang || 'en-US' , title : userConfig . title || 'VitePress' , description : userConfig . description || 'A VitePress site' , base : userConfig . base ? userConfig . base . replace ( /([^/])$/ , '$1/' ) : '/' , head : userConfig . head || [ ] , themeConfig : userConfig . themeConfig || { } , locales : userConfig . locales || { } , langs : createLangDictionary ( userConfig ) , scrollOffset : userConfig . scrollOffset || 90 } ; }