Skip to content

Commit 98d4b96

Browse files
committed
fs: move rmdir recursive option to end-of-life
Has been runtime deprecated for ~ 5 years now. It's time.
1 parent 0b3fc0d commit 98d4b96

12 files changed

+80
-398
lines changed

doc/api/deprecations.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,6 +3057,9 @@ The [`crypto.Certificate()` constructor][] is deprecated. Use
30573057

30583058
<!-- YAML
30593059
changes:
3060+
- version: REPLACEME
3061+
pr-url: https://github.com/nodejs/node/pull/58616
3062+
description: End-of-Life.
30603063
- version: v16.0.0
30613064
pr-url: https://github.com/nodejs/node/pull/37302
30623065
description: Runtime deprecation.
@@ -3068,10 +3071,10 @@ changes:
30683071
description: Documentation-only deprecation.
30693072
-->
30703073

3071-
Type: Runtime
3074+
Type: End-of-Life
30723075

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

30763079
Use `fs.rm(path, { recursive: true, force: true })`,
30773080
`fs.rmSync(path, { recursive: true, force: true })` or

lib/fs.js

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ const {
101101
},
102102
copyObject,
103103
Dirent,
104-
emitRecursiveRmdirWarning,
105104
getDirent,
106105
getDirents,
107106
getOptions,
@@ -1108,11 +1107,7 @@ function lazyLoadRimraf() {
11081107
/**
11091108
* Asynchronously removes a directory.
11101109
* @param {string | Buffer | URL} path
1111-
* @param {{
1112-
* maxRetries?: number;
1113-
* recursive?: boolean;
1114-
* retryDelay?: number;
1115-
* }} [options]
1110+
* @param {{}} [options]
11161111
* @param {(err?: Error) => any} callback
11171112
* @returns {void}
11181113
*/
@@ -1122,60 +1117,41 @@ function rmdir(path, options, callback) {
11221117
options = undefined;
11231118
}
11241119

1120+
if (options?.recursive !== undefined) {
1121+
throw new ERR_INVALID_ARG_VALUE(
1122+
'options.recursive',
1123+
options.recursive,
1124+
'is no longer supported',
1125+
);
1126+
}
1127+
11251128
callback = makeCallback(callback);
11261129
path = getValidatedPath(path);
11271130

1128-
if (options?.recursive) {
1129-
emitRecursiveRmdirWarning();
1130-
validateRmOptions(
1131-
path,
1132-
{ ...options, force: false },
1133-
true,
1134-
(err, options) => {
1135-
if (err === false) {
1136-
const req = new FSReqCallback();
1137-
req.oncomplete = callback;
1138-
binding.rmdir(path, req);
1139-
return;
1140-
}
1141-
if (err) {
1142-
return callback(err);
1143-
}
1144-
1145-
lazyLoadRimraf();
1146-
rimraf(path, options, callback);
1147-
});
1148-
} else {
1149-
validateRmdirOptions(options);
1150-
const req = new FSReqCallback();
1151-
req.oncomplete = callback;
1152-
binding.rmdir(path, req);
1153-
}
1131+
validateRmdirOptions(options);
1132+
const req = new FSReqCallback();
1133+
req.oncomplete = callback;
1134+
binding.rmdir(path, req);
11541135
}
11551136

11561137
/**
11571138
* Synchronously removes a directory.
11581139
* @param {string | Buffer | URL} path
1159-
* @param {{
1160-
* maxRetries?: number;
1161-
* recursive?: boolean;
1162-
* retryDelay?: number;
1163-
* }} [options]
1140+
* @param {{}} [options]
11641141
* @returns {void}
11651142
*/
11661143
function rmdirSync(path, options) {
11671144
path = getValidatedPath(path);
11681145

1169-
if (options?.recursive) {
1170-
emitRecursiveRmdirWarning();
1171-
options = validateRmOptionsSync(path, { ...options, force: false }, true);
1172-
if (options !== false) {
1173-
return binding.rmSync(path, options.maxRetries, options.recursive, options.retryDelay);
1174-
}
1175-
} else {
1176-
validateRmdirOptions(options);
1146+
if (options?.recursive !== undefined) {
1147+
throw new ERR_INVALID_ARG_VALUE(
1148+
'options.recursive',
1149+
options.recursive,
1150+
'is no longer supported',
1151+
);
11771152
}
11781153

1154+
validateRmdirOptions(options);
11791155
binding.rmdir(path);
11801156
}
11811157

lib/internal/fs/promises.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ const {
5656
kWriteFileMaxChunkSize,
5757
},
5858
copyObject,
59-
emitRecursiveRmdirWarning,
6059
getDirents,
6160
getOptions,
6261
getStatFsFromBinding,
@@ -812,16 +811,17 @@ async function rm(path, options) {
812811

813812
async function rmdir(path, options) {
814813
path = getValidatedPath(path);
815-
options = validateRmdirOptions(options);
816814

817-
if (options.recursive) {
818-
emitRecursiveRmdirWarning();
819-
const stats = await stat(path);
820-
if (stats.isDirectory()) {
821-
return lazyRimRaf()(path, options);
822-
}
815+
if (options?.recursive !== undefined) {
816+
throw new ERR_INVALID_ARG_VALUE(
817+
'options.recursive',
818+
options.recursive,
819+
'is no longer supported',
820+
);
823821
}
824822

823+
options = validateRmdirOptions(options);
824+
825825
return await PromisePrototypeThen(
826826
binding.rmdir(path, kUsePromises),
827827
undefined,

lib/internal/fs/utils.js

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -778,12 +778,6 @@ const defaultRmOptions = {
778778
maxRetries: 0,
779779
};
780780

781-
const defaultRmdirOptions = {
782-
retryDelay: 100,
783-
maxRetries: 0,
784-
recursive: false,
785-
};
786-
787781
const validateCpOptions = hideStackFrames((options) => {
788782
if (options === undefined)
789783
return { ...defaultCpOptions };
@@ -807,7 +801,10 @@ const validateCpOptions = hideStackFrames((options) => {
807801

808802
const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
809803
options = validateRmdirOptions(options, defaultRmOptions);
810-
validateBoolean(options.force, 'options.force');
804+
validateBoolean.withoutStackTrace(options.force, 'options.force');
805+
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
806+
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
807+
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
811808

812809
lazyLoadFs().lstat(path, (err, stats) => {
813810
if (err) {
@@ -839,6 +836,10 @@ const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
839836
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
840837
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
841838
validateBoolean.withoutStackTrace(options.force, 'options.force');
839+
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
840+
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
841+
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
842+
842843

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

865-
let recursiveRmdirWarned;
866-
function emitRecursiveRmdirWarning() {
867-
if (recursiveRmdirWarned === undefined) {
868-
// TODO(joyeecheung): use getOptionValue('--no-deprecation') instead.
869-
recursiveRmdirWarned = process.noDeprecation;
870-
}
871-
if (!recursiveRmdirWarned) {
872-
process.emitWarning(
873-
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
874-
'will be removed. Use fs.rm(path, { recursive: true }) instead',
875-
'DeprecationWarning',
876-
'DEP0147',
877-
);
878-
recursiveRmdirWarned = true;
879-
}
880-
}
881-
882866
const validateRmdirOptions = hideStackFrames(
883-
(options, defaults = defaultRmdirOptions) => {
867+
(options, defaults = { __proto__: null }) => {
884868
if (options === undefined)
885869
return defaults;
886870
validateObject.withoutStackTrace(options, 'options');
887871

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

890-
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
891-
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
892-
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
893-
894874
return options;
895875
});
896876

@@ -950,7 +930,6 @@ module.exports = {
950930
copyObject,
951931
Dirent,
952932
DirentFromStats,
953-
emitRecursiveRmdirWarning,
954933
getDirent,
955934
getDirents,
956935
getOptions,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const {
6+
rmdir,
7+
rmdirSync,
8+
promises: { rmdir: rmdirPromise }
9+
} = require('fs');
10+
11+
assert.throws(() => {
12+
rmdir('nonexistent', {
13+
recursive: true,
14+
}, common.mustNotCall());
15+
}, {
16+
code: 'ERR_INVALID_ARG_VALUE',
17+
});
18+
19+
assert.throws(() => {
20+
rmdirSync('nonexistent', {
21+
recursive: true,
22+
});
23+
}, {
24+
code: 'ERR_INVALID_ARG_VALUE',
25+
});
26+
27+
rmdirPromise('nonexistent', {
28+
recursive: true,
29+
}).then(common.mustNotCall(), common.mustCall((err) => {
30+
assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');
31+
}));

test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js

Lines changed: 0 additions & 22 deletions
This file was deleted.

test/parallel/test-fs-rmdir-recursive-sync-warns-on-file.js

Lines changed: 0 additions & 22 deletions
This file was deleted.

test/parallel/test-fs-rmdir-recursive-warns-not-found.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

test/parallel/test-fs-rmdir-recursive-warns-on-file.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)