Skip to content

Commit

Permalink
fs: add new option depth to readdir which regulates depth of recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
prettydiff committed Sep 12, 2023
1 parent 41a3a1d commit 6460775
Show file tree
Hide file tree
Showing 4 changed files with 669 additions and 73 deletions.
237 changes: 234 additions & 3 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,9 @@ closed after the iterator exits.
<!-- YAML
added: v10.0.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/49255
description: Extended `recursive` option to allow a function for filtering.
- version:
- v20.1.0
- v18.17.0
Expand All @@ -1304,7 +1307,12 @@ changes:
* `options` {string|Object}
* `encoding` {string} **Default:** `'utf8'`
* `withFileTypes` {boolean} **Default:** `false`
* `recursive` {boolean} **Default:** `false`
* `recursive` {boolean|Function} **Default:** `false`
* `directory` {string|fs.Dirent} A given directory file system artifact
name.
* `depth` {integer} The number of steps traversed from the supplied base
path.
* Returns: {boolean}
* Returns: {Promise} Fulfills with an array of the names of the files in
the directory excluding `'.'` and `'..'`.
Expand All @@ -1318,6 +1326,13 @@ will be passed as {Buffer} objects.
If `options.withFileTypes` is set to `true`, the resolved array will contain
{fs.Dirent} objects.
When passing a function to `options.recursive` the first argument populates
with the name of a directory, or {fs.Dirent} object if `options.withFileTypes`
is true, and directory depth relative to the base path as the second argument.
This function expects to return a boolean which determines the descendant
directories to traverse. Filtering using this function does not limit what
populates in the resultant list, only which descendant directories to traverse.
```mjs
import { readdir } from 'node:fs/promises';
Expand All @@ -1330,6 +1345,68 @@ try {
}
```
Example with unfiltered recursion.
```mjs
import { readdir } from 'node:fs/promises';
try {
// Will traverse all descendant directories, fully recursive
const files = await readdir(path, { recursive: true });
for (const file of files)
console.log(file);
} catch (err) {
console.error(err);
}
```
Example with filtered recursion.
```mjs
import { readdir } from 'node:fs/promises';
try {
const files = await readdir(path, { recursive: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name
return (directory.includes('system') && depth < 5);
} });
for (const file of files)
console.log(file);
} catch (err) {
console.error(err);
}
```
Example with filtered recursion and dirent.
```mjs
import { readdir } from 'node:fs/promises';
try {
const files = await readdir(path, {
withFileTypes: true,
recursive: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name and 'games' in the path string
return (
directory.name.includes('system') &&
depth < 5
);
},
});
for (const file of files)
console.log(file);
} catch (err) {
console.error(err);
}
// Should expect result: 'games/combat/system'
// Should not expect result: 'action/q/v/games/combat/system'
// Should not expect result: 'games/action'
```
### `fsPromises.readFile(path[, options])`
<!-- YAML
Expand Down Expand Up @@ -3580,6 +3657,9 @@ above values.
<!-- YAML
added: v0.1.8
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/49255
description: Extended `recursive` option to allow a function for filtering.
- version:
- v20.1.0
- v18.17.0
Expand Down Expand Up @@ -3614,7 +3694,12 @@ changes:
* `options` {string|Object}
* `encoding` {string} **Default:** `'utf8'`
* `withFileTypes` {boolean} **Default:** `false`
* `recursive` {boolean} **Default:** `false`
* `recursive` {boolean|Function} **Default:** `false`
* `directory` {string|fs.Dirent} A given directory file system artifact
name.
* `depth` {integer} The number of steps traversed from the supplied base
path.
* Returns: {boolean}
* `callback` {Function}
* `err` {Error}
* `files` {string\[]|Buffer\[]|fs.Dirent\[]}
Expand All @@ -3633,6 +3718,85 @@ the filenames returned will be passed as {Buffer} objects.
If `options.withFileTypes` is set to `true`, the `files` array will contain
{fs.Dirent} objects.
When passing a function to `options.recursive` the first argument populates
with the name of a directory, or {fs.Dirent} object if `options.withFileTypes`
is true, and directory depth relative to the base path as the second argument.
This function expects to return a boolean which determines the descendant
directories to traverse. Filtering using this function does not limit what
populates in the resultant list, only which descendant directories to traverse.
```mjs
import { readdir } from 'node:fs';

function callback(err, files) {
if (err === null) {
console.log(files);
}
}
fs.readdir(path, callback);
```
Example with unfiltered recursion.
```mjs
import { readdir } from 'node:fs';

function callback(err, files) {
if (err === null) {
console.log(files);
}
}
// Will traverse all descendant directories, fully recursive
fs.readdir(path, { recursion: true }, callback);
```
Example with filtered recursion.
```mjs
import { readdir } from 'node:fs';

function callback(err, files) {
if (err === null) {
console.log(files);
}
}
fs.readdir(path, {
recursion: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name
return (directory.includes('system') && depth < 5);
},
}, callback);
```
Example with filtered recursion and dirent.
```mjs
import { readdir } from 'node:fs';

function callback(err, files) {
if (err === null) {
console.log(files);
}
}
fs.readdir(path, {
withFileTypes: true,
recursion: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name and 'games' in the path string
return (
directory.name.includes('system') &&
depth < 5
);
},
}, callback);
// Should expect result: 'games/combat/system'
// Should not expect result: 'action/q/v/games/combat/system'
// Should not expect result: 'games/action'
```
### `fs.readFile(path[, options], callback)`
<!-- YAML
Expand Down Expand Up @@ -5662,6 +5826,9 @@ this API: [`fs.open()`][].
<!-- YAML
added: v0.1.21
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/49255
description: Extended `recursive` option to allow a function for filtering.
- version:
- v20.1.0
- v18.17.0
Expand All @@ -5680,7 +5847,12 @@ changes:
* `options` {string|Object}
* `encoding` {string} **Default:** `'utf8'`
* `withFileTypes` {boolean} **Default:** `false`
* `recursive` {boolean} **Default:** `false`
* `recursive` {boolean|Function} **Default:** `false`
* `directory` {string|fs.Dirent} A given directory file system artifact
name.
* `depth` {integer} The number of steps traversed from the supplied base
path.
* Returns: {boolean}
* Returns: {string\[]|Buffer\[]|fs.Dirent\[]}
Reads the contents of the directory.
Expand All @@ -5695,6 +5867,65 @@ the filenames returned will be passed as {Buffer} objects.
If `options.withFileTypes` is set to `true`, the result will contain
{fs.Dirent} objects.
When passing a function to `options.recursive` the first argument populates
with the name of a directory, or {fs.Dirent} object if `options.withFileTypes`
is true, and directory depth relative to the base path as the second argument.
This function expects to return a boolean which determines the descendant
directories to traverse. Filtering using this function does not limit what
populates in the resultant list, only which descendant directories to traverse.
```mjs
import { readdir } from 'node:fs';
const files = fs.readdirSync(path);
```
Example with unfiltered recursion.
```mjs
import { readdir } from 'node:fs';
// Will traverse all descendant directories, fully recursive
const files = fs.readdirSync(path, { recursion: true });
```
Example with filtered recursion.
```mjs
import { readdir } from 'node:fs';
const files = fs.readdirSync(path, {
recursion: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name
return (directory.includes('system') && depth < 5);
},
});
```
Example with filtered recursion and dirent.
```mjs
import { readdir } from 'node:fs';

const files = fs.readdirSync(path, {
withFileTypes: true,
recursion: function(directory, depth) {
// Will not traverse directories with a depth greater than 4 and
// will traverse directories only that contain 'system' in the
// directory's name and 'games' in the path string
return (
directory.name.includes('system') &&
depth < 5
);
},
});
// Should expect result: 'games/combat/system'
// Should not expect result: 'action/q/v/games/combat/system'
// Should not expect result: 'games/action'
```
### `fs.readFileSync(path[, options])`
<!-- YAML
Expand Down
Loading

0 comments on commit 6460775

Please sign in to comment.