@yarnpkg/fslib
Advanced tools
Comparing version 2.0.0-rc.14 to 2.0.0-rc.15
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.copyPromise = copyPromise; | ||
var _fs = _interopRequireDefault(require("fs")); | ||
var _path = require("../path"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = __importDefault(require("fs")); | ||
const path_1 = require("../path"); | ||
async function copyPromise(destinationFs, destination, sourceFs, source, opts) { | ||
const normalizedDestination = destinationFs.pathUtils.normalize(destination); | ||
const normalizedSource = sourceFs.pathUtils.normalize(source); | ||
const operations = []; | ||
const utimes = []; | ||
await destinationFs.mkdirpPromise(destination); | ||
await copyImpl(operations, utimes, destinationFs, normalizedDestination, sourceFs, normalizedSource, opts); | ||
for (const operation of operations) await operation(); | ||
for (const [p, atime, mtime] of utimes) { | ||
await destinationFs.utimesPromise(p, atime, mtime); | ||
} | ||
const normalizedDestination = destinationFs.pathUtils.normalize(destination); | ||
const normalizedSource = sourceFs.pathUtils.normalize(source); | ||
const operations = []; | ||
const utimes = []; | ||
await destinationFs.mkdirpPromise(destination); | ||
await copyImpl(operations, utimes, destinationFs, normalizedDestination, sourceFs, normalizedSource, opts); | ||
for (const operation of operations) | ||
await operation(); | ||
for (const [p, atime, mtime] of utimes) { | ||
await destinationFs.utimesPromise(p, atime, mtime); | ||
} | ||
} | ||
exports.copyPromise = copyPromise; | ||
async function copyImpl(operations, utimes, destinationFs, destination, sourceFs, source, opts) { | ||
const destinationStat = await maybeLStat(destinationFs, destination); | ||
const sourceStat = await sourceFs.lstatPromise(source); | ||
utimes.push([destination, sourceStat.atime, sourceStat.mtime]); | ||
switch (true) { | ||
case sourceStat.isDirectory(): | ||
{ | ||
await copyFolder(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
case sourceStat.isFile(): | ||
{ | ||
await copyFile(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
case sourceStat.isSymbolicLink(): | ||
{ | ||
await copySymlink(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
default: | ||
{ | ||
throw new Error(`Unsupported file type (${sourceStat.mode})`); | ||
} | ||
break; | ||
} | ||
operations.push(async () => destinationFs.chmodPromise(destination, sourceStat.mode & 0o777)); | ||
const destinationStat = await maybeLStat(destinationFs, destination); | ||
const sourceStat = await sourceFs.lstatPromise(source); | ||
utimes.push([destination, sourceStat.atime, sourceStat.mtime]); | ||
switch (true) { | ||
case sourceStat.isDirectory(): | ||
{ | ||
await copyFolder(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
case sourceStat.isFile(): | ||
{ | ||
await copyFile(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
case sourceStat.isSymbolicLink(): | ||
{ | ||
await copySymlink(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts); | ||
} | ||
break; | ||
default: | ||
{ | ||
throw new Error(`Unsupported file type (${sourceStat.mode})`); | ||
} | ||
break; | ||
} | ||
operations.push(async () => destinationFs.chmodPromise(destination, sourceStat.mode & 0o777)); | ||
} | ||
async function maybeLStat(baseFs, p) { | ||
try { | ||
return await baseFs.lstatPromise(p); | ||
} catch (e) { | ||
return null; | ||
} | ||
try { | ||
return await baseFs.lstatPromise(p); | ||
} | ||
catch (e) { | ||
return null; | ||
} | ||
} | ||
async function copyFolder(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { | ||
if (destinationStat !== null && !destinationStat.isDirectory()) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} else { | ||
return; | ||
if (destinationStat !== null && !destinationStat.isDirectory()) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} | ||
else { | ||
return; | ||
} | ||
} | ||
} | ||
if (destinationStat === null) operations.push(async () => destinationFs.mkdirPromise(destination, { | ||
mode: sourceStat.mode | ||
})); | ||
const entries = await sourceFs.readdirPromise(source); | ||
await Promise.all(entries.map(async entry => { | ||
await copyImpl(operations, utimes, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), opts); | ||
})); | ||
if (destinationStat === null) | ||
operations.push(async () => destinationFs.mkdirPromise(destination, { mode: sourceStat.mode })); | ||
const entries = await sourceFs.readdirPromise(source); | ||
await Promise.all(entries.map(async (entry) => { | ||
await copyImpl(operations, utimes, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), opts); | ||
})); | ||
} | ||
async function copyFile(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { | ||
if (destinationStat !== null) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} else { | ||
return; | ||
if (destinationStat !== null) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} | ||
else { | ||
return; | ||
} | ||
} | ||
} | ||
if (destinationFs === sourceFs) { | ||
operations.push(async () => destinationFs.copyFilePromise(source, destination, _fs.default.constants.COPYFILE_FICLONE)); | ||
} else { | ||
operations.push(async () => destinationFs.writeFilePromise(destination, (await sourceFs.readFilePromise(source)))); | ||
} | ||
if (destinationFs === sourceFs) { | ||
operations.push(async () => destinationFs.copyFilePromise(source, destination, fs_1.default.constants.COPYFILE_FICLONE)); | ||
} | ||
else { | ||
operations.push(async () => destinationFs.writeFilePromise(destination, await sourceFs.readFilePromise(source))); | ||
} | ||
} | ||
async function copySymlink(operations, utimes, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) { | ||
if (destinationStat !== null) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} else { | ||
return; | ||
if (destinationStat !== null) { | ||
if (opts.overwrite) { | ||
operations.push(async () => destinationFs.removePromise(destination)); | ||
destinationStat = null; | ||
} | ||
else { | ||
return; | ||
} | ||
} | ||
} | ||
const target = await sourceFs.readlinkPromise(source); | ||
operations.push(async () => destinationFs.symlinkPromise((0, _path.convertPath)(destinationFs.pathUtils, target), destination)); | ||
} | ||
const target = await sourceFs.readlinkPromise(source); | ||
operations.push(async () => destinationFs.symlinkPromise(path_1.convertPath(destinationFs.pathUtils, target), destination)); | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.AliasFS = void 0; | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
class AliasFS extends _ProxiedFS.ProxiedFS { | ||
constructor(target, { | ||
baseFs, | ||
pathUtils | ||
}) { | ||
super(pathUtils); | ||
this.target = void 0; | ||
this.baseFs = void 0; | ||
this.target = target; | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.target; | ||
} | ||
getBaseFs() { | ||
return this.baseFs; | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
mapToBase(p) { | ||
return p; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
class AliasFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(target, { baseFs, pathUtils }) { | ||
super(pathUtils); | ||
this.target = target; | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.target; | ||
} | ||
getBaseFs() { | ||
return this.baseFs; | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
mapToBase(p) { | ||
return p; | ||
} | ||
} | ||
exports.AliasFS = AliasFS; | ||
exports.AliasFS = AliasFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.CwdFS = void 0; | ||
var _NodeFS = require("./NodeFS"); | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
var _path = require("./path"); | ||
class CwdFS extends _ProxiedFS.ProxiedFS { | ||
constructor(target, { | ||
baseFs = new _NodeFS.NodeFS() | ||
} = {}) { | ||
super(_path.ppath); | ||
this.target = void 0; | ||
this.baseFs = void 0; | ||
this.target = target; | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.pathUtils.resolve(this.baseFs.getRealPath(), this.target); | ||
} | ||
mapFromBase(path) { | ||
return this.pathUtils.relative(this.getRealPath(), path); | ||
} | ||
mapToBase(path) { | ||
return this.pathUtils.resolve(this.getRealPath(), path); | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
const path_1 = require("./path"); | ||
class CwdFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(target, { baseFs = new NodeFS_1.NodeFS() } = {}) { | ||
super(path_1.ppath); | ||
this.target = target; | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.pathUtils.resolve(this.baseFs.getRealPath(), this.target); | ||
} | ||
mapFromBase(path) { | ||
return this.pathUtils.relative(this.getRealPath(), path); | ||
} | ||
mapToBase(path) { | ||
return this.pathUtils.resolve(this.getRealPath(), path); | ||
} | ||
} | ||
exports.CwdFS = CwdFS; | ||
exports.CwdFS = CwdFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.EBUSY = EBUSY; | ||
exports.ENOSYS = ENOSYS; | ||
exports.EINVAL = EINVAL; | ||
exports.EBADF = EBADF; | ||
exports.ENOENT = ENOENT; | ||
exports.ENOTDIR = ENOTDIR; | ||
exports.EISDIR = EISDIR; | ||
exports.EEXIST = EEXIST; | ||
exports.EROFS = EROFS; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function makeError(code, message) { | ||
return Object.assign(new Error(`${code}: ${message}`), { | ||
code | ||
}); | ||
return Object.assign(new Error(`${code}: ${message}`), { code }); | ||
} | ||
function EBUSY(message) { | ||
return makeError(`EBUSY`, message); | ||
return makeError(`EBUSY`, message); | ||
} | ||
exports.EBUSY = EBUSY; | ||
function ENOSYS(message, reason) { | ||
return makeError(`ENOSYS`, `${message}, ${reason}`); | ||
return makeError(`ENOSYS`, `${message}, ${reason}`); | ||
} | ||
exports.ENOSYS = ENOSYS; | ||
function EINVAL(reason) { | ||
return makeError(`EINVAL`, `invalid argument, ${reason}`); | ||
return makeError(`EINVAL`, `invalid argument, ${reason}`); | ||
} | ||
exports.EINVAL = EINVAL; | ||
function EBADF(reason) { | ||
return makeError(`EBADF`, `bad file descriptor, ${reason}`); | ||
return makeError(`EBADF`, `bad file descriptor, ${reason}`); | ||
} | ||
exports.EBADF = EBADF; | ||
function ENOENT(reason) { | ||
return makeError(`ENOENT`, `no such file or directory, ${reason}`); | ||
return makeError(`ENOENT`, `no such file or directory, ${reason}`); | ||
} | ||
exports.ENOENT = ENOENT; | ||
function ENOTDIR(reason) { | ||
return makeError(`ENOTDIR`, `not a directory, ${reason}`); | ||
return makeError(`ENOTDIR`, `not a directory, ${reason}`); | ||
} | ||
exports.ENOTDIR = ENOTDIR; | ||
function EISDIR(reason) { | ||
return makeError(`EISDIR`, `illegal operation on a directory, ${reason}`); | ||
return makeError(`EISDIR`, `illegal operation on a directory, ${reason}`); | ||
} | ||
exports.EISDIR = EISDIR; | ||
function EEXIST(reason) { | ||
return makeError(`EEXIST`, `file already exists, ${reason}`); | ||
return makeError(`EEXIST`, `file already exists, ${reason}`); | ||
} | ||
exports.EEXIST = EEXIST; | ||
function EROFS(reason) { | ||
return makeError(`EROFS`, `read-only filesystem, ${reason}`); | ||
} | ||
return makeError(`EROFS`, `read-only filesystem, ${reason}`); | ||
} | ||
exports.EROFS = EROFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.normalizeLineEndings = normalizeLineEndings; | ||
exports.BasePortableFakeFS = exports.FakeFS = void 0; | ||
var _os = require("os"); | ||
var _copyPromise = require("./algorithms/copyPromise"); | ||
var _path = require("./path"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const os_1 = require("os"); | ||
const copyPromise_1 = require("./algorithms/copyPromise"); | ||
const path_1 = require("./path"); | ||
const path_2 = require("./path"); | ||
class FakeFS { | ||
constructor(pathUtils) { | ||
this.pathUtils = void 0; | ||
this.pathUtils = pathUtils; | ||
} | ||
async removePromise(p) { | ||
let stat; | ||
try { | ||
stat = await this.lstatPromise(p); | ||
} catch (error) { | ||
if (error.code === `ENOENT`) { | ||
return; | ||
} else { | ||
throw error; | ||
} | ||
constructor(pathUtils) { | ||
this.pathUtils = pathUtils; | ||
} | ||
if (stat.isDirectory()) { | ||
for (const entry of await this.readdirPromise(p)) await this.removePromise(this.pathUtils.resolve(p, entry)); // 5 gives 1s worth of retries at worst | ||
for (let t = 0; t < 5; ++t) { | ||
async removePromise(p) { | ||
let stat; | ||
try { | ||
await this.rmdirPromise(p); | ||
break; | ||
} catch (error) { | ||
if (error.code === `EBUSY` || error.code === `ENOTEMPTY`) { | ||
await new Promise(resolve => setTimeout(resolve, t * 100)); | ||
continue; | ||
} else { | ||
throw error; | ||
} | ||
stat = await this.lstatPromise(p); | ||
} | ||
} | ||
} else { | ||
await this.unlinkPromise(p); | ||
catch (error) { | ||
if (error.code === `ENOENT`) { | ||
return; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
if (stat.isDirectory()) { | ||
for (const entry of await this.readdirPromise(p)) | ||
await this.removePromise(this.pathUtils.resolve(p, entry)); | ||
// 5 gives 1s worth of retries at worst | ||
for (let t = 0; t < 5; ++t) { | ||
try { | ||
await this.rmdirPromise(p); | ||
break; | ||
} | ||
catch (error) { | ||
if (error.code === `EBUSY` || error.code === `ENOTEMPTY`) { | ||
await new Promise(resolve => setTimeout(resolve, t * 100)); | ||
continue; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
await this.unlinkPromise(p); | ||
} | ||
} | ||
} | ||
removeSync(p) { | ||
let stat; | ||
try { | ||
stat = this.lstatSync(p); | ||
} catch (error) { | ||
if (error.code === `ENOENT`) { | ||
return; | ||
} else { | ||
throw error; | ||
} | ||
removeSync(p) { | ||
let stat; | ||
try { | ||
stat = this.lstatSync(p); | ||
} | ||
catch (error) { | ||
if (error.code === `ENOENT`) { | ||
return; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
if (stat.isDirectory()) { | ||
for (const entry of this.readdirSync(p)) | ||
this.removeSync(this.pathUtils.resolve(p, entry)); | ||
this.rmdirSync(p); | ||
} | ||
else { | ||
this.unlinkSync(p); | ||
} | ||
} | ||
if (stat.isDirectory()) { | ||
for (const entry of this.readdirSync(p)) this.removeSync(this.pathUtils.resolve(p, entry)); | ||
this.rmdirSync(p); | ||
} else { | ||
this.unlinkSync(p); | ||
async mkdirpPromise(p, { chmod, utimes } = {}) { | ||
p = this.resolve(p); | ||
if (p === this.pathUtils.dirname(p)) | ||
return; | ||
const parts = p.split(this.pathUtils.sep); | ||
for (let u = 2; u <= parts.length; ++u) { | ||
const subPath = parts.slice(0, u).join(this.pathUtils.sep); | ||
if (!this.existsSync(subPath)) { | ||
try { | ||
await this.mkdirPromise(subPath); | ||
} | ||
catch (error) { | ||
if (error.code === `EEXIST`) { | ||
continue; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
if (chmod != null) | ||
await this.chmodPromise(subPath, chmod); | ||
if (utimes != null) { | ||
await this.utimesPromise(subPath, utimes[0], utimes[1]); | ||
} | ||
else { | ||
const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); | ||
await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
async mkdirpPromise(p, { | ||
chmod, | ||
utimes | ||
} = {}) { | ||
p = this.resolve(p); | ||
if (p === this.pathUtils.dirname(p)) return; | ||
const parts = p.split(this.pathUtils.sep); | ||
for (let u = 2; u <= parts.length; ++u) { | ||
const subPath = parts.slice(0, u).join(this.pathUtils.sep); | ||
if (!this.existsSync(subPath)) { | ||
mkdirpSync(p, { chmod, utimes } = {}) { | ||
p = this.resolve(p); | ||
if (p === this.pathUtils.dirname(p)) | ||
return; | ||
const parts = p.split(this.pathUtils.sep); | ||
for (let u = 2; u <= parts.length; ++u) { | ||
const subPath = parts.slice(0, u).join(this.pathUtils.sep); | ||
if (!this.existsSync(subPath)) { | ||
try { | ||
this.mkdirSync(subPath); | ||
} | ||
catch (error) { | ||
if (error.code === `EEXIST`) { | ||
continue; | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
if (chmod != null) | ||
this.chmodSync(subPath, chmod); | ||
if (utimes != null) { | ||
this.utimesSync(subPath, utimes[0], utimes[1]); | ||
} | ||
else { | ||
const parentStat = this.statSync(this.pathUtils.dirname(subPath)); | ||
this.utimesSync(subPath, parentStat.atime, parentStat.mtime); | ||
} | ||
} | ||
} | ||
} | ||
async copyPromise(destination, source, { baseFs = this, overwrite = true } = {}) { | ||
return await copyPromise_1.copyPromise(this, destination, baseFs, source, { overwrite }); | ||
} | ||
copySync(destination, source, { baseFs = this, overwrite = true } = {}) { | ||
const stat = baseFs.lstatSync(source); | ||
const exists = this.existsSync(destination); | ||
if (stat.isDirectory()) { | ||
this.mkdirpSync(destination); | ||
const directoryListing = baseFs.readdirSync(source); | ||
for (const entry of directoryListing) { | ||
this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { baseFs, overwrite }); | ||
} | ||
} | ||
else if (stat.isFile()) { | ||
if (!exists || overwrite) { | ||
if (exists) | ||
this.removeSync(destination); | ||
const content = baseFs.readFileSync(source); | ||
this.writeFileSync(destination, content); | ||
} | ||
} | ||
else if (stat.isSymbolicLink()) { | ||
if (!exists || overwrite) { | ||
if (exists) | ||
this.removeSync(destination); | ||
const target = baseFs.readlinkSync(source); | ||
this.symlinkSync(path_2.convertPath(this.pathUtils, target), destination); | ||
} | ||
} | ||
else { | ||
throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); | ||
} | ||
const mode = stat.mode & 0o777; | ||
this.chmodSync(destination, mode); | ||
} | ||
async changeFilePromise(p, content, { automaticNewlines } = {}) { | ||
let current = ''; | ||
try { | ||
await this.mkdirPromise(subPath); | ||
} catch (error) { | ||
if (error.code === `EEXIST`) { | ||
continue; | ||
} else { | ||
throw error; | ||
} | ||
current = await this.readFilePromise(p, `utf8`); | ||
} | ||
if (chmod != null) await this.chmodPromise(subPath, chmod); | ||
if (utimes != null) { | ||
await this.utimesPromise(subPath, utimes[0], utimes[1]); | ||
} else { | ||
const parentStat = await this.statPromise(this.pathUtils.dirname(subPath)); | ||
await this.utimesPromise(subPath, parentStat.atime, parentStat.mtime); | ||
catch (error) { | ||
// ignore errors, no big deal | ||
} | ||
} | ||
const normalizedContent = automaticNewlines | ||
? normalizeLineEndings(current, content) | ||
: content; | ||
if (current === normalizedContent) | ||
return; | ||
await this.writeFilePromise(p, normalizedContent); | ||
} | ||
} | ||
mkdirpSync(p, { | ||
chmod, | ||
utimes | ||
} = {}) { | ||
p = this.resolve(p); | ||
if (p === this.pathUtils.dirname(p)) return; | ||
const parts = p.split(this.pathUtils.sep); | ||
for (let u = 2; u <= parts.length; ++u) { | ||
const subPath = parts.slice(0, u).join(this.pathUtils.sep); | ||
if (!this.existsSync(subPath)) { | ||
changeFileSync(p, content, { automaticNewlines = false } = {}) { | ||
let current = ''; | ||
try { | ||
this.mkdirSync(subPath); | ||
} catch (error) { | ||
if (error.code === `EEXIST`) { | ||
continue; | ||
} else { | ||
throw error; | ||
} | ||
current = this.readFileSync(p, `utf8`); | ||
} | ||
if (chmod != null) this.chmodSync(subPath, chmod); | ||
if (utimes != null) { | ||
this.utimesSync(subPath, utimes[0], utimes[1]); | ||
} else { | ||
const parentStat = this.statSync(this.pathUtils.dirname(subPath)); | ||
this.utimesSync(subPath, parentStat.atime, parentStat.mtime); | ||
catch (error) { | ||
// ignore errors, no big deal | ||
} | ||
} | ||
const normalizedContent = automaticNewlines | ||
? normalizeLineEndings(current, content) | ||
: content; | ||
if (current === normalizedContent) | ||
return; | ||
this.writeFileSync(p, normalizedContent); | ||
} | ||
} | ||
async copyPromise(destination, source, { | ||
baseFs = this, | ||
overwrite = true | ||
} = {}) { | ||
return await (0, _copyPromise.copyPromise)(this, destination, baseFs, source, { | ||
overwrite | ||
}); | ||
} | ||
copySync(destination, source, { | ||
baseFs = this, | ||
overwrite = true | ||
} = {}) { | ||
const stat = baseFs.lstatSync(source); | ||
const exists = this.existsSync(destination); | ||
if (stat.isDirectory()) { | ||
this.mkdirpSync(destination); | ||
const directoryListing = baseFs.readdirSync(source); | ||
for (const entry of directoryListing) { | ||
this.copySync(this.pathUtils.join(destination, entry), baseFs.pathUtils.join(source, entry), { | ||
baseFs, | ||
overwrite | ||
}); | ||
} | ||
} else if (stat.isFile()) { | ||
if (!exists || overwrite) { | ||
if (exists) this.removeSync(destination); | ||
const content = baseFs.readFileSync(source); | ||
this.writeFileSync(destination, content); | ||
} | ||
} else if (stat.isSymbolicLink()) { | ||
if (!exists || overwrite) { | ||
if (exists) this.removeSync(destination); | ||
const target = baseFs.readlinkSync(source); | ||
this.symlinkSync((0, _path.convertPath)(this.pathUtils, target), destination); | ||
} | ||
} else { | ||
throw new Error(`Unsupported file type (file: ${source}, mode: 0o${stat.mode.toString(8).padStart(6, `0`)})`); | ||
async movePromise(fromP, toP) { | ||
try { | ||
await this.renamePromise(fromP, toP); | ||
} | ||
catch (error) { | ||
if (error.code === `EXDEV`) { | ||
await this.copyPromise(toP, fromP); | ||
await this.removePromise(fromP); | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
const mode = stat.mode & 0o777; | ||
this.chmodSync(destination, mode); | ||
} | ||
async changeFilePromise(p, content, { | ||
automaticNewlines | ||
} = {}) { | ||
let current = ''; | ||
try { | ||
current = await this.readFilePromise(p, `utf8`); | ||
} catch (error) {// ignore errors, no big deal | ||
moveSync(fromP, toP) { | ||
try { | ||
this.renameSync(fromP, toP); | ||
} | ||
catch (error) { | ||
if (error.code === `EXDEV`) { | ||
this.copySync(toP, fromP); | ||
this.removeSync(fromP); | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; | ||
if (current === normalizedContent) return; | ||
await this.writeFilePromise(p, normalizedContent); | ||
} | ||
changeFileSync(p, content, { | ||
automaticNewlines = false | ||
} = {}) { | ||
let current = ''; | ||
try { | ||
current = this.readFileSync(p, `utf8`); | ||
} catch (error) {// ignore errors, no big deal | ||
} | ||
const normalizedContent = automaticNewlines ? normalizeLineEndings(current, content) : content; | ||
if (current === normalizedContent) return; | ||
this.writeFileSync(p, normalizedContent); | ||
} | ||
async movePromise(fromP, toP) { | ||
try { | ||
await this.renamePromise(fromP, toP); | ||
} catch (error) { | ||
if (error.code === `EXDEV`) { | ||
await this.copyPromise(toP, fromP); | ||
await this.removePromise(fromP); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
moveSync(fromP, toP) { | ||
try { | ||
this.renameSync(fromP, toP); | ||
} catch (error) { | ||
if (error.code === `EXDEV`) { | ||
this.copySync(toP, fromP); | ||
this.removeSync(fromP); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
} | ||
async lockPromise(affectedPath, callback) { | ||
const lockPath = `${affectedPath}.flock`; | ||
const interval = 1000 / 60; | ||
const startTime = Date.now(); | ||
let fd = null; // Even when we detect that a lock file exists, we still look inside to see | ||
// whether the pid that created it is still alive. It's not foolproof | ||
// (there are false positive), but there are no false negative and that's | ||
// all that matters in 99% of the cases. | ||
const isAlive = async () => { | ||
let pid; | ||
try { | ||
[pid] = await this.readJsonPromise(lockPath); | ||
} catch (error) { | ||
// If we can't read the file repeatedly, we assume the process was | ||
// aborted before even writing finishing writing the payload. | ||
return Date.now() - startTime < 500; | ||
} | ||
try { | ||
// "As a special case, a signal of 0 can be used to test for the | ||
// existence of a process" - so we check whether it's alive. | ||
process.kill(pid, 0); | ||
return true; | ||
} catch (error) { | ||
return false; | ||
} | ||
}; | ||
while (fd === null) { | ||
try { | ||
fd = await this.openPromise(lockPath, `wx`); | ||
} catch (error) { | ||
if (error.code === `EEXIST`) { | ||
if (!(await isAlive())) { | ||
async lockPromise(affectedPath, callback) { | ||
const lockPath = `${affectedPath}.flock`; | ||
const interval = 1000 / 60; | ||
const startTime = Date.now(); | ||
let fd = null; | ||
// Even when we detect that a lock file exists, we still look inside to see | ||
// whether the pid that created it is still alive. It's not foolproof | ||
// (there are false positive), but there are no false negative and that's | ||
// all that matters in 99% of the cases. | ||
const isAlive = async () => { | ||
let pid; | ||
try { | ||
await this.unlinkPromise(lockPath); | ||
continue; | ||
} catch (error) {// No big deal if we can't remove it. Just fallback to wait for | ||
// it to be eventually released by its owner. | ||
([pid] = await this.readJsonPromise(lockPath)); | ||
} | ||
} | ||
if (Date.now() - startTime < 60 * 1000) { | ||
await new Promise(resolve => setTimeout(resolve, interval)); | ||
} else { | ||
throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); | ||
} | ||
} else { | ||
throw error; | ||
catch (error) { | ||
// If we can't read the file repeatedly, we assume the process was | ||
// aborted before even writing finishing writing the payload. | ||
return Date.now() - startTime < 500; | ||
} | ||
try { | ||
// "As a special case, a signal of 0 can be used to test for the | ||
// existence of a process" - so we check whether it's alive. | ||
process.kill(pid, 0); | ||
return true; | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
}; | ||
while (fd === null) { | ||
try { | ||
fd = await this.openPromise(lockPath, `wx`); | ||
} | ||
catch (error) { | ||
if (error.code === `EEXIST`) { | ||
if (!await isAlive()) { | ||
try { | ||
await this.unlinkPromise(lockPath); | ||
continue; | ||
} | ||
catch (error) { | ||
// No big deal if we can't remove it. Just fallback to wait for | ||
// it to be eventually released by its owner. | ||
} | ||
} | ||
if (Date.now() - startTime < 60 * 1000) { | ||
await new Promise(resolve => setTimeout(resolve, interval)); | ||
} | ||
else { | ||
throw new Error(`Couldn't acquire a lock in a reasonable time (via ${lockPath})`); | ||
} | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
} | ||
await this.writePromise(fd, JSON.stringify([process.pid])); | ||
try { | ||
return await callback(); | ||
} | ||
finally { | ||
await this.closePromise(fd); | ||
await this.unlinkPromise(lockPath); | ||
} | ||
} | ||
await this.writePromise(fd, JSON.stringify([process.pid])); | ||
try { | ||
return await callback(); | ||
} finally { | ||
await this.closePromise(fd); | ||
await this.unlinkPromise(lockPath); | ||
async readJsonPromise(p) { | ||
const content = await this.readFilePromise(p, `utf8`); | ||
try { | ||
return JSON.parse(content); | ||
} | ||
catch (error) { | ||
error.message += ` (in ${p})`; | ||
throw error; | ||
} | ||
} | ||
} | ||
async readJsonPromise(p) { | ||
const content = await this.readFilePromise(p, `utf8`); | ||
try { | ||
return JSON.parse(content); | ||
} catch (error) { | ||
error.message += ` (in ${p})`; | ||
throw error; | ||
async readJsonSync(p) { | ||
const content = this.readFileSync(p, `utf8`); | ||
try { | ||
return JSON.parse(content); | ||
} | ||
catch (error) { | ||
error.message += ` (in ${p})`; | ||
throw error; | ||
} | ||
} | ||
} | ||
async readJsonSync(p) { | ||
const content = this.readFileSync(p, `utf8`); | ||
try { | ||
return JSON.parse(content); | ||
} catch (error) { | ||
error.message += ` (in ${p})`; | ||
throw error; | ||
async writeJsonPromise(p, data) { | ||
return await this.writeFilePromise(p, `${JSON.stringify(data, null, 2)}\n`); | ||
} | ||
} | ||
async writeJsonPromise(p, data) { | ||
return await this.writeFilePromise(p, `${JSON.stringify(data, null, 2)}\n`); | ||
} | ||
writeJsonSync(p, data) { | ||
return this.writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`); | ||
} | ||
async preserveTimePromise(p, cb) { | ||
const stat = await this.lstatPromise(p); | ||
const result = await cb(); | ||
if (typeof result !== `undefined`) p = result; | ||
if (this.lutimesPromise) { | ||
await this.lutimesPromise(p, stat.atime, stat.mtime); | ||
} else if (!stat.isSymbolicLink()) { | ||
await this.utimesPromise(p, stat.atime, stat.mtime); | ||
writeJsonSync(p, data) { | ||
return this.writeFileSync(p, `${JSON.stringify(data, null, 2)}\n`); | ||
} | ||
} | ||
async preserveTimeSync(p, cb) { | ||
const stat = this.lstatSync(p); | ||
const result = cb(); | ||
if (typeof result !== `undefined`) p = result; | ||
if (this.lutimesSync) { | ||
this.lutimesSync(p, stat.atime, stat.mtime); | ||
} else if (!stat.isSymbolicLink()) { | ||
this.utimesSync(p, stat.atime, stat.mtime); | ||
async preserveTimePromise(p, cb) { | ||
const stat = await this.lstatPromise(p); | ||
const result = await cb(); | ||
if (typeof result !== `undefined`) | ||
p = result; | ||
if (this.lutimesPromise) { | ||
await this.lutimesPromise(p, stat.atime, stat.mtime); | ||
} | ||
else if (!stat.isSymbolicLink()) { | ||
await this.utimesPromise(p, stat.atime, stat.mtime); | ||
} | ||
} | ||
} | ||
async preserveTimeSync(p, cb) { | ||
const stat = this.lstatSync(p); | ||
const result = cb(); | ||
if (typeof result !== `undefined`) | ||
p = result; | ||
if (this.lutimesSync) { | ||
this.lutimesSync(p, stat.atime, stat.mtime); | ||
} | ||
else if (!stat.isSymbolicLink()) { | ||
this.utimesSync(p, stat.atime, stat.mtime); | ||
} | ||
} | ||
} | ||
exports.FakeFS = FakeFS; | ||
FakeFS.DEFAULT_TIME = 315532800; | ||
; | ||
class BasePortableFakeFS extends FakeFS { | ||
constructor() { | ||
super(_path.ppath); | ||
} | ||
resolve(p) { | ||
return this.pathUtils.resolve(_path.PortablePath.root, p); | ||
} | ||
constructor() { | ||
super(path_2.ppath); | ||
} | ||
resolve(p) { | ||
return this.pathUtils.resolve(path_1.PortablePath.root, p); | ||
} | ||
} | ||
exports.BasePortableFakeFS = BasePortableFakeFS; | ||
function getEndOfLine(content) { | ||
const matches = content.match(/\r?\n/g); | ||
if (matches === null) return _os.EOL; | ||
const crlf = matches.filter(nl => nl === `\r\n`).length; | ||
const lf = matches.length - crlf; | ||
return crlf > lf ? `\r\n` : `\n`; | ||
const matches = content.match(/\r?\n/g); | ||
if (matches === null) | ||
return os_1.EOL; | ||
const crlf = matches.filter(nl => nl === `\r\n`).length; | ||
const lf = matches.length - crlf; | ||
return crlf > lf ? `\r\n` : `\n`; | ||
} | ||
function normalizeLineEndings(originalContent, newContent) { | ||
return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); | ||
} | ||
return newContent.replace(/\r?\n/g, getEndOfLine(originalContent)); | ||
} | ||
exports.normalizeLineEndings = normalizeLineEndings; |
548
lib/index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.patchFs = patchFs; | ||
exports.extendFs = extendFs; | ||
Object.defineProperty(exports, "CreateReadStreamOptions", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.CreateReadStreamOptions; | ||
} | ||
}); | ||
Object.defineProperty(exports, "CreateWriteStreamOptions", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.CreateWriteStreamOptions; | ||
} | ||
}); | ||
Object.defineProperty(exports, "MkdirOptions", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.MkdirOptions; | ||
} | ||
}); | ||
Object.defineProperty(exports, "WatchOptions", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.WatchOptions; | ||
} | ||
}); | ||
Object.defineProperty(exports, "WatchCallback", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.WatchCallback; | ||
} | ||
}); | ||
Object.defineProperty(exports, "Watcher", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.Watcher; | ||
} | ||
}); | ||
Object.defineProperty(exports, "WriteFileOptions", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.WriteFileOptions; | ||
} | ||
}); | ||
Object.defineProperty(exports, "normalizeLineEndings", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.normalizeLineEndings; | ||
} | ||
}); | ||
Object.defineProperty(exports, "FakeFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _FakeFS.FakeFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "NodeFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _NodeFS.NodeFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "FSPath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.FSPath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "Path", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.Path; | ||
} | ||
}); | ||
Object.defineProperty(exports, "PortablePath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.PortablePath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "NativePath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.NativePath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "Filename", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.Filename; | ||
} | ||
}); | ||
Object.defineProperty(exports, "ParsedPath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.ParsedPath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "PathUtils", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.PathUtils; | ||
} | ||
}); | ||
Object.defineProperty(exports, "FormatInputPathObject", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.FormatInputPathObject; | ||
} | ||
}); | ||
Object.defineProperty(exports, "npath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.npath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "ppath", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.ppath; | ||
} | ||
}); | ||
Object.defineProperty(exports, "toFilename", { | ||
enumerable: true, | ||
get: function () { | ||
return _path.toFilename; | ||
} | ||
}); | ||
Object.defineProperty(exports, "AliasFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _AliasFS.AliasFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "CwdFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _CwdFS.CwdFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "JailFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _JailFS.JailFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "LazyFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _LazyFS.LazyFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "NoFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _NoFS.NoFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "PosixFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _PosixFS.PosixFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "ProxiedFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _ProxiedFS.ProxiedFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "VirtualFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _VirtualFS.VirtualFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "ZipFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _ZipFS.ZipFS; | ||
} | ||
}); | ||
Object.defineProperty(exports, "ZipOpenFS", { | ||
enumerable: true, | ||
get: function () { | ||
return _ZipOpenFS.ZipOpenFS; | ||
} | ||
}); | ||
exports.xfs = void 0; | ||
var _FakeFS = require("./FakeFS"); | ||
var _NodeFS = require("./NodeFS"); | ||
var _path = require("./path"); | ||
var _AliasFS = require("./AliasFS"); | ||
var _CwdFS = require("./CwdFS"); | ||
var _JailFS = require("./JailFS"); | ||
var _LazyFS = require("./LazyFS"); | ||
var _NoFS = require("./NoFS"); | ||
var _PosixFS = require("./PosixFS"); | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
var _VirtualFS = require("./VirtualFS"); | ||
var _ZipFS = require("./ZipFS"); | ||
var _ZipOpenFS = require("./ZipOpenFS"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const path_1 = require("./path"); | ||
var FakeFS_1 = require("./FakeFS"); | ||
exports.normalizeLineEndings = FakeFS_1.normalizeLineEndings; | ||
var path_2 = require("./path"); | ||
exports.PortablePath = path_2.PortablePath; | ||
var path_3 = require("./path"); | ||
exports.npath = path_3.npath; | ||
exports.ppath = path_3.ppath; | ||
exports.toFilename = path_3.toFilename; | ||
var AliasFS_1 = require("./AliasFS"); | ||
exports.AliasFS = AliasFS_1.AliasFS; | ||
var FakeFS_2 = require("./FakeFS"); | ||
exports.FakeFS = FakeFS_2.FakeFS; | ||
var CwdFS_1 = require("./CwdFS"); | ||
exports.CwdFS = CwdFS_1.CwdFS; | ||
var JailFS_1 = require("./JailFS"); | ||
exports.JailFS = JailFS_1.JailFS; | ||
var LazyFS_1 = require("./LazyFS"); | ||
exports.LazyFS = LazyFS_1.LazyFS; | ||
var NoFS_1 = require("./NoFS"); | ||
exports.NoFS = NoFS_1.NoFS; | ||
var NodeFS_2 = require("./NodeFS"); | ||
exports.NodeFS = NodeFS_2.NodeFS; | ||
var PosixFS_1 = require("./PosixFS"); | ||
exports.PosixFS = PosixFS_1.PosixFS; | ||
var ProxiedFS_1 = require("./ProxiedFS"); | ||
exports.ProxiedFS = ProxiedFS_1.ProxiedFS; | ||
var VirtualFS_1 = require("./VirtualFS"); | ||
exports.VirtualFS = VirtualFS_1.VirtualFS; | ||
var ZipFS_1 = require("./ZipFS"); | ||
exports.ZipFS = ZipFS_1.ZipFS; | ||
var ZipOpenFS_1 = require("./ZipOpenFS"); | ||
exports.ZipOpenFS = ZipOpenFS_1.ZipOpenFS; | ||
function patchFs(patchedFs, fakeFs) { | ||
const SYNC_IMPLEMENTATIONS = new Set([`accessSync`, `appendFileSync`, `createReadStream`, `chmodSync`, `closeSync`, `copyFileSync`, `lstatSync`, `mkdirSync`, `openSync`, `readSync`, `readlinkSync`, `readFileSync`, `readdirSync`, `readlinkSync`, `realpathSync`, `renameSync`, `rmdirSync`, `statSync`, `symlinkSync`, `unlinkSync`, `utimesSync`, `watch`, `writeFileSync`, `writeSync`]); | ||
const ASYNC_IMPLEMENTATIONS = new Set([`accessPromise`, `appendFilePromise`, `chmodPromise`, `closePromise`, `copyFilePromise`, `lstatPromise`, `mkdirPromise`, `openPromise`, `readdirPromise`, `realpathPromise`, `readFilePromise`, `readdirPromise`, `readlinkPromise`, `renamePromise`, `rmdirPromise`, `statPromise`, `symlinkPromise`, `unlinkPromise`, `utimesPromise`, `writeFilePromise`, `writeSync`]); | ||
patchedFs.existsSync = p => { | ||
try { | ||
return fakeFs.existsSync(p); | ||
} catch (error) { | ||
return false; | ||
} | ||
}; | ||
patchedFs.exists = (p, ...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => {}; | ||
process.nextTick(() => { | ||
fakeFs.existsPromise(p).then(exists => { | ||
callback(exists); | ||
}, () => { | ||
callback(false); | ||
}); | ||
}); | ||
}; | ||
patchedFs.read = (p, buffer, ...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => {}; | ||
process.nextTick(() => { | ||
fakeFs.readPromise(p, buffer, ...args).then(bytesRead => { | ||
callback(null, bytesRead, buffer); | ||
}, error => { | ||
callback(error); | ||
}); | ||
}); | ||
}; | ||
for (const fnName of ASYNC_IMPLEMENTATIONS) { | ||
const fakeImpl = fakeFs[fnName].bind(fakeFs); | ||
const origName = fnName.replace(/Promise$/, ``); | ||
patchedFs[origName] = (...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => {}; | ||
process.nextTick(() => { | ||
fakeImpl(...args).then(result => { | ||
callback(null, result); | ||
}, error => { | ||
callback(error); | ||
const SYNC_IMPLEMENTATIONS = new Set([ | ||
`accessSync`, | ||
`appendFileSync`, | ||
`createReadStream`, | ||
`chmodSync`, | ||
`closeSync`, | ||
`copyFileSync`, | ||
`lstatSync`, | ||
`mkdirSync`, | ||
`openSync`, | ||
`readSync`, | ||
`readlinkSync`, | ||
`readFileSync`, | ||
`readdirSync`, | ||
`readlinkSync`, | ||
`realpathSync`, | ||
`renameSync`, | ||
`rmdirSync`, | ||
`statSync`, | ||
`symlinkSync`, | ||
`unlinkSync`, | ||
`utimesSync`, | ||
`watch`, | ||
`writeFileSync`, | ||
`writeSync`, | ||
]); | ||
const ASYNC_IMPLEMENTATIONS = new Set([ | ||
`accessPromise`, | ||
`appendFilePromise`, | ||
`chmodPromise`, | ||
`closePromise`, | ||
`copyFilePromise`, | ||
`lstatPromise`, | ||
`mkdirPromise`, | ||
`openPromise`, | ||
`readdirPromise`, | ||
`realpathPromise`, | ||
`readFilePromise`, | ||
`readdirPromise`, | ||
`readlinkPromise`, | ||
`renamePromise`, | ||
`rmdirPromise`, | ||
`statPromise`, | ||
`symlinkPromise`, | ||
`unlinkPromise`, | ||
`utimesPromise`, | ||
`writeFilePromise`, | ||
`writeSync`, | ||
]); | ||
patchedFs.existsSync = (p) => { | ||
try { | ||
return fakeFs.existsSync(p); | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
}; | ||
patchedFs.exists = (p, ...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => { }; | ||
process.nextTick(() => { | ||
fakeFs.existsPromise(p).then(exists => { | ||
callback(exists); | ||
}, () => { | ||
callback(false); | ||
}); | ||
}); | ||
}); | ||
}; | ||
} | ||
for (const fnName of SYNC_IMPLEMENTATIONS) { | ||
const fakeImpl = fakeFs[fnName].bind(fakeFs); | ||
const origName = fnName; | ||
patchedFs[origName] = fakeImpl; | ||
} | ||
patchedFs.realpathSync.native = patchedFs.realpathSync; | ||
patchedFs.realpath.native = patchedFs.realpath; | ||
patchedFs.read = (p, buffer, ...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => { }; | ||
process.nextTick(() => { | ||
fakeFs.readPromise(p, buffer, ...args).then(bytesRead => { | ||
callback(null, bytesRead, buffer); | ||
}, error => { | ||
callback(error); | ||
}); | ||
}); | ||
}; | ||
for (const fnName of ASYNC_IMPLEMENTATIONS) { | ||
const fakeImpl = fakeFs[fnName].bind(fakeFs); | ||
const origName = fnName.replace(/Promise$/, ``); | ||
patchedFs[origName] = (...args) => { | ||
const hasCallback = typeof args[args.length - 1] === `function`; | ||
const callback = hasCallback ? args.pop() : () => { }; | ||
process.nextTick(() => { | ||
fakeImpl(...args).then((result) => { | ||
callback(null, result); | ||
}, (error) => { | ||
callback(error); | ||
}); | ||
}); | ||
}; | ||
} | ||
for (const fnName of SYNC_IMPLEMENTATIONS) { | ||
const fakeImpl = fakeFs[fnName].bind(fakeFs); | ||
const origName = fnName; | ||
patchedFs[origName] = fakeImpl; | ||
} | ||
patchedFs.realpathSync.native = patchedFs.realpathSync; | ||
patchedFs.realpath.native = patchedFs.realpath; | ||
} | ||
exports.patchFs = patchFs; | ||
function extendFs(realFs, fakeFs) { | ||
const patchedFs = Object.create(realFs); | ||
patchFs(patchedFs, fakeFs); | ||
return patchedFs; | ||
const patchedFs = Object.create(realFs); | ||
patchFs(patchedFs, fakeFs); | ||
return patchedFs; | ||
} | ||
const xfs = Object.assign(new _NodeFS.NodeFS(), { | ||
mktempSync(cb) { | ||
// We lazily load `tmp` because it injects itself into the `process` | ||
// events (to clean the folders at exit time), and it may lead to | ||
// large memory leaks. Better avoid loading it until we can't do | ||
// otherwise (ideally the fix would be for `tmp` itself to only | ||
// attach cleaners after the first call). | ||
const tmp = require(`tmp`); | ||
const { | ||
name, | ||
removeCallback | ||
} = tmp.dirSync({ | ||
unsafeCleanup: true | ||
}); | ||
if (typeof cb === `undefined`) { | ||
return _path.npath.toPortablePath(name); | ||
} else { | ||
try { | ||
return cb(_path.npath.toPortablePath(name)); | ||
} finally { | ||
removeCallback(); | ||
} | ||
} | ||
}, | ||
mktempPromise(cb) { | ||
// We lazily load `tmp` because it injects itself into the `process` | ||
// events (to clean the folders at exit time), and it may lead to | ||
// large memory leaks. Better avoid loading it until we can't do | ||
// otherwise (ideally the fix would be for `tmp` itself to only | ||
// attach cleaners after the first call). | ||
const tmp = require(`tmp`); | ||
if (typeof cb === `undefined`) { | ||
return new Promise((resolve, reject) => { | ||
tmp.dir({ | ||
unsafeCleanup: true | ||
}, (err, path) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(_path.npath.toPortablePath(path)); | ||
} | ||
}); | ||
}); | ||
} else { | ||
return new Promise((resolve, reject) => { | ||
tmp.dir({ | ||
unsafeCleanup: true | ||
}, (err, path, cleanup) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
Promise.resolve(_path.npath.toPortablePath(path)).then(cb).then(result => { | ||
cleanup(); | ||
resolve(result); | ||
}, error => { | ||
cleanup(); | ||
reject(error); | ||
exports.extendFs = extendFs; | ||
exports.xfs = Object.assign(new NodeFS_1.NodeFS(), { | ||
mktempSync(cb) { | ||
// We lazily load `tmp` because it injects itself into the `process` | ||
// events (to clean the folders at exit time), and it may lead to | ||
// large memory leaks. Better avoid loading it until we can't do | ||
// otherwise (ideally the fix would be for `tmp` itself to only | ||
// attach cleaners after the first call). | ||
const tmp = require(`tmp`); | ||
const { name, removeCallback } = tmp.dirSync({ unsafeCleanup: true }); | ||
if (typeof cb === `undefined`) { | ||
return path_1.npath.toPortablePath(name); | ||
} | ||
else { | ||
try { | ||
return cb(path_1.npath.toPortablePath(name)); | ||
} | ||
finally { | ||
removeCallback(); | ||
} | ||
} | ||
}, | ||
mktempPromise(cb) { | ||
// We lazily load `tmp` because it injects itself into the `process` | ||
// events (to clean the folders at exit time), and it may lead to | ||
// large memory leaks. Better avoid loading it until we can't do | ||
// otherwise (ideally the fix would be for `tmp` itself to only | ||
// attach cleaners after the first call). | ||
const tmp = require(`tmp`); | ||
if (typeof cb === `undefined`) { | ||
return new Promise((resolve, reject) => { | ||
tmp.dir({ unsafeCleanup: true }, (err, path) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
resolve(path_1.npath.toPortablePath(path)); | ||
} | ||
}); | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
} | ||
else { | ||
return new Promise((resolve, reject) => { | ||
tmp.dir({ unsafeCleanup: true }, (err, path, cleanup) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
Promise.resolve(path_1.npath.toPortablePath(path)).then(cb).then(result => { | ||
cleanup(); | ||
resolve(result); | ||
}, error => { | ||
cleanup(); | ||
reject(error); | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
}, | ||
}); | ||
exports.xfs = xfs; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.JailFS = void 0; | ||
var _NodeFS = require("./NodeFS"); | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
var _path = require("./path"); | ||
const JAIL_ROOT = _path.PortablePath.root; | ||
class JailFS extends _ProxiedFS.ProxiedFS { | ||
constructor(target, { | ||
baseFs = new _NodeFS.NodeFS() | ||
} = {}) { | ||
super(_path.ppath); | ||
this.target = void 0; | ||
this.baseFs = void 0; | ||
this.target = this.pathUtils.resolve(_path.PortablePath.root, target); | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.pathUtils.resolve(this.baseFs.getRealPath(), this.pathUtils.relative(_path.PortablePath.root, this.target)); | ||
} | ||
getTarget() { | ||
return this.target; | ||
} | ||
getBaseFs() { | ||
return this.baseFs; | ||
} | ||
mapToBase(p) { | ||
const normalized = this.pathUtils.normalize(p); | ||
if (this.pathUtils.isAbsolute(p)) return this.pathUtils.resolve(this.target, this.pathUtils.relative(JAIL_ROOT, p)); | ||
if (normalized.match(/^\.\.\//)) throw new Error(`Resolving this path (${p}) would escape the jail`); | ||
return this.pathUtils.resolve(this.target, p); | ||
} | ||
mapFromBase(p) { | ||
return this.pathUtils.resolve(JAIL_ROOT, this.pathUtils.relative(this.target, p)); | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
const path_1 = require("./path"); | ||
const JAIL_ROOT = path_1.PortablePath.root; | ||
class JailFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(target, { baseFs = new NodeFS_1.NodeFS() } = {}) { | ||
super(path_1.ppath); | ||
this.target = this.pathUtils.resolve(path_1.PortablePath.root, target); | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.pathUtils.resolve(this.baseFs.getRealPath(), this.pathUtils.relative(path_1.PortablePath.root, this.target)); | ||
} | ||
getTarget() { | ||
return this.target; | ||
} | ||
getBaseFs() { | ||
return this.baseFs; | ||
} | ||
mapToBase(p) { | ||
const normalized = this.pathUtils.normalize(p); | ||
if (this.pathUtils.isAbsolute(p)) | ||
return this.pathUtils.resolve(this.target, this.pathUtils.relative(JAIL_ROOT, p)); | ||
if (normalized.match(/^\.\.\//)) | ||
throw new Error(`Resolving this path (${p}) would escape the jail`); | ||
return this.pathUtils.resolve(this.target, p); | ||
} | ||
mapFromBase(p) { | ||
return this.pathUtils.resolve(JAIL_ROOT, this.pathUtils.relative(this.target, p)); | ||
} | ||
} | ||
exports.JailFS = JailFS; | ||
exports.JailFS = JailFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.LazyFS = void 0; | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
class LazyFS extends _ProxiedFS.ProxiedFS { | ||
constructor(factory, pathUtils) { | ||
super(pathUtils); | ||
this.factory = void 0; | ||
this.instance = null; | ||
this.factory = factory; | ||
} | ||
get baseFs() { | ||
if (!this.instance) this.instance = this.factory(); | ||
return this.instance; | ||
} | ||
set baseFs(value) { | ||
this.instance = value; | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
mapToBase(p) { | ||
return p; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
class LazyFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(factory, pathUtils) { | ||
super(pathUtils); | ||
this.instance = null; | ||
this.factory = factory; | ||
} | ||
get baseFs() { | ||
if (!this.instance) | ||
this.instance = this.factory(); | ||
return this.instance; | ||
} | ||
set baseFs(value) { | ||
this.instance = value; | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
mapToBase(p) { | ||
return p; | ||
} | ||
} | ||
exports.LazyFS = LazyFS; | ||
exports.LazyFS = LazyFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.NodeFS = void 0; | ||
var _fs = _interopRequireDefault(require("fs")); | ||
var _FakeFS = require("./FakeFS"); | ||
var _path = require("./path"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
class NodeFS extends _FakeFS.BasePortableFakeFS { | ||
constructor(realFs = _fs.default) { | ||
super(); | ||
this.realFs = void 0; | ||
this.realFs = realFs; | ||
} | ||
getRealPath() { | ||
return _path.PortablePath.root; | ||
} | ||
async openPromise(p, flags, mode) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.open(_path.npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
openSync(p, flags, mode) { | ||
return this.realFs.openSync(_path.npath.fromPortablePath(p), flags, mode); | ||
} | ||
async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(bytesRead); | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = __importDefault(require("fs")); | ||
const FakeFS_1 = require("./FakeFS"); | ||
const path_1 = require("./path"); | ||
class NodeFS extends FakeFS_1.BasePortableFakeFS { | ||
constructor(realFs = fs_1.default) { | ||
super(); | ||
this.realFs = realFs; | ||
} | ||
getRealPath() { | ||
return path_1.PortablePath.root; | ||
} | ||
async openPromise(p, flags, mode) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.open(path_1.npath.fromPortablePath(p), flags, mode, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
openSync(p, flags, mode) { | ||
return this.realFs.openSync(path_1.npath.fromPortablePath(p), flags, mode); | ||
} | ||
async readPromise(fd, buffer, offset = 0, length = 0, position = -1) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(bytesRead); | ||
} | ||
}); | ||
}); | ||
} | ||
readSync(fd, buffer, offset, length, position) { | ||
return this.realFs.readSync(fd, buffer, offset, length, position); | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
return await new Promise((resolve, reject) => { | ||
if (typeof buffer === `string`) { | ||
return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); | ||
} | ||
else { | ||
return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
if (typeof buffer === `string`) { | ||
return this.realFs.writeSync(fd, buffer, offset); | ||
} | ||
}); | ||
}); | ||
} | ||
readSync(fd, buffer, offset, length, position) { | ||
return this.realFs.readSync(fd, buffer, offset, length, position); | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
return await new Promise((resolve, reject) => { | ||
if (typeof buffer === `string`) { | ||
return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject)); | ||
} else { | ||
return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
if (typeof buffer === `string`) { | ||
return this.realFs.writeSync(fd, buffer, offset); | ||
} else { | ||
return this.realFs.writeSync(fd, buffer, offset, length, position); | ||
else { | ||
return this.realFs.writeSync(fd, buffer, offset, length, position); | ||
} | ||
} | ||
} | ||
async closePromise(fd) { | ||
await new Promise((resolve, reject) => { | ||
this.realFs.close(fd, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
closeSync(fd) { | ||
this.realFs.closeSync(fd); | ||
} | ||
createReadStream(p, opts) { | ||
const realPath = p !== null ? _path.npath.fromPortablePath(p) : p; | ||
return this.realFs.createReadStream(realPath, opts); | ||
} | ||
createWriteStream(p, opts) { | ||
const realPath = p !== null ? _path.npath.fromPortablePath(p) : p; | ||
return this.realFs.createWriteStream(realPath, opts); | ||
} | ||
async realpathPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.realpath(_path.npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); | ||
}).then(path => { | ||
return _path.npath.toPortablePath(path); | ||
}); | ||
} | ||
realpathSync(p) { | ||
return _path.npath.toPortablePath(this.realFs.realpathSync(_path.npath.fromPortablePath(p), {})); | ||
} | ||
async existsPromise(p) { | ||
return await new Promise(resolve => { | ||
this.realFs.exists(_path.npath.fromPortablePath(p), resolve); | ||
}); | ||
} | ||
accessSync(p, mode) { | ||
return this.realFs.accessSync(_path.npath.fromPortablePath(p), mode); | ||
} | ||
async accessPromise(p, mode) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.access(_path.npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
existsSync(p) { | ||
return this.realFs.existsSync(_path.npath.fromPortablePath(p)); | ||
} | ||
async statPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.stat(_path.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
statSync(p) { | ||
return this.realFs.statSync(_path.npath.fromPortablePath(p)); | ||
} | ||
async lstatPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.lstat(_path.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
lstatSync(p) { | ||
return this.realFs.lstatSync(_path.npath.fromPortablePath(p)); | ||
} | ||
async chmodPromise(p, mask) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.chmod(_path.npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
chmodSync(p, mask) { | ||
return this.realFs.chmodSync(_path.npath.fromPortablePath(p), mask); | ||
} | ||
async renamePromise(oldP, newP) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.rename(_path.npath.fromPortablePath(oldP), _path.npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.realFs.renameSync(_path.npath.fromPortablePath(oldP), _path.npath.fromPortablePath(newP)); | ||
} | ||
async copyFilePromise(sourceP, destP, flags = 0) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.copyFile(_path.npath.fromPortablePath(sourceP), _path.npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
return this.realFs.copyFileSync(_path.npath.fromPortablePath(sourceP), _path.npath.fromPortablePath(destP), flags); | ||
} | ||
async appendFilePromise(p, content, opts) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); | ||
} else { | ||
this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
appendFileSync(p, content, opts) { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.appendFileSync(fsNativePath, content, opts); | ||
} else { | ||
this.realFs.appendFileSync(fsNativePath, content); | ||
async closePromise(fd) { | ||
await new Promise((resolve, reject) => { | ||
this.realFs.close(fd, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
} | ||
async writeFilePromise(p, content, opts) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); | ||
} else { | ||
this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
writeFileSync(p, content, opts) { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.writeFileSync(fsNativePath, content, opts); | ||
} else { | ||
this.realFs.writeFileSync(fsNativePath, content); | ||
closeSync(fd) { | ||
this.realFs.closeSync(fd); | ||
} | ||
} | ||
async unlinkPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.unlink(_path.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
unlinkSync(p) { | ||
return this.realFs.unlinkSync(_path.npath.fromPortablePath(p)); | ||
} | ||
async utimesPromise(p, atime, mtime) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.utimes(_path.npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
this.realFs.utimesSync(_path.npath.fromPortablePath(p), atime, mtime); | ||
} | ||
async mkdirPromise(p, opts) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.mkdir(_path.npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.realFs.mkdirSync(_path.npath.fromPortablePath(p), opts); | ||
} | ||
async rmdirPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.rmdir(_path.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
rmdirSync(p) { | ||
return this.realFs.rmdirSync(_path.npath.fromPortablePath(p)); | ||
} | ||
async symlinkPromise(target, p) { | ||
const type = target.endsWith(`/`) ? `dir` : `file`; | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.symlink(_path.npath.fromPortablePath(target.replace(/\/+$/, ``)), _path.npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
symlinkSync(target, p) { | ||
const type = target.endsWith(`/`) ? `dir` : `file`; | ||
return this.realFs.symlinkSync(_path.npath.fromPortablePath(target.replace(/\/+$/, ``)), _path.npath.fromPortablePath(p), type); | ||
} | ||
async readFilePromise(p, encoding) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
readFileSync(p, encoding) { | ||
const fsNativePath = typeof p === `string` ? _path.npath.fromPortablePath(p) : p; | ||
return this.realFs.readFileSync(fsNativePath, encoding); | ||
} | ||
async readdirPromise(p, { | ||
withFileTypes | ||
} = {}) { | ||
return await new Promise((resolve, reject) => { | ||
if (withFileTypes) { | ||
this.realFs.readdir(_path.npath.fromPortablePath(p), { | ||
withFileTypes: true | ||
}, this.makeCallback(resolve, reject)); | ||
} else { | ||
this.realFs.readdir(_path.npath.fromPortablePath(p), this.makeCallback(value => resolve(value), reject)); | ||
} | ||
}); | ||
} | ||
readdirSync(p, { | ||
withFileTypes | ||
} = {}) { | ||
if (withFileTypes) { | ||
return this.realFs.readdirSync(_path.npath.fromPortablePath(p), { | ||
withFileTypes: true | ||
}); | ||
} else { | ||
return this.realFs.readdirSync(_path.npath.fromPortablePath(p)); | ||
createReadStream(p, opts) { | ||
const realPath = (p !== null ? path_1.npath.fromPortablePath(p) : p); | ||
return this.realFs.createReadStream(realPath, opts); | ||
} | ||
} | ||
async readlinkPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.readlink(_path.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}).then(path => { | ||
return _path.npath.toPortablePath(path); | ||
}); | ||
} | ||
readlinkSync(p) { | ||
return _path.npath.toPortablePath(this.realFs.readlinkSync(_path.npath.fromPortablePath(p))); | ||
} | ||
watch(p, a, b) { | ||
return this.realFs.watch(_path.npath.fromPortablePath(p), // @ts-ignore | ||
a, b); | ||
} | ||
makeCallback(resolve, reject) { | ||
return (err, result) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(result); | ||
} | ||
}; | ||
} | ||
createWriteStream(p, opts) { | ||
const realPath = (p !== null ? path_1.npath.fromPortablePath(p) : p); | ||
return this.realFs.createWriteStream(realPath, opts); | ||
} | ||
async realpathPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.realpath(path_1.npath.fromPortablePath(p), {}, this.makeCallback(resolve, reject)); | ||
}).then(path => { | ||
return path_1.npath.toPortablePath(path); | ||
}); | ||
} | ||
realpathSync(p) { | ||
return path_1.npath.toPortablePath(this.realFs.realpathSync(path_1.npath.fromPortablePath(p), {})); | ||
} | ||
async existsPromise(p) { | ||
return await new Promise(resolve => { | ||
this.realFs.exists(path_1.npath.fromPortablePath(p), resolve); | ||
}); | ||
} | ||
accessSync(p, mode) { | ||
return this.realFs.accessSync(path_1.npath.fromPortablePath(p), mode); | ||
} | ||
async accessPromise(p, mode) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.access(path_1.npath.fromPortablePath(p), mode, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
existsSync(p) { | ||
return this.realFs.existsSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
async statPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.stat(path_1.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
statSync(p) { | ||
return this.realFs.statSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
async lstatPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.lstat(path_1.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
lstatSync(p) { | ||
return this.realFs.lstatSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
async chmodPromise(p, mask) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.chmod(path_1.npath.fromPortablePath(p), mask, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
chmodSync(p, mask) { | ||
return this.realFs.chmodSync(path_1.npath.fromPortablePath(p), mask); | ||
} | ||
async renamePromise(oldP, newP) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.rename(path_1.npath.fromPortablePath(oldP), path_1.npath.fromPortablePath(newP), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.realFs.renameSync(path_1.npath.fromPortablePath(oldP), path_1.npath.fromPortablePath(newP)); | ||
} | ||
async copyFilePromise(sourceP, destP, flags = 0) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.copyFile(path_1.npath.fromPortablePath(sourceP), path_1.npath.fromPortablePath(destP), flags, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
return this.realFs.copyFileSync(path_1.npath.fromPortablePath(sourceP), path_1.npath.fromPortablePath(destP), flags); | ||
} | ||
async appendFilePromise(p, content, opts) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.appendFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); | ||
} | ||
else { | ||
this.realFs.appendFile(fsNativePath, content, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
appendFileSync(p, content, opts) { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.appendFileSync(fsNativePath, content, opts); | ||
} | ||
else { | ||
this.realFs.appendFileSync(fsNativePath, content); | ||
} | ||
} | ||
async writeFilePromise(p, content, opts) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.writeFile(fsNativePath, content, opts, this.makeCallback(resolve, reject)); | ||
} | ||
else { | ||
this.realFs.writeFile(fsNativePath, content, this.makeCallback(resolve, reject)); | ||
} | ||
}); | ||
} | ||
writeFileSync(p, content, opts) { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
if (opts) { | ||
this.realFs.writeFileSync(fsNativePath, content, opts); | ||
} | ||
else { | ||
this.realFs.writeFileSync(fsNativePath, content); | ||
} | ||
} | ||
async unlinkPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.unlink(path_1.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
unlinkSync(p) { | ||
return this.realFs.unlinkSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
async utimesPromise(p, atime, mtime) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.utimes(path_1.npath.fromPortablePath(p), atime, mtime, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
this.realFs.utimesSync(path_1.npath.fromPortablePath(p), atime, mtime); | ||
} | ||
async mkdirPromise(p, opts) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.mkdir(path_1.npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.realFs.mkdirSync(path_1.npath.fromPortablePath(p), opts); | ||
} | ||
async rmdirPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.rmdir(path_1.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
rmdirSync(p) { | ||
return this.realFs.rmdirSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
async symlinkPromise(target, p) { | ||
const type = target.endsWith(`/`) ? `dir` : `file`; | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.symlink(path_1.npath.fromPortablePath(target.replace(/\/+$/, ``)), path_1.npath.fromPortablePath(p), type, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
symlinkSync(target, p) { | ||
const type = target.endsWith(`/`) ? `dir` : `file`; | ||
return this.realFs.symlinkSync(path_1.npath.fromPortablePath(target.replace(/\/+$/, ``)), path_1.npath.fromPortablePath(p), type); | ||
} | ||
async readFilePromise(p, encoding) { | ||
return await new Promise((resolve, reject) => { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
this.realFs.readFile(fsNativePath, encoding, this.makeCallback(resolve, reject)); | ||
}); | ||
} | ||
readFileSync(p, encoding) { | ||
const fsNativePath = typeof p === `string` ? path_1.npath.fromPortablePath(p) : p; | ||
return this.realFs.readFileSync(fsNativePath, encoding); | ||
} | ||
async readdirPromise(p, { withFileTypes } = {}) { | ||
return await new Promise((resolve, reject) => { | ||
if (withFileTypes) { | ||
this.realFs.readdir(path_1.npath.fromPortablePath(p), { withFileTypes: true }, this.makeCallback(resolve, reject)); | ||
} | ||
else { | ||
this.realFs.readdir(path_1.npath.fromPortablePath(p), this.makeCallback(value => resolve(value), reject)); | ||
} | ||
}); | ||
} | ||
readdirSync(p, { withFileTypes } = {}) { | ||
if (withFileTypes) { | ||
return this.realFs.readdirSync(path_1.npath.fromPortablePath(p), { withFileTypes: true }); | ||
} | ||
else { | ||
return this.realFs.readdirSync(path_1.npath.fromPortablePath(p)); | ||
} | ||
} | ||
async readlinkPromise(p) { | ||
return await new Promise((resolve, reject) => { | ||
this.realFs.readlink(path_1.npath.fromPortablePath(p), this.makeCallback(resolve, reject)); | ||
}).then(path => { | ||
return path_1.npath.toPortablePath(path); | ||
}); | ||
} | ||
readlinkSync(p) { | ||
return path_1.npath.toPortablePath(this.realFs.readlinkSync(path_1.npath.fromPortablePath(p))); | ||
} | ||
watch(p, a, b) { | ||
return this.realFs.watch(path_1.npath.fromPortablePath(p), | ||
// @ts-ignore | ||
a, b); | ||
} | ||
makeCallback(resolve, reject) { | ||
return (err, result) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
resolve(result); | ||
} | ||
}; | ||
} | ||
} | ||
exports.NodeFS = NodeFS; | ||
exports.NodeFS = NodeFS; |
373
lib/NoFS.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.NoFS = void 0; | ||
var _FakeFS = require("./FakeFS"); | ||
var _path = require("./path"); | ||
const makeError = () => Object.assign(new Error(`ENOSYS: unsupported filesystem access`), { | ||
code: `ENOSYS` | ||
}); | ||
class NoFS extends _FakeFS.FakeFS { | ||
constructor() { | ||
super(_path.ppath); | ||
} | ||
getRealPath() { | ||
throw makeError(); | ||
} | ||
resolve() { | ||
throw makeError(); | ||
} | ||
async openPromise() { | ||
throw makeError(); | ||
} | ||
openSync() { | ||
throw makeError(); | ||
} | ||
async readPromise() { | ||
throw makeError(); | ||
} | ||
readSync() { | ||
throw makeError(); | ||
} | ||
async writePromise() { | ||
throw makeError(); | ||
} | ||
writeSync() { | ||
throw makeError(); | ||
} | ||
async closePromise() { | ||
throw makeError(); | ||
} | ||
closeSync() { | ||
throw makeError(); | ||
} | ||
createWriteStream() { | ||
throw makeError(); | ||
} | ||
createReadStream() { | ||
throw makeError(); | ||
} | ||
async realpathPromise() { | ||
throw makeError(); | ||
} | ||
realpathSync() { | ||
throw makeError(); | ||
} | ||
async readdirPromise() { | ||
throw makeError(); | ||
} | ||
readdirSync() { | ||
throw makeError(); | ||
} | ||
async existsPromise(p) { | ||
throw makeError(); | ||
} | ||
existsSync(p) { | ||
throw makeError(); | ||
} | ||
async accessPromise() { | ||
throw makeError(); | ||
} | ||
accessSync() { | ||
throw makeError(); | ||
} | ||
async statPromise() { | ||
throw makeError(); | ||
} | ||
statSync() { | ||
throw makeError(); | ||
} | ||
async lstatPromise(p) { | ||
throw makeError(); | ||
} | ||
lstatSync(p) { | ||
throw makeError(); | ||
} | ||
async chmodPromise() { | ||
throw makeError(); | ||
} | ||
chmodSync() { | ||
throw makeError(); | ||
} | ||
async mkdirPromise() { | ||
throw makeError(); | ||
} | ||
mkdirSync() { | ||
throw makeError(); | ||
} | ||
async rmdirPromise() { | ||
throw makeError(); | ||
} | ||
rmdirSync() { | ||
throw makeError(); | ||
} | ||
async symlinkPromise() { | ||
throw makeError(); | ||
} | ||
symlinkSync() { | ||
throw makeError(); | ||
} | ||
async renamePromise() { | ||
throw makeError(); | ||
} | ||
renameSync() { | ||
throw makeError(); | ||
} | ||
async copyFilePromise() { | ||
throw makeError(); | ||
} | ||
copyFileSync() { | ||
throw makeError(); | ||
} | ||
async appendFilePromise() { | ||
throw makeError(); | ||
} | ||
appendFileSync() { | ||
throw makeError(); | ||
} | ||
async writeFilePromise() { | ||
throw makeError(); | ||
} | ||
writeFileSync() { | ||
throw makeError(); | ||
} | ||
async unlinkPromise() { | ||
throw makeError(); | ||
} | ||
unlinkSync() { | ||
throw makeError(); | ||
} | ||
async utimesPromise() { | ||
throw makeError(); | ||
} | ||
utimesSync() { | ||
throw makeError(); | ||
} | ||
async readFilePromise() { | ||
throw makeError(); | ||
} | ||
readFileSync() { | ||
throw makeError(); | ||
} | ||
async readlinkPromise() { | ||
throw makeError(); | ||
} | ||
readlinkSync() { | ||
throw makeError(); | ||
} | ||
watch() { | ||
throw makeError(); | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const FakeFS_1 = require("./FakeFS"); | ||
const path_1 = require("./path"); | ||
const makeError = () => Object.assign(new Error(`ENOSYS: unsupported filesystem access`), { code: `ENOSYS` }); | ||
class NoFS extends FakeFS_1.FakeFS { | ||
constructor() { | ||
super(path_1.ppath); | ||
} | ||
getRealPath() { | ||
throw makeError(); | ||
} | ||
resolve() { | ||
throw makeError(); | ||
} | ||
async openPromise() { | ||
throw makeError(); | ||
} | ||
openSync() { | ||
throw makeError(); | ||
} | ||
async readPromise() { | ||
throw makeError(); | ||
} | ||
readSync() { | ||
throw makeError(); | ||
} | ||
async writePromise() { | ||
throw makeError(); | ||
} | ||
writeSync() { | ||
throw makeError(); | ||
} | ||
async closePromise() { | ||
throw makeError(); | ||
} | ||
closeSync() { | ||
throw makeError(); | ||
} | ||
createWriteStream() { | ||
throw makeError(); | ||
} | ||
createReadStream() { | ||
throw makeError(); | ||
} | ||
async realpathPromise() { | ||
throw makeError(); | ||
} | ||
realpathSync() { | ||
throw makeError(); | ||
} | ||
async readdirPromise() { | ||
throw makeError(); | ||
} | ||
readdirSync() { | ||
throw makeError(); | ||
} | ||
async existsPromise(p) { | ||
throw makeError(); | ||
} | ||
existsSync(p) { | ||
throw makeError(); | ||
} | ||
async accessPromise() { | ||
throw makeError(); | ||
} | ||
accessSync() { | ||
throw makeError(); | ||
} | ||
async statPromise() { | ||
throw makeError(); | ||
} | ||
statSync() { | ||
throw makeError(); | ||
} | ||
async lstatPromise(p) { | ||
throw makeError(); | ||
} | ||
lstatSync(p) { | ||
throw makeError(); | ||
} | ||
async chmodPromise() { | ||
throw makeError(); | ||
} | ||
chmodSync() { | ||
throw makeError(); | ||
} | ||
async mkdirPromise() { | ||
throw makeError(); | ||
} | ||
mkdirSync() { | ||
throw makeError(); | ||
} | ||
async rmdirPromise() { | ||
throw makeError(); | ||
} | ||
rmdirSync() { | ||
throw makeError(); | ||
} | ||
async symlinkPromise() { | ||
throw makeError(); | ||
} | ||
symlinkSync() { | ||
throw makeError(); | ||
} | ||
async renamePromise() { | ||
throw makeError(); | ||
} | ||
renameSync() { | ||
throw makeError(); | ||
} | ||
async copyFilePromise() { | ||
throw makeError(); | ||
} | ||
copyFileSync() { | ||
throw makeError(); | ||
} | ||
async appendFilePromise() { | ||
throw makeError(); | ||
} | ||
appendFileSync() { | ||
throw makeError(); | ||
} | ||
async writeFilePromise() { | ||
throw makeError(); | ||
} | ||
writeFileSync() { | ||
throw makeError(); | ||
} | ||
async unlinkPromise() { | ||
throw makeError(); | ||
} | ||
unlinkSync() { | ||
throw makeError(); | ||
} | ||
async utimesPromise() { | ||
throw makeError(); | ||
} | ||
utimesSync() { | ||
throw makeError(); | ||
} | ||
async readFilePromise() { | ||
throw makeError(); | ||
} | ||
readFileSync() { | ||
throw makeError(); | ||
} | ||
async readlinkPromise() { | ||
throw makeError(); | ||
} | ||
readlinkSync() { | ||
throw makeError(); | ||
} | ||
watch() { | ||
throw makeError(); | ||
} | ||
} | ||
exports.NoFS = NoFS; | ||
NoFS.instance = new NoFS(); | ||
NoFS.instance = new NoFS(); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.convertPath = convertPath; | ||
exports.toFilename = toFilename; | ||
exports.ppath = exports.npath = exports.PortablePath = void 0; | ||
var _path = _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const PortablePath = { | ||
root: `/`, | ||
dot: `.` | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
exports.PortablePath = PortablePath; | ||
const npath = Object.create(_path.default); | ||
exports.npath = npath; | ||
const ppath = Object.create(_path.default.posix); | ||
exports.ppath = ppath; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const path_1 = __importDefault(require("path")); | ||
exports.PortablePath = { | ||
root: `/`, | ||
dot: `.`, | ||
}; | ||
exports.npath = Object.create(path_1.default); | ||
exports.ppath = Object.create(path_1.default.posix); | ||
const contains = function (pathUtils, from, to) { | ||
from = pathUtils.normalize(from); | ||
to = pathUtils.normalize(to); | ||
if (from === to) return `.`; | ||
if (!from.endsWith(pathUtils.sep)) from = from + pathUtils.sep; | ||
if (to.startsWith(from)) { | ||
return to.slice(from.length); | ||
} else { | ||
return null; | ||
} | ||
from = pathUtils.normalize(from); | ||
to = pathUtils.normalize(to); | ||
if (from === to) | ||
return `.`; | ||
if (!from.endsWith(pathUtils.sep)) | ||
from = (from + pathUtils.sep); | ||
if (to.startsWith(from)) { | ||
return to.slice(from.length); | ||
} | ||
else { | ||
return null; | ||
} | ||
}; | ||
npath.fromPortablePath = fromPortablePath; | ||
npath.toPortablePath = toPortablePath; | ||
npath.contains = (from, to) => contains(npath, from, to); | ||
ppath.contains = (from, to) => contains(ppath, from, to); | ||
exports.npath.fromPortablePath = fromPortablePath; | ||
exports.npath.toPortablePath = toPortablePath; | ||
exports.npath.contains = (from, to) => contains(exports.npath, from, to); | ||
exports.ppath.contains = (from, to) => contains(exports.ppath, from, to); | ||
const WINDOWS_PATH_REGEXP = /^[a-zA-Z]:.*$/; | ||
const PORTABLE_PATH_REGEXP = /^\/[a-zA-Z]:.*$/; // Path should look like "/N:/berry/scripts/plugin-pack.js" | ||
const PORTABLE_PATH_REGEXP = /^\/[a-zA-Z]:.*$/; | ||
// Path should look like "/N:/berry/scripts/plugin-pack.js" | ||
// And transform to "N:\berry\scripts\plugin-pack.js" | ||
function fromPortablePath(p) { | ||
if (process.platform !== 'win32') return p; | ||
return p.match(PORTABLE_PATH_REGEXP) ? p.substring(1).replace(/\//g, `\\`) : p; | ||
} // Path should look like "N:/berry/scripts/plugin-pack.js" | ||
if (process.platform !== 'win32') | ||
return p; | ||
return p.match(PORTABLE_PATH_REGEXP) ? p.substring(1).replace(/\//g, `\\`) : p; | ||
} | ||
// Path should look like "N:/berry/scripts/plugin-pack.js" | ||
// And transform to "/N:/berry/scripts/plugin-pack.js" | ||
function toPortablePath(p) { | ||
if (process.platform !== 'win32') return p; | ||
return (p.match(WINDOWS_PATH_REGEXP) ? `/${p}` : p).replace(/\\/g, `/`); | ||
if (process.platform !== 'win32') | ||
return p; | ||
return (p.match(WINDOWS_PATH_REGEXP) ? `/${p}` : p).replace(/\\/g, `/`); | ||
} | ||
function convertPath(targetPathUtils, sourcePath) { | ||
return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath); | ||
return (targetPathUtils === exports.npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath)); | ||
} | ||
exports.convertPath = convertPath; | ||
function toFilename(filename) { | ||
if (npath.parse(filename).dir !== '' || ppath.parse(filename).dir !== '') throw new Error(`Invalid filename: "${filename}"`); | ||
return filename; | ||
} | ||
if (exports.npath.parse(filename).dir !== '' || exports.ppath.parse(filename).dir !== '') | ||
throw new Error(`Invalid filename: "${filename}"`); | ||
return filename; | ||
} | ||
exports.toFilename = toFilename; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.PosixFS = void 0; | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
var _path = require("./path"); | ||
class PosixFS extends _ProxiedFS.ProxiedFS { | ||
constructor(baseFs) { | ||
super(_path.npath); | ||
this.baseFs = void 0; | ||
this.baseFs = baseFs; | ||
} | ||
mapFromBase(path) { | ||
return _path.npath.fromPortablePath(path); | ||
} | ||
mapToBase(path) { | ||
return _path.npath.toPortablePath(path); | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
const path_1 = require("./path"); | ||
class PosixFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(baseFs) { | ||
super(path_1.npath); | ||
this.baseFs = baseFs; | ||
} | ||
mapFromBase(path) { | ||
return path_1.npath.fromPortablePath(path); | ||
} | ||
mapToBase(path) { | ||
return path_1.npath.toPortablePath(path); | ||
} | ||
} | ||
exports.PosixFS = PosixFS; | ||
exports.PosixFS = PosixFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.ProxiedFS = void 0; | ||
var _FakeFS = require("./FakeFS"); | ||
class ProxiedFS extends _FakeFS.FakeFS { | ||
constructor(...args) { | ||
super(...args); | ||
this.baseFs = void 0; | ||
} | ||
resolve(path) { | ||
return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); | ||
} | ||
getRealPath() { | ||
return this.mapFromBase(this.baseFs.getRealPath()); | ||
} | ||
openPromise(p, flags, mode) { | ||
return this.baseFs.openPromise(this.mapToBase(p), flags, mode); | ||
} | ||
openSync(p, flags, mode) { | ||
return this.baseFs.openSync(this.mapToBase(p), flags, mode); | ||
} | ||
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); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const FakeFS_1 = require("./FakeFS"); | ||
class ProxiedFS extends FakeFS_1.FakeFS { | ||
resolve(path) { | ||
return this.mapFromBase(this.baseFs.resolve(this.mapToBase(path))); | ||
} | ||
} | ||
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); | ||
getRealPath() { | ||
return this.mapFromBase(this.baseFs.getRealPath()); | ||
} | ||
} | ||
closePromise(fd) { | ||
return this.baseFs.closePromise(fd); | ||
} | ||
closeSync(fd) { | ||
this.baseFs.closeSync(fd); | ||
} | ||
createReadStream(p, opts) { | ||
return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); | ||
} | ||
createWriteStream(p, opts) { | ||
return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); | ||
} | ||
async realpathPromise(p) { | ||
return this.mapFromBase((await this.baseFs.realpathPromise(this.mapToBase(p)))); | ||
} | ||
realpathSync(p) { | ||
return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); | ||
} | ||
existsPromise(p) { | ||
return this.baseFs.existsPromise(this.mapToBase(p)); | ||
} | ||
existsSync(p) { | ||
return this.baseFs.existsSync(this.mapToBase(p)); | ||
} | ||
accessSync(p, mode) { | ||
return this.baseFs.accessSync(this.mapToBase(p), mode); | ||
} | ||
accessPromise(p, mode) { | ||
return this.baseFs.accessPromise(this.mapToBase(p), mode); | ||
} | ||
statPromise(p) { | ||
return this.baseFs.statPromise(this.mapToBase(p)); | ||
} | ||
statSync(p) { | ||
return this.baseFs.statSync(this.mapToBase(p)); | ||
} | ||
lstatPromise(p) { | ||
return this.baseFs.lstatPromise(this.mapToBase(p)); | ||
} | ||
lstatSync(p) { | ||
return this.baseFs.lstatSync(this.mapToBase(p)); | ||
} | ||
chmodPromise(p, mask) { | ||
return this.baseFs.chmodPromise(this.mapToBase(p), mask); | ||
} | ||
chmodSync(p, mask) { | ||
return this.baseFs.chmodSync(this.mapToBase(p), mask); | ||
} | ||
renamePromise(oldP, newP) { | ||
return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); | ||
} | ||
copyFilePromise(sourceP, destP, flags = 0) { | ||
return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); | ||
} | ||
appendFilePromise(p, content, opts) { | ||
return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); | ||
} | ||
appendFileSync(p, content, opts) { | ||
return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); | ||
} | ||
writeFilePromise(p, content, opts) { | ||
return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); | ||
} | ||
writeFileSync(p, content, opts) { | ||
return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); | ||
} | ||
unlinkPromise(p) { | ||
return this.baseFs.unlinkPromise(this.mapToBase(p)); | ||
} | ||
unlinkSync(p) { | ||
return this.baseFs.unlinkSync(this.mapToBase(p)); | ||
} | ||
utimesPromise(p, atime, mtime) { | ||
return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); | ||
} | ||
mkdirPromise(p, opts) { | ||
return this.baseFs.mkdirPromise(this.mapToBase(p), opts); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.baseFs.mkdirSync(this.mapToBase(p), opts); | ||
} | ||
rmdirPromise(p) { | ||
return this.baseFs.rmdirPromise(this.mapToBase(p)); | ||
} | ||
rmdirSync(p) { | ||
return this.baseFs.rmdirSync(this.mapToBase(p)); | ||
} | ||
symlinkPromise(target, p) { | ||
return this.baseFs.symlinkPromise(this.mapToBase(target), this.mapToBase(p)); | ||
} | ||
symlinkSync(target, p) { | ||
return this.baseFs.symlinkSync(this.mapToBase(target), this.mapToBase(p)); | ||
} | ||
readFilePromise(p, encoding) { | ||
// This weird condition is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
if (encoding === 'utf8') { | ||
return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); | ||
} else { | ||
return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); | ||
openPromise(p, flags, mode) { | ||
return this.baseFs.openPromise(this.mapToBase(p), flags, mode); | ||
} | ||
} | ||
readFileSync(p, encoding) { | ||
// This weird condition is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
if (encoding === 'utf8') { | ||
return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); | ||
} else { | ||
return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); | ||
openSync(p, flags, mode) { | ||
return this.baseFs.openSync(this.mapToBase(p), flags, mode); | ||
} | ||
} | ||
async readdirPromise(p, { | ||
withFileTypes | ||
} = {}) { | ||
return this.baseFs.readdirPromise(this.mapToBase(p), { | ||
withFileTypes: withFileTypes | ||
}); | ||
} | ||
readdirSync(p, { | ||
withFileTypes | ||
} = {}) { | ||
return this.baseFs.readdirSync(this.mapToBase(p), { | ||
withFileTypes: withFileTypes | ||
}); | ||
} | ||
async readlinkPromise(p) { | ||
return this.mapFromBase((await this.baseFs.readlinkPromise(this.mapToBase(p)))); | ||
} | ||
readlinkSync(p) { | ||
return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); | ||
} | ||
watch(p, a, b) { | ||
return this.baseFs.watch(this.mapToBase(p), // @ts-ignore | ||
a, b); | ||
} | ||
fsMapToBase(p) { | ||
if (typeof p === `number`) { | ||
return p; | ||
} else { | ||
return this.mapToBase(p); | ||
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); | ||
} | ||
} | ||
closePromise(fd) { | ||
return this.baseFs.closePromise(fd); | ||
} | ||
closeSync(fd) { | ||
this.baseFs.closeSync(fd); | ||
} | ||
createReadStream(p, opts) { | ||
return this.baseFs.createReadStream(p !== null ? this.mapToBase(p) : p, opts); | ||
} | ||
createWriteStream(p, opts) { | ||
return this.baseFs.createWriteStream(p !== null ? this.mapToBase(p) : p, opts); | ||
} | ||
async realpathPromise(p) { | ||
return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(p))); | ||
} | ||
realpathSync(p) { | ||
return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(p))); | ||
} | ||
existsPromise(p) { | ||
return this.baseFs.existsPromise(this.mapToBase(p)); | ||
} | ||
existsSync(p) { | ||
return this.baseFs.existsSync(this.mapToBase(p)); | ||
} | ||
accessSync(p, mode) { | ||
return this.baseFs.accessSync(this.mapToBase(p), mode); | ||
} | ||
accessPromise(p, mode) { | ||
return this.baseFs.accessPromise(this.mapToBase(p), mode); | ||
} | ||
statPromise(p) { | ||
return this.baseFs.statPromise(this.mapToBase(p)); | ||
} | ||
statSync(p) { | ||
return this.baseFs.statSync(this.mapToBase(p)); | ||
} | ||
lstatPromise(p) { | ||
return this.baseFs.lstatPromise(this.mapToBase(p)); | ||
} | ||
lstatSync(p) { | ||
return this.baseFs.lstatSync(this.mapToBase(p)); | ||
} | ||
chmodPromise(p, mask) { | ||
return this.baseFs.chmodPromise(this.mapToBase(p), mask); | ||
} | ||
chmodSync(p, mask) { | ||
return this.baseFs.chmodSync(this.mapToBase(p), mask); | ||
} | ||
renamePromise(oldP, newP) { | ||
return this.baseFs.renamePromise(this.mapToBase(oldP), this.mapToBase(newP)); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.baseFs.renameSync(this.mapToBase(oldP), this.mapToBase(newP)); | ||
} | ||
copyFilePromise(sourceP, destP, flags = 0) { | ||
return this.baseFs.copyFilePromise(this.mapToBase(sourceP), this.mapToBase(destP), flags); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
return this.baseFs.copyFileSync(this.mapToBase(sourceP), this.mapToBase(destP), flags); | ||
} | ||
appendFilePromise(p, content, opts) { | ||
return this.baseFs.appendFilePromise(this.fsMapToBase(p), content, opts); | ||
} | ||
appendFileSync(p, content, opts) { | ||
return this.baseFs.appendFileSync(this.fsMapToBase(p), content, opts); | ||
} | ||
writeFilePromise(p, content, opts) { | ||
return this.baseFs.writeFilePromise(this.fsMapToBase(p), content, opts); | ||
} | ||
writeFileSync(p, content, opts) { | ||
return this.baseFs.writeFileSync(this.fsMapToBase(p), content, opts); | ||
} | ||
unlinkPromise(p) { | ||
return this.baseFs.unlinkPromise(this.mapToBase(p)); | ||
} | ||
unlinkSync(p) { | ||
return this.baseFs.unlinkSync(this.mapToBase(p)); | ||
} | ||
utimesPromise(p, atime, mtime) { | ||
return this.baseFs.utimesPromise(this.mapToBase(p), atime, mtime); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
return this.baseFs.utimesSync(this.mapToBase(p), atime, mtime); | ||
} | ||
mkdirPromise(p, opts) { | ||
return this.baseFs.mkdirPromise(this.mapToBase(p), opts); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.baseFs.mkdirSync(this.mapToBase(p), opts); | ||
} | ||
rmdirPromise(p) { | ||
return this.baseFs.rmdirPromise(this.mapToBase(p)); | ||
} | ||
rmdirSync(p) { | ||
return this.baseFs.rmdirSync(this.mapToBase(p)); | ||
} | ||
symlinkPromise(target, p) { | ||
return this.baseFs.symlinkPromise(this.mapToBase(target), this.mapToBase(p)); | ||
} | ||
symlinkSync(target, p) { | ||
return this.baseFs.symlinkSync(this.mapToBase(target), this.mapToBase(p)); | ||
} | ||
readFilePromise(p, encoding) { | ||
// This weird condition is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
if (encoding === 'utf8') { | ||
return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); | ||
} | ||
else { | ||
return this.baseFs.readFilePromise(this.fsMapToBase(p), encoding); | ||
} | ||
} | ||
readFileSync(p, encoding) { | ||
// This weird condition is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
if (encoding === 'utf8') { | ||
return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); | ||
} | ||
else { | ||
return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); | ||
} | ||
} | ||
async readdirPromise(p, { withFileTypes } = {}) { | ||
return this.baseFs.readdirPromise(this.mapToBase(p), { withFileTypes: withFileTypes }); | ||
} | ||
readdirSync(p, { withFileTypes } = {}) { | ||
return this.baseFs.readdirSync(this.mapToBase(p), { withFileTypes: withFileTypes }); | ||
} | ||
async readlinkPromise(p) { | ||
return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(p))); | ||
} | ||
readlinkSync(p) { | ||
return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(p))); | ||
} | ||
watch(p, a, b) { | ||
return this.baseFs.watch(this.mapToBase(p), | ||
// @ts-ignore | ||
a, b); | ||
} | ||
fsMapToBase(p) { | ||
if (typeof p === `number`) { | ||
return p; | ||
} | ||
else { | ||
return this.mapToBase(p); | ||
} | ||
} | ||
} | ||
exports.ProxiedFS = ProxiedFS; | ||
exports.ProxiedFS = ProxiedFS; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.VirtualFS = void 0; | ||
var _NodeFS = require("./NodeFS"); | ||
var _ProxiedFS = require("./ProxiedFS"); | ||
var _path = require("./path"); | ||
const NUMBER_REGEXP = /^[0-9]+$/; // $0: full path | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const ProxiedFS_1 = require("./ProxiedFS"); | ||
const path_1 = require("./path"); | ||
const NUMBER_REGEXP = /^[0-9]+$/; | ||
// $0: full path | ||
// $1: virtual folder | ||
@@ -20,77 +13,65 @@ // $2: virtual segment | ||
// $5: subpath | ||
const VIRTUAL_REGEXP = /^(\/(?:[^\/]+\/)*?\$\$virtual)((?:\/([^\/]+)(?:\/([^\/]+))?)?((?:\/.*)?))$/; | ||
class VirtualFS extends _ProxiedFS.ProxiedFS { | ||
static makeVirtualPath(base, component, to) { | ||
if (_path.ppath.basename(base) !== `$$virtual`) throw new Error(`Assertion failed: Virtual folders must be named "$$virtual"`); // Obtains the relative distance between the virtual path and its actual target | ||
const target = _path.ppath.relative(_path.ppath.dirname(base), to); | ||
const segments = target.split(`/`); // Counts how many levels we need to go back to start applying the rest of the path | ||
let depth = 0; | ||
while (depth < segments.length && segments[depth] === `..`) depth += 1; | ||
const finalSegments = segments.slice(depth); | ||
const fullVirtualPath = _path.ppath.join(base, component, String(depth), ...finalSegments); | ||
return fullVirtualPath; | ||
} | ||
static resolveVirtual(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) return p; | ||
const target = _path.ppath.dirname(match[1]); | ||
if (!match[3] || !match[4]) return target; | ||
const isnum = NUMBER_REGEXP.test(match[4]); | ||
if (!isnum) return p; | ||
const depth = Number(match[4]); | ||
const backstep = `../`.repeat(depth); | ||
const subpath = match[5] || `.`; | ||
return VirtualFS.resolveVirtual(_path.ppath.join(target, backstep, subpath)); | ||
} | ||
constructor({ | ||
baseFs = new _NodeFS.NodeFS() | ||
} = {}) { | ||
super(_path.ppath); | ||
this.baseFs = void 0; | ||
this.baseFs = baseFs; | ||
} | ||
getRealPath() { | ||
return this.baseFs.getRealPath(); | ||
} | ||
realpathSync(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) return this.baseFs.realpathSync(p); | ||
if (!match[5]) return p; | ||
const realpath = this.baseFs.realpathSync(this.mapToBase(p)); | ||
return VirtualFS.makeVirtualPath(match[1], match[3], realpath); | ||
} | ||
async realpathPromise(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) return await this.baseFs.realpathPromise(p); | ||
if (!match[5]) return p; | ||
const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); | ||
return VirtualFS.makeVirtualPath(match[1], match[3], realpath); | ||
} | ||
mapToBase(p) { | ||
return VirtualFS.resolveVirtual(p); | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
class VirtualFS extends ProxiedFS_1.ProxiedFS { | ||
constructor({ baseFs = new NodeFS_1.NodeFS() } = {}) { | ||
super(path_1.ppath); | ||
this.baseFs = baseFs; | ||
} | ||
static makeVirtualPath(base, component, to) { | ||
if (path_1.ppath.basename(base) !== `$$virtual`) | ||
throw new Error(`Assertion failed: Virtual folders must be named "$$virtual"`); | ||
// Obtains the relative distance between the virtual path and its actual target | ||
const target = path_1.ppath.relative(path_1.ppath.dirname(base), to); | ||
const segments = target.split(`/`); | ||
// Counts how many levels we need to go back to start applying the rest of the path | ||
let depth = 0; | ||
while (depth < segments.length && segments[depth] === `..`) | ||
depth += 1; | ||
const finalSegments = segments.slice(depth); | ||
const fullVirtualPath = path_1.ppath.join(base, component, String(depth), ...finalSegments); | ||
return fullVirtualPath; | ||
} | ||
static resolveVirtual(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) | ||
return p; | ||
const target = path_1.ppath.dirname(match[1]); | ||
if (!match[3] || !match[4]) | ||
return target; | ||
const isnum = NUMBER_REGEXP.test(match[4]); | ||
if (!isnum) | ||
return p; | ||
const depth = Number(match[4]); | ||
const backstep = `../`.repeat(depth); | ||
const subpath = (match[5] || `.`); | ||
return VirtualFS.resolveVirtual(path_1.ppath.join(target, backstep, subpath)); | ||
} | ||
getRealPath() { | ||
return this.baseFs.getRealPath(); | ||
} | ||
realpathSync(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) | ||
return this.baseFs.realpathSync(p); | ||
if (!match[5]) | ||
return p; | ||
const realpath = this.baseFs.realpathSync(this.mapToBase(p)); | ||
return VirtualFS.makeVirtualPath(match[1], match[3], realpath); | ||
} | ||
async realpathPromise(p) { | ||
const match = p.match(VIRTUAL_REGEXP); | ||
if (!match) | ||
return await this.baseFs.realpathPromise(p); | ||
if (!match[5]) | ||
return p; | ||
const realpath = await this.baseFs.realpathPromise(this.mapToBase(p)); | ||
return VirtualFS.makeVirtualPath(match[1], match[3], realpath); | ||
} | ||
mapToBase(p) { | ||
return VirtualFS.resolveVirtual(p); | ||
} | ||
mapFromBase(p) { | ||
return p; | ||
} | ||
} | ||
exports.VirtualFS = VirtualFS; | ||
exports.VirtualFS = VirtualFS; |
1739
lib/ZipFS.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.ZipFS = void 0; | ||
var _libzip = _interopRequireDefault(require("@yarnpkg/libzip")); | ||
var _fs = require("fs"); | ||
var _stream = require("stream"); | ||
var _util = require("util"); | ||
var _FakeFS = require("./FakeFS"); | ||
var _NodeFS = require("./NodeFS"); | ||
var errors = _interopRequireWildcard(require("./errors")); | ||
var _path = require("./path"); | ||
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = require("fs"); | ||
const stream_1 = require("stream"); | ||
const util_1 = require("util"); | ||
const FakeFS_1 = require("./FakeFS"); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const errors = __importStar(require("./errors")); | ||
const path_1 = require("./path"); | ||
const S_IFMT = 0o170000; | ||
@@ -34,948 +21,826 @@ const S_IFDIR = 0o040000; | ||
const S_IFLNK = 0o120000; | ||
class DirEntry { | ||
constructor() { | ||
this.name = ``; | ||
this.mode = 0; | ||
} | ||
isBlockDevice() { | ||
return false; | ||
} | ||
isCharacterDevice() { | ||
return false; | ||
} | ||
isDirectory() { | ||
return (this.mode & S_IFMT) === S_IFDIR; | ||
} | ||
isFIFO() { | ||
return false; | ||
} | ||
isFile() { | ||
return (this.mode & S_IFMT) === S_IFREG; | ||
} | ||
isSocket() { | ||
return false; | ||
} | ||
isSymbolicLink() { | ||
return (this.mode & S_IFMT) === S_IFLNK; | ||
} | ||
constructor() { | ||
this.name = ``; | ||
this.mode = 0; | ||
} | ||
isBlockDevice() { | ||
return false; | ||
} | ||
isCharacterDevice() { | ||
return false; | ||
} | ||
isDirectory() { | ||
return (this.mode & S_IFMT) === S_IFDIR; | ||
} | ||
isFIFO() { | ||
return false; | ||
} | ||
isFile() { | ||
return (this.mode & S_IFMT) === S_IFREG; | ||
} | ||
isSocket() { | ||
return false; | ||
} | ||
isSymbolicLink() { | ||
return (this.mode & S_IFMT) === S_IFLNK; | ||
} | ||
} | ||
class StatEntry { | ||
constructor() { | ||
this.dev = 0; | ||
this.ino = 0; | ||
this.mode = 0; | ||
this.nlink = 1; | ||
this.rdev = 0; | ||
this.blocks = 1; | ||
} | ||
isBlockDevice() { | ||
return false; | ||
} | ||
isCharacterDevice() { | ||
return false; | ||
} | ||
isDirectory() { | ||
return (this.mode & S_IFMT) === S_IFDIR; | ||
} | ||
isFIFO() { | ||
return false; | ||
} | ||
isFile() { | ||
return (this.mode & S_IFMT) === S_IFREG; | ||
} | ||
isSocket() { | ||
return false; | ||
} | ||
isSymbolicLink() { | ||
return (this.mode & S_IFMT) === S_IFLNK; | ||
} | ||
constructor() { | ||
this.dev = 0; | ||
this.ino = 0; | ||
this.mode = 0; | ||
this.nlink = 1; | ||
this.rdev = 0; | ||
this.blocks = 1; | ||
} | ||
isBlockDevice() { | ||
return false; | ||
} | ||
isCharacterDevice() { | ||
return false; | ||
} | ||
isDirectory() { | ||
return (this.mode & S_IFMT) === S_IFDIR; | ||
} | ||
isFIFO() { | ||
return false; | ||
} | ||
isFile() { | ||
return (this.mode & S_IFMT) === S_IFREG; | ||
} | ||
isSocket() { | ||
return false; | ||
} | ||
isSymbolicLink() { | ||
return (this.mode & S_IFMT) === S_IFLNK; | ||
} | ||
} | ||
function makeDefaultStats() { | ||
return Object.assign(new StatEntry(), { | ||
uid: 0, | ||
gid: 0, | ||
size: 0, | ||
blksize: 0, | ||
atimeMs: 0, | ||
mtimeMs: 0, | ||
ctimeMs: 0, | ||
birthtimeMs: 0, | ||
atime: new Date(0), | ||
mtime: new Date(0), | ||
ctime: new Date(0), | ||
birthtime: new Date(0), | ||
mode: S_IFREG | 0o644 | ||
}); | ||
return Object.assign(new StatEntry(), { | ||
uid: 0, | ||
gid: 0, | ||
size: 0, | ||
blksize: 0, | ||
atimeMs: 0, | ||
mtimeMs: 0, | ||
ctimeMs: 0, | ||
birthtimeMs: 0, | ||
atime: new Date(0), | ||
mtime: new Date(0), | ||
ctime: new Date(0), | ||
birthtime: new Date(0), | ||
mode: S_IFREG | 0o644, | ||
}); | ||
} | ||
function toUnixTimestamp(time) { | ||
if (typeof time === 'string' && String(+time) === time) return +time; // @ts-ignore | ||
if (Number.isFinite(time)) { | ||
if (time < 0) { | ||
return Date.now() / 1000; | ||
} else { | ||
return time; | ||
if (typeof time === 'string' && String(+time) === time) | ||
return +time; | ||
// @ts-ignore | ||
if (Number.isFinite(time)) { | ||
if (time < 0) { | ||
return Date.now() / 1000; | ||
} | ||
else { | ||
return time; | ||
} | ||
} | ||
} // convert to 123.456 UNIX timestamp | ||
if ((0, _util.isDate)(time)) return time.getTime() / 1000; | ||
throw new Error(`Invalid time`); | ||
// convert to 123.456 UNIX timestamp | ||
if (util_1.isDate(time)) | ||
return time.getTime() / 1000; | ||
throw new Error(`Invalid time`); | ||
} | ||
class ZipFS extends _FakeFS.BasePortableFakeFS { | ||
constructor(source, opts = {}) { | ||
super(); | ||
this.baseFs = void 0; | ||
this.path = void 0; | ||
this.stats = void 0; | ||
this.zip = void 0; | ||
this.listings = new Map(); | ||
this.entries = new Map(); | ||
this.fds = new Map(); | ||
this.nextFd = 0; | ||
this.ready = false; | ||
this.readOnly = false; | ||
const pathOptions = opts; | ||
if (typeof source === `string`) { | ||
const { | ||
baseFs = new _NodeFS.NodeFS() | ||
} = pathOptions; | ||
this.baseFs = baseFs; | ||
this.path = source; | ||
} else { | ||
this.path = null; | ||
this.baseFs = null; | ||
class ZipFS extends FakeFS_1.BasePortableFakeFS { | ||
constructor(source, opts) { | ||
super(); | ||
this.listings = new Map(); | ||
this.entries = new Map(); | ||
this.fds = new Map(); | ||
this.nextFd = 0; | ||
this.ready = false; | ||
this.readOnly = false; | ||
this.libzip = opts.libzip; | ||
const pathOptions = opts; | ||
if (typeof source === `string`) { | ||
const { baseFs = new NodeFS_1.NodeFS() } = pathOptions; | ||
this.baseFs = baseFs; | ||
this.path = source; | ||
} | ||
else { | ||
this.path = null; | ||
this.baseFs = null; | ||
} | ||
if (opts.stats) { | ||
this.stats = opts.stats; | ||
} | ||
else { | ||
if (typeof source === `string`) { | ||
try { | ||
this.stats = this.baseFs.statSync(source); | ||
} | ||
catch (error) { | ||
if (error.code === `ENOENT` && pathOptions.create) { | ||
this.stats = makeDefaultStats(); | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
} | ||
else { | ||
this.stats = makeDefaultStats(); | ||
} | ||
} | ||
const errPtr = this.libzip.malloc(4); | ||
try { | ||
let flags = 0; | ||
if (typeof source === `string` && pathOptions.create) | ||
flags |= this.libzip.ZIP_CREATE | this.libzip.ZIP_TRUNCATE; | ||
if (opts.readOnly) { | ||
flags |= this.libzip.ZIP_RDONLY; | ||
this.readOnly = true; | ||
} | ||
if (typeof source === `string`) { | ||
this.zip = this.libzip.open(path_1.npath.fromPortablePath(source), flags, errPtr); | ||
} | ||
else { | ||
const lzSource = this.allocateUnattachedSource(source); | ||
try { | ||
this.zip = this.libzip.openFromSource(lzSource, flags, errPtr); | ||
} | ||
catch (error) { | ||
this.libzip.source.free(lzSource); | ||
throw error; | ||
} | ||
} | ||
if (this.zip === 0) { | ||
const error = this.libzip.struct.errorS(); | ||
this.libzip.error.initWithCode(error, this.libzip.getValue(errPtr, `i32`)); | ||
throw new Error(this.libzip.error.strerror(error)); | ||
} | ||
} | ||
finally { | ||
this.libzip.free(errPtr); | ||
} | ||
this.listings.set(path_1.PortablePath.root, new Set()); | ||
const entryCount = this.libzip.getNumEntries(this.zip, 0); | ||
for (let t = 0; t < entryCount; ++t) { | ||
const raw = this.libzip.getName(this.zip, t, 0); | ||
if (path_1.ppath.isAbsolute(raw)) | ||
continue; | ||
const p = path_1.ppath.resolve(path_1.PortablePath.root, raw); | ||
this.registerEntry(p, t); | ||
// If the raw path is a directory, register it | ||
// to prevent empty folder being skipped | ||
if (raw.endsWith('/')) { | ||
this.registerListing(p); | ||
} | ||
} | ||
this.ready = true; | ||
} | ||
if (opts.stats) { | ||
this.stats = opts.stats; | ||
} else { | ||
if (typeof source === `string`) { | ||
getAllFiles() { | ||
return Array.from(this.entries.keys()); | ||
} | ||
getRealPath() { | ||
if (!this.path) | ||
throw new Error(`ZipFS don't have real paths when loaded from a buffer`); | ||
return this.path; | ||
} | ||
saveAndClose() { | ||
if (!this.path || !this.baseFs) | ||
throw new Error(`ZipFS cannot be saved and must be discarded when loaded from a buffer`); | ||
if (!this.ready) | ||
throw errors.EBUSY(`archive closed, close`); | ||
if (this.readOnly) | ||
return this.discardAndClose(); | ||
const previousMod = this.baseFs.existsSync(this.path) | ||
? this.baseFs.statSync(this.path).mode & 0o777 | ||
: null; | ||
const rc = this.libzip.close(this.zip); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
// this.libzip overrides the chmod when writing the archive, which is a weird | ||
// behavior I don't totally understand (plus the umask seems bogus in some | ||
// weird cases - maybe related to emscripten?) | ||
// | ||
// See also https://github.com/nih-at/libzip/issues/77 | ||
if (previousMod === null) | ||
this.baseFs.chmodSync(this.path, this.stats.mode); | ||
else if (previousMod !== (this.baseFs.statSync(this.path).mode & 0o777)) | ||
this.baseFs.chmodSync(this.path, previousMod); | ||
this.ready = false; | ||
} | ||
discardAndClose() { | ||
if (!this.ready) | ||
throw errors.EBUSY(`archive closed, close`); | ||
this.libzip.discard(this.zip); | ||
this.ready = false; | ||
} | ||
async openPromise(p, flags, mode) { | ||
return this.openSync(p, flags, mode); | ||
} | ||
openSync(p, flags, mode) { | ||
const fd = this.nextFd++; | ||
this.fds.set(fd, { cursor: 0, p }); | ||
return fd; | ||
} | ||
async readPromise(fd, buffer, offset, length, position) { | ||
return this.readSync(fd, buffer, offset, length, position); | ||
} | ||
readSync(fd, buffer, offset = 0, length = 0, position = -1) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw errors.EBADF(`read`); | ||
let realPosition; | ||
if (position === -1 || position === null) | ||
realPosition = entry.cursor; | ||
else | ||
realPosition = position; | ||
const source = this.readFileSync(entry.p); | ||
source.copy(buffer, offset, realPosition, realPosition + length); | ||
const bytesRead = Math.max(0, Math.min(source.length - realPosition, length)); | ||
if (position === -1) | ||
entry.cursor += bytesRead; | ||
return bytesRead; | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
if (typeof buffer === `string`) { | ||
return this.writeSync(fd, buffer, position); | ||
} | ||
else { | ||
return this.writeSync(fd, buffer, offset, length, position); | ||
} | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw errors.EBADF(`read`); | ||
throw new Error(`Unimplemented`); | ||
} | ||
async closePromise(fd) { | ||
return this.closeSync(fd); | ||
} | ||
closeSync(fd) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw errors.EBADF(`read`); | ||
this.fds.delete(fd); | ||
} | ||
createReadStream(p, { encoding } = {}) { | ||
if (p === null) | ||
throw new Error(`Unimplemented`); | ||
const stream = Object.assign(new stream_1.PassThrough(), { | ||
bytesRead: 0, | ||
path: p, | ||
close: () => { | ||
clearImmediate(immediate); | ||
}, | ||
}); | ||
const immediate = setImmediate(() => { | ||
try { | ||
const data = this.readFileSync(p, encoding); | ||
stream.bytesRead = data.length; | ||
stream.write(data); | ||
stream.end(); | ||
} | ||
catch (error) { | ||
stream.emit(`error`, error); | ||
stream.end(); | ||
} | ||
}); | ||
return stream; | ||
} | ||
createWriteStream(p, { encoding } = {}) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`open '${p}'`); | ||
if (p === null) | ||
throw new Error(`Unimplemented`); | ||
const stream = Object.assign(new stream_1.PassThrough(), { | ||
bytesWritten: 0, | ||
path: p, | ||
close: () => { | ||
stream.end(); | ||
}, | ||
}); | ||
const chunks = []; | ||
stream.on(`data`, chunk => { | ||
const chunkBuffer = Buffer.from(chunk); | ||
stream.bytesWritten += chunkBuffer.length; | ||
chunks.push(chunkBuffer); | ||
}); | ||
stream.on(`end`, () => { | ||
this.writeFileSync(p, Buffer.concat(chunks), encoding); | ||
}); | ||
return stream; | ||
} | ||
async realpathPromise(p) { | ||
return this.realpathSync(p); | ||
} | ||
realpathSync(p) { | ||
const resolvedP = this.resolveFilename(`lstat '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`lstat '${p}'`); | ||
return resolvedP; | ||
} | ||
async existsPromise(p) { | ||
return this.existsSync(p); | ||
} | ||
existsSync(p) { | ||
let resolvedP; | ||
try { | ||
this.stats = this.baseFs.statSync(source); | ||
} catch (error) { | ||
if (error.code === `ENOENT` && pathOptions.create) { | ||
this.stats = makeDefaultStats(); | ||
} else { | ||
resolvedP = this.resolveFilename(`stat '${p}'`, p); | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
return this.entries.has(resolvedP) || this.listings.has(resolvedP); | ||
} | ||
async accessPromise(p, mode) { | ||
return this.accessSync(p, mode); | ||
} | ||
accessSync(p, mode = fs_1.constants.F_OK) { | ||
const resolvedP = this.resolveFilename(`access '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`access '${p}'`); | ||
if (this.readOnly && (mode & fs_1.constants.W_OK)) { | ||
throw errors.EROFS(`access '${p}'`); | ||
} | ||
} | ||
async statPromise(p) { | ||
return this.statSync(p); | ||
} | ||
statSync(p) { | ||
const resolvedP = this.resolveFilename(`stat '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`stat '${p}'`); | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) | ||
throw errors.ENOTDIR(`stat '${p}'`); | ||
return this.statImpl(`stat '${p}'`, resolvedP); | ||
} | ||
async lstatPromise(p) { | ||
return this.lstatSync(p); | ||
} | ||
lstatSync(p) { | ||
const resolvedP = this.resolveFilename(`lstat '${p}'`, p, false); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`lstat '${p}'`); | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) | ||
throw errors.ENOTDIR(`lstat '${p}'`); | ||
return this.statImpl(`lstat '${p}'`, resolvedP); | ||
} | ||
statImpl(reason, p) { | ||
const entry = this.entries.get(p); | ||
// File, or explicit directory | ||
if (typeof entry !== `undefined`) { | ||
const stat = this.libzip.struct.statS(); | ||
const rc = this.libzip.statIndex(this.zip, entry, 0, 0, stat); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
const uid = this.stats.uid; | ||
const gid = this.stats.gid; | ||
const size = (this.libzip.struct.statSize(stat) >>> 0); | ||
const blksize = 512; | ||
const blocks = Math.ceil(size / blksize); | ||
const mtimeMs = (this.libzip.struct.statMtime(stat) >>> 0) * 1000; | ||
const atimeMs = mtimeMs; | ||
const birthtimeMs = mtimeMs; | ||
const ctimeMs = mtimeMs; | ||
const atime = new Date(atimeMs); | ||
const birthtime = new Date(birthtimeMs); | ||
const ctime = new Date(ctimeMs); | ||
const mtime = new Date(mtimeMs); | ||
const type = this.listings.has(p) | ||
? S_IFDIR | ||
: S_IFREG; | ||
const defaultMode = type === S_IFDIR | ||
? 0o755 | ||
: 0o644; | ||
const mode = type | (this.getUnixMode(entry, defaultMode) & 0o777); | ||
return Object.assign(new StatEntry(), { uid, gid, size, blksize, blocks, atime, birthtime, ctime, mtime, atimeMs, birthtimeMs, ctimeMs, mtimeMs, mode }); | ||
} | ||
// Implicit directory | ||
if (this.listings.has(p)) { | ||
const uid = this.stats.uid; | ||
const gid = this.stats.gid; | ||
const size = 0; | ||
const blksize = 512; | ||
const blocks = 0; | ||
const atimeMs = this.stats.mtimeMs; | ||
const birthtimeMs = this.stats.mtimeMs; | ||
const ctimeMs = this.stats.mtimeMs; | ||
const mtimeMs = this.stats.mtimeMs; | ||
const atime = new Date(atimeMs); | ||
const birthtime = new Date(birthtimeMs); | ||
const ctime = new Date(ctimeMs); | ||
const mtime = new Date(mtimeMs); | ||
const mode = S_IFDIR | 0o755; | ||
return Object.assign(new StatEntry(), { uid, gid, size, blksize, blocks, atime, birthtime, ctime, mtime, atimeMs, birthtimeMs, ctimeMs, mtimeMs, mode }); | ||
} | ||
throw new Error(`Unreachable`); | ||
} | ||
getUnixMode(index, defaultMode) { | ||
const rc = this.libzip.file.getExternalAttributes(this.zip, index, 0, 0, this.libzip.uint08S, this.libzip.uint32S); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
const opsys = this.libzip.getValue(this.libzip.uint08S, `i8`) >>> 0; | ||
if (opsys !== this.libzip.ZIP_OPSYS_UNIX) | ||
return defaultMode; | ||
return this.libzip.getValue(this.libzip.uint32S, `i32`) >>> 16; | ||
} | ||
registerListing(p) { | ||
let listing = this.listings.get(p); | ||
if (listing) | ||
return listing; | ||
const parentListing = this.registerListing(path_1.ppath.dirname(p)); | ||
listing = new Set(); | ||
parentListing.add(path_1.ppath.basename(p)); | ||
this.listings.set(p, listing); | ||
return listing; | ||
} | ||
registerEntry(p, index) { | ||
const parentListing = this.registerListing(path_1.ppath.dirname(p)); | ||
parentListing.add(path_1.ppath.basename(p)); | ||
this.entries.set(p, index); | ||
} | ||
resolveFilename(reason, p, resolveLastComponent = true) { | ||
if (!this.ready) | ||
throw errors.EBUSY(`archive closed, ${reason}`); | ||
let resolvedP = path_1.ppath.resolve(path_1.PortablePath.root, p); | ||
if (resolvedP === `/`) | ||
return path_1.PortablePath.root; | ||
while (true) { | ||
const parentP = this.resolveFilename(reason, path_1.ppath.dirname(resolvedP), true); | ||
const isDir = this.listings.has(parentP); | ||
const doesExist = this.entries.has(parentP); | ||
if (!isDir && !doesExist) | ||
throw errors.ENOENT(reason); | ||
if (!isDir) | ||
throw errors.ENOTDIR(reason); | ||
resolvedP = path_1.ppath.resolve(parentP, path_1.ppath.basename(resolvedP)); | ||
if (!resolveLastComponent) | ||
break; | ||
const index = this.libzip.name.locate(this.zip, resolvedP); | ||
if (index === -1) | ||
break; | ||
if (this.isSymbolicLink(index)) { | ||
const target = this.getFileSource(index).toString(); | ||
resolvedP = path_1.ppath.resolve(path_1.ppath.dirname(resolvedP), target); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
return resolvedP; | ||
} | ||
allocateBuffer(content) { | ||
if (!Buffer.isBuffer(content)) | ||
content = Buffer.from(content); | ||
const buffer = this.libzip.malloc(content.byteLength); | ||
if (!buffer) | ||
throw new Error(`Couldn't allocate enough memory`); | ||
// Copy the file into the Emscripten heap | ||
const heap = new Uint8Array(this.libzip.HEAPU8.buffer, buffer, content.byteLength); | ||
heap.set(content); | ||
return { buffer, byteLength: content.byteLength }; | ||
} | ||
allocateUnattachedSource(content) { | ||
const error = this.libzip.struct.errorS(); | ||
const { buffer, byteLength } = this.allocateBuffer(content); | ||
const source = this.libzip.source.fromUnattachedBuffer(buffer, byteLength, 0, true, error); | ||
if (source === 0) { | ||
this.libzip.free(error); | ||
throw new Error(this.libzip.error.strerror(error)); | ||
} | ||
return source; | ||
} | ||
allocateSource(content) { | ||
const { buffer, byteLength } = this.allocateBuffer(content); | ||
const source = this.libzip.source.fromBuffer(this.zip, buffer, byteLength, 0, true); | ||
if (source === 0) { | ||
this.libzip.free(buffer); | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
} | ||
return source; | ||
} | ||
setFileSource(p, content) { | ||
const target = path_1.ppath.relative(path_1.PortablePath.root, p); | ||
const lzSource = this.allocateSource(content); | ||
try { | ||
return this.libzip.file.add(this.zip, target, lzSource, this.libzip.ZIP_FL_OVERWRITE); | ||
} | ||
catch (error) { | ||
this.libzip.source.free(lzSource); | ||
throw error; | ||
} | ||
} | ||
} else { | ||
this.stats = makeDefaultStats(); | ||
} | ||
} | ||
const errPtr = _libzip.default.malloc(4); | ||
try { | ||
let flags = 0; | ||
if (typeof source === `string` && pathOptions.create) flags |= _libzip.default.ZIP_CREATE | _libzip.default.ZIP_TRUNCATE; | ||
if (opts.readOnly) { | ||
flags |= _libzip.default.ZIP_RDONLY; | ||
this.readOnly = true; | ||
} | ||
if (typeof source === `string`) { | ||
this.zip = _libzip.default.open(_path.npath.fromPortablePath(source), flags, errPtr); | ||
} else { | ||
const lzSource = this.allocateUnattachedSource(source); | ||
isSymbolicLink(index) { | ||
const attrs = this.libzip.file.getExternalAttributes(this.zip, index, 0, 0, this.libzip.uint08S, this.libzip.uint32S); | ||
if (attrs === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
const opsys = this.libzip.getValue(this.libzip.uint08S, `i8`) >>> 0; | ||
if (opsys !== this.libzip.ZIP_OPSYS_UNIX) | ||
return false; | ||
const attributes = this.libzip.getValue(this.libzip.uint32S, `i32`) >>> 16; | ||
return (attributes & S_IFMT) === S_IFLNK; | ||
} | ||
getFileSource(index) { | ||
const stat = this.libzip.struct.statS(); | ||
const rc = this.libzip.statIndex(this.zip, index, 0, 0, stat); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
const size = this.libzip.struct.statSize(stat); | ||
const buffer = this.libzip.malloc(size); | ||
try { | ||
this.zip = _libzip.default.openFromSource(lzSource, flags, errPtr); | ||
} catch (error) { | ||
_libzip.default.source.free(lzSource); | ||
throw error; | ||
const file = this.libzip.fopenIndex(this.zip, index, 0, 0); | ||
if (file === 0) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
try { | ||
const rc = this.libzip.fread(file, buffer, size, 0); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.file.getError(file))); | ||
else if (rc < size) | ||
throw new Error(`Incomplete read`); | ||
else if (rc > size) | ||
throw new Error(`Overread`); | ||
const memory = this.libzip.HEAPU8.subarray(buffer, buffer + size); | ||
const data = Buffer.from(memory); | ||
return data; | ||
} | ||
finally { | ||
this.libzip.fclose(file); | ||
} | ||
} | ||
} | ||
if (this.zip === 0) { | ||
const error = _libzip.default.struct.errorS(); | ||
_libzip.default.error.initWithCode(error, _libzip.default.getValue(errPtr, `i32`)); | ||
throw new Error(_libzip.default.error.strerror(error)); | ||
} | ||
} finally { | ||
_libzip.default.free(errPtr); | ||
finally { | ||
this.libzip.free(buffer); | ||
} | ||
} | ||
this.listings.set(_path.PortablePath.root, new Set()); | ||
const entryCount = _libzip.default.getNumEntries(this.zip, 0); | ||
for (let t = 0; t < entryCount; ++t) { | ||
const raw = _libzip.default.getName(this.zip, t, 0); | ||
if (_path.ppath.isAbsolute(raw)) continue; | ||
const p = _path.ppath.resolve(_path.PortablePath.root, raw); | ||
this.registerEntry(p, t); // If the raw path is a directory, register it | ||
// to prevent empty folder being skipped | ||
if (raw.endsWith('/')) { | ||
this.registerListing(p); | ||
} | ||
async chmodPromise(p, mask) { | ||
return this.chmodSync(p, mask); | ||
} | ||
this.ready = true; | ||
} | ||
getAllFiles() { | ||
return Array.from(this.entries.keys()); | ||
} | ||
getRealPath() { | ||
if (!this.path) throw new Error(`ZipFS don't have real paths when loaded from a buffer`); | ||
return this.path; | ||
} | ||
saveAndClose() { | ||
if (!this.path || !this.baseFs) throw new Error(`ZipFS cannot be saved and must be discarded when loaded from a buffer`); | ||
if (!this.ready) throw errors.EBUSY(`archive closed, close`); | ||
if (this.readOnly) return this.discardAndClose(); | ||
const previousMod = this.baseFs.existsSync(this.path) ? this.baseFs.statSync(this.path).mode & 0o777 : null; | ||
const rc = _libzip.default.close(this.zip); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); // Libzip overrides the chmod when writing the archive, which is a weird | ||
// behavior I don't totally understand (plus the umask seems bogus in some | ||
// weird cases - maybe related to emscripten?) | ||
// | ||
// See also https://github.com/nih-at/libzip/issues/77 | ||
if (previousMod === null) this.baseFs.chmodSync(this.path, this.stats.mode);else if (previousMod !== (this.baseFs.statSync(this.path).mode & 0o777)) this.baseFs.chmodSync(this.path, previousMod); | ||
this.ready = false; | ||
} | ||
discardAndClose() { | ||
if (!this.ready) throw errors.EBUSY(`archive closed, close`); | ||
_libzip.default.discard(this.zip); | ||
this.ready = false; | ||
} | ||
async openPromise(p, flags, mode) { | ||
return this.openSync(p, flags, mode); | ||
} | ||
openSync(p, flags, mode) { | ||
const fd = this.nextFd++; | ||
this.fds.set(fd, { | ||
cursor: 0, | ||
p | ||
}); | ||
return fd; | ||
} | ||
async readPromise(fd, buffer, offset, length, position) { | ||
return this.readSync(fd, buffer, offset, length, position); | ||
} | ||
readSync(fd, buffer, offset = 0, length = 0, position = -1) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) throw errors.EBADF(`read`); | ||
let realPosition; | ||
if (position === -1 || position === null) realPosition = entry.cursor;else realPosition = position; | ||
const source = this.readFileSync(entry.p); | ||
source.copy(buffer, offset, realPosition, realPosition + length); | ||
const bytesRead = Math.max(0, Math.min(source.length - realPosition, length)); | ||
if (position === -1) entry.cursor += bytesRead; | ||
return bytesRead; | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
if (typeof buffer === `string`) { | ||
return this.writeSync(fd, buffer, position); | ||
} else { | ||
return this.writeSync(fd, buffer, offset, length, position); | ||
chmodSync(p, mask) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`chmod '${p}'`); | ||
const resolvedP = this.resolveFilename(`chmod '${p}'`, p, false); | ||
// We silently ignore chmod requests for directories | ||
if (this.listings.has(resolvedP)) | ||
return; | ||
const entry = this.entries.get(resolvedP); | ||
if (typeof entry === `undefined`) | ||
throw new Error(`Assertion failed: The entry should have been registered (${resolvedP})`); | ||
const oldMod = this.getUnixMode(entry, S_IFREG | 0o000); | ||
const newMod = oldMod & (~0o777) | mask; | ||
const rc = this.libzip.file.setExternalAttributes(this.zip, entry, 0, 0, this.libzip.ZIP_OPSYS_UNIX, newMod << 16); | ||
if (rc === -1) { | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
} | ||
} | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) throw errors.EBADF(`read`); | ||
throw new Error(`Unimplemented`); | ||
} | ||
async closePromise(fd) { | ||
return this.closeSync(fd); | ||
} | ||
closeSync(fd) { | ||
const entry = this.fds.get(fd); | ||
if (typeof entry === `undefined`) throw errors.EBADF(`read`); | ||
this.fds.delete(fd); | ||
} | ||
createReadStream(p, { | ||
encoding | ||
} = {}) { | ||
if (p === null) throw new Error(`Unimplemented`); | ||
const stream = Object.assign(new _stream.PassThrough(), { | ||
bytesRead: 0, | ||
path: p, | ||
close: () => { | ||
clearImmediate(immediate); | ||
} | ||
}); | ||
const immediate = setImmediate(() => { | ||
try { | ||
const data = this.readFileSync(p, encoding); | ||
stream.bytesRead = data.length; | ||
stream.write(data); | ||
stream.end(); | ||
} catch (error) { | ||
stream.emit(`error`, error); | ||
stream.end(); | ||
} | ||
}); | ||
return stream; | ||
} | ||
createWriteStream(p, { | ||
encoding | ||
} = {}) { | ||
if (this.readOnly) throw errors.EROFS(`open '${p}'`); | ||
if (p === null) throw new Error(`Unimplemented`); | ||
const stream = Object.assign(new _stream.PassThrough(), { | ||
bytesWritten: 0, | ||
path: p, | ||
close: () => { | ||
stream.end(); | ||
} | ||
}); | ||
const chunks = []; | ||
stream.on(`data`, chunk => { | ||
const chunkBuffer = Buffer.from(chunk); | ||
stream.bytesWritten += chunkBuffer.length; | ||
chunks.push(chunkBuffer); | ||
}); | ||
stream.on(`end`, () => { | ||
this.writeFileSync(p, Buffer.concat(chunks), encoding); | ||
}); | ||
return stream; | ||
} | ||
async realpathPromise(p) { | ||
return this.realpathSync(p); | ||
} | ||
realpathSync(p) { | ||
const resolvedP = this.resolveFilename(`lstat '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`lstat '${p}'`); | ||
return resolvedP; | ||
} | ||
async existsPromise(p) { | ||
return this.existsSync(p); | ||
} | ||
existsSync(p) { | ||
let resolvedP; | ||
try { | ||
resolvedP = this.resolveFilename(`stat '${p}'`, p); | ||
} catch (error) { | ||
return false; | ||
async renamePromise(oldP, newP) { | ||
return this.renameSync(oldP, newP); | ||
} | ||
return this.entries.has(resolvedP) || this.listings.has(resolvedP); | ||
} | ||
async accessPromise(p, mode) { | ||
return this.accessSync(p, mode); | ||
} | ||
accessSync(p, mode = _fs.constants.F_OK) { | ||
const resolvedP = this.resolveFilename(`access '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`access '${p}'`); | ||
if (this.readOnly && mode & _fs.constants.W_OK) { | ||
throw errors.EROFS(`access '${p}'`); | ||
renameSync(oldP, newP) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
} | ||
async statPromise(p) { | ||
return this.statSync(p); | ||
} | ||
statSync(p) { | ||
const resolvedP = this.resolveFilename(`stat '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`stat '${p}'`); | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) throw errors.ENOTDIR(`stat '${p}'`); | ||
return this.statImpl(`stat '${p}'`, resolvedP); | ||
} | ||
async lstatPromise(p) { | ||
return this.lstatSync(p); | ||
} | ||
lstatSync(p) { | ||
const resolvedP = this.resolveFilename(`lstat '${p}'`, p, false); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`lstat '${p}'`); | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) throw errors.ENOTDIR(`lstat '${p}'`); | ||
return this.statImpl(`lstat '${p}'`, resolvedP); | ||
} | ||
statImpl(reason, p) { | ||
const entry = this.entries.get(p); // File, or explicit directory | ||
if (typeof entry !== `undefined`) { | ||
const stat = _libzip.default.struct.statS(); | ||
const rc = _libzip.default.statIndex(this.zip, entry, 0, 0, stat); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
const uid = this.stats.uid; | ||
const gid = this.stats.gid; | ||
const size = _libzip.default.struct.statSize(stat) >>> 0; | ||
const blksize = 512; | ||
const blocks = Math.ceil(size / blksize); | ||
const mtimeMs = (_libzip.default.struct.statMtime(stat) >>> 0) * 1000; | ||
const atimeMs = mtimeMs; | ||
const birthtimeMs = mtimeMs; | ||
const ctimeMs = mtimeMs; | ||
const atime = new Date(atimeMs); | ||
const birthtime = new Date(birthtimeMs); | ||
const ctime = new Date(ctimeMs); | ||
const mtime = new Date(mtimeMs); | ||
const type = this.listings.has(p) ? S_IFDIR : S_IFREG; | ||
const defaultMode = type === S_IFDIR ? 0o755 : 0o644; | ||
const mode = type | this.getUnixMode(entry, defaultMode) & 0o777; | ||
return Object.assign(new StatEntry(), { | ||
uid, | ||
gid, | ||
size, | ||
blksize, | ||
blocks, | ||
atime, | ||
birthtime, | ||
ctime, | ||
mtime, | ||
atimeMs, | ||
birthtimeMs, | ||
ctimeMs, | ||
mtimeMs, | ||
mode | ||
}); | ||
} // Implicit directory | ||
if (this.listings.has(p)) { | ||
const uid = this.stats.uid; | ||
const gid = this.stats.gid; | ||
const size = 0; | ||
const blksize = 512; | ||
const blocks = 0; | ||
const atimeMs = this.stats.mtimeMs; | ||
const birthtimeMs = this.stats.mtimeMs; | ||
const ctimeMs = this.stats.mtimeMs; | ||
const mtimeMs = this.stats.mtimeMs; | ||
const atime = new Date(atimeMs); | ||
const birthtime = new Date(birthtimeMs); | ||
const ctime = new Date(ctimeMs); | ||
const mtime = new Date(mtimeMs); | ||
const mode = S_IFDIR | 0o755; | ||
return Object.assign(new StatEntry(), { | ||
uid, | ||
gid, | ||
size, | ||
blksize, | ||
blocks, | ||
atime, | ||
birthtime, | ||
ctime, | ||
mtime, | ||
atimeMs, | ||
birthtimeMs, | ||
ctimeMs, | ||
mtimeMs, | ||
mode | ||
}); | ||
async copyFilePromise(sourceP, destP, flags) { | ||
return this.copyFileSync(sourceP, destP, flags); | ||
} | ||
throw new Error(`Unreachable`); | ||
} | ||
getUnixMode(index, defaultMode) { | ||
const rc = _libzip.default.file.getExternalAttributes(this.zip, index, 0, 0, _libzip.default.uint08S, _libzip.default.uint32S); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
const opsys = _libzip.default.getValue(_libzip.default.uint08S, `i8`) >>> 0; | ||
if (opsys !== _libzip.default.ZIP_OPSYS_UNIX) return defaultMode; | ||
return _libzip.default.getValue(_libzip.default.uint32S, `i32`) >>> 16; | ||
} | ||
registerListing(p) { | ||
let listing = this.listings.get(p); | ||
if (listing) return listing; | ||
const parentListing = this.registerListing(_path.ppath.dirname(p)); | ||
listing = new Set(); | ||
parentListing.add(_path.ppath.basename(p)); | ||
this.listings.set(p, listing); | ||
return listing; | ||
} | ||
registerEntry(p, index) { | ||
const parentListing = this.registerListing(_path.ppath.dirname(p)); | ||
parentListing.add(_path.ppath.basename(p)); | ||
this.entries.set(p, index); | ||
} | ||
resolveFilename(reason, p, resolveLastComponent = true) { | ||
if (!this.ready) throw errors.EBUSY(`archive closed, ${reason}`); | ||
let resolvedP = _path.ppath.resolve(_path.PortablePath.root, p); | ||
if (resolvedP === `/`) return _path.PortablePath.root; | ||
while (true) { | ||
const parentP = this.resolveFilename(reason, _path.ppath.dirname(resolvedP), true); | ||
const isDir = this.listings.has(parentP); | ||
const doesExist = this.entries.has(parentP); | ||
if (!isDir && !doesExist) throw errors.ENOENT(reason); | ||
if (!isDir) throw errors.ENOTDIR(reason); | ||
resolvedP = _path.ppath.resolve(parentP, _path.ppath.basename(resolvedP)); | ||
if (!resolveLastComponent) break; | ||
const index = _libzip.default.name.locate(this.zip, resolvedP); | ||
if (index === -1) break; | ||
if (this.isSymbolicLink(index)) { | ||
const target = this.getFileSource(index).toString(); | ||
resolvedP = _path.ppath.resolve(_path.ppath.dirname(resolvedP), target); | ||
} else { | ||
break; | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`copyfile '${sourceP} -> '${destP}'`); | ||
if ((flags & fs_1.constants.COPYFILE_FICLONE_FORCE) !== 0) | ||
throw errors.ENOSYS(`unsupported clone operation`, `copyfile '${sourceP}' -> ${destP}'`); | ||
const resolvedSourceP = this.resolveFilename(`copyfile '${sourceP} -> ${destP}'`, sourceP); | ||
const indexSource = this.entries.get(resolvedSourceP); | ||
if (typeof indexSource === `undefined`) | ||
throw errors.EINVAL(`copyfile '${sourceP}' -> '${destP}'`); | ||
const resolvedDestP = this.resolveFilename(`copyfile '${sourceP}' -> ${destP}'`, destP); | ||
const indexDest = this.entries.get(resolvedDestP); | ||
if ((flags & (fs_1.constants.COPYFILE_EXCL | fs_1.constants.COPYFILE_FICLONE_FORCE)) !== 0 && typeof indexDest !== `undefined`) | ||
throw errors.EEXIST(`copyfile '${sourceP}' -> '${destP}'`); | ||
const source = this.getFileSource(indexSource); | ||
const newIndex = this.setFileSource(resolvedDestP, source); | ||
if (newIndex !== indexDest) { | ||
this.registerEntry(resolvedDestP, newIndex); | ||
} | ||
} | ||
return resolvedP; | ||
} | ||
allocateBuffer(content) { | ||
if (!Buffer.isBuffer(content)) content = Buffer.from(content); | ||
const buffer = _libzip.default.malloc(content.byteLength); | ||
if (!buffer) throw new Error(`Couldn't allocate enough memory`); // Copy the file into the Emscripten heap | ||
const heap = new Uint8Array(_libzip.default.HEAPU8.buffer, buffer, content.byteLength); | ||
heap.set(content); | ||
return { | ||
buffer, | ||
byteLength: content.byteLength | ||
}; | ||
} | ||
allocateUnattachedSource(content) { | ||
const error = _libzip.default.struct.errorS(); | ||
const { | ||
buffer, | ||
byteLength | ||
} = this.allocateBuffer(content); | ||
const source = _libzip.default.source.fromUnattachedBuffer(buffer, byteLength, 0, true, error); | ||
if (source === 0) { | ||
_libzip.default.free(error); | ||
throw new Error(_libzip.default.error.strerror(error)); | ||
async appendFilePromise(p, content, opts) { | ||
return this.appendFileSync(p, content, opts); | ||
} | ||
return source; | ||
} | ||
allocateSource(content) { | ||
const { | ||
buffer, | ||
byteLength | ||
} = this.allocateBuffer(content); | ||
const source = _libzip.default.source.fromBuffer(this.zip, buffer, byteLength, 0, true); | ||
if (source === 0) { | ||
_libzip.default.free(buffer); | ||
throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
appendFileSync(p, content, opts = {}) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`open '${p}'`); | ||
if (typeof opts === `undefined`) | ||
opts = { flag: `a` }; | ||
else if (typeof opts === `string`) | ||
opts = { flag: `a`, encoding: opts }; | ||
else if (typeof opts.flag === `undefined`) | ||
opts = Object.assign({ flag: `a` }, opts); | ||
return this.writeFileSync(p, content, opts); | ||
} | ||
return source; | ||
} | ||
setFileSource(p, content) { | ||
const target = _path.ppath.relative(_path.PortablePath.root, p); | ||
const lzSource = this.allocateSource(content); | ||
try { | ||
return _libzip.default.file.add(this.zip, target, lzSource, _libzip.default.ZIP_FL_OVERWRITE); | ||
} catch (error) { | ||
_libzip.default.source.free(lzSource); | ||
throw error; | ||
async writeFilePromise(p, content, opts) { | ||
return this.writeFileSync(p, content, opts); | ||
} | ||
} | ||
isSymbolicLink(index) { | ||
const attrs = _libzip.default.file.getExternalAttributes(this.zip, index, 0, 0, _libzip.default.uint08S, _libzip.default.uint32S); | ||
if (attrs === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
const opsys = _libzip.default.getValue(_libzip.default.uint08S, `i8`) >>> 0; | ||
if (opsys !== _libzip.default.ZIP_OPSYS_UNIX) return false; | ||
const attributes = _libzip.default.getValue(_libzip.default.uint32S, `i32`) >>> 16; | ||
return (attributes & S_IFMT) === S_IFLNK; | ||
} | ||
getFileSource(index) { | ||
const stat = _libzip.default.struct.statS(); | ||
const rc = _libzip.default.statIndex(this.zip, index, 0, 0, stat); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
const size = _libzip.default.struct.statSize(stat); | ||
const buffer = _libzip.default.malloc(size); | ||
try { | ||
const file = _libzip.default.fopenIndex(this.zip, index, 0, 0); | ||
if (file === 0) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
try { | ||
const rc = _libzip.default.fread(file, buffer, size, 0); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.file.getError(file)));else if (rc < size) throw new Error(`Incomplete read`);else if (rc > size) throw new Error(`Overread`); | ||
const memory = _libzip.default.HEAPU8.subarray(buffer, buffer + size); | ||
const data = Buffer.from(memory); | ||
return data; | ||
} finally { | ||
_libzip.default.fclose(file); | ||
} | ||
} finally { | ||
_libzip.default.free(buffer); | ||
writeFileSync(p, content, opts) { | ||
if (typeof p !== `string`) | ||
throw errors.EBADF(`read`); | ||
if (this.readOnly) | ||
throw errors.EROFS(`open '${p}'`); | ||
const resolvedP = this.resolveFilename(`open '${p}'`, p); | ||
if (this.listings.has(resolvedP)) | ||
throw errors.EISDIR(`open '${p}'`); | ||
const index = this.entries.get(resolvedP); | ||
if (index !== undefined && typeof opts === `object` && opts.flag && opts.flag.includes(`a`)) | ||
content = Buffer.concat([this.getFileSource(index), Buffer.from(content)]); | ||
let encoding = null; | ||
if (typeof opts === `string`) | ||
encoding = opts; | ||
else if (typeof opts === `object` && opts.encoding) | ||
encoding = opts.encoding; | ||
if (encoding !== null) | ||
content = content.toString(encoding); | ||
const newIndex = this.setFileSource(resolvedP, content); | ||
if (newIndex !== index) { | ||
this.registerEntry(resolvedP, newIndex); | ||
} | ||
} | ||
} | ||
async chmodPromise(p, mask) { | ||
return this.chmodSync(p, mask); | ||
} | ||
chmodSync(p, mask) { | ||
if (this.readOnly) throw errors.EROFS(`chmod '${p}'`); | ||
const resolvedP = this.resolveFilename(`chmod '${p}'`, p, false); // We silently ignore chmod requests for directories | ||
if (this.listings.has(resolvedP)) return; | ||
const entry = this.entries.get(resolvedP); | ||
if (typeof entry === `undefined`) throw new Error(`Assertion failed: The entry should have been registered (${resolvedP})`); | ||
const oldMod = this.getUnixMode(entry, S_IFREG | 0o000); | ||
const newMod = oldMod & ~0o777 | mask; | ||
const rc = _libzip.default.file.setExternalAttributes(this.zip, entry, 0, 0, _libzip.default.ZIP_OPSYS_UNIX, newMod << 16); | ||
if (rc === -1) { | ||
throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
async unlinkPromise(p) { | ||
return this.unlinkSync(p); | ||
} | ||
} | ||
async renamePromise(oldP, newP) { | ||
return this.renameSync(oldP, newP); | ||
} | ||
renameSync(oldP, newP) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
async copyFilePromise(sourceP, destP, flags) { | ||
return this.copyFileSync(sourceP, destP, flags); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
if (this.readOnly) throw errors.EROFS(`copyfile '${sourceP} -> '${destP}'`); | ||
if ((flags & _fs.constants.COPYFILE_FICLONE_FORCE) !== 0) throw errors.ENOSYS(`unsupported clone operation`, `copyfile '${sourceP}' -> ${destP}'`); | ||
const resolvedSourceP = this.resolveFilename(`copyfile '${sourceP} -> ${destP}'`, sourceP); | ||
const indexSource = this.entries.get(resolvedSourceP); | ||
if (typeof indexSource === `undefined`) throw errors.EINVAL(`copyfile '${sourceP}' -> '${destP}'`); | ||
const resolvedDestP = this.resolveFilename(`copyfile '${sourceP}' -> ${destP}'`, destP); | ||
const indexDest = this.entries.get(resolvedDestP); | ||
if ((flags & (_fs.constants.COPYFILE_EXCL | _fs.constants.COPYFILE_FICLONE_FORCE)) !== 0 && typeof indexDest !== `undefined`) throw errors.EEXIST(`copyfile '${sourceP}' -> '${destP}'`); | ||
const source = this.getFileSource(indexSource); | ||
const newIndex = this.setFileSource(resolvedDestP, source); | ||
if (newIndex !== indexDest) { | ||
this.registerEntry(resolvedDestP, newIndex); | ||
unlinkSync(p) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
} | ||
async appendFilePromise(p, content, opts) { | ||
return this.appendFileSync(p, content, opts); | ||
} | ||
appendFileSync(p, content, opts = {}) { | ||
if (this.readOnly) throw errors.EROFS(`open '${p}'`); | ||
if (typeof opts === `undefined`) opts = { | ||
flag: `a` | ||
};else if (typeof opts === `string`) opts = { | ||
flag: `a`, | ||
encoding: opts | ||
};else if (typeof opts.flag === `undefined`) opts = { | ||
flag: `a`, | ||
...opts | ||
}; | ||
return this.writeFileSync(p, content, opts); | ||
} | ||
async writeFilePromise(p, content, opts) { | ||
return this.writeFileSync(p, content, opts); | ||
} | ||
writeFileSync(p, content, opts) { | ||
if (typeof p !== `string`) throw errors.EBADF(`read`); | ||
if (this.readOnly) throw errors.EROFS(`open '${p}'`); | ||
const resolvedP = this.resolveFilename(`open '${p}'`, p); | ||
if (this.listings.has(resolvedP)) throw errors.EISDIR(`open '${p}'`); | ||
const index = this.entries.get(resolvedP); | ||
if (index !== undefined && typeof opts === `object` && opts.flag && opts.flag.includes(`a`)) content = Buffer.concat([this.getFileSource(index), Buffer.from(content)]); | ||
let encoding = null; | ||
if (typeof opts === `string`) encoding = opts;else if (typeof opts === `object` && opts.encoding) encoding = opts.encoding; | ||
if (encoding !== null) content = content.toString(encoding); | ||
const newIndex = this.setFileSource(resolvedP, content); | ||
if (newIndex !== index) { | ||
this.registerEntry(resolvedP, newIndex); | ||
async utimesPromise(p, atime, mtime) { | ||
return this.utimesSync(p, atime, mtime); | ||
} | ||
} | ||
async unlinkPromise(p) { | ||
return this.unlinkSync(p); | ||
} | ||
unlinkSync(p) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
async utimesPromise(p, atime, mtime) { | ||
return this.utimesSync(p, atime, mtime); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
if (this.readOnly) throw errors.EROFS(`utimes '${p}'`); | ||
const resolvedP = this.resolveFilename(`utimes '${p}'`, p); | ||
this.utimesImpl(resolvedP, mtime); | ||
} | ||
async lutimesPromise(p, atime, mtime) { | ||
return this.lutimesSync(p, atime, mtime); | ||
} | ||
lutimesSync(p, atime, mtime) { | ||
if (this.readOnly) throw errors.EROFS(`lutimes '${p}'`); | ||
const resolvedP = this.resolveFilename(`utimes '${p}'`, p, false); | ||
this.utimesImpl(resolvedP, mtime); | ||
} | ||
utimesImpl(resolvedP, mtime) { | ||
if (this.listings.has(resolvedP)) if (!this.entries.has(resolvedP)) this.hydrateDirectory(resolvedP); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) throw new Error(`Unreachable`); | ||
const rc = _libzip.default.file.setMtime(this.zip, entry, 0, toUnixTimestamp(mtime), 0); | ||
if (rc === -1) { | ||
throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
utimesSync(p, atime, mtime) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`utimes '${p}'`); | ||
const resolvedP = this.resolveFilename(`utimes '${p}'`, p); | ||
this.utimesImpl(resolvedP, mtime); | ||
} | ||
} | ||
async mkdirPromise(p, opts) { | ||
return this.mkdirSync(p, opts); | ||
} | ||
mkdirSync(p, opts) { | ||
if (opts && opts.recursive) return this.mkdirpSync(p, { | ||
chmod: opts.mode | ||
}); | ||
if (this.readOnly) throw errors.EROFS(`mkdir '${p}'`); | ||
const resolvedP = this.resolveFilename(`mkdir '${p}'`, p); | ||
if (this.entries.has(resolvedP) || this.listings.has(resolvedP)) throw errors.EEXIST(`mkdir '${p}'`); | ||
this.hydrateDirectory(resolvedP); | ||
} | ||
async rmdirPromise(p) { | ||
return this.rmdirSync(p); | ||
} | ||
rmdirSync(p) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
hydrateDirectory(resolvedP) { | ||
const index = _libzip.default.dir.add(this.zip, _path.ppath.relative(_path.PortablePath.root, resolvedP)); | ||
if (index === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
this.registerListing(resolvedP); | ||
this.registerEntry(resolvedP, index); | ||
return index; | ||
} | ||
async symlinkPromise(target, p) { | ||
return this.symlinkSync(target, p); | ||
} | ||
symlinkSync(target, p) { | ||
if (this.readOnly) throw errors.EROFS(`symlink '${target}' -> '${p}'`); | ||
const resolvedP = this.resolveFilename(`symlink '${target}' -> '${p}'`, p); | ||
if (this.listings.has(resolvedP)) throw errors.EISDIR(`symlink '${target}' -> '${p}'`); | ||
if (this.entries.has(resolvedP)) throw errors.EEXIST(`symlink '${target}' -> '${p}'`); | ||
const index = this.setFileSource(resolvedP, target); | ||
this.registerEntry(resolvedP, index); | ||
const rc = _libzip.default.file.setExternalAttributes(this.zip, index, 0, 0, _libzip.default.ZIP_OPSYS_UNIX, (0o120000 | 0o777) << 16); | ||
if (rc === -1) { | ||
throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
async lutimesPromise(p, atime, mtime) { | ||
return this.lutimesSync(p, atime, mtime); | ||
} | ||
} | ||
async readFilePromise(p, encoding) { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return this.readFileSync(p, encoding); | ||
default: | ||
return this.readFileSync(p, encoding); | ||
lutimesSync(p, atime, mtime) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`lutimes '${p}'`); | ||
const resolvedP = this.resolveFilename(`utimes '${p}'`, p, false); | ||
this.utimesImpl(resolvedP, mtime); | ||
} | ||
} | ||
readFileSync(p, encoding) { | ||
if (typeof p !== `string`) throw errors.EBADF(`read`); // This is messed up regarding the TS signatures | ||
if (typeof encoding === `object`) // @ts-ignore | ||
encoding = encoding ? encoding.encoding : undefined; | ||
const resolvedP = this.resolveFilename(`open '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`open '${p}'`); // Ensures that the last component is a directory, if the user said so (even if it is we'll throw right after with EISDIR anyway) | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) throw errors.ENOTDIR(`open '${p}'`); | ||
if (this.listings.has(resolvedP)) throw errors.EISDIR(`read`); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) throw new Error(`Unreachable`); | ||
const data = this.getFileSource(entry); | ||
return encoding ? data.toString(encoding) : data; | ||
} | ||
async readdirPromise(p, { | ||
withFileTypes | ||
} = {}) { | ||
return this.readdirSync(p, { | ||
withFileTypes: withFileTypes | ||
}); | ||
} | ||
readdirSync(p, { | ||
withFileTypes | ||
} = {}) { | ||
const resolvedP = this.resolveFilename(`scandir '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`scandir '${p}'`); | ||
const directoryListing = this.listings.get(resolvedP); | ||
if (!directoryListing) throw errors.ENOTDIR(`scandir '${p}'`); | ||
const entries = [...directoryListing]; | ||
if (!withFileTypes) return entries; | ||
return entries.map(name => { | ||
return Object.assign(this.statImpl(`lstat`, _path.ppath.join(p, name)), { | ||
name | ||
}); | ||
}); | ||
} | ||
async readlinkPromise(p) { | ||
return this.readlinkSync(p); | ||
} | ||
readlinkSync(p) { | ||
const resolvedP = this.resolveFilename(`readlink '${p}'`, p, false); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`readlink '${p}'`); // Ensure that the last component is a directory (if it is we'll throw right after with EISDIR anyway) | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) throw errors.ENOTDIR(`open '${p}'`); | ||
if (this.listings.has(resolvedP)) throw errors.EINVAL(`readlink '${p}'`); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) throw new Error(`Unreachable`); | ||
const rc = _libzip.default.file.getExternalAttributes(this.zip, entry, 0, 0, _libzip.default.uint08S, _libzip.default.uint32S); | ||
if (rc === -1) throw new Error(_libzip.default.error.strerror(_libzip.default.getError(this.zip))); | ||
const opsys = _libzip.default.getValue(_libzip.default.uint08S, `i8`) >>> 0; | ||
if (opsys !== _libzip.default.ZIP_OPSYS_UNIX) throw errors.EINVAL(`readlink '${p}'`); | ||
const attributes = _libzip.default.getValue(_libzip.default.uint32S, `i32`) >>> 16; | ||
if ((attributes & 0o170000) !== 0o120000) throw errors.EINVAL(`readlink '${p}'`); | ||
return this.getFileSource(entry).toString(); | ||
} | ||
watch(p, a, b) { | ||
let persistent; | ||
switch (typeof a) { | ||
case `function`: | ||
case `string`: | ||
case `undefined`: | ||
{ | ||
persistent = true; | ||
utimesImpl(resolvedP, mtime) { | ||
if (this.listings.has(resolvedP)) | ||
if (!this.entries.has(resolvedP)) | ||
this.hydrateDirectory(resolvedP); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) | ||
throw new Error(`Unreachable`); | ||
const rc = this.libzip.file.setMtime(this.zip, entry, 0, toUnixTimestamp(mtime), 0); | ||
if (rc === -1) { | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
} | ||
break; | ||
default: | ||
{ | ||
// @ts-ignore | ||
({ | ||
persistent = true | ||
} = a); | ||
} | ||
async mkdirPromise(p, opts) { | ||
return this.mkdirSync(p, opts); | ||
} | ||
mkdirSync(p, opts) { | ||
if (opts && opts.recursive) | ||
return this.mkdirpSync(p, { chmod: opts.mode }); | ||
if (this.readOnly) | ||
throw errors.EROFS(`mkdir '${p}'`); | ||
const resolvedP = this.resolveFilename(`mkdir '${p}'`, p); | ||
if (this.entries.has(resolvedP) || this.listings.has(resolvedP)) | ||
throw errors.EEXIST(`mkdir '${p}'`); | ||
this.hydrateDirectory(resolvedP); | ||
} | ||
async rmdirPromise(p) { | ||
return this.rmdirSync(p); | ||
} | ||
rmdirSync(p) { | ||
throw new Error(`Unimplemented`); | ||
} | ||
hydrateDirectory(resolvedP) { | ||
const index = this.libzip.dir.add(this.zip, path_1.ppath.relative(path_1.PortablePath.root, resolvedP)); | ||
if (index === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
this.registerListing(resolvedP); | ||
this.registerEntry(resolvedP, index); | ||
return index; | ||
} | ||
async symlinkPromise(target, p) { | ||
return this.symlinkSync(target, p); | ||
} | ||
symlinkSync(target, p) { | ||
if (this.readOnly) | ||
throw errors.EROFS(`symlink '${target}' -> '${p}'`); | ||
const resolvedP = this.resolveFilename(`symlink '${target}' -> '${p}'`, p); | ||
if (this.listings.has(resolvedP)) | ||
throw errors.EISDIR(`symlink '${target}' -> '${p}'`); | ||
if (this.entries.has(resolvedP)) | ||
throw errors.EEXIST(`symlink '${target}' -> '${p}'`); | ||
const index = this.setFileSource(resolvedP, target); | ||
this.registerEntry(resolvedP, index); | ||
const rc = this.libzip.file.setExternalAttributes(this.zip, index, 0, 0, this.libzip.ZIP_OPSYS_UNIX, (0o120000 | 0o777) << 16); | ||
if (rc === -1) { | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
} | ||
break; | ||
} | ||
if (!persistent) return { | ||
on: () => {}, | ||
close: () => {} | ||
}; | ||
const interval = setInterval(() => {}, 24 * 60 * 60 * 1000); | ||
return { | ||
on: () => {}, | ||
close: () => { | ||
clearInterval(interval); | ||
} | ||
}; | ||
} | ||
async readFilePromise(p, encoding) { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return this.readFileSync(p, encoding); | ||
default: | ||
return this.readFileSync(p, encoding); | ||
} | ||
} | ||
readFileSync(p, encoding) { | ||
if (typeof p !== `string`) | ||
throw errors.EBADF(`read`); | ||
// This is messed up regarding the TS signatures | ||
if (typeof encoding === `object`) | ||
// @ts-ignore | ||
encoding = encoding ? encoding.encoding : undefined; | ||
const resolvedP = this.resolveFilename(`open '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`open '${p}'`); | ||
// Ensures that the last component is a directory, if the user said so (even if it is we'll throw right after with EISDIR anyway) | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) | ||
throw errors.ENOTDIR(`open '${p}'`); | ||
if (this.listings.has(resolvedP)) | ||
throw errors.EISDIR(`read`); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) | ||
throw new Error(`Unreachable`); | ||
const data = this.getFileSource(entry); | ||
return encoding ? data.toString(encoding) : data; | ||
} | ||
async readdirPromise(p, { withFileTypes } = {}) { | ||
return this.readdirSync(p, { withFileTypes: withFileTypes }); | ||
} | ||
readdirSync(p, { withFileTypes } = {}) { | ||
const resolvedP = this.resolveFilename(`scandir '${p}'`, p); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`scandir '${p}'`); | ||
const directoryListing = this.listings.get(resolvedP); | ||
if (!directoryListing) | ||
throw errors.ENOTDIR(`scandir '${p}'`); | ||
const entries = [...directoryListing]; | ||
if (!withFileTypes) | ||
return entries; | ||
return entries.map(name => { | ||
return Object.assign(this.statImpl(`lstat`, path_1.ppath.join(p, name)), { | ||
name, | ||
}); | ||
}); | ||
} | ||
async readlinkPromise(p) { | ||
return this.readlinkSync(p); | ||
} | ||
readlinkSync(p) { | ||
const resolvedP = this.resolveFilename(`readlink '${p}'`, p, false); | ||
if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) | ||
throw errors.ENOENT(`readlink '${p}'`); | ||
// Ensure that the last component is a directory (if it is we'll throw right after with EISDIR anyway) | ||
if (p[p.length - 1] === `/` && !this.listings.has(resolvedP)) | ||
throw errors.ENOTDIR(`open '${p}'`); | ||
if (this.listings.has(resolvedP)) | ||
throw errors.EINVAL(`readlink '${p}'`); | ||
const entry = this.entries.get(resolvedP); | ||
if (entry === undefined) | ||
throw new Error(`Unreachable`); | ||
const rc = this.libzip.file.getExternalAttributes(this.zip, entry, 0, 0, this.libzip.uint08S, this.libzip.uint32S); | ||
if (rc === -1) | ||
throw new Error(this.libzip.error.strerror(this.libzip.getError(this.zip))); | ||
const opsys = this.libzip.getValue(this.libzip.uint08S, `i8`) >>> 0; | ||
if (opsys !== this.libzip.ZIP_OPSYS_UNIX) | ||
throw errors.EINVAL(`readlink '${p}'`); | ||
const attributes = this.libzip.getValue(this.libzip.uint32S, `i32`) >>> 16; | ||
if ((attributes & 0o170000) !== 0o120000) | ||
throw errors.EINVAL(`readlink '${p}'`); | ||
return this.getFileSource(entry).toString(); | ||
} | ||
watch(p, a, b) { | ||
let persistent; | ||
switch (typeof a) { | ||
case `function`: | ||
case `string`: | ||
case `undefined`: | ||
{ | ||
persistent = true; | ||
} | ||
break; | ||
default: | ||
{ | ||
// @ts-ignore | ||
({ persistent = true } = a); | ||
} | ||
break; | ||
} | ||
if (!persistent) | ||
return { on: () => { }, close: () => { } }; | ||
const interval = setInterval(() => { }, 24 * 60 * 60 * 1000); | ||
return { on: () => { }, close: () => { clearInterval(interval); } }; | ||
} | ||
} | ||
exports.ZipFS = ZipFS; | ||
; | ||
; |
1479
lib/ZipOpenFS.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.ZipOpenFS = void 0; | ||
var _fs = require("fs"); | ||
var _FakeFS = require("./FakeFS"); | ||
var _NodeFS = require("./NodeFS"); | ||
var _ZipFS = require("./ZipFS"); | ||
var _path = require("./path"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = require("fs"); | ||
const FakeFS_1 = require("./FakeFS"); | ||
const NodeFS_1 = require("./NodeFS"); | ||
const ZipFS_1 = require("./ZipFS"); | ||
const path_1 = require("./path"); | ||
const ZIP_FD = 0x80000000; | ||
class ZipOpenFS extends _FakeFS.BasePortableFakeFS { | ||
static open(fn) { | ||
const zipOpenFs = new ZipOpenFS(); | ||
try { | ||
return fn(zipOpenFs); | ||
} finally { | ||
zipOpenFs.saveAndClose(); | ||
class ZipOpenFS extends FakeFS_1.BasePortableFakeFS { | ||
constructor({ libzip, baseFs = new NodeFS_1.NodeFS(), filter = null, maxOpenFiles = Infinity, readOnlyArchives = false, useCache = true }) { | ||
super(); | ||
this.fdMap = new Map(); | ||
this.nextFd = 3; | ||
this.isZip = new Set(); | ||
this.notZip = new Set(); | ||
this.libzip = libzip; | ||
this.baseFs = baseFs; | ||
this.zipInstances = useCache ? new Map() : null; | ||
this.filter = filter; | ||
this.maxOpenFiles = maxOpenFiles; | ||
this.readOnlyArchives = readOnlyArchives; | ||
this.isZip = new Set(); | ||
this.notZip = new Set(); | ||
} | ||
} | ||
static async openPromise(fn) { | ||
const zipOpenFs = new ZipOpenFS(); | ||
try { | ||
return await fn(zipOpenFs); | ||
} finally { | ||
zipOpenFs.saveAndClose(); | ||
static async openPromise(fn, opts) { | ||
const zipOpenFs = new ZipOpenFS(opts); | ||
try { | ||
return await fn(zipOpenFs); | ||
} | ||
finally { | ||
zipOpenFs.saveAndClose(); | ||
} | ||
} | ||
} | ||
constructor({ | ||
baseFs = new _NodeFS.NodeFS(), | ||
filter = null, | ||
maxOpenFiles = Infinity, | ||
readOnlyArchives = false, | ||
useCache = true | ||
} = {}) { | ||
super(); | ||
this.baseFs = void 0; | ||
this.zipInstances = void 0; | ||
this.fdMap = new Map(); | ||
this.nextFd = 3; | ||
this.filter = void 0; | ||
this.maxOpenFiles = void 0; | ||
this.readOnlyArchives = void 0; | ||
this.isZip = new Set(); | ||
this.notZip = new Set(); | ||
this.baseFs = baseFs; | ||
this.zipInstances = useCache ? new Map() : null; | ||
this.filter = filter; | ||
this.maxOpenFiles = maxOpenFiles; | ||
this.readOnlyArchives = readOnlyArchives; | ||
this.isZip = new Set(); | ||
this.notZip = new Set(); | ||
} | ||
getRealPath() { | ||
return this.baseFs.getRealPath(); | ||
} | ||
saveAndClose() { | ||
if (this.zipInstances) { | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
zipFs.saveAndClose(); | ||
this.zipInstances.delete(path); | ||
} | ||
getRealPath() { | ||
return this.baseFs.getRealPath(); | ||
} | ||
} | ||
discardAndClose() { | ||
if (this.zipInstances) { | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
zipFs.discardAndClose(); | ||
this.zipInstances.delete(path); | ||
} | ||
saveAndClose() { | ||
if (this.zipInstances) { | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
zipFs.saveAndClose(); | ||
this.zipInstances.delete(path); | ||
} | ||
} | ||
} | ||
} | ||
remapFd(zipFs, fd) { | ||
const remappedFd = this.nextFd++ | ZIP_FD; | ||
this.fdMap.set(remappedFd, [zipFs, fd]); | ||
return remappedFd; | ||
} | ||
async openPromise(p, flags, mode) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.openPromise(p, flags, mode); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return this.remapFd(zipFs, (await zipFs.openPromise(subPath, flags, mode))); | ||
}); | ||
} | ||
openSync(p, flags, mode) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.openSync(p, flags, mode); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return this.remapFd(zipFs, zipFs.openSync(subPath, flags, mode)); | ||
}); | ||
} | ||
async readPromise(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) return await this.baseFs.readPromise(fd, buffer, offset, length, position); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, read`), { | ||
code: `EBADF` | ||
}); | ||
const [zipFs, realFd] = entry; | ||
return await zipFs.readPromise(realFd, buffer, offset, length, position); | ||
} | ||
readSync(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) return this.baseFs.readSync(fd, buffer, offset, length, position); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, read`), { | ||
code: `EBADF` | ||
}); | ||
const [zipFs, realFd] = entry; | ||
return zipFs.readSync(realFd, buffer, offset, length, position); | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) { | ||
if (typeof buffer === `string`) { | ||
return await this.baseFs.writePromise(fd, buffer, offset); | ||
} else { | ||
return await this.baseFs.writePromise(fd, buffer, offset, length, position); | ||
} | ||
discardAndClose() { | ||
if (this.zipInstances) { | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
zipFs.discardAndClose(); | ||
this.zipInstances.delete(path); | ||
} | ||
} | ||
} | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, write`), { | ||
code: `EBADF` | ||
}); | ||
const [zipFs, realFd] = entry; | ||
if (typeof buffer === `string`) { | ||
return await zipFs.writePromise(realFd, buffer, offset); | ||
} else { | ||
return await zipFs.writePromise(realFd, buffer, offset, length, position); | ||
remapFd(zipFs, fd) { | ||
const remappedFd = this.nextFd++ | ZIP_FD; | ||
this.fdMap.set(remappedFd, [zipFs, fd]); | ||
return remappedFd; | ||
} | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) { | ||
if (typeof buffer === `string`) { | ||
return this.baseFs.writeSync(fd, buffer, offset); | ||
} else { | ||
return this.baseFs.writeSync(fd, buffer, offset, length, position); | ||
} | ||
async openPromise(p, flags, mode) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.openPromise(p, flags, mode); | ||
}, async (zipFs, { subPath }) => { | ||
return this.remapFd(zipFs, await zipFs.openPromise(subPath, flags, mode)); | ||
}); | ||
} | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, write`), { | ||
code: `EBADF` | ||
}); | ||
const [zipFs, realFd] = entry; | ||
if (typeof buffer === `string`) { | ||
return zipFs.writeSync(realFd, buffer, offset); | ||
} else { | ||
return zipFs.writeSync(realFd, buffer, offset, length, position); | ||
openSync(p, flags, mode) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.openSync(p, flags, mode); | ||
}, (zipFs, { subPath }) => { | ||
return this.remapFd(zipFs, zipFs.openSync(subPath, flags, mode)); | ||
}); | ||
} | ||
} | ||
async closePromise(fd) { | ||
if ((fd & ZIP_FD) === 0) return await this.baseFs.closePromise(fd); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, close`), { | ||
code: `EBADF` | ||
}); | ||
this.fdMap.delete(fd); | ||
const [zipFs, realFd] = entry; | ||
return await zipFs.closePromise(realFd); | ||
} | ||
closeSync(fd) { | ||
if ((fd & ZIP_FD) === 0) return this.baseFs.closeSync(fd); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) throw Object.assign(new Error(`EBADF: bad file descriptor, close`), { | ||
code: `EBADF` | ||
}); | ||
this.fdMap.delete(fd); | ||
const [zipFs, realFd] = entry; | ||
return zipFs.closeSync(realFd); | ||
} | ||
createReadStream(p, opts) { | ||
if (p === null) return this.baseFs.createReadStream(p, opts); | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.createReadStream(p, opts); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.createReadStream(subPath, opts); | ||
}); | ||
} | ||
createWriteStream(p, opts) { | ||
if (p === null) return this.baseFs.createWriteStream(p, opts); | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.createWriteStream(p, opts); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.createWriteStream(subPath, opts); | ||
}); | ||
} | ||
async realpathPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.realpathPromise(p); | ||
}, async (zipFs, { | ||
archivePath, | ||
subPath | ||
}) => { | ||
return this.pathUtils.resolve((await this.baseFs.realpathPromise(archivePath)), this.pathUtils.relative(_path.PortablePath.root, (await zipFs.realpathPromise(subPath)))); | ||
}); | ||
} | ||
realpathSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.realpathSync(p); | ||
}, (zipFs, { | ||
archivePath, | ||
subPath | ||
}) => { | ||
return this.pathUtils.resolve(this.baseFs.realpathSync(archivePath), this.pathUtils.relative(_path.PortablePath.root, zipFs.realpathSync(subPath))); | ||
}); | ||
} | ||
async existsPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.existsPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.existsPromise(subPath); | ||
}); | ||
} | ||
existsSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.existsSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.existsSync(subPath); | ||
}); | ||
} | ||
async accessPromise(p, mode) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.accessPromise(p, mode); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.accessPromise(subPath, mode); | ||
}); | ||
} | ||
accessSync(p, mode) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.accessSync(p, mode); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.accessSync(subPath, mode); | ||
}); | ||
} | ||
async statPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.statPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.statPromise(subPath); | ||
}); | ||
} | ||
statSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.statSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.statSync(subPath); | ||
}); | ||
} | ||
async lstatPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.lstatPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.lstatPromise(subPath); | ||
}); | ||
} | ||
lstatSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.lstatSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.lstatSync(subPath); | ||
}); | ||
} | ||
async chmodPromise(p, mask) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.chmodPromise(p, mask); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.chmodPromise(subPath, mask); | ||
}); | ||
} | ||
chmodSync(p, mask) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.chmodSync(p, mask); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.chmodSync(subPath, mask); | ||
}); | ||
} | ||
async renamePromise(oldP, newP) { | ||
return await this.makeCallPromise(oldP, async () => { | ||
return await this.makeCallPromise(newP, async () => { | ||
return await this.baseFs.renamePromise(oldP, newP); | ||
}, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
async readPromise(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) | ||
return await this.baseFs.readPromise(fd, buffer, offset, length, position); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), { code: `EBADF` }); | ||
const [zipFs, realFd] = entry; | ||
return await zipFs.readPromise(realFd, buffer, offset, length, position); | ||
} | ||
readSync(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) | ||
return this.baseFs.readSync(fd, buffer, offset, length, position); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), { code: `EBADF` }); | ||
const [zipFs, realFd] = entry; | ||
return zipFs.readSync(realFd, buffer, offset, length, position); | ||
} | ||
async writePromise(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) { | ||
if (typeof buffer === `string`) { | ||
return await this.baseFs.writePromise(fd, buffer, offset); | ||
} | ||
else { | ||
return await this.baseFs.writePromise(fd, buffer, offset, length, position); | ||
} | ||
} | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, write`), { code: `EBADF` }); | ||
const [zipFs, realFd] = entry; | ||
if (typeof buffer === `string`) { | ||
return await zipFs.writePromise(realFd, buffer, offset); | ||
} | ||
else { | ||
return await zipFs.writePromise(realFd, buffer, offset, length, position); | ||
} | ||
} | ||
writeSync(fd, buffer, offset, length, position) { | ||
if ((fd & ZIP_FD) === 0) { | ||
if (typeof buffer === `string`) { | ||
return this.baseFs.writeSync(fd, buffer, offset); | ||
} | ||
else { | ||
return this.baseFs.writeSync(fd, buffer, offset, length, position); | ||
} | ||
} | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, write`), { code: `EBADF` }); | ||
const [zipFs, realFd] = entry; | ||
if (typeof buffer === `string`) { | ||
return zipFs.writeSync(realFd, buffer, offset); | ||
} | ||
else { | ||
return zipFs.writeSync(realFd, buffer, offset, length, position); | ||
} | ||
} | ||
async closePromise(fd) { | ||
if ((fd & ZIP_FD) === 0) | ||
return await this.baseFs.closePromise(fd); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, close`), { code: `EBADF` }); | ||
this.fdMap.delete(fd); | ||
const [zipFs, realFd] = entry; | ||
return await zipFs.closePromise(realFd); | ||
} | ||
closeSync(fd) { | ||
if ((fd & ZIP_FD) === 0) | ||
return this.baseFs.closeSync(fd); | ||
const entry = this.fdMap.get(fd); | ||
if (typeof entry === `undefined`) | ||
throw Object.assign(new Error(`EBADF: bad file descriptor, close`), { code: `EBADF` }); | ||
this.fdMap.delete(fd); | ||
const [zipFs, realFd] = entry; | ||
return zipFs.closeSync(realFd); | ||
} | ||
createReadStream(p, opts) { | ||
if (p === null) | ||
return this.baseFs.createReadStream(p, opts); | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.createReadStream(p, opts); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.createReadStream(subPath, opts); | ||
}); | ||
}); | ||
}, async (zipFsO, { | ||
subPath: subPathO | ||
}) => { | ||
return await this.makeCallPromise(newP, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
} | ||
createWriteStream(p, opts) { | ||
if (p === null) | ||
return this.baseFs.createWriteStream(p, opts); | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.createWriteStream(p, opts); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.createWriteStream(subPath, opts); | ||
}); | ||
}, async (zipFsN, { | ||
subPath: subPathN | ||
}) => { | ||
if (zipFsO !== zipFsN) { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
}); | ||
} else { | ||
return await zipFsO.renamePromise(subPathO, subPathN); | ||
} | ||
}); | ||
}); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.makeCallSync(oldP, () => { | ||
return this.makeCallSync(newP, () => { | ||
return this.baseFs.renameSync(oldP, newP); | ||
}, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
} | ||
async realpathPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.realpathPromise(p); | ||
}, async (zipFs, { archivePath, subPath }) => { | ||
return this.pathUtils.resolve(await this.baseFs.realpathPromise(archivePath), this.pathUtils.relative(path_1.PortablePath.root, await zipFs.realpathPromise(subPath))); | ||
}); | ||
}); | ||
}, (zipFsO, { | ||
subPath: subPathO | ||
}) => { | ||
return this.makeCallSync(newP, () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
} | ||
realpathSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.realpathSync(p); | ||
}, (zipFs, { archivePath, subPath }) => { | ||
return this.pathUtils.resolve(this.baseFs.realpathSync(archivePath), this.pathUtils.relative(path_1.PortablePath.root, zipFs.realpathSync(subPath))); | ||
}); | ||
}, (zipFsN, { | ||
subPath: subPathN | ||
}) => { | ||
if (zipFsO !== zipFsN) { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { | ||
code: `EEXDEV` | ||
}); | ||
} else { | ||
return zipFsO.renameSync(subPathO, subPathN); | ||
} | ||
}); | ||
}); | ||
} | ||
async copyFilePromise(sourceP, destP, flags = 0) { | ||
const fallback = async (sourceFs, sourceP, destFs, destP) => { | ||
if ((flags & _fs.constants.COPYFILE_FICLONE_FORCE) !== 0) throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP}' -> ${destP}'`), { | ||
code: `EXDEV` | ||
}); | ||
if (flags & _fs.constants.COPYFILE_EXCL && (await this.existsPromise(sourceP))) throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP}' -> '${destP}'`), { | ||
code: `EEXIST` | ||
}); | ||
let content; | ||
try { | ||
content = await sourceFs.readFilePromise(sourceP); | ||
} catch (error) { | ||
throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP}' -> '${destP}'`), { | ||
code: `EINVAL` | ||
} | ||
async existsPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.existsPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.existsPromise(subPath); | ||
}); | ||
} | ||
await destFs.writeFilePromise(destP, content); | ||
}; | ||
return await this.makeCallPromise(sourceP, async () => { | ||
return await this.makeCallPromise(destP, async () => { | ||
return await this.baseFs.copyFilePromise(sourceP, destP, flags); | ||
}, async (zipFsD, { | ||
subPath: subPathD | ||
}) => { | ||
return await fallback(this.baseFs, sourceP, zipFsD, subPathD); | ||
}); | ||
}, async (zipFsS, { | ||
subPath: subPathS | ||
}) => { | ||
return await this.makeCallPromise(destP, async () => { | ||
return await fallback(zipFsS, subPathS, this.baseFs, destP); | ||
}, async (zipFsD, { | ||
subPath: subPathD | ||
}) => { | ||
if (zipFsS !== zipFsD) { | ||
return await fallback(zipFsS, subPathS, zipFsD, subPathD); | ||
} else { | ||
return await zipFsS.copyFilePromise(subPathS, subPathD, flags); | ||
} | ||
existsSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.existsSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.existsSync(subPath); | ||
}); | ||
} | ||
async accessPromise(p, mode) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.accessPromise(p, mode); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.accessPromise(subPath, mode); | ||
}); | ||
} | ||
accessSync(p, mode) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.accessSync(p, mode); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.accessSync(subPath, mode); | ||
}); | ||
} | ||
async statPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.statPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.statPromise(subPath); | ||
}); | ||
} | ||
statSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.statSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.statSync(subPath); | ||
}); | ||
} | ||
async lstatPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.lstatPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.lstatPromise(subPath); | ||
}); | ||
} | ||
lstatSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.lstatSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.lstatSync(subPath); | ||
}); | ||
} | ||
async chmodPromise(p, mask) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.chmodPromise(p, mask); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.chmodPromise(subPath, mask); | ||
}); | ||
} | ||
chmodSync(p, mask) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.chmodSync(p, mask); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.chmodSync(subPath, mask); | ||
}); | ||
} | ||
async renamePromise(oldP, newP) { | ||
return await this.makeCallPromise(oldP, async () => { | ||
return await this.makeCallPromise(newP, async () => { | ||
return await this.baseFs.renamePromise(oldP, newP); | ||
}, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
}); | ||
}, async (zipFsO, { subPath: subPathO }) => { | ||
return await this.makeCallPromise(newP, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
}, async (zipFsN, { subPath: subPathN }) => { | ||
if (zipFsO !== zipFsN) { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
} | ||
else { | ||
return await zipFsO.renamePromise(subPathO, subPathN); | ||
} | ||
}); | ||
}); | ||
} | ||
renameSync(oldP, newP) { | ||
return this.makeCallSync(oldP, () => { | ||
return this.makeCallSync(newP, () => { | ||
return this.baseFs.renameSync(oldP, newP); | ||
}, async () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
}); | ||
}, (zipFsO, { subPath: subPathO }) => { | ||
return this.makeCallSync(newP, () => { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
}, (zipFsN, { subPath: subPathN }) => { | ||
if (zipFsO !== zipFsN) { | ||
throw Object.assign(new Error(`EEXDEV: cross-device link not permitted`), { code: `EEXDEV` }); | ||
} | ||
else { | ||
return zipFsO.renameSync(subPathO, subPathN); | ||
} | ||
}); | ||
}); | ||
} | ||
async copyFilePromise(sourceP, destP, flags = 0) { | ||
const fallback = async (sourceFs, sourceP, destFs, destP) => { | ||
if ((flags & fs_1.constants.COPYFILE_FICLONE_FORCE) !== 0) | ||
throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP}' -> ${destP}'`), { code: `EXDEV` }); | ||
if ((flags & fs_1.constants.COPYFILE_EXCL) && await this.existsPromise(sourceP)) | ||
throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP}' -> '${destP}'`), { code: `EEXIST` }); | ||
let content; | ||
try { | ||
content = await sourceFs.readFilePromise(sourceP); | ||
} | ||
catch (error) { | ||
throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP}' -> '${destP}'`), { code: `EINVAL` }); | ||
} | ||
await destFs.writeFilePromise(destP, content); | ||
}; | ||
return await this.makeCallPromise(sourceP, async () => { | ||
return await this.makeCallPromise(destP, async () => { | ||
return await this.baseFs.copyFilePromise(sourceP, destP, flags); | ||
}, async (zipFsD, { subPath: subPathD }) => { | ||
return await fallback(this.baseFs, sourceP, zipFsD, subPathD); | ||
}); | ||
}, async (zipFsS, { subPath: subPathS }) => { | ||
return await this.makeCallPromise(destP, async () => { | ||
return await fallback(zipFsS, subPathS, this.baseFs, destP); | ||
}, async (zipFsD, { subPath: subPathD }) => { | ||
if (zipFsS !== zipFsD) { | ||
return await fallback(zipFsS, subPathS, zipFsD, subPathD); | ||
} | ||
else { | ||
return await zipFsS.copyFilePromise(subPathS, subPathD, flags); | ||
} | ||
}); | ||
}); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
const fallback = (sourceFs, sourceP, destFs, destP) => { | ||
if ((flags & fs_1.constants.COPYFILE_FICLONE_FORCE) !== 0) | ||
throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP}' -> ${destP}'`), { code: `EXDEV` }); | ||
if ((flags & fs_1.constants.COPYFILE_EXCL) && this.existsSync(sourceP)) | ||
throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP}' -> '${destP}'`), { code: `EEXIST` }); | ||
let content; | ||
try { | ||
content = sourceFs.readFileSync(sourceP); | ||
} | ||
catch (error) { | ||
throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP}' -> '${destP}'`), { code: `EINVAL` }); | ||
} | ||
destFs.writeFileSync(destP, content); | ||
}; | ||
return this.makeCallSync(sourceP, () => { | ||
return this.makeCallSync(destP, () => { | ||
return this.baseFs.copyFileSync(sourceP, destP, flags); | ||
}, (zipFsD, { subPath: subPathD }) => { | ||
return fallback(this.baseFs, sourceP, zipFsD, subPathD); | ||
}); | ||
}, (zipFsS, { subPath: subPathS }) => { | ||
return this.makeCallSync(destP, () => { | ||
return fallback(zipFsS, subPathS, this.baseFs, destP); | ||
}, (zipFsD, { subPath: subPathD }) => { | ||
if (zipFsS !== zipFsD) { | ||
return fallback(zipFsS, subPathS, zipFsD, subPathD); | ||
} | ||
else { | ||
return zipFsS.copyFileSync(subPathS, subPathD, flags); | ||
} | ||
}); | ||
}); | ||
} | ||
async appendFilePromise(p, content, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.appendFilePromise(p, content, opts); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.appendFilePromise(subPath, content, opts); | ||
}); | ||
} | ||
appendFileSync(p, content, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.appendFileSync(p, content, opts); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.appendFileSync(subPath, content, opts); | ||
}); | ||
} | ||
async writeFilePromise(p, content, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.writeFilePromise(p, content, opts); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.writeFilePromise(subPath, content, opts); | ||
}); | ||
} | ||
writeFileSync(p, content, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.writeFileSync(p, content, opts); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.writeFileSync(subPath, content, opts); | ||
}); | ||
} | ||
async unlinkPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.unlinkPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.unlinkPromise(subPath); | ||
}); | ||
} | ||
unlinkSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.unlinkSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.unlinkSync(subPath); | ||
}); | ||
} | ||
async utimesPromise(p, atime, mtime) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.utimesPromise(p, atime, mtime); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.utimesPromise(subPath, atime, mtime); | ||
}); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.utimesSync(p, atime, mtime); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.utimesSync(subPath, atime, mtime); | ||
}); | ||
} | ||
async mkdirPromise(p, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.mkdirPromise(p, opts); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.mkdirPromise(subPath, opts); | ||
}); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.mkdirSync(p, opts); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.mkdirSync(subPath, opts); | ||
}); | ||
} | ||
async rmdirPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.rmdirPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.rmdirPromise(subPath); | ||
}); | ||
} | ||
rmdirSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.rmdirSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.rmdirSync(subPath); | ||
}); | ||
} | ||
async symlinkPromise(target, p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.symlinkPromise(target, p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.symlinkPromise(target, subPath); | ||
}); | ||
} | ||
symlinkSync(target, p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.symlinkSync(target, p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.symlinkSync(target, subPath); | ||
}); | ||
} | ||
async readFilePromise(p, encoding) { | ||
return this.makeCallPromise(p, async () => { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return await this.baseFs.readFilePromise(p, encoding); | ||
default: | ||
return await this.baseFs.readFilePromise(p, encoding); | ||
} | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.readFilePromise(subPath, encoding); | ||
}); | ||
} | ||
readFileSync(p, encoding) { | ||
return this.makeCallSync(p, () => { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return this.baseFs.readFileSync(p, encoding); | ||
default: | ||
return this.baseFs.readFileSync(p, encoding); | ||
} | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.readFileSync(subPath, encoding); | ||
}); | ||
} | ||
async readdirPromise(p, { withFileTypes } = {}) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.readdirPromise(p, { withFileTypes: withFileTypes }); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.readdirPromise(subPath, { withFileTypes: withFileTypes }); | ||
}, { | ||
requireSubpath: false, | ||
}); | ||
} | ||
readdirSync(p, { withFileTypes } = {}) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.readdirSync(p, { withFileTypes: withFileTypes }); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.readdirSync(subPath, { withFileTypes: withFileTypes }); | ||
}, { | ||
requireSubpath: false, | ||
}); | ||
} | ||
async readlinkPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.readlinkPromise(p); | ||
}, async (zipFs, { subPath }) => { | ||
return await zipFs.readlinkPromise(subPath); | ||
}); | ||
} | ||
readlinkSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.readlinkSync(p); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.readlinkSync(subPath); | ||
}); | ||
} | ||
watch(p, a, b) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.watch(p, | ||
// @ts-ignore | ||
a, b); | ||
}, (zipFs, { subPath }) => { | ||
return zipFs.watch(subPath, | ||
// @ts-ignore | ||
a, b); | ||
}); | ||
} | ||
async makeCallPromise(p, discard, accept, { requireSubpath = true } = {}) { | ||
if (typeof p !== `string`) | ||
return await discard(); | ||
const normalizedP = this.pathUtils.normalize(this.pathUtils.resolve(path_1.PortablePath.root, p)); | ||
const zipInfo = this.findZip(normalizedP); | ||
if (!zipInfo) | ||
return await discard(); | ||
if (requireSubpath && zipInfo.subPath === `/`) | ||
return await discard(); | ||
return await this.getZipPromise(zipInfo.archivePath, async (zipFs) => await accept(zipFs, zipInfo)); | ||
} | ||
makeCallSync(p, discard, accept, { requireSubpath = true } = {}) { | ||
if (typeof p !== `string`) | ||
return discard(); | ||
const normalizedP = this.pathUtils.normalize(this.pathUtils.resolve(path_1.PortablePath.root, p)); | ||
const zipInfo = this.findZip(normalizedP); | ||
if (!zipInfo) | ||
return discard(); | ||
if (requireSubpath && zipInfo.subPath === `/`) | ||
return discard(); | ||
return this.getZipSync(zipInfo.archivePath, zipFs => accept(zipFs, zipInfo)); | ||
} | ||
findZip(p) { | ||
if (this.filter && !this.filter.test(p)) | ||
return null; | ||
const parts = p.split(/\//g); | ||
for (let t = 2; t <= parts.length; ++t) { | ||
const archivePath = parts.slice(0, t).join(`/`); | ||
if (this.notZip.has(archivePath)) | ||
continue; | ||
if (this.isZip.has(archivePath)) | ||
return { archivePath, subPath: this.pathUtils.resolve(path_1.PortablePath.root, parts.slice(t).join(`/`)) }; | ||
let realArchivePath = archivePath; | ||
let stat; | ||
while (true) { | ||
try { | ||
stat = this.baseFs.lstatSync(realArchivePath); | ||
} | ||
catch (error) { | ||
return null; | ||
} | ||
if (stat.isSymbolicLink()) { | ||
realArchivePath = this.pathUtils.resolve(this.pathUtils.dirname(realArchivePath), this.baseFs.readlinkSync(realArchivePath)); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
const isZip = stat.isFile() && this.pathUtils.extname(realArchivePath) === `.zip`; | ||
if (isZip) { | ||
this.isZip.add(archivePath); | ||
return { archivePath, subPath: this.pathUtils.resolve(path_1.PortablePath.root, parts.slice(t).join(`/`)) }; | ||
} | ||
else { | ||
this.notZip.add(archivePath); | ||
if (stat.isFile()) { | ||
return null; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
copyFileSync(sourceP, destP, flags = 0) { | ||
const fallback = (sourceFs, sourceP, destFs, destP) => { | ||
if ((flags & _fs.constants.COPYFILE_FICLONE_FORCE) !== 0) throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${sourceP}' -> ${destP}'`), { | ||
code: `EXDEV` | ||
}); | ||
if (flags & _fs.constants.COPYFILE_EXCL && this.existsSync(sourceP)) throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${sourceP}' -> '${destP}'`), { | ||
code: `EEXIST` | ||
}); | ||
let content; | ||
try { | ||
content = sourceFs.readFileSync(sourceP); | ||
} catch (error) { | ||
throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${sourceP}' -> '${destP}'`), { | ||
code: `EINVAL` | ||
return null; | ||
} | ||
limitOpenFiles(max) { | ||
if (this.zipInstances === null) | ||
return; | ||
let closeCount = this.zipInstances.size - max; | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
if (closeCount <= 0) | ||
break; | ||
zipFs.saveAndClose(); | ||
this.zipInstances.delete(path); | ||
closeCount -= 1; | ||
} | ||
} | ||
async getZipPromise(p, accept) { | ||
const getZipOptions = async () => ({ | ||
baseFs: this.baseFs, | ||
libzip: this.libzip, | ||
readOnly: this.readOnlyArchives, | ||
stats: await this.baseFs.statPromise(p), | ||
}); | ||
} | ||
destFs.writeFileSync(destP, content); | ||
}; | ||
return this.makeCallSync(sourceP, () => { | ||
return this.makeCallSync(destP, () => { | ||
return this.baseFs.copyFileSync(sourceP, destP, flags); | ||
}, (zipFsD, { | ||
subPath: subPathD | ||
}) => { | ||
return fallback(this.baseFs, sourceP, zipFsD, subPathD); | ||
}); | ||
}, (zipFsS, { | ||
subPath: subPathS | ||
}) => { | ||
return this.makeCallSync(destP, () => { | ||
return fallback(zipFsS, subPathS, this.baseFs, destP); | ||
}, (zipFsD, { | ||
subPath: subPathD | ||
}) => { | ||
if (zipFsS !== zipFsD) { | ||
return fallback(zipFsS, subPathS, zipFsD, subPathD); | ||
} else { | ||
return zipFsS.copyFileSync(subPathS, subPathD, flags); | ||
if (this.zipInstances) { | ||
let zipFs = this.zipInstances.get(p); | ||
if (!zipFs) | ||
zipFs = new ZipFS_1.ZipFS(p, await getZipOptions()); | ||
// Removing then re-adding the field allows us to easily implement | ||
// a basic LRU garbage collection strategy | ||
this.zipInstances.delete(p); | ||
this.zipInstances.set(p, zipFs); | ||
this.limitOpenFiles(this.maxOpenFiles); | ||
return await accept(zipFs); | ||
} | ||
}); | ||
}); | ||
} | ||
async appendFilePromise(p, content, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.appendFilePromise(p, content, opts); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.appendFilePromise(subPath, content, opts); | ||
}); | ||
} | ||
appendFileSync(p, content, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.appendFileSync(p, content, opts); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.appendFileSync(subPath, content, opts); | ||
}); | ||
} | ||
async writeFilePromise(p, content, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.writeFilePromise(p, content, opts); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.writeFilePromise(subPath, content, opts); | ||
}); | ||
} | ||
writeFileSync(p, content, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.writeFileSync(p, content, opts); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.writeFileSync(subPath, content, opts); | ||
}); | ||
} | ||
async unlinkPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.unlinkPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.unlinkPromise(subPath); | ||
}); | ||
} | ||
unlinkSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.unlinkSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.unlinkSync(subPath); | ||
}); | ||
} | ||
async utimesPromise(p, atime, mtime) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.utimesPromise(p, atime, mtime); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.utimesPromise(subPath, atime, mtime); | ||
}); | ||
} | ||
utimesSync(p, atime, mtime) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.utimesSync(p, atime, mtime); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.utimesSync(subPath, atime, mtime); | ||
}); | ||
} | ||
async mkdirPromise(p, opts) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.mkdirPromise(p, opts); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.mkdirPromise(subPath, opts); | ||
}); | ||
} | ||
mkdirSync(p, opts) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.mkdirSync(p, opts); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.mkdirSync(subPath, opts); | ||
}); | ||
} | ||
async rmdirPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.rmdirPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.rmdirPromise(subPath); | ||
}); | ||
} | ||
rmdirSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.rmdirSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.rmdirSync(subPath); | ||
}); | ||
} | ||
async symlinkPromise(target, p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.symlinkPromise(target, p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.symlinkPromise(target, subPath); | ||
}); | ||
} | ||
symlinkSync(target, p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.symlinkSync(target, p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.symlinkSync(target, subPath); | ||
}); | ||
} | ||
async readFilePromise(p, encoding) { | ||
return this.makeCallPromise(p, async () => { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return await this.baseFs.readFilePromise(p, encoding); | ||
default: | ||
return await this.baseFs.readFilePromise(p, encoding); | ||
} | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.readFilePromise(subPath, encoding); | ||
}); | ||
} | ||
readFileSync(p, encoding) { | ||
return this.makeCallSync(p, () => { | ||
// This weird switch is required to tell TypeScript that the signatures are proper (otherwise it thinks that only the generic one is covered) | ||
switch (encoding) { | ||
case `utf8`: | ||
return this.baseFs.readFileSync(p, encoding); | ||
default: | ||
return this.baseFs.readFileSync(p, encoding); | ||
} | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.readFileSync(subPath, encoding); | ||
}); | ||
} | ||
async readdirPromise(p, { | ||
withFileTypes | ||
} = {}) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.readdirPromise(p, { | ||
withFileTypes: withFileTypes | ||
}); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.readdirPromise(subPath, { | ||
withFileTypes: withFileTypes | ||
}); | ||
}, { | ||
requireSubpath: false | ||
}); | ||
} | ||
readdirSync(p, { | ||
withFileTypes | ||
} = {}) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.readdirSync(p, { | ||
withFileTypes: withFileTypes | ||
}); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.readdirSync(subPath, { | ||
withFileTypes: withFileTypes | ||
}); | ||
}, { | ||
requireSubpath: false | ||
}); | ||
} | ||
async readlinkPromise(p) { | ||
return await this.makeCallPromise(p, async () => { | ||
return await this.baseFs.readlinkPromise(p); | ||
}, async (zipFs, { | ||
subPath | ||
}) => { | ||
return await zipFs.readlinkPromise(subPath); | ||
}); | ||
} | ||
readlinkSync(p) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.readlinkSync(p); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.readlinkSync(subPath); | ||
}); | ||
} | ||
watch(p, a, b) { | ||
return this.makeCallSync(p, () => { | ||
return this.baseFs.watch(p, // @ts-ignore | ||
a, b); | ||
}, (zipFs, { | ||
subPath | ||
}) => { | ||
return zipFs.watch(subPath, // @ts-ignore | ||
a, b); | ||
}); | ||
} | ||
async makeCallPromise(p, discard, accept, { | ||
requireSubpath = true | ||
} = {}) { | ||
if (typeof p !== `string`) return await discard(); | ||
const normalizedP = this.pathUtils.normalize(this.pathUtils.resolve(_path.PortablePath.root, p)); | ||
const zipInfo = this.findZip(normalizedP); | ||
if (!zipInfo) return await discard(); | ||
if (requireSubpath && zipInfo.subPath === `/`) return await discard(); | ||
return await this.getZipPromise(zipInfo.archivePath, async zipFs => await accept(zipFs, zipInfo)); | ||
} | ||
makeCallSync(p, discard, accept, { | ||
requireSubpath = true | ||
} = {}) { | ||
if (typeof p !== `string`) return discard(); | ||
const normalizedP = this.pathUtils.normalize(this.pathUtils.resolve(_path.PortablePath.root, p)); | ||
const zipInfo = this.findZip(normalizedP); | ||
if (!zipInfo) return discard(); | ||
if (requireSubpath && zipInfo.subPath === `/`) return discard(); | ||
return this.getZipSync(zipInfo.archivePath, zipFs => accept(zipFs, zipInfo)); | ||
} | ||
findZip(p) { | ||
if (this.filter && !this.filter.test(p)) return null; | ||
const parts = p.split(/\//g); | ||
for (let t = 2; t <= parts.length; ++t) { | ||
const archivePath = parts.slice(0, t).join(`/`); | ||
if (this.notZip.has(archivePath)) continue; | ||
if (this.isZip.has(archivePath)) return { | ||
archivePath, | ||
subPath: this.pathUtils.resolve(_path.PortablePath.root, parts.slice(t).join(`/`)) | ||
}; | ||
let realArchivePath = archivePath; | ||
let stat; | ||
while (true) { | ||
try { | ||
stat = this.baseFs.lstatSync(realArchivePath); | ||
} catch (error) { | ||
return null; | ||
else { | ||
const zipFs = new ZipFS_1.ZipFS(p, await getZipOptions()); | ||
try { | ||
return await accept(zipFs); | ||
} | ||
finally { | ||
zipFs.saveAndClose(); | ||
} | ||
} | ||
if (stat.isSymbolicLink()) { | ||
realArchivePath = this.pathUtils.resolve(this.pathUtils.dirname(realArchivePath), this.baseFs.readlinkSync(realArchivePath)); | ||
} else { | ||
break; | ||
} | ||
getZipSync(p, accept) { | ||
const getZipOptions = () => ({ | ||
baseFs: this.baseFs, | ||
libzip: this.libzip, | ||
readOnly: this.readOnlyArchives, | ||
stats: this.baseFs.statSync(p), | ||
}); | ||
if (this.zipInstances) { | ||
let zipFs = this.zipInstances.get(p); | ||
if (!zipFs) | ||
this.zipInstances.set(p, zipFs = new ZipFS_1.ZipFS(p, getZipOptions())); | ||
return accept(zipFs); | ||
} | ||
} | ||
const isZip = stat.isFile() && this.pathUtils.extname(realArchivePath) === `.zip`; | ||
if (isZip) { | ||
this.isZip.add(archivePath); | ||
return { | ||
archivePath, | ||
subPath: this.pathUtils.resolve(_path.PortablePath.root, parts.slice(t).join(`/`)) | ||
}; | ||
} else { | ||
this.notZip.add(archivePath); | ||
if (stat.isFile()) { | ||
return null; | ||
else { | ||
const zipFs = new ZipFS_1.ZipFS(p, getZipOptions()); | ||
try { | ||
return accept(zipFs); | ||
} | ||
finally { | ||
zipFs.saveAndClose(); | ||
} | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
limitOpenFiles(max) { | ||
if (this.zipInstances === null) return; | ||
let closeCount = this.zipInstances.size - max; | ||
for (const [path, zipFs] of this.zipInstances.entries()) { | ||
if (closeCount <= 0) break; | ||
zipFs.saveAndClose(); | ||
this.zipInstances.delete(path); | ||
closeCount -= 1; | ||
} | ||
} | ||
async getZipPromise(p, accept) { | ||
const getZipOptions = async () => ({ | ||
baseFs: this.baseFs, | ||
readOnly: this.readOnlyArchives, | ||
stats: await this.baseFs.statPromise(p) | ||
}); | ||
if (this.zipInstances) { | ||
let zipFs = this.zipInstances.get(p); | ||
if (!zipFs) zipFs = new _ZipFS.ZipFS(p, (await getZipOptions())); // Removing then re-adding the field allows us to easily implement | ||
// a basic LRU garbage collection strategy | ||
this.zipInstances.delete(p); | ||
this.zipInstances.set(p, zipFs); | ||
this.limitOpenFiles(this.maxOpenFiles); | ||
return await accept(zipFs); | ||
} else { | ||
const zipFs = new _ZipFS.ZipFS(p, (await getZipOptions())); | ||
try { | ||
return await accept(zipFs); | ||
} finally { | ||
zipFs.saveAndClose(); | ||
} | ||
} | ||
} | ||
getZipSync(p, accept) { | ||
const getZipOptions = () => ({ | ||
baseFs: this.baseFs, | ||
readOnly: this.readOnlyArchives, | ||
stats: this.baseFs.statSync(p) | ||
}); | ||
if (this.zipInstances) { | ||
let zipFs = this.zipInstances.get(p); | ||
if (!zipFs) this.zipInstances.set(p, zipFs = new _ZipFS.ZipFS(p, getZipOptions())); | ||
return accept(zipFs); | ||
} else { | ||
const zipFs = new _ZipFS.ZipFS(p, getZipOptions()); | ||
try { | ||
return accept(zipFs); | ||
} finally { | ||
zipFs.saveAndClose(); | ||
} | ||
} | ||
} | ||
} | ||
exports.ZipOpenFS = ZipOpenFS; | ||
exports.ZipOpenFS = ZipOpenFS; |
{ | ||
"name": "@yarnpkg/fslib", | ||
"version": "2.0.0-rc.14", | ||
"version": "2.0.0-rc.15", | ||
"main": "./lib/index.js", | ||
"sideEffects": false, | ||
"dependencies": { | ||
"@yarnpkg/libzip": "^2.0.0-rc.5", | ||
"@yarnpkg/libzip": "^2.0.0-rc.8", | ||
"tmp": "^0.1.0" | ||
@@ -9,0 +9,0 @@ }, |
153830
33
3924
Updated@yarnpkg/libzip@^2.0.0-rc.8