fix(okr): frontmatter-verdi krysser ikke linjeskift (patch-lane #5)
`get()`-regexens verdi-gren brukte `\s*`, som inkluderer linjeskift. Enhver
key med tom rest-av-linje slukte dermed den neste ikke-tomme linja. Utslaget
var bredere enn list-keys: en tom `title:` returnerte neste keys hele linje
("type: OKR"), og et tomt `description:` dempet okf-checks anbefalt-felt-
advarsel med data som tilhorte en annen key.
Verdi-grenen strammet til `[ \t]*`. Innrykk-ankeret (`^\s*`) er urort -- det
er load-bearing for inject-okr-context.mjs:69s nestede organisasjon:-lesing.
Kontrakt-kommentaren i :13-16 lovet allerede null for list-keys; den er naa
sann i stedet for aa bli rettet ned.
Sju RED-verifiserte tester: (L1) list-key gir null - (L2) tom skalar sluker
ikke neste rot-key - (L3) tom key foran list-blokk - (L4) innrykk-toleransen
bevart, forelder gir null - (L5) tab-separert verdi - (L6) tomt anbefalt felt
demper ikke okf-check-advarselen (rootLevelGet arvet defekten) - (L7)
broedtekst-fallbacken plukker ikke list-verdi fra frontmatter.
(L7) gjor S57s latente begrunnelse maalbar: uttrekket i okf-check.mjs:125 ble
beholdt mot nettopp denne defekten, og naar fm-laget endelig taper for
list-keys er `body = raw` foerste gang en roednende mutasjon.
Mutasjons-verifisert (M1 revert, M3 anker-fjerning, M4 uttrekk-fjerning). M2
viste at (L5) ikke vokter tegnklassen -- .trim() gjor `[ \t]*` og `[ ]*`
ekvivalente -- saa testen er omskrevet til aa paastaa det den faktisk viser.
Suite 321 -> 328.
This commit is contained in:
parent
35a0bb8377
commit
9a68441161
4 changed files with 109 additions and 15 deletions
|
|
@ -11,6 +11,17 @@
|
||||||
// beholder en intern '#' ("A #B" -> A #B). Retter comment-leak-bugen der
|
// beholder en intern '#' ("A #B" -> A #B). Retter comment-leak-bugen der
|
||||||
// `okr_frikoblet_fra_loenn: true # ...` lakk kommentaren inn i verdien.
|
// `okr_frikoblet_fra_loenn: true # ...` lakk kommentaren inn i verdien.
|
||||||
//
|
//
|
||||||
|
// Verdi-delen matches med `[ \t]*`, ALDRI `\s*`: `\s` inkluderer linjeskift, saa
|
||||||
|
// en verdi-`\s*` lot enhver key med tom rest-av-linje sluke den neste ikke-tomme
|
||||||
|
// linja. Utslaget var ikke begrenset til list-keys -- en tom `title:` returnerte
|
||||||
|
// neste keys hele linje ("type: OKR"), og et tomt `description:` dempet
|
||||||
|
// okf-checks anbefalt-felt-advarsel med data som tilhorte en annen key.
|
||||||
|
// De to `\s`-ene har ULIK jobb: innrykk-anker (bevart) vs. verdi-avgrensning
|
||||||
|
// (strammet). Tester: (L1)-(L4) + (L6). Bytt aldri verdi-grenen tilbake til `\s*`.
|
||||||
|
// `\t` i klassen er intensjons-dokumentasjon, ikke atferd: .trim() under gjor
|
||||||
|
// `[ \t]*` og `[ ]*` ekvivalente (mutasjons-verifisert). Det som BAERER fiksen er
|
||||||
|
// at linjeskift er utenfor klassen.
|
||||||
|
//
|
||||||
// Tolererer fler-linje OKF-list-verdier (f.eks. `tags:`) uten krasj: get() paa
|
// Tolererer fler-linje OKF-list-verdier (f.eks. `tags:`) uten krasj: get() paa
|
||||||
// en list-key returnerer null (rest-av-linja er tom); list-elementer paa
|
// en list-key returnerer null (rest-av-linja er tom); list-elementer paa
|
||||||
// foelgende linjer konsumeres aldri (ingen konsument leser tre-filenes `tags`).
|
// foelgende linjer konsumeres aldri (ingen konsument leser tre-filenes `tags`).
|
||||||
|
|
@ -26,7 +37,7 @@ export function parseFrontmatter(content) {
|
||||||
|
|
||||||
const get = (key) => {
|
const get = (key) => {
|
||||||
if (raw === null) return null;
|
if (raw === null) return null;
|
||||||
const m = raw.match(new RegExp(`^\\s*${key}:\\s*(.*)$`, 'm'));
|
const m = raw.match(new RegExp(`^\\s*${key}:[ \\t]*(.*)$`, 'm'));
|
||||||
if (!m) return null;
|
if (!m) return null;
|
||||||
let v = m[1].trim();
|
let v = m[1].trim();
|
||||||
if (v === '') return null;
|
if (v === '') return null;
|
||||||
|
|
|
||||||
|
|
@ -113,15 +113,13 @@ function rootMarkers(root) {
|
||||||
// hver for seg (mutasjon M1 roedner (20a)/(20d) NETTOPP fordi fallbacken ikke
|
// hver for seg (mutasjon M1 roedner (20a)/(20d) NETTOPP fordi fallbacken ikke
|
||||||
// ser frontmatter-linjene).
|
// ser frontmatter-linjene).
|
||||||
//
|
//
|
||||||
// AERLIG OM DEKNINGEN: uttrekket er ikke produksjonsobserverbart i dag. Naar
|
// DEKNING: uttrekket ER produksjonsobserverbart siden lib/frontmatter.mjs's
|
||||||
// noekkelen finnes i frontmatter i en form parseFrontmatter i det hele tatt
|
// list-key-kontrakt ble sann (verdi-grenen strammet fra `\s*` til `[ \t]*`).
|
||||||
// returnerer, vinner fm-laget foer fallbacken kjoeres -- saa `body = raw`
|
// get() paa en list-key gir naa null, saa fm-laget taper og fallbacken kjoerer
|
||||||
// roedner ingen test (maalt, ikke antatt). Det beholdes likevel: fjernes det,
|
// for list-keys -- foerste gang den grenen naas i praksis. Uten uttrekket ville
|
||||||
// ligger en latent defekt og venter paa at lib/frontmatter.mjs's list-key-
|
// `^okf_version:` matchet INNE i frontmatteren og plukket «- 9.9». `body = raw`
|
||||||
// kontrakt (:13-15) blir sann. I dag returnerer get() paa en list-key foerste
|
// roedner naa (L7) (mutasjons-verifisert). S57 beholdt dette mot nettopp den
|
||||||
// LIST-ELEMENT, ikke null, fordi `\s*` i :29-regexen spiser linjeskiftet.
|
// latente defekten; den er ikke lenger latent, og vakten er ekte.
|
||||||
// Fikses det (patch-lane), begynner fallbacken aa kjoere for list-keys -- og
|
|
||||||
// uten dette uttrekket ville den plukket «- a» ut av frontmatter.
|
|
||||||
const body = fmRaw === null ? raw : raw.slice(raw.indexOf('\n---', 3) + 4);
|
const body = fmRaw === null ? raw : raw.slice(raw.indexOf('\n---', 3) + 4);
|
||||||
const pick = (key) => {
|
const pick = (key) => {
|
||||||
const fromFm = fmGet(key);
|
const fromFm = fmGet(key);
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,54 @@ test('writeFrontmatter: array-verdi (tags) -> OKF multi-linje liste (Step 3)', (
|
||||||
const { get } = parseFrontmatter(block);
|
const { get } = parseFrontmatter(block);
|
||||||
assert.equal(get('type'), 'OKR', 'skalar FOR list-blokk resolver');
|
assert.equal(get('type'), 'OKR', 'skalar FOR list-blokk resolver');
|
||||||
assert.equal(get('kilde'), 'innboks', 'skalar ETTER innrykket list-blokk resolver fortsatt');
|
assert.equal(get('kilde'), 'innboks', 'skalar ETTER innrykket list-blokk resolver fortsatt');
|
||||||
// Lese-siden uendret (Step 3 scope = kun skrive-siden): get() paa en list-key
|
// get() paa en list-key returnerer null -- tolerance-kontrakten i
|
||||||
// krasjer ikke (eksisterende tolerance-kontrakt, frontmatter.mjs:14-16). Den
|
// frontmatter.mjs:14-16 er sann etter at verdi-grenen ble strammet fra \s*
|
||||||
// returnerer foerste list-element fordi parser-\s* spiser newline -- IKKE
|
// til [ \t]* (se (L1)). Fram til da returnerte den foerste list-ELEMENT.
|
||||||
// null; konsumentene leser aldri tag-VERDIER, kun at nabo-skalarer resolver.
|
assert.equal(get('tags'), null, 'get paa list-key gir null');
|
||||||
assert.doesNotThrow(() => get('tags'), 'get paa list-key krasjer ikke');
|
});
|
||||||
|
|
||||||
|
// --- Linjeskift-aksen (L1-L5) ------------------------------------------------
|
||||||
|
// `:\s*(.*)$` lot \s* krysse linjeskift, saa ENHVER key med tom rest-av-linje
|
||||||
|
// slukte den neste ikke-tomme linja. Utslaget er ikke begrenset til list-keys:
|
||||||
|
// en tom `title:` returnerte neste keys HELE linje ("type: OKR"). Fikset ved aa
|
||||||
|
// stramme KUN den andre \s* til [ \t]*; den foerste (`^\s*`, innrykk-toleranse)
|
||||||
|
// er load-bearing for inject-okr-context.mjs:69 og staar urort -- (L4) vokter det.
|
||||||
|
|
||||||
|
test('(L1) list-key: get() returnerer null (kontrakten :14-16 blir sann)', () => {
|
||||||
|
const { get } = parseFrontmatter(
|
||||||
|
'---\ntype: OKR\ntags:\n - alpha\n - beta\ntitle: Ekte tittel\n---\n',
|
||||||
|
);
|
||||||
|
assert.equal(get('tags'), null, 'list-key skal gi null, ikke foerste list-element');
|
||||||
|
assert.equal(get('title'), 'Ekte tittel', 'skalar etter list-blokk resolver fortsatt');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(L2) tom skalar-key sluker ikke neste rot-key', () => {
|
||||||
|
const { get } = parseFrontmatter('---\ntitle:\ntype: OKR\n---\n');
|
||||||
|
assert.equal(get('title'), null, 'tom title skal gi null, ikke "type: OKR"');
|
||||||
|
assert.equal(get('type'), 'OKR', 'den slukte keyen resolver selv');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(L3) tom key rett foran innrykket list-blokk gir null', () => {
|
||||||
|
const { get } = parseFrontmatter('---\ntype: OKR\ndescription:\ntags:\n - x\n---\n');
|
||||||
|
assert.equal(get('description'), null, 'tom description skal gi null, ikke "tags:"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(L4) innrykk-toleransen BEVART: nestet oppslag resolver, forelder gir null', () => {
|
||||||
|
const { get } = parseFrontmatter(
|
||||||
|
'---\norganisasjon:\n navn: "NestetOrg"\n type: "offentlig"\n---\n',
|
||||||
|
);
|
||||||
|
assert.equal(get('navn'), 'NestetOrg', 'load-bearing inject:69 -- foerste \\s* er urort');
|
||||||
|
assert.equal(get('organisasjon'), null, 'tom forelder-key skal ikke gi "navn: ..."');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(L5) tab etter kolon: verdien resolver rent', () => {
|
||||||
|
// MERK: denne er IKKE en vakt for `\t` i tegnklassen. Mutasjonstest viste at
|
||||||
|
// `[ ]*` passerer like godt -- .trim() paa :39 normaliserer tabene uansett,
|
||||||
|
// saa `[ \t]*` og `[ ]*` er atferdsmessig ekvivalente for all input. `\t` staar
|
||||||
|
// igjen som intensjons-dokumentasjon (horisontal whitespace), ikke som atferd.
|
||||||
|
// Testen vokter kontrakten "tab-separert verdi resolver", som holder uansett.
|
||||||
|
const { get } = parseFrontmatter('---\nnavn:\t\tOrg\n---\n');
|
||||||
|
assert.equal(get('navn'), 'Org');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('writeFrontmatter: skalar uendret av array-gren (additiv)', () => {
|
test('writeFrontmatter: skalar uendret av array-gren (additiv)', () => {
|
||||||
|
|
|
||||||
|
|
@ -1194,6 +1194,48 @@ test('(N4) okf-check: et NESTET anbefalt felt demper ikke advarselen', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('(L6) okf-check: et TOMT anbefalt felt demper ikke advarselen', () => {
|
||||||
|
// Linjeskift-aksen naar rootLevelGet: innrykk-filteret fjerner list-elementer,
|
||||||
|
// men et tomt `description:` fulgt av neste ROT-key slukte den linja og gjorde
|
||||||
|
// feltet ikke-tomt -- advarselen ble dempet av data som tilhorte `title`.
|
||||||
|
const dir = tmpRoot();
|
||||||
|
try {
|
||||||
|
buildCleanIngest(dir);
|
||||||
|
writeFileSync(
|
||||||
|
join(dir, 'dokumenter', 'tom-anbefalt.md'),
|
||||||
|
'---\ntype: Notat\ndescription:\ntitle: Ekte tittel\n---\n# Tom anbefalt\n',
|
||||||
|
);
|
||||||
|
const r = checkBundle(dir, { files: [join(dir, 'dokumenter', 'tom-anbefalt.md')] });
|
||||||
|
assert.ok(
|
||||||
|
r.warnings.some((w) => /tom-anbefalt\.md: mangler anbefalt felt .description./.test(w)),
|
||||||
|
`tomt description -> advarsel forventet, fikk:\n${r.warnings.join('\n')}`,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
rmSync(dir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('(L7) okf-check: broedtekst-fallbacken plukker ikke list-verdi FRA frontmatter', () => {
|
||||||
|
// S57 beholdt broedtekst-uttrekket (okf-check.mjs:125) mot en LATENT defekt den
|
||||||
|
// ikke kunne maale: saa lenge get() paa en list-key ga foerste list-element,
|
||||||
|
// vant fm-laget alltid og fallbacken kjorte aldri for list-keys. Etter (L1) gir
|
||||||
|
// fm-laget null -> fallbacken kjorer -> uttrekket er foerste gang observerbart.
|
||||||
|
// Uten det ville `^okf_version:` matchet inne i frontmatteren og plukket «- 9.9».
|
||||||
|
const dir = tmpRoot();
|
||||||
|
try {
|
||||||
|
buildCleanIngest(dir);
|
||||||
|
writeFileSync(
|
||||||
|
join(dir, 'index.md'),
|
||||||
|
['---', 'type: Index', 'okf_version:', ' - 9.9', '---', '# Rot', '', 'okf_layout: kb-layout-2026-06', ''].join('\n'),
|
||||||
|
);
|
||||||
|
const r = checkBundle(dir, { files: [] });
|
||||||
|
assert.equal(r.okfVersion, null, 'list-verdi i frontmatter skal ikke lekke via fallbacken');
|
||||||
|
assert.equal(r.okfLayout, 'kb-layout-2026-06', 'ekte broedtekst-markoer resolver fortsatt');
|
||||||
|
} finally {
|
||||||
|
rmSync(dir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('(N5) okf-check: en NESTET okf_version i rot-index leses ikke som rot-markoer', () => {
|
test('(N5) okf-check: en NESTET okf_version i rot-index leses ikke som rot-markoer', () => {
|
||||||
const dir = tmpRoot();
|
const dir = tmpRoot();
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue