diff --git a/package.json b/package.json index 5765ee8394..1b6c15597b 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "@playwright/test": "catalog:cli", "@types/markdown-it": "catalog:types", "@types/node": "catalog:types", - "@types/semver": "catalog:types", "@types/which": "catalog:types", "@types/ws": "catalog:types", "@unocss/eslint-config": "catalog:buildtools", diff --git a/packages/devtools/client/composables/npm.ts b/packages/devtools/client/composables/npm.ts index 3735d1e525..6e3615a37e 100644 --- a/packages/devtools/client/composables/npm.ts +++ b/packages/devtools/client/composables/npm.ts @@ -1,5 +1,5 @@ import type { NpmCommandOptions } from '../../src/types' -import semver from 'semver' +import { satisfies } from 'verkit' import { computed, ref } from 'vue' import { useNuxtApp } from '#app/nuxt' import { rpc } from './rpc' @@ -25,7 +25,7 @@ export function satisfyNuxtVersion(range: string) { return computed(() => { if (!nuxt?.value?.current) return false - return semver.satisfies(nuxt.value.current, range) + return satisfies(nuxt.value.current, range) }) } diff --git a/packages/devtools/package.json b/packages/devtools/package.json index ef1f86c462..0d29c427e5 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -69,12 +69,12 @@ "pathe": "catalog:frontend", "perfect-debounce": "catalog:frontend", "pkg-types": "catalog:prod", - "semver": "catalog:prod", "sirv": "catalog:prod", "structured-clone-es": "catalog:frontend", "tinyexec": "catalog:prod", "tinyglobby": "catalog:prod", "unstorage": "catalog:prod", + "verkit": "catalog:prod", "vite-plugin-inspect": "catalog:prod", "vite-plugin-vue-tracer": "catalog:prod", "which": "catalog:prod", diff --git a/packages/devtools/src/integrations/timeline.ts b/packages/devtools/src/integrations/timeline.ts index fe07f00aa3..0cd2ef19c0 100644 --- a/packages/devtools/src/integrations/timeline.ts +++ b/packages/devtools/src/integrations/timeline.ts @@ -1,7 +1,7 @@ import type { Import } from 'unimport' import type { NuxtDevtoolsServerContext } from '../types' import { resolve } from 'pathe' -import semver from 'semver' +import { isGreaterOrEqual } from 'verkit' import { runtimeDir } from '../dirs' const DEFINE_UPPER_RE = /^define[A-Z]/ @@ -37,7 +37,7 @@ export function setup({ nuxt, options }: NuxtDevtoolsServerContext) { nuxt.hook('imports:context', (unimport) => { const ctx = unimport.getInternalContext() - if (!ctx.version || !semver.gte(ctx.version, '3.1.0')) + if (!ctx.version || !isGreaterOrEqual(ctx.version, '3.1.0')) throw new Error(`[Nuxt DevTools] The timeline feature requires \`unimport\` >= v3.1.0, but got \`${ctx.version || '(unknown)'}\`. Please upgrade using \`nuxi upgrade --force\`.`) ctx.addons.push( diff --git a/packages/devtools/src/npm/index.ts b/packages/devtools/src/npm/index.ts index e4a8c9cde9..9e3f789b2c 100644 --- a/packages/devtools/src/npm/index.ts +++ b/packages/devtools/src/npm/index.ts @@ -4,7 +4,7 @@ import { logger, useNuxt } from '@nuxt/kit' import { getPackageInfo } from 'local-pkg' import { fetch } from 'ofetch' import { readPackageJSON } from 'pkg-types' -import semver from 'semver' +import { isLess } from 'verkit' export async function getMainPackageJSON(nuxt = useNuxt()) { return readPackageJSON(nuxt.options.rootDir) @@ -32,7 +32,7 @@ export async function checkForUpdateOf(name: string, current?: string, nuxt = us fetch, }) - const needsUpdate = !!latest && latest !== current && semver.lt(current, latest) + const needsUpdate = !!latest && latest !== current && isLess(current, latest) return { name, diff --git a/packages/devtools/test/version-comparison.test.ts b/packages/devtools/test/version-comparison.test.ts new file mode 100644 index 0000000000..f4802341da --- /dev/null +++ b/packages/devtools/test/version-comparison.test.ts @@ -0,0 +1,26 @@ +import { isGreaterOrEqual, isLess, satisfies } from 'verkit' +import { describe, expect, it } from 'vitest' + +describe('version comparisons', () => { + it('checks the minimum supported unimport version', () => { + expect(isGreaterOrEqual('3.1.0', '3.1.0')).toBe(true) + expect(isGreaterOrEqual('3.0.9', '3.1.0')).toBe(false) + }) + + it('detects stable and prerelease package updates', () => { + expect(isLess('4.0.0', '4.0.1')).toBe(true) + expect(isLess('4.0.0-alpha.1', '4.0.0')).toBe(true) + expect(isLess('4.0.1', '4.0.0')).toBe(false) + }) + + it('preserves default prerelease range behavior', () => { + expect(satisfies('4.0.0-alpha.7', '^4.0.0-alpha.1')).toBe(true) + expect(satisfies('4.0.0-alpha.7', '^4.0.0')).toBe(false) + }) + + it('rejects invalid comparison inputs', () => { + expect(() => isLess('invalid', '4.0.0')).toThrow(TypeError) + expect(() => isGreaterOrEqual('invalid', '3.1.0')).toThrow(TypeError) + expect(satisfies('invalid', '^4.0.0')).toBe(false) + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6ae2b6233..16ea452022 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -336,6 +336,9 @@ catalogs: unstorage: specifier: ^1.17.5 version: 1.17.5 + verkit: + specifier: ^0.1.2 + version: 0.1.2 vite-plugin-inspect: specifier: ^12.0.2 version: 12.0.2 @@ -361,9 +364,6 @@ catalogs: '@types/node': specifier: ^26.1.1 version: 26.1.1 - '@types/semver': - specifier: ^7.7.1 - version: 7.7.1 '@types/which': specifier: ^3.0.4 version: 3.0.4 @@ -425,9 +425,6 @@ importers: '@types/node': specifier: catalog:types version: 26.1.1 - '@types/semver': - specifier: catalog:types - version: 7.7.1 '@types/which': specifier: catalog:types version: 3.0.4 @@ -575,9 +572,6 @@ importers: pkg-types: specifier: catalog:prod version: 2.3.1 - semver: - specifier: ^7.8.5 - version: 7.8.5 sirv: specifier: catalog:prod version: 3.0.2 @@ -593,6 +587,9 @@ importers: unstorage: specifier: catalog:prod version: 1.17.5(db0@0.3.4)(ioredis@5.11.1) + verkit: + specifier: catalog:prod + version: 0.1.2 vite: specifier: ~8.0.14 version: 8.0.16(@types/node@26.1.1)(@vitejs/devtools@0.4.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) @@ -3317,9 +3314,6 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/semver@7.7.1': - resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/sinonjs__fake-timers@8.1.1': resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} @@ -8269,6 +8263,10 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + verkit@0.1.2: + resolution: {integrity: sha512-WqkT8n3hqizuCu71W3bUzf5fjBmkbXcudsehe/NbxA8PgqoKnSOY5K0Ba2ckg1qaRaSpSz7as/n9K1R9JXjQKg==} + engines: {node: '>=18.12.0'} + verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} engines: {'0': node >=0.6.0} @@ -11180,8 +11178,6 @@ snapshots: '@types/resolve@1.20.2': {} - '@types/semver@7.7.1': {} - '@types/sinonjs__fake-timers@8.1.1': {} '@types/sizzle@2.3.10': {} @@ -17769,6 +17765,8 @@ snapshots: vary@1.1.2: {} + verkit@0.1.2: {} + verror@1.10.0: dependencies: assert-plus: 1.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7b88ab50af..03bc1b38bc 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,6 +8,7 @@ minimumReleaseAgeExclude: - vite-plugin-inspect@12.0.2 - '@devframes/hub@0.6.1' - devframe@0.6.1 + - verkit@0.1.2 resolutionMode: highest shamefullyHoist: true shellEmulator: true @@ -172,11 +173,11 @@ catalogs: magicast: ^0.5.3 nostics: ^1.1.4 pkg-types: ^2.3.1 - semver: ^7.8.5 sirv: ^3.0.2 tinyexec: ^1.2.4 tinyglobby: ^0.2.17 unstorage: ^1.17.5 + verkit: ^0.1.2 vite-plugin-inspect: ^12.0.2 vite-plugin-vue-tracer: ^1.4.0 which: ^7.0.0 @@ -186,7 +187,6 @@ catalogs: '@types/markdown-it': ^14.1.2 '@types/markdown-it-link-attributes': ^3.0.5 '@types/node': ^26.1.1 - '@types/semver': ^7.7.1 '@types/which': ^3.0.4 '@types/ws': ^8.18.1 '@unhead/schema': ^3.1.8