| [9af201e] | 1 | # fast-glob
|
|---|
| 2 |
|
|---|
| 3 | > It's a very fast and efficient [glob][glob_definition] library for [Node.js][node_js].
|
|---|
| 4 |
|
|---|
| 5 | This 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 | * [Old and modern mode](#old-and-modern-mode)
|
|---|
| 14 | * [Pattern syntax](#pattern-syntax)
|
|---|
| 15 | * [Basic syntax](#basic-syntax)
|
|---|
| 16 | * [Advanced syntax](#advanced-syntax)
|
|---|
| 17 | * [Installation](#installation)
|
|---|
| 18 | * [API](#api)
|
|---|
| 19 | * [Asynchronous](#asynchronous)
|
|---|
| 20 | * [Synchronous](#synchronous)
|
|---|
| 21 | * [Stream](#stream)
|
|---|
| 22 | * [patterns](#patterns)
|
|---|
| 23 | * [[options]](#options)
|
|---|
| 24 | * [Helpers](#helpers)
|
|---|
| 25 | * [generateTasks](#generatetaskspatterns-options)
|
|---|
| 26 | * [isDynamicPattern](#isdynamicpatternpattern-options)
|
|---|
| 27 | * [escapePath](#escapepathpath)
|
|---|
| 28 | * [convertPathToPattern](#convertpathtopatternpath)
|
|---|
| 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 | ## Old and modern mode
|
|---|
| 78 |
|
|---|
| 79 | This package works in two modes, depending on the environment in which it is used.
|
|---|
| 80 |
|
|---|
| 81 | * **Old mode**. Node.js below 10.10 or when the [`stats`](#stats) option is *enabled*.
|
|---|
| 82 | * **Modern mode**. Node.js 10.10+ and the [`stats`](#stats) option is *disabled*.
|
|---|
| 83 |
|
|---|
| 84 | The modern mode is faster. Learn more about the [internal mechanism][nodelib_fs_scandir_old_and_modern_modern].
|
|---|
| 85 |
|
|---|
| 86 | ## Pattern syntax
|
|---|
| 87 |
|
|---|
| 88 | > :warning: Always use forward-slashes in glob expressions (patterns and [`ignore`](#ignore) option). Use backslashes for escaping characters.
|
|---|
| 89 |
|
|---|
| 90 | There 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).
|
|---|
| 91 |
|
|---|
| 92 | > :book: This package uses [`micromatch`][micromatch] as a library for pattern matching.
|
|---|
| 93 |
|
|---|
| 94 | ### Basic syntax
|
|---|
| 95 |
|
|---|
| 96 | * An asterisk (`*`) — matches everything except slashes (path separators), hidden files (names starting with `.`).
|
|---|
| 97 | * A double star or globstar (`**`) — matches zero or more directories.
|
|---|
| 98 | * Question mark (`?`) – matches any single character except slashes (path separators).
|
|---|
| 99 | * Sequence (`[seq]`) — matches any character in sequence.
|
|---|
| 100 |
|
|---|
| 101 | > :book: A few additional words about the [basic matching behavior][picomatch_matching_behavior].
|
|---|
| 102 |
|
|---|
| 103 | Some examples:
|
|---|
| 104 |
|
|---|
| 105 | * `src/**/*.js` — matches all files in the `src` directory (any level of nesting) that have the `.js` extension.
|
|---|
| 106 | * `src/*.??` — matches all files in the `src` directory (only first level of nesting) that have a two-character extension.
|
|---|
| 107 | * `file-[01].js` — matches files: `file-0.js`, `file-1.js`.
|
|---|
| 108 |
|
|---|
| 109 | ### Advanced syntax
|
|---|
| 110 |
|
|---|
| 111 | * [Escapes characters][micromatch_backslashes] (`\\`) — matching special characters (`$^*+?()[]`) as literals.
|
|---|
| 112 | * [POSIX character classes][picomatch_posix_brackets] (`[[:digit:]]`).
|
|---|
| 113 | * [Extended globs][micromatch_extglobs] (`?(pattern-list)`).
|
|---|
| 114 | * [Bash style brace expansions][micromatch_braces] (`{}`).
|
|---|
| 115 | * [Regexp character classes][micromatch_regex_character_classes] (`[1-5]`).
|
|---|
| 116 | * [Regex groups][regular_expressions_brackets] (`(a|b)`).
|
|---|
| 117 |
|
|---|
| 118 | > :book: A few additional words about the [advanced matching behavior][micromatch_extended_globbing].
|
|---|
| 119 |
|
|---|
| 120 | Some examples:
|
|---|
| 121 |
|
|---|
| 122 | * `src/**/*.{css,scss}` — matches all files in the `src` directory (any level of nesting) that have the `.css` or `.scss` extension.
|
|---|
| 123 | * `file-[[:digit:]].js` — matches files: `file-0.js`, `file-1.js`, …, `file-9.js`.
|
|---|
| 124 | * `file-{1..3}.js` — matches files: `file-1.js`, `file-2.js`, `file-3.js`.
|
|---|
| 125 | * `file-(1|2)` — matches files: `file-1.js`, `file-2.js`.
|
|---|
| 126 |
|
|---|
| 127 | ## Installation
|
|---|
| 128 |
|
|---|
| 129 | ```console
|
|---|
| 130 | npm install fast-glob
|
|---|
| 131 | ```
|
|---|
| 132 |
|
|---|
| 133 | ## API
|
|---|
| 134 |
|
|---|
| 135 | ### Asynchronous
|
|---|
| 136 |
|
|---|
| 137 | ```js
|
|---|
| 138 | fg(patterns, [options])
|
|---|
| 139 | fg.async(patterns, [options])
|
|---|
| 140 | fg.glob(patterns, [options])
|
|---|
| 141 | ```
|
|---|
| 142 |
|
|---|
| 143 | Returns a `Promise` with an array of matching entries.
|
|---|
| 144 |
|
|---|
| 145 | ```js
|
|---|
| 146 | const fg = require('fast-glob');
|
|---|
| 147 |
|
|---|
| 148 | const entries = await fg(['.editorconfig', '**/index.js'], { dot: true });
|
|---|
| 149 |
|
|---|
| 150 | // ['.editorconfig', 'services/index.js']
|
|---|
| 151 | ```
|
|---|
| 152 |
|
|---|
| 153 | ### Synchronous
|
|---|
| 154 |
|
|---|
| 155 | ```js
|
|---|
| 156 | fg.sync(patterns, [options])
|
|---|
| 157 | fg.globSync(patterns, [options])
|
|---|
| 158 | ```
|
|---|
| 159 |
|
|---|
| 160 | Returns an array of matching entries.
|
|---|
| 161 |
|
|---|
| 162 | ```js
|
|---|
| 163 | const fg = require('fast-glob');
|
|---|
| 164 |
|
|---|
| 165 | const entries = fg.sync(['.editorconfig', '**/index.js'], { dot: true });
|
|---|
| 166 |
|
|---|
| 167 | // ['.editorconfig', 'services/index.js']
|
|---|
| 168 | ```
|
|---|
| 169 |
|
|---|
| 170 | ### Stream
|
|---|
| 171 |
|
|---|
| 172 | ```js
|
|---|
| 173 | fg.stream(patterns, [options])
|
|---|
| 174 | fg.globStream(patterns, [options])
|
|---|
| 175 | ```
|
|---|
| 176 |
|
|---|
| 177 | Returns a [`ReadableStream`][node_js_stream_readable_streams] when the `data` event will be emitted with matching entry.
|
|---|
| 178 |
|
|---|
| 179 | ```js
|
|---|
| 180 | const fg = require('fast-glob');
|
|---|
| 181 |
|
|---|
| 182 | const stream = fg.stream(['.editorconfig', '**/index.js'], { dot: true });
|
|---|
| 183 |
|
|---|
| 184 | for await (const entry of stream) {
|
|---|
| 185 | // .editorconfig
|
|---|
| 186 | // services/index.js
|
|---|
| 187 | }
|
|---|
| 188 | ```
|
|---|
| 189 |
|
|---|
| 190 | #### patterns
|
|---|
| 191 |
|
|---|
| 192 | * Required: `true`
|
|---|
| 193 | * Type: `string | string[]`
|
|---|
| 194 |
|
|---|
| 195 | Any correct pattern(s).
|
|---|
| 196 |
|
|---|
| 197 | > :1234: [Pattern syntax](#pattern-syntax)
|
|---|
| 198 | >
|
|---|
| 199 | > :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.
|
|---|
| 200 |
|
|---|
| 201 | #### [options]
|
|---|
| 202 |
|
|---|
| 203 | * Required: `false`
|
|---|
| 204 | * Type: [`Options`](#options-3)
|
|---|
| 205 |
|
|---|
| 206 | See [Options](#options-3) section.
|
|---|
| 207 |
|
|---|
| 208 | ### Helpers
|
|---|
| 209 |
|
|---|
| 210 | #### `generateTasks(patterns, [options])`
|
|---|
| 211 |
|
|---|
| 212 | Returns the internal representation of patterns ([`Task`](./src/managers/tasks.ts) is a combining patterns by base directory).
|
|---|
| 213 |
|
|---|
| 214 | ```js
|
|---|
| 215 | fg.generateTasks('*');
|
|---|
| 216 |
|
|---|
| 217 | [{
|
|---|
| 218 | base: '.', // Parent directory for all patterns inside this task
|
|---|
| 219 | dynamic: true, // Dynamic or static patterns are in this task
|
|---|
| 220 | patterns: ['*'],
|
|---|
| 221 | positive: ['*'],
|
|---|
| 222 | negative: []
|
|---|
| 223 | }]
|
|---|
| 224 | ```
|
|---|
| 225 |
|
|---|
| 226 | ##### patterns
|
|---|
| 227 |
|
|---|
| 228 | * Required: `true`
|
|---|
| 229 | * Type: `string | string[]`
|
|---|
| 230 |
|
|---|
| 231 | Any correct pattern(s).
|
|---|
| 232 |
|
|---|
| 233 | ##### [options]
|
|---|
| 234 |
|
|---|
| 235 | * Required: `false`
|
|---|
| 236 | * Type: [`Options`](#options-3)
|
|---|
| 237 |
|
|---|
| 238 | See [Options](#options-3) section.
|
|---|
| 239 |
|
|---|
| 240 | #### `isDynamicPattern(pattern, [options])`
|
|---|
| 241 |
|
|---|
| 242 | Returns `true` if the passed pattern is a dynamic pattern.
|
|---|
| 243 |
|
|---|
| 244 | > :1234: [What is a static or dynamic pattern?](#what-is-a-static-or-dynamic-pattern)
|
|---|
| 245 |
|
|---|
| 246 | ```js
|
|---|
| 247 | fg.isDynamicPattern('*'); // true
|
|---|
| 248 | fg.isDynamicPattern('abc'); // false
|
|---|
| 249 | ```
|
|---|
| 250 |
|
|---|
| 251 | ##### pattern
|
|---|
| 252 |
|
|---|
| 253 | * Required: `true`
|
|---|
| 254 | * Type: `string`
|
|---|
| 255 |
|
|---|
| 256 | Any correct pattern.
|
|---|
| 257 |
|
|---|
| 258 | ##### [options]
|
|---|
| 259 |
|
|---|
| 260 | * Required: `false`
|
|---|
| 261 | * Type: [`Options`](#options-3)
|
|---|
| 262 |
|
|---|
| 263 | See [Options](#options-3) section.
|
|---|
| 264 |
|
|---|
| 265 | #### `escapePath(path)`
|
|---|
| 266 |
|
|---|
| 267 | Returns the path with escaped special characters depending on the platform.
|
|---|
| 268 |
|
|---|
| 269 | * Posix:
|
|---|
| 270 | * `*?|(){}[]`;
|
|---|
| 271 | * `!` at the beginning of line;
|
|---|
| 272 | * `@+!` before the opening parenthesis;
|
|---|
| 273 | * `\\` before non-special characters;
|
|---|
| 274 | * Windows:
|
|---|
| 275 | * `(){}[]`
|
|---|
| 276 | * `!` at the beginning of line;
|
|---|
| 277 | * `@+!` before the opening parenthesis;
|
|---|
| 278 | * Characters like `*?|` cannot be used in the path ([windows_naming_conventions][windows_naming_conventions]), so they will not be escaped;
|
|---|
| 279 |
|
|---|
| 280 | ```js
|
|---|
| 281 | fg.escapePath('!abc');
|
|---|
| 282 | // \\!abc
|
|---|
| 283 | fg.escapePath('[OpenSource] mrmlnc – fast-glob (Deluxe Edition) 2014') + '/*.flac'
|
|---|
| 284 | // \\[OpenSource\\] mrmlnc – fast-glob \\(Deluxe Edition\\) 2014/*.flac
|
|---|
| 285 |
|
|---|
| 286 | fg.posix.escapePath('C:\\Program Files (x86)\\**\\*');
|
|---|
| 287 | // C:\\\\Program Files \\(x86\\)\\*\\*\\*
|
|---|
| 288 | fg.win32.escapePath('C:\\Program Files (x86)\\**\\*');
|
|---|
| 289 | // Windows: C:\\Program Files \\(x86\\)\\**\\*
|
|---|
| 290 | ```
|
|---|
| 291 |
|
|---|
| 292 | #### `convertPathToPattern(path)`
|
|---|
| 293 |
|
|---|
| 294 | Converts a path to a pattern depending on the platform, including special character escaping.
|
|---|
| 295 |
|
|---|
| 296 | * Posix. Works similarly to the `fg.posix.escapePath` method.
|
|---|
| 297 | * Windows. Works similarly to the `fg.win32.escapePath` method, additionally converting backslashes to forward slashes in cases where they are not escape characters (`!()+@{}[]`).
|
|---|
| 298 |
|
|---|
| 299 | ```js
|
|---|
| 300 | fg.convertPathToPattern('[OpenSource] mrmlnc – fast-glob (Deluxe Edition) 2014') + '/*.flac';
|
|---|
| 301 | // \\[OpenSource\\] mrmlnc – fast-glob \\(Deluxe Edition\\) 2014/*.flac
|
|---|
| 302 |
|
|---|
| 303 | fg.convertPathToPattern('C:/Program Files (x86)/**/*');
|
|---|
| 304 | // Posix: C:/Program Files \\(x86\\)/\\*\\*/\\*
|
|---|
| 305 | // Windows: C:/Program Files \\(x86\\)/**/*
|
|---|
| 306 |
|
|---|
| 307 | fg.convertPathToPattern('C:\\Program Files (x86)\\**\\*');
|
|---|
| 308 | // Posix: C:\\\\Program Files \\(x86\\)\\*\\*\\*
|
|---|
| 309 | // Windows: C:/Program Files \\(x86\\)/**/*
|
|---|
| 310 |
|
|---|
| 311 | fg.posix.convertPathToPattern('\\\\?\\c:\\Program Files (x86)') + '/**/*';
|
|---|
| 312 | // Posix: \\\\\\?\\\\c:\\\\Program Files \\(x86\\)/**/* (broken pattern)
|
|---|
| 313 | fg.win32.convertPathToPattern('\\\\?\\c:\\Program Files (x86)') + '/**/*';
|
|---|
| 314 | // Windows: //?/c:/Program Files \\(x86\\)/**/*
|
|---|
| 315 | ```
|
|---|
| 316 |
|
|---|
| 317 | ## Options
|
|---|
| 318 |
|
|---|
| 319 | ### Common options
|
|---|
| 320 |
|
|---|
| 321 | #### concurrency
|
|---|
| 322 |
|
|---|
| 323 | * Type: `number`
|
|---|
| 324 | * Default: `os.cpus().length`
|
|---|
| 325 |
|
|---|
| 326 | Specifies the maximum number of concurrent requests from a reader to read directories.
|
|---|
| 327 |
|
|---|
| 328 | > :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`.
|
|---|
| 329 |
|
|---|
| 330 | <details>
|
|---|
| 331 |
|
|---|
| 332 | <summary>More details</summary>
|
|---|
| 333 |
|
|---|
| 334 | In Node, there are [two types of threads][nodejs_thread_pool]: Event Loop (code) and a Thread Pool (fs, dns, …). The thread pool size controlled by the `UV_THREADPOOL_SIZE` environment variable. Its default size is 4 ([documentation][libuv_thread_pool]). The pool is one for all tasks within a single Node process.
|
|---|
| 335 |
|
|---|
| 336 | Any code can make 4 real concurrent accesses to the file system. The rest of the FS requests will wait in the queue.
|
|---|
| 337 |
|
|---|
| 338 | > :book: Each new instance of FG in the same Node process will use the same Thread pool.
|
|---|
| 339 |
|
|---|
| 340 | But this package also has the `concurrency` option. This option allows you to control the number of concurrent accesses to the FS at the package level. By default, this package has a value equal to the number of cores available for the current Node process. This allows you to set a value smaller than the pool size (`concurrency: 1`) or, conversely, to prepare tasks for the pool queue more quickly (`concurrency: Number.POSITIVE_INFINITY`).
|
|---|
| 341 |
|
|---|
| 342 | So, in fact, this package can **only make 4 concurrent requests to the FS**. You can increase this value by using an environment variable (`UV_THREADPOOL_SIZE`), but in practice this does not give a multiple advantage.
|
|---|
| 343 |
|
|---|
| 344 | </details>
|
|---|
| 345 |
|
|---|
| 346 | #### cwd
|
|---|
| 347 |
|
|---|
| 348 | * Type: `string`
|
|---|
| 349 | * Default: `process.cwd()`
|
|---|
| 350 |
|
|---|
| 351 | The current working directory in which to search.
|
|---|
| 352 |
|
|---|
| 353 | #### deep
|
|---|
| 354 |
|
|---|
| 355 | * Type: `number`
|
|---|
| 356 | * Default: `Infinity`
|
|---|
| 357 |
|
|---|
| 358 | Specifies the maximum depth of a read directory relative to the start directory.
|
|---|
| 359 |
|
|---|
| 360 | For example, you have the following tree:
|
|---|
| 361 |
|
|---|
| 362 | ```js
|
|---|
| 363 | dir/
|
|---|
| 364 | └── one/ // 1
|
|---|
| 365 | └── two/ // 2
|
|---|
| 366 | └── file.js // 3
|
|---|
| 367 | ```
|
|---|
| 368 |
|
|---|
| 369 | ```js
|
|---|
| 370 | // With base directory
|
|---|
| 371 | fg.sync('dir/**', { onlyFiles: false, deep: 1 }); // ['dir/one']
|
|---|
| 372 | fg.sync('dir/**', { onlyFiles: false, deep: 2 }); // ['dir/one', 'dir/one/two']
|
|---|
| 373 |
|
|---|
| 374 | // With cwd option
|
|---|
| 375 | fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 1 }); // ['one']
|
|---|
| 376 | fg.sync('**', { onlyFiles: false, cwd: 'dir', deep: 2 }); // ['one', 'one/two']
|
|---|
| 377 | ```
|
|---|
| 378 |
|
|---|
| 379 | > :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.
|
|---|
| 380 |
|
|---|
| 381 | #### followSymbolicLinks
|
|---|
| 382 |
|
|---|
| 383 | * Type: `boolean`
|
|---|
| 384 | * Default: `true`
|
|---|
| 385 |
|
|---|
| 386 | Indicates whether to traverse descendants of symbolic link directories when expanding `**` patterns.
|
|---|
| 387 |
|
|---|
| 388 | > :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.
|
|---|
| 389 |
|
|---|
| 390 | > :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.
|
|---|
| 391 |
|
|---|
| 392 | #### fs
|
|---|
| 393 |
|
|---|
| 394 | * Type: `FileSystemAdapter`
|
|---|
| 395 | * Default: `fs.*`
|
|---|
| 396 |
|
|---|
| 397 | Custom implementation of methods for working with the file system. Supports objects with enumerable properties only.
|
|---|
| 398 |
|
|---|
| 399 | ```ts
|
|---|
| 400 | export interface FileSystemAdapter {
|
|---|
| 401 | lstat?: typeof fs.lstat;
|
|---|
| 402 | stat?: typeof fs.stat;
|
|---|
| 403 | lstatSync?: typeof fs.lstatSync;
|
|---|
| 404 | statSync?: typeof fs.statSync;
|
|---|
| 405 | readdir?: typeof fs.readdir;
|
|---|
| 406 | readdirSync?: typeof fs.readdirSync;
|
|---|
| 407 | }
|
|---|
| 408 | ```
|
|---|
| 409 |
|
|---|
| 410 | #### ignore
|
|---|
| 411 |
|
|---|
| 412 | * Type: `string[]`
|
|---|
| 413 | * Default: `[]`
|
|---|
| 414 |
|
|---|
| 415 | An array of glob patterns to exclude matches. This is an alternative way to use negative patterns.
|
|---|
| 416 |
|
|---|
| 417 | ```js
|
|---|
| 418 | dir/
|
|---|
| 419 | ├── package-lock.json
|
|---|
| 420 | └── package.json
|
|---|
| 421 | ```
|
|---|
| 422 |
|
|---|
| 423 | ```js
|
|---|
| 424 | fg.sync(['*.json', '!package-lock.json']); // ['package.json']
|
|---|
| 425 | fg.sync('*.json', { ignore: ['package-lock.json'] }); // ['package.json']
|
|---|
| 426 | ```
|
|---|
| 427 |
|
|---|
| 428 | #### suppressErrors
|
|---|
| 429 |
|
|---|
| 430 | * Type: `boolean`
|
|---|
| 431 | * Default: `false`
|
|---|
| 432 |
|
|---|
| 433 | By default this package suppress only `ENOENT` errors. Set to `true` to suppress any error.
|
|---|
| 434 |
|
|---|
| 435 | > :book: Can be useful when the directory has entries with a special level of access.
|
|---|
| 436 |
|
|---|
| 437 | #### throwErrorOnBrokenSymbolicLink
|
|---|
| 438 |
|
|---|
| 439 | * Type: `boolean`
|
|---|
| 440 | * Default: `false`
|
|---|
| 441 |
|
|---|
| 442 | Throw an error when symbolic link is broken if `true` or safely return `lstat` call if `false`.
|
|---|
| 443 |
|
|---|
| 444 | > :book: This option has no effect on errors when reading the symbolic link directory.
|
|---|
| 445 |
|
|---|
| 446 | ### Output control
|
|---|
| 447 |
|
|---|
| 448 | #### absolute
|
|---|
| 449 |
|
|---|
| 450 | * Type: `boolean`
|
|---|
| 451 | * Default: `false`
|
|---|
| 452 |
|
|---|
| 453 | Return the absolute path for entries.
|
|---|
| 454 |
|
|---|
| 455 | ```js
|
|---|
| 456 | fg.sync('*.js', { absolute: false }); // ['index.js']
|
|---|
| 457 | fg.sync('*.js', { absolute: true }); // ['/home/user/index.js']
|
|---|
| 458 | ```
|
|---|
| 459 |
|
|---|
| 460 | > :book: This option is required if you want to use negative patterns with absolute path, for example, `!${__dirname}/*.js`.
|
|---|
| 461 |
|
|---|
| 462 | #### markDirectories
|
|---|
| 463 |
|
|---|
| 464 | * Type: `boolean`
|
|---|
| 465 | * Default: `false`
|
|---|
| 466 |
|
|---|
| 467 | Mark the directory path with the final slash.
|
|---|
| 468 |
|
|---|
| 469 | ```js
|
|---|
| 470 | fg.sync('*', { onlyFiles: false, markDirectories: false }); // ['index.js', 'controllers']
|
|---|
| 471 | fg.sync('*', { onlyFiles: false, markDirectories: true }); // ['index.js', 'controllers/']
|
|---|
| 472 | ```
|
|---|
| 473 |
|
|---|
| 474 | #### objectMode
|
|---|
| 475 |
|
|---|
| 476 | * Type: `boolean`
|
|---|
| 477 | * Default: `false`
|
|---|
| 478 |
|
|---|
| 479 | Returns objects (instead of strings) describing entries.
|
|---|
| 480 |
|
|---|
| 481 | ```js
|
|---|
| 482 | fg.sync('*', { objectMode: false }); // ['src/index.js']
|
|---|
| 483 | fg.sync('*', { objectMode: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent> }]
|
|---|
| 484 | ```
|
|---|
| 485 |
|
|---|
| 486 | The object has the following fields:
|
|---|
| 487 |
|
|---|
| 488 | * name (`string`) — the last part of the path (basename)
|
|---|
| 489 | * path (`string`) — full path relative to the pattern base directory
|
|---|
| 490 | * dirent ([`fs.Dirent`][node_js_fs_class_fs_dirent]) — instance of `fs.Dirent`
|
|---|
| 491 |
|
|---|
| 492 | > :book: An object is an internal representation of entry, so getting it does not affect performance.
|
|---|
| 493 |
|
|---|
| 494 | #### onlyDirectories
|
|---|
| 495 |
|
|---|
| 496 | * Type: `boolean`
|
|---|
| 497 | * Default: `false`
|
|---|
| 498 |
|
|---|
| 499 | Return only directories.
|
|---|
| 500 |
|
|---|
| 501 | ```js
|
|---|
| 502 | fg.sync('*', { onlyDirectories: false }); // ['index.js', 'src']
|
|---|
| 503 | fg.sync('*', { onlyDirectories: true }); // ['src']
|
|---|
| 504 | ```
|
|---|
| 505 |
|
|---|
| 506 | > :book: If `true`, the [`onlyFiles`](#onlyfiles) option is automatically `false`.
|
|---|
| 507 |
|
|---|
| 508 | #### onlyFiles
|
|---|
| 509 |
|
|---|
| 510 | * Type: `boolean`
|
|---|
| 511 | * Default: `true`
|
|---|
| 512 |
|
|---|
| 513 | Return only files.
|
|---|
| 514 |
|
|---|
| 515 | ```js
|
|---|
| 516 | fg.sync('*', { onlyFiles: false }); // ['index.js', 'src']
|
|---|
| 517 | fg.sync('*', { onlyFiles: true }); // ['index.js']
|
|---|
| 518 | ```
|
|---|
| 519 |
|
|---|
| 520 | #### stats
|
|---|
| 521 |
|
|---|
| 522 | * Type: `boolean`
|
|---|
| 523 | * Default: `false`
|
|---|
| 524 |
|
|---|
| 525 | Enables an [object mode](#objectmode) with an additional field:
|
|---|
| 526 |
|
|---|
| 527 | * stats ([`fs.Stats`][node_js_fs_class_fs_stats]) — instance of `fs.Stats`
|
|---|
| 528 |
|
|---|
| 529 | ```js
|
|---|
| 530 | fg.sync('*', { stats: false }); // ['src/index.js']
|
|---|
| 531 | fg.sync('*', { stats: true }); // [{ name: 'index.js', path: 'src/index.js', dirent: <fs.Dirent>, stats: <fs.Stats> }]
|
|---|
| 532 | ```
|
|---|
| 533 |
|
|---|
| 534 | > :book: Returns `fs.stat` instead of `fs.lstat` for symbolic links when the [`followSymbolicLinks`](#followsymboliclinks) option is specified.
|
|---|
| 535 | >
|
|---|
| 536 | > :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.
|
|---|
| 537 |
|
|---|
| 538 | #### unique
|
|---|
| 539 |
|
|---|
| 540 | * Type: `boolean`
|
|---|
| 541 | * Default: `true`
|
|---|
| 542 |
|
|---|
| 543 | Ensures that the returned entries are unique.
|
|---|
| 544 |
|
|---|
| 545 | ```js
|
|---|
| 546 | fg.sync(['*.json', 'package.json'], { unique: false }); // ['package.json', 'package.json']
|
|---|
| 547 | fg.sync(['*.json', 'package.json'], { unique: true }); // ['package.json']
|
|---|
| 548 | ```
|
|---|
| 549 |
|
|---|
| 550 | If `true` and similar entries are found, the result is the first found.
|
|---|
| 551 |
|
|---|
| 552 | ### Matching control
|
|---|
| 553 |
|
|---|
| 554 | #### braceExpansion
|
|---|
| 555 |
|
|---|
| 556 | * Type: `boolean`
|
|---|
| 557 | * Default: `true`
|
|---|
| 558 |
|
|---|
| 559 | Enables Bash-like brace expansion.
|
|---|
| 560 |
|
|---|
| 561 | > :1234: [Syntax description][bash_hackers_syntax_expansion_brace] or more [detailed description][micromatch_braces].
|
|---|
| 562 |
|
|---|
| 563 | ```js
|
|---|
| 564 | dir/
|
|---|
| 565 | ├── abd
|
|---|
| 566 | ├── acd
|
|---|
| 567 | └── a{b,c}d
|
|---|
| 568 | ```
|
|---|
| 569 |
|
|---|
| 570 | ```js
|
|---|
| 571 | fg.sync('a{b,c}d', { braceExpansion: false }); // ['a{b,c}d']
|
|---|
| 572 | fg.sync('a{b,c}d', { braceExpansion: true }); // ['abd', 'acd']
|
|---|
| 573 | ```
|
|---|
| 574 |
|
|---|
| 575 | #### caseSensitiveMatch
|
|---|
| 576 |
|
|---|
| 577 | * Type: `boolean`
|
|---|
| 578 | * Default: `true`
|
|---|
| 579 |
|
|---|
| 580 | Enables a [case-sensitive][wikipedia_case_sensitivity] mode for matching files.
|
|---|
| 581 |
|
|---|
| 582 | ```js
|
|---|
| 583 | dir/
|
|---|
| 584 | ├── file.txt
|
|---|
| 585 | └── File.txt
|
|---|
| 586 | ```
|
|---|
| 587 |
|
|---|
| 588 | ```js
|
|---|
| 589 | fg.sync('file.txt', { caseSensitiveMatch: false }); // ['file.txt', 'File.txt']
|
|---|
| 590 | fg.sync('file.txt', { caseSensitiveMatch: true }); // ['file.txt']
|
|---|
| 591 | ```
|
|---|
| 592 |
|
|---|
| 593 | #### dot
|
|---|
| 594 |
|
|---|
| 595 | * Type: `boolean`
|
|---|
| 596 | * Default: `false`
|
|---|
| 597 |
|
|---|
| 598 | Allow patterns to match entries that begin with a period (`.`).
|
|---|
| 599 |
|
|---|
| 600 | > :book: Note that an explicit dot in a portion of the pattern will always match dot files.
|
|---|
| 601 |
|
|---|
| 602 | ```js
|
|---|
| 603 | dir/
|
|---|
| 604 | ├── .editorconfig
|
|---|
| 605 | └── package.json
|
|---|
| 606 | ```
|
|---|
| 607 |
|
|---|
| 608 | ```js
|
|---|
| 609 | fg.sync('*', { dot: false }); // ['package.json']
|
|---|
| 610 | fg.sync('*', { dot: true }); // ['.editorconfig', 'package.json']
|
|---|
| 611 | ```
|
|---|
| 612 |
|
|---|
| 613 | #### extglob
|
|---|
| 614 |
|
|---|
| 615 | * Type: `boolean`
|
|---|
| 616 | * Default: `true`
|
|---|
| 617 |
|
|---|
| 618 | Enables Bash-like `extglob` functionality.
|
|---|
| 619 |
|
|---|
| 620 | > :1234: [Syntax description][micromatch_extglobs].
|
|---|
| 621 |
|
|---|
| 622 | ```js
|
|---|
| 623 | dir/
|
|---|
| 624 | ├── README.md
|
|---|
| 625 | └── package.json
|
|---|
| 626 | ```
|
|---|
| 627 |
|
|---|
| 628 | ```js
|
|---|
| 629 | fg.sync('*.+(json|md)', { extglob: false }); // []
|
|---|
| 630 | fg.sync('*.+(json|md)', { extglob: true }); // ['README.md', 'package.json']
|
|---|
| 631 | ```
|
|---|
| 632 |
|
|---|
| 633 | #### globstar
|
|---|
| 634 |
|
|---|
| 635 | * Type: `boolean`
|
|---|
| 636 | * Default: `true`
|
|---|
| 637 |
|
|---|
| 638 | Enables recursively repeats a pattern containing `**`. If `false`, `**` behaves exactly like `*`.
|
|---|
| 639 |
|
|---|
| 640 | ```js
|
|---|
| 641 | dir/
|
|---|
| 642 | └── a
|
|---|
| 643 | └── b
|
|---|
| 644 | ```
|
|---|
| 645 |
|
|---|
| 646 | ```js
|
|---|
| 647 | fg.sync('**', { onlyFiles: false, globstar: false }); // ['a']
|
|---|
| 648 | fg.sync('**', { onlyFiles: false, globstar: true }); // ['a', 'a/b']
|
|---|
| 649 | ```
|
|---|
| 650 |
|
|---|
| 651 | #### baseNameMatch
|
|---|
| 652 |
|
|---|
| 653 | * Type: `boolean`
|
|---|
| 654 | * Default: `false`
|
|---|
| 655 |
|
|---|
| 656 | If set to `true`, then patterns without slashes will be matched against the basename of the path if it contains slashes.
|
|---|
| 657 |
|
|---|
| 658 | ```js
|
|---|
| 659 | dir/
|
|---|
| 660 | └── one/
|
|---|
| 661 | └── file.md
|
|---|
| 662 | ```
|
|---|
| 663 |
|
|---|
| 664 | ```js
|
|---|
| 665 | fg.sync('*.md', { baseNameMatch: false }); // []
|
|---|
| 666 | fg.sync('*.md', { baseNameMatch: true }); // ['one/file.md']
|
|---|
| 667 | ```
|
|---|
| 668 |
|
|---|
| 669 | ## FAQ
|
|---|
| 670 |
|
|---|
| 671 | ## What is a static or dynamic pattern?
|
|---|
| 672 |
|
|---|
| 673 | All patterns can be divided into two types:
|
|---|
| 674 |
|
|---|
| 675 | * **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.
|
|---|
| 676 | * **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.
|
|---|
| 677 |
|
|---|
| 678 | A pattern is considered dynamic if it contains the following characters (`…` — any characters or their absence) or options:
|
|---|
| 679 |
|
|---|
| 680 | * The [`caseSensitiveMatch`](#casesensitivematch) option is disabled
|
|---|
| 681 | * `\\` (the escape character)
|
|---|
| 682 | * `*`, `?`, `!` (at the beginning of line)
|
|---|
| 683 | * `[…]`
|
|---|
| 684 | * `(…|…)`
|
|---|
| 685 | * `@(…)`, `!(…)`, `*(…)`, `?(…)`, `+(…)` (respects the [`extglob`](#extglob) option)
|
|---|
| 686 | * `{…,…}`, `{…..…}` (respects the [`braceExpansion`](#braceexpansion) option)
|
|---|
| 687 |
|
|---|
| 688 | ## How to write patterns on Windows?
|
|---|
| 689 |
|
|---|
| 690 | Always 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.
|
|---|
| 691 |
|
|---|
| 692 | **Bad**
|
|---|
| 693 |
|
|---|
| 694 | ```ts
|
|---|
| 695 | [
|
|---|
| 696 | 'directory\\*',
|
|---|
| 697 | path.join(process.cwd(), '**')
|
|---|
| 698 | ]
|
|---|
| 699 | ```
|
|---|
| 700 |
|
|---|
| 701 | **Good**
|
|---|
| 702 |
|
|---|
| 703 | ```ts
|
|---|
| 704 | [
|
|---|
| 705 | 'directory/*',
|
|---|
| 706 | fg.convertPathToPattern(process.cwd()) + '/**'
|
|---|
| 707 | ]
|
|---|
| 708 | ```
|
|---|
| 709 |
|
|---|
| 710 | > :book: Use the [`.convertPathToPattern`](#convertpathtopatternpath) package to convert Windows-style path to a Unix-style path.
|
|---|
| 711 |
|
|---|
| 712 | Read more about [matching with backslashes][micromatch_backslashes].
|
|---|
| 713 |
|
|---|
| 714 | ## Why are parentheses match wrong?
|
|---|
| 715 |
|
|---|
| 716 | ```js
|
|---|
| 717 | dir/
|
|---|
| 718 | └── (special-*file).txt
|
|---|
| 719 | ```
|
|---|
| 720 |
|
|---|
| 721 | ```js
|
|---|
| 722 | fg.sync(['(special-*file).txt']) // []
|
|---|
| 723 | ```
|
|---|
| 724 |
|
|---|
| 725 | Refers to Bash. You need to escape special characters:
|
|---|
| 726 |
|
|---|
| 727 | ```js
|
|---|
| 728 | fg.sync(['\\(special-*file\\).txt']) // ['(special-*file).txt']
|
|---|
| 729 | ```
|
|---|
| 730 |
|
|---|
| 731 | Read more about [matching special characters as literals][picomatch_matching_special_characters_as_literals]. Or use the [`.escapePath`](#escapepathpath).
|
|---|
| 732 |
|
|---|
| 733 | ## How to exclude directory from reading?
|
|---|
| 734 |
|
|---|
| 735 | You 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.
|
|---|
| 736 |
|
|---|
| 737 | ```js
|
|---|
| 738 | first/
|
|---|
| 739 | ├── file.md
|
|---|
| 740 | └── second/
|
|---|
| 741 | └── file.txt
|
|---|
| 742 | ```
|
|---|
| 743 |
|
|---|
| 744 | If you don't want to read the `second` directory, you must write the following pattern: `!**/second` or `!**/second/**`.
|
|---|
| 745 |
|
|---|
| 746 | ```js
|
|---|
| 747 | fg.sync(['**/*.md', '!**/second']); // ['first/file.md']
|
|---|
| 748 | fg.sync(['**/*.md'], { ignore: ['**/second/**'] }); // ['first/file.md']
|
|---|
| 749 | ```
|
|---|
| 750 |
|
|---|
| 751 | > :warning: When you write `!**/second/**/*` it means that the directory will be **read**, but all the entries will not be included in the results.
|
|---|
| 752 |
|
|---|
| 753 | You have to understand that if you write the pattern to exclude directories, then the directory will not be read under any circumstances.
|
|---|
| 754 |
|
|---|
| 755 | ## How to use UNC path?
|
|---|
| 756 |
|
|---|
| 757 | You cannot use [Uniform Naming Convention (UNC)][unc_path] paths as patterns (due to syntax) directly, but you can use them as [`cwd`](#cwd) directory or use the `fg.convertPathToPattern` method.
|
|---|
| 758 |
|
|---|
| 759 | ```ts
|
|---|
| 760 | // cwd
|
|---|
| 761 | fg.sync('*', { cwd: '\\\\?\\C:\\Python27' /* or //?/C:/Python27 */ });
|
|---|
| 762 | fg.sync('Python27/*', { cwd: '\\\\?\\C:\\' /* or //?/C:/ */ });
|
|---|
| 763 |
|
|---|
| 764 | // .convertPathToPattern
|
|---|
| 765 | fg.sync(fg.convertPathToPattern('\\\\?\\c:\\Python27') + '/*');
|
|---|
| 766 | ```
|
|---|
| 767 |
|
|---|
| 768 | ## Compatible with `node-glob`?
|
|---|
| 769 |
|
|---|
| 770 | | node-glob | fast-glob |
|
|---|
| 771 | | :----------: | :-------: |
|
|---|
| 772 | | `cwd` | [`cwd`](#cwd) |
|
|---|
| 773 | | `root` | – |
|
|---|
| 774 | | `dot` | [`dot`](#dot) |
|
|---|
| 775 | | `nomount` | – |
|
|---|
| 776 | | `mark` | [`markDirectories`](#markdirectories) |
|
|---|
| 777 | | `nosort` | – |
|
|---|
| 778 | | `nounique` | [`unique`](#unique) |
|
|---|
| 779 | | `nobrace` | [`braceExpansion`](#braceexpansion) |
|
|---|
| 780 | | `noglobstar` | [`globstar`](#globstar) |
|
|---|
| 781 | | `noext` | [`extglob`](#extglob) |
|
|---|
| 782 | | `nocase` | [`caseSensitiveMatch`](#casesensitivematch) |
|
|---|
| 783 | | `matchBase` | [`baseNameMatch`](#basenamematch) |
|
|---|
| 784 | | `nodir` | [`onlyFiles`](#onlyfiles) |
|
|---|
| 785 | | `ignore` | [`ignore`](#ignore) |
|
|---|
| 786 | | `follow` | [`followSymbolicLinks`](#followsymboliclinks) |
|
|---|
| 787 | | `realpath` | – |
|
|---|
| 788 | | `absolute` | [`absolute`](#absolute) |
|
|---|
| 789 |
|
|---|
| 790 | ## Benchmarks
|
|---|
| 791 |
|
|---|
| 792 | You can see results [here](https://github.com/mrmlnc/fast-glob/actions/workflows/benchmark.yml?query=branch%3Amaster) for every commit into the `main` branch.
|
|---|
| 793 |
|
|---|
| 794 | * **Product benchmark** – comparison with the main competitors.
|
|---|
| 795 | * **Regress benchmark** – regression between the current version and the version from the npm registry.
|
|---|
| 796 |
|
|---|
| 797 | ## Changelog
|
|---|
| 798 |
|
|---|
| 799 | See the [Releases section of our GitHub project][github_releases] for changelog for each release version.
|
|---|
| 800 |
|
|---|
| 801 | ## License
|
|---|
| 802 |
|
|---|
| 803 | This software is released under the terms of the MIT license.
|
|---|
| 804 |
|
|---|
| 805 | [bash_hackers_syntax_expansion_brace]: https://wiki.bash-hackers.org/syntax/expansion/brace
|
|---|
| 806 | [github_releases]: https://github.com/mrmlnc/fast-glob/releases
|
|---|
| 807 | [glob_definition]: https://en.wikipedia.org/wiki/Glob_(programming)
|
|---|
| 808 | [glob_linux_man]: http://man7.org/linux/man-pages/man3/glob.3.html
|
|---|
| 809 | [micromatch_backslashes]: https://github.com/micromatch/micromatch#backslashes
|
|---|
| 810 | [micromatch_braces]: https://github.com/micromatch/braces
|
|---|
| 811 | [micromatch_extended_globbing]: https://github.com/micromatch/micromatch#extended-globbing
|
|---|
| 812 | [micromatch_extglobs]: https://github.com/micromatch/micromatch#extglobs
|
|---|
| 813 | [micromatch_regex_character_classes]: https://github.com/micromatch/micromatch#regex-character-classes
|
|---|
| 814 | [micromatch]: https://github.com/micromatch/micromatch
|
|---|
| 815 | [node_js_fs_class_fs_dirent]: https://nodejs.org/api/fs.html#fs_class_fs_dirent
|
|---|
| 816 | [node_js_fs_class_fs_stats]: https://nodejs.org/api/fs.html#fs_class_fs_stats
|
|---|
| 817 | [node_js_stream_readable_streams]: https://nodejs.org/api/stream.html#stream_readable_streams
|
|---|
| 818 | [node_js]: https://nodejs.org/en
|
|---|
| 819 | [nodelib_fs_scandir_old_and_modern_modern]: https://github.com/nodelib/nodelib/blob/master/packages/fs/fs.scandir/README.md#old-and-modern-mode
|
|---|
| 820 | [npm_normalize_path]: https://www.npmjs.com/package/normalize-path
|
|---|
| 821 | [npm_unixify]: https://www.npmjs.com/package/unixify
|
|---|
| 822 | [picomatch_matching_behavior]: https://github.com/micromatch/picomatch#matching-behavior-vs-bash
|
|---|
| 823 | [picomatch_matching_special_characters_as_literals]: https://github.com/micromatch/picomatch#matching-special-characters-as-literals
|
|---|
| 824 | [picomatch_posix_brackets]: https://github.com/micromatch/picomatch#posix-brackets
|
|---|
| 825 | [regular_expressions_brackets]: https://www.regular-expressions.info/brackets.html
|
|---|
| 826 | [unc_path]: https://learn.microsoft.com/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc
|
|---|
| 827 | [wikipedia_case_sensitivity]: https://en.wikipedia.org/wiki/Case_sensitivity
|
|---|
| 828 | [nodejs_thread_pool]: https://nodejs.org/en/docs/guides/dont-block-the-event-loop
|
|---|
| 829 | [libuv_thread_pool]: http://docs.libuv.org/en/v1.x/threadpool.html
|
|---|
| 830 | [windows_naming_conventions]: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
|
|---|