wip
This commit is contained in:
parent
cc89f0c75c
commit
afd28d934e
26 changed files with 2103 additions and 427 deletions
96
data-pipeline/utils/verify-enriched-file.ts
Normal file
96
data-pipeline/utils/verify-enriched-file.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import fs from "fs";
|
||||
|
||||
interface VerificationResult {
|
||||
valid: boolean;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that an enriched JSON file matches the expected schema.
|
||||
* Returns detailed error messages for any violations.
|
||||
*/
|
||||
export function verifyEnrichedFile(filePath: string): VerificationResult {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return { valid: false, errors: ["File does not exist"] };
|
||||
}
|
||||
|
||||
let data: unknown;
|
||||
try {
|
||||
data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
||||
} catch (_error: unknown) {
|
||||
return { valid: false, errors: ["Invalid JSON syntax"] };
|
||||
}
|
||||
|
||||
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
||||
return { valid: false, errors: ["Root must be an object"] };
|
||||
}
|
||||
|
||||
const obj = data as Record<string, unknown>;
|
||||
|
||||
// Required top-level fields
|
||||
const requiredFields = ["word", "language", "pos", "senses"];
|
||||
for (const field of requiredFields) {
|
||||
if (!(field in obj)) {
|
||||
errors.push(`Missing required field: "${field}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate senses array
|
||||
if (!Array.isArray(obj["senses"])) {
|
||||
errors.push('"senses" must be an array');
|
||||
} else if (obj["senses"].length === 0) {
|
||||
errors.push('"senses" array cannot be empty');
|
||||
} else {
|
||||
for (let i = 0; i < obj["senses"].length; i++) {
|
||||
const sense = obj["senses"][i] as Record<string, unknown>;
|
||||
const sensePrefix = `senses[${i}]`;
|
||||
|
||||
if (!sense["sense"] || typeof sense["sense"] !== "string") {
|
||||
errors.push(`${sensePrefix}: missing or invalid "sense"`);
|
||||
}
|
||||
if (!sense["example"] || typeof sense["example"] !== "string") {
|
||||
errors.push(`${sensePrefix}: missing or invalid "example"`);
|
||||
}
|
||||
if (
|
||||
!["easy", "medium", "hard"].includes(
|
||||
sense["difficulty_level"] as string,
|
||||
)
|
||||
) {
|
||||
errors.push(`${sensePrefix}: invalid "difficulty_level"`);
|
||||
}
|
||||
if (!sense["translations"] || typeof sense["translations"] !== "object") {
|
||||
errors.push(`${sensePrefix}: missing "translations"`);
|
||||
} else {
|
||||
const trans = sense["translations"] as Record<string, unknown>;
|
||||
for (const lang of ["de", "it", "es", "fr"]) {
|
||||
if (!Array.isArray(trans[lang])) {
|
||||
errors.push(
|
||||
`${sensePrefix}: missing or invalid "${lang}" translations`,
|
||||
);
|
||||
} else {
|
||||
for (let j = 0; j < (trans[lang] as unknown[]).length; j++) {
|
||||
const t = (trans[lang] as unknown[])[j] as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
if (!t["word"] || typeof t["word"] !== "string") {
|
||||
errors.push(`${sensePrefix}.${lang}[${j}]: missing "word"`);
|
||||
}
|
||||
if (
|
||||
!["masculine", "feminine", "neuter", null].includes(
|
||||
t["gender"] as string | null,
|
||||
)
|
||||
) {
|
||||
errors.push(`${sensePrefix}.${lang}[${j}]: invalid "gender"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: errors.length === 0, errors };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue