146 lines · 4.8 KB · TypeScript
RawDownload
import { createResolver, defineNuxtModule, logger } from '@nuxt/kit'import { defu } from 'defu'import { existsSync } from 'node:fs'import { join } from 'node:path'import { inferSiteURL, getPackageJsonMetadata } from '../utils/meta'import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git' const log = logger.withTag('docus') type I18nLocale = string | { code: string, name?: string }type DocusI18nOptions = { locales?: I18nLocale[], strategy?: string }type DocusMcpOptions = { route?: string, enabled?: boolean }type RegisterModuleOptions = {  langDir: string  locales: Array<{ code: string, name: string, file: string }>} export default defineNuxtModule({  meta: {    name: 'config',  },  async setup(_options, nuxt) {    const dir = nuxt.options.rootDir    const url = inferSiteURL()    const meta = await getPackageJsonMetadata(dir)    const gitInfo = await getLocalGitInfo(dir) || getGitEnv()    const siteName = (typeof nuxt.options.site === 'object' && nuxt.options.site?.name) || meta.name || gitInfo?.name || ''     nuxt.options.llms = defu(nuxt.options.llms, {      domain: url,      title: siteName,      description: meta.description || '',      full: {        title: siteName,        description: meta.description || '',      },    })     nuxt.options.site = defu(nuxt.options.site, {      url,      name: siteName,      debug: false,    }) as typeof nuxt.options.site     nuxt.options.appConfig.header = defu(nuxt.options.appConfig.header, {      title: siteName,    })     nuxt.options.appConfig.seo = defu(nuxt.options.appConfig.seo, {      titleTemplate: `%s - ${siteName}`,      title: siteName,      description: meta.description || '',    })     nuxt.options.appConfig.github = defu(nuxt.options.appConfig.github, {      owner: gitInfo?.owner,      name: gitInfo?.name,      url: gitInfo?.url,      branch: getGitBranch(),    })     /*    ** MCP route (expose to client so the page header dropdown stays in sync    ** with the user-configured `mcp.route` from @nuxtjs/mcp-toolkit)    */    const mcpOptions = (nuxt.options as typeof nuxt.options & { mcp?: DocusMcpOptions }).mcp    nuxt.options.runtimeConfig.public.mcp = defu(      nuxt.options.runtimeConfig.public.mcp as DocusMcpOptions | undefined,      { route: mcpOptions?.route || '/mcp' },    )     const forcedColorMode = (nuxt.options.appConfig.docus as Record<string, unknown>)?.colorMode as string | undefined    if (forcedColorMode === 'light' || forcedColorMode === 'dark') {      nuxt.options.colorMode = defu({ preference: forcedColorMode, fallback: forcedColorMode }, nuxt.options.colorMode || {}) as typeof nuxt.options.colorMode    }     /*    ** I18N    */    const typedNuxtOptions = nuxt.options as typeof nuxt.options & { i18n?: false | DocusI18nOptions }    const i18nOptions = typedNuxtOptions.i18n     if (i18nOptions && typeof i18nOptions === 'object' && i18nOptions.locales) {      const { resolve } = createResolver(import.meta.url)       // Filter locales to only include existing ones      const filteredLocales = i18nOptions.locales.filter((locale: I18nLocale) => {        const localeCode = typeof locale === 'string' ? locale : locale.code         // Check for JSON locale file        const localeFilePath = resolve('../i18n/locales', `${localeCode}.json`)        const hasLocaleFile = existsSync(localeFilePath)         // Check for content folder        const contentPath = join(nuxt.options.rootDir, 'content', localeCode)        const hasContentFolder = existsSync(contentPath)         if (!hasLocaleFile) {          log.warn(`Locale file not found: ${localeCode}.json - skipping locale "${localeCode}"`)        }         if (!hasContentFolder) {          log.warn(`Content folder not found: content/${localeCode}/ - skipping locale "${localeCode}"`)        }         return hasLocaleFile && hasContentFolder      })       // Override strategy to prefix      typedNuxtOptions.i18n = {        ...i18nOptions,        strategy: 'prefix',      }       // Expose filtered locales      nuxt.options.runtimeConfig.public.docus = {        filteredLocales,      }       const registerI18nModule = nuxt.hook as unknown as (name: string, callback: (register: (options: RegisterModuleOptions) => void) => void) => void       registerI18nModule('i18n:registerModule', (register) => {        const langDir = resolve('../i18n/locales')         const locales = filteredLocales.map((locale: I18nLocale) => {          return typeof locale === 'string'            ? {                code: locale,                name: locale,                file: `${locale}.json`,              }            : {                code: locale.code,                name: locale.name || locale.code,                file: `${locale.code}.json`,              }        })         register({          langDir,          locales,        })      })    }  },})