0
# Utility APIs
1
2
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.
3
4
## Capabilities
5
6
### Core Type Definitions
7
8
Fundamental data structures used throughout patch-package.
9
10
```typescript { .api }
11
/**
12
* Core package details interface
13
*/
14
interface PackageDetails {
15
/** Human-readable package path specifier */
16
humanReadablePathSpecifier: string;
17
/** Package path specifier */
18
pathSpecifier: string;
19
/** File system path to package */
20
path: string;
21
/** Package name */
22
name: string;
23
/** Whether package is nested */
24
isNested: boolean;
25
/** Array of package names in hierarchy */
26
packageNames: string[];
27
}
28
29
/**
30
* Extended package details with patch information
31
*/
32
interface PatchedPackageDetails extends PackageDetails {
33
/** Package version */
34
version: string;
35
/** Patch file name */
36
patchFilename: string;
37
/** Development dependency only */
38
isDevOnly: boolean;
39
/** Optional sequence name */
40
sequenceName?: string;
41
/** Optional sequence number */
42
sequenceNumber?: number;
43
}
44
```
45
46
### Package Detail Parsing
47
48
Functions for parsing and extracting package information from various string formats.
49
50
```typescript { .api }
51
/**
52
* Parse package name and version from string
53
* @param str - String containing package info
54
* @returns Parsed name and version info or null if invalid
55
*/
56
function parseNameAndVersion(str: string): ParsedNameVersion | null;
57
58
interface ParsedNameVersion {
59
packageName: string;
60
version: string;
61
sequenceName?: string;
62
sequenceNumber?: number;
63
}
64
65
/**
66
* Extract package details from patch filename
67
* @param patchFilename - Patch file name
68
* @returns Package details or null if invalid filename
69
*/
70
function getPackageDetailsFromPatchFilename(patchFilename: string): PatchedPackageDetails | null;
71
72
/**
73
* Parse package details from CLI string
74
* @param specifier - Package specifier string
75
* @returns Package details or null if invalid
76
*/
77
function getPatchDetailsFromCliString(specifier: string): PackageDetails | null;
78
```
79
80
**Usage Examples:**
81
82
```typescript
83
import {
84
parseNameAndVersion,
85
getPackageDetailsFromPatchFilename,
86
getPatchDetailsFromCliString
87
} from "patch-package/dist/PackageDetails";
88
89
// Parse version info
90
const nameVersion = parseNameAndVersion("lodash+4.17.21++001_security-fix");
91
// Returns: { packageName: "lodash", version: "4.17.21", sequenceName: "security-fix", sequenceNumber: 1 }
92
93
// Extract from patch filename
94
const patchDetails = getPackageDetailsFromPatchFilename("react+17.0.2.patch");
95
96
// Parse CLI input
97
const cliDetails = getPatchDetailsFromCliString("@types/node");
98
```
99
100
## Cross-Platform Path Utilities
101
102
### Path Operations
103
104
Cross-platform path handling utilities that work consistently across Windows, macOS, and Linux.
105
106
```typescript { .api }
107
/**
108
* Cross-platform path joining
109
* @param args - Path segments to join
110
* @returns Joined path with correct separators
111
*/
112
function join(...args: string[]): string;
113
114
/**
115
* Cross-platform path resolution
116
* @param args - Path segments to resolve
117
* @returns Absolute resolved path
118
*/
119
function resolve(...args: string[]): string;
120
121
/**
122
* Cross-platform relative path calculation
123
* @param from - Source path
124
* @param to - Target path
125
* @returns Relative path from source to target
126
*/
127
function relative(from: string, to: string): string;
128
129
/**
130
* Get directory name from path
131
* @param path - File or directory path
132
* @returns Directory name
133
*/
134
function dirname(path: string): string;
135
```
136
137
**Usage Examples:**
138
139
```typescript
140
import { join, resolve, relative, dirname } from "patch-package/dist/path";
141
142
// Cross-platform path joining
143
const patchPath = join("patches", "lodash+4.17.21.patch");
144
// Windows: "patches\\lodash+4.17.21.patch"
145
// Unix: "patches/lodash+4.17.21.patch"
146
147
// Resolve absolute path
148
const absolutePath = resolve("./patches", "../node_modules", "lodash");
149
150
// Calculate relative path
151
const relPath = relative("/app", "/app/node_modules/lodash");
152
// Returns: "node_modules/lodash"
153
154
// Get directory
155
const dir = dirname("/path/to/file.patch");
156
// Returns: "/path/to"
157
```
158
159
## File System Operations
160
161
### File Hashing
162
163
Content hashing for patch validation and integrity checking.
164
165
```typescript { .api }
166
/**
167
* Generate SHA-256 hash of file content
168
* @param filePath - Path to file to hash
169
* @returns SHA-256 hash string
170
*/
171
function hashFile(filePath: string): string;
172
173
/**
174
* Coerce version string to valid semver format
175
* @param version - Version string to coerce
176
* @returns Valid semver string or null if invalid
177
*/
178
function coerceSemVer(version: string): string | null;
179
```
180
181
**Usage Examples:**
182
183
```typescript
184
import { hashFile } from "patch-package/dist/hash";
185
import { coerceSemVer } from "patch-package/dist/coerceSemVer";
186
187
// Generate file hash for validation
188
const patchHash = hashFile("patches/lodash+4.17.21.patch");
189
console.log(`Patch hash: ${patchHash}`);
190
191
// Coerce version to valid semver
192
const validVersion = coerceSemVer("1.0.0-beta.1+build.123");
193
// Returns: "1.0.0-beta.1"
194
195
const invalidVersion = coerceSemVer("not-a-version");
196
// Returns: null
197
198
// Use in state management
199
import { savePatchApplicationState } from "patch-package/dist/stateFile";
200
savePatchApplicationState({
201
packageDetails,
202
patches: [{
203
patchFilename: "lodash+4.17.21.patch",
204
patchContentHash: hashFile("patches/lodash+4.17.21.patch"),
205
didApply: true
206
}],
207
isRebasing: false
208
});
209
```
210
211
### Safe Process Execution
212
213
Secure process spawning for executing shell commands.
214
215
```typescript { .api }
216
/**
217
* Safely execute shell commands
218
* @param command - Command to execute
219
* @param args - Command arguments array
220
* @param options - Spawn options
221
* @returns Spawn result with status and output
222
*/
223
function spawnSafeSync(
224
command: string,
225
args?: string[],
226
options?: SpawnSafeOptions
227
): SpawnResult;
228
229
interface SpawnSafeOptions {
230
/** Current working directory */
231
cwd?: string;
232
/** Environment variables */
233
env?: Record<string, string>;
234
/** Input to pass to command */
235
input?: string | Buffer;
236
/** Stdio configuration */
237
stdio?: "pipe" | "inherit" | "ignore";
238
/** Timeout in milliseconds */
239
timeout?: number;
240
/** Kill signal */
241
killSignal?: string;
242
}
243
244
interface SpawnResult {
245
/** Exit status code */
246
status: number | null;
247
/** Kill signal if terminated */
248
signal: string | null;
249
/** Standard output */
250
stdout: Buffer;
251
/** Standard error */
252
stderr: Buffer;
253
}
254
```
255
256
**Usage Examples:**
257
258
```typescript
259
import { spawnSafeSync } from "patch-package/dist/spawnSafe";
260
261
// Execute git command safely
262
const result = spawnSafeSync("git", ["diff", "--no-index", "original", "modified"], {
263
cwd: "/path/to/package",
264
timeout: 30000
265
});
266
267
if (result.status === 0) {
268
const diff = result.stdout.toString();
269
console.log("Git diff output:", diff);
270
} else {
271
console.error("Git command failed:", result.stderr.toString());
272
}
273
```
274
275
## Regular Expression Utilities
276
277
### RegExp Creation
278
279
Utility for creating regular expressions with error handling and validation.
280
281
```typescript { .api }
282
/**
283
* Create RegExp with error handling and validation
284
* @param reString - Regular expression string
285
* @param name - Name for error reporting
286
* @param defaultValue - Default regex if parsing fails
287
* @param caseSensitive - Case sensitivity flag
288
* @returns Compiled regular expression
289
*/
290
function makeRegExp(
291
reString: string,
292
name: string,
293
defaultValue: RegExp,
294
caseSensitive: boolean
295
): RegExp;
296
```
297
298
**Usage Examples:**
299
300
```typescript
301
import { makeRegExp } from "patch-package/dist/makeRegExp";
302
303
// Create include pattern with error handling
304
const includePaths = makeRegExp(
305
"src/.*\\.(js|ts)$",
306
"include paths",
307
/.*/,
308
false
309
);
310
311
// Create exclude pattern
312
const excludePaths = makeRegExp(
313
"(test|spec|__tests__)/.*",
314
"exclude paths",
315
/^package\.json$/,
316
true // case sensitive
317
);
318
319
// Use in patch creation
320
import { makePatch } from "patch-package/dist/makePatch";
321
makePatch({
322
packagePathSpecifier: "my-package",
323
appPath: process.cwd(),
324
packageManager: "npm",
325
includePaths,
326
excludePaths,
327
// ... other options
328
});
329
```
330
331
## Type Safety Utilities
332
333
### Exhaustiveness Checking
334
335
TypeScript utility for exhaustive type checking.
336
337
```typescript { .api }
338
/**
339
* TypeScript exhaustiveness checking utility
340
* @param x - Value that should never be reached
341
* @throws Error if called (indicates missing case)
342
*/
343
function assertNever(x: never): never;
344
```
345
346
**Usage Examples:**
347
348
```typescript
349
import { assertNever } from "patch-package/dist/assertNever";
350
351
type PackageManager = "npm" | "yarn" | "npm-shrinkwrap";
352
353
function handlePackageManager(pm: PackageManager) {
354
switch (pm) {
355
case "npm":
356
return "Using npm";
357
case "yarn":
358
return "Using yarn";
359
case "npm-shrinkwrap":
360
return "Using npm-shrinkwrap";
361
default:
362
// TypeScript will ensure this is never reached
363
return assertNever(pm);
364
}
365
}
366
```
367
368
## State File Management
369
370
### State Persistence
371
372
Utilities for managing patch application state persistence.
373
374
```typescript { .api }
375
/** State file name constant */
376
const STATE_FILE_NAME: ".patch-package.json";
377
378
/**
379
* Get current patch application state
380
* @param packageDetails - Package details
381
* @returns Current state or null if none exists
382
*/
383
function getPatchApplicationState(packageDetails: PackageDetails): PatchApplicationState | null;
384
385
/**
386
* Save patch application state
387
* @param options - State save options
388
*/
389
function savePatchApplicationState(options: SaveStateOptions): void;
390
391
/**
392
* Clear patch application state
393
* @param packageDetails - Package details
394
*/
395
function clearPatchApplicationState(packageDetails: PackageDetails): void;
396
397
interface SaveStateOptions {
398
packageDetails: PackageDetails;
399
patches: PatchState[];
400
isRebasing: boolean;
401
}
402
403
interface PatchState {
404
patchFilename: string;
405
patchContentHash: string;
406
didApply: boolean;
407
}
408
409
interface PatchApplicationState {
410
version: number;
411
patches: PatchState[];
412
isRebasing: boolean;
413
}
414
```
415
416
## Complete Utility Integration Example
417
418
```typescript
419
import {
420
getPatchDetailsFromCliString,
421
parseNameAndVersion,
422
join,
423
resolve,
424
hashFile,
425
makeRegExp,
426
spawnSafeSync,
427
getPatchApplicationState,
428
savePatchApplicationState
429
} from "patch-package/dist";
430
431
// Complete workflow using utilities
432
async function processPackagePatch(packageName: string) {
433
// Parse package details
434
const packageDetails = getPatchDetailsFromCliString(packageName);
435
if (!packageDetails) {
436
throw new Error(`Invalid package: ${packageName}`);
437
}
438
439
// Build paths using cross-platform utilities
440
const patchDir = resolve("patches");
441
const patchPath = join(patchDir, `${packageName}+1.0.0.patch`);
442
443
// Create regex patterns with error handling
444
const includePaths = makeRegExp("src/.*\\.(js|ts)$", "include", /.*/, false);
445
const excludePaths = makeRegExp("test/.*", "exclude", /^package\.json$/, false);
446
447
// Check current state
448
const currentState = getPatchApplicationState(packageDetails);
449
450
// Generate file hash for validation
451
const patchHash = hashFile(patchPath);
452
453
// Execute git command safely
454
const gitResult = spawnSafeSync("git", ["status", "--porcelain"], {
455
cwd: packageDetails.path,
456
timeout: 10000
457
});
458
459
// Update state
460
savePatchApplicationState({
461
packageDetails,
462
patches: [{
463
patchFilename: `${packageName}+1.0.0.patch`,
464
patchContentHash: patchHash,
465
didApply: true
466
}],
467
isRebasing: false
468
});
469
470
return {
471
packageDetails,
472
patchPath,
473
currentState,
474
gitStatus: gitResult.stdout.toString()
475
};
476
}
477
```
478
479
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.