Skip to content
This repository was archived by the owner on Jul 18, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ public override string ToString()
for (int i = 0; i < DeminifiedStackFrameResults.Count; i++)
{
StackFrame deminFrame = DeminifiedStackFrameResults[i].DeminifiedStackFrame;
StackFrame frame = string.IsNullOrEmpty(deminFrame.MethodName) ? MinifiedStackFrames[i] : deminFrame;

// Use deminified info wherever possible, merging if necessary so we always print a full frame
StackFrame frame = new StackFrame()
{
MethodName = deminFrame.MethodName ?? MinifiedStackFrames[i].MethodName,
SourcePosition = deminFrame.SourcePosition ?? MinifiedStackFrames[i].SourcePosition,
FilePath = deminFrame.SourcePosition != null ? deminFrame.FilePath : MinifiedStackFrames[i].FilePath
};

output += $"{Environment.NewLine} {frame}";
}
Expand Down
16 changes: 13 additions & 3 deletions src/SourceMapToolkit.CallstackDeminifier/FunctionMapGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@ public List<FunctionMapEntry> GenerateFunctionMap(StreamReader sourceCodeStreamR
return null;
}

List<FunctionMapEntry> result = ParseSourceCode(sourceCodeStreamReader);
List<FunctionMapEntry> result;
try
{
result = ParseSourceCode(sourceCodeStreamReader);

foreach (FunctionMapEntry functionMapEntry in result)
foreach (FunctionMapEntry functionMapEntry in result)
{
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
}
}
catch
{
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
// Failed to parse JavaScript source. This is common as the JS parser does not support ES2015+.
// Continue to regular source map deminification.
result = null;
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ internal interface IStackFrameDeminifier
/// This method will deminify a single stack from from a minified stack trace.
/// </summary>
/// <returns>Returns a StackFrameDeminificationResult that contains a stack trace that has been translated to the original source code. The DeminificationError Property indicates if the StackFrame could not be deminified. DeminifiedStackFrame will not be null, but any properties of DeminifiedStackFrame could be null if the value could not be extracted. </returns>
StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame);
StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ namespace SourcemapToolkit.CallstackDeminifier
/// <summary>
/// This class only deminfies the method name in a stack frame. It does not depend on having a source map available during runtime.
/// </summary>
internal class SimpleStackFrameDeminifier : IStackFrameDeminifier
internal class MethodNameStackFrameDeminifier : IStackFrameDeminifier
{
protected readonly IFunctionMapConsumer _functionMapConsumer;
protected readonly IFunctionMapStore _functionMapStore;

public SimpleStackFrameDeminifier(IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer)
public MethodNameStackFrameDeminifier(IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer)
{
_functionMapStore = functionMapStore;
_functionMapConsumer = functionMapConsumer;
}
/// <summary>
/// This method will deminify the method name of a single stack from from a minified stack trace.
/// </summary>
public virtual StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame)
public virtual StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName)
{
StackFrameDeminificationResult result = new StackFrameDeminificationResult
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<Compile Include="IStackFrameDeminifier.cs" />
<Compile Include="IStackTraceParser.cs" />
<Compile Include="KeyValueCache.cs" />
<Compile Include="SimpleStackFrameDeminifier.cs" />
<Compile Include="MethodNameStackFrameDeminifier.cs" />
<Compile Include="SourceMapStore.cs" />
<Compile Include="StackFrame.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public class StackFrameDeminificationResult
/// </summary>
public StackFrame DeminifiedStackFrame { get; set; }

/// <summary>
/// The original name of the symbol at this frame's position
/// </summary>
public string DeminifiedSymbolName { get; set; }

/// <summary>
/// An enum indicating if any errors occured when deminifying the stack frame.
/// </summary>
Expand Down
37 changes: 30 additions & 7 deletions src/SourceMapToolkit.CallstackDeminifier/StackFrameDeminifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@ namespace SourcemapToolkit.CallstackDeminifier
/// Since source maps take up a large amount of memory, this class consumes considerably
/// more memory than SimpleStackFrame Deminifier during runtime.
/// </summary>
internal class StackFrameDeminifier : SimpleStackFrameDeminifier
internal class StackFrameDeminifier : IStackFrameDeminifier
{
private readonly ISourceMapStore _sourceMapStore;
private readonly MethodNameStackFrameDeminifier _methodNameDeminifier = null;

public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer) : base (functionMapStore, functionMapConsumer)
public StackFrameDeminifier(ISourceMapStore sourceMapStore)
{
_sourceMapStore = sourceMapStore;
}

public StackFrameDeminifier(ISourceMapStore sourceMapStore, IFunctionMapStore functionMapStore, IFunctionMapConsumer functionMapConsumer) : this(sourceMapStore)
{
_methodNameDeminifier = new MethodNameStackFrameDeminifier(functionMapStore, functionMapConsumer);
}

/// <summary>
/// This method will deminify a single stack from from a minified stack trace.
/// </summary>
/// <returns>Returns a StackFrameDeminificationResult that contains a stack trace that has been translated to the original source code. The DeminificationError Property indicates if the StackFrame could not be deminified. DeminifiedStackFrame will not be null, but any properties of DeminifiedStackFrame could be null if the value could not be extracted. </returns>
public override StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame)
public StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName)
{
if (stackFrame == null)
{
Expand All @@ -32,7 +38,21 @@ public override StackFrameDeminificationResult DeminifyStackFrame(StackFrame sta
SourceMap sourceMap = _sourceMapStore.GetSourceMapForUrl(stackFrame.FilePath);
SourcePosition generatedSourcePosition = stackFrame.SourcePosition;

StackFrameDeminificationResult result = base.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult result = null;
if (_methodNameDeminifier != null)
{
result = _methodNameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName);
}

if (result == null || result.DeminificationError == DeminificationError.NoSourceCodeProvided)
{
result = new StackFrameDeminificationResult
{
DeminificationError = DeminificationError.None,
DeminifiedStackFrame = new StackFrame { MethodName = callerSymbolName }
};
}

if (result.DeminificationError == DeminificationError.None)
{
MappingEntry generatedSourcePositionMappingEntry =
Expand All @@ -53,9 +73,12 @@ public override StackFrameDeminificationResult DeminifyStackFrame(StackFrame sta
result.DeminificationError = DeminificationError.NoMatchingMapingInSourceMap;
}
}

result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry?.OriginalFileName;
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry?.OriginalSourcePosition;
else
{
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry.OriginalFileName;
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry.OriginalSourcePosition;
result.DeminifiedSymbolName = generatedSourcePositionMappingEntry.OriginalName;
}
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,41 @@ public static StackTraceDeminifier GetStackTraceDeminfier(ISourceMapProvider sou

return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
}


/// <summary>
/// Creates a StackTraceDeminifier which does not depend on JS files, and is ES2015+ compatible.
/// StackTrace deminifiers created with this method will keep source maps cached, and thus use significantly more memory during runtime than the ones generated with GetMethodNameOnlyStackTraceDeminfier.
/// </summary>
/// <param name="sourceMapProvider">Consumers of the API should implement this interface, which provides the source map for a given JavaScript file. Throws ArgumentNullException if the parameter is set to null.</param>
public static StackTraceDeminifier GetMapOnlyStackTraceDeminfier(ISourceMapProvider sourceMapProvider)
{
return GetMapOnlyStackTraceDeminfier(sourceMapProvider, new StackTraceParser());
}

/// <summary>
/// Creates a StackTraceDeminifier which does not depend on JS files, and is ES2015+ compatible.
/// StackTrace deminifiers created with this method will keep source maps cached, and thus use significantly more memory during runtime than the ones generated with GetMethodNameOnlyStackTraceDeminfier.
/// </summary>
/// <param name="sourceMapProvider">Consumers of the API should implement this interface, which provides the source map for a given JavaScript file. Throws ArgumentNullException if the parameter is set to null.</param>
/// <param name="stackTraceParser">Consumers of the API should implement this interface, which provides a parser for the stacktrace. Throws ArgumentNullException if the parameter is set to null.</param>
public static StackTraceDeminifier GetMapOnlyStackTraceDeminfier(ISourceMapProvider sourceMapProvider, IStackTraceParser stackTraceParser)
{
if (sourceMapProvider == null)
{
throw new ArgumentNullException(nameof(sourceMapProvider));
}

if (stackTraceParser == null)
{
throw new ArgumentNullException(nameof(stackTraceParser));
}

ISourceMapStore sourceMapStore = new SourceMapStore(sourceMapProvider);
IStackFrameDeminifier stackFrameDeminifier = new StackFrameDeminifier(sourceMapStore);

return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
}

/// <summary>
/// Creates a StackTraceDeminifier that only deminifies the method names. StackTrace deminifiers created with this method will use significantly less memory during runtime than the
/// </summary>
Expand All @@ -71,7 +105,7 @@ public static StackTraceDeminifier GetMethodNameOnlyStackTraceDeminfier(ISourceM
ValidateArguments(sourceMapProvider, generatedCodeProvider, stackTraceParser);

SourceMapParser sourceMapParser = new SourceMapParser();
IStackFrameDeminifier stackFrameDeminifier = new SimpleStackFrameDeminifier(new FunctionMapStore(generatedCodeProvider, (url) => sourceMapParser.ParseSourceMap(sourceMapProvider.GetSourceMapContentsForCallstackUrl(url))), new FunctionMapConsumer());
IStackFrameDeminifier stackFrameDeminifier = new MethodNameStackFrameDeminifier(new FunctionMapStore(generatedCodeProvider, (url) => sourceMapParser.ParseSourceMap(sourceMapProvider.GetSourceMapContentsForCallstackUrl(url))), new FunctionMapConsumer());

return new StackTraceDeminifier(stackFrameDeminifier, stackTraceParser);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ public DeminifyStackTraceResult DeminifyStackTrace(string stackTraceString)
result.Message = message;
result.DeminifiedStackFrameResults = new List<StackFrameDeminificationResult>();

foreach (StackFrame minifiedStackFrame in result.MinifiedStackFrames)
// Deminify frames in reverse order so we can pass the symbol name from caller
// (i.e. the function name) into the next level's deminification.
string callerSymbolName = null;
for (int i = result.MinifiedStackFrames.Count - 1; i >= 0; i--)
{
result.DeminifiedStackFrameResults.Add(_stackFrameDeminifier.DeminifyStackFrame(minifiedStackFrame));
var frame = _stackFrameDeminifier.DeminifyStackFrame(result.MinifiedStackFrames[i], callerSymbolName);
callerSymbolName = frame?.DeminifiedSymbolName;
result.DeminifiedStackFrameResults.Insert(0, frame);
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
<Compile Include="KeyValueCacheUnitTests.cs" />
<Compile Include="StackFrameDeminifierUnitTests.cs" />
<Compile Include="StackTraceDeminifierClosureEndToEndTests.cs" />
<Compile Include="StackTraceDeminifierMapOnlyEndToEndTests.cs" />
<Compile Include="StackTraceDeminifierWebpackEndToEndTests.cs" />
<Compile Include="StackTraceDeminifierEndToEndTests.cs" />
<Compile Include="StackTraceDeminifierUnitTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private IStackFrameDeminifier GetStackFrameDeminifierWithMockDependencies(ISourc

if (useSimpleStackFrameDeminier)
{
return new SimpleStackFrameDeminifier(functionMapStore, functionMapConsumer);
return new MethodNameStackFrameDeminifier(functionMapStore, functionMapConsumer);
}
else
{
Expand All @@ -45,7 +45,7 @@ public void DeminifyStackFrame_NullInputStackFrame_ThrowsException()
StackFrame stackFrame = null;

// Act
Assert.Throws<ArgumentNullException>( ()=> stackFrameDeminifier.DeminifyStackFrame(stackFrame));
Assert.Throws<ArgumentNullException>( ()=> stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null));
}

[Fact]
Expand All @@ -56,7 +56,7 @@ public void DeminifyStackFrame_StackFrameNullProperties_DoesNotThrowException()
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies();

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.MethodName);
Expand All @@ -77,7 +77,7 @@ public void SimpleStackFrameDeminierDeminifyStackFrame_FunctionMapReturnsNull_No
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, useSimpleStackFrameDeminier:true);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.NoSourceCodeProvided, stackFrameDeminification.DeminificationError);
Expand All @@ -102,7 +102,7 @@ public void SimpleStackFrameDeminierDeminifyStackFrame_GetWRappingFunctionForSou
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.NoWrapingFunctionFound, stackFrameDeminification.DeminificationError);
Expand All @@ -128,7 +128,7 @@ public void SimpleStackFrameDeminierDeminifyStackFrame_WrapingFunctionFound_NoDe
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer, useSimpleStackFrameDeminier: true);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.None, stackFrameDeminification.DeminificationError);
Expand All @@ -155,7 +155,7 @@ public void StackFrameDeminierDeminifyStackFrame_SourceMapProviderReturnsNull_No
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.NoSourceMap, stackFrameDeminification.DeminificationError);
Expand Down Expand Up @@ -183,7 +183,7 @@ public void StackFrameDeminierDeminifyStackFrame_SourceMapParsingNull_SourceMapF
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore,functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.SourceMapFailedToParse, stackFrameDeminification.DeminificationError);
Expand Down Expand Up @@ -213,7 +213,7 @@ public void StackFrameDeminierDeminifyStackFrame_SourceMapGeneratedMappingEntryN
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore, functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);

// Act
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame);
StackFrameDeminificationResult stackFrameDeminification = stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null);

// Assert
Assert.Equal(DeminificationError.NoMatchingMapingInSourceMap, stackFrameDeminification.DeminificationError);
Expand Down
Loading