Skip to content

Commit 1b03296

Browse files
feat: require files, audio, and thumbnail frontmatter fields (#51)
Co-authored-by: Paperclip <noreply@paperclip.ing>
1 parent f629d8e commit 1b03296

1 file changed

Lines changed: 66 additions & 2 deletions

File tree

scripts/validate.ts

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,29 +166,52 @@ function validateFiles(
166166
}
167167
}
168168

169+
// Categories that require an "audio" frontmatter field
170+
const AUDIO_REQUIRED_CATEGORIES: readonly Category[] = [
171+
"locksounds",
172+
"hornsounds",
173+
"boombox",
174+
"lightshows",
175+
];
176+
177+
// Categories that require a "thumbnail" frontmatter field
178+
const THUMBNAIL_REQUIRED_CATEGORIES: readonly Category[] = ["wraps"];
179+
169180
function validateFilesField(
170181
meta: Record<string, unknown>,
171182
category: string,
172183
slug: string,
173184
itemDir: string
174185
): void {
175-
if (meta.files === undefined) return;
186+
if (meta.files === undefined) {
187+
error(`${category}/${slug}.md: missing required field "files"`);
188+
return;
189+
}
176190

177191
if (!Array.isArray(meta.files)) {
178192
error(`${category}/${slug}.md: "files" must be an array`);
179193
return;
180194
}
181195

196+
if (meta.files.length === 0) {
197+
error(`${category}/${slug}.md: "files" must contain at least one entry`);
198+
return;
199+
}
200+
182201
for (const entry of meta.files) {
183202
if (!entry || typeof entry !== "object") {
184-
error(`${category}/${slug}.md: each entry in "files" must be an object with a "name" field`);
203+
error(`${category}/${slug}.md: each entry in "files" must be an object with "name" and "label" fields`);
185204
continue;
186205
}
187206
const fileEntry = entry as Record<string, unknown>;
188207
if (!fileEntry.name || typeof fileEntry.name !== "string" || fileEntry.name.trim() === "") {
189208
error(`${category}/${slug}.md: each entry in "files" must have a non-empty "name" string`);
190209
continue;
191210
}
211+
if (!fileEntry.label || typeof fileEntry.label !== "string" || fileEntry.label.trim() === "") {
212+
error(`${category}/${slug}.md: each entry in "files" must have a non-empty "label" string`);
213+
continue;
214+
}
192215
const filePath = path.join(itemDir, String(fileEntry.name));
193216
if (!fs.existsSync(filePath)) {
194217
error(
@@ -198,6 +221,45 @@ function validateFilesField(
198221
}
199222
}
200223

224+
function validateAudioField(
225+
meta: Record<string, unknown>,
226+
category: string,
227+
slug: string,
228+
itemDir: string
229+
): void {
230+
if (!AUDIO_REQUIRED_CATEGORIES.includes(category as Category)) return;
231+
232+
if (meta.audio === undefined) {
233+
error(`${category}/${slug}.md: missing required field "audio"`);
234+
return;
235+
}
236+
237+
if (typeof meta.audio !== "string" || meta.audio.trim() === "") {
238+
error(`${category}/${slug}.md: "audio" must be a non-empty string`);
239+
return;
240+
}
241+
242+
const audioPath = path.join(itemDir, String(meta.audio));
243+
if (!fs.existsSync(audioPath)) {
244+
error(`${category}/${slug}.md: audio file "${meta.audio}" not found`);
245+
}
246+
}
247+
248+
function validateThumbnailRequired(
249+
meta: Record<string, unknown>,
250+
category: string,
251+
slug: string,
252+
itemDir: string
253+
): void {
254+
if (!THUMBNAIL_REQUIRED_CATEGORIES.includes(category as Category)) return;
255+
256+
if (meta.thumbnail === undefined) {
257+
error(`${category}/${slug}.md: missing required field "thumbnail"`);
258+
return;
259+
}
260+
// Actual thumbnail format/existence validation is handled in validateMeta
261+
}
262+
201263
function parseArgs(): { collection?: Category } {
202264
const args = process.argv.slice(2);
203265
const collectionIdx = args.indexOf("--collection");
@@ -270,6 +332,8 @@ function main(): void {
270332
validateMeta(meta, category, slug, knownTags, itemDir);
271333
validateFiles(itemDir, category, slug);
272334
validateFilesField(meta, category, slug, itemDir);
335+
validateAudioField(meta, category, slug, itemDir);
336+
validateThumbnailRequired(meta, category, slug, itemDir);
273337
}
274338
}
275339

0 commit comments

Comments
 (0)