forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1/**
2 * Detects if a package name is a platform-specific native binary package.
3 * These are typically optional dependencies that contain native binaries
4 * for specific OS/architecture combinations (e.g., @oxlint/win32-x64, esbuild-darwin-arm64).
5 * Sourced from searches for esbuild, and the napi-rs build triplets support matrix.
6 */
7
8const PLATFORMS = new Set([
9 'win32',
10 'darwin',
11 'linux',
12 'android',
13 'freebsd',
14 'openbsd',
15 'netbsd',
16 'sunos',
17 'aix',
18])
19
20const ARCHITECTURES = new Set([
21 'x64',
22 'arm64',
23 'arm',
24 'ia32',
25 'ppc64',
26 'ppc64le',
27 's390x',
28 'riscv64',
29 'mips64el',
30 'loong64',
31])
32
33const ABI_SUFFIXES = new Set(['gnu', 'musl', 'msvc', 'gnueabihf'])
34
35/**
36 * Checks if a package name is a platform-specific native binary package.
37 * Matches patterns like:
38 * - @scope/pkg-win32-x64
39 * - @scope/pkg-linux-arm64-gnu
40 * - pkg-darwin-arm64
41 * - @rollup/rollup-linux-x64-musl
42 *
43 * @param name - The full package name (including scope if present)
44 * @returns true if the package appears to be a platform-specific binary
45 */
46export function isPlatformSpecificPackage(name: string): boolean {
47 const unscopedName = name.startsWith('@') ? (name.split('/')[1] ?? '') : name
48 if (!unscopedName) return false
49
50 const parts = unscopedName.split('-')
51 if (parts.length < 2) return false
52
53 // Look for OS-arch pattern anywhere in the name as suffix parts
54 // e.g., "pkg-linux-x64-gnu" -> ["pkg", "linux", "x64", "gnu"]
55 for (let i = 0; i < parts.length - 1; i++) {
56 const os = parts[i]
57 const arch = parts[i + 1]
58
59 if (os && arch && PLATFORMS.has(os) && ARCHITECTURES.has(arch)) {
60 // Optional ABI suffix check (next part if exists)
61 const abiSuffix = parts[i + 2]
62 if (abiSuffix && !ABI_SUFFIXES.has(abiSuffix)) {
63 // NOTE: Has an extra part after arch but it's not a known ABI - might be a false positive??
64 // but still consider it a match if OS+arch pattern is found at the end
65 if (i + 2 === parts.length - 1) {
66 // Extra unknown suffix at the end - be conservative
67 continue
68 }
69 }
70 return true
71 }
72 }
73
74 return false
75}