diff --git a/tools/verify-media-library-ux-1.44.0.mjs b/tools/verify-media-library-ux-1.44.0.mjs new file mode 100644 index 0000000..fbe1437 --- /dev/null +++ b/tools/verify-media-library-ux-1.44.0.mjs @@ -0,0 +1,91 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const root = process.cwd(); +const read = relative => fs.readFileSync(path.join(root, relative), 'utf8'); +const js = read('public/media-library-ux.js'); +const css = read('public/media-library-ux.css'); +const loader = read('public/ux-foundation.js'); +const html = read('public/index.html'); +const pkg = JSON.parse(read('package.json')); + +const failures = []; +const expect = (condition, message) => { + if (!condition) failures.push(message); +}; +const includesAll = (source, values, label) => { + for (const value of values) expect(source.includes(value), `${label}: ${value}`); +}; + +includesAll(html, [ + 'id="media-library"', + 'id="media-grid"', + 'id="media-search"', + 'id="media-source"', + 'id="media-sort"', + 'id="media-favorites-only"', + 'id="media-selected-count"', + 'id="media-lightbox"', + 'id="media-lightbox-stage"', +], 'Bestehender Medienvertrag fehlt'); + +includesAll(loader, [ + 'media-library-ux.css?v=1.44.0', + 'media-library-ux.js?v=1.44.0', + 'data-ux-media-library', + 'loadMediaLibraryAssets()', +], 'UX-Loader bindet Medienbibliothek nicht vollständig ein'); + +expect(pkg.scripts?.['verify:media-library'] === 'node tools/verify-media-library-ux-1.44.0.mjs', 'verify:media-library Script fehlt'); +expect(pkg.scripts?.['verify:all']?.includes('npm run verify:media-library'), 'verify:all enthält das Medienbibliothek-Gate nicht'); + +includesAll(js, [ + 'DENSITY_KEY', + 'data-media-density-option', + 'ux-media-filter-details', + 'ux-media-active-filters', + 'ux-media-filter-chip', + 'data-has-media-selection', + 'ux-media-batch-more', + 'MutationObserver', + 'data-media-preview', + 'data-media-use', + 'data-ux-media-preview-nav', + "event.key === 'ArrowLeft'", + "event.key === 'ArrowRight'", + 'requestAnimationFrame', +], 'Medienbibliothek-UX-Vertrag fehlt'); + +includesAll(css, [ + '#media-library[data-media-density="compact"]', + '#media-library[data-media-density="large"]', + '.ux-media-command', + '.ux-media-filter-panel', + '.ux-media-active-filters', + '#media-library[data-has-media-selection] .media-batchbar', + '.ux-media-batch-more', + '#media-library .media-grid', + '#media-library .media-card-actions', + '.ux-media-lightbox-nav', + '@media (max-width: 760px)', + '@media (max-width: 470px)', + '@media (prefers-reduced-motion: reduce)', + ':focus-visible', + 'var(--', +], 'Medienbibliothek-CSS-Vertrag fehlt'); + +expect(!/\bfetch\s*\(/.test(js), 'Additive Medien-UX darf keine eigenen Netzwerkaufrufe ausführen'); +expect(!/\bapi\s*\(/.test(js), 'Additive Medien-UX darf keine Vendoo-API direkt aufrufen'); +expect(!/\.innerHTML\s*=/.test(js), 'Medien-UX darf keine innerHTML-Zuweisungen verwenden'); +expect(!/\.outerHTML\s*=/.test(js), 'Medien-UX darf keine outerHTML-Zuweisungen verwenden'); +expect(!/\.onclick\s*=/.test(js), 'Medien-UX darf keine onclick-Zuweisungen verwenden'); +expect(!/confirm\s*\(/.test(js), 'Gefährliche Medienaktionen müssen in der bestehenden geprüften Logik bleiben'); +expect(!/DELETE|PATCH|POST|PUT/.test(js), 'Medien-UX darf keine Schreiboperationen implementieren'); + +if (failures.length) { + console.error('Media Library UX Gate fehlgeschlagen:'); + for (const failure of failures) console.error(`- ${failure}`); + process.exit(1); +} + +console.log('Media Library UX Gate bestanden.');