Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -3057,6 +3057,9 @@ The [`crypto.Certificate()` constructor][] is deprecated. Use

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/58616
description: End-of-Life.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/37302
description: Runtime deprecation.
Expand All @@ -3068,10 +3071,10 @@ changes:
description: Documentation-only deprecation.
-->

Type: Runtime
Type: End-of-Life

In future versions of Node.js, `recursive` option will be ignored for
`fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir`.
The `fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir` methods used
to support a `recursive` option. That option has been removed.

Use `fs.rm(path, { recursive: true, force: true })`,
`fs.rmSync(path, { recursive: true, force: true })` or
Expand Down
57 changes: 21 additions & 36 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1589,6 +1589,9 @@
<!-- YAML
added: v10.0.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/00000

Check warning on line 1593 in doc/api/fs.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: Remove `recursive` option.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/37216
description: "Using `fsPromises.rmdir(path, { recursive: true })` on a `path`
Expand Down Expand Up @@ -1622,18 +1625,10 @@
-->
* `path` {string|Buffer|URL}
* `options` {Object}
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
`EPERM` error is encountered, Node.js retries the operation with a linear
backoff wait of `retryDelay` milliseconds longer on each try. This option
represents the number of retries. This option is ignored if the `recursive`
option is not `true`. **Default:** `0`.
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
recursive mode, operations are retried on failure. **Default:** `false`.
**Deprecated.**
* `retryDelay` {integer} The amount of time in milliseconds to wait between
retries. This option is ignored if the `recursive` option is not `true`.
**Default:** `100`.
* `options` {Object} There are currently no options exposed. There used to
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
deprecated and removed. The `options` argument is still accepted for
backwards compatibility but it is not used.
* Returns: {Promise} Fulfills with `undefined` upon success.
Removes the directory identified by `path`.
Expand Down Expand Up @@ -4255,6 +4250,9 @@
<!-- YAML
added: v0.0.2
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/00000

Check warning on line 4254 in doc/api/fs.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: Remove `recursive` option.
- version: v18.0.0
pr-url: https://github.com/nodejs/node/pull/41678
description: Passing an invalid callback to the `callback` argument
Expand Down Expand Up @@ -4305,18 +4303,10 @@
-->
* `path` {string|Buffer|URL}
* `options` {Object}
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
`EPERM` error is encountered, Node.js retries the operation with a linear
backoff wait of `retryDelay` milliseconds longer on each try. This option
represents the number of retries. This option is ignored if the `recursive`
option is not `true`. **Default:** `0`.
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
recursive mode, operations are retried on failure. **Default:** `false`.
**Deprecated.**
* `retryDelay` {integer} The amount of time in milliseconds to wait between
retries. This option is ignored if the `recursive` option is not `true`.
**Default:** `100`.
* `options` {Object} There are currently no options exposed. There used to
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
deprecated and removed. The `options` argument is still accepted for
backwards compatibility but it is not used.
* `callback` {Function}
* `err` {Error}
Expand Down Expand Up @@ -6234,6 +6224,9 @@
<!-- YAML
added: v0.1.21
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/00000

Check warning on line 6228 in doc/api/fs.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: Remove `recursive` option.
- version: v16.0.0
pr-url: https://github.com/nodejs/node/pull/37216
description: "Using `fs.rmdirSync(path, { recursive: true })` on a `path`
Expand Down Expand Up @@ -6271,18 +6264,10 @@
-->
* `path` {string|Buffer|URL}
* `options` {Object}
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
`EPERM` error is encountered, Node.js retries the operation with a linear
backoff wait of `retryDelay` milliseconds longer on each try. This option
represents the number of retries. This option is ignored if the `recursive`
option is not `true`. **Default:** `0`.
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
recursive mode, operations are retried on failure. **Default:** `false`.
**Deprecated.**
* `retryDelay` {integer} The amount of time in milliseconds to wait between
retries. This option is ignored if the `recursive` option is not `true`.
**Default:** `100`.
* `options` {Object} There are currently no options exposed. There used to
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
deprecated and removed. The `options` argument is still accepted for
backwards compatibility but it is not used.
Synchronous rmdir(2). Returns `undefined`.
Expand Down
66 changes: 21 additions & 45 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ const {
},
copyObject,
Dirent,
emitRecursiveRmdirWarning,
getDirent,
getDirents,
getOptions,
Expand Down Expand Up @@ -1108,11 +1107,7 @@ function lazyLoadRimraf() {
/**
* Asynchronously removes a directory.
* @param {string | Buffer | URL} path
* @param {{
* maxRetries?: number;
* recursive?: boolean;
* retryDelay?: number;
* }} [options]
* @param {{}} [options]
* @param {(err?: Error) => any} callback
* @returns {void}
*/
Expand All @@ -1122,60 +1117,41 @@ function rmdir(path, options, callback) {
options = undefined;
}

if (options?.recursive !== undefined) {
throw new ERR_INVALID_ARG_VALUE(
'options.recursive',
options.recursive,
'is no longer supported',
);
}

callback = makeCallback(callback);
path = getValidatedPath(path);

if (options?.recursive) {
emitRecursiveRmdirWarning();
validateRmOptions(
path,
{ ...options, force: false },
true,
(err, options) => {
if (err === false) {
const req = new FSReqCallback();
req.oncomplete = callback;
binding.rmdir(path, req);
return;
}
if (err) {
return callback(err);
}

lazyLoadRimraf();
rimraf(path, options, callback);
});
} else {
validateRmdirOptions(options);
const req = new FSReqCallback();
req.oncomplete = callback;
binding.rmdir(path, req);
}
validateRmdirOptions(options);
const req = new FSReqCallback();
req.oncomplete = callback;
binding.rmdir(path, req);
}

/**
* Synchronously removes a directory.
* @param {string | Buffer | URL} path
* @param {{
* maxRetries?: number;
* recursive?: boolean;
* retryDelay?: number;
* }} [options]
* @param {{}} [options]
* @returns {void}
*/
function rmdirSync(path, options) {
path = getValidatedPath(path);

if (options?.recursive) {
emitRecursiveRmdirWarning();
options = validateRmOptionsSync(path, { ...options, force: false }, true);
if (options !== false) {
return binding.rmSync(path, options.maxRetries, options.recursive, options.retryDelay);
}
} else {
validateRmdirOptions(options);
if (options?.recursive !== undefined) {
throw new ERR_INVALID_ARG_VALUE(
'options.recursive',
options.recursive,
'is no longer supported',
);
}

validateRmdirOptions(options);
binding.rmdir(path);
}

Expand Down
16 changes: 8 additions & 8 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const {
kWriteFileMaxChunkSize,
},
copyObject,
emitRecursiveRmdirWarning,
getDirents,
getOptions,
getStatFsFromBinding,
Expand Down Expand Up @@ -812,16 +811,17 @@ async function rm(path, options) {

async function rmdir(path, options) {
path = getValidatedPath(path);
options = validateRmdirOptions(options);

if (options.recursive) {
emitRecursiveRmdirWarning();
const stats = await stat(path);
if (stats.isDirectory()) {
return lazyRimRaf()(path, options);
}
if (options?.recursive !== undefined) {
throw new ERR_INVALID_ARG_VALUE(
'options.recursive',
options.recursive,
'is no longer supported',
);
}

options = validateRmdirOptions(options);

return await PromisePrototypeThen(
binding.rmdir(path, kUsePromises),
undefined,
Expand Down
39 changes: 9 additions & 30 deletions lib/internal/fs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,12 +778,6 @@ const defaultRmOptions = {
maxRetries: 0,
};

const defaultRmdirOptions = {
retryDelay: 100,
maxRetries: 0,
recursive: false,
};

const validateCpOptions = hideStackFrames((options) => {
if (options === undefined)
return { ...defaultCpOptions };
Expand All @@ -807,7 +801,10 @@ const validateCpOptions = hideStackFrames((options) => {

const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
options = validateRmdirOptions(options, defaultRmOptions);
validateBoolean(options.force, 'options.force');
validateBoolean.withoutStackTrace(options.force, 'options.force');
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');

lazyLoadFs().lstat(path, (err, stats) => {
if (err) {
Expand Down Expand Up @@ -839,6 +836,10 @@ const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
validateBoolean.withoutStackTrace(options.force, 'options.force');
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');


if (!options.force || expectDir || !options.recursive) {
const isDirectory = lazyLoadFs()
Expand All @@ -862,35 +863,14 @@ const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
return options;
});

let recursiveRmdirWarned;
function emitRecursiveRmdirWarning() {
if (recursiveRmdirWarned === undefined) {
// TODO(joyeecheung): use getOptionValue('--no-deprecation') instead.
recursiveRmdirWarned = process.noDeprecation;
}
if (!recursiveRmdirWarned) {
process.emitWarning(
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
'will be removed. Use fs.rm(path, { recursive: true }) instead',
'DeprecationWarning',
'DEP0147',
);
recursiveRmdirWarned = true;
}
}

const validateRmdirOptions = hideStackFrames(
(options, defaults = defaultRmdirOptions) => {
(options, defaults = { __proto__: null }) => {
if (options === undefined)
return defaults;
validateObject.withoutStackTrace(options, 'options');

options = { ...defaults, ...options };

validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');

return options;
});

Expand Down Expand Up @@ -950,7 +930,6 @@ module.exports = {
copyObject,
Dirent,
DirentFromStats,
emitRecursiveRmdirWarning,
getDirent,
getDirents,
getOptions,
Expand Down
31 changes: 31 additions & 0 deletions test/parallel/test-fs-rmdir-recursive-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const {
rmdir,
rmdirSync,
promises: { rmdir: rmdirPromise }
} = require('fs');

assert.throws(() => {
rmdir('nonexistent', {
recursive: true,
}, common.mustNotCall());
}, {
code: 'ERR_INVALID_ARG_VALUE',
});

assert.throws(() => {
rmdirSync('nonexistent', {
recursive: true,
});
}, {
code: 'ERR_INVALID_ARG_VALUE',
});

rmdirPromise('nonexistent', {
recursive: true,
}).then(common.mustNotCall(), common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');
}));
22 changes: 0 additions & 22 deletions test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js

This file was deleted.

Loading
Loading