Fix broken node modules with no fuss - create and apply patches to npm dependencies instantly
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Package manager detection, version resolution, and lockfile integration for npm, yarn, and npm-shrinkwrap environments. This module provides comprehensive support for different package managers and their specific behaviors, lockfile formats, and resolution strategies.
Automatic detection of package manager based on lockfiles and project configuration.
/**
* Detect which package manager is being used
* @param appRootPath - Application root directory path
* @param overridePackageManager - Force specific package manager
* @returns Detected or overridden package manager
*/
function detectPackageManager(
appRootPath: string,
overridePackageManager: PackageManager | null
): PackageManager;
type PackageManager = "yarn" | "npm" | "npm-shrinkwrap";The detection logic checks for:
yarn.lock → yarnpackage-lock.json → npmnpm-shrinkwrap.json → npm-shrinkwrapUsage Examples:
import { detectPackageManager } from "patch-package/dist/detectPackageManager";
// Auto-detect package manager
const packageManager = detectPackageManager(process.cwd(), null);
console.log(`Using package manager: ${packageManager}`);
// Force yarn usage
const forcedYarn = detectPackageManager(process.cwd(), "yarn");
// Use in patch creation
import { makePatch } from "patch-package/dist/makePatch";
makePatch({
packagePathSpecifier: "lodash",
appPath: process.cwd(),
packageManager: detectPackageManager(process.cwd(), null),
// ... other options
});Resolution of package versions and locations from lockfiles.
/**
* Get package resolution from lockfiles
* @param options - Package resolution options
* @returns Resolved package version string
*/
function getPackageResolution(options: PackageResolutionOptions): string;
interface PackageResolutionOptions {
/** Package details for resolution */
packageDetails: PackageDetails;
/** Package manager type */
packageManager: PackageManager;
/** Application path */
appPath: string;
}Resolution behavior varies by package manager:
package-lock.json for exact versionsyarn.lock for resolution infonpm-shrinkwrap.json for locked versionsUsage Examples:
import { getPackageResolution } from "patch-package/dist/getPackageResolution";
import { getPatchDetailsFromCliString } from "patch-package/dist/PackageDetails";
const packageDetails = getPatchDetailsFromCliString("lodash");
const resolution = getPackageResolution({
packageDetails,
packageManager: "yarn",
appPath: process.cwd()
});
console.log(`Resolved version: ${resolution}`);Utilities for working with package versions and semver.
/**
* Get package version from package.json
* @param packageJsonPath - Path to package.json file
* @returns Package version string
*/
function getPackageVersion(packageJsonPath: string): string;
/**
* Coerce version string to valid semver
* @param version - Version string to coerce
* @returns Valid semver string or null if invalid
*/
function coerceSemVer(version: string): string | null;Usage Examples:
import { getPackageVersion, coerceSemVer } from "patch-package/dist/getPackageVersion";
// Read version from package.json
const version = getPackageVersion("./node_modules/lodash/package.json");
// Coerce non-standard version to semver
const coercedVersion = coerceSemVer("1.0.0-beta.1+build.123");
// Returns: "1.0.0-beta.1"
const invalidVersion = coerceSemVer("not-a-version");
// Returns: nullDetermine if a package is a development dependency to optimize patch application.
/**
* Check if package is development dependency
* @param options - Development dependency check options
* @returns True if package is dev dependency
*/
function packageIsDevDependency(options: DevDepOptions): boolean;
interface DevDepOptions {
/** Application path */
appPath: string;
/** Patch details for the package */
patchDetails: PatchedPackageDetails;
}This function checks:
devDependencies in package.jsonUsage Examples:
import { packageIsDevDependency } from "patch-package/dist/packageIsDevDependency";
const isDevDep = packageIsDevDependency({
appPath: process.cwd(),
patchDetails: {
name: "typescript",
version: "4.5.0",
// ... other patch details
}
});
if (isDevDep) {
console.log("This is a development dependency");
}Handle relative file dependencies in package resolutions.
/**
* Resolve relative file dependencies in package resolutions
* @param appRootPath - Application root path
* @param resolutions - Package resolutions map
* @returns Updated resolutions with resolved file paths
*/
function resolveRelativeFileDependencies(
appRootPath: string,
resolutions: Record<string, string>
): Record<string, string>;Handles cases like:
"my-package": "file:../local-package""utils": "file:./packages/utils"Usage Examples:
import { resolveRelativeFileDependencies } from "patch-package/dist/resolveRelativeFileDependencies";
const resolutions = {
"local-utils": "file:../utils",
"shared-lib": "file:./packages/shared",
"regular-dep": "^1.0.0"
};
const resolved = resolveRelativeFileDependencies(process.cwd(), resolutions);
// Converts relative file: paths to absolute pathsFind application root by locating package.json files in the directory hierarchy.
/**
* Find application root by locating package.json
* @returns Application root path
* @throws Error if no package.json found
*/
function getAppRootPath(): string;The function searches up the directory tree from the current working directory until it finds a package.json file, indicating the project root.
Usage Examples:
import { getAppRootPath } from "patch-package/dist/getAppRootPath";
try {
const appRoot = getAppRootPath();
console.log(`Application root: ${appRoot}`);
} catch (error) {
console.error("Could not find application root");
}npm-specific handling including:
package-lock.json parsingyarn v1-specific handling including:
yarn.lock parsingSupport for monorepo structures:
Workspace Example:
import { detectPackageManager } from "patch-package/dist/detectPackageManager";
import { getAppRootPath } from "patch-package/dist/getAppRootPath";
// Works in monorepo workspaces
const appRoot = getAppRootPath(); // Finds workspace root
const packageManager = detectPackageManager(appRoot, null);
// Will correctly detect yarn workspaces or npm workspaces
console.log(`Workspace uses ${packageManager}`);import {
detectPackageManager,
getPackageResolution,
packageIsDevDependency,
getAppRootPath
} from "patch-package/dist";
// Full workflow example
async function analyzePackage(packageName: string) {
// Find application root
const appPath = getAppRootPath();
// Detect package manager
const packageManager = detectPackageManager(appPath, null);
console.log(`Using ${packageManager}`);
// Get package details
const packageDetails = getPatchDetailsFromCliString(packageName);
if (!packageDetails) {
throw new Error(`Invalid package: ${packageName}`);
}
// Resolve package version
const resolution = getPackageResolution({
packageDetails,
packageManager,
appPath
});
console.log(`Resolved version: ${resolution}`);
// Check if development dependency
const isDevDep = packageIsDevDependency({
appPath,
patchDetails: {
...packageDetails,
version: resolution,
patchFilename: `${packageName}+${resolution}.patch`,
isDevOnly: false
}
});
console.log(`Development dependency: ${isDevDep}`);
return {
packageManager,
resolution,
isDevDep,
appPath
};
}This integration layer ensures patch-package works seamlessly across different package manager environments while respecting each manager's specific behaviors and conventions.
Install with Tessl CLI
npx tessl i tessl/npm-patch-package