Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add --disable-warning option #50661

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`
Ethan-Arrowood marked this conversation as resolved.
Show resolved Hide resolved

> 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);
});
});
});