@yarnpkg/pnpify
Version:
469 lines (468 loc) • 18.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PortableNodeModulesFS = exports.NodeModulesFS = void 0;
const tslib_1 = require("tslib");
const fslib_1 = require("@yarnpkg/fslib");
const fslib_2 = require("@yarnpkg/fslib");
const fslib_3 = require("@yarnpkg/fslib");
const nm_1 = require("@yarnpkg/nm");
const fs_1 = tslib_1.__importDefault(require("fs"));
const WatchManager_1 = require("./WatchManager");
const dynamicRequire_1 = require("./dynamicRequire");
const resolveNodeModulesPath_1 = require("./resolveNodeModulesPath");
class NodeModulesFS extends fslib_3.ProxiedFS {
constructor(pnp, { realFs = fs_1.default, pnpifyFs = true } = {}) {
super(fslib_2.npath);
this.baseFs = new PortableNodeModulesFS(pnp, { baseFs: new fslib_3.NodeFS(realFs), pnpifyFs });
}
mapFromBase(path) {
return fslib_2.npath.fromPortablePath(path);
}
mapToBase(path) {
return fslib_2.npath.toPortablePath(path);
}
}
exports.NodeModulesFS = NodeModulesFS;
const WRITE_FLAGS_REGEX = /[+wa]/;
class PortableNodeModulesFS extends fslib_3.FakeFS {
constructor(pnp, { baseFs = new fslib_3.NodeFS(), pnpifyFs = true } = {}) {
super(fslib_2.ppath);
if (!pnp.getDependencyTreeRoots)
throw new Error(`NodeModulesFS supports PnP API versions 3+, please upgrade your PnP API provider`);
this.options = { baseFs, pnpifyFs };
this.baseFs = baseFs;
const { tree, errors } = (0, nm_1.buildNodeModulesTree)(pnp, this.options);
if (!tree)
throw new Error(`Assertion failed. Have got non-persistable node_modules graph, errors:\n${JSON.stringify(errors)}`);
this.nodeModulesTree = tree;
this.watchManager = new WatchManager_1.WatchManager();
const pnpRootPath = fslib_2.npath.toPortablePath(pnp.getPackageInformation(pnp.topLevel).packageLocation);
this.pnpFilePath = fslib_2.ppath.join(pnpRootPath, fslib_1.Filename.pnpCjs);
this.watchPnpFile(pnpRootPath);
}
watchPnpFile(pnpRootPath) {
this.baseFs.watch(pnpRootPath, { persistent: false }, (_, filename) => {
if (filename === fslib_1.Filename.pnpCjs) {
const pnp = (0, dynamicRequire_1.dynamicRequireNoCache)(this.pnpFilePath);
const nodeModulesTree = (0, nm_1.buildNodeModulesTree)(pnp, this.options);
if (!nodeModulesTree)
throw new Error(`Assertion failed. Have got non-persistable node_modules graph`);
this.watchManager.notifyWatchers((nodePath) => (0, resolveNodeModulesPath_1.resolveNodeModulesPath)(nodePath, this.nodeModulesTree));
}
});
}
persistPath(dir) {
const pathStack = [];
let curPath = dir;
while (!this.baseFs.existsSync(curPath)) {
pathStack.push(curPath);
curPath = fslib_2.ppath.dirname(curPath);
}
for (const fullPath of pathStack.reverse()) {
this.baseFs.mkdirSync(fullPath);
}
}
persistVirtualParentFolder(p) {
if (typeof p !== `number`) {
const parentPath = this.resolvePath(fslib_2.ppath.dirname(p));
if (parentPath.dirList) {
this.persistPath(parentPath.resolvedPath);
}
}
}
getExtractHint(hints) {
return this.baseFs.getExtractHint(hints);
}
resolve(path) {
return this.baseFs.resolve(this.resolvePath(path).resolvedPath);
}
getBaseFs() {
return this.baseFs;
}
resolvePath(p) {
if (typeof p === `number`) {
return { resolvedPath: p, fullOriginalPath: p };
}
else {
const fullOriginalPath = this.pathUtils.resolve(p);
return { ...(0, resolveNodeModulesPath_1.resolveNodeModulesPath)(fullOriginalPath, this.nodeModulesTree), fullOriginalPath };
}
}
resolveFilePath(p) {
if (typeof p === `number`)
return p;
const pnpPath = this.resolvePath(p);
return pnpPath.resolvedPath;
}
resolveDirOrFilePath(p) {
if (typeof p === `number`)
return p;
const pnpPath = this.resolvePath(p);
return pnpPath.forwardedDirPath || pnpPath.resolvedPath;
}
resolveLink(opts) {
const { p, onSymlink, onRealPath, statOptions } = opts;
const pnpPath = this.resolvePath(p);
if (pnpPath.isSymlink) {
let stat;
try {
stat = this.baseFs.lstatSync(pnpPath.resolvedPath, statOptions);
}
catch { }
if (stat) {
return onSymlink(stat, this.pathUtils.relative(this.pathUtils.dirname(pnpPath.fullOriginalPath), pnpPath.resolvedPath));
}
}
return onRealPath(pnpPath.forwardedDirPath || pnpPath.resolvedPath);
}
static makeSymlinkStats(stats) {
return Object.assign(stats, {
isFile: () => false,
isDirectory: () => false,
isSymbolicLink: () => true,
});
}
getRealPath() {
return this.baseFs.getRealPath();
}
async openPromise(p, flags, mode) {
if (WRITE_FLAGS_REGEX.test(flags))
this.persistVirtualParentFolder(p);
return await this.baseFs.openPromise(this.resolveFilePath(p), flags, mode);
}
openSync(p, flags, mode) {
if (WRITE_FLAGS_REGEX.test(flags))
this.persistVirtualParentFolder(p);
return this.baseFs.openSync(this.resolveFilePath(p), flags, mode);
}
async opendirPromise(p, opts) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList || this.resolvePath(fslib_2.ppath.join(p, `node_modules`)).dirList) {
let fsDirList = [];
try {
fsDirList = await this.baseFs.readdirPromise(pnpPath.resolvedPath);
}
catch { }
const entries = Array.from(pnpPath.dirList || [`node_modules`]).concat(fsDirList).sort();
return (0, fslib_2.opendir)(this, p, entries);
}
else {
return await this.baseFs.opendirPromise(pnpPath.resolvedPath, opts);
}
}
opendirSync(p, opts) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList || this.resolvePath(fslib_2.ppath.join(p, `node_modules`)).dirList) {
let fsDirList = [];
try {
fsDirList = this.baseFs.readdirSync(pnpPath.resolvedPath);
}
catch { }
const entries = Array.from(pnpPath.dirList || [`node_modules`]).concat(fsDirList).sort();
return (0, fslib_2.opendir)(this, p, entries);
}
else {
return this.baseFs.opendirSync(pnpPath.resolvedPath, opts);
}
}
async readPromise(fd, buffer, offset, length, position) {
return await this.baseFs.readPromise(fd, buffer, offset, length, position);
}
readSync(fd, buffer, offset, length, position) {
return this.baseFs.readSync(fd, buffer, offset, length, position);
}
async writePromise(fd, buffer, offset, length, position) {
if (typeof buffer === `string`) {
return await this.baseFs.writePromise(fd, buffer, offset);
}
else {
return await this.baseFs.writePromise(fd, buffer, offset, length, position);
}
}
writeSync(fd, buffer, offset, length, position) {
if (typeof buffer === `string`) {
return this.baseFs.writeSync(fd, buffer, offset);
}
else {
return this.baseFs.writeSync(fd, buffer, offset, length, position);
}
}
async closePromise(fd) {
await this.baseFs.closePromise(fd);
}
closeSync(fd) {
this.baseFs.closeSync(fd);
}
createReadStream(p, opts) {
return this.baseFs.createReadStream(p !== null ? this.resolveFilePath(p) : p, opts);
}
createWriteStream(p, opts) {
return this.baseFs.createWriteStream(p !== null ? this.resolveDirOrFilePath(p) : p, opts);
}
async realpathPromise(p) {
const pnpPath = this.resolvePath(p);
return pnpPath.dirList ? pnpPath.resolvedPath : this.baseFs.realpathPromise(pnpPath.resolvedPath);
}
realpathSync(p) {
const pnpPath = this.resolvePath(p);
return pnpPath.dirList ? pnpPath.resolvedPath : this.baseFs.realpathSync(pnpPath.resolvedPath);
}
async existsPromise(p) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList) {
return true;
}
else {
return await this.baseFs.existsPromise(pnpPath.resolvedPath);
}
}
existsSync(p) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList) {
return true;
}
else {
return this.baseFs.existsSync(pnpPath.resolvedPath);
}
}
async accessPromise(p, mode) {
return await this.baseFs.accessPromise(this.resolveDirOrFilePath(p), mode);
}
accessSync(p, mode) {
return this.baseFs.accessSync(this.resolveDirOrFilePath(p), mode);
}
async statPromise(p, opts) {
return await this.baseFs.statPromise(this.resolveDirOrFilePath(p), opts);
}
statSync(p, opts) {
return this.baseFs.statSync(this.resolveDirOrFilePath(p), opts);
}
async fstatPromise(fd, opts) {
return await this.baseFs.fstatPromise(fd, opts);
}
fstatSync(fd, opts) {
return this.baseFs.fstatSync(fd, opts);
}
async lstatPromise(p, opts) {
return this.resolveLink({
p,
op: `lstat`,
onSymlink: stats => PortableNodeModulesFS.makeSymlinkStats(stats),
onRealPath: async (resolvedPath) => await this.baseFs.lstatPromise(resolvedPath, opts),
statOptions: opts,
});
}
lstatSync(p, opts) {
return this.resolveLink({
p,
op: `lstat`,
onSymlink: stats => PortableNodeModulesFS.makeSymlinkStats(stats),
onRealPath: resolvedPath => this.baseFs.lstatSync(resolvedPath, opts),
statOptions: opts,
});
}
async fchmodPromise(fd, mask) {
return this.baseFs.fchmodPromise(this.resolveDirOrFilePath(fd), mask);
}
fchmodSync(fd, mask) {
return this.baseFs.fchmodSync(this.resolveDirOrFilePath(fd), mask);
}
async chmodPromise(p, mask) {
return await this.baseFs.chmodPromise(this.resolveDirOrFilePath(p), mask);
}
chmodSync(p, mask) {
return this.baseFs.chmodSync(this.resolveDirOrFilePath(p), mask);
}
async fchownPromise(fd, uid, gid) {
return this.baseFs.fchownPromise(this.resolveDirOrFilePath(fd), uid, gid);
}
fchownSync(fd, uid, gid) {
return this.baseFs.fchownSync(this.resolveDirOrFilePath(fd), uid, gid);
}
async chownPromise(p, uid, gid) {
return await this.baseFs.chownPromise(this.resolveDirOrFilePath(p), uid, gid);
}
chownSync(p, uid, gid) {
return this.baseFs.chownSync(this.resolveDirOrFilePath(p), uid, gid);
}
async renamePromise(oldP, newP) {
return await this.baseFs.renamePromise(this.resolveDirOrFilePath(oldP), this.resolveDirOrFilePath(newP));
}
renameSync(oldP, newP) {
return this.baseFs.renameSync(this.resolveDirOrFilePath(oldP), this.resolveDirOrFilePath(newP));
}
async copyFilePromise(sourceP, destP, flags) {
return await this.baseFs.copyFilePromise(this.resolveFilePath(sourceP), this.resolveDirOrFilePath(destP), flags);
}
copyFileSync(sourceP, destP, flags) {
return this.baseFs.copyFileSync(this.resolveFilePath(sourceP), this.resolveDirOrFilePath(destP), flags);
}
async appendFilePromise(p, content, opts) {
return await this.baseFs.appendFilePromise(this.resolveDirOrFilePath(p), content, opts);
}
appendFileSync(p, content, opts) {
return this.baseFs.appendFileSync(this.resolveDirOrFilePath(p), content, opts);
}
async writeFilePromise(p, content, opts) {
return await this.baseFs.writeFilePromise(this.resolveDirOrFilePath(p), content, opts);
}
writeFileSync(p, content, opts) {
return this.baseFs.writeFileSync(this.resolveDirOrFilePath(p), content, opts);
}
async unlinkPromise(p) {
return await this.baseFs.unlinkPromise(this.resolveDirOrFilePath(p));
}
unlinkSync(p) {
return this.baseFs.unlinkSync(this.resolveDirOrFilePath(p));
}
async utimesPromise(p, atime, mtime) {
return await this.baseFs.utimesPromise(this.resolveDirOrFilePath(p), atime, mtime);
}
utimesSync(p, atime, mtime) {
return this.baseFs.utimesSync(this.resolveDirOrFilePath(p), atime, mtime);
}
async lutimesPromise(p, atime, mtime) {
return await this.baseFs.lutimesPromise(this.resolveDirOrFilePath(p), atime, mtime);
}
lutimesSync(p, atime, mtime) {
return this.baseFs.lutimesSync(this.resolveDirOrFilePath(p), atime, mtime);
}
async mkdirPromise(p, opts) {
const pnpPath = this.resolvePath(p);
this.persistVirtualParentFolder(p);
return this.baseFs.mkdirPromise(pnpPath.resolvedPath, opts);
}
mkdirSync(p, opts) {
const pnpPath = this.resolvePath(p);
this.persistVirtualParentFolder(p);
return this.baseFs.mkdirSync(pnpPath.resolvedPath, opts);
}
async rmdirPromise(p, opts) {
return await this.baseFs.rmdirPromise(this.resolveDirOrFilePath(p), opts);
}
rmdirSync(p, opts) {
return this.baseFs.rmdirSync(this.resolveDirOrFilePath(p), opts);
}
async rmPromise(p, opts) {
return await this.baseFs.rmPromise(this.resolveDirOrFilePath(p), opts);
}
rmSync(p, opts) {
return this.baseFs.rmSync(this.resolveDirOrFilePath(p), opts);
}
async linkPromise(existingP, newP) {
return await this.baseFs.linkPromise(this.resolveDirOrFilePath(existingP), this.resolveDirOrFilePath(newP));
}
linkSync(existingP, newP) {
return this.baseFs.linkSync(this.resolveDirOrFilePath(existingP), this.resolveDirOrFilePath(newP));
}
async symlinkPromise(target, p) {
return await this.baseFs.symlinkPromise(this.resolveDirOrFilePath(target), this.resolveDirOrFilePath(p));
}
symlinkSync(target, p) {
return this.baseFs.symlinkSync(this.resolveDirOrFilePath(target), this.resolveDirOrFilePath(p));
}
async readFilePromise(p, encoding) {
return await this.baseFs.readFilePromise(this.resolveFilePath(p), encoding);
}
readFileSync(p, encoding) {
return this.baseFs.readFileSync(this.resolveFilePath(p), encoding);
}
async readdirPromise(p, opts) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList || this.resolvePath(fslib_2.ppath.join(p, `node_modules`)).dirList) {
if (opts?.recursive)
throw new Error(`Unsupported option 'recursive' for NodeModulesFS.readdirPromise`);
let fsDirList = [];
try {
fsDirList = await this.baseFs.readdirPromise(pnpPath.resolvedPath);
}
catch { }
const entries = Array.from(pnpPath.dirList || [`node_modules`]).concat(fsDirList).sort();
if (!opts?.withFileTypes)
return entries;
return entries.map(name => {
return Object.assign(this.lstatSync(fslib_2.ppath.join(p, name)), {
name,
path: undefined,
});
});
}
else {
return await this.baseFs.readdirPromise(pnpPath.resolvedPath, opts);
}
}
readdirSync(p, opts) {
const pnpPath = this.resolvePath(p);
if (pnpPath.dirList || this.resolvePath(fslib_2.ppath.join(p, `node_modules`)).dirList) {
if (opts?.recursive)
throw new Error(`Unsupported option 'recursive' for NodeModulesFS.readdirSync`);
let fsDirList = [];
try {
fsDirList = this.baseFs.readdirSync(pnpPath.resolvedPath);
}
catch { }
const entries = Array.from(pnpPath.dirList || [`node_modules`]).concat(fsDirList).sort();
if (!opts?.withFileTypes)
return entries;
return entries.map(name => {
return Object.assign(this.lstatSync(fslib_2.ppath.join(p, name)), {
name,
path: undefined,
});
});
}
else {
return this.baseFs.readdirSync(pnpPath.resolvedPath, opts);
}
}
async readlinkPromise(p) {
return this.resolveLink({
p,
op: `readlink`,
onSymlink: (_stats, targetPath) => targetPath,
onRealPath: async (targetPath) => await this.baseFs.readlinkPromise(this.resolveDirOrFilePath(targetPath)),
});
}
readlinkSync(p) {
return this.resolveLink({
p,
op: `readlink`,
onSymlink: (_stats, targetPath) => targetPath,
onRealPath: targetPath => this.baseFs.readlinkSync(this.resolveDirOrFilePath(targetPath)),
});
}
async truncatePromise(p, len) {
return await this.baseFs.truncatePromise(this.resolveDirOrFilePath(p), len);
}
truncateSync(p, len) {
return this.baseFs.truncateSync(this.resolveDirOrFilePath(p), len);
}
async ftruncatePromise(fd, len) {
return await this.baseFs.ftruncatePromise(fd, len);
}
ftruncateSync(fd, len) {
return this.baseFs.ftruncateSync(fd, len);
}
watch(p, a, b) {
const pnpPath = this.resolvePath(p);
const watchPath = pnpPath.resolvedPath;
if (watchPath && pnpPath.dirList) {
const callback = typeof a === `function` ? a : typeof b === `function` ? b : () => { };
return this.watchManager.registerWatcher(watchPath, pnpPath.dirList, callback);
}
else {
return this.baseFs.watch(this.resolveDirOrFilePath(p),
// @ts-expect-error
a, b);
}
}
watchFile(p, a, b) {
return this.baseFs.watchFile(this.resolveDirOrFilePath(p),
// @ts-expect-error
a, b);
}
unwatchFile(p, cb) {
return this.baseFs.unwatchFile(this.resolveDirOrFilePath(p), cb);
}
}
exports.PortableNodeModulesFS = PortableNodeModulesFS;