|
| 1 | +const path = require("path"); |
| 2 | +const fs = require("fs"); |
| 3 | +const packList = require("npm-packlist"); |
| 4 | +const precinct = require("precinct"); |
| 5 | +const resolve = require("resolve"); |
| 6 | +const readPkgUp = require("read-pkg-up"); |
| 7 | +const requirePackageName = require("require-package-name"); |
| 8 | +const alwaysIgnored = new Set(["aws-sdk"]); |
| 9 | +const debug = require("debug")("@netlify/zip-it-and-ship-it:finders"); |
| 10 | + |
| 11 | +const ignoredExtensions = new Set([ |
| 12 | + ".log", |
| 13 | + ".lock", |
| 14 | + ".html", |
| 15 | + ".md", |
| 16 | + ".map", |
| 17 | + ".ts", |
| 18 | + ".png", |
| 19 | + ".jpeg", |
| 20 | + ".jpg", |
| 21 | + ".gif", |
| 22 | + ".css", |
| 23 | + ".patch" |
| 24 | +]); |
| 25 | + |
| 26 | +function ignoreMissing(dependency, optional) { |
| 27 | + return alwaysIgnored.has(dependency) || (optional && dependency in optional); |
| 28 | +} |
| 29 | + |
| 30 | +function includeModuleFile(packageJson, moduleFilePath) { |
| 31 | + if (packageJson.files) { |
| 32 | + return true; |
| 33 | + } |
| 34 | + |
| 35 | + return !ignoredExtensions.has(path.extname(moduleFilePath)); |
| 36 | +} |
| 37 | + |
| 38 | +function getDependencies(filename, basedir) { |
| 39 | + const servicePath = basedir; |
| 40 | + |
| 41 | + const filePaths = new Set(); |
| 42 | + const modulePaths = new Set(); |
| 43 | + const pkgs = {}; |
| 44 | + |
| 45 | + const modulesToProcess = []; |
| 46 | + const localFilesToProcess = [filename]; |
| 47 | + |
| 48 | + function handle(name, basedir, optionalDependencies) { |
| 49 | + const moduleName = requirePackageName(name.replace(/\\/, "/")); |
| 50 | + |
| 51 | + if (alwaysIgnored.has(moduleName)) { |
| 52 | + return; |
| 53 | + } |
| 54 | + |
| 55 | + try { |
| 56 | + const pathToModule = resolve.sync(path.join(moduleName, "package.json"), { |
| 57 | + basedir |
| 58 | + }); |
| 59 | + const pkg = readPkgUp.sync({ cwd: pathToModule }); |
| 60 | + |
| 61 | + if (pkg) { |
| 62 | + modulesToProcess.push(pkg); |
| 63 | + } |
| 64 | + } catch (e) { |
| 65 | + if (e.code === "MODULE_NOT_FOUND") { |
| 66 | + if (ignoreMissing(moduleName, optionalDependencies)) { |
| 67 | + debug(`WARNING missing optional dependency: ${moduleName}`); |
| 68 | + return null; |
| 69 | + } |
| 70 | + try { |
| 71 | + // this resolves the requested import also against any set up NODE_PATH extensions, etc. |
| 72 | + const resolved = require.resolve(name); |
| 73 | + localFilesToProcess.push(resolved); |
| 74 | + return; |
| 75 | + } catch (e) { |
| 76 | + throw new Error(`Could not find "${moduleName}" module in file: ${filename.replace( |
| 77 | + path.dirname(basedir), |
| 78 | + "" |
| 79 | + )}. |
| 80 | + |
| 81 | +Please ensure "${moduleName}" is installed in the project.`); |
| 82 | + } |
| 83 | + } |
| 84 | + throw e; |
| 85 | + } |
| 86 | + } |
| 87 | + |
| 88 | + while (localFilesToProcess.length) { |
| 89 | + const currentLocalFile = localFilesToProcess.pop(); |
| 90 | + |
| 91 | + if (filePaths.has(currentLocalFile)) { |
| 92 | + continue; |
| 93 | + } |
| 94 | + |
| 95 | + filePaths.add(currentLocalFile); |
| 96 | + precinct |
| 97 | + .paperwork(currentLocalFile, { includeCore: false }) |
| 98 | + .forEach(dependency => { |
| 99 | + if (dependency.indexOf(".") === 0) { |
| 100 | + const abs = resolve.sync(dependency, { |
| 101 | + basedir: path.dirname(currentLocalFile) |
| 102 | + }); |
| 103 | + localFilesToProcess.push(abs); |
| 104 | + } else { |
| 105 | + handle(dependency, servicePath); |
| 106 | + } |
| 107 | + }); |
| 108 | + } |
| 109 | + |
| 110 | + while (modulesToProcess.length) { |
| 111 | + const currentModule = modulesToProcess.pop(); |
| 112 | + const currentModulePath = path.join(currentModule.path, ".."); |
| 113 | + const packageJson = currentModule.pkg; |
| 114 | + |
| 115 | + if (modulePaths.has(currentModulePath)) { |
| 116 | + continue; |
| 117 | + } |
| 118 | + modulePaths.add(currentModulePath); |
| 119 | + pkgs[currentModulePath] = packageJson; |
| 120 | + ["dependencies", "peerDependencies", "optionalDependencies"].forEach( |
| 121 | + key => { |
| 122 | + const dependencies = packageJson[key]; |
| 123 | + |
| 124 | + if (dependencies) { |
| 125 | + Object.keys(dependencies).forEach(dependency => { |
| 126 | + handle( |
| 127 | + dependency, |
| 128 | + currentModulePath, |
| 129 | + packageJson.optionalDependencies |
| 130 | + ); |
| 131 | + }); |
| 132 | + } |
| 133 | + } |
| 134 | + ); |
| 135 | + } |
| 136 | + |
| 137 | + modulePaths.forEach(modulePath => { |
| 138 | + const packageJson = pkgs[modulePath]; |
| 139 | + let moduleFilePaths; |
| 140 | + |
| 141 | + moduleFilePaths = packList.sync({ path: modulePath }); |
| 142 | + |
| 143 | + moduleFilePaths.forEach(moduleFilePath => { |
| 144 | + if (includeModuleFile(packageJson, moduleFilePath)) { |
| 145 | + filePaths.add(path.join(modulePath, moduleFilePath)); |
| 146 | + } |
| 147 | + }); |
| 148 | + }); |
| 149 | + |
| 150 | + // TODO: get rid of this |
| 151 | + const sizes = {}; |
| 152 | + filePaths.forEach(filepath => { |
| 153 | + const stat = fs.lstatSync(filepath); |
| 154 | + const ext = path.extname(filepath); |
| 155 | + sizes[ext] = (sizes[ext] || 0) + stat.size; |
| 156 | + }); |
| 157 | + debug("Sizes per extension: ", sizes); |
| 158 | + |
| 159 | + return Array.from(filePaths); |
| 160 | +} |
| 161 | + |
| 162 | +function findModuleDir(dir) { |
| 163 | + let basedir = dir; |
| 164 | + while (!fs.existsSync(path.join(basedir, "package.json"))) { |
| 165 | + const newBasedir = path.dirname(basedir); |
| 166 | + if (newBasedir === basedir) { |
| 167 | + return null; |
| 168 | + } |
| 169 | + basedir = newBasedir; |
| 170 | + } |
| 171 | + return basedir; |
| 172 | +} |
| 173 | + |
| 174 | +function findHandler(functionPath) { |
| 175 | + if (fs.lstatSync(functionPath).isFile()) { |
| 176 | + return functionPath; |
| 177 | + } |
| 178 | + |
| 179 | + const handlerPath = path.join( |
| 180 | + functionPath, |
| 181 | + `${path.basename(functionPath)}.js` |
| 182 | + ); |
| 183 | + if (!fs.existsSync(handlerPath)) { |
| 184 | + return; |
| 185 | + } |
| 186 | + return handlerPath; |
| 187 | +} |
| 188 | + |
| 189 | +module.exports = { getDependencies, findModuleDir, findHandler }; |
0 commit comments