Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/node-modules-inspector/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default defineBuildConfig({
rollup: {
inlineDependencies: [
'@antfu/utils',
'semver',
],
},
})
5 changes: 2 additions & 3 deletions packages/node-modules-inspector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@
"tinyglobby": "catalog:deps",
"unconfig": "catalog:deps",
"unstorage": "catalog:deps",
"valibot": "catalog:deps"
"valibot": "catalog:deps",
"verkit": "catalog:deps"
},
"devDependencies": {
"@types/semver": "catalog:types",
"@unocss/nuxt": "catalog:bundling",
"@valibot/to-json-schema": "catalog:testing",
"@vueuse/nuxt": "catalog:bundling",
Expand All @@ -76,7 +76,6 @@
"modern-screenshot": "catalog:frontend",
"nanovis": "catalog:frontend",
"rollup": "catalog:bundling",
"semver": "catalog:deps",
"theme-vitesse": "catalog:frontend",
"vite-hot-client": "catalog:frontend"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { NpmMetaLatest } from 'node-modules-tools'
import { Tooltip } from 'floating-vue'
import semver from 'semver'
import { difference, isGreater } from 'verkit'
import { computed } from 'vue'

const props = withDefaults(defineProps<{
Expand All @@ -15,13 +15,13 @@ const props = withDefaults(defineProps<{
const versionDiff = computed(() => {
if (!props.latest || !props.version)
return ''
return semver.diff(props.latest.version, props.version)
return difference(props.latest.version, props.version)
})

const updateAvailable = computed(() => {
if (!props.latest || !props.version)
return false
return semver.gt(props.latest.version, props.version)
return isGreater(props.latest.version, props.version)
})
</script>

Expand Down
4 changes: 2 additions & 2 deletions packages/node-modules-inspector/src/app/utils/prompts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { PackageNode } from 'node-modules-tools'
import type { DepUpgradeAction, MaintainerActionItem, PublintAction } from '../state/maintainer-actions'
import { formatMessage } from 'publint/utils'
import semver from 'semver'
import { getMajor } from 'verkit'
import { parseSemverRange } from './semver'

function safeMajor(version: string | undefined): number | undefined {
if (!version)
return undefined
try {
return semver.major(version)
return getMajor(version)
}
catch {
return undefined
Expand Down
37 changes: 37 additions & 0 deletions packages/node-modules-inspector/src/app/utils/semver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest'
import { compareSemverRange, parseSemverRange } from './semver'

describe('parseSemverRange', () => {
it('parses unions and partial versions', () => {
expect(parseSemverRange('^20.19 || ^22.12 || >=24')).toEqual({
valid: true,
raw: '^20.19 || ^22.12 || >=24',
highest: '24.0.0',
lowest: '20.19.0',
parts: ['^20.19', '^22.12', '>=24'],
bare: ['20.19.0', '22.12.0', '24.0.0'],
})
})

it('preserves prerelease versions', () => {
expect(parseSemverRange('^1.0.0-beta.1')).toMatchObject({
valid: true,
highest: '1.0.0-beta.1',
lowest: '1.0.0-beta.1',
})
})

it('rejects invalid ranges', () => {
expect(parseSemverRange('not a range')).toEqual({
valid: false,
raw: 'not a range',
})
})
})

describe('compareSemverRange', () => {
it('orders ranges by their lowest version', () => {
expect(compareSemverRange('^1.0.0', '^2.0.0')).toBe(1)
expect(compareSemverRange('^2.0.0', '^1.0.0')).toBe(-1)
})
})
6 changes: 3 additions & 3 deletions packages/node-modules-inspector/src/app/utils/semver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import semver from 'semver'
import { isValid, isValidRange } from 'verkit'
import { compareSemver } from '../../shared/semver'

export { compareSemver }
Expand All @@ -24,7 +24,7 @@ export function parseSemverRange(range: string) {
}
SemverParseCache.set(range, result)

if (!semver.validRange(range)) {
if (!isValidRange(range)) {
return result
}

Expand All @@ -46,7 +46,7 @@ export function parseSemverRange(range: string) {

const highest = partsBare.at(-1)!
const lowest = partsBare.at(0)!
if (!semver.valid(highest) || !semver.valid(lowest)) {
if (!isValid(highest) || !isValid(lowest)) {
return result
}

Expand Down
2 changes: 1 addition & 1 deletion packages/node-modules-inspector/src/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default defineNuxtConfig({
'modern-screenshot',
'floating-vue',
'@antfu/utils',
'semver',
'verkit',
'devframe/client',
'publint/utils',
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,37 @@ describe('computeMaintainerActions', () => {
expect(items).toEqual([])
})

it('ignores prerelease versions when finding the highest installed version', () => {
const stable = pkg({ name: 'dep', version: '1.5.0' })
const prerelease = pkg({ name: 'dep', version: '2.0.0-beta.1' })
const consumer = pkg({
name: 'consumer',
version: '1.0.0',
dependencies: { dep: '^1.0.0' },
})
const all = [consumer, stable, prerelease]
const items = computeMaintainerActions({
packages: all,
versions: buildVersions(all),
})
expect(items).toEqual([])
})

it('ignores invalid semver ranges', () => {
const dep = pkg({ name: 'dep', version: '2.0.0' })
const consumer = pkg({
name: 'consumer',
version: '1.0.0',
dependencies: { dep: 'not a range' },
})
const all = [consumer, dep]
const items = computeMaintainerActions({
packages: all,
versions: buildVersions(all),
})
expect(items).toEqual([])
})

it('resolves catalog: ranges', () => {
const dep1 = pkg({ name: 'dep', version: '1.0.0' })
const dep2 = pkg({ name: 'dep', version: '2.0.0' })
Expand Down Expand Up @@ -167,4 +198,27 @@ describe('groupMaintainerActions', () => {
expect(groups).toHaveLength(1)
expect(groups[0]!.consumer.version).toBe('2.0.0')
})

it('filters consumers to the latest major version', () => {
const dep = pkg({ name: 'dep', version: '2.0.0' })
const consumer = pkg({
name: 'consumer',
version: '2.1.0',
dependencies: { dep: '^1.0.0' },
})
const all = [consumer, dep]
const items = computeMaintainerActions({
packages: all,
versions: buildVersions(all),
})

expect(groupMaintainerActions(items, {
latestOnly: true,
latestVersionOf: () => '2.5.0',
})).toHaveLength(1)
expect(groupMaintainerActions(items, {
latestOnly: true,
latestVersionOf: () => '3.0.0',
})).toEqual([])
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PackageNode, PublintMessage } from 'node-modules-tools'
import type { ParsedAuthor } from 'node-modules-tools/utils'
import semver from 'semver'
import { getMajor, getPrerelease, isGreaterThanRange, satisfies } from 'verkit'
import { compareSemver } from '../semver'

export function authorKey(author: ParsedAuthor): string {
Expand Down Expand Up @@ -86,7 +86,7 @@ function isPlainSemverRange(range: string | undefined): range is string {

function safeSatisfies(version: string, range: string) {
try {
return semver.satisfies(version, range)
return satisfies(version, range)
}
catch {
return null
Expand All @@ -95,15 +95,15 @@ function safeSatisfies(version: string, range: string) {

function safeGtr(version: string, range: string) {
try {
return semver.gtr(version, range)
return isGreaterThanRange(version, range)
}
catch {
return null
}
}

function isStable(version: string) {
return semver.prerelease(version) === null
return getPrerelease(version) === null
}

function getPublintMessagesFor(
Expand Down Expand Up @@ -337,7 +337,7 @@ export function groupMaintainerActions(
if (!latest)
return true
try {
return semver.major(g.consumer.version) === semver.major(latest)
return getMajor(g.consumer.version) === getMajor(latest)
}
catch {
return true
Expand Down
17 changes: 17 additions & 0 deletions packages/node-modules-inspector/src/shared/semver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, it, vi } from 'vitest'
import { compareSemver } from './semver'

describe('compareSemver', () => {
it('compares stable and prerelease versions', () => {
expect(compareSemver('1.0.0', '2.0.0')).toBe(-1)
expect(compareSemver('1.0.0', '1.0.0-beta.1')).toBe(1)
expect(compareSemver('1.0.0-beta.2', '1.0.0-beta.1')).toBe(1)
})

it('falls back for invalid versions', () => {
const error = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(compareSemver('invalid', '1.0.0')).toBe(0)
expect(error).toHaveBeenCalledOnce()
error.mockRestore()
})
})
4 changes: 2 additions & 2 deletions packages/node-modules-inspector/src/shared/semver.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import semver from 'semver'
import { compare } from 'verkit'

export function compareSemver(a: string, b: string): number {
if (a === b)
return 0
try {
return semver.compare(a, b)
return compare(a, b)
}
catch (e) {
console.error('Failed to compare semver ', e)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AuditLevelString, NpmMeta } from 'node-modules-tools'
import type { ListPackagesNpmMetaOptions } from './types'
import pLimit from 'p-limit'
import { satisfies } from 'semver'
import { satisfies } from 'verkit'

interface AuditReport {
id: string
Expand Down
4 changes: 2 additions & 2 deletions packages/node-modules-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"pathe": "catalog:deps",
"pkg-types": "catalog:types",
"publint": "catalog:deps",
"semver": "catalog:deps",
"tinyexec": "catalog:deps"
"tinyexec": "catalog:deps",
"verkit": "catalog:deps"
},
"devDependencies": {
"@pnpm/list": "catalog:types",
Expand Down
2 changes: 2 additions & 0 deletions packages/node-modules-tools/src/utils/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ describe('constructPackageFilter', () => {
const filter = constructPackageFilter('foo@^1.0.0')
expect(filter({ name: 'foo', version: '1.0.0' })).toBe(true)
expect(filter({ name: 'foo', version: '1.1.0' })).toBe(true)
expect(filter({ name: 'foo', version: '1.1.0-beta.1' })).toBe(false)
expect(filter({ name: 'foo', version: '2.0.0' })).toBe(false)
expect(filter({ name: 'foo', version: 'invalid' })).toBe(false)
})

it('prefix', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/node-modules-tools/src/utils/filter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { satisfies } from 'semver'
import { satisfies } from 'verkit'

export interface PackageNodeLike {
name: string
Expand Down
Loading
Loading