Add image-diff-checker extension#17275
Conversation
|
Congratulations on your new Raycast extension! 🚀 Due to our current reduced availability, the initial review may take up to 10-15 business days Once the PR is approved and merged, the extension will be available on our Store. |
There was a problem hiding this comment.
PR Summary
Added a new Image Diff Checker extension that compares two images and highlights differences, supporting JPEG, JPG, PNG, and GIF formats.
- The extension uses
pixelmatchandjimplibraries to process images and generate visual diffs with a clean form-based UI - The implementation includes proper file validation with test coverage in
src/hooks/use-image-form/file-validation.spec.ts - The
metadatafolder with screenshots is missing but required since this is a view command (https://developers.raycast.com/basics/prepare-an-extension-for-store#how-to-use-it) - The
comparefunction insrc/utils/pixelmatch.tsshould be wrapped in a try-catch block since image processing operations can fail - The
fileValidationfunction insrc/hooks/use-image-form/file-validation.tsdoesn't explicitly returnundefinedwhen validation passes
💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!
12 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile
| export const fileValidation = (value?: string[]) => { | ||
| if (!value) return "The item is required."; | ||
| if (value?.length === 0) return "The item is required."; | ||
| const isValid = checkExtension(value[0]); | ||
| if (!isValid) return "Invalid file type."; | ||
| }; |
There was a problem hiding this comment.
logic: The function doesn't return anything when validation passes. This will return undefined which might cause issues with form validation. Consider returning undefined explicitly or returning null to indicate successful validation.
| export const fileValidation = (value?: string[]) => { | |
| if (!value) return "The item is required."; | |
| if (value?.length === 0) return "The item is required."; | |
| const isValid = checkExtension(value[0]); | |
| if (!isValid) return "Invalid file type."; | |
| }; | |
| export const fileValidation = (value?: string[]) => { | |
| if (!value) return "The item is required."; | |
| if (value?.length === 0) return "The item is required."; | |
| const isValid = checkExtension(value[0]); | |
| if (!isValid) return "Invalid file type."; | |
| return undefined; // Explicitly return undefined for valid files | |
| }; |
| describe("required", () => { | ||
| test("should return required error for empty array", () => { | ||
| expect(fileValidation([])).toBe(ERRORS.required); | ||
| }); |
There was a problem hiding this comment.
logic: Missing test for the undefined input case. The fileValidation function handles both empty arrays and undefined values, but only the empty array case is tested here.
| "pixelmatch": "^7.1.0", | ||
| "pngjs": "^7.0.0" |
There was a problem hiding this comment.
style: There's a version mismatch between pixelmatch v7.1.0 and the @types/pngjs v6.0.5. The pixelmatch library is using pngjs v7.0.0, but the type definitions are for v6.x
| onSubmit(values) { | ||
| const diffImageSource = compare(values.actual[0], values.expected[0]); | ||
| createMarkdown(diffImageSource); | ||
| }, |
There was a problem hiding this comment.
logic: Missing error handling for image comparison. If compare() or createMarkdown() fails, there's no error handling or feedback to the user.
| const createMarkdown = async ( | ||
| diffImageSource: Promise<{ | ||
| diffBuffer: Buffer; | ||
| width: number; | ||
| height: number; | ||
| }>, | ||
| ) => { |
There was a problem hiding this comment.
style: Accepting a Promise as a parameter instead of awaiting it in the caller creates unnecessary complexity.
| if (expectedImage.bitmap.width !== width || expectedImage.bitmap.height !== height) { | ||
| expectedImage.resize({ w: width, h: height }); | ||
| } |
There was a problem hiding this comment.
style: Resizing only the expected image might lead to distortion if aspect ratios differ significantly. Consider maintaining aspect ratio or providing an option for different scaling strategies.
| const expectedBuffer = expectedImage.bitmap.data; | ||
| const diffBuffer = Buffer.alloc(actualBuffer.length); | ||
|
|
||
| pixelmatch(actualBuffer, expectedBuffer, diffBuffer, width, height, { threshold: 0.2 }); |
There was a problem hiding this comment.
style: The threshold value of 0.2 is hardcoded. Consider making this configurable via preferences to allow users to adjust sensitivity of the comparison.
| const actualImage = await Jimp.read(actual); | ||
| const expectedImage = await Jimp.read(expected); |
There was a problem hiding this comment.
logic: Missing error handling for image loading failures. If either image can't be read, this will throw an unhandled exception.
|
Is this ready for another review? |
|
@pernielsentikaer Yes, I have addressed the feedback and made the necessary changes. The pull request is now ready for another review. |
pernielsentikaer
left a comment
There was a problem hiding this comment.
Hi 👋
Looks good to me, approved 🔥
|
Published to the Raycast Store: |
|
🎉 🎉 🎉 Such a great contribution deserves a reward, but unfortunately we couldn't find your Raycast account based on your GitHub username (@yasuhiro-yamamoto). |
Description
Screencast
Checklist
npm run buildand tested this distribution build in Raycastassetsfolder are used by the extension itselfREADMEare placed outside of themetadatafolder