mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-12 18:49:41 -04:00
* chore: update all dependencies to latest versions Update all outdated dependencies across the monorepo catalog and fix breaking changes from major version bumps. Notable updates: - ESLint 9 → 10 (fix custom rule API, disable new no-useless-assignment) - @stylistic/eslint-plugin 4 → 5 (auto-fixed indent changes) - @cyclonedx/cyclonedx-library 9 → 10 (adapt to removed SPDX API) - esbuild 0.25 → 0.27 - TypeScript 5.9.2 → 5.9.3 - Various @types packages, test utilities, and build tools Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update unified/remark/mdast imports for v11/v4 API changes Update imports in get-release-text for the new ESM named exports: - mdast-util-to-string: default → { toString } - unified: default → { unified } Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve typecheck errors from dependency updates - isexe v4: use named import { sync } instead of default export - remark-parse/remark-stringify v11: add vfile as packageExtension dependency so TypeScript can resolve type declarations - get-release-text: remove unused @ts-expect-error directives Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: revert runtime dependency major version bumps Revert major version bumps for runtime dependencies that are bundled into pnpm to fix test failures where pnpm add silently fails: - bin-links: keep ^5.0.0 (was ^6.0.0) - cli-truncate: keep ^4.0.0 (was ^5.2.0) - delay: keep ^6.0.0 (was ^7.0.0) - filenamify: keep ^6.0.0 (was ^7.0.1) - find-up: keep ^7.0.0 (was ^8.0.0) - isexe: keep 2.0.0 (was 4.0.0) - normalize-newline: keep 4.1.0 (was 5.0.0) - p-queue: keep ^8.1.0 (was ^9.1.0) - ps-list: keep ^8.1.1 (was ^9.0.0) - string-length: keep ^6.0.0 (was ^7.0.1) - symlink-dir: keep ^7.0.0 (was ^9.0.0) - terminal-link: keep ^4.0.0 (was ^5.0.0) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: restore runtime dependency major version bumps Re-apply all runtime dependency major version bumps that were previously reverted. All packages maintain their default exports except isexe v4 which needs named imports. Updated runtime deps: - bin-links: ^5.0.0 → ^6.0.0 - cli-truncate: ^4.0.0 → ^5.2.0 - delay: ^6.0.0 → ^7.0.0 - filenamify: ^6.0.0 → ^7.0.1 - find-up: ^7.0.0 → ^8.0.0 - isexe: 2.0.0 → 4.0.0 (fix: use named import { sync }) - normalize-newline: 4.1.0 → 5.0.0 - p-queue: ^8.1.0 → ^9.1.0 - ps-list: ^8.1.1 → ^9.0.0 - string-length: ^6.0.0 → ^7.0.1 - symlink-dir: ^7.0.0 → ^9.0.0 - terminal-link: ^4.0.0 → ^5.0.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: revert tempy to 3.0.0 to fix bundle hang tempy 3.2.0 pulls in temp-dir 3.0.0 which uses async fs.realpath() inside its module init. When bundled by esbuild into the __esm lazy init pattern, this causes a deadlock during module initialization, making the pnpm binary hang silently on startup. Keeping tempy at 3.0.0 which uses temp-dir 2.x (sync fs.realpathSync). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add comment explaining why tempy cannot be upgraded Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: revert nock to 13.3.4 for node-fetch compatibility nock 14 changed its HTTP interception mechanism in a way that doesn't properly intercept node-fetch requests, causing audit tests to hang waiting for responses that are never intercepted. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add comment explaining why nock cannot be upgraded Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: update symlink-dir imports for v10 ESM named exports symlink-dir v10 removed the default export and switched to named exports: { symlinkDir, symlinkDirSync }. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: revert @typescript/native-preview to working version Newer tsgo dev builds (>= 20260318) have a regression where @types/node cannot be resolved, breaking all node built-in types. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: vulnerabilities * fix: align comment indentation in runLifecycleHook Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: pin msgpackr to 1.11.8 for TypeScript 5.9 compatibility msgpackr 1.11.9 has broken type definitions that use Iterable/Iterator without required type arguments, causing compile errors with TS 5.9. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
190 lines
6.4 KiB
TypeScript
190 lines
6.4 KiB
TypeScript
// cspell:ignore ents
|
|
import fs from 'node:fs'
|
|
|
|
import { type LockfileObject, type PackageSnapshot, readWantedLockfile, type TarballResolution } from '@pnpm/lockfile.fs'
|
|
import {
|
|
nameVerFromPkgSnapshot,
|
|
} from '@pnpm/lockfile.utils'
|
|
import { getFilePathByModeInCafs, type PackageFilesIndex } from '@pnpm/store.cafs'
|
|
import { StoreIndex, storeIndexKey } from '@pnpm/store.index'
|
|
import type { DepPath } from '@pnpm/types'
|
|
import Fuse from 'fuse-native'
|
|
import schemas from 'hyperdrive-schemas'
|
|
|
|
import * as cafsExplorer from './cafsExplorer.js'
|
|
import { makeVirtualNodeModules } from './makeVirtualNodeModules.js'
|
|
|
|
const TIME = new Date()
|
|
const STAT_DEFAULT = {
|
|
mtime: TIME,
|
|
atime: TIME,
|
|
ctime: TIME,
|
|
nlink: 1,
|
|
uid: process.getuid ? process.getuid() : 0,
|
|
gid: process.getgid ? process.getgid() : 0,
|
|
}
|
|
|
|
export interface FuseHandlers {
|
|
open: (p: string, flags: string | number, cb: (exitCode: number, fd?: number) => void) => void
|
|
release: (p: string, fd: number, cb: (exitCode: number) => void) => void
|
|
read: (p: string, fd: number, buffer: Buffer, length: number, position: number, cb: (readBytes: number) => void) => void
|
|
readlink: (p: string, cb: (returnCode: number, target?: string) => void) => void
|
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
getattr: (p: string, cb: (returnCode: number, files?: any) => void) => void
|
|
readdir: (p: string, cb: (returnCode: number, files?: string[]) => void) => void
|
|
}
|
|
|
|
export async function createFuseHandlers (lockfileDir: string, storeDir: string): Promise<FuseHandlers> {
|
|
const lockfile = await readWantedLockfile(lockfileDir, { ignoreIncompatible: true })
|
|
if (lockfile == null) throw new Error('Cannot generate a .pnp.cjs without a lockfile')
|
|
return createFuseHandlersFromLockfile(lockfile, storeDir)
|
|
}
|
|
|
|
export function createFuseHandlersFromLockfile (lockfile: LockfileObject, storeDir: string): FuseHandlers {
|
|
const storeIndex = new StoreIndex(storeDir)
|
|
const pkgSnapshotCache = new Map<string, { name: string, version: string, pkgSnapshot: PackageSnapshot, index: PackageFilesIndex }>()
|
|
const virtualNodeModules = makeVirtualNodeModules(lockfile)
|
|
return {
|
|
open (p: string, flags: string | number, cb: (exitCode: number, fd?: number) => void) {
|
|
const dirEnt = getDirEnt(p)
|
|
if (dirEnt?.entryType !== 'index') {
|
|
cb(-1)
|
|
return
|
|
}
|
|
const fileInfo = dirEnt.index.files.get(dirEnt.subPath)
|
|
if (!fileInfo) {
|
|
cb(-1)
|
|
return
|
|
}
|
|
const filePathInStore = getFilePathByModeInCafs(storeDir, fileInfo.digest, fileInfo.mode)
|
|
fs.open(filePathInStore, flags, (err, fd) => {
|
|
if (err != null) {
|
|
cb(-1)
|
|
return
|
|
}
|
|
cb(0, fd)
|
|
})
|
|
},
|
|
release (p: string, fd: number, cb: (exitCode: number) => void) {
|
|
fs.close(fd, (err) => {
|
|
cb((err != null) ? -1 : 0)
|
|
})
|
|
},
|
|
read (p: string, fd: number, buffer: Buffer, length: number, position: number, cb: (readBytes: number) => void) {
|
|
fs.read(fd, buffer, 0, length, position, (err, bytesRead) => {
|
|
if (err != null) {
|
|
cb(-1)
|
|
return
|
|
}
|
|
cb(bytesRead)
|
|
})
|
|
},
|
|
readlink (p: string, cb: (returnCode: number, target?: string) => void) {
|
|
const dirEnt = getDirEnt(p)
|
|
if (dirEnt?.entryType !== 'symlink') {
|
|
cb(Fuse.ENOENT)
|
|
return
|
|
}
|
|
cb(0, dirEnt.target)
|
|
},
|
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
getattr (p: string, cb: (returnCode: number, files?: any) => void) {
|
|
const dirEnt = getDirEnt(p)
|
|
if (dirEnt == null) {
|
|
cb(Fuse.ENOENT)
|
|
return
|
|
}
|
|
if (dirEnt.entryType === 'directory' || dirEnt.entryType === 'index' && !dirEnt.subPath) {
|
|
cb(0, schemas.Stat.directory({
|
|
...STAT_DEFAULT,
|
|
size: 1,
|
|
}))
|
|
return
|
|
}
|
|
if (dirEnt.entryType === 'symlink') {
|
|
cb(0, schemas.Stat.symlink({
|
|
...STAT_DEFAULT,
|
|
size: 1,
|
|
}))
|
|
return
|
|
}
|
|
if (dirEnt.entryType === 'index') {
|
|
switch (cafsExplorer.dirEntityType(dirEnt.index, dirEnt.subPath)) {
|
|
case 'file': {
|
|
const fileInfo = dirEnt.index.files.get(dirEnt.subPath)!
|
|
cb(0, schemas.Stat.file({
|
|
...STAT_DEFAULT,
|
|
mode: fileInfo.mode,
|
|
size: fileInfo.size,
|
|
}))
|
|
return
|
|
}
|
|
case 'directory':
|
|
cb(0, schemas.Stat.directory({
|
|
...STAT_DEFAULT,
|
|
size: 1,
|
|
}))
|
|
return
|
|
default:
|
|
cb(Fuse.ENOENT)
|
|
return
|
|
}
|
|
}
|
|
cb(Fuse.ENOENT)
|
|
},
|
|
readdir,
|
|
}
|
|
function readdir (p: string, cb: (returnCode: number, files?: string[]) => void) {
|
|
const dirEnt = getDirEnt(p)
|
|
if (dirEnt?.entryType === 'index') {
|
|
const dirEnts = cafsExplorer.readdir(dirEnt.index, dirEnt.subPath)
|
|
if (dirEnts.length === 0) {
|
|
cb(Fuse.ENOENT)
|
|
return
|
|
}
|
|
cb(0, dirEnts)
|
|
return
|
|
}
|
|
if ((dirEnt == null) || dirEnt.entryType !== 'directory') {
|
|
cb(Fuse.ENOENT)
|
|
return
|
|
}
|
|
cb(0, Object.keys(dirEnt.entries))
|
|
}
|
|
function getDirEnt (p: string) {
|
|
let currentDirEntry = virtualNodeModules
|
|
const parts = p === '/' ? [] : p.split('/')
|
|
parts.shift()
|
|
while ((parts.length > 0) && currentDirEntry && currentDirEntry.entryType === 'directory') {
|
|
currentDirEntry = currentDirEntry.entries[parts.shift()!]
|
|
}
|
|
if (currentDirEntry?.entryType === 'index') {
|
|
const pkg = getPkgInfo(currentDirEntry.depPath)
|
|
if (pkg == null) {
|
|
return null
|
|
}
|
|
return {
|
|
...currentDirEntry,
|
|
index: pkg.index,
|
|
subPath: parts.join('/'),
|
|
}
|
|
}
|
|
return currentDirEntry
|
|
}
|
|
function getPkgInfo (depPath: string) {
|
|
if (!pkgSnapshotCache.has(depPath)) {
|
|
const pkgSnapshot = lockfile.packages?.[depPath as DepPath]
|
|
if (pkgSnapshot == null) return undefined
|
|
const nameVer = nameVerFromPkgSnapshot(depPath, pkgSnapshot)
|
|
const pkgIndexFilePath = storeIndexKey((pkgSnapshot.resolution as TarballResolution).integrity!, `${nameVer.name}@${nameVer.version}`)
|
|
const pkgIndex = storeIndex.get(pkgIndexFilePath) as PackageFilesIndex
|
|
pkgSnapshotCache.set(depPath, {
|
|
...nameVer,
|
|
pkgSnapshot,
|
|
index: pkgIndex,
|
|
})
|
|
}
|
|
return pkgSnapshotCache.get(depPath)
|
|
}
|
|
}
|