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

utility-apis.mddocs/

Utility APIs

Supporting utilities for path handling, file operations, state management, and type definitions used throughout the patch-package ecosystem. These utilities provide cross-platform compatibility, type safety, and robust error handling.

Capabilities

Core Type Definitions

Fundamental data structures used throughout patch-package.

/**
 * Core package details interface
 */
interface PackageDetails {
  /** Human-readable package path specifier */
  humanReadablePathSpecifier: string;
  /** Package path specifier */
  pathSpecifier: string;
  /** File system path to package */
  path: string;
  /** Package name */
  name: string;
  /** Whether package is nested */
  isNested: boolean;
  /** Array of package names in hierarchy */
  packageNames: string[];
}

/**
 * Extended package details with patch information
 */
interface PatchedPackageDetails extends PackageDetails {
  /** Package version */
  version: string;
  /** Patch file name */
  patchFilename: string;
  /** Development dependency only */
  isDevOnly: boolean;
  /** Optional sequence name */
  sequenceName?: string;
  /** Optional sequence number */
  sequenceNumber?: number;
}

Package Detail Parsing

Functions for parsing and extracting package information from various string formats.

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

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

/**
 * Extract package details from patch filename
 * @param patchFilename - Patch file name
 * @returns Package details or null if invalid filename
 */
function getPackageDetailsFromPatchFilename(patchFilename: string): PatchedPackageDetails | null;

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

Usage Examples:

import { 
  parseNameAndVersion,
  getPackageDetailsFromPatchFilename,
  getPatchDetailsFromCliString 
} from "patch-package/dist/PackageDetails";

// Parse version info
const nameVersion = parseNameAndVersion("lodash+4.17.21++001_security-fix");
// Returns: { packageName: "lodash", version: "4.17.21", sequenceName: "security-fix", sequenceNumber: 1 }

// Extract from patch filename
const patchDetails = getPackageDetailsFromPatchFilename("react+17.0.2.patch");

// Parse CLI input
const cliDetails = getPatchDetailsFromCliString("@types/node");

Cross-Platform Path Utilities

Path Operations

Cross-platform path handling utilities that work consistently across Windows, macOS, and Linux.

/**
 * Cross-platform path joining
 * @param args - Path segments to join
 * @returns Joined path with correct separators
 */
function join(...args: string[]): string;

/**
 * Cross-platform path resolution
 * @param args - Path segments to resolve
 * @returns Absolute resolved path
 */
function resolve(...args: string[]): string;

/**
 * Cross-platform relative path calculation
 * @param from - Source path
 * @param to - Target path
 * @returns Relative path from source to target
 */
function relative(from: string, to: string): string;

/**
 * Get directory name from path
 * @param path - File or directory path
 * @returns Directory name
 */
function dirname(path: string): string;

Usage Examples:

import { join, resolve, relative, dirname } from "patch-package/dist/path";

// Cross-platform path joining
const patchPath = join("patches", "lodash+4.17.21.patch");
// Windows: "patches\\lodash+4.17.21.patch"
// Unix: "patches/lodash+4.17.21.patch"

// Resolve absolute path
const absolutePath = resolve("./patches", "../node_modules", "lodash");

// Calculate relative path
const relPath = relative("/app", "/app/node_modules/lodash");
// Returns: "node_modules/lodash"

// Get directory
const dir = dirname("/path/to/file.patch");
// Returns: "/path/to"

File System Operations

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;

/**
 * Coerce version string to valid semver format
 * @param version - Version string to coerce
 * @returns Valid semver string or null if invalid
 */
function coerceSemVer(version: string): string | null;

Usage Examples:

import { hashFile } from "patch-package/dist/hash";
import { coerceSemVer } from "patch-package/dist/coerceSemVer";

// Generate file hash for validation
const patchHash = hashFile("patches/lodash+4.17.21.patch");
console.log(`Patch hash: ${patchHash}`);

// Coerce version to valid semver
const validVersion = coerceSemVer("1.0.0-beta.1+build.123");
// Returns: "1.0.0-beta.1"

const invalidVersion = coerceSemVer("not-a-version");
// Returns: null

// Use in state management
import { savePatchApplicationState } from "patch-package/dist/stateFile";
savePatchApplicationState({
  packageDetails,
  patches: [{
    patchFilename: "lodash+4.17.21.patch",
    patchContentHash: hashFile("patches/lodash+4.17.21.patch"),
    didApply: true
  }],
  isRebasing: false
});

Safe Process Execution

Secure process spawning for executing shell commands.

/**
 * Safely execute shell commands
 * @param command - Command to execute
 * @param args - Command arguments array
 * @param options - Spawn options
 * @returns Spawn result with status and output
 */
function spawnSafeSync(
  command: string, 
  args?: string[], 
  options?: SpawnSafeOptions
): SpawnResult;

interface SpawnSafeOptions {
  /** Current working directory */
  cwd?: string;
  /** Environment variables */
  env?: Record<string, string>;
  /** Input to pass to command */
  input?: string | Buffer;
  /** Stdio configuration */
  stdio?: "pipe" | "inherit" | "ignore";
  /** Timeout in milliseconds */
  timeout?: number;
  /** Kill signal */
  killSignal?: string;
}

interface SpawnResult {
  /** Exit status code */
  status: number | null;
  /** Kill signal if terminated */
  signal: string | null;
  /** Standard output */
  stdout: Buffer;
  /** Standard error */
  stderr: Buffer;
}

Usage Examples:

import { spawnSafeSync } from "patch-package/dist/spawnSafe";

// Execute git command safely
const result = spawnSafeSync("git", ["diff", "--no-index", "original", "modified"], {
  cwd: "/path/to/package",
  timeout: 30000
});

if (result.status === 0) {
  const diff = result.stdout.toString();
  console.log("Git diff output:", diff);
} else {
  console.error("Git command failed:", result.stderr.toString());
}

Regular Expression Utilities

RegExp Creation

Utility for creating regular expressions with error handling and validation.

/**
 * 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;

Usage Examples:

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

// Create include pattern with error handling
const includePaths = makeRegExp(
  "src/.*\\.(js|ts)$", 
  "include paths", 
  /.*/, 
  false
);

// Create exclude pattern
const excludePaths = makeRegExp(
  "(test|spec|__tests__)/.*", 
  "exclude paths", 
  /^package\.json$/, 
  true // case sensitive
);

// Use in patch creation
import { makePatch } from "patch-package/dist/makePatch";
makePatch({
  packagePathSpecifier: "my-package",
  appPath: process.cwd(),
  packageManager: "npm",
  includePaths,
  excludePaths,
  // ... other options
});

Type Safety Utilities

Exhaustiveness Checking

TypeScript utility for exhaustive type checking.

/**
 * TypeScript exhaustiveness checking utility
 * @param x - Value that should never be reached
 * @throws Error if called (indicates missing case)
 */
function assertNever(x: never): never;

Usage Examples:

import { assertNever } from "patch-package/dist/assertNever";

type PackageManager = "npm" | "yarn" | "npm-shrinkwrap";

function handlePackageManager(pm: PackageManager) {
  switch (pm) {
    case "npm":
      return "Using npm";
    case "yarn":
      return "Using yarn";
    case "npm-shrinkwrap":
      return "Using npm-shrinkwrap";
    default:
      // TypeScript will ensure this is never reached
      return assertNever(pm);
  }
}

State File Management

State Persistence

Utilities for managing patch application state persistence.

/** State file name constant */
const STATE_FILE_NAME: ".patch-package.json";

/**
 * Get current patch application state
 * @param packageDetails - Package details
 * @returns Current state or null if none exists
 */
function getPatchApplicationState(packageDetails: PackageDetails): PatchApplicationState | null;

/**
 * Save patch application state
 * @param options - State save options
 */
function savePatchApplicationState(options: SaveStateOptions): void;

/**
 * Clear patch application state
 * @param packageDetails - Package details
 */
function clearPatchApplicationState(packageDetails: PackageDetails): void;

interface SaveStateOptions {
  packageDetails: PackageDetails;
  patches: PatchState[];
  isRebasing: boolean;
}

interface PatchState {
  patchFilename: string;
  patchContentHash: string;
  didApply: boolean;
}

interface PatchApplicationState {
  version: number;
  patches: PatchState[];
  isRebasing: boolean;
}

Complete Utility Integration Example

import {
  getPatchDetailsFromCliString,
  parseNameAndVersion,
  join,
  resolve,
  hashFile,
  makeRegExp,
  spawnSafeSync,
  getPatchApplicationState,
  savePatchApplicationState
} from "patch-package/dist";

// Complete workflow using utilities
async function processPackagePatch(packageName: string) {
  // Parse package details
  const packageDetails = getPatchDetailsFromCliString(packageName);
  if (!packageDetails) {
    throw new Error(`Invalid package: ${packageName}`);
  }
  
  // Build paths using cross-platform utilities
  const patchDir = resolve("patches");
  const patchPath = join(patchDir, `${packageName}+1.0.0.patch`);
  
  // Create regex patterns with error handling
  const includePaths = makeRegExp("src/.*\\.(js|ts)$", "include", /.*/, false);
  const excludePaths = makeRegExp("test/.*", "exclude", /^package\.json$/, false);
  
  // Check current state
  const currentState = getPatchApplicationState(packageDetails);
  
  // Generate file hash for validation
  const patchHash = hashFile(patchPath);
  
  // Execute git command safely
  const gitResult = spawnSafeSync("git", ["status", "--porcelain"], {
    cwd: packageDetails.path,
    timeout: 10000
  });
  
  // Update state
  savePatchApplicationState({
    packageDetails,
    patches: [{
      patchFilename: `${packageName}+1.0.0.patch`,
      patchContentHash: patchHash,
      didApply: true
    }],
    isRebasing: false
  });
  
  return {
    packageDetails,
    patchPath,
    currentState,
    gitStatus: gitResult.stdout.toString()
  };
}

These utilities form the foundation that enables patch-package to work reliably across different platforms, package managers, and project structures while maintaining type safety and robust error handling.

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