#!/usr/bin/env node import fs from "node:fs/promises"; import path from "node:path"; const input = process.argv[2] ?? "tokens"; const output = process.argv[3] ?? "color-preview.html"; function isColor(value) { return ( typeof value === "string" && ( /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value) || /^rgb\(/i.test(value) || /^rgba\(/i.test(value) || /^hsl\(/i.test(value) || /^hsla\(/i.test(value) || /^oklch\(/i.test(value) || /^color\(/i.test(value) ) ); } function unwrapToken(node) { if (!node || typeof node !== "object") return node; if ("$value" in node) return node.$value; if ("value" in node) return node.value; return node; } async function walkFiles(dir) { const out = []; const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const full = path.join(dir, entry.name); if (entry.isDirectory()) { out.push(...await walkFiles(full)); } else if (/\.(json|tokens\.json)$/i.test(entry.name)) { out.push(full); } } return out; } function collectColors(obj, prefix = [], source = "unknown") { const colors = []; if (!obj || typeof obj !== "object") return colors; for (const [key, raw] of Object.entries(obj)) { const value = unwrapToken(raw); const name = [...prefix, key]; if (isColor(value)) { colors.push({ name: name.join("."), value, source }); } else if (value && typeof value === "object") { colors.push(...collectColors(value, name, source)); } } return colors; } function htmlEscape(s) { return String(s) .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """); } function makeHtml(colors) { const cards = colors.map(c => `
${htmlEscape(c.name)} ${htmlEscape(c.source)}
`).join("\n"); return ` Color Preview

Color Preview

${cards || "

No colors found.

"}
`; } const stat = await fs.stat(input).catch(() => null); if (!stat) { console.error(`Input not found: ${input}`); process.exit(1); } const files = stat.isDirectory() ? await walkFiles(input) : [input]; const colors = []; for (const file of files) { const json = JSON.parse(await fs.readFile(file, "utf8")); colors.push(...collectColors(json, [], file)); } colors.sort((a, b) => a.name.localeCompare(b.name)); await fs.mkdir(path.dirname(output), { recursive: true }); await fs.writeFile(output, makeHtml(colors), "utf8"); console.log(`Wrote ${output}`); console.log(`Found ${colors.length} colors.`);