Skip to content

Commit 219932a

Browse files
matzavinosrefack
matzavinos
authored andcommitted
errors: convert 'fs'
covert lib/fs.js over to using lib/internal/errors.js i have not addressed the cases that use errnoException(), for reasons described in GH-12926 - throw the ERR_INVALID_CALLBACK error when the the callback is invalid - replace the ['object', 'string'] with ['string', 'object'] in the error constructor call, to better match the previous err msg in the getOptions() function - add error ERR_VALUE_OUT_OF_RANGE in lib/internal/errors.js, this error is thrown when a numeric value is out of range - document the ERR_VALUE_OUT_OF_RANGE err in errors.md - correct the expected args, in the error thrown in the function fs._toUnixTimestamp() to ['Date', 'time in seconds'] (lib/fs.js) - update the listener error type in the fs.watchFile() function, from Error to TypeError (lib/fs.js) - update errors from ERR_INVALID_OPT_VALUE to ERR_INVALID_ARG_TYPE in the functions fs.ReadStream() and fs.WriteStream(), for the cases of range errors use the new error: ERR_VALUE_OUT_OF_RANGE (lib/fs.js) PR-URL: #15043 Refs: #11273 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent a517466 commit 219932a

17 files changed

+246
-116
lines changed

doc/api/errors.md

+5
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,11 @@ Used when an attempt is made to launch a Node.js process with an unknown
11361136
by errors in user code, although it is not impossible. Occurrences of this error
11371137
are most likely an indication of a bug within Node.js itself.
11381138

1139+
<a id="ERR_VALUE_OUT_OF_RANGE"></a>
1140+
### ERR_VALUE_OUT_OF_RANGE
1141+
1142+
Used when a number value is out of range.
1143+
11391144
<a id="ERR_V8BREAKITERATOR"></a>
11401145
### ERR_V8BREAKITERATOR
11411146

lib/fs.js

+55-18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const { isUint8Array, createPromise, promiseResolve } = process.binding('util');
3333
const binding = process.binding('fs');
3434
const fs = exports;
3535
const Buffer = require('buffer').Buffer;
36+
const errors = require('internal/errors');
3637
const Stream = require('stream').Stream;
3738
const EventEmitter = require('events');
3839
const FSReqWrap = binding.FSReqWrap;
@@ -72,8 +73,10 @@ function getOptions(options, defaultOptions) {
7273
defaultOptions.encoding = options;
7374
options = defaultOptions;
7475
} else if (typeof options !== 'object') {
75-
throw new TypeError('"options" must be a string or an object, got ' +
76-
typeof options + ' instead.');
76+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
77+
'options',
78+
['string', 'object'],
79+
options);
7780
}
7881

7982
if (options.encoding !== 'buffer')
@@ -128,7 +131,7 @@ function makeCallback(cb) {
128131
}
129132

130133
if (typeof cb !== 'function') {
131-
throw new TypeError('"callback" argument must be a function');
134+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
132135
}
133136

134137
return function() {
@@ -145,7 +148,7 @@ function makeStatsCallback(cb) {
145148
}
146149

147150
if (typeof cb !== 'function') {
148-
throw new TypeError('"callback" argument must be a function');
151+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
149152
}
150153

151154
return function(err) {
@@ -156,8 +159,11 @@ function makeStatsCallback(cb) {
156159

157160
function nullCheck(path, callback) {
158161
if (('' + path).indexOf('\u0000') !== -1) {
159-
var er = new Error('Path must be a string without null bytes');
160-
er.code = 'ENOENT';
162+
const er = new errors.Error('ERR_INVALID_ARG_TYPE',
163+
'path',
164+
'string without null bytes',
165+
path);
166+
161167
if (typeof callback !== 'function')
162168
throw er;
163169
process.nextTick(callback, er);
@@ -274,7 +280,7 @@ fs.access = function(path, mode, callback) {
274280
callback = mode;
275281
mode = fs.F_OK;
276282
} else if (typeof callback !== 'function') {
277-
throw new TypeError('"callback" argument must be a function');
283+
throw new errors.TypeError('ERR_INVALID_CALLBACK');
278284
}
279285

280286
if (handleError((path = getPathFromURL(path)), callback))
@@ -1193,7 +1199,10 @@ function toUnixTimestamp(time) {
11931199
// convert to 123.456 UNIX timestamp
11941200
return time.getTime() / 1000;
11951201
}
1196-
throw new Error('Cannot parse time: ' + time);
1202+
throw new errors.Error('ERR_INVALID_ARG_TYPE',
1203+
'time',
1204+
['Date', 'time in seconds'],
1205+
time);
11971206
}
11981207

11991208
// exported for unit tests, not for public consumption
@@ -1495,7 +1504,10 @@ fs.watchFile = function(filename, options, listener) {
14951504
}
14961505

14971506
if (typeof listener !== 'function') {
1498-
throw new Error('"watchFile()" requires a listener function');
1507+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
1508+
'listener',
1509+
'function',
1510+
listener);
14991511
}
15001512

15011513
stat = statWatchers.get(filename);
@@ -1842,8 +1854,12 @@ fs.realpath = function realpath(p, options, callback) {
18421854
fs.mkdtemp = function(prefix, options, callback) {
18431855
callback = makeCallback(typeof options === 'function' ? options : callback);
18441856
options = getOptions(options, {});
1845-
if (!prefix || typeof prefix !== 'string')
1846-
throw new TypeError('filename prefix is required');
1857+
if (!prefix || typeof prefix !== 'string') {
1858+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
1859+
'prefix',
1860+
'string',
1861+
prefix);
1862+
}
18471863
if (!nullCheck(prefix, callback)) {
18481864
return;
18491865
}
@@ -1856,8 +1872,12 @@ fs.mkdtemp = function(prefix, options, callback) {
18561872

18571873

18581874
fs.mkdtempSync = function(prefix, options) {
1859-
if (!prefix || typeof prefix !== 'string')
1860-
throw new TypeError('filename prefix is required');
1875+
if (!prefix || typeof prefix !== 'string') {
1876+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
1877+
'prefix',
1878+
'string',
1879+
prefix);
1880+
}
18611881
options = getOptions(options, {});
18621882
nullCheck(prefix);
18631883
return binding.mkdtemp(prefix + 'XXXXXX', options.encoding);
@@ -1903,16 +1923,26 @@ function ReadStream(path, options) {
19031923

19041924
if (this.start !== undefined) {
19051925
if (typeof this.start !== 'number') {
1906-
throw new TypeError('"start" option must be a Number');
1926+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
1927+
'start',
1928+
'number',
1929+
this.start);
19071930
}
19081931
if (this.end === undefined) {
19091932
this.end = Infinity;
19101933
} else if (typeof this.end !== 'number') {
1911-
throw new TypeError('"end" option must be a Number');
1934+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
1935+
'end',
1936+
'number',
1937+
this.end);
19121938
}
19131939

19141940
if (this.start > this.end) {
1915-
throw new Error('"start" option must be <= "end" option');
1941+
const errVal = `{start: ${this.start}, end: ${this.end}}`;
1942+
throw new errors.RangeError('ERR_VALUE_OUT_OF_RANGE',
1943+
'start',
1944+
'<= "end"',
1945+
errVal);
19161946
}
19171947

19181948
this.pos = this.start;
@@ -2069,10 +2099,17 @@ function WriteStream(path, options) {
20692099

20702100
if (this.start !== undefined) {
20712101
if (typeof this.start !== 'number') {
2072-
throw new TypeError('"start" option must be a Number');
2102+
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
2103+
'start',
2104+
'number',
2105+
this.start);
20732106
}
20742107
if (this.start < 0) {
2075-
throw new Error('"start" must be >= zero');
2108+
const errVal = `{start: ${this.start}}`;
2109+
throw new errors.RangeError('ERR_VALUE_OUT_OF_RANGE',
2110+
'start',
2111+
'>= 0',
2112+
errVal);
20762113
}
20772114

20782115
this.pos = this.start;

lib/internal/errors.js

+3
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s');
264264
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s');
265265
E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
266266
E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type');
267+
E('ERR_VALUE_OUT_OF_RANGE', (start, end, value) => {
268+
return `The value of "${start}" must be ${end}. Received "${value}"`;
269+
});
267270
E('ERR_V8BREAKITERATOR', 'Full ICU data not installed. ' +
268271
'See https://github.com/nodejs/node/wiki/Intl');
269272
E('ERR_VALID_PERFORMANCE_ENTRY_TYPE',

test/parallel/test-file-write-stream3.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,15 @@ function run_test_3() {
176176

177177
const run_test_4 = common.mustCall(function() {
178178
// Error: start must be >= zero
179-
assert.throws(
180-
function() {
181-
fs.createWriteStream(filepath, { start: -5, flags: 'r+' });
182-
},
183-
/"start" must be/
184-
);
179+
const block = () => {
180+
fs.createWriteStream(filepath, { start: -5, flags: 'r+' });
181+
};
182+
const err = {
183+
code: 'ERR_VALUE_OUT_OF_RANGE',
184+
message: 'The value of "start" must be >= 0. Received "{start: -5}"',
185+
type: RangeError
186+
};
187+
common.expectsError(block, err);
185188
});
186189

187190
run_test_1();

test/parallel/test-fs-access.js

+17-7
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,23 @@ assert.throws(() => {
8585
fs.access(100, fs.F_OK, common.mustNotCall());
8686
}, /^TypeError: path must be a string or Buffer$/);
8787

88-
assert.throws(() => {
89-
fs.access(__filename, fs.F_OK);
90-
}, /^TypeError: "callback" argument must be a function$/);
91-
92-
assert.throws(() => {
93-
fs.access(__filename, fs.F_OK, {});
94-
}, /^TypeError: "callback" argument must be a function$/);
88+
common.expectsError(
89+
() => {
90+
fs.access(__filename, fs.F_OK);
91+
},
92+
{
93+
code: 'ERR_INVALID_CALLBACK',
94+
type: TypeError
95+
});
96+
97+
common.expectsError(
98+
() => {
99+
fs.access(__filename, fs.F_OK, {});
100+
},
101+
{
102+
code: 'ERR_INVALID_CALLBACK',
103+
type: TypeError
104+
});
95105

96106
assert.doesNotThrow(() => {
97107
fs.accessSync(__filename);

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const common = require('../common');
33
const assert = require('assert');
44
const fs = require('fs');
5-
const cbTypeError = /^TypeError: "callback" argument must be a function$/;
65
const callbackThrowValues = [null, true, false, 0, 1, 'foo', /foo/, [], {}];
76

87
const { sep } = require('path');
@@ -24,7 +23,10 @@ assert.doesNotThrow(testMakeCallback());
2423

2524
function invalidCallbackThrowsTests() {
2625
callbackThrowValues.forEach((value) => {
27-
assert.throws(testMakeCallback(value), cbTypeError);
26+
common.expectsError(testMakeCallback(value), {
27+
code: 'ERR_INVALID_CALLBACK',
28+
type: TypeError
29+
});
2830
});
2931
}
3032

test/parallel/test-fs-makeStatsCallback.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
const common = require('../common');
33
const assert = require('assert');
44
const fs = require('fs');
5-
const cbTypeError = /^TypeError: "callback" argument must be a function$/;
65
const callbackThrowValues = [null, true, false, 0, 1, 'foo', /foo/, [], {}];
76
const warn = 'Calling an asynchronous function without callback is deprecated.';
87

@@ -23,7 +22,10 @@ assert.doesNotThrow(testMakeStatsCallback());
2322

2423
function invalidCallbackThrowsTests() {
2524
callbackThrowValues.forEach((value) => {
26-
assert.throws(testMakeStatsCallback(value), cbTypeError);
25+
common.expectsError(testMakeStatsCallback(value), {
26+
code: 'ERR_INVALID_CALLBACK',
27+
type: TypeError
28+
});
2729
});
2830
}
2931

test/parallel/test-fs-mkdtemp-prefix-check.js

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
'use strict';
22
const common = require('../common');
3-
const assert = require('assert');
43
const fs = require('fs');
54

6-
const expectedError = /^TypeError: filename prefix is required$/;
75
const prefixValues = [undefined, null, 0, true, false, 1, ''];
86

97
function fail(value) {
10-
assert.throws(
11-
() => fs.mkdtempSync(value, {}),
12-
expectedError
13-
);
8+
common.expectsError(
9+
() => {
10+
fs.mkdtempSync(value, {});
11+
},
12+
{
13+
code: 'ERR_INVALID_ARG_TYPE',
14+
type: TypeError
15+
});
1416
}
1517

1618
function failAsync(value) {
17-
assert.throws(
18-
() => fs.mkdtemp(value, common.mustNotCall()), expectedError
19-
);
19+
common.expectsError(
20+
() => {
21+
fs.mkdtemp(value, common.mustNotCall());
22+
},
23+
{
24+
code: 'ERR_INVALID_ARG_TYPE',
25+
type: TypeError
26+
});
2027
}
2128

2229
prefixValues.forEach((prefixValue) => {

test/parallel/test-fs-non-number-arguments-throw.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,32 @@ fs.writeFileSync(tempFile, 'abc\ndef');
1313
const sanity = 'def';
1414
const saneEmitter = fs.createReadStream(tempFile, { start: 4, end: 6 });
1515

16-
assert.throws(function() {
17-
fs.createReadStream(tempFile, { start: '4', end: 6 });
18-
}, /^TypeError: "start" option must be a Number$/,
19-
"start as string didn't throw an error for createReadStream");
16+
common.expectsError(
17+
() => {
18+
fs.createReadStream(tempFile, { start: '4', end: 6 });
19+
},
20+
{
21+
code: 'ERR_INVALID_ARG_TYPE',
22+
type: TypeError
23+
});
2024

21-
assert.throws(function() {
22-
fs.createReadStream(tempFile, { start: 4, end: '6' });
23-
}, /^TypeError: "end" option must be a Number$/,
24-
"end as string didn't throw an error for createReadStream");
25+
common.expectsError(
26+
() => {
27+
fs.createReadStream(tempFile, { start: 4, end: '6' });
28+
},
29+
{
30+
code: 'ERR_INVALID_ARG_TYPE',
31+
type: TypeError
32+
});
2533

26-
assert.throws(function() {
27-
fs.createWriteStream(tempFile, { start: '4' });
28-
}, /^TypeError: "start" option must be a Number$/,
29-
"start as string didn't throw an error for createWriteStream");
34+
common.expectsError(
35+
() => {
36+
fs.createWriteStream(tempFile, { start: '4' });
37+
},
38+
{
39+
code: 'ERR_INVALID_ARG_TYPE',
40+
type: TypeError
41+
});
3042

3143
saneEmitter.on('data', common.mustCall(function(data) {
3244
assert.strictEqual(

test/parallel/test-fs-null-bytes.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,27 @@ const fs = require('fs');
2626
const URL = require('url').URL;
2727

2828
function check(async, sync) {
29-
const expected = /Path must be a string without null bytes/;
3029
const argsSync = Array.prototype.slice.call(arguments, 2);
3130
const argsAsync = argsSync.concat((er) => {
32-
assert(er && expected.test(er.message));
33-
assert.strictEqual(er.code, 'ENOENT');
31+
common.expectsError(
32+
() => {
33+
throw er;
34+
},
35+
{
36+
code: 'ERR_INVALID_ARG_TYPE',
37+
type: Error
38+
});
3439
});
3540

3641
if (sync) {
37-
assert.throws(() => {
38-
sync.apply(null, argsSync);
39-
}, expected);
42+
common.expectsError(
43+
() => {
44+
sync.apply(null, argsSync);
45+
},
46+
{
47+
code: 'ERR_INVALID_ARG_TYPE',
48+
type: Error,
49+
});
4050
}
4151

4252
if (async) {

0 commit comments

Comments
 (0)