Skip to content

Commit

Permalink
Merge pull request #8 from MaceWindu/master
Browse files Browse the repository at this point in the history
Release 1.0.0 RC3
  • Loading branch information
MaceWindu authored Feb 15, 2021
2 parents 71d0249 + fa9d8f6 commit 26ae987
Show file tree
Hide file tree
Showing 43 changed files with 1,400 additions and 668 deletions.
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ dotnet_diagnostic.CA1051.severity = none # CA1051: Do not declare visible instan
dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1716.severity = none # CA1716: Identifiers should not match keywords
dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types
dotnet_diagnostic.CA2231.severity = none # CA2231: Overload operator equals on overriding ValueType.Equals
dotnet_diagnostic.CA2249.severity = none # CA2249: Consider using String.Contains instead of String.IndexOf

dotnet_diagnostic.IDE0045.severity = none # IDE0045: Use conditional expression for assignment
dotnet_diagnostic.IDE0046.severity = none # IDE0046: Convert to conditional expression
dotnet_diagnostic.IDE0048.severity = none # IDE0048: Add parentheses for clarity
dotnet_diagnostic.IDE0058.severity = none # IDE0058: computed value is never used
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Source Map Tools [![Build Status](https://dev.azure.com/sourcemaptools/sourcemaptools/_apis/build/status/build?branchName=master)](https://dev.azure.com/sourcemaptools/sourcemaptools/_build/latest?definitionId=1&branchName=master) [![NuGet](https://img.shields.io/nuget/v/SourceMapTools.svg)](https://www.nuget.org/packages/SourceMapTools/)
# Source Map Tools [![Build Status](https://img.shields.io/azure-devops/build/sourcemaptools/sourcemaptools/1/master?label=build%20(master))](https://dev.azure.com/sourcemaptools/sourcemaptools/_build/latest?definitionId=1&branchName=master) [![NuGet](https://img.shields.io/nuget/v/SourceMapTools.svg)](https://www.nuget.org/packages/SourceMapTools/) [![License](https://img.shields.io/github/license/MaceWindu/sourcemap-tools)](LICENSE.txt)

This is a C# library for working with JavaScript source maps and deminifying JavaScript callstacks.

Expand Down
2 changes: 1 addition & 1 deletion ci/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ variables:
- name: assemblyVersion
value: 1.0.0
- name: packageVersion
value: 1.0.0-rc.2
value: 1.0.0-rc.3
- name: nugetDevVersion
value: 1.0.0

Expand Down
6 changes: 3 additions & 3 deletions src/SourceMapTools/CallstackDeminifier/BindingInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace SourcemapToolkit.CallstackDeminifier
/// Describes information regarding a binding that can be used for minification.
/// Examples include methods, functions, and object declarations.
/// </summary>
internal class BindingInformation
internal struct BindingInformation
{
public BindingInformation(string name, SourcePosition sourcePosition)
{
Expand All @@ -16,11 +16,11 @@ public BindingInformation(string name, SourcePosition sourcePosition)
/// <summary>
/// The name of the method or class
/// </summary>
public string Name { get; }
public readonly string Name;

/// <summary>
/// The location of the function name or class declaration
/// </summary>
public SourcePosition SourcePosition { get; }
public readonly SourcePosition SourcePosition;
}
}
43 changes: 34 additions & 9 deletions src/SourceMapTools/CallstackDeminifier/DeminifyStackTraceResult.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,68 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using SourcemapToolkit.SourcemapParser;

namespace SourcemapToolkit.CallstackDeminifier
{
/// <summary>
/// Contains stack trace details (both minified and diminified).
/// </summary>
public class DeminifyStackTraceResult
{
internal DeminifyStackTraceResult(
string? message,
IReadOnlyList<StackFrame> minifiedStackFrames,
IReadOnlyList<StackFrameDeminificationResult> deminifiedStackFrameResults,
string? message)
IReadOnlyList<StackFrameDeminificationResult> deminifiedStackFrameResults)
{
MinifiedStackFrames = minifiedStackFrames;
DeminifiedStackFrameResults = deminifiedStackFrameResults;
Message = message;
}

/// <summary>
/// Gets error message, associated with stack trace.
/// </summary>
public string? Message { get; }

/// <summary>
/// Gets list of stack frames for minified stack.
/// </summary>
public IReadOnlyList<StackFrame> MinifiedStackFrames { get; }

/// <summary>
/// Gets list of stack frames for de-minified stack.
/// </summary>
public IReadOnlyList<StackFrameDeminificationResult> DeminifiedStackFrameResults { get; }

/// <summary>
/// Returns string that represents stack trace
/// </summary>
public override string ToString()
{
var output = Message ?? string.Empty;
var sb = new StringBuilder();

if (!string.IsNullOrEmpty(Message))
{
sb.Append(Message);
}

for (var i = 0; i < DeminifiedStackFrameResults.Count; i++)
{
var deminFrame = DeminifiedStackFrameResults[i].DeminifiedStackFrame;

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

output += $"{Environment.NewLine} {frame}";
sb
.AppendLine()
.Append(" ")
.Append(frame);
}

return output;
return sb.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ namespace SourcemapToolkit.CallstackDeminifier
/// </summary>
internal class FunctionFinderVisitor : AllAstVisitor
{
private readonly SourceMap _sourceMap;

internal List<FunctionMapEntry> FunctionMap { get; } = new List<FunctionMapEntry>();

public FunctionFinderVisitor(SourceMap sourceMap)
{
_sourceMap = sourceMap;
}

protected override void VisitArrowFunctionExpression(ArrowFunctionExpression arrowFunctionExpression)
{
base.VisitArrowFunctionExpression(arrowFunctionExpression);
Expand Down Expand Up @@ -42,6 +49,7 @@ private void VisitFunction(IFunction function)
{
var functionMapEntry = new FunctionMapEntry(
bindings,
_sourceMap.GetDeminifiedMethodName(bindings),
GetSourcePosition(function.Body.Location.Start),
GetSourcePosition(function.Body.Location.End));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class FunctionMapConsumer : IFunctionMapConsumer
{
foreach (var mapEntry in functionMap)
{
if (mapEntry.StartSourcePosition < sourcePosition && mapEntry.EndSourcePosition > sourcePosition)
if (mapEntry.Start < sourcePosition && mapEntry.End > sourcePosition)
{
return mapEntry;
}
Expand Down
16 changes: 9 additions & 7 deletions src/SourceMapTools/CallstackDeminifier/FunctionMapEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ internal class FunctionMapEntry
{
public FunctionMapEntry(
IReadOnlyList<BindingInformation> bindings,
SourcePosition startSourcePosition,
SourcePosition endSourcePosition)
string? deminifiedMethodName,
SourcePosition start,
SourcePosition end)
{
Bindings = bindings;
StartSourcePosition = startSourcePosition;
EndSourcePosition = endSourcePosition;
DeminifiedMethodName = deminifiedMethodName;
Start = start;
End = end;
}

/// <summary>
Expand All @@ -29,16 +31,16 @@ public FunctionMapEntry(
/// If this entry represents a function whose name was minified, this value
/// may contain an associated deminfied name corresponding to the function.
/// </summary>
public string? DeminfifiedMethodName { get; set; }
public string? DeminifiedMethodName { get; }

/// <summary>
/// Denotes the location of the beginning of this function
/// </summary>
public SourcePosition StartSourcePosition { get; }
public SourcePosition Start { get; }

/// <summary>
/// Denotes the end location of this function
/// </summary>
public SourcePosition EndSourcePosition { get; }
public SourcePosition End { get; }
}
}
69 changes: 9 additions & 60 deletions src/SourceMapTools/CallstackDeminifier/FunctionMapGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using Esprima;
using SourcemapToolkit.SourcemapParser;
Expand All @@ -22,12 +21,7 @@ internal class FunctionMapGenerator : IFunctionMapGenerator
IReadOnlyList<FunctionMapEntry>? result;
try
{
result = ParseSourceCode(sourceCodeStream);

foreach (var functionMapEntry in result)
{
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
}
result = ParseSourceCode(sourceCodeStream, sourceMap);
}
catch
{
Expand All @@ -42,7 +36,7 @@ internal class FunctionMapGenerator : IFunctionMapGenerator
/// <summary>
/// Iterates over all the code in the JavaScript file to get a list of all the functions declared in that file.
/// </summary>
internal static IReadOnlyList<FunctionMapEntry> ParseSourceCode(Stream sourceCodeStream)
internal static IReadOnlyList<FunctionMapEntry> ParseSourceCode(Stream sourceCodeStream, SourceMap sourceMap)
{
string sourceCode;
using (sourceCodeStream)
Expand All @@ -55,61 +49,16 @@ internal static IReadOnlyList<FunctionMapEntry> ParseSourceCode(Stream sourceCod

var script = jsParser.ParseScript();

var functionFinderVisitor = new FunctionFinderVisitor();
var functionFinderVisitor = new FunctionFinderVisitor(sourceMap);
functionFinderVisitor.Visit(script);

// Sort in descending order by start position
functionFinderVisitor.FunctionMap.Sort((x, y) => y.StartSourcePosition.CompareTo(x.StartSourcePosition));
// Sort in descending order by start position. This allows the first result found in a linear search to be the "closest function to the [consumer's] source position".
//
// ATTN: It may be possible to do this with an ascending order sort, followed by a series of binary searches on rows & columns.
// Our current profiles show the memory pressure being a bigger issue than the stack lookup, so I'm leaving this for now.
functionFinderVisitor.FunctionMap.Sort((x, y) => y.Start.CompareTo(x.Start));

return functionFinderVisitor.FunctionMap;
}

/// <summary>
/// Gets the original name corresponding to a function based on the information provided in the source map.
/// </summary>
internal static string? GetDeminifiedMethodNameFromSourceMap(FunctionMapEntry wrappingFunction, SourceMap sourceMap)
{
if (wrappingFunction == null)
{
throw new ArgumentNullException(nameof(wrappingFunction));
}

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

if (wrappingFunction.Bindings != null && wrappingFunction.Bindings.Count > 0)
{
var entryNames = new List<string>();

foreach (var binding in wrappingFunction.Bindings)
{
var entry = sourceMap.GetMappingEntryForGeneratedSourcePosition(binding.SourcePosition);
if (entry != null && entry.OriginalName != null)
{
entryNames.Add(entry.OriginalName);
}
}

// // The object name already contains the method name, so do not append it
if (entryNames.Count > 1 && entryNames[entryNames.Count - 2].EndsWith("." + entryNames[entryNames.Count - 1], StringComparison.Ordinal))
{
entryNames.RemoveAt(entryNames.Count - 1);
}

if (entryNames.Count > 2 && entryNames[entryNames.Count - 2] == "prototype")
{
entryNames.RemoveAt(entryNames.Count - 2);
}

if (entryNames.Count > 0)
{
return string.Join(".", entryNames);
}
}

return null;
}
}
}
52 changes: 52 additions & 0 deletions src/SourceMapTools/CallstackDeminifier/IReadOnlyListExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Collections.Generic;

namespace SourcemapToolkit.SourcemapParser
{
internal static class IReadOnlyListExtensions
{
public static int IndexOf<T>(this IReadOnlyList<T> input, T value)
{
var equalityComparer = EqualityComparer<T>.Default;
for (var i = 0; i < input.Count; i++)
{
if (equalityComparer.Equals(input[i], value))
{
return i;
}
}

return -1;
}

/// <summary>
/// Copied from: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/arraysorthelper.cs,63a9955a91f2b37b
/// </summary>
public static int BinarySearch<T>(this IReadOnlyList<T> input, T item, IComparer<T> comparer)
{
var lo = 0;
var hi = input.Count - 1;

while (lo <= hi)
{
var i = lo + ((hi - lo) >> 1);
var order = comparer.Compare(input[i], item);

if (order == 0)
{
return i;
}

if (order < 0)
{
lo = i + 1;
}
else
{
hi = i - 1;
}
}

return ~lo;
}
}
}
3 changes: 3 additions & 0 deletions src/SourceMapTools/CallstackDeminifier/IStackTraceParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace SourcemapToolkit.CallstackDeminifier
{
/// <summary>
/// Stack trace parser contract.
/// </summary>
public interface IStackTraceParser
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ StackFrameDeminificationResult IStackFrameDeminifier.DeminifyStackFrame(StackFra

return new StackFrameDeminificationResult(
deminificationError,
new StackFrame(wrappingFunction?.DeminfifiedMethodName));
new StackFrame(wrappingFunction?.DeminifiedMethodName));
}
}
}
Loading

0 comments on commit 26ae987

Please sign in to comment.