File size: 3,199 Bytes
d9879cf | 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 | import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { z } from 'zod';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const SuccessMustIncludeSchema = z.object({
id: z.string(),
desc: z.string(),
weight: z.number()
});
const CriteriaSchema = z.object({
version: z.string().optional(),
type: z.string().optional(),
goal: z.string().optional(),
success: z.object({
mustInclude: z.array(SuccessMustIncludeSchema),
threshold: z.object({ minScore: z.number(), minMustPass: z.number() }).optional()
}).optional(),
evaluation: z.object({
tone: z.string().optional(),
format: z.string().optional(),
examples: z.string().optional()
}).optional(),
remediation: z.object({
dayNumber: z.number().optional(),
hint: z.string().optional()
}).optional()
});
const TrackDaySchema = z.object({
dayNumber: z.number(),
title: z.string(),
lessonText: z.string(),
exerciseType: z.string().optional(),
exercisePrompt: z.string().optional(),
exerciseCriteria: CriteriaSchema.optional(),
buttonsJson: z.array(z.object({ id: z.string(), title: z.string() })).optional(),
badges: z.array(z.string()).optional(),
imageUrl: z.string().optional(),
videoUrl: z.string().optional(),
videoCaption: z.string().optional()
});
const TrackSchema = z.object({
trackId: z.string(),
title: z.string(),
language: z.enum(['WOLOF', 'FR', 'EN']),
description: z.string().optional(),
totalDays: z.number().optional(),
version: z.string().optional(),
days: z.array(TrackDaySchema)
});
function validateContent() {
console.log('π Starting Content Validation (Zod Pre-commit)...');
const contentDir = path.resolve(__dirname, '../content/tracks');
if (!fs.existsSync(contentDir)) {
console.warn(`β οΈ Content directory not found: ${contentDir}`);
return;
}
const files = fs.readdirSync(contentDir).filter(f => f.endsWith('.json'));
let hasErrors = false;
for (const file of files) {
const filePath = path.join(contentDir, file);
try {
const fileContent = fs.readFileSync(filePath, 'utf-8');
const jsonData = JSON.parse(fileContent);
const r = TrackSchema.safeParse(jsonData);
if (!r.success) {
console.error(`β Validation Failed: ${file}`);
r.error.issues.forEach((e: z.ZodIssue) => {
console.error(` - Path: ${e.path.join('.')}`);
console.error(` - Error: ${e.message}`);
});
hasErrors = true;
} else {
console.log(`β
Validated: ${file}`);
}
} catch (e: unknown) {
hasErrors = true;
console.error(`β Parse Error in ${file}: ${(e instanceof Error ? e.message : String(e))}`);
}
}
if (hasErrors) {
process.exit(1);
} else {
console.log('π All 10 JSON Track files are strictly valid Zod structures.');
}
}
validateContent();
|