Files
vendoo/tools/generate-design-tokens.mjs
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

57 lines
2.9 KiB
JavaScript

import { readFileSync, writeFileSync } from 'fs';
import { dirname, join, resolve } from 'path';
import { fileURLToPath } from 'url';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const sourcePath = join(root, 'public', 'design-system', 'tokens', 'source.json');
const cssPath = join(root, 'public', 'design-system', 'tokens.css');
const contractPath = join(root, 'public', 'design-system', 'theme-contract.json');
const source = JSON.parse(readFileSync(sourcePath, 'utf8'));
const failures = [];
if (source.schemaVersion !== 1) failures.push('schemaVersion muss 1 sein');
if (!/^\d+\.\d+\.\d+$/.test(String(source.contractVersion || ''))) failures.push('contractVersion ist ungültig');
if (!Array.isArray(source.themes) || !source.themes.includes('light') || !source.themes.includes('dark')) failures.push('light und dark müssen definiert sein');
const cssVars = new Set();
for (const [name, token] of Object.entries(source.tokens || {})) {
if (!/^[a-z][A-Za-z0-9]*(?:\.[a-z][A-Za-z0-9]*)+$/.test(name)) failures.push(`Ungültiger Tokenname: ${name}`);
if (!/^--vd-[a-z0-9-]+$/.test(String(token.css || ''))) failures.push(`Ungültige CSS-Variable: ${name}`);
if (cssVars.has(token.css)) failures.push(`Doppelte CSS-Variable: ${token.css}`);
cssVars.add(token.css);
for (const theme of source.themes) if (typeof token[theme] !== 'string' || !token[theme].trim()) failures.push(`${name} fehlt in Theme ${theme}`);
}
if (failures.length) {
console.error(`Design-Token-Generierung fehlgeschlagen (${failures.length}):`);
failures.forEach(item => console.error(`- ${item}`));
process.exit(1);
}
function block(selector, theme) {
const lines = Object.values(source.tokens).map(token => ` ${token.css}: ${token[theme]};`);
return `${selector} {\n${lines.join('\n')}\n}`;
}
const css = `/* Automatisch generiert aus design-system/tokens/source.json. Nicht direkt bearbeiten. */\n` +
`/* Contract ${source.contractVersion} */\n` +
`${block(':root', 'light')}\n\n${block('[data-theme="dark"]', 'dark')}\n\n${block('[data-theme="contrast"]', 'contrast')}\n\n` +
`@media (prefers-reduced-motion: reduce) {\n :root { --vd-motion-fast: 0ms; --vd-motion-normal: 0ms; }\n}\n`;
writeFileSync(cssPath, css, 'utf8');
const contract = {
schemaVersion: source.schemaVersion,
contractVersion: source.contractVersion,
themes: source.themes,
tokens: Object.fromEntries(Object.entries(source.tokens).map(([name, token]) => [name, {
css: token.css,
type: token.type,
customizable: Boolean(token.customizable),
label: token.label || name,
group: token.group || name.split('.')[0],
...(token.min !== undefined ? { min: token.min } : {}),
...(token.max !== undefined ? { max: token.max } : {}),
}])),
};
writeFileSync(contractPath, `${JSON.stringify(contract, null, 2)}\n`, 'utf8');
console.log(`Design Tokens erzeugt: ${Object.keys(source.tokens).length} Tokens, ${source.themes.length} Themes.`);