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

patch-creation.mddocs/

Patch Creation

Core functionality for creating patch files from modified node_modules. The patch creation system generates git-style diff patches, handles file filtering, manages patch sequences, and integrates with GitHub issue creation workflows.

Capabilities

Main Patch Creation Function

Creates patch files based on package modifications in node_modules.

/**
 * Create patch files based on package modifications
 * @param options - Configuration for patch creation
 */
function makePatch(options: MakePatchOptions): void;

interface MakePatchOptions {
  /** Package identifier (e.g., "lodash", "@types/node") */
  packagePathSpecifier: string;
  /** Application root path */
  appPath: string;
  /** Package manager type */
  packageManager: PackageManager;
  /** Files to include (regexp pattern) */
  includePaths: RegExp;
  /** Files to exclude (regexp pattern) */
  excludePaths: RegExp;
  /** Output directory for patches */
  patchDir: string;
  /** Open GitHub issue creation link */
  createIssue: boolean;
  /** Patch creation mode */
  mode: PatchMode;
}

Usage Examples:

import { makePatch } from "patch-package/dist/makePatch";
import { detectPackageManager } from "patch-package/dist/detectPackageManager";

// Basic patch creation
makePatch({
  packagePathSpecifier: "lodash",
  appPath: process.cwd(),
  packageManager: detectPackageManager(process.cwd(), null),
  includePaths: /.*/,
  excludePaths: /^package\.json$/,
  patchDir: "patches",
  createIssue: false,
  mode: { type: "overwrite_last" }
});

// Create patch with custom filtering
makePatch({
  packagePathSpecifier: "react",
  appPath: "/path/to/app",
  packageManager: "yarn",
  includePaths: /src\/.*\.js$/,
  excludePaths: /(test|spec)\/.*$/,
  patchDir: "custom-patches",
  createIssue: true,
  mode: { type: "append", name: "performance-fix" }
});

Patch Creation Modes

Controls how new patches are handled relative to existing patches.

type PatchMode = 
  | { type: "overwrite_last" }
  | { type: "append", name?: string };
  • Overwrite Mode: Replaces the most recent patch for the package
  • Append Mode: Adds a new patch to the sequence, optionally with a descriptive name

Error Handling

Specialized error handling for patch sequence failures.

/**
 * Log error messages for patch sequence failures
 * @param patchDetails - Details of the failed patch
 */
function logPatchSequenceError(patchDetails: PatchedPackageDetails): void;

Package Details Integration

Package Resolution

The patch creation system integrates with package resolution to identify target packages.

/**
 * Parse package details from CLI string
 * @param specifier - Package specifier string
 * @returns Package details or null if invalid
 */
function getPatchDetailsFromCliString(specifier: string): PackageDetails | null;

/**
 * Parse package name and version from string
 * @param str - String containing package info
 * @returns Parsed name and version info
 */
function parseNameAndVersion(str: string): ParsedNameVersion | null;

interface ParsedNameVersion {
  packageName: string;
  version: string;
  sequenceName?: string;
  sequenceNumber?: number;
}

File Filtering

Advanced file filtering for precise control over what gets included in patches.

/**
 * Remove files matching exclude patterns from directory
 * @param dir - Directory to filter
 * @param includePaths - RegExp for files to include
 * @param excludePaths - RegExp for files to exclude
 */
function removeIgnoredFiles(
  dir: string, 
  includePaths: RegExp, 
  excludePaths: RegExp
): void;

/**
 * Create RegExp with error handling and validation
 * @param reString - Regular expression string
 * @param name - Name for error reporting
 * @param defaultValue - Default regex if parsing fails
 * @param caseSensitive - Case sensitivity flag
 * @returns Compiled regular expression
 */
function makeRegExp(
  reString: string, 
  name: string, 
  defaultValue: RegExp, 
  caseSensitive: boolean
): RegExp;

Filtering Examples:

// Include only TypeScript files
const includePaths = makeRegExp(
  ".*\\.ts$", 
  "include", 
  /.*/, 
  false
);

// Exclude test and build directories
const excludePaths = makeRegExp(
  "(test|build|dist)/.*", 
  "exclude", 
  /^package\.json$/, 
  false
);

makePatch({
  packagePathSpecifier: "my-package",
  appPath: process.cwd(),
  packageManager: "npm",
  includePaths,
  excludePaths,
  patchDir: "patches",
  createIssue: false,
  mode: { type: "overwrite_last" }
});

GitHub Integration

Issue Creation

Automatic GitHub issue creation to encourage upstream contribution.

/**
 * Extract VCS details from package
 * @param packageDetails - Package details
 * @returns VCS details or null if not available
 */
function getPackageVCSDetails(packageDetails: PackageDetails): VCSDetails | null;

interface VCSDetails {
  repo: string;
  org: string;
  provider: "GitHub";
}

/**
 * Determine if issue creation should be recommended
 * @param vcsDetails - Version control system details
 * @returns Whether to recommend issue creation
 */
function shouldRecommendIssue(vcsDetails: VCSDetails | null): boolean;

/**
 * Print issue creation prompt if appropriate
 * @param vcs - VCS details
 * @param packageDetails - Package details
 * @param packageManager - Package manager type
 */
function maybePrintIssueCreationPrompt(
  vcs: VCSDetails, 
  packageDetails: PackageDetails, 
  packageManager: PackageManager
): void;

/**
 * Open GitHub issue creation link in browser
 * @param options - Issue creation configuration
 */
function openIssueCreationLink(options: IssueCreationOptions): void;

interface IssueCreationOptions {
  packageDetails: PackageDetails;
  patchDetails: PatchedPackageDetails;
  vcsDetails: VCSDetails;
  packageManager: PackageManager;
}

Advanced Features

Development Dependency Detection

Automatically detects if a patched 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 {
  appPath: string;
  patchDetails: PatchedPackageDetails;
}

File Hashing

Content hashing for patch validation and integrity checking.

/**
 * Generate SHA-256 hash of file content
 * @param filePath - Path to file to hash
 * @returns SHA-256 hash string
 */
function hashFile(filePath: string): string;

Cross-Platform Path Handling

Utilities for cross-platform path operations during patch creation.

// Cross-platform path utilities
function join(...args: string[]): string;
function resolve(...args: string[]): string;
function relative(from: string, to: string): string;
function dirname(path: string): string;

Patch Creation Workflow

The typical patch creation workflow involves:

  1. Package Detection: Identify the target package in node_modules
  2. Change Detection: Compare current state with original package
  3. File Filtering: Apply include/exclude patterns
  4. Diff Generation: Create git-style diff patches
  5. Sequence Management: Handle patch ordering and naming
  6. Validation: Verify patch integrity and completeness
  7. GitHub Integration: Optionally prompt for upstream issue creation

Complete Example:

import { makePatch } from "patch-package/dist/makePatch";
import { detectPackageManager } from "patch-package/dist/detectPackageManager";
import { makeRegExp } from "patch-package/dist/makeRegExp";

// Create patch with comprehensive configuration
const packageManager = detectPackageManager(process.cwd(), null);
const includePaths = makeRegExp("src/.*\\.(js|ts)$", "include", /.*/, false);
const excludePaths = makeRegExp("(test|spec)/.*", "exclude", /^package\.json$/, false);

makePatch({
  packagePathSpecifier: "problematic-package",
  appPath: process.cwd(),
  packageManager,
  includePaths,
  excludePaths,
  patchDir: "patches",
  createIssue: true,
  mode: { type: "append", name: "fix-memory-leak" }
});

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