mirror of
https://github.com/Manavarya09/design-extract.git
synced 2026-09-19 02:41:14 +08:00
48b92c794b
Reliability fixes that restore trust on real sites: - colors.js: brand-color detection rewritten — ranks chromatic clusters by interactiveBg x100 + saturation x2 + log(usage), requires HSL sat >25 or an interactive-bg hit. Linear primary: #d0d6e0 (gray) -> #e4f222 (lime). Stripe: #533afd. Verified on 5 ground-truth sites. - accessibility.js + crawler.js: crawler now emits hasText per element (direct text-node child with visible chars); WCAG extractor filters decorative glyph spans, transparent overlays, non-text containers. Linear: 25% (171 failing pairs) -> 83% (1 failing pair). - scoring.js: rubric recalibrated against Stripe/Linear/Vercel/GitHub/Apple. Loosened color/shadow/radii/type-scale thresholds; softened spacing no-base penalty when tokenization is present; cssHealth now weighted in the overall. Linear 47->76, Stripe 81->88, Apple 83->86. New CLI flags: - --selector <css>: scope extraction to a DOM subtree. Stripe: 2409 -> 112 elements when scoped to footer. Falls back to full doc if invalid. - --system-chrome: channel: 'chrome' in Playwright launch; skips the bundled Chromium download. - --json: full extraction to stdout (already partial in v7, now first-class and documented). New distribution surfaces (each publishes to its own registry): - vscode-extension/: Extract-from-URL + inject-into-workspace commands. - raycast-extension/: Extract, Score, Copy-CLI commands. - figma-plugin/: URL or paste-JSON -> Figma Variables with multi-mode. - github-action/: "Design regression guard" runs designlang on PRs, diffs tokens vs baseline, comments the delta, optional fail-on-change. - smithery.yaml + smithery.dockerfile + docs/MCP-REGISTRY.md: MCP registry submission checklist. - chrome-extension/PRIVACY.md + STORE_LISTING.md: Chrome/Firefox/Edge store listing prep (extension code already existed in v7.1). - docs/LAUNCH.md: PH + Show HN + Twitter copy + day-of checklist. - docs/demo.tape: VHS tape for the animated README hero. README updated: hero references demo.gif with PNG fallback, adds "Install everywhere" table for the new surfaces, documents the three new flags. .npmignore excludes every companion-surface directory so the npm tarball stays 109KB / 73 files. All 275 tests pass.
82 lines
2.3 KiB
JavaScript
82 lines
2.3 KiB
JavaScript
#!/usr/bin/env node
|
|
// Minimal diff for DTCG-shaped (and legacy) design-tokens.json files.
|
|
// Usage: node diff-tokens.js <baseline.json> <new.json>
|
|
//
|
|
// Emits markdown to stdout. Each `- {path}: {from} → {to}` line is one changed
|
|
// token; the action's outputs key off these lines.
|
|
|
|
const { readFileSync } = require('fs');
|
|
|
|
function load(p) {
|
|
try { return JSON.parse(readFileSync(p, 'utf8')); }
|
|
catch (e) { console.error(`Failed to read ${p}: ${e.message}`); process.exit(0); }
|
|
}
|
|
|
|
// DTCG leaves are `{ "$value": ..., "$type": ... }`. Legacy leaves are strings
|
|
// or primitives. Normalise into a flat `{ path: value }` map.
|
|
function flatten(node, path, out) {
|
|
if (node == null) return;
|
|
if (typeof node !== 'object') {
|
|
out[path] = node;
|
|
return;
|
|
}
|
|
if ('$value' in node && (typeof node.$value !== 'object' || node.$value === null)) {
|
|
out[path] = node.$value;
|
|
return;
|
|
}
|
|
if (Array.isArray(node)) {
|
|
out[path] = JSON.stringify(node);
|
|
return;
|
|
}
|
|
for (const key of Object.keys(node)) {
|
|
if (key.startsWith('$')) continue;
|
|
flatten(node[key], path ? `${path}.${key}` : key, out);
|
|
}
|
|
}
|
|
|
|
const [baselinePath, newPath] = process.argv.slice(2);
|
|
const baseline = load(baselinePath);
|
|
const next = load(newPath);
|
|
|
|
const a = {};
|
|
const b = {};
|
|
flatten(baseline, '', a);
|
|
flatten(next, '', b);
|
|
|
|
const added = [];
|
|
const removed = [];
|
|
const changed = [];
|
|
|
|
for (const k of Object.keys(b)) {
|
|
if (!(k in a)) added.push([k, b[k]]);
|
|
else if (a[k] !== b[k]) changed.push([k, a[k], b[k]]);
|
|
}
|
|
for (const k of Object.keys(a)) {
|
|
if (!(k in b)) removed.push([k, a[k]]);
|
|
}
|
|
|
|
const total = added.length + removed.length + changed.length;
|
|
|
|
if (total === 0) {
|
|
console.log('**No design token changes** — the extracted design matches the baseline.');
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log(`**${total} token changes** vs baseline (${changed.length} changed, ${added.length} added, ${removed.length} removed).`);
|
|
console.log('');
|
|
if (changed.length) {
|
|
console.log('#### Changed');
|
|
for (const [k, from, to] of changed) console.log(`- \`${k}\`: \`${from}\` → \`${to}\``);
|
|
console.log('');
|
|
}
|
|
if (added.length) {
|
|
console.log('#### Added');
|
|
for (const [k, v] of added) console.log(`- \`${k}\`: \`${v}\``);
|
|
console.log('');
|
|
}
|
|
if (removed.length) {
|
|
console.log('#### Removed');
|
|
for (const [k, v] of removed) console.log(`- \`${k}\` (was \`${v}\`)`);
|
|
console.log('');
|
|
}
|