forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1import { describe, expect, it, vi } from 'vitest'
2import type { PackumentVersion } from '../../../../shared/types'
3
4// Mock Nitro globals before importing the module
5vi.stubGlobal('defineCachedFunction', (fn: Function) => fn)
6vi.stubGlobal('$fetch', vi.fn())
7
8const { TARGET_PLATFORM, matchesPlatform, resolveVersion } =
9 await import('../../../../server/utils/dependency-resolver')
10
11describe('dependency-resolver', () => {
12 describe('TARGET_PLATFORM', () => {
13 it('is configured for linux-x64-glibc', () => {
14 expect(TARGET_PLATFORM).toEqual({
15 os: 'linux',
16 cpu: 'x64',
17 libc: 'glibc',
18 })
19 })
20 })
21
22 describe('matchesPlatform', () => {
23 it('returns true for packages without platform restrictions', () => {
24 const version = {} as PackumentVersion
25 expect(matchesPlatform(version)).toBe(true)
26 })
27
28 it('returns true when os includes linux', () => {
29 const version = { os: ['linux', 'darwin'] } as PackumentVersion
30 expect(matchesPlatform(version)).toBe(true)
31 })
32
33 it('returns false when os excludes linux', () => {
34 const version = { os: ['darwin', 'win32'] } as PackumentVersion
35 expect(matchesPlatform(version)).toBe(false)
36 })
37
38 it('handles negated os values (!linux)', () => {
39 const version = { os: ['!win32'] } as PackumentVersion
40 expect(matchesPlatform(version)).toBe(true)
41
42 const excluded = { os: ['!linux'] } as PackumentVersion
43 expect(matchesPlatform(excluded)).toBe(false)
44 })
45
46 it('returns true when cpu includes x64', () => {
47 const version = { cpu: ['x64', 'arm64'] } as PackumentVersion
48 expect(matchesPlatform(version)).toBe(true)
49 })
50
51 it('returns false when cpu excludes x64', () => {
52 const version = { cpu: ['arm64', 'arm'] } as PackumentVersion
53 expect(matchesPlatform(version)).toBe(false)
54 })
55
56 it('handles negated cpu values (!x64)', () => {
57 const version = { cpu: ['!arm64'] } as PackumentVersion
58 expect(matchesPlatform(version)).toBe(true)
59
60 const excluded = { cpu: ['!x64'] } as PackumentVersion
61 expect(matchesPlatform(excluded)).toBe(false)
62 })
63
64 it('returns true when libc includes glibc', () => {
65 const version = { libc: ['glibc'] } as unknown as PackumentVersion
66 expect(matchesPlatform(version)).toBe(true)
67 })
68
69 it('returns false when libc is musl only', () => {
70 const version = { libc: ['musl'] } as unknown as PackumentVersion
71 expect(matchesPlatform(version)).toBe(false)
72 })
73
74 it('handles negated libc values (!glibc)', () => {
75 const version = { libc: ['!musl'] } as unknown as PackumentVersion
76 expect(matchesPlatform(version)).toBe(true)
77
78 const excluded = { libc: ['!glibc'] } as unknown as PackumentVersion
79 expect(matchesPlatform(excluded)).toBe(false)
80 })
81
82 it('requires all platform constraints to match', () => {
83 const version = {
84 os: ['linux'],
85 cpu: ['arm64'], // doesn't match x64
86 } as PackumentVersion
87 expect(matchesPlatform(version)).toBe(false)
88 })
89
90 it('ignores empty arrays', () => {
91 const version = { os: [], cpu: [], libc: [] } as unknown as PackumentVersion
92 expect(matchesPlatform(version)).toBe(true)
93 })
94 })
95
96 describe('resolveVersion', () => {
97 const versions = ['1.0.0', '1.0.1', '1.1.0', '2.0.0', '2.0.0-beta.1', '3.0.0']
98
99 it('returns exact version if it exists', () => {
100 expect(resolveVersion('1.0.0', versions)).toBe('1.0.0')
101 expect(resolveVersion('2.0.0', versions)).toBe('2.0.0')
102 })
103
104 it('returns null for exact version that does not exist', () => {
105 expect(resolveVersion('1.0.2', versions)).toBe(null)
106 })
107
108 it('resolves semver ranges', () => {
109 expect(resolveVersion('^1.0.0', versions)).toBe('1.1.0')
110 expect(resolveVersion('~1.0.0', versions)).toBe('1.0.1')
111 expect(resolveVersion('>=2.0.0', versions)).toBe('3.0.0')
112 expect(resolveVersion('<2.0.0', versions)).toBe('1.1.0')
113 })
114
115 it('resolves * to latest stable', () => {
116 expect(resolveVersion('*', versions)).toBe('3.0.0')
117 })
118
119 it('handles npm: protocol aliases', () => {
120 expect(resolveVersion('npm:other-pkg@^1.0.0', versions)).toBe('1.1.0')
121 expect(resolveVersion('npm:@scope/pkg@2.0.0', versions)).toBe('2.0.0')
122 })
123
124 it('returns null for invalid npm: protocol', () => {
125 expect(resolveVersion('npm:', versions)).toBe(null)
126 expect(resolveVersion('npm:pkg', versions)).toBe(null)
127 })
128
129 it('returns null for URLs', () => {
130 expect(resolveVersion('https://github.com/user/repo', versions)).toBe(null)
131 expect(resolveVersion('http://example.com/pkg.tgz', versions)).toBe(null)
132 expect(resolveVersion('git://github.com/user/repo.git', versions)).toBe(null)
133 expect(resolveVersion('git+https://github.com/user/repo.git', versions)).toBe(null)
134 })
135
136 it('returns null for file: protocol', () => {
137 expect(resolveVersion('file:../local-pkg', versions)).toBe(null)
138 })
139
140 it('returns null for GitHub shorthand (contains /)', () => {
141 expect(resolveVersion('user/repo', versions)).toBe(null)
142 expect(resolveVersion('user/repo#branch', versions)).toBe(null)
143 })
144
145 it('handles prerelease versions when explicitly requested', () => {
146 // Exact prerelease version match
147 expect(resolveVersion('2.0.0-beta.1', versions)).toBe('2.0.0-beta.1')
148 // Range with prerelease - semver correctly prefers stable 2.0.0 over 2.0.0-beta.1
149 expect(resolveVersion('^2.0.0-beta.0', versions)).toBe('2.0.0')
150 })
151 })
152})