0
# File System Metadata
1
2
Cached filesystem metadata operations providing efficient access to file statistics, symbolic link resolution, and real path determination. All operations cache results to minimize expensive filesystem calls.
3
4
## Capabilities
5
6
### File Statistics (lstat)
7
8
Get file metadata similar to Node's `fs.lstat()` but with caching and simplified return values.
9
10
```typescript { .api }
11
/**
12
* Get file statistics asynchronously
13
* @param entry - Path to analyze (defaults to current working directory)
14
* @returns Promise resolving to Path object with metadata, or undefined if error
15
*/
16
lstat(entry?: string | PathBase): Promise<PathBase | undefined>;
17
18
/**
19
* Get file statistics synchronously
20
* @param entry - Path to analyze (defaults to current working directory)
21
* @returns Path object with metadata, or undefined if error
22
*/
23
lstatSync(entry?: string | PathBase): PathBase | undefined;
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { PathScurry } from "path-scurry";
30
31
const pw = new PathScurry();
32
33
// Async lstat
34
const fileInfo = await pw.lstat("package.json");
35
if (fileInfo) {
36
console.log(`File type: ${fileInfo.getType()}`);
37
console.log(`Size: ${fileInfo.size} bytes`);
38
console.log(`Modified: ${fileInfo.mtime}`);
39
console.log(`Is file: ${fileInfo.isFile()}`);
40
} else {
41
console.log("File does not exist or cannot be accessed");
42
}
43
44
// Sync lstat
45
const dirInfo = pw.lstatSync("./src");
46
if (dirInfo?.isDirectory()) {
47
console.log(`Directory depth: ${dirInfo.depth()}`);
48
}
49
50
// Using Path objects directly
51
const path = pw.cwd.resolve("./config.json");
52
const stats = await path.lstat();
53
if (stats) {
54
console.log(`Full path: ${stats.fullpath()}`);
55
console.log(`Is symlink: ${stats.isSymbolicLink()}`);
56
}
57
```
58
59
### Symbolic Link Resolution (readlink)
60
61
Resolve symbolic links to their target paths with optional return format control.
62
63
```typescript { .api }
64
/**
65
* Read symbolic link target asynchronously
66
* @param entry - Symbolic link to resolve (defaults to current working directory)
67
* @param opt - Control return format (Path object vs string)
68
* @returns Promise resolving to link target or undefined if not a symlink/error
69
*/
70
readlink(): Promise<string | undefined>;
71
readlink(opt: { withFileTypes: false }): Promise<string | undefined>;
72
readlink(opt: { withFileTypes: true }): Promise<PathBase | undefined>;
73
readlink(opt: { withFileTypes: boolean }): Promise<PathBase | string | undefined>;
74
readlink(entry: string | PathBase, opt?: { withFileTypes: false }): Promise<string | undefined>;
75
readlink(entry: string | PathBase, opt: { withFileTypes: true }): Promise<PathBase | undefined>;
76
readlink(entry: string | PathBase, opt: { withFileTypes: boolean }): Promise<string | PathBase | undefined>;
77
78
/**
79
* Read symbolic link target synchronously
80
* @param entry - Symbolic link to resolve
81
* @param opt - Control return format (Path object vs string)
82
* @returns Link target or undefined if not a symlink/error
83
*/
84
readlinkSync(entry?: string | PathBase): string | undefined;
85
readlinkSync(opt: { withFileTypes: false }): string | undefined;
86
readlinkSync(opt: { withFileTypes: true }): PathBase | undefined;
87
readlinkSync(opt: { withFileTypes: boolean }): PathBase | string | undefined;
88
readlinkSync(entry: string | PathBase, opt?: { withFileTypes: false }): string | undefined;
89
readlinkSync(entry: string | PathBase, opt: { withFileTypes: true }): PathBase | undefined;
90
readlinkSync(entry: string | PathBase, opt: { withFileTypes: boolean }): string | PathBase | undefined;
91
```
92
93
**Usage Examples:**
94
95
```typescript
96
const pw = new PathScurry();
97
98
// Read symlink target as string
99
const target = await pw.readlink("./symlink-to-file");
100
if (target) {
101
console.log(`Symlink points to: ${target}`);
102
}
103
104
// Read symlink target as Path object
105
const targetPath = await pw.readlink("./symlink-to-dir", { withFileTypes: true });
106
if (targetPath) {
107
console.log(`Target is directory: ${targetPath.isDirectory()}`);
108
console.log(`Target full path: ${targetPath.fullpath()}`);
109
}
110
111
// Using Path objects directly
112
const link = pw.cwd.resolve("./some-symlink");
113
if (link.canReadlink()) {
114
const resolved = await link.readlink();
115
if (resolved) {
116
console.log(`Link resolved to: ${resolved.fullpath()}`);
117
}
118
}
119
120
// Sync version
121
const syncTarget = pw.readlinkSync("./another-link");
122
if (syncTarget) {
123
console.log(`Synchronous readlink result: ${syncTarget}`);
124
}
125
```
126
127
### Real Path Resolution (realpath)
128
129
Resolve paths to their canonical absolute form, following all symbolic links.
130
131
```typescript { .api }
132
/**
133
* Resolve path to canonical absolute form asynchronously
134
* @param entry - Path to resolve (defaults to current working directory)
135
* @param opt - Control return format (Path object vs string)
136
* @returns Promise resolving to canonical path or undefined if error
137
*/
138
realpath(): Promise<string | undefined>;
139
realpath(opt: { withFileTypes: false }): Promise<string | undefined>;
140
realpath(opt: { withFileTypes: true }): Promise<PathBase | undefined>;
141
realpath(opt: { withFileTypes: boolean }): Promise<PathBase | string | undefined>;
142
realpath(entry: string | PathBase, opt?: { withFileTypes: false }): Promise<string | undefined>;
143
realpath(entry: string | PathBase, opt: { withFileTypes: true }): Promise<PathBase | undefined>;
144
realpath(entry: string | PathBase, opt: { withFileTypes: boolean }): Promise<string | PathBase | undefined>;
145
146
/**
147
* Resolve path to canonical absolute form synchronously
148
* @param entry - Path to resolve
149
* @param opt - Control return format (Path object vs string)
150
* @returns Canonical path or undefined if error
151
*/
152
realpathSync(): string | undefined;
153
realpathSync(opt: { withFileTypes: false }): string | undefined;
154
realpathSync(opt: { withFileTypes: true }): PathBase | undefined;
155
realpathSync(opt: { withFileTypes: boolean }): PathBase | string | undefined;
156
realpathSync(entry: string | PathBase, opt?: { withFileTypes: false }): string | undefined;
157
realpathSync(entry: string | PathBase, opt: { withFileTypes: true }): PathBase | undefined;
158
realpathSync(entry: string | PathBase, opt: { withFileTypes: boolean }): string | PathBase | undefined;
159
```
160
161
**Usage Examples:**
162
163
```typescript
164
const pw = new PathScurry();
165
166
// Resolve real path as string
167
const real = await pw.realpath("./some/path/with/symlinks");
168
if (real) {
169
console.log(`Real path: ${real}`);
170
}
171
172
// Resolve real path as Path object
173
const realPath = await pw.realpath("./complex/symlink/chain", { withFileTypes: true });
174
if (realPath) {
175
console.log(`Real path exists: ${!realPath.isENOENT()}`);
176
console.log(`Real path type: ${realPath.getType()}`);
177
}
178
179
// Direct Path object usage
180
const path = pw.cwd.resolve("./might-be-symlink");
181
const resolved = await path.realpath();
182
if (resolved) {
183
console.log(`Canonical path: ${resolved.fullpath()}`);
184
if (resolved !== path) {
185
console.log("Path was resolved through symlinks");
186
}
187
}
188
189
// Sync version
190
const syncReal = pw.realpathSync("./symlinked-directory");
191
if (syncReal) {
192
console.log(`Sync realpath: ${syncReal}`);
193
}
194
```
195
196
### Path Object Metadata Methods
197
198
Metadata operations available directly on Path objects with additional caching checks.
199
200
```typescript { .api }
201
/**
202
* Get cached lstat result without filesystem access
203
* @returns Path object if lstat has been called, undefined otherwise
204
*/
205
lstatCached(): PathBase | undefined;
206
207
/**
208
* Get cached readlink result without filesystem access
209
* @returns Cached link target or undefined if not cached
210
*/
211
readlinkCached(): PathBase | undefined;
212
213
/**
214
* Get cached realpath result without filesystem access
215
* @returns Cached real path or undefined if not cached
216
*/
217
realpathCached(): PathBase | undefined;
218
219
/**
220
* Check if readlink operation is likely to succeed
221
* @returns True if path might be a readable symbolic link
222
*/
223
canReadlink(): boolean;
224
225
/**
226
* Check if path is known to not exist
227
* @returns True if previous operations determined path doesn't exist
228
*/
229
isENOENT(): boolean;
230
```
231
232
**Usage Examples:**
233
234
```typescript
235
const path = pw.cwd.resolve("./some-file");
236
237
// Check cached status before expensive operations
238
const cachedStats = path.lstatCached();
239
if (cachedStats) {
240
console.log("Already have stats:", cachedStats.getType());
241
} else {
242
const stats = await path.lstat();
243
console.log("Fetched stats:", stats?.getType());
244
}
245
246
// Check if path is worth reading as symlink
247
if (path.canReadlink()) {
248
const target = await path.readlink();
249
console.log("Symlink target:", target?.fullpath());
250
} else {
251
console.log("Not a symlink or readlink would fail");
252
}
253
254
// Check existence status
255
if (path.isENOENT()) {
256
console.log("Path is known to not exist");
257
} else {
258
console.log("Path might exist (or status unknown)");
259
}
260
```
261
262
### Available Statistics Properties
263
264
Path objects expose filesystem statistics after successful `lstat()` calls:
265
266
```typescript { .api }
267
interface PathBase {
268
// File system statistics (available after lstat)
269
readonly dev?: number; // Device ID
270
readonly mode?: number; // File mode
271
readonly nlink?: number; // Number of hard links
272
readonly uid?: number; // User ID
273
readonly gid?: number; // Group ID
274
readonly rdev?: number; // Device ID (special files)
275
readonly blksize?: number; // Block size
276
readonly ino?: number; // Inode number
277
readonly size?: number; // File size in bytes
278
readonly blocks?: number; // Number of blocks
279
readonly atimeMs?: number; // Access time (milliseconds)
280
readonly mtimeMs?: number; // Modification time (milliseconds)
281
readonly ctimeMs?: number; // Status change time (milliseconds)
282
readonly birthtimeMs?: number; // Creation time (milliseconds)
283
readonly atime?: Date; // Access time
284
readonly mtime?: Date; // Modification time
285
readonly ctime?: Date; // Status change time
286
readonly birthtime?: Date; // Creation time
287
}
288
```
289
290
**Usage Example:**
291
292
```typescript
293
const fileInfo = await pw.lstat("./large-file.dat");
294
if (fileInfo) {
295
console.log(`File size: ${fileInfo.size} bytes`);
296
console.log(`Last modified: ${fileInfo.mtime}`);
297
console.log(`Inode: ${fileInfo.ino}`);
298
console.log(`Mode: ${fileInfo.mode?.toString(8)}`); // Octal permissions
299
}
300
```