diff --git a/Jint.Tests.PublicInterface/CallStackTests.cs b/Jint.Tests.PublicInterface/CallStackTests.cs index 28f680385..bce0af8fa 100644 --- a/Jint.Tests.PublicInterface/CallStackTests.cs +++ b/Jint.Tests.PublicInterface/CallStackTests.cs @@ -55,7 +55,7 @@ public void ShouldReturnTheSourceMapStack() { var sourceMap = SourceMapParser.Parse("""{"version":3,"file":"custom.js","sourceRoot":"","sources":["custom.ts"],"names":[],"mappings":"AAEA,SAAS,CAAC,CAAC,CAAM;IAChB,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,IAAI,CAAC,GAAG,UAAU,CAAM;IACvB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACb,CAAC,CAAA;AAED,CAAC,CAAC,CAAC,CAAC,CAAC"}"""); - string BuildCallStackHandler(string description, SourceLocation location, List arguments) + string BuildCallStackHandler(string description, SourceLocation location, string[] arguments) { if (location.SourceFile != sourceMap.File) { diff --git a/Jint/Options.cs b/Jint/Options.cs index 2279e1d29..cdaf84162 100644 --- a/Jint/Options.cs +++ b/Jint/Options.cs @@ -27,7 +27,7 @@ public class Options public delegate bool ExceptionHandlerDelegate(Exception exception); - public delegate string? BuildCallStackDelegate(string shortDescription, SourceLocation location, List? arguments); + public delegate string? BuildCallStackDelegate(string shortDescription, SourceLocation location, string[]? arguments); /// /// Execution constraints for the engine. @@ -304,7 +304,7 @@ public class InteropOptions /// stack traces to code different from the code being executed, eg. when /// executing code transpiled from TypeScript. /// - public BuildCallStackDelegate BuildCallStackHandler { get; set; } = static (string description, SourceLocation location, List? arguments) => null; + public BuildCallStackDelegate? BuildCallStackHandler { get; set; } /// /// diff --git a/Jint/Runtime/CallStack/JintCallStack.cs b/Jint/Runtime/CallStack/JintCallStack.cs index 2e933955a..0abe76537 100644 --- a/Jint/Runtime/CallStack/JintCallStack.cs +++ b/Jint/Runtime/CallStack/JintCallStack.cs @@ -116,24 +116,17 @@ public override string ToString() internal string BuildCallStackString(Engine engine, SourceLocation location, int excludeTop = 0) { + var customCallStackBuilder = engine.Options.Interop.BuildCallStackHandler; + static void AppendLocation( ref ValueStringBuilder sb, string shortDescription, in SourceLocation loc, in CallStackElement? element, - Engine engine) + Options.BuildCallStackDelegate? callStackBuilder) { - List? arguments = null; - - if (element?.Arguments is not null) - { - arguments = element.Value.Arguments.Value.Select(GetPropertyKey).ToList(); - } - - var str = engine.Options.Interop.BuildCallStackHandler.Invoke(shortDescription, loc, arguments); - if (!string.IsNullOrEmpty(str)) + if (callStackBuilder != null && TryInvokeCustomCallStackHandler(callStackBuilder, element, shortDescription, loc, ref sb)) { - sb.Append(str); return; } @@ -145,16 +138,19 @@ static void AppendLocation( sb.Append(shortDescription); } - if (arguments is not null) + if (element?.Arguments is not null) { + // it's a function sb.Append(" ("); - for (var index = 0; index < arguments.Count; index++) + var arguments = element.Value.Arguments.Value; + for (var i = 0; i < arguments.Count; i++) { - if (index != 0) + if (i != 0) { sb.Append(", "); } - sb.Append(arguments[index]); + + sb.Append(GetPropertyKey(arguments[i])); } sb.Append(')'); } @@ -175,7 +171,7 @@ static void AppendLocation( var element = index >= 0 ? _stack[index] : (CallStackElement?) null; var shortDescription = element?.ToString() ?? ""; - AppendLocation(ref builder, shortDescription, location, element, engine); + AppendLocation(ref builder, shortDescription, location, element, customCallStackBuilder); location = element?.Location ?? default; index--; @@ -183,9 +179,9 @@ static void AppendLocation( while (index >= -1) { element = index >= 0 ? _stack[index] : null; - shortDescription = element?.ToString() ?? string.Empty; + shortDescription = element?.ToString() ?? ""; - AppendLocation(ref builder, shortDescription, location, element, engine); + AppendLocation(ref builder, shortDescription, location, element, customCallStackBuilder); location = element?.Location ?? default; index--; @@ -198,6 +194,34 @@ static void AppendLocation( return result; } + private static bool TryInvokeCustomCallStackHandler( + Options.BuildCallStackDelegate handler, + CallStackElement? element, + string shortDescription, + SourceLocation loc, + ref ValueStringBuilder sb) + { + string[]? arguments = null; + if (element?.Arguments is not null) + { + var args = element.Value.Arguments.Value; + arguments = args.Count > 0 ? new string[args.Count] : []; + for (var i = 0; i < arguments.Length; i++) + { + arguments[i] = GetPropertyKey(args[i]); + } + } + + var str = handler(shortDescription, loc, arguments); + if (!string.IsNullOrEmpty(str)) + { + sb.Append(str); + return true; + } + + return false; + } + /// /// A version of that cannot get into loop as we are already building a stack. /// @@ -215,8 +239,7 @@ private static string GetPropertyKey(Node expression) if (expression is MemberExpression { Computed: false } staticMemberExpression) { - return GetPropertyKey(staticMemberExpression.Object) + "." + - GetPropertyKey(staticMemberExpression.Property); + return $"{GetPropertyKey(staticMemberExpression.Object)}.{GetPropertyKey(staticMemberExpression.Property)}"; } return "?";