util: fix util.getCallSites plurality

`util.getCallSite` returns an array of call site objects. Rename the
function to reflect that it returns a given count of frames captured
as an array of call site object.

Renames the first parameter `frames` to be `frameCount` to indicate
that it specifies the count of returned call sites.

PR-URL: https://github.com/nodejs/node/pull/55626
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
This commit is contained in:
Chengzhong Wu 2024-11-02 23:24:56 +08:00 committed by GitHub
parent 9a16fdea34
commit 68dc15e400
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 89 additions and 61 deletions

View File

@ -1,15 +1,15 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const { getCallSite } = require('node:util'); const { getCallSites } = require('node:util');
const assert = require('node:assert'); const assert = require('node:assert');
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [1e6], n: [1e6],
method: ['ErrorCallSite', 'ErrorCallSiteSerialized', 'CPP'], method: ['ErrorCallSites', 'ErrorCallSitesSerialized', 'CPP'],
}); });
function ErrorGetCallSite() { function ErrorGetCallSites() {
const originalStackFormatter = Error.prepareStackTrace; const originalStackFormatter = Error.prepareStackTrace;
Error.prepareStackTrace = (_err, stack) => { Error.prepareStackTrace = (_err, stack) => {
if (stack && stack.length > 1) { if (stack && stack.length > 1) {
@ -25,15 +25,15 @@ function ErrorGetCallSite() {
return err.stack; return err.stack;
} }
function ErrorCallSiteSerialized() { function ErrorCallSitesSerialized() {
const callsite = ErrorGetCallSite(); const callSites = ErrorGetCallSites();
const serialized = []; const serialized = [];
for (let i = 0; i < callsite.length; ++i) { for (let i = 0; i < callSites.length; ++i) {
serialized.push({ serialized.push({
functionName: callsite[i].getFunctionName(), functionName: callSites[i].getFunctionName(),
scriptName: callsite[i].getFileName(), scriptName: callSites[i].getFileName(),
lineNumber: callsite[i].getLineNumber(), lineNumber: callSites[i].getLineNumber(),
column: callsite[i].getColumnNumber(), column: callSites[i].getColumnNumber(),
}); });
} }
return serialized; return serialized;
@ -42,14 +42,14 @@ function ErrorCallSiteSerialized() {
function main({ n, method }) { function main({ n, method }) {
let fn; let fn;
switch (method) { switch (method) {
case 'ErrorCallSite': case 'ErrorCallSites':
fn = ErrorGetCallSite; fn = ErrorGetCallSites;
break; break;
case 'ErrorCallSiteSerialized': case 'ErrorCallSitesSerialized':
fn = ErrorCallSiteSerialized; fn = ErrorCallSitesSerialized;
break; break;
case 'CPP': case 'CPP':
fn = getCallSite; fn = getCallSites;
break; break;
} }
let lastStack = {}; let lastStack = {};

View File

@ -3761,6 +3761,19 @@ Instantiating classes without the `new` qualifier exported by the `node:repl` mo
It is recommended to use the `new` qualifier instead. This applies to all REPL classes, including It is recommended to use the `new` qualifier instead. This applies to all REPL classes, including
`REPLServer` and `Recoverable`. `REPLServer` and `Recoverable`.
### DEP0186: `util.getCallSite`
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/55626
description: Runtime deprecation.
-->
Type: Runtime
The `util.getCallSite` API has been removed. Please use [`util.getCallSites()`][] instead.
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3 [RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
[RFC 8247 Section 2.4]: https://www.rfc-editor.org/rfc/rfc8247#section-2.4 [RFC 8247 Section 2.4]: https://www.rfc-editor.org/rfc/rfc8247#section-2.4
@ -3886,6 +3899,7 @@ It is recommended to use the `new` qualifier instead. This applies to all REPL c
[`url.parse()`]: url.md#urlparseurlstring-parsequerystring-slashesdenotehost [`url.parse()`]: url.md#urlparseurlstring-parsequerystring-slashesdenotehost
[`url.resolve()`]: url.md#urlresolvefrom-to [`url.resolve()`]: url.md#urlresolvefrom-to
[`util._extend()`]: util.md#util_extendtarget-source [`util._extend()`]: util.md#util_extendtarget-source
[`util.getCallSites()`]: util.md#utilgetcallsitesframecount
[`util.getSystemErrorName()`]: util.md#utilgetsystemerrornameerr [`util.getSystemErrorName()`]: util.md#utilgetsystemerrornameerr
[`util.inspect()`]: util.md#utilinspectobject-options [`util.inspect()`]: util.md#utilinspectobject-options
[`util.inspect.custom`]: util.md#utilinspectcustom [`util.inspect.custom`]: util.md#utilinspectcustom

View File

@ -364,7 +364,7 @@ util.formatWithOptions({ colors: true }, 'See object %O', { foo: 42 });
// when printed to a terminal. // when printed to a terminal.
``` ```
## `util.getCallSite(frames)` ## `util.getCallSites(frameCount)`
> Stability: 1.1 - Active development > Stability: 1.1 - Active development
@ -372,23 +372,23 @@ util.formatWithOptions({ colors: true }, 'See object %O', { foo: 42 });
added: v22.9.0 added: v22.9.0
--> -->
* `frames` {number} Number of frames returned in the stacktrace. * `frameCount` {number} Number of frames to capture as call site objects.
**Default:** `10`. Allowable range is between 1 and 200. **Default:** `10`. Allowable range is between 1 and 200.
* Returns: {Object\[]} An array of stacktrace objects * Returns: {Object\[]} An array of call site objects
* `functionName` {string} Returns the name of the function associated with this stack frame. * `functionName` {string} Returns the name of the function associated with this call site.
* `scriptName` {string} Returns the name of the resource that contains the script for the * `scriptName` {string} Returns the name of the resource that contains the script for the
function for this StackFrame. function for this call site.
* `lineNumber` {number} Returns the number, 1-based, of the line for the associate function call. * `lineNumber` {number} Returns the number, 1-based, of the line for the associate function call.
* `column` {number} Returns the 1-based column offset on the line for the associated function call. * `column` {number} Returns the 1-based column offset on the line for the associated function call.
Returns an array of stacktrace objects containing the stack of Returns an array of call site objects containing the stack of
the caller function. the caller function.
```js ```js
const util = require('node:util'); const util = require('node:util');
function exampleFunction() { function exampleFunction() {
const callSites = util.getCallSite(); const callSites = util.getCallSites();
console.log('Call Sites:'); console.log('Call Sites:');
callSites.forEach((callSite, index) => { callSites.forEach((callSite, index) => {

View File

@ -330,13 +330,13 @@ function parseEnv(content) {
/** /**
* Returns the callSite * Returns the callSite
* @param {number} frames * @param {number} frameCount
* @returns {object} * @returns {object}
*/ */
function getCallSite(frames = 10) { function getCallSites(frameCount = 10) {
// Using kDefaultMaxCallStackSizeToCapture as reference // Using kDefaultMaxCallStackSizeToCapture as reference
validateNumber(frames, 'frames', 1, 200); validateNumber(frameCount, 'frameCount', 1, 200);
return binding.getCallSite(frames); return binding.getCallSites(frameCount);
}; };
// Keep the `exports =` so that various functions can still be monkeypatched // Keep the `exports =` so that various functions can still be monkeypatched
@ -353,7 +353,12 @@ module.exports = {
format, format,
styleText, styleText,
formatWithOptions, formatWithOptions,
getCallSite, // Deprecated getCallSite.
// This API can be removed in next semver-minor release.
getCallSite: deprecate(getCallSites,
'The `util.getCallSite` API is deprecated. Please use `util.getCallSites()` instead.',
'DEP0186'),
getCallSites,
getSystemErrorMap, getSystemErrorMap,
getSystemErrorName, getSystemErrorName,
getSystemErrorMessage, getSystemErrorMessage,

View File

@ -247,7 +247,7 @@ static void ParseEnv(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(dotenv.ToObject(env)); args.GetReturnValue().Set(dotenv.ToObject(env));
} }
static void GetCallSite(const FunctionCallbackInfo<Value>& args) { static void GetCallSites(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate(); Isolate* isolate = env->isolate();
@ -345,7 +345,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetProxyDetails); registry->Register(GetProxyDetails);
registry->Register(GetCallerLocation); registry->Register(GetCallerLocation);
registry->Register(PreviewEntries); registry->Register(PreviewEntries);
registry->Register(GetCallSite); registry->Register(GetCallSites);
registry->Register(GetOwnNonIndexProperties); registry->Register(GetOwnNonIndexProperties);
registry->Register(GetConstructorName); registry->Register(GetConstructorName);
registry->Register(GetExternalValue); registry->Register(GetExternalValue);
@ -451,7 +451,7 @@ void Initialize(Local<Object> target,
SetMethodNoSideEffect( SetMethodNoSideEffect(
context, target, "getConstructorName", GetConstructorName); context, target, "getConstructorName", GetConstructorName);
SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue); SetMethodNoSideEffect(context, target, "getExternalValue", GetExternalValue);
SetMethodNoSideEffect(context, target, "getCallSite", GetCallSite); SetMethodNoSideEffect(context, target, "getCallSites", GetCallSites);
SetMethod(context, target, "sleep", Sleep); SetMethod(context, target, "sleep", Sleep);
SetMethod(context, target, "parseEnv", ParseEnv); SetMethod(context, target, "parseEnv", ParseEnv);

View File

@ -30,7 +30,7 @@ const net = require('net');
// Do not require 'os' until needed so that test-os-checked-function can // Do not require 'os' until needed so that test-os-checked-function can
// monkey patch it. If 'os' is required here, that test will fail. // monkey patch it. If 'os' is required here, that test will fail.
const path = require('path'); const path = require('path');
const { inspect, getCallSite } = require('util'); const { inspect, getCallSites } = require('util');
const { isMainThread } = require('worker_threads'); const { isMainThread } = require('worker_threads');
const { isModuleNamespaceObject } = require('util/types'); const { isModuleNamespaceObject } = require('util/types');
@ -550,7 +550,7 @@ function canCreateSymLink() {
} }
function mustNotCall(msg) { function mustNotCall(msg) {
const callSite = getCallSite()[1]; const callSite = getCallSites()[1];
return function mustNotCall(...args) { return function mustNotCall(...args) {
const argsInfo = args.length > 0 ? const argsInfo = args.length > 0 ?
`\ncalled with arguments: ${args.map((arg) => inspect(arg)).join(', ')}` : ''; `\ncalled with arguments: ${args.map((arg) => inspect(arg)).join(', ')}` : '';

View File

@ -1,4 +0,0 @@
const util = require('node:util');
const assert = require('node:assert');
assert.ok(util.getCallSite().length > 1);
process.stdout.write(util.getCallSite()[0].scriptName);

4
test/fixtures/get-call-sites.js vendored Normal file
View File

@ -0,0 +1,4 @@
const util = require('node:util');
const assert = require('node:assert');
assert.ok(util.getCallSites().length > 1);
process.stdout.write(util.getCallSites()[0].scriptName);

View File

@ -0,0 +1,9 @@
'use strict';
require('../common');
const { getCallSite } = require('node:util');
const { expectWarning } = require('../common');
const warning = 'The `util.getCallSite` API is deprecated. Please use `util.getCallSites()` instead.';
expectWarning('DeprecationWarning', warning, 'DEP0186');
getCallSite();

View File

@ -3,68 +3,68 @@
const common = require('../common'); const common = require('../common');
const fixtures = require('../common/fixtures'); const fixtures = require('../common/fixtures');
const file = fixtures.path('get-call-site.js'); const file = fixtures.path('get-call-sites.js');
const { getCallSite } = require('node:util'); const { getCallSites } = require('node:util');
const { spawnSync } = require('node:child_process'); const { spawnSync } = require('node:child_process');
const assert = require('node:assert'); const assert = require('node:assert');
{ {
const callsite = getCallSite(); const callSites = getCallSites();
assert.ok(callsite.length > 1); assert.ok(callSites.length > 1);
assert.match( assert.match(
callsite[0].scriptName, callSites[0].scriptName,
/test-util-getCallSite/, /test-util-getcallsites/,
'node:util should be ignored', 'node:util should be ignored',
); );
} }
{ {
const callsite = getCallSite(3); const callSites = getCallSites(3);
assert.strictEqual(callsite.length, 3); assert.strictEqual(callSites.length, 3);
assert.match( assert.match(
callsite[0].scriptName, callSites[0].scriptName,
/test-util-getCallSite/, /test-util-getcallsites/,
'node:util should be ignored', 'node:util should be ignored',
); );
} }
// Guarantee dot-left numbers are ignored // Guarantee dot-left numbers are ignored
{ {
const callsite = getCallSite(3.6); const callSites = getCallSites(3.6);
assert.strictEqual(callsite.length, 3); assert.strictEqual(callSites.length, 3);
} }
{ {
const callsite = getCallSite(3.4); const callSites = getCallSites(3.4);
assert.strictEqual(callsite.length, 3); assert.strictEqual(callSites.length, 3);
} }
{ {
assert.throws(() => { assert.throws(() => {
// Max than kDefaultMaxCallStackSizeToCapture // Max than kDefaultMaxCallStackSizeToCapture
getCallSite(201); getCallSites(201);
}, common.expectsError({ }, common.expectsError({
code: 'ERR_OUT_OF_RANGE' code: 'ERR_OUT_OF_RANGE'
})); }));
assert.throws(() => { assert.throws(() => {
getCallSite(-1); getCallSites(-1);
}, common.expectsError({ }, common.expectsError({
code: 'ERR_OUT_OF_RANGE' code: 'ERR_OUT_OF_RANGE'
})); }));
assert.throws(() => { assert.throws(() => {
getCallSite({}); getCallSites({});
}, common.expectsError({ }, common.expectsError({
code: 'ERR_INVALID_ARG_TYPE' code: 'ERR_INVALID_ARG_TYPE'
})); }));
} }
{ {
const callsite = getCallSite(1); const callSites = getCallSites(1);
assert.strictEqual(callsite.length, 1); assert.strictEqual(callSites.length, 1);
assert.match( assert.match(
callsite[0].scriptName, callSites[0].scriptName,
/test-util-getCallSite/, /test-util-getcallsites/,
'node:util should be ignored', 'node:util should be ignored',
); );
} }
@ -77,8 +77,8 @@ const assert = require('node:assert');
'-e', '-e',
`const util = require('util'); `const util = require('util');
const assert = require('assert'); const assert = require('assert');
assert.ok(util.getCallSite().length > 1); assert.ok(util.getCallSites().length > 1);
process.stdout.write(util.getCallSite()[0].scriptName); process.stdout.write(util.getCallSites()[0].scriptName);
`, `,
], ],
); );
@ -100,7 +100,7 @@ const assert = require('node:assert');
{ {
const originalStackTraceLimit = Error.stackTraceLimit; const originalStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 0; Error.stackTraceLimit = 0;
const callsite = getCallSite(); const callSites = getCallSites();
assert.notStrictEqual(callsite.length, 0); assert.notStrictEqual(callSites.length, 0);
Error.stackTraceLimit = originalStackTraceLimit; Error.stackTraceLimit = originalStackTraceLimit;
} }