renderdiff 0.0.0-stage → 0.1.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.
@@ -0,0 +1,191 @@
1
+ import type { Locator, Page } from "playwright";
2
+ /**
3
+ * Configuration: built-in defaults, the user-facing `RenderdiffConfig` shape, and the
4
+ * loader that merges a `renderdiff.config.*` file into a `ResolvedConfig`.
5
+ *
6
+ * Precedence is always: CLI flag > config file > built-in default.
7
+ */
8
+ /** A Playwright selector per side. */
9
+ export type Sides = {
10
+ left: string;
11
+ right: string;
12
+ };
13
+ /**
14
+ * A route to diff: the path loaded on each side, normalized (no trailing slash, `/` for the
15
+ * index). Both are the same path unless the route is a pair. With a selector, each side
16
+ * compares that one element instead of the whole page.
17
+ */
18
+ export interface Route {
19
+ left: string;
20
+ right: string;
21
+ selector: Sides | null;
22
+ }
23
+ /**
24
+ * A route as written: `/a`, the pair `/a::/b`, or `{ left, right?, selector? }` (right
25
+ * defaults to left).
26
+ */
27
+ export type RouteSpec = string | {
28
+ left: string;
29
+ right?: string;
30
+ selector?: string | Sides;
31
+ };
32
+ /** `pricing` / `/pricing/` -> `/pricing`; `/` stays `/`. */
33
+ export declare const normalize: (url: string) => string;
34
+ /** `/a` for a plain route, `/a::/b` for a pair — the route's name in stdout and results.json. */
35
+ export declare const label: (r: Omit<Route, "selector">) => string;
36
+ /** `.card`, or `.new | .old` when the sides differ. */
37
+ export declare const selectorText: (s: Sides) => string;
38
+ /** The label plus ` [selector]`: unique per route in a run, so the compact summary's group key. */
39
+ export declare const name: (r: Route) => string;
40
+ /**
41
+ * Specs -> normalized, deduplicated routes; throws on an empty side or a glob. A string is a
42
+ * pair when it has a `::` followed by `/` (or ending it, so `/a::` is an empty side, not a
43
+ * literal), which keeps `?q=std::vector` and `/wiki/Talk:Foo` single routes. A CLI
44
+ * `selector` replaces every route's own.
45
+ */
46
+ export declare function parseRoutes(specs: RouteSpec[], selector?: Sides): Route[];
47
+ /**
48
+ * Viewports to compare at. Each value sits *inside* a common responsive band rather
49
+ * than on a boundary (640/768/1024/1280/1536 are the usual breakpoints), so a layout
50
+ * switch never flaps between the two captures.
51
+ */
52
+ export declare const DEFAULT_WIDTHS: number[];
53
+ /** Directory a run writes its screenshots and `report.html` into. Relative to cwd. */
54
+ export declare const DEFAULT_OUT_DIR = "renderdiff-out";
55
+ /**
56
+ * Captures run in parallel. Two by default — if one side points at a live site we are
57
+ * a guest there. No extra rate limiting needed: each worker holds at most one load per
58
+ * origin at a time, so this is also the most concurrent loads either origin sees.
59
+ */
60
+ export declare const DEFAULT_CONCURRENCY = 2;
61
+ /**
62
+ * Third-party origins aborted at the network layer. Must stay symmetric — blocking on
63
+ * one side only is itself a diff.
64
+ *
65
+ * Blocked rather than hidden because A/B tooling rewrites arbitrary DOM to run
66
+ * experiments, and CSS cannot pre-empt an experiment you have not seen.
67
+ *
68
+ * User config appends to this list; it never replaces it.
69
+ */
70
+ export declare const DEFAULT_BLOCK_URL_PATTERNS: string[];
71
+ /**
72
+ * Consent banners and dev-server chrome to hide. Common vendors only — add your own
73
+ * site's selectors via `hideSelectors` in the config file.
74
+ *
75
+ * Two constraints apply to anything added here:
76
+ *
77
+ * 1. Match the banner element EXACTLY. Consent scripts habitually also stamp a class
78
+ * on <html> (e.g. `…-notice-loaded`), so a substring selector like
79
+ * `[class*=cookie-notice]` hides the whole document — and blank matches blank, so
80
+ * every page then passes.
81
+ * 2. Hide, never remove. Removing these after the page's cookie script has run wedges
82
+ * the renderer and screenshots hang.
83
+ *
84
+ * Only for chrome that should be absent on both sides. Content that exists on both but
85
+ * drifts belongs in `masks`.
86
+ */
87
+ export declare const DEFAULT_HIDE_SELECTORS: string[];
88
+ /**
89
+ * Browser-context settings pinned on both sides, so locale, timezone, theme and motion
90
+ * preferences can't differ between the two loads. Listed in the report.
91
+ */
92
+ export declare const CONTEXT_OPTIONS: {
93
+ readonly deviceScaleFactor: 1;
94
+ readonly reducedMotion: "reduce";
95
+ readonly timezoneId: "UTC";
96
+ readonly locale: "en-US";
97
+ readonly colorScheme: "light";
98
+ };
99
+ /** Fill colour for masks and for height/width padding. Loud on purpose. */
100
+ export declare const MASK_COLOR = "#FF00FF";
101
+ /**
102
+ * Content that renders on both sides but whose value drifts — live counters, clocks,
103
+ * "N minutes ago". Painted over on both sides, so the noise cancels.
104
+ *
105
+ * Masks rather than CSS: these occupy a box, and hiding one reflows the page.
106
+ * `visibility:hidden` is no better — "9.9k" and "10.0k" size their box differently and
107
+ * shove their flex neighbours around.
108
+ *
109
+ * Declared as data, not branches, so the report can list the same `reason`s it masks
110
+ * instead of restating them in prose that silently goes stale.
111
+ *
112
+ * Keep the list short. Every mask is coverage given up, so add only what is proven to
113
+ * drift.
114
+ */
115
+ export type Mask = {
116
+ /**
117
+ * The route path this applies to, e.g. `/pricing`; every route when omitted. On a pair
118
+ * it matches either side's path and paints both, so the noise still cancels.
119
+ */
120
+ urlPath?: string;
121
+ /** Why it drifts — surfaced verbatim in the report. */
122
+ reason: string;
123
+ } & ({
124
+ selector: string;
125
+ } | {
126
+ locate: (page: Page) => Locator;
127
+ });
128
+ /** The shape a `renderdiff.config.*` file default-exports. Every field is optional. */
129
+ export interface RenderdiffConfig {
130
+ /** Left origin, e.g. `http://localhost:3000`. A trailing slash is stripped. */
131
+ left?: string;
132
+ /** Right origin, e.g. `https://example.com`. A trailing slash is stripped. */
133
+ right?: string;
134
+ /** Routes to diff when none are passed on the command line. A route object may take a `selector`. */
135
+ routes?: RouteSpec[];
136
+ /** Viewport widths. Replaces {@link DEFAULT_WIDTHS} outright. */
137
+ widths?: number[];
138
+ /** Fail the run if any comparison scores below this, 0..1. */
139
+ threshold?: number;
140
+ /** Where to write screenshots and `report.html`. Relative paths resolve from cwd. */
141
+ outDir?: string;
142
+ /** Parallel workers. */
143
+ concurrency?: number;
144
+ /** Extra URL globs to abort, appended to {@link DEFAULT_BLOCK_URL_PATTERNS}. */
145
+ blockUrlPatterns?: string[];
146
+ /** Extra selectors to hide, appended to {@link DEFAULT_HIDE_SELECTORS}. */
147
+ hideSelectors?: string[];
148
+ /** Raw CSS injected after the built-in rules. An escape hatch. */
149
+ extraCss?: string;
150
+ /** Per-route regions painted over on both sides. */
151
+ masks?: Mask[];
152
+ }
153
+ /** A fully merged config. Everything the run needs, nothing optional. */
154
+ export interface ResolvedConfig {
155
+ left: string;
156
+ right: string;
157
+ widths: number[];
158
+ threshold: number | null;
159
+ outDir: string;
160
+ concurrency: number;
161
+ blockUrlPatterns: string[];
162
+ /** Built-in plus configured selectors hidden on both sides. */
163
+ hideSelectors: string[];
164
+ /** The complete stylesheet injected into every page. */
165
+ neutralizeCss: string;
166
+ masks: Mask[];
167
+ }
168
+ /** package.json's version; the same relative path resolves from `src/` and `dist/`. */
169
+ export declare function version(): string;
170
+ /** Identity helper — exists purely so editors type-check a config file. */
171
+ export declare function defineConfig(config: RenderdiffConfig): RenderdiffConfig;
172
+ export declare function masksFor(cfg: ResolvedConfig, page: Page, route: Route): Locator[];
173
+ /**
174
+ * Load a config file. An explicit `--config` path must exist; otherwise cwd is probed
175
+ * and finding nothing is fine — the CLI works with flags alone.
176
+ */
177
+ export declare function loadConfig(explicitPath?: string): Promise<{
178
+ config: RenderdiffConfig;
179
+ path: string | null;
180
+ }>;
181
+ /** CLI-supplied values. `undefined` means "not passed", so the config file wins. */
182
+ export interface CliOverrides {
183
+ left?: string;
184
+ right?: string;
185
+ widths?: number[];
186
+ threshold?: number;
187
+ outDir?: string;
188
+ concurrency?: number;
189
+ }
190
+ /** Merge built-in defaults, the config file, and CLI flags into one resolved config. */
191
+ export declare function resolveConfig(file: RenderdiffConfig, cli: CliOverrides): ResolvedConfig;
package/dist/config.js ADDED
@@ -0,0 +1,331 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
+ /** `pricing` / `/pricing/` -> `/pricing`; `/` stays `/`. */
13
+ export const normalize = (url) => {
14
+ const trimmed = url.replace(/^\/+/, "").replace(/\/+$/, "");
15
+ return trimmed ? `/${trimmed}` : "/";
16
+ };
17
+ /** `/a` for a plain route, `/a::/b` for a pair — the route's name in stdout and results.json. */
18
+ export const label = (r) => r.left === r.right ? r.left : `${r.left}::${r.right}`;
19
+ /** `.card`, or `.new | .old` when the sides differ. */
20
+ export const selectorText = (s) => (s.left === s.right ? s.left : `${s.left} | ${s.right}`);
21
+ /** The label plus ` [selector]`: unique per route in a run, so the compact summary's group key. */
22
+ export const name = (r) => label(r) + (r.selector ? ` [${selectorText(r.selector)}]` : "");
23
+ /**
24
+ * Specs -> normalized, deduplicated routes; throws on an empty side or a glob. A string is a
25
+ * pair when it has a `::` followed by `/` (or ending it, so `/a::` is an empty side, not a
26
+ * literal), which keeps `?q=std::vector` and `/wiki/Talk:Foo` single routes. A CLI
27
+ * `selector` replaces every route's own.
28
+ */
29
+ export function parseRoutes(specs, selector) {
30
+ const out = new Map();
31
+ for (const spec of specs) {
32
+ let sides;
33
+ if (typeof spec === "string") {
34
+ const i = spec.search(/::(?=\/|$)/);
35
+ sides = i === -1 ? [spec, spec] : [spec.slice(0, i), spec.slice(i + 2)];
36
+ }
37
+ else {
38
+ sides = [spec.left, spec.right ?? spec.left];
39
+ }
40
+ const shown = typeof spec === "string" ? spec : JSON.stringify(spec);
41
+ if (!sides[0] || !sides[1])
42
+ throw new Error(`route ${shown} has an empty side`);
43
+ // Its label would collide with the pair's, and dedupe would silently drop one of them.
44
+ if (typeof spec !== "string" && sides.some((s) => /::(?=\/|$)/.test(s))) {
45
+ throw new Error(`route ${shown}: a side containing "::/" reads as a pair`);
46
+ }
47
+ const glob = sides.find((s) => s.includes("*"));
48
+ if (glob)
49
+ throw new Error(`globs are not supported (${glob}) — pass literal paths.`);
50
+ const own = typeof spec === "string" ? undefined : spec.selector;
51
+ const route = {
52
+ left: normalize(sides[0]),
53
+ right: normalize(sides[1]),
54
+ selector: selector ?? (typeof own === "string" ? { left: own, right: own } : (own ?? null)),
55
+ };
56
+ const same = out.get(name(route));
57
+ if (same && JSON.stringify(same) !== JSON.stringify(route)) {
58
+ throw new Error(`two routes both read as ${name(route)}; change one of their selectors`);
59
+ }
60
+ out.set(name(route), route);
61
+ }
62
+ return [...out.values()];
63
+ }
64
+ /**
65
+ * Viewports to compare at. Each value sits *inside* a common responsive band rather
66
+ * than on a boundary (640/768/1024/1280/1536 are the usual breakpoints), so a layout
67
+ * switch never flaps between the two captures.
68
+ */
69
+ export const DEFAULT_WIDTHS = [1440, 1152, 896, 704, 375];
70
+ /** Directory a run writes its screenshots and `report.html` into. Relative to cwd. */
71
+ export const DEFAULT_OUT_DIR = "renderdiff-out";
72
+ /**
73
+ * Captures run in parallel. Two by default — if one side points at a live site we are
74
+ * a guest there. No extra rate limiting needed: each worker holds at most one load per
75
+ * origin at a time, so this is also the most concurrent loads either origin sees.
76
+ */
77
+ export const DEFAULT_CONCURRENCY = 2;
78
+ /**
79
+ * Third-party origins aborted at the network layer. Must stay symmetric — blocking on
80
+ * one side only is itself a diff.
81
+ *
82
+ * Blocked rather than hidden because A/B tooling rewrites arbitrary DOM to run
83
+ * experiments, and CSS cannot pre-empt an experiment you have not seen.
84
+ *
85
+ * User config appends to this list; it never replaces it.
86
+ */
87
+ export const DEFAULT_BLOCK_URL_PATTERNS = [
88
+ "**://*.visualwebsiteoptimizer.com/**",
89
+ "**://*.googletagmanager.com/**",
90
+ "**://*.google-analytics.com/**",
91
+ "**://cdn.segment.com/**",
92
+ "**://*.intercom.io/**",
93
+ "**://*.intercomcdn.com/**",
94
+ "**://*.hotjar.com/**",
95
+ "**://snap.licdn.com/**",
96
+ "**://connect.facebook.net/**",
97
+ "**://*.onetrust.com/**",
98
+ "**://cdn.cookielaw.org/**",
99
+ ];
100
+ /**
101
+ * Consent banners and dev-server chrome to hide. Common vendors only — add your own
102
+ * site's selectors via `hideSelectors` in the config file.
103
+ *
104
+ * Two constraints apply to anything added here:
105
+ *
106
+ * 1. Match the banner element EXACTLY. Consent scripts habitually also stamp a class
107
+ * on <html> (e.g. `…-notice-loaded`), so a substring selector like
108
+ * `[class*=cookie-notice]` hides the whole document — and blank matches blank, so
109
+ * every page then passes.
110
+ * 2. Hide, never remove. Removing these after the page's cookie script has run wedges
111
+ * the renderer and screenshots hang.
112
+ *
113
+ * Only for chrome that should be absent on both sides. Content that exists on both but
114
+ * drifts belongs in `masks`.
115
+ */
116
+ export const DEFAULT_HIDE_SELECTORS = [
117
+ "#onetrust-consent-sdk",
118
+ ".osano-cm-window",
119
+ "astro-dev-toolbar",
120
+ "#astro-dev-toolbar-root",
121
+ "nextjs-portal",
122
+ ];
123
+ /** Kills motion so two captures taken seconds apart agree. Always applied. */
124
+ const STILL_CSS = `
125
+ *,*::before,*::after{animation:none!important;transition:none!important;caret-color:transparent!important}
126
+ html{scroll-behavior:auto!important}
127
+ `;
128
+ /**
129
+ * Browser-context settings pinned on both sides, so locale, timezone, theme and motion
130
+ * preferences can't differ between the two loads. Listed in the report.
131
+ */
132
+ export const CONTEXT_OPTIONS = {
133
+ deviceScaleFactor: 1,
134
+ reducedMotion: "reduce",
135
+ timezoneId: "UTC",
136
+ locale: "en-US",
137
+ colorScheme: "light",
138
+ };
139
+ /** Fill colour for masks and for height/width padding. Loud on purpose. */
140
+ export const MASK_COLOR = "#FF00FF";
141
+ /** package.json's version; the same relative path resolves from `src/` and `dist/`. */
142
+ export function version() {
143
+ const pkg = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
144
+ try {
145
+ return JSON.parse(fs.readFileSync(pkg, "utf8")).version ?? "unknown";
146
+ }
147
+ catch {
148
+ return "unknown";
149
+ }
150
+ }
151
+ /** Identity helper — exists purely so editors type-check a config file. */
152
+ export function defineConfig(config) {
153
+ return config;
154
+ }
155
+ export function masksFor(cfg, page, route) {
156
+ return cfg.masks
157
+ .filter((m) => m.urlPath === undefined || m.urlPath === route.left || m.urlPath === route.right)
158
+ .map((m) => ("selector" in m ? page.locator(m.selector) : m.locate(page)));
159
+ }
160
+ /** Config filenames probed in cwd, in order. */
161
+ const CONFIG_NAMES = [
162
+ "renderdiff.config.ts",
163
+ "renderdiff.config.mts",
164
+ "renderdiff.config.js",
165
+ "renderdiff.config.mjs",
166
+ ];
167
+ const isStrArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
168
+ /**
169
+ * Load a config file. An explicit `--config` path must exist; otherwise cwd is probed
170
+ * and finding nothing is fine — the CLI works with flags alone.
171
+ */
172
+ export async function loadConfig(explicitPath) {
173
+ let file = null;
174
+ if (explicitPath) {
175
+ file = path.resolve(process.cwd(), explicitPath);
176
+ if (!fs.existsSync(file)) {
177
+ throw new Error(`config file not found: ${file}`);
178
+ }
179
+ }
180
+ else {
181
+ for (const name of CONFIG_NAMES) {
182
+ const candidate = path.resolve(process.cwd(), name);
183
+ if (fs.existsSync(candidate)) {
184
+ file = candidate;
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ if (!file)
190
+ return { config: {}, path: null };
191
+ let mod;
192
+ try {
193
+ mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(file).href)));
194
+ }
195
+ catch (e) {
196
+ const msg = e instanceof Error ? e.message : String(e);
197
+ throw new Error(`could not load ${file}:\n ${msg}`);
198
+ }
199
+ const config = mod.default;
200
+ if (config === undefined) {
201
+ throw new Error(`${file} has no default export`);
202
+ }
203
+ if (typeof config !== "object" || config === null || Array.isArray(config)) {
204
+ throw new Error(`${file} must default-export an object`);
205
+ }
206
+ validate(config, file);
207
+ return { config: config, path: file };
208
+ }
209
+ /** Reject a malformed config here, naming the key, rather than deep inside a run. */
210
+ function validate(c, file) {
211
+ const bad = (key, expected) => {
212
+ throw new Error(`${file}: \`${key}\` must be ${expected}`);
213
+ };
214
+ for (const key of ["left", "right", "outDir", "extraCss"]) {
215
+ if (c[key] !== undefined && typeof c[key] !== "string")
216
+ bad(key, "a string");
217
+ }
218
+ for (const key of ["blockUrlPatterns", "hideSelectors"]) {
219
+ if (c[key] !== undefined && !isStrArray(c[key])) {
220
+ bad(key, "an array of strings");
221
+ }
222
+ }
223
+ if (c.routes !== undefined) {
224
+ if (!Array.isArray(c.routes))
225
+ bad("routes", "an array");
226
+ c.routes.forEach((r, i) => {
227
+ if (typeof r === "string")
228
+ return;
229
+ if (typeof r !== "object" || r === null || Array.isArray(r)) {
230
+ bad(`routes[${i}]`, "a string or an object { left, right?, selector? }");
231
+ }
232
+ const o = r;
233
+ for (const key of Object.keys(o)) {
234
+ if (!["left", "right", "selector"].includes(key)) {
235
+ throw new Error(`${file}: \`routes[${i}].${key}\` is not a route key (left, right, selector)`);
236
+ }
237
+ }
238
+ const sel = o.selector;
239
+ if (sel !== undefined &&
240
+ !(typeof sel === "string" && sel) &&
241
+ !(typeof sel === "object" && sel !== null &&
242
+ Object.keys(sel).sort().join() === "left,right" &&
243
+ [sel.left, sel.right].every((v) => typeof v === "string" && v))) {
244
+ bad(`routes[${i}].selector`, "a non-empty string or { left, right } of non-empty strings");
245
+ }
246
+ if (typeof o.left !== "string" || !o.left)
247
+ bad(`routes[${i}].left`, "a non-empty string");
248
+ if (o.right !== undefined && (typeof o.right !== "string" || !o.right)) {
249
+ bad(`routes[${i}].right`, "a non-empty string");
250
+ }
251
+ });
252
+ }
253
+ if (c.widths !== undefined) {
254
+ if (!Array.isArray(c.widths) ||
255
+ !c.widths.every((w) => typeof w === "number" && Number.isFinite(w) && w > 0)) {
256
+ bad("widths", "an array of positive numbers");
257
+ }
258
+ }
259
+ if (c.threshold !== undefined) {
260
+ const t = c.threshold;
261
+ if (typeof t !== "number" || !Number.isFinite(t) || t < 0 || t > 1) {
262
+ bad("threshold", "a number between 0 and 1");
263
+ }
264
+ }
265
+ if (c.concurrency !== undefined) {
266
+ const n = c.concurrency;
267
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
268
+ bad("concurrency", "a positive integer");
269
+ }
270
+ }
271
+ if (c.masks !== undefined) {
272
+ if (!Array.isArray(c.masks))
273
+ bad("masks", "an array");
274
+ c.masks.forEach((m, i) => {
275
+ const o = m;
276
+ if (typeof o !== "object" || o === null) {
277
+ bad(`masks[${i}]`, "an object");
278
+ return;
279
+ }
280
+ if (o.urlPath !== undefined && typeof o.urlPath !== "string") {
281
+ bad(`masks[${i}].urlPath`, "a string");
282
+ }
283
+ if (typeof o.reason !== "string")
284
+ bad(`masks[${i}].reason`, "a string");
285
+ if (("selector" in o) === ("locate" in o)) {
286
+ throw new Error(`${file}: \`masks[${i}]\` needs exactly one of \`selector\` or \`locate\``);
287
+ }
288
+ if (o.selector !== undefined && typeof o.selector !== "string") {
289
+ bad(`masks[${i}].selector`, "a string");
290
+ }
291
+ if (o.locate !== undefined && typeof o.locate !== "function") {
292
+ bad(`masks[${i}].locate`, "a function (page) => Locator");
293
+ }
294
+ });
295
+ }
296
+ }
297
+ /** Merge built-in defaults, the config file, and CLI flags into one resolved config. */
298
+ export function resolveConfig(file, cli) {
299
+ const left = cli.left ?? file.left;
300
+ const right = cli.right ?? file.right;
301
+ if (!left || !right) {
302
+ throw new Error(!left && !right
303
+ ? "left and right origins are required (two positional URLs, --left and --right, " +
304
+ "or left and right in renderdiff.config.*)"
305
+ : !left
306
+ ? "left origin is required (first positional URL, --left, or left in renderdiff.config.*)"
307
+ : "right origin is required (second positional URL, --right, or right in renderdiff.config.*)");
308
+ }
309
+ const hideSelectors = [
310
+ ...DEFAULT_HIDE_SELECTORS,
311
+ ...(file.hideSelectors ?? []),
312
+ ];
313
+ return {
314
+ left: left.replace(/\/+$/, ""),
315
+ right: right.replace(/\/+$/, ""),
316
+ widths: cli.widths ?? file.widths ?? [...DEFAULT_WIDTHS],
317
+ threshold: cli.threshold ?? file.threshold ?? null,
318
+ outDir: path.resolve(process.cwd(), cli.outDir ?? file.outDir ?? DEFAULT_OUT_DIR),
319
+ concurrency: cli.concurrency ?? file.concurrency ?? DEFAULT_CONCURRENCY,
320
+ blockUrlPatterns: [
321
+ ...DEFAULT_BLOCK_URL_PATTERNS,
322
+ ...(file.blockUrlPatterns ?? []),
323
+ ],
324
+ hideSelectors,
325
+ neutralizeCss: STILL_CSS +
326
+ `${hideSelectors.join(",")}{display:none!important}\n` +
327
+ (file.extraCss ?? ""),
328
+ masks: (file.masks ?? []).map((m) => m.urlPath === undefined ? m : { ...m, urlPath: normalize(m.urlPath) }),
329
+ };
330
+ }
331
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /** Number formatting shared by the console summary (`run.ts`) and the HTML report. */
2
+ /** Down to 4 decimals, so a shot that differs never reads as 100% or clears a threshold it missed. The epsilon absorbs float error like 0.29 * 1e4 = 2899.99…. */
3
+ export declare const floor4: (n: number) => number;
4
+ export declare const pct: (n: number) => string;
5
+ export declare const signed: (n: number) => string;
6
+ export declare const fmtRegion: (r: {
7
+ x: number;
8
+ y: number;
9
+ w: number;
10
+ h: number;
11
+ }) => string;
12
+ /** Signed like the height delta: + when left has the extra rows, − when right does. */
13
+ export declare const fmtBand: (b: {
14
+ side: "left" | "right";
15
+ y: number;
16
+ h: number;
17
+ }) => string;
package/dist/format.js ADDED
@@ -0,0 +1,9 @@
1
+ /** Number formatting shared by the console summary (`run.ts`) and the HTML report. */
2
+ /** Down to 4 decimals, so a shot that differs never reads as 100% or clears a threshold it missed. The epsilon absorbs float error like 0.29 * 1e4 = 2899.99…. */
3
+ export const floor4 = (n) => Math.floor(n * 1e4 + 1e-7) / 1e4;
4
+ export const pct = (n) => `${(floor4(n) * 100).toFixed(2)}%`;
5
+ export const signed = (n) => (n > 0 ? `+${n}` : `${n}`);
6
+ export const fmtRegion = (r) => `${r.w}×${r.h} at (${r.x},${r.y})`;
7
+ /** Signed like the height delta: + when left has the extra rows, − when right does. */
8
+ export const fmtBand = (b) => `${b.side === "left" ? "+" : "-"}${b.h}px at y=${b.y} (${b.side})`;
9
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,kKAAkK;AAClK,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;AACtE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACrE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAiD,EAAE,EAAE,CAC7E,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AACrC,uFAAuF;AACvF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAmD,EAAE,EAAE,CAC7E,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Library entry point. The CLI (`dist/cli.js`) is the primary interface; this exists so
3
+ * a config file can be type-checked:
4
+ *
5
+ * import { defineConfig } from "renderdiff";
6
+ * export default defineConfig({ … });
7
+ *
8
+ * That import only resolves when `renderdiff` is also installed in the project (or linked) —
9
+ * a globally-installed CLI is not importable from an arbitrary directory. A plain
10
+ * object export works everywhere and needs nothing from this module.
11
+ */
12
+ export { defineConfig, DEFAULT_BLOCK_URL_PATTERNS, DEFAULT_CONCURRENCY, DEFAULT_HIDE_SELECTORS, DEFAULT_OUT_DIR, DEFAULT_WIDTHS, MASK_COLOR, type Mask, type ResolvedConfig, type Route, type RouteSpec, type Sides, type RenderdiffConfig, } from "./config.ts";
13
+ export { type ComparedResult, type CropResult, type ErrorResult, type Results, type RouteResult, type RunMeta, type Summary, } from "./report.ts";
14
+ export { type Band, type Box, type Region, type TextDiff } from "./compare.ts";
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Library entry point. The CLI (`dist/cli.js`) is the primary interface; this exists so
3
+ * a config file can be type-checked:
4
+ *
5
+ * import { defineConfig } from "renderdiff";
6
+ * export default defineConfig({ … });
7
+ *
8
+ * That import only resolves when `renderdiff` is also installed in the project (or linked) —
9
+ * a globally-installed CLI is not importable from an arbitrary directory. A plain
10
+ * object export works everywhere and needs nothing from this module.
11
+ */
12
+ export { defineConfig, DEFAULT_BLOCK_URL_PATTERNS, DEFAULT_CONCURRENCY, DEFAULT_HIDE_SELECTORS, DEFAULT_OUT_DIR, DEFAULT_WIDTHS, MASK_COLOR, } from "./config.js";
13
+ export {} from "./report.js";
14
+ export {} from "./compare.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC1B,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,UAAU,GAOX,MAAM,aAAa,CAAC;AAErB,OAAO,EAQN,MAAM,aAAa,CAAC;AAErB,OAAO,EAAmD,MAAM,cAAc,CAAC"}