@coder/pixel-storybook 0.1.0 → 0.1.3-canary.20260616.2a423fe

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.
Files changed (57) hide show
  1. package/README.md +0 -4
  2. package/{dist → build}/api.d.ts +3 -3
  3. package/{dist → build}/api.js +53 -52
  4. package/build/bin.js +103 -0
  5. package/{dist → build}/checkDifferences.d.ts +3 -3
  6. package/{dist → build}/checkDifferences.js +16 -15
  7. package/{dist → build}/compare/compare.d.ts +2 -2
  8. package/{dist → build}/compare/compare.js +17 -16
  9. package/{dist → build}/compare/pixelmatch.js +12 -6
  10. package/{dist → build}/compare/utils.d.ts +1 -1
  11. package/{dist → build}/compare/utils.js +2 -2
  12. package/{dist → build}/compare/worker.js +3 -2
  13. package/{dist → build}/concurrency.d.ts +6 -6
  14. package/{dist → build}/concurrency.js +13 -10
  15. package/{dist → build}/config.d.ts +289 -307
  16. package/{dist → build}/config.js +122 -130
  17. package/{dist → build}/configHelper.js +6 -5
  18. package/build/constants.js +3 -0
  19. package/{dist → build}/crawler/storybook.d.ts +2 -2
  20. package/{dist → build}/crawler/storybook.js +37 -36
  21. package/{dist → build}/crawler/utils.d.ts +1 -1
  22. package/{dist → build}/crawler/utils.js +5 -4
  23. package/{dist → build}/createShots.js +16 -15
  24. package/build/index.d.ts +2 -0
  25. package/build/index.js +2 -0
  26. package/{dist → build}/log.d.ts +4 -4
  27. package/{dist → build}/log.js +10 -9
  28. package/{dist → build}/runner.d.ts +1 -1
  29. package/{dist → build}/runner.js +42 -41
  30. package/{dist → build}/schemas.d.ts +28 -32
  31. package/{dist → build}/schemas.js +25 -26
  32. package/{dist → build}/shard.d.ts +2 -2
  33. package/{dist → build}/shard.js +3 -2
  34. package/{dist → build}/shots/shots.d.ts +2 -2
  35. package/{dist → build}/shots/shots.js +35 -38
  36. package/{dist → build}/shots/utils.d.ts +7 -7
  37. package/{dist → build}/shots/utils.js +28 -27
  38. package/{dist → build}/types.d.ts +2 -2
  39. package/build/types.js +2 -0
  40. package/{dist → build}/upload.d.ts +2 -2
  41. package/{dist → build}/upload.js +8 -7
  42. package/{dist → build}/uploadStorybook.d.ts +1 -1
  43. package/{dist → build}/uploadStorybook.js +20 -19
  44. package/{dist → build}/utils.d.ts +3 -3
  45. package/{dist → build}/utils.js +35 -35
  46. package/package.json +68 -63
  47. package/dist/bin.js +0 -102
  48. package/dist/constants.js +0 -2
  49. package/dist/index.d.ts +0 -2
  50. package/dist/index.js +0 -1
  51. package/dist/types.js +0 -1
  52. package/{dist → build}/bin.d.ts +0 -0
  53. package/{dist → build}/compare/pixelmatch.d.ts +0 -0
  54. package/{dist → build}/compare/worker.d.ts +0 -0
  55. package/{dist → build}/configHelper.d.ts +0 -0
  56. package/{dist → build}/constants.d.ts +0 -0
  57. package/{dist → build}/createShots.d.ts +1 -1
package/README.md CHANGED
@@ -13,7 +13,3 @@ npm install @coder/pixel-storybook
13
13
  ```sh
14
14
  npx pixel-storybook
15
15
  ```
16
-
17
- ## License
18
-
19
- [MIT](LICENSE)
@@ -1,6 +1,6 @@
1
- import type { PlatformModeConfig } from './config.js';
2
- import { type LogMemory, log } from './log.js';
3
- import type { StabilizationResult } from './types.js';
1
+ import type { PlatformModeConfig } from "./config.js";
2
+ import { type LogMemory, log } from "./log.js";
3
+ import type { StabilizationResult } from "./types.js";
4
4
  export type ShotConfig = {
5
5
  name: string;
6
6
  threshold?: number;
@@ -1,52 +1,52 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { retry } from './concurrency.js';
3
- import { log, logMemory } from './log.js';
4
- import { getVersion } from './utils.js';
1
+ import { readFile } from "node:fs/promises";
2
+ import { retry } from "./concurrency.js";
3
+ import { log, logMemory } from "./log.js";
4
+ import { getVersion } from "./utils.js";
5
5
  const version = getVersion();
6
6
  const defaultHeaders = {
7
- 'x-api-version': '3',
8
- 'x-client-version': version ?? 'unknown',
7
+ "x-api-version": "3",
8
+ "x-client-version": version ?? "unknown",
9
9
  };
10
10
  const apiRoutes = {
11
- getApiToken: '/auth/get-api-token',
12
- init: '/app/init',
13
- finalize: '/app/finalize',
14
- prepareUpload: '/file/prepare-upload',
15
- uploadShot: '/file/upload-shot',
16
- processShots: '/app/process-shots',
17
- recordLogs: '/app/record-logs',
18
- uploadStorybookBuild: '/app/upload-storybook',
11
+ getApiToken: "/auth/get-api-token",
12
+ init: "/app/init",
13
+ finalize: "/app/finalize",
14
+ prepareUpload: "/file/prepare-upload",
15
+ uploadShot: "/file/upload-shot",
16
+ processShots: "/app/process-shots",
17
+ recordLogs: "/app/record-logs",
18
+ uploadStorybookBuild: "/app/upload-storybook",
19
19
  };
20
20
  class ApiError extends Error {
21
21
  status;
22
22
  responseData;
23
23
  constructor(message, status, responseData) {
24
24
  super(message);
25
- this.name = 'ApiError';
25
+ this.name = "ApiError";
26
26
  this.status = status;
27
27
  this.responseData = responseData;
28
28
  }
29
29
  }
30
30
  const sendToAPI = async (config, parameters, fileKey, customLogger) => {
31
31
  const logger = customLogger?.process ?? log.process;
32
- logger('info', 'api', `⚡️ Sending to API [${parameters.action}]`);
33
- logger('info', 'api', `Endpoint: ${config.lostPixelPlatform}${apiRoutes[parameters.action]}`);
32
+ logger("info", "api", `⚡️ Sending to API [${parameters.action}]`);
33
+ logger("info", "api", `Endpoint: ${config.lostPixelPlatform}${apiRoutes[parameters.action]}`);
34
34
  try {
35
35
  const apiCall = async () => {
36
36
  const url = `${config.lostPixelPlatform}${apiRoutes[parameters.action]}`;
37
37
  let body;
38
38
  const headers = {
39
39
  ...defaultHeaders,
40
- Authorization: `Bearer ${parameters.apiToken ?? ''}`,
41
- 'x-api-key': config.apiKey ?? 'undefined',
40
+ "Authorization": `Bearer ${parameters.apiToken ?? ""}`,
41
+ "x-api-key": config.apiKey ?? "undefined",
42
42
  };
43
43
  if (fileKey) {
44
44
  const form = new FormData();
45
45
  for (const [key, element] of Object.entries(parameters.payload)) {
46
46
  if (key === fileKey) {
47
47
  const fileBuffer = await readFile(element);
48
- const blob = new Blob([fileBuffer], { type: 'image/png' });
49
- form.append(key, blob, element.split('/').pop());
48
+ const blob = new Blob([fileBuffer], { type: "image/png" });
49
+ form.append(key, blob, element.split("/").pop());
50
50
  }
51
51
  else {
52
52
  form.append(key, element);
@@ -57,10 +57,10 @@ const sendToAPI = async (config, parameters, fileKey, customLogger) => {
57
57
  }
58
58
  else {
59
59
  body = JSON.stringify(parameters.payload);
60
- headers['Content-type'] = 'application/json';
60
+ headers["Content-type"] = "application/json";
61
61
  }
62
62
  const response = await fetch(url, {
63
- method: 'POST',
63
+ method: "POST",
64
64
  headers,
65
65
  body,
66
66
  });
@@ -80,8 +80,8 @@ const sendToAPI = async (config, parameters, fileKey, customLogger) => {
80
80
  times: 3,
81
81
  interval(retryCount) {
82
82
  const delay = Math.round(2 ** retryCount * 3000 * Math.random());
83
- logger('info', 'api', `🔄 Retry attempt ${retryCount} in ${delay}ms [${parameters.action}]`);
84
- logger('info', 'api', `${config.lostPixelPlatform}${apiRoutes[parameters.action]}`);
83
+ logger("info", "api", `🔄 Retry attempt ${retryCount} in ${delay}ms [${parameters.action}]`);
84
+ logger("info", "api", `${config.lostPixelPlatform}${apiRoutes[parameters.action]}`);
85
85
  return delay;
86
86
  },
87
87
  errorFilter(error) {
@@ -93,33 +93,33 @@ const sendToAPI = async (config, parameters, fileKey, customLogger) => {
93
93
  },
94
94
  }, apiCall);
95
95
  if (!response.ok) {
96
- logger('error', 'api', `Error: Failed to send to API [${parameters.action}]. Status: ${response.status}`);
96
+ logger("error", "api", `Error: Failed to send to API [${parameters.action}]. Status: ${response.status}`);
97
97
  process.exit(1);
98
98
  }
99
- const outdatedApiRequest = response?.headers?.['x-api-version-warning'];
99
+ const outdatedApiRequest = response?.headers?.["x-api-version-warning"];
100
100
  if (outdatedApiRequest &&
101
- (parameters.action === 'prepareUpload' ||
102
- parameters.action === 'finalize')) {
103
- logger('info', 'api', [
104
- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~',
101
+ (parameters.action === "prepareUpload" ||
102
+ parameters.action === "finalize")) {
103
+ logger("info", "api", [
104
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
105
105
  `~~ ⚠️ ${outdatedApiRequest}`,
106
- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~',
107
- ].join('\n'));
106
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
107
+ ].join("\n"));
108
108
  }
109
- logger('info', 'api', `🤘 Successfully sent to API [${parameters.action}]`);
109
+ logger("info", "api", `🤘 Successfully sent to API [${parameters.action}]`);
110
110
  return response.data;
111
111
  }
112
112
  catch (error) {
113
113
  if (error instanceof ApiError) {
114
- logger('error', 'api', 'API response: ', error.responseData || error.message);
114
+ logger("error", "api", "API response: ", error.responseData || error.message);
115
115
  }
116
116
  else if (error instanceof Error) {
117
- logger('error', 'api', error.message);
117
+ logger("error", "api", error.message);
118
118
  }
119
119
  else {
120
- logger('error', 'api', error);
120
+ logger("error", "api", error);
121
121
  }
122
- if (parameters.action === 'getApiToken') {
122
+ if (parameters.action === "getApiToken") {
123
123
  process.exit(1);
124
124
  }
125
125
  throw error;
@@ -127,7 +127,7 @@ const sendToAPI = async (config, parameters, fileKey, customLogger) => {
127
127
  };
128
128
  export const getApiToken = async (config) => {
129
129
  return sendToAPI(config, {
130
- action: 'getApiToken',
130
+ action: "getApiToken",
131
131
  payload: {
132
132
  projectId: config.lostPixelProjectId,
133
133
  },
@@ -135,7 +135,7 @@ export const getApiToken = async (config) => {
135
135
  };
136
136
  export const sendInitToAPI = async (config, apiToken) => {
137
137
  return sendToAPI(config, {
138
- action: 'init',
138
+ action: "init",
139
139
  apiToken,
140
140
  payload: {
141
141
  commit: config.commitHash,
@@ -146,7 +146,7 @@ export const sendInitToAPI = async (config, apiToken) => {
146
146
  };
147
147
  export const sendFinalizeToAPI = async (config, apiToken) => {
148
148
  return sendToAPI(config, {
149
- action: 'finalize',
149
+ action: "finalize",
150
150
  apiToken,
151
151
  payload: {
152
152
  projectId: config.lostPixelProjectId,
@@ -158,7 +158,7 @@ export const sendFinalizeToAPI = async (config, apiToken) => {
158
158
  };
159
159
  export const prepareUpload = async (config, apiToken, shotNamesWithHashes) => {
160
160
  return sendToAPI(config, {
161
- action: 'prepareUpload',
161
+ action: "prepareUpload",
162
162
  apiToken,
163
163
  payload: {
164
164
  branchName: config.commitRefName,
@@ -173,18 +173,18 @@ export const uploadShot = async ({ config, apiToken, uploadToken, uploadUrl, nam
173
173
  ...config,
174
174
  lostPixelPlatform: uploadUrl,
175
175
  }, {
176
- action: 'uploadShot',
176
+ action: "uploadShot",
177
177
  apiToken,
178
178
  payload: {
179
179
  uploadToken,
180
180
  name,
181
181
  file,
182
182
  },
183
- }, 'file', logger);
183
+ }, "file", logger);
184
184
  };
185
185
  export const processShots = async (config, apiToken, uploadToken, shotsConfig) => {
186
186
  return sendToAPI(config, {
187
- action: 'processShots',
187
+ action: "processShots",
188
188
  apiToken,
189
189
  payload: {
190
190
  uploadToken,
@@ -198,7 +198,7 @@ export const processShots = async (config, apiToken, uploadToken, shotsConfig) =
198
198
  };
199
199
  export const uploadStorybookBuild = async (config, apiToken, filePath) => {
200
200
  return sendToAPI(config, {
201
- action: 'uploadStorybookBuild',
201
+ action: "uploadStorybookBuild",
202
202
  apiToken,
203
203
  payload: {
204
204
  projectId: config.lostPixelProjectId,
@@ -208,12 +208,12 @@ export const uploadStorybookBuild = async (config, apiToken, filePath) => {
208
208
  commit: config.commitHash,
209
209
  file: filePath,
210
210
  },
211
- }, 'file');
211
+ }, "file");
212
212
  };
213
213
  export const sendRecordLogsToAPI = async (config, apiToken) => {
214
214
  try {
215
215
  await sendToAPI(config, {
216
- action: 'recordLogs',
216
+ action: "recordLogs",
217
217
  apiToken,
218
218
  payload: {
219
219
  branchName: config.commitRefName,
@@ -225,14 +225,15 @@ export const sendRecordLogsToAPI = async (config, apiToken) => {
225
225
  }
226
226
  catch (error) {
227
227
  if (error instanceof ApiError) {
228
- log.process('error', 'api', 'API response: ', error.responseData || error.message);
228
+ log.process("error", "api", "API response: ", error.responseData || error.message);
229
229
  }
230
230
  else if (error instanceof Error) {
231
- log.process('error', 'api', error.message);
231
+ log.process("error", "api", error.message);
232
232
  }
233
233
  else {
234
- log.process('error', 'api', error);
234
+ log.process("error", "api", error);
235
235
  }
236
- log.process('error', 'api', 'Error: Failed to send logs to API');
236
+ log.process("error", "api", "Error: Failed to send logs to API");
237
237
  }
238
238
  };
239
+ //# sourceMappingURL=api.js.map
package/build/bin.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ import { cp } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { parseArgs } from "node:util";
7
+ import { sendFinalizeToAPI } from "./api.js";
8
+ import { config, configure, isPlatformModeConfig } from "./config.js";
9
+ import { log } from "./log.js";
10
+ import { getPlatformApiToken, platformRunner, runner } from "./runner.js";
11
+ import { uploadStorybook } from "./uploadStorybook.js";
12
+ import { getVersion, isLocalDebugMode } from "./utils.js";
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ const { positionals: commandArgs, values: optionValues } = parseArgs({
16
+ args: process.argv.slice(2),
17
+ options: {
18
+ help: { type: "boolean", short: "h" },
19
+ version: { type: "boolean", short: "v" },
20
+ },
21
+ allowPositionals: true,
22
+ strict: false,
23
+ });
24
+ const version = getVersion();
25
+ if (optionValues.version) {
26
+ log.process("info", "general", version ?? "unknown");
27
+ process.exit(0);
28
+ }
29
+ if (optionValues.help) {
30
+ printHelp();
31
+ process.exit(0);
32
+ }
33
+ if (version) {
34
+ log.process("info", "general", `Version: ${version}`);
35
+ }
36
+ function printHelp() {
37
+ log.process("info", "general", [
38
+ "Usage: pixel-storybook [command] [options]",
39
+ "",
40
+ "Visual regression testing tool for Storybook. Captures screenshots",
41
+ "via Playwright and compares them against baselines.",
42
+ "",
43
+ "Commands:",
44
+ " init-js Create a lostpixel.config.js in the current directory",
45
+ " init-ts Create a lostpixel.config.ts in the current directory",
46
+ " update Update baseline images with the current shots",
47
+ " local Enable local debug mode",
48
+ " meta Generate metadata for each shot",
49
+ " finalize Finalize a platform run (platform mode)",
50
+ " upload-storybook Upload a Storybook build to the platform",
51
+ "",
52
+ "Options:",
53
+ " -h, --help Print this help message and exit",
54
+ " -v, --version Print the version and exit",
55
+ " -m <mode> Set the mode (e.g. update)",
56
+ " --shard <n/total> Run a specific shard of the suite (e.g. 2/4)",
57
+ "",
58
+ "Environment variables:",
59
+ " LOST_PIXEL_MODE Same as -m",
60
+ ' LOST_PIXEL_LOCAL Set to "true" for local debug mode',
61
+ ' LOST_PIXEL_GENERATE_META Set to "true" to generate metadata',
62
+ " LOST_PIXEL_SHARD Same as --shard",
63
+ ].join("\n"));
64
+ }
65
+ (async () => {
66
+ if (commandArgs.includes("init-js")) {
67
+ log.process("info", "general", "Initializing javascript lost-pixel config");
68
+ await cp(path.join(__dirname, "..", "config-templates", "example.lostpixel.config.js"), path.join(process.cwd(), "./lostpixel.config.js"));
69
+ log.process("info", "general", "✅ Config successfully initialized");
70
+ }
71
+ else if (commandArgs.includes("init-ts")) {
72
+ log.process("info", "general", "Initializing typescript lost-pixel config");
73
+ // Replace local type resolution with module resolution
74
+ const file = readFileSync(path.join(__dirname, "..", "config-templates", "example.lostpixel.config.ts"));
75
+ const modifiedFile = file.toString().replace("../src/config", "lost-pixel");
76
+ writeFileSync(path.join(process.cwd(), "./lostpixel.config.ts"), modifiedFile);
77
+ log.process("info", "general", "✅ Config successfully initialized");
78
+ }
79
+ else {
80
+ await configure({
81
+ localDebugMode: isLocalDebugMode(),
82
+ });
83
+ if (isPlatformModeConfig(config)) {
84
+ log.process("info", "general", `🚀 Starting Pixel Storybook in 'platform' mode`);
85
+ const apiToken = await getPlatformApiToken(config);
86
+ if (commandArgs.includes("finalize")) {
87
+ await sendFinalizeToAPI(config, apiToken);
88
+ }
89
+ else if (commandArgs.includes("upload-storybook")) {
90
+ log.process("info", "general", "📤 Starting Pixel storybook build upload");
91
+ await uploadStorybook(config, apiToken);
92
+ }
93
+ else {
94
+ await platformRunner(config, apiToken);
95
+ }
96
+ }
97
+ else {
98
+ log.process("info", "general", `🚀 Starting Pixel Storybook in 'generateOnly' mode`);
99
+ await runner(config);
100
+ }
101
+ }
102
+ })();
103
+ //# sourceMappingURL=bin.js.map
@@ -1,10 +1,10 @@
1
- import type { ShotItem } from './types.js';
1
+ import type { ShotItem } from "./types.js";
2
2
  export declare const checkDifferences: (shotItems: ShotItem[]) => Promise<{
3
3
  aboveThresholdDifferenceItems: {
4
+ url: string;
4
5
  shotMode: "storybook";
5
6
  id: string;
6
7
  shotName: string;
7
- url: string;
8
8
  filePathBaseline: string;
9
9
  filePathCurrent: string;
10
10
  filePathDifference: string;
@@ -31,10 +31,10 @@ export declare const checkDifferences: (shotItems: ShotItem[]) => Promise<{
31
31
  waitForSelector?: string | undefined;
32
32
  }[];
33
33
  noBaselinesItems: {
34
+ url: string;
34
35
  shotMode: "storybook";
35
36
  id: string;
36
37
  shotName: string;
37
- url: string;
38
38
  filePathBaseline: string;
39
39
  filePathCurrent: string;
40
40
  filePathDifference: string;
@@ -1,15 +1,15 @@
1
- import { existsSync, writeFileSync } from 'node:fs';
2
- import path from 'node:path';
3
- import { compareImages } from './compare/compare.js';
4
- import { mapLimit } from './concurrency.js';
5
- import { config, isPlatformModeConfig } from './config.js';
6
- import { log } from './log.js';
7
- import { featureNotSupported, shallGenerateMeta } from './utils.js';
1
+ import { existsSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { compareImages } from "./compare/compare.js";
4
+ import { mapLimit } from "./concurrency.js";
5
+ import { config, isPlatformModeConfig } from "./config.js";
6
+ import { log } from "./log.js";
7
+ import { featureNotSupported, shallGenerateMeta } from "./utils.js";
8
8
  export const checkDifferences = async (shotItems) => {
9
9
  if (isPlatformModeConfig(config)) {
10
- return featureNotSupported('checkDifferences()');
10
+ return featureNotSupported("checkDifferences()");
11
11
  }
12
- log.process('info', 'general', `Comparing ${shotItems.length} screenshots using '${config.compareEngine}' as compare engine`);
12
+ log.process("info", "general", `Comparing ${shotItems.length} screenshots using '${config.compareEngine}' as compare engine`);
13
13
  const total = shotItems.length;
14
14
  const noBaselinesItems = [];
15
15
  const aboveThresholdDifferenceItems = [];
@@ -23,12 +23,12 @@ export const checkDifferences = async (shotItems) => {
23
23
  itemIndex: index,
24
24
  totalItems: total,
25
25
  })
26
- .process('info', 'general', message);
26
+ .process("info", "general", message);
27
27
  };
28
28
  logger(`Comparing '${shotItem.id}'`);
29
29
  const baselineImageExists = existsSync(shotItem.filePathBaseline);
30
30
  if (!baselineImageExists) {
31
- logger('Baseline image missing. Will be treated as addition.');
31
+ logger("Baseline image missing. Will be treated as addition.");
32
32
  noBaselinesItems.push(shotItem);
33
33
  return;
34
34
  }
@@ -55,13 +55,14 @@ export const checkDifferences = async (shotItems) => {
55
55
  }
56
56
  }
57
57
  else {
58
- logger('No difference found.');
58
+ logger("No difference found.");
59
59
  }
60
60
  });
61
61
  if (shallGenerateMeta()) {
62
- log.process('info', 'general', `Writing meta file with ${Object.entries(comparisonResults).length} items.`);
63
- writeFileSync(`${path.join(config.imagePathCurrent, 'meta')}.json`, JSON.stringify(comparisonResults, null, 2));
62
+ log.process("info", "general", `Writing meta file with ${Object.entries(comparisonResults).length} items.`);
63
+ writeFileSync(`${path.join(config.imagePathCurrent, "meta")}.json`, JSON.stringify(comparisonResults, null, 2));
64
64
  }
65
- log.process('info', 'general', 'Comparison done!');
65
+ log.process("info", "general", "Comparison done!");
66
66
  return { aboveThresholdDifferenceItems, noBaselinesItems };
67
67
  };
68
+ //# sourceMappingURL=checkDifferences.js.map
@@ -1,5 +1,5 @@
1
- import { type CompareResult } from './pixelmatch.js';
2
- export { checkThreshold } from './pixelmatch.js';
1
+ import { type CompareResult } from "./pixelmatch.js";
2
+ export { checkThreshold } from "./pixelmatch.js";
3
3
  export declare const compareImagesViaPixelmatch: (threshold: number, baselineShotPath: string, currentShotPath: string, differenceShotPath?: string) => Promise<CompareResult>;
4
4
  export declare const compareImagesViaOdiff: (threshold: number, baselineShotPath: string, currentShotPath: string, differenceShotPath: string) => Promise<CompareResult>;
5
5
  export declare const compareImages: (threshold: number, baselineShotPath: string, currentShotPath: string, differenceShotPath: string) => Promise<CompareResult>;
@@ -1,18 +1,18 @@
1
- import { existsSync } from 'node:fs';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { Worker } from 'node:worker_threads';
5
- import { compare as odiffCompare } from 'odiff-bin';
6
- import { config, isPlatformModeConfig } from '../config.js';
7
- import { featureNotSupported } from '../utils.js';
8
- import { runPixelmatchComparison } from './pixelmatch.js';
9
- export { checkThreshold } from './pixelmatch.js';
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { Worker } from "node:worker_threads";
5
+ import { compare as odiffCompare } from "odiff-bin";
6
+ import { config, isPlatformModeConfig } from "../config.js";
7
+ import { featureNotSupported } from "../utils.js";
8
+ import { runPixelmatchComparison } from "./pixelmatch.js";
9
+ export { checkThreshold } from "./pixelmatch.js";
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
  // Resolve the compiled worker script. Available after `pnpm build`.
13
13
  // When running from source (e.g. vitest), the .js file won't exist
14
14
  // and we fall back to inline comparison on the main thread.
15
- const workerScript = path.join(__dirname, 'worker.js');
15
+ const workerScript = path.join(__dirname, "worker.js");
16
16
  const canUseWorker = existsSync(workerScript);
17
17
  const comparePixelmatchWorker = (threshold, baselineShotPath, currentShotPath, differenceShotPath) => {
18
18
  return new Promise((resolve, reject) => {
@@ -24,9 +24,9 @@ const comparePixelmatchWorker = (threshold, baselineShotPath, currentShotPath, d
24
24
  differenceShotPath,
25
25
  },
26
26
  });
27
- worker.on('message', resolve);
28
- worker.on('error', reject);
29
- worker.on('exit', (code) => {
27
+ worker.on("message", resolve);
28
+ worker.on("error", reject);
29
+ worker.on("exit", (code) => {
30
30
  if (code !== 0) {
31
31
  reject(new Error(`Pixelmatch worker exited with code ${code}`));
32
32
  }
@@ -50,7 +50,7 @@ export const compareImagesViaOdiff = async (threshold, baselineShotPath, current
50
50
  isWithinThreshold: true,
51
51
  };
52
52
  }
53
- if (result.reason === 'pixel-diff') {
53
+ if (result.reason === "pixel-diff") {
54
54
  let isWithinThreshold = true;
55
55
  // Treat theshold as percentage
56
56
  const pixelDifferencePercentage = Number(result.diffPercentage / 100);
@@ -71,10 +71,11 @@ export const compareImagesViaOdiff = async (threshold, baselineShotPath, current
71
71
  };
72
72
  export const compareImages = async (threshold, baselineShotPath, currentShotPath, differenceShotPath) => {
73
73
  if (isPlatformModeConfig(config)) {
74
- return featureNotSupported('compareImages()');
74
+ return featureNotSupported("compareImages()");
75
75
  }
76
- if (config.compareEngine === 'pixelmatch') {
76
+ if (config.compareEngine === "pixelmatch") {
77
77
  return compareImagesViaPixelmatch(threshold, baselineShotPath, currentShotPath, differenceShotPath);
78
78
  }
79
79
  return compareImagesViaOdiff(threshold, baselineShotPath, currentShotPath, differenceShotPath);
80
80
  };
81
+ //# sourceMappingURL=compare.js.map
@@ -1,7 +1,7 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
2
- import pixelmatch from 'pixelmatch';
3
- import { PNG } from 'pngjs';
4
- import { resizeImage } from './utils.js';
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import pixelmatch from "pixelmatch";
3
+ import { PNG } from "pngjs";
4
+ import { resizeImage } from "./utils.js";
5
5
  export const checkThreshold = (threshold, pixelsTotal, pixelDifference) => {
6
6
  // Treat theshold as percentage
7
7
  if (threshold < 1) {
@@ -14,13 +14,18 @@ export const runPixelmatchComparison = (threshold, baselineShotPath, currentShot
14
14
  const baselineImageBuffer = readFileSync(baselineShotPath);
15
15
  const currentImageBuffer = readFileSync(currentShotPath);
16
16
  if (baselineImageBuffer.equals(currentImageBuffer)) {
17
- return { pixelDifference: 0, pixelDifferencePercentage: 0, isWithinThreshold: true };
17
+ return {
18
+ pixelDifference: 0,
19
+ pixelDifferencePercentage: 0,
20
+ isWithinThreshold: true,
21
+ };
18
22
  }
19
23
  let baselineImage = PNG.sync.read(baselineImageBuffer);
20
24
  let currentImage = PNG.sync.read(currentImageBuffer);
21
25
  const maxWidth = Math.max(baselineImage.width || 100, currentImage.width || 100);
22
26
  const maxHeight = Math.max(baselineImage.height || 100, currentImage.height || 100);
23
- if (baselineImage.width !== currentImage.width || baselineImage.height !== currentImage.height) {
27
+ if (baselineImage.width !== currentImage.width ||
28
+ baselineImage.height !== currentImage.height) {
24
29
  baselineImage = resizeImage(baselineImage, maxWidth, maxHeight);
25
30
  currentImage = resizeImage(currentImage, maxWidth, maxHeight);
26
31
  }
@@ -44,3 +49,4 @@ export const runPixelmatchComparison = (threshold, baselineShotPath, currentShot
44
49
  isWithinThreshold: true,
45
50
  };
46
51
  };
52
+ //# sourceMappingURL=pixelmatch.js.map
@@ -1,2 +1,2 @@
1
- import { PNG } from 'pngjs';
1
+ import { PNG } from "pngjs";
2
2
  export declare const resizeImage: (originalImage: PNG, width: number, height: number) => PNG;
@@ -1,4 +1,4 @@
1
- import { PNG } from 'pngjs';
1
+ import { PNG } from "pngjs";
2
2
  export const resizeImage = (originalImage, width, height) => {
3
3
  const newImage = new PNG({
4
4
  width,
@@ -8,7 +8,6 @@ export const resizeImage = (originalImage, width, height) => {
8
8
  });
9
9
  for (let x = 0; x < width; x++) {
10
10
  for (let y = 0; y < height; y++) {
11
- // eslint-disable-next-line no-bitwise
12
11
  const index = ((width * y + x) << 2) + 3;
13
12
  newImage.data[index] = 64;
14
13
  }
@@ -16,3 +15,4 @@ export const resizeImage = (originalImage, width, height) => {
16
15
  PNG.bitblt(originalImage, newImage, 0, 0, originalImage.width, originalImage.height, 0, 0);
17
16
  return newImage;
18
17
  };
18
+ //# sourceMappingURL=utils.js.map
@@ -1,6 +1,7 @@
1
1
  // This file runs inside a worker_threads Worker.
2
2
  // It performs the CPU-bound pixelmatch comparison off the main thread.
3
- import { parentPort, workerData } from 'node:worker_threads';
4
- import { runPixelmatchComparison } from './pixelmatch.js';
3
+ import { parentPort, workerData } from "node:worker_threads";
4
+ import { runPixelmatchComparison } from "./pixelmatch.js";
5
5
  const result = runPixelmatchComparison(workerData.threshold, workerData.baselineShotPath, workerData.currentShotPath, workerData.differenceShotPath);
6
6
  parentPort?.postMessage(result);
7
+ //# sourceMappingURL=worker.js.map
@@ -1,16 +1,16 @@
1
1
  /**
2
- * Default number of concurrent shots to take, derived from the number of
3
- * CPUs the process is allowed to use (respects cgroup CPU quotas).
2
+ * Default number of concurrent shots to take, derived from the number of CPUs
3
+ * the process is allowed to use (respects cgroup CPU quotas).
4
4
  */
5
5
  export declare const defaultShotConcurrency: () => number;
6
6
  /**
7
- * Run an array of async tasks with a concurrency limit.
8
- * Drop-in replacement for `async.mapLimit`.
7
+ * Run an array of async tasks with a concurrency limit. Drop-in replacement for
8
+ * `async.mapLimit`.
9
9
  */
10
10
  export declare const mapLimit: <T, R>(items: Iterable<T>, limit: number, fn: (item: T) => Promise<R>) => Promise<R[]>;
11
11
  /**
12
- * Retry an async function with exponential backoff.
13
- * Drop-in replacement for `async.retry`.
12
+ * Retry an async function with exponential backoff. Drop-in replacement for
13
+ * `async.retry`.
14
14
  */
15
15
  export declare const retry: <T>(options: {
16
16
  times: number;