0
# Path Handling
1
2
Cross-platform path manipulation utilities that provide type-safe path operations and conversion between different path formats.
3
4
## Overview
5
6
The @yarnpkg/fslib package provides comprehensive path handling through two main utilities:
7
- `ppath` - Portable path utilities for cross-platform compatibility
8
- `npath` - Native path utilities with platform-specific behavior
9
10
## Core Types
11
12
### Path Types
13
14
```typescript { .api }
15
// Basic path types
16
type PortablePath = string & { readonly __portable_path__: unique symbol };
17
type NativePath = string & { readonly __native_path__: unique symbol };
18
type Filename = string & { readonly __filename__: unique symbol };
19
type Path = PortablePath | NativePath;
20
type FSPath<T> = T | number; // Path or file descriptor
21
22
// Path component types
23
interface ParsedPath<P extends Path> {
24
root: P;
25
dir: P;
26
base: Filename;
27
ext: string;
28
name: string;
29
}
30
31
interface FormatInputPathObject<P extends Path> {
32
root?: P;
33
dir?: P;
34
base?: Filename;
35
ext?: string;
36
name?: string;
37
}
38
```
39
40
## Portable Path Utilities (ppath)
41
42
The `ppath` utility provides cross-platform path operations that always use forward slashes as separators.
43
44
### Basic Operations
45
46
```typescript { .api }
47
import { ppath, type PortablePath } from '@yarnpkg/fslib';
48
49
// Join path segments
50
const joined = ppath.join('/base' as PortablePath, 'sub', 'file.txt');
51
// Result: '/base/sub/file.txt' as PortablePath
52
53
// Resolve to absolute path
54
const resolved = ppath.resolve('/current' as PortablePath, '../relative/path');
55
// Result: '/relative/path' as PortablePath
56
57
// Normalize path
58
const normalized = ppath.normalize('/path/./to/../file.txt' as PortablePath);
59
// Result: '/path/file.txt' as PortablePath
60
```
61
62
### Path Analysis
63
64
```typescript { .api }
65
import { ppath, type PortablePath } from '@yarnpkg/fslib';
66
67
// Check if path is absolute
68
const isAbsolute = ppath.isAbsolute('/absolute/path' as PortablePath);
69
// Result: true
70
71
// Get relative path between two paths
72
const relative = ppath.relative(
73
'/from/directory' as PortablePath,
74
'/to/file.txt' as PortablePath
75
);
76
// Result: '../to/file.txt' as PortablePath
77
78
// Check if one path contains another
79
const contains = ppath.contains(
80
'/parent' as PortablePath,
81
'/parent/child/file.txt' as PortablePath
82
);
83
// Result: true
84
```
85
86
### Path Components
87
88
```typescript { .api }
89
import { ppath, type PortablePath, type Filename } from '@yarnpkg/fslib';
90
91
const filePath = '/path/to/file.txt' as PortablePath;
92
93
// Get directory name
94
const dirname = ppath.dirname(filePath);
95
// Result: '/path/to' as PortablePath
96
97
// Get base name
98
const basename = ppath.basename(filePath);
99
// Result: 'file.txt' as Filename
100
101
const basenameNoExt = ppath.basename(filePath, '.txt');
102
// Result: 'file' as Filename
103
104
// Get file extension
105
const extension = ppath.extname(filePath);
106
// Result: '.txt'
107
```
108
109
### Path Parsing and Formatting
110
111
```typescript { .api }
112
import { ppath, type PortablePath } from '@yarnpkg/fslib';
113
114
// Parse path into components
115
const parsed = ppath.parse('/path/to/file.txt' as PortablePath);
116
// Result: {
117
// root: '/' as PortablePath,
118
// dir: '/path/to' as PortablePath,
119
// base: 'file.txt' as Filename,
120
// ext: '.txt',
121
// name: 'file'
122
// }
123
124
// Format path from components
125
const formatted = ppath.format({
126
dir: '/path/to' as PortablePath,
127
name: 'file',
128
ext: '.txt'
129
});
130
// Result: '/path/to/file.txt' as PortablePath
131
```
132
133
### Working Directory Operations
134
135
```typescript { .api }
136
import { ppath } from '@yarnpkg/fslib';
137
138
// Get current working directory
139
const cwd = ppath.cwd();
140
// Result: Current working directory as PortablePath
141
```
142
143
## Native Path Utilities (npath)
144
145
The `npath` utility provides platform-specific path operations and conversion utilities.
146
147
### Basic Operations
148
149
```typescript { .api }
150
import { npath, type NativePath } from '@yarnpkg/fslib';
151
152
// All standard path operations (same interface as ppath)
153
const joined = npath.join('/base' as NativePath, 'sub', 'file.txt');
154
const resolved = npath.resolve('/current' as NativePath, '../relative/path');
155
const normalized = npath.normalize('/path/./to/../file.txt' as NativePath);
156
```
157
158
### Path Conversion
159
160
```typescript { .api }
161
import { npath, type PortablePath, type NativePath } from '@yarnpkg/fslib';
162
163
// Convert portable path to native path
164
const portablePath = '/path/to/file.txt' as PortablePath;
165
const nativePath = npath.fromPortablePath(portablePath);
166
// On Windows: 'C:\\path\\to\\file.txt' as NativePath
167
// On Unix: '/path/to/file.txt' as NativePath
168
169
// Convert native path to portable path
170
const backToPortable = npath.toPortablePath(nativePath);
171
// Result: '/path/to/file.txt' as PortablePath
172
```
173
174
## Path Constants
175
176
### Portable Path Constants
177
178
```typescript { .api }
179
import { PortablePath } from '@yarnpkg/fslib';
180
181
// Root path
182
const root = PortablePath.root; // '/' as PortablePath
183
184
// Current directory
185
const dot = PortablePath.dot; // '.' as PortablePath
186
187
// Parent directory
188
const parent = PortablePath.parent; // '..' as PortablePath
189
```
190
191
### Filename Constants
192
193
```typescript { .api }
194
import { Filename } from '@yarnpkg/fslib';
195
196
// Common directory and file names
197
const home = Filename.home; // '~' as Filename
198
const nodeModules = Filename.nodeModules; // 'node_modules' as Filename
199
const packageJson = Filename.manifest; // 'package.json' as Filename
200
const yarnLock = Filename.lockfile; // 'yarn.lock' as Filename
201
202
// Yarn-specific files
203
const virtual = Filename.virtual; // '__virtual__' as Filename
204
const pnpCjs = Filename.pnpCjs; // '.pnp.cjs' as Filename
205
const pnpData = Filename.pnpData; // '.pnp.data.json' as Filename
206
const pnpLoader = Filename.pnpEsmLoader; // '.pnp.loader.mjs' as Filename
207
const yarnrc = Filename.rc; // '.yarnrc.yml' as Filename
208
const env = Filename.env; // '.env' as Filename
209
```
210
211
## Advanced Path Operations
212
213
### Generic Path Conversion
214
215
```typescript { .api }
216
import { convertPath, ppath, npath, type PortablePath, type NativePath } from '@yarnpkg/fslib';
217
218
// Convert between path types using utilities
219
const nativePath = '/some/path' as NativePath;
220
const portablePath = convertPath(ppath, nativePath);
221
// Result: '/some/path' as PortablePath
222
223
const backToNative = convertPath(npath, portablePath);
224
// Result: '/some/path' as NativePath (or platform-specific format)
225
```
226
227
### Path Validation and Safety
228
229
```typescript { .api }
230
import { ppath, type PortablePath } from '@yarnpkg/fslib';
231
232
// Check if path is contained within another path (security)
233
function isPathSafe(basePath: PortablePath, targetPath: PortablePath): boolean {
234
const resolved = ppath.resolve(basePath, targetPath);
235
return ppath.contains(basePath, resolved);
236
}
237
238
// Usage
239
const isAllowed = isPathSafe(
240
'/safe/directory' as PortablePath,
241
'relative/path/to/file.txt' as PortablePath
242
);
243
```
244
245
### Working with Path Collections
246
247
```typescript { .api }
248
import { ppath, type PortablePath } from '@yarnpkg/fslib';
249
250
// Find common ancestor path
251
function findCommonPath(paths: PortablePath[]): PortablePath {
252
if (paths.length === 0) return '/' as PortablePath;
253
254
let common = paths[0];
255
for (const path of paths.slice(1)) {
256
while (!ppath.contains(common, path) && !ppath.contains(path, common)) {
257
common = ppath.dirname(common);
258
}
259
}
260
return common;
261
}
262
263
// Usage
264
const commonPath = findCommonPath([
265
'/project/src/components/Button.tsx' as PortablePath,
266
'/project/src/utils/helpers.ts' as PortablePath,
267
'/project/src/types/index.ts' as PortablePath
268
]);
269
// Result: '/project/src' as PortablePath
270
```
271
272
## Integration Examples
273
274
### File System Integration
275
276
```typescript { .api }
277
import { xfs, ppath, type PortablePath } from '@yarnpkg/fslib';
278
279
// Combine path utilities with filesystem operations
280
async function processFileTree(basePath: PortablePath): Promise<void> {
281
const files = await xfs.readdirPromise(basePath, { withFileTypes: true });
282
283
for (const file of files) {
284
const fullPath = ppath.join(basePath, file.name);
285
286
if (file.isDirectory()) {
287
console.log(`Directory: ${ppath.relative(ppath.cwd(), fullPath)}`);
288
await processFileTree(fullPath);
289
} else {
290
const ext = ppath.extname(fullPath);
291
console.log(`File: ${file.name} (${ext})`);
292
}
293
}
294
}
295
```
296
297
### Cross-Platform Path Handling
298
299
```typescript { .api }
300
import { npath, ppath, type PortablePath, type NativePath } from '@yarnpkg/fslib';
301
302
// Handle paths from different sources
303
function normalizePath(inputPath: string): PortablePath {
304
// Assume input might be native or portable
305
try {
306
// Try to treat as native path and convert
307
const asNative = inputPath as NativePath;
308
return npath.toPortablePath(asNative);
309
} catch {
310
// Already portable or invalid
311
return ppath.normalize(inputPath as PortablePath);
312
}
313
}
314
315
// Usage with various input formats
316
const paths = [
317
'/unix/style/path',
318
'C:\\Windows\\Style\\Path',
319
'./relative/path',
320
'../parent/directory'
321
];
322
323
const normalized = paths.map(normalizePath);
324
```
325
326
## Related Documentation
327
328
- [Filesystem Abstractions](./filesystem-abstractions.md) - Core filesystem interfaces that use these path types
329
- [Filesystem Implementations](./filesystem-implementations.md) - Concrete filesystems working with paths
330
- [Advanced Features](./advanced-features.md) - Advanced operations using path utilities