CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-patch-package

Fix broken node modules with no fuss - create and apply patches to npm dependencies instantly

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

package-management.mddocs/

Package Management Integration

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.

Capabilities

Package Manager Detection

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 → yarn
  • package-lock.json → npm
  • npm-shrinkwrap.json → npm-shrinkwrap
  • Falls back to npm if no lockfile is found

Usage 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
});

Package Resolution

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:

  • npm: Reads package-lock.json for exact versions
  • yarn: Parses yarn.lock for resolution info
  • npm-shrinkwrap: Uses npm-shrinkwrap.json for locked versions

Usage 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}`);

Version Utilities

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: null

Dependency Analysis

Development Dependency Detection

Determine 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.json
  • Nested dependency relationships
  • Package installation context

Usage 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");
}

File Dependency Resolution

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"
  • Relative path resolution across different project structures

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 paths

Application Root Detection

App Root Discovery

Find 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");
}

Package Manager-Specific Behaviors

npm Integration

npm-specific handling including:

  • package-lock.json parsing
  • npm v5+ compatibility
  • Shrinkwrap file support
  • npm workspace detection

yarn Integration

yarn v1-specific handling including:

  • yarn.lock parsing
  • Yarn workspace detection
  • Resolution strategy differences
  • Version constraint handling

Workspace Support

Support for monorepo structures:

  • npm workspaces
  • yarn workspaces
  • Lerna integration
  • Relative dependency resolution

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}`);

Integration Examples

Complete Package Manager Workflow

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

docs

cli-interface.md

index.md

package-management.md

patch-application.md

patch-creation.md

rebase-operations.md

utility-apis.md

tile.json