dembrandt 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -15
- package/dist/index.d.ts +8 -0
- package/dist/index.js +392 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/colors.d.ts +101 -0
- package/dist/lib/colors.js +405 -0
- package/dist/lib/colors.js.map +1 -0
- package/dist/lib/discovery.d.ts +31 -0
- package/dist/lib/discovery.js +243 -0
- package/dist/lib/discovery.js.map +1 -0
- package/dist/lib/dtcg/validate.d.ts +51 -0
- package/dist/lib/dtcg/validate.js +1403 -0
- package/dist/lib/dtcg/validate.js.map +1 -0
- package/dist/lib/extractors/breakpoints.d.ts +5 -0
- package/dist/lib/extractors/breakpoints.js +450 -0
- package/dist/lib/extractors/breakpoints.js.map +1 -0
- package/dist/lib/extractors/colors.d.ts +2 -0
- package/dist/lib/extractors/colors.js +606 -0
- package/dist/lib/extractors/colors.js.map +1 -0
- package/dist/lib/extractors/components.d.ts +4 -0
- package/dist/lib/extractors/components.js +370 -0
- package/dist/lib/extractors/components.js.map +1 -0
- package/dist/lib/extractors/index.d.ts +9 -0
- package/dist/lib/extractors/index.js +1095 -0
- package/dist/lib/extractors/index.js.map +1 -0
- package/dist/lib/extractors/logo.d.ts +2 -0
- package/dist/lib/extractors/logo.js +626 -0
- package/dist/lib/extractors/logo.js.map +1 -0
- package/dist/lib/extractors/spacing.d.ts +4 -0
- package/dist/lib/extractors/spacing.js +162 -0
- package/dist/lib/extractors/spacing.js.map +1 -0
- package/dist/lib/extractors/typography.d.ts +1 -0
- package/dist/lib/extractors/typography.js +163 -0
- package/dist/lib/extractors/typography.js.map +1 -0
- package/dist/lib/formatters/dtcg.d.ts +10 -0
- package/dist/lib/formatters/dtcg.js +416 -0
- package/dist/lib/formatters/dtcg.js.map +1 -0
- package/dist/lib/formatters/markdown.d.ts +5 -0
- package/dist/lib/formatters/markdown.js +568 -0
- package/dist/lib/formatters/markdown.js.map +1 -0
- package/dist/lib/formatters/pdf.d.ts +12 -0
- package/dist/lib/formatters/pdf.js +1117 -0
- package/dist/lib/formatters/pdf.js.map +1 -0
- package/dist/lib/formatters/terminal.d.ts +6 -0
- package/dist/lib/formatters/terminal.js +954 -0
- package/dist/lib/formatters/terminal.js.map +1 -0
- package/dist/lib/formatters/theme.d.ts +35 -0
- package/{lib → dist/lib}/formatters/theme.js +15 -16
- package/dist/lib/formatters/theme.js.map +1 -0
- package/dist/lib/merger.d.ts +14 -0
- package/dist/lib/merger.js +362 -0
- package/dist/lib/merger.js.map +1 -0
- package/dist/lib/normalize.d.ts +28 -0
- package/dist/lib/normalize.js +55 -0
- package/dist/lib/normalize.js.map +1 -0
- package/dist/lib/robots.d.ts +12 -0
- package/dist/lib/robots.js +110 -0
- package/dist/lib/robots.js.map +1 -0
- package/dist/lib/types.d.ts +319 -0
- package/dist/lib/types.js +7 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/version.d.ts +126 -0
- package/dist/lib/version.js +145 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.js +249 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/package.json +78 -0
- package/dist/test/_vitest-shim.d.ts +13 -0
- package/dist/test/_vitest-shim.js +23 -0
- package/dist/test/_vitest-shim.js.map +1 -0
- package/dist/test/cli.test.d.ts +1 -0
- package/dist/test/cli.test.js +24 -0
- package/dist/test/cli.test.js.map +1 -0
- package/dist/test/colors.test.d.ts +1 -0
- package/dist/test/colors.test.js +64 -0
- package/dist/test/colors.test.js.map +1 -0
- package/dist/test/dtcg-validate.test.d.ts +1 -0
- package/dist/test/dtcg-validate.test.js +2129 -0
- package/dist/test/dtcg-validate.test.js.map +1 -0
- package/dist/test/markdown.test.d.ts +1 -0
- package/dist/test/markdown.test.js +145 -0
- package/dist/test/markdown.test.js.map +1 -0
- package/dist/test/normalize.test.d.ts +1 -0
- package/dist/test/normalize.test.js +45 -0
- package/dist/test/normalize.test.js.map +1 -0
- package/dist/test/version.test.d.ts +1 -0
- package/dist/test/version.test.js +73 -0
- package/dist/test/version.test.js.map +1 -0
- package/package.json +35 -17
- package/index.js +0 -367
- package/lib/colors.js +0 -336
- package/lib/discovery.js +0 -247
- package/lib/extractors/breakpoints.js +0 -432
- package/lib/extractors/colors.js +0 -572
- package/lib/extractors/components.js +0 -368
- package/lib/extractors/index.js +0 -1051
- package/lib/extractors/logo.js +0 -602
- package/lib/extractors/spacing.js +0 -178
- package/lib/extractors/typography.js +0 -173
- package/lib/formatters/markdown.js +0 -591
- package/lib/formatters/pdf.js +0 -975
- package/lib/formatters/terminal.js +0 -1085
- package/lib/formatters/w3c.js +0 -497
- package/lib/merger.js +0 -364
- package/lib/robots.js +0 -101
- package/lib/types.js +0 -204
- package/mcp-server.js +0 -321
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Requires Node.js 18+
|
|
|
25
25
|
Use Dembrandt as a tool in Claude Code, Cursor, Windsurf, or any MCP-compatible client. Ask your agent to "extract the color palette from example.com" and it calls Dembrandt automatically.
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
claude mcp add --transport stdio dembrandt -- npx -y dembrandt-mcp
|
|
28
|
+
claude mcp add --transport stdio dembrandt -- npx -y --package dembrandt dembrandt-mcp
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Or add to your project's `.mcp.json`:
|
|
@@ -35,7 +35,7 @@ Or add to your project's `.mcp.json`:
|
|
|
35
35
|
"mcpServers": {
|
|
36
36
|
"dembrandt": {
|
|
37
37
|
"command": "npx",
|
|
38
|
-
"args": ["-y", "dembrandt-mcp"]
|
|
38
|
+
"args": ["-y", "--package", "dembrandt", "dembrandt-mcp"]
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -57,7 +57,7 @@ Load extractions, track token drift, and compare snapshots. **[dembrandt.com/app
|
|
|
57
57
|
* **Visual diff.** Color swatches, before/after values, delta scores per category.
|
|
58
58
|
* **Snapshot history.** GitHub-style calendar per domain.
|
|
59
59
|
* **Copy tokens.** Paste values straight into Copilot, Claude, or Cursor.
|
|
60
|
-
* **No login.** Your data stays in the browser
|
|
60
|
+
* **No login.** Your data stays in the browser. Drift is computed locally — nothing is sent to any server.
|
|
61
61
|
|
|
62
62
|
## Recipes
|
|
63
63
|
|
|
@@ -145,7 +145,7 @@ dembrandt example.com --browser=firefox --save-output --dtcg
|
|
|
145
145
|
Firefox browser is installed automatically with `npm install`. If you need to install manually:
|
|
146
146
|
|
|
147
147
|
```bash
|
|
148
|
-
npx playwright install firefox
|
|
148
|
+
npx playwright@$(node -p "require('playwright-core/package.json').version") install firefox
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
### W3C Design Tokens (DTCG) Format
|
|
@@ -175,7 +175,7 @@ DESIGN.md reports only what Dembrandt observed on the source site. Exact values
|
|
|
175
175
|
Use `--wcag` to check accessibility contrast ratios across the page. Unlike palette-based checkers, dembrandt walks the actual DOM and finds what color is rendered on top of what background — per element.
|
|
176
176
|
|
|
177
177
|
```bash
|
|
178
|
-
dembrandt
|
|
178
|
+
dembrandt dembrandt.com --wcag
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
Returns every text/background pair with contrast ratio and WCAG 2.1 grade (AA, AA-Large, AAA, or fail), sorted by how often each pair appears. Results are shown in terminal and included in JSON output as `wcag`.
|
|
@@ -187,7 +187,7 @@ Also captures **interactive state contrast**: dembrandt simulates hover, focus,
|
|
|
187
187
|
Motion tokens are extracted automatically on every run — no flag needed. Dembrandt analyzes CSS transitions and animations across the page and returns a structured motion profile.
|
|
188
188
|
|
|
189
189
|
```bash
|
|
190
|
-
dembrandt
|
|
190
|
+
dembrandt dembrandt.com
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
Returns:
|
|
@@ -207,51 +207,66 @@ dembrandt example.com --brand-guide
|
|
|
207
207
|
# Saves to: output/example.com/TIMESTAMP.brand-guide.pdf
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
+
## Continuous integration
|
|
211
|
+
|
|
212
|
+
Dembrandt drives a real browser, so the browser revision must match `playwright-core`.
|
|
213
|
+
|
|
214
|
+
If you are not using the Playwright container image, install the browser revision that matches `playwright-core`:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# in dembrandt's own repo
|
|
218
|
+
npm run install-browser
|
|
219
|
+
# elsewhere — derive the version so it always matches
|
|
220
|
+
npx playwright@$(node -p "require('playwright-core/package.json').version") install --with-deps chromium
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
A mismatched version fails with "Executable doesn't exist". The container image avoids this entirely — just match its tag (`v1.60.0`) to the `playwright-core` version.
|
|
224
|
+
|
|
210
225
|
## Recipes
|
|
211
226
|
|
|
212
227
|
**Quick brand scan**
|
|
213
228
|
```bash
|
|
214
|
-
dembrandt
|
|
229
|
+
dembrandt dembrandt.com
|
|
215
230
|
```
|
|
216
231
|
|
|
217
232
|
**Compare two sites**
|
|
218
233
|
```bash
|
|
219
|
-
dembrandt
|
|
234
|
+
dembrandt dembrandt.com --save-output
|
|
220
235
|
dembrandt braintree.com --save-output
|
|
221
|
-
# Compare output/
|
|
236
|
+
# Compare output/dembrandt.com and output/braintree.com side by side
|
|
222
237
|
```
|
|
223
238
|
|
|
224
239
|
**Multi-page audit** — get a fuller picture across the whole site
|
|
225
240
|
```bash
|
|
226
|
-
dembrandt
|
|
241
|
+
dembrandt dembrandt.com --crawl 10 --sitemap --save-output
|
|
227
242
|
```
|
|
228
243
|
|
|
229
244
|
**Spot-check a value** — verify a specific token fast
|
|
230
245
|
```bash
|
|
231
|
-
dembrandt
|
|
246
|
+
dembrandt dembrandt.com --json-only | grep -i "border-radius"
|
|
232
247
|
```
|
|
233
248
|
|
|
234
249
|
**Export for Tailwind** — get spacing and color values into your config
|
|
235
250
|
```bash
|
|
236
|
-
dembrandt
|
|
251
|
+
dembrandt dembrandt.com --dtcg --save-output
|
|
237
252
|
# Use the .tokens.json with Style Dictionary to generate tailwind.config.js
|
|
238
253
|
```
|
|
239
254
|
|
|
240
255
|
**Export for Tokens Studio / Figma**
|
|
241
256
|
```bash
|
|
242
|
-
dembrandt
|
|
257
|
+
dembrandt dembrandt.com --dtcg --save-output
|
|
243
258
|
# Import the .tokens.json directly into Tokens Studio
|
|
244
259
|
```
|
|
245
260
|
|
|
246
261
|
**Generate DESIGN.md for your AI agent**
|
|
247
262
|
```bash
|
|
248
|
-
dembrandt
|
|
263
|
+
dembrandt dembrandt.com --design-md
|
|
249
264
|
# Point your agent at the output DESIGN.md
|
|
250
265
|
```
|
|
251
266
|
|
|
252
267
|
**Accessibility audit** — check contrast on any live URL
|
|
253
268
|
```bash
|
|
254
|
-
dembrandt
|
|
269
|
+
dembrandt dembrandt.com --wcag
|
|
255
270
|
```
|
|
256
271
|
|
|
257
272
|
**Regression baseline** — snapshot now, catch drift later
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Dembrandt - Design Token Extraction CLI
|
|
4
|
+
*
|
|
5
|
+
* Extracts design tokens, brand colors, typography, spacing, and component styles
|
|
6
|
+
* from any website using Playwright.
|
|
7
|
+
*/
|
|
8
|
+
import { program } from "commander";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
import { chromium, firefox } from "playwright-core";
|
|
12
|
+
import { extractBranding } from "./lib/extractors/index.js";
|
|
13
|
+
import { displayResults } from "./lib/formatters/terminal.js";
|
|
14
|
+
import { color } from "./lib/formatters/theme.js";
|
|
15
|
+
import { toDtcgTokens } from "./lib/formatters/dtcg.js";
|
|
16
|
+
import { generatePDF } from "./lib/formatters/pdf.js";
|
|
17
|
+
import { generateDesignMd } from "./lib/formatters/markdown.js";
|
|
18
|
+
import { parseSitemap } from "./lib/discovery.js";
|
|
19
|
+
import { mergeResults } from "./lib/merger.js";
|
|
20
|
+
import { writeFileSync, mkdirSync, readFileSync } from "fs";
|
|
21
|
+
import { join, dirname } from "path";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
import { checkRobotsTxt } from "./lib/robots.js";
|
|
24
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const { version } = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8"));
|
|
26
|
+
/**
|
|
27
|
+
* ora options for a spinner on the given stream. The spinner animates only on
|
|
28
|
+
* a real interactive terminal: a non-TTY (piped) or CI environment gets the
|
|
29
|
+
* final status lines without the frame churn that garbles logs. Some CI runners
|
|
30
|
+
* allocate a pseudo-TTY, so we check CI explicitly rather than rely on isTTY.
|
|
31
|
+
*/
|
|
32
|
+
function spinnerOptions(useStderr = false) {
|
|
33
|
+
const stream = useStderr ? process.stderr : process.stdout;
|
|
34
|
+
return { stream, isEnabled: Boolean(stream.isTTY) && !process.env.CI };
|
|
35
|
+
}
|
|
36
|
+
program
|
|
37
|
+
.name("dembrandt")
|
|
38
|
+
.description("Extract design tokens from any website.")
|
|
39
|
+
.version(version)
|
|
40
|
+
.enablePositionalOptions()
|
|
41
|
+
.argument("<url>")
|
|
42
|
+
.argument("[paths...]", "Additional paths on the same domain to extract and merge, e.g. /pricing /docs")
|
|
43
|
+
.option("--browser <type>", "Browser to use (chromium|firefox); set BROWSER_CDP_ENDPOINT env var to connect to an existing Chromium instance via CDP", "chromium")
|
|
44
|
+
.option("--json-only", "Output raw JSON")
|
|
45
|
+
.option("--save-output", "Save JSON file to output folder")
|
|
46
|
+
.option("--dtcg", "Export in W3C Design Tokens (DTCG) format")
|
|
47
|
+
.option("--dark-mode", "Extract colors from dark mode")
|
|
48
|
+
.option("--mobile", "Extract from mobile viewport")
|
|
49
|
+
.option("--slow", "3x longer timeouts for slow-loading sites")
|
|
50
|
+
.option("--brand-guide", "Export a brand guide PDF")
|
|
51
|
+
.option("--design-md", "Export a DESIGN.md file")
|
|
52
|
+
.option("--no-sandbox", "Disable browser sandbox (needed for Docker/CI)")
|
|
53
|
+
.option("--raw-colors", "Include pre-filter raw colors in JSON output")
|
|
54
|
+
.option("--screenshot <path>", "Save a viewport screenshot of the page (not full-page)")
|
|
55
|
+
.option("--wcag", "Analyze WCAG contrast ratios between palette colors")
|
|
56
|
+
.option("--crawl [n]", "Auto-discover and extract up to N pages via DOM links (default: 5); combine with --sitemap to use sitemap discovery instead", (v) => {
|
|
57
|
+
if (v === undefined || v === true)
|
|
58
|
+
return 5;
|
|
59
|
+
const n = parseInt(v, 10);
|
|
60
|
+
if (isNaN(n) || n < 1)
|
|
61
|
+
throw new Error(`--crawl must be a positive integer, got: ${v}`);
|
|
62
|
+
return n;
|
|
63
|
+
})
|
|
64
|
+
.option("--sitemap", "Discover pages from sitemap.xml instead of DOM links; use alone or combine with --crawl to set page limit")
|
|
65
|
+
.option("--cookie <string>", "Cookie string for authenticated pages, e.g. \"session=abc; token=xyz\"")
|
|
66
|
+
.option("--header <string>", "Extra HTTP header, e.g. \"Authorization: Bearer eyJ...\"")
|
|
67
|
+
.option("--stealth", "Enable anti-detection: navigator spoofing, human mouse simulation, randomized fingerprint (use only when authorized)")
|
|
68
|
+
.option("--user-agent <string>", "Custom user agent string")
|
|
69
|
+
.option("--locale <string>", "Browser locale for fingerprint, e.g. en-GB, fi-FI; affects content only if the site reacts to Accept-Language (default: en-US)")
|
|
70
|
+
.option("--timezone <string>", "Browser timezone for fingerprint, e.g. Europe/Helsinki; affects content only if the site reacts to timezone (default: America/New_York)")
|
|
71
|
+
.option("--accept-language <string>", "Custom Accept-Language header value")
|
|
72
|
+
.option("--screen-size <WxH>", "Physical screen resolution to report, e.g. 1920x1080 (default: 1920x1080)")
|
|
73
|
+
.action(async (input, paths, opts) => {
|
|
74
|
+
let url = input;
|
|
75
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
76
|
+
url = "https://" + url;
|
|
77
|
+
}
|
|
78
|
+
// In --json-only mode, redirect all status output to stderr so stdout is clean JSON
|
|
79
|
+
const originalConsoleLog = console.log;
|
|
80
|
+
if (opts.jsonOnly) {
|
|
81
|
+
console.log = (...args) => console.error(...args);
|
|
82
|
+
}
|
|
83
|
+
const spinner = ora({ text: "Starting extraction...", ...spinnerOptions(opts.jsonOnly) }).start();
|
|
84
|
+
try {
|
|
85
|
+
const robots = await checkRobotsTxt(url);
|
|
86
|
+
if (robots.status === "ok" && robots.allowed === false) {
|
|
87
|
+
spinner.warn(chalk.hex("#FFB86C")(`robots.txt disallows this path (rule: "${robots.rule}"). Proceeding anyway — respect the site's terms.`));
|
|
88
|
+
spinner.start("Starting extraction...");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// robots check is advisory; never block extraction
|
|
93
|
+
}
|
|
94
|
+
let browser = null;
|
|
95
|
+
try {
|
|
96
|
+
let useHeaded = false;
|
|
97
|
+
let result;
|
|
98
|
+
while (true) {
|
|
99
|
+
// Select browser type based on --browser flag
|
|
100
|
+
const browserType = opts.browser === 'firefox' ? firefox : chromium;
|
|
101
|
+
spinner.text = `Launching browser (${useHeaded ? "visible" : "headless"} mode)`;
|
|
102
|
+
// Firefox-specific launch args (Firefox doesn't support Chromium flags)
|
|
103
|
+
const launchArgs = opts.browser === 'firefox'
|
|
104
|
+
? [] // Firefox has different flags
|
|
105
|
+
: ["--disable-blink-features=AutomationControlled"];
|
|
106
|
+
if (opts.noSandbox && opts.browser === 'chromium') {
|
|
107
|
+
launchArgs.push("--no-sandbox", "--disable-setuid-sandbox");
|
|
108
|
+
}
|
|
109
|
+
if (process.env.BROWSER_CDP_ENDPOINT) {
|
|
110
|
+
if (opts.browser !== 'chromium') {
|
|
111
|
+
throw new Error("BROWSER_CDP_ENDPOINT is only supported with --browser chromium.");
|
|
112
|
+
}
|
|
113
|
+
spinner.text = "Connecting over CDP...";
|
|
114
|
+
browser = await browserType.connectOverCDP(process.env.BROWSER_CDP_ENDPOINT);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
browser = await browserType.launch({
|
|
118
|
+
headless: !useHeaded,
|
|
119
|
+
args: launchArgs,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const crawlN = opts.crawl ?? null;
|
|
124
|
+
const isAutoCrawl = crawlN && !opts.sitemap && (!paths || paths.length === 0);
|
|
125
|
+
const hasExplicitPaths = paths && paths.length > 0;
|
|
126
|
+
result = await extractBranding(url, spinner, browser, {
|
|
127
|
+
navigationTimeout: 90000,
|
|
128
|
+
verbose: !opts.jsonOnly,
|
|
129
|
+
darkMode: opts.darkMode,
|
|
130
|
+
mobile: opts.mobile,
|
|
131
|
+
slow: opts.slow,
|
|
132
|
+
screenshotPath: opts.screenshot,
|
|
133
|
+
discoverLinks: isAutoCrawl ? crawlN - 1 : null,
|
|
134
|
+
wcag: opts.wcag,
|
|
135
|
+
includeRawColors: opts.rawColors,
|
|
136
|
+
stealth: opts.stealth,
|
|
137
|
+
cookie: opts.cookie,
|
|
138
|
+
header: opts.header,
|
|
139
|
+
userAgent: opts.userAgent,
|
|
140
|
+
locale: opts.locale,
|
|
141
|
+
timezoneId: opts.timezone,
|
|
142
|
+
acceptLanguage: opts.acceptLanguage,
|
|
143
|
+
screenSize: opts.screenSize,
|
|
144
|
+
_version: version,
|
|
145
|
+
});
|
|
146
|
+
// Build list of additional URLs to extract
|
|
147
|
+
let additionalUrls = [];
|
|
148
|
+
if (hasExplicitPaths) {
|
|
149
|
+
// Explicit paths: resolve against base URL
|
|
150
|
+
const base = new URL(result.url);
|
|
151
|
+
additionalUrls = paths.map(p => {
|
|
152
|
+
if (p.startsWith('http'))
|
|
153
|
+
return p;
|
|
154
|
+
return `${base.protocol}//${base.host}${p.startsWith('/') ? p : '/' + p}`;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (opts.sitemap) {
|
|
158
|
+
if (!opts.jsonOnly)
|
|
159
|
+
spinner.start("Fetching sitemap...");
|
|
160
|
+
const max = crawlN ? crawlN - 1 : 20;
|
|
161
|
+
additionalUrls = await parseSitemap(result.url, max);
|
|
162
|
+
if (additionalUrls.length === 0 && result.url !== url) {
|
|
163
|
+
additionalUrls = await parseSitemap(url, max);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else if (isAutoCrawl) {
|
|
167
|
+
additionalUrls = result._discoveredLinks || [];
|
|
168
|
+
}
|
|
169
|
+
delete result._discoveredLinks;
|
|
170
|
+
if (additionalUrls.length === 0) {
|
|
171
|
+
if ((hasExplicitPaths || opts.sitemap || isAutoCrawl) && !opts.jsonOnly) {
|
|
172
|
+
spinner.warn("No additional pages discovered");
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
spinner.stop();
|
|
177
|
+
if (!opts.jsonOnly)
|
|
178
|
+
console.log(chalk.dim(` Found ${additionalUrls.length} page(s) to analyze`));
|
|
179
|
+
const allResults = [result];
|
|
180
|
+
for (let i = 0; i < additionalUrls.length; i++) {
|
|
181
|
+
const pageUrl = additionalUrls[i];
|
|
182
|
+
const pageNum = i + 2;
|
|
183
|
+
const total = additionalUrls.length + 1;
|
|
184
|
+
if (!opts.jsonOnly)
|
|
185
|
+
spinner.start(`Extracting page ${pageNum}/${total}: ${new URL(pageUrl).pathname}`);
|
|
186
|
+
await new Promise(r => setTimeout(r, 1500 + Math.random() * 1500));
|
|
187
|
+
try {
|
|
188
|
+
const pageResult = await extractBranding(pageUrl, spinner, browser, {
|
|
189
|
+
navigationTimeout: 90000,
|
|
190
|
+
verbose: !opts.jsonOnly,
|
|
191
|
+
darkMode: opts.darkMode,
|
|
192
|
+
mobile: opts.mobile,
|
|
193
|
+
slow: opts.slow,
|
|
194
|
+
stealth: opts.stealth,
|
|
195
|
+
userAgent: opts.userAgent,
|
|
196
|
+
locale: opts.locale,
|
|
197
|
+
timezoneId: opts.timezone,
|
|
198
|
+
acceptLanguage: opts.acceptLanguage,
|
|
199
|
+
});
|
|
200
|
+
delete pageResult._discoveredLinks;
|
|
201
|
+
allResults.push(pageResult);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
if (!opts.jsonOnly)
|
|
205
|
+
spinner.warn(`Skipping ${pageUrl}: ${String(err?.message || err).slice(0, 80)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
spinner.stop();
|
|
209
|
+
result = mergeResults(allResults);
|
|
210
|
+
}
|
|
211
|
+
if (!hasExplicitPaths && !opts.sitemap && !isAutoCrawl) {
|
|
212
|
+
delete result._discoveredLinks;
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
await browser.close();
|
|
218
|
+
browser = null;
|
|
219
|
+
if (useHeaded || process.env.BROWSER_CDP_ENDPOINT)
|
|
220
|
+
throw err;
|
|
221
|
+
if (err.message.includes("Timeout") ||
|
|
222
|
+
err.message.includes("net::ERR_")) {
|
|
223
|
+
spinner.warn("Navigation failed → retrying with visible browser");
|
|
224
|
+
console.error(chalk.dim(` ↳ Error: ${err.message}`));
|
|
225
|
+
console.error(chalk.dim(` ↳ URL: ${url}`));
|
|
226
|
+
console.error(chalk.dim(` ↳ Mode: headless`));
|
|
227
|
+
useHeaded = true;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
console.log();
|
|
234
|
+
// Strip raw colors unless --raw-colors flag is set
|
|
235
|
+
if (!opts.rawColors && result.colors && result.colors.rawColors) {
|
|
236
|
+
delete result.colors.rawColors;
|
|
237
|
+
}
|
|
238
|
+
// Convert to W3C format if requested
|
|
239
|
+
const outputData = opts.dtcg ? toDtcgTokens(result) : result;
|
|
240
|
+
// Collect "saved to" notices and print them after the results below
|
|
241
|
+
const savedNotices = [];
|
|
242
|
+
// Save JSON output if --save-output or --dtcg is specified
|
|
243
|
+
if (opts.saveOutput || opts.dtcg) {
|
|
244
|
+
try {
|
|
245
|
+
const domain = new URL(url).hostname.replace("www.", "");
|
|
246
|
+
const timestamp = new Date()
|
|
247
|
+
.toISOString()
|
|
248
|
+
.replace(/[:.]/g, "-")
|
|
249
|
+
.split(".")[0];
|
|
250
|
+
// Save to current working directory, not installation directory
|
|
251
|
+
const outputDir = join(process.cwd(), "output", domain);
|
|
252
|
+
mkdirSync(outputDir, { recursive: true });
|
|
253
|
+
const suffix = opts.dtcg ? '.tokens' : '';
|
|
254
|
+
const filename = `${timestamp}_v${version}${suffix}.json`;
|
|
255
|
+
const filepath = join(outputDir, filename);
|
|
256
|
+
writeFileSync(filepath, JSON.stringify(outputData, null, 2));
|
|
257
|
+
const jsonLabel = opts.dtcg
|
|
258
|
+
? 'DTCG tokens saved (--dtcg)'
|
|
259
|
+
: 'JSON saved (--save-output)';
|
|
260
|
+
savedNotices.push(chalk.dim(`💾 ${jsonLabel}: ${color.info(`output/${domain}/${filename}`)}`));
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
console.log(color.warning(`! Could not save JSON file: ${err.message}`));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Generate PDF brand guide
|
|
267
|
+
if (opts.brandGuide) {
|
|
268
|
+
try {
|
|
269
|
+
const pdfDomain = new URL(url).hostname.replace("www.", "");
|
|
270
|
+
const now = new Date();
|
|
271
|
+
const pdfDate = now.toISOString().slice(0, 10);
|
|
272
|
+
const pdfTime = `${String(now.getHours()).padStart(2, '0')}-${String(now.getMinutes()).padStart(2, '0')}`;
|
|
273
|
+
const pdfDir = join(process.cwd(), "output", pdfDomain);
|
|
274
|
+
mkdirSync(pdfDir, { recursive: true });
|
|
275
|
+
const pdfFilename = `${pdfDomain}-brand-guide-${pdfDate}-${pdfTime}.pdf`;
|
|
276
|
+
const pdfPath = join(pdfDir, pdfFilename);
|
|
277
|
+
spinner.start("Generating PDF brand guide...");
|
|
278
|
+
await generatePDF(result, pdfPath, browser);
|
|
279
|
+
spinner.stop();
|
|
280
|
+
savedNotices.push(chalk.dim(`💾 Brand guide PDF saved (--brand-guide): ${color.info(`output/${pdfDomain}/${pdfFilename}`)}`));
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
spinner.stop();
|
|
284
|
+
console.log(color.warning(`Could not generate PDF: ${err.message}`));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Generate DESIGN.md
|
|
288
|
+
if (opts.designMd) {
|
|
289
|
+
try {
|
|
290
|
+
const mdDomain = new URL(url).hostname.replace("www.", "");
|
|
291
|
+
const mdDir = join(process.cwd(), "output", mdDomain);
|
|
292
|
+
mkdirSync(mdDir, { recursive: true });
|
|
293
|
+
const mdPath = join(mdDir, "DESIGN.md");
|
|
294
|
+
writeFileSync(mdPath, generateDesignMd(result));
|
|
295
|
+
savedNotices.push(chalk.dim(`💾 DESIGN.md saved (--design-md): ${color.info(`output/${mdDomain}/DESIGN.md`)}`));
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
console.log(color.warning(`Could not generate DESIGN.md: ${err.message}`));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Output to terminal
|
|
302
|
+
const summaryLine = color.accent('✨ Analysis summary: ') +
|
|
303
|
+
chalk.dim(`${result.colors?.palette?.length ?? 0} colors, ` +
|
|
304
|
+
`${result.typography?.styles?.length ?? 0} text styles, ` +
|
|
305
|
+
`${result.breakpoints?.length ?? 0} breakpoints.`);
|
|
306
|
+
if (opts.jsonOnly) {
|
|
307
|
+
console.log = originalConsoleLog;
|
|
308
|
+
console.log(JSON.stringify(outputData, null, 2));
|
|
309
|
+
console.error(summaryLine);
|
|
310
|
+
for (const notice of savedNotices)
|
|
311
|
+
console.error(notice);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
console.log();
|
|
315
|
+
displayResults(result);
|
|
316
|
+
console.log();
|
|
317
|
+
console.log(summaryLine);
|
|
318
|
+
for (const notice of savedNotices)
|
|
319
|
+
console.log(notice);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
spinner.fail("Failed");
|
|
324
|
+
console.error(chalk.red("\n✗ Extraction failed"));
|
|
325
|
+
console.error(chalk.red(` Error: ${err.message}`));
|
|
326
|
+
console.error(chalk.dim(` URL: ${url}`));
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
finally {
|
|
330
|
+
if (browser)
|
|
331
|
+
await browser.close();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
// Grouped --help for the root command. Commander 11 has no native option groups,
|
|
335
|
+
// so render them via a custom formatHelp. Subcommands keep a single flat list.
|
|
336
|
+
const OPTION_GROUPS = [
|
|
337
|
+
["Extraction", ["--dark-mode", "--mobile", "--slow", "--crawl", "--sitemap", "--browser"]],
|
|
338
|
+
["Output & export", ["--json-only", "--save-output", "--dtcg", "--brand-guide", "--design-md", "--screenshot", "--raw-colors"]],
|
|
339
|
+
["Analysis", ["--wcag"]],
|
|
340
|
+
["Network & auth", ["--cookie", "--header", "--user-agent", "--locale", "--timezone", "--accept-language", "--screen-size"]],
|
|
341
|
+
["Anti-detection", ["--stealth", "--no-sandbox"]],
|
|
342
|
+
];
|
|
343
|
+
program.configureHelp({
|
|
344
|
+
formatHelp(cmd, helper) {
|
|
345
|
+
const helpWidth = helper.helpWidth ?? 80;
|
|
346
|
+
const termWidth = helper.padWidth(cmd, helper);
|
|
347
|
+
const indent = 2;
|
|
348
|
+
const item = (term, desc) => {
|
|
349
|
+
if (!desc)
|
|
350
|
+
return term;
|
|
351
|
+
const full = `${term.padEnd(termWidth + 2)}${desc}`;
|
|
352
|
+
return helper.wrap(full, helpWidth - indent, termWidth + 2);
|
|
353
|
+
};
|
|
354
|
+
const block = (lines) => lines.map((l) => " ".repeat(indent) + l).join("\n");
|
|
355
|
+
const out = [`Usage: ${helper.commandUsage(cmd)}`, ""];
|
|
356
|
+
const description = helper.commandDescription(cmd);
|
|
357
|
+
if (description)
|
|
358
|
+
out.push(description, "");
|
|
359
|
+
const args = helper.visibleArguments(cmd);
|
|
360
|
+
if (args.length) {
|
|
361
|
+
out.push("Arguments:", block(args.map((a) => item(helper.argumentTerm(a), helper.argumentDescription(a)))), "");
|
|
362
|
+
}
|
|
363
|
+
const options = helper.visibleOptions(cmd);
|
|
364
|
+
if (options.length) {
|
|
365
|
+
if (cmd.parent) {
|
|
366
|
+
out.push("Options:", block(options.map((o) => item(helper.optionTerm(o), helper.optionDescription(o)))), "");
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
const byLong = new Map(options.map((o) => [o.long ?? o.short, o]));
|
|
370
|
+
const used = new Set();
|
|
371
|
+
for (const [title, flags] of OPTION_GROUPS) {
|
|
372
|
+
const groupOpts = flags.map((f) => byLong.get(f)).filter(Boolean);
|
|
373
|
+
if (!groupOpts.length)
|
|
374
|
+
continue;
|
|
375
|
+
groupOpts.forEach((o) => used.add(o));
|
|
376
|
+
out.push(`${title}:`, block(groupOpts.map((o) => item(helper.optionTerm(o), helper.optionDescription(o)))), "");
|
|
377
|
+
}
|
|
378
|
+
const rest = options.filter((o) => !used.has(o));
|
|
379
|
+
if (rest.length) {
|
|
380
|
+
out.push("General:", block(rest.map((o) => item(helper.optionTerm(o), helper.optionDescription(o)))), "");
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const commands = helper.visibleCommands(cmd);
|
|
385
|
+
if (commands.length) {
|
|
386
|
+
out.push("Commands:", block(commands.map((c) => item(helper.subcommandTerm(c), helper.subcommandDescription(c)))), "");
|
|
387
|
+
}
|
|
388
|
+
return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
program.parse();
|
|
392
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Conversion Utilities
|
|
3
|
+
*
|
|
4
|
+
* Converts colors between RGB, LCH, and OKLCH color spaces.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Convert RGB to LCH
|
|
8
|
+
* @param {number} r - Red (0-255)
|
|
9
|
+
* @param {number} g - Green (0-255)
|
|
10
|
+
* @param {number} b - Blue (0-255)
|
|
11
|
+
* @returns {{ l: number, c: number, h: number }}
|
|
12
|
+
*/
|
|
13
|
+
export declare function rgbToLch(r: any, g: any, b: any): {
|
|
14
|
+
l: any;
|
|
15
|
+
c: number;
|
|
16
|
+
h: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Convert RGB to OKLCH
|
|
20
|
+
* @param {number} r - Red (0-255)
|
|
21
|
+
* @param {number} g - Green (0-255)
|
|
22
|
+
* @param {number} b - Blue (0-255)
|
|
23
|
+
* @returns {{ l: number, c: number, h: number }}
|
|
24
|
+
*/
|
|
25
|
+
export declare function rgbToOklch(r: any, g: any, b: any): {
|
|
26
|
+
l: any;
|
|
27
|
+
c: number;
|
|
28
|
+
h: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Format LCH values as CSS lch() string
|
|
32
|
+
* @param {{ l: number, c: number, h: number }} lch
|
|
33
|
+
* @param {number} [alpha] - Optional alpha value (0-1)
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatLch(lch: any, alpha: any): string;
|
|
37
|
+
/**
|
|
38
|
+
* Format OKLCH values as CSS oklch() string
|
|
39
|
+
* @param {{ l: number, c: number, h: number }} oklch
|
|
40
|
+
* @param {number} [alpha] - Optional alpha value (0-1)
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatOklch(oklch: any, alpha: any): string;
|
|
44
|
+
/**
|
|
45
|
+
* Compute CIE76 delta-E perceptual distance between two hex colors.
|
|
46
|
+
* Returns 0 for identical colors, ~100 for maximally different.
|
|
47
|
+
* @param {string} hex1 - Hex color string (e.g. "#ff0000")
|
|
48
|
+
* @param {string} hex2 - Hex color string
|
|
49
|
+
* @returns {number}
|
|
50
|
+
*/
|
|
51
|
+
export declare function deltaE(hex1: any, hex2: any): number;
|
|
52
|
+
/**
|
|
53
|
+
* Perceptual color distance using CIEDE2000 — the accurate successor to the
|
|
54
|
+
* CIE76 Euclidean distance in deltaE(). Accepts hex or rgb()/rgba() strings.
|
|
55
|
+
* Returns 0 for identical inputs and 100 when either color cannot be parsed.
|
|
56
|
+
* A just-noticeable difference is ~2.3.
|
|
57
|
+
* @param {string} c1
|
|
58
|
+
* @param {string} c2
|
|
59
|
+
* @returns {number}
|
|
60
|
+
*/
|
|
61
|
+
export declare function deltaE2000(c1: any, c2: any): number;
|
|
62
|
+
/**
|
|
63
|
+
* Parse a hex color string and return RGB values
|
|
64
|
+
* @param {string} hex - Hex color (#fff, #ffffff, #ffffffaa)
|
|
65
|
+
* @returns {{ r: number, g: number, b: number, a?: number } | null}
|
|
66
|
+
*/
|
|
67
|
+
export declare function hexToRgb(hex: any): {
|
|
68
|
+
r: number;
|
|
69
|
+
g: number;
|
|
70
|
+
b: number;
|
|
71
|
+
a?: undefined;
|
|
72
|
+
} | {
|
|
73
|
+
r: number;
|
|
74
|
+
g: number;
|
|
75
|
+
b: number;
|
|
76
|
+
a: number;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Compute WCAG 2.1 relative luminance for a hex color.
|
|
80
|
+
* @param {string} hex
|
|
81
|
+
* @returns {number|null}
|
|
82
|
+
*/
|
|
83
|
+
export declare function relativeLuminance(hex: any): number;
|
|
84
|
+
/**
|
|
85
|
+
* Compute WCAG contrast ratios for all pairs in a color palette.
|
|
86
|
+
* @param {Array<{color: string, normalized: string, confidence: string}>} palette
|
|
87
|
+
* @returns {Array<{fg: string, bg: string, ratio: number, aa: boolean, aaLarge: boolean, aaa: boolean}>}
|
|
88
|
+
*/
|
|
89
|
+
export declare function computeWcag(palette: any): any[];
|
|
90
|
+
/**
|
|
91
|
+
* Convert any supported color format to all formats
|
|
92
|
+
* @param {string} colorString - Color in hex, rgb(), or rgba() format
|
|
93
|
+
* @returns {{ hex: string, rgb: string, lch: string, oklch: string, hasAlpha: boolean } | null}
|
|
94
|
+
*/
|
|
95
|
+
export declare function convertColor(colorString: any): {
|
|
96
|
+
hex: string;
|
|
97
|
+
rgb: string;
|
|
98
|
+
lch: string;
|
|
99
|
+
oklch: string;
|
|
100
|
+
hasAlpha: boolean;
|
|
101
|
+
};
|