Skip to content

Commit

Permalink
src: add --disable-warning option
Browse files Browse the repository at this point in the history
Co-authored-by: Geoffrey Booth <webadmin@geoffreybooth.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: #50661
Fixes: #30810
Fixes: #47478
Fixes: #46862
Fixes: #40940
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
  • Loading branch information
3 people authored and targos committed Nov 23, 2023
1 parent d4dcdd0 commit 15a9c0b
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
55 changes: 55 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,57 @@ Affects the default output directory of:
* [`--heap-prof-dir`][]
* [`--redirect-warnings`][]

### `--disable-warning=code-or-type`

> Stability: 1.1 - Active development
<!-- YAML
added: REPLACEME
-->

Disable specific process warnings by `code` or `type`.

Warnings emitted from [`process.emitWarning()`][emit_warning] may contain a
`code` and a `type`. This option will not-emit warnings that have a matching
`code` or `type`.

List of [deprecation warnings][].

The Node.js core warning types are: `DeprecationWarning` and
`ExperimentalWarning`

For example, the following script will not emit
[DEP0025 `require('node:sys')`][DEP0025 warning] when executed with
`node --disable-warning=DEP0025`:

```mjs
import sys from 'node:sys';
```

```cjs
const sys = require('node:sys');
```

For example, the following script will emit the
[DEP0025 `require('node:sys')`][DEP0025 warning], but not any Experimental
Warnings (such as
[ExperimentalWarning: `vm.measureMemory` is an experimental feature][]
in <=v21) when executed with `node --disable-warning=ExperimentalWarnings`:

```mjs
import sys from 'node:sys';
import vm from 'node:vm';

vm.measureMemory();
```

```cjs
const sys = require('node:sys');
const vm = require('node:vm');

vm.measureMemory();
```

### `--disable-proto=mode`

<!-- YAML
Expand Down Expand Up @@ -2327,6 +2378,7 @@ Node.js options that are allowed are:
* `--conditions`, `-C`
* `--diagnostic-dir`
* `--disable-proto`
* `--disable-warning`
* `--dns-result-order`
* `--enable-fips`
* `--enable-network-family-autoselection`
Expand Down Expand Up @@ -2779,7 +2831,9 @@ done
[CommonJS]: modules.md
[CommonJS module]: modules.md
[CustomEvent Web API]: https://dom.spec.whatwg.org/#customevent
[DEP0025 warning]: deprecations.md#dep0025-requirenodesys
[ECMAScript module]: esm.md#modules-ecmascript-modules
[ExperimentalWarning: `vm.measureMemory` is an experimental feature]: vm.md#vmmeasurememoryoptions
[Fetch API]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[File System Permissions]: permissions.md#file-system-permissions
[Module customization hooks]: module.md#customization-hooks
Expand Down Expand Up @@ -2835,6 +2889,7 @@ done
[context-aware]: addons.md#context-aware-addons
[debugger]: debugger.md
[debugging security implications]: https://nodejs.org/en/docs/guides/debugging-getting-started/#security-implications
[deprecation warnings]: deprecations.md#list-of-deprecated-apis
[emit_warning]: process.md#processemitwarningwarning-options
[environment_variables]: #environment-variables
[filtering tests by name]: test.md#filtering-tests-by-name
Expand Down
18 changes: 18 additions & 0 deletions lib/internal/process/warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ const {
ErrorPrototypeToString,
ErrorCaptureStackTrace,
String,
SafeSet,
} = primordials;

const {
getOptionValue,
} = require('internal/options');

const assert = require('internal/assert');
const {
codes: {
Expand Down Expand Up @@ -89,8 +94,21 @@ function doEmitWarning(warning) {
process.emit('warning', warning);
}

let disableWarningSet;

function onWarning(warning) {
if (!disableWarningSet) {
disableWarningSet = new SafeSet();
const disableWarningValues = getOptionValue('--disable-warning');
for (let i = 0; i < disableWarningValues.length; i++) {
disableWarningSet.add(disableWarningValues[i]);
}
}
if ((warning?.code && disableWarningSet.has(warning.code)) ||
(warning?.name && disableWarningSet.has(warning.name))) return;

if (!(warning instanceof Error)) return;

const isDeprecation = warning.name === 'DeprecationWarning';
if (isDeprecation && process.noDeprecation) return;
const trace = process.traceProcessWarnings ||
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::warnings,
kAllowedInEnvvar,
true);
AddOption("--disable-warning",
"silence specific process warnings",
&EnvironmentOptions::disable_warnings,
kAllowedInEnvvar);
AddOption("--force-context-aware",
"disable loading non-context-aware addons",
&EnvironmentOptions::force_context_aware,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class EnvironmentOptions : public Options {
bool allow_native_addons = true;
bool global_search_paths = true;
bool warnings = true;
std::vector<std::string> disable_warnings;
bool force_context_aware = false;
bool pending_deprecation = false;
bool preserve_symlinks = false;
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/disable-warning-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use strict';
const path = require('node:path');
const { Worker } = require('node:worker_threads');
new Worker(path.join(__dirname, './disable-warning.js'));
15 changes: 15 additions & 0 deletions test/fixtures/disable-warning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

process.emitWarning('Deprecation Warning 1', {
code: 'DEP1',
type: 'DeprecationWarning'
});

process.emitWarning('Deprecation Warning 2', {
code: 'DEP2',
type: 'DeprecationWarning'
});

process.emitWarning('Experimental Warning', {
type: 'ExperimentalWarning'
});
163 changes: 163 additions & 0 deletions test/parallel/test-process-warnings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { spawnPromisified } from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import { describe, it } from 'node:test';
import assert from 'node:assert';

const fixturePath = fixtures.path('disable-warning.js');
const fixturePathWorker = fixtures.path('disable-warning-worker.js');
const dep1Message = /\(node:\d+\) \[DEP1\] DeprecationWarning/;
const dep2Message = /\(node:\d+\) \[DEP2\] DeprecationWarning/;
const experimentalWarningMessage = /\(node:\d+\) ExperimentalWarning/;

describe('process warnings', { concurrency: true }, () => {

it('should emit all warnings by default', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.match(stderr, dep1Message);
assert.match(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

describe('--no-warnings', { concurrency: true }, () => {
it('should silence all warnings by default', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--no-warnings',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.doesNotMatch(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.doesNotMatch(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
});

describe('--no-deprecation', { concurrency: true }, () => {
it('should silence all deprecation warnings', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--no-deprecation',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.doesNotMatch(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
});

describe('--disable-warning', { concurrency: true }, () => {
it('should silence deprecation warning DEP1', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=DEP1',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.doesNotMatch(stderr, dep1Message);
assert.match(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should silence deprecation warnings DEP1 and DEP2', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=DEP1',
'--disable-warning=DEP2',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.doesNotMatch(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should silence all deprecation warnings using type DeprecationWarning', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=DeprecationWarning',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.doesNotMatch(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should silence all experimental warnings using type ExperimentalWarning', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=ExperimentalWarning',
fixturePath,
]);

assert.strictEqual(stdout, '');
assert.match(stderr, dep1Message);
assert.match(stderr, dep2Message);
assert.doesNotMatch(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should pass down option to worker', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=DEP2',
fixturePathWorker,
]);

assert.strictEqual(stdout, '');
assert.match(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should not support a comma separated list', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
'--disable-warning=DEP1,DEP2',
fixturePathWorker,
]);

assert.strictEqual(stdout, '');
assert.match(stderr, dep1Message);
assert.match(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should be specifiable in NODE_OPTIONS', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
fixturePath,
], {
env: {
...process.env,
NODE_OPTIONS: '--disable-warning=DEP2'
}
});

assert.strictEqual(stdout, '');
assert.match(stderr, dep1Message);
assert.doesNotMatch(stderr, dep2Message);
assert.match(stderr, experimentalWarningMessage);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});
});
});

0 comments on commit 15a9c0b

Please sign in to comment.