Skip to content

Commit 3a52e60

Browse files
committed
fix: improved schema validation
1 parent 6e9f4b5 commit 3a52e60

File tree

1 file changed

+33
-55
lines changed

1 file changed

+33
-55
lines changed

src/lib/config.ts

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import fs from 'fs';
22
import path from 'path';
33
import yaml from 'js-yaml';
4+
import { z } from 'astro:content';
45

5-
interface SiteConfig {
6-
sections: {
7-
about: boolean;
8-
workExperience: boolean;
9-
talks: boolean;
10-
writing: boolean;
11-
socialLinks: boolean;
12-
};
13-
elements: {
14-
avatar: boolean;
15-
themeSwitch: boolean;
16-
header: boolean;
17-
footer: boolean;
18-
};
19-
}
6+
const SiteConfigSchema = z.object({
7+
sections: z.object({
8+
about: z.boolean(),
9+
workExperience: z.boolean(),
10+
talks: z.boolean(),
11+
writing: z.boolean(),
12+
socialLinks: z.boolean(),
13+
}),
14+
elements: z.object({
15+
avatar: z.boolean(),
16+
themeSwitch: z.boolean(),
17+
header: z.boolean(),
18+
footer: z.boolean(),
19+
}),
20+
});
21+
22+
type SiteConfig = z.infer<typeof SiteConfigSchema>;
2023

2124
const defaultConfig: SiteConfig = {
2225
sections: {
@@ -55,42 +58,8 @@ function deepMerge(target: any, source: any): any {
5558
return target;
5659
}
5760

58-
function isValidConfig(config: any): boolean {
59-
if (
60-
!config ||
61-
typeof config !== 'object' ||
62-
!config.sections ||
63-
typeof config.sections !== 'object' ||
64-
!config.elements ||
65-
typeof config.elements !== 'object'
66-
) {
67-
return false;
68-
}
69-
// Optionally, check for required keys
70-
const sectionKeys = [
71-
'about',
72-
'workExperience',
73-
'talks',
74-
'writing',
75-
'socialLinks',
76-
];
77-
const elementKeys = [
78-
'avatar',
79-
'themeSwitch',
80-
'header',
81-
'footer',
82-
];
83-
for (const key of sectionKeys) {
84-
if (typeof config.sections[key] !== 'boolean') {
85-
return false;
86-
}
87-
}
88-
for (const key of elementKeys) {
89-
if (typeof config.elements[key] !== 'boolean') {
90-
return false;
91-
}
92-
}
93-
return true;
61+
function isValidConfig(config: SiteConfig): config is SiteConfig {
62+
return SiteConfigSchema.safeParse(config).success;
9463
}
9564

9665
export function getSiteConfig(): SiteConfig {
@@ -100,23 +69,32 @@ export function getSiteConfig(): SiteConfig {
10069
const fileContents = fs.readFileSync(configPath, 'utf8');
10170
loadedConfig = yaml.load(fileContents);
10271
if (!loadedConfig || typeof loadedConfig !== 'object') {
103-
console.warn('config.yml is empty or not a valid YAML object, using defaults');
72+
console.warn(
73+
'config.yml is empty or not a valid YAML object, using defaults',
74+
);
10475
return defaultConfig;
10576
}
10677
// Merge loaded config with defaults
10778
const mergedConfig = deepMerge(loadedConfig, defaultConfig);
10879
if (!isValidConfig(mergedConfig)) {
109-
console.warn('config.yml is malformed or missing required fields, using defaults');
80+
console.warn(
81+
'config.yml is malformed or missing required fields, using defaults',
82+
);
11083
return defaultConfig;
11184
}
11285
return mergedConfig as SiteConfig;
11386
} catch (error: any) {
11487
if (error.code === 'ENOENT') {
11588
console.warn('config.yml not found, using defaults');
116-
} else if (error.name === 'YAMLException' || error instanceof yaml.YAMLException) {
89+
} else if (
90+
error.name === 'YAMLException' ||
91+
error instanceof yaml.YAMLException
92+
) {
11793
console.warn('config.yml is malformed YAML, using defaults');
11894
} else {
119-
console.warn(`Error loading config.yml: ${error.message}, using defaults`);
95+
console.warn(
96+
`Error loading config.yml: ${error.message}, using defaults`,
97+
);
12098
}
12199
return defaultConfig;
122100
}

0 commit comments

Comments
 (0)