feat(okr): aarsrapport del III-generator
This commit is contained in:
parent
8ef8f7a405
commit
77031b0c9a
3 changed files with 384 additions and 65 deletions
|
|
@ -8,9 +8,8 @@
|
|||
//
|
||||
// Former: tertial | arsrapport | etatsstyring
|
||||
// EN kommandoflate med argument, ikke tre kommandoer -- samme moenster som
|
||||
// /okr:oppsett full|mvp|arkiver|oppdater|vis. Bare `tertial` er implementert
|
||||
// i D5; arsrapport og etatsstyring kommer i steg 11-12 og svarer inntil da
|
||||
// med exit 2 og en forklarende melding, aldri stum feil.
|
||||
// /okr:oppsett full|mvp|arkiver|oppdater|vis. `etatsstyring` kommer i steg 12
|
||||
// og svarer inntil da med exit 2 og en forklarende melding, aldri stum feil.
|
||||
//
|
||||
// Exit-koder (kontrakten commands/rapport.md mapper til norsk brukertekst):
|
||||
// 0 rapporten er skrevet
|
||||
|
|
@ -22,13 +21,43 @@
|
|||
//
|
||||
// Zero npm dependencies.
|
||||
|
||||
import { existsSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { basename, join } from 'node:path';
|
||||
import { existsSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { basename, dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { writeFrontmatter } from '../lib/frontmatter.mjs';
|
||||
import { parseFrontmatter, writeFrontmatter } from '../lib/frontmatter.mjs';
|
||||
import { lesSyklus } from '../lib/syklus-data.mjs';
|
||||
import { tertialrapport } from '../lib/syklus-rapport.mjs';
|
||||
import { arsrapportDelIII, tertialrapport } from '../lib/syklus-rapport.mjs';
|
||||
|
||||
// historikk/ er SOESKEN av syklus/, altsaa <syklusDir>/../../historikk. Den
|
||||
// avledningen er en determinisme-risiko: regnet ut blindt ville en syklus-katalog
|
||||
// utenfor et OKR-tre pekt paa en vilkaarlig katalog paa maskinen, og rapporten
|
||||
// variert med hva som tilfeldigvis laa der. Derfor avledes stien KUN naar
|
||||
// foreldrekatalogen faktisk heter `syklus`; ellers finnes det ingen historikk.
|
||||
//
|
||||
// Katalogen leses direkte -- ALDRI via index.md. Indeksen er navigasjon og kan
|
||||
// peke paa filer som ikke finnes (fixturen har en slik dangling-lenke med vilje);
|
||||
// et styringsdokument som lister materiale som ikke eksisterer er verre enn et
|
||||
// som utelater seksjonen. readdir sorteres, fordi byte-identiske kjoeringer er
|
||||
// kontrakt og lesrekkefolgen fra filsystemet ikke er garantert.
|
||||
function lesHistorikk(syklusDir) {
|
||||
const syklusRot = dirname(resolve(syklusDir));
|
||||
if (basename(syklusRot) !== 'syklus') return [];
|
||||
const dir = join(dirname(syklusRot), 'historikk');
|
||||
let filer;
|
||||
try {
|
||||
filer = readdirSync(dir);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return filer
|
||||
.filter((n) => n.endsWith('.md') && n !== 'index.md')
|
||||
.sort()
|
||||
.map((fil) => {
|
||||
const fm = parseFrontmatter(readFileSync(join(dir, fil), 'utf8'));
|
||||
return { tittel: fm.get('title') ?? fil.replace(/\.md$/, ''), fil };
|
||||
});
|
||||
}
|
||||
|
||||
const FORMER = {
|
||||
tertial: {
|
||||
|
|
@ -37,8 +66,16 @@ const FORMER = {
|
|||
beskrivelse: 'Maskingenerert tertialrapport med committed og aspirational holdt fra hverandre.',
|
||||
bygg: tertialrapport,
|
||||
},
|
||||
// Steg 11-12. Oppfoert her, ikke skjult, saa flaten er synlig foer den virker.
|
||||
arsrapport: null,
|
||||
arsrapport: {
|
||||
filnavn: 'rapport-arsrapport.md',
|
||||
tittel: (id) => `Aarsrapport del III ${id}`,
|
||||
beskrivelse: 'Maskingenerert underlag til aarsrapportens del III. Vurderingen av maaloppnaaelse er reservert til virksomheten.',
|
||||
bygg: arsrapportDelIII,
|
||||
// Disklesing hoerer til orkestratoren, ikke til lib/: generatorformen skal
|
||||
// kunne testes uten et tre paa filsystemet.
|
||||
kontekst: (syklusDir) => ({ historikk: lesHistorikk(syklusDir) }),
|
||||
},
|
||||
// Steg 12. Oppfoert her, ikke skjult, saa flaten er synlig foer den virker.
|
||||
etatsstyring: null,
|
||||
};
|
||||
|
||||
|
|
@ -50,7 +87,7 @@ class Bruksfeil extends Error {}
|
|||
// okr-second-brain-search paa kjoepet.
|
||||
// Filnavnet starter bevisst IKKE med `okr-`: ellers ville neste lesSyklus()
|
||||
// plukket rapporten opp som en OKR-definisjon.
|
||||
function komponer(form, syklus, naa) {
|
||||
function komponer(form, syklus, naa, kontekst) {
|
||||
const frontmatter = writeFrontmatter({
|
||||
type: 'Status',
|
||||
resource: 'local',
|
||||
|
|
@ -58,7 +95,7 @@ function komponer(form, syklus, naa) {
|
|||
description: form.beskrivelse,
|
||||
timestamp: naa,
|
||||
});
|
||||
return `${frontmatter}\n${form.bygg(syklus, { naa })}`;
|
||||
return `${frontmatter}\n${form.bygg(syklus, { naa, ...kontekst })}`;
|
||||
}
|
||||
|
||||
// Atomisk skriv: temp i SAMME katalog (rename er kun atomisk innen filsystem),
|
||||
|
|
@ -94,8 +131,9 @@ export function genererRapport(syklusDir, formNavn, opts = {}) {
|
|||
|
||||
const naa = opts.naa || process.env.OKR_NOW || new Date().toISOString();
|
||||
const syklus = lesSyklus(syklusDir);
|
||||
const kontekst = form.kontekst ? form.kontekst(syklusDir) : {};
|
||||
const maal = join(syklusDir, form.filnavn);
|
||||
skrivAtomisk(maal, komponer(form, syklus, naa));
|
||||
skrivAtomisk(maal, komponer(form, syklus, naa, kontekst));
|
||||
return { fil: maal, syklus: syklus.id, okrer: syklus.okrer.length };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue