-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathloader.ts
More file actions
120 lines (111 loc) · 3.63 KB
/
loader.ts
File metadata and controls
120 lines (111 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { cosmiconfig } from 'cosmiconfig';
import fs from 'fs';
import path from 'path';
import { createJiti } from 'jiti';
import { AutodocsConfig } from './types';
import { DEFAULT_CONFIG } from './defaults';
// Setup jiti for loading TS files
const jiti = createJiti(__filename);
export async function loadConfig(searchFrom?: string): Promise<AutodocsConfig | null> {
const explorer = cosmiconfig('autodocs', {
searchPlaces: [
'autodocs.config.ts',
'autodocs.config.js',
'autodocs.config.mjs',
'autodocs.config.cjs',
'autodocs.config.json',
'package.json',
],
loaders: {
'.ts': (filepath: string) => jiti.import(filepath, { default: true }),
},
});
try {
const resolvedPath = searchFrom ? path.resolve(searchFrom) : undefined;
const hasExplicitConfig =
resolvedPath && path.extname(resolvedPath) && fs.existsSync(resolvedPath);
const result = hasExplicitConfig
? await explorer.load(resolvedPath)
: await explorer.search(searchFrom);
if (!result || result.isEmpty) {
if (hasExplicitConfig && resolvedPath) {
const ext = path.extname(resolvedPath);
if (ext === '.json') {
const raw = await fs.promises.readFile(resolvedPath, 'utf-8');
return mergeConfig(DEFAULT_CONFIG, JSON.parse(raw) as Partial<AutodocsConfig>);
}
if (['.ts', '.js', '.mjs', '.cjs'].includes(ext)) {
const loaded = await jiti.import(resolvedPath, { default: true });
const config = (loaded as { default?: unknown }).default || loaded;
return mergeConfig(DEFAULT_CONFIG, config as Partial<AutodocsConfig>);
}
}
return null;
}
// Handle "export default" from TS/ESM files
const rawConfig = result.config as unknown;
const hasDefaultExport =
typeof rawConfig === 'object' && rawConfig !== null && 'default' in rawConfig;
const config = hasDefaultExport
? ((rawConfig as { default?: unknown }).default ?? rawConfig)
: rawConfig;
return mergeConfig(DEFAULT_CONFIG, config as Partial<AutodocsConfig>);
} catch (error) {
throw new Error(
`Failed to load config: ${error instanceof Error ? error.message : String(error)}`,
{
cause: error,
}
);
}
}
export function mergeConfig(
base: AutodocsConfig,
override: Partial<AutodocsConfig>
): AutodocsConfig {
return {
...base,
...override,
output: {
...base.output,
...override.output,
},
theme: {
...base.theme,
...(override.theme || {}),
} as import('./types').ThemeConfig,
features: {
...base.features,
...override.features,
},
};
}
export function resolveConfigPaths(config: AutodocsConfig, configDir: string): AutodocsConfig {
const resolveAssetPath = (value?: string): string | undefined => {
if (!value) {
return value;
}
if (/^(https?:|data:)/.test(value) || value.startsWith('/')) {
return value;
}
return path.resolve(configDir, value);
};
return {
...config,
include: config.include.map((p) => path.resolve(configDir, p)),
exclude: config.exclude?.map((p) => path.resolve(configDir, p)),
output: {
...config.output,
dir: path.resolve(configDir, config.output.dir),
},
tsconfig: config.tsconfig ? path.resolve(configDir, config.tsconfig) : undefined,
cacheDir: config.cacheDir ? path.resolve(configDir, config.cacheDir) : config.cacheDir,
theme: config.theme
? {
...config.theme,
logo: resolveAssetPath(config.theme.logo),
favicon: resolveAssetPath(config.theme.favicon),
}
: config.theme,
};
}