Files
ponomar-pwa/scripts/validate-great-compline.ts
2026-08-01 02:43:24 +03:00

90 lines
2.8 KiB
TypeScript

/**
* Validate Great Compline data: prayer files referenced by the
* GreatCompline template must exist and be well-formed.
* Run with: npx tsx scripts/validate-great-compline.ts
*/
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
const __dirname = new URL('.', import.meta.url).pathname;
const ROOT = join(__dirname, '..', 'static', 'data');
const TEMPLATE = join(ROOT, 'shared', 'services', 'templates', 'GreatCompline.json');
const PRAYERS = join(ROOT, 'cu', 'services', 'prayers');
const TEMPLATES = join(ROOT, 'shared', 'services', 'templates');
const BIBLE = join(ROOT, 'cu', 'bible', 'elis');
interface ServiceNode {
type: string;
what?: string;
file?: string;
verses?: string;
cmd?: string;
}
let errors = 0;
let warnings = 0;
function err(msg: string) { console.error(` ERROR: ${msg}`); errors++; }
function warn(msg: string) { console.warn(` WARN: ${msg}`); warnings++; }
const nodes: ServiceNode[] = JSON.parse(readFileSync(TEMPLATE, 'utf-8'));
console.log(`GreatCompline.json: ${nodes.length} nodes`);
const usedPrayers = new Set<string>();
for (const n of nodes) {
if (n.type === 'CREATE') {
if (!n.what) { err('CREATE without what'); continue; }
usedPrayers.add(n.what);
const p = join(PRAYERS, `${n.what}.json`);
if (!existsSync(p)) {
err(`missing prayer: ${n.what}.json`);
continue;
}
const prayerNodes = JSON.parse(readFileSync(p, 'utf-8'));
if (!Array.isArray(prayerNodes) || prayerNodes.length === 0) {
err(`empty prayer: ${n.what}.json`);
continue;
}
for (const pn of prayerNodes) {
if (!pn.type || !pn.value) {
err(`${n.what}.json: node missing type/value`);
break;
}
}
}
if (n.type === 'GET') {
if (!n.file) { err('GET without file'); continue; }
if (n.file.startsWith('Var/')) continue;
const p = join(TEMPLATES, `${n.file}.json`);
if (!existsSync(p)) {
err(`missing template: ${n.file}.json`);
}
}
if (n.type === 'BIBLE') {
const v = n.verses ?? '';
const book = v.split('_')[0];
const p = join(BIBLE, `${book}.text`);
if (!existsSync(p)) {
err(`missing bible book: ${book}`);
}
}
}
console.log(`\n${usedPrayers.size} unique prayers referenced`);
// Verify the Great Canon data files exist
const CANONS = join(ROOT, 'shared', 'services', 'canons', 'great-canon');
for (let i = 1; i <= 4; i++) {
const p = join(CANONS, `part${i}.json`);
if (!existsSync(p)) err(`missing great canon part${i}.json`);
else {
const data = JSON.parse(readFileSync(p, 'utf-8'));
if (data.odes.length !== 9) err(`part${i}.json: expected 9 odes`);
}
}
console.log(`\n${errors + warnings} issues (${errors} errors, ${warnings} warnings)`);
process.exit(errors > 0 ? 1 : 0);