mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 21:58:48 +02:00
process: remove process.exit()
, process.exitCode
coercion to integer
This removes the deprecation, `DEP0164` and validates the exit code for both `process.exit([code])` and `process.exitCode`. Signed-off-by: Daeyeon Jeong <daeyeon.dev@gmail.com> PR-URL: https://github.com/nodejs/node/pull/43716 Refs: https://github.com/nodejs/node/pull/43738 Refs: https://github.com/nodejs/node/pull/44714 Refs: https://github.com/nodejs/node/pull/44711 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
This commit is contained in:
parent
19f3973828
commit
2d0d99733b
7 changed files with 176 additions and 148 deletions
|
@ -3178,6 +3178,9 @@ thing instead.
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/43716
|
||||||
|
description: End-of-Life.
|
||||||
- version: v19.0.0
|
- version: v19.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/44711
|
pr-url: https://github.com/nodejs/node/pull/44711
|
||||||
description: Runtime deprecation.
|
description: Runtime deprecation.
|
||||||
|
@ -3195,7 +3198,7 @@ changes:
|
||||||
coercion.
|
coercion.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Type: Runtime
|
Type: End-of-Life
|
||||||
|
|
||||||
Values other than `undefined`, `null`, integer numbers, and integer strings
|
Values other than `undefined`, `null`, integer numbers, and integer strings
|
||||||
(e.g., `'1'`) are deprecated as value for the `code` parameter in
|
(e.g., `'1'`) are deprecated as value for the `code` parameter in
|
||||||
|
|
|
@ -1708,9 +1708,15 @@ that started the Node.js process. Symbolic links, if any, are resolved.
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.13
|
added: v0.1.13
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/43716
|
||||||
|
description: Only accepts a code of type number, or of type string if it
|
||||||
|
represents an integer.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `code` {integer} The exit code. **Default:** `0`.
|
* `code` {integer|string|null|undefined} The exit code. For string type, only
|
||||||
|
integer strings (e.g.,'1') are allowed. **Default:** `0`.
|
||||||
|
|
||||||
The `process.exit()` method instructs Node.js to terminate the process
|
The `process.exit()` method instructs Node.js to terminate the process
|
||||||
synchronously with an exit status of `code`. If `code` is omitted, exit uses
|
synchronously with an exit status of `code`. If `code` is omitted, exit uses
|
||||||
|
@ -1810,9 +1816,15 @@ than the current process.
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.11.8
|
added: v0.11.8
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/43716
|
||||||
|
description: Only accepts a code of type number, or of type string if it
|
||||||
|
represents an integer.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* {integer}
|
* {integer|string|null|undefined} The exit code. For string type, only
|
||||||
|
integer strings (e.g.,'1') are allowed. **Default:** `undefined`.
|
||||||
|
|
||||||
A number which will be the process exit code, when the process either
|
A number which will be the process exit code, when the process either
|
||||||
exits gracefully, or is exited via [`process.exit()`][] without specifying
|
exits gracefully, or is exited via [`process.exit()`][] without specifying
|
||||||
|
|
|
@ -60,6 +60,8 @@ const {
|
||||||
ArrayPrototypeFill,
|
ArrayPrototypeFill,
|
||||||
FunctionPrototypeCall,
|
FunctionPrototypeCall,
|
||||||
JSONParse,
|
JSONParse,
|
||||||
|
Number,
|
||||||
|
NumberIsNaN,
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ObjectGetPrototypeOf,
|
ObjectGetPrototypeOf,
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
|
@ -74,6 +76,9 @@ const {
|
||||||
deprecate,
|
deprecate,
|
||||||
exposeInterface,
|
exposeInterface,
|
||||||
} = require('internal/util');
|
} = require('internal/util');
|
||||||
|
const {
|
||||||
|
validateInteger,
|
||||||
|
} = require('internal/validators');
|
||||||
const {
|
const {
|
||||||
exiting_aliased_Uint32Array,
|
exiting_aliased_Uint32Array,
|
||||||
getHiddenValue,
|
getHiddenValue,
|
||||||
|
@ -103,12 +108,6 @@ process.domain = null;
|
||||||
process._exiting = false;
|
process._exiting = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
const warnIntegerCoercionDeprecation = deprecate(
|
|
||||||
() => {},
|
|
||||||
'Implicit coercion to integer for exit code is deprecated.',
|
|
||||||
'DEP0164'
|
|
||||||
);
|
|
||||||
|
|
||||||
let exitCode;
|
let exitCode;
|
||||||
|
|
||||||
ObjectDefineProperty(process, 'exitCode', {
|
ObjectDefineProperty(process, 'exitCode', {
|
||||||
|
@ -117,8 +116,13 @@ process._exiting = false;
|
||||||
return exitCode;
|
return exitCode;
|
||||||
},
|
},
|
||||||
set(code) {
|
set(code) {
|
||||||
if (perThreadSetup.isDeprecatedExitCode(code)) {
|
if (code !== null && code !== undefined) {
|
||||||
warnIntegerCoercionDeprecation();
|
let value = code;
|
||||||
|
if (typeof code === 'string' && code !== '' &&
|
||||||
|
NumberIsNaN((value = Number(code)))) {
|
||||||
|
value = code;
|
||||||
|
}
|
||||||
|
validateInteger(value, 'code');
|
||||||
}
|
}
|
||||||
exitCode = code;
|
exitCode = code;
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,10 +13,7 @@ const {
|
||||||
ArrayPrototypeSplice,
|
ArrayPrototypeSplice,
|
||||||
BigUint64Array,
|
BigUint64Array,
|
||||||
Float64Array,
|
Float64Array,
|
||||||
Number,
|
|
||||||
NumberIsInteger,
|
|
||||||
NumberMAX_SAFE_INTEGER,
|
NumberMAX_SAFE_INTEGER,
|
||||||
NumberMIN_SAFE_INTEGER,
|
|
||||||
ObjectFreeze,
|
ObjectFreeze,
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ReflectApply,
|
ReflectApply,
|
||||||
|
@ -183,25 +180,12 @@ function wrapProcessMethods(binding) {
|
||||||
|
|
||||||
memoryUsage.rss = rss;
|
memoryUsage.rss = rss;
|
||||||
|
|
||||||
const { deprecate } = require('internal/util');
|
|
||||||
const warnIntegerCoercionDeprecationSync = deprecate(
|
|
||||||
() => {},
|
|
||||||
'Implicit coercion to integer for exit code is deprecated.',
|
|
||||||
'DEP0164',
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
function exit(code) {
|
function exit(code) {
|
||||||
process.off('exit', handleProcessExit);
|
process.off('exit', handleProcessExit);
|
||||||
|
|
||||||
if (isDeprecatedExitCode(code)) {
|
if (arguments.length !== 0) {
|
||||||
// Emit the deprecation warning synchronously since deprecation warning is
|
|
||||||
// generally emitted in a next tick but we have no next tick timing here.
|
|
||||||
warnIntegerCoercionDeprecationSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code || code === 0)
|
|
||||||
process.exitCode = code;
|
process.exitCode = code;
|
||||||
|
}
|
||||||
|
|
||||||
if (!process._exiting) {
|
if (!process._exiting) {
|
||||||
process._exiting = true;
|
process._exiting = true;
|
||||||
|
@ -424,23 +408,6 @@ function toggleTraceCategoryState(asyncHooksEnabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDeprecatedExitCode(code) {
|
|
||||||
if (code !== null && code !== undefined) {
|
|
||||||
const value =
|
|
||||||
typeof code === 'string' && code !== '' ? Number(code) : code;
|
|
||||||
// Check if the value is an integer.
|
|
||||||
if (
|
|
||||||
typeof value !== 'number' ||
|
|
||||||
!NumberIsInteger(value) ||
|
|
||||||
value < NumberMIN_SAFE_INTEGER ||
|
|
||||||
value > NumberMAX_SAFE_INTEGER
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
toggleTraceCategoryState,
|
toggleTraceCategoryState,
|
||||||
assert,
|
assert,
|
||||||
|
@ -449,5 +416,4 @@ module.exports = {
|
||||||
hrtime,
|
hrtime,
|
||||||
hrtimeBigInt,
|
hrtimeBigInt,
|
||||||
refreshHrtimeBuffer,
|
refreshHrtimeBuffer,
|
||||||
isDeprecatedExitCode,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
require('../common');
|
|
||||||
|
|
||||||
const deprecated = [
|
|
||||||
{
|
|
||||||
code: '',
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: '1 one',
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'two',
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: {},
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: [],
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: true,
|
|
||||||
expected: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: false,
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 2n,
|
|
||||||
expected: 0,
|
|
||||||
expected_useProcessExitCode: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 2.1,
|
|
||||||
expected: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: Infinity,
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: NaN,
|
|
||||||
expected: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const args = deprecated;
|
|
||||||
|
|
||||||
if (process.argv[2] === undefined) {
|
|
||||||
const { spawnSync } = require('node:child_process');
|
|
||||||
const { inspect, debuglog } = require('node:util');
|
|
||||||
const { strictEqual } = require('node:assert');
|
|
||||||
|
|
||||||
const debug = debuglog('test');
|
|
||||||
const node = process.execPath;
|
|
||||||
const test = (index, useProcessExitCode) => {
|
|
||||||
const { status: code, stderr } = spawnSync(node, [
|
|
||||||
__filename,
|
|
||||||
index,
|
|
||||||
useProcessExitCode,
|
|
||||||
]);
|
|
||||||
debug(`actual: ${code}, ${inspect(args[index])} ${!!useProcessExitCode}`);
|
|
||||||
debug(`${stderr}`);
|
|
||||||
|
|
||||||
const expected =
|
|
||||||
useProcessExitCode && args[index].expected_useProcessExitCode ?
|
|
||||||
args[index].expected_useProcessExitCode :
|
|
||||||
args[index].expected;
|
|
||||||
|
|
||||||
strictEqual(code, expected, `actual: ${code}, ${inspect(args[index])}`);
|
|
||||||
strictEqual(
|
|
||||||
['[DEP0164]'].some((pattern) => stderr.includes(pattern)),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const index of args.keys()) {
|
|
||||||
// Check `process.exit([code])`
|
|
||||||
test(index);
|
|
||||||
// Check exit with `process.exitCode`
|
|
||||||
test(index, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const index = parseInt(process.argv[2]);
|
|
||||||
const useProcessExitCode = process.argv[3] !== 'undefined';
|
|
||||||
if (Number.isNaN(index)) {
|
|
||||||
return process.exit(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useProcessExitCode) {
|
|
||||||
process.exitCode = args[index].code;
|
|
||||||
} else {
|
|
||||||
process.exit(args[index].code);
|
|
||||||
}
|
|
||||||
}
|
|
143
test/parallel/test-process-exit-code-validation.js
Normal file
143
test/parallel/test-process-exit-code-validation.js
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('../common');
|
||||||
|
|
||||||
|
const invalids = [
|
||||||
|
{
|
||||||
|
code: '',
|
||||||
|
expected: 1,
|
||||||
|
pattern: "Received type string \\(''\\)$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '1 one',
|
||||||
|
expected: 1,
|
||||||
|
pattern: "Received type string \\('1 one'\\)$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'two',
|
||||||
|
expected: 1,
|
||||||
|
pattern: "Received type string \\('two'\\)$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: {},
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received an instance of Object$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: [],
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received an instance of Array$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: true,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received type boolean \\(true\\)$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: false,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received type boolean \\(false\\)$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 2n,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received type bigint \\(2n\\)$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 2.1,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received 2.1$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: Infinity,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received Infinity$',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: NaN,
|
||||||
|
expected: 1,
|
||||||
|
pattern: 'Received NaN$',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const valids = [
|
||||||
|
{
|
||||||
|
code: 1,
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '2',
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: undefined,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: null,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 0,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '0',
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const args = [...invalids, ...valids];
|
||||||
|
|
||||||
|
if (process.argv[2] === undefined) {
|
||||||
|
const { spawnSync } = require('node:child_process');
|
||||||
|
const { inspect, debuglog } = require('node:util');
|
||||||
|
const { throws, strictEqual } = require('node:assert');
|
||||||
|
|
||||||
|
const debug = debuglog('test');
|
||||||
|
const node = process.execPath;
|
||||||
|
const test = (index, useProcessExitCode) => {
|
||||||
|
const { status: code } = spawnSync(node, [
|
||||||
|
__filename,
|
||||||
|
index,
|
||||||
|
useProcessExitCode,
|
||||||
|
]);
|
||||||
|
debug(`actual: ${code}, ${inspect(args[index])} ${!!useProcessExitCode}`);
|
||||||
|
strictEqual(
|
||||||
|
code,
|
||||||
|
args[index].expected,
|
||||||
|
`actual: ${code}, ${inspect(args[index])}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check process.exitCode
|
||||||
|
for (const arg of invalids) {
|
||||||
|
debug(`invaild code: ${inspect(arg.code)}`);
|
||||||
|
throws(() => (process.exitCode = arg.code), new RegExp(arg.pattern));
|
||||||
|
}
|
||||||
|
for (const arg of valids) {
|
||||||
|
debug(`vaild code: ${inspect(arg.code)}`);
|
||||||
|
process.exitCode = arg.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
throws(() => {
|
||||||
|
delete process.exitCode;
|
||||||
|
}, /Cannot delete property 'exitCode' of #<process>/);
|
||||||
|
process.exitCode = 0;
|
||||||
|
|
||||||
|
// Check process.exit([code])
|
||||||
|
for (const index of args.keys()) {
|
||||||
|
test(index);
|
||||||
|
test(index, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const index = parseInt(process.argv[2]);
|
||||||
|
const useProcessExitCode = process.argv[3] !== 'undefined';
|
||||||
|
if (Number.isNaN(index)) {
|
||||||
|
return process.exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useProcessExitCode) {
|
||||||
|
process.exitCode = args[index].code;
|
||||||
|
} else {
|
||||||
|
process.exit(args[index].code);
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ if (isMainThread) {
|
||||||
assert.strictEqual(headers[':status'], 200);
|
assert.strictEqual(headers[':status'], 200);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
req.on('data', common.mustCall(process.exit));
|
req.on('data', common.mustCall(() => process.exit()));
|
||||||
req.on('end', common.mustNotCall());
|
req.on('end', common.mustNotCall());
|
||||||
req.end();
|
req.end();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue