Skip to content

Commit a854e47

Browse files
committed
refactor: migrate to fast-npm-meta
1 parent 825f3bb commit a854e47

File tree

9 files changed

+48
-72
lines changed

9 files changed

+48
-72
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@
7777
"*": "eslint --fix"
7878
},
7979
"devDependencies": {
80-
"@npm/types": "^2.1.0",
8180
"@types/node": "^25.1.0",
8281
"@types/vscode": "1.101.0",
8382
"@vida0905/eslint-config": "^2.9.0",
8483
"@vscode/vsce": "^3.7.1",
8584
"eslint": "^9.39.2",
85+
"fast-npm-meta": "^1.0.0",
8686
"husky": "^9.1.7",
8787
"jsonc-parser": "^3.3.1",
8888
"module-replacements": "^2.11.0",

pnpm-lock.yaml

Lines changed: 9 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/providers/completion-item/version.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,27 @@ export class VersionCompletionItemProvider<T extends Extractor> implements Compl
3232

3333
const prefix = extractVersionPrefix(version)
3434

35-
let versionsKV = Object.values(pkg.versions)
35+
const items: CompletionItem[] = []
3636

37-
if (config.versionCompletion === 'provenance-only')
38-
versionsKV = versionsKV.filter(({ hasProvenance }) => hasProvenance)
37+
for (const version in pkg.versionsMeta) {
38+
const meta = pkg.versionsMeta[version]
39+
40+
if (config.versionCompletion === 'provenance-only' && !meta.provenance)
41+
continue
3942

40-
return versionsKV.map(({ version, tag }) => {
4143
const text = `${prefix}${version}`
4244
const item = new CompletionItem(text, CompletionItemKind.Value)
4345

4446
item.range = this.extractor.getNodeRange(document, versionNode)
4547
item.insertText = text
48+
49+
const tag = pkg.versionToTag.get(version)
4650
if (tag)
4751
item.detail = tag
4852

49-
return item
50-
})
53+
items.push(item)
54+
}
55+
56+
return items
5157
}
5258
}

src/providers/diagnostics/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { DependencyInfo, Extractor, ValidNode } from '#types/extractor'
2-
import type { ResolvedPackument } from '#utils/npm'
2+
import type { PackageVersionsInfoWithMetadata } from 'fast-npm-meta'
33
import type { Awaitable } from 'reactive-vscode'
44
import type { Diagnostic, TextDocument } from 'vscode'
55
import { basename } from 'node:path'
@@ -15,7 +15,7 @@ import { checkVulnerability } from './rules/vulnerability'
1515
export interface NodeDiagnosticInfo extends Pick<Diagnostic, 'message' | 'severity'> {
1616
node: ValidNode
1717
}
18-
export type DiagnosticRule = (dep: DependencyInfo, pkg: ResolvedPackument) => Awaitable<NodeDiagnosticInfo | undefined>
18+
export type DiagnosticRule = (dep: DependencyInfo, pkg: PackageVersionsInfoWithMetadata) => Awaitable<NodeDiagnosticInfo | undefined>
1919

2020
const rules: DiagnosticRule[] = [
2121
checkDeprecation,

src/providers/diagnostics/rules/deprecation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { DiagnosticSeverity } from 'vscode'
44

55
export const checkDeprecation: DiagnosticRule = (dep, pkg) => {
66
const exactVersion = extractVersion(dep.version)
7-
const versionInfo = pkg.versions[exactVersion]
7+
const versionInfo = pkg.versionsMeta[exactVersion]
88

99
if (!versionInfo?.deprecated)
1010
return

src/providers/diagnostics/rules/vulnerability.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ const DIAGNOSTIC_MAPPING: Record<Exclude<OsvSeverityLevel, 'unknown'>, Diagnosti
1313

1414
export const checkVulnerability: DiagnosticRule = async (dep, pkg) => {
1515
const exactVersion = extractVersion(dep.version)
16-
const versionInfo = pkg.versions[exactVersion]
16+
const versionInfo = pkg.versionsMeta[exactVersion]
1717

1818
if (!versionInfo)
1919
return
2020

21-
const { totalCounts } = await getVulnerability({ name: dep.name, version: versionInfo.version })
21+
const { totalCounts } = await getVulnerability({ name: dep.name, version: exactVersion })
2222

2323
const message: string[] = []
2424
let severity: DiagnosticSeverity | null = null

src/providers/hover/npmx.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export class NpmxHoverProvider<T extends Extractor> implements HoverProvider {
2727
md.isTrusted = true
2828

2929
const pkg = await getPackageInfo(name)
30-
const currentVersion = pkg.versions[coercedVersion]
30+
const currentVersion = pkg.versionsMeta[coercedVersion]
3131
if (currentVersion) {
32-
if (currentVersion.hasProvenance)
33-
md.appendMarkdown(`[$(verified) Verified provenance](https://www.npmjs.com/package/${name}/v/${currentVersion.version}#provenance)\n\n`)
32+
if (currentVersion.provenance)
33+
md.appendMarkdown(`[$(verified) Verified provenance](https://www.npmjs.com/package/${name}/v/${version}#provenance)\n\n`)
3434
}
3535

3636
const footer = [

src/utils/npm.ts

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
1-
import type { Packument, PackumentVersion } from '@npm/types'
1+
import type { PackageVersionsInfoWithMetadata } from 'fast-npm-meta'
22
import { logger } from '#state'
3-
import { ofetch } from 'ofetch'
3+
import { getVersions } from 'fast-npm-meta'
44
import { memoize } from './memoize'
55

6-
const NPM_REGISTRY = 'https://registry.npmjs.org'
7-
8-
interface ResolvedPackumentVersion extends Pick<PackumentVersion, 'version'> {
9-
tag?: string
10-
hasProvenance: boolean
11-
deprecated?: string
12-
}
13-
14-
export interface ResolvedPackument {
15-
versions: Record<string, ResolvedPackumentVersion>
16-
}
17-
186
/**
197
* Encode a package name for use in npm registry URLs.
208
* Handles scoped packages (e.g., @scope/name -> @scope%2Fname).
@@ -26,32 +14,24 @@ export function encodePackageName(name: string): string {
2614
return encodeURIComponent(name)
2715
}
2816

29-
export const getPackageInfo = memoize<string, Promise<ResolvedPackument>>(async (name) => {
30-
logger.info(`Fetching package info for ${name}`)
31-
const encodedName = encodePackageName(name)
32-
33-
const pkg = await ofetch<Packument>(`${NPM_REGISTRY}/${encodedName}`)
34-
logger.info(`Fetched package info for ${name}`)
17+
export interface PackageInfo extends PackageVersionsInfoWithMetadata {
18+
versionToTag: Map<string, string>
19+
}
3520

36-
const resolvedVersions = Object.fromEntries(
37-
Object.keys(pkg.versions)
38-
.filter((v) => pkg.time[v])
39-
.map<[string, ResolvedPackumentVersion]>((v) => [
40-
v,
41-
{
42-
version: v,
43-
// @ts-expect-error present if published with provenance
44-
hasProvenance: !!pkg.versions[v].dist.attestations,
45-
deprecated: pkg.versions[v].deprecated,
46-
},
47-
]),
48-
)
21+
export const getPackageInfo = memoize<string, Promise<PackageInfo>>(async (name) => {
22+
logger.info(`Fetching package info for ${name}`)
4923

50-
Object.entries(pkg['dist-tags']).forEach(([tag, version]) => {
51-
resolvedVersions[version].tag = tag
24+
const pkg = await getVersions(name, {
25+
metadata: true,
5226
})
27+
logger.info(`Fetched package info for ${name}`)
5328

54-
return {
55-
versions: resolvedVersions,
29+
const versionToTag = new Map<string, string>()
30+
if (pkg.distTags) {
31+
for (const [tag, ver] of Object.entries(pkg.distTags)) {
32+
versionToTag.set(ver, tag)
33+
}
5634
}
35+
36+
return { ...pkg, versionToTag }
5737
})

tsdown.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineConfig({
1515
'jsonc-parser',
1616
'yaml',
1717
'ofetch',
18+
'fast-npm-meta',
1819
],
1920
minify: 'dce-only',
2021
})

0 commit comments

Comments
 (0)