1 | /// <reference types="node" />
|
2 | import * as fs from "fs";
|
3 | /**
|
4 | * Comparison options.
|
5 | */
|
6 | export interface Options {
|
7 | /**
|
8 | * Properties to be used in various extension points ie. result builder.
|
9 | */
|
10 | [key: string]: any;
|
11 | /**
|
12 | * Compares files by size. Defaults to 'false'.
|
13 | *
|
14 | * Usually one of `compareSize` or `compareContent` options has to be activated. Otherwise files are compared by name disregarding size or content.
|
15 | */
|
16 | compareSize?: boolean;
|
17 | /**
|
18 | * Compares files by content. Defaults to 'false'.
|
19 | *
|
20 | * Usually one of `compareSize` or `compareContent` options has to be activated. Otherwise files are compared by name disregarding size or content.
|
21 | */
|
22 | compareContent?: boolean;
|
23 | /**
|
24 | * Compares files by date of modification (stat.mtime). Defaults to 'false'.
|
25 | *
|
26 | * Also see {@link Options.dateTolerance}.
|
27 | */
|
28 | compareDate?: boolean;
|
29 | /**
|
30 | * Two files are considered to have the same date if the difference between their modification dates fits within date tolerance. Defaults to 1000 ms.
|
31 | */
|
32 | dateTolerance?: number;
|
33 | /**
|
34 | * Compares entries by symlink. Defaults to 'false'.
|
35 |
|
36 | * If this option is enabled two entries must have the same type in order to be considered equal.
|
37 | * They have to be either two fies, two directories or two symlinks.
|
38 | *
|
39 | * If left entry is a file and right entry is a symlink, they are considered distinct disregarding the content of the file.
|
40 | *
|
41 | * Further if both entries are symlinks they need to have the same link value. For example if one symlink points to '/x/b.txt' and the other to '/x/../x/b.txt' the symlinks are considered distinct even if they point to the same file.
|
42 | */
|
43 | compareSymlink?: boolean;
|
44 | /**
|
45 | * Skips sub directories. Defaults to 'false'.
|
46 | */
|
47 | skipSubdirs?: boolean;
|
48 | /**
|
49 | * Ignore empty directories. Defaults to 'false'.
|
50 | */
|
51 | skipEmptyDirs?: boolean;
|
52 | /**
|
53 | * Ignore symbolic links. Defaults to 'false'.
|
54 | */
|
55 | skipSymlinks?: boolean;
|
56 | /**
|
57 | * Ignores case when comparing names. Defaults to 'false'.
|
58 | */
|
59 | ignoreCase?: boolean;
|
60 | /**
|
61 | * Toggles presence of diffSet in output. If true, only statistics are provided. Use this when comparing large number of files to avoid out of memory situations. Defaults to 'false'.
|
62 | */
|
63 | noDiffSet?: boolean;
|
64 | /**
|
65 | * File name filter. Comma separated minimatch patterns. See [Glob patterns](https://github.com/gliviu/dir-compare#glob-patterns).
|
66 | */
|
67 | includeFilter?: string;
|
68 | /**
|
69 | * File/directory name exclude filter. Comma separated minimatch patterns. See [Glob patterns](https://github.com/gliviu/dir-compare#glob-patterns).
|
70 | */
|
71 | excludeFilter?: string;
|
72 | /**
|
73 | * Handle permission denied errors. Defaults to 'false'.
|
74 | *
|
75 | * By default when some entry cannot be read due to `EACCES` error the comparison will
|
76 | * stop immediately with an exception.
|
77 | *
|
78 | * If `handlePermissionDenied` is set to true the comparison will continue when unreadable entries are encountered.
|
79 | *
|
80 | * Offending entries will be reported within {@link Difference.permissionDeniedState}, {@link Difference.reason} and {@link Result.permissionDenied}.
|
81 | *
|
82 | * Lets consider we want to compare two identical folders `A` and `B` with `B/dir2` being unreadable for the current user.
|
83 | * ```
|
84 | * A B
|
85 | * ├── dir1 ├── dir1
|
86 | * ├──── file1 ├──── file1
|
87 | * ├── dir2 ├── dir2 (permission denied)
|
88 | * └─────file2 └─────file2
|
89 | * ```
|
90 | *
|
91 | * {@link Result.diffSet} will look like:
|
92 | *
|
93 | * |relativePath |path1 |path2 | state |reason |permissionDeniedState|
|
94 | * |--------------|---------|---------|------------|------------------------|---------------------|
|
95 | * |[/] |dir1 |dir1 |`equal` | | |
|
96 | * |[/dir1] |file1 |file1 |`equal` | | |
|
97 | * |[/] |dir2 |dir2 |`distinct` | `permission-denied` |`access-error-right` |
|
98 | * |[/dir2] |file2 |missing |`left` | | |
|
99 | *
|
100 | * And {@link Result.permissionDenied} statistics look like
|
101 | * ```json
|
102 | * {
|
103 | * leftPermissionDenied: 0,
|
104 | * rightPermissionDenied: 1,
|
105 | * distinctPermissionDenied: 0,
|
106 | * totalPermissionDenied: 1
|
107 | * }
|
108 | * ```
|
109 | */
|
110 | handlePermissionDenied?: boolean;
|
111 | /**
|
112 | * Extension point used for constructing the {@link Result} object.
|
113 | *
|
114 | * See [Result builder](https://github.com/gliviu/dir-compare#result-builder).
|
115 | */
|
116 | resultBuilder?: ResultBuilder;
|
117 | /**
|
118 | * Extension point used to perform sync file content comparison.
|
119 | *
|
120 | * See [File comparators](https://github.com/gliviu/dir-compare#file-content-comparators).
|
121 | */
|
122 | compareFileSync?: CompareFileSync;
|
123 | /**
|
124 | * Extension point used to perform async file content comparison.
|
125 | *
|
126 | * See [File comparators](https://github.com/gliviu/dir-compare#file-content-comparators).
|
127 | */
|
128 | compareFileAsync?: CompareFileAsync;
|
129 | /**
|
130 | * Extension point used to compare files or directories names.
|
131 | *
|
132 | * See [Name comparators](https://github.com/gliviu/dir-compare#name-comparators).
|
133 | */
|
134 | compareNameHandler?: CompareNameHandler;
|
135 | /**
|
136 | * Extension point used to control which files or directories should be included in the comparison.
|
137 | *
|
138 | * See [Glob filter](https://github.com/gliviu/dir-compare#glob-filter).
|
139 | */
|
140 | filterHandler?: FilterHandler;
|
141 | }
|
142 | /**
|
143 | * List of differences occurred during comparison.
|
144 | */
|
145 | export type DiffSet = Array<Difference>;
|
146 | /**
|
147 | * @internal
|
148 | */
|
149 | export type OptionalDiffSet = DiffSet | undefined;
|
150 | export type EntryOrigin = 'left' | 'right';
|
151 | export interface Entry {
|
152 | name: string;
|
153 | absolutePath: string;
|
154 | path: string;
|
155 | /**
|
156 | * Whether this entry originated from the left or the right dir.
|
157 | */
|
158 | origin: EntryOrigin;
|
159 | stat: fs.Stats;
|
160 | lstat: fs.Stats;
|
161 | isDirectory: boolean;
|
162 | isSymlink: boolean;
|
163 | isBrokenLink: boolean;
|
164 | /**
|
165 | * True when this entry is not readable.
|
166 | * This value is set only when {@link Options.handlePermissionDenied} is enabled.
|
167 | */
|
168 | isPermissionDenied: boolean;
|
169 | }
|
170 | /**
|
171 | * Comparison result.
|
172 | */
|
173 | export interface Result extends Statistics {
|
174 | /**
|
175 | * Detailed list of comparison results.
|
176 | * Present if {@link Options.noDiffSet} is false.
|
177 | */
|
178 | diffSet?: DiffSet;
|
179 | }
|
180 | /**
|
181 | * Basic statistics information. Does not have any computed fields.
|
182 | */
|
183 | export interface InitialStatistics {
|
184 | /**
|
185 | * Any property is allowed if default result builder is not used.
|
186 | */
|
187 | [key: string]: any;
|
188 | /**
|
189 | * Number of distinct entries.
|
190 | */
|
191 | distinct: number;
|
192 | /**
|
193 | * Number of equal entries.
|
194 | */
|
195 | equal: number;
|
196 | /**
|
197 | * Number of entries only in path1.
|
198 | */
|
199 | left: number;
|
200 | /**
|
201 | * Number of entries only in path2.
|
202 | */
|
203 | right: number;
|
204 | /**
|
205 | * Number of distinct files.
|
206 | */
|
207 | distinctFiles: number;
|
208 | /**
|
209 | * Number of equal files.
|
210 | */
|
211 | equalFiles: number;
|
212 | /**
|
213 | * Number of files only in path1.
|
214 | */
|
215 | leftFiles: number;
|
216 | /**
|
217 | * Number of files only in path2
|
218 | */
|
219 | rightFiles: number;
|
220 | /**
|
221 | * Number of distinct directories.
|
222 | */
|
223 | distinctDirs: number;
|
224 | /**
|
225 | * Number of equal directories.
|
226 | */
|
227 | equalDirs: number;
|
228 | /**
|
229 | * Number of directories only in path1.
|
230 | */
|
231 | leftDirs: number;
|
232 | /**
|
233 | * Number of directories only in path2.
|
234 | */
|
235 | rightDirs: number;
|
236 | /**
|
237 | * Stats about broken links.
|
238 | */
|
239 | brokenLinks: BrokenLinksStatistics;
|
240 | /**
|
241 | * Statistics available if 'compareSymlink' options is used.
|
242 | */
|
243 | symlinks?: SymlinkStatistics;
|
244 | /**
|
245 | * Stats about entries that could not be accessed.
|
246 | */
|
247 | permissionDenied: PermissionDeniedStatistics;
|
248 | }
|
249 | /**
|
250 | * In addition to fields inherited from {@link InitialStatistics} this class
|
251 | * adds fields computed at the final stage of the comparison.
|
252 | */
|
253 | export interface Statistics extends InitialStatistics {
|
254 | /**
|
255 | * True if directories are identical.
|
256 | */
|
257 | same: boolean;
|
258 | /**
|
259 | * Total number of differences (distinct+left+right).
|
260 | */
|
261 | differences: number;
|
262 | /**
|
263 | * Total number of entries (differences+equal).
|
264 | */
|
265 | total: number;
|
266 | /**
|
267 | * Total number of different files (distinctFiles+leftFiles+rightFiles).
|
268 | */
|
269 | differencesFiles: number;
|
270 | /**
|
271 | * Total number of files (differencesFiles+equalFiles).
|
272 | */
|
273 | totalFiles: number;
|
274 | /**
|
275 | * Total number of different directories (distinctDirs+leftDirs+rightDirs).
|
276 | */
|
277 | differencesDirs: number;
|
278 | /**
|
279 | * Total number of directories (differencesDirs+equalDirs).
|
280 | */
|
281 | totalDirs: number;
|
282 | }
|
283 | export interface BrokenLinksStatistics {
|
284 | /**
|
285 | * Number of broken links only in path1
|
286 | */
|
287 | leftBrokenLinks: number;
|
288 | /**
|
289 | * Number of broken links only in path2
|
290 | */
|
291 | rightBrokenLinks: number;
|
292 | /**
|
293 | * Number of broken links with same name appearing in both path1 and path2 (leftBrokenLinks + rightBrokenLinks + distinctBrokenLinks)
|
294 | */
|
295 | distinctBrokenLinks: number;
|
296 | /**
|
297 | * Total number of broken links
|
298 | */
|
299 | totalBrokenLinks: number;
|
300 | }
|
301 | export interface PermissionDeniedStatistics {
|
302 | /**
|
303 | * Number of forbidden entries found only in path1
|
304 | */
|
305 | leftPermissionDenied: number;
|
306 | /**
|
307 | * Number of forbidden entries found only in path2
|
308 | */
|
309 | rightPermissionDenied: number;
|
310 | /**
|
311 | * Number of forbidden entries with same name appearing in both path1 and path2 (leftPermissionDenied + rightPermissionDenied + distinctPermissionDenied)
|
312 | */
|
313 | distinctPermissionDenied: number;
|
314 | /**
|
315 | * Total number of forbidden entries
|
316 | */
|
317 | totalPermissionDenied: number;
|
318 | }
|
319 | export interface SymlinkStatistics {
|
320 | /**
|
321 | * Number of distinct links.
|
322 | */
|
323 | distinctSymlinks: number;
|
324 | /**
|
325 | * Number of equal links.
|
326 | */
|
327 | equalSymlinks: number;
|
328 | /**
|
329 | * Number of links only in path1.
|
330 | */
|
331 | leftSymlinks: number;
|
332 | /**
|
333 | * Number of links only in path2
|
334 | */
|
335 | rightSymlinks: number;
|
336 | /**
|
337 | * Total number of different links (distinctSymlinks+leftSymlinks+rightSymlinks).
|
338 | */
|
339 | differencesSymlinks: number;
|
340 | /**
|
341 | * Total number of links (differencesSymlinks+equalSymlinks).
|
342 | */
|
343 | totalSymlinks: number;
|
344 | }
|
345 | /**
|
346 | * State of left/right entries relative to each other.
|
347 | * * `equal` - Identical entries are found in both left/right dirs.
|
348 | * * `left` - Entry is found only in left dir.
|
349 | * * `right` - Entry is found only in right dir.
|
350 | * * `distinct` - Entries exist in both left/right dir but have different content. See {@link Difference.reason} to understan why entries are considered distinct.
|
351 | */
|
352 | export type DifferenceState = "equal" | "left" | "right" | "distinct";
|
353 | /**
|
354 | * Permission related state of left/right entries. Available only when {@link Options.handlePermissionDenied} is enabled.
|
355 | * * `access-ok` - Both entries are accessible.
|
356 | * * `access-error-both` - Neither entry can be accessed.
|
357 | * * `access-error-left` - Left entry cannot be accessed.
|
358 | * * `access-error-right` - Right entry cannot be accessed.
|
359 | */
|
360 | export type PermissionDeniedState = "access-ok" | "access-error-both" | "access-error-left" | "access-error-right";
|
361 | /**
|
362 | * Type of entry.
|
363 | */
|
364 | export type DifferenceType = "missing" | "file" | "directory" | "broken-link";
|
365 | /**
|
366 | * Provides reason when two identically named entries are distinct.
|
367 | *
|
368 | * Not available if entries are equal.
|
369 | *
|
370 | * * `different-size` - Files differ in size.
|
371 | * * `different-date - Entry dates are different. Used when {@link Options.compareDate} is `true`.
|
372 | * * `different-content` - File contents are different. Used when {@link Options.compareContent} is `true`.
|
373 | * * `broken-link` - Both left/right entries are broken links.
|
374 | * * `different-symlink` - Symlinks are different. See {@link Options.compareSymlink} for details.
|
375 | * * `permission-denied` - One or both left/right entries are not accessible. See {@link Options.handlePermissionDenied} for details.
|
376 | */
|
377 | export type Reason = undefined | "different-size" | "different-date" | "different-content" | "broken-link" | 'different-symlink' | 'permission-denied';
|
378 | export interface Difference {
|
379 | /**
|
380 | * Any property is allowed if default result builder is not used.
|
381 | */
|
382 | [key: string]: any;
|
383 | /**
|
384 | * Path not including file/directory name; can be relative or absolute depending on call to compare().
|
385 | * Is undefined if missing on the left side.
|
386 | */
|
387 | path1?: string;
|
388 | /**
|
389 | * Path not including file/directory name; can be relative or absolute depending on call to compare().
|
390 | * Is undefined if missing on the right side.
|
391 | */
|
392 | path2?: string;
|
393 | /**
|
394 | * Path relative to the root directory of the comparison.
|
395 | */
|
396 | relativePath: string;
|
397 | /**
|
398 | * Left file/directory name.
|
399 | * Is undefined if missing on the left side.
|
400 | */
|
401 | name1?: string;
|
402 | /**
|
403 | * Right file/directory name.
|
404 | * Is undefined if missing on the right side.
|
405 | */
|
406 | name2?: string;
|
407 | /**
|
408 | * See {@link DifferenceState}
|
409 | */
|
410 | state: DifferenceState;
|
411 | /**
|
412 | * Permission related state of left/right entries.
|
413 | */
|
414 | permissionDeniedState: PermissionDeniedState;
|
415 | /**
|
416 | * Type of left entry.
|
417 | * Is undefined if missing on the left side.
|
418 | */
|
419 | type1: DifferenceType;
|
420 | /**
|
421 | * Type of right entry.
|
422 | * Is undefined if missing on the right side.
|
423 | */
|
424 | type2: DifferenceType;
|
425 | /**
|
426 | * Left file size.
|
427 | * Is undefined if missing on the left side.
|
428 | */
|
429 | size1?: number;
|
430 | /**
|
431 | * Right file size.
|
432 | * Is undefined if missing on the right side.
|
433 | */
|
434 | size2?: number;
|
435 | /**
|
436 | * Left entry modification date (stat.mtime).
|
437 | * Is undefined if missing on the left side.
|
438 | */
|
439 | date1?: Date;
|
440 | /**
|
441 | * Right entry modification date (stat.mtime).
|
442 | * Is undefined if missing on the right side.
|
443 | */
|
444 | date2?: Date;
|
445 | /**
|
446 | * Depth level relative to root dir.
|
447 | */
|
448 | level: number;
|
449 | /**
|
450 | * Provides reason when two identically named entries are distinct.
|
451 | */
|
452 | reason: Reason;
|
453 | }
|
454 | /**
|
455 | * Extension point used for constructing the {@link Result} object.
|
456 | * Called for each compared entry pair.
|
457 | * Updates 'statistics' and 'diffSet'.
|
458 | * @param entry1 Left entry.
|
459 | * @param entry2 Right entry.
|
460 | * @param state See {@link DifferenceState}.
|
461 | * @param level Depth level relative to root dir.
|
462 | * @param relativePath Path relative to the root directory of the comparison.
|
463 | * @param statistics Statistics to be updated.
|
464 | * @param diffSet Status per each entry to be appended.
|
465 | * Do not append if {@link Options.noDiffSet} is false.
|
466 | * @param reason See {@link Reason}. Not available if entries are equal.
|
467 | */
|
468 | export type ResultBuilder = (entry1: Entry | undefined, entry2: Entry | undefined, state: DifferenceState, level: number, relativePath: string, options: Options, statistics: InitialStatistics, diffSet: DiffSet | undefined, reason: Reason | undefined, permissionDeniedState: PermissionDeniedState) => void;
|
469 | /**
|
470 | * Extension point used to perform sync file content comparison.
|
471 | */
|
472 | export type CompareFileSync = (path1: string, stat1: fs.Stats, path2: string, stat2: fs.Stats, options: Options) => boolean;
|
473 | /**
|
474 | * Extension point used to perform async file content comparison.
|
475 | */
|
476 | export type CompareFileAsync = (path1: string, stat1: fs.Stats, path2: string, stat2: fs.Stats, options: Options) => Promise<boolean>;
|
477 | export interface CompareFileHandler {
|
478 | compareSync: CompareFileSync;
|
479 | compareAsync: CompareFileAsync;
|
480 | }
|
481 | /**
|
482 | * Extension point used to compare files or directories names.
|
483 | * The comparison should be dependent on received options (ie. case sensitive, ...).
|
484 | * Returns 0 if names are identical, -1 if name1<name2, 1 if name1>name2.
|
485 | */
|
486 | export type CompareNameHandler = (name1: string, name2: string, options: Options) => 0 | 1 | -1;
|
487 | /**
|
488 | * Extension point used to control which files or directories should be included in the comparison.
|
489 | *
|
490 | * @param entry Filesystem entry to include or ignore.
|
491 | * @param relativePath Path relative to the root directory of the comparison. It depends on {@link Entry.origin}.
|
492 | * @param option Comparison options.
|
493 | * @returns Returns true if the entry is to be processed or false to ignore it.
|
494 | */
|
495 | export type FilterHandler = (entry: Entry, relativePath: string, options: Options) => boolean;
|
496 | export interface FileCompareHandlers {
|
497 | /**
|
498 | * Compares files based on their binary content.
|
499 | *
|
500 | * This is the default file content comparator.
|
501 | * It is used when {@link Options.compareContent} is true and custom file comparator
|
502 | * is not specified (ie. {@link Options.compareFileSync} or {@link Options.compareFileAsync} are 'undefined').
|
503 | */
|
504 | defaultFileCompare: CompareFileHandler;
|
505 | /**
|
506 | * Compares files line by line.
|
507 | *
|
508 | * These additional options are available:
|
509 | * * ignoreLineEnding - true/false (default: false) - Ignore cr/lf line endings
|
510 | * * ignoreWhiteSpaces - true/false (default: false) - Ignore white spaces at the beginning and ending of a line (similar to 'diff -b')
|
511 | * * ignoreAllWhiteSpaces - true/false (default: false) - Ignore all white space differences (similar to 'diff -w')
|
512 | * * ignoreEmptyLines - true/false (default: false) - Ignores differences caused by empty lines (similar to 'diff -B')
|
513 | */
|
514 | lineBasedFileCompare: CompareFileHandler;
|
515 | }
|
516 | export interface CompareNameHandlers {
|
517 | /**
|
518 | * Compares file or directory names using the 'strcmp' function.
|
519 | * It is used if {@link Options.compareNameHandler} is not specified.
|
520 | */
|
521 | defaultNameCompare: CompareNameHandler;
|
522 | }
|
523 | export interface FilterHandlers {
|
524 | /**
|
525 | * Uses minimatch to include/ignore files based on {@link Options.includeFilter} and {@link Options.excludeFilter}.
|
526 | * It is used if {@link Options.filterHandler} is not specified.
|
527 | */
|
528 | defaultFilterHandler: FilterHandler;
|
529 | }
|
530 | //# sourceMappingURL=types.d.ts.map |
\ | No newline at end of file |