UNPKG

static-fs

Version:

A static filesystem to bundle files and read them using NodeJS

1,597 lines (1,272 loc) 73.1 kB
(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