diff --git a/doc/api/util.md b/doc/api/util.md index 958a49977e1a17..9067383d817614 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -10,7 +10,11 @@ The `node:util` module supports the needs of Node.js internal APIs. Many of the utilities are useful for application and module developers as well. To access it: -```js +```mjs +import util from 'node:util'; +``` + +```cjs const util = require('node:util'); ``` @@ -29,13 +33,27 @@ an `(err, value) => ...` callback as the last argument. In the callback, the first argument will be the rejection reason (or `null` if the `Promise` resolved), and the second argument will be the resolved value. -```js -const util = require('node:util'); +```mjs +import { callbackify } from 'node:util'; async function fn() { return 'hello world'; } -const callbackFunction = util.callbackify(fn); +const callbackFunction = callbackify(fn); + +callbackFunction((err, ret) => { + if (err) throw err; + console.log(ret); +}); +``` + +```cjs +const { callbackify } = require('node:util'); + +async function fn() { + return 'hello world'; +} +const callbackFunction = callbackify(fn); callbackFunction((err, ret) => { if (err) throw err; @@ -89,11 +107,18 @@ environment variable. If the `section` name appears within the value of that environment variable, then the returned function operates similar to [`console.error()`][]. If not, then the returned function is a no-op. -```js -const util = require('node:util'); -const debuglog = util.debuglog('foo'); +```mjs +import { debuglog } from 'node:util'; +const log = debuglog('foo'); + +log('hello from foo [%d]', 123); +``` + +```cjs +const { debuglog } = require('node:util'); +const log = debuglog('foo'); -debuglog('hello from foo [%d]', 123); +log('hello from foo [%d]', 123); ``` If this program is run with `NODE_DEBUG=foo` in the environment, then @@ -108,11 +133,18 @@ environment variable set, then it will not print anything. The `section` supports wildcard also: -```js -const util = require('node:util'); -const debuglog = util.debuglog('foo-bar'); +```mjs +import { debuglog } from 'node:util'; +const log = debuglog('foo'); -debuglog('hi there, it\'s foo-bar [%d]', 2333); +log('hi there, it\'s foo-bar [%d]', 2333); +``` + +```cjs +const { debuglog } = require('node:util'); +const log = debuglog('foo'); + +log('hi there, it\'s foo-bar [%d]', 2333); ``` if it is run with `NODE_DEBUG=foo*` in the environment, then it will output @@ -129,12 +161,21 @@ The optional `callback` argument can be used to replace the logging function with a different function that doesn't have any initialization or unnecessary wrapping. -```js -const util = require('node:util'); -let debuglog = util.debuglog('internals', (debug) => { +```mjs +import { debuglog } from 'node:util'; +let log = debuglog('internals', (debug) => { // Replace with a logging function that optimizes out // testing if the section is enabled - debuglog = debug; + log = debug; +}); +``` + +```cjs +const { debuglog } = require('node:util'); +let log = debuglog('internals', (debug) => { + // Replace with a logging function that optimizes out + // testing if the section is enabled + log = debug; }); ``` @@ -152,9 +193,17 @@ If the `section` name appears within the value of that environment variable, then the returned value will be `true`. If not, then the returned value will be `false`. -```js -const util = require('node:util'); -const enabled = util.debuglog('foo').enabled; +```mjs +import { debuglog } from 'node:util'; +const enabled = debuglog('foo').enabled; +if (enabled) { + console.log('hello from foo [%d]', 123); +} +``` + +```cjs +const { debuglog } = require('node:util'); +const enabled = debuglog('foo').enabled; if (enabled) { console.log('hello from foo [%d]', 123); } @@ -196,10 +245,18 @@ changes: The `util.deprecate()` method wraps `fn` (which may be a function or class) in such a way that it is marked as deprecated. -```js -const util = require('node:util'); +```mjs +import { deprecate } from 'node:util'; -exports.obsoleteFunction = util.deprecate(() => { +export const obsoleteFunction = deprecate(() => { + // Do something here. +}, 'obsoleteFunction() is deprecated. Use newShinyFunction() instead.'); +``` + +```cjs +const { deprecate } = require('node:util'); + +exports.obsoleteFunction = deprecate(() => { // Do something here. }, 'obsoleteFunction() is deprecated. Use newShinyFunction() instead.'); ``` @@ -213,11 +270,40 @@ emitting a warning. If the same optional `code` is supplied in multiple calls to `util.deprecate()`, the warning will be emitted only once for that `code`. -```js -const util = require('node:util'); +```mjs +import { deprecate } from 'node:util'; + +const fn1 = deprecate( + () => 'a value', + 'deprecation message', + 'DEP0001', +); +const fn2 = deprecate( + () => 'a different value', + 'other dep message', + 'DEP0001', +); +fn1(); // Emits a deprecation warning with code DEP0001 +fn2(); // Does not emit a deprecation warning because it has the same code +``` -const fn1 = util.deprecate(someFunction, someMessage, 'DEP0001'); -const fn2 = util.deprecate(someOtherFunction, someOtherMessage, 'DEP0001'); +```cjs +const { deprecate } = require('node:util'); + +const fn1 = deprecate( + function() { + return 'a value'; + }, + 'deprecation message', + 'DEP0001', +); +const fn2 = deprecate( + function() { + return 'a different value'; + }, + 'other dep message', + 'DEP0001', +); fn1(); // Emits a deprecation warning with code DEP0001 fn2(); // Does not emit a deprecation warning because it has the same code ``` @@ -400,11 +486,48 @@ changes: Returns an array of call site objects containing the stack of the caller function. -```js -const util = require('node:util'); +```mjs +import { getCallSites } from 'node:util'; + +function exampleFunction() { + const callSites = getCallSites(); + + console.log('Call Sites:'); + callSites.forEach((callSite, index) => { + console.log(`CallSite ${index + 1}:`); + console.log(`Function Name: ${callSite.functionName}`); + console.log(`Script Name: ${callSite.scriptName}`); + console.log(`Line Number: ${callSite.lineNumber}`); + console.log(`Column Number: ${callSite.column}`); + }); + // CallSite 1: + // Function Name: exampleFunction + // Script Name: /home/example.js + // Line Number: 5 + // Column Number: 26 + + // CallSite 2: + // Function Name: anotherFunction + // Script Name: /home/example.js + // Line Number: 22 + // Column Number: 3 + + // ... +} + +// A function to simulate another stack layer +function anotherFunction() { + exampleFunction(); +} + +anotherFunction(); +``` + +```cjs +const { getCallSites } = require('node:util'); function exampleFunction() { - const callSites = util.getCallSites(); + const callSites = getCallSites(); console.log('Call Sites:'); callSites.forEach((callSite, index) => { @@ -412,7 +535,7 @@ function exampleFunction() { console.log(`Function Name: ${callSite.functionName}`); console.log(`Script Name: ${callSite.scriptName}`); console.log(`Line Number: ${callSite.lineNumber}`); - console.log(`Column Number: ${callSite.columnNumber}`); + console.log(`Column Number: ${callSite.column}`); }); // CallSite 1: // Function Name: exampleFunction @@ -443,13 +566,31 @@ When the `--enable-source-maps` flag is enabled, for example when using `--exper `sourceMap` will be true by default. ```ts -import util from 'node:util'; +import { getCallSites } from 'node:util'; interface Foo { foo: string; } -const callSites = util.getCallSites({ sourceMap: true }); +const callSites = getCallSites({ sourceMap: true }); + +// With sourceMap: +// Function Name: '' +// Script Name: example.js +// Line Number: 7 +// Column Number: 26 + +// Without sourceMap: +// Function Name: '' +// Script Name: example.js +// Line Number: 2 +// Column Number: 26 +``` + +```cjs +const { getCallSites } = require('node:util'); + +const callSites = getCallSites({ sourceMap: true }); // With sourceMap: // Function Name: '' @@ -583,7 +724,24 @@ stream.write('It works!'); // Received data: "It works!" ES6 example using `class` and `extends`: -```js +```mjs +import EventEmitter from 'node:events'; + +class MyStream extends EventEmitter { + write(data) { + this.emit('data', data); + } +} + +const stream = new MyStream(); + +stream.on('data', (data) => { + console.log(`Received data: "${data}"`); +}); +stream.write('With ES6'); +``` + +```cjs const EventEmitter = require('node:events'); class MyStream extends EventEmitter { @@ -767,7 +925,23 @@ util.inspect(baz); // '[foo] {}' Circular references point to their anchor by using a reference index: -```js +```mjs +import { inspect } from 'node:util'; + +const obj = {}; +obj.a = [obj]; +obj.b = {}; +obj.b.inner = obj.b; +obj.b.obj = obj; + +console.log(inspect(obj)); +// { +// a: [ [Circular *1] ], +// b: { inner: [Circular *2], obj: [Circular *1] } +// } +``` + +```cjs const { inspect } = require('node:util'); const obj = {}; @@ -785,7 +959,13 @@ console.log(inspect(obj)); The following example inspects all properties of the `util` object: -```js +```mjs +import util from 'node:util'; + +console.log(util.inspect(util, { showHidden: true, depth: null })); +``` + +```cjs const util = require('node:util'); console.log(util.inspect(util, { showHidden: true, depth: null })); @@ -793,8 +973,8 @@ console.log(util.inspect(util, { showHidden: true, depth: null })); The following example highlights the effect of the `compact` option: -```js -const util = require('node:util'); +```mjs +import { inspect } from 'node:util'; const o = { a: [1, 2, [[ @@ -804,7 +984,7 @@ const o = { 'foo']], 4], b: new Map([['za', 1], ['zb', 'test']]), }; -console.log(util.inspect(o, { compact: true, depth: 5, breakLength: 80 })); +console.log(inspect(o, { compact: true, depth: 5, breakLength: 80 })); // { a: // [ 1, @@ -816,7 +996,57 @@ console.log(util.inspect(o, { compact: true, depth: 5, breakLength: 80 })); // b: Map(2) { 'za' => 1, 'zb' => 'test' } } // Setting `compact` to false or an integer creates more reader friendly output. -console.log(util.inspect(o, { compact: false, depth: 5, breakLength: 80 })); +console.log(inspect(o, { compact: false, depth: 5, breakLength: 80 })); + +// { +// a: [ +// 1, +// 2, +// [ +// [ +// 'Lorem ipsum dolor sit amet,\n' + +// 'consectetur adipiscing elit, sed do eiusmod \n' + +// 'tempor incididunt ut labore et dolore magna aliqua.', +// 'test', +// 'foo' +// ] +// ], +// 4 +// ], +// b: Map(2) { +// 'za' => 1, +// 'zb' => 'test' +// } +// } + +// Setting `breakLength` to e.g. 150 will print the "Lorem ipsum" text in a +// single line. +``` + +```cjs +const { inspect } = require('node:util'); + +const o = { + a: [1, 2, [[ + 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit, sed do ' + + 'eiusmod \ntempor incididunt ut labore et dolore magna aliqua.', + 'test', + 'foo']], 4], + b: new Map([['za', 1], ['zb', 'test']]), +}; +console.log(inspect(o, { compact: true, depth: 5, breakLength: 80 })); + +// { a: +// [ 1, +// 2, +// [ [ 'Lorem ipsum dolor sit amet,\nconsectetur [...]', // A long line +// 'test', +// 'foo' ] ], +// 4 ], +// b: Map(2) { 'za' => 1, 'zb' => 'test' } } + +// Setting `compact` to false or an integer creates more reader friendly output. +console.log(inspect(o, { compact: false, depth: 5, breakLength: 80 })); // { // a: [ @@ -849,7 +1079,18 @@ guarantee which entries are displayed. That means retrieving the same [`WeakSet`][] entries twice may result in different output. Furthermore, entries with no remaining strong references may be garbage collected at any time. -```js +```mjs +import { inspect } from 'node:util'; + +const obj = { a: 1 }; +const obj2 = { b: 2 }; +const weakSet = new WeakSet([obj, obj2]); + +console.log(inspect(weakSet, { showHidden: true })); +// WeakSet { { a: 1 }, { b: 2 } } +``` + +```cjs const { inspect } = require('node:util'); const obj = { a: 1 }; @@ -863,7 +1104,32 @@ console.log(inspect(weakSet, { showHidden: true })); The `sorted` option ensures that an object's property insertion order does not impact the result of `util.inspect()`. -```js +```mjs +import { inspect } from 'node:util'; +import assert from 'node:assert'; + +const o1 = { + b: [2, 3, 1], + a: '`a` comes before `b`', + c: new Set([2, 3, 1]), +}; +console.log(inspect(o1, { sorted: true })); +// { a: '`a` comes before `b`', b: [ 2, 3, 1 ], c: Set(3) { 1, 2, 3 } } +console.log(inspect(o1, { sorted: (a, b) => b.localeCompare(a) })); +// { c: Set(3) { 3, 2, 1 }, b: [ 2, 3, 1 ], a: '`a` comes before `b`' } + +const o2 = { + c: new Set([2, 1, 3]), + a: '`a` comes before `b`', + b: [2, 3, 1], +}; +assert.strict.equal( + inspect(o1, { sorted: true }), + inspect(o2, { sorted: true }), +); +``` + +```cjs const { inspect } = require('node:util'); const assert = require('node:assert'); @@ -891,13 +1157,31 @@ assert.strict.equal( The `numericSeparator` option adds an underscore every three digits to all numbers. -```js +```mjs +import { inspect } from 'node:util'; + +const thousand = 1000; +const million = 1000000; +const bigNumber = 123456789n; +const bigDecimal = 1234.12345; + +console.log(inspect(thousand, { numericSeparator: true })); +// 1_000 +console.log(inspect(million, { numericSeparator: true })); +// 1_000_000 +console.log(inspect(bigNumber, { numericSeparator: true })); +// 123_456_789n +console.log(inspect(bigDecimal, { numericSeparator: true })); +// 1_234.123_45 +``` + +```cjs const { inspect } = require('node:util'); -const thousand = 1_000; -const million = 1_000_000; -const bigNumber = 123_456_789n; -const bigDecimal = 1_234.123_45; +const thousand = 1000; +const million = 1000000; +const bigNumber = 123456789n; +const bigDecimal = 1234.12345; console.log(inspect(thousand, { numericSeparator: true })); // 1_000 @@ -1023,15 +1307,46 @@ Objects may also define their own which `util.inspect()` will invoke and use the result of when inspecting the object. -```js -const util = require('node:util'); +```mjs +import { inspect } from 'node:util'; + +class Box { + constructor(value) { + this.value = value; + } + + [inspect.custom](depth, options, inspect) { + if (depth < 0) { + return options.stylize('[Box]', 'special'); + } + + const newOptions = Object.assign({}, options, { + depth: options.depth === null ? null : options.depth - 1, + }); + + // Five space padding because that's the size of "Box< ". + const padding = ' '.repeat(5); + const inner = inspect(this.value, newOptions) + .replace(/\n/g, `\n${padding}`); + return `${options.stylize('Box', 'special')}< ${inner} >`; + } +} + +const box = new Box(true); + +console.log(inspect(box)); +// "Box< true >" +``` + +```cjs +const { inspect } = require('node:util'); class Box { constructor(value) { this.value = value; } - [util.inspect.custom](depth, options, inspect) { + [inspect.custom](depth, options, inspect) { if (depth < 0) { return options.stylize('[Box]', 'special'); } @@ -1050,24 +1365,36 @@ class Box { const box = new Box(true); -util.inspect(box); -// Returns: "Box< true >" +console.log(inspect(box)); +// "Box< true >" ``` Custom `[util.inspect.custom](depth, opts, inspect)` functions typically return a string but may return a value of any type that will be formatted accordingly by `util.inspect()`. -```js -const util = require('node:util'); +```mjs +import { inspect } from 'node:util'; const obj = { foo: 'this will not show up in the inspect() output' }; -obj[util.inspect.custom] = (depth) => { +obj[inspect.custom] = (depth) => { return { bar: 'baz' }; }; -util.inspect(obj); -// Returns: "{ bar: 'baz' }" +console.log(inspect(obj)); +// "{ bar: 'baz' }" +``` + +```cjs +const { inspect } = require('node:util'); + +const obj = { foo: 'this will not show up in the inspect() output' }; +obj[inspect.custom] = (depth) => { + return { bar: 'baz' }; +}; + +console.log(inspect(obj)); +// "{ bar: 'baz' }" ``` ### `util.inspect.custom` @@ -1127,12 +1454,21 @@ The `defaultOptions` value allows customization of the default options used by object containing one or more valid [`util.inspect()`][] options. Setting option properties directly is also supported. -```js -const util = require('node:util'); -const arr = Array(101).fill(0); +```mjs +import { inspect } from 'node:util'; +const arr = Array(156).fill(0); console.log(arr); // Logs the truncated array -util.inspect.defaultOptions.maxArrayLength = null; +inspect.defaultOptions.maxArrayLength = null; +console.log(arr); // logs the full array +``` + +```cjs +const { inspect } = require('node:util'); +const arr = Array(156).fill(0); + +console.log(arr); // Logs the truncated array +inspect.defaultOptions.maxArrayLength = null; console.log(arr); // logs the full array ``` @@ -1774,12 +2110,24 @@ Takes a function following the common error-first callback style, i.e. taking an `(err, value) => ...` callback as the last argument, and returns a version that returns promises. -```js -const util = require('node:util'); -const fs = require('node:fs'); +```mjs +import { promisify } from 'node:util'; +import { stat } from 'node:fs'; + +const promisifiedStat = promisify(stat); +promisifiedStat('.').then((stats) => { + // Do something with `stats` +}).catch((error) => { + // Handle the error. +}); +``` -const stat = util.promisify(fs.stat); -stat('.').then((stats) => { +```cjs +const { promisify } = require('node:util'); +const { stat } = require('node:fs'); + +const promisifiedStat = promisify(stat); +promisifiedStat('.').then((stats) => { // Do something with `stats` }).catch((error) => { // Handle the error. @@ -1788,14 +2136,28 @@ stat('.').then((stats) => { Or, equivalently using `async function`s: -```js -const util = require('node:util'); -const fs = require('node:fs'); +```mjs +import { promisify } from 'node:util'; +import { stat } from 'node:fs'; + +const promisifiedStat = promisify(stat); + +async function callStat() { + const stats = await promisifiedStat('.'); + console.log(`This directory is owned by ${stats.uid}`); +} -const stat = util.promisify(fs.stat); +callStat(); +``` + +```cjs +const { promisify } = require('node:util'); +const { stat } = require('node:fs'); + +const promisifiedStat = promisify(stat); async function callStat() { - const stats = await stat('.'); + const stats = await promisifiedStat('.'); console.log(`This directory is owned by ${stats.uid}`); } @@ -1814,8 +2176,8 @@ callback as its last argument. Using `promisify()` on class methods or other methods that use `this` may not work as expected unless handled specially: -```js -const util = require('node:util'); +```mjs +import { promisify } from 'node:util'; class Foo { constructor() { @@ -1829,8 +2191,33 @@ class Foo { const foo = new Foo(); -const naiveBar = util.promisify(foo.bar); -// TypeError: Cannot read property 'a' of undefined +const naiveBar = promisify(foo.bar); +// TypeError: Cannot read properties of undefined (reading 'a') +// naiveBar().then(a => console.log(a)); + +naiveBar.call(foo).then((a) => console.log(a)); // '42' + +const bindBar = naiveBar.bind(foo); +bindBar().then((a) => console.log(a)); // '42' +``` + +```cjs +const { promisify } = require('node:util'); + +class Foo { + constructor() { + this.a = 42; + } + + bar(callback) { + callback(null, this.a); + } +} + +const foo = new Foo(); + +const naiveBar = promisify(foo.bar); +// TypeError: Cannot read properties of undefined (reading 'a') // naiveBar().then(a => console.log(a)); naiveBar.call(foo).then((a) => console.log(a)); // '42' @@ -1844,19 +2231,35 @@ bindBar().then((a) => console.log(a)); // '42' Using the `util.promisify.custom` symbol one can override the return value of [`util.promisify()`][]: -```js -const util = require('node:util'); +```mjs +import { promisify } from 'node:util'; function doSomething(foo, callback) { // ... } -doSomething[util.promisify.custom] = (foo) => { +doSomething[promisify.custom] = (foo) => { return getPromiseSomehow(); }; -const promisified = util.promisify(doSomething); -console.log(promisified === doSomething[util.promisify.custom]); +const promisified = promisify(doSomething); +console.log(promisified === doSomething[promisify.custom]); +// prints 'true' +``` + +```cjs +const { promisify } = require('node:util'); + +function doSomething(foo, callback) { + // ... +} + +doSomething[promisify.custom] = (foo) => { + return getPromiseSomehow(); +}; + +const promisified = promisify(doSomething); +console.log(promisified === doSomething[promisify.custom]); // prints 'true' ``` @@ -1988,7 +2391,7 @@ const errorMessage = styleText( // Validate if process.stderr has TTY { stream: stderr }, ); -console.error(successMessage); +console.error(errorMessage); ``` `util.inspect.colors` also provides text formats such as `italic`, and @@ -2603,12 +3006,24 @@ DECLARE_NAPI_PROPERTY("myNapi", MyNapi) ... ``` -```js +```mjs +import native from 'napi_addon.node'; +import { types } from 'node:util'; + +const data = native.myNapi(); +types.isExternal(data); // returns true +types.isExternal(0); // returns false +types.isExternal(new String('foo')); // returns false +``` + +```cjs const native = require('napi_addon.node'); +const { types } = require('node:util'); + const data = native.myNapi(); -util.types.isExternal(data); // returns true -util.types.isExternal(0); // returns false -util.types.isExternal(new String('foo')); // returns false +types.isExternal(data); // returns true +types.isExternal(0); // returns false +types.isExternal(new String('foo')); // returns false ``` For further information on `napi_create_external`, refer to @@ -2832,11 +3247,23 @@ returning `true` for that value. `isNativeError()` returns `true` for errors which come from a different [realm][] while `instanceof Error` returns `false` for these errors: -```js -const vm = require('node:vm'); -const context = vm.createContext({}); -const myError = vm.runInContext('new Error()', context); -console.log(util.types.isNativeError(myError)); // true +```mjs +import { createContext, runInContext } from 'node:vm'; +import { types } from 'node:util'; + +const context = createContext({}); +const myError = runInContext('new Error()', context); +console.log(types.isNativeError(myError)); // true +console.log(myError instanceof Error); // false +``` + +```cjs +const { createContext, runInContext } = require('node:vm'); +const { types } = require('node:util'); + +const context = createContext({}); +const myError = runInContext('new Error()', context); +console.log(types.isNativeError(myError)); // true console.log(myError instanceof Error); // false ```