diff --git a/extensions/npm/package-lock.json b/extensions/npm/package-lock.json index 7ea1f29c..671903b7 100644 --- a/extensions/npm/package-lock.json +++ b/extensions/npm/package-lock.json @@ -7,9 +7,9 @@ "name": "npm", "license": "MIT", "dependencies": { - "@raycast/utils": "^2.2.3", + "@raycast/utils": "^2.2.4", "@uidotdev/usehooks": "^2.4.1", - "@vicinae/api": "^0.20.9", + "@vicinae/api": "^0.20.15", "find-up": "^8.0.0", "package-manager-detector": "^1.6.0", "semver": "^7.7.4" @@ -17,7 +17,7 @@ "devDependencies": { "@biomejs/biome": "^2.4.8", "@types/semver": "^7.7.1", - "typescript": "^5.9.3" + "typescript": "^6.0.3" } }, "node_modules/@biomejs/biome": { @@ -1626,9 +1626,9 @@ "peer": true }, "node_modules/@raycast/utils": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@raycast/utils/-/utils-2.2.3.tgz", - "integrity": "sha512-YwqleVl0Wk/FOq+672gtvswuwMqjNqIr+c63FhouTEHc1LJ3zaohLSkW4+UcfBjPU8HySKQm+kJqZW1iOM9fnA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@raycast/utils/-/utils-2.2.4.tgz", + "integrity": "sha512-XkxW5bUZACxl2zP4M6Qtkj9a1nbOKcRBm96BLkJ6O4Q7L/vFSnc+3pPJ/i0ZLVOExx5LJMJY0jnNPo91xqJnFQ==", "license": "MIT", "dependencies": { "dequal": "^2.0.3" @@ -1648,7 +1648,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1683,9 +1682,9 @@ } }, "node_modules/@vicinae/api": { - "version": "0.20.9", - "resolved": "https://registry.npmjs.org/@vicinae/api/-/api-0.20.9.tgz", - "integrity": "sha512-ujRtyJdKxYc/c68LygQUc2qCHH2Cef6HXWGvBQhJTYrxhMi6oCXyKHBxUApgMrOHD8X+YbCu6GSjVkKiLQOrHA==", + "version": "0.20.15", + "resolved": "https://registry.npmjs.org/@vicinae/api/-/api-0.20.15.tgz", + "integrity": "sha512-7FAUgdQJ+D8krDfiAfXmxKMtqo3a/oLxC4F6IA14WSCc6Wh1NWqwNyBvmPJxxrpuNg1/eQcPfHaWqm1rZCzCMA==", "license": "ISC", "dependencies": { "@jgoz/esbuild-plugin-typecheck": "^4.0.3", @@ -4978,9 +4977,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 230d853c..a09594a6 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -3,7 +3,9 @@ "name": "npm", "title": "NPM", "description": "An extenstion to manage npm packages", - "categories": ["Developer Tools"], + "categories": [ + "Developer Tools" + ], "license": "MIT", "author": "FredrikMWold", "contributors": [], @@ -91,9 +93,9 @@ "lint": "vici lint" }, "dependencies": { - "@raycast/utils": "^2.2.3", + "@raycast/utils": "^2.2.4", "@uidotdev/usehooks": "^2.4.1", - "@vicinae/api": "^0.20.9", + "@vicinae/api": "^0.20.15", "find-up": "^8.0.0", "package-manager-detector": "^1.6.0", "semver": "^7.7.4" @@ -101,6 +103,6 @@ "devDependencies": { "@biomejs/biome": "^2.4.8", "@types/semver": "^7.7.1", - "typescript": "^5.9.3" + "typescript": "^6.0.3" } } diff --git a/extensions/npm/src/hooks/useGetVersionUpdate.ts b/extensions/npm/src/hooks/useGetVersionUpdate.ts index eb98d4e3..4921abfd 100644 --- a/extensions/npm/src/hooks/useGetVersionUpdate.ts +++ b/extensions/npm/src/hooks/useGetVersionUpdate.ts @@ -1,40 +1,34 @@ -import { useFetch } from "@raycast/utils"; -import semver from "semver"; +import { usePromise } from "@raycast/utils"; +import { useRef } from "react"; import type { Package } from "../types"; -export const useGetVersionUpdate = (npmPackage: Package) => { - const encodedName = encodeURIComponent(npmPackage.name); - - const { data, isLoading } = useFetch( - `https://registry.npmjs.com/${encodedName}`, - { - parseResponse: async (response) => { - const data = (await response.json()) as Response; - const latestVersion = data["dist-tags"].latest; - const latestSemver = semver.coerce(latestVersion); - const currentSemver = semver.coerce(npmPackage.version); - const hasUpdate = - latestSemver !== null && - currentSemver !== null && - semver.gt(latestSemver, currentSemver); +export const useGetVersionUpdate = (npmPackage: Package[]) => { + const abortable = useRef(null); + const { data = [], isLoading } = usePromise( + async () => { + const responses = npmPackage.map(async (pkg) => { + const res = await fetch(`https://registry.npmjs.org/${pkg.name}`, { + signal: abortable.current?.signal, + }); + const json = (await res.json()) as Response; + const latestVersion = json["dist-tags"].latest; return { - hasUpdate, - versionData: { - name: npmPackage.name, - version: npmPackage.version, - hasUpdate, - newVersion: latestVersion, - }, + name: pkg.name, + newVersion: latestVersion, } as const; - }, + }); + return Promise.all(responses); + }, + [], + { + abortable, }, ); - if (data) return data; - return { hasUpdate: false, isLoading, versionData: undefined }; + return { data, isLoading }; }; -type Response = { +export type Response = { name: string; "dist-tags": { latest: string; diff --git a/extensions/npm/src/hooks/useUpdatePackages.ts b/extensions/npm/src/hooks/useUpdatePackages.ts index ba5d0576..eac27a64 100644 --- a/extensions/npm/src/hooks/useUpdatePackages.ts +++ b/extensions/npm/src/hooks/useUpdatePackages.ts @@ -1,10 +1,12 @@ -import { Cache, showToast, Toast } from "@vicinae/api"; +import { showToast, Toast } from "@vicinae/api"; import { execSync } from "child_process"; import { useState } from "react"; -import type { PackageManager } from "../utils/getPackageManager"; import type { Package } from "../types"; -import { usePackageManger } from "./usePackageManger"; import { getInstalledPackages } from "../utils/getPackageJson"; +import type { PackageManager } from "../utils/getPackageManager"; +import { usePackageManger } from "./usePackageManger"; +import { useGetVersionUpdate } from "./useGetVersionUpdate"; +import { hasUpdate } from "../utils/hasUpdate"; export const useUpdatePackages = (path?: string) => { const [selectedDependencies, setSelectedDependencies] = useState( @@ -15,10 +17,25 @@ export const useUpdatePackages = (path?: string) => { >([]); const [error, setError] = useState(""); const { packageManager } = usePackageManger(path); - const [packages, setPackages] = useState(() => + const [installedPackages, setInstalledPackages] = useState(() => getInstalledPackages(packageManager, path), ); + const { data: versionUpdates, isLoading } = + useGetVersionUpdate(installedPackages); + + const packages = installedPackages + .map((pkg) => { + const newVersionData = versionUpdates.find( + (update) => update.name === pkg.name, + ); + return { + ...pkg, + newVersion: newVersionData?.newVersion || "", + }; + }) + .filter(hasUpdate); + const npmCommand = buildUpdateCommand( packageManager, selectedDependencies, @@ -50,7 +67,7 @@ export const useUpdatePackages = (path?: string) => { title: `Successfully updated packages`, style: Toast.Style.Success, }); - setPackages(getInstalledPackages(packageManager, path)); + setInstalledPackages(getInstalledPackages(packageManager, path)); setSelectedDependencies([]); setSelectedDevDependencies([]); }; @@ -81,6 +98,7 @@ export const useUpdatePackages = (path?: string) => { onSelectDevDependency, clearError, npmCommand, + isLoading, }; }; diff --git a/extensions/npm/src/npm-update-global.tsx b/extensions/npm/src/npm-update-global.tsx index dd135fe1..0eceb152 100644 --- a/extensions/npm/src/npm-update-global.tsx +++ b/extensions/npm/src/npm-update-global.tsx @@ -7,6 +7,7 @@ import type { Package } from "./types"; export default function NpmUpdateGlobal() { const { + isLoading, packages, updatePackages, selectedDependencies, @@ -20,7 +21,7 @@ export default function NpmUpdateGlobal() { return ; } return ( - + {packages .filter((pkg) => !pkg.dev) @@ -52,8 +53,6 @@ const DependencyListItem = ({ onSelect: (dependency: string) => void; npmCommand: string; }) => { - const { hasUpdate, versionData } = useGetVersionUpdate(pkg); - if (!hasUpdate) return; return ( ; } return ( - + {packages .filter((pkg) => !pkg.dev) @@ -76,8 +78,6 @@ const DependencyListItem = ({ onSelect: (dependency: string) => void; npmCommand: string; }) => { - const { hasUpdate, versionData } = useGetVersionUpdate(pkg); - if (!hasUpdate) return; return ( { + const latestSemver = semver.coerce(pkg.newVersion); + const currentSemver = semver.coerce(pkg.version); + return ( + latestSemver !== null && + currentSemver !== null && + semver.gt(latestSemver, currentSemver) + ); +};