@smushytaco/custompatch
Version:
Tool for patching buggy NPM packages instead of forking them
143 lines (141 loc) • 6 kB
JavaScript
import fs from 'node:fs';
import path from 'pathe';
import os from 'node:os';
import { program } from 'commander';
import pacote from 'pacote';
import pc from 'picocolors';
import { p as programOptions, o as ownPackage, c as currentDirectory, a as patchDirectory } from './variables.mjs';
import { r as readPatch, g as getConfig, c as comparePackages } from './patch-utilities.mjs';
import { n as npmTarballURL } from './npm-utilities.mjs';
import 'diff';
import './file-utilities.mjs';
import './utilities.mjs';
const patchFiles = [];
const missingPackages = [];
function addPatchFileIfExists(packageName, version) {
const thePackageName = packageName.replaceAll("+", path.sep);
const destination = path.join(currentDirectory, "node_modules", thePackageName);
if (!fs.existsSync(destination)) {
console.warn(`${pc.yellowBright("WARNING:")} Package "${thePackageName}" is not installed, skipping this patch.`);
return;
}
patchFiles.push({ packageName, version });
}
try {
if (!programOptions.version) {
console.log(`${pc.whiteBright("CustomPatch")} version ${pc.greenBright(ownPackage.version)}!
`);
}
if (!fs.existsSync(path.join(currentDirectory, "node_modules"))) {
console.error(`${pc.redBright("ERROR:")} Missing "node_modules" folder.`);
process.exit(1);
}
if (programOptions.patch && programOptions.reverse) {
console.error(`${pc.redBright("ERROR:")} Cannot use -p/--patch and -r/--reverse together.`);
process.exit(1);
}
if (programOptions.patch || programOptions.reverse) {
const action = programOptions.reverse ? "reverse" : "apply";
const packageNames = program.args;
if (!fs.existsSync(patchDirectory)) {
console.warn(`${pc.yellowBright("WARNING:")} Missing "patches" folder, nothing to do.`);
process.exit(2);
}
const allPatchFiles = fs.readdirSync(patchDirectory).filter((item) => item.endsWith(".patch"));
let selectedPatchFiles;
if (packageNames.length > 0) {
selectedPatchFiles = allPatchFiles.filter((patchFile) => {
const package_ = patchFile.replace(".patch", "").split("#");
const packageName = package_[0].replaceAll("+", path.sep);
return packageNames.includes(packageName);
});
for (const package_ of packageNames) {
const found = selectedPatchFiles.some((patchFile) => {
const packageInFile = patchFile.replace(".patch", "").split("#")[0];
return packageInFile === package_.replaceAll("/", "+");
});
if (!found) {
missingPackages.push(package_);
}
}
if (selectedPatchFiles.length === 0 && missingPackages.length > 0) {
for (const package_ of missingPackages) {
console.warn(`${pc.yellowBright("WARNING:")} No patches found for package "${package_}".`);
}
process.exit(0);
}
} else {
selectedPatchFiles = allPatchFiles;
}
for (const patchFile of selectedPatchFiles) {
const package_ = patchFile.replace(".patch", "").split("#");
addPatchFileIfExists(package_[0], package_[1]);
}
if (missingPackages.length > 0) {
for (const package_ of missingPackages) {
console.warn(`${pc.yellowBright("WARNING:")} No patches found for package "${package_}".`);
}
}
console.log(`${action === "apply" ? "Applying" : "Reversing"} ${pc.cyanBright(patchFiles.length)} patch${patchFiles.length === 1 ? "." : "es."}`);
for (const { packageName, version } of patchFiles) {
try {
await readPatch(packageName, version, programOptions.reverse);
} catch (error) {
console.error(`${pc.redBright("ERROR:")} Failed to ${action} patch for ${packageName} - ${error instanceof Error ? error.message : String(error)}`);
}
}
} else if (program.args.length > 0) {
for (const packageName of program.args) {
await makePatch(packageName);
}
} else {
if (!fs.existsSync(patchDirectory)) {
console.warn(`${pc.yellowBright("WARNING:")} Missing "patches" folder, nothing to do.`);
process.exit(2);
}
for (const item of fs.readdirSync(patchDirectory)) {
if (!item.endsWith(".patch"))
continue;
const package_ = item.replace(".patch", "").split("#");
addPatchFileIfExists(package_[0], package_[1]);
}
console.log(`Found ${pc.cyanBright(patchFiles.length)} ${patchFiles.length === 1 ? "patch." : "patches."}`);
for (const { packageName, version } of patchFiles) {
try {
await readPatch(packageName, version);
} catch (error) {
console.error(`${pc.redBright("ERROR:")} Failed to apply patch for ${packageName} - ${error instanceof Error ? error.message : String(error)}`);
}
}
}
} catch (error) {
console.error(`${pc.redBright("ERROR:")} Unhandled error: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
async function makePatch(packageName) {
console.log(`Creating patch for: ${pc.magentaBright(packageName)}.`);
const config = getConfig(packageName);
if (config) {
await fetchPackage(packageName, npmTarballURL(packageName, config.version), config.version);
} else {
console.error(`${pc.redBright("ERROR:")} Could not find the URL for tarball.`);
}
}
async function fetchPackage(packageName, url, version) {
console.log(`Fetching tarball of ${pc.whiteBright(packageName)} from ${pc.green(url)}`);
const destination = path.join(os.tmpdir(), packageName);
try {
await pacote.extract(url, destination);
await comparePackages(packageName, version);
} catch (error) {
console.error(pc.redBright(error instanceof Error ? error.message : String(error)));
return;
}
try {
await fs.promises.rm(destination, { recursive: true, force: true });
} catch (error) {
console.error(`${pc.redBright("ERROR:")} Could not clean up the TEMP folder - ${error instanceof Error ? error.message : String(error)}`);
}
}
//# sourceMappingURL=cli.mjs.map