How do I have so many partners??
1import { load } from 'js-yaml';
2import { readFileSync } from 'fs';
3import type { PolyculeData, Settings, Person, Relationship, RelationshipType } from './types.js';
4
5const VALID_TYPES = new Set<RelationshipType>([
6 'primary_partner', 'partner', 'nesting_partner', 'anchor_partner', 'fwb', 'casual',
7 'queerplatonic', 'comet', 'friend', 'metamour', 'tbd',
8]);
9
10export function parseConfig(filePath: string): PolyculeData {
11 let raw: string;
12 try {
13 raw = readFileSync(filePath, 'utf8');
14 } catch {
15 throw new Error(`Cannot read file: ${filePath}`);
16 }
17
18 const data = load(raw) as Record<string, unknown>;
19 if (!data || typeof data !== 'object') throw new Error('Config must be a YAML object');
20 if (!Array.isArray(data['people'])) throw new Error('"people" must be an array');
21 if (!Array.isArray(data['relationships'])) throw new Error('"relationships" must be an array');
22
23 const s = data['settings'] as Record<string, unknown> | undefined;
24 const settings: Settings = {
25 theme: s?.['theme'] === 'light' ? 'light' : 'dark',
26 nodeScale: s?.['nodeScale'] === 'connections' ? 'connections' : 'uniform',
27 // mainNode validated below once person IDs are known
28 };
29
30 const people: Person[] = (data['people'] as unknown[]).map((p, i) => {
31 const person = p as Record<string, unknown>;
32 if (!person?.['id']) throw new Error(`Person[${i}] missing "id"`);
33 if (!person?.['name']) throw new Error(`Person "${person['id']}" missing "name"`);
34 return {
35 id: String(person['id']),
36 name: String(person['name']),
37 pronouns: person['pronouns'] != null ? String(person['pronouns']) : undefined,
38 photo: person['photo'] != null ? String(person['photo']) : undefined,
39 color: person['color'] != null ? String(person['color']) : undefined,
40 links: Array.isArray(person['links'])
41 ? (person['links'] as Record<string, unknown>[]).map(l => ({
42 label: String(l['label']),
43 url: String(l['url']),
44 }))
45 : [],
46 };
47 });
48
49 const ids = new Set(people.map(p => p.id));
50
51 const mainNodeRaw = s?.['mainNode'] != null ? String(s['mainNode']) : undefined;
52 if (mainNodeRaw !== undefined) {
53 if (!ids.has(mainNodeRaw)) throw new Error(`settings.mainNode "${mainNodeRaw}" is not a valid person id`);
54 settings.mainNode = mainNodeRaw;
55 }
56
57 const relationships: Relationship[] = (data['relationships'] as unknown[]).map((r, i) => {
58 const rel = r as Record<string, unknown>;
59 if (!rel?.['from']) throw new Error(`Relationship[${i}] missing "from"`);
60 if (!rel?.['to']) throw new Error(`Relationship[${i}] missing "to"`);
61 if (!rel?.['type']) throw new Error(`Relationship[${i}] missing "type"`);
62 const type = rel['type'] as string;
63 if (!VALID_TYPES.has(type as RelationshipType)) {
64 throw new Error(
65 `Relationship[${i}] invalid type "${type}". Valid: ${[...VALID_TYPES].join(', ')}`
66 );
67 }
68 const from = String(rel['from']);
69 const to = String(rel['to']);
70 if (!ids.has(from)) throw new Error(`Unknown person "${from}"`);
71 if (!ids.has(to)) throw new Error(`Unknown person "${to}"`);
72 return {
73 from,
74 to,
75 type: type as RelationshipType,
76 label: rel['label'] != null ? String(rel['label']) : undefined,
77 };
78 });
79
80 return { settings, people, relationships };
81}