Skip to content

Commit e9f2cec

Browse files
committed
Revert "fs: Revert throw on invalid callbacks"
This reverts commit 8250bfd. PR-URL: nodejs#18668 Refs: nodejs#12562 Refs: nodejs#12976 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
1 parent 009e418 commit e9f2cec

13 files changed

+173
-116
lines changed

doc/api/deprecations.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,10 @@ explicitly via error event handlers set on the domain instead.
162162
<a id="DEP0013"></a>
163163
### DEP0013: fs asynchronous function without callback
164164

165-
Type: Runtime
165+
Type: End-of-Life
166166

167-
Calling an asynchronous function without a callback is deprecated.
167+
Calling an asynchronous function without a callback throws a `TypeError`
168+
REPLACEME onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562)
168169

169170
<a id="DEP0014"></a>
170171
### DEP0014: fs.read legacy String interface

doc/api/fs.md

+150-30
Large diffs are not rendered by default.

lib/fs.js

+5-49
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ const { kMaxLength } = require('buffer');
7777

7878
const isWindows = process.platform === 'win32';
7979

80-
const DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
8180
const errnoException = errors.errnoException;
8281

8382
let truncateWarn = true;
@@ -106,46 +105,17 @@ function handleErrorFromBinding(ctx) {
106105
}
107106
}
108107

109-
// TODO(joyeecheung): explore how the deprecation could be solved via linting
110-
// rules. See https://github.com/nodejs/node/pull/12976
111-
function rethrow() {
112-
process.emitWarning(
113-
'Calling an asynchronous function without callback is deprecated.',
114-
'DeprecationWarning', 'DEP0013', rethrow
115-
);
116-
117-
// Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
118-
// is fairly slow to generate.
119-
if (DEBUG) {
120-
var backtrace = new Error();
121-
return function(err) {
122-
if (err) {
123-
backtrace.stack = `${err.name}: ${err.message}` +
124-
backtrace.stack.substr(backtrace.name.length);
125-
throw backtrace;
126-
}
127-
};
128-
}
129-
130-
return function(err) {
131-
if (err) {
132-
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs
133-
}
134-
};
135-
}
136-
137108
function maybeCallback(cb) {
138-
return typeof cb === 'function' ? cb : rethrow();
109+
if (typeof cb === 'function')
110+
return cb;
111+
112+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
139113
}
140114

141115
// Ensure that callbacks run in the global context. Only use this function
142116
// for callbacks that are passed to the binding layer, callbacks that are
143117
// invoked from JS already run in the proper scope.
144118
function makeCallback(cb) {
145-
if (cb === undefined) {
146-
return rethrow();
147-
}
148-
149119
if (typeof cb !== 'function') {
150120
throw new errors.TypeError('ERR_INVALID_CALLBACK');
151121
}
@@ -159,10 +129,6 @@ function makeCallback(cb) {
159129
// an optimization, since the data passed back to the callback needs to be
160130
// transformed anyway.
161131
function makeStatsCallback(cb) {
162-
if (cb === undefined) {
163-
return rethrow();
164-
}
165-
166132
if (typeof cb !== 'function') {
167133
throw new errors.TypeError('ERR_INVALID_CALLBACK');
168134
}
@@ -191,8 +157,6 @@ fs.access = function(path, mode, callback) {
191157
if (typeof mode === 'function') {
192158
callback = mode;
193159
mode = fs.F_OK;
194-
} else if (typeof callback !== 'function') {
195-
throw new errors.TypeError('ERR_INVALID_CALLBACK');
196160
}
197161

198162
path = getPathFromURL(path);
@@ -218,16 +182,8 @@ fs.accessSync = function(path, mode) {
218182
handleErrorFromBinding(ctx);
219183
};
220184

221-
// fs.exists never throws even when the arguments are invalid - if there is
222-
// a callback it would invoke it with false, otherwise it emits a warning
223-
// (see the comments of rethrow()).
224-
// This is to bring it inline with fs.existsSync, which never throws.
225-
// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior
226185
fs.exists = function(path, callback) {
227-
if (typeof callback !== 'function') {
228-
rethrow();
229-
return;
230-
}
186+
maybeCallback(callback);
231187

232188
function suppressedCallback(err) {
233189
callback(err ? false : true);

test/fixtures/test-fs-readfile-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2020
// USE OR OTHER DEALINGS IN THE SOFTWARE.
2121

22-
require('fs').readFile('/'); // throws EISDIR
22+
require('fs').readFileSync('/'); // throws EISDIR

test/parallel/test-fs-access.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ fs.access(readOnlyFile, fs.F_OK | fs.R_OK, common.mustCall((err) => {
8080
assert.ifError(err);
8181
}));
8282

83-
fs.access(readOnlyFile, fs.W_OK, common.mustCall((err) => {
83+
fs.access(readOnlyFile, fs.W_OK, common.mustCall(function(err) {
84+
assert.strictEqual(this, undefined);
8485
if (hasWriteAccessForReadonlyFile) {
8586
assert.ifError(err);
8687
} else {

test/parallel/test-fs-append-file.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,9 @@ fs.open(filename5, 'a+', function(e, fd) {
146146
});
147147
});
148148

149-
// test that a missing callback emits a warning, even if the last argument is a
150-
// function.
151-
const filename6 = join(tmpdir.path, 'append6.txt');
152-
const warn = 'Calling an asynchronous function without callback is deprecated.';
153-
common.expectWarning('DeprecationWarning', warn);
154-
fs.appendFile(filename6, console.log);
149+
assert.throws(
150+
() => fs.appendFile(join(tmpdir.path, 'append6.txt'), console.log),
151+
{ code: 'ERR_INVALID_CALLBACK' });
155152

156153
process.on('exit', function() {
157154
assert.strictEqual(12, ncallbacks);

test/parallel/test-fs-exists.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ const fs = require('fs');
2626
const { URL } = require('url');
2727
const f = __filename;
2828

29-
// Only warnings are emitted when the callback is invalid
30-
fs.exists(f);
31-
fs.exists();
32-
fs.exists(f, {});
29+
assert.throws(() => fs.exists(f), { code: 'ERR_INVALID_CALLBACK' });
30+
assert.throws(() => fs.exists(), { code: 'ERR_INVALID_CALLBACK' });
31+
assert.throws(() => fs.exists(f, {}), { code: 'ERR_INVALID_CALLBACK' });
3332

3433
fs.exists(f, common.mustCall(function(y) {
3534
assert.strictEqual(y, true);

test/parallel/test-fs-fchmod.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const fs = require('fs');
4444

4545
// Check for mode values range
4646
const modeUpperBoundaryValue = 0o777;
47-
fs.fchmod(1, modeUpperBoundaryValue);
47+
fs.fchmod(1, modeUpperBoundaryValue, common.mustCall());
4848
fs.fchmodSync(1, modeUpperBoundaryValue);
4949

5050
// umask of 0o777 is equal to 775

test/parallel/test-fs-make-callback.js

-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const fs = require('fs');
44
const callbackThrowValues = [null, true, false, 0, 1, 'foo', /foo/, [], {}];
55

66
const { sep } = require('path');
7-
const warn = 'Calling an asynchronous function without callback is deprecated.';
87

98
const tmpdir = require('../common/tmpdir');
109
tmpdir.refresh();
@@ -16,11 +15,6 @@ function testMakeCallback(cb) {
1615
};
1716
}
1817

19-
common.expectWarning('DeprecationWarning', warn);
20-
21-
// Passing undefined/nothing calls rethrow() internally, which emits a warning
22-
testMakeCallback()();
23-
2418
function invalidCallbackThrowsTests() {
2519
callbackThrowValues.forEach((value) => {
2620
common.expectsError(testMakeCallback(value), {

test/parallel/test-fs-makeStatsCallback.js

-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const common = require('../common');
33
const fs = require('fs');
44
const callbackThrowValues = [null, true, false, 0, 1, 'foo', /foo/, [], {}];
5-
const warn = 'Calling an asynchronous function without callback is deprecated.';
65

76
function testMakeStatsCallback(cb) {
87
return function() {
@@ -11,14 +10,9 @@ function testMakeStatsCallback(cb) {
1110
};
1211
}
1312

14-
common.expectWarning('DeprecationWarning', warn);
15-
1613
// Verify the case where a callback function is provided
1714
testMakeStatsCallback(common.mustCall())();
1815

19-
// Passing undefined/nothing calls rethrow() internally, which emits a warning
20-
testMakeStatsCallback()();
21-
2216
function invalidCallbackThrowsTests() {
2317
callbackThrowValues.forEach((value) => {
2418
common.expectsError(testMakeStatsCallback(value), {

test/parallel/test-fs-mkdtemp.js

-5
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,3 @@ fs.mkdtemp(path.join(tmpdir.path, 'bar.'), common.mustCall(handler));
2929
// Same test as above, but making sure that passing an options object doesn't
3030
// affect the way the callback function is handled.
3131
fs.mkdtemp(path.join(tmpdir.path, 'bar.'), {}, common.mustCall(handler));
32-
33-
// Making sure that not passing a callback doesn't crash, as a default function
34-
// is passed internally.
35-
fs.mkdtemp(path.join(tmpdir.path, 'bar-'));
36-
fs.mkdtemp(path.join(tmpdir.path, 'bar-'), {});

test/parallel/test-fs-readfile-error.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function test(env, cb) {
4848

4949
test({ NODE_DEBUG: '' }, common.mustCall((data) => {
5050
assert(/EISDIR/.test(data));
51-
assert(!/test-fs-readfile-error/.test(data));
51+
assert(/test-fs-readfile-error/.test(data));
5252
}));
5353

5454
test({ NODE_DEBUG: 'fs' }, common.mustCall((data) => {
@@ -57,7 +57,7 @@ test({ NODE_DEBUG: 'fs' }, common.mustCall((data) => {
5757
}));
5858

5959
common.expectsError(
60-
() => { fs.readFile(() => {}); },
60+
() => { fs.readFile(() => {}, common.mustNotCall()); },
6161
{
6262
code: 'ERR_INVALID_ARG_TYPE',
6363
message: 'The "path" argument must be one of type string, Buffer, or URL',

test/parallel/test-fs-write-no-fd.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use strict';
2-
require('../common');
2+
const common = require('../common');
33
const fs = require('fs');
44
const assert = require('assert');
55

66
assert.throws(function() {
7-
fs.write(null, Buffer.allocUnsafe(1), 0, 1);
7+
fs.write(null, Buffer.allocUnsafe(1), 0, 1, common.mustNotCall());
88
}, /TypeError/);
99

1010
assert.throws(function() {
11-
fs.write(null, '1', 0, 1);
11+
fs.write(null, '1', 0, 1, common.mustNotCall());
1212
}, /TypeError/);

0 commit comments

Comments
 (0)