@@ -25,6 +25,7 @@ const {
2525 ArrayIsArray,
2626 ArrayPrototypeJoin,
2727 ArrayPrototypePop,
28+ ArrayPrototypePush,
2829 Date,
2930 DatePrototypeGetDate,
3031 DatePrototypeGetHours,
@@ -70,6 +71,7 @@ const {
7071 validateNumber,
7172 validateString,
7273 validateOneOf,
74+ validateObject,
7375} = require ( 'internal/validators' ) ;
7476const { isBuffer } = require ( 'buffer' ) . Buffer ;
7577const {
@@ -84,11 +86,13 @@ function lazyUtilColors() {
8486 utilColors ??= require ( 'internal/util/colors' ) ;
8587 return utilColors ;
8688}
89+ const { getOptionValue } = require ( 'internal/options' ) ;
8790
8891const binding = internalBinding ( 'util' ) ;
8992
9093const {
9194 deprecate,
95+ getLazy,
9296 getSystemErrorMap,
9397 getSystemErrorName : internalErrorName ,
9498 getSystemErrorMessage : internalErrorMessage ,
@@ -472,14 +476,90 @@ function parseEnv(content) {
472476 return binding . parseEnv ( content ) ;
473477}
474478
479+ const lazySourceMap = getLazy ( ( ) => require ( 'internal/source_map/source_map_cache' ) ) ;
480+
481+ /**
482+ * @typedef {object } CallSite // The call site
483+ * @property {string } scriptName // The name of the resource that contains the
484+ * script for the function for this StackFrame
485+ * @property {string } functionName // The name of the function associated with this stack frame
486+ * @property {number } lineNumber // The number, 1-based, of the line for the associate function call
487+ * @property {number } columnNumber // The 1-based column offset on the line for the associated function call
488+ */
489+
490+ /**
491+ * @param {CallSite } callSite // The call site object to reconstruct from source map
492+ * @returns {CallSite | undefined } // The reconstructed call site object
493+ */
494+ function reconstructCallSite ( callSite ) {
495+ const { scriptName, lineNumber, column } = callSite ;
496+ const sourceMap = lazySourceMap ( ) . findSourceMap ( scriptName ) ;
497+ if ( ! sourceMap ) return ;
498+ const entry = sourceMap . findEntry ( lineNumber - 1 , column - 1 ) ;
499+ if ( ! entry ?. originalSource ) return ;
500+ return {
501+ __proto__ : null ,
502+ // If the name is not found, it is an empty string to match the behavior of `util.getCallSite()`
503+ functionName : entry . name ?? '' ,
504+ scriptName : entry . originalSource ,
505+ lineNumber : entry . originalLine + 1 ,
506+ column : entry . originalColumn + 1 ,
507+ } ;
508+ }
509+
510+ /**
511+ *
512+ * The call site array to map
513+ * @param {CallSite[] } callSites
514+ * Array of objects with the reconstructed call site
515+ * @returns {CallSite[] }
516+ */
517+ function mapCallSite ( callSites ) {
518+ const result = [ ] ;
519+ for ( let i = 0 ; i < callSites . length ; ++ i ) {
520+ const callSite = callSites [ i ] ;
521+ const found = reconstructCallSite ( callSite ) ;
522+ ArrayPrototypePush ( result , found ?? callSite ) ;
523+ }
524+ return result ;
525+ }
526+
527+ /**
528+ * @typedef {object } CallSiteOptions // The call site options
529+ * @property {boolean } sourceMap // Enable source map support
530+ */
531+
475532/**
476533 * Returns the callSite
477534 * @param {number } frameCount
478- * @returns {object }
535+ * @param {CallSiteOptions } options
536+ * @returns {CallSite[] }
479537 */
480- function getCallSites ( frameCount = 10 ) {
538+ function getCallSites ( frameCount = 10 , options ) {
539+ // If options is not provided check if frameCount is an object
540+ if ( options === undefined ) {
541+ if ( typeof frameCount === 'object' ) {
542+ // If frameCount is an object, it is the options object
543+ options = frameCount ;
544+ validateObject ( options , 'options' ) ;
545+ validateBoolean ( options . sourceMap , 'options.sourceMap' ) ;
546+ frameCount = 10 ;
547+ } else {
548+ // If options is not provided, set it to an empty object
549+ options = { } ;
550+ } ;
551+ } else {
552+ // If options is provided, validate it
553+ validateObject ( options , 'options' ) ;
554+ validateBoolean ( options . sourceMap , 'options.sourceMap' ) ;
555+ }
556+
481557 // Using kDefaultMaxCallStackSizeToCapture as reference
482558 validateNumber ( frameCount , 'frameCount' , 1 , 200 ) ;
559+ // If options.sourceMaps is true or if sourceMaps are enabled but the option.sourceMaps is not set explictly to false
560+ if ( options . sourceMap === true || ( getOptionValue ( '--enable-source-maps' ) && options . sourceMap !== false ) ) {
561+ return mapCallSite ( binding . getCallSites ( frameCount ) ) ;
562+ }
483563 return binding . getCallSites ( frameCount ) ;
484564} ;
485565
0 commit comments