24
24
const {
25
25
ArrayIsArray,
26
26
ArrayPrototypePop,
27
+ ArrayPrototypePush,
27
28
Error,
28
29
ErrorCaptureStackTrace,
29
30
FunctionPrototypeBind,
@@ -61,6 +62,7 @@ const {
61
62
validateNumber,
62
63
validateString,
63
64
validateOneOf,
65
+ validateObject,
64
66
} = require ( 'internal/validators' ) ;
65
67
const {
66
68
isReadableStream,
@@ -74,11 +76,13 @@ function lazyUtilColors() {
74
76
utilColors ??= require ( 'internal/util/colors' ) ;
75
77
return utilColors ;
76
78
}
79
+ const { getOptionValue } = require ( 'internal/options' ) ;
77
80
78
81
const binding = internalBinding ( 'util' ) ;
79
82
80
83
const {
81
84
deprecate,
85
+ getLazy,
82
86
getSystemErrorMap,
83
87
getSystemErrorName : internalErrorName ,
84
88
getSystemErrorMessage : internalErrorMessage ,
@@ -328,14 +332,90 @@ function parseEnv(content) {
328
332
return binding . parseEnv ( content ) ;
329
333
}
330
334
335
+ const lazySourceMap = getLazy ( ( ) => require ( 'internal/source_map/source_map_cache' ) ) ;
336
+
337
+ /**
338
+ * @typedef {object } CallSite // The call site
339
+ * @property {string } scriptName // The name of the resource that contains the
340
+ * script for the function for this StackFrame
341
+ * @property {string } functionName // The name of the function associated with this stack frame
342
+ * @property {number } lineNumber // The number, 1-based, of the line for the associate function call
343
+ * @property {number } columnNumber // The 1-based column offset on the line for the associated function call
344
+ */
345
+
346
+ /**
347
+ * @param {CallSite } callSite // The call site object to reconstruct from source map
348
+ * @returns {CallSite | undefined } // The reconstructed call site object
349
+ */
350
+ function reconstructCallSite ( callSite ) {
351
+ const { scriptName, lineNumber, column } = callSite ;
352
+ const sourceMap = lazySourceMap ( ) . findSourceMap ( scriptName ) ;
353
+ if ( ! sourceMap ) return ;
354
+ const entry = sourceMap . findEntry ( lineNumber - 1 , column - 1 ) ;
355
+ if ( ! entry ?. originalSource ) return ;
356
+ return {
357
+ __proto__ : null ,
358
+ // If the name is not found, it is an empty string to match the behavior of `util.getCallSite()`
359
+ functionName : entry . name ?? '' ,
360
+ scriptName : entry . originalSource ,
361
+ lineNumber : entry . originalLine + 1 ,
362
+ column : entry . originalColumn + 1 ,
363
+ } ;
364
+ }
365
+
366
+ /**
367
+ *
368
+ * The call site array to map
369
+ * @param {CallSite[] } callSites
370
+ * Array of objects with the reconstructed call site
371
+ * @returns {CallSite[] }
372
+ */
373
+ function mapCallSite ( callSites ) {
374
+ const result = [ ] ;
375
+ for ( let i = 0 ; i < callSites . length ; ++ i ) {
376
+ const callSite = callSites [ i ] ;
377
+ const found = reconstructCallSite ( callSite ) ;
378
+ ArrayPrototypePush ( result , found ?? callSite ) ;
379
+ }
380
+ return result ;
381
+ }
382
+
383
+ /**
384
+ * @typedef {object } CallSiteOptions // The call site options
385
+ * @property {boolean } sourceMap // Enable source map support
386
+ */
387
+
331
388
/**
332
389
* Returns the callSite
333
390
* @param {number } frameCount
334
- * @returns {object }
391
+ * @param {CallSiteOptions } options
392
+ * @returns {CallSite[] }
335
393
*/
336
- function getCallSites ( frameCount = 10 ) {
394
+ function getCallSites ( frameCount = 10 , options ) {
395
+ // If options is not provided check if frameCount is an object
396
+ if ( options === undefined ) {
397
+ if ( typeof frameCount === 'object' ) {
398
+ // If frameCount is an object, it is the options object
399
+ options = frameCount ;
400
+ validateObject ( options , 'options' ) ;
401
+ validateBoolean ( options . sourceMap , 'options.sourceMap' ) ;
402
+ frameCount = 10 ;
403
+ } else {
404
+ // If options is not provided, set it to an empty object
405
+ options = { } ;
406
+ } ;
407
+ } else {
408
+ // If options is provided, validate it
409
+ validateObject ( options , 'options' ) ;
410
+ validateBoolean ( options . sourceMap , 'options.sourceMap' ) ;
411
+ }
412
+
337
413
// Using kDefaultMaxCallStackSizeToCapture as reference
338
414
validateNumber ( frameCount , 'frameCount' , 1 , 200 ) ;
415
+ // If options.sourceMaps is true or if sourceMaps are enabled but the option.sourceMaps is not set explictly to false
416
+ if ( options . sourceMap === true || ( getOptionValue ( '--enable-source-maps' ) && options . sourceMap !== false ) ) {
417
+ return mapCallSite ( binding . getCallSites ( frameCount ) ) ;
418
+ }
339
419
return binding . getCallSites ( frameCount ) ;
340
420
} ;
341
421
0 commit comments