static-fs
Version:
A static filesystem to bundle files and read them using NodeJS
1,597 lines (1,272 loc) • 73.1 kB
JavaScript
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ({
/***/ "./node_modules/webpack/buildin/harmony-module.js":
/***/ (function(module, exports) {
module.exports = function(originalModule) {
if (!originalModule.webpackPolyfill) {
var module = Object.create(originalModule);
// module.parent = undefined by default
if (!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function() {
return module.i;
}
});
Object.defineProperty(module, "exports", {
enumerable: true
});
module.webpackPolyfill = 1;
}
return module;
};
/***/ }),
/***/ "./src/common/index.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// CONCATENATED MODULE: ./src/common/constants.js
// size of integers in file. (node uses 6-byte integers in buffer.)
const INT_SIZE = 6;
// holds if we are running under windows os
const isWindows = process.platform === 'win32';
// EXTERNAL MODULE: external "crypto"
var external_crypto_ = __webpack_require__("crypto");
// CONCATENATED MODULE: ./src/common/crypto.js
function calculateHash(content) {
return Object(external_crypto_["createHash"])('sha256')
.update(JSON.stringify(content))
.digest('base64');
}
// EXTERNAL MODULE: external "fs"
var external_fs_ = __webpack_require__("fs");
// EXTERNAL MODULE: external "path"
var external_path_ = __webpack_require__("path");
// CONCATENATED MODULE: ./src/common/fs.js
// shallow copy original function implementations before we start tweaking.
const fs = { ...external_fs_ };
// promisify async functions.
function readdir(path) {
return new Promise((r, j) => fs.readdir(path, (err, files) => (err ? j(err) : r(files))));
}
function stat(path) {
return new Promise((r, j) => fs.stat(path, (err, files) => (err ? j(err) : r(files))));
}
function lstat(path) {
return new Promise((r, j) => fs.lstat(path, (err, files) => (err ? j(err) : r(files))));
}
function fs_open(path, flags, mode) {
return new Promise((r, j) => fs.open(path, flags, mode, (err, descriptor) => (err ? j(err) : r(descriptor))));
}
function fs_close(fd) {
return new Promise((r, j) => fs.close(fd, (err) => (err ? j(err) : r())));
}
function write(fd, buffer, offset, length, position) {
return new Promise((r, j) =>
fs.write(fd, buffer, offset || 0, length || buffer.length, position || undefined, (err, written) =>
err ? j(err) : r(written),
),
);
}
function read(fd, buffer, offset, length, position) {
return new Promise((r, j) =>
fs.read(fd, buffer, offset, length, position || null, (err, bytes) => (err ? j(err) : r(bytes))),
);
}
function readFile(path, options) {
return new Promise((r, j) => fs.readFile(path, options, (err, data) => (err ? j(err) : r(data))));
}
function fs_mkdir(path) {
return new Promise((r, j) => fs.mkdir(path, (err) => (err ? j(err) : r())));
}
function writeFile(filename, content) {
return new Promise((r, j) => fs.writeFile(filename, content, (err) => (err ? j(err) : r())));
}
async function copyFile(source, target) {
await mkdir(Object(external_path_["dirname"])(target));
return await new Promise((resolve, reject) => {
const rd = fs.createReadStream(source);
rd.on('error', rejectCleanup);
const wr = fs.createWriteStream(target);
wr.on('error', rejectCleanup);
function rejectCleanup(err) {
rd.destroy();
wr.end();
reject(err);
}
wr.on('finish', () => {
rd.close();
wr.close();
resolve();
});
rd.pipe(wr);
});
}
const exists = (path) => new Promise((r) => fs.stat(path, (err) => (err ? r(false) : r(true))));
async function isDirectory(dirPath) {
try {
if (await exists(dirPath)) {
return (await lstat(dirPath)).isDirectory();
}
} catch (e) {
// don't throw!
}
return false;
}
async function isFile(filePath) {
try {
if (await exists(filePath)) {
return !(await lstat(filePath)).isDirectory();
}
} catch (e) {
// don't throw!
}
return false;
}
async function mkdir(dirPath) {
if (!(await isDirectory(dirPath))) {
const p = Object(external_path_["normalize"])(dirPath + '/');
const parent = Object(external_path_["dirname"])(dirPath);
if (!(await isDirectory(parent))) {
if (p !== parent) {
await mkdir(parent);
}
}
try {
await fs_mkdir(p);
} catch (e) {
if (!(await isDirectory(p))) {
throw new Error(e);
}
}
}
}
// CONCATENATED MODULE: ./src/common/path.js
// Strips down a path into an absolute-style unix path
function unixifyPath(filePath) {
if (!isWindows) return filePath;
if (filePath && typeof filePath === 'string') {
return (
filePath
// change \\?\<letter>:\ to <letter>:\
.replace(/^\\\\\?\\(.):\\/, '$1:\\')
// change backslashes to forward slashes. (and remove duplicates)
// eslint-disable-next-line no-useless-escape
.replace(/[\\\/]+/g, '/')
// remove drive letter from front
.replace(/^([a-zA-Z]+:|\.\/)/, '')
// drop any trailing slash
.replace(/(.+?)\/$/, '$1')
);
}
return filePath;
}
function isWindowsPath(filePath) {
if (!isWindows) return filePath;
if (filePath && filePath.length >= 3) {
if (filePath.charCodeAt(0) === 92 && filePath.charCodeAt(1) === 92) {
return true;
}
if (filePath.charCodeAt(1) === 58 && filePath.charCodeAt(2) === 92) {
const code = filePath.charCodeAt(0);
return (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
}
}
return false;
}
function sanitizePath(...args) {
const resolvedPath = Object(external_path_["resolve"])(...args);
return unixifyPath(resolvedPath);
}
// CONCATENATED MODULE: ./src/common/string.js
function stripBOM(content) {
return content && content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
}
// CONCATENATED MODULE: ./src/common/index.js
/* concated harmony reexport INT_SIZE */__webpack_require__.d(__webpack_exports__, "a", function() { return INT_SIZE; });
/* concated harmony reexport isWindows */__webpack_require__.d(__webpack_exports__, "d", function() { return isWindows; });
/* concated harmony reexport calculateHash */__webpack_require__.d(__webpack_exports__, "b", function() { return calculateHash; });
/* concated harmony reexport readdir */__webpack_require__.d(__webpack_exports__, "i", function() { return readdir; });
/* concated harmony reexport stat */__webpack_require__.d(__webpack_exports__, "k", function() { return stat; });
/* unused concated harmony import lstat */
/* concated harmony reexport open */__webpack_require__.d(__webpack_exports__, "g", function() { return fs_open; });
/* concated harmony reexport close */__webpack_require__.d(__webpack_exports__, "c", function() { return fs_close; });
/* concated harmony reexport write */__webpack_require__.d(__webpack_exports__, "n", function() { return write; });
/* unused concated harmony import read */
/* concated harmony reexport readFile */__webpack_require__.d(__webpack_exports__, "h", function() { return readFile; });
/* unused concated harmony import writeFile */
/* unused concated harmony import copyFile */
/* unused concated harmony import exists */
/* unused concated harmony import isDirectory */
/* unused concated harmony import isFile */
/* concated harmony reexport mkdir */__webpack_require__.d(__webpack_exports__, "f", function() { return mkdir; });
/* concated harmony reexport unixifyPath */__webpack_require__.d(__webpack_exports__, "m", function() { return unixifyPath; });
/* concated harmony reexport isWindowsPath */__webpack_require__.d(__webpack_exports__, "e", function() { return isWindowsPath; });
/* concated harmony reexport sanitizePath */__webpack_require__.d(__webpack_exports__, "j", function() { return sanitizePath; });
/* concated harmony reexport stripBOM */__webpack_require__.d(__webpack_exports__, "l", function() { return stripBOM; });
/***/ }),
/***/ "./src/filesystem/index.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// EXTERNAL MODULE: external "path"
var external_path_ = __webpack_require__("path");
// EXTERNAL MODULE: external "os"
var external_os_ = __webpack_require__("os");
// EXTERNAL MODULE: ./src/common/index.js + 5 modules
var common = __webpack_require__("./src/common/index.js");
// EXTERNAL MODULE: external "stream"
var external_stream_ = __webpack_require__("stream");
// EXTERNAL MODULE: external "util"
var external_util_ = __webpack_require__("util");
var external_util_default = /*#__PURE__*/__webpack_require__.n(external_util_);
// CONCATENATED MODULE: ./src/filesystem/streams/read.js
// NOTE: this is a raw re-implementation of https://github.com/nodejs/node/blob/v10.x/lib/internal/fs/streams.js#L45
// that is setup to follow our needs for the static filesystem
const ERR_STR_OPTS = (typeOfOptions) =>
`Expected options to be either an object or a string, but got ${typeOfOptions} instead`;
function assertEncoding(encoding) {
if (encoding && !Buffer.isEncoding(encoding)) throw new Error(`ERR_INVALID_OPT_VALUE_ENCODING ${encoding}`);
}
function getOptions(options, defaultOptions) {
if (options === null || options === undefined || typeof options === 'function') {
return defaultOptions;
}
if (typeof options === 'string') {
defaultOptions = external_util_default.a._extend({}, defaultOptions);
defaultOptions.encoding = options;
options = defaultOptions;
} else if (typeof options !== 'object') {
throw new ERR_STR_OPTS(typeof options);
}
if (options.encoding !== 'buffer') assertEncoding(options.encoding);
return options;
}
function copyObject(source) {
const target = {};
for (const key in source) target[key] = source[key];
return target;
}
const kMinPoolSpace = 128;
let pool;
// It can happen that we expect to read a large chunk of data, and reserve
// a large chunk of the pool accordingly, but the read() call only filled
// a portion of it. If a concurrently executing read() then uses the same pool,
// the "reserved" portion cannot be used, so we allow it to be re-used as a
// new pool later.
const poolFragments = [];
function allocNewPool(poolSize) {
if (poolFragments.length > 0) pool = poolFragments.pop();
else pool = Buffer.allocUnsafe(poolSize);
pool.used = 0;
}
function ReadStream(sfs, path, options) {
if (!(this instanceof ReadStream)) return new ReadStream(sfs, path, options);
this._sfs = sfs;
// a little bit bigger buffer and water marks by default
options = copyObject(getOptions(options, {}));
if (options.highWaterMark === undefined) options.highWaterMark = 64 * 1024;
// for backwards compat do not emit close on destroy.
options.emitClose = false;
external_stream_["Readable"].call(this, options);
this.path = path;
this.fd = options.fd === undefined ? null : options.fd;
this.flags = options.flags === undefined ? 'r' : options.flags;
this.mode = options.mode === undefined ? 0o666 : options.mode;
this.start = options.start;
this.end = options.end;
this.autoClose = options.autoClose === undefined ? true : options.autoClose;
this.pos = undefined;
this.bytesRead = 0;
this.closed = false;
if (this.start !== undefined) {
if (typeof this.start !== 'number' || Number.isNaN(this.start)) {
throw new TypeError('"start" option must be a Number');
}
if (this.end === undefined) {
this.end = Infinity;
} else if (typeof this.end !== 'number' || Number.isNaN(this.end)) {
throw new TypeError('"end" option must be a Number');
}
if (this.start > this.end) {
throw new Error('"start" option must be <= "end" option');
}
this.pos = this.start;
}
if (typeof this.end !== 'number') this.end = Infinity;
else if (Number.isNaN(this.end)) throw new TypeError('"end" option must be a Number');
if (!this.fd || !this.fd.type || this.fd.type !== 'static_fs_file_descriptor') this.open();
this.on('end', function() {
if (this.autoClose) {
this.destroy();
}
});
}
external_util_default.a.inherits(ReadStream, external_stream_["Readable"]);
ReadStream.prototype.open = function() {
this._sfs.open(this.path, (er, fd) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
return;
}
this.fd = fd;
this.emit('open', fd);
this.emit('ready');
// start the flow of data.
this.read();
});
};
ReadStream.prototype._read = function(n) {
if (!this.fd || !this.fd.type || this.fd.type !== 'static_fs_file_descriptor') {
return this.once('open', function() {
this._read(n);
});
}
if (this.destroyed) return;
if (!pool || pool.length - pool.used < kMinPoolSpace) {
// discard the old pool.
allocNewPool(this.readableHighWaterMark);
}
// Grab another reference to the pool in the case that while we're
// in the thread pool another read() finishes up the pool, and
// allocates a new one.
const thisPool = pool;
let toRead = Math.min(pool.length - pool.used, n);
const start = pool.used;
if (this.pos !== undefined) toRead = Math.min(this.end - this.pos + 1, toRead);
else toRead = Math.min(this.end - this.bytesRead + 1, toRead);
// already read everything we were supposed to read!
// treat as EOF.
if (toRead <= 0) return this.push(null);
// the actual read.
this._sfs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
} else {
let b = null;
// Now that we know how much data we have actually read, re-wind the
// 'used' field if we can, and otherwise allow the remainder of our
// reservation to be used as a new pool later.
if (start + toRead === thisPool.used && thisPool === pool) thisPool.used += bytesRead - toRead;
else if (toRead - bytesRead > kMinPoolSpace)
poolFragments.push(thisPool.slice(start + bytesRead, start + toRead));
if (bytesRead > 0) {
this.bytesRead += bytesRead;
b = thisPool.slice(start, start + bytesRead);
}
this.push(b);
}
});
// move the pool positions, and internal position for reading.
if (this.pos !== undefined) this.pos += toRead;
pool.used += toRead;
};
ReadStream.prototype._destroy = function(err, cb) {
if (!this.fd || !this.fd.type || this.fd.type !== 'static_fs_file_descriptor') {
this.once('open', closeFsStream.bind(null, this, cb, err));
return;
}
closeFsStream(this, cb, err);
this.fd = null;
};
function closeFsStream(stream, cb, err) {
stream._sfs.close(stream.fd, (er) => {
er = er || err;
cb(er);
stream.closed = true;
if (!er) stream.emit('close');
});
}
ReadStream.prototype.close = function(cb) {
this.destroy(null, cb);
};
Object.defineProperty(ReadStream.prototype, 'pending', {
get() {
return this.fd === null;
},
configurable: true,
});
// CONCATENATED MODULE: ./src/filesystem/streams/index.js
// EXTERNAL MODULE: external "fs"
var external_fs_ = __webpack_require__("fs");
// CONCATENATED MODULE: ./src/filesystem/volume/readable.js
const fs = { ...external_fs_ };
class readable_ReadableStaticVolume {
constructor(sourcePath) {
this.sourcePath = sourcePath;
this.moutingRoot = Object(external_path_["resolve"])(Object(external_path_["dirname"])(this.sourcePath), '../');
this.runtimePath = Object(external_path_["resolve"])(Object(external_path_["dirname"])(this.sourcePath), 'static_fs_runtime.js');
this.reset();
}
reset() {
this.buf = Buffer.alloc(1024 * 16);
this.directoriesIndex = {};
this.fd = -1;
this.hash = '';
this.intBuffer = Buffer.alloc(common["a" /* INT_SIZE */]);
this.index = {};
this.statData = {};
this.filesBeingRead = {};
this.pathVolumeIndex = {};
}
load() {
if (this.fd >= 0) {
return;
}
// clone the original static fs values and set some defaults
this.statData = {
isDirectory: () => false,
isSymbolicLink: () => false,
isBlockDevice: () => false,
isCharacterDevice: () => false,
isFile: () => false,
isFIFO: () => false,
isSocket: () => false,
size: 0,
...fs.statSync(this.sourcePath),
};
// read the index
this.fd = fs.openSync(this.sourcePath, 'r');
// close on process exit.
let dataOffset = this.readInt();
// read hash
let hashSize = this.readInt();
if (hashSize > this.buf.length) {
this.buf = Buffer.alloc(hashSize);
}
this.readBuffer(this.buf, hashSize);
this.hash = this.buf.toString('utf8', 0, hashSize);
const hashCheckIndex = {};
do {
const nameSz = this.readInt();
if (nameSz === 0) {
break;
}
const dataSz = this.readInt();
if (nameSz > this.buf.length) {
this.buf = Buffer.alloc(nameSz);
}
this.readBuffer(this.buf, nameSz);
const name = this.buf.toString('utf8', 0, nameSz);
const mountedName = this._resolveMountedPath(name);
hashCheckIndex[name] = true;
// add entry for file into index
this.index[mountedName] = Object.assign({}, this.statData, {
ino: dataOffset, // the location in the static fs
size: dataSz, // the size of the file
blocks: 1, // one block
blksize: dataSz, // of file size size.
isFile: () => true, // it's a file!
});
// this creates an index (every_path) -> (sourcePath)
// it also needs to assign inside addParentFolders
this.pathVolumeIndex[mountedName] = this.sourcePath;
// ensure parent path has a directory entry
this.addParentFolders(mountedName);
// build our directories index
this.updateDirectoriesIndex(mountedName);
dataOffset += dataSz;
} while (true);
const hashCheck = Object(common["b" /* calculateHash */])(Object.keys(hashCheckIndex).sort());
if (hashCheck !== this.hash) {
throw new Error(
`Something went wrong loading the volume ${this.sourcePath}. Check hash after loading is different from the one stored in the volume.`,
);
}
return this.pathVolumeIndex;
}
readBuffer(buffer, length) {
return fs.readSync(this.fd, buffer, 0, length || buffer.length, null);
}
readInt() {
fs.readSync(this.fd, this.intBuffer, 0, common["a" /* INT_SIZE */], null);
return this.intBuffer.readIntBE(0, 6);
}
shutdown() {
fs.closeSync(this.fd);
this.reset();
}
getFromDirectoriesIndex(filePath) {
return this.directoriesIndex[Object(common["j" /* sanitizePath */])(filePath)];
}
getFromIndex(filePath) {
return this.index[Object(common["j" /* sanitizePath */])(filePath)];
}
addParentFolders(name) {
const parent = Object(external_path_["dirname"])(name);
if (parent && !this.index[parent] && parent.includes(Object(common["m" /* unixifyPath */])(this.moutingRoot))) {
this.index[parent] = Object.assign({}, this.statData, { isDirectory: () => true });
this.pathVolumeIndex[parent] = this.sourcePath;
return this.addParentFolders(parent);
}
}
updateDirectoriesIndex(name) {
if (!this.index[name] || Object(common["m" /* unixifyPath */])(this.moutingRoot) === name) {
return;
}
const directoryAlreadyExists = this.directoriesIndex[name];
if (!directoryAlreadyExists) {
this.directoriesIndex[name] = {};
}
const isFile = this.index[name].isFile();
const isDirectory = this.index[name].isDirectory();
const parent = Object(external_path_["dirname"])(name);
if (isFile || isDirectory) {
const fileName = Object(external_path_["basename"])(name);
if (!this.directoriesIndex[parent]) {
this.directoriesIndex[parent] = {};
}
this.directoriesIndex[parent][fileName] = true;
}
this.updateDirectoriesIndex(parent);
}
_resolveMountedPath(unmountedPath) {
if (unmountedPath.includes(this.moutingRoot)) {
return unmountedPath;
}
return Object(common["j" /* sanitizePath */])(this.moutingRoot, unmountedPath);
}
readFileSync(filePath, options) {
const sanitizedFilePath = Object(common["j" /* sanitizePath */])(filePath);
const item = this.index[sanitizedFilePath];
if (!item || !item.isFile()) {
return undefined;
}
const encoding = options
? typeof options === 'string'
? options
: typeof options === 'object'
? options.encoding
: null
: null;
// re-alloc if necessary
if (this.buf.length < item.size) {
this.buf = Buffer.alloc(item.size);
}
// read the content and return a string
fs.readSync(this.fd, this.buf, 0, item.size, item.ino);
if (!encoding) {
const buf = Buffer.alloc(item.size);
this.buf.copy(buf);
return buf;
}
return this.buf.toString(encoding, 0, item.size);
}
_deleteReadFileFromCache(filePath, length, position) {
const cachedBuffer = this.filesBeingRead[filePath].buffer;
if (position >= cachedBuffer.length || position + length >= cachedBuffer.length) {
this.filesBeingRead[filePath].consumers -= 1;
}
if (this.filesBeingRead[filePath].consumers <= 0) {
delete this.filesBeingRead[filePath];
}
}
_readFromCache(filePath, buffer, offset, length, position, callback) {
const cachedBuffer = this.filesBeingRead[filePath].buffer;
if (position >= cachedBuffer.length) {
this._deleteReadFileFromCache(filePath, length, position);
callback(null, 0, buffer);
return;
}
const copiedBytes = cachedBuffer.copy(buffer, offset, position, Math.min(position + length, cachedBuffer.length));
this._deleteReadFileFromCache(filePath, length, position);
callback(null, copiedBytes, buffer);
}
read(filePath, buffer, offset, length, position, callback) {
const sanitizedFilePath = Object(common["j" /* sanitizePath */])(filePath);
const item = this.index[sanitizedFilePath];
if (item && item.isFile()) {
// read the content and return a string
if (this.filesBeingRead[filePath]) {
this.filesBeingRead[filePath].consumers += 1;
this._readFromCache(filePath, buffer, offset, length, position, callback);
} else {
const cachedFile = (this.filesBeingRead[filePath] = {
buffer: Buffer.alloc(item.size),
consumers: 1,
});
fs.read(this.fd, cachedFile.buffer, 0, item.size, item.ino, (err) => {
if (err) {
callback(err);
}
this._readFromCache(filePath, buffer, offset, length, position, callback);
});
}
} else {
callback(new Error());
}
}
}
// CONCATENATED MODULE: ./src/filesystem/volume/writable.js
class writable_WritableStaticVolume {
constructor(mountingRoot) {
this.mountingRoot = mountingRoot;
this.outputFile = Object(external_path_["resolve"])(this.mountingRoot, 'static_fs/static_fs_volume.sfsv');
this.reset();
}
reset() {
this.hash = '';
this.hashBuffer = Buffer.allocUnsafe(0);
this.index = [];
this.directoriesIndex = {};
this.intBuffer = Buffer.alloc(common["a" /* INT_SIZE */]);
}
async addFolder(sourceFolder, exclusions) {
if (this.mountingRoot === sourceFolder) {
throw new Error('You cannot add the mounting root of the project to the static filesystem');
}
if (!sourceFolder.includes(this.mountingRoot)) {
throw new Error(
`All the files to include into the static filesystem should has mountingRoot has parent: ${this.mountingRoot}`,
);
}
const calculatedTargetFolder = Object(external_path_["relative"])(this.mountingRoot, sourceFolder);
await this.getFileNames(sourceFolder, calculatedTargetFolder, exclusions);
}
get headerLength() {
let size = common["a" /* INT_SIZE */]; // start of data
// put hash size in header
this.hashBuffer = Buffer.from(this.hash, 'utf-8');
size += common["a" /* INT_SIZE */];
size += this.hashBuffer.byteLength;
const filePaths = Object.keys(this.index);
for (const each of filePaths) {
size += common["a" /* INT_SIZE */]; // name size
size += common["a" /* INT_SIZE */]; // data size
const filenameBuffer = Buffer.from(each, 'utf-8');
this.index[each].filename = filenameBuffer;
size += filenameBuffer.byteLength; // name itself.
}
size += common["a" /* INT_SIZE */]; // trailing zero.
return size;
}
writeInt(fd, value, position) {
this.intBuffer.writeIntBE(value, 0, 6);
return Object(common["n" /* write */])(fd, this.intBuffer, 0, common["a" /* INT_SIZE */], position);
}
async write() {
await Object(common["f" /* mkdir */])(Object(external_path_["dirname"])(this.outputFile));
this.hash = Object(common["b" /* calculateHash */])(Object.keys(this.index).sort());
let dataOffset = this.headerLength;
const fd = await Object(common["g" /* open */])(this.outputFile, 'w');
let headerPosition = await this.writeInt(fd, dataOffset);
headerPosition += await this.writeInt(fd, this.hashBuffer.byteLength);
headerPosition += await Object(common["n" /* write */])(fd, this.hashBuffer, 0, this.hashBuffer.byteLength, headerPosition);
const all = [];
const filePaths = Object.keys(this.index);
// start writing out the data
for (const each of filePaths) {
const entry = this.index[each];
const position = dataOffset;
dataOffset += entry.size;
const buf = await this.index[each].getBuffer();
await Object(common["n" /* write */])(fd, buf, 0, buf.length, position);
}
// finish writing all the buffers.
await Promise.all(all);
// write the header
for (const each of filePaths) {
const entry = this.index[each];
headerPosition += await this.writeInt(fd, entry.filename.length, headerPosition);
headerPosition += await this.writeInt(fd, entry.size, headerPosition);
headerPosition += await Object(common["n" /* write */])(fd, entry.filename, 0, entry.filename.length, headerPosition);
}
await Object(common["c" /* close */])(fd);
return this.hash;
}
async getFileNames(sourceFolder, targetFolder, exclusions) {
const files = await Object(common["i" /* readdir */])(sourceFolder);
const all = [];
for (const file of files) {
// compute the path names
const sourcePath = `${sourceFolder}${external_path_["sep"]}${file}`;
const targetPath = `${targetFolder}${external_path_["sep"]}${file}`;
// is declared exclusion?
const foundExclusion = exclusions[sourceFolder] || exclusions[sourcePath];
if (foundExclusion) {
continue;
}
// is this a directory
const ss = await Object(common["k" /* stat */])(sourcePath);
if (ss.isDirectory()) {
this.directoriesIndex[sourcePath] = {
hasNativeModules: false,
};
all.push(this.getFileNames(sourcePath, targetPath, exclusions));
continue;
}
const isNativeModuleFile = file.endsWith('.node');
if (isNativeModuleFile) {
this.directoriesIndex[sourcePath] = {
hasNativeModules: true,
};
continue;
}
// it's a file. capture the details.
this.index[targetPath] = {
size: ss.size,
getBuffer: () => Object(common["h" /* readFile */])(sourcePath),
};
}
// wait for children to finish
await Promise.all(all);
}
getAddedFilesAndFolders() {
const addParentsForFolder = (folderPath, accum) => {
const parent = Object(external_path_["dirname"])(folderPath);
if (parent && parent !== this.mountingRoot && parent.includes(this.mountingRoot)) {
accum[parent] = true;
return addParentsForFolder(parent, accum);
}
};
const foldersWithNativeModulesIndex = Object.keys(this.directoriesIndex).reduce((accum, folderPath) => {
if (this.directoriesIndex[folderPath].hasNativeModules && !accum[folderPath]) {
accum[folderPath] = true;
addParentsForFolder(folderPath, accum);
}
return accum;
}, {});
const addedFolders = Object.keys(this.directoriesIndex)
.filter((folderPath) => !foldersWithNativeModulesIndex[folderPath])
.map((folderPath) => Object(external_path_["resolve"])(this.mountingRoot, folderPath));
const addedFiles = Object.keys(this.index).map((filePath) => Object(external_path_["resolve"])(this.mountingRoot, filePath));
return addedFiles.concat(addedFolders).sort((a, b) => b.localeCompare(a));
}
}
// CONCATENATED MODULE: ./src/filesystem/volume/index.js
// CONCATENATED MODULE: ./src/filesystem/filesystem.js
class filesystem_StaticFilesystem {
static NewError(code, method, filepath) {
switch (code) {
case external_os_["constants"].errno.ENOENT:
return {
...new Error(`ENOENT: no such file or directory, ${method} '${filepath}'`),
code: 'ENOENT',
path: filepath,
errno: external_os_["constants"].errno.ENOENT,
};
case external_os_["constants"].errno.EISDIR:
return {
...new Error(`EISDIR: illegal operation on a directory, ${method} '${filepath}'`),
code: 'EISDIR',
path: filepath,
errno: external_os_["constants"].errno.EISDIR,
};
}
return {
...new Error(`UNKNOWN: Error, ${method} '${filepath}'`),
code: 'UNKNOWN',
path: filepath,
errno: -10000,
};
}
constructor() {
this.volumes = {};
this.fds = {};
this.pathVolumeMap = {};
}
shutdown() {
for (const volume of Object.values(this.volumes)) {
volume.shutdown();
}
}
load(sourcePath) {
sourcePath = Object(external_path_["resolve"])(sourcePath);
if (this.volumes[sourcePath]) {
// already loaded?
return this;
}
const volume = new readable_ReadableStaticVolume(sourcePath);
const pathVolumeIndex = volume.load();
this.pathVolumeMap = {
...this.pathVolumeMap,
...pathVolumeIndex,
};
this.volumes[volume.sourcePath] = volume;
return this;
}
get loadedVolumes() {
return Object.keys(this.volumes);
}
unload(sourcePath) {
sourcePath = Object(external_path_["resolve"])(sourcePath);
if (!this.volumes[sourcePath]) {
return this;
}
const volumeToUnload = this.volumes[sourcePath];
if (volumeToUnload.sourcePath !== sourcePath) {
return this;
}
volumeToUnload.shutdown();
return this;
}
get entries() {
return Object.keys(this.pathVolumeMap);
}
readFileSync(filePath, options) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
throw filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'readFileSync', filePath);
}
return volume.readFileSync(filePath, options);
}
readFile(filePath, options, callback) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'readFile', filePath));
});
return;
}
const foundFile = volume.readFileSync(filePath, options);
process.nextTick(() => {
callback(undefined, foundFile);
});
}
read(fd, buffer, offset, length, position, callback) {
try {
this.getValidatedFD(fd);
} catch (e) {
process.nextTick(() => {
callback(e);
});
return;
}
const filePath = fd.filePath;
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'read', fd));
});
return;
}
process.nextTick(() => {
volume.read(filePath, buffer, offset, length, position, callback);
});
}
realpathSync(filePath) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
throw filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'realpathSync', filePath);
}
return volume.getFromIndex(filePath) ? Object(common["j" /* sanitizePath */])(filePath) : undefined;
}
realpath(filePath, callback) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'realpath', filePath));
});
return;
}
const foundPath = volume.getFromIndex(filePath) ? Object(common["j" /* sanitizePath */])(filePath) : undefined;
process.nextTick(() => {
callback(undefined, foundPath);
});
}
volumeForFilepathSync(filePath) {
const targetPath = Object(common["j" /* sanitizePath */])(filePath);
const volumePathForFilePath = this.pathVolumeMap[targetPath];
if (!volumePathForFilePath) {
return undefined;
}
const volumeForFilePath = this.volumes[volumePathForFilePath];
if (!volumeForFilePath) {
return undefined;
}
return volumeForFilePath;
}
statSync(filePath) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'statSync', filePath);
}
return volume.getFromIndex(filePath);
}
stat(filePath, callback) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'stat', filePath));
});
return;
}
const foundStat = volume.getFromIndex(filePath);
process.nextTick(() => {
callback(undefined, foundStat);
});
}
readdirSync(filePath) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'readdirSync', filePath);
}
return Object.keys(volume.getFromDirectoriesIndex(filePath)) || [];
}
readdir(filePath, callback) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'readdir', filePath));
});
return;
}
process.nextTick(() => {
callback(undefined, Object.keys(volume.getFromDirectoriesIndex(filePath)) || []);
});
}
getValidatedFD(fd) {
if (!fd || !fd.type || fd.type !== 'static_fs_file_descriptor') {
throw filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.EBADF, 'getValidatedFD', fd);
}
const sfsFd = this.fds[fd.id];
if (!sfsFd) {
throw filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.EEXIST, 'getValidatedFD', fd);
}
return sfsFd;
}
open(filePath, callback) {
const volume = this.volumeForFilepathSync(filePath);
if (!volume) {
process.nextTick(() => {
callback(filesystem_StaticFilesystem.NewError(external_os_["constants"].errno.ENOENT, 'open', filePath));
});
return;
}
const fdIdentifier = `${volume.sourcePath}#${Object(common["j" /* sanitizePath */])(filePath)}`;
this.fds[fdIdentifier] = {
type: 'static_fs_file_descriptor',
id: fdIdentifier,
volumeSourcePath: volume.sourcePath,
filePath: filePath,
};
process.nextTick(() => {
callback(undefined, this.fds[fdIdentifier]);
});
}
close(fd, callback) {
try {
this.getValidatedFD(fd);
} catch (e) {
process.nextTick(() => {
callback(e);
});
return;
}
delete this.fds[fd.id];
process.nextTick(() => {
callback();
});
}
fstat(fd, callback) {
try {
this.getValidatedFD(fd);
} catch (e) {
process.nextTick(() => {
callback(e);
});
return;
}
this.stat(fd.filePath, callback);
}
createReadStream(filePath, options) {
return new ReadStream(this, filePath, options);
}
}
// CONCATENATED MODULE: ./src/filesystem/index.js
/* concated harmony reexport StaticFilesystem */__webpack_require__.d(__webpack_exports__, "a", function() { return filesystem_StaticFilesystem; });
/* unused concated harmony import ReadableStaticVolume */
/* unused concated harmony import WritableStaticVolume */
/***/ }),
/***/ "./src/runtime/index.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./src/runtime/runtime.js
var runtime = __webpack_require__("./src/runtime/runtime.js");
// EXTERNAL MODULE: ./src/runtime/patch/filesystem.js
var filesystem = __webpack_require__("./src/runtime/patch/filesystem.js");
// EXTERNAL MODULE: ./src/runtime/patch/module_loader.js
var module_loader = __webpack_require__("./src/runtime/patch/module_loader.js");
// CONCATENATED MODULE: ./src/runtime/patch/index.js
// CONCATENATED MODULE: ./src/runtime/index.js
/* concated harmony reexport list */__webpack_require__.d(__webpack_exports__, "list", function() { return runtime["a" /* list */]; });
/* concated harmony reexport load */__webpack_require__.d(__webpack_exports__, "load", function() { return runtime["b" /* load */]; });
/* concated harmony reexport unload */__webpack_require__.d(__webpack_exports__, "unload", function() { return runtime["c" /* unload */]; });
/* concated harmony reexport patchFilesystem */__webpack_require__.d(__webpack_exports__, "patchFilesystem", function() { return filesystem["a" /* patchFilesystem */]; });
/* concated harmony reexport patchModuleLoader */__webpack_require__.d(__webpack_exports__, "patchModuleLoader", function() { return module_loader["a" /* patchModuleLoader */]; });
/***/ }),
/***/ "./src/runtime/patch/filesystem.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return patchFilesystem; });
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("fs");
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
const MemberType = {
Constructor: 0,
Method: 1,
Property: 2,
};
const metadata = {
StatWatcher: MemberType.Constructor,
FSWatcher: MemberType.Constructor,
ReadStream: MemberType.Constructor,
WriteStream: MemberType.Constructor,
ReadFileStream: MemberType.Constructor,
WriteFileStream: MemberType.Constructor,
Stats: MemberType.Constructor,
constants: MemberType.Property,
F_OK: MemberType.Property,
R_OK: MemberType.Property,
W_OK: MemberType.Property,
X_OK: MemberType.Property,
};
function patchFilesystem(volume, original = fs__WEBPACK_IMPORTED_MODULE_0___default.a) {
// create a backup before modification
const backup = { ...original };
// iterate over the filesystem and patch members
for (const member of Object.getOwnPropertyNames(original)) {
if (!volume[member] || typeof volume[member] !== typeof original[member]) {
continue;
}
switch (metadata[member]) {
case MemberType.Constructor:
// bind as a constructor
original[member] = volume[member].bind(null, volume);
break;
case MemberType.Property:
// skip overwrite property
break;
default:
// bind as a method
original[member] = volume[member].bind(volume);
break;
}
}
// return a delegate to undo those changes.
return () => patchFilesystem(backup, original);
}
/***/ }),
/***/ "./src/runtime/patch/module_loader.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return patchModuleLoader; });
/* harmony import */ var module__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("module");
/* harmony import */ var module__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(module__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("fs");
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("path");
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__("./src/common/index.js");
function patchModuleLoader(volume) {
const backup = { ...module__WEBPACK_IMPORTED_MODULE_0__ };
const preserveSymlinks = false;
const statCache = {};
const packageMainCache = {};
// Used to speed up module loading. Returns the contents of the file as
// a string or undefined when the file cannot be opened. The speedup
// comes from not creating Error objects on failure.
function internalModuleReadFile(path) {
try {
return volume.readFileSync(path, 'utf8');
} catch {
/* no-op */
}
return undefined;
}
// Used to speed up module loading. Returns 0 if the path refers to
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
// The speedup comes from not creating thousands of Stat and Error objects.
function internalModuleStat(filename) {
try {
return volume.statSync(filename).isDirectory() ? 1 : 0;
} catch {
/* no-op */
}
return -2; // ENOENT
}
function stat(filename) {
filename = Object(path__WEBPACK_IMPORTED_MODULE_2__["toNamespacedPath"])(filename);
const result = statCache[filename];
return result !== undefined ? result : (statCache[filename] = internalModuleStat(filename));
}
function readPackage(requestPath) {
const entry = packageMainCache[requestPath];
if (entry) {
return entry;
}
const jsonPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(requestPath, 'package.json');
const json = internalModuleReadFile(Object(path__WEBPACK_IMPORTED_MODULE_2__["toNamespacedPath"])(jsonPath));
if (json === undefined) {
return false;
}
let pkg;
try {
pkg = packageMainCache[requestPath] = JSON.parse(json).main;
} catch (e) {
e.path = jsonPath;
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
throw e;
}
return pkg;
}
function tryFile(requestPath, isMain) {
if (preserveSymlinks && !isMain) {
return stat(requestPath) === 0 ? Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(requestPath) : undefined;
}
return stat(requestPath) === 0 ? volume.realpathSync(requestPath) : undefined;
}
// given a path check a the file exists with any of the set extensions
function tryExtensions(p, exts, isMain) {
for (let i = 0; i < exts.length; i++) {
const filename = tryFile(p + exts[i], isMain);
if (filename) {
return filename;
}
}
return undefined;
}
function tryPackage(requestPath, exts, isMain) {
let pkg = readPackage(requestPath);
if (pkg) {
let filename = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(requestPath, pkg);
return (
tryFile(filename, isMain) ||
tryExtensions(filename, exts, isMain) ||
tryExtensions(Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(filename, 'index'), exts, isMain)
);
}
return undefined;
}
// Native extension for .js
module__WEBPACK_IMPORTED_MODULE_0__["_extensions"]['.js'] = (module, filename) => {
const readFileFn = stat(filename) === 0 ? volume.readFileSync.bind(volume) : fs__WEBPACK_IMPORTED_MODULE_1__["readFileSync"].bind(this);
module._compile(Object(_common__WEBPACK_IMPORTED_MODULE_3__[/* stripBOM */ "l"])(readFileFn(filename, 'utf8')), filename);
};
// Native extension for .json
module__WEBPACK_IMPORTED_MODULE_0__["_extensions"]['.json'] = (module, filename) => {
const readFileFn = stat(filename) === 0 ? volume.readFileSync.bind(volume) : fs__WEBPACK_IMPORTED_MODULE_1__["readFileSync"].bind(this);
try {
module.exports = JSON.parse(Object(_common__WEBPACK_IMPORTED_MODULE_3__[/* stripBOM */ "l"])(readFileFn(filename, 'utf8')));
} catch (err) {
throw { ...err, message: filename + ': ' + err.message };
}
};
module__WEBPACK_IMPORTED_MODULE_0__["_originalFindPath"] = module__WEBPACK_IMPORTED_MODULE_0__["_findPath"];
module__WEBPACK_IMPORTED_MODULE_0__["_findPath"] = (request, paths, isMain) => {
const isRelative =
request.startsWith('./') ||
request.startsWith('../') ||
((_common__WEBPACK_IMPORTED_MODULE_3__[/* isWindows */ "d"] && request.startsWith('.\\')) || request.startsWith('..\\'));
let result = module__WEBPACK_IMPORTED_MODULE_0__["_alternateFindPath"](request, paths, isMain);
// NOTE: special use case when we have a findPath call with a relative file request where
// the given path is in the real fs and the relative file
// is inside the static fs
if (isRelative && paths.length === 1) {
const resolvedRequest = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(paths[0], request);
result = module__WEBPACK_IMPORTED_MODULE_0__["_alternateFindPath"](resolvedRequest, paths, isMain);
}
if (result) {
return result;
}
// NOTE: special use case when we have a findPath call with a relative file request where
// the given path is inside the static fs and the relative file
// request in the real fs (for example in the native modules).
if (isRelative && paths.length === 1) {
const resolvedRequest = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(paths[0], request);
resu