diff --git a/.reviews/api/src/index.js.json b/.reviews/api/src/index.js.json new file mode 100644 index 0000000..c069902 --- /dev/null +++ b/.reviews/api/src/index.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "// Catches all uncaught errors so process never dies\nprocess.on('uncaughtException', err => {\n\tconsole.log('Caught exception: ', err);\n});\n\nimport dotenv from 'dotenv'\ndotenv.config()\nimport bodyParser from 'body-parser'\nimport express from 'express'\nimport cors from 'cors'\nimport http from 'http'\nconst app = express()\nconst server = http.createServer(app);\napp.use(bodyParser.json())\nconst port = process.env.PORT\nimport axios from 'axios'\nimport pug from 'pug'\nimport { DateTime } from 'luxon'\nimport bcrypt from 'bcrypt'\nconst saltRounds = 10\nimport { get } from 'lodash-es'\nimport { default as s } from 'smarts'\nconst smarts = s()\nimport thingtime from 'thingtime'\nimport { Server } from 'socket.io';\nconst io = new Server(server, {\n\tcors: {\n\t\torigin: '*',\n\t\tmethods: ['GET', 'POST'],\n\t},\n})\n\nimport { v4 as uuidv4 } from 'uuid'\n\n(async () => {\n\n\tawait thingtime.init()\n\n\t// Express middleware\n\tapp.use(cors({\n\t\torigin: '*',\n\t}))\n\n\tapp.get('/', (req, res) => {\n\t\tres.status(200).send('Hello ThingTime World!')\n\t})\n\n\tapp.get('/v1/thing', async (req, res) => {\n\n\t\t// console.log('req', req.query)\n\n\t\tconst { request } = req.query\n\n\t\tif (request === 'get') {\n\n\t\t\tconst { uuid } = req.query\n\n\t\t\tconst thing = await thingtime.get(uuid)\n\n\t\t\tres.status(200).send({\n\t\t\t\tthing: smarts.serialize(thing),\n\t\t\t})\n\n\t\t} else {\n\n\t\t\tlet { thing } = req.query\n\t\t\tthing = smarts.parse(thing, { noFunctions: true })\n\n\t\t\tif (!thing) {\n\t\t\t\tres.status(400).send('No thing provided')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tawait thingtime.save(thing)\n\n\t\t\tres.status(200).send()\n\t\t}\n\n\t})\n\n\t// socket config\n\tio.on('connection', socket => {\n\t\tconsole.log('Something with socket id', socket.id, 'connected')\n\n\t\tsocket.on('registerListener', msg => {\n\t\t\tconsole.log('Message from socket with id', socket.id)\n\t\t\tthingtime.registerListener(socket, msg.uuid)\n\t\t})\n\n\t\tsocket.on('disconnect', () => {\n\t\t\tconsole.log('Something with socket id', socket.id, 'disconnected')\n\t\t})\n\t});\n\n\tapp.get('/privacy-policy', async (req, res) => res.status(200).send(pug.compile(`\n.privacy-policy(\n style=\"max-width: 600px margin: 0 auto padding-top: 100px\"\n)\n h1.title.text-white(\n style='fontSize: 48px fontWeight: bold'\n )\n | Privacy Policy\n p.subtitle\n | The friendly ThingTime API Privacy Policy\n p.answer\n .pt-12 This API uses YouTube API Services\n .pt-12 ThingTime API does not use any analytics tools to store any data, nor does it store any user data of any kind.\n .pt-12 We do not allow any 3rd parties to serve Ads on ThingTime API\n .pt-12 You can contact ThingTime API at\n a(href='emailto:subberAPI@alopu.com', style=\"padding-left: 6px\") subberAPI@alopu.com\n .pt-12\n a.underline(href='https://www.youtube.com/t/terms') YouTube Terms of Service\n .pt-12\n a.underline(href='https://policies.google.com/privacy') Google Privacy Policy\nstyle(type=\"text/css\").\n .pt-12 { padding-top: 12px }\n`)()))\n\n\tserver.listen(port, () => {\n\t\tconsole.log(`Example app listening at http://localhost:${port}`)\n\t})\n})()\n", + "review": "**Grade: 5**\n\n# Bugs\n- The code does not handle the absence of a port number gracefully, which could cause the server to fail to start if `process.env.PORT` is undefined.\n- Catching all uncaught exceptions without a strategy for handling various error types or restarting the server can potentially lead to data loss or corrupted states.\n- On the `/v1/thing` endpoint, the conversion of `thing` using `smarts.parse` does not handle parse errors, which might result in application crashes or undefined behavior.\n\n# Optimizations\n- Import statements can be organized in a logical order and grouped, which helps enhance readability and maintainability.\n- Use a dedicated error-handling middleware for better express.js error management.\n- Use environment variable validation to ensure that necessary variables like `PORT` are properly set.\n- Implement rate limiting and input validation for API endpoints to improve security and resilience against misuse.\n- Consider using async error handling techniques like `express-async-errors` for better async control flow.\n\n# Good points\n- The code uses `dotenv` for environment variable management, which is a good practice.\n- Usage of modern JavaScript features like async/await contributes to code readability and maintainability.\n- The code is clear in showing its intended functionality, separating concerns using different routes and setups for Express and Socket.io servers.\n\n# Summary\nThe code sets up an Express app combined with a Socket.io server that seems to support real-time features, likely related to the \"ThingTime\" library. However, it suffers from error handling that might not be robust enough to manage all potential faults safely, especially with uncaught exceptions that are not thoroughly processed. The imports could be better organized and more stringent validation should be applied throughout to ensure the server's resilience and robustness.\n\n# Open source alternatives\n- [Socket.io](https://github.com/socketio/socket.io) for real-time, bidirectional, and event-based communication.\n- [Express](https://github.com/expressjs/express) to manage web server routes and middleware.\n- [dotenv](https://github.com/motdotla/dotenv) for loading environment variables.\n- [node-fetch](https://github.com/node-fetch/node-fetch) or [axios](https://github.com/axios/axios) alternatives for making HTTP requests.\n- [mongoose](https://github.com/Automattic/mongoose) or [Sequelize](https://github.com/sequelize/sequelize) for robust data interaction.", + "filename": "index.js", + "path": "api/src/index.js", + "directory": "src", + "grade": 5, + "size": 2984, + "line_count": 123 +} \ No newline at end of file diff --git a/.reviews/api/src/index.js.md b/.reviews/api/src/index.js.md new file mode 100644 index 0000000..77cf8bd --- /dev/null +++ b/.reviews/api/src/index.js.md @@ -0,0 +1,28 @@ +**Grade: 5** + +# Bugs +- The code does not handle the absence of a port number gracefully, which could cause the server to fail to start if `process.env.PORT` is undefined. +- Catching all uncaught exceptions without a strategy for handling various error types or restarting the server can potentially lead to data loss or corrupted states. +- On the `/v1/thing` endpoint, the conversion of `thing` using `smarts.parse` does not handle parse errors, which might result in application crashes or undefined behavior. + +# Optimizations +- Import statements can be organized in a logical order and grouped, which helps enhance readability and maintainability. +- Use a dedicated error-handling middleware for better express.js error management. +- Use environment variable validation to ensure that necessary variables like `PORT` are properly set. +- Implement rate limiting and input validation for API endpoints to improve security and resilience against misuse. +- Consider using async error handling techniques like `express-async-errors` for better async control flow. + +# Good points +- The code uses `dotenv` for environment variable management, which is a good practice. +- Usage of modern JavaScript features like async/await contributes to code readability and maintainability. +- The code is clear in showing its intended functionality, separating concerns using different routes and setups for Express and Socket.io servers. + +# Summary +The code sets up an Express app combined with a Socket.io server that seems to support real-time features, likely related to the "ThingTime" library. However, it suffers from error handling that might not be robust enough to manage all potential faults safely, especially with uncaught exceptions that are not thoroughly processed. The imports could be better organized and more stringent validation should be applied throughout to ensure the server's resilience and robustness. + +# Open source alternatives +- [Socket.io](https://github.com/socketio/socket.io) for real-time, bidirectional, and event-based communication. +- [Express](https://github.com/expressjs/express) to manage web server routes and middleware. +- [dotenv](https://github.com/motdotla/dotenv) for loading environment variables. +- [node-fetch](https://github.com/node-fetch/node-fetch) or [axios](https://github.com/axios/axios) alternatives for making HTTP requests. +- [mongoose](https://github.com/Automattic/mongoose) or [Sequelize](https://github.com/sequelize/sequelize) for robust data interaction. \ No newline at end of file diff --git a/.reviews/api/src/test.js.json b/.reviews/api/src/test.js.json new file mode 100644 index 0000000..aef8dc1 --- /dev/null +++ b/.reviews/api/src/test.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import tests from 'tests'\n\ntests()\n", + "review": "# 2\n\n## Bugs\n- The import statement syntax is incorrect; it should be `import` and not importing a valid module.\n- `'tests'` suggests either a module or a file intended to be imported, but there's no indication that such a module exists or can be found.\n- The code snippet lacks function definitions, variable declarations, or necessary imports to actually run any tests.\n\n## Optimizations\n- Ensure that the module or file you are trying to import actually exists in your project or is installable via a package manager like npm.\n- Consider using a specific testing framework like Jest, Mocha, or Jasmine which comes with its own set of testing utilities and functions.\n- Use descriptive and explicit import paths or module names to enhance readability and maintainability.\n- Implement error handling to manage module load failures.\n\n## Good points\n- There's an intention to modularize testing by importing tests, which can help with code organization if implemented correctly.\n\n## Summary\nThe code is very minimal and likely will not run as intended without additional context or information. The intent seems to be to execute some tests, but as it stands, it lacks the necessary components to be functional. It appears to be a conceptual starting point rather than a complete test file. To be functional, it should include error checking, specify correct module importing, and probably use a well-established test framework for better structure and functionality.\n\n## Open source alternatives\n- **Jest**: A delightful JavaScript Testing Framework with a focus on simplicity.\n- **Mocha**: A feature-rich JavaScript test framework running on Node.js and in the browser.\n- **Jasmine**: A behavior-driven development framework for testing JavaScript code.", + "filename": "test.js", + "path": "api/src/test.js", + "directory": "src", + "grade": 2, + "size": 35, + "line_count": 4 +} \ No newline at end of file diff --git a/.reviews/api/src/test.js.md b/.reviews/api/src/test.js.md new file mode 100644 index 0000000..758209e --- /dev/null +++ b/.reviews/api/src/test.js.md @@ -0,0 +1,23 @@ +# 2 + +## Bugs +- The import statement syntax is incorrect; it should be `import` and not importing a valid module. +- `'tests'` suggests either a module or a file intended to be imported, but there's no indication that such a module exists or can be found. +- The code snippet lacks function definitions, variable declarations, or necessary imports to actually run any tests. + +## Optimizations +- Ensure that the module or file you are trying to import actually exists in your project or is installable via a package manager like npm. +- Consider using a specific testing framework like Jest, Mocha, or Jasmine which comes with its own set of testing utilities and functions. +- Use descriptive and explicit import paths or module names to enhance readability and maintainability. +- Implement error handling to manage module load failures. + +## Good points +- There's an intention to modularize testing by importing tests, which can help with code organization if implemented correctly. + +## Summary +The code is very minimal and likely will not run as intended without additional context or information. The intent seems to be to execute some tests, but as it stands, it lacks the necessary components to be functional. It appears to be a conceptual starting point rather than a complete test file. To be functional, it should include error checking, specify correct module importing, and probably use a well-established test framework for better structure and functionality. + +## Open source alternatives +- **Jest**: A delightful JavaScript Testing Framework with a focus on simplicity. +- **Mocha**: A feature-rich JavaScript test framework running on Node.js and in the browser. +- **Jasmine**: A behavior-driven development framework for testing JavaScript code. \ No newline at end of file diff --git a/.reviews/ecosystem.config.js.json b/.reviews/ecosystem.config.js.json new file mode 100644 index 0000000..e950653 --- /dev/null +++ b/.reviews/ecosystem.config.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "module.exports = {\n apps: [\n {\n script: 'npm run app',\n name: 'tt',\n namespace: 'thingtime'\n }\n // {\n // \tscript: 'npm run api',\n // \tname: 'tt-api',\n // namespace: \"thingtime\",\n // \twatch: ['node', 'node/*/node_modules', 'node/**/node_modules', 'node/node_modules'],\n // \tignore_watch: [],\n // },\n ]\n};\n", + "review": "8\n\n### Bugs\n- No apparent bugs in the current implementation.\n\n### Optimizations\n- Consider separating the configurations into environment-specific files to improve scalability and maintainability.\n- The commented-out section could be removed if it's not intended to be used, making the code cleaner.\n\n### Good points\n- The code follows the PM2 configuration structure correctly.\n- It utilizes namespacing for better organization in PM2.\n- Use of comments to indicate potential future expansions (API configuration).\n\n### Summary\nThis is a clean and straightforward PM2 configuration file for managing Node.js applications. It defines an application (`tt`) with its associated namespace `thingtime`. The use of comments suggests a forward-looking approach to potential expansions, although that also indicates areas where optimization may be needed for future maintainability and clarity.\n\n### Open source alternatives\n- **PM2** itself is an open-source process manager for Node.js that you are currently configuring.\n- **Forever:** Another Node.js script manager for process management that could be an alternative to PM2.\n- **nodemon:** While not exactly the same as PM2, nodemon can be used for automatically restarting the node application when file changes are detected.", + "filename": "ecosystem.config.js", + "path": "ecosystem.config.js", + "directory": "", + "grade": 8, + "size": 350, + "line_count": 17 +} \ No newline at end of file diff --git a/.reviews/ecosystem.config.js.md b/.reviews/ecosystem.config.js.md new file mode 100644 index 0000000..6d2b633 --- /dev/null +++ b/.reviews/ecosystem.config.js.md @@ -0,0 +1,21 @@ +8 + +### Bugs +- No apparent bugs in the current implementation. + +### Optimizations +- Consider separating the configurations into environment-specific files to improve scalability and maintainability. +- The commented-out section could be removed if it's not intended to be used, making the code cleaner. + +### Good points +- The code follows the PM2 configuration structure correctly. +- It utilizes namespacing for better organization in PM2. +- Use of comments to indicate potential future expansions (API configuration). + +### Summary +This is a clean and straightforward PM2 configuration file for managing Node.js applications. It defines an application (`tt`) with its associated namespace `thingtime`. The use of comments suggests a forward-looking approach to potential expansions, although that also indicates areas where optimization may be needed for future maintainability and clarity. + +### Open source alternatives +- **PM2** itself is an open-source process manager for Node.js that you are currently configuring. +- **Forever:** Another Node.js script manager for process management that could be an alternative to PM2. +- **nodemon:** While not exactly the same as PM2, nodemon can be used for automatically restarting the node application when file changes are detected. \ No newline at end of file diff --git a/.reviews/next/global.d.ts.json b/.reviews/next/global.d.ts.json new file mode 100644 index 0000000..e4a2c39 --- /dev/null +++ b/.reviews/next/global.d.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "interface EventTarget {\n value: any\n}\n", + "review": "# 2\n\n### Bugs\n- The `EventTarget` interface incorrectly includes a `value` property, which is not standard.\n- The interface does not conform to TypeScript's expected definition for an event target.\n \n### Optimizations\n- Implement the `EventTarget` interface according to the DOM specification, which does not include a `value` property.\n- If you need to extend `EventTarget` to have a `value` property, consider creating a separate interface that extends it.\n \n### Good points\n- The code uses TypeScript interfaces to define structures, which is in line with TypeScript best practices.\n\n### Summary\nThe interface provided incorrectly attempts to add a `value` property to the `EventTarget` interface. In web APIs, `EventTarget` is a standard interface in the DOM (Document Object Model) that does not have a `value` property; it is more commonly associated with event handling capabilities like `addEventListener`. If there's a specific need for an object with a `value` within your events, consider extending `EventTarget` or using a different name for the custom interface.\n\n### Open source alternatives\n- [TypeScript DOM Types](https://github.com/microsoft/TypeScript/tree/main/lib) includes correct standard DOM type declarations, including `EventTarget`.\n", + "filename": "global.d.ts", + "path": "next/global.d.ts", + "directory": "next", + "grade": 2, + "size": 39, + "line_count": 4 +} \ No newline at end of file diff --git a/.reviews/next/global.d.ts.md b/.reviews/next/global.d.ts.md new file mode 100644 index 0000000..6beb9d4 --- /dev/null +++ b/.reviews/next/global.d.ts.md @@ -0,0 +1,18 @@ +# 2 + +### Bugs +- The `EventTarget` interface incorrectly includes a `value` property, which is not standard. +- The interface does not conform to TypeScript's expected definition for an event target. + +### Optimizations +- Implement the `EventTarget` interface according to the DOM specification, which does not include a `value` property. +- If you need to extend `EventTarget` to have a `value` property, consider creating a separate interface that extends it. + +### Good points +- The code uses TypeScript interfaces to define structures, which is in line with TypeScript best practices. + +### Summary +The interface provided incorrectly attempts to add a `value` property to the `EventTarget` interface. In web APIs, `EventTarget` is a standard interface in the DOM (Document Object Model) that does not have a `value` property; it is more commonly associated with event handling capabilities like `addEventListener`. If there's a specific need for an object with a `value` within your events, consider extending `EventTarget` or using a different name for the custom interface. + +### Open source alternatives +- [TypeScript DOM Types](https://github.com/microsoft/TypeScript/tree/main/lib) includes correct standard DOM type declarations, including `EventTarget`. diff --git a/.reviews/next/next.config.mjs.json b/.reviews/next/next.config.mjs.json new file mode 100644 index 0000000..bf1917e --- /dev/null +++ b/.reviews/next/next.config.mjs.json @@ -0,0 +1,11 @@ +{ + "extension": ".mjs", + "source": "/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default nextConfig;\n", + "review": "8\n\n### Bugs\n- No apparent bugs in the given code.\n\n### Optimizations\n- Consider adding detailed configurations to utilize Next.js's full potential features, such as custom webpack modifications, export paths, etc.\n- Consider defining environment variables for build optimization and customization.\n \n### Good points\n- The use of JSDoc type annotations helps to improve code understanding and maintainability.\n- The configuration is well-structured and easy to read.\n- It is export ready for further module augmentations or extensions.\n\n### Summary\nThe provided code is a simple and clean Next.js configuration template with no present bugs. While it does not contain many configurations, it's readily set up to be extended with more detailed settings to leverage Next.js capabilities for a production-ready application.\n\n### Open source alternatives\n- **Create Next App:** A boilerplate to kickstart a Next.js project, which often contains a suggested configuration setup.\n- **Next.js Examples:** Various GitHub repositories from the Next.js GitHub organization that demonstrate different configurations and usages of Next.js.", + "filename": "next.config.mjs", + "path": "next/next.config.mjs", + "directory": "next", + "grade": 8, + "size": 92, + "line_count": 5 +} \ No newline at end of file diff --git a/.reviews/next/next.config.mjs.md b/.reviews/next/next.config.mjs.md new file mode 100644 index 0000000..5e30b1c --- /dev/null +++ b/.reviews/next/next.config.mjs.md @@ -0,0 +1,20 @@ +8 + +### Bugs +- No apparent bugs in the given code. + +### Optimizations +- Consider adding detailed configurations to utilize Next.js's full potential features, such as custom webpack modifications, export paths, etc. +- Consider defining environment variables for build optimization and customization. + +### Good points +- The use of JSDoc type annotations helps to improve code understanding and maintainability. +- The configuration is well-structured and easy to read. +- It is export ready for further module augmentations or extensions. + +### Summary +The provided code is a simple and clean Next.js configuration template with no present bugs. While it does not contain many configurations, it's readily set up to be extended with more detailed settings to leverage Next.js capabilities for a production-ready application. + +### Open source alternatives +- **Create Next App:** A boilerplate to kickstart a Next.js project, which often contains a suggested configuration setup. +- **Next.js Examples:** Various GitHub repositories from the Next.js GitHub organization that demonstrate different configurations and usages of Next.js. \ No newline at end of file diff --git a/.reviews/next/postcss.config.mjs.json b/.reviews/next/postcss.config.mjs.json new file mode 100644 index 0000000..733baa4 --- /dev/null +++ b/.reviews/next/postcss.config.mjs.json @@ -0,0 +1,11 @@ +{ + "extension": ".mjs", + "source": "/** @type {import('postcss-load-config').Config} */\nconst config = {\n plugins: {\n tailwindcss: {},\n },\n};\n\nexport default config;\n", + "review": "8\n\n## Bugs\n- No bugs identified in the code.\n\n## Optimizations\n- Consider adding more detailed configuration for `tailwindcss` if there's a need for custom setup or integration with other PostCSS plugins.\n- If you plan to use other PostCSS plugins, list them under `plugins` to ensure future scalability and maintainability.\n\n## Good points\n- Code is clean, minimalistic, and serves its purpose efficiently.\n- Usage of type annotations (`@type`) to ensure the configuration object aligns with expected type from `postcss-load-config`.\n- Conforms to modern JavaScript standards by using `export default`.\n\n## Summary\nThe code provided is a minimal but effective configuration for using `tailwindcss` with PostCSS. It leverages type annotations to ensure compatibility with the expected configuration object. While it currently only includes Tailwind CSS, it's easily extendable to incorporate more plugins if needed. The minimalist design is sufficient, but additional configurations might be necessary depending on the complexity of the project.\n\n## Open source alternatives\n- **PostCSS CLI**: For using PostCSS directly via CLI without requiring additional configuration in JavaScript.\n- **Create React App (CRA) with PostCSS**: When building React applications, CRA provides a way to integrate PostCSS with minimal manual configuration.\n- **Vue CLI**: For Vue.js applications, Vue CLI allows for integration with PostCSS using plugin options.\n- **Parcel**: A zero-config bundler that supports PostCSS and TailwindCSS out of the box for projects seeking simplicity and speed without extensive setup.", + "filename": "postcss.config.mjs", + "path": "next/postcss.config.mjs", + "directory": "next", + "grade": 8, + "size": 135, + "line_count": 9 +} \ No newline at end of file diff --git a/.reviews/next/postcss.config.mjs.md b/.reviews/next/postcss.config.mjs.md new file mode 100644 index 0000000..ca749ff --- /dev/null +++ b/.reviews/next/postcss.config.mjs.md @@ -0,0 +1,22 @@ +8 + +## Bugs +- No bugs identified in the code. + +## Optimizations +- Consider adding more detailed configuration for `tailwindcss` if there's a need for custom setup or integration with other PostCSS plugins. +- If you plan to use other PostCSS plugins, list them under `plugins` to ensure future scalability and maintainability. + +## Good points +- Code is clean, minimalistic, and serves its purpose efficiently. +- Usage of type annotations (`@type`) to ensure the configuration object aligns with expected type from `postcss-load-config`. +- Conforms to modern JavaScript standards by using `export default`. + +## Summary +The code provided is a minimal but effective configuration for using `tailwindcss` with PostCSS. It leverages type annotations to ensure compatibility with the expected configuration object. While it currently only includes Tailwind CSS, it's easily extendable to incorporate more plugins if needed. The minimalist design is sufficient, but additional configurations might be necessary depending on the complexity of the project. + +## Open source alternatives +- **PostCSS CLI**: For using PostCSS directly via CLI without requiring additional configuration in JavaScript. +- **Create React App (CRA) with PostCSS**: When building React applications, CRA provides a way to integrate PostCSS with minimal manual configuration. +- **Vue CLI**: For Vue.js applications, Vue CLI allows for integration with PostCSS using plugin options. +- **Parcel**: A zero-config bundler that supports PostCSS and TailwindCSS out of the box for projects seeking simplicity and speed without extensive setup. \ No newline at end of file diff --git a/.reviews/next/src/app/globals.css.json b/.reviews/next/src/app/globals.css.json new file mode 100644 index 0000000..3c150f5 --- /dev/null +++ b/.reviews/next/src/app/globals.css.json @@ -0,0 +1,11 @@ +{ + "extension": ".css", + "source": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n --foreground-rgb: 0, 0, 0;\n --background-start-rgb: 214, 219, 220;\n --background-end-rgb: 255, 255, 255;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --foreground-rgb: 255, 255, 255;\n --background-start-rgb: 0, 0, 0;\n --background-end-rgb: 0, 0, 0;\n }\n}\n\nbody {\n color: rgb(var(--foreground-rgb));\n background: linear-gradient(\n to bottom,\n transparent,\n rgb(var(--background-end-rgb))\n )\n rgb(var(--background-start-rgb));\n}\n\n@layer utilities {\n .text-balance {\n text-wrap: balance;\n }\n}\n", + "review": "7\n\n### Bugs\n- No explicit bugs, but a potential issue is readability in certain color contrast conditions between foreground and background colors.\n\n### Optimizations\n- Consider defining more color variables to provide additional customization options for foreground background colors.\n- Use named variables instead of relying directly on CSS color values (e.g., `primary-color`, `secondary-color`).\n- Consider using Tailwind's `@apply` directive to apply utility classes instead of defining custom CSS classes unless necessary.\n- The linear gradient could be more detailed, using more stops if necessary, to ensure smoother transitions between colors.\n\n### Good Points\n- The use of CSS variables (`--foreground-rgb`, `--background-start-rgb`, `--background-end-rgb`) for color themes allows for easy theme adaptability and reuse.\n- Integrating `prefers-color-scheme` for dark mode adaptation is a modern and user-friendly approach.\n- Tailwind CSS is leveraged effectively to manage base, components, and utilities, promoting consistent styling.\n\n### Summary\nThe code is well-structured, utilizing Tailwind CSS to maintain concise styling while accommodating dark mode through the `prefers-color-scheme` media query. It effectively employs CSS variables for better maintainability and adaptability of themes. However, further optimization using Tailwind\u2019s directives might reduce redundancy or complexity.\n\n### Open source alternatives\n- **DaisyUI**: An extension of Tailwind CSS that offers theming and component libraries out-of-the-box.\n- **Twemoji**: If the code aims towards design systems, Twemoji can provide consistent emoji styling integrated with Tailwind CSS.\n- **Chakra UI and Headless UI**: Both can work with Tailwind to offer accessible components and themes.", + "filename": "globals.css", + "path": "next/src/app/globals.css", + "directory": "app", + "grade": 7, + "size": 606, + "line_count": 34 +} \ No newline at end of file diff --git a/.reviews/next/src/app/globals.css.md b/.reviews/next/src/app/globals.css.md new file mode 100644 index 0000000..52a563a --- /dev/null +++ b/.reviews/next/src/app/globals.css.md @@ -0,0 +1,23 @@ +7 + +### Bugs +- No explicit bugs, but a potential issue is readability in certain color contrast conditions between foreground and background colors. + +### Optimizations +- Consider defining more color variables to provide additional customization options for foreground background colors. +- Use named variables instead of relying directly on CSS color values (e.g., `primary-color`, `secondary-color`). +- Consider using Tailwind's `@apply` directive to apply utility classes instead of defining custom CSS classes unless necessary. +- The linear gradient could be more detailed, using more stops if necessary, to ensure smoother transitions between colors. + +### Good Points +- The use of CSS variables (`--foreground-rgb`, `--background-start-rgb`, `--background-end-rgb`) for color themes allows for easy theme adaptability and reuse. +- Integrating `prefers-color-scheme` for dark mode adaptation is a modern and user-friendly approach. +- Tailwind CSS is leveraged effectively to manage base, components, and utilities, promoting consistent styling. + +### Summary +The code is well-structured, utilizing Tailwind CSS to maintain concise styling while accommodating dark mode through the `prefers-color-scheme` media query. It effectively employs CSS variables for better maintainability and adaptability of themes. However, further optimization using Tailwind’s directives might reduce redundancy or complexity. + +### Open source alternatives +- **DaisyUI**: An extension of Tailwind CSS that offers theming and component libraries out-of-the-box. +- **Twemoji**: If the code aims towards design systems, Twemoji can provide consistent emoji styling integrated with Tailwind CSS. +- **Chakra UI and Headless UI**: Both can work with Tailwind to offer accessible components and themes. \ No newline at end of file diff --git a/.reviews/next/src/app/page.module.css.json b/.reviews/next/src/app/page.module.css.json new file mode 100644 index 0000000..8b99688 --- /dev/null +++ b/.reviews/next/src/app/page.module.css.json @@ -0,0 +1,11 @@ +{ + "extension": ".css", + "source": ".main {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: center;\n padding: 6rem;\n min-height: 100vh;\n}\n\n.description {\n display: inherit;\n justify-content: inherit;\n align-items: inherit;\n font-size: 0.85rem;\n max-width: var(--max-width);\n width: 100%;\n z-index: 2;\n font-family: var(--font-mono);\n}\n\n.description a {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 0.5rem;\n}\n\n.description p {\n position: relative;\n margin: 0;\n padding: 1rem;\n background-color: rgba(var(--callout-rgb), 0.5);\n border: 1px solid rgba(var(--callout-border-rgb), 0.3);\n border-radius: var(--border-radius);\n}\n\n.code {\n font-weight: 700;\n font-family: var(--font-mono);\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(4, minmax(25%, auto));\n max-width: 100%;\n width: var(--max-width);\n}\n\n.card {\n padding: 1rem 1.2rem;\n border-radius: var(--border-radius);\n background: rgba(var(--card-rgb), 0);\n border: 1px solid rgba(var(--card-border-rgb), 0);\n transition: background 200ms, border 200ms;\n}\n\n.card span {\n display: inline-block;\n transition: transform 200ms;\n}\n\n.card h2 {\n font-weight: 600;\n margin-bottom: 0.7rem;\n}\n\n.card p {\n margin: 0;\n opacity: 0.6;\n font-size: 0.9rem;\n line-height: 1.5;\n max-width: 30ch;\n text-wrap: balance;\n}\n\n.center {\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n padding: 4rem 0;\n}\n\n.center::before {\n background: var(--secondary-glow);\n border-radius: 50%;\n width: 480px;\n height: 360px;\n margin-left: -400px;\n}\n\n.center::after {\n background: var(--primary-glow);\n width: 240px;\n height: 180px;\n z-index: -1;\n}\n\n.center::before,\n.center::after {\n content: \"\";\n left: 50%;\n position: absolute;\n filter: blur(45px);\n transform: translateZ(0);\n}\n\n.logo {\n position: relative;\n}\n/* Enable hover only on non-touch devices */\n@media (hover: hover) and (pointer: fine) {\n .card:hover {\n background: rgba(var(--card-rgb), 0.1);\n border: 1px solid rgba(var(--card-border-rgb), 0.15);\n }\n\n .card:hover span {\n transform: translateX(4px);\n }\n}\n\n@media (prefers-reduced-motion) {\n .card:hover span {\n transform: none;\n }\n}\n\n/* Mobile */\n@media (max-width: 700px) {\n .content {\n padding: 4rem;\n }\n\n .grid {\n grid-template-columns: 1fr;\n margin-bottom: 120px;\n max-width: 320px;\n text-align: center;\n }\n\n .card {\n padding: 1rem 2.5rem;\n }\n\n .card h2 {\n margin-bottom: 0.5rem;\n }\n\n .center {\n padding: 8rem 0 6rem;\n }\n\n .center::before {\n transform: none;\n height: 300px;\n }\n\n .description {\n font-size: 0.8rem;\n }\n\n .description a {\n padding: 1rem;\n }\n\n .description p,\n .description div {\n display: flex;\n justify-content: center;\n position: fixed;\n width: 100%;\n }\n\n .description p {\n align-items: center;\n inset: 0 0 auto;\n padding: 2rem 1rem 1.4rem;\n border-radius: 0;\n border: none;\n border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);\n background: linear-gradient(\n to bottom,\n rgba(var(--background-start-rgb), 1),\n rgba(var(--callout-rgb), 0.5)\n );\n background-clip: padding-box;\n backdrop-filter: blur(24px);\n }\n\n .description div {\n align-items: flex-end;\n pointer-events: none;\n inset: auto 0 0;\n padding: 2rem;\n height: 200px;\n background: linear-gradient(\n to bottom,\n transparent 0%,\n rgb(var(--background-end-rgb)) 40%\n );\n z-index: 1;\n }\n}\n\n/* Tablet and Smaller Desktop */\n@media (min-width: 701px) and (max-width: 1120px) {\n .grid {\n grid-template-columns: repeat(2, 50%);\n }\n}\n\n@media (prefers-color-scheme: dark) {\n .vercelLogo {\n filter: invert(1);\n }\n\n .logo {\n filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);\n }\n}\n\n@keyframes rotate {\n from {\n transform: rotate(360deg);\n }\n to {\n transform: rotate(0deg);\n }\n}\n", + "review": "7\n\n### Bugs\n- None apparent in the given CSS code.\n\n### Optimizations\n- Use `inherit` only when necessary in `.description` to ensure clarity, actual values could be more explicit for better understanding or maintenance.\n- Consider reducing the use of `z-index` and use a concise commenting strategy for complex positioning within the layout.\n- Use CSS custom properties more extensively for color and font values to ensure ease in theme manipulation and consistency.\n\n### Good points\n- Responsive design approach is thoughtfully addressed with the appropriate media queries for different screen sizes.\n- Use of CSS variables (`--max-width`, `--font-mono`, etc.) for customizable themes and consistent styling.\n- Hover effects are disabled on touch devices, improving usability.\n- `prefers-reduced-motion` media query accommodates users with motion sensitivity.\n\n### Summary\nThe CSS code is generally well-structured and addresses various important aspects of styling, including responsiveness and accessibility. The use of CSS variables and media queries is commendable and structurally rigorous, ensuring different devices are catered to. There are no evident bugs, but there are opportunities for optimizations, particularly in the use of explicit values instead of `inherit` to improve clarity for maintainers.\n\n### Open source alternatives\n- Bootstrap: A responsive grid-based framework that offers utility classes and components.\n- Tailwind CSS: A utility-first CSS framework for rapid UI development.\n- Foundation: A responsive front-end framework with similar responsive design capabilities.", + "filename": "page.module.css", + "path": "next/src/app/page.module.css", + "directory": "app", + "grade": 7, + "size": 3926, + "line_count": 231 +} \ No newline at end of file diff --git a/.reviews/next/src/app/page.module.css.md b/.reviews/next/src/app/page.module.css.md new file mode 100644 index 0000000..51ec201 --- /dev/null +++ b/.reviews/next/src/app/page.module.css.md @@ -0,0 +1,23 @@ +7 + +### Bugs +- None apparent in the given CSS code. + +### Optimizations +- Use `inherit` only when necessary in `.description` to ensure clarity, actual values could be more explicit for better understanding or maintenance. +- Consider reducing the use of `z-index` and use a concise commenting strategy for complex positioning within the layout. +- Use CSS custom properties more extensively for color and font values to ensure ease in theme manipulation and consistency. + +### Good points +- Responsive design approach is thoughtfully addressed with the appropriate media queries for different screen sizes. +- Use of CSS variables (`--max-width`, `--font-mono`, etc.) for customizable themes and consistent styling. +- Hover effects are disabled on touch devices, improving usability. +- `prefers-reduced-motion` media query accommodates users with motion sensitivity. + +### Summary +The CSS code is generally well-structured and addresses various important aspects of styling, including responsiveness and accessibility. The use of CSS variables and media queries is commendable and structurally rigorous, ensuring different devices are catered to. There are no evident bugs, but there are opportunities for optimizations, particularly in the use of explicit values instead of `inherit` to improve clarity for maintainers. + +### Open source alternatives +- Bootstrap: A responsive grid-based framework that offers utility classes and components. +- Tailwind CSS: A utility-first CSS framework for rapid UI development. +- Foundation: A responsive front-end framework with similar responsive design capabilities. \ No newline at end of file diff --git a/.reviews/next/src/global-types.d.ts.json b/.reviews/next/src/global-types.d.ts.json new file mode 100644 index 0000000..16e9507 --- /dev/null +++ b/.reviews/next/src/global-types.d.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "// modify window / globalThis to support any properties\n// so there's no property does not exist on window typescript errors\n\n// Path: app/src/global-types.d.ts\ndeclare global {\n interface Window {\n [key: string]: any;\n }\n \n // Modify React component props/args to allow anything\n // so we don't get errors \n // Property 'fullPath' does not exist on type '{ children?: ReactNode; }'.\n \n interface ForwardRefRenderFunction {\n T: any;\n (props: any, ref: React.Ref): React.ReactElement | null;\n }\n \n}\n\nexport {};\n", + "review": "# 4\n\n## Bugs\n- The `ForwardRefRenderFunction` interface is incorrectly defined as it represents a function type, not an interface. This issue would lead to TypeScript errors.\n- The definition `[key: string]: any;` on the `Window` interface can lead to allowing any kind of property, disregarding type safety and introducing potential type errors.\n\n## Optimizations\n- Instead of using `[key: string]: any;` for the `Window` interface, consider defining specific properties you need to extend, to retain type safety while also extending flexibility as needed.\n- Correctly define `ForwardRefRenderFunction` as a function type instead of an interface. Use TypeScript's types for this rather than `any`, if possible.\n \n## Good points\n- The code correctly uses TypeScript's `declare global` to extend the `Window` interface.\n \n## Summary\nThe TypeScript code tries to make the `Window` object and React component props more flexible by allowing any properties to be used, which can be beneficial in certain use cases. However, the approach sacrifices type safety, one of the core benefits of using TypeScript. The incorrect approach taken with `ForwardRefRenderFunction` as an interface rather than a type/function can lead to errors and reduced clarity. \n\n## Open source alternatives\n- `global.d.ts`: An existing setup often used in TypeScript projects is not an external library but an industry-standard approach, which can offer examples or templates on how to properly extend global interfaces.\n- `typescript-react-boilerplate`: Provides a more structured way of managing React TypeScript projects, possibly offering guidance in extending types without losing type safety.", + "filename": "global-types.d.ts", + "path": "next/src/global-types.d.ts", + "directory": "src", + "grade": 4, + "size": 534, + "line_count": 22 +} \ No newline at end of file diff --git a/.reviews/next/src/global-types.d.ts.md b/.reviews/next/src/global-types.d.ts.md new file mode 100644 index 0000000..4708ae6 --- /dev/null +++ b/.reviews/next/src/global-types.d.ts.md @@ -0,0 +1,19 @@ +# 4 + +## Bugs +- The `ForwardRefRenderFunction` interface is incorrectly defined as it represents a function type, not an interface. This issue would lead to TypeScript errors. +- The definition `[key: string]: any;` on the `Window` interface can lead to allowing any kind of property, disregarding type safety and introducing potential type errors. + +## Optimizations +- Instead of using `[key: string]: any;` for the `Window` interface, consider defining specific properties you need to extend, to retain type safety while also extending flexibility as needed. +- Correctly define `ForwardRefRenderFunction` as a function type instead of an interface. Use TypeScript's types for this rather than `any`, if possible. + +## Good points +- The code correctly uses TypeScript's `declare global` to extend the `Window` interface. + +## Summary +The TypeScript code tries to make the `Window` object and React component props more flexible by allowing any properties to be used, which can be beneficial in certain use cases. However, the approach sacrifices type safety, one of the core benefits of using TypeScript. The incorrect approach taken with `ForwardRefRenderFunction` as an interface rather than a type/function can lead to errors and reduced clarity. + +## Open source alternatives +- `global.d.ts`: An existing setup often used in TypeScript projects is not an external library but an industry-standard approach, which can offer examples or templates on how to properly extend global interfaces. +- `typescript-react-boilerplate`: Provides a more structured way of managing React TypeScript projects, possibly offering guidance in extending types without losing type safety. \ No newline at end of file diff --git a/.reviews/next/src/gp/GradientPath.js.json b/.reviews/next/src/gp/GradientPath.js.json new file mode 100644 index 0000000..bebcdab --- /dev/null +++ b/.reviews/next/src/gp/GradientPath.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { DEFAULT_PRECISION } from \"./_constants\"\nimport { getData, strokeToFill } from \"./_data\"\nimport { convertPathToNode, segmentToD, styleAttrs, svgElem } from \"./_utils\"\n\nexport const GradientPath = class {\n constructor({ path, segments, samples, precision = DEFAULT_PRECISION }) {\n // If the path being passed isn't a DOM node already, make it one\n this.path = convertPathToNode(path)\n\n this.segments = segments\n this.samples = samples\n this.precision = precision\n\n // Check if nodeName is path and that the path is closed, otherwise it's closed by default\n this.pathClosed =\n this.path.nodeName == \"path\"\n ? this.path.getAttribute(\"d\").match(/z/gi)\n : true\n\n // Store the render cycles that the user creates\n this.renders = []\n\n // Append a group to the SVG to capture everything we render and ensure our paths and circles are properly encapsulated\n this.svg = path.closest(\"svg\")\n this.group = svgElem(\"g\", {\n class: \"gradient-path\",\n })\n\n // Get the data\n this.data = getData({ path, segments, samples, precision })\n\n // Append the main group to the SVG\n this.svg.appendChild(this.group)\n\n // Remove the main path once we have the data values\n this.path.parentNode.removeChild(this.path)\n }\n\n remove() {\n this.group.parentNode.removeChild(this.group)\n }\n\n render({\n type,\n stroke = [\"white\", \"black\", \"white\"],\n strokeWidth = 1,\n fill = [\"white\", \"black\", \"white\"],\n width,\n animation = {},\n }) {\n // Store information from this render cycle\n const renderCycle = {}\n\n // Create a group for each element\n const elemGroup = svgElem(\"g\", { class: `element-${type}` })\n\n this.group.appendChild(elemGroup)\n renderCycle.group = elemGroup\n\n if (type === \"path\") {\n // If we specify a width and fill, then we need to outline the path and then average the join points of the segments\n // If we do not specify a width and fill, then we will be stroking and can leave the data \"as is\"\n renderCycle.data =\n width && fill\n ? strokeToFill(this.data, width, this.precision, this.pathClosed)\n : this.data\n\n for (let j = 0; j < renderCycle.data.length; j++) {\n const { samples, progress } = renderCycle.data[j]\n\n // Create a path for each segment and append it to its elemGroup\n elemGroup.appendChild(\n svgElem(\"path\", {\n class: \"path-segment\",\n d: segmentToD(samples),\n ...styleAttrs(fill, stroke, strokeWidth, progress, animation),\n })\n )\n }\n } else if (type === \"circle\") {\n renderCycle.data = this.data.flatMap(({ samples }) => samples)\n\n for (let j = 0; j < renderCycle.data.length; j++) {\n const { x, y, progress } = renderCycle.data[j]\n\n // Create a circle for each sample and append it to its elemGroup\n elemGroup.appendChild(\n svgElem(\"circle\", {\n class: \"circle-sample\",\n cx: x,\n cy: y,\n r: width / 2,\n ...styleAttrs(fill, stroke, strokeWidth, progress, animation),\n })\n )\n }\n }\n\n // Save the information in the current renderCycle and pop it onto the renders array\n this.renders.push(renderCycle)\n\n // Return this for method chaining\n return this\n }\n}\n", + "review": "## 6\n\n### Bugs\n- No explicit handling of cases where `path` might not be properly converted to a DOM node or may be misformatted.\n- Assumes all necessary imports and functions exist and function as intended without verifying their presence or their return types.\n\n### Optimizations\n- Consider adding type-checking or input validation for the `path` and other parameters in the constructor to ensure they meet expected criteria.\n- Error handling could be improved, particularly around DOM manipulations to handle unexpected behavior gracefully.\n- Remove the path element and its parent only if they are present to prevent potential runtime errors.\n- Performance could be enhanced by defensive copying or checking mutation behavior for reused data structures, e.g., `renderCycle.data`.\n\n### Good points\n- Uses modular imports and exports, indicating a well-structured codebase.\n- The `GradientPath` class design pattern is clear, separating concerns with methods focused on rendering and removal.\n- Configurable parameters for rendering give flexibility to users for customizing the output.\n\n### Summary\nThe provided code defines a `GradientPath` class used to render paths and circles based on a given SVG path element. It validates the path's closure status, removes the node after capturing data, and has rendering methods that support different configurations for customization. While the functionality is well compartmentalized, the code could benefit from improved validation, error handling, and certain performance optimizations.\n\n### Open source alternatives\n- [Snap.svg](http://snapsvg.io/): A JavaScript library for working with SVG.\n- [Two.js](https://two.js.org/): A two-dimensional drawing library for modern web browsers.", + "filename": "GradientPath.js", + "path": "next/src/gp/GradientPath.js", + "directory": "gp", + "grade": 6, + "size": 3348, + "line_count": 106 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/GradientPath.js.md b/.reviews/next/src/gp/GradientPath.js.md new file mode 100644 index 0000000..c7ca954 --- /dev/null +++ b/.reviews/next/src/gp/GradientPath.js.md @@ -0,0 +1,23 @@ +## 6 + +### Bugs +- No explicit handling of cases where `path` might not be properly converted to a DOM node or may be misformatted. +- Assumes all necessary imports and functions exist and function as intended without verifying their presence or their return types. + +### Optimizations +- Consider adding type-checking or input validation for the `path` and other parameters in the constructor to ensure they meet expected criteria. +- Error handling could be improved, particularly around DOM manipulations to handle unexpected behavior gracefully. +- Remove the path element and its parent only if they are present to prevent potential runtime errors. +- Performance could be enhanced by defensive copying or checking mutation behavior for reused data structures, e.g., `renderCycle.data`. + +### Good points +- Uses modular imports and exports, indicating a well-structured codebase. +- The `GradientPath` class design pattern is clear, separating concerns with methods focused on rendering and removal. +- Configurable parameters for rendering give flexibility to users for customizing the output. + +### Summary +The provided code defines a `GradientPath` class used to render paths and circles based on a given SVG path element. It validates the path's closure status, removes the node after capturing data, and has rendering methods that support different configurations for customization. While the functionality is well compartmentalized, the code could benefit from improved validation, error handling, and certain performance optimizations. + +### Open source alternatives +- [Snap.svg](http://snapsvg.io/): A JavaScript library for working with SVG. +- [Two.js](https://two.js.org/): A two-dimensional drawing library for modern web browsers. \ No newline at end of file diff --git a/.reviews/next/src/gp/Sample.js.json b/.reviews/next/src/gp/Sample.js.json new file mode 100644 index 0000000..9c619e8 --- /dev/null +++ b/.reviews/next/src/gp/Sample.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export default class Sample {\n constructor({ x, y, progress, segment }) {\n this.x = x\n this.y = y\n this.progress = progress\n this.segment = segment\n }\n}\n", + "review": "# 6\n\n### Bugs\n- The code does not contain any apparent bugs, though its functionality is limited.\n\n### Optimizations\n- Add type-checking to ensure that `x`, `y`, `progress`, and `segment` are of the expected types.\n- Consider using default parameter values in the constructor for better flexibility.\n- Add documentation comments to explain the class functionality and its intended usage.\n\n### Good points\n- The class uses ES6 syntax, which is modern and widely supported.\n- Follows a clear naming convention for properties and the constructor.\n- Utilizes destructuring in the constructor for concise property assignment.\n\n### Summary\nThe code provided is a simple JavaScript class definition with a constructor that initializes four properties. It effectively uses modern JavaScript features like destructuring and concise methods. However, with its current functionality, it appears to be more of a placeholder or a data structure without any methods for data manipulation or validation. Adding comments and type checks could enhance its robustness and usability.\n\n### Open source alternatives\n- **Immutable.js**: While not a direct one-to-one for simple classes, Immutable.js provides immutable data structures, which are an alternative approach to handling clean and efficient data states in JavaScript.\n- **Ramda**: A practical library for functional programming in JavaScript that can facilitate the handling of data structures and transformations.", + "filename": "Sample.js", + "path": "next/src/gp/Sample.js", + "directory": "gp", + "grade": 6, + "size": 167, + "line_count": 9 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/Sample.js.md b/.reviews/next/src/gp/Sample.js.md new file mode 100644 index 0000000..b51bdde --- /dev/null +++ b/.reviews/next/src/gp/Sample.js.md @@ -0,0 +1,21 @@ +# 6 + +### Bugs +- The code does not contain any apparent bugs, though its functionality is limited. + +### Optimizations +- Add type-checking to ensure that `x`, `y`, `progress`, and `segment` are of the expected types. +- Consider using default parameter values in the constructor for better flexibility. +- Add documentation comments to explain the class functionality and its intended usage. + +### Good points +- The class uses ES6 syntax, which is modern and widely supported. +- Follows a clear naming convention for properties and the constructor. +- Utilizes destructuring in the constructor for concise property assignment. + +### Summary +The code provided is a simple JavaScript class definition with a constructor that initializes four properties. It effectively uses modern JavaScript features like destructuring and concise methods. However, with its current functionality, it appears to be more of a placeholder or a data structure without any methods for data manipulation or validation. Adding comments and type checks could enhance its robustness and usability. + +### Open source alternatives +- **Immutable.js**: While not a direct one-to-one for simple classes, Immutable.js provides immutable data structures, which are an alternative approach to handling clean and efficient data states in JavaScript. +- **Ramda**: A practical library for functional programming in JavaScript that can facilitate the handling of data structures and transformations. \ No newline at end of file diff --git a/.reviews/next/src/gp/Segment.js.json b/.reviews/next/src/gp/Segment.js.json new file mode 100644 index 0000000..a44bb71 --- /dev/null +++ b/.reviews/next/src/gp/Segment.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { getMiddleSample } from \"./_utils\"\n\nexport default class Segment {\n constructor({ samples }) {\n this.samples = samples\n this.progress = getMiddleSample(samples).progress\n }\n}\n", + "review": "8\n\n### Bugs\n- No apparent bugs were found in the code snippet itself.\n\n### Optimizations\n- Include input validation to check if `samples` is an array and contains the expected structure.\n- Add default values or error handling if `getMiddleSample(samples)` returns undefined or unexpected results.\n- Consider making the class immutable if the data should not change after initialization by using `Object.freeze`.\n\n### Good points\n- Good use of destructuring to make the constructor concise.\n- Assumes the existence of a utility function, `getMiddleSample`, promoting modular code.\n\n### Summary\nThe code is concise and appears to be functional, assuming the utility function works correctly. It could benefit from additional checks and validations to safeguard against potential runtime issues and improve robustness. \n\n### Open source alternatives\n- **Tone.js** - Can manage segments and samples as part of a larger audio manipulation library.\n- **wavesurfer.js** - Can be used for handling and visualizing audio segments with samples.", + "filename": "Segment.js", + "path": "next/src/gp/Segment.js", + "directory": "gp", + "grade": 8, + "size": 191, + "line_count": 9 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/Segment.js.md b/.reviews/next/src/gp/Segment.js.md new file mode 100644 index 0000000..3714574 --- /dev/null +++ b/.reviews/next/src/gp/Segment.js.md @@ -0,0 +1,20 @@ +8 + +### Bugs +- No apparent bugs were found in the code snippet itself. + +### Optimizations +- Include input validation to check if `samples` is an array and contains the expected structure. +- Add default values or error handling if `getMiddleSample(samples)` returns undefined or unexpected results. +- Consider making the class immutable if the data should not change after initialization by using `Object.freeze`. + +### Good points +- Good use of destructuring to make the constructor concise. +- Assumes the existence of a utility function, `getMiddleSample`, promoting modular code. + +### Summary +The code is concise and appears to be functional, assuming the utility function works correctly. It could benefit from additional checks and validations to safeguard against potential runtime issues and improve robustness. + +### Open source alternatives +- **Tone.js** - Can manage segments and samples as part of a larger audio manipulation library. +- **wavesurfer.js** - Can be used for handling and visualizing audio segments with samples. \ No newline at end of file diff --git a/.reviews/next/src/gp/_constants.js.json b/.reviews/next/src/gp/_constants.js.json new file mode 100644 index 0000000..be733ab --- /dev/null +++ b/.reviews/next/src/gp/_constants.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export const DEFAULT_PRECISION = 2\n", + "review": "8\n\n## Bugs\n- There are no bugs present in this one-line code snippet. \n\n## Optimizations\n- Consider adding a comment to provide context or an example for how `DEFAULT_PRECISION` might be used, especially if this is part of a larger codebase. This can help improve code readability.\n- Consider using more descriptive constant names depending on the context, like `DECIMAL_PRECISION` if it specifically relates to decimal numbers, to avoid ambiguity.\n\n## Good points\n- Using `const` ensures that the value remains immutable, which is a best practice for values meant to remain constant.\n- The intent of the code is clear, assuming that `DEFAULT_PRECISION` is used within a relevant context.\n\n## Summary\nThe code is a straightforward declaration of a constant, which suggests a reasonable approach to code structure by using constants for values that should not change. The code is clean, with no visible redundancies, but lacks context which might be crucial for understanding its purpose within a larger codebase.\n\n## Open source alternatives\n- Since this is merely a constant declaration, there aren\u2019t direct open source alternatives. However, for libraries that deal with precision in numerical computations, you might look into libraries like math.js or big.js which provide tools for dealing with numbers and precision that may incorporate similar constants internally.", + "filename": "_constants.js", + "path": "next/src/gp/_constants.js", + "directory": "gp", + "grade": 8, + "size": 35, + "line_count": 2 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/_constants.js.md b/.reviews/next/src/gp/_constants.js.md new file mode 100644 index 0000000..3aa948b --- /dev/null +++ b/.reviews/next/src/gp/_constants.js.md @@ -0,0 +1,18 @@ +8 + +## Bugs +- There are no bugs present in this one-line code snippet. + +## Optimizations +- Consider adding a comment to provide context or an example for how `DEFAULT_PRECISION` might be used, especially if this is part of a larger codebase. This can help improve code readability. +- Consider using more descriptive constant names depending on the context, like `DECIMAL_PRECISION` if it specifically relates to decimal numbers, to avoid ambiguity. + +## Good points +- Using `const` ensures that the value remains immutable, which is a best practice for values meant to remain constant. +- The intent of the code is clear, assuming that `DEFAULT_PRECISION` is used within a relevant context. + +## Summary +The code is a straightforward declaration of a constant, which suggests a reasonable approach to code structure by using constants for values that should not change. The code is clean, with no visible redundancies, but lacks context which might be crucial for understanding its purpose within a larger codebase. + +## Open source alternatives +- Since this is merely a constant declaration, there aren’t direct open source alternatives. However, for libraries that deal with precision in numerical computations, you might look into libraries like math.js or big.js which provide tools for dealing with numbers and precision that may incorporate similar constants internally. \ No newline at end of file diff --git a/.reviews/next/src/gp/_data.js.json b/.reviews/next/src/gp/_data.js.json new file mode 100644 index 0000000..9fdb4c2 --- /dev/null +++ b/.reviews/next/src/gp/_data.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { DEFAULT_PRECISION } from \"./_constants\"\nimport { convertPathToNode } from \"./_utils\"\nimport Sample from \"./Sample\"\nimport Segment from \"./Segment\"\n\n// The main function responsible for getting data\n// This will take a path, number of samples, number of samples, and a precision value\n// It will return an array of Segments, which in turn contains an array of Samples\n// This can later be used to generate a stroked path, converted to outlines for a filled path, or flattened for plotting SVG circles\nexport const getData = ({\n path,\n segments,\n samples,\n precision = DEFAULT_PRECISION,\n}) => {\n // Convert the given path to a DOM node if it isn't already one\n path = convertPathToNode(path)\n\n // We decrement the number of samples per segment because when we group them later we will add on the first sample of the following segment\n if (samples > 1) samples--\n\n // Get total length of path, total number of samples we will be generating, and two blank arrays to hold samples and segments\n const pathLength = path.getTotalLength(),\n totalSamples = segments * samples,\n allSamples = [],\n allSegments = []\n\n // For the number of total samples, get the x, y, and progress values for each sample along the path\n for (let sample = 0; sample <= totalSamples; sample++) {\n const progress = sample / totalSamples\n\n let { x, y } = path.getPointAtLength(progress * pathLength)\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n x = +x.toFixed(precision)\n y = +y.toFixed(precision)\n }\n\n // Create a new Sample and push it onto the allSamples array\n allSamples.push(new Sample({ x, y, progress }))\n }\n\n // Out of all the samples gathered previously, sort them into groups of segments\n // Each group includes the samples of the current segment, with the last sample being first sample from the next segment\n for (let segment = 0; segment < segments; segment++) {\n const currentStart = segment * samples,\n nextStart = currentStart + samples,\n segmentSamples = []\n\n // Push all current samples onto segmentSamples\n for (let samInSeg = 0; samInSeg < samples; samInSeg++) {\n segmentSamples.push(allSamples[currentStart + samInSeg])\n }\n\n // Push the first sample from the next segment onto segmentSamples\n segmentSamples.push(allSamples[nextStart])\n\n // Create a new Segment with the samples from segmentSamples\n allSegments.push(new Segment({ samples: segmentSamples }))\n }\n\n // Return our group of segments\n return allSegments\n}\n\n// The function responsible for converting strokable data (from getData()) into fillable data\n// This allows any SVG path to be filled instead of just stroked, allowing for the user to fill and stroke paths simultaneously\n// We start by outlining the stroked data given a specified width and the we average together the edges where adjacent segments touch\nexport const strokeToFill = (data, width, precision, pathClosed) => {\n const outlinedStrokes = outlineStrokes(data, width, precision),\n averagedSegmentJoins = averageSegmentJoins(\n outlinedStrokes,\n precision,\n pathClosed\n )\n\n return averagedSegmentJoins\n}\n\n// An internal function for outlining stroked data\nconst outlineStrokes = (data, width, precision) => {\n // We need to get the points perpendicular to a startPoint, given an angle, radius, and precision\n const getPerpSamples = (angle, radius, precision, startPoint) => {\n const p0 = new Sample({\n ...startPoint,\n x: Math.sin(angle) * radius + startPoint.x,\n y: -Math.cos(angle) * radius + startPoint.y,\n }),\n p1 = new Sample({\n ...startPoint,\n x: -Math.sin(angle) * radius + startPoint.x,\n y: Math.cos(angle) * radius + startPoint.y,\n })\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n p0.x = +p0.x.toFixed(precision)\n p0.y = +p0.y.toFixed(precision)\n p1.x = +p1.x.toFixed(precision)\n p1.y = +p1.y.toFixed(precision)\n }\n\n return [p0, p1]\n }\n\n // We need to set the radius (half of the width) and have a holding array for outlined Segments\n const radius = width / 2,\n outlinedData = []\n\n for (let i = 0; i < data.length; i++) {\n const samples = data[i].samples,\n segmentSamples = []\n\n // For each sample point and the following sample point (if there is one) compute the angle\n // Also compute the sample's various perpendicular points (with a distance of radius away from the sample point)\n for (let j = 0; j < samples.length; j++) {\n // If we're at the end of the segment and there are no further points, get outta here!\n if (samples[j + 1] === undefined) break\n\n const p0 = samples[j], // First point\n p1 = samples[j + 1], // Second point\n angle = Math.atan2(p1.y - p0.y, p1.x - p0.x), // Perpendicular angle to p0 and p1\n p0Perps = getPerpSamples(angle, radius, precision, p0), // Get perpedicular points with a distance of radius away from p0\n p1Perps = getPerpSamples(angle, radius, precision, p1) // Get perpedicular points with a distance of radius away from p1\n\n // We only need the p0 perpendenciular points for the first sample\n // The p0 for j > 0 will always be the same as p1 anyhow, so let's not add redundant points\n if (j === 0) {\n segmentSamples.push(...p0Perps)\n }\n\n // Always push the second sample point's perpendicular points\n segmentSamples.push(...p1Perps)\n }\n\n // segmentSamples is out of order...\n // Given a segmentSamples length of 8, the points need to be rearranged from: 0, 2, 4, 6, 7, 5, 3, 1\n outlinedData.push(\n new Segment({\n samples: [\n ...segmentSamples.filter((s, i) => i % 2 === 0),\n ...segmentSamples.filter((s, i) => i % 2 === 1).reverse(),\n ],\n })\n )\n }\n\n return outlinedData\n}\n\n// An internal function taking outlinedData (from outlineStrokes()) and averaging adjacent edges\n// If we didn't do this, our data would be fillable, but it would look stroked\n// This function fixes where segments overlap and underlap each other\nconst averageSegmentJoins = (outlinedData, precision, pathClosed) => {\n // Find the average x and y between two points (p0 and p1)\n const avg = (p0, p1) => ({\n x: (p0.x + p1.x) / 2,\n y: (p0.y + p1.y) / 2,\n })\n\n // Recombine the new x and y positions with all the other keys in the object\n const combine = (segment, pos, avg) => ({\n ...segment[pos],\n x: avg.x,\n y: avg.y,\n })\n\n const init_outlinedData = JSON.parse(JSON.stringify(outlinedData)) //clone initial outlinedData Object\n\n for (let i = 0; i < outlinedData.length; i++) {\n // If path is closed: the current segment's samples;\n // If path is open: the current segments' samples, as long as it's not the last segment; Otherwise, the current segments' sample of the initial outlinedData object\n const currentSamples = pathClosed\n ? outlinedData[i].samples\n : outlinedData[i + 1]\n ? outlinedData[i].samples\n : init_outlinedData[i].samples,\n // If path is closed: the next segment's samples, otherwise, the first segment's samples\n // If path is open: the next segment's samples, otherwise, the first segment's samples of the initial outlinedData object\n nextSamples = pathClosed\n ? outlinedData[i + 1]\n ? outlinedData[i + 1].samples\n : outlinedData[0].samples\n : outlinedData[i + 1]\n ? outlinedData[i + 1].samples\n : init_outlinedData[0].samples,\n currentMiddle = currentSamples.length / 2, // The \"middle\" sample in the current segment's samples\n nextEnd = nextSamples.length - 1 // The last sample in the next segment's samples\n\n // Average two sets of outlined samples to create p0Average and p1Average\n const p0Average = avg(currentSamples[currentMiddle - 1], nextSamples[0]),\n p1Average = avg(currentSamples[currentMiddle], nextSamples[nextEnd])\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n p0Average.x = +p0Average.x.toFixed(precision)\n p0Average.y = +p0Average.y.toFixed(precision)\n p1Average.x = +p1Average.x.toFixed(precision)\n p1Average.y = +p1Average.y.toFixed(precision)\n }\n\n // Replace the previous values with new Samples\n currentSamples[currentMiddle - 1] = new Sample({\n ...combine(currentSamples, currentMiddle - 1, p0Average),\n })\n currentSamples[currentMiddle] = new Sample({\n ...combine(currentSamples, currentMiddle, p1Average),\n })\n nextSamples[0] = new Sample({\n ...combine(nextSamples, 0, p0Average),\n })\n nextSamples[nextEnd] = new Sample({\n ...combine(nextSamples, nextEnd, p1Average),\n })\n }\n\n return outlinedData\n}\n", + "review": "# 7\n\n## Bugs\n- No validation of input parameters like `path`, which could lead to potential runtime errors if incorrect data types are provided.\n- Possibility of division by zero in `getData` if `segments` or `samples` is zero, which could raise an exception.\n- Assumes `path` has defined methods like `getTotalLength` without checking if they exist or handling errors if they're not available.\n- In `averageSegmentJoins`, there's potential risk of accessing undefined array elements if `outlinedData` length is less than expected, particularly in loop iterations.\n\n## Optimizations\n- Consider adding validation checks for input parameters (e.g., ensuring `segments` and `samples` are positive numbers).\n- Avoid unnecessary calculations by short-circuiting conditions when precision is not needed.\n- Use `Object.assign()` or spread operator to clone objects instead of JSON stringification and parsing for better performance.\n- Reduce redundancy by extracting repetitive logic, such as rounding and averaging, into separate utility functions.\n- Consider using more descriptive parameter names to enhance code readability.\n\n## Good points\n- Implements a clear transformation of path data to samples and segments, showing a logical step-by-step process.\n- Attempts to handle precision in the calculations, offering flexibility to the caller.\n- Thoroughly comments the purpose and process of each function and code block, aiding in comprehension.\n\n## Summary\nThe code effectively maps path data into segmented samples with an option for precision. It demonstrates consistent approach in processing data, maintaining modularity with separate functions for distinct tasks. However, this implementation lacks input validation, which can cause runtime issues with unexpected inputs. By addressing potential errors, optimizing code redundancy, and ensuring input validity, the solution can be made more robust and efficient.\n\n## Open source alternatives\n- Snap.svg: A JavaScript library for modern SVG graphics focusing on delivering faster performance and better optimization.\n- D3.js: While primarily focused on data visualization, it includes powerful utilities for manipulating documents based on data, including path generation and modification.", + "filename": "_data.js", + "path": "next/src/gp/_data.js", + "directory": "gp", + "grade": 7, + "size": 8782, + "line_count": 220 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/_data.js.md b/.reviews/next/src/gp/_data.js.md new file mode 100644 index 0000000..f0a8214 --- /dev/null +++ b/.reviews/next/src/gp/_data.js.md @@ -0,0 +1,26 @@ +# 7 + +## Bugs +- No validation of input parameters like `path`, which could lead to potential runtime errors if incorrect data types are provided. +- Possibility of division by zero in `getData` if `segments` or `samples` is zero, which could raise an exception. +- Assumes `path` has defined methods like `getTotalLength` without checking if they exist or handling errors if they're not available. +- In `averageSegmentJoins`, there's potential risk of accessing undefined array elements if `outlinedData` length is less than expected, particularly in loop iterations. + +## Optimizations +- Consider adding validation checks for input parameters (e.g., ensuring `segments` and `samples` are positive numbers). +- Avoid unnecessary calculations by short-circuiting conditions when precision is not needed. +- Use `Object.assign()` or spread operator to clone objects instead of JSON stringification and parsing for better performance. +- Reduce redundancy by extracting repetitive logic, such as rounding and averaging, into separate utility functions. +- Consider using more descriptive parameter names to enhance code readability. + +## Good points +- Implements a clear transformation of path data to samples and segments, showing a logical step-by-step process. +- Attempts to handle precision in the calculations, offering flexibility to the caller. +- Thoroughly comments the purpose and process of each function and code block, aiding in comprehension. + +## Summary +The code effectively maps path data into segmented samples with an option for precision. It demonstrates consistent approach in processing data, maintaining modularity with separate functions for distinct tasks. However, this implementation lacks input validation, which can cause runtime issues with unexpected inputs. By addressing potential errors, optimizing code redundancy, and ensuring input validity, the solution can be made more robust and efficient. + +## Open source alternatives +- Snap.svg: A JavaScript library for modern SVG graphics focusing on delivering faster performance and better optimization. +- D3.js: While primarily focused on data visualization, it includes powerful utilities for manipulating documents based on data, including path generation and modification. \ No newline at end of file diff --git a/.reviews/next/src/gp/_utils.js.json b/.reviews/next/src/gp/_utils.js.json new file mode 100644 index 0000000..d5b46e7 --- /dev/null +++ b/.reviews/next/src/gp/_utils.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import tinygradient from \"tinygradient\"\n\n// An internal function to help with easily creating SVG elements with an object of attributes\nexport const svgElem = (type, attrs) => {\n const elem = document.createElementNS(\"http://www.w3.org/2000/svg\", type),\n attributes = Object.keys(attrs)\n\n for (let i = 0; i < attributes.length; i++) {\n const attr = attributes[i]\n\n elem.setAttribute(attr, attrs[attr])\n }\n\n return elem\n}\n\n// An internal function to help with the repetition of adding fill, stroke, and stroke-width attributes\nexport const styleAttrs = (fill, stroke, strokeWidth, progress, animation) => {\n const determineColor = (type, progress) =>\n typeof type === \"string\" ? type : tinygradient(type).rgbAt(progress)\n\n const attrs = {}\n\n if (stroke) {\n attrs[\"stroke\"] = determineColor(stroke, progress)\n attrs[\"stroke-width\"] = strokeWidth\n }\n\n if (fill) {\n attrs[\"fill\"] = determineColor(fill, progress)\n }\n\n if (animation?.name) {\n // TODO: add animation-direction support\n\n const duration = animation.duration || 5\n\n attrs[\"style\"] = `\n animation-name: ${animation?.name}; \n animation-delay: ${progress * duration - duration}s;\n animation-duration: ${duration}s; \n animation-iteration-count: infinite; \n animation-timing-function: linear;`\n }\n\n return attrs\n}\n\n// An internal function to convert any array of samples into a \"d\" attribute to be passed to an SVG path\nexport const segmentToD = (samples) => {\n let d = \"\"\n\n for (let i = 0; i < samples.length; i++) {\n const { x, y } = samples[i],\n prevSample = i === 0 ? null : samples[i - 1]\n\n if (i === 0 && i !== samples.length - 1) {\n d += `M${x},${y}`\n } else if (x !== prevSample.x && y !== prevSample.y) {\n d += `L${x},${y}`\n } else if (x !== prevSample.x) {\n d += `H${x}`\n } else if (y !== prevSample.y) {\n d += `V${y}`\n }\n\n if (i === samples.length - 1) {\n d += \"Z\"\n }\n }\n\n return d\n}\n\n// An internal function for getting the colors of a segment, we need to get middle most sample (sorted by progress along the path)\nexport const getMiddleSample = (samples) => {\n const sortedSamples = [...samples].sort((a, b) => a.progress - b.progress)\n\n return sortedSamples[(sortedSamples.length / 2) | 0]\n}\n\n// An internal function for converting any D3 selection or DOM-like element into a DOM node\nexport const convertPathToNode = (path) =>\n path instanceof Element || path instanceof HTMLDocument ? path : path.node()\n", + "review": "8\n\n### Bugs\n- None found in the provided code snippet.\n\n### Optimizations\n- Use modern ES6+ features like `for...of` instead of traditional `for` loops for better readability.\n- Inline comments can be added for better clarity in complex logical parts, especially within loops.\n- Make use of `let` and `const` consistently to avoid any potential re-assignment issues by using `const` where variables are not reassigned.\n\n### Good points\n- The code is well-structured with each function performing a specific task.\n- Use of ternary operators and modern JavaScript features like destructuring and spread operators.\n- Proper usage of self-explanatory function and variable names.\n- Handles complex SVG attribute manipulations efficiently.\n\n### Summary\nThe provided code is of high quality, demonstrating good use of modern JavaScript practices and a helper library, `tinygradient`, for gradient manipulations. It is concise, making effective use of ES6+ features such as destructuring, spread/rest operators, and ternary operations for clean code. There are no apparent bugs. The code could be made slightly more readable using newer loop constructs and clarifying comments.\n\n### Open source alternatives\n- [Snap.svg](http://snapsvg.io/) is an open-source library for working with SVG.\n- [D3.js](https://d3js.org/) provides powerful capabilities for data visualization using SVG.\n- [Rapha\u00ebl](http://raphaeljs.com/) is a small JavaScript library that should simplify your work with vector graphics on the web.", + "filename": "_utils.js", + "path": "next/src/gp/_utils.js", + "directory": "gp", + "grade": 8, + "size": 2502, + "line_count": 85 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/_utils.js.md b/.reviews/next/src/gp/_utils.js.md new file mode 100644 index 0000000..e8401d9 --- /dev/null +++ b/.reviews/next/src/gp/_utils.js.md @@ -0,0 +1,23 @@ +8 + +### Bugs +- None found in the provided code snippet. + +### Optimizations +- Use modern ES6+ features like `for...of` instead of traditional `for` loops for better readability. +- Inline comments can be added for better clarity in complex logical parts, especially within loops. +- Make use of `let` and `const` consistently to avoid any potential re-assignment issues by using `const` where variables are not reassigned. + +### Good points +- The code is well-structured with each function performing a specific task. +- Use of ternary operators and modern JavaScript features like destructuring and spread operators. +- Proper usage of self-explanatory function and variable names. +- Handles complex SVG attribute manipulations efficiently. + +### Summary +The provided code is of high quality, demonstrating good use of modern JavaScript practices and a helper library, `tinygradient`, for gradient manipulations. It is concise, making effective use of ES6+ features such as destructuring, spread/rest operators, and ternary operations for clean code. There are no apparent bugs. The code could be made slightly more readable using newer loop constructs and clarifying comments. + +### Open source alternatives +- [Snap.svg](http://snapsvg.io/) is an open-source library for working with SVG. +- [D3.js](https://d3js.org/) provides powerful capabilities for data visualization using SVG. +- [Raphaël](http://raphaeljs.com/) is a small JavaScript library that should simplify your work with vector graphics on the web. \ No newline at end of file diff --git a/.reviews/next/src/gp/index.js.json b/.reviews/next/src/gp/index.js.json new file mode 100644 index 0000000..43d1d63 --- /dev/null +++ b/.reviews/next/src/gp/index.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export { default as GradientPath } from \"./GradientPath\"\nexport { getData, strokeToFill } from \"./_data\"\n", + "review": "8\n\n### Bugs\n- There are no evident bugs within this small piece of code.\n\n### Optimizations\n- Ensure that `./GradientPath` and `./_data` paths are correct and accessible to prevent any import errors.\n- Consider adding comments to explain the functionality of exported items for better maintainability.\n\n### Good points\n- Uses ES6 module export syntax effectively.\n- Exports both default and named exports which provides flexibility in usage.\n- The file structure appears to be well-organized.\n\n### Summary\nThis code snippet is clean and follows modern JavaScript practices. It exports a default module and named modules, allowing for flexible import in other parts of an application. No bugs are evident, but ensuring the proper path and including comments would enhance the maintainability of this code.\n\n### Open source alternatives\n- D3.js: A JavaScript library for manipulating documents based on data.\n- Chart.js: A simple yet flexible JavaScript charting for designers and developers.\n- Highcharts: A charting library written in pure JavaScript, although not fully open-source, it offers many open-source features.", + "filename": "index.js", + "path": "next/src/gp/index.js", + "directory": "gp", + "grade": 8, + "size": 105, + "line_count": 3 +} \ No newline at end of file diff --git a/.reviews/next/src/gp/index.js.md b/.reviews/next/src/gp/index.js.md new file mode 100644 index 0000000..bd21d1a --- /dev/null +++ b/.reviews/next/src/gp/index.js.md @@ -0,0 +1,21 @@ +8 + +### Bugs +- There are no evident bugs within this small piece of code. + +### Optimizations +- Ensure that `./GradientPath` and `./_data` paths are correct and accessible to prevent any import errors. +- Consider adding comments to explain the functionality of exported items for better maintainability. + +### Good points +- Uses ES6 module export syntax effectively. +- Exports both default and named exports which provides flexibility in usage. +- The file structure appears to be well-organized. + +### Summary +This code snippet is clean and follows modern JavaScript practices. It exports a default module and named modules, allowing for flexible import in other parts of an application. No bugs are evident, but ensuring the proper path and including comments would enhance the maintainability of this code. + +### Open source alternatives +- D3.js: A JavaScript library for manipulating documents based on data. +- Chart.js: A simple yet flexible JavaScript charting for designers and developers. +- Highcharts: A charting library written in pure JavaScript, although not fully open-source, it offers many open-source features. \ No newline at end of file diff --git a/.reviews/next/tailwind.config.ts.json b/.reviews/next/tailwind.config.ts.json new file mode 100644 index 0000000..230d541 --- /dev/null +++ b/.reviews/next/tailwind.config.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "import type { Config } from \"tailwindcss\";\n\nconst config: Config = {\n content: [\n \"./src/pages/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./src/components/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./src/app/**/*.{js,ts,jsx,tsx,mdx}\",\n ],\n theme: {\n extend: {\n backgroundImage: {\n \"gradient-radial\": \"radial-gradient(var(--tw-gradient-stops))\",\n \"gradient-conic\":\n \"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))\",\n },\n },\n },\n plugins: [],\n};\nexport default config;\n", + "review": "**8**\n\n### Bugs\n- No evident bugs are present in this configuration file.\n\n### Optimizations\n- Consider adding more comments for clarity, especially if more customization will be added in the future.\n- If there are recurring theme attributes across projects, consider abstracting them to a shared configuration.\n- Consider specifying default `plugins` or giving future directions for customizable options if this configuration is to be shared or expanded upon.\n\n### Good points\n- The configuration uses the `extend` feature of Tailwind CSS effectively, allowing for easy customization without overriding the default styles.\n- Gradient background utilities are a nice feature for modern design needs.\n- The use of TypeScript for type safety with the `Config` type adds to code reliability.\n\n### Summary\nThe Tailwind CSS configuration file is well-structured and employs Tailwind's `extend` feature efficiently to introduce custom backdrops for radial and conic gradients. It follows good practices by using TypeScript for added assurance against type errors. The configuration could be optimized with more extensive comments or plans for future plugin use, which would aid in clarity and extensibility, especially in a collaborative environment.\n\n### Open source alternatives\n- Personal preferences are highly regarded in this domain, but for more comprehensive or flexible solutions, consider exploring complete utility-first CSS frameworks like [Bootstrap](https://getbootstrap.com/) or [Bulma](https://bulma.io/), or even plugins/extensions within Tailwind itself if more functionality is needed.", + "filename": "tailwind.config.ts", + "path": "next/tailwind.config.ts", + "directory": "next", + "grade": 8, + "size": 510, + "line_count": 21 +} \ No newline at end of file diff --git a/.reviews/next/tailwind.config.ts.md b/.reviews/next/tailwind.config.ts.md new file mode 100644 index 0000000..a6b2799 --- /dev/null +++ b/.reviews/next/tailwind.config.ts.md @@ -0,0 +1,20 @@ +**8** + +### Bugs +- No evident bugs are present in this configuration file. + +### Optimizations +- Consider adding more comments for clarity, especially if more customization will be added in the future. +- If there are recurring theme attributes across projects, consider abstracting them to a shared configuration. +- Consider specifying default `plugins` or giving future directions for customizable options if this configuration is to be shared or expanded upon. + +### Good points +- The configuration uses the `extend` feature of Tailwind CSS effectively, allowing for easy customization without overriding the default styles. +- Gradient background utilities are a nice feature for modern design needs. +- The use of TypeScript for type safety with the `Config` type adds to code reliability. + +### Summary +The Tailwind CSS configuration file is well-structured and employs Tailwind's `extend` feature efficiently to introduce custom backdrops for radial and conic gradients. It follows good practices by using TypeScript for added assurance against type errors. The configuration could be optimized with more extensive comments or plans for future plugin use, which would aid in clarity and extensibility, especially in a collaborative environment. + +### Open source alternatives +- Personal preferences are highly regarded in this domain, but for more comprehensive or flexible solutions, consider exploring complete utility-first CSS frameworks like [Bootstrap](https://getbootstrap.com/) or [Bulma](https://bulma.io/), or even plugins/extensions within Tailwind itself if more functionality is needed. \ No newline at end of file diff --git a/.reviews/raycast/raycast-env.d.ts.json b/.reviews/raycast/raycast-env.d.ts.json new file mode 100644 index 0000000..953584a --- /dev/null +++ b/.reviews/raycast/raycast-env.d.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/// \n\n/* \ud83d\udea7 \ud83d\udea7 \ud83d\udea7\n * This file is auto-generated from the extension's manifest.\n * Do not modify manually. Instead, update the `package.json` file.\n * \ud83d\udea7 \ud83d\udea7 \ud83d\udea7 */\n\n/* eslint-disable @typescript-eslint/ban-types */\n\ntype ExtensionPreferences = {\n /** Image Input - Where to obtain the image to modify. */\n \"inputMethod\": \"Finder\" | \"Path Finder\" | \"Clipboard\",\n /** Image Output - How to handle the result of the image modification, i.e. where to save the modified image, or whether to copy it to the clipboard. */\n \"imageResultHandling\": \"replaceOriginal\" | \"saveInContainingFolder\" | \"copyToClipboard\" | \"openInPreview\" | \"saveToDownloads\" | \"saveToDesktop\",\n /** cwebp Lossless - Whether to use lossless conversion */\n \"cwebpLossless\": boolean\n}\n\n/** Preferences accessible in all the extension's commands */\ndeclare type Preferences = ExtensionPreferences\n\ndeclare namespace Preferences {\n /** Preferences accessible in the `commander` command */\n export type Commander = ExtensionPreferences & {\n /** Name of Command to run - The name of the command/function to run */\n \"name\"?: string\n}\n /** Preferences accessible in the `commanderOpenNewFinderWindow` command */\n export type CommanderOpenNewFinderWindow = ExtensionPreferences & {\n /** Name of Command to run - The name of the command/function to run */\n \"name\"?: string\n}\n /** Preferences accessible in the `commanderTrim` command */\n export type CommanderTrim = ExtensionPreferences & {\n /** Name of Command to run - The name of the command/function to run */\n \"name\"?: string\n}\n /** Preferences accessible in the `commanderMp4ToMp3` command */\n export type CommanderMp4ToMp3 = ExtensionPreferences & {\n /** Name of Command to run - The name of the command/function to run */\n \"name\"?: string\n}\n /** Preferences accessible in the `commanderConvert` command */\n export type CommanderConvert = ExtensionPreferences & {\n /** Name of Command to run - The name of the command/function to run */\n \"name\"?: string,\n /** Additional - Whether to trim the image */\n \"trim\": boolean,\n /** Enabled Formats - Whether to show WEBP as a conversion option */\n \"showWEBP\": boolean,\n /** - Whether to show ASTC as a conversion option */\n \"showASTC\": boolean,\n /** - Whether to show BMP as a conversion option */\n \"showBMP\": boolean,\n /** - Whether to show DDS as a conversion option */\n \"showDDS\": boolean,\n /** - Whether to show EXR as a conversion option */\n \"showEXR\": boolean,\n /** - Whether to show GIF as a conversion option */\n \"showGIF\": boolean,\n /** - Whether to show HEIC as a conversion option */\n \"showHEIC\": boolean,\n /** - Whether to show HEICS as a conversion option */\n \"showHEICS\": boolean,\n /** - Whether to show ICNS as a conversion option */\n \"showICNS\": boolean,\n /** - Whether to show ICO as a conversion option */\n \"showICO\": boolean,\n /** - Whether to show JPEG as a conversion option */\n \"showJPEG\": boolean,\n /** - Whether to show JP2 as a conversion option */\n \"showJP2\": boolean,\n /** - Whether to show KTX as a conversion option */\n \"showKTX\": boolean,\n /** - Whether to show PBM as a conversion option */\n \"showPBM\": boolean,\n /** - Whether to show PDF as a conversion option */\n \"showPDF\": boolean,\n /** - Whether to show PNG as a conversion option */\n \"showPNG\": boolean,\n /** - Whether to show PSD as a conversion option */\n \"showPSD\": boolean,\n /** - Whether to show PVR as a conversion option */\n \"showPVR\": boolean,\n /** - Whether to show TGA as a conversion option */\n \"showTGA\": boolean,\n /** - Whether to show TIFF as a conversion option */\n \"showTIFF\": boolean,\n /** - Whether to show SVG as a conversion option */\n \"showSVG\": boolean\n}\n}\n\ndeclare namespace Arguments {\n /** Arguments passed to the `commander` command */\n export type Commander = {}\n /** Arguments passed to the `commanderOpenNewFinderWindow` command */\n export type CommanderOpenNewFinderWindow = {\n /** Path */\n \"path\": string\n}\n /** Arguments passed to the `commanderTrim` command */\n export type CommanderTrim = {}\n /** Arguments passed to the `commanderMp4ToMp3` command */\n export type CommanderMp4ToMp3 = {}\n /** Arguments passed to the `commanderConvert` command */\n export type CommanderConvert = {}\n}\n\n", + "review": "8\n\n## Bugs\n- No explicit errors or issues were identified from the provided code as it primarily concerns type definitions and does not contain implementation logic.\n\n## Optimizations\n- Type aliasing can be used for the repetitive format options to reduce redundancy.\n- Consider breaking down the `Preferences` type into smaller, more manageable pieces if the structure is expected to grow more complex.\n\n## Good points\n- The use of TypeScript's `type` and `namespace` for organizing and defining data structure brings clarity and structure to the code.\n- Provides clear indication of where to update the code (`package.json` file) rather than the generated code itself.\n- Extensive use of comments to explain each property, which enhances understandability and maintainability.\n\n## Summary\nThe provided code is a clean implementation of type declarations using TypeScript, suitable for an auto-generated file that should not be modified manually. It demonstrates good practices in terms of clarity, organization, and documentation of code. However, there might be room for optimization through the use of type aliasing for repetitive code sections.\n\n## Open source alternatives\n- [ImageMagick](https://imagemagick.org) - an open-source software suite for displaying, converting, and editing raster image and vector image files.\n- [GraphicsMagick](http://www.graphicsmagick.org/) - known as the Swiss Army knife of image processing, it is a robust collection of tools and libraries to read, write, and manipulate an image in any of the more popular image formats.", + "filename": "raycast-env.d.ts", + "path": "raycast/raycast-env.d.ts", + "directory": "raycast", + "grade": 8, + "size": 4289, + "line_count": 110 +} \ No newline at end of file diff --git a/.reviews/raycast/raycast-env.d.ts.md b/.reviews/raycast/raycast-env.d.ts.md new file mode 100644 index 0000000..ec791a0 --- /dev/null +++ b/.reviews/raycast/raycast-env.d.ts.md @@ -0,0 +1,20 @@ +8 + +## Bugs +- No explicit errors or issues were identified from the provided code as it primarily concerns type definitions and does not contain implementation logic. + +## Optimizations +- Type aliasing can be used for the repetitive format options to reduce redundancy. +- Consider breaking down the `Preferences` type into smaller, more manageable pieces if the structure is expected to grow more complex. + +## Good points +- The use of TypeScript's `type` and `namespace` for organizing and defining data structure brings clarity and structure to the code. +- Provides clear indication of where to update the code (`package.json` file) rather than the generated code itself. +- Extensive use of comments to explain each property, which enhances understandability and maintainability. + +## Summary +The provided code is a clean implementation of type declarations using TypeScript, suitable for an auto-generated file that should not be modified manually. It demonstrates good practices in terms of clarity, organization, and documentation of code. However, there might be room for optimization through the use of type aliasing for repetitive code sections. + +## Open source alternatives +- [ImageMagick](https://imagemagick.org) - an open-source software suite for displaying, converting, and editing raster image and vector image files. +- [GraphicsMagick](http://www.graphicsmagick.org/) - known as the Swiss Army knife of image processing, it is a robust collection of tools and libraries to read, write, and manipulate an image in any of the more popular image formats. \ No newline at end of file diff --git a/.reviews/raycast/src/flip-horizontally.ts.json b/.reviews/raycast/src/flip-horizontally.ts.json new file mode 100644 index 0000000..a4dd692 --- /dev/null +++ b/.reviews/raycast/src/flip-horizontally.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file flip-horizontally.ts\n *\n * @summary Raycast command to flip selected images horizontally.\n *\n * Created at : 2023-07-06 14:54:33\n * Last modified : 2023-07-18 18:48:24\n */\n\nimport flip from \"./operations/flipOperation\";\nimport { Direction } from \"./utilities/enums\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command() {\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => flip(selectedImages, Direction.HORIZONTAL),\n selectedImages,\n inProgressMessage: \"Flipping in progress...\",\n successMessage: \"Flipped\",\n failureMessage: \"Failed to flip\",\n });\n}\n", + "review": "# 8\n\n## Bugs\n- No visible bugs present in this code snippet.\n\n## Optimizations\n- Consider adding error handling when calling `getSelectedImages` to deal with potential async errors.\n- It might be useful to implement logging for debugging purposes when operations fail.\n\n## Good points\n- Code is clearly structured and modular.\n- Use of async/await greatly simplifies asynchronous code management.\n- The command pattern is well implemented for running an operation.\n- Constant use of TypeScript imports will likely promote type safety.\n\n## Summary\nThe code is well organized, follows good practices for modularity, and is mostly clean with a clear purpose: flipping selected images horizontally. The use of async operations and command patterns allows for flexibility and scalability. There are some opportunities to improve robustness with additional error handling.\n\n## Open source alternatives\n- **ImageMagick**: A command-line tool and library to flip or modify images.\n- **Sharp**: A high-performance Node.js library to deal with images, including transformations like flipping.\n- **Jimp**: A library written entirely in JavaScript for image manipulation.", + "filename": "flip-horizontally.ts", + "path": "raycast/src/flip-horizontally.ts", + "directory": "src", + "grade": 8, + "size": 724, + "line_count": 25 +} \ No newline at end of file diff --git a/.reviews/raycast/src/flip-horizontally.ts.md b/.reviews/raycast/src/flip-horizontally.ts.md new file mode 100644 index 0000000..cc75a54 --- /dev/null +++ b/.reviews/raycast/src/flip-horizontally.ts.md @@ -0,0 +1,22 @@ +# 8 + +## Bugs +- No visible bugs present in this code snippet. + +## Optimizations +- Consider adding error handling when calling `getSelectedImages` to deal with potential async errors. +- It might be useful to implement logging for debugging purposes when operations fail. + +## Good points +- Code is clearly structured and modular. +- Use of async/await greatly simplifies asynchronous code management. +- The command pattern is well implemented for running an operation. +- Constant use of TypeScript imports will likely promote type safety. + +## Summary +The code is well organized, follows good practices for modularity, and is mostly clean with a clear purpose: flipping selected images horizontally. The use of async operations and command patterns allows for flexibility and scalability. There are some opportunities to improve robustness with additional error handling. + +## Open source alternatives +- **ImageMagick**: A command-line tool and library to flip or modify images. +- **Sharp**: A high-performance Node.js library to deal with images, including transformations like flipping. +- **Jimp**: A library written entirely in JavaScript for image manipulation. \ No newline at end of file diff --git a/.reviews/raycast/src/flip-vertically.ts.json b/.reviews/raycast/src/flip-vertically.ts.json new file mode 100644 index 0000000..8606382 --- /dev/null +++ b/.reviews/raycast/src/flip-vertically.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file flip-vertically.ts\n *\n * @summary Raycast command to flip selected images vertically.\n *\n * Created at : 2023-07-06 14:55:04\n * Last modified : 2023-07-18 18:48:29\n */\n\nimport flip from \"./operations/flipOperation\";\nimport { Direction } from \"./utilities/enums\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command() {\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => flip(selectedImages, Direction.HORIZONTAL),\n selectedImages,\n inProgressMessage: \"Flipping in progress...\",\n successMessage: \"Flipped\",\n failureMessage: \"Failed to flip\",\n });\n}\n", + "review": "**8**\n\n### Bugs\n- No explicit bugs are identified in the code snippet provided.\n\n### Optimizations\n- Consider adding error handling when fetching the selected images to handle scenarios where no images are returned.\n- Add type annotations for the function to ensure TypeScript's full type-checking benefits are utilized.\n- Improve readability by using named import for the flip function which makes the code more readable.\n\n### Good points\n- Successfully uses asynchronous functions to handle operations, suggesting non-blocking code.\n- The code is modularized - separating operations and utilities which helps in maintaining and organizing the code.\n- Uses a clean and functional approach for executing the flip operation.\n- Constants are used for direction, minimizing the risk of errors from hard-coding strings.\n\n### Summary\nThe provided TypeScript code for flipping images vertically is generally well-written and organized. It incorporates asynchronous operations and good use of modularization. While it lacks direct error handling for certain operations, the overall architecture is clean and efficient. Some improvements could be made regarding type safety and better readability.\n\n### Open source alternatives\n- ImageMagick: A robust image manipulation tool that can perform tasks including flipping images.\n- GraphicsMagick: Similar to ImageMagick, it supports image manipulation operations including flipping.\n- Sharp: A high-performance Node.js library for image processing, capable of performing various transformations such as flipping images.", + "filename": "flip-vertically.ts", + "path": "raycast/src/flip-vertically.ts", + "directory": "src", + "grade": 8, + "size": 720, + "line_count": 25 +} \ No newline at end of file diff --git a/.reviews/raycast/src/flip-vertically.ts.md b/.reviews/raycast/src/flip-vertically.ts.md new file mode 100644 index 0000000..d2caca8 --- /dev/null +++ b/.reviews/raycast/src/flip-vertically.ts.md @@ -0,0 +1,23 @@ +**8** + +### Bugs +- No explicit bugs are identified in the code snippet provided. + +### Optimizations +- Consider adding error handling when fetching the selected images to handle scenarios where no images are returned. +- Add type annotations for the function to ensure TypeScript's full type-checking benefits are utilized. +- Improve readability by using named import for the flip function which makes the code more readable. + +### Good points +- Successfully uses asynchronous functions to handle operations, suggesting non-blocking code. +- The code is modularized - separating operations and utilities which helps in maintaining and organizing the code. +- Uses a clean and functional approach for executing the flip operation. +- Constants are used for direction, minimizing the risk of errors from hard-coding strings. + +### Summary +The provided TypeScript code for flipping images vertically is generally well-written and organized. It incorporates asynchronous operations and good use of modularization. While it lacks direct error handling for certain operations, the overall architecture is clean and efficient. Some improvements could be made regarding type safety and better readability. + +### Open source alternatives +- ImageMagick: A robust image manipulation tool that can perform tasks including flipping images. +- GraphicsMagick: Similar to ImageMagick, it supports image manipulation operations including flipping. +- Sharp: A high-performance Node.js library for image processing, capable of performing various transformations such as flipping images. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/anyOperation.ts.json b/.reviews/raycast/src/operations/anyOperation.ts.json new file mode 100644 index 0000000..2888987 --- /dev/null +++ b/.reviews/raycast/src/operations/anyOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/convertOperation.ts\n *\n * @summary Image conversion operation with support for basic image formats, SVGs, WebP, and PDFs.\n *\n * Created at : 2023-07-dd 00:19:37\n * Last modified : 2024-01-27 13:31:19\n */\n\nimport { execSync } from \"child_process\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport path from \"path\";\n\nimport { environment, getPreferenceValues } from \"@raycast/api\";\n\nimport { convertPDF, convertSVG, moveImageResultsToFinalDestination } from \"../utilities/utils\";\nimport { ConvertPreferences, ExtensionPreferences } from \"../utilities/preferences\";\nimport { ImageResultHandling } from \"../utilities/enums\";\n\n/**\n * Converts images to the specified format, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to convert.\n * @param desiredType The desired format to convert the images to.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function any(sourcePaths: string[], desiredType: string, trim?: boolean) {\n const preferences = getPreferenceValues();\n\n const convertPreferences = getPreferenceValues();\n\n trim = trim || convertPreferences?.trim || desiredType?.includes(\"Trimmed\");\n\n const resultPaths = [];\n for (const item of sourcePaths) {\n const extension = desiredType.toLowerCase()?.replace(\"trimmed\", \"\");\n\n const pathComponents = item.split(\".\");\n let newPath = pathComponents.slice(0, -1).join(\"\");\n\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, `.${desiredType.toLowerCase()}`) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n console.log(\"nik trim\", trim);\n\n console.log(\"nik desiredType\", desiredType);\n\n if (desiredType?.includes(\"Trimmed\")) {\n desiredType = desiredType?.replace(\"Trimmed\", \"\");\n }\n\n console.log(\"nik desiredType\", desiredType);\n\n const trimmedPath = `${newPath}.${extension}`;\n if (trim) {\n newPath = `${newPath}.tmp.${extension}`;\n } else {\n newPath = `${newPath}.${extension}`;\n }\n\n console.log(\"nik desiredType\", desiredType);\n\n if (desiredType === \"MP3\") {\n // const platform = os.arch() === \"arm64\" ? \"/arm\" : \"/x86\";\n // execSync(`chmod +x ${environment.assetsPath}/webp${platform}/cwebp`);\n // execSync(`${environment.assetsPath}/webp${platform}/cwebp ${preferences?.cwebpLossless ? '-lossless' : ''} \"${item}\" -o \"${newPath}\"`);\n // use ${item} as input.mp4 and ${newPath} as output.mp3\n execSync(`ffmpeg -i \"${item}\" -vn -ar 44100 -ac 2 -ab 320k -f mp3 \"${newPath}\"`);\n // resultPaths.push(newPath);\n } else if (desiredType === \"Trim\") {\n // using convert -trim ${item} ${newPath}\n execSync(`convert -trim \"${item}\" \"${newPath}\"`);\n } else if (desiredType === \"WEBP\") {\n // Input Format -> WebP\n // detect platform is arm or x86\n const platform = os.arch() === \"arm64\" ? \"/arm\" : \"/x86\";\n execSync(`chmod +x ${environment.assetsPath}/webp${platform}/cwebp`);\n execSync(\n `${environment.assetsPath}/webp${platform}/cwebp ${\n preferences?.cwebpLossless ? \"-lossless\" : \"\"\n } \"${item}\" -o \"${newPath}\"`\n );\n\n console.log(\"nik trim\", trim);\n\n if (trim) {\n // const trimmedPath =\n // execSync(`echo $(which convert) >> /tmp/convert.txt`);\n // execSync(`convert -trim \"${newPath}\" \"${trimmedPath}\"`);\n // /opt/homebrew/bin/convert\n execSync(`/opt/homebrew/bin/convert -trim \"${newPath}\" \"${trimmedPath}\"`);\n\n // remove the tmp file\n fs.unlinkSync(newPath);\n }\n } else if (pathComponents.at(-1)?.toLowerCase() == \"svg\") {\n // SVG -> NSBitmapImageRep -> Desired Format\n convertSVG(desiredType, item, newPath);\n } else if (desiredType == \"SVG\") {\n const bmpPath = `${environment.supportPath}/tmp.bmp`;\n execSync(`chmod +x ${environment.assetsPath}/potrace/potrace`);\n if (pathComponents.at(-1)?.toLowerCase() == \"webp\") {\n // WebP -> PNG -> BMP -> SVG\n const pngPath = `${environment.supportPath}/tmp.png`;\n execSync(`chmod +x ${environment.assetsPath}/webp/dwebp`);\n execSync(`${environment.assetsPath}/webp/dwebp \"${item}\" -o \"${pngPath}\"`);\n execSync(\n `sips --setProperty format \"bmp\" \"${pngPath}\" --out \"${bmpPath}\" && ${environment.assetsPath}/potrace/potrace -s --tight -o \"${newPath}\" \"${bmpPath}\"; rm \"${bmpPath}\"; rm \"${pngPath}\"`\n );\n } else {\n // Input Format -> BMP -> SVG\n execSync(\n `sips --setProperty format \"bmp\" \"${item}\" --out \"${bmpPath}\" && ${environment.assetsPath}/potrace/potrace -s --tight -o \"${newPath}\" \"${bmpPath}\"; rm \"${bmpPath}\"`\n );\n }\n } else if (pathComponents.at(-1)?.toLowerCase() == \"webp\") {\n // WebP -> PNG -> Desired Format\n execSync(`chmod +x ${environment.assetsPath}/webp/dwebp`);\n execSync(`${environment.assetsPath}/webp/dwebp \"${item}\" -o \"${newPath}\"`);\n execSync(`sips --setProperty format ${desiredType.toLowerCase()} \"${newPath}\"`);\n } else if (pathComponents.at(-1)?.toLowerCase() == \"pdf\") {\n // PDF -> Desired Format\n const itemName = path.basename(item);\n const folderName = `${itemName?.substring(0, itemName.lastIndexOf(\".\"))} ${desiredType}`;\n const folderPath = path.join(newPath.split(\"/\").slice(0, -1).join(\"/\"), folderName);\n execSync(`mkdir -p \"${folderPath}\"`);\n convertPDF(desiredType, item, folderPath);\n } else {\n // General Input Format -> Desired Format\n execSync(`sips --setProperty format ${desiredType.toLowerCase()} \"${item}\" --out \"${newPath}\"`);\n }\n\n resultPaths.push(newPath);\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "# 6\n\n## Bugs\n- Incorrect handling and conversion of file formats, especially if the `desiredType` is not explicitly handled.\n- Potential overwriting of files if file existence checks are not correctly performed.\n- Use of hard-coded paths (e.g., `/opt/homebrew/bin/convert`) might not work on all systems.\n- Assumes presence of third-party tools like `ffmpeg`, `convert`, and others without checking their availability.\n- Potential for silent failures due to the broad use of `execSync` without error handling.\n\n## Optimizations\n- Implement error handling for `execSync` to capture and handle errors gracefully.\n- Introduce a logging mechanism to replace console logs for better debugging and tracking.\n- Refactor for better modularity; extract some of the longer conditionals into separate functions.\n- Use path utilities for safer path manipulations instead of manually splitting strings.\n- Consider async versions or non-blocking alternatives for file operations for better performance.\n- Eliminate any hard-coded paths and allow configuration or detection of tool paths.\n- Checks for the presence of external dependencies should be done before attempting conversions.\n\n## Good points\n- Good use of preferences to make it configurable for various users.\n- Comprehensive handling of multiple image conversion paths.\n- Adequate handling of temporary file storage and deletion to prevent clutter.\n\n## Summary\nThe script is capable of converting images among a variety of file formats but lacks robust error handling and could benefit from code modularity and optimization improvements. It also assumes too much about the user's environment regarding the availability of conversion tools, which can result in unexpected failures.\n\n## Open source alternatives\n- **ImageMagick**: A powerful toolset for batch processing of images with wide format support.\n- **GraphicsMagick**: A lightweight version of ImageMagick with similar functionalities.\n- **Pillow**: A Python imaging library that offers a simpler API for image processing.\n- **FFmpeg**: Effective for image and audio format conversions, especially for video and audio files.", + "filename": "anyOperation.ts", + "path": "raycast/src/operations/anyOperation.ts", + "directory": "operations", + "grade": 6, + "size": 6523, + "line_count": 156 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/anyOperation.ts.md b/.reviews/raycast/src/operations/anyOperation.ts.md new file mode 100644 index 0000000..9da1cd8 --- /dev/null +++ b/.reviews/raycast/src/operations/anyOperation.ts.md @@ -0,0 +1,31 @@ +# 6 + +## Bugs +- Incorrect handling and conversion of file formats, especially if the `desiredType` is not explicitly handled. +- Potential overwriting of files if file existence checks are not correctly performed. +- Use of hard-coded paths (e.g., `/opt/homebrew/bin/convert`) might not work on all systems. +- Assumes presence of third-party tools like `ffmpeg`, `convert`, and others without checking their availability. +- Potential for silent failures due to the broad use of `execSync` without error handling. + +## Optimizations +- Implement error handling for `execSync` to capture and handle errors gracefully. +- Introduce a logging mechanism to replace console logs for better debugging and tracking. +- Refactor for better modularity; extract some of the longer conditionals into separate functions. +- Use path utilities for safer path manipulations instead of manually splitting strings. +- Consider async versions or non-blocking alternatives for file operations for better performance. +- Eliminate any hard-coded paths and allow configuration or detection of tool paths. +- Checks for the presence of external dependencies should be done before attempting conversions. + +## Good points +- Good use of preferences to make it configurable for various users. +- Comprehensive handling of multiple image conversion paths. +- Adequate handling of temporary file storage and deletion to prevent clutter. + +## Summary +The script is capable of converting images among a variety of file formats but lacks robust error handling and could benefit from code modularity and optimization improvements. It also assumes too much about the user's environment regarding the availability of conversion tools, which can result in unexpected failures. + +## Open source alternatives +- **ImageMagick**: A powerful toolset for batch processing of images with wide format support. +- **GraphicsMagick**: A lightweight version of ImageMagick with similar functionalities. +- **Pillow**: A Python imaging library that offers a simpler API for image processing. +- **FFmpeg**: Effective for image and audio format conversions, especially for video and audio files. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/convertOperation.ts.json b/.reviews/raycast/src/operations/convertOperation.ts.json new file mode 100644 index 0000000..d73e706 --- /dev/null +++ b/.reviews/raycast/src/operations/convertOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/convertOperation.ts\n *\n * @summary Image conversion operation with support for basic image formats, SVGs, WebP, and PDFs.\n *\n * Created at : 2023-07-dd 00:19:37\n * Last modified : 2024-01-27 13:31:19\n */\n\nimport { execSync } from \"child_process\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport path from \"path\";\n\nimport { environment, getPreferenceValues } from \"@raycast/api\";\n\nimport { convertPDF, convertSVG, moveImageResultsToFinalDestination } from \"../utilities/utils\";\nimport { ExtensionPreferences } from \"../utilities/preferences\";\nimport { ImageResultHandling } from \"../utilities/enums\";\n\n/**\n * Converts images to the specified format, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to convert.\n * @param desiredType The desired format to convert the images to.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function convert(sourcePaths: string[], desiredType: string) {\n const preferences = getPreferenceValues();\n\n const resultPaths = [];\n for (const item of sourcePaths) {\n const pathComponents = item.split(\".\");\n let newPath = pathComponents.slice(0, -1).join(\"\") + \".\" + desiredType.toLowerCase();\n\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, `.${desiredType.toLowerCase()}`) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n if (desiredType === \"WEBP\") {\n // Input Format -> WebP\n // detect platform is arm or x86\n const platform = os.arch() === \"arm64\" ? \"/arm\" : \"/x86\";\n execSync(`chmod +x ${environment.assetsPath}/webp${platform}/cwebp`);\n execSync(`${environment.assetsPath}/webp${platform}/cwebp ${preferences?.cwebpLossless ? '-lossless' : ''} \"${item}\" -o \"${newPath}\"`);\n } else if (pathComponents.at(-1)?.toLowerCase() == \"svg\") {\n // SVG -> NSBitmapImageRep -> Desired Format\n convertSVG(desiredType, item, newPath);\n } else if (desiredType == \"SVG\") {\n const bmpPath = `${environment.supportPath}/tmp.bmp`;\n execSync(`chmod +x ${environment.assetsPath}/potrace/potrace`);\n if (pathComponents.at(-1)?.toLowerCase() == \"webp\") {\n // WebP -> PNG -> BMP -> SVG\n const pngPath = `${environment.supportPath}/tmp.png`;\n execSync(`chmod +x ${environment.assetsPath}/webp/dwebp`);\n execSync(`${environment.assetsPath}/webp/dwebp \"${item}\" -o \"${pngPath}\"`);\n execSync(\n `sips --setProperty format \"bmp\" \"${pngPath}\" --out \"${bmpPath}\" && ${environment.assetsPath}/potrace/potrace -s --tight -o \"${newPath}\" \"${bmpPath}\"; rm \"${bmpPath}\"; rm \"${pngPath}\"`\n );\n } else {\n // Input Format -> BMP -> SVG\n execSync(\n `sips --setProperty format \"bmp\" \"${item}\" --out \"${bmpPath}\" && ${environment.assetsPath}/potrace/potrace -s --tight -o \"${newPath}\" \"${bmpPath}\"; rm \"${bmpPath}\"`\n );\n }\n } else if (pathComponents.at(-1)?.toLowerCase() == \"webp\") {\n // WebP -> PNG -> Desired Format\n execSync(`chmod +x ${environment.assetsPath}/webp/dwebp`);\n execSync(`${environment.assetsPath}/webp/dwebp \"${item}\" -o \"${newPath}\"`);\n execSync(`sips --setProperty format ${desiredType.toLowerCase()} \"${newPath}\"`);\n } else if (pathComponents.at(-1)?.toLowerCase() == \"pdf\") {\n // PDF -> Desired Format\n const itemName = path.basename(item);\n const folderName = `${itemName?.substring(0, itemName.lastIndexOf(\".\"))} ${desiredType}`;\n const folderPath = path.join(newPath.split(\"/\").slice(0, -1).join(\"/\"), folderName);\n execSync(`mkdir -p \"${folderPath}\"`);\n convertPDF(desiredType, item, folderPath);\n } else {\n // General Input Format -> Desired Format\n execSync(`sips --setProperty format ${desiredType.toLowerCase()} \"${item}\" --out \"${newPath}\"`);\n }\n\n resultPaths.push(newPath);\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "# 7\n\n## Bugs\n- The file operation on temporary BMP files (`rm \"${bmpPath}\"`) might not execute if an error occurs earlier, leading to potential leftover files.\n- The script assumes the input file extensions as types for conversions, which might lead to issues with files that have incorrect extensions.\n\n## Optimizations\n- Consider using `async/await` with file operations to improve non-blocking behavior, especially if running on environments that support parallel operations or if handling many files.\n- Use a logger for error tracking within the `execSync` executions to capture potential errors instead of letting them silently pass.\n- Use more descriptive function and variable names that match common coding standards (e.g., `pathComponents` could be `fileExtensionSegments`).\n- Avoid hardcoding strings; consider using constants or an enumeration for mapping extensions/formats.\n- Refactor code to eliminate repeated logics, such as similar `execSync` calls for WebP handling. Consider encapsulating common logic into helper functions.\n\n## Good points\n- The code efficiently handles different image formats with conditionals that manage conversion specifics.\n- The usage of `os.homedir()` and `os.tmpdir()` is an excellent way to ensure platform-independent directory handling.\n- It accounts for potential filename conflicts by appending an incrementing number to the filename.\n\n## Summary\nThis code is structured to convert images from various formats into a user-specified format. While its current state is functional, there are several areas where code readability and maintainability could improve. The use of synchronous execution might also lead to performance bottlenecks in cases where many conversions happen at once. Nonetheless, the approach provides flexibility in target format handling through appropriate use of preferences and enums.\n\n## Open source alternatives\n- **ImageMagick**: A powerful, open-source tool that can convert and manipulate image formats from the command line.\n- **GraphicsMagick**: A similar tool to ImageMagick, often regarded as more efficient for certain operations.\n- **Sharp**: An open-source high-performance Node.js library for image processing with a focus on modern use cases.", + "filename": "convertOperation.ts", + "path": "raycast/src/operations/convertOperation.ts", + "directory": "operations", + "grade": 7, + "size": 4691, + "line_count": 104 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/convertOperation.ts.md b/.reviews/raycast/src/operations/convertOperation.ts.md new file mode 100644 index 0000000..fff0230 --- /dev/null +++ b/.reviews/raycast/src/operations/convertOperation.ts.md @@ -0,0 +1,25 @@ +# 7 + +## Bugs +- The file operation on temporary BMP files (`rm "${bmpPath}"`) might not execute if an error occurs earlier, leading to potential leftover files. +- The script assumes the input file extensions as types for conversions, which might lead to issues with files that have incorrect extensions. + +## Optimizations +- Consider using `async/await` with file operations to improve non-blocking behavior, especially if running on environments that support parallel operations or if handling many files. +- Use a logger for error tracking within the `execSync` executions to capture potential errors instead of letting them silently pass. +- Use more descriptive function and variable names that match common coding standards (e.g., `pathComponents` could be `fileExtensionSegments`). +- Avoid hardcoding strings; consider using constants or an enumeration for mapping extensions/formats. +- Refactor code to eliminate repeated logics, such as similar `execSync` calls for WebP handling. Consider encapsulating common logic into helper functions. + +## Good points +- The code efficiently handles different image formats with conditionals that manage conversion specifics. +- The usage of `os.homedir()` and `os.tmpdir()` is an excellent way to ensure platform-independent directory handling. +- It accounts for potential filename conflicts by appending an incrementing number to the filename. + +## Summary +This code is structured to convert images from various formats into a user-specified format. While its current state is functional, there are several areas where code readability and maintainability could improve. The use of synchronous execution might also lead to performance bottlenecks in cases where many conversions happen at once. Nonetheless, the approach provides flexibility in target format handling through appropriate use of preferences and enums. + +## Open source alternatives +- **ImageMagick**: A powerful, open-source tool that can convert and manipulate image formats from the command line. +- **GraphicsMagick**: A similar tool to ImageMagick, often regarded as more efficient for certain operations. +- **Sharp**: An open-source high-performance Node.js library for image processing with a focus on modern use cases. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/filterOperation.ts.json b/.reviews/raycast/src/operations/filterOperation.ts.json new file mode 100644 index 0000000..7df01a4 --- /dev/null +++ b/.reviews/raycast/src/operations/filterOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/filterOperation.ts\n *\n * @summary Image filter operation with support for basic image formats, SVGs, WebP, and PDFs.\n *\n * Created at : 2023-07-dd 00:32:49\n * Last modified : 2023-07-dd 00:32:49\n */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport { getPreferenceValues } from \"@raycast/api\";\n\nimport { Filter } from \"../utilities/types\";\nimport { moveImageResultsToFinalDestination } from \"../utilities/utils\";\nimport { ExtensionPreferences } from \"../utilities/preferences\";\nimport { ImageResultHandling } from \"../utilities/enums\";\n\n/**\n * Applies the specified filter to images, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to convert.\n * @param filter The filter to apply to the images.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function applyFilter(sourcePaths: string[], filter: Filter) {\n const preferences = getPreferenceValues();\n\n const resultPaths = [];\n for (const imageFilePath of sourcePaths) {\n let newPath = path.join(\n path.dirname(imageFilePath),\n path.basename(imageFilePath, path.extname(imageFilePath)) + (imageFilePath.endsWith(\".pdf\") ? \".pdf\" : \".png\")\n );\n\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n // Ensure that the file name is unique, unless the user wants to replace the original\n if (\n preferences.imageResultHandling != ImageResultHandling.ReplaceOriginal &&\n os.tmpdir() != path.dirname(newPath)\n ) {\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` ${iter}` + path.extname(newPath)\n );\n iter++;\n }\n }\n await filter.applyMethod(imageFilePath, newPath, filter.CIFilterName);\n resultPaths.push(newPath);\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "7\n\n### Bugs\n- No apparent bugs were detected in the current code.\n\n### Optimizations\n- **Code Duplication**: Consider extracting duplicated path-handling logic into a helper function to enhance readability and maintainability.\n- **Error Handling**: The code lacks error handling. Ensure exceptions are caught and handled appropriately to avoid unhandled promise rejections.\n- **Asynchronous Operations**: The function `fs.existsSync()` could be replaced with an asynchronous version to maintain consistent async operations.\n- **Magic Strings and Numbers**: Use constants or enums instead of magic numbers (`2` in the naming loop) or strings (like `\"Downloads\"`).\n- **Inefficient Path Checking**: There is repetitive use of `os.tmpdir() != path.dirname(newPath)` inside a loop which evaluates the same condition multiple times without changes.\n\n### Good points\n- **Modular Code**: The functionality is neatly divided into specific modules and functions.\n- **Configuration Handling**: Nicely integrates user preferences using `getPreferenceValues`.\n- **Platform Compatibility**: Utilizes `os.homedir()` and `os.tmpdir()` for OS-independent paths.\n- **Readable**: The structure of the code is easy-to-follow, enhancing readability.\n\n### Summary\nThe code is generally well-structured and organized, with a clear objective and efficient use of existing libraries and functions, including handling of user preferences and platform-independent paths. There is room for improvement, mainly in reducing code duplication, adding error handling, and optimizing synchronous checks with asynchronous equivalents. Improving these aspects can contribute to the robustness and efficiency of the code.\n\n### Open source alternatives\n- **ImageMagick**: A very popular and full-featured suite for editing images, including applying various filters.\n- **Sharp**: A high-performance Node.js library for image processing, supporting various transformations and file formats.\n- **jimp**: A lightweight JavaScript library for image manipulation providing in-built functionality for filters and transformations.", + "filename": "filterOperation.ts", + "path": "raycast/src/operations/filterOperation.ts", + "directory": "operations", + "grade": 7, + "size": 2560, + "line_count": 69 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/filterOperation.ts.md b/.reviews/raycast/src/operations/filterOperation.ts.md new file mode 100644 index 0000000..b809b5b --- /dev/null +++ b/.reviews/raycast/src/operations/filterOperation.ts.md @@ -0,0 +1,25 @@ +7 + +### Bugs +- No apparent bugs were detected in the current code. + +### Optimizations +- **Code Duplication**: Consider extracting duplicated path-handling logic into a helper function to enhance readability and maintainability. +- **Error Handling**: The code lacks error handling. Ensure exceptions are caught and handled appropriately to avoid unhandled promise rejections. +- **Asynchronous Operations**: The function `fs.existsSync()` could be replaced with an asynchronous version to maintain consistent async operations. +- **Magic Strings and Numbers**: Use constants or enums instead of magic numbers (`2` in the naming loop) or strings (like `"Downloads"`). +- **Inefficient Path Checking**: There is repetitive use of `os.tmpdir() != path.dirname(newPath)` inside a loop which evaluates the same condition multiple times without changes. + +### Good points +- **Modular Code**: The functionality is neatly divided into specific modules and functions. +- **Configuration Handling**: Nicely integrates user preferences using `getPreferenceValues`. +- **Platform Compatibility**: Utilizes `os.homedir()` and `os.tmpdir()` for OS-independent paths. +- **Readable**: The structure of the code is easy-to-follow, enhancing readability. + +### Summary +The code is generally well-structured and organized, with a clear objective and efficient use of existing libraries and functions, including handling of user preferences and platform-independent paths. There is room for improvement, mainly in reducing code duplication, adding error handling, and optimizing synchronous checks with asynchronous equivalents. Improving these aspects can contribute to the robustness and efficiency of the code. + +### Open source alternatives +- **ImageMagick**: A very popular and full-featured suite for editing images, including applying various filters. +- **Sharp**: A high-performance Node.js library for image processing, supporting various transformations and file formats. +- **jimp**: A lightweight JavaScript library for image manipulation providing in-built functionality for filters and transformations. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/flipOperation.ts.json b/.reviews/raycast/src/operations/flipOperation.ts.json new file mode 100644 index 0000000..56f3732 --- /dev/null +++ b/.reviews/raycast/src/operations/flipOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/flipOperation.ts\n *\n * @summary Image flipping operation with support for basic image formats, SVGs, WebP, and PDFs.\n *\n * Created at : 2023-07-05 23:16:12\n * Last modified : 2023-07-06 15:48:56\n */\n\nimport { execSync } from \"child_process\";\nimport path from \"path\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n flipPDF,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n} from \"../utilities/utils\";\nimport { Direction } from \"../utilities/enums\";\n\n/**\n * Flips images vertically or horizontally, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to flip.\n * @param direction The direction in which to flip the images.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function flip(sourcePaths: string[], direction: Direction) {\n const pathStrings = '\"' + sourcePaths.join('\" \"') + '\"';\n const newPaths = getDestinationPaths(sourcePaths);\n const directionString = direction == Direction.HORIZONTAL ? \"horizontal\" : \"vertical\";\n\n if (\n pathStrings.toLowerCase().includes(\"webp\") ||\n pathStrings.toLowerCase().includes(\"svg\") ||\n pathStrings.toLowerCase().includes(\"pdf\")\n ) {\n // Special types present -- Handle each image individually\n const resultPaths = [];\n for (const imgPath of sourcePaths) {\n if (imgPath.toLowerCase().endsWith(\"webp\")) {\n // Convert to PNG, flip and restore to WebP\n resultPaths.push(await execSIPSCommandOnWebP(`sips --flip ${directionString}`, imgPath));\n } else if (imgPath.toLowerCase().endsWith(\"svg\")) {\n // Convert to PNG, flip, and restore to SVG\n resultPaths.push(await execSIPSCommandOnSVG(`sips --flip ${directionString}`, imgPath));\n } else if (imgPath.toLowerCase().endsWith(\"pdf\")) {\n // Flip each page of PDF\n resultPaths.push(flipPDF(imgPath, direction));\n } else {\n // Image is not a special format, so just flip it using SIPS\n const newPath = newPaths[sourcePaths.indexOf(imgPath)];\n resultPaths.push(newPath);\n execSync(`sips --flip ${directionString} -o \"${newPath}\" \"${imgPath}\"`);\n }\n }\n await moveImageResultsToFinalDestination(resultPaths);\n } else {\n // No special types -- Flip all images at once\n const outputLocation = newPaths.length == 1 ? newPaths[0] : path.join(path.dirname(newPaths[0]), \"flipped\");\n\n if (newPaths.length > 1) execSync(`mkdir -p \"${outputLocation}\"`);\n\n execSync(`sips --flip ${directionString} -o \"${outputLocation}\" ${pathStrings}`);\n await moveImageResultsToFinalDestination(newPaths);\n }\n}\n", + "review": "**7**\n\n## Bugs\n- The code lacks error handling, especially for operations that involve file manipulation or external command execution.\n- Depending on external command-line tools like `sips` may lead to platform compatibility issues.\n\n## Optimizations\n- Implement error handling to catch and respond to errors during file operations and command executions.\n- Consider using a library like `sharp` for image manipulation which provides cross-platform support and comprehensive image handling functionality within Node.js.\n- Instead of `execSync`, consider using asynchronous alternatives to avoid blocking the main thread, improving performance and responsiveness.\n\n## Good points\n- The code is modular, with operations and utilities separated into functions. This enhances readability and maintainability.\n- It supports multiple image formats, including complex format handling like SVG, WebP, and PDFs.\n- The use of enums for direction enhances code clarity and minimizes errors related to direction strings.\n\n## Summary\nThis code provides a function to flip images vertically or horizontally, supporting various image formats such as PNG, SVG, WebP, and PDFs. It uses native command-line tools for handling the images, which might lead to platform-specific issues or performance bottlenecks due to the synchronous nature of `execSync`. Although it effectively manages different formats through utility functions, adding error handling and optimizing for performance through asynchronous operations or using a cross-platform image library would improve its robustness.\n\n## Open source alternatives\n- `Sharp`: A high-performance Node.js library for image processing, supporting various formats.\n- `Jimp`: Another popular image processing library in Node.js that can handle multiple image formats.\n- `PDFKit`: For handling PDF files specifically, offering functionalities like creation and manipulation in Node.js.", + "filename": "flipOperation.ts", + "path": "raycast/src/operations/flipOperation.ts", + "directory": "operations", + "grade": 7, + "size": 2665, + "line_count": 69 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/flipOperation.ts.md b/.reviews/raycast/src/operations/flipOperation.ts.md new file mode 100644 index 0000000..c7c4382 --- /dev/null +++ b/.reviews/raycast/src/operations/flipOperation.ts.md @@ -0,0 +1,23 @@ +**7** + +## Bugs +- The code lacks error handling, especially for operations that involve file manipulation or external command execution. +- Depending on external command-line tools like `sips` may lead to platform compatibility issues. + +## Optimizations +- Implement error handling to catch and respond to errors during file operations and command executions. +- Consider using a library like `sharp` for image manipulation which provides cross-platform support and comprehensive image handling functionality within Node.js. +- Instead of `execSync`, consider using asynchronous alternatives to avoid blocking the main thread, improving performance and responsiveness. + +## Good points +- The code is modular, with operations and utilities separated into functions. This enhances readability and maintainability. +- It supports multiple image formats, including complex format handling like SVG, WebP, and PDFs. +- The use of enums for direction enhances code clarity and minimizes errors related to direction strings. + +## Summary +This code provides a function to flip images vertically or horizontally, supporting various image formats such as PNG, SVG, WebP, and PDFs. It uses native command-line tools for handling the images, which might lead to platform-specific issues or performance bottlenecks due to the synchronous nature of `execSync`. Although it effectively manages different formats through utility functions, adding error handling and optimizing for performance through asynchronous operations or using a cross-platform image library would improve its robustness. + +## Open source alternatives +- `Sharp`: A high-performance Node.js library for image processing, supporting various formats. +- `Jimp`: Another popular image processing library in Node.js that can handle multiple image formats. +- `PDFKit`: For handling PDF files specifically, offering functionalities like creation and manipulation in Node.js. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/optimizeOperation.ts.json b/.reviews/raycast/src/operations/optimizeOperation.ts.json new file mode 100644 index 0000000..fe40d8a --- /dev/null +++ b/.reviews/raycast/src/operations/optimizeOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/optimizeOperation.ts\n *\n * @summary Image optimization operation with support for basic image formats, SVGs, and WebP.\n *\n * Created at : 2023-07-05 23:49:16\n * Last modified : 2023-07-06 14:51:57\n */\n\nimport { execSync } from \"child_process\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport path from \"path\";\nimport { runAppleScriptSync } from \"run-applescript\";\nimport { optimize as svgoOptimize } from \"svgo\";\n\nimport { environment, getPreferenceValues } from \"@raycast/api\";\n\nimport { getDestinationPaths, moveImageResultsToFinalDestination } from \"../utilities/utils\";\nimport { ExtensionPreferences } from \"../utilities/preferences\";\nimport { ImageResultHandling } from \"../utilities/enums\";\n\n/**\n * Optimizes a JPEG image by applying lossy compression.\n *\n * @param jpegPath The path of the JPEG image to optimize.\n * @param newPath The path to save the optimized JPEG image to.\n * @param amount The amount of compression to apply to the JPEG image.\n */\nconst optimizeJPEG = (jpegPath: string, newPath: string, amount: number) => {\n runAppleScriptSync(`use framework \"Foundation\"\n \n -- Load JPEG image from file\n set jpegData to current application's NSData's alloc()'s initWithContentsOfFile:\"${jpegPath}\"\n \n -- Create bitmap image representation from image\n set bitmapRep to current application's NSBitmapImageRep's imageRepWithData:jpegData\n \n -- Compress bitmap representation\n set compressionFactor to ${1.0 - amount / 100.0}\n set compressedData to bitmapRep's representationUsingType:(current application's NSBitmapImageFileTypeJPEG) |properties|:{NSImageCompressionFactor:compressionFactor}\n \n -- Save compressed data to file\n set compressedFilePath to \"${newPath}\"\n compressedData's writeToFile:compressedFilePath atomically:false`);\n};\n\n/**\n * Optimizes a WebP image by converting it to a JPEG, optimizing the JPEG, and then converting it back to a WebP.\n *\n * @param webpPath The path of the WebP image to optimize.\n * @param amount The amount of compression to apply to the JPEG image.\n * @returns The path of the optimized WebP image.\n */\nconst optimizeWEBP = (webpPath: string, amount: number) => {\n const preferences = getPreferenceValues();\n const jpegPath = `${environment.supportPath}/tmp.jpeg`;\n\n let newPath = webpPath.substring(0, webpPath.toLowerCase().lastIndexOf(\".webp\")) + \" (Optimized).webp\";\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n execSync(`chmod +x ${environment.assetsPath}/webp/cwebp`);\n execSync(`chmod +x ${environment.assetsPath}/webp/dwebp`);\n\n execSync(`${environment.assetsPath}/webp/dwebp \"${webpPath}\" -o \"${jpegPath}\"`);\n optimizeJPEG(jpegPath, newPath, amount);\n execSync(`${environment.assetsPath}/webp/cwebp \"${jpegPath}\" -o \"${newPath}\"; rm \"${jpegPath}\"`);\n return newPath;\n};\n\n/**\n * Optimize SVG images using SVGO.\n *\n * @param svgPath The path of the SVG image to optimize.\n * @returns The path of the optimized SVG image.\n */\nconst optimizeSVG = (svgPath: string) => {\n const preferences = getPreferenceValues();\n\n let newPath = svgPath.substring(0, svgPath.toLowerCase().lastIndexOf(\".svg\")) + \" (Optimized).svg\";\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n const data = fs.readFileSync(svgPath);\n const result = svgoOptimize(data.toString(), {\n path: newPath,\n multipass: true,\n });\n fs.writeFileSync(newPath, result.data);\n return newPath;\n};\n\n/**\n * Optimize images using format-specific strategies, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to optimize.\n * @param amount The level of optimization to apply, from 0 to 100.\n * @returns A promise that resolves when optimization is complete.\n */\nexport default async function optimize(sourcePaths: string[], amount: number) {\n const newPaths = getDestinationPaths(sourcePaths);\n\n const resultPaths = [];\n for (const imgPath of sourcePaths) {\n if (imgPath.toLowerCase().endsWith(\"webp\")) {\n // Convert to JPEG, optimize, and restore to WebP\n resultPaths.push(optimizeWEBP(imgPath, amount));\n } else if (imgPath.toLowerCase().endsWith(\"svg\")) {\n // Optimize SVG using SVGO\n resultPaths.push(optimizeSVG(imgPath));\n } else if (imgPath.toLowerCase().endsWith(\"jpg\") || imgPath.toLowerCase().endsWith(\"jpeg\")) {\n // Optimize JPEG images using NSBitmapImageRep compression\n let newPath = newPaths[sourcePaths.indexOf(imgPath)];\n newPath = path.join(path.dirname(newPath), path.basename(newPath, path.extname(newPath)) + \" (Optimized).jpeg\");\n resultPaths.push(newPath);\n optimizeJPEG(imgPath, newPath, amount);\n } else {\n // Optimize any other SIPS-compatible image type\n const jpegPath = `${environment.supportPath}/tmp.jpeg`;\n let newPath = newPaths[sourcePaths.indexOf(imgPath)];\n resultPaths.push(newPath);\n newPath = path.join(path.dirname(newPath), path.basename(newPath, path.extname(newPath)) + \" (Optimized).jpeg\");\n resultPaths.push(newPath);\n\n optimizeJPEG(imgPath, jpegPath, amount);\n execSync(`sips --setProperty format jpeg \"${jpegPath}\" --out \"${newPath}\"; rm \"${jpegPath}\"`);\n }\n }\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "# 6\n\n## Bugs\n- Incorrect handling of file extensions in some contexts (e.g., `jpeg` vs. `jpg`).\n- Potential errors in environments where the AppleScript or child_process executions are unsupported or malfunction.\n- Using AppleScript potentially limits the code to macOS environments.\n\n## Optimizations\n- **Encapsulation**: Separate logic for handling file paths into utility functions to avoid repetition.\n- **Cross-platform compatibility**: Avoid using AppleScript to make the code cross-platform.\n- **Type Safety**: Leverage TypeScript types more extensively.\n- **Concurrency**: Consider optimizing images concurrently to reduce execution time.\n- **Error Handling**: Implement comprehensive error handling for file operations and external command executions.\n- **Configuration Management**: Use a configuration object to define paths and preferences, minimizing the use of environment variables.\n\n## Good Points\n- **Comprehensive Image Handling**: Includes methods for optimizing JPEG, WebP, and SVG images.\n- **Use of External Libraries**: Integrates `svgo` for SVG optimization effectively.\n- **User Preferences**: Provides user preference handling for saving optimized images based on configured settings.\n- **Logical Structure**: Breaks down different optimization tasks into individual functions, aiding readability.\n\n## Summary\nThe provided code effectively implements image optimization operations, supporting various formats like JPEG, WebP, and SVG. It incorporates user preferences for the desired storage location of optimized images. However, the use of AppleScript limits compatibility to macOS. Additionally, repeated logic could benefit from refactoring, while incorporating better error handling and considering concurrent operations might improve the overall performance. Attention to cross-platform compatibility and encapsulation would enhance the code maintainability and usability.\n\n## Open source alternatives\n- **ImageMagick**: A powerful open source tool that handles image conversion and optimization across multiple platforms.\n- **Sharp**: A high-performance Node.js library for resizing images and converting formats.\n- **Squoosh**: A web-based image compressor that uses various libraries for compression, such as MozJPEG, WebP, and OptiPNG.", + "filename": "optimizeOperation.ts", + "path": "raycast/src/operations/optimizeOperation.ts", + "directory": "operations", + "grade": 6, + "size": 6817, + "line_count": 166 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/optimizeOperation.ts.md b/.reviews/raycast/src/operations/optimizeOperation.ts.md new file mode 100644 index 0000000..32b6579 --- /dev/null +++ b/.reviews/raycast/src/operations/optimizeOperation.ts.md @@ -0,0 +1,28 @@ +# 6 + +## Bugs +- Incorrect handling of file extensions in some contexts (e.g., `jpeg` vs. `jpg`). +- Potential errors in environments where the AppleScript or child_process executions are unsupported or malfunction. +- Using AppleScript potentially limits the code to macOS environments. + +## Optimizations +- **Encapsulation**: Separate logic for handling file paths into utility functions to avoid repetition. +- **Cross-platform compatibility**: Avoid using AppleScript to make the code cross-platform. +- **Type Safety**: Leverage TypeScript types more extensively. +- **Concurrency**: Consider optimizing images concurrently to reduce execution time. +- **Error Handling**: Implement comprehensive error handling for file operations and external command executions. +- **Configuration Management**: Use a configuration object to define paths and preferences, minimizing the use of environment variables. + +## Good Points +- **Comprehensive Image Handling**: Includes methods for optimizing JPEG, WebP, and SVG images. +- **Use of External Libraries**: Integrates `svgo` for SVG optimization effectively. +- **User Preferences**: Provides user preference handling for saving optimized images based on configured settings. +- **Logical Structure**: Breaks down different optimization tasks into individual functions, aiding readability. + +## Summary +The provided code effectively implements image optimization operations, supporting various formats like JPEG, WebP, and SVG. It incorporates user preferences for the desired storage location of optimized images. However, the use of AppleScript limits compatibility to macOS. Additionally, repeated logic could benefit from refactoring, while incorporating better error handling and considering concurrent operations might improve the overall performance. Attention to cross-platform compatibility and encapsulation would enhance the code maintainability and usability. + +## Open source alternatives +- **ImageMagick**: A powerful open source tool that handles image conversion and optimization across multiple platforms. +- **Sharp**: A high-performance Node.js library for resizing images and converting formats. +- **Squoosh**: A web-based image compressor that uses various libraries for compression, such as MozJPEG, WebP, and OptiPNG. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/padOperation.ts.json b/.reviews/raycast/src/operations/padOperation.ts.json new file mode 100644 index 0000000..756f7f3 --- /dev/null +++ b/.reviews/raycast/src/operations/padOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/padOperation.ts\n *\n * @summary Image padding operation with support for basic image formats, SVGs, and WebP.\n *\n * Created at : 2023-07-05 23:35:48\n * Last modified : 2023-07-06 14:51:59\n */\n\nimport { execSync } from \"child_process\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n} from \"../utilities/utils\";\n\n/**\n * Adds padding of the specified width and color to images, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to pad.\n * @param padding The width of the padding to add.\n * @param color The color of the padding to add as a hex string with no leading #.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function pad(sourcePaths: string[], padding: number, color: string) {\n const newPaths = getDestinationPaths(sourcePaths);\n const resultPaths: string[] = [];\n\n for (const imagePath of sourcePaths) {\n const dimensions = execSync(`sips -g pixelWidth -g pixelHeight \"${imagePath}\"`)\n .toString()\n .split(/(: |\\n)/g);\n const oldWidth = parseInt(dimensions[4]);\n const oldHeight = parseInt(dimensions[8]);\n\n if (imagePath.toLowerCase().endsWith(\".webp\")) {\n // Convert to PNG, apply padding, then restore to WebP\n resultPaths.push(\n await execSIPSCommandOnWebP(\n `sips --padToHeightWidth ${oldHeight + padding} ${oldWidth + padding} --padColor ${color}`,\n imagePath\n )\n );\n } else if (imagePath.toLowerCase().endsWith(\".svg\")) {\n // Convert to PNG, apply padding, then restore to SVG\n resultPaths.push(\n await execSIPSCommandOnSVG(\n `sips --padToHeightWidth ${oldHeight + padding} ${oldWidth + padding} --padColor ${color}`,\n imagePath\n )\n );\n } else {\n // Image is not a special format, so pad using SIPS\n const newPath = newPaths[sourcePaths.indexOf(imagePath)];\n resultPaths.push(newPath);\n\n execSync(\n `sips --padToHeightWidth ${oldHeight + padding} ${\n oldWidth + padding\n } --padColor ${color} -o \"${newPath}\" \"${imagePath}\"`\n );\n }\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "# 7\n\n## Bugs\n- The code assumes that SIPS is available in all environments, which could cause errors if it's not installed or supported.\n- Types for the image dimensions parsed from `sips` output aren't validated; potential risk if dimensions parsing fails or returns unexpected data.\n- The code does not handle the case where `getDestinationPaths` returns an undefined or null path, which may lead to runtime errors.\n\n## Optimizations\n- Consider adding error handling around external command executions with `execSync` for more robust error management.\n- Implement caching or memoization for `getDestinationPaths` if the function is compute-intensive to enhance performance.\n- Use specific libraries or native APIs for image processing that might be more efficient or provide better cross-compatibility with various formats and systems.\n\n## Good Points\n- The code supports multiple image formats including SVG and WebP, showing flexibility.\n- Image padding operation is abstracted at a high level with modular functions like `execSIPSCommandOnWebP` and `execSIPSCommandOnSVG` that separate concerns.\n- Utilizes a promise-based approach for asynchronous processing, promoting scalability and responsiveness.\n\n## Summary\nThe `padOperation.ts` file provides a versatile padding mechanism for images in various formats by employing the SIPS command-line utility. The code is well-structured with a clear division of responsibilities across functions. However, it presumes the availability of the SIPS tool across environments, which might not hold universally, and lacks error handling around command execution. By leveraging native libraries or more robust error handling techniques, the code can be significantly enhanced in terms of reliability and performance.\n\n## Open source alternatives\n- [Sharp](https://github.com/lovell/sharp): A high-performance image processing library for Node.js that supports padding among other features.\n- [Jimp](https://github.com/oliver-moran/jimp): An image processing library for Node.js entirely in JavaScript, capable of handling padding and various image manipulations.", + "filename": "padOperation.ts", + "path": "raycast/src/operations/padOperation.ts", + "directory": "operations", + "grade": 7, + "size": 2291, + "line_count": 69 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/padOperation.ts.md b/.reviews/raycast/src/operations/padOperation.ts.md new file mode 100644 index 0000000..445e3fa --- /dev/null +++ b/.reviews/raycast/src/operations/padOperation.ts.md @@ -0,0 +1,23 @@ +# 7 + +## Bugs +- The code assumes that SIPS is available in all environments, which could cause errors if it's not installed or supported. +- Types for the image dimensions parsed from `sips` output aren't validated; potential risk if dimensions parsing fails or returns unexpected data. +- The code does not handle the case where `getDestinationPaths` returns an undefined or null path, which may lead to runtime errors. + +## Optimizations +- Consider adding error handling around external command executions with `execSync` for more robust error management. +- Implement caching or memoization for `getDestinationPaths` if the function is compute-intensive to enhance performance. +- Use specific libraries or native APIs for image processing that might be more efficient or provide better cross-compatibility with various formats and systems. + +## Good Points +- The code supports multiple image formats including SVG and WebP, showing flexibility. +- Image padding operation is abstracted at a high level with modular functions like `execSIPSCommandOnWebP` and `execSIPSCommandOnSVG` that separate concerns. +- Utilizes a promise-based approach for asynchronous processing, promoting scalability and responsiveness. + +## Summary +The `padOperation.ts` file provides a versatile padding mechanism for images in various formats by employing the SIPS command-line utility. The code is well-structured with a clear division of responsibilities across functions. However, it presumes the availability of the SIPS tool across environments, which might not hold universally, and lacks error handling around command execution. By leveraging native libraries or more robust error handling techniques, the code can be significantly enhanced in terms of reliability and performance. + +## Open source alternatives +- [Sharp](https://github.com/lovell/sharp): A high-performance image processing library for Node.js that supports padding among other features. +- [Jimp](https://github.com/oliver-moran/jimp): An image processing library for Node.js entirely in JavaScript, capable of handling padding and various image manipulations. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/resizeOperation.ts.json b/.reviews/raycast/src/operations/resizeOperation.ts.json new file mode 100644 index 0000000..43ad2eb --- /dev/null +++ b/.reviews/raycast/src/operations/resizeOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/resizeOperation.ts\n *\n * @summary Image resizing operation with support for basic image formats, SVGs, and WebP.\n *\n * Created at : 2023-07-05 23:31:23\n * Last modified : 2023-07-06 14:52:02\n */\n\nimport { execSync } from \"child_process\";\nimport path from \"path\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n} from \"../utilities/utils\";\n\n/**\n * Resizes images to the specified width and height, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to resize.\n * @param width The width to resize the images to, or -1 if the width should be automatically calculated.\n * @param height The height to resize the images to, or -1 if the height should be automatically calculated.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function resize(sourcePaths: string[], width: number, height: number) {\n const pathStrings = '\"' + sourcePaths.join('\" \"') + '\"';\n const newPaths = getDestinationPaths(sourcePaths);\n\n if (pathStrings.toLocaleLowerCase().includes(\"webp\") || pathStrings.toLocaleLowerCase().includes(\"svg\")) {\n // Special formats in selection -- Handle each image individually\n const resultPaths = [];\n for (const imgPath of sourcePaths) {\n if (imgPath.toLowerCase().endsWith(\".webp\")) {\n // Convert to PNG, rotate and restore to WebP\n if (width != -1 && height == -1) {\n resultPaths.push(await execSIPSCommandOnWebP(`sips --resampleWidth ${width}`, imgPath));\n } else if (width == -1 && height != -1) {\n resultPaths.push(await execSIPSCommandOnWebP(`sips --resampleHeight ${height}`, imgPath));\n } else {\n resultPaths.push(await execSIPSCommandOnWebP(`sips --resampleHeightWidth ${height} ${width}`, imgPath));\n }\n } else if (imgPath.toLowerCase().endsWith(\".svg\")) {\n // Convert to PNG, resize, and restore to WebP\n if (width != -1 && height == -1) {\n resultPaths.push(await execSIPSCommandOnSVG(`sips --resampleWidth ${width}`, imgPath));\n } else if (width == -1 && height != -1) {\n resultPaths.push(await execSIPSCommandOnSVG(`sips --resampleHeight ${height}`, imgPath));\n } else {\n resultPaths.push(await execSIPSCommandOnSVG(`sips --resampleHeightWidth ${height} ${width}`, imgPath));\n }\n } else {\n // Image is not a special format, so just rotate it using SIPS\n const newPath = newPaths[sourcePaths.indexOf(imgPath)];\n resultPaths.push(newPath);\n\n if (width != -1 && height == -1) {\n execSync(`sips --resampleWidth ${width} -o \"${newPath}\" \"${imgPath}\"`);\n } else if (width == -1 && height != -1) {\n execSync(`sips --resampleHeight ${height} -o \"${newPath}\" \"${imgPath}\"`);\n } else {\n execSync(`sips --resampleHeightWidth ${height} -o \"${newPath}\" ${width} \"${imgPath}\"`);\n }\n }\n }\n await moveImageResultsToFinalDestination(resultPaths);\n } else {\n // No special formats -- Run commands on all images at once\n const outputLocation = newPaths.length == 1 ? newPaths[0] : path.join(path.dirname(newPaths[0]), \"resized\");\n\n if (newPaths.length > 1) execSync(`mkdir -p \"${outputLocation}\"`);\n\n if (width != -1 && height == -1) {\n execSync(`sips --resampleWidth ${width} -o \"${outputLocation}\" ${pathStrings}`);\n } else if (width == -1 && height != -1) {\n execSync(`sips --resampleHeight ${height} -o \"${outputLocation}\" ${pathStrings}`);\n } else {\n execSync(`sips --resampleHeightWidth ${height} ${width} -o \"${outputLocation}\" ${pathStrings}`);\n }\n await moveImageResultsToFinalDestination(newPaths);\n }\n}\n", + "review": "# 6\n\n## Bugs\n- Improper handling of invalid width and height parameters (e.g., both set to `-1`).\n- Lack of error handling for exceptions (e.g., failed execSync command).\n- Potential issue with path handling in `execSync` not being robust to shell meta-characters.\n\n## Optimizations\n- Add robust error handling for `execSync` and await operations.\n- Consider parameter validation and error checking for width and height inputs.\n- Use `const` instead of `let` for immutable variables for better readability.\n- Simplify the command strings using template literals and avoid repetitive code.\n- Consider optimizing asynchronous handling, possibly using `Promise.all`.\n\n## Good points\n- Clearly defined function with parameters and return type.\n- Comprehensive handling of different image formats including SVG and WebP.\n- Use of utility functions to modularize code such as `getDestinationPaths`.\n\n## Summary\nThe code achieves its intended function of resizing images and handles several formats effectively. However, there's room for improvement mainly in error handling, input validation, and potential refactoring opportunities to minimize repetitive code. More attention to security and performance considerations around shell command execution would improve its robustness.\n\n## Open source alternatives\n- [sharp](https://github.com/lovell/sharp): A high-performance image processing library in Node.js, supporting a wide array of operations on images.\n- [jimp](https://github.com/oliver-moran/jimp): An image processing library written entirely in JavaScript for Node, with comprehensive support for basic image manipulation.\n- [gm](https://github.com/aheckmann/gm): Node bindings to GraphicsMagick, a powerful image processing tool.\n", + "filename": "resizeOperation.ts", + "path": "raycast/src/operations/resizeOperation.ts", + "directory": "operations", + "grade": 6, + "size": 3794, + "line_count": 85 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/resizeOperation.ts.md b/.reviews/raycast/src/operations/resizeOperation.ts.md new file mode 100644 index 0000000..74e54b3 --- /dev/null +++ b/.reviews/raycast/src/operations/resizeOperation.ts.md @@ -0,0 +1,26 @@ +# 6 + +## Bugs +- Improper handling of invalid width and height parameters (e.g., both set to `-1`). +- Lack of error handling for exceptions (e.g., failed execSync command). +- Potential issue with path handling in `execSync` not being robust to shell meta-characters. + +## Optimizations +- Add robust error handling for `execSync` and await operations. +- Consider parameter validation and error checking for width and height inputs. +- Use `const` instead of `let` for immutable variables for better readability. +- Simplify the command strings using template literals and avoid repetitive code. +- Consider optimizing asynchronous handling, possibly using `Promise.all`. + +## Good points +- Clearly defined function with parameters and return type. +- Comprehensive handling of different image formats including SVG and WebP. +- Use of utility functions to modularize code such as `getDestinationPaths`. + +## Summary +The code achieves its intended function of resizing images and handles several formats effectively. However, there's room for improvement mainly in error handling, input validation, and potential refactoring opportunities to minimize repetitive code. More attention to security and performance considerations around shell command execution would improve its robustness. + +## Open source alternatives +- [sharp](https://github.com/lovell/sharp): A high-performance image processing library in Node.js, supporting a wide array of operations on images. +- [jimp](https://github.com/oliver-moran/jimp): An image processing library written entirely in JavaScript for Node, with comprehensive support for basic image manipulation. +- [gm](https://github.com/aheckmann/gm): Node bindings to GraphicsMagick, a powerful image processing tool. diff --git a/.reviews/raycast/src/operations/rotateOperation.ts.json b/.reviews/raycast/src/operations/rotateOperation.ts.json new file mode 100644 index 0000000..5c64c38 --- /dev/null +++ b/.reviews/raycast/src/operations/rotateOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/rotateOperation.ts\n *\n * @summary Image rotation operation with support for basic image formats, SVGs, WebP, and PDFs.\n *\n * Created at : 2023-07-05 23:24:24\n * Last modified : 2023-07-06 14:52:04\n */\n\nimport { execSync } from \"child_process\";\nimport * as fs from \"fs\";\nimport path from \"path\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n rotatePDF,\n} from \"../utilities/utils\";\n\n/**\n * Rotates images by the given amount of degrees, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to rotate.\n * @param degrees The amount of degrees to rotate the images.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function rotate(sourcePaths: string[], degrees: number) {\n const pathStrings = '\"' + sourcePaths.join('\" \"') + '\"';\n const newPaths = getDestinationPaths(sourcePaths);\n\n if (\n pathStrings.toLowerCase().includes(\"webp\") ||\n pathStrings.toLowerCase().includes(\"svg\") ||\n pathStrings.toLowerCase().includes(\"pdf\")\n ) {\n // Special formats in selection -- Handle each image individually\n const resultPaths = [];\n for (const imgPath of sourcePaths) {\n if (imgPath.toLowerCase().endsWith(\"webp\")) {\n // Convert to PNG, flip and restore to WebP\n resultPaths.push(await execSIPSCommandOnWebP(`sips --rotate ${degrees}`, imgPath));\n } else if (imgPath.toLowerCase().endsWith(\"svg\")) {\n // Convert to PNG, rotate, and restore to SVG\n resultPaths.push(await execSIPSCommandOnSVG(`sips --rotate ${degrees}`, imgPath));\n } else if (imgPath.toLowerCase().endsWith(\"pdf\")) {\n // Rotate each page of a PDF\n resultPaths.push(rotatePDF(imgPath, degrees));\n } else {\n // Image is not a special format, so just rotate it using SIPS\n const newPath = newPaths[sourcePaths.indexOf(imgPath)];\n resultPaths.push(newPath);\n execSync(`sips --rotate ${degrees} -o \"${newPath}\" \"${imgPath}\"`);\n }\n }\n await moveImageResultsToFinalDestination(resultPaths);\n } else {\n // No special formats -- Flip all images at once\n if (newPaths.length == 1) {\n execSync(`sips --rotate ${degrees} -o \"${newPaths[0]}\" ${pathStrings}`);\n } else {\n let exportDir = path.join(path.dirname(newPaths[0]), \"rotated\");\n\n let iter = 1;\n while (fs.existsSync(exportDir)) {\n exportDir = exportDir + `-${iter}`;\n iter++;\n }\n\n await fs.promises.mkdir(exportDir, { recursive: true });\n execSync(`sips --rotate ${degrees} -o \"${exportDir}\" ${pathStrings}`);\n\n sourcePaths.forEach((imgPath, index) => {\n fs.renameSync(path.join(exportDir, path.basename(imgPath)), newPaths[index]);\n });\n\n await fs.promises.rm(exportDir, { recursive: true, force: true });\n }\n await moveImageResultsToFinalDestination(newPaths);\n }\n}\n", + "review": "# 7\n\n## Bugs\n- The code uses `includes` and checks file extensions, which might result in false positives if these strings appear elsewhere in the filename.\n- The asynchronous nature of operations and use of `execSync` might lead to performance bottlenecks or block the event loop.\n\n## Optimizations\n- Use a more reliable way to check extensions, such as `path.extname()`.\n- Consider replacing `execSync` calls with asynchronous alternatives to avoid blocking the main thread.\n- Improve handling of file paths to prevent potential false positives and provide better logic on file type checking.\n\n## Good points\n- Organizes image manipulation functionalities logically with helper functions abstracted in a separate utility module.\n- Supports multiple image formats including special formats like WebP, SVG, and PDFs, enhancing flexibility.\n\n## Summary\nThe code effectively performs image rotations while supporting various formats. It uses helper utilities to manage different cases for SVG, WebP, and PDF files. However, it could benefit from improved file extension handling and a non-blocking approach to executing command-line tools. Additionally, leveraging asynchronous operations more consistently would enhance performance and reliability.\n\n## Open source alternatives\n- **ImageMagick**: A widely-used open-source image manipulation tool with comprehensive format support and operations.\n- **GraphicsMagick**: A fork of ImageMagick, focusing on efficiency and less resource consumption while maintaining similar functionalities.", + "filename": "rotateOperation.ts", + "path": "raycast/src/operations/rotateOperation.ts", + "directory": "operations", + "grade": 7, + "size": 2980, + "line_count": 83 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/rotateOperation.ts.md b/.reviews/raycast/src/operations/rotateOperation.ts.md new file mode 100644 index 0000000..9398347 --- /dev/null +++ b/.reviews/raycast/src/operations/rotateOperation.ts.md @@ -0,0 +1,21 @@ +# 7 + +## Bugs +- The code uses `includes` and checks file extensions, which might result in false positives if these strings appear elsewhere in the filename. +- The asynchronous nature of operations and use of `execSync` might lead to performance bottlenecks or block the event loop. + +## Optimizations +- Use a more reliable way to check extensions, such as `path.extname()`. +- Consider replacing `execSync` calls with asynchronous alternatives to avoid blocking the main thread. +- Improve handling of file paths to prevent potential false positives and provide better logic on file type checking. + +## Good points +- Organizes image manipulation functionalities logically with helper functions abstracted in a separate utility module. +- Supports multiple image formats including special formats like WebP, SVG, and PDFs, enhancing flexibility. + +## Summary +The code effectively performs image rotations while supporting various formats. It uses helper utilities to manage different cases for SVG, WebP, and PDF files. However, it could benefit from improved file extension handling and a non-blocking approach to executing command-line tools. Additionally, leveraging asynchronous operations more consistently would enhance performance and reliability. + +## Open source alternatives +- **ImageMagick**: A widely-used open-source image manipulation tool with comprehensive format support and operations. +- **GraphicsMagick**: A fork of ImageMagick, focusing on efficiency and less resource consumption while maintaining similar functionalities. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/runOperation.ts.json b/.reviews/raycast/src/operations/runOperation.ts.json new file mode 100644 index 0000000..1c4bf08 --- /dev/null +++ b/.reviews/raycast/src/operations/runOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/runOperation.ts\n *\n * @summary Runs an operation on the selected images.\n *\n * Created at : 2023-07-18 18:45:28\n * Last modified : 2023-07-18 18:46:08\n */\n\nimport { showToast, Toast } from \"@raycast/api\";\n\nimport { cleanup, showErrorToast } from \"../utilities/utils\";\n\n/**\n * Runs an operation on the selected images, displaying a toast while the operation is in progress.\n *\n * @param params.operation The operation to run.\n * @param params.selectedImages The paths of the selected images.\n * @param params.inProgressMessage The message to display while the operation is in progress.\n * @param params.successMessage The message to display if the operation succeeds.\n * @param params.failureMessage The message to display if the operation fails.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function runOperation(params: {\n operation: () => Promise;\n selectedImages: string[];\n inProgressMessage: string;\n successMessage: string;\n failureMessage: string;\n}) {\n if (params.selectedImages.length === 0 || (params.selectedImages.length === 1 && params.selectedImages[0] === \"\")) {\n await showToast({ title: \"No images selected\", style: Toast.Style.Failure });\n return;\n }\n\n const toast = await showToast({ title: params.inProgressMessage, style: Toast.Style.Animated });\n const pluralized = `image${params.selectedImages.length === 1 ? \"\" : \"s\"}`;\n try {\n await params.operation();\n toast.title = `${params.successMessage} ${params.selectedImages.length.toString()} ${pluralized}`;\n toast.style = Toast.Style.Success;\n } catch (error) {\n await showErrorToast(\n `${params.failureMessage} ${params.selectedImages.length.toString()} ${pluralized}`,\n error as Error,\n toast\n );\n } finally {\n await cleanup();\n }\n}\n", + "review": "## 7\n\n### Bugs\n- No specific bugs were identified in the code.\n\n### Optimizations\n- Consider using TypeScript's optional chaining or nullish coalescing for more concise checking of `params.selectedImages`.\n- The function could benefit from input validation, ensuring that `operation` is indeed a function before execution.\n- Improving error messages for better debugging might be helpful, currently, the error handling is relatively generic.\n\n### Good points\n- Utilizes async/await properly for handling asynchronous operations, making the code easier to follow.\n- Logical and concise error handling with try-catch for robustness.\n- Uses descriptive variable names such as `pluralized` and `toast`, which improves readability.\n\n### Summary\nThe code effectively fulfills its purpose, which is to execute an operation on a set of selected images while updating the user via toast notifications regarding the operation's status. The structure is clear, using async/await for asynchronous logic and try/catch for error management. The existing utility functions are well-utilized from the `utils` module, and the UI feedback is thoughtful. However, there\u2019s room to enhance input validation, error messaging, and potentially compact some of the logic with modern TypeScript features.\n\n### Open source alternatives\n- **ImageMagick**: This is a comprehensive, open-source suite for image manipulation that also provides APIs for programmatic control.\n- **Sharp**: A high-performance Node.js module focusing on fast and accessible image transformations.\n", + "filename": "runOperation.ts", + "path": "raycast/src/operations/runOperation.ts", + "directory": "operations", + "grade": 7, + "size": 1842, + "line_count": 52 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/runOperation.ts.md b/.reviews/raycast/src/operations/runOperation.ts.md new file mode 100644 index 0000000..216ea7b --- /dev/null +++ b/.reviews/raycast/src/operations/runOperation.ts.md @@ -0,0 +1,21 @@ +## 7 + +### Bugs +- No specific bugs were identified in the code. + +### Optimizations +- Consider using TypeScript's optional chaining or nullish coalescing for more concise checking of `params.selectedImages`. +- The function could benefit from input validation, ensuring that `operation` is indeed a function before execution. +- Improving error messages for better debugging might be helpful, currently, the error handling is relatively generic. + +### Good points +- Utilizes async/await properly for handling asynchronous operations, making the code easier to follow. +- Logical and concise error handling with try-catch for robustness. +- Uses descriptive variable names such as `pluralized` and `toast`, which improves readability. + +### Summary +The code effectively fulfills its purpose, which is to execute an operation on a set of selected images while updating the user via toast notifications regarding the operation's status. The structure is clear, using async/await for asynchronous logic and try/catch for error management. The existing utility functions are well-utilized from the `utils` module, and the UI feedback is thoughtful. However, there’s room to enhance input validation, error messaging, and potentially compact some of the logic with modern TypeScript features. + +### Open source alternatives +- **ImageMagick**: This is a comprehensive, open-source suite for image manipulation that also provides APIs for programmatic control. +- **Sharp**: A high-performance Node.js module focusing on fast and accessible image transformations. diff --git a/.reviews/raycast/src/operations/scaleOperation.ts.json b/.reviews/raycast/src/operations/scaleOperation.ts.json new file mode 100644 index 0000000..14479c8 --- /dev/null +++ b/.reviews/raycast/src/operations/scaleOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/scaleOperation.ts\n *\n * @summary Image scaling operation with support for basic image formats, SVGs, and WebP.\n *\n * Created at : 2023-07-05 23:05:46\n * Last modified : 2023-07-06 15:48:36\n */\n\nimport { execSync } from \"child_process\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n} from \"../utilities/utils\";\n\n/**\n * Scales images by the given scale factor, storing the results according to the user's preferences.\n *\n * @param sourcePaths The paths of the images to scale.\n * @param scaleFactor The factor by which to scale the images.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function scale(sourcePaths: string[], scaleFactor: number) {\n const newPaths = getDestinationPaths(sourcePaths);\n const resultPaths: string[] = [];\n\n for (const imagePath of sourcePaths) {\n const dimensions = execSync(`sips -g pixelWidth -g pixelHeight \"${imagePath}\"`)\n .toString()\n .split(/(: |\\n)/g);\n const oldWidth = parseInt(dimensions[4]);\n const oldHeight = parseInt(dimensions[8]);\n\n if (imagePath.toLowerCase().endsWith(\"webp\")) {\n // Convert to PNG, scale, the restore to WebP\n resultPaths.push(\n await execSIPSCommandOnWebP(\n `sips --resampleHeightWidth ${oldHeight * scaleFactor} ${oldWidth * scaleFactor}`,\n imagePath\n )\n );\n } else if (imagePath.toLowerCase().endsWith(\"svg\")) {\n // Convert to PNG, scale, and restore to SVG\n resultPaths.push(\n await execSIPSCommandOnSVG(\n `sips --resampleHeightWidth ${oldHeight * scaleFactor} ${oldWidth * scaleFactor}`,\n imagePath\n )\n );\n } else {\n // File is a normal image type\n const newPath = newPaths[sourcePaths.indexOf(imagePath)];\n resultPaths.push(newPath);\n execSync(\n `sips --resampleHeightWidth ${oldHeight * scaleFactor} ${oldWidth * scaleFactor} -o \"${newPath}\" \"${imagePath}\"`\n );\n }\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "**Grade: 6**\n\n### Bugs\n- Incorrect splitting of dimensions due to split(/(: |\\n)/g), which might not always reliably split the output into required parts.\n\n### Optimizations\n- **Error Handling:** No error handling is present for potential exceptions that may arise from execSync calls.\n- **Code Reuse:** Similar code blocks for handling WebP and SVG formats can be refactored into a reusable function.\n- **Parallel Execution:** Consider processing images in parallel to improve performance, especially for large batches, using promises.\n- **Validation:** Validate if the `scaleFactor` is a positive number.\n- **Library Alternative:** Native handling of image scaling with robust node libraries like sharp or Jimp could replace system calls, enhancing cross-platform usage.\n \n### Good Points\n- **Modular Function Design:** The function is well modularized and works separately from other functionalities.\n- **Multiple Format Handling:** Supports various image formats, including SVG and WebP.\n- **Clear Documentation:** Clear function documentation and comments.\n\n### Summary\nThe code provides a functional image scaling solution with support for multiple formats. However, it is somewhat reliant on system-level commands (SIPS), which may not be cross-platform and lacks error handling. There is potential to improve performance through parallel processing and refactor some sections for improved maintainability.\n\n### Open source alternatives\n- **Sharp:** A high-performance Node.js image processing library that supports various image transformations efficiently.\n- **Jimp:** An image processing library for Node.js with no external dependencies, supporting different image formats and transformations.", + "filename": "scaleOperation.ts", + "path": "raycast/src/operations/scaleOperation.ts", + "directory": "operations", + "grade": 6, + "size": 2110, + "line_count": 65 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/scaleOperation.ts.md b/.reviews/raycast/src/operations/scaleOperation.ts.md new file mode 100644 index 0000000..a42006f --- /dev/null +++ b/.reviews/raycast/src/operations/scaleOperation.ts.md @@ -0,0 +1,23 @@ +**Grade: 6** + +### Bugs +- Incorrect splitting of dimensions due to split(/(: |\n)/g), which might not always reliably split the output into required parts. + +### Optimizations +- **Error Handling:** No error handling is present for potential exceptions that may arise from execSync calls. +- **Code Reuse:** Similar code blocks for handling WebP and SVG formats can be refactored into a reusable function. +- **Parallel Execution:** Consider processing images in parallel to improve performance, especially for large batches, using promises. +- **Validation:** Validate if the `scaleFactor` is a positive number. +- **Library Alternative:** Native handling of image scaling with robust node libraries like sharp or Jimp could replace system calls, enhancing cross-platform usage. + +### Good Points +- **Modular Function Design:** The function is well modularized and works separately from other functionalities. +- **Multiple Format Handling:** Supports various image formats, including SVG and WebP. +- **Clear Documentation:** Clear function documentation and comments. + +### Summary +The code provides a functional image scaling solution with support for multiple formats. However, it is somewhat reliant on system-level commands (SIPS), which may not be cross-platform and lacks error handling. There is potential to improve performance through parallel processing and refactor some sections for improved maintainability. + +### Open source alternatives +- **Sharp:** A high-performance Node.js image processing library that supports various image transformations efficiently. +- **Jimp:** An image processing library for Node.js with no external dependencies, supporting different image formats and transformations. \ No newline at end of file diff --git a/.reviews/raycast/src/operations/stripEXIFOperation.ts.json b/.reviews/raycast/src/operations/stripEXIFOperation.ts.json new file mode 100644 index 0000000..02b7909 --- /dev/null +++ b/.reviews/raycast/src/operations/stripEXIFOperation.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file operations/padOperation.ts\n *\n * @summary Image sanitization operation with support for basic image formats, SVGs, and WebP.\n *\n * Created at : 2023-07-05 23:35:48\n * Last modified : 2024-01-28 05:10:25\n */\n\nimport { execSync } from \"child_process\";\n\nimport {\n execSIPSCommandOnSVG,\n execSIPSCommandOnWebP,\n getDestinationPaths,\n moveImageResultsToFinalDestination,\n} from \"../utilities/utils\";\nimport { ExifToolLocation } from \"../utilities/enums\";\nimport { environment } from \"@raycast/api\";\n\n/**\n * Strips EXIF data from the given images.\n *\n * @param sourcePaths The paths of the images to strip EXIF data from.\n * @param exifToolLocation The location of the ExifTool binary.\n * @returns A promise that resolves when the operation is complete.\n */\nexport default async function stripEXIF(sourcePaths: string[], exifToolLocation: ExifToolLocation) {\n const newPaths = getDestinationPaths(sourcePaths);\n const resultPaths: string[] = [];\n\n const exifCommand =\n exifToolLocation === ExifToolLocation.ON_PATH\n ? \"exiftool\"\n : `\"${environment.supportPath}/Image-ExifTool-12.74/exiftool\"`;\n\n // Make sure ExifTool is executable\n if (exifToolLocation === ExifToolLocation.SUPPORT_DIR) {\n execSync(`chmod +x \"${environment.supportPath}/Image-ExifTool-12.74/exiftool\"`);\n }\n\n for (const imagePath of sourcePaths) {\n if (imagePath.toLowerCase().endsWith(\".webp\")) {\n // Convert to PNG, remove EXIF, then restore to WebP\n resultPaths.push(await execSIPSCommandOnWebP(`${exifCommand} -all= \"${imagePath}\"`, imagePath));\n } else if (imagePath.toLowerCase().endsWith(\".svg\")) {\n // Convert to PNG, remove EXIF, then restore to SVG\n resultPaths.push(await execSIPSCommandOnSVG(`${exifCommand} -all= \"${imagePath}\"`, imagePath));\n } else {\n // Image is not a special format, so just strip EXIF data\n const newPath = newPaths[sourcePaths.indexOf(imagePath)];\n resultPaths.push(newPath);\n\n execSync(`${exifCommand} -all= -o \"${newPath}\" \"${imagePath}\"`);\n }\n }\n\n await moveImageResultsToFinalDestination(resultPaths);\n}\n", + "review": "# 7\n\n## Bugs\n- No handling for errors when executing shell commands using `execSync`, which can lead to application crashes if the command fails.\n- Assumption that EXIF tool is compatible and found at specified paths without checking.\n- Improper validation or handling for file paths and existence.\n\n## Optimizations\n- Use asynchronous functions with error handling instead of `execSync` to prevent blocking the event loop and better error control.\n- Add validation checks for input paths to ensure they exist and are valid.\n- Consider batching the operations to enhance performance rather than sequentially modifying each file.\n- Use environment variables to dynamically resolve the `exiftool` path rather than hardcoding paths.\n\n## Good points\n- Clear documentation and comments at the beginning of the file and functions, enhancing readability.\n- Modular structure by dividing utilities into separate functions, promoting reusability and maintainability.\n\n## Summary\nThe code provides a utility to strip EXIF data from various image formats, utilizing shell commands to perform operations like converting types and stripping metadata. While it is well-documented and structured, it lacks error handling and could benefit from optimizations like asynchronous processing and dynamic path resolution. The absence of error handling with `execSync` could pose stability issues, and the hardcoded paths for the 'exiftool' make it less flexible across different environments.\n\n## Open source alternatives\n- **ExifTool by Phil Harvey**: This is the tool being utilized, an open source platform for reading, writing, and editing metadata in images.\n- **piexifjs**: A JavaScript library for manipulating EXIF data directly within images, client-side without needing external binaries.\n- **sharp**: An open-source tool for high-performance image processing, offering features beyond metadata stripping, like resizing and converting images.", + "filename": "stripEXIFOperation.ts", + "path": "raycast/src/operations/stripEXIFOperation.ts", + "directory": "operations", + "grade": 7, + "size": 2105, + "line_count": 60 +} \ No newline at end of file diff --git a/.reviews/raycast/src/operations/stripEXIFOperation.ts.md b/.reviews/raycast/src/operations/stripEXIFOperation.ts.md new file mode 100644 index 0000000..3949193 --- /dev/null +++ b/.reviews/raycast/src/operations/stripEXIFOperation.ts.md @@ -0,0 +1,24 @@ +# 7 + +## Bugs +- No handling for errors when executing shell commands using `execSync`, which can lead to application crashes if the command fails. +- Assumption that EXIF tool is compatible and found at specified paths without checking. +- Improper validation or handling for file paths and existence. + +## Optimizations +- Use asynchronous functions with error handling instead of `execSync` to prevent blocking the event loop and better error control. +- Add validation checks for input paths to ensure they exist and are valid. +- Consider batching the operations to enhance performance rather than sequentially modifying each file. +- Use environment variables to dynamically resolve the `exiftool` path rather than hardcoding paths. + +## Good points +- Clear documentation and comments at the beginning of the file and functions, enhancing readability. +- Modular structure by dividing utilities into separate functions, promoting reusability and maintainability. + +## Summary +The code provides a utility to strip EXIF data from various image formats, utilizing shell commands to perform operations like converting types and stripping metadata. While it is well-documented and structured, it lacks error handling and could benefit from optimizations like asynchronous processing and dynamic path resolution. The absence of error handling with `execSync` could pose stability issues, and the hardcoded paths for the 'exiftool' make it less flexible across different environments. + +## Open source alternatives +- **ExifTool by Phil Harvey**: This is the tool being utilized, an open source platform for reading, writing, and editing metadata in images. +- **piexifjs**: A JavaScript library for manipulating EXIF data directly within images, client-side without needing external binaries. +- **sharp**: An open-source tool for high-performance image processing, offering features beyond metadata stripping, like resizing and converting images. \ No newline at end of file diff --git a/.reviews/raycast/src/optimize.ts.json b/.reviews/raycast/src/optimize.ts.json new file mode 100644 index 0000000..0f1fee6 --- /dev/null +++ b/.reviews/raycast/src/optimize.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file optimize.ts\n *\n * @summary Raycast command to optimize selected images.\n *\n * Created at : 2023-07-06 14:55:16\n * Last modified : 2023-07-18 18:48:32\n */\n\nimport { showToast, Toast } from \"@raycast/api\";\n\nimport optimize from \"./operations/optimizeOperation\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command(props: { arguments: { optimizationFactor: string } }) {\n const { optimizationFactor } = props.arguments;\n\n let optimizationValue = 100;\n if (optimizationFactor != \"\") {\n optimizationValue = parseFloat(optimizationFactor);\n if (!optimizationValue) {\n await showToast({ title: \"Invalid optimization factor\", style: Toast.Style.Failure });\n return;\n }\n }\n\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => optimize(selectedImages, optimizationValue),\n selectedImages,\n inProgressMessage: \"Optimization in progress...\",\n successMessage: \"Optimized\",\n failureMessage: \"Failed to optimize\",\n });\n}\n", + "review": "8\n\n### Bugs\n- No apparent bugs observed in the code.\n\n### Optimizations\n- Add error handling when `getSelectedImages` or `runOperation` might fail, including network errors or file access issues.\n- Consider validating `optimizationFactor` more strictly to ensure it falls within an acceptable range (e.g., 0-100).\n- Add type safety by defining the structure of `selectedImages` or other complex data structures.\n- Include comments for complex lines or logic to improve readability.\n\n### Good points\n- Efficient and clear use of asynchronous functions with `async/await`.\n- Good modularity by separating operations into utility functions.\n- Proper use of `import` to manage dependencies enhances maintainability.\n- Informative feedback is provided to the user with toast messages.\n\n### Summary\nThis script efficiently performs an optimization operation on selected images with user feedback through toast notifications. It\u2019s well-structured, dividing responsibilities across utility functions (`getSelectedImages`, `runOperation`) and dependencies from Raycast API. Some potential improvements could be made in error handling and input validation.\n\n### Open source alternatives\n- **ImageOptim:** A tool that compresses images without sacrificing quality, an open-source script and applicable API exist for similar operations.\n- **Sharp:** A high-performance Node.js image processing library that provides image optimization capabilities.", + "filename": "optimize.ts", + "path": "raycast/src/optimize.ts", + "directory": "src", + "grade": 8, + "size": 1100, + "line_count": 37 +} \ No newline at end of file diff --git a/.reviews/raycast/src/optimize.ts.md b/.reviews/raycast/src/optimize.ts.md new file mode 100644 index 0000000..8418619 --- /dev/null +++ b/.reviews/raycast/src/optimize.ts.md @@ -0,0 +1,23 @@ +8 + +### Bugs +- No apparent bugs observed in the code. + +### Optimizations +- Add error handling when `getSelectedImages` or `runOperation` might fail, including network errors or file access issues. +- Consider validating `optimizationFactor` more strictly to ensure it falls within an acceptable range (e.g., 0-100). +- Add type safety by defining the structure of `selectedImages` or other complex data structures. +- Include comments for complex lines or logic to improve readability. + +### Good points +- Efficient and clear use of asynchronous functions with `async/await`. +- Good modularity by separating operations into utility functions. +- Proper use of `import` to manage dependencies enhances maintainability. +- Informative feedback is provided to the user with toast messages. + +### Summary +This script efficiently performs an optimization operation on selected images with user feedback through toast notifications. It’s well-structured, dividing responsibilities across utility functions (`getSelectedImages`, `runOperation`) and dependencies from Raycast API. Some potential improvements could be made in error handling and input validation. + +### Open source alternatives +- **ImageOptim:** A tool that compresses images without sacrificing quality, an open-source script and applicable API exist for similar operations. +- **Sharp:** A high-performance Node.js image processing library that provides image optimization capabilities. \ No newline at end of file diff --git a/.reviews/raycast/src/pad.ts.json b/.reviews/raycast/src/pad.ts.json new file mode 100644 index 0000000..1aa92d8 --- /dev/null +++ b/.reviews/raycast/src/pad.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file pad.ts\n *\n * @summary Raycast command to add padding to selected images.\n *\n * Created at : 2023-07-06 14:55:36\n * Last modified : 2023-07-18 18:48:38\n */\n\nimport { getPreferenceValues, showToast, Toast } from \"@raycast/api\";\n\nimport pad from \"./operations/padOperation\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport { PadPreferences } from \"./utilities/preferences\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command(props: { arguments: { amount: string; hexcolor: string } }) {\n const { amount, hexcolor } = props.arguments;\n const selectedImages = await getSelectedImages();\n const preferences = getPreferenceValues();\n\n const padAmount = parseInt(amount);\n if (isNaN(padAmount) || padAmount < 0) {\n await showToast({ title: \"Padding amount must be a positive integer\", style: Toast.Style.Failure });\n return;\n }\n\n let hexString = hexcolor || preferences.defaultPadColor;\n if (hexString.startsWith(\"#\")) {\n hexString = hexString.substring(1);\n }\n if (!hexString.match(/[0-9A-Fa-f]{6}/)) {\n await showToast({ title: \"Invalid HEX Color\", style: Toast.Style.Failure });\n return;\n }\n\n await runOperation({\n operation: () => pad(selectedImages, padAmount, hexString),\n selectedImages,\n inProgressMessage: \"Padding in progress...\",\n successMessage: \"Padded\",\n failureMessage: \"Failed to pad\",\n });\n}\n", + "review": "**Grade: 8**\n\n### Bugs\n- No specific bugs were identified in the provided code snippet.\n\n### Optimizations\n- Consider validating if the `selectedImages` array is empty and notify the user, preventing unnecessary operations.\n- Use a regex pattern to verify the hex color more robustly, ensuring it consistently detects valid colors.\n- Add error handling for `runOperation` to address unexpected issues within the operation.\n- Ensure that the hex color is adapted for alpha transparency if needed.\n\n### Good Points\n- The code is well-organized with functions for specific tasks, promoting readability.\n- Proper validation for input parameters (amount and hexcolor) is implemented.\n- User feedback is integrated into the process, ensuring a good user experience with toasts handling both successes and failures.\n- Async-await is used properly for handling asynchronous functions, maintaining clean and understandable flow control.\n\n### Summary\nThe code is generally clean and well-structured, with a focus on validating user inputs and managing user feedback through toast notifications. The separation of logic into utility functions like `getSelectedImages`, `pad`, and `runOperation` promotes maintainability and modularity. There are opportunities for further validation, such as ensuring selected images are available and enhancing hex color validation. \n\n### Open source alternatives\n- **ImageMagick**: An open-source software suite for displaying, converting, and editing raster image and vector image files.\n- **GIMP**: A free and open-source image editor, which can be used for tasks such as photo retouching, image editing, and image composition.\n- **Krita**: An open-source application for digital painting, image editing, and animation.", + "filename": "pad.ts", + "path": "raycast/src/pad.ts", + "directory": "src", + "grade": 8, + "size": 1434, + "line_count": 45 +} \ No newline at end of file diff --git a/.reviews/raycast/src/pad.ts.md b/.reviews/raycast/src/pad.ts.md new file mode 100644 index 0000000..58f3a53 --- /dev/null +++ b/.reviews/raycast/src/pad.ts.md @@ -0,0 +1,24 @@ +**Grade: 8** + +### Bugs +- No specific bugs were identified in the provided code snippet. + +### Optimizations +- Consider validating if the `selectedImages` array is empty and notify the user, preventing unnecessary operations. +- Use a regex pattern to verify the hex color more robustly, ensuring it consistently detects valid colors. +- Add error handling for `runOperation` to address unexpected issues within the operation. +- Ensure that the hex color is adapted for alpha transparency if needed. + +### Good Points +- The code is well-organized with functions for specific tasks, promoting readability. +- Proper validation for input parameters (amount and hexcolor) is implemented. +- User feedback is integrated into the process, ensuring a good user experience with toasts handling both successes and failures. +- Async-await is used properly for handling asynchronous functions, maintaining clean and understandable flow control. + +### Summary +The code is generally clean and well-structured, with a focus on validating user inputs and managing user feedback through toast notifications. The separation of logic into utility functions like `getSelectedImages`, `pad`, and `runOperation` promotes maintainability and modularity. There are opportunities for further validation, such as ensuring selected images are available and enhancing hex color validation. + +### Open source alternatives +- **ImageMagick**: An open-source software suite for displaying, converting, and editing raster image and vector image files. +- **GIMP**: A free and open-source image editor, which can be used for tasks such as photo retouching, image editing, and image composition. +- **Krita**: An open-source application for digital painting, image editing, and animation. \ No newline at end of file diff --git a/.reviews/raycast/src/resize.ts.json b/.reviews/raycast/src/resize.ts.json new file mode 100644 index 0000000..a2bb603 --- /dev/null +++ b/.reviews/raycast/src/resize.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file resize.ts\n *\n * @summary Raycast command to resize selected images to a specified width and/or height.\n *\n * Created at : 2023-07-06 14:55:58\n * Last modified : 2023-07-18 18:48:42\n */\n\nimport { showToast, Toast } from \"@raycast/api\";\n\nimport resize from \"./operations/resizeOperation\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command(props: { arguments: { width: string; height: string } }) {\n const { width, height } = props.arguments;\n\n if (width == \"\" && height == \"\") {\n await showToast({ title: \"Must specify either width or height\", style: Toast.Style.Failure });\n return;\n }\n\n const widthInt = width == \"\" ? -1 : parseInt(width);\n const heightInt = height == \"\" ? -1 : parseInt(height);\n\n if (isNaN(widthInt)) {\n await showToast({ title: \"Width must be an integer\", style: Toast.Style.Failure });\n return;\n } else if (isNaN(heightInt)) {\n await showToast({ title: \"Height must be an integer\", style: Toast.Style.Failure });\n return;\n }\n\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => resize(selectedImages, widthInt, heightInt),\n selectedImages,\n inProgressMessage: \"Resizing in progress...\",\n successMessage: \"Resized\",\n failureMessage: \"Failed to resize\",\n });\n}\n", + "review": "# 8\n\n## Bugs\n- No significant bugs apparent in the code.\n\n## Optimizations\n- Convert width and height to integers before validating if they are empty to avoid repetition.\n- Consider adding validation to ensure width and height are positive before use in resizing.\n- Check if `getSelectedImages` accounts for possible errors or returns an empty array, potentially needing an additional user feedback if no images are selected.\n \n## Good points\n- The code is well-structured with clear separation of concerns.\n- Effective use of async/await for handling asynchronous operations.\n- Good error handling with user feedback using toast messages.\n- Modularized operations allow for easy maintenance and unit testing.\n- Code comments provide a clear summary at the top of the file.\n\n## Summary\nThe code provides functionality to resize images by setting a specific width and/or height using a Command interface. It checks for empty inputs and validates conversions to integers, ensuring that the user inputs correct data before processing. The use of modular functions with proper async operations and feedback makes this program easy to extend and maintain; however, minor improvements could be made to further optimize the validation process.\n\n## Open source alternatives\n- **ImageMagick**: A powerful open-source tool to convert, edit, or compose bitmap images. \n- **GraphicsMagick**: A fork of ImageMagick known for its speed and efficiency.\n- **Sharp**: A high-performance Node.js library for image processing that enables resizing, cropping, and more.", + "filename": "resize.ts", + "path": "raycast/src/resize.ts", + "directory": "src", + "grade": 8, + "size": 1379, + "line_count": 44 +} \ No newline at end of file diff --git a/.reviews/raycast/src/resize.ts.md b/.reviews/raycast/src/resize.ts.md new file mode 100644 index 0000000..86e1ce2 --- /dev/null +++ b/.reviews/raycast/src/resize.ts.md @@ -0,0 +1,24 @@ +# 8 + +## Bugs +- No significant bugs apparent in the code. + +## Optimizations +- Convert width and height to integers before validating if they are empty to avoid repetition. +- Consider adding validation to ensure width and height are positive before use in resizing. +- Check if `getSelectedImages` accounts for possible errors or returns an empty array, potentially needing an additional user feedback if no images are selected. + +## Good points +- The code is well-structured with clear separation of concerns. +- Effective use of async/await for handling asynchronous operations. +- Good error handling with user feedback using toast messages. +- Modularized operations allow for easy maintenance and unit testing. +- Code comments provide a clear summary at the top of the file. + +## Summary +The code provides functionality to resize images by setting a specific width and/or height using a Command interface. It checks for empty inputs and validates conversions to integers, ensuring that the user inputs correct data before processing. The use of modular functions with proper async operations and feedback makes this program easy to extend and maintain; however, minor improvements could be made to further optimize the validation process. + +## Open source alternatives +- **ImageMagick**: A powerful open-source tool to convert, edit, or compose bitmap images. +- **GraphicsMagick**: A fork of ImageMagick known for its speed and efficiency. +- **Sharp**: A high-performance Node.js library for image processing that enables resizing, cropping, and more. \ No newline at end of file diff --git a/.reviews/raycast/src/rotate.ts.json b/.reviews/raycast/src/rotate.ts.json new file mode 100644 index 0000000..9bcce34 --- /dev/null +++ b/.reviews/raycast/src/rotate.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file rotate.ts\n *\n * @summary Raycast command to rotate selected images by a specified number of degrees.\n *\n * Created at : 2023-07-06 14:56:15\n * Last modified : 2023-07-18 18:48:47\n */\n\nimport { getPreferenceValues, showToast, Toast } from \"@raycast/api\";\n\nimport rotate from \"./operations/rotateOperation\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport { RotatePreferences } from \"./utilities/preferences\";\nimport { parser } from \"mathjs\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command(props: { arguments: { angle: string } }) {\n const { angle } = props.arguments;\n const preferences = getPreferenceValues();\n\n let angleNumber = parseFloat(parser().evaluate(angle).toString());\n if (isNaN(angleNumber)) {\n await showToast({ title: \"Angle must be a number\", style: Toast.Style.Failure });\n return;\n }\n\n if (preferences.rotationUnit === \"radians\") {\n angleNumber = angleNumber * (180 / Math.PI);\n }\n\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => rotate(selectedImages, angleNumber),\n selectedImages,\n inProgressMessage: \"Rotation in progress...\",\n successMessage: \"Rotated\",\n failureMessage: \"Failed to rotate\",\n });\n}\n", + "review": "**7**\n\n### Bugs\n- None identified in the provided code snippet; it appears to execute its main function without error.\n\n### Optimizations\n- Use `Math.PI` directly when converting radians to degrees for enhanced readability instead of recalculating `180 / Math.PI`.\n- Consider adding error handling for the `getSelectedImages()` and `runOperation` calls to provide a fallback mechanism if external module functions fail.\n\n### Good points\n- The use of `mathjs` parser allows flexible input for the angle (supporting expressions).\n- Separation of concerns is handled well by delegating the rotate logic to a separate module (`rotateOperation`).\n- User feedback is effectively provided through toast notifications.\n\n### Summary\nThe code is well-structured for a command module intended to rotate images. It effectively parses input, converts units as needed, executes a rotation operation, and provides comprehensive user feedback via toast messages. Improvements could be made in error handling and maintaining readable conversion formulas.\n\n### Open source alternatives\n- **GIMP (GNU Image Manipulation Program)**: Provides extensive image editing features, including rotation.\n- **ImageMagick**: A command-line tool for image manipulation, including rotating images by specified degrees.\n- **Paint.NET**: An open-source image and photo editing software with a straightforward user interface, supporting image rotation.", + "filename": "rotate.ts", + "path": "raycast/src/rotate.ts", + "directory": "src", + "grade": 7, + "size": 1295, + "line_count": 41 +} \ No newline at end of file diff --git a/.reviews/raycast/src/rotate.ts.md b/.reviews/raycast/src/rotate.ts.md new file mode 100644 index 0000000..cf2a0e1 --- /dev/null +++ b/.reviews/raycast/src/rotate.ts.md @@ -0,0 +1,21 @@ +**7** + +### Bugs +- None identified in the provided code snippet; it appears to execute its main function without error. + +### Optimizations +- Use `Math.PI` directly when converting radians to degrees for enhanced readability instead of recalculating `180 / Math.PI`. +- Consider adding error handling for the `getSelectedImages()` and `runOperation` calls to provide a fallback mechanism if external module functions fail. + +### Good points +- The use of `mathjs` parser allows flexible input for the angle (supporting expressions). +- Separation of concerns is handled well by delegating the rotate logic to a separate module (`rotateOperation`). +- User feedback is effectively provided through toast notifications. + +### Summary +The code is well-structured for a command module intended to rotate images. It effectively parses input, converts units as needed, executes a rotation operation, and provides comprehensive user feedback via toast messages. Improvements could be made in error handling and maintaining readable conversion formulas. + +### Open source alternatives +- **GIMP (GNU Image Manipulation Program)**: Provides extensive image editing features, including rotation. +- **ImageMagick**: A command-line tool for image manipulation, including rotating images by specified degrees. +- **Paint.NET**: An open-source image and photo editing software with a straightforward user interface, supporting image rotation. \ No newline at end of file diff --git a/.reviews/raycast/src/scale.ts.json b/.reviews/raycast/src/scale.ts.json new file mode 100644 index 0000000..1bf1ba4 --- /dev/null +++ b/.reviews/raycast/src/scale.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file scale.ts\n *\n * @summary Raycast command to scale selected images by a given factor.\n *\n * Created at : 2023-07-06 14:56:29\n * Last modified : 2023-07-18 18:48:52\n */\n\nimport { showToast, Toast } from \"@raycast/api\";\n\nimport scale from \"./operations/scaleOperation\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport runOperation from \"./operations/runOperation\";\n\nexport default async function Command(props: { arguments: { scaleFactor: string } }) {\n const { scaleFactor } = props.arguments;\n\n const scaleNumber = parseFloat(scaleFactor);\n if (isNaN(scaleNumber)) {\n await showToast({ title: \"Scale factor must be a number\", style: Toast.Style.Failure });\n return;\n }\n\n const selectedImages = await getSelectedImages();\n await runOperation({\n operation: () => scale(selectedImages, scaleNumber),\n selectedImages,\n inProgressMessage: \"Scaling in progress...\",\n successMessage: \"Scaled\",\n failureMessage: \"Failed to scale\",\n });\n}\n", + "review": "# 7\n\n## Bugs\n- No explicit error handling if `getSelectedImages()` fails or returns undefined.\n- Missing type checking for the values returned by `getSelectedImages()`.\n\n## Optimizations\n- TypeScript types can be explicitly defined for functions and returned values for better type safety.\n- Consider using try-catch blocks to manage potential errors better during asynchronous operations.\n\n## Good points\n- The code utilizes asynchronous functions efficiently with `async/await`.\n- The use of modular functions like `getSelectedImages` and `runOperation` signifies good separation of concerns.\n- User feedback is implemented via the Raycast Toast API, providing clear messaging for success or failure.\n\n## Summary\nThe provided code is concise and effectively leverages asynchronous functions to perform image scaling. It correctly utilizes separation of concerns by abstracting different operations into separate modules, e.g., `scaleOperation` and `runOperation`. However, the code can be improved with additional error handling to manage potential failures when retrieving images and scaling them. Defining specific TypeScript types would enhance type safety, increasing code robustness.\n\n## Open source alternatives\n- **ImageMagick**: A powerful open-source software system to convert, edit, or compose images, capable of handling various image transformations including scaling.", + "filename": "scale.ts", + "path": "raycast/src/scale.ts", + "directory": "src", + "grade": 7, + "size": 988, + "line_count": 34 +} \ No newline at end of file diff --git a/.reviews/raycast/src/scale.ts.md b/.reviews/raycast/src/scale.ts.md new file mode 100644 index 0000000..6b5caf7 --- /dev/null +++ b/.reviews/raycast/src/scale.ts.md @@ -0,0 +1,20 @@ +# 7 + +## Bugs +- No explicit error handling if `getSelectedImages()` fails or returns undefined. +- Missing type checking for the values returned by `getSelectedImages()`. + +## Optimizations +- TypeScript types can be explicitly defined for functions and returned values for better type safety. +- Consider using try-catch blocks to manage potential errors better during asynchronous operations. + +## Good points +- The code utilizes asynchronous functions efficiently with `async/await`. +- The use of modular functions like `getSelectedImages` and `runOperation` signifies good separation of concerns. +- User feedback is implemented via the Raycast Toast API, providing clear messaging for success or failure. + +## Summary +The provided code is concise and effectively leverages asynchronous functions to perform image scaling. It correctly utilizes separation of concerns by abstracting different operations into separate modules, e.g., `scaleOperation` and `runOperation`. However, the code can be improved with additional error handling to manage potential failures when retrieving images and scaling them. Defining specific TypeScript types would enhance type safety, increasing code robustness. + +## Open source alternatives +- **ImageMagick**: A powerful open-source software system to convert, edit, or compose images, capable of handling various image transformations including scaling. \ No newline at end of file diff --git a/.reviews/raycast/src/strip-exif.ts.json b/.reviews/raycast/src/strip-exif.ts.json new file mode 100644 index 0000000..18802c2 --- /dev/null +++ b/.reviews/raycast/src/strip-exif.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "import { execSync } from \"child_process\";\nimport * as https from \"https\";\nimport * as tar from \"tar\";\nimport * as fs from \"fs\";\nimport * as crypto from \"crypto\";\n\nimport { confirmAlert, environment, LocalStorage, showToast, Toast } from \"@raycast/api\";\n\nimport runOperation from \"./operations/runOperation\";\nimport stripEXIF from \"./operations/stripEXIFOperation\";\nimport { ExifToolLocation } from \"./utilities/enums\";\nimport { getSelectedImages } from \"./utilities/utils\";\nimport path from \"path\";\n\n/**\n * Prompts the user to install ExifTool. If the user accepts, ExifTool is installed to the support directory.\n */\nasync function installExifTool() {\n if (\n await confirmAlert({\n title: \"Install ExifTool\",\n message:\n \"ExifTool is required to strip EXIF data. Would you like to install it now?\\n\\nThis will use 26.2 MB of disk space.\",\n primaryAction: {\n title: \"Install\",\n },\n })\n ) {\n const toast = await showToast({\n title: \"Installing ExifTool...\",\n style: Toast.Style.Animated,\n });\n\n const supportPath = environment.supportPath;\n const tarURL = \"https://exiftool.org/Image-ExifTool-12.74.tar.gz\";\n const checksum = \"aedb28b1427c53205ab261fa31ff3feda73e7f17a0c181453651680e5666c48a\";\n\n let waiting = true;\n https.get(tarURL, async (response) => {\n const tarName = \"Image-ExifTool-12.74.tar.gz\";\n const tarPath = path.join(supportPath, tarName);\n const file = fs.createWriteStream(tarPath);\n response.pipe(file);\n\n // Checksum verification\n let valid = false;\n const hash = crypto.createHash(\"sha256\");\n response.on(\"data\", (data) => hash.update(data));\n response.on(\"end\", async () => {\n const hex = hash.digest(\"hex\");\n if (hex !== checksum) {\n toast.title = \"Checksum verification failed\";\n toast.style = Toast.Style.Failure;\n waiting = false;\n return;\n }\n valid = true;\n });\n\n file.on(\"finish\", async () => {\n file.close();\n if (valid) {\n // Extract the tarball\n await tar.x({ file: `${supportPath}/Image-ExifTool-12.74.tar.gz`, cwd: supportPath });\n await LocalStorage.setItem(\"exifToolLocation\", ExifToolLocation.SUPPORT_DIR);\n waiting = false;\n }\n await fs.promises.unlink(tarPath);\n toast.title = \"Done!\";\n toast.style = Toast.Style.Success;\n });\n });\n\n while (waiting) {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n } else {\n await LocalStorage.removeItem(\"exifToolLocation\");\n }\n}\n\n/**\n * Determines whether ExifTool is on the path. If not, prompts the user to install it.\n */\nasync function setExifToolLocation() {\n // See if ExifTool is on the path\n try {\n execSync(\"exiftool -ver\");\n await LocalStorage.setItem(\"exifToolLocation\", ExifToolLocation.ON_PATH);\n } catch (error) {\n // If not, prompt the user to install it\n await installExifTool();\n }\n}\n\n/**\n * Gets the location of ExifTool, either on the path or in the support directory.\n * @returns The location of ExifTool, either on the path or in the support directory.\n */\nasync function getExifToolLocation() {\n const initialLocation = await LocalStorage.getItem(\"exifToolLocation\");\n if (\n initialLocation !== ExifToolLocation.ON_PATH &&\n (initialLocation !== ExifToolLocation.SUPPORT_DIR ||\n !fs.existsSync(`${environment.supportPath}/Image-ExifTool-12.74/exiftool`))\n ) {\n await setExifToolLocation();\n }\n return await LocalStorage.getItem(\"exifToolLocation\");\n}\n\nexport default async function Command() {\n const selectedImages = await getSelectedImages();\n const exifToolLocation = await getExifToolLocation();\n if (!exifToolLocation) {\n await showToast({\n title: \"Command Cancelled\",\n message: \"ExifTool is required to strip EXIF data.\",\n style: Toast.Style.Failure,\n });\n return;\n }\n\n await runOperation({\n operation: () => stripEXIF(selectedImages, exifToolLocation as ExifToolLocation),\n selectedImages,\n inProgressMessage: \"Sanitizing...\",\n successMessage: \"Sanitized\",\n failureMessage: \"Failed to sanitize\",\n });\n}\n", + "review": "## 7\n\n### Bugs\n- **Checksum Validation Issue:** The variable `valid` is assigned but potentially read before it's updated due to asynchronous flow.\n- **Potential Async Leak:** Use of `fs.createWriteStream` and file operations might cause issues if they aren't properly awaited.\n\n### Optimizations\n- **Remove the `valid` flag:** Directly move checksum verification inside `file.on(\"finish\", ...` to avoid confusion.\n- **Use Promises for better Control:** Wrap the `https.get`, `file.on(\"finish\", ...)`, and `response.on(\"end\", ...)` with Promises for better error handling and cleaner async code.\n- **Readability improvement:** Use `async/await` consistently for an easier-to-read code structure rather than mixing with callbacks.\n- **Detect and handle HTTPS download errors:** Add error handling for the download request in case of network issues.\n- **Optimize file path assembly:** Use `path.join` consistently instead of concatenating paths with template strings.\n\n### Good points\n- **User Confirmation:** Proper user confirmation is implemented for the installation process.\n- **Feedback messages:** The user is consistently informed of the progress and outcome through toast messages.\n- **Checksum Verification:** There is a built-in security feature with checksum verification to ensure the integrity of the downloaded file.\n- **Use of Constants:** Constants like the tar URL and checksum are kept cleanly at the start, improving maintainability.\n\n### Summary\nThe code handles the installation of a third-party tool (ExifTool), checking if it's already installed, and managing its installation if necessary. It's equipped with user notifications and checksum verifications for ensuring software integrity. Despite being generally well-structured, enhancements in asynchronous handling, error management, and certain code simplifications could elevate its quality and reliability.\n\n### Open source alternatives\n- **ExifTool**: The same tool used in this script, but its native installation or use from command line can often be a direct alternative without custom scripts.\n- **ImageMagick**: Another powerful tool to manipulate images and metadata, which can handle EXIF data.\n- **MetaEdit**: A lighter tool suite for editing metadata in image files, often available in many package managers.", + "filename": "strip-exif.ts", + "path": "raycast/src/strip-exif.ts", + "directory": "src", + "grade": 7, + "size": 4192, + "line_count": 132 +} \ No newline at end of file diff --git a/.reviews/raycast/src/strip-exif.ts.md b/.reviews/raycast/src/strip-exif.ts.md new file mode 100644 index 0000000..5f9fd39 --- /dev/null +++ b/.reviews/raycast/src/strip-exif.ts.md @@ -0,0 +1,26 @@ +## 7 + +### Bugs +- **Checksum Validation Issue:** The variable `valid` is assigned but potentially read before it's updated due to asynchronous flow. +- **Potential Async Leak:** Use of `fs.createWriteStream` and file operations might cause issues if they aren't properly awaited. + +### Optimizations +- **Remove the `valid` flag:** Directly move checksum verification inside `file.on("finish", ...` to avoid confusion. +- **Use Promises for better Control:** Wrap the `https.get`, `file.on("finish", ...)`, and `response.on("end", ...)` with Promises for better error handling and cleaner async code. +- **Readability improvement:** Use `async/await` consistently for an easier-to-read code structure rather than mixing with callbacks. +- **Detect and handle HTTPS download errors:** Add error handling for the download request in case of network issues. +- **Optimize file path assembly:** Use `path.join` consistently instead of concatenating paths with template strings. + +### Good points +- **User Confirmation:** Proper user confirmation is implemented for the installation process. +- **Feedback messages:** The user is consistently informed of the progress and outcome through toast messages. +- **Checksum Verification:** There is a built-in security feature with checksum verification to ensure the integrity of the downloaded file. +- **Use of Constants:** Constants like the tar URL and checksum are kept cleanly at the start, improving maintainability. + +### Summary +The code handles the installation of a third-party tool (ExifTool), checking if it's already installed, and managing its installation if necessary. It's equipped with user notifications and checksum verifications for ensuring software integrity. Despite being generally well-structured, enhancements in asynchronous handling, error management, and certain code simplifications could elevate its quality and reliability. + +### Open source alternatives +- **ExifTool**: The same tool used in this script, but its native installation or use from command line can often be a direct alternative without custom scripts. +- **ImageMagick**: Another powerful tool to manipulate images and metadata, which can handle EXIF data. +- **MetaEdit**: A lighter tool suite for editing metadata in image files, often available in many package managers. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/clipboard.ts.json b/.reviews/raycast/src/utilities/clipboard.ts.json new file mode 100644 index 0000000..17b97aa --- /dev/null +++ b/.reviews/raycast/src/utilities/clipboard.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/clipboard.ts\n *\n * @summary Utilities for interacting with and getting images from the clipboard.\n *\n * Created at : 2023-07-06 14:50:26\n * Last modified : 2023-07-06 15:48:31\n */\n\nimport { runAppleScript } from \"run-applescript\";\n\n/**\n * Gets the images from the clipboard as paths to temporary PNG files.\n *\n * @returns A promise resolving to the list of image paths.\n */\nexport const getClipboardImages = async (): Promise => {\n return runAppleScript(`use framework \"AppKit\"\n use framework \"PDFKit\"\n \n set pb to current application's NSPasteboard's generalPasteboard()\n set theItems to pb's readObjectsForClasses:({current application's NSURL, current application's NSImage, current application's NSAttributedString}) options:{}\n \n set theImages to {}\n repeat with i from 0 to ((theItems's |count|()) - 1)\n set theItem to (theItems's objectAtIndex:i)\n if (theItem's |class|()) is current application's NSImage then\n copy theItem to end of theImages\n else if (theItem's |class|()) is current application's NSURL then\n if (theItem's absoluteString() as text) ends with \".pdf\" then\n set theImage to (current application's PDFDocument's alloc()'s initWithURL:theItem)\n else\n set theImage to (current application's NSImage's alloc()'s initWithContentsOfURL:theItem)\n end if\n if theImage is not missing value then\n copy theImage to end of theImages\n end if\n else if (theItem's |class|()) is current application's NSConcreteAttributedString then\n repeat with i from 0 to ((theItem's |length|()) - 1)\n set attrs to (theItem's attributesAtIndex:i longestEffectiveRange:(missing value) inRange:{i, (theItem's |length|()) - i})\n set theAttachment to (attrs's objectForKey:\"NSAttachment\")\n if theAttachment is not missing value then\n set cell to theAttachment's attachmentCell()\n set theImage to cell's image()\n copy theImage to end of theImages\n end if\n end repeat\n end if\n end repeat\n \n set tempDir to current application's NSTemporaryDirectory() as text\n set filePaths to {}\n repeat with i from 1 to count theImages\n set theImage to item i of theImages\n set theFile to tempDir & \"clipboardImage_\" & i\n if theImage's |class|() is current application's PDFDocument then\n set theFile to theFile & \".pdf\"\n (theImage's writeToFile:theFile)\n else\n set theFile to theFile & \".png\"\n set theTIFFData to theImage's TIFFRepresentation()\n set theBitmap to (current application's NSBitmapImageRep's alloc()'s initWithData:theTIFFData)\n set thePNGData to (theBitmap's representationUsingType:(current application's NSBitmapImageFileTypePNG) |properties|:(current application's NSDictionary's alloc()'s init()))\n (thePNGData's writeToFile:theFile atomically:false)\n end if\n copy theFile to end of filePaths\n end repeat\n \n return filePaths`);\n};\n\n/**\n * Gets the files from the clipboard as paths to temporary files.\n *\n * @returns A promise resolving to the list of file paths.\n */\nexport const getClipboardFiles = async (): Promise => {\n return runAppleScript(`use framework \"AppKit\"\n use framework \"PDFKit\"\n \n set pb to current application's NSPasteboard's generalPasteboard()\n set theItems to pb's readObjectsForClasses:({current application's NSURL}) options:{}\n \n set tempDir to current application's NSTemporaryDirectory() as text\n set filePaths to {}\n repeat with i from 0 to ((theItems's |count|()) - 1)\n set theItem to (theItems's objectAtIndex:i)\n if (theItem's |class|()) is current application's NSURL then\n set theFile to tempDir & \"clipboardFile_\" & (i + 1) & \".\" & (theItem's pathExtension())\n -- Copy the file content to the temporary file\n (current application's NSFileManager's defaultManager()'s copyItemAtURL:theItem toURL:(current application's |NSURL|'s fileURLWithPath:theFile) |error|:(missing value))\n copy theFile to end of filePaths\n end if\n end repeat\n \n return filePaths`);\n};\n\n\n/**\n * Copies the images at the given paths to the clipboard. Handles PDFs as well.\n *\n * @param filePaths The paths of the images to copy.\n */\nexport const copyImagesAtPathsToClipboard = async (filePaths: string | string[]) => {\n const paths = Array.isArray(filePaths) ? filePaths : [filePaths];\n await runAppleScript(`use framework \"Foundation\"\n use framework \"PDFKit\"\n use scripting additions\n \n set thePasteboard to current application's NSPasteboard's generalPasteboard()\n thePasteboard's clearContents()\n \n -- Handle PDFs separately\n set pdfPaths to {\"${paths.filter((p) => p.endsWith(\".pdf\")).join('\", \"')}\"}\n \n set pdfItems to current application's NSMutableArray's alloc()'s init()\n repeat with pdfPath in pdfPaths\n if length of pdfPath is not 0 then\n set pdfItem to current application's NSPasteboardItem's alloc()'s init()\n set pdfData to current application's NSData's dataWithContentsOfFile:pdfPath\n pdfItem's setData:pdfData forType:(current application's NSPasteboardTypePDF)\n pdfItems's addObject:pdfItem\n end if\n end repeat\n \n if pdfItems's |count|() > 0 then\n thePasteboard's writeObjects:pdfItems\n end if\n \n -- Handle all other image types\n set theFiles to {\"${paths.join('\", \"')}\"}\n \n set theImages to {}\n repeat with theFile in theFiles\n if length of theFile is not 0 then\n set theImage to (current application's NSImage's alloc()'s initWithContentsOfFile:theFile)\n if theImage is not missing value then\n copy theImage to end of theImages\n end if\n end if\n end repeat\n \n if (count theImages) > 0 then\n thePasteboard's writeObjects:theImages\n end if`);\n};\n", + "review": "**Grade: 7**\n\n### Bugs\n- There is an assumption that `writeObjects` will overwrite the clipboard content if both PDFs and other image types are written separately.\n\n### Optimizations\n- Instead of using both `NSMutableArray` and conditionally checking if `pdfItems` or `theImages` have content, start by checking if `paths` isn't empty and handle that with concise control flow.\n- Function `getClipboardImages` and `getClipboardFiles` return types mistakenly documented as `Promise`, should be `Promise`.\n- Could use TypeScript interfaces for structured data management and clarity.\n- Consider handling errors in the asynchrony process, ensuring any AppleScript errors are captured and communicated.\n- Combining `use framework` statements to optimize the script and avoid redefining those libraries.\n\n### Good Points\n- The code is modular, with separate functions handling distinct tasks: retrieving images, files, and copying images to the clipboard.\n- It uses AppleScript integration effectively to perform clipboard manipulations.\n- Efficiently uses `NSPasteboard` and supports multiple file/image types including PDFs.\n\n### Summary\nThe code offers utilities for clipboard interaction in macOS, especially for fetching and copying images and files. It leverages AppleScript to manage clipboard content and integrates well with macOS frameworks. While functional, there's room for clearer error handling, better type documentation, and slight optimization in code structure to improve readability and performance.\n\n### Open Source Alternatives\n- **Electron**: Comes with APIs to interact with clipboard content across platforms.\n- **Clipboard.js**: Though focused on text copy/paste, it can pair with other tools for broader functionality.", + "filename": "clipboard.ts", + "path": "raycast/src/utilities/clipboard.ts", + "directory": "utilities", + "grade": 7, + "size": 6154, + "line_count": 148 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/clipboard.ts.md b/.reviews/raycast/src/utilities/clipboard.ts.md new file mode 100644 index 0000000..97b88be --- /dev/null +++ b/.reviews/raycast/src/utilities/clipboard.ts.md @@ -0,0 +1,23 @@ +**Grade: 7** + +### Bugs +- There is an assumption that `writeObjects` will overwrite the clipboard content if both PDFs and other image types are written separately. + +### Optimizations +- Instead of using both `NSMutableArray` and conditionally checking if `pdfItems` or `theImages` have content, start by checking if `paths` isn't empty and handle that with concise control flow. +- Function `getClipboardImages` and `getClipboardFiles` return types mistakenly documented as `Promise`, should be `Promise`. +- Could use TypeScript interfaces for structured data management and clarity. +- Consider handling errors in the asynchrony process, ensuring any AppleScript errors are captured and communicated. +- Combining `use framework` statements to optimize the script and avoid redefining those libraries. + +### Good Points +- The code is modular, with separate functions handling distinct tasks: retrieving images, files, and copying images to the clipboard. +- It uses AppleScript integration effectively to perform clipboard manipulations. +- Efficiently uses `NSPasteboard` and supports multiple file/image types including PDFs. + +### Summary +The code offers utilities for clipboard interaction in macOS, especially for fetching and copying images and files. It leverages AppleScript to manage clipboard content and integrates well with macOS frameworks. While functional, there's room for clearer error handling, better type documentation, and slight optimization in code structure to improve readability and performance. + +### Open Source Alternatives +- **Electron**: Comes with APIs to interact with clipboard content across platforms. +- **Clipboard.js**: Though focused on text copy/paste, it can pair with other tools for broader functionality. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/enums.ts.json b/.reviews/raycast/src/utilities/enums.ts.json new file mode 100644 index 0000000..d6737d4 --- /dev/null +++ b/.reviews/raycast/src/utilities/enums.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/enums.ts\n *\n * @summary Enumerations used throughout the extension.\n *\n * Created at : 2023-07-06 00:52:09\n * Last modified : 2023-07-06 15:48:29\n */\n\n/**\n * Directions for flipping images.\n */\nexport enum Direction {\n HORIZONTAL = 0,\n VERTICAL = 1,\n}\n\n/**\n * Strategy for handling the result of the image processing, i.e. where to save or display the result.\n */\nexport enum ImageResultHandling {\n ReplaceOriginal = \"replaceOriginal\",\n SaveInContainingFolder = \"saveInContainingFolder\",\n CopyToClipboard = \"copyToClipboard\",\n OpenInPreview = \"openInPreview\",\n SaveToDownloads = \"saveToDownloads\",\n SaveToDesktop = \"saveToDesktop\",\n}\n\n/**\n * The place to look for the ExifTool binary.\n */\nexport enum ExifToolLocation {\n ON_PATH = \"path\",\n SUPPORT_DIR = \"support\",\n}\n", + "review": "8\n\n### Bugs\n- No bugs found in the provided code.\n\n### Optimizations\n- Add comments to describe what each enum is used for, especially if their purpose is not immediately obvious.\n- Use consistent naming conventions, such as capitalizing all the enum values or using `snake_case`.\n\n### Good points\n- The enums are clearly defined, which improves code readability and maintainability.\n- The code uses TypeScript's strong typing system effectively with enums.\n- The file is well-documented with a summary and timestamps for creation and last modification, indicating good documentation habits.\n\n### Summary\nThe code defines three enums in TypeScript which are cleanly implemented and improve the clarity of handling directions, image result handling, and ExifTool location configuration. The use of enums is appropriate and leverages TypeScript's ability to provide descriptive and maintainable code structures. However, minor optimizations related to documentation and naming consistency should be considered.\n\n### Open source alternatives\n- **PIXI.js** for dealing with image manipulations in a browser setting.\n- **Sharp** for image processing in Node.js, which can handle flipping and more.\n- **Jimp** which is a JavaScript image processor for Node that can also flip images.", + "filename": "enums.ts", + "path": "raycast/src/utilities/enums.ts", + "directory": "utilities", + "grade": 8, + "size": 805, + "line_count": 37 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/enums.ts.md b/.reviews/raycast/src/utilities/enums.ts.md new file mode 100644 index 0000000..91a2898 --- /dev/null +++ b/.reviews/raycast/src/utilities/enums.ts.md @@ -0,0 +1,21 @@ +8 + +### Bugs +- No bugs found in the provided code. + +### Optimizations +- Add comments to describe what each enum is used for, especially if their purpose is not immediately obvious. +- Use consistent naming conventions, such as capitalizing all the enum values or using `snake_case`. + +### Good points +- The enums are clearly defined, which improves code readability and maintainability. +- The code uses TypeScript's strong typing system effectively with enums. +- The file is well-documented with a summary and timestamps for creation and last modification, indicating good documentation habits. + +### Summary +The code defines three enums in TypeScript which are cleanly implemented and improve the clarity of handling directions, image result handling, and ExifTool location configuration. The use of enums is appropriate and leverages TypeScript's ability to provide descriptive and maintainable code structures. However, minor optimizations related to documentation and naming consistency should be considered. + +### Open source alternatives +- **PIXI.js** for dealing with image manipulations in a browser setting. +- **Sharp** for image processing in Node.js, which can handle flipping and more. +- **Jimp** which is a JavaScript image processor for Node that can also flip images. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/filters.ts.json b/.reviews/raycast/src/utilities/filters.ts.json new file mode 100644 index 0000000..b7e8854 --- /dev/null +++ b/.reviews/raycast/src/utilities/filters.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/filters.ts\n *\n * @summary Helper functions and resources for applying filters to images and PDFs using Core Image and ASObjC.\n *\n * Created at : 2023-07-dd 00:44:28\n * Last modified : 2023-07-dd 00:44:28\n */\n\nimport { runAppleScript, runAppleScriptSync } from \"run-applescript\";\n\nimport { Filter } from \"./types\";\n\n/**\n * First part of the ASObjC script that applies a filter to an image. Initializes the filter and sets its default values. Initializes the image or PDF document to apply the filter to.\n *\n * @param source The path to the image or PDF document to apply the filter to.\n * @param destination The path to output the filtered image or PDF document.\n * @param CIFilterName The name of the CIFilter to apply.\n * @returns The beginning of an ASObjC script with filled-in parameters.\n */\nconst initializeFilterScript = (source: string, destination: string, CIFilterName: string) => {\n return `use framework \"Foundation\"\n use framework \"Quartz\"\n use framework \"PDFKit\"\n\n set res to \"\"\n set thePDF to missing value\n applyFilter(\"${source}\", \"${destination}\")\n on applyFilter(sourcePath, destinationPath)\n global thePDF\n set repeatCount to 1\n if \"${source}\" ends with \".pdf\" and \"${destination}\" is not \"\" then\n set thePDF to current application's PDFDocument's alloc()'s initWithURL:(current application's |NSURL|'s fileURLWithPath:sourcePath)\n set pageCount to thePDF's pageCount()\n set repeatCount to pageCount\n end if\n\n repeat with i from 1 to repeatCount\n if repeatCount > 1 then\n set thePage to thePDF's pageAtIndex:(i - 1)\n set theData to thePage's dataRepresentation()\n set theImage to current application's NSImage's alloc()'s initWithData:theData\n else\n set theImage to current application's NSImage's alloc()'s initWithContentsOfFile:sourcePath\n end if\n \n -- Set up the Filter\n set filterName to \"${CIFilterName}\"\n set theFilter to current application's CIFilter's filterWithName:filterName\n theFilter's setDefaults()`;\n};\n\n/**\n * Second part of the ASObjC script that applies a filter to an image. Applies the filter to the image, crops the result to the original image size, and calls the saveImage() handler.\n */\nconst baseFilterResultScript = `-- Get result & crop to original image size\n set theBounds to current application's NSMakeRect(0, 0, theImage's |size|()'s width, theImage's |size|()'s height)\n set uncroppedOutput to theFilter's valueForKey:(current application's kCIOutputImageKey)\n set croppedOutput to uncroppedOutput's imageByCroppingToRect:(uncroppedOutput's extent())\n \n -- Convert back to NSImage and save to file\n set theRep to current application's NSCIImageRep's imageRepWithCIImage:croppedOutput\n set theResult to current application's NSImage's alloc()'s initWithSize:(theRep's |size|())\n theResult's addRepresentation:theRep\n saveImage(theResult, sourcePath, destinationPath, i)`;\n\n/**\n * Third part of the ASObjC script that applies a filter to an image. Saves the filtered image to the destination path. Iteratively converts a PDF document to filtered images.\n */\nconst saveImageScript = `on saveImage(imageToSave, sourcePath, destinationPath, iter)\n global thePDF\n if destinationPath ends with \".pdf\" then\n -- Replaces the contents of a PDF page with the supplied NSImage\n set newPage to current application's PDFPage's alloc()'s initWithImage:imageToSave\n thePDF's removePageAtIndex:(iter - 1)\n thePDF's insertPage:newPage atIndex:(iter - 1)\n else\n -- Saves an NSImage to the supplied file path\n set theTIFFData to imageToSave's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theImageProperties to current application's NSDictionary's dictionaryWithObject:1 forKey:(current application's NSImageCompressionFactor)\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n theResultData's writeToFile:destinationPath atomically:false\n end if\nend saveImage`;\n\nexport const getFilterThumbnail = (filter: Filter, source: string) => {\n return runAppleScriptSync(`${initializeFilterScript(source, \"\", filter.CIFilterName)}\n set theCIImage to current application's CIImage's imageWithData:(theImage's TIFFRepresentation())\n theFilter's setValue:theCIImage forKey:\"inputImage\"\n ${baseFilterResultScript}\n end repeat\n end applyFilter\n \n on saveImage(imageToSave, sourcePath, destinationPath, iter)\n global res\n -- Saves an NSImage to the supplied file path\n set theTIFFData to imageToSave's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theImageProperties to current application's NSDictionary's dictionaryWithObject:1 forKey:(current application's NSImageCompressionFactor)\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n set base64String to (theResultData's base64EncodedStringWithOptions:0) as text\n set res to \"data:image/png;base64,\" & base64String\n end saveImage\n \n return res`);\n};\n\n/**\n * The concluding part of the ASObjC script that applies a filter to an image. Joins all the parts of the script together and runs it.\n *\n * @param source The path to the image or PDF document to apply the filter to.\n * @param destination The path to output the filtered image or PDF document.\n * @param CIFilterName The name of the CIFilter to apply.\n * @returns A promise that resolves when the script has finished running.\n */\nexport const applyBasicFilter = async (source: string, destination: string, CIFilterName: string) => {\n return runAppleScript(`${initializeFilterScript(source, destination, CIFilterName)}\n set theCIImage to current application's CIImage's imageWithData:(theImage's TIFFRepresentation())\n theFilter's setValue:theCIImage forKey:\"inputImage\"\n ${baseFilterResultScript}\n end repeat\n\n -- Save PDFs\n if \"${source}\" ends with \".pdf\" then\n thePDF's writeToFile:\"${destination}\"\n end if\n end applyFilter\n ${saveImageScript}`);\n};\n\n/**\n * All supported filters.\n */\nexport const filters: Filter[] = [\n {\n name: \"Bloom\",\n description: \"Softens edges and adds a glow\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIBloom\",\n thumbnail: \"thumbnails/bloom.webp\",\n },\n {\n name: \"Bokeh Blur\",\n description: \"Applies a Bokeh effect\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIBokehBlur\",\n thumbnail: \"thumbnails/bokeh_blur.webp\",\n },\n {\n name: \"Box Blur\",\n description: \"Blur effect using a box-shaped convolution kernel\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIBoxBlur\",\n thumbnail: \"thumbnails/box_blur.webp\",\n },\n {\n name: \"Chrome\",\n description: \"Increase brightness and saturation\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectChrome\",\n thumbnail: \"thumbnails/chrome.webp\",\n },\n {\n name: \"Circular Screen\",\n description: \"Simulates a circular-shaped halftone screen\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CICircularScreen\",\n thumbnail: \"thumbnails/circular_screen.webp\",\n },\n {\n name: \"Circular Wrap\",\n description: \"Wraps an image around a transparent circle\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CICircularWrap\",\n thumbnail: \"thumbnails/circular_wrap.webp\",\n },\n {\n name: \"CMYK Halftone\",\n description: \"Creates a halftoned rendition of an image using cyan, magenta, yellow, and black\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CICMYKHalftone\",\n thumbnail: \"thumbnails/cmyk_halftone.webp\",\n },\n {\n name: \"Comic\",\n description: \"Makes images look like comic book drawings\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIComicEffect\",\n thumbnail: \"thumbnails/comic.webp\",\n },\n {\n name: \"Crystallize\",\n description: \"Creates polygon-shaped color blocks by aggregating pixel values\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CICrystallize\",\n thumbnail: \"thumbnails/crystallize.webp\",\n },\n {\n name: \"Depth Of Field\",\n description: \"Simulates tilt-shift\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIDepthOfField\",\n thumbnail: \"thumbnails/depth_of_field.webp\",\n },\n {\n name: \"Disc Blur\",\n description: \"Blur effect that uses a disc-shaped convolution kernel\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIDiscBlur\",\n thumbnail: \"thumbnails/disc_blur.webp\",\n },\n {\n name: \"Dither\",\n description: \"Adds noise to reduce distortion\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIDither\",\n thumbnail: \"thumbnails/dither.webp\",\n },\n {\n name: \"Document Enhancement\",\n description: \"Removes unwanted shadows, whitens background, and enhances contrast\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIDocumentEnhancer\",\n thumbnail: \"thumbnails/document_enhancement.webp\",\n },\n {\n name: \"Dot Screen\",\n description: \"Simulates the dot pattern of a halftone screen\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIDotScreen\",\n thumbnail: \"thumbnails/dot_screen.webp\",\n },\n {\n name: \"Edges\",\n description: \"Detects edges and highlights them colorfully, blackening other areas\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIEdges\",\n thumbnail: \"thumbnails/edges.webp\",\n },\n {\n name: \"Edge Work\",\n description: \"White woodblock cutout effect\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIEdgeWork\",\n thumbnail: \"thumbnails/edge_work.webp\",\n },\n {\n name: \"Fade\",\n description: \"Decreases saturation\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectFade\",\n thumbnail: \"thumbnails/fade.webp\",\n },\n {\n name: \"Gaussian Blur\",\n description: \"Blurs the image using a Gaussian filter\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIGaussianBlur\",\n thumbnail: \"thumbnails/gaussian_blur.webp\",\n },\n {\n name: \"Gloom\",\n description: \"Dulls highlights\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIGloom\",\n thumbnail: \"thumbnails/gloom.webp\",\n },\n {\n name: \"Hatched Screen\",\n description: \"Simulates the hatched pattern of a halftone screen\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIHatchedScreen\",\n thumbnail: \"thumbnails/hatched_screen.webp\",\n },\n {\n name: \"Hexagonal Pixellate\",\n description: \"Pixellates images using hexagons\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIHexagonalPixellate\",\n thumbnail: \"thumbnails/hexagonal_pixellate.webp\",\n },\n {\n name: \"Instant\",\n description: \"Decreases saturation, reduces contrast\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectInstant\",\n thumbnail: \"thumbnails/instant.webp\",\n },\n {\n name: \"Invert\",\n description: \"Inverts colors\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIColorInvert\",\n thumbnail: \"thumbnails/invert.webp\",\n },\n {\n name: \"Kaleidoscope\",\n description: \"Creates a kaleidoscopic image by applying 12-way symmetry\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIKaleidoscope\",\n thumbnail: \"thumbnails/kaleidoscope.webp\",\n },\n {\n name: \"Line Overlay\",\n description: \"Black woodblock cutout effect\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CILineOverlay\",\n thumbnail: \"thumbnails/line_overlay.webp\",\n },\n {\n name: \"Line Screen\",\n description: \"Simulates the line pattern of a halftone screen\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CILineScreen\",\n thumbnail: \"thumbnails/line_screen.webp\",\n },\n {\n name: \"Maximum Component\",\n description: \"Converts image to grayscale using the maximum of the three color components\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIMaximumComponent\",\n thumbnail: \"thumbnails/maximum_component.webp\",\n },\n {\n name: \"Median\",\n description: \"Reduces noise by calculating median pixel values\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CILineOverlay\",\n thumbnail: \"thumbnails/median.webp\",\n },\n {\n name: \"Minimum Component\",\n description: \"Converts image to grayscale using the minimum of the three color components\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIMinimumComponent\",\n thumbnail: \"thumbnails/minimum_component.webp\",\n },\n {\n name: \"Mono\",\n description: \"Desaturates images and reduces contrast\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectMono\",\n thumbnail: \"thumbnails/mono.webp\",\n },\n {\n name: \"Motion Blur\",\n description: \"Blur effect simulating a camera moving while capturing an image\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIMotionBlur\",\n thumbnail: \"thumbnails/motion_blur.webp\",\n },\n {\n name: \"Noir\",\n description: \"Desaturates images and increases contrast\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectNoir\",\n thumbnail: \"thumbnails/noir.webp\",\n },\n {\n name: \"Noise Reduction\",\n description: \"Reduces noise by sharpening areas of low luminance\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CINoiseReduction\",\n thumbnail: \"thumbnails/noise_reduction.webp\",\n },\n {\n name: \"Pixellate\",\n description: \"Pixellates images with large square pixels\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPixellate\",\n thumbnail: \"thumbnails/pixellate.webp\",\n },\n {\n name: \"Posterize\",\n description: \"Flattens colors\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIColorPosterize\",\n thumbnail: \"thumbnails/posterize.webp\",\n },\n {\n name: \"Pointillize\",\n description: \"Pixellates images with dots\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPointillize\",\n thumbnail: \"thumbnails/pointillize.webp\",\n },\n {\n name: \"Process\",\n description: \"Gives images a cooler toner\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectProcess\",\n thumbnail: \"thumbnails/process.webp\",\n },\n {\n name: \"Sepia\",\n description: \"Maps all colors to shades of brown\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CISepiaTone\",\n thumbnail: \"thumbnails/sepia.webp\",\n },\n {\n name: \"Sharpen Luminance\",\n description: \"Increases detailed by sharpening based on luminance\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CISharpenLuminance\",\n thumbnail: \"thumbnails/sharpen_luminance.webp\",\n },\n {\n name: \"Thermal\",\n description: \"Thermal camera effect\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIThermal\",\n thumbnail: \"thumbnails/thermal.webp\",\n },\n {\n name: \"Tonal\",\n description: \"Decreases saturation and contrast\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectTonal\",\n thumbnail: \"thumbnails/tonal.webp\",\n },\n {\n name: \"Transfer\",\n description: \"Makes images warmer\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIPhotoEffectTransfer\",\n thumbnail: \"thumbnails/transfer.webp\",\n },\n {\n name: \"Vignette\",\n description: \"Adds shading to the corners of images\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIVignette\",\n thumbnail: \"thumbnails/vignette.webp\",\n },\n {\n name: \"X-Ray\",\n description: \"X-Ray image effect\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIXRay\",\n thumbnail: \"thumbnails/x-ray.webp\",\n },\n {\n name: \"Zoom Blur\",\n description: \"Blur simulating a camera zooming in while capturing an image\",\n applyMethod: applyBasicFilter,\n CIFilterName: \"CIZoomBlur\",\n thumbnail: \"thumbnails/zoom_blur.webp\",\n },\n];\n", + "review": "# 7\n\n## Bugs\n- Potential variable shadowing for `destinationPath` could lead to errors.\n- The `CIMinimumComponent` filter uses a wrong CIFilterName in the \"Median\" filter section (`CILineOverlay` instead of `CIMedianFilter`).\n- Error handling is not explicitly implemented for script executions.\n\n## Optimizations\n- Extract repeated logic used across `applyBasicFilter` and `getFilterThumbnail` to a separate function to enhance maintainability.\n- Add error handling for AppleScript execution to improve robustness.\n- Use a consistent naming convention for better readability.\n- Consider lazy loading or condensing the number of imports if the file grows larger.\n- Use modern JavaScript or TypeScript features such as optional chaining or nullish coalescing to handle potential undefined values elegantly.\n\n## Good points\n- The use of comments is clear and informative, which aids in understanding the code.\n- Code is organized logically with separate functions for each main task, which is usually good for readability and maintainability.\n- Comprehensive filter dictionary shows a wide range of processing options.\n- ASObjC script demonstrates a good understanding of Core Image and PDFKit frameworks available in macOS.\n\n## Summary\nThe provided code is a well-structured TypeScript module designed to apply various image filters using AppleScript and macOS frameworks. The functions logically separate concerns, making it easy to follow. There is room for improvement in error handling and optimization of repeated code, and some corrections are necessary for filter settings. The code's scope with filters is commendable for wide usage scenarios, albeit with potential bug risks if script execution fails.\n\n## Open source alternatives\n- **ImageMagick**: A highly versatile software suite to create, edit, and convert bitmap images.\n- **GIMP**: Open-source image editor equivalent to Photoshop, allowing various filters and effects.\n- **Krita**: Primarily a digital painting tool but offers filtering capabilities with open-source flexibility.", + "filename": "filters.ts", + "path": "raycast/src/utilities/filters.ts", + "directory": "utilities", + "grade": 7, + "size": 15976, + "line_count": 453 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/filters.ts.md b/.reviews/raycast/src/utilities/filters.ts.md new file mode 100644 index 0000000..cca7018 --- /dev/null +++ b/.reviews/raycast/src/utilities/filters.ts.md @@ -0,0 +1,27 @@ +# 7 + +## Bugs +- Potential variable shadowing for `destinationPath` could lead to errors. +- The `CIMinimumComponent` filter uses a wrong CIFilterName in the "Median" filter section (`CILineOverlay` instead of `CIMedianFilter`). +- Error handling is not explicitly implemented for script executions. + +## Optimizations +- Extract repeated logic used across `applyBasicFilter` and `getFilterThumbnail` to a separate function to enhance maintainability. +- Add error handling for AppleScript execution to improve robustness. +- Use a consistent naming convention for better readability. +- Consider lazy loading or condensing the number of imports if the file grows larger. +- Use modern JavaScript or TypeScript features such as optional chaining or nullish coalescing to handle potential undefined values elegantly. + +## Good points +- The use of comments is clear and informative, which aids in understanding the code. +- Code is organized logically with separate functions for each main task, which is usually good for readability and maintainability. +- Comprehensive filter dictionary shows a wide range of processing options. +- ASObjC script demonstrates a good understanding of Core Image and PDFKit frameworks available in macOS. + +## Summary +The provided code is a well-structured TypeScript module designed to apply various image filters using AppleScript and macOS frameworks. The functions logically separate concerns, making it easy to follow. There is room for improvement in error handling and optimization of repeated code, and some corrections are necessary for filter settings. The code's scope with filters is commendable for wide usage scenarios, albeit with potential bug risks if script execution fails. + +## Open source alternatives +- **ImageMagick**: A highly versatile software suite to create, edit, and convert bitmap images. +- **GIMP**: Open-source image editor equivalent to Photoshop, allowing various filters and effects. +- **Krita**: Primarily a digital painting tool but offers filtering capabilities with open-source flexibility. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/generators.ts.json b/.reviews/raycast/src/utilities/generators.ts.json new file mode 100644 index 0000000..86d6325 --- /dev/null +++ b/.reviews/raycast/src/utilities/generators.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/generators.ts\n *\n * @summary Image generators and associated utilities.\n *\n * Created at : 2023-07-06 11:54:14\n * Last modified : 2023-07-06 16:47:11\n */\n\nimport { runAppleScript } from \"run-applescript\";\n\nimport { Generator, GeneratorKey } from \"./types\";\n\n/**\n * Common single dimension values for images. These are permuted to generate the available image sizes.\n */\nexport const standardDimensions = [1024, 512, 256, 128, 100, 64, 50, 32];\n\n/**\n * Generates a placeholder image of the specified dimensions. The image is a solid gray color.\n *\n * @param width The width of the image.\n * @param height The height of the image.\n * @param destination The destination path for the image.\n * @returns A promise that resolves when the image has been generated and saved. If no destination is specified, the promise resolves with the data URL of the generated image.\n */\nexport const generatePlaceholder = async (width: number, height: number, destination?: string) => {\n return runAppleScript(`use framework \"Foundation\"\n use framework \"Quartz\"\n \n set theCIImage to current application's CIImage's imageWithColor:(current application's CIColor's grayColor())\n set theBounds to current application's NSMakeRect(0, 0, ${width}, ${height})\n set croppedOutput to theCIImage's imageByCroppingToRect:theBounds\n \n -- Convert back to NSImage and save to file\n set theRep to current application's NSCIImageRep's imageRepWithCIImage:croppedOutput\n set theResult to current application's NSImage's alloc()'s initWithSize:(theRep's |size|())\n theResult's addRepresentation:theRep\n ${\n destination == undefined\n ? `set theTIFFData to theResult's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n set theBase64String to theResultData's base64EncodedStringWithOptions:0\n return \"data:image/png;base64,\" & theBase64String`\n : `saveImage(theResult, \"${destination}\")\n \n on saveImage(imageToSave, destinationPath)\n -- Saves an NSImage to the supplied file path\n set theTIFFData to imageToSave's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n theResultData's writeToFile:destinationPath atomically:false\n end saveImage`\n }`);\n};\n\n/**\n * Generates a data URL of a preview image for the specified CIFilter.\n *\n * @param CIFilterName The name of the CIFilter to generate a preview for.\n * @param inputs The input key/value pairs for the CIFilter.\n * @returns A promise that resolves with the data URL of the generated preview.\n */\nexport const generatePreview = async (CIFilterName: string, inputs: { [key: string]: unknown }) => {\n return runAppleScript(`use framework \"Foundation\"\n use framework \"Quartz\"\n use scripting additions\n \n set filterName to \"${CIFilterName}\"\n set theFilter to current application's CIFilter's filterWithName:filterName\n theFilter's setDefaults()\n\n set imgWidth to 256\n set imgHeight to 256\n \n set theCIImage to current application's CIImage's emptyImage()\n ${Object.entries(inputs)\n .map(([key, value]) => `theFilter's setValue:(${value}) forKey:\"${key}\"`)\n .join(\"\\n\")}\n \n set theBounds to current application's NSMakeRect(0, 0, imgWidth, imgHeight)\n set uncroppedOutput to theFilter's valueForKey:(current application's kCIOutputImageKey)\n set croppedOutput to uncroppedOutput's imageByCroppingToRect:theBounds\n \n -- Convert back to NSImage and save to file\n set theRep to current application's NSCIImageRep's imageRepWithCIImage:croppedOutput\n set theResult to current application's NSImage's alloc()'s initWithSize:(theRep's |size|())\n theResult's addRepresentation:theRep\n\n -- Saves an NSImage to the supplied file path\n set theTIFFData to theResult's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n set theBase64String to (theResultData's base64EncodedStringWithOptions:0) as text\n return \"data:image/png;base64,\" & theBase64String\n `);\n};\n\n/**\n * Generates a full-size render of the specified CIFilter.\n *\n * @param destination The destination path for the generated image.\n * @param CIFilterName The name of the CIFilter to generate a preview for.\n * @param width The width of the generated image.\n * @param height The height of the generated image.\n * @param inputs The input key/value pairs for the CIFilter.\n * @returns A promise that resolves when the image has been generated and saved.\n */\nexport const generate = async (\n destination: string,\n CIFilterName: string,\n width: number,\n height: number,\n inputs: { [key: string]: unknown }\n) => {\n return runAppleScript(`use framework \"Foundation\"\n use framework \"Quartz\"\n use scripting additions\n \n set filterName to \"${CIFilterName}\"\n set theFilter to current application's CIFilter's filterWithName:filterName\n theFilter's setDefaults()\n\n set imgWidth to ${width}\n set imgHeight to ${height}\n\n set theCIImage to current application's CIImage's emptyImage()\n ${Object.entries(inputs)\n .map(([key, value]) => `theFilter's setValue:(${value}) forKey:\"${key}\"`)\n .join(\"\\n\")}\n \n set theBounds to current application's NSMakeRect(0, 0, imgWidth, imgHeight)\n set uncroppedOutput to theFilter's valueForKey:(current application's kCIOutputImageKey)\n set croppedOutput to uncroppedOutput's imageByCroppingToRect:theBounds\n \n -- Convert back to NSImage and save to file\n set theRep to current application's NSCIImageRep's imageRepWithCIImage:croppedOutput\n set theResult to current application's NSImage's alloc()'s initWithSize:(theRep's |size|())\n theResult's addRepresentation:theRep\n saveImage(theResult, \"${destination}\")\n \n on saveImage(imageToSave, destinationPath)\n -- Saves an NSImage to the supplied file path\n set theTIFFData to imageToSave's TIFFRepresentation()\n set theBitmapImageRep to current application's NSBitmapImageRep's imageRepWithData:theTIFFData\n set theResultData to theBitmapImageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)\n theResultData's writeToFile:destinationPath atomically:false\n end saveImage`);\n};\n\n/**\n * All available generators.\n */\nexport const generators: { [key in GeneratorKey]: Generator } = {\n Checkerboard: {\n applyMethod: generate,\n CIFilterName: \"CICheckerboardGenerator\",\n name: \"Checkerboard\",\n thumbnail: \"thumbnails/checkerboard.webp\",\n },\n ConstantColor: {\n applyMethod: generate,\n CIFilterName: \"CIConstantColorGenerator\",\n name: \"Constant Color\",\n thumbnail: \"thumbnails/constant_color.webp\",\n },\n LenticularHalo: {\n applyMethod: generate,\n CIFilterName: \"CILenticularHaloGenerator\",\n name: \"Lenticular Halo\",\n thumbnail: \"thumbnails/lenticular_halo.webp\",\n },\n LinearGradient: {\n applyMethod: generate,\n CIFilterName: \"CILinearGradient\",\n name: \"Linear Gradient\",\n thumbnail: \"thumbnails/linear_gradient.webp\",\n },\n RadialGradient: {\n applyMethod: generate,\n CIFilterName: \"CIRadialGradient\",\n name: \"Radial Gradient\",\n thumbnail: \"thumbnails/radial_gradient.webp\",\n },\n Random: {\n applyMethod: generate,\n CIFilterName: \"CIRandomGenerator\",\n name: \"Random\",\n thumbnail: \"thumbnails/random.webp\",\n },\n StarShine: {\n applyMethod: generate,\n CIFilterName: \"CIStarShineGenerator\",\n name: \"Star Shine\",\n thumbnail: \"thumbnails/star_shine.webp\",\n },\n Stripes: {\n applyMethod: generate,\n CIFilterName: \"CIStripesGenerator\",\n name: \"Stripes\",\n thumbnail: \"thumbnails/stripes.webp\",\n },\n Sunbeams: {\n applyMethod: generate,\n CIFilterName: \"CISunbeamsGenerator\",\n name: \"Sunbeams\",\n thumbnail: \"thumbnails/sunbeams.webp\",\n },\n};\n\n// The rest of this file is made up of helper functions for generating CIFilter inputs.\n\nexport const getCheckerboardOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => [\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${\n greenValues[0] / 255\n } blue:${blueValues[0] / 255} alpha:${alphaValues[0] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[1] / 255} green:${\n greenValues[1] / 255\n } blue:${blueValues[1] / 255} alpha:${alphaValues[1] / 255}`,\n inputWidth: \"imgWidth / 4\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[2] / 255} green:${\n greenValues[2] / 255\n } blue:${blueValues[2] / 255} alpha:${alphaValues[2] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[3] / 255} green:${\n greenValues[3] / 255\n } blue:${blueValues[3] / 255} alpha:${alphaValues[3] / 255}`,\n inputWidth: \"imgWidth / 8\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[4] / 255} green:${\n greenValues[4] / 255\n } blue:${blueValues[4] / 255} alpha:${alphaValues[4] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[5] / 255} green:${\n greenValues[5] / 255\n } blue:${blueValues[5] / 255} alpha:${alphaValues[5] / 255}`,\n inputWidth: \"imgWidth / 16\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[6] / 255} green:${\n greenValues[6] / 255\n } blue:${blueValues[6] / 255} alpha:${alphaValues[6] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[7] / 255} green:${\n greenValues[7] / 255\n } blue:${blueValues[7] / 255} alpha:${alphaValues[7] / 255}`,\n inputWidth: \"imgWidth / 32\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[8] / 255} green:${\n greenValues[8] / 255\n } blue:${blueValues[8] / 255} alpha:${alphaValues[8] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[9] / 255} green:${\n greenValues[9] / 255\n } blue:${blueValues[9] / 255} alpha:${alphaValues[9] / 255}`,\n inputWidth: \"imgWidth / 64\",\n },\n];\n\nexport const getStripeOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => [\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${\n greenValues[0] / 255\n } blue:${blueValues[0] / 255} alpha:${alphaValues[0] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[1] / 255} green:${\n greenValues[1] / 255\n } blue:${blueValues[1] / 255} alpha:${alphaValues[1] / 255}`,\n inputWidth: \"imgWidth / 4\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[2] / 255} green:${\n greenValues[2] / 255\n } blue:${blueValues[2] / 255} alpha:${alphaValues[2] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[3] / 255} green:${\n greenValues[3] / 255\n } blue:${blueValues[3] / 255} alpha:${alphaValues[3] / 255}`,\n inputWidth: \"imgWidth / 8\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[4] / 255} green:${\n greenValues[4] / 255\n } blue:${blueValues[4] / 255} alpha:${alphaValues[4] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[5] / 255} green:${\n greenValues[5] / 255\n } blue:${blueValues[5] / 255} alpha:${alphaValues[5] / 255}`,\n inputWidth: \"imgWidth / 16\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[6] / 255} green:${\n greenValues[6] / 255\n } blue:${blueValues[6] / 255} alpha:${alphaValues[6] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[7] / 255} green:${\n greenValues[7] / 255\n } blue:${blueValues[7] / 255} alpha:${alphaValues[7] / 255}`,\n inputWidth: \"imgWidth / 32\",\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[8] / 255} green:${\n greenValues[8] / 255\n } blue:${blueValues[8] / 255} alpha:${alphaValues[8] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[9] / 255} green:${\n greenValues[9] / 255\n } blue:${blueValues[9] / 255} alpha:${alphaValues[9] / 255}`,\n inputWidth: \"imgWidth / 64\",\n },\n];\n\nexport const getSolidColorOptions = (redValues: number[], greenValues: number[], blueValues: number[]) =>\n Array(10)\n .fill(0)\n .map((_, i) => ({\n inputColor: `current application's CIColor's colorWithRed:${redValues[i] / 255} green:${\n greenValues[i] / 255\n } blue:${blueValues[i] / 255} alpha:1.0`,\n }));\n\nexport const getLinearGradientOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => [\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${\n greenValues[0] / 255\n } blue:${blueValues[0] / 255} alpha:${alphaValues[0] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[1] / 255} green:${\n greenValues[1] / 255\n } blue:${blueValues[1] / 255} alpha:${alphaValues[1] / 255}`,\n inputPoint0: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputPoint1: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[2] / 255} green:${\n greenValues[2] / 255\n } blue:${blueValues[2] / 255} alpha:${alphaValues[2] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[3] / 255} green:${\n greenValues[3] / 255\n } blue:${blueValues[3] / 255} alpha:${alphaValues[3] / 255}`,\n inputPoint0: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputPoint1: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[4] / 255} green:${\n greenValues[4] / 255\n } blue:${blueValues[4] / 255} alpha:${alphaValues[4] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[5] / 255} green:${\n greenValues[5] / 255\n } blue:${blueValues[5] / 255} alpha:${alphaValues[5] / 255}`,\n inputPoint0: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputPoint1: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[6] / 255} green:${\n greenValues[6] / 255\n } blue:${blueValues[6] / 255} alpha:${alphaValues[6] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[7] / 255} green:${\n greenValues[7] / 255\n } blue:${blueValues[7] / 255} alpha:${alphaValues[7] / 255}`,\n inputPoint0: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputPoint1: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[8] / 255} green:${\n greenValues[8] / 255\n } blue:${blueValues[8] / 255} alpha:${alphaValues[8] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[9] / 255} green:${\n greenValues[9] / 255\n } blue:${blueValues[9] / 255} alpha:${alphaValues[9] / 255}`,\n inputPoint0: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputPoint1: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n },\n];\n\nexport const getRadialGradientOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => [\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${\n greenValues[0] / 255\n } blue:${blueValues[0] / 255} alpha:${alphaValues[0] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[1] / 255} green:${\n greenValues[1] / 255\n } blue:${blueValues[1] / 255} alpha:${alphaValues[1] / 255}`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputRadius0: `((random number) * imgWidth)`,\n inputRadius1: `((random number) * imgWidth)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[2] / 255} green:${\n greenValues[2] / 255\n } blue:${blueValues[2] / 255} alpha:${alphaValues[2] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[3] / 255} green:${\n greenValues[3] / 255\n } blue:${blueValues[3] / 255} alpha:${alphaValues[3] / 255}`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputRadius0: `((random number) * imgWidth)`,\n inputRadius1: `((random number) * imgWidth)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[4] / 255} green:${\n greenValues[4] / 255\n } blue:${blueValues[4] / 255} alpha:${alphaValues[4] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[5] / 255} green:${\n greenValues[5] / 255\n } blue:${blueValues[5] / 255} alpha:${alphaValues[5] / 255}`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputRadius0: `((random number) * imgWidth)`,\n inputRadius1: `((random number) * imgWidth)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[6] / 255} green:${\n greenValues[6] / 255\n } blue:${blueValues[6] / 255} alpha:${alphaValues[6] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[7] / 255} green:${\n greenValues[7] / 255\n } blue:${blueValues[7] / 255} alpha:${alphaValues[7] / 255}`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputRadius0: `((random number) * imgWidth)`,\n inputRadius1: `((random number) * imgWidth)`,\n },\n {\n inputColor0: `current application's CIColor's colorWithRed:${redValues[8] / 255} green:${\n greenValues[8] / 255\n } blue:${blueValues[8] / 255} alpha:${alphaValues[8] / 255}`,\n inputColor1: `current application's CIColor's colorWithRed:${redValues[9] / 255} green:${\n greenValues[9] / 255\n } blue:${blueValues[9] / 255} alpha:${alphaValues[9] / 255}`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputRadius0: `((random number) * imgWidth)`,\n inputRadius1: `((random number) * imgWidth)`,\n },\n];\n\nexport const getStarShineOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => ({\n inputColor: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${greenValues[0] / 255} blue:${\n blueValues[0] / 255\n } alpha:${alphaValues[0] / 255}`,\n inputCrossScale: `((random number) * 10)`,\n inputCrossAngle: `((random number) * 90)`,\n inputCrossOpacity: `((random number) * 9) - 8`,\n inputCrossWidth: `((random number) * imgWidth / 5)`,\n inputEpsilon: `((random number) * 1)`,\n inputRadius: `((random number) * imgWidth / 10)`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n});\n\nexport const getLenticularHaloOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => ({\n inputColor: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${greenValues[0] / 255} blue:${\n blueValues[0] / 255\n } alpha:${alphaValues[0] / 255}`,\n inputHaloRadius: `((random number) * imgWidth / 10)`,\n inputHaloWidth: `((random number) * imgWidth / 10)`,\n inputStriationStrength: `((random number) * 1)`,\n inputStriationContrast: `((random number) * 5)`,\n inputTime: `((random number) * 10)`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n inputHaloOverlap: `((random number) * 0.99)`,\n});\n\nexport const getSunbeamsOptions = (\n redValues: number[],\n greenValues: number[],\n blueValues: number[],\n alphaValues: number[]\n) => ({\n inputColor: `current application's CIColor's colorWithRed:${redValues[0] / 255} green:${greenValues[0] / 255} blue:${\n blueValues[0] / 255\n } alpha:${alphaValues[0] / 255}`,\n inputSunRadius: `((random number) * imgWidth / 10)`,\n inputMaxStriationRadius: `((random number) * imgWidth / 10)`,\n inputStriationStrength: `((random number) * 1)`,\n inputStriationContrast: `((random number) * 5)`,\n inputTime: `((random number) * 10)`,\n inputCenter: `current application's CIVector's vectorWithX:((random number) * imgWidth) Y:((random number) * imgHeight)`,\n});\n", + "review": "# 7\n\n## Bugs\n- Some CIImage initializations use `emptyImage()`, which may not be the best approach for every filter.\n- Some filter input keys like `kCIOutputImageKey` assume that the filter will always produce an output image key; this may not be true for all filters and can cause runtime errors.\n\n## Optimizations\n- Consider implementing better error handling within the `runAppleScript` calls to manage potential AppleScript execution failures.\n- Use a mapping or configuration file for repeated code segments like CIFilter name and thumbnail details in the `generators` object.\n- Refactor code to avoid repeating similar blocks for different functions, e.g., `get*Options` methods. Consider a more flexible function that accepts parameters to reduce redundancy.\n- Consider switching to native JavaScript solutions for image generation to bypass AppleScript dependency and make the code platform-independent.\n\n## Good Points\n- The structure is organized, with clearly defined functions that provide utilities for different image generator operations.\n- Comments and JSDoc style annotations are consistently used throughout the codebase, providing clear guidance on the functionality of each function.\n- Use of constants and function decomposition increases modularity and code readability.\n\n## Summary\nThis script effectively manages image generation utilizing macOS-specific utilities through AppleScript and provides a comprehensive suite of different generators using Core Image filters. The script embraces modularity and readability through consistent documentation and function segmentation. However, it has room for optimizations and error management improvements, and also could benefit from platform-independent implementations.\n\n## Open source alternatives\n- **ImageMagick**: An open-source software suite for displaying, converting, and editing raster image and vector image files.\n- **Canvas**: Used in JavaScript with the HTML5 `` element for drawing graphics and images from scratch.", + "filename": "generators.ts", + "path": "raycast/src/utilities/generators.ts", + "directory": "utilities", + "grade": 7, + "size": 22142, + "line_count": 502 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/generators.ts.md b/.reviews/raycast/src/utilities/generators.ts.md new file mode 100644 index 0000000..3eab4ad --- /dev/null +++ b/.reviews/raycast/src/utilities/generators.ts.md @@ -0,0 +1,23 @@ +# 7 + +## Bugs +- Some CIImage initializations use `emptyImage()`, which may not be the best approach for every filter. +- Some filter input keys like `kCIOutputImageKey` assume that the filter will always produce an output image key; this may not be true for all filters and can cause runtime errors. + +## Optimizations +- Consider implementing better error handling within the `runAppleScript` calls to manage potential AppleScript execution failures. +- Use a mapping or configuration file for repeated code segments like CIFilter name and thumbnail details in the `generators` object. +- Refactor code to avoid repeating similar blocks for different functions, e.g., `get*Options` methods. Consider a more flexible function that accepts parameters to reduce redundancy. +- Consider switching to native JavaScript solutions for image generation to bypass AppleScript dependency and make the code platform-independent. + +## Good Points +- The structure is organized, with clearly defined functions that provide utilities for different image generator operations. +- Comments and JSDoc style annotations are consistently used throughout the codebase, providing clear guidance on the functionality of each function. +- Use of constants and function decomposition increases modularity and code readability. + +## Summary +This script effectively manages image generation utilizing macOS-specific utilities through AppleScript and provides a comprehensive suite of different generators using Core Image filters. The script embraces modularity and readability through consistent documentation and function segmentation. However, it has room for optimizations and error management improvements, and also could benefit from platform-independent implementations. + +## Open source alternatives +- **ImageMagick**: An open-source software suite for displaying, converting, and editing raster image and vector image files. +- **Canvas**: Used in JavaScript with the HTML5 `` element for drawing graphics and images from scratch. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/preferences.ts.json b/.reviews/raycast/src/utilities/preferences.ts.json new file mode 100644 index 0000000..5f1a389 --- /dev/null +++ b/.reviews/raycast/src/utilities/preferences.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/preferences.ts\n *\n * @summary Preferences for the extension as a whole and for individual commands.\n *\n * Created at : 2023-07-06 15:34:53\n * Last modified : 2023-07-06 15:41:56\n */\n\n/**\n * Preferences for the extension as a whole.\n */\nexport interface ExtensionPreferences {\n /**\n * The source of input images -- either \"Clipboard\" or the name of a file manager (e.g. \"Finder\" or \"Path Finder\").\n */\n inputMethod: string;\n\n /**\n * The strategy for handling the result of the image processing, i.e. where to save or display the result. One of {@link ImageResultHandling}.\n */\n imageResultHandling: string;\n\n /**\n * Whether to use lossless conversions with cwebp\n */\n cwebpLossless: boolean;\n}\n\n/**\n * Preferences for the convert command. Specifies which image formats to show in the conversion formats list.\n */\nexport interface ConvertPreferences {\n trim: boolean;\n showASTC: boolean;\n showBMP: boolean;\n showDDS: boolean;\n showEXR: boolean;\n showGIF: boolean;\n showHEIC: boolean;\n showHEICS: boolean;\n showICNS: boolean;\n showICO: boolean;\n showJPEG: boolean;\n showJP2: boolean;\n showKTX: boolean;\n showPBM: boolean;\n showPDF: boolean;\n showPNG: boolean;\n showPSD: boolean;\n showPVR: boolean;\n showTGA: boolean;\n showTIFF: boolean;\n showWEBP: boolean;\n showSVG: boolean;\n [key: string]: boolean;\n}\n\n/**\n * Preferences for the rotate command.\n */\nexport interface RotatePreferences {\n /**\n * The unit to use when specifying the rotation angle, either \"degrees\" or \"radians\".\n */\n rotationUnit: string;\n}\n\n/**\n * Preferences for the pad command.\n */\nexport interface PadPreferences {\n /**\n * The default color to use when padding images and no color argument is provided.\n */\n defaultPadColor: string;\n}\n", + "review": "8\n\n### Bugs\n- No explicit bugs identified in the code.\n\n### Optimizations\n- Use enumerations for `inputMethod` and `imageResultHandling` to restrict values to predefined options.\n- Consider using TypeScript types for stricter type checks, e.g., using specific string literal types for fields that have limited valid options like `rotationUnit`.\n\n### Good points\n- Clear and descriptive comments are provided, making it easy to understand the purpose of each interface and field.\n- Uses TypeScript interface nicely to define structured data and ensure type safety.\n- The code is well-organized, with each preference type clearly separated and documented.\n\n### Summary\nThe code provides a well-structured definition of preference interfaces for an application's image handling functionality. There are no obvious bugs, and the use of TypeScript interfaces is effectively implemented. However, the code could benefit from using string literal types or enumerations for fields that are expected to have a limited set of predefined values. This would enhance both type safety and readability.\n\n### Open source alternatives\n- **ImageMagick**: A robust tool for image conversion and transformation.\n- **GraphicsMagick**: A similar tool to ImageMagick, optimized for high performance.", + "filename": "preferences.ts", + "path": "raycast/src/utilities/preferences.ts", + "directory": "utilities", + "grade": 8, + "size": 1785, + "line_count": 78 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/preferences.ts.md b/.reviews/raycast/src/utilities/preferences.ts.md new file mode 100644 index 0000000..e2f0173 --- /dev/null +++ b/.reviews/raycast/src/utilities/preferences.ts.md @@ -0,0 +1,20 @@ +8 + +### Bugs +- No explicit bugs identified in the code. + +### Optimizations +- Use enumerations for `inputMethod` and `imageResultHandling` to restrict values to predefined options. +- Consider using TypeScript types for stricter type checks, e.g., using specific string literal types for fields that have limited valid options like `rotationUnit`. + +### Good points +- Clear and descriptive comments are provided, making it easy to understand the purpose of each interface and field. +- Uses TypeScript interface nicely to define structured data and ensure type safety. +- The code is well-organized, with each preference type clearly separated and documented. + +### Summary +The code provides a well-structured definition of preference interfaces for an application's image handling functionality. There are no obvious bugs, and the use of TypeScript interfaces is effectively implemented. However, the code could benefit from using string literal types or enumerations for fields that are expected to have a limited set of predefined values. This would enhance both type safety and readability. + +### Open source alternatives +- **ImageMagick**: A robust tool for image conversion and transformation. +- **GraphicsMagick**: A similar tool to ImageMagick, optimized for high performance. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/types.ts.json b/.reviews/raycast/src/utilities/types.ts.json new file mode 100644 index 0000000..f998785 --- /dev/null +++ b/.reviews/raycast/src/utilities/types.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/types.ts\n *\n * @summary Types used throughout the extension.\n *\n * Created at : 2023-07-06 14:47:41\n * Last modified : 2023-07-06 15:48:21\n */\n\n/**\n * A wrapper around a CIFilter that can be applied to images.\n */\nexport type Filter = {\n /**\n * The name of the filter.\n */\n name: string;\n\n /**\n * A brief description of what the filter does.\n */\n description: string;\n\n /**\n * The method to apply the filter to an image.\n *\n * @param source The path of the image to apply the filter to.\n * @param destination The path to save the filtered image to.\n * @param CIFilterName The name of the CIFilter to apply.\n * @returns A promise that resolves when the operation is complete.\n */\n applyMethod: (source: string, destination: string, CIFilterName: string) => Promise;\n\n /**\n * The CIFilter name to use when applying the filter.\n */\n CIFilterName: string;\n\n /**\n * The location in the extension's assets folder of the thumbnail image for the filter.\n */\n thumbnail: string;\n};\n\n/**\n * A wrapper around a CIFilter belonging to CICategoryGenerator that can be used to generate images.\n */\nexport type Generator = {\n /**\n * The name of the generator.\n */\n name: string;\n\n /**\n * The method to generate an image.\n *\n * @param destination The path to save the generated image to.\n * @param CIFilterName The name of the CIFilter to use to generate the image.\n * @param width The width of the generated image.\n * @param height The height of the generated image.\n * @param inputs The inputs to the CIFilter.\n * @returns A promise that resolves when the operation is complete.\n */\n applyMethod: (\n destination: string,\n CIFilterName: string,\n width: number,\n height: number,\n inputs: { [key: string]: unknown }\n ) => Promise;\n\n /**\n * The CIFilter name to use when generating the image.\n */\n CIFilterName: string;\n\n /**\n * The location in the extension's assets folder of the thumbnail image for the generator.\n */\n thumbnail: string;\n};\n\n/**\n * Keys for generator filters.\n */\nexport type GeneratorKey =\n | \"Checkerboard\"\n | \"ConstantColor\"\n | \"LenticularHalo\"\n | \"LinearGradient\"\n | \"RadialGradient\"\n | \"Random\"\n | \"StarShine\"\n | \"Stripes\"\n | \"Sunbeams\";\n\n/**\n * The options to use when generating an image. Corresponds to the key-value pairs in the CIFilter's input dictionary.\n */\nexport type GeneratorOptions = {\n [key: string]: unknown;\n};\n", + "review": "# 8\n\n## Bugs\n- No apparent bugs in the provided TypeScript type definitions.\n\n## Optimizations\n- Consider using more specific types for parameters and return values where possible instead of `string` or `unknown`, to leverage TypeScript's type-checking capabilities for error prevention. \n- For `GeneratorOptions`, if there are known keys and value types, defining them explicitly could enhance type safety and code readability.\n- Document defaults or potential values for inputs, CIFilterNames, and other parameters if they are known and constrained.\n\n## Good Points\n- The code is well-organized and has clear documentation for each type and property.\n- Usage of TypeScript types and interfaces promotes consistency and maintainability in larger codebases.\n- The promise-based `applyMethod` for asynchronous operations is modern and suitable for operations like image processing, which might be time-consuming.\n\n## Summary\nOverall, the TypeScript code is clean and effectively utilizes type definitions to enhance maintainability and readability. The documentation is thorough, providing insightful comments on the functionalities and use cases of the types. While no significant bugs are identified, there is room for more specific typing to maximize the benefits of TypeScript\u2019s strong type system.\n\n## Open source alternatives\n- **ImageMagick**: A robust image processing library that supports filter operations and image generation.\n- **Sharp**: A high-performance image processing library for Node.js, with support for many image transformations and filters.\n- **Jimp**: A pure JavaScript image processing library in Node, commonly used for simple manipulations and transformations.", + "filename": "types.ts", + "path": "raycast/src/utilities/types.ts", + "directory": "utilities", + "grade": 8, + "size": 2481, + "line_count": 103 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/types.ts.md b/.reviews/raycast/src/utilities/types.ts.md new file mode 100644 index 0000000..9ccb3e9 --- /dev/null +++ b/.reviews/raycast/src/utilities/types.ts.md @@ -0,0 +1,22 @@ +# 8 + +## Bugs +- No apparent bugs in the provided TypeScript type definitions. + +## Optimizations +- Consider using more specific types for parameters and return values where possible instead of `string` or `unknown`, to leverage TypeScript's type-checking capabilities for error prevention. +- For `GeneratorOptions`, if there are known keys and value types, defining them explicitly could enhance type safety and code readability. +- Document defaults or potential values for inputs, CIFilterNames, and other parameters if they are known and constrained. + +## Good Points +- The code is well-organized and has clear documentation for each type and property. +- Usage of TypeScript types and interfaces promotes consistency and maintainability in larger codebases. +- The promise-based `applyMethod` for asynchronous operations is modern and suitable for operations like image processing, which might be time-consuming. + +## Summary +Overall, the TypeScript code is clean and effectively utilizes type definitions to enhance maintainability and readability. The documentation is thorough, providing insightful comments on the functionalities and use cases of the types. While no significant bugs are identified, there is room for more specific typing to maximize the benefits of TypeScript’s strong type system. + +## Open source alternatives +- **ImageMagick**: A robust image processing library that supports filter operations and image generation. +- **Sharp**: A high-performance image processing library for Node.js, with support for many image transformations and filters. +- **Jimp**: A pure JavaScript image processing library in Node, commonly used for simple manipulations and transformations. \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/utils.ts.json b/.reviews/raycast/src/utilities/utils.ts.json new file mode 100644 index 0000000..e97f41b --- /dev/null +++ b/.reviews/raycast/src/utilities/utils.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/**\n * @file utilities/utils.ts\n *\n * @summary Helper functions used throughout the extension.\n *\n * Created at : 2023-07-06 14:48:00\n * Last modified : 2024-01-27 13:31:10\n */\n\nimport { execSync } from \"child_process\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport path from \"path\";\nimport { runAppleScript, runAppleScriptSync } from \"run-applescript\";\n\nimport {\n Clipboard,\n environment,\n getFrontmostApplication,\n getPreferenceValues,\n LocalStorage,\n showToast,\n Toast,\n} from \"@raycast/api\";\n\nimport { Direction, ImageResultHandling } from \"./enums\";\nimport { copyImagesAtPathsToClipboard, getClipboardFiles, getClipboardImages } from \"./clipboard\";\nimport { ExtensionPreferences } from \"./preferences\";\n\n/**\n * Gets currently selected images in Finder.\n *\n * @returns A promise resolving to the comma-separated list of images as a string.\n */\nconst getSelectedFinderImages = async (): Promise => {\n return runAppleScript(\n `set imageTypes to {\"PNG\", \"JPG\", \"JPEG\", \"TIF\", \"HEIF\", \"GIF\", \"ICO\", \"ICNS\", \"ASTC\", \"BMP\", \"DDS\", \"EXR\", \"JP2\", \"KTX\", \"Portable Bitmap\", \"Adobe Photoshop\", \"PVR\", \"TGA\", \"WebP\", \"SVG\", \"PDF\", \"HEIC\"}\n \n tell application \"Finder\"\n set theSelection to selection\n\n if theSelection is {} and (count Finder windows) > 0 then\n repeat with i from 1 to (count Finder windows)\n activate window i\n set theSelection to selection\n\n set selectionKinds to {}\n repeat with j from 1 to (count theSelection)\n set selectionKinds to selectionKinds & kind of (item j of theSelection)\n end repeat\n\n set containsImage to false\n repeat with imageType in imageTypes\n if selectionKinds contains imageType then\n set containsImage to true\n exit repeat\n end if\n end repeat\n end repeat\n end if\n\n if theSelection is {} then\n return\n else if (theSelection count) is equal to 1 then\n repeat with imageType in imageTypes\n if (kind of the first item of theSelection) contains imageType then\n return the POSIX path of (theSelection as alias)\n exit repeat\n end if\n end repeat\n else\n set thePaths to {}\n repeat with i from 1 to (theSelection count)\n repeat with imageType in imageTypes\n if (kind of (item i of theSelection)) contains imageType then\n copy (POSIX path of (item i of theSelection as alias)) to end of thePaths\n exit repeat\n end if\n end repeat\n end repeat\n return thePaths\n end if\n end tell`\n );\n};\n\n/**\n * Gets currently selected images in Path Finder.\n *\n * @returns A promise resolving to the comma-separated list of images as a string.\n */\nconst getSelectedPathFinderImages = async (): Promise => {\n return runAppleScript(\n `set imageTypes to {\"PNG\", \"JPG\", \"JPEG\", \"TIF\", \"HEIF\", \"GIF\", \"ICO\", \"ICNS\", \"ASTC\", \"BMP\", \"DDS\", \"EXR\", \"JP2\", \"KTX\", \"Portable Bitmap\", \"Adobe Photoshop\", \"PVR\", \"TGA\", \"WebP\", \"SVG\", \"PDF\", \"HEIC\"}\n\n tell application \"Path Finder\"\n set theSelection to selection\n\n if theSelection is {} and (count windows) > 0 then\n repeat with i from 1 to (count windows)\n activate window i\n set theSelection to selection\n\n set selectionKinds to {}\n repeat with j from 1 to (count theSelection)\n set selectionKinds to selectionKinds & kind of (item j of theSelection)\n end repeat\n\n set containsImage to false\n repeat with imageType in imageTypes\n if selectionKinds contains imageType then\n set containsImage to true\n exit repeat\n end if\n end repeat\n end repeat\n end if\n\n if theSelection is {} then\n return\n else if (theSelection count) is equal to 1 then\n repeat with imageType in imageTypes\n if (kind of the first item of theSelection) contains imageType then\n return the POSIX path of first item of theSelection\n exit repeat\n end if\n end repeat\n else\n set thePaths to {}\n repeat with i from 1 to (theSelection count)\n repeat with imageType in imageTypes\n if (kind of (item i of theSelection)) contains imageType then\n copy (POSIX path of (item i of theSelection)) to end of thePaths\n exit repeat\n end if\n end repeat\n end repeat\n return thePaths\n end if\n end tell`\n );\n};\n\n/**\n * Gets currently selected files in Finder.\n *\n * @returns A promise resolving to the comma-separated list of files as a string.\n */\nconst getSelectedFinderFiles = async (): Promise => {\n return runAppleScript(\n `\n tell application \"Finder\"\n set theSelection to selection\n\n if (count of theSelection) > 1 then\n set thePaths to {}\n repeat with i from 1 to (count of theSelection)\n set theFile to item i of theSelection\n set thePath to (POSIX path of (theFile as alias))\n copy thePath to the end of thePaths\n end repeat\n return thePaths\n else\n return the POSIX path of (theSelection as alias)\n end if\n\n end tell`\n );\n};\n\n\n/**\n * Gets currently selected files in Path Finder.\n *\n * @returns A promise resolving to the comma-separated list of files as a string.\n */\nconst getSelectedPathFinderFiles = async (): Promise => {\n return runAppleScript(\n `\n \n tell application \"Path Finder\"\n set theSelection to selection\n\n if theSelection is {} and (count windows) > 0 then\n repeat with i from 1 to (count windows)\n activate window i\n set theSelection to selection\n\n set containsFile to true\n end repeat\n end if\n\n if theSelection is {} then\n return\n else if (theSelection count) is equal to 1 then\n return the POSIX path of first item of theSelection\n else\n set thePaths to {}\n repeat with i from 1 to (theSelection count)\n copy (POSIX path of (item i of theSelection)) to end of thePaths\n end repeat\n return thePaths\n end if\n end tell\n \n `\n );\n};\n\n/**\n * Cleans up temporary files created by the extension.\n *\n * @returns A promise resolving when the cleanup is complete.\n */\nexport const cleanup = async () => {\n const itemsToRemove = (await LocalStorage.getItem(\"itemsToRemove\")) ?? \"\";\n const itemsToRemoveArray = itemsToRemove.toString().split(\", \");\n for (const item of itemsToRemoveArray) {\n if (fs.existsSync(item)) {\n await fs.promises.rm(item);\n }\n }\n await LocalStorage.removeItem(\"itemsToRemove\");\n};\n\n/**\n * Gets selected images in the preferred file manager application.\n *\n * @returns A promise resolving to the list of selected image paths.\n */\nexport const getSelectedImages = async (): Promise => {\n const selectedImages: string[] = [];\n\n // Get name of preferred file manager\n const extensionPreferences = getPreferenceValues();\n const inputMethod = extensionPreferences.inputMethod;\n let inputMethodError = false;\n\n if (inputMethod == \"Clipboard\") {\n // Extract images from clipboard\n try {\n const clipboardImages = (await getClipboardImages()).split(\", \");\n await LocalStorage.setItem(\"itemsToRemove\", clipboardImages.join(\", \"));\n if (clipboardImages.filter((i) => i.trim().length > 0).length > 0) {\n return clipboardImages;\n }\n } catch (error) {\n // Error getting images from clipboard, fall back to Finder/Path Finder\n console.error(\"Couldn't get images from clipboard\");\n inputMethodError = true;\n }\n }\n\n // Get name of frontmost application\n let activeApp = inputMethod;\n try {\n activeApp = (await getFrontmostApplication()).name;\n } catch {\n console.error(\"Couldn't get frontmost application\");\n }\n\n // Attempt to get selected images from Path Finder\n try {\n if (inputMethod == \"Path Finder\") {\n const pathFinderImages = (await getSelectedPathFinderImages()).split(\", \");\n pathFinderImages.forEach((imgPath) => {\n if (!selectedImages.includes(imgPath)) {\n selectedImages.push(imgPath);\n }\n });\n if (selectedImages.length > 0) {\n return selectedImages;\n }\n }\n } catch (error) {\n // Error getting images from Path Finder, fall back to Finder\n console.error(\"Couldn't get images from Path Finder\");\n inputMethodError = true;\n }\n\n // Get selected images from Finder -- use as fallback for desktop selections & on error\n const finderImages = (await getSelectedFinderImages()).split(\", \");\n if (activeApp == \"Finder\" || inputMethod == \"Finder\" || inputMethodError) {\n selectedImages.push(...finderImages);\n } else {\n // Add desktop selections\n finderImages.forEach((imgPath) => {\n if (imgPath.split(\"/\").at(-2) == \"Desktop\" && !selectedImages.includes(imgPath)) {\n selectedImages.push(imgPath);\n }\n });\n }\n\n return selectedImages;\n};\n\n/**\n * Gets selected files in the preferred file manager application.\n *\n * @returns A promise resolving to the list of selected image paths.\n */\nexport const getSelectedFiles = async (): Promise => {\n const selectedFiles: string[] = [];\n\n // Get name of preferred file manager\n const extensionPreferences = getPreferenceValues();\n const inputMethod = extensionPreferences.inputMethod;\n let inputMethodError = false;\n \n // console.log('nik inputMethod', inputMethod)\n\n if (inputMethod == \"Clipboard\") {\n // Extract images from clipboard\n try {\n const clipboardFiles = (await getClipboardFiles()).split(\", \");\n await LocalStorage.setItem(\"itemsToRemove\", clipboardFiles.join(\", \"));\n if (clipboardFiles.filter((i) => i.trim().length > 0).length > 0) {\n return clipboardFiles;\n }\n } catch (error) {\n // Error getting images from clipboard, fall back to Finder/Path Finder\n console.error(\"Couldn't get images from clipboard\");\n inputMethodError = true;\n }\n }\n\n // Get name of frontmost application\n let activeApp = inputMethod;\n try {\n activeApp = (await getFrontmostApplication()).name;\n } catch {\n console.error(\"Couldn't get frontmost application\");\n }\n\n // Attempt to get selected images from Path Finder\n try {\n if (inputMethod == \"Path Finder\") {\n const pathFinderFiles = (await getSelectedPathFinderFiles()).split(\", \");\n pathFinderFiles.forEach((imgPath) => {\n if (!selectedFiles.includes(imgPath)) {\n selectedFiles.push(imgPath);\n }\n });\n if (selectedFiles.length > 0) {\n return selectedFiles;\n }\n }\n } catch (error) {\n // Error getting images from Path Finder, fall back to Finder\n console.error(\"Couldn't get images from Path Finder\");\n inputMethodError = true;\n }\n\n // Get selected images from Finder -- use as fallback for desktop selections & on error\n const finderFiles = (await getSelectedFinderFiles()).split(\", \");\n // console.log('nik finderFiles', finderFiles)\n if (activeApp == \"Finder\" || inputMethod == \"Finder\" || inputMethodError) {\n selectedFiles.push(...finderFiles);\n } else {\n // Add desktop selections\n finderFiles.forEach((imgPath) => {\n if (imgPath.split(\"/\").at(-2) == \"Desktop\" && !selectedFiles.includes(imgPath)) {\n selectedFiles.push(imgPath);\n }\n });\n }\n\n return selectedFiles;\n};\n\n/**\n * Puts the produced images in the user's preferred location, deleting the files at the given paths.\n *\n * @param imagePaths The paths of the produced images.\n * @returns A promise resolving when the operation is complete.\n */\nexport const moveImageResultsToFinalDestination = async (imagePaths: string[]) => {\n const preferences = getPreferenceValues();\n // Handle the result per the user's preference\n if (preferences.imageResultHandling == ImageResultHandling.CopyToClipboard) {\n await copyImagesAtPathsToClipboard(imagePaths);\n deleteFiles(imagePaths);\n } else if (preferences.imageResultHandling == ImageResultHandling.OpenInPreview) {\n console.log(imagePaths);\n await openPathsInPreview(imagePaths);\n deleteFiles(imagePaths);\n }\n};\n\n/**\n * Executes a SIPS command on a WebP image, using a temporary PNG in the process.\n *\n * @param command The SIPS command to execute.\n * @param webpPath The path of the WebP image.\n * @returns A promise resolving to the path of the resulting image.\n */\nexport const execSIPSCommandOnWebP = async (command: string, webpPath: string): Promise => {\n const preferences = getPreferenceValues();\n const tmpPath = `${environment.supportPath}/tmp.png`;\n\n let newPath = webpPath;\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n const cpuType = os.cpus()[0].model.includes(\"Apple\") ? \"arm\" : \"x86\";\n\n if (cpuType == \"arm\") {\n // Make sure the arm binaries are executable\n execSync(`chmod +x ${environment.assetsPath}/webp/arm/dwebp`);\n execSync(`chmod +x ${environment.assetsPath}/webp/arm/cwebp`);\n // Remove x86 binaries if they exist\n if (fs.existsSync(`${environment.assetsPath}/webp/x86/dwebp`)) {\n await fs.promises.rm(`${environment.assetsPath}/webp/x86/dwebp`);\n }\n if (fs.existsSync(`${environment.assetsPath}/webp/x86/cwebp`)) {\n await fs.promises.rm(`${environment.assetsPath}/webp/x86/cwebp`);\n }\n } else {\n // Make sure the x86 binaries are executable\n execSync(`chmod +x ${environment.assetsPath}/webp/x86/dwebp`);\n execSync(`chmod +x ${environment.assetsPath}/webp/x86/cwebp`);\n\n // Remove arm binaries if they exist\n if (fs.existsSync(`${environment.assetsPath}/webp/arm/dwebp`)) {\n await fs.promises.rm(`${environment.assetsPath}/webp/arm/dwebp`);\n }\n if (fs.existsSync(`${environment.assetsPath}/webp/arm/cwebp`)) {\n await fs.promises.rm(`${environment.assetsPath}/webp/arm/cwebp`);\n }\n }\n\n execSync(\n `${environment.assetsPath}/webp/${cpuType}/dwebp \"${webpPath}\" -o \"${tmpPath}\" && ${command} \"${tmpPath}\" && ${environment.assetsPath}/webp/${cpuType}/cwebp \"${tmpPath}\" -o \"${newPath}\" ; rm \"${tmpPath}\"`\n );\n return newPath;\n};\n\n/**\n * Executes a SIPS command on an SVG image, using a temporary PNG in the process.\n *\n * @param command The SIPS command to execute.\n * @param svgPath The path of the SVG image.\n */\nexport const execSIPSCommandOnSVG = async (command: string, svgPath: string): Promise => {\n const preferences = getPreferenceValues();\n const tmpPath = `${environment.supportPath}/tmp.bmp`;\n\n let newPath = svgPath;\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n convertSVG(\"BMP\", svgPath, tmpPath);\n execSync(`chmod +x ${environment.assetsPath}/potrace/potrace`);\n execSync(\n `${command} \"${tmpPath}\" && ${environment.assetsPath}/potrace/potrace -s --tight -o \"${newPath}\" \"${tmpPath}\"; rm \"${tmpPath}\"`\n );\n return newPath;\n};\n\n/**\n * Converts an SVG to a SIPS-compatible image type.\n *\n * @param targetType The desired image type.\n * @param svgPath The path of the SVG image.\n * @param newPath The path to save the resulting image in.\n */\nexport const convertSVG = (targetType: string, svgPath: string, newPath: string) => {\n runAppleScriptSync(`use framework \"Foundation\"\n use scripting additions\n\n -- Load SVG image from file\n set svgFilePath to \"${svgPath}\"\n set svgData to current application's NSData's alloc()'s initWithContentsOfFile:svgFilePath\n \n -- Create image from SVG data\n set svgImage to current application's NSImage's alloc()'s initWithData:svgData\n \n -- Convert image to PNG data\n set tiffData to svgImage's TIFFRepresentation()\n set theBitmap to current application's NSBitmapImageRep's alloc()'s initWithData:tiffData\n set pngData to theBitmap's representationUsingType:(current application's NSBitmapImageFileType${targetType}) |properties|:(missing value)\n \n -- Save PNG data to file\n pngData's writeToFile:\"${newPath}\" atomically:false`);\n};\n\n/**\n * Converts a PDF to a SIPS-compatible image type, with each page stored in its own image file.\n *\n * @param targetType The desired image type.\n * @param pdfPath The path of the PDF document.\n * @param newPathBase The folder to place the resulting images in.\n */\nexport const convertPDF = (targetType: string, pdfPath: string, newPathBase: string) => {\n const preferences = getPreferenceValues();\n runAppleScriptSync(`use framework \"Foundation\"\n use framework \"PDFKit\"\n \n -- Load the PDF file as NSData\n set pdfData to current application's NSData's dataWithContentsOfFile:\"${pdfPath}\"\n \n -- Create a PDFDocument from the PDF data\n set pdfDoc to current application's PDFDocument's alloc()'s initWithData:pdfData\n\n ${\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ? `set pageImages to current application's NSMutableArray's alloc()'s init()`\n : ``\n }\n \n set pageCount to (pdfDoc's pageCount()) - 1\n repeat with pageIndex from 0 to pageCount\n -- Create an NSImage from each page of the PDF document\n set pdfPage to (pdfDoc's pageAtIndex:pageIndex)\n set pdfRect to (pdfPage's boundsForBox:(current application's kPDFDisplayBoxMediaBox))\n set pdfImage to (current application's NSImage's alloc()'s initWithSize:{item 1 of item 2 of pdfRect, item 2 of item 2 of pdfRect})\n pdfImage's lockFocus()\n (pdfPage's drawWithBox:(current application's kPDFDisplayBoxMediaBox))\n pdfImage's unlockFocus()\n\n ${\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard\n ? `pageImages's addObject:pdfImage`\n : `\n \n -- Convert the NSImage to PNG data\n set pngData to pdfImage's TIFFRepresentation()\n set pngRep to (current application's NSBitmapImageRep's imageRepWithData:pngData)\n set pngData to (pngRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value))\n \n -- Write the PNG data to a new file\n set filePath to \"${newPathBase}/page-\" & pageIndex + 1 & \".${targetType.toLowerCase()}\"\n set fileURL to current application's NSURL's fileURLWithPath:filePath\n ${preferences.imageResultHandling == ImageResultHandling.OpenInPreview ? `pageImages's addObject:fileURL` : ``}\n pngData's writeToURL:fileURL atomically:false`\n }\n end repeat\n\n ${\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ? `\n -- Open the images of each page in Preview, then delete their temporary files\n tell application \"Finder\"\n set previewPath to POSIX path of ((application file id \"com.apple.Preview\") as text)\n set previewURL to current application's NSURL's fileURLWithPath:previewPath\n end tell\n\n set workspace to current application's NSWorkspace's sharedWorkspace()\n set config to current application's NSWorkspaceOpenConfiguration's configuration()\n workspace's openURLs:pageImages withApplicationAtURL:previewURL configuration:config completionHandler:(missing value)\n delay 1\n \n set fileManager to current application's NSFileManager's defaultManager()\n repeat with imageURL in pageImages\n fileManager's removeItemAtURL:imageURL |error|:(missing value)\n end repeat\n `\n : ``\n }\n \n ${\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard\n ? `\n -- Copy the image of each page to the clipboard\n set thePasteboard to current application's NSPasteboard's generalPasteboard()\n thePasteboard's clearContents()\n thePasteboard's writeObjects:pageImages`\n : ``\n }`);\n};\n\n/**\n * Rotates each page of a PDF by the specified degrees.\n *\n * @param pdfPath The path of the PDF to rotate.\n * @param degrees The amount to rotate each page by. Must be a multiple of 90.\n */\nexport const rotatePDF = (pdfPath: string, degrees: number): string => {\n const preferences = getPreferenceValues();\n\n let newPath = pdfPath;\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath, path.extname(newPath)) + \".pdf\");\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath, path.extname(newPath)) + \".pdf\");\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath, path.extname(newPath)) + \".pdf\");\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n runAppleScriptSync(`use framework \"Foundation\"\n use framework \"PDFKit\"\n \n -- Load the PDF file as NSData\n set pdfData to current application's NSData's dataWithContentsOfFile:\"${pdfPath}\"\n \n -- Create a PDFDocument from the PDF data\n set pdfDoc to current application's PDFDocument's alloc()'s initWithData:pdfData\n \n -- Loop through the pages and rotate each one\n repeat with i from 0 to ((pdfDoc's pageCount()) - 1)\n set pdfPage to (pdfDoc's pageAtIndex:i)\n pdfPage's setRotation:((pdfPage's |rotation|()) + ${degrees})\n end repeat\n \n -- Write the modified PDF data to a new file\n set rotatedPdfData to pdfDoc's dataRepresentation()\n rotatedPdfData's writeToFile:\"${newPath}\" atomically:false`);\n return newPath;\n};\n\n/**\n *\n * @param pdfPath The PDF to flip each page of.\n * @param direction The direction to flip. Must be a valid {@link Direction}.\n */\nexport const flipPDF = (pdfPath: string, direction: Direction) => {\n const preferences = getPreferenceValues();\n\n let newPath = pdfPath;\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n let iter = 2;\n while (fs.existsSync(newPath) && os.tmpdir() != path.dirname(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n\n const flipInstruction =\n direction == Direction.HORIZONTAL\n ? `(transform's scaleXBy:-1 yBy:1)\n (transform's translateXBy:(-(item 1 of item 2 of pdfRect)) yBy:0)`\n : `(transform's scaleXBy:1 yBy:-1)\n (transform's translateXBy:0 yBy:(-(item 2 of item 2 of pdfRect)))`;\n\n runAppleScriptSync(`use framework \"Foundation\"\n use framework \"PDFKit\"\n \n -- Load the PDF file as NSData\n set pdfData to current application's NSData's dataWithContentsOfFile:\"${pdfPath}\"\n \n -- Create a PDFDocument from the PDF data\n set pdfDoc to current application's PDFDocument's alloc()'s initWithData:pdfData\n \n -- Flip each page\n repeat with i from 0 to ((pdfDoc's pageCount()) - 1)\n set thePDFPage to (pdfDoc's pageAtIndex:i)\n set pdfRect to (thePDFPage's boundsForBox:(current application's kPDFDisplayBoxMediaBox))\n set flippedPdfImage to (current application's NSImage's alloc()'s initWithSize:(item 2 of pdfRect))\n \n flippedPdfImage's lockFocus()\n set transform to current application's NSAffineTransform's alloc()'s init()\n ${flipInstruction}\n transform's concat()\n (thePDFPage's drawWithBox:(current application's kPDFDisplayBoxMediaBox))\n flippedPdfImage's unlockFocus()\n \n set newPage to (current application's PDFPage's alloc()'s initWithImage:flippedPdfImage)\n \n (pdfDoc's removePageAtIndex:i)\n (pdfDoc's insertPage:newPage atIndex:i)\n end repeat\n \n -- Write the modified PDF data to the file\n set flippedPdfData to pdfDoc's dataRepresentation()\n flippedPdfData's writeToFile:\"${newPath}\" atomically:false`);\n return newPath;\n};\n\n/**\n * Gets the destination path for an image, given the original path and the desired extension, taking the user's preferences into account.\n * @param originalPath The original path of the image.\n * @param targetExtension The desired extension of the image. If not provided, the original extension will be used.\n * @returns The destination path for the image.\n */\nexport const getImageDestination = (originalPath: string, targetExtension?: string): string => {\n const preferences = getPreferenceValues();\n\n // Decompose the original path into its components\n const originalExtension = path.extname(originalPath);\n const originalName = path.basename(originalPath, originalExtension);\n const originalDir = path.dirname(originalPath);\n\n // Construct & return the new path\n const newExtension = targetExtension ? `${targetExtension}` : originalExtension;\n const newFileName = `${originalName}.${newExtension}`;\n\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n const desktopPath = path.join(os.homedir(), \"Downloads\");\n return path.join(desktopPath, newFileName);\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n const desktopPath = path.join(os.homedir(), \"Desktop\");\n return path.join(desktopPath, newFileName);\n }\n return path.join(originalDir, newFileName);\n};\n\n/**\n * Opens the specified paths in Preview.\n *\n * @param filePaths The paths of the files to open.\n */\nexport const openPathsInPreview = async (filePaths: string | string[]) => {\n const paths = Array.isArray(filePaths) ? filePaths : [filePaths];\n const containsSVG = paths.some((p) => path.extname(p) == \".svg\");\n\n await runAppleScript(`use framework \"Foundation\"\n use scripting additions\n set pageImages to {${paths.map((p) => `current application's NSURL's fileURLWithPath:\"${p}\"`).join(\", \")}}\n\n set workspace to current application's NSWorkspace's sharedWorkspace()\n set config to current application's NSWorkspaceOpenConfiguration's configuration()\n\n ${\n containsSVG\n ? `tell application \"Finder\"\n set safariPath to POSIX path of ((application file id \"com.apple.Safari\") as text)\n set safariURL to current application's NSURL's fileURLWithPath:safariPath\n end tell\n\n workspace's openURLs:pageImages withApplicationAtURL:safariURL configuration:config completionHandler:(missing value)\n \n tell application \"Safari\"\n set finished to false\n set iter to 0\n repeat while ((count of windows) = 0 or finished is not true) and iter < 10\n delay 0.5\n set iter to iter + 1\n\n set currentStatus to true\n repeat with doc in (path of documents as list)\n repeat with thePath in {\"${paths.map((p) => encodeURI(`file://${p}`)).join('\", \"')}\"}\n if thePath is not in doc then\n set currentStatus to false\n end if\n end repeat\n end repeat\n set finished to currentStatus\n end repeat\n end tell\n `\n : `tell application \"Finder\"\n set previewPath to POSIX path of ((application file id \"com.apple.Preview\") as text)\n set previewURL to current application's NSURL's fileURLWithPath:previewPath\n end tell\n\n workspace's openURLs:pageImages withApplicationAtURL:previewURL configuration:config completionHandler:(missing value)\n \n tell application \"Preview\"\n set finished to false\n set iter to 0\n repeat while ((count of windows) = 0 or finished is not true) and iter < 10\n delay 0.5\n set iter to iter + 1\n\n set currentStatus to true\n repeat with doc in (path of documents as list)\n repeat with thePath in {\"${paths.join('\", \"')}\"}\n if thePath is not in doc then\n set currentStatus to false\n end if\n end repeat\n end repeat\n set finished to currentStatus\n end repeat\n end tell`\n }`);\n};\n\n/**\n * Deletes the files at the given paths.\n *\n * @param filePaths The paths of the files to delete.\n */\nexport const deleteFiles = (filePaths: string | string[]) => {\n const paths = Array.isArray(filePaths) ? filePaths : [filePaths];\n for (const path of paths) {\n fs.unlinkSync(path);\n }\n};\n\n/**\n * Returns the name of the frontmost application based on whether it owns the menubar.\n *\n * @returns The name of the frontmost application, or \"Finder\" if no application owns the menubar, which shouldn't generally happen.\n */\nexport const getMenubarOwningApplication = () => {\n return runAppleScriptSync(`use framework \"Foundation\"\n use scripting additions\n set workspace to current application's NSWorkspace's sharedWorkspace()\n set runningApps to workspace's runningApplications()\n \n set targetApp to missing value\n repeat with theApp in runningApps\n if theApp's ownsMenuBar() then\n set targetApp to theApp\n exit repeat\n end if\n end repeat\n \n if targetApp is missing value then\n return \"Finder\"\n else\n return targetApp's localizedName() as text\n end if`);\n};\n\n/**\n * Returns the current directory of the file manager. Tries Path Finder first, if it's the frontmost application, then falls back to Finder.\n *\n * @returns The current directory of the file manager.\n */\nexport const getCurrentDirectory = () => {\n // Get name of frontmost application\n let activeApp = \"Finder\";\n try {\n activeApp = getMenubarOwningApplication();\n } catch {\n console.error(\"Couldn't get frontmost application\");\n }\n\n // Attempt to get current directory of Path Finder\n try {\n if (activeApp == \"Path Finder\") {\n return runAppleScriptSync(`tell application \"Path Finder\"\n if 1 \u2264 (count finder windows) then\n get POSIX path of (target of finder window 1)\n else\n get POSIX path of desktop\n end if\n end tell`);\n }\n } catch (error) {\n // Error getting directory of Path Finder, fall back to Finder\n console.error(\"Couldn't get current directory of Path Finder\");\n }\n\n // Fallback to getting current directory from Finder\n return runAppleScriptSync(`tell application \"Finder\"\n if 1 <= (count Finder windows) then\n get POSIX path of (target of window 1 as alias)\n else\n get POSIX path of (desktop as alias)\n end if\n end tell`);\n};\n\n/**\n * Returns the destination paths for the given original paths, based on the user's preferences.\n *\n * @param originalPaths The original paths of image files.\n * @param generated Whether the images were generated by the extension.\n * @returns The destination paths for the given original paths.\n */\nexport const getDestinationPaths = (originalPaths: string[], generated = false): string[] => {\n const preferences = getPreferenceValues();\n return originalPaths.map((imgPath) => {\n let newPath = imgPath;\n if (preferences.imageResultHandling == ImageResultHandling.SaveToDownloads) {\n newPath = path.join(os.homedir(), \"Downloads\", path.basename(newPath));\n } else if (preferences.imageResultHandling == ImageResultHandling.SaveToDesktop) {\n newPath = path.join(os.homedir(), \"Desktop\", path.basename(newPath));\n } else if (\n (preferences.imageResultHandling == ImageResultHandling.SaveInContainingFolder ||\n preferences.imageResultHandling == ImageResultHandling.ReplaceOriginal) &&\n (preferences.inputMethod == \"Clipboard\" || generated)\n ) {\n newPath = path.join(getCurrentDirectory(), path.basename(newPath));\n } else if (\n preferences.imageResultHandling == ImageResultHandling.CopyToClipboard ||\n preferences.imageResultHandling == ImageResultHandling.OpenInPreview\n ) {\n newPath = path.join(os.tmpdir(), path.basename(newPath));\n }\n\n if (\n preferences.imageResultHandling != ImageResultHandling.ReplaceOriginal &&\n os.tmpdir() != path.dirname(newPath)\n ) {\n let iter = 2;\n while (fs.existsSync(newPath)) {\n newPath = path.join(\n path.dirname(newPath),\n path.basename(newPath, path.extname(newPath)) + ` (${iter})${path.extname(newPath)}`\n );\n iter++;\n }\n }\n\n return newPath;\n });\n};\n\n/**\n * Shows or updates a toast to display the given error, and logs the error to the console.\n *\n * @param title The title of the toast.\n * @param error The error to show.\n * @param toast The toast to update.\n */\nexport const showErrorToast = async (title: string, error: Error, toast?: Toast) => {\n console.error(error);\n if (!toast) {\n toast = await showToast({\n title: title,\n message: error.message,\n style: Toast.Style.Failure,\n primaryAction: {\n title: \"Copy Error\",\n onAction: async () => {\n await Clipboard.copy(error.message);\n },\n },\n });\n } else {\n toast.title = title;\n toast.message = error.message;\n toast.style = Toast.Style.Failure;\n toast.primaryAction = {\n title: \"Copy Error\",\n onAction: async () => {\n await Clipboard.copy(error.message);\n },\n };\n }\n};\n", + "review": "# 7\n\n## Bugs\n- The script uses `runAppleScriptSync` in multiple places, which can block the event loop if scripts take a long time.\n- In multiple functions handling file operations, there seems to be no error handling in case paths are invalid or files cannot be accessed.\n- Assumes the existence of `environment.assetsPath` for binary paths without checking if the directory exists.\n- Potential issues with `execSync` if commands fail; errors are not being caught.\n- If the clipboard operation fails (`getClipboardImages()` and `getClipboardFiles()`), the `inputMethodError` variable may not handle errors gracefully.\n\n## Optimizations\n- Consider converting synchronous AppleScript calls to asynchronous to avoid blocking.\n- Provide fallback mechanisms or user notifications if file paths or binaries do not exist.\n- Avoid repetitive code by centralizing the logic for acquiring selected images and directories.\n- Error handling can be enhanced, especially for file system operations.\n- Check local storage item existence before usage to handle potential null exceptions.\n- Use more descriptive names for temporary files to aid debugging.\n- Instead of copying and pasting paths when constructing file paths, use utility functions to improve readability.\n\n## Good Points\n- Modular organization of image handling functions allows for easy maintenance.\n- Use of environment paths and preferences shows a clear intent to create a customizable extension.\n- Various utility functions for dealing with a wide range of image formats and conversions.\n\n## Summary\nThe script provides a comprehensive set of utility functions to interact with file manager applications, converting and handling images and optimizing user preferences. While it generally follows good organizational practices, it has several areas that could be improved upon, particularly in terms of error handling, blocking operations, and redundant code. Streamlining these aspects can enhance the maintainability and reliability of the script.\n\n## Open source alternatives\n- ImageMagick: A feature-rich command-line tool for manipulating images, supporting various formats.\n- GraphicsMagick: Another open-source tool which is considered an ImageMagick alternative or complement.\n- Sips: Although part of macOS, can be utilized for batch processing and image conversions from the command line.", + "filename": "utils.ts", + "path": "raycast/src/utilities/utils.ts", + "directory": "utilities", + "grade": 7, + "size": 35472, + "line_count": 985 +} \ No newline at end of file diff --git a/.reviews/raycast/src/utilities/utils.ts.md b/.reviews/raycast/src/utilities/utils.ts.md new file mode 100644 index 0000000..6b5d1e5 --- /dev/null +++ b/.reviews/raycast/src/utilities/utils.ts.md @@ -0,0 +1,30 @@ +# 7 + +## Bugs +- The script uses `runAppleScriptSync` in multiple places, which can block the event loop if scripts take a long time. +- In multiple functions handling file operations, there seems to be no error handling in case paths are invalid or files cannot be accessed. +- Assumes the existence of `environment.assetsPath` for binary paths without checking if the directory exists. +- Potential issues with `execSync` if commands fail; errors are not being caught. +- If the clipboard operation fails (`getClipboardImages()` and `getClipboardFiles()`), the `inputMethodError` variable may not handle errors gracefully. + +## Optimizations +- Consider converting synchronous AppleScript calls to asynchronous to avoid blocking. +- Provide fallback mechanisms or user notifications if file paths or binaries do not exist. +- Avoid repetitive code by centralizing the logic for acquiring selected images and directories. +- Error handling can be enhanced, especially for file system operations. +- Check local storage item existence before usage to handle potential null exceptions. +- Use more descriptive names for temporary files to aid debugging. +- Instead of copying and pasting paths when constructing file paths, use utility functions to improve readability. + +## Good Points +- Modular organization of image handling functions allows for easy maintenance. +- Use of environment paths and preferences shows a clear intent to create a customizable extension. +- Various utility functions for dealing with a wide range of image formats and conversions. + +## Summary +The script provides a comprehensive set of utility functions to interact with file manager applications, converting and handling images and optimizing user preferences. While it generally follows good organizational practices, it has several areas that could be improved upon, particularly in terms of error handling, blocking operations, and redundant code. Streamlining these aspects can enhance the maintainability and reliability of the script. + +## Open source alternatives +- ImageMagick: A feature-rich command-line tool for manipulating images, supporting various formats. +- GraphicsMagick: Another open-source tool which is considered an ImageMagick alternative or complement. +- Sips: Although part of macOS, can be utilized for batch processing and image conversions from the command line. \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/mongodb/connection.ts.json b/.reviews/remix/app/api/utils/mongodb/connection.ts.json new file mode 100644 index 0000000..6204ca4 --- /dev/null +++ b/.reviews/remix/app/api/utils/mongodb/connection.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "import { MongoClient } from 'mongodb';\n\nexport const createConnection = async () => {\n const client = new MongoClient(process.env.MONGODB_URI, {});\n await client.connect();\n return client;\n};\n", + "review": "**Grade: 7**\n\n### Bugs\n- No specific bugs present in the code snippet, but it heavily depends on a valid `MONGODB_URI` in the environment variables; if not set, it will cause a runtime error.\n\n### Optimizations\n- Consider making `client` connection closed gracefully or reusing it rather than establishing a new connection each time `createConnection` is called.\n- Add error handling for connection failures to manage potential exceptions and avoid application crashes.\n- Consider using a connection pool with a defined size or configuration options for improved performance in high-load scenarios, like using `{ useNewUrlParser: true, useUnifiedTopology: true }`.\n\n### Good Points\n- Uses async/await for handling asynchronous connections, which is a clean and modern approach.\n- Follows a modular approach by encapsulating the creation of the MongoClient connection.\n\n### Summary\nThe code provides a clean and straightforward implementation for creating a connection with MongoDB using the `MongoClient`. It effectively leverages ES6 features like async/await for asynchronous operations. However, it lacks proper error handling and optimizations related to connection reuse and configuration tuning, which could be critical in a production environment.\n\n### Open source alternatives\n- **Mongoose** - An ODM (Object Data Modeling) library for MongoDB and Node.js that provides a higher-level API and additional features like schema validation.\n- **Mongoist** - A simpler, flexible Node.js library for working with MongoDB that simplifies callback and promise handling.", + "filename": "connection.ts", + "path": "remix/app/api/utils/mongodb/connection.ts", + "directory": "mongodb", + "grade": 7, + "size": 195, + "line_count": 8 +} \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/mongodb/connection.ts.md b/.reviews/remix/app/api/utils/mongodb/connection.ts.md new file mode 100644 index 0000000..80c95b4 --- /dev/null +++ b/.reviews/remix/app/api/utils/mongodb/connection.ts.md @@ -0,0 +1,20 @@ +**Grade: 7** + +### Bugs +- No specific bugs present in the code snippet, but it heavily depends on a valid `MONGODB_URI` in the environment variables; if not set, it will cause a runtime error. + +### Optimizations +- Consider making `client` connection closed gracefully or reusing it rather than establishing a new connection each time `createConnection` is called. +- Add error handling for connection failures to manage potential exceptions and avoid application crashes. +- Consider using a connection pool with a defined size or configuration options for improved performance in high-load scenarios, like using `{ useNewUrlParser: true, useUnifiedTopology: true }`. + +### Good Points +- Uses async/await for handling asynchronous connections, which is a clean and modern approach. +- Follows a modular approach by encapsulating the creation of the MongoClient connection. + +### Summary +The code provides a clean and straightforward implementation for creating a connection with MongoDB using the `MongoClient`. It effectively leverages ES6 features like async/await for asynchronous operations. However, it lacks proper error handling and optimizations related to connection reuse and configuration tuning, which could be critical in a production environment. + +### Open source alternatives +- **Mongoose** - An ODM (Object Data Modeling) library for MongoDB and Node.js that provides a higher-level API and additional features like schema validation. +- **Mongoist** - A simpler, flexible Node.js library for working with MongoDB that simplifies callback and promise handling. \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/userCheckExists.ts.json b/.reviews/remix/app/api/utils/userCheckExists.ts.json new file mode 100644 index 0000000..117db8c --- /dev/null +++ b/.reviews/remix/app/api/utils/userCheckExists.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "// query mongodb for user objects with the username provided\n// if user exists, return true\n// if user does not exist, return false\n\nimport { createConnection } from './mongodb/connection';\n\nexport const userCheckExists = async ({ username }) => {\n \n const client = await createConnection();\n const db = client.db('auth');\n const collection = db.collection('users');\n const user = await collection.findOne({ username });\n \n if (user) {\n return true;\n }\n \n return false;\n \n}\n ", + "review": "**Grade: 6**\n\n### Bugs\n- No error handling for the database connection or querying process could lead to uncaught exceptions.\n\n### Optimizations\n- Implement error handling for database operations to manage failures gracefully.\n- Consider using a try-finally block to ensure that the client connection is closed properly.\n- The function assumes the database connection is always successful; ensure connection retries or adjustments are in place.\n- It is advisable to validate the `username` input to prevent injection attacks or invalid data types.\n \n### Good points\n- The code is generally straightforward and easy to read.\n- The function correctly abstracts the database connection logic, which can be reused.\n\n### Summary\nThe code effectively performs its intended operation of checking if a user exists in a MongoDB collection. However, the absence of error handling makes it brittle and risks application stability in case of exceptions during database interactions. Implementing error handling and ensuring the database connection is closed after operations would significantly improve code reliability. Furthermore, ensuring input validation adds security against potentially harmful input.\n\n### Open source alternatives\n- **Mongoose**: An elegant MongoDB object modeling for Node.js with built-in validation, casting, business logic hooks, and more.\n- **Sequelize**: Although primarily for SQL databases, it supports No-SQL databases through custom extensions and could be adapted.", + "filename": "userCheckExists.ts", + "path": "remix/app/api/utils/userCheckExists.ts", + "directory": "utils", + "grade": 6, + "size": 490, + "line_count": 21 +} \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/userCheckExists.ts.md b/.reviews/remix/app/api/utils/userCheckExists.ts.md new file mode 100644 index 0000000..4984c61 --- /dev/null +++ b/.reviews/remix/app/api/utils/userCheckExists.ts.md @@ -0,0 +1,21 @@ +**Grade: 6** + +### Bugs +- No error handling for the database connection or querying process could lead to uncaught exceptions. + +### Optimizations +- Implement error handling for database operations to manage failures gracefully. +- Consider using a try-finally block to ensure that the client connection is closed properly. +- The function assumes the database connection is always successful; ensure connection retries or adjustments are in place. +- It is advisable to validate the `username` input to prevent injection attacks or invalid data types. + +### Good points +- The code is generally straightforward and easy to read. +- The function correctly abstracts the database connection logic, which can be reused. + +### Summary +The code effectively performs its intended operation of checking if a user exists in a MongoDB collection. However, the absence of error handling makes it brittle and risks application stability in case of exceptions during database interactions. Implementing error handling and ensuring the database connection is closed after operations would significantly improve code reliability. Furthermore, ensuring input validation adds security against potentially harmful input. + +### Open source alternatives +- **Mongoose**: An elegant MongoDB object modeling for Node.js with built-in validation, casting, business logic hooks, and more. +- **Sequelize**: Although primarily for SQL databases, it supports No-SQL databases through custom extensions and could be adapted. \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/userValidatePassword.ts.json b/.reviews/remix/app/api/utils/userValidatePassword.ts.json new file mode 100644 index 0000000..f347014 --- /dev/null +++ b/.reviews/remix/app/api/utils/userValidatePassword.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "// query mongodb for user objects with the username provided\n// if user exists, return true\n// if user does not exist, return false\n\nimport { createConnection } from './mongodb/connection';\n\nimport bcrypt from 'bcrypt';\n\nexport const userValidatePassword = async ({ username, password }) => {\n \n const client = await createConnection();\n const db = client.db('auth');\n const collection = db.collection('users');\n const user = await collection.findOne({ username });\n \n if (!user) {\n return false;\n }\n \n const { password: hash } = user;\n \n const match = await bcrypt.compare(password, hash);\n \n if (match) {\n return true;\n }\n \n return false;\n \n}\n ", + "review": "**7**\n\n### Bugs\n- None identified in the code.\n\n### Optimizations\n- **Connection Handling**: Ensure that the database connection is closed after it is used to prevent potential connection leaks.\n- **Password Comparison**: The password comparison operation returns a boolean, thus you can return its result directly instead of using an `if` statement.\n- **Error Handling**: Add try-catch blocks to handle any exceptions that might arise during database operations or bcrypt comparison.\n\n### Good points\n- **Async/Await Usage**: The code effectively uses async/await for handling asynchronous operations, which is readable and efficient.\n- **Modularization**: The code is neatly encapsulated into a function for reusability.\n\n### Summary\nThe code effectively queries a MongoDB database to validate a user's password using bcrypt for comparison. It uses async/await efficiently for asynchronous programming. While the code is functional, it lacks error handling and proper management of the database connection lifecycle. These optimizations, when applied, can help improve resource usage and error management.\n\n### Open source alternatives\n- **Mongoose**: An elegant MongoDB object modeling for Node.js which can simplify database interactions.\n- **Passport.js**: A comprehensive library for user authentication in Node.js, which can handle various types of authentication including username and password.\n", + "filename": "userValidatePassword.ts", + "path": "remix/app/api/utils/userValidatePassword.ts", + "directory": "utils", + "grade": 7, + "size": 671, + "line_count": 31 +} \ No newline at end of file diff --git a/.reviews/remix/app/api/utils/userValidatePassword.ts.md b/.reviews/remix/app/api/utils/userValidatePassword.ts.md new file mode 100644 index 0000000..5031917 --- /dev/null +++ b/.reviews/remix/app/api/utils/userValidatePassword.ts.md @@ -0,0 +1,20 @@ +**7** + +### Bugs +- None identified in the code. + +### Optimizations +- **Connection Handling**: Ensure that the database connection is closed after it is used to prevent potential connection leaks. +- **Password Comparison**: The password comparison operation returns a boolean, thus you can return its result directly instead of using an `if` statement. +- **Error Handling**: Add try-catch blocks to handle any exceptions that might arise during database operations or bcrypt comparison. + +### Good points +- **Async/Await Usage**: The code effectively uses async/await for handling asynchronous operations, which is readable and efficient. +- **Modularization**: The code is neatly encapsulated into a function for reusability. + +### Summary +The code effectively queries a MongoDB database to validate a user's password using bcrypt for comparison. It uses async/await efficiently for asynchronous programming. While the code is functional, it lacks error handling and proper management of the database connection lifecycle. These optimizations, when applied, can help improve resource usage and error management. + +### Open source alternatives +- **Mongoose**: An elegant MongoDB object modeling for Node.js which can simplify database interactions. +- **Passport.js**: A comprehensive library for user authentication in Node.js, which can handle various types of authentication including username and password. diff --git a/.reviews/remix/app/global-types.d.ts.json b/.reviews/remix/app/global-types.d.ts.json new file mode 100644 index 0000000..e97d0af --- /dev/null +++ b/.reviews/remix/app/global-types.d.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "// modify window / globalThis to support any properties\n// so there's no property does not exist on window typescript errors\n\n// Path: app/global-types.d.ts\ndeclare global {\n interface Window {\n [key: string]: any;\n }\n \n // Modify React component props/args to allow anything\n // so we don't get errors \n // Property 'fullPath' does not exist on type '{ children?: ReactNode; }'.\n \n interface ForwardRefRenderFunction {\n T: any;\n (props: any, ref: React.Ref): React.ReactElement | null;\n }\n \n}\n\nexport {};\n", + "review": "# 4\n\n## Bugs\n- The `ForwardRefRenderFunction` interface modification is incorrect. TypeScript interfaces should not define function signatures this way.\n- Incorrect usage of generics in the `ForwardRefRenderFunction` interface. `T` is declared but not used appropriately.\n\n## Optimizations\n- Instead of declaring `[key: string]: any;` on the `Window` interface, it's better to add explicit properties whenever possible to maintain type safety.\n- For the `ForwardRefRenderFunction`, consider using more specific prop and ref types whenever possible to leverage TypeScript's type checking capabilities.\n\n## Good Points\n- Utilizes TypeScript's `declare global` for augmenting global types, reflecting an understanding of TypeScript\u2019s type declaration system.\n- Export statement is used to ensure this file is treated as a module, which is good for preventing global scope contamination.\n\n## Summary\nThe code effectively expands the global `Window` and `ForwardRefRenderFunction` interfaces to avoid TypeScript errors regarding property existence. However, this approach circumvents one of TypeScript's key advantages\u2014type safety\u2014which might lead to less predictable bug surfaces. An explicit declaration of expected properties and purpose-specific TypeScript interfaces should be favored over using `any` to maintain code robustness and integrity. The approach may be practical temporarily but is discouraged for long-term use.\n\n## Open source alternatives\n- **TypeScript ESLint**: This tool can help in progressively enhancing TypeScript codebases, highlighting potential improvements and errors, which could be a more sustainable approach to code type issues.\n- **React Types Solutions**: Libraries like `@types/react` provide comprehensive type definitions for better integration with TypeScript and React JSX elements without sacrificing type safety.", + "filename": "global-types.d.ts", + "path": "remix/app/global-types.d.ts", + "directory": "app", + "grade": 4, + "size": 530, + "line_count": 22 +} \ No newline at end of file diff --git a/.reviews/remix/app/global-types.d.ts.md b/.reviews/remix/app/global-types.d.ts.md new file mode 100644 index 0000000..c972ad7 --- /dev/null +++ b/.reviews/remix/app/global-types.d.ts.md @@ -0,0 +1,20 @@ +# 4 + +## Bugs +- The `ForwardRefRenderFunction` interface modification is incorrect. TypeScript interfaces should not define function signatures this way. +- Incorrect usage of generics in the `ForwardRefRenderFunction` interface. `T` is declared but not used appropriately. + +## Optimizations +- Instead of declaring `[key: string]: any;` on the `Window` interface, it's better to add explicit properties whenever possible to maintain type safety. +- For the `ForwardRefRenderFunction`, consider using more specific prop and ref types whenever possible to leverage TypeScript's type checking capabilities. + +## Good Points +- Utilizes TypeScript's `declare global` for augmenting global types, reflecting an understanding of TypeScript’s type declaration system. +- Export statement is used to ensure this file is treated as a module, which is good for preventing global scope contamination. + +## Summary +The code effectively expands the global `Window` and `ForwardRefRenderFunction` interfaces to avoid TypeScript errors regarding property existence. However, this approach circumvents one of TypeScript's key advantages—type safety—which might lead to less predictable bug surfaces. An explicit declaration of expected properties and purpose-specific TypeScript interfaces should be favored over using `any` to maintain code robustness and integrity. The approach may be practical temporarily but is discouraged for long-term use. + +## Open source alternatives +- **TypeScript ESLint**: This tool can help in progressively enhancing TypeScript codebases, highlighting potential improvements and errors, which could be a more sustainable approach to code type issues. +- **React Types Solutions**: Libraries like `@types/react` provide comprehensive type definitions for better integration with TypeScript and React JSX elements without sacrificing type safety. \ No newline at end of file diff --git a/.reviews/remix/app/gp/GradientPath.js.json b/.reviews/remix/app/gp/GradientPath.js.json new file mode 100644 index 0000000..0ef518f --- /dev/null +++ b/.reviews/remix/app/gp/GradientPath.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { DEFAULT_PRECISION } from \"./_constants\"\nimport { getData, strokeToFill } from \"./_data\"\nimport { convertPathToNode, segmentToD, styleAttrs, svgElem } from \"./_utils\"\n\nexport const GradientPath = class {\n constructor({ path, segments, samples, precision = DEFAULT_PRECISION }) {\n // If the path being passed isn't a DOM node already, make it one\n this.path = convertPathToNode(path)\n\n this.segments = segments\n this.samples = samples\n this.precision = precision\n\n // Check if nodeName is path and that the path is closed, otherwise it's closed by default\n this.pathClosed =\n this.path.nodeName == \"path\"\n ? this.path.getAttribute(\"d\").match(/z/gi)\n : true\n\n // Store the render cycles that the user creates\n this.renders = []\n\n // Append a group to the SVG to capture everything we render and ensure our paths and circles are properly encapsulated\n this.svg = path.closest(\"svg\")\n this.group = svgElem(\"g\", {\n class: \"gradient-path\",\n })\n\n // Get the data\n this.data = getData({ path, segments, samples, precision })\n\n // Append the main group to the SVG\n this.svg.appendChild(this.group)\n\n // Remove the main path once we have the data values\n this.path.parentNode.removeChild(this.path)\n }\n\n remove() {\n this.group.parentNode.removeChild(this.group)\n }\n\n render({\n type,\n stroke = [\"white\", \"black\", \"white\"],\n strokeWidth = 1,\n fill = [\"white\", \"black\", \"white\"],\n width,\n animation = {},\n }) {\n // Store information from this render cycle\n const renderCycle = {}\n\n // Create a group for each element\n const elemGroup = svgElem(\"g\", { class: `element-${type}` })\n\n this.group.appendChild(elemGroup)\n renderCycle.group = elemGroup\n\n if (type === \"path\") {\n // If we specify a width and fill, then we need to outline the path and then average the join points of the segments\n // If we do not specify a width and fill, then we will be stroking and can leave the data \"as is\"\n renderCycle.data =\n width && fill\n ? strokeToFill(this.data, width, this.precision, this.pathClosed)\n : this.data\n\n for (let j = 0; j < renderCycle.data.length; j++) {\n const { samples, progress } = renderCycle.data[j]\n\n // Create a path for each segment and append it to its elemGroup\n elemGroup.appendChild(\n svgElem(\"path\", {\n class: \"path-segment\",\n d: segmentToD(samples),\n ...styleAttrs(fill, stroke, strokeWidth, progress, animation),\n })\n )\n }\n } else if (type === \"circle\") {\n renderCycle.data = this.data.flatMap(({ samples }) => samples)\n\n for (let j = 0; j < renderCycle.data.length; j++) {\n const { x, y, progress } = renderCycle.data[j]\n\n // Create a circle for each sample and append it to its elemGroup\n elemGroup.appendChild(\n svgElem(\"circle\", {\n class: \"circle-sample\",\n cx: x,\n cy: y,\n r: width / 2,\n ...styleAttrs(fill, stroke, strokeWidth, progress, animation),\n })\n )\n }\n }\n\n // Save the information in the current renderCycle and pop it onto the renders array\n this.renders.push(renderCycle)\n\n // Return this for method chaining\n return this\n }\n}\n", + "review": "## 6\n\n### Bugs\n- No explicit handling of cases where `path` might not be properly converted to a DOM node or may be misformatted.\n- Assumes all necessary imports and functions exist and function as intended without verifying their presence or their return types.\n\n### Optimizations\n- Consider adding type-checking or input validation for the `path` and other parameters in the constructor to ensure they meet expected criteria.\n- Error handling could be improved, particularly around DOM manipulations to handle unexpected behavior gracefully.\n- Remove the path element and its parent only if they are present to prevent potential runtime errors.\n- Performance could be enhanced by defensive copying or checking mutation behavior for reused data structures, e.g., `renderCycle.data`.\n\n### Good points\n- Uses modular imports and exports, indicating a well-structured codebase.\n- The `GradientPath` class design pattern is clear, separating concerns with methods focused on rendering and removal.\n- Configurable parameters for rendering give flexibility to users for customizing the output.\n\n### Summary\nThe provided code defines a `GradientPath` class used to render paths and circles based on a given SVG path element. It validates the path's closure status, removes the node after capturing data, and has rendering methods that support different configurations for customization. While the functionality is well compartmentalized, the code could benefit from improved validation, error handling, and certain performance optimizations.\n\n### Open source alternatives\n- [Snap.svg](http://snapsvg.io/): A JavaScript library for working with SVG.\n- [Two.js](https://two.js.org/): A two-dimensional drawing library for modern web browsers.", + "filename": "GradientPath.js", + "path": "remix/app/gp/GradientPath.js", + "directory": "gp", + "grade": 6, + "size": 3348, + "line_count": 106 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/GradientPath.js.md b/.reviews/remix/app/gp/GradientPath.js.md new file mode 100644 index 0000000..c7ca954 --- /dev/null +++ b/.reviews/remix/app/gp/GradientPath.js.md @@ -0,0 +1,23 @@ +## 6 + +### Bugs +- No explicit handling of cases where `path` might not be properly converted to a DOM node or may be misformatted. +- Assumes all necessary imports and functions exist and function as intended without verifying their presence or their return types. + +### Optimizations +- Consider adding type-checking or input validation for the `path` and other parameters in the constructor to ensure they meet expected criteria. +- Error handling could be improved, particularly around DOM manipulations to handle unexpected behavior gracefully. +- Remove the path element and its parent only if they are present to prevent potential runtime errors. +- Performance could be enhanced by defensive copying or checking mutation behavior for reused data structures, e.g., `renderCycle.data`. + +### Good points +- Uses modular imports and exports, indicating a well-structured codebase. +- The `GradientPath` class design pattern is clear, separating concerns with methods focused on rendering and removal. +- Configurable parameters for rendering give flexibility to users for customizing the output. + +### Summary +The provided code defines a `GradientPath` class used to render paths and circles based on a given SVG path element. It validates the path's closure status, removes the node after capturing data, and has rendering methods that support different configurations for customization. While the functionality is well compartmentalized, the code could benefit from improved validation, error handling, and certain performance optimizations. + +### Open source alternatives +- [Snap.svg](http://snapsvg.io/): A JavaScript library for working with SVG. +- [Two.js](https://two.js.org/): A two-dimensional drawing library for modern web browsers. \ No newline at end of file diff --git a/.reviews/remix/app/gp/Sample.js.json b/.reviews/remix/app/gp/Sample.js.json new file mode 100644 index 0000000..7aef451 --- /dev/null +++ b/.reviews/remix/app/gp/Sample.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export default class Sample {\n constructor({ x, y, progress, segment }) {\n this.x = x\n this.y = y\n this.progress = progress\n this.segment = segment\n }\n}\n", + "review": "# 6\n\n### Bugs\n- The code does not contain any apparent bugs, though its functionality is limited.\n\n### Optimizations\n- Add type-checking to ensure that `x`, `y`, `progress`, and `segment` are of the expected types.\n- Consider using default parameter values in the constructor for better flexibility.\n- Add documentation comments to explain the class functionality and its intended usage.\n\n### Good points\n- The class uses ES6 syntax, which is modern and widely supported.\n- Follows a clear naming convention for properties and the constructor.\n- Utilizes destructuring in the constructor for concise property assignment.\n\n### Summary\nThe code provided is a simple JavaScript class definition with a constructor that initializes four properties. It effectively uses modern JavaScript features like destructuring and concise methods. However, with its current functionality, it appears to be more of a placeholder or a data structure without any methods for data manipulation or validation. Adding comments and type checks could enhance its robustness and usability.\n\n### Open source alternatives\n- **Immutable.js**: While not a direct one-to-one for simple classes, Immutable.js provides immutable data structures, which are an alternative approach to handling clean and efficient data states in JavaScript.\n- **Ramda**: A practical library for functional programming in JavaScript that can facilitate the handling of data structures and transformations.", + "filename": "Sample.js", + "path": "remix/app/gp/Sample.js", + "directory": "gp", + "grade": 6, + "size": 167, + "line_count": 9 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/Sample.js.md b/.reviews/remix/app/gp/Sample.js.md new file mode 100644 index 0000000..b51bdde --- /dev/null +++ b/.reviews/remix/app/gp/Sample.js.md @@ -0,0 +1,21 @@ +# 6 + +### Bugs +- The code does not contain any apparent bugs, though its functionality is limited. + +### Optimizations +- Add type-checking to ensure that `x`, `y`, `progress`, and `segment` are of the expected types. +- Consider using default parameter values in the constructor for better flexibility. +- Add documentation comments to explain the class functionality and its intended usage. + +### Good points +- The class uses ES6 syntax, which is modern and widely supported. +- Follows a clear naming convention for properties and the constructor. +- Utilizes destructuring in the constructor for concise property assignment. + +### Summary +The code provided is a simple JavaScript class definition with a constructor that initializes four properties. It effectively uses modern JavaScript features like destructuring and concise methods. However, with its current functionality, it appears to be more of a placeholder or a data structure without any methods for data manipulation or validation. Adding comments and type checks could enhance its robustness and usability. + +### Open source alternatives +- **Immutable.js**: While not a direct one-to-one for simple classes, Immutable.js provides immutable data structures, which are an alternative approach to handling clean and efficient data states in JavaScript. +- **Ramda**: A practical library for functional programming in JavaScript that can facilitate the handling of data structures and transformations. \ No newline at end of file diff --git a/.reviews/remix/app/gp/Segment.js.json b/.reviews/remix/app/gp/Segment.js.json new file mode 100644 index 0000000..51fd92d --- /dev/null +++ b/.reviews/remix/app/gp/Segment.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { getMiddleSample } from \"./_utils\"\n\nexport default class Segment {\n constructor({ samples }) {\n this.samples = samples\n this.progress = getMiddleSample(samples).progress\n }\n}\n", + "review": "8\n\n### Bugs\n- No apparent bugs were found in the code snippet itself.\n\n### Optimizations\n- Include input validation to check if `samples` is an array and contains the expected structure.\n- Add default values or error handling if `getMiddleSample(samples)` returns undefined or unexpected results.\n- Consider making the class immutable if the data should not change after initialization by using `Object.freeze`.\n\n### Good points\n- Good use of destructuring to make the constructor concise.\n- Assumes the existence of a utility function, `getMiddleSample`, promoting modular code.\n\n### Summary\nThe code is concise and appears to be functional, assuming the utility function works correctly. It could benefit from additional checks and validations to safeguard against potential runtime issues and improve robustness. \n\n### Open source alternatives\n- **Tone.js** - Can manage segments and samples as part of a larger audio manipulation library.\n- **wavesurfer.js** - Can be used for handling and visualizing audio segments with samples.", + "filename": "Segment.js", + "path": "remix/app/gp/Segment.js", + "directory": "gp", + "grade": 8, + "size": 191, + "line_count": 9 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/Segment.js.md b/.reviews/remix/app/gp/Segment.js.md new file mode 100644 index 0000000..3714574 --- /dev/null +++ b/.reviews/remix/app/gp/Segment.js.md @@ -0,0 +1,20 @@ +8 + +### Bugs +- No apparent bugs were found in the code snippet itself. + +### Optimizations +- Include input validation to check if `samples` is an array and contains the expected structure. +- Add default values or error handling if `getMiddleSample(samples)` returns undefined or unexpected results. +- Consider making the class immutable if the data should not change after initialization by using `Object.freeze`. + +### Good points +- Good use of destructuring to make the constructor concise. +- Assumes the existence of a utility function, `getMiddleSample`, promoting modular code. + +### Summary +The code is concise and appears to be functional, assuming the utility function works correctly. It could benefit from additional checks and validations to safeguard against potential runtime issues and improve robustness. + +### Open source alternatives +- **Tone.js** - Can manage segments and samples as part of a larger audio manipulation library. +- **wavesurfer.js** - Can be used for handling and visualizing audio segments with samples. \ No newline at end of file diff --git a/.reviews/remix/app/gp/_constants.js.json b/.reviews/remix/app/gp/_constants.js.json new file mode 100644 index 0000000..0fad1f7 --- /dev/null +++ b/.reviews/remix/app/gp/_constants.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export const DEFAULT_PRECISION = 2\n", + "review": "8\n\n## Bugs\n- There are no bugs present in this one-line code snippet. \n\n## Optimizations\n- Consider adding a comment to provide context or an example for how `DEFAULT_PRECISION` might be used, especially if this is part of a larger codebase. This can help improve code readability.\n- Consider using more descriptive constant names depending on the context, like `DECIMAL_PRECISION` if it specifically relates to decimal numbers, to avoid ambiguity.\n\n## Good points\n- Using `const` ensures that the value remains immutable, which is a best practice for values meant to remain constant.\n- The intent of the code is clear, assuming that `DEFAULT_PRECISION` is used within a relevant context.\n\n## Summary\nThe code is a straightforward declaration of a constant, which suggests a reasonable approach to code structure by using constants for values that should not change. The code is clean, with no visible redundancies, but lacks context which might be crucial for understanding its purpose within a larger codebase.\n\n## Open source alternatives\n- Since this is merely a constant declaration, there aren\u2019t direct open source alternatives. However, for libraries that deal with precision in numerical computations, you might look into libraries like math.js or big.js which provide tools for dealing with numbers and precision that may incorporate similar constants internally.", + "filename": "_constants.js", + "path": "remix/app/gp/_constants.js", + "directory": "gp", + "grade": 8, + "size": 35, + "line_count": 2 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/_constants.js.md b/.reviews/remix/app/gp/_constants.js.md new file mode 100644 index 0000000..3aa948b --- /dev/null +++ b/.reviews/remix/app/gp/_constants.js.md @@ -0,0 +1,18 @@ +8 + +## Bugs +- There are no bugs present in this one-line code snippet. + +## Optimizations +- Consider adding a comment to provide context or an example for how `DEFAULT_PRECISION` might be used, especially if this is part of a larger codebase. This can help improve code readability. +- Consider using more descriptive constant names depending on the context, like `DECIMAL_PRECISION` if it specifically relates to decimal numbers, to avoid ambiguity. + +## Good points +- Using `const` ensures that the value remains immutable, which is a best practice for values meant to remain constant. +- The intent of the code is clear, assuming that `DEFAULT_PRECISION` is used within a relevant context. + +## Summary +The code is a straightforward declaration of a constant, which suggests a reasonable approach to code structure by using constants for values that should not change. The code is clean, with no visible redundancies, but lacks context which might be crucial for understanding its purpose within a larger codebase. + +## Open source alternatives +- Since this is merely a constant declaration, there aren’t direct open source alternatives. However, for libraries that deal with precision in numerical computations, you might look into libraries like math.js or big.js which provide tools for dealing with numbers and precision that may incorporate similar constants internally. \ No newline at end of file diff --git a/.reviews/remix/app/gp/_data.js.json b/.reviews/remix/app/gp/_data.js.json new file mode 100644 index 0000000..5b6fddb --- /dev/null +++ b/.reviews/remix/app/gp/_data.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import { DEFAULT_PRECISION } from \"./_constants\"\nimport { convertPathToNode } from \"./_utils\"\nimport Sample from \"./Sample\"\nimport Segment from \"./Segment\"\n\n// The main function responsible for getting data\n// This will take a path, number of samples, number of samples, and a precision value\n// It will return an array of Segments, which in turn contains an array of Samples\n// This can later be used to generate a stroked path, converted to outlines for a filled path, or flattened for plotting SVG circles\nexport const getData = ({\n path,\n segments,\n samples,\n precision = DEFAULT_PRECISION,\n}) => {\n // Convert the given path to a DOM node if it isn't already one\n path = convertPathToNode(path)\n\n // We decrement the number of samples per segment because when we group them later we will add on the first sample of the following segment\n if (samples > 1) samples--\n\n // Get total length of path, total number of samples we will be generating, and two blank arrays to hold samples and segments\n const pathLength = path.getTotalLength(),\n totalSamples = segments * samples,\n allSamples = [],\n allSegments = []\n\n // For the number of total samples, get the x, y, and progress values for each sample along the path\n for (let sample = 0; sample <= totalSamples; sample++) {\n const progress = sample / totalSamples\n\n let { x, y } = path.getPointAtLength(progress * pathLength)\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n x = +x.toFixed(precision)\n y = +y.toFixed(precision)\n }\n\n // Create a new Sample and push it onto the allSamples array\n allSamples.push(new Sample({ x, y, progress }))\n }\n\n // Out of all the samples gathered previously, sort them into groups of segments\n // Each group includes the samples of the current segment, with the last sample being first sample from the next segment\n for (let segment = 0; segment < segments; segment++) {\n const currentStart = segment * samples,\n nextStart = currentStart + samples,\n segmentSamples = []\n\n // Push all current samples onto segmentSamples\n for (let samInSeg = 0; samInSeg < samples; samInSeg++) {\n segmentSamples.push(allSamples[currentStart + samInSeg])\n }\n\n // Push the first sample from the next segment onto segmentSamples\n segmentSamples.push(allSamples[nextStart])\n\n // Create a new Segment with the samples from segmentSamples\n allSegments.push(new Segment({ samples: segmentSamples }))\n }\n\n // Return our group of segments\n return allSegments\n}\n\n// The function responsible for converting strokable data (from getData()) into fillable data\n// This allows any SVG path to be filled instead of just stroked, allowing for the user to fill and stroke paths simultaneously\n// We start by outlining the stroked data given a specified width and the we average together the edges where adjacent segments touch\nexport const strokeToFill = (data, width, precision, pathClosed) => {\n const outlinedStrokes = outlineStrokes(data, width, precision),\n averagedSegmentJoins = averageSegmentJoins(\n outlinedStrokes,\n precision,\n pathClosed\n )\n\n return averagedSegmentJoins\n}\n\n// An internal function for outlining stroked data\nconst outlineStrokes = (data, width, precision) => {\n // We need to get the points perpendicular to a startPoint, given an angle, radius, and precision\n const getPerpSamples = (angle, radius, precision, startPoint) => {\n const p0 = new Sample({\n ...startPoint,\n x: Math.sin(angle) * radius + startPoint.x,\n y: -Math.cos(angle) * radius + startPoint.y,\n }),\n p1 = new Sample({\n ...startPoint,\n x: -Math.sin(angle) * radius + startPoint.x,\n y: Math.cos(angle) * radius + startPoint.y,\n })\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n p0.x = +p0.x.toFixed(precision)\n p0.y = +p0.y.toFixed(precision)\n p1.x = +p1.x.toFixed(precision)\n p1.y = +p1.y.toFixed(precision)\n }\n\n return [p0, p1]\n }\n\n // We need to set the radius (half of the width) and have a holding array for outlined Segments\n const radius = width / 2,\n outlinedData = []\n\n for (let i = 0; i < data.length; i++) {\n const samples = data[i].samples,\n segmentSamples = []\n\n // For each sample point and the following sample point (if there is one) compute the angle\n // Also compute the sample's various perpendicular points (with a distance of radius away from the sample point)\n for (let j = 0; j < samples.length; j++) {\n // If we're at the end of the segment and there are no further points, get outta here!\n if (samples[j + 1] === undefined) break\n\n const p0 = samples[j], // First point\n p1 = samples[j + 1], // Second point\n angle = Math.atan2(p1.y - p0.y, p1.x - p0.x), // Perpendicular angle to p0 and p1\n p0Perps = getPerpSamples(angle, radius, precision, p0), // Get perpedicular points with a distance of radius away from p0\n p1Perps = getPerpSamples(angle, radius, precision, p1) // Get perpedicular points with a distance of radius away from p1\n\n // We only need the p0 perpendenciular points for the first sample\n // The p0 for j > 0 will always be the same as p1 anyhow, so let's not add redundant points\n if (j === 0) {\n segmentSamples.push(...p0Perps)\n }\n\n // Always push the second sample point's perpendicular points\n segmentSamples.push(...p1Perps)\n }\n\n // segmentSamples is out of order...\n // Given a segmentSamples length of 8, the points need to be rearranged from: 0, 2, 4, 6, 7, 5, 3, 1\n outlinedData.push(\n new Segment({\n samples: [\n ...segmentSamples.filter((s, i) => i % 2 === 0),\n ...segmentSamples.filter((s, i) => i % 2 === 1).reverse(),\n ],\n })\n )\n }\n\n return outlinedData\n}\n\n// An internal function taking outlinedData (from outlineStrokes()) and averaging adjacent edges\n// If we didn't do this, our data would be fillable, but it would look stroked\n// This function fixes where segments overlap and underlap each other\nconst averageSegmentJoins = (outlinedData, precision, pathClosed) => {\n // Find the average x and y between two points (p0 and p1)\n const avg = (p0, p1) => ({\n x: (p0.x + p1.x) / 2,\n y: (p0.y + p1.y) / 2,\n })\n\n // Recombine the new x and y positions with all the other keys in the object\n const combine = (segment, pos, avg) => ({\n ...segment[pos],\n x: avg.x,\n y: avg.y,\n })\n\n const init_outlinedData = JSON.parse(JSON.stringify(outlinedData)) //clone initial outlinedData Object\n\n for (let i = 0; i < outlinedData.length; i++) {\n // If path is closed: the current segment's samples;\n // If path is open: the current segments' samples, as long as it's not the last segment; Otherwise, the current segments' sample of the initial outlinedData object\n const currentSamples = pathClosed\n ? outlinedData[i].samples\n : outlinedData[i + 1]\n ? outlinedData[i].samples\n : init_outlinedData[i].samples,\n // If path is closed: the next segment's samples, otherwise, the first segment's samples\n // If path is open: the next segment's samples, otherwise, the first segment's samples of the initial outlinedData object\n nextSamples = pathClosed\n ? outlinedData[i + 1]\n ? outlinedData[i + 1].samples\n : outlinedData[0].samples\n : outlinedData[i + 1]\n ? outlinedData[i + 1].samples\n : init_outlinedData[0].samples,\n currentMiddle = currentSamples.length / 2, // The \"middle\" sample in the current segment's samples\n nextEnd = nextSamples.length - 1 // The last sample in the next segment's samples\n\n // Average two sets of outlined samples to create p0Average and p1Average\n const p0Average = avg(currentSamples[currentMiddle - 1], nextSamples[0]),\n p1Average = avg(currentSamples[currentMiddle], nextSamples[nextEnd])\n\n // If the user asks to round our x and y values, do so\n if (precision) {\n p0Average.x = +p0Average.x.toFixed(precision)\n p0Average.y = +p0Average.y.toFixed(precision)\n p1Average.x = +p1Average.x.toFixed(precision)\n p1Average.y = +p1Average.y.toFixed(precision)\n }\n\n // Replace the previous values with new Samples\n currentSamples[currentMiddle - 1] = new Sample({\n ...combine(currentSamples, currentMiddle - 1, p0Average),\n })\n currentSamples[currentMiddle] = new Sample({\n ...combine(currentSamples, currentMiddle, p1Average),\n })\n nextSamples[0] = new Sample({\n ...combine(nextSamples, 0, p0Average),\n })\n nextSamples[nextEnd] = new Sample({\n ...combine(nextSamples, nextEnd, p1Average),\n })\n }\n\n return outlinedData\n}\n", + "review": "# 7\n\n## Bugs\n- No validation of input parameters like `path`, which could lead to potential runtime errors if incorrect data types are provided.\n- Possibility of division by zero in `getData` if `segments` or `samples` is zero, which could raise an exception.\n- Assumes `path` has defined methods like `getTotalLength` without checking if they exist or handling errors if they're not available.\n- In `averageSegmentJoins`, there's potential risk of accessing undefined array elements if `outlinedData` length is less than expected, particularly in loop iterations.\n\n## Optimizations\n- Consider adding validation checks for input parameters (e.g., ensuring `segments` and `samples` are positive numbers).\n- Avoid unnecessary calculations by short-circuiting conditions when precision is not needed.\n- Use `Object.assign()` or spread operator to clone objects instead of JSON stringification and parsing for better performance.\n- Reduce redundancy by extracting repetitive logic, such as rounding and averaging, into separate utility functions.\n- Consider using more descriptive parameter names to enhance code readability.\n\n## Good points\n- Implements a clear transformation of path data to samples and segments, showing a logical step-by-step process.\n- Attempts to handle precision in the calculations, offering flexibility to the caller.\n- Thoroughly comments the purpose and process of each function and code block, aiding in comprehension.\n\n## Summary\nThe code effectively maps path data into segmented samples with an option for precision. It demonstrates consistent approach in processing data, maintaining modularity with separate functions for distinct tasks. However, this implementation lacks input validation, which can cause runtime issues with unexpected inputs. By addressing potential errors, optimizing code redundancy, and ensuring input validity, the solution can be made more robust and efficient.\n\n## Open source alternatives\n- Snap.svg: A JavaScript library for modern SVG graphics focusing on delivering faster performance and better optimization.\n- D3.js: While primarily focused on data visualization, it includes powerful utilities for manipulating documents based on data, including path generation and modification.", + "filename": "_data.js", + "path": "remix/app/gp/_data.js", + "directory": "gp", + "grade": 7, + "size": 8782, + "line_count": 220 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/_data.js.md b/.reviews/remix/app/gp/_data.js.md new file mode 100644 index 0000000..f0a8214 --- /dev/null +++ b/.reviews/remix/app/gp/_data.js.md @@ -0,0 +1,26 @@ +# 7 + +## Bugs +- No validation of input parameters like `path`, which could lead to potential runtime errors if incorrect data types are provided. +- Possibility of division by zero in `getData` if `segments` or `samples` is zero, which could raise an exception. +- Assumes `path` has defined methods like `getTotalLength` without checking if they exist or handling errors if they're not available. +- In `averageSegmentJoins`, there's potential risk of accessing undefined array elements if `outlinedData` length is less than expected, particularly in loop iterations. + +## Optimizations +- Consider adding validation checks for input parameters (e.g., ensuring `segments` and `samples` are positive numbers). +- Avoid unnecessary calculations by short-circuiting conditions when precision is not needed. +- Use `Object.assign()` or spread operator to clone objects instead of JSON stringification and parsing for better performance. +- Reduce redundancy by extracting repetitive logic, such as rounding and averaging, into separate utility functions. +- Consider using more descriptive parameter names to enhance code readability. + +## Good points +- Implements a clear transformation of path data to samples and segments, showing a logical step-by-step process. +- Attempts to handle precision in the calculations, offering flexibility to the caller. +- Thoroughly comments the purpose and process of each function and code block, aiding in comprehension. + +## Summary +The code effectively maps path data into segmented samples with an option for precision. It demonstrates consistent approach in processing data, maintaining modularity with separate functions for distinct tasks. However, this implementation lacks input validation, which can cause runtime issues with unexpected inputs. By addressing potential errors, optimizing code redundancy, and ensuring input validity, the solution can be made more robust and efficient. + +## Open source alternatives +- Snap.svg: A JavaScript library for modern SVG graphics focusing on delivering faster performance and better optimization. +- D3.js: While primarily focused on data visualization, it includes powerful utilities for manipulating documents based on data, including path generation and modification. \ No newline at end of file diff --git a/.reviews/remix/app/gp/_utils.js.json b/.reviews/remix/app/gp/_utils.js.json new file mode 100644 index 0000000..baa9b4e --- /dev/null +++ b/.reviews/remix/app/gp/_utils.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "import tinygradient from \"tinygradient\"\n\n// An internal function to help with easily creating SVG elements with an object of attributes\nexport const svgElem = (type, attrs) => {\n const elem = document.createElementNS(\"http://www.w3.org/2000/svg\", type),\n attributes = Object.keys(attrs)\n\n for (let i = 0; i < attributes.length; i++) {\n const attr = attributes[i]\n\n elem.setAttribute(attr, attrs[attr])\n }\n\n return elem\n}\n\n// An internal function to help with the repetition of adding fill, stroke, and stroke-width attributes\nexport const styleAttrs = (fill, stroke, strokeWidth, progress, animation) => {\n const determineColor = (type, progress) =>\n typeof type === \"string\" ? type : tinygradient(type).rgbAt(progress)\n\n const attrs = {}\n\n if (stroke) {\n attrs[\"stroke\"] = determineColor(stroke, progress)\n attrs[\"stroke-width\"] = strokeWidth\n }\n\n if (fill) {\n attrs[\"fill\"] = determineColor(fill, progress)\n }\n\n if (animation?.name) {\n // TODO: add animation-direction support\n\n const duration = animation.duration || 5\n\n attrs[\"style\"] = `\n animation-name: ${animation?.name}; \n animation-delay: ${progress * duration - duration}s;\n animation-duration: ${duration}s; \n animation-iteration-count: infinite; \n animation-timing-function: linear;`\n }\n\n return attrs\n}\n\n// An internal function to convert any array of samples into a \"d\" attribute to be passed to an SVG path\nexport const segmentToD = (samples) => {\n let d = \"\"\n\n for (let i = 0; i < samples.length; i++) {\n const { x, y } = samples[i],\n prevSample = i === 0 ? null : samples[i - 1]\n\n if (i === 0 && i !== samples.length - 1) {\n d += `M${x},${y}`\n } else if (x !== prevSample.x && y !== prevSample.y) {\n d += `L${x},${y}`\n } else if (x !== prevSample.x) {\n d += `H${x}`\n } else if (y !== prevSample.y) {\n d += `V${y}`\n }\n\n if (i === samples.length - 1) {\n d += \"Z\"\n }\n }\n\n return d\n}\n\n// An internal function for getting the colors of a segment, we need to get middle most sample (sorted by progress along the path)\nexport const getMiddleSample = (samples) => {\n const sortedSamples = [...samples].sort((a, b) => a.progress - b.progress)\n\n return sortedSamples[(sortedSamples.length / 2) | 0]\n}\n\n// An internal function for converting any D3 selection or DOM-like element into a DOM node\nexport const convertPathToNode = (path) =>\n path instanceof Element || path instanceof HTMLDocument ? path : path.node()\n", + "review": "8\n\n### Bugs\n- None found in the provided code snippet.\n\n### Optimizations\n- Use modern ES6+ features like `for...of` instead of traditional `for` loops for better readability.\n- Inline comments can be added for better clarity in complex logical parts, especially within loops.\n- Make use of `let` and `const` consistently to avoid any potential re-assignment issues by using `const` where variables are not reassigned.\n\n### Good points\n- The code is well-structured with each function performing a specific task.\n- Use of ternary operators and modern JavaScript features like destructuring and spread operators.\n- Proper usage of self-explanatory function and variable names.\n- Handles complex SVG attribute manipulations efficiently.\n\n### Summary\nThe provided code is of high quality, demonstrating good use of modern JavaScript practices and a helper library, `tinygradient`, for gradient manipulations. It is concise, making effective use of ES6+ features such as destructuring, spread/rest operators, and ternary operations for clean code. There are no apparent bugs. The code could be made slightly more readable using newer loop constructs and clarifying comments.\n\n### Open source alternatives\n- [Snap.svg](http://snapsvg.io/) is an open-source library for working with SVG.\n- [D3.js](https://d3js.org/) provides powerful capabilities for data visualization using SVG.\n- [Rapha\u00ebl](http://raphaeljs.com/) is a small JavaScript library that should simplify your work with vector graphics on the web.", + "filename": "_utils.js", + "path": "remix/app/gp/_utils.js", + "directory": "gp", + "grade": 8, + "size": 2502, + "line_count": 85 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/_utils.js.md b/.reviews/remix/app/gp/_utils.js.md new file mode 100644 index 0000000..e8401d9 --- /dev/null +++ b/.reviews/remix/app/gp/_utils.js.md @@ -0,0 +1,23 @@ +8 + +### Bugs +- None found in the provided code snippet. + +### Optimizations +- Use modern ES6+ features like `for...of` instead of traditional `for` loops for better readability. +- Inline comments can be added for better clarity in complex logical parts, especially within loops. +- Make use of `let` and `const` consistently to avoid any potential re-assignment issues by using `const` where variables are not reassigned. + +### Good points +- The code is well-structured with each function performing a specific task. +- Use of ternary operators and modern JavaScript features like destructuring and spread operators. +- Proper usage of self-explanatory function and variable names. +- Handles complex SVG attribute manipulations efficiently. + +### Summary +The provided code is of high quality, demonstrating good use of modern JavaScript practices and a helper library, `tinygradient`, for gradient manipulations. It is concise, making effective use of ES6+ features such as destructuring, spread/rest operators, and ternary operations for clean code. There are no apparent bugs. The code could be made slightly more readable using newer loop constructs and clarifying comments. + +### Open source alternatives +- [Snap.svg](http://snapsvg.io/) is an open-source library for working with SVG. +- [D3.js](https://d3js.org/) provides powerful capabilities for data visualization using SVG. +- [Raphaël](http://raphaeljs.com/) is a small JavaScript library that should simplify your work with vector graphics on the web. \ No newline at end of file diff --git a/.reviews/remix/app/gp/index.js.json b/.reviews/remix/app/gp/index.js.json new file mode 100644 index 0000000..3d5779b --- /dev/null +++ b/.reviews/remix/app/gp/index.js.json @@ -0,0 +1,11 @@ +{ + "extension": ".js", + "source": "export { default as GradientPath } from \"./GradientPath\"\nexport { getData, strokeToFill } from \"./_data\"\n", + "review": "8\n\n### Bugs\n- There are no evident bugs within this small piece of code.\n\n### Optimizations\n- Ensure that `./GradientPath` and `./_data` paths are correct and accessible to prevent any import errors.\n- Consider adding comments to explain the functionality of exported items for better maintainability.\n\n### Good points\n- Uses ES6 module export syntax effectively.\n- Exports both default and named exports which provides flexibility in usage.\n- The file structure appears to be well-organized.\n\n### Summary\nThis code snippet is clean and follows modern JavaScript practices. It exports a default module and named modules, allowing for flexible import in other parts of an application. No bugs are evident, but ensuring the proper path and including comments would enhance the maintainability of this code.\n\n### Open source alternatives\n- D3.js: A JavaScript library for manipulating documents based on data.\n- Chart.js: A simple yet flexible JavaScript charting for designers and developers.\n- Highcharts: A charting library written in pure JavaScript, although not fully open-source, it offers many open-source features.", + "filename": "index.js", + "path": "remix/app/gp/index.js", + "directory": "gp", + "grade": 8, + "size": 105, + "line_count": 3 +} \ No newline at end of file diff --git a/.reviews/remix/app/gp/index.js.md b/.reviews/remix/app/gp/index.js.md new file mode 100644 index 0000000..bd21d1a --- /dev/null +++ b/.reviews/remix/app/gp/index.js.md @@ -0,0 +1,21 @@ +8 + +### Bugs +- There are no evident bugs within this small piece of code. + +### Optimizations +- Ensure that `./GradientPath` and `./_data` paths are correct and accessible to prevent any import errors. +- Consider adding comments to explain the functionality of exported items for better maintainability. + +### Good points +- Uses ES6 module export syntax effectively. +- Exports both default and named exports which provides flexibility in usage. +- The file structure appears to be well-organized. + +### Summary +This code snippet is clean and follows modern JavaScript practices. It exports a default module and named modules, allowing for flexible import in other parts of an application. No bugs are evident, but ensuring the proper path and including comments would enhance the maintainability of this code. + +### Open source alternatives +- D3.js: A JavaScript library for manipulating documents based on data. +- Chart.js: A simple yet flexible JavaScript charting for designers and developers. +- Highcharts: A charting library written in pure JavaScript, although not fully open-source, it offers many open-source features. \ No newline at end of file diff --git a/.reviews/remix/remix.env.d.ts.json b/.reviews/remix/remix.env.d.ts.json new file mode 100644 index 0000000..7820ac2 --- /dev/null +++ b/.reviews/remix/remix.env.d.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "/// \n/// \n", + "review": "8\n\n# Bugs\n- No apparent bugs in the provided code snippet.\n\n# Optimizations\n- Consider adding more context or comments to describe the purpose of these references for better understanding by other developers.\n- Ensure that the referenced packages (`@remix-run/dev` and `@vercel/remix`) are correctly installed in the project to avoid any runtime errors.\n\n# Good points\n- Proper use of TypeScript reference directives which helps in providing better type-checking and IDE support.\n- Utilizes scoped packages, which help in organizing code and dependencies more efficiently.\n\n# Summary\nThe provided snippet is a straightforward use of TypeScript reference directives to include type definitions for Remix Run and Vercel Remix. Although minimal, it is correctly implemented within its context, assuming the relevant packages are installed and used in a larger codebase. The snippet does not exhibit any direct issues but could benefit from additional documentation or comments for clarity.\n\n# Open source alternatives\n- **Next.js**: A popular open-source React framework for building server-side rendered and static web applications, often used as an alternative to Remix.\n- **Gatsby**: Another React-based open-source framework used for building websites and apps that offer server-side rendering and static site generation.\n- **Nuxt.js**: Primarily used with Vue.js, it serves similar purposes for building modern web applications with SSR capabilities.", + "filename": "remix.env.d.ts", + "path": "remix/remix.env.d.ts", + "directory": "remix", + "grade": 8, + "size": 81, + "line_count": 3 +} \ No newline at end of file diff --git a/.reviews/remix/remix.env.d.ts.md b/.reviews/remix/remix.env.d.ts.md new file mode 100644 index 0000000..aad8120 --- /dev/null +++ b/.reviews/remix/remix.env.d.ts.md @@ -0,0 +1,20 @@ +8 + +# Bugs +- No apparent bugs in the provided code snippet. + +# Optimizations +- Consider adding more context or comments to describe the purpose of these references for better understanding by other developers. +- Ensure that the referenced packages (`@remix-run/dev` and `@vercel/remix`) are correctly installed in the project to avoid any runtime errors. + +# Good points +- Proper use of TypeScript reference directives which helps in providing better type-checking and IDE support. +- Utilizes scoped packages, which help in organizing code and dependencies more efficiently. + +# Summary +The provided snippet is a straightforward use of TypeScript reference directives to include type definitions for Remix Run and Vercel Remix. Although minimal, it is correctly implemented within its context, assuming the relevant packages are installed and used in a larger codebase. The snippet does not exhibit any direct issues but could benefit from additional documentation or comments for clarity. + +# Open source alternatives +- **Next.js**: A popular open-source React framework for building server-side rendered and static web applications, often used as an alternative to Remix. +- **Gatsby**: Another React-based open-source framework used for building websites and apps that offer server-side rendering and static site generation. +- **Nuxt.js**: Primarily used with Vue.js, it serves similar purposes for building modern web applications with SSR capabilities. \ No newline at end of file diff --git a/.reviews/remix/vite.config.ts.json b/.reviews/remix/vite.config.ts.json new file mode 100644 index 0000000..c9f1002 --- /dev/null +++ b/.reviews/remix/vite.config.ts.json @@ -0,0 +1,11 @@ +{ + "extension": ".ts", + "source": "import { vitePlugin as remix } from '@remix-run/dev';\nimport { installGlobals } from '@remix-run/node';\nimport { defineConfig } from 'vite';\nimport tsconfigPaths from 'vite-tsconfig-paths';\nimport { flatRoutes } from 'remix-flat-routes';\n\ninstallGlobals();\n\nexport default defineConfig({\n // define web socket port\n\n server: {\n port: 9999,\n hmr: {\n port: 9998\n }\n },\n plugins: [\n remix({\n routes: async (defineRoutes) => {\n return flatRoutes('routes', defineRoutes);\n },\n\n serverModuleFormat: 'cjs',\n\n // app path\n appDirectory: 'app'\n }),\n tsconfigPaths()\n ]\n // plugins: [remix(), tsconfigPaths()],\n});\n", + "review": "8\n\n### Bugs\n- No apparent bugs in the code provided. The configuration is syntactically correct and logical.\n\n### Optimizations\n- Unnecessary commented-out plugins line at the bottom, consider removing it to clean up the code.\n- Make explicit what happens inside `flatRoutes` function to ensure clarity and maintainability.\n- Consider using environment variables for defining ports for easier configuration and scalability.\n- Include comments or documentation for each main section or more complex logic situations to improve readability, especially for the async `routes` definition.\n\n### Good points\n- The code cleanly imports necessary modules at the beginning, promoting modularity and clarity.\n- Uses async/await within the routes configuration, which is a modern JavaScript feature for handling asynchronous code effectively.\n- The ports for the server are explicitly defined, making it easy to understand and change when needed.\n\n### Summary\nThe snippet presents a well-structured and modern Vite configuration for a Remix application. Using `vite-tsconfig-paths` is a good practice for easy typescript path management, and flat routing from `remix-flat-routes` is efficiently employed. However, a few improvements in clarity and maintainability could be applied, such as cleaning up the code from unnecessary comments and making use of environment variables for configuration purposes.\n\n### Open source alternatives\n- [Create Remix](https://github.com/remix-run/remix): The official Remix repository which provides comprehensive guidelines and starting points for Remix applications.\n- [Nuxt](https://nuxt.com/): Although primarily used with Vue.js, it provides a similar developer experience for building modern web applications.", + "filename": "vite.config.ts", + "path": "remix/vite.config.ts", + "directory": "remix", + "grade": 8, + "size": 666, + "line_count": 33 +} \ No newline at end of file diff --git a/.reviews/remix/vite.config.ts.md b/.reviews/remix/vite.config.ts.md new file mode 100644 index 0000000..4e64f97 --- /dev/null +++ b/.reviews/remix/vite.config.ts.md @@ -0,0 +1,22 @@ +8 + +### Bugs +- No apparent bugs in the code provided. The configuration is syntactically correct and logical. + +### Optimizations +- Unnecessary commented-out plugins line at the bottom, consider removing it to clean up the code. +- Make explicit what happens inside `flatRoutes` function to ensure clarity and maintainability. +- Consider using environment variables for defining ports for easier configuration and scalability. +- Include comments or documentation for each main section or more complex logic situations to improve readability, especially for the async `routes` definition. + +### Good points +- The code cleanly imports necessary modules at the beginning, promoting modularity and clarity. +- Uses async/await within the routes configuration, which is a modern JavaScript feature for handling asynchronous code effectively. +- The ports for the server are explicitly defined, making it easy to understand and change when needed. + +### Summary +The snippet presents a well-structured and modern Vite configuration for a Remix application. Using `vite-tsconfig-paths` is a good practice for easy typescript path management, and flat routing from `remix-flat-routes` is efficiently employed. However, a few improvements in clarity and maintainability could be applied, such as cleaning up the code from unnecessary comments and making use of environment variables for configuration purposes. + +### Open source alternatives +- [Create Remix](https://github.com/remix-run/remix): The official Remix repository which provides comprehensive guidelines and starting points for Remix applications. +- [Nuxt](https://nuxt.com/): Although primarily used with Vue.js, it provides a similar developer experience for building modern web applications. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index a44aa25..0000000 --- a/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 🌈 Welcome 👋 to Thingtime 🦄 🧠 -https://thingtime.com - -Thingtime is a powerful platform for storing and sharing information of all kinds. Whether you want to keep track of your personal notes, collaborate on a project with your team, or build a new app that relies on rich data, Thingtime has you covered. - -With Thingtime, you can create and share any abstract data structure you want, or store any practical piece of information and share it for people and machines to use equally. Thingtime is not only a platform, but also an ecosystem that empowers developers and users alike to build, share, and utilize all kinds of data and knowledge. - -At Thingtime, we believe that data and knowledge should be open, accessible, and empowering. We are building Thingtime to make this vision a reality. Join us and start exploring the limitless possibilities of data! - -# 💹 Donate on Indiegogo to save humanity 🩷 -### You can get Merch 🌈 + other benefits 🦄💯 -https://www.indiegogo.com/projects/thingtime-a-gui-for-the-internet/coming_soon - -## Or Donate on GoFundMe 💖 -https://www.gofundme.com/f/thingtime - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index a8ff2b7..0000000 --- a/package-lock.json +++ /dev/null @@ -1,716 +0,0 @@ -{ - "name": "thingtime", - "version": "0.0.11", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "thingtime", - "version": "0.0.11", - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "smarts": "2.0.0", - "typescript": "^4.9.5" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", - "dependencies": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/polyfill": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", - "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", - "deprecated": "🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information.", - "dependencies": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@babel/polyfill/node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true - }, - "node_modules/@babel/standalone": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.24.10.tgz", - "integrity": "sha512-nGC37EKfmelpyCXto1pw6SBkD5ZQRdMbL6WISi28xWit9dtiy9dChU1WgEfzturUTxrmOGkMDRrCydFMA7uOaQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/core-js": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", - "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deepmerge": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", - "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.0.tgz", - "integrity": "sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==" - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-mergeable-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz", - "integrity": "sha512-CPduJfuGg8h8vW74WOxHtHmtQutyQBzR+3MjQ6iDHIYdbOnm1YC7jv43SqCoU8OPGTJD4nibmiryA4kmogbGrA==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/smarts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/smarts/-/smarts-2.0.0.tgz", - "integrity": "sha512-E+d1Jx7KgmM26Z0vh85bN3RttS4qvrB0Me0unwPnlbP0PfWpvRhkMCSsGBObRqat16TfzRH+IW2rxIsphTreDQ==", - "dependencies": { - "@babel/core": "^7.14.8", - "@babel/generator": "^7.8.4", - "@babel/parser": "^7.22.5", - "@babel/polyfill": "^7.4.4", - "@babel/standalone": "^7.14.8", - "@babel/template": "^7.14.8", - "@babel/types": "^7.15.0", - "core-js": "^3.6.4", - "deepmerge": "^3.2.0", - "is-mergeable-object": "^1.1.1", - "prettier": "^2.3.2", - "uuid": "^3.4.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index a4e1485..0000000 --- a/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "thingtime", - "version": "0.0.11", - "description": "Thing Time", - "main": "none", - "scripts": { - "app": "npm run remix", - "remix": "npm run dev --prefix remix", - "build-remix": "npm run build --prefix remix", - "next": "npm run dev --prefix next", - "api": "npm run dev --prefix api", - "postinstall": "pnpm i --prefix next ; pnpm i --prefix=api" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/lopugit/thingtime.git" - }, - "author": "lopu", - "license": "ISC", - "bugs": { - "url": "https://github.com/lopugit/thingtime/issues" - }, - "homepage": "https://github.com/lopugit/thingtime#readme", - "dependencies": { - "smarts": "2.0.0", - "typescript": "^4.9.5" - } -} diff --git a/vercel.json b/vercel.json deleted file mode 100644 index e69de29..0000000