Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | 1x 1x 1x 1x 1x 2x 2x 2x 2x 1x 4x 2x 2x 1x 44x 66x 66x 2x 64x 62x 12x 50x 50x 50x 50x 50x 50x 24x 24x 2x 22x 50x 50x 2x 48x 48x 6x 50x 50x 1x 24x 24x 1x 168x 1x 66x 1x 1x 1x 1x 84x 33x 33x 1x 32x 1x 1x 1x 84x 33x 33x 1x 32x | import * as path from "./path" import { Resolver } from "./resolver" import { Tar } from "./tar" type Module = any // eslint-disable-line @typescript-eslint/no-explicit-any export interface FileReader { exists(filePath: string): boolean read(filePath: string, encoding?: "utf8"): string | Uint8Array } const originalExports = Symbol("originalExports") /** * Allow requiring modules and files from a provided file system. */ export class RequireFS extends Resolver { private readonly reader: FileReader private readonly customModules: Map<string, Module> private readonly requireCache: Map<string, Module> public constructor(reader: FileReader) { super() this.reader = reader this.customModules = new Map() this.requireCache = new Map() } /** * Provide a custom module. */ public provide(moduleName: string, value: Module): void { if (this.customModules.has(moduleName)) { throw new Error("custom module has already been registered with this name") } this.customModules.set(moduleName, value) } /** * Require a path relative to the root. */ public require(target: string): Module { return this.doRequire(`./${path.normalize(target)}`, "./") } /** * Attempt to require the provided path. If the path requires another path, it * will recursively follow the dependency tree and return any exported data. */ private doRequire(importPath: string, directoryPath: string): Module { if (this.customModules.has(importPath)) { return this.customModules.get(importPath) } const resolvedPath = this.resolvePath(importPath, directoryPath) if (this.requireCache.has(resolvedPath)) { return this.requireCache.get(resolvedPath).exports } // Provide globals that can be referenced in the `eval`. let exports = {} const module = { exports, [originalExports]: exports } // We must do this immediately in case of circular imports. This means that // a circular import can't catch reassigned values but it's better than // failing. this.requireCache.set(resolvedPath, { exports }) /* eslint-disable @typescript-eslint/no-unused-vars */ // @ts-ignore const __dirname = path.dirname(resolvedPath) // Some modules will try to use `define` if it exists (lodash) and we only // want modules using our custom-provided `require` function. // @ts-ignore const define = undefined // @ts-ignore const require = (target: string): Module => { const nativeModule = this.tryNativeRequire(target) if (typeof nativeModule !== "undefined" && nativeModule !== null) { return nativeModule } return this.doRequire(target, path.dirname(resolvedPath)) } /* eslint-enable @typescript-eslint/no-unused-vars */ const content = this.readFile(resolvedPath, "utf8") if (/\.json$/.test(resolvedPath)) { exports = JSON.parse(content) } else { eval(`'use strict'; ${content}`) // It's possible that `exports` or `module.exports` have been reassigned. // In that case use the reassigned version, giving preference to // `exports`. if ( exports === module[originalExports] && // exports not reassigned module.exports !== module[originalExports] // module.exports reassigned ) { exports = module.exports } } // Set it again in case it was reassigned. this.requireCache.set(resolvedPath, { exports }) return exports } /** * Require a module using NodeJS's `module.require`. Note that script runners * (e.g. Jest, which uses `resolve.Sync` under the hood) may interfere. */ private tryNativeRequire(modulePath: string): Module { try { return require(modulePath) } catch (e) { // Don't throw here. The module may be retrievable in another way. } } protected isFile(filePath: string): boolean { return this.reader.exists(filePath) } public readFile(filePath: string): Uint8Array public readFile(filePath: string, encoding: "utf8"): string public readFile(filePath: string, encoding?: "utf8"): string | Uint8Array { return this.reader.read(filePath, encoding) } } /** * Return a readable and requirable file system from a tar. */ export const fromTar = (content: Uint8Array): RequireFS => { const tar = Tar.fromUint8Array(content) return new RequireFS({ exists: (filePath: string): boolean => { return !!tar.getFile(filePath) }, read: (filePath: string, encoding?: "utf8"): string | Uint8Array => { const file = tar.getFile(filePath) if (!file) { throw new Error(`"${filePath}" does not exist`) } return encoding ? file.read(encoding) : file.read() }, }) } /** * Return a readable and requirable file system from a zip. */ export const fromZip = (content: Uint8Array): RequireFS => { // @ts-ignore const zip = new (require("jszip") as typeof import("jszip"))(content) return new RequireFS({ exists: (filePath: string): boolean => { return !!zip.file(filePath) }, read: (filePath: string, encoding?: "utf8"): string | Uint8Array => { const file = zip.file(filePath) if (!file) { throw new Error(`"${filePath}" does not exist`) } return encoding ? zip.file(filePath).asText() : zip.file(filePath).asUint8Array() }, }) } |