UNPKG

23.6 kBMarkdownView Raw
1# fast-glob
2
3> It's a very fast and efficient [glob][glob_definition] library for [Node.js][node_js].
4
5This package provides methods for traversing the file system and returning pathnames that matched a defined set of a specified pattern according to the rules used by the Unix Bash shell with some simplifications, meanwhile results are returned in **arbitrary order**. Quick, simple, effective.
6
7## Table of Contents
8
9<details>
10<summary><strong>Details</strong></summary>
11
12* [Highlights](#highlights)
13* [Donation](#donation)
14* [Old and modern mode](#old-and-modern-mode)
15* [Pattern syntax](#pattern-syntax)
16 * [Basic syntax](#basic-syntax)
17 * [Advanced syntax](#advanced-syntax)
18* [Installation](#installation)
19* [API](#api)
20 * [Asynchronous](#asynchronous)
21 * [Synchronous](#synchronous)
22 * [Stream](#stream)
23 * [patterns](#patterns)
24 * [[options]](#options)
25 * [Helpers](#helpers)
26 * [generateTasks](#generatetaskspatterns-options)
27 * [isDynamicPattern](#isdynamicpatternpattern-options)
28 * [escapePath](#escapepathpattern)
29* [Options](#options-3)
30 * [Common](#common)
31 * [concurrency](#concurrency)
32 * [cwd](#cwd)
33 * [deep](#deep)
34 * [followSymbolicLinks](#followsymboliclinks)
35 * [fs](#fs)
36 * [ignore](#ignore)
37 * [suppressErrors](#suppresserrors)
38 * [throwErrorOnBrokenSymbolicLink](#throwerroronbrokensymboliclink)
39 * [Output control](#output-control)
40 * [absolute](#absolute)
41 * [markDirectories](#markdirectories)
42 * [objectMode](#objectmode)
43 * [onlyDirectories](#onlydirectories)
44 * [onlyFiles](#onlyfiles)
45 * [stats](#stats)
46 * [unique](#unique)
47 * [Matching control](#matching-control)
48 * [braceExpansion](#braceexpansion)
49 * [caseSensitiveMatch](#casesensitivematch)
50 * [dot](#dot)
51 * [extglob](#extglob)
52 * [globstar](#globstar)
53 * [baseNameMatch](#basenamematch)
54* [FAQ](#faq)
55 * [What is a static or dynamic pattern?](#what-is-a-static-or-dynamic-pattern)
56 * [How to write patterns on Windows?](#how-to-write-patterns-on-windows)
57 * [Why are parentheses match wrong?](#why-are-parentheses-match-wrong)
58 * [How to exclude directory from reading?](#how-to-exclude-directory-from-reading)
59 * [How to use UNC path?](#how-to-use-unc-path)
60 * [Compatible with `node-glob`?](#compatible-with-node-glob)
61* [Benchmarks](#benchmarks)
62 * [Server](#server)
63 * [Nettop](#nettop)
64* [Changelog](#changelog)
65* [License](#license)
66
67</details>
68
69## Highlights
70
71* Fast. Probably the fastest.
72* Supports multiple and negative patterns.
73* Synchronous, Promise and Stream API.
74* Object mode. Can return more than just strings.
75* Error-tolerant.
76
77## Donation
78
79Do you like this project? Support it by donating, creating an issue or pull request.
80
81[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)][paypal_mrmlnc]
82
83## Old and modern mode
84
85This package works in two modes, depending on the environment in which it is used.
86
87* **Old mode**. Node.js below 10.10 or when the [`stats`](#stats) option is *enabled*.
88* **Modern mode**. Node.js 10.10+ and the [`stats`](#stats) option is *disabled*.
89
90The modern mode is faster. Learn more about the [internal mechanism][nodelib_fs_scandir_old_and_modern_modern].
91
92## Pattern syntax
93
94> :warning: Always use forward-slashes in glob expressions (patterns and [`ignore`](#ignore) option). Use backslashes for escaping characters.
95
96There is more than one form of syntax: basic and advanced. Below is a brief overview of the supported features. Also pay attention to our [FAQ](#faq).
97
98> :book: This package uses a [`micromatch`][micromatch] as a library for pattern matching.
99
100### Basic syntax
101
102* An asterisk (`*`) — matches everything except slashes (path separators), hidden files (names starting with `.`).
103* A double star or globstar (`**`) — matches zero or more directories.
104* Question mark (`?`) – matches any single character except slashes (path separators).
105* Sequence (`[seq]`) — matches any character in sequence.
106
107> :book: A few additional words about the [basic matching behavior][picomatch_matching_behavior].
108
109Some examples:
110
111* `src/**/*.js` — matches all files in the `src` directory (any level of nesting) that have the `.js` extension.
112* `src/*.??` — matches all files in the `src` directory (only first level of nesting) that have a two-character extension.
113* `file-[01].js` — matches files: `file-0.js`, `file-1.js`.
114
115### Advanced syntax
116
117* [Escapes characters][micromatch_backslashes] (`\\`) — matching special characters (`$^*+?()[]`) as literals.
118* [POSIX character classes][picomatch_posix_brackets] (`[[:digit:]]`).
119* [Extended globs][micromatch_extglobs] (`?(pattern-list)`).
120* [Bash style brace expansions][micromatch_braces] (`{}`).
121* [Regexp character classes][micromatch_regex_character_classes] (`[1-5]`).
122* [Regex groups][regular_expressions_brackets] (`(a|b)`).
123
124> :book: A few additional words about the [advanced matching behavior][micromatch_extended_globbing].
125
126Some examples:
127
128* `src/**/*.{css,scss}` — matches all files in the `src` directory (any level of nesting) that have the `.css` or `.scss` extension.
129* `file-[[:digit:]].js` — matches files: `file-0.js`, `file-1.js`, …, `file-9.js`.
130* `file-{1..3}.js` — matches files: `file-1.js`, `file-2.js`, `file-3.js`.
131* `file-(1|2)` — matches files: `file-1.js`, `file-2.js`.
132
133## Installation
134
135```console
136npm install fast-glob
137```
138
139## API
140
141### Asynchronous
142
143```js
144fg(patterns, [options])
145```
146
147Returns a `Promise` with an array of matching entries.
148
149```js
150const fg = require('fast-glob');
151
152const entries = await fg(['.editorconfig', '**/index.js'], { dot: true });
153
154// ['.editorconfig', 'services/index.js']
155```
156
157### Synchronous
158
159```js
160fg.sync(patterns, [options])
161```
162
163Returns an array of matching entries.
164
165```js
166const fg = require('fast-glob');
167
168const entries = fg.sync(['.editorconfig', '**/index.js'], { dot: true });
169
170// ['.editorconfig', 'services/index.js']
171```
172
173### Stream
174
175```js
176fg.stream(patterns, [options])
177```
178
179Returns a [`ReadableStream`][node_js_stream_readable_streams] when the `data` event will be emitted with matching entry.
180
181```js
182const fg = require('fast-glob');
183
184const stream = fg.stream(['.editorconfig', '**/index.js'], { dot: true });
185
186for await (const entry of stream) {
187 // .editorconfig
188 // services/index.js
189}
190```
191
192#### patterns
193
194* Required: `true`
195* Type: `string | string[]`
196
197Any correct pattern(s).
198
199> :1234: [Pattern syntax](#pattern-syntax)
200>
201> :warning: This package does not respect the order of patterns. First, all the negative patterns are applied, and only then the positive patterns. If you want to get a certain order of records, use sorting or split calls.
202
203#### [options]
204
205* Required: `false`
206* Type: [`Options`](#options-3)
207
208See [Options](#options-3) section.
209
210### Helpers
211
212#### `generateTasks(patterns, [options])`
213
214Returns the internal representation of patterns ([`Task`](./src/managers/tasks.ts) is a combining patterns by base directory).
215
216```js
217fg.generateTasks('*');
218
219[{
220 base: '.', // Parent directory for all patterns inside this task
221 dynamic: true, // Dynamic or static patterns are in this task
222 patterns: ['*'],
223 positive: ['*'],
224 negative: []
225}]
226```
227
228##### patterns
229
230* Required: `true`
231* Type: `string | string[]`
232
233Any correct pattern(s).
234
235##### [options]
236
237* Required: `false`
238* Type: [`Options`](#options-3)
239
240See [Options](#options-3) section.
241
242#### `isDynamicPattern(pattern, [options])`
243
244Returns `true` if the passed pattern is a dynamic pattern.
245
246> :1234: [What is a static or dynamic pattern?](#what-is-a-static-or-dynamic-pattern)
247
248```js
249fg.isDynamicPattern('*'); // true
250fg.isDynamicPattern('abc'); // false
251```
252
253##### pattern
254
255* Required: `true`
256* Type: `string`
257
258Any correct pattern.
259
260##### [options]
261
262* Required: `false`
263* Type: [`Options`](#options-3)
264
265See [Options](#options-3) section.
266
267#### `escapePath(pattern)`
268
269Returns a path with escaped special characters (`*?|(){}[]`, `!` at the beginning of line, `@+!` before the opening parenthesis).
270
271```js
272fg.escapePath('!abc'); // \\!abc
273fg.escapePath('C:/Program Files (x86)'); // C:/Program Files \\(x86\\)
274```
275
276##### pattern
277
278* Required: `true`
279* Type: `string`
280
281Any string, for example, a path to a file.
282
283## Options
284
285### Common options
286
287#### concurrency
288
289* Type: `number`
290* Default: `os.cpus().length`
291
292Specifies the maximum number of concurrent requests from a reader to read directories.
293
294> :book: The higher the number, the higher the performance and load on the file system. If you want to read in quiet mode, set the value to a comfortable number or `1`.
295
296#### cwd
297
298* Type: `string`
299* Default: `process.cwd()`
300
301The current working directory in which to search.
302
303#### deep
304
305* Type: `number`
306* Default: `Infinity`
307
308Specifies the maximum depth of a read directory relative to the start directory.
309
310For example, you have the following tree:
311
312```js
313dir/
314└── one/ // 1
315 └── two/ // 2
316 └── file.js // 3
317```
318
319```js
320// With base directory
321fg.sync('dir/**', { onlyFiles: false, deep: 1 }); // ['dir/one']
322fg.sync('dir/**', { onlyFiles: false, deep: 2 }); // ['dir/one', 'dir/one/two']
323
324// With cwd option
325fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 1 }); // ['one']
326fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 2 }); // ['one', 'one/two']
327```
328
329> :book: If you specify a pattern with some base directory, this directory will not participate in the calculation of the depth of the found directories. Think of it as a [`cwd`](#cwd) option.
330
331#### followSymbolicLinks
332
333* Type: `boolean`
334* Default: `true`
335
336Indicates whether to traverse descendants of symbolic link directories when expanding `**` patterns.
337
338> :book: Note that this option does not affect the base directory of the pattern. For example, if `./a` is a symlink to directory `./b` and you specified `['./a**', './b/**']` patterns, then directory `./a` will still be read.
339
340> :book: If the [`stats`](#stats) option is specified, the information about the symbolic link (`fs.lstat`) will be replaced with information about the entry (`fs.stat`) behind it.
341
342#### fs
343
344* Type: `FileSystemAdapter`
345* Default: `fs.*`
346
347Custom implementation of methods for working with the file system.
348
349```ts
350export interface FileSystemAdapter {
351 lstat?: typeof fs.lstat;
352 stat?: typeof fs.stat;
353 lstatSync?: typeof fs.lstatSync;
354 statSync?: typeof fs.statSync;
355 readdir?: typeof fs.readdir;
356 readdirSync?: typeof fs.readdirSync;
357}
358```
359
360#### ignore
361
362* Type: `string[]`
363* Default: `[]`
364
365An array of glob patterns to exclude matches. This is an alternative way to use negative patterns.
366
367```js
368dir/
369├── package-lock.json
370└── package.json
371```
372
373```js
374fg.sync(['*.json', '!package-lock.json']); // ['package.json']
375fg.sync('*.json', { ignore: ['package-lock.json'] }); // ['package.json']
376```
377
378#### suppressErrors
379
380* Type: `boolean`
381* Default: `false`
382
383By default this package suppress only `ENOENT` errors. Set to `true` to suppress any error.
384
385> :book: Can be useful when the directory has entries with a special level of access.
386
387#### throwErrorOnBrokenSymbolicLink
388
389* Type: `boolean`
390* Default: `false`
391
392Throw an error when symbolic link is broken if `true` or safely return `lstat` call if `false`.
393
394> :book: This option has no effect on errors when reading the symbolic link directory.
395
396### Output control
397
398#### absolute
399
400* Type: `boolean`
401* Default: `false`
402
403Return the absolute path for entries.
404
405```js
406fg.sync('*.js', { absolute: false }); // ['index.js']
407fg.sync('*.js', { absolute: true }); // ['/home/user/index.js']
408```
409
410> :book: This option is required if you want to use negative patterns with absolute path, for example, `!${__dirname}/*.js`.
411
412#### markDirectories
413
414* Type: `boolean`
415* Default: `false`
416
417Mark the directory path with the final slash.
418
419```js
420fg.sync('*', { onlyFiles: false, markDirectories: false }); // ['index.js', 'controllers']
421fg.sync('*', { onlyFiles: false, markDirectories: true }); // ['index.js', 'controllers/']
422```
423
424#### objectMode
425
426* Type: `boolean`
427* Default: `false`
428
429Returns objects (instead of strings) describing entries.
430
431```js
432fg.sync('*', { objectMode: false }); // ['src/index.js']
433fg.sync('*', { objectMode: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent> }]
434```
435
436The object has the following fields:
437
438* name (`string`) — the last part of the path (basename)
439* path (`string`) — full path relative to the pattern base directory
440* dirent ([`fs.Dirent`][node_js_fs_class_fs_dirent]) — instance of `fs.Dirent`
441
442> :book: An object is an internal representation of entry, so getting it does not affect performance.
443
444#### onlyDirectories
445
446* Type: `boolean`
447* Default: `false`
448
449Return only directories.
450
451```js
452fg.sync('*', { onlyDirectories: false }); // ['index.js', 'src']
453fg.sync('*', { onlyDirectories: true }); // ['src']
454```
455
456> :book: If `true`, the [`onlyFiles`](#onlyfiles) option is automatically `false`.
457
458#### onlyFiles
459
460* Type: `boolean`
461* Default: `true`
462
463Return only files.
464
465```js
466fg.sync('*', { onlyFiles: false }); // ['index.js', 'src']
467fg.sync('*', { onlyFiles: true }); // ['index.js']
468```
469
470#### stats
471
472* Type: `boolean`
473* Default: `false`
474
475Enables an [object mode](#objectmode) with an additional field:
476
477* stats ([`fs.Stats`][node_js_fs_class_fs_stats]) — instance of `fs.Stats`
478
479```js
480fg.sync('*', { stats: false }); // ['src/index.js']
481fg.sync('*', { stats: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent>, stats: <fs.Stats> }]
482```
483
484> :book: Returns `fs.stat` instead of `fs.lstat` for symbolic links when the [`followSymbolicLinks`](#followsymboliclinks) option is specified.
485>
486> :warning: Unlike [object mode](#objectmode) this mode requires additional calls to the file system. On average, this mode is slower at least twice. See [old and modern mode](#old-and-modern-mode) for more details.
487
488#### unique
489
490* Type: `boolean`
491* Default: `true`
492
493Ensures that the returned entries are unique.
494
495```js
496fg.sync(['*.json', 'package.json'], { unique: false }); // ['package.json', 'package.json']
497fg.sync(['*.json', 'package.json'], { unique: true }); // ['package.json']
498```
499
500If `true` and similar entries are found, the result is the first found.
501
502### Matching control
503
504#### braceExpansion
505
506* Type: `boolean`
507* Default: `true`
508
509Enables Bash-like brace expansion.
510
511> :1234: [Syntax description][bash_hackers_syntax_expansion_brace] or more [detailed description][micromatch_braces].
512
513```js
514dir/
515├── abd
516├── acd
517└── a{b,c}d
518```
519
520```js
521fg.sync('a{b,c}d', { braceExpansion: false }); // ['a{b,c}d']
522fg.sync('a{b,c}d', { braceExpansion: true }); // ['abd', 'acd']
523```
524
525#### caseSensitiveMatch
526
527* Type: `boolean`
528* Default: `true`
529
530Enables a [case-sensitive][wikipedia_case_sensitivity] mode for matching files.
531
532```js
533dir/
534├── file.txt
535└── File.txt
536```
537
538```js
539fg.sync('file.txt', { caseSensitiveMatch: false }); // ['file.txt', 'File.txt']
540fg.sync('file.txt', { caseSensitiveMatch: true }); // ['file.txt']
541```
542
543#### dot
544
545* Type: `boolean`
546* Default: `false`
547
548Allow patterns to match entries that begin with a period (`.`).
549
550> :book: Note that an explicit dot in a portion of the pattern will always match dot files.
551
552```js
553dir/
554├── .editorconfig
555└── package.json
556```
557
558```js
559fg.sync('*', { dot: false }); // ['package.json']
560fg.sync('*', { dot: true }); // ['.editorconfig', 'package.json']
561```
562
563#### extglob
564
565* Type: `boolean`
566* Default: `true`
567
568Enables Bash-like `extglob` functionality.
569
570> :1234: [Syntax description][micromatch_extglobs].
571
572```js
573dir/
574├── README.md
575└── package.json
576```
577
578```js
579fg.sync('*.+(json|md)', { extglob: false }); // []
580fg.sync('*.+(json|md)', { extglob: true }); // ['README.md', 'package.json']
581```
582
583#### globstar
584
585* Type: `boolean`
586* Default: `true`
587
588Enables recursively repeats a pattern containing `**`. If `false`, `**` behaves exactly like `*`.
589
590```js
591dir/
592└── a
593 └── b
594```
595
596```js
597fg.sync('**', { onlyFiles: false, globstar: false }); // ['a']
598fg.sync('**', { onlyFiles: false, globstar: true }); // ['a', 'a/b']
599```
600
601#### baseNameMatch
602
603* Type: `boolean`
604* Default: `false`
605
606If set to `true`, then patterns without slashes will be matched against the basename of the path if it contains slashes.
607
608```js
609dir/
610└── one/
611 └── file.md
612```
613
614```js
615fg.sync('*.md', { baseNameMatch: false }); // []
616fg.sync('*.md', { baseNameMatch: true }); // ['one/file.md']
617```
618
619## FAQ
620
621## What is a static or dynamic pattern?
622
623All patterns can be divided into two types:
624
625* **static**. A pattern is considered static if it can be used to get an entry on the file system without using matching mechanisms. For example, the `file.js` pattern is a static pattern because we can just verify that it exists on the file system.
626* **dynamic**. A pattern is considered dynamic if it cannot be used directly to find occurrences without using a matching mechanisms. For example, the `*` pattern is a dynamic pattern because we cannot use this pattern directly.
627
628A pattern is considered dynamic if it contains the following characters (`…` — any characters or their absence) or options:
629
630* The [`caseSensitiveMatch`](#casesensitivematch) option is disabled
631* `\\` (the escape character)
632* `*`, `?`, `!` (at the beginning of line)
633* `[…]`
634* `(…|…)`
635* `@(…)`, `!(…)`, `*(…)`, `?(…)`, `+(…)` (respects the [`extglob`](#extglob) option)
636* `{…,…}`, `{…..…}` (respects the [`braceExpansion`](#braceexpansion) option)
637
638## How to write patterns on Windows?
639
640Always use forward-slashes in glob expressions (patterns and [`ignore`](#ignore) option). Use backslashes for escaping characters. With the [`cwd`](#cwd) option use a convenient format.
641
642**Bad**
643
644```ts
645[
646 'directory\\*',
647 path.join(process.cwd(), '**')
648]
649```
650
651**Good**
652
653```ts
654[
655 'directory/*',
656 path.join(process.cwd(), '**').replace(/\\/g, '/')
657]
658```
659
660> :book: Use the [`normalize-path`][npm_normalize_path] or the [`unixify`][npm_unixify] package to convert Windows-style path to a Unix-style path.
661
662Read more about [matching with backslashes][micromatch_backslashes].
663
664## Why are parentheses match wrong?
665
666```js
667dir/
668└── (special-*file).txt
669```
670
671```js
672fg.sync(['(special-*file).txt']) // []
673```
674
675Refers to Bash. You need to escape special characters:
676
677```js
678fg.sync(['\\(special-*file\\).txt']) // ['(special-*file).txt']
679```
680
681Read more about [matching special characters as literals][picomatch_matching_special_characters_as_literals].
682
683## How to exclude directory from reading?
684
685You can use a negative pattern like this: `!**/node_modules` or `!**/node_modules/**`. Also you can use [`ignore`](#ignore) option. Just look at the example below.
686
687```js
688first/
689├── file.md
690└── second/
691 └── file.txt
692```
693
694If you don't want to read the `second` directory, you must write the following pattern: `!**/second` or `!**/second/**`.
695
696```js
697fg.sync(['**/*.md', '!**/second']); // ['first/file.md']
698fg.sync(['**/*.md'], { ignore: ['**/second/**'] }); // ['first/file.md']
699```
700
701> :warning: When you write `!**/second/**/*` it means that the directory will be **read**, but all the entries will not be included in the results.
702
703You have to understand that if you write the pattern to exclude directories, then the directory will not be read under any circumstances.
704
705## How to use UNC path?
706
707You cannot use [Uniform Naming Convention (UNC)][unc_path] paths as patterns (due to syntax), but you can use them as [`cwd`](#cwd) directory.
708
709```ts
710fg.sync('*', { cwd: '\\\\?\\C:\\Python27' /* or //?/C:/Python27 */ });
711fg.sync('Python27/*', { cwd: '\\\\?\\C:\\' /* or //?/C:/ */ });
712```
713
714## Compatible with `node-glob`?
715
716| node-glob | fast-glob |
717| :----------: | :-------: |
718| `cwd` | [`cwd`](#cwd) |
719| `root` | – |
720| `dot` | [`dot`](#dot) |
721| `nomount` | – |
722| `mark` | [`markDirectories`](#markdirectories) |
723| `nosort` | – |
724| `nounique` | [`unique`](#unique) |
725| `nobrace` | [`braceExpansion`](#braceexpansion) |
726| `noglobstar` | [`globstar`](#globstar) |
727| `noext` | [`extglob`](#extglob) |
728| `nocase` | [`caseSensitiveMatch`](#casesensitivematch) |
729| `matchBase` | [`baseNameMatch`](#basenamematch) |
730| `nodir` | [`onlyFiles`](#onlyfiles) |
731| `ignore` | [`ignore`](#ignore) |
732| `follow` | [`followSymbolicLinks`](#followsymboliclinks) |
733| `realpath` | – |
734| `absolute` | [`absolute`](#absolute) |
735
736## Benchmarks
737
738### Server
739
740Link: [Vultr Bare Metal][vultr_pricing_baremetal]
741
742* Processor: E3-1270v6 (8 CPU)
743* RAM: 32GB
744* Disk: SSD ([Intel DC S3520 SSDSC2BB240G7][intel_ssd])
745
746You can see results [here][github_gist_benchmark_server] for latest release.
747
748### Nettop
749
750Link: [Zotac bi323][zotac_bi323]
751
752* Processor: Intel N3150 (4 CPU)
753* RAM: 8GB
754* Disk: SSD ([Silicon Power SP060GBSS3S55S25][silicon_power_ssd])
755
756You can see results [here][github_gist_benchmark_nettop] for latest release.
757
758## Changelog
759
760See the [Releases section of our GitHub project][github_releases] for changelog for each release version.
761
762## License
763
764This software is released under the terms of the MIT license.
765
766[bash_hackers_syntax_expansion_brace]: https://wiki.bash-hackers.org/syntax/expansion/brace
767[github_gist_benchmark_nettop]: https://gist.github.com/mrmlnc/f06246b197f53c356895fa35355a367c#file-fg-benchmark-nettop-product-txt
768[github_gist_benchmark_server]: https://gist.github.com/mrmlnc/f06246b197f53c356895fa35355a367c#file-fg-benchmark-server-product-txt
769[github_releases]: https://github.com/mrmlnc/fast-glob/releases
770[glob_definition]: https://en.wikipedia.org/wiki/Glob_(programming)
771[glob_linux_man]: http://man7.org/linux/man-pages/man3/glob.3.html
772[intel_ssd]: https://ark.intel.com/content/www/us/en/ark/products/93012/intel-ssd-dc-s3520-series-240gb-2-5in-sata-6gb-s-3d1-mlc.html
773[micromatch_backslashes]: https://github.com/micromatch/micromatch#backslashes
774[micromatch_braces]: https://github.com/micromatch/braces
775[micromatch_extended_globbing]: https://github.com/micromatch/micromatch#extended-globbing
776[micromatch_extglobs]: https://github.com/micromatch/micromatch#extglobs
777[micromatch_regex_character_classes]: https://github.com/micromatch/micromatch#regex-character-classes
778[micromatch]: https://github.com/micromatch/micromatch
779[node_js_fs_class_fs_dirent]: https://nodejs.org/api/fs.html#fs_class_fs_dirent
780[node_js_fs_class_fs_stats]: https://nodejs.org/api/fs.html#fs_class_fs_stats
781[node_js_stream_readable_streams]: https://nodejs.org/api/stream.html#stream_readable_streams
782[node_js]: https://nodejs.org/en
783[nodelib_fs_scandir_old_and_modern_modern]: https://github.com/nodelib/nodelib/blob/master/packages/fs/fs.scandir/README.md#old-and-modern-mode
784[npm_normalize_path]: https://www.npmjs.com/package/normalize-path
785[npm_unixify]: https://www.npmjs.com/package/unixify
786[paypal_mrmlnc]:https://paypal.me/mrmlnc
787[picomatch_matching_behavior]: https://github.com/micromatch/picomatch#matching-behavior-vs-bash
788[picomatch_matching_special_characters_as_literals]: https://github.com/micromatch/picomatch#matching-special-characters-as-literals
789[picomatch_posix_brackets]: https://github.com/micromatch/picomatch#posix-brackets
790[regular_expressions_brackets]: https://www.regular-expressions.info/brackets.html
791[silicon_power_ssd]: https://www.silicon-power.com/web/product-1
792[unc_path]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc
793[vultr_pricing_baremetal]: https://www.vultr.com/pricing/baremetal
794[wikipedia_case_sensitivity]: https://en.wikipedia.org/wiki/Case_sensitivity
795[zotac_bi323]: https://www.zotac.com/ee/product/mini_pcs/zbox-bi323