diff --git a/__tests__/unit/node/config.test.ts b/__tests__/unit/node/config.test.ts new file mode 100644 index 000000000..9837879c3 --- /dev/null +++ b/__tests__/unit/node/config.test.ts @@ -0,0 +1,39 @@ +import { mergeConfig } from 'node/config' +import type { MarkdownItAsync } from 'markdown-it-async' + +describe('node/config', () => { + test('merges markdown config hooks from extended configs', async () => { + const calls: string[] = [] + const md = {} as MarkdownItAsync + + const merged = mergeConfig( + { + markdown: { + lineNumbers: true, + config() { + calls.push('base') + } + } + }, + { + markdown: { + attrs: { + allowedAttributes: ['id'] + }, + async config() { + calls.push('extended') + } + } + } + ) + + expect(merged.markdown?.lineNumbers).toBe(true) + expect(merged.markdown?.attrs).toEqual({ + allowedAttributes: ['id'] + }) + + await merged.markdown?.config?.(md) + + expect(calls).toEqual(['base', 'extended']) + }) +}) diff --git a/src/node/config.ts b/src/node/config.ts index bdcd00e17..26bf6c0ee 100644 --- a/src/node/config.ts +++ b/src/node/config.ts @@ -7,7 +7,8 @@ import { loadConfigFromFile, mergeConfig as mergeViteConfig, normalizePath, - type ConfigEnv + type ConfigEnv, + type UserConfig as ViteUserConfig } from 'vite' import { DEFAULT_THEME_PATH } from './alias' import type { DefaultTheme } from './defaultTheme' @@ -22,6 +23,7 @@ import { type HeadConfig, type SiteData } from './shared' +import type { MarkdownOptions } from './markdown/markdown' import type { RawConfigExports, SiteConfig, UserConfig } from './siteConfig' import { glob } from './utils/glob' @@ -288,10 +290,14 @@ async function resolveConfigExtends( return resolved } -export function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) { +export function mergeConfig( + a: A, + b: B, + isRoot = true +): A & B { const merged: Record = { ...a } for (const key in b) { - const value = b[key as keyof UserConfig] + const value = b[key] if (value == null) { continue } @@ -302,7 +308,12 @@ export function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) { } if (isObject(existing) && isObject(value)) { if (isRoot && key === 'vite') { - merged[key] = mergeViteConfig(existing, value) + merged[key] = mergeViteConfig( + existing as ViteUserConfig, + value as ViteUserConfig + ) + } else if (isRoot && key === 'markdown') { + merged[key] = mergeMarkdownConfig(existing, value as MarkdownOptions) } else { merged[key] = mergeConfig(existing, value, false) } @@ -310,6 +321,19 @@ export function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) { } merged[key] = value } + return merged as A & B +} + +function mergeMarkdownConfig(a: MarkdownOptions, b: MarkdownOptions) { + const merged = mergeConfig(a, b, false) + const baseConfig = a.config + const extendedConfig = b.config + if (baseConfig && extendedConfig) { + merged.config = async (md) => { + await baseConfig(md) + await extendedConfig(md) + } + } return merged }