712086ddca
Показ анимации кубиков игрокам, закрытие оверлеев с окнами, ручной ввод количества, меньший радиус кисти, блок спонсоров в «О программе»; плюс черновик game systems / character sheet. Co-authored-by: Cursor <cursoragent@cursor.com>
41 lines
1.9 KiB
TypeScript
41 lines
1.9 KiB
TypeScript
import type { SystemDefinition, ValidationIssue, ValidationResult } from './types';
|
|
import { SYSTEM_FORMAT, FORMAT_VERSION } from './types';
|
|
|
|
function err(path: string, message: string, code: string): ValidationIssue {
|
|
return { path, message, code };
|
|
}
|
|
|
|
export function validateSystemDefinition(system: unknown): ValidationResult {
|
|
const errors: ValidationIssue[] = [];
|
|
if (!system || typeof system !== 'object') {
|
|
return { ok: false, errors: [err('$', 'System must be an object', 'type')] };
|
|
}
|
|
const s = system as Partial<SystemDefinition>;
|
|
if (s.format !== SYSTEM_FORMAT) errors.push(err('format', `Expected ${SYSTEM_FORMAT}`, 'format'));
|
|
if (s.formatVersion !== FORMAT_VERSION) {
|
|
errors.push(err('formatVersion', `Expected ${FORMAT_VERSION}`, 'formatVersion'));
|
|
}
|
|
if (!s.id || typeof s.id !== 'string') errors.push(err('id', 'id required', 'required'));
|
|
if (!s.name || typeof s.name !== 'string') errors.push(err('name', 'name required', 'required'));
|
|
if (typeof s.schemaVersion !== 'number') errors.push(err('schemaVersion', 'number required', 'type'));
|
|
if (typeof s.revision !== 'number') errors.push(err('revision', 'number required', 'type'));
|
|
if (!s.bricks || typeof s.bricks !== 'object') errors.push(err('bricks', 'bricks required', 'required'));
|
|
if (!Array.isArray(s.creationRules)) errors.push(err('creationRules', 'array required', 'type'));
|
|
if (!s.sheetLayout || !Array.isArray(s.sheetLayout.pages)) {
|
|
errors.push(err('sheetLayout.pages', 'pages required', 'required'));
|
|
}
|
|
|
|
const derived = s.bricks?.derived ?? [];
|
|
const keys = new Set(derived.map((d) => d.key));
|
|
for (const d of derived) {
|
|
if (!d.formula) errors.push(err(`derived.${d.key}`, 'formula required', 'required'));
|
|
for (const dep of d.dependsOn ?? []) {
|
|
if (dep.startsWith('derived.') && !keys.has(dep.slice('derived.'.length))) {
|
|
// allow forward refs; cycle checked elsewhere
|
|
}
|
|
}
|
|
}
|
|
|
|
return { ok: errors.length === 0, errors };
|
|
}
|