@mseep/dembrandt 0.19.5
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/LICENSE +21 -0
- package/README.md +408 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +532 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/browser.d.ts +16 -0
- package/dist/lib/browser.js +27 -0
- package/dist/lib/browser.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/compare.d.ts +31 -0
- package/dist/lib/compare.js +46 -0
- package/dist/lib/compare.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/drift.d.ts +64 -0
- package/dist/lib/drift.js +383 -0
- package/dist/lib/drift.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/exit-codes.d.ts +29 -0
- package/dist/lib/exit-codes.js +26 -0
- package/dist/lib/exit-codes.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 +657 -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 +1257 -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 +163 -0
- package/dist/lib/extractors/spacing.js.map +1 -0
- package/dist/lib/extractors/teach.d.ts +1 -0
- package/dist/lib/extractors/teach.js +66 -0
- package/dist/lib/extractors/teach.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/findings.d.ts +34 -0
- package/dist/lib/findings.js +166 -0
- package/dist/lib/findings.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/html.d.ts +25 -0
- package/dist/lib/formatters/html.js +479 -0
- package/dist/lib/formatters/html.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 +1121 -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/dist/lib/formatters/theme.js +37 -0
- 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 +29 -0
- package/dist/lib/normalize.js +59 -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/run-summary.d.ts +40 -0
- package/dist/lib/run-summary.js +64 -0
- package/dist/lib/run-summary.js.map +1 -0
- package/dist/lib/types.d.ts +329 -0
- package/dist/lib/types.js +7 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/version.d.ts +134 -0
- package/dist/lib/version.js +153 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.js +311 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/package.json +106 -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/compare.test.d.ts +1 -0
- package/dist/test/compare.test.js +57 -0
- package/dist/test/compare.test.js.map +1 -0
- package/dist/test/drift.test.d.ts +1 -0
- package/dist/test/drift.test.js +53 -0
- package/dist/test/drift.test.js.map +1 -0
- package/dist/test/dtcg-formatter.test.d.ts +1 -0
- package/dist/test/dtcg-formatter.test.js +48 -0
- package/dist/test/dtcg-formatter.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/exit-codes.test.d.ts +1 -0
- package/dist/test/exit-codes.test.js +53 -0
- package/dist/test/exit-codes.test.js.map +1 -0
- package/dist/test/findings.test.d.ts +1 -0
- package/dist/test/findings.test.js +77 -0
- package/dist/test/findings.test.js.map +1 -0
- package/dist/test/html.test.d.ts +1 -0
- package/dist/test/html.test.js +95 -0
- package/dist/test/html.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/merger.test.d.ts +1 -0
- package/dist/test/merger.test.js +98 -0
- package/dist/test/merger.test.js.map +1 -0
- package/dist/test/normalize.test.d.ts +1 -0
- package/dist/test/normalize.test.js +47 -0
- package/dist/test/normalize.test.js.map +1 -0
- package/dist/test/run-summary.test.d.ts +1 -0
- package/dist/test/run-summary.test.js +45 -0
- package/dist/test/run-summary.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 +106 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mergeResults } from '../lib/merger.js';
|
|
4
|
+
/**
|
|
5
|
+
* mergeResults feeds both the terminal display and the DTCG formatter. It is a
|
|
6
|
+
* pure function, so it is tested directly with synthetic extraction results
|
|
7
|
+
* rather than live pages. These assertions pin the union invariants: perceptual
|
|
8
|
+
* dedup, pageCount, count summation, multi-page confidence boost, homepage-wins
|
|
9
|
+
* semantics, and the pages provenance array.
|
|
10
|
+
*/
|
|
11
|
+
function page(url, overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
url,
|
|
14
|
+
extractedAt: `${url}-time`,
|
|
15
|
+
siteName: 'Test',
|
|
16
|
+
logo: { url: 'logo.svg' },
|
|
17
|
+
favicons: [],
|
|
18
|
+
colors: { palette: [], semantic: {}, cssVariables: {} },
|
|
19
|
+
typography: { styles: [], sources: {} },
|
|
20
|
+
spacing: { commonValues: [] },
|
|
21
|
+
borderRadius: { values: [] },
|
|
22
|
+
borders: { combinations: [] },
|
|
23
|
+
shadows: [],
|
|
24
|
+
gradients: [],
|
|
25
|
+
motion: { durations: [], easings: [], animations: [], contexts: {}, interactiveDeltas: [] },
|
|
26
|
+
components: { buttons: [], inputs: {}, links: [], badges: {} },
|
|
27
|
+
breakpoints: [],
|
|
28
|
+
iconSystem: [],
|
|
29
|
+
frameworks: [],
|
|
30
|
+
...overrides,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const color = (hex, count, confidence) => ({ normalized: hex, color: hex, count, confidence });
|
|
34
|
+
test('mergeResults throws on empty input', () => {
|
|
35
|
+
assert.throws(() => mergeResults([]), /No results to merge/);
|
|
36
|
+
});
|
|
37
|
+
test('mergeResults returns a single result unchanged', () => {
|
|
38
|
+
const only = page('https://a.test');
|
|
39
|
+
assert.equal(mergeResults([only]), only);
|
|
40
|
+
});
|
|
41
|
+
test('mergeResults unions palette with perceptual dedup, pageCount and count', () => {
|
|
42
|
+
const home = page('https://a.test', {
|
|
43
|
+
colors: {
|
|
44
|
+
palette: [color('#0066cc', 10, 'high'), color('#777777', 2, 'low')],
|
|
45
|
+
semantic: { primary: '#0066cc' },
|
|
46
|
+
cssVariables: {},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const second = page('https://a.test/pricing', {
|
|
50
|
+
colors: {
|
|
51
|
+
// #0166cc is within deltaE 15 of #0066cc -> collapses.
|
|
52
|
+
// #777777 repeats -> low confidence boosted by multi-page presence.
|
|
53
|
+
// #cc0000 is page-only.
|
|
54
|
+
palette: [color('#0166cc', 6, 'high'), color('#777777', 3, 'low'), color('#cc0000', 4, 'low')],
|
|
55
|
+
semantic: { primary: '#cc0000', secondary: '#00aa00' },
|
|
56
|
+
cssVariables: {},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
const merged = mergeResults([home, second]);
|
|
60
|
+
const pal = merged.colors.palette;
|
|
61
|
+
const blue = pal.find((c) => c.normalized === '#0066cc');
|
|
62
|
+
assert.ok(blue, 'near-duplicate blues collapse to the higher-count canonical');
|
|
63
|
+
assert.equal(blue.pageCount, 2);
|
|
64
|
+
assert.equal(blue.count, 16);
|
|
65
|
+
assert.equal(pal.some((c) => c.normalized === '#0166cc'), false);
|
|
66
|
+
const gray = pal.find((c) => c.normalized === '#777777');
|
|
67
|
+
assert.equal(gray.pageCount, 2);
|
|
68
|
+
assert.equal(gray.count, 5);
|
|
69
|
+
assert.equal(gray.confidence, 'medium'); // low -> medium because pageCount > 1
|
|
70
|
+
const red = pal.find((c) => c.normalized === '#cc0000');
|
|
71
|
+
assert.equal(red.pageCount, 1);
|
|
72
|
+
assert.equal(red.confidence, 'low');
|
|
73
|
+
// Homepage semantic wins; missing keys are filled from later pages.
|
|
74
|
+
assert.equal(merged.colors.semantic.primary, '#0066cc');
|
|
75
|
+
assert.equal(merged.colors.semantic.secondary, '#00aa00');
|
|
76
|
+
});
|
|
77
|
+
test('mergeResults dedupes typography by family/size/weight and sums spacing', () => {
|
|
78
|
+
const style = (family, size, weight) => ({ family, size, weight });
|
|
79
|
+
const home = page('https://a.test', {
|
|
80
|
+
typography: { styles: [style('Inter', '16px', '400')], sources: {} },
|
|
81
|
+
spacing: { commonValues: [{ px: '8px', count: 5 }] },
|
|
82
|
+
});
|
|
83
|
+
const second = page('https://a.test/x', {
|
|
84
|
+
typography: { styles: [style('Inter', '16px', '400'), style('Inter', '24px', '700')], sources: {} },
|
|
85
|
+
spacing: { commonValues: [{ px: '8px', count: 3 }, { px: '16px', count: 2 }] },
|
|
86
|
+
});
|
|
87
|
+
const merged = mergeResults([home, second]);
|
|
88
|
+
assert.equal(merged.typography.styles.length, 2);
|
|
89
|
+
const eight = merged.spacing.commonValues.find((v) => v.px === '8px');
|
|
90
|
+
assert.equal(eight.count, 8);
|
|
91
|
+
assert.ok(merged.spacing.commonValues.find((v) => v.px === '16px'));
|
|
92
|
+
});
|
|
93
|
+
test('mergeResults records per-page provenance in the pages array', () => {
|
|
94
|
+
const merged = mergeResults([page('https://a.test'), page('https://a.test/pricing')]);
|
|
95
|
+
assert.equal(merged.pages.length, 2);
|
|
96
|
+
assert.deepEqual(merged.pages.map((p) => p.url), ['https://a.test', 'https://a.test/pricing']);
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=merger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.test.js","sourceRoot":"","sources":["../../test/merger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ingest hardening: transients never persist, and loose unions canonicalize so
|
|
3
|
+
* the drift engine never compares a string weight against a number weight.
|
|
4
|
+
*/
|
|
5
|
+
import { test } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { stripTransient, normalizeExtraction } from '../lib/normalize.js';
|
|
8
|
+
const base = {
|
|
9
|
+
url: 'https://x.com/',
|
|
10
|
+
extractedAt: '2026-01-01T00:00:00.000Z',
|
|
11
|
+
meta: { dembrandtVersion: '0.16.0', schemaVersion: '1.0.0' },
|
|
12
|
+
colors: { palette: [], semantic: {}, cssVariables: {} },
|
|
13
|
+
typography: {
|
|
14
|
+
styles: [{ context: 'body', family: 'Inter', size: '16px', weight: '700' }],
|
|
15
|
+
sources: { adobeFonts: false },
|
|
16
|
+
},
|
|
17
|
+
spacing: { scaleType: 'base-8', commonValues: [{ px: '16px' }, { px: 24 }] },
|
|
18
|
+
borderRadius: { values: [] },
|
|
19
|
+
borders: {},
|
|
20
|
+
shadows: [],
|
|
21
|
+
components: { buttons: [], inputs: { text: [] }, links: [], badges: { all: [] } },
|
|
22
|
+
breakpoints: [],
|
|
23
|
+
iconSystem: [],
|
|
24
|
+
frameworks: [],
|
|
25
|
+
};
|
|
26
|
+
test('stripTransient removes internal crawl fields and does not mutate input', () => {
|
|
27
|
+
const input = { ...base, _discoveredLinks: [1], _extractedUrls: [2], _pageResults: [3] };
|
|
28
|
+
const out = stripTransient(input);
|
|
29
|
+
assert.strictEqual(out._discoveredLinks, undefined);
|
|
30
|
+
assert.strictEqual(out._extractedUrls, undefined);
|
|
31
|
+
assert.strictEqual(out._pageResults, undefined);
|
|
32
|
+
// input untouched
|
|
33
|
+
assert.deepStrictEqual(input._discoveredLinks, [1]);
|
|
34
|
+
});
|
|
35
|
+
test('normalizeExtraction canonicalizes loose unions for diffing', () => {
|
|
36
|
+
const out = normalizeExtraction({ ...base, _pageResults: [9] });
|
|
37
|
+
assert.strictEqual(out.typography.styles[0].weight, 700); // string -> number
|
|
38
|
+
assert.strictEqual(out.spacing.commonValues[0].px, 16); // "16px" -> 16
|
|
39
|
+
assert.strictEqual(out.spacing.commonValues[1].px, 24); // already number
|
|
40
|
+
assert.strictEqual(out.spacing.commonValues[0].display, '16px'); // display backfilled
|
|
41
|
+
assert.strictEqual(out.spacing.commonValues[1].display, '24px'); // backfilled from number
|
|
42
|
+
assert.deepStrictEqual(out.typography.sources.adobeFonts, []); // false -> []
|
|
43
|
+
assert.ok(Array.isArray(out.components.inputs)); // object -> array
|
|
44
|
+
assert.ok(Array.isArray(out.components.badges));
|
|
45
|
+
assert.strictEqual(out._pageResults, undefined); // also stripped
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=normalize.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.test.js","sourceRoot":"","sources":["../../test/normalize.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { activeFlags, pathSummary } from '../lib/run-summary.js';
|
|
4
|
+
/**
|
|
5
|
+
* The closing-summary "what shaped this run" lines (DEM-99): which flags were
|
|
6
|
+
* active and which paths were merged. Pinned here so the summary stays honest
|
|
7
|
+
* as flags are added.
|
|
8
|
+
*/
|
|
9
|
+
test('activeFlags: no flags -> empty (no line printed)', () => {
|
|
10
|
+
assert.deepEqual(activeFlags({}), []);
|
|
11
|
+
assert.deepEqual(activeFlags(), []);
|
|
12
|
+
});
|
|
13
|
+
test('activeFlags: behaviour-only flags are surfaced (they write no file)', () => {
|
|
14
|
+
assert.deepEqual(activeFlags({ darkMode: true, wcag: true, mobile: true, slow: true, stealth: true }), ['--dark-mode', '--mobile', '--slow', '--stealth', '--wcag']);
|
|
15
|
+
});
|
|
16
|
+
test('activeFlags: artifact flags included alongside behaviour flags', () => {
|
|
17
|
+
assert.deepEqual(activeFlags({ dtcg: true, saveOutput: true, html: '/tmp/r.html', compare: 'base.json', brandGuide: true, designMd: true, screenshot: '/tmp/s.png' }), ['--dtcg', '--save-output', '--html', '--compare', '--brand-guide', '--design-md', '--screenshot']);
|
|
18
|
+
});
|
|
19
|
+
test('activeFlags: --html present with no value (true) still counts', () => {
|
|
20
|
+
assert.deepEqual(activeFlags({ html: true }), ['--html']);
|
|
21
|
+
});
|
|
22
|
+
test('activeFlags: --crawl renders its count, bare flag has none', () => {
|
|
23
|
+
assert.deepEqual(activeFlags({ crawl: 5 }), ['--crawl 5']);
|
|
24
|
+
assert.deepEqual(activeFlags({ crawl: true }), ['--crawl']);
|
|
25
|
+
assert.deepEqual(activeFlags({ crawl: null }), []);
|
|
26
|
+
assert.deepEqual(activeFlags({ crawl: false }), []);
|
|
27
|
+
});
|
|
28
|
+
test('activeFlags: --browser only when non-default; --no-sandbox only when false', () => {
|
|
29
|
+
assert.deepEqual(activeFlags({ browser: 'chromium' }), []);
|
|
30
|
+
assert.deepEqual(activeFlags({ browser: 'firefox' }), ['--browser firefox']);
|
|
31
|
+
assert.deepEqual(activeFlags({ sandbox: false }), ['--no-sandbox']);
|
|
32
|
+
assert.deepEqual(activeFlags({ sandbox: true }), []);
|
|
33
|
+
});
|
|
34
|
+
test('pathSummary: explicit paths are listed (they are positional, not flags)', () => {
|
|
35
|
+
assert.deepEqual(pathSummary(['/recipes', '/pricing'], 3), ['/recipes', '/pricing', '(3 pages merged)']);
|
|
36
|
+
});
|
|
37
|
+
test('pathSummary: crawl/sitemap have no explicit paths, just the merged count', () => {
|
|
38
|
+
assert.deepEqual(pathSummary([], 2), ['(2 pages merged)']);
|
|
39
|
+
assert.deepEqual(pathSummary(undefined, 4), ['(4 pages merged)']);
|
|
40
|
+
});
|
|
41
|
+
test('pathSummary: single page -> nothing (no merge happened)', () => {
|
|
42
|
+
assert.deepEqual(pathSummary(undefined, 1), []);
|
|
43
|
+
assert.deepEqual(pathSummary([], 0), []);
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=run-summary.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-summary.test.js","sourceRoot":"","sources":["../../test/run-summary.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locks the output version contract: the three independent version axes and the
|
|
3
|
+
* DTCG $extensions key shape that consumers (dembrandt-next, MCP, skills, drift)
|
|
4
|
+
* depend on.
|
|
5
|
+
*/
|
|
6
|
+
import { test } from 'node:test';
|
|
7
|
+
import assert from 'node:assert/strict';
|
|
8
|
+
import { buildDembrandtProvenance, checkSchemaCompatibility, formatCompatibilityNotice, SCHEMA_VERSION, EXTENSION_KEY, DTCG_SPEC_VERSION, } from '../lib/version.js';
|
|
9
|
+
test('buildDembrandtProvenance carries the three version axes', () => {
|
|
10
|
+
const ext = buildDembrandtProvenance({
|
|
11
|
+
url: 'https://www.acme.com/pricing',
|
|
12
|
+
extractedAt: '2026-01-01T00:00:00.000Z',
|
|
13
|
+
meta: { dembrandtVersion: '9.9.9' },
|
|
14
|
+
});
|
|
15
|
+
assert.strictEqual(ext.schemaVersion, SCHEMA_VERSION);
|
|
16
|
+
assert.strictEqual(ext.toolVersion, '9.9.9');
|
|
17
|
+
assert.strictEqual(ext.specVersion, DTCG_SPEC_VERSION);
|
|
18
|
+
assert.strictEqual(ext.generator, 'dembrandt');
|
|
19
|
+
assert.strictEqual(ext.source.domain, 'acme.com');
|
|
20
|
+
assert.strictEqual(ext.source.url, 'https://www.acme.com/pricing');
|
|
21
|
+
});
|
|
22
|
+
test('EXTENSION_KEY is reverse-domain; SCHEMA_VERSION is semver', () => {
|
|
23
|
+
assert.strictEqual(EXTENSION_KEY, 'com.dembrandt');
|
|
24
|
+
assert.match(SCHEMA_VERSION, /^\d+\.\d+\.\d+$/);
|
|
25
|
+
});
|
|
26
|
+
test('missing tool version degrades to null and domain to "unknown", never throws', () => {
|
|
27
|
+
const ext = buildDembrandtProvenance({});
|
|
28
|
+
assert.strictEqual(ext.toolVersion, null);
|
|
29
|
+
assert.strictEqual(ext.source.domain, 'unknown');
|
|
30
|
+
assert.strictEqual(ext.source.url, null);
|
|
31
|
+
});
|
|
32
|
+
test('compatibility compares the schema contract, not the churning tool version', () => {
|
|
33
|
+
// The exact bug behind "unknown vs v0.14.0": a refactor-only release bumps the
|
|
34
|
+
// tool version but leaves the contract alone. Must read as fully compatible.
|
|
35
|
+
const current = checkSchemaCompatibility({
|
|
36
|
+
meta: { schemaVersion: SCHEMA_VERSION, dembrandtVersion: '99.0.0' },
|
|
37
|
+
});
|
|
38
|
+
assert.strictEqual(current.status, 'current');
|
|
39
|
+
assert.strictEqual(current.compatible, true);
|
|
40
|
+
assert.strictEqual(formatCompatibilityNotice(current), null);
|
|
41
|
+
// Same major, additive minor/patch drift either direction stays compatible.
|
|
42
|
+
const minorDrift = checkSchemaCompatibility({ meta: { schemaVersion: '1.4.2' } });
|
|
43
|
+
assert.strictEqual(minorDrift.status, 'compatible');
|
|
44
|
+
assert.strictEqual(minorDrift.compatible, true);
|
|
45
|
+
assert.strictEqual(formatCompatibilityNotice(minorDrift), null);
|
|
46
|
+
});
|
|
47
|
+
test('compatibility flags breaking major drift in both directions', () => {
|
|
48
|
+
const outdated = checkSchemaCompatibility({ meta: { schemaVersion: '0.9.0' } });
|
|
49
|
+
assert.strictEqual(outdated.status, 'outdated');
|
|
50
|
+
assert.strictEqual(outdated.compatible, false);
|
|
51
|
+
assert.match(formatCompatibilityNotice(outdated), /Re-extract recommended/);
|
|
52
|
+
const ahead = checkSchemaCompatibility({ meta: { schemaVersion: '2.0.0' } });
|
|
53
|
+
assert.strictEqual(ahead.status, 'ahead');
|
|
54
|
+
assert.strictEqual(ahead.compatible, false);
|
|
55
|
+
assert.match(formatCompatibilityNotice(ahead), /Upgrade dembrandt/);
|
|
56
|
+
});
|
|
57
|
+
test('compatibility degrades legacy and unknown extractions without throwing', () => {
|
|
58
|
+
// Pre-1.0 tallenne: has a tool version, no schemaVersion. This is the case the
|
|
59
|
+
// old viewer mislabelled "unknown vs v0.14.0".
|
|
60
|
+
const legacy = checkSchemaCompatibility({ meta: { dembrandtVersion: '0.14.0' } });
|
|
61
|
+
assert.strictEqual(legacy.status, 'legacy');
|
|
62
|
+
assert.strictEqual(legacy.compatible, false);
|
|
63
|
+
assert.strictEqual(legacy.found, null);
|
|
64
|
+
assert.match(legacy.message, /v0\.14\.0/);
|
|
65
|
+
const unknown = checkSchemaCompatibility({});
|
|
66
|
+
assert.strictEqual(unknown.status, 'unknown');
|
|
67
|
+
assert.strictEqual(unknown.compatible, false);
|
|
68
|
+
assert.strictEqual(unknown.toolVersion, null);
|
|
69
|
+
// Malformed version string must not throw; falls back to unknown/legacy.
|
|
70
|
+
const garbage = checkSchemaCompatibility({ meta: { schemaVersion: 'not-a-version' } });
|
|
71
|
+
assert.strictEqual(garbage.compatible, false);
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=version.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../../test/version.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mseep/dembrandt",
|
|
3
|
+
"version": "0.19.5",
|
|
4
|
+
"description": "Extract design tokens and publicly visible CSS information from any website",
|
|
5
|
+
"mcpName": "io.github.dembrandt/dembrandt",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"dembrandt": "dist/index.js",
|
|
10
|
+
"dembrandt-mcp": "dist/mcp-server.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./dtcg": "./dist/lib/dtcg/validate.js",
|
|
15
|
+
"./drift": {
|
|
16
|
+
"types": "./dist/lib/drift.d.ts",
|
|
17
|
+
"default": "./dist/lib/drift.js"
|
|
18
|
+
},
|
|
19
|
+
"./report": {
|
|
20
|
+
"types": "./dist/lib/formatters/html.d.ts",
|
|
21
|
+
"default": "./dist/lib/formatters/html.js"
|
|
22
|
+
},
|
|
23
|
+
"./normalize": "./dist/lib/normalize.js",
|
|
24
|
+
"./types": {
|
|
25
|
+
"types": "./dist/lib/types.d.ts",
|
|
26
|
+
"default": "./dist/lib/types.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"start": "node dist/index.js",
|
|
34
|
+
"prepublishOnly": "npm run build",
|
|
35
|
+
"test": "npm run build && node --test dist/test/*.test.js",
|
|
36
|
+
"install-browser": "node tools/install-browser.mjs",
|
|
37
|
+
"qa:baseline": "npm run build && node test/qa.mjs --baseline",
|
|
38
|
+
"qa:diff": "npm run build && node test/qa.mjs --diff",
|
|
39
|
+
"qa:site": "npm run build && node test/qa.mjs --site",
|
|
40
|
+
"gold:label": "npm run build && node tools/gold-label.mjs",
|
|
41
|
+
"gold:run": "npm run build && node tools/gold-run.mjs",
|
|
42
|
+
"gold:judge": "npm run build && node tools/gold-ai-judge.mjs",
|
|
43
|
+
"gold:tune": "node tools/gold-tune.mjs",
|
|
44
|
+
"gold:cluster": "node tools/gold-cluster.mjs",
|
|
45
|
+
"gold:analyze": "node tools/gold-analyze.mjs",
|
|
46
|
+
"build": "tsc && cp package.json dist/package.json",
|
|
47
|
+
"lint": "eslint ."
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"design-tokens",
|
|
51
|
+
"design-system",
|
|
52
|
+
"branding",
|
|
53
|
+
"css-analysis",
|
|
54
|
+
"cli",
|
|
55
|
+
"playwright",
|
|
56
|
+
"mseep",
|
|
57
|
+
"mcp-server"
|
|
58
|
+
],
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/dembrandt/dembrandt.git"
|
|
62
|
+
},
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/dembrandt/dembrandt/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://dembrandt.com",
|
|
67
|
+
"author": "thevangelist <info@esajuhana.com>",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"chalk": "^5.3.0",
|
|
71
|
+
"commander": "^11.1.0",
|
|
72
|
+
"ora": "^7.0.1",
|
|
73
|
+
"playwright-core": "^1.60.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
77
|
+
"playwright": "^1.60.0",
|
|
78
|
+
"zod": "4.3.6"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"@modelcontextprotocol/sdk": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"zod": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"playwright": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"engines": {
|
|
92
|
+
"node": ">=18.0.0"
|
|
93
|
+
},
|
|
94
|
+
"devDependencies": {
|
|
95
|
+
"@eslint/js": "10.0.1",
|
|
96
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
97
|
+
"@types/node": "25.9.2",
|
|
98
|
+
"eslint": "10.4.1",
|
|
99
|
+
"playwright": "^1.57.0",
|
|
100
|
+
"playwright-core": "1.60.0",
|
|
101
|
+
"typescript": "6.0.3",
|
|
102
|
+
"typescript-eslint": "8.60.1",
|
|
103
|
+
"zod": "4.3.6"
|
|
104
|
+
},
|
|
105
|
+
"publisher": "mseep"
|
|
106
|
+
}
|