UNPKG

npm-ipfsify

Version:

Node.JS Package Management for the Distributed Web

204 lines (199 loc) 10.8 kB
const child_process = require("child_process"); const fs = require("fs-extra"); const ipfsAPI = require("ipfs-api"); const npm = require("npm"); const os = require("os"); const path = require("path"); const process = require("process"); const recursive = require("recursive-readdir"); let ipfs = ipfsAPI("/ip4/127.0.0.1/tcp/5001"); function ipfsifyPackage(nodeModulesDir, packageName, packageMap, callback) { let modDir = path.join(nodeModulesDir, packageName); fs.readJson(path.join(modDir, "package.json"), (err, package_json) => { if (err) { callback(err); } else { let dependencies = package_json.dependencies ? Object.getOwnPropertyNames(package_json.dependencies) : []; let submodulesDir = path.join(modDir, "node_modules"); let packages = []; let loop = i => { if (i < dependencies.length) { if (packageMap[dependencies[i]]) { loop(i + 1); } else { let loop2 = dir => { fs.access(path.join(dir, dependencies[i]), fs.constants.F_OK, err => { if (err) { let parent = path.dirname(path.dirname(dir)); if (path.basename(parent) === "node_modules") { loop2(parent); } else { callback(err, packages); } } else { ipfsifyPackage(dir, dependencies[i], packageMap, (err, pkgs) => { if (pkgs) { packages.push(...pkgs); } if (err) { callback(err, packages); } else { loop(i + 1); } }); } }); } loop2(submodulesDir); } } else { recursive(modDir, (err, files) => { if (err) { callback(err, packages); } else { loop = i => { if (i < files.length) { if (files[i].endsWith(".js")) { fs.readFile(files[i], { "encoding": "utf8" }, (err, data) => { if (err) { callback(err, packages); } else { let regex = /(require\s*\(\s*['"])([^'"/]+)(\/?[^'"]*['"]\s*\))/gm; let match; while (match = regex.exec(data)) { if (packageMap[match[2]]) { data = data.substr(0, match.index) + match[1] + "/ipfs/" + packageMap[match[2]] + match[3] + data.substr(match.index + match[0].length); } } fs.writeFile(files[i], data, { "encoding": "utf8" }, err => { if (err) { callback(err, packages); } else { loop(i + 1); } }) } }); } else { loop(i + 1); } } else { package_json._where = "/npm-ipfsify"; fs.writeFile(path.join(modDir, "package.json"), JSON.stringify(package_json), { "encoding": "utf8" }, err => { if (err) { callback(err, packages); } else { let dataFiles = []; let dirs = [] loop = i => { if (i < files.length) { if (files[i].indexOf("node_modules", modDir.length) < 0) { fs.stat(files[i], (err, stats) => { if (err) { callback(err, packages); } else { if (stats.isDirectory()) { dirs.push(files[i]); } else { dataFiles.push(files[i]); } loop(i + 1); } }); } else { loop(i + 1); } } else { let stream = ipfs.files.addReadableStream(); stream.on("error", err => { callback(err, packages); }); stream.on("data", file => { if (file.path === "package") { packageMap[packageName] = file.hash; packages.push({ "name": package_json.name, "version": package_json.version, "hash": file.hash }); callback(null, packages); } }); dataFiles.forEach(file => { stream.write({ "path": path.join("package", file.substr(modDir.length + 1)), "content": fs.createReadStream(file) }); }); dirs.forEach(dir => { stream.write({ "path": path.join("package", dir.substr(modDir.length + 1)) }); }); stream.end(); } }; loop(0); } }); } }; loop(0); } }); } }; loop(0); } }); } function ipfsify(packageName, callback) { fs.mkdtemp(path.join(os.tmpdir(), "npm-ipfsify-"), (err, dir) => { if (err) { callback(err); } else { let oldCallback = callback; callback = (err, res) => { process.chdir(".."); fs.remove(dir, err2 => { if (err2) { console.error("Warning: could not delete temporary directory"); } oldCallback(err, res); }); }; process.chdir(dir); npm.load({ "loaded": false }, err => { if (err) { callback(err); } else { npm.commands.install([ packageName ], err => { if (err) { callback(err); } else { ipfsifyPackage(path.join(dir, "node_modules"), packageName.split("@")[0], {}, callback); } }); npm.on("log", console.log.bind(console)); } }); } }); } module.exports = { "ipfsifyPackage": ipfsifyPackage, "ipfsify": ipfsify };