Files
easy-slides/scripts/lib/config.ts
T
2026-08-29 18:59:33 +08:00

71 lines
1.9 KiB
TypeScript

import { access, readFile } from 'node:fs/promises'
import path from 'node:path'
import { pathToFileURL } from 'node:url'
export interface EasySlidesConfig {
title: string
description: string
slidesDir: string
outDir: string
exportDir: string
theme?: string
}
const defaults: EasySlidesConfig = {
title: 'easy-slides',
description: 'Markdown presentations powered by easy-slides',
slidesDir: 'slides',
outDir: 'dist',
exportDir: 'exports',
}
export async function loadProjectConfig(cwd = process.cwd()): Promise<EasySlidesConfig> {
const candidates = [
'easy-slides.config.mjs',
'easy-slides.config.js',
'easy-slides.config.json',
]
for (const candidate of candidates) {
const filename = path.join(cwd, candidate)
if (!(await exists(filename)))
continue
const loaded = candidate.endsWith('.json')
? JSON.parse(await readFile(filename, 'utf8'))
: (await import(`${pathToFileURL(filename).href}?t=${Date.now()}`)).default
return normalizeConfig(loaded)
}
return { ...defaults }
}
export function normalizeConfig(value: Partial<EasySlidesConfig> | undefined): EasySlidesConfig {
return {
...defaults,
...value,
slidesDir: normalizeRelativePath(value?.slidesDir ?? defaults.slidesDir, 'slidesDir'),
outDir: normalizeRelativePath(value?.outDir ?? defaults.outDir, 'outDir'),
exportDir: normalizeRelativePath(value?.exportDir ?? defaults.exportDir, 'exportDir'),
}
}
function normalizeRelativePath(value: string, field: string) {
const normalized = value.trim().replace(/[\\/]+$/, '')
const portable = normalized.replaceAll('\\', '/')
if (!normalized || path.isAbsolute(normalized) || portable === '..' || portable.startsWith('../'))
throw new Error(`${field} 必须是项目内的相对路径`)
return normalized
}
async function exists(filename: string) {
try {
await access(filename)
return true
}
catch {
return false
}
}