source: Klonkt/scripts/admin-css-gelijk.mjs@ d8f8f07

main
Last change on this file since d8f8f07 was abd2093, checked in by Robin <roboburr@…>, 3 weeks ago

Beheer: audio en playlists ook op de gedeelde ax-romp

Mijn regressie van de vorige commit: ik haalde de opmaak van de tabbalk
uit media-tabs.ejs en zette hem in de partial, maar audio en playlists
nemen die partial niet op. Hun tabbalk stond er dus wel in de markup en
had geen enkele regel CSS -- vijf kale links, en de pagina zat er niet
meer onder.

Beide pagina's nemen de partial nu op, boven hun eigen style-blok zodat
wat daar blijft staan later komt en dus wint.

En daarmee kon het ontdubbelen alsnog, maar nu met een echte ontleding:
scripts/admin-css.mjs leest de tekens een voor een en kent commentaar,
tekenreeksen en geneste blokken. Dat was nodig -- mijn regex van
vanochtend telde @media-varianten als losse regels en commentaar als
selector, en zat er voor playlists 7 regels naast. Twee fouten zaten ook
in de eerste versie van dit script: /* Mobiel */ voor een @media maakte
het blok onherkenbaar, en geneste regels droegen posities uit hun
binnentekst -- daarmee had het weghalen de verkeerde bytes geknipt.

Weg: 27 regels uit admin-audio, 34 uit admin-playlists. Wat afwijkt
blijft staan en wordt gemeld (audio heeft 10 eigen varianten, playlists
2).

scripts/admin-css-gelijk.mjs is het bewijs: hij rendert elke pagina nu
en zoals hij was, rekent per (media-context, selector) uit wat er
uiteindelijk geldt, en legt de twee naast elkaar. Uitkomst over alle
vijf: geen regel verdwenen, geen regel veranderd, en op audio en
playlists 21 resp. 22 regels erbij -- de tabbalk voorop.

Dat audio en playlists nu ook .ax-grid en .ax-tile meekrijgen die ze niet
gebruiken, is de prijs van een gedeelde partial. Een paar honderd bytes.

Co-Authored-By: Claude Opus 5 <noreply@…>

  • Property mode set to 100644
File size: 4.8 KB
RevLine 
[abd2093]1/**
2 * Bewijst dat het ontdubbelen niets aan de OPMAAK heeft veranderd.
3 *
4 * node scripts/admin-css-gelijk.mjs <git-ref> (standaard HEAD)
5 *
6 * Rendert elke beheerpagina twee keer -- zoals hij nu is, en zoals hij in de
7 * opgegeven git-ref was -- verzamelt uit de uitvoer ALLE style-blokken, en
8 * rekent per (media-context, selector) uit welke verklaringen er uiteindelijk
9 * gelden. Later in het document wint, zoals in een browser.
10 *
11 * Daarna legt hij de twee kaarten naast elkaar. Gelijk = de ingreep was
12 * werkelijk alleen verplaatsen.
13 *
14 * WAAROM DIT NODIG IS. "De tests zijn groen" zegt hier niets: de suite raakt
15 * geen enkele view. En "het rendert" ook niet: een pagina die zijn halve
16 * opmaak kwijt is rendert prima. Zo raakten audio en playlists hun tabbalk
17 * kwijt -- de markup stond er, de regels niet, en niets viel om.
18 *
19 * WEL VERWACHT: regels die ERBIJ komen. De partial brengt .ax-tab en .ax-tabs
20 * mee, en dat is de hele bedoeling. Die worden apart gemeld, niet als fout.
21 */
22import fs from 'node:fs';
23import path from 'node:path';
24import ejs from 'ejs';
25
26// De OUDE views als map, niet als git-ref: de testkloon op de server heeft geen
27// .git, en een controle die alleen in een werkboom kan draaien is er een die je
28// daar niet draait.
29// git archive <ref> src/views | tar x -C /tmp/oud
30// node scripts/admin-css-gelijk.mjs /tmp/oud
31const OUD = process.argv[2];
32if (!OUD) { console.error('gebruik: node scripts/admin-css-gelijk.mjs <map met oude src/views>'); process.exit(2); }
33
34const basis = {
35 t: (k) => k, thumb: (u) => u, formatDate: (d) => String(d || ''),
36 audioOn: true, success: null, error: null, csrfToken: 'x',
37 siteUrlBase: '', locale: 'nl',
38};
39const PAGINAS = {
40 'admin-audio': { tracks: [], playlists: [], maxBytesMb: 20, maxWavMb: 100, site: { id: 's1', slug: 'x' } },
41 'admin-playlists': { playlists: [] },
42 'admin-media': { items: [], unusedCount: 0 },
43 'admin-videos': { items: [] },
44 'admin-listeners': { luisteraars: [] },
45};
46
47// ── dezelfde ontleding als admin-css.mjs ──────────────────────────
48const norm = (s) => s.replace(/\s+/g, ' ').trim();
49const schoon = (s) => s.replace(/\/\*[\s\S]*?\*\//g, ' ');
50function ontleed(css, context = '') {
51 const uit = []; let i = 0, start = 0, diepte = 0, blokStart = -1;
52 while (i < css.length) {
53 const c = css[i];
54 if (c === '/' && css[i + 1] === '*') { const e = css.indexOf('*/', i + 2); i = e === -1 ? css.length : e + 2; continue; }
55 if (c === '"' || c === "'") { const q = c; i++; while (i < css.length && css[i] !== q) { if (css[i] === '\\') i++; i++; } i++; continue; }
56 if (c === '{') { if (diepte === 0) blokStart = i; diepte++; i++; continue; }
57 if (c === '}') {
58 diepte--;
59 if (diepte === 0) {
60 const kop = norm(schoon(css.slice(start, blokStart)));
61 const lijf = css.slice(blokStart + 1, i);
62 if (kop.startsWith('@media') || kop.startsWith('@supports')) uit.push(...ontleed(lijf, kop));
63 else uit.push({ context, selector: kop, verklaringen: schoon(lijf).split(';').map(norm).filter(Boolean).sort().join('; ') });
64 start = i + 1;
65 }
66 i++; continue;
67 }
68 i++;
69 }
70 return uit;
71}
72
73/** Wat geldt er uiteindelijk: later in het document wint. */
74function effectief(html) {
75 const kaart = new Map();
76 for (const m of html.matchAll(/<style>([\s\S]*?)<\/style>/g)) {
77 for (const r of ontleed(m[1])) kaart.set(`${r.context}||${r.selector}`, r.verklaringen);
78 }
79 return kaart;
80}
81
82let stuk = 0;
83for (const [naam, data] of Object.entries(PAGINAS)) {
84 const locals = { ...basis, ...data };
85 let nu, toen;
86 try { nu = effectief(await ejs.renderFile(`src/views/pages/${naam}.ejs`, locals)); }
87 catch (e) { console.log(`STUK ${naam} (nu): ${e.message.split('\n')[0]}`); stuk++; continue; }
88 try { toen = effectief(await ejs.renderFile(path.join(OUD, `src/views/pages/${naam}.ejs`), locals)); }
89 catch (e) { console.log(`? ${naam}: oude versie rendert niet (${e.message.split('\n')[0]}) -- overgeslagen`); continue; }
90
91 const verdwenen = [...toen.keys()].filter((k) => !nu.has(k));
92 const veranderd = [...toen.keys()].filter((k) => nu.has(k) && nu.get(k) !== toen.get(k));
93 const nieuw = [...nu.keys()].filter((k) => !toen.has(k));
94
95 if (verdwenen.length || veranderd.length) {
96 stuk++;
97 console.log(`STUK ${naam}`);
98 for (const k of verdwenen) console.log(` WEG ${k.replace('||', ' ')}`);
99 for (const k of veranderd) console.log(` VERANDERD ${k.replace('||', ' ')}\n was: ${toen.get(k)}\n is : ${nu.get(k)}`);
100 } else {
101 console.log(`OK ${naam} ${toen.size} regels ongewijzigd, ${nieuw.length} erbij`);
102 for (const k of nieuw) console.log(` + ${k.replace('||', ' ')}`);
103 }
104}
105console.log(stuk ? `\n${stuk} pagina('s) veranderd van opmaak` : '\nopmaak identiek');
106process.exit(stuk ? 1 : 0);
Note: See TracBrowser for help on using the repository browser.