GeezerVison is showing github.com — process: runtime deprecate coercion to integer in `process.exit()` · nodejs/node@ada2d05
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/deprecations.md +4-1Lines changed: 4 additions & 1 deletion - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -3175,6 +3175,9 @@ thing instead. | 3175 | 3175 |
| 3176 | 3176 | <!-- YAML | 3177 | 3177 | changes: | | 3178 | + - version: REPLACEME | | 3179 | + pr-url: https://github.com/nodejs/node/pull/44711 | | 3180 | + description: Runtime deprecation. | 3178 | 3181 | - version: v18.10.0 | 3179 | 3182 | pr-url: https://github.com/nodejs/node/pull/44714 | 3180 | 3183 | description: Documentation-only deprecation of `process.exitCode` integer | @@ -3187,7 +3190,7 @@ changes: | 3187 | 3190 | coercion. | 3188 | 3191 | --> | 3189 | 3192 |
| 3190 | | -Type: Documentation-only | | 3193 | +Type: Runtime | 3191 | 3194 |
| 3192 | 3195 | Values other than `undefined`, `null`, integer numbers, and integer strings | 3193 | 3196 | (e.g., `'1'`) are deprecated as value for the `code` parameter in | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/bootstrap/node.js +25Lines changed: 25 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -102,6 +102,31 @@ process.domain = null; | 102 | 102 | } | 103 | 103 | process._exiting = false; | 104 | 104 |
| | 105 | +{ | | 106 | + const warnIntegerCoercionDeprecation = deprecate( | | 107 | + () => {}, | | 108 | + 'Implicit coercion to integer for exit code is deprecated.', | | 109 | + 'DEP0164' | | 110 | + ); | | 111 | + | | 112 | + let exitCode; | | 113 | + | | 114 | + ObjectDefineProperty(process, 'exitCode', { | | 115 | + __proto__: null, | | 116 | + get() { | | 117 | + return exitCode; | | 118 | + }, | | 119 | + set(code) { | | 120 | + if (perThreadSetup.isDeprecatedExitCode(code)) { | | 121 | + warnIntegerCoercionDeprecation(); | | 122 | + } | | 123 | + exitCode = code; | | 124 | + }, | | 125 | + enumerable: true, | | 126 | + configurable: false, | | 127 | + }); | | 128 | +} | | 129 | + | 105 | 130 | // process.config is serialized config.gypi | 106 | 131 | const nativeModule = internalBinding('builtins'); | 107 | 132 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/process/per_thread.js +35Lines changed: 35 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,7 +13,10 @@ const { | 13 | 13 | ArrayPrototypeSplice, | 14 | 14 | BigUint64Array, | 15 | 15 | Float64Array, | | 16 | + Number, | | 17 | + NumberIsInteger, | 16 | 18 | NumberMAX_SAFE_INTEGER, | | 19 | + NumberMIN_SAFE_INTEGER, | 17 | 20 | ObjectFreeze, | 18 | 21 | ObjectDefineProperty, | 19 | 22 | ReflectApply, | @@ -180,9 +183,23 @@ function wrapProcessMethods(binding) { | 180 | 183 |
| 181 | 184 | memoryUsage.rss = rss; | 182 | 185 |
| | 186 | + const { deprecate } = require('internal/util'); | | 187 | + const warnIntegerCoercionDeprecationSync = deprecate( | | 188 | + () => {}, | | 189 | + 'Implicit coercion to integer for exit code is deprecated.', | | 190 | + 'DEP0164', | | 191 | + true | | 192 | + ); | | 193 | + | 183 | 194 | function exit(code) { | 184 | 195 | process.off('exit', handleProcessExit); | 185 | 196 |
| | 197 | + if (isDeprecatedExitCode(code)) { | | 198 | + // Emit the deprecation warning synchronously since deprecation warning is | | 199 | + // generally emitted in a next tick but we have no next tick timing here. | | 200 | + warnIntegerCoercionDeprecationSync(); | | 201 | + } | | 202 | + | 186 | 203 | if (code || code === 0) | 187 | 204 | process.exitCode = code; | 188 | 205 |
| @@ -407,6 +424,23 @@ function toggleTraceCategoryState(asyncHooksEnabled) { | 407 | 424 | } | 408 | 425 | } | 409 | 426 |
| | 427 | +function isDeprecatedExitCode(code) { | | 428 | + if (code !== null && code !== undefined) { | | 429 | + const value = | | 430 | + typeof code === 'string' && code !== '' ? Number(code) : code; | | 431 | + // Check if the value is an integer. | | 432 | + if ( | | 433 | + typeof value !== 'number' || | | 434 | + !NumberIsInteger(value) || | | 435 | + value < NumberMIN_SAFE_INTEGER || | | 436 | + value > NumberMAX_SAFE_INTEGER | | 437 | + ) { | | 438 | + return true; | | 439 | + } | | 440 | + } | | 441 | + return false; | | 442 | +} | | 443 | + | 410 | 444 | module.exports = { | 411 | 445 | toggleTraceCategoryState, | 412 | 446 | assert, | @@ -415,4 +449,5 @@ module.exports = { | 415 | 449 | hrtime, | 416 | 450 | hrtimeBigInt, | 417 | 451 | refreshHrtimeBuffer, | | 452 | + isDeprecatedExitCode, | 418 | 453 | }; |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/process/warning.js +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -166,8 +166,8 @@ function emitWarning(warning, type, code, ctor) { | 166 | 166 | process.nextTick(doEmitWarning, warning); | 167 | 167 | } | 168 | 168 |
| 169 | | -function emitWarningSync(warning) { | 170 | | - process.emit('warning', createWarningObject(warning)); | | 169 | +function emitWarningSync(warning, type, code, ctor) { | | 170 | + process.emit('warning', createWarningObject(warning, type, code, ctor)); | 171 | 171 | } | 172 | 172 |
| 173 | 173 | function createWarningObject(warning, type, code, ctor, detail) { | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/util.js +5-2Lines changed: 5 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -96,7 +96,7 @@ let validateString; | 96 | 96 | // Mark that a method should not be used. | 97 | 97 | // Returns a modified function which warns once by default. | 98 | 98 | // If --no-deprecation is set, then it is a no-op. | 99 | | -function deprecate(fn, msg, code) { | | 99 | +function deprecate(fn, msg, code, useEmitSync) { | 100 | 100 | if (process.noDeprecation === true) { | 101 | 101 | return fn; | 102 | 102 | } | @@ -114,7 +114,10 @@ function deprecate(fn, msg, code) { | 114 | 114 | warned = true; | 115 | 115 | if (code !== undefined) { | 116 | 116 | if (!codesWarned.has(code)) { | 117 | | - process.emitWarning(msg, 'DeprecationWarning', code, deprecated); | | 117 | + const emitWarning = useEmitSync ? | | 118 | + require('internal/process/warning').emitWarningSync : | | 119 | + process.emitWarning; | | 120 | + emitWarning(msg, 'DeprecationWarning', code, deprecated); | 118 | 121 | codesWarned.add(code); | 119 | 122 | } | 120 | 123 | } else { | |
Collapse file Copy file name to clipboard +100Lines changed: 100 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +require('../common'); | | 4 | + | | 5 | +const deprecated = [ | | 6 | + { | | 7 | + code: '', | | 8 | + expected: 0, | | 9 | + }, | | 10 | + { | | 11 | + code: '1 one', | | 12 | + expected: 0, | | 13 | + }, | | 14 | + { | | 15 | + code: 'two', | | 16 | + expected: 0, | | 17 | + }, | | 18 | + { | | 19 | + code: {}, | | 20 | + expected: 0, | | 21 | + }, | | 22 | + { | | 23 | + code: [], | | 24 | + expected: 0, | | 25 | + }, | | 26 | + { | | 27 | + code: true, | | 28 | + expected: 1, | | 29 | + }, | | 30 | + { | | 31 | + code: false, | | 32 | + expected: 0, | | 33 | + }, | | 34 | + { | | 35 | + code: 2n, | | 36 | + expected: 0, | | 37 | + expected_useProcessExitCode: 1, | | 38 | + }, | | 39 | + { | | 40 | + code: 2.1, | | 41 | + expected: 2, | | 42 | + }, | | 43 | + { | | 44 | + code: Infinity, | | 45 | + expected: 0, | | 46 | + }, | | 47 | + { | | 48 | + code: NaN, | | 49 | + expected: 0, | | 50 | + }, | | 51 | +]; | | 52 | +const args = deprecated; | | 53 | + | | 54 | +if (process.argv[2] === undefined) { | | 55 | + const { spawnSync } = require('node:child_process'); | | 56 | + const { inspect, debuglog } = require('node:util'); | | 57 | + const { strictEqual } = require('node:assert'); | | 58 | + | | 59 | + const debug = debuglog('test'); | | 60 | + const node = process.execPath; | | 61 | + const test = (index, useProcessExitCode) => { | | 62 | + const { status: code, stderr } = spawnSync(node, [ | | 63 | + __filename, | | 64 | + index, | | 65 | + useProcessExitCode, | | 66 | + ]); | | 67 | + debug(`actual: ${code}, ${inspect(args[index])} ${!!useProcessExitCode}`); | | 68 | + debug(`${stderr}`); | | 69 | + | | 70 | + const expected = | | 71 | + useProcessExitCode && args[index].expected_useProcessExitCode ? | | 72 | + args[index].expected_useProcessExitCode : | | 73 | + args[index].expected; | | 74 | + | | 75 | + strictEqual(code, expected, `actual: ${code}, ${inspect(args[index])}`); | | 76 | + strictEqual( | | 77 | + ['[DEP0164]'].some((pattern) => stderr.includes(pattern)), | | 78 | + true | | 79 | + ); | | 80 | + }; | | 81 | + | | 82 | + for (const index of args.keys()) { | | 83 | + // Check `process.exit([code])` | | 84 | + test(index); | | 85 | + // Check exit with `process.exitCode` | | 86 | + test(index, true); | | 87 | + } | | 88 | +} else { | | 89 | + const index = parseInt(process.argv[2]); | | 90 | + const useProcessExitCode = process.argv[3] !== 'undefined'; | | 91 | + if (Number.isNaN(index)) { | | 92 | + return process.exit(100); | | 93 | + } | | 94 | + | | 95 | + if (useProcessExitCode) { | | 96 | + process.exitCode = args[index].code; | | 97 | + } else { | | 98 | + process.exit(args[index].code); | | 99 | + } | | 100 | +} |
|