From 483ac6fc0c931460322c6e2a9e64f45ca332fcb0 Mon Sep 17 00:00:00 2001 From: a1mer Date: Thu, 23 Nov 2023 19:10:25 +0800 Subject: [PATCH] feat: more sensible counter and version color (#86) Co-authored-by: Anthony Fu --- src/commands/check/render.ts | 4 +++- src/io/resolves.ts | 28 ++++++++++++++++++++++++++-- src/render.ts | 13 +++++-------- src/types.ts | 3 +-- src/utils/diff.ts | 17 ++++++++++------- test/resolves.test.ts | 25 +++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/commands/check/render.ts b/src/commands/check/render.ts index 0aef5ef..a262797 100644 --- a/src/commands/check/render.ts +++ b/src/commands/check/render.ts @@ -2,6 +2,7 @@ import c from 'picocolors' import semver from 'semver' import type { CheckOptions, + DiffType, InteractiveContext, PackageMeta, ResolvedDepChange, @@ -10,6 +11,7 @@ import { DependenciesTypeShortMap } from '../../types' import { sortDepChanges } from '../../utils/sort' import { timeDifference } from '../../utils/time' import { FIG_CHECK, FIG_NO_POINTER, FIG_POINTER, FIG_UNCHECK, colorizeVersionDiff, formatTable } from '../../render' +import { DiffColorMap } from '../../utils/diff' export function renderChange(change: ResolvedDepChange, interactive?: InteractiveContext) { const update = change.update && (!interactive || change.interactiveChecked) @@ -73,7 +75,7 @@ export function renderChanges( }) const diffEntries = Object.keys(diffCounts).length ? Object.entries(diffCounts) - .map(([key, value]) => `${c.yellow(value)} ${key}`) + .map(([key, value]) => `${c[DiffColorMap[key as DiffType || 'patch']](value)} ${key}`) .join(', ') : c.dim('no change') diff --git a/src/io/resolves.ts b/src/io/resolves.ts index 09ca697..1faaff7 100644 --- a/src/io/resolves.ts +++ b/src/io/resolves.ts @@ -5,7 +5,7 @@ import pacote from 'pacote' import semver from 'semver' import _debug from 'debug' import { getNpmConfig } from '../utils/npm' -import type { CheckOptions, DependencyFilter, DependencyResolvedCallback, PackageData, PackageMeta, RangeMode, RawDep, ResolvedDepChange } from '../types' +import type { CheckOptions, DependencyFilter, DependencyResolvedCallback, DiffType, PackageData, PackageMeta, RangeMode, RawDep, ResolvedDepChange } from '../types' import { diffSorter } from '../filters/diff-sorter' import { getMaxSatisfying, getPrefixedVersion } from '../utils/versions' import { getPackageMode } from '../utils/config' @@ -136,7 +136,7 @@ export function updateTargetVersion( const target = semver.minVersion(dep.targetVersion)! dep.currentVersionTime = dep.pkgData.time?.[current.toString()] - dep.diff = semver.diff(current, target) + dep.diff = getDiff(current, target) dep.update = dep.diff !== null && semver.lt(current, target) } catch (e) { @@ -148,6 +148,30 @@ export function updateTargetVersion( } } +export function getDiff(current: semver.SemVer, target: semver.SemVer): DiffType { + if (semver.eq(current, target)) + return null + + const tilde = semver.satisfies(target, `~${current}`, { includePrerelease: true }) + const caret = semver.satisfies(target, `^${current}`, { includePrerelease: true }) + const gte = semver.satisfies(target, `>=${current}`, { includePrerelease: true }) + + if (tilde) { + if (caret) + return 'patch' + else + return 'major' + } + else if (caret) { + return 'minor' + } + else if (gte) { + return 'major' + } + + return 'error' +} + export async function resolveDependency( raw: RawDep, options: CheckOptions, diff --git a/src/render.ts b/src/render.ts index 23fef47..3a0d65b 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,4 +1,7 @@ import c from 'picocolors' +import { SemVer } from 'semver' +import { getDiff } from './io/resolves' +import { DiffColorMap } from './utils/diff' export const FIG_CHECK = c.green('◉') export const FIG_UNCHECK = c.gray('◌') @@ -92,14 +95,8 @@ export function colorizeVersionDiff(from: string, to: string, hightlightRange = let i = partsToColor.findIndex((part, i) => part !== partsToCompare[i]) i = i >= 0 ? i : partsToColor.length - // major = red (or any change before 1.0.0) - // minor = cyan - // patch = green - const color = (i === 0 || partsToColor[0] === '0') - ? 'red' - : i === 1 - ? 'cyan' - : 'green' + const diffType = getDiff(new SemVer(from), new SemVer(to)) + const color = DiffColorMap[diffType || 'patch'] // if we are colorizing only part of the word, add a dot in the middle const middot = (i > 0 && i < partsToColor.length) ? '.' : '' diff --git a/src/types.ts b/src/types.ts index 301a1aa..c5ef359 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,4 @@ import type { Packument } from 'pacote' -import type semver from 'semver' import type { SortOption } from './utils/sort' export type RangeMode = 'default' | 'major' | 'minor' | 'patch' | 'latest' | 'newest' @@ -20,7 +19,7 @@ export interface RawDep { update: boolean } -export type DiffType = ReturnType | 'error' +export type DiffType = 'major' | 'minor' | 'patch' | 'error' | null export interface PackageData { tags: Record diff --git a/src/utils/diff.ts b/src/utils/diff.ts index 9422625..1360da8 100644 --- a/src/utils/diff.ts +++ b/src/utils/diff.ts @@ -1,11 +1,14 @@ export const DiffMap = { 'error': -1, 'major': 0, - 'premajor': 1, - 'minor': 2, - 'preminor': 3, - 'patch': 4, - 'prepatch': 5, - 'prerelease': 6, - '': 7, + 'minor': 1, + 'patch': 2, + '': 3, } + +export const DiffColorMap = { + major: 'red', + minor: 'cyan', + patch: 'green', + error: 'red', +} as const diff --git a/test/resolves.test.ts b/test/resolves.test.ts index 5afd47d..c680d6f 100644 --- a/test/resolves.test.ts +++ b/test/resolves.test.ts @@ -1,7 +1,9 @@ import process from 'node:process' import { expect, it } from 'vitest' +import { SemVer } from 'semver' import type { CheckOptions, DependencyFilter, RawDep } from '../src' import { resolveDependency } from '../src' +import { getDiff } from '../src/io/resolves' const filter: DependencyFilter = () => true @@ -103,3 +105,26 @@ it('resolveDependency', async () => { const target = await resolveDependency(makeLocalPkg('1.0.0'), options, filter) expect(target.resolveError).not.toBeNull() }, 10000) + +it('getDiff', () => { + // normal + expect(getDiff(new SemVer('1.2.3'), new SemVer('1.2.3'))).toBe(null) + expect(getDiff(new SemVer('1.2.3'), new SemVer('1.2.4'))).toBe('patch') + expect(getDiff(new SemVer('1.2.3'), new SemVer('1.3.3'))).toBe('minor') + expect(getDiff(new SemVer('1.2.3'), new SemVer('2.2.3'))).toBe('major') + + // 0.x + expect(getDiff(new SemVer('0.1.2'), new SemVer('0.1.3'))).toBe('patch') + expect(getDiff(new SemVer('0.1.2'), new SemVer('0.2.2'))).toBe('major') + expect(getDiff(new SemVer('0.0.3'), new SemVer('0.0.4'))).toBe('major') + + // pre + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('1.2.3'))).toBe('patch') + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('1.2.4'))).toBe('patch') + expect(getDiff(new SemVer('1.2.2'), new SemVer('1.2.3-a'))).toBe('patch') + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('1.2.3-b'))).toBe('patch') + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('1.2.4-b'))).toBe('patch') + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('1.3.3-a'))).toBe('minor') + expect(getDiff(new SemVer('1.2.3-a'), new SemVer('2.2.3-a'))).toBe('major') + expect(getDiff(new SemVer('2.0.0-a'), new SemVer('2.0.0'))).toBe('patch') +})