// ═══════════════════════════════════════════════════════════════════════════════ // De opdrachtregel lezen. Meer niet. // // Apart van cli.js omdat dit het enige deel van de opdrachtregel is dat te // toetsen valt zonder iets te starten. Dezelfde scheiding als policy.js aan de // relay-kant: pure functies aan de ene kant, alles wat schijf of netwerk raakt // aan de andere. // ═══════════════════════════════════════════════════════════════════════════════ export const OPDRACHTEN = { nieuw: { argumenten: ['naam'], uitleg: 'Maakt een nieuwe eigenaar met verse sleutels' }, lijst: { argumenten: [], uitleg: 'Toont de eigenaars in het register' }, schrijf: { argumenten: ['naam', 'label'], uitleg: 'Schrijft een blob weg voor deze eigenaar' }, lees: { argumenten: ['naam'], uitleg: 'Toont de blobs van deze eigenaar' }, test: { argumenten: ['naam'], uitleg: 'Test of de relay deze eigenaar toelaat, zonder te verbinden' }, spiegel: { argumenten: ['naam'], uitleg: 'Haalt deze eigenaar op in een lege database, via de relay' }, sync: { argumenten: ['naam'], uitleg: 'Verbindt en blijft draaien tot Ctrl-C' }, vergeet: { argumenten: ['naam'], uitleg: 'Haalt een eigenaar uit het register' }, ui: { argumenten: [], uitleg: 'Start het bedieningsvlak in de browser' }, }; /** * Leest `process.argv.slice(2)`. * * Geeft `{fout}` in plaats van te gooien: de aanroeper drukt dat af met de * gebruiksaanwijzing eronder, en dat leest beter dan een stack trace. * * Vlaggen zijn `--naam waarde` of `--naam=waarde`. Een losse `--naam` is `true`. */ export const leesArgumenten = (argv) => { const losse = []; const vlaggen = {}; for (let i = 0; i < argv.length; i += 1) { const stuk = argv[i]; if (!stuk.startsWith('--')) { losse.push(stuk); continue; } const kaal = stuk.slice(2); const isGelijk = kaal.indexOf('='); if (isGelijk > 0) { vlaggen[kaal.slice(0, isGelijk)] = kaal.slice(isGelijk + 1); continue; } const volgende = argv[i + 1]; if (volgende !== undefined && !volgende.startsWith('--')) { vlaggen[kaal] = volgende; i += 1; } else { vlaggen[kaal] = true; } } const [opdracht, ...rest] = losse; if (opdracht === undefined) return { fout: null, opdracht: null, waarden: {}, vlaggen }; const vorm = OPDRACHTEN[opdracht]; if (!vorm) return { fout: `Onbekende opdracht "${opdracht}".`, opdracht: null, waarden: {}, vlaggen }; if (rest.length < vorm.argumenten.length) { const ontbreekt = vorm.argumenten.slice(rest.length).join(', '); return { fout: `"${opdracht}" mist: ${ontbreekt}.`, opdracht, waarden: {}, vlaggen }; } if (rest.length > vorm.argumenten.length) { // Streng, en met opzet. `schrijf piet mijn label` ziet er goed uit en zou // anders stil "mijn" als label nemen; dan sta je te kijken naar een blob die // anders heet dan je typte. return { fout: `"${opdracht}" verwacht ${vorm.argumenten.length} argument(en), niet ${rest.length}. Gebruik aanhalingstekens om een label met spaties.`, opdracht, waarden: {}, vlaggen, }; } const waarden = {}; vorm.argumenten.forEach((naam, plek) => { waarden[naam] = rest[plek]; }); return { fout: null, opdracht, waarden, vlaggen }; }; export const gebruiksaanwijzing = () => { const regels = ['Gebruik: node src/cli.js [argumenten]', '']; for (const [naam, vorm] of Object.entries(OPDRACHTEN)) { const argumenten = vorm.argumenten.map((a) => `<${a}>`).join(' '); regels.push(` ${`${naam} ${argumenten}`.trim().padEnd(24)}${vorm.uitleg}`); } regels.push(''); regels.push('Vlaggen:'); regels.push(' --bytes Omvang van de blob bij `schrijf` (standaard 64)'); regels.push(' --lokaal Schrijven zonder de relay, bij `schrijf`'); regels.push(' --wacht Seconden wachten op de relay, bij `spiegel` (standaard 15)'); regels.push(' --poort Poort van het bedieningsvlak bij `ui`'); regels.push(''); regels.push('Het adres van de relay komt uit .env; zie .env.sample.'); return regels.join('\n'); };