Reduce memory pressure from sourcemaptoolkit (#84)
* DeminifyStackTrace perf improvements. * Make ToString() on a DeminifyStackTraceResult use fewer allocations. * Make ParseStackTrace use fewer allocations and have its result be immutable * Make most fields on FunctionMapEntry be read-only * Fix unit test warnings * Make FunctionMapEntry immutable * Make the SourcePosition class immutable * Fix build warnings * Make MappingEntry be a struct * Make binding information be a struct * Make sourcemap immutable * Additional clean-up * More clean-up. * Make more things read-only * Remove accidental Debugger.Launch() * Leave comment about why the FunctionMap is stored in descending order * Some more clean-up * fix typo * fix comment to remove reference to other project. * Rename GetDeminifiedMethodNameFromSourceMap --> GetDeminifiedMethodName in unit tests. * Add unit tests for new code. * Remove duplicate StringExtensions classes.
This commit is contained in:
Родитель
ef2988141b
Коммит
38362c5ed1
|
@ -1,19 +1,24 @@
|
|||
using System;
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourcemapToolkit.CallstackDeminifier
|
||||
{
|
||||
public class DeminifyStackTraceResult
|
||||
{
|
||||
public string Message;
|
||||
|
||||
public List<StackFrame> MinifiedStackFrames;
|
||||
|
||||
public List<StackFrameDeminificationResult> DeminifiedStackFrameResults;
|
||||
public string Message { get; }
|
||||
public IReadOnlyList<StackFrame> MinifiedStackFrames { get; }
|
||||
public IReadOnlyList<StackFrameDeminificationResult> DeminifiedStackFrameResults { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string output = Message ?? string.Empty;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (!string.IsNullOrEmpty(Message))
|
||||
{
|
||||
sb.Append(Message);
|
||||
}
|
||||
|
||||
for (int i = 0; i < DeminifiedStackFrameResults.Count; i++)
|
||||
{
|
||||
StackFrame deminFrame = DeminifiedStackFrameResults[i].DeminifiedStackFrame;
|
||||
|
@ -22,14 +27,26 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
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
|
||||
SourcePosition = deminFrame.SourcePosition != SourcePosition.NotFound ? deminFrame.SourcePosition : MinifiedStackFrames[i].SourcePosition,
|
||||
FilePath = deminFrame.SourcePosition != SourcePosition.NotFound ? deminFrame.FilePath : MinifiedStackFrames[i].FilePath
|
||||
};
|
||||
|
||||
output += $"{Environment.NewLine} {frame}";
|
||||
sb.AppendLine();
|
||||
sb.Append(" ");
|
||||
sb.Append(frame);
|
||||
}
|
||||
|
||||
return output;
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public DeminifyStackTraceResult(
|
||||
string message,
|
||||
IReadOnlyList<StackFrame> minifiedStackFrames,
|
||||
IReadOnlyList<StackFrameDeminificationResult> deminifiedStackFrameResults)
|
||||
{
|
||||
Message = message;
|
||||
MinifiedStackFrames = minifiedStackFrames;
|
||||
DeminifiedStackFrameResults = deminifiedStackFrameResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,99 +11,82 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
internal class FunctionFinderVisitor : TreeVisitor
|
||||
{
|
||||
internal readonly List<FunctionMapEntry> FunctionMap = new List<FunctionMapEntry>();
|
||||
internal readonly List<FunctionMapEntry> FunctionMap;
|
||||
internal readonly SourceMap SourceMap;
|
||||
|
||||
public FunctionFinderVisitor(SourceMap sourceMap)
|
||||
{
|
||||
FunctionMap = new List<FunctionMapEntry>();
|
||||
SourceMap = sourceMap;
|
||||
}
|
||||
|
||||
public override void Visit(FunctionObject node)
|
||||
{
|
||||
base.Visit(node);
|
||||
List<BindingInformation> bindings = GetBindings(node);
|
||||
var bindings = GetBindings(node);
|
||||
|
||||
if (bindings != null)
|
||||
{
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
Bindings = bindings,
|
||||
StartSourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = node.Body.Context.StartLineNumber - 1, // Souce maps work with zero based line and column numbers, the AST works with one based line numbers. We want to use zero-based everywhere.
|
||||
ZeroBasedColumnNumber = node.Body.Context.StartColumn
|
||||
},
|
||||
EndSourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = node.Body.Context.EndLineNumber - 1, // Souce maps work with zero based line and column numbers, the AST works with one based line numbers. We want to use zero-based everywhere.
|
||||
ZeroBasedColumnNumber = node.Body.Context.EndColumn
|
||||
}
|
||||
};
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry(
|
||||
bindings: bindings,
|
||||
deminifiedMethodName: SourceMap.GetDeminifiedMethodName(bindings),
|
||||
startSourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: node.Body.Context.StartLineNumber - 1, // Souce maps work with zero based line and column numbers, the AST works with one based line numbers. We want to use zero-based everywhere.
|
||||
zeroBasedColumnNumber: node.Body.Context.StartColumn),
|
||||
endSourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: node.Body.Context.EndLineNumber - 1, // Souce maps work with zero based line and column numbers, the AST works with one based line numbers. We want to use zero-based everywhere.
|
||||
zeroBasedColumnNumber: node.Body.Context.EndColumn));
|
||||
|
||||
FunctionMap.Add(functionMapEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name and location information related to the function name binding for a FunctionObject node
|
||||
/// </summary>
|
||||
private List<BindingInformation> GetBindings(FunctionObject node)
|
||||
private IReadOnlyList<BindingInformation> GetBindings(FunctionObject node)
|
||||
{
|
||||
List<BindingInformation> result = new List<BindingInformation>();
|
||||
// Gets the name of an object property that a function is bound to, like the static method foo in the example "object.foo = function () {}"
|
||||
BinaryOperator parentBinaryOperator = node.Parent as BinaryOperator;
|
||||
if (parentBinaryOperator != null)
|
||||
if (node.Parent is BinaryOperator parentBinaryOperator)
|
||||
{
|
||||
result.AddRange(ExtractBindingsFromBinaryOperator(parentBinaryOperator));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Gets the name of an object property that a function is bound to against the prototype, like the instance method foo in the example "object.prototype = {foo: function () {}}"
|
||||
ObjectLiteralProperty parentObjectLiteralProperty = node.Parent as ObjectLiteralProperty;
|
||||
if (parentObjectLiteralProperty != null)
|
||||
if (node.Parent is ObjectLiteralProperty parentObjectLiteralProperty)
|
||||
{
|
||||
// See if we can get the name of the object that this method belongs to
|
||||
ObjectLiteral objectLiteralParent = parentObjectLiteralProperty.Parent?.Parent as ObjectLiteral;
|
||||
if (objectLiteralParent != null && objectLiteralParent.Parent is BinaryOperator)
|
||||
if (objectLiteralParent != null && objectLiteralParent.Parent is BinaryOperator binaryOperator)
|
||||
{
|
||||
result.AddRange(ExtractBindingsFromBinaryOperator((BinaryOperator)objectLiteralParent.Parent));
|
||||
result.AddRange(ExtractBindingsFromBinaryOperator(binaryOperator));
|
||||
}
|
||||
|
||||
result.Add(
|
||||
new BindingInformation
|
||||
{
|
||||
Name = parentObjectLiteralProperty.Name.Name,
|
||||
SourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = parentObjectLiteralProperty.Context.StartLineNumber - 1,
|
||||
ZeroBasedColumnNumber = parentObjectLiteralProperty.Context.StartColumn
|
||||
}
|
||||
});
|
||||
new BindingInformation(
|
||||
name: parentObjectLiteralProperty.Name.Name,
|
||||
sourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: parentObjectLiteralProperty.Context.StartLineNumber - 1,
|
||||
zeroBasedColumnNumber: parentObjectLiteralProperty.Context.StartColumn)));
|
||||
return result;
|
||||
}
|
||||
|
||||
BindingIdentifier bindingIdentifier = null;
|
||||
|
||||
// Gets the name of a variable that a function is bound to, like foo in the example "var foo = function () {}"
|
||||
VariableDeclaration parentVariableDeclaration = node.Parent as VariableDeclaration;
|
||||
if (parentVariableDeclaration != null)
|
||||
{
|
||||
bindingIdentifier = parentVariableDeclaration.Binding as BindingIdentifier;
|
||||
}
|
||||
// Gets the name bound to the function, like foo in the example "function foo() {}
|
||||
else
|
||||
{
|
||||
bindingIdentifier = node.Binding;
|
||||
}
|
||||
|
||||
BindingIdentifier bindingIdentifier = (node.Parent is VariableDeclaration parentVariableDeclaration) ?
|
||||
parentVariableDeclaration.Binding as BindingIdentifier :
|
||||
node.Binding; // Gets the name bound to the function, like foo in the example "function foo() {}
|
||||
|
||||
if (bindingIdentifier != null)
|
||||
{
|
||||
result.Add(
|
||||
new BindingInformation
|
||||
{
|
||||
Name = bindingIdentifier.Name,
|
||||
SourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = bindingIdentifier.Context.StartLineNumber - 1,
|
||||
new BindingInformation(
|
||||
name: bindingIdentifier.Name,
|
||||
sourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: bindingIdentifier.Context.StartLineNumber - 1,
|
||||
// Souce maps work with zero based line and column numbers, the AST works with one based line numbers. We want to use zero-based everywhere.
|
||||
ZeroBasedColumnNumber = bindingIdentifier.Context.StartColumn
|
||||
}
|
||||
});
|
||||
zeroBasedColumnNumber: bindingIdentifier.Context.StartColumn)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -125,15 +108,11 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
if (member.Name != "prototype")
|
||||
{
|
||||
int offset = member.NameContext.Code.StartsWith(".") ? 1 : 0;
|
||||
yield return new BindingInformation
|
||||
{
|
||||
Name = member.Name,
|
||||
SourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = member.NameContext.StartLineNumber - 1,
|
||||
ZeroBasedColumnNumber = member.NameContext.StartColumn + offset
|
||||
}
|
||||
};
|
||||
yield return new BindingInformation(
|
||||
name: member.Name,
|
||||
sourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: member.NameContext.StartLineNumber - 1,
|
||||
zeroBasedColumnNumber: member.NameContext.StartColumn + offset));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -144,15 +123,11 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
|
||||
private BindingInformation ExtractBindingsFromNode(AstNode node)
|
||||
{
|
||||
return new BindingInformation
|
||||
{
|
||||
Name = node.Context.Code,
|
||||
SourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = node.Context.StartLineNumber - 1,
|
||||
ZeroBasedColumnNumber = node.Context.StartColumn
|
||||
}
|
||||
};
|
||||
return new BindingInformation(
|
||||
name: node.Context.Code,
|
||||
sourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: node.Context.StartLineNumber - 1,
|
||||
zeroBasedColumnNumber: node.Context.StartColumn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
/// <param name="sourcePosition">The location of the code around which we wish to find a wrapping function</param>
|
||||
/// <param name="functionMap">The function map, sorted in decreasing order by start source position, that represents the file containing the code of interest</param>
|
||||
public FunctionMapEntry GetWrappingFunctionForSourceLocation(SourcePosition sourcePosition, List<FunctionMapEntry> functionMap)
|
||||
public FunctionMapEntry GetWrappingFunctionForSourceLocation(SourcePosition sourcePosition, IReadOnlyList<FunctionMapEntry> functionMap)
|
||||
{
|
||||
foreach (FunctionMapEntry mapEntry in functionMap)
|
||||
{
|
||||
|
|
|
@ -7,17 +7,23 @@ 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
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the method or class
|
||||
/// </summary>
|
||||
public string Name;
|
||||
public readonly string Name;
|
||||
|
||||
/// <summary>
|
||||
/// The location of the function name or class declaration
|
||||
/// </summary>
|
||||
public SourcePosition SourcePosition;
|
||||
public readonly SourcePosition SourcePosition;
|
||||
|
||||
public BindingInformation(string name, SourcePosition sourcePosition)
|
||||
{
|
||||
Name = name;
|
||||
SourcePosition = sourcePosition;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -30,22 +36,34 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// To get the complete name of the function associated with this mapping entry
|
||||
/// append the names of each bindings with a "."
|
||||
/// </summary>
|
||||
public List<BindingInformation> Bindings { get; set; }
|
||||
public IReadOnlyList<BindingInformation> Bindings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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; set; }
|
||||
public SourcePosition StartSourcePosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Denotes the end location of this function
|
||||
/// </summary>
|
||||
public SourcePosition EndSourcePosition { get; set; }
|
||||
public SourcePosition EndSourcePosition { get; }
|
||||
|
||||
public FunctionMapEntry(
|
||||
IReadOnlyList<BindingInformation> bindings,
|
||||
string deminifiedMethodName,
|
||||
SourcePosition startSourcePosition,
|
||||
SourcePosition endSourcePosition)
|
||||
{
|
||||
Bindings = bindings;
|
||||
DeminifiedMethodName = deminifiedMethodName;
|
||||
StartSourcePosition = startSourcePosition;
|
||||
EndSourcePosition = endSourcePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Ajax.Utilities;
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
|
||||
|
@ -13,22 +12,17 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// Returns a FunctionMap describing the locations of every funciton in the source code.
|
||||
/// The functions are to be sorted descending by start position.
|
||||
/// </summary>
|
||||
public List<FunctionMapEntry> GenerateFunctionMap(StreamReader sourceCodeStreamReader, SourceMap sourceMap)
|
||||
public IReadOnlyList<FunctionMapEntry> GenerateFunctionMap(StreamReader sourceCodeStreamReader, SourceMap sourceMap)
|
||||
{
|
||||
if (sourceCodeStreamReader == null || sourceMap == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<FunctionMapEntry> result;
|
||||
IReadOnlyList<FunctionMapEntry> result;
|
||||
try
|
||||
{
|
||||
result = ParseSourceCode(sourceCodeStreamReader);
|
||||
|
||||
foreach (FunctionMapEntry functionMapEntry in result)
|
||||
{
|
||||
functionMapEntry.DeminfifiedMethodName = GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
}
|
||||
result = ParseSourceCode(sourceCodeStreamReader, sourceMap);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -43,7 +37,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <summary>
|
||||
/// Iterates over all the code in the JavaScript file to get a list of all the functions declared in that file.
|
||||
/// </summary>
|
||||
internal List<FunctionMapEntry> ParseSourceCode(StreamReader sourceCodeStreamReader)
|
||||
internal IReadOnlyList<FunctionMapEntry> ParseSourceCode(StreamReader sourceCodeStreamReader, SourceMap sourceMap)
|
||||
{
|
||||
if (sourceCodeStreamReader == null)
|
||||
{
|
||||
|
@ -60,68 +54,16 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
|
||||
Block block = jsParser.Parse(sourceCode, codeSettings);
|
||||
|
||||
FunctionFinderVisitor functionFinderVisitor = new FunctionFinderVisitor();
|
||||
FunctionFinderVisitor functionFinderVisitor = new FunctionFinderVisitor(sourceMap);
|
||||
functionFinderVisitor.Visit(block);
|
||||
|
||||
// Sort in descending order by start position
|
||||
|
||||
// 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.StartSourcePosition.CompareTo(x.StartSourcePosition));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
string methodName = null;
|
||||
|
||||
if (wrappingFunction.Bindings != null && wrappingFunction.Bindings.Count > 0)
|
||||
{
|
||||
MappingEntry objectProtoypeMappingEntry = null;
|
||||
if (wrappingFunction.Bindings.Count == 2)
|
||||
{
|
||||
objectProtoypeMappingEntry =
|
||||
sourceMap.GetMappingEntryForGeneratedSourcePosition(wrappingFunction.Bindings[0].SourcePosition);
|
||||
}
|
||||
|
||||
MappingEntry mappingEntry =
|
||||
sourceMap.GetMappingEntryForGeneratedSourcePosition(wrappingFunction.Bindings.Last().SourcePosition);
|
||||
|
||||
if (mappingEntry?.OriginalName != null)
|
||||
{
|
||||
if (objectProtoypeMappingEntry?.OriginalName != null)
|
||||
{
|
||||
string objectName = objectProtoypeMappingEntry.OriginalName;
|
||||
if (objectProtoypeMappingEntry.OriginalSourcePosition?.ZeroBasedColumnNumber == mappingEntry.OriginalSourcePosition?.ZeroBasedColumnNumber
|
||||
&& objectProtoypeMappingEntry.OriginalSourcePosition?.ZeroBasedLineNumber == mappingEntry.OriginalSourcePosition?.ZeroBasedLineNumber
|
||||
&& objectName.EndsWith($".{mappingEntry.OriginalName}"))
|
||||
{
|
||||
// The object name already contains the method name, so do not append it
|
||||
methodName = objectName;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodName = $"{objectName}.{mappingEntry.OriginalName}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodName = mappingEntry.OriginalName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
internal class FunctionMapStore : IFunctionMapStore
|
||||
{
|
||||
private readonly IFunctionMapGenerator _functionMapGenerator;
|
||||
private readonly KeyValueCache<string,List<FunctionMapEntry>> _functionMapCache;
|
||||
private readonly KeyValueCache<string, IReadOnlyList<FunctionMapEntry>> _functionMapCache;
|
||||
|
||||
public FunctionMapStore(ISourceCodeProvider sourceCodeProvider, Func<string, SourceMap> sourceMapGetter)
|
||||
{
|
||||
_functionMapGenerator = new FunctionMapGenerator();
|
||||
_functionMapCache = new KeyValueCache<string, List<FunctionMapEntry>>(sourceCodeUrl => _functionMapGenerator.GenerateFunctionMap(
|
||||
_functionMapCache = new KeyValueCache<string, IReadOnlyList<FunctionMapEntry>>(sourceCodeUrl => _functionMapGenerator.GenerateFunctionMap(
|
||||
sourceCodeProvider.GetSourceCode(sourceCodeUrl),
|
||||
sourceMapGetter(sourceCodeUrl)));
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// Once a function map is generated, the value is cached in memory for future usages.
|
||||
/// </summary>
|
||||
/// <param name="sourceCodeUrl">The URL of the file for which a function map is required</param>
|
||||
public List<FunctionMapEntry> GetFunctionMapForSourceCode(string sourceCodeUrl)
|
||||
public IReadOnlyList<FunctionMapEntry> GetFunctionMapForSourceCode(string sourceCodeUrl)
|
||||
{
|
||||
return _functionMapCache.GetValue(sourceCodeUrl);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
/// <param name="sourcePosition">The location of the code around which we wish to find a wrapping function</param>
|
||||
/// <param name="functionMap">The function map, sorted in decreasing order by start source position, that represents the file containing the code of interest</param>
|
||||
FunctionMapEntry GetWrappingFunctionForSourceLocation(SourcePosition sourcePosition, List<FunctionMapEntry> functionMap);
|
||||
FunctionMapEntry GetWrappingFunctionForSourceLocation(SourcePosition sourcePosition, IReadOnlyList<FunctionMapEntry> functionMap);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,6 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// Returns a FunctionMap describing the locations of every funciton in the source code.
|
||||
/// The functions are to be sorted in decreasing order by start position.
|
||||
/// </summary>
|
||||
List<FunctionMapEntry> GenerateFunctionMap(StreamReader sourceCodeStreamReader, SourceMap sourceMap);
|
||||
IReadOnlyList<FunctionMapEntry> GenerateFunctionMap(StreamReader sourceCodeStreamReader, SourceMap sourceMap);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,6 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
{
|
||||
internal interface IFunctionMapStore
|
||||
{
|
||||
List<FunctionMapEntry> GetFunctionMapForSourceCode(string sourceCodeUrl);
|
||||
IReadOnlyList<FunctionMapEntry> GetFunctionMapForSourceCode(string sourceCodeUrl);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <remarks>
|
||||
/// This override drops the Message out param for backward compatibility
|
||||
/// </remarks>
|
||||
List<StackFrame> ParseStackTrace(string stackTraceString);
|
||||
IReadOnlyList<StackFrame> ParseStackTrace(string stackTraceString);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a list of StackFrame objects based on the input stack trace.
|
||||
|
@ -31,6 +31,6 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// Any parts of the stack trace that could not be parsed are excluded from
|
||||
/// the result. Does not ever return null.
|
||||
/// </returns>
|
||||
List<StackFrame> ParseStackTrace(string stackTraceString, out string message);
|
||||
IReadOnlyList<StackFrame> ParseStackTrace(string stackTraceString, out string message);
|
||||
}
|
||||
}
|
|
@ -21,21 +21,22 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
public virtual StackFrameDeminificationResult DeminifyStackFrame(StackFrame stackFrame, string callerSymbolName)
|
||||
{
|
||||
StackFrameDeminificationResult result = new StackFrameDeminificationResult
|
||||
{
|
||||
DeminificationError = DeminificationError.None
|
||||
};
|
||||
if (stackFrame == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stackFrame));
|
||||
}
|
||||
|
||||
StackFrameDeminificationResult result = new StackFrameDeminificationResult
|
||||
{
|
||||
DeminificationError = DeminificationError.None
|
||||
};
|
||||
|
||||
FunctionMapEntry wrappingFunction = null;
|
||||
|
||||
// This code deminifies the stack frame by finding the wrapping function in
|
||||
// the generated code and then using the source map to find the name and
|
||||
// and original source location.
|
||||
List<FunctionMapEntry> functionMap = _functionMapStore.GetFunctionMapForSourceCode(stackFrame.FilePath);
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = _functionMapStore.GetFunctionMapForSourceCode(stackFrame.FilePath);
|
||||
if (functionMap != null)
|
||||
{
|
||||
wrappingFunction =
|
||||
|
@ -51,7 +52,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
result.DeminificationError = DeminificationError.NoSourceCodeProvided;
|
||||
}
|
||||
|
||||
result.DeminifiedStackFrame = new StackFrame {MethodName = wrappingFunction?.DeminfifiedMethodName};
|
||||
result.DeminifiedStackFrame = new StackFrame {MethodName = wrappingFunction?.DeminifiedMethodName};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
|
||||
namespace SourcemapToolkit.CallstackDeminifier
|
||||
{
|
||||
internal static class SourceMapExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the original name corresponding to a function based on the information provided in the source map.
|
||||
/// </summary>
|
||||
internal static string GetDeminifiedMethodName(this SourceMap sourceMap, IReadOnlyList<BindingInformation> bindings)
|
||||
{
|
||||
if (sourceMap == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sourceMap));
|
||||
}
|
||||
|
||||
string methodName = null;
|
||||
|
||||
if (bindings != null && bindings.Count > 0)
|
||||
{
|
||||
MappingEntry? objectProtoypeMappingEntry = null;
|
||||
if (bindings.Count == 2)
|
||||
{
|
||||
objectProtoypeMappingEntry =
|
||||
sourceMap.GetMappingEntryForGeneratedSourcePosition(bindings[0].SourcePosition);
|
||||
}
|
||||
|
||||
MappingEntry? mappingEntry =
|
||||
sourceMap.GetMappingEntryForGeneratedSourcePosition(bindings.Last().SourcePosition);
|
||||
|
||||
if (mappingEntry?.OriginalName != null)
|
||||
{
|
||||
if (objectProtoypeMappingEntry?.OriginalName != null)
|
||||
{
|
||||
string objectName = objectProtoypeMappingEntry.Value.OriginalName;
|
||||
if (objectProtoypeMappingEntry.Value.OriginalSourcePosition.ZeroBasedColumnNumber == mappingEntry.Value.OriginalSourcePosition.ZeroBasedColumnNumber
|
||||
&& objectProtoypeMappingEntry.Value.OriginalSourcePosition.ZeroBasedLineNumber == mappingEntry.Value.OriginalSourcePosition.ZeroBasedLineNumber
|
||||
&& objectName.Length > mappingEntry.Value.OriginalName.Length
|
||||
&& objectName.EndsWith(mappingEntry.Value.OriginalName)
|
||||
&& (objectName[objectName.Length - 1 - mappingEntry.Value.OriginalName.Length] == '.'))
|
||||
{
|
||||
// The object name already contains the method name, so do not append it
|
||||
methodName = objectName;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodName = $"{objectName}.{mappingEntry.Value.OriginalName}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodName = mappingEntry.Value.OriginalName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="SourceMapExtensions.cs" />
|
||||
<Compile Include="StackFrameDeminificationResult.cs" />
|
||||
<Compile Include="DeminifyStackTraceResult.cs" />
|
||||
<Compile Include="FunctionFinderVisitor.cs" />
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <summary>
|
||||
/// The zero-based position of this stack entry.
|
||||
/// </summary>
|
||||
public SourcePosition SourcePosition { get; set; }
|
||||
public SourcePosition SourcePosition { get; set; } = SourcePosition.NotFound;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
if (!string.IsNullOrWhiteSpace(FilePath))
|
||||
{
|
||||
output += $" in {FilePath}";
|
||||
if (SourcePosition != null)
|
||||
if (SourcePosition != SourcePosition.NotFound)
|
||||
{
|
||||
output += $":{SourcePosition.ZeroBasedLineNumber + 1}:{SourcePosition.ZeroBasedColumnNumber + 1}";
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
|
||||
if (result.DeminificationError == DeminificationError.None)
|
||||
{
|
||||
MappingEntry generatedSourcePositionMappingEntry =
|
||||
MappingEntry? generatedSourcePositionMappingEntry =
|
||||
sourceMap?.GetMappingEntryForGeneratedSourcePosition(generatedSourcePosition);
|
||||
|
||||
if (generatedSourcePositionMappingEntry == null)
|
||||
|
@ -75,9 +75,9 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
}
|
||||
else
|
||||
{
|
||||
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry.OriginalFileName;
|
||||
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry.OriginalSourcePosition;
|
||||
result.DeminifiedSymbolName = generatedSourcePositionMappingEntry.OriginalName;
|
||||
result.DeminifiedStackFrame.FilePath = generatedSourcePositionMappingEntry.Value.OriginalFileName;
|
||||
result.DeminifiedStackFrame.SourcePosition = generatedSourcePositionMappingEntry.Value.OriginalSourcePosition;
|
||||
result.DeminifiedSymbolName = generatedSourcePositionMappingEntry.Value.OriginalName;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,21 +23,23 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// </summary>
|
||||
public DeminifyStackTraceResult DeminifyStackTrace(string stackTraceString)
|
||||
{
|
||||
DeminifyStackTraceResult result = new DeminifyStackTraceResult();
|
||||
result.MinifiedStackFrames = _stackTraceParser.ParseStackTrace(stackTraceString, out string message);
|
||||
result.Message = message;
|
||||
result.DeminifiedStackFrameResults = new List<StackFrameDeminificationResult>();
|
||||
var minifiedStackFrames = _stackTraceParser.ParseStackTrace(stackTraceString, out string message);
|
||||
var deminifiedStackFrameResults = new List<StackFrameDeminificationResult>(minifiedStackFrames.Count);
|
||||
|
||||
// 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--)
|
||||
for (int i = minifiedStackFrames.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var frame = _stackFrameDeminifier.DeminifyStackFrame(result.MinifiedStackFrames[i], callerSymbolName);
|
||||
var frame = _stackFrameDeminifier.DeminifyStackFrame(minifiedStackFrames[i], callerSymbolName);
|
||||
callerSymbolName = frame?.DeminifiedSymbolName;
|
||||
result.DeminifiedStackFrameResults.Insert(0, frame);
|
||||
deminifiedStackFrameResults.Add(frame);
|
||||
}
|
||||
|
||||
deminifiedStackFrameResults.Reverse();
|
||||
|
||||
var result = new DeminifyStackTraceResult(message, minifiedStackFrames, deminifiedStackFrameResults);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// <remarks>
|
||||
/// This override drops the Message out param for backward compatibility
|
||||
/// </remarks>
|
||||
public List<StackFrame> ParseStackTrace(string stackTraceString)
|
||||
public IReadOnlyList<StackFrame> ParseStackTrace(string stackTraceString)
|
||||
{
|
||||
return ParseStackTrace(stackTraceString, out string message);
|
||||
return ParseStackTrace(stackTraceString, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -45,7 +45,7 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
/// Any parts of the stack trace that could not be parsed are excluded from
|
||||
/// the result. Does not ever return null.
|
||||
/// </returns>
|
||||
public virtual List<StackFrame> ParseStackTrace(string stackTraceString, out string message)
|
||||
public virtual IReadOnlyList<StackFrame> ParseStackTrace(string stackTraceString, out string message)
|
||||
{
|
||||
if (stackTraceString == null)
|
||||
{
|
||||
|
@ -53,19 +53,23 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
}
|
||||
|
||||
message = null;
|
||||
List<StackFrame> stackTrace = new List<StackFrame>();
|
||||
List<string> stackFrameStrings = stackTraceString.Split('\n').ToList();
|
||||
string[] stackFrameStrings = stackTraceString.SplitFast('\n');
|
||||
|
||||
int startingIndex = 0;
|
||||
|
||||
var firstFrame = stackFrameStrings.First();
|
||||
if (!firstFrame.StartsWith(" ") && TryExtractMethodNameFromFrame(firstFrame) == null)
|
||||
{
|
||||
message = firstFrame.Trim();
|
||||
stackFrameStrings.RemoveAt(0);
|
||||
startingIndex = 1;
|
||||
}
|
||||
|
||||
foreach (string frame in stackFrameStrings)
|
||||
// Allocate assuming none of the frames are null.
|
||||
List<StackFrame> stackTrace = new List<StackFrame>(stackFrameStrings.Length - startingIndex);
|
||||
|
||||
for (int i = startingIndex; i < stackFrameStrings.Length; i++)
|
||||
{
|
||||
StackFrame parsedStackFrame = TryParseSingleStackFrame(frame);
|
||||
StackFrame parsedStackFrame = TryParseSingleStackFrame(stackFrameStrings[i]);
|
||||
|
||||
if (parsedStackFrame != null)
|
||||
{
|
||||
|
@ -119,7 +123,10 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(methodName))
|
||||
{
|
||||
methodName = null;
|
||||
}
|
||||
|
||||
return methodName;
|
||||
}
|
||||
|
||||
|
@ -145,14 +152,12 @@ namespace SourcemapToolkit.CallstackDeminifier
|
|||
if (lineNumberMatch.Success)
|
||||
{
|
||||
result.FilePath = lineNumberMatch.Groups[1].Value;
|
||||
result.SourcePosition = new SourcePosition
|
||||
{
|
||||
result.SourcePosition = new SourcePosition(
|
||||
// The browser provides one-based line and column numbers, but the
|
||||
// rest of this library uses zero-based values. Normalize to make
|
||||
// the stack frames zero based.
|
||||
ZeroBasedLineNumber = int.Parse(lineNumberMatch.Groups[2].Value, CultureInfo.InvariantCulture) - 1,
|
||||
ZeroBasedColumnNumber = int.Parse(lineNumberMatch.Groups[3].Value, CultureInfo.InvariantCulture) -1
|
||||
};
|
||||
zeroBasedLineNumber: int.Parse(lineNumberMatch.Groups[2].Value, CultureInfo.InvariantCulture) - 1,
|
||||
zeroBasedColumnNumber: int.Parse(lineNumberMatch.Groups[3].Value, CultureInfo.InvariantCulture) -1);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
internal static class IReadOnlyListExtensions
|
||||
{
|
||||
public static int IndexOf<T>(this IReadOnlyList<T> input, T value)
|
||||
{
|
||||
EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
|
||||
for (int 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)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = input.Count - 1;
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
int i = lo + ((hi - lo) >> 1);
|
||||
int order = comparer.Compare(input[i], item);
|
||||
|
||||
if (order == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
if (order < 0)
|
||||
{
|
||||
lo = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~lo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,46 +2,81 @@
|
|||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
public class MappingEntry
|
||||
public struct MappingEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The location of the line of code in the transformed code
|
||||
/// </summary>
|
||||
public SourcePosition GeneratedSourcePosition;
|
||||
public readonly SourcePosition GeneratedSourcePosition;
|
||||
|
||||
/// <summary>
|
||||
/// The location of the code in the original source code
|
||||
/// </summary>
|
||||
public SourcePosition OriginalSourcePosition;
|
||||
public readonly SourcePosition OriginalSourcePosition;
|
||||
|
||||
/// <summary>
|
||||
/// The original name of the code referenced by this mapping entry
|
||||
/// </summary>
|
||||
public string OriginalName;
|
||||
public readonly string OriginalName;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the file that originally contained this code
|
||||
/// </summary>
|
||||
public string OriginalFileName;
|
||||
public readonly string OriginalFileName;
|
||||
|
||||
public MappingEntry Clone()
|
||||
public MappingEntry(
|
||||
SourcePosition generatedSourcePosition,
|
||||
SourcePosition? originalSourcePosition = null,
|
||||
string originalName = null,
|
||||
string originalFileName = null)
|
||||
{
|
||||
return new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = this.GeneratedSourcePosition.Clone(),
|
||||
OriginalSourcePosition = this.OriginalSourcePosition.Clone(),
|
||||
OriginalFileName = this.OriginalFileName,
|
||||
OriginalName = this.OriginalName
|
||||
};
|
||||
GeneratedSourcePosition = generatedSourcePosition;
|
||||
OriginalSourcePosition = originalSourcePosition ?? SourcePosition.NotFound;
|
||||
OriginalName = originalName;
|
||||
OriginalFileName = originalFileName;
|
||||
}
|
||||
|
||||
public Boolean IsValueEqual(MappingEntry anEntry)
|
||||
public MappingEntry CloneWithResetColumnNumber()
|
||||
{
|
||||
return (
|
||||
this.OriginalName == anEntry.OriginalName &&
|
||||
this.OriginalFileName == anEntry.OriginalFileName &&
|
||||
this.GeneratedSourcePosition.CompareTo(anEntry.GeneratedSourcePosition) == 0 &&
|
||||
this.OriginalSourcePosition.CompareTo(anEntry.OriginalSourcePosition) == 0);
|
||||
return new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: GeneratedSourcePosition.ZeroBasedLineNumber,
|
||||
zeroBasedColumnNumber: 0),
|
||||
originalSourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: OriginalSourcePosition.ZeroBasedLineNumber,
|
||||
zeroBasedColumnNumber: 0),
|
||||
originalName: OriginalName,
|
||||
originalFileName: OriginalFileName);
|
||||
}
|
||||
|
||||
public bool Equals(MappingEntry that)
|
||||
{
|
||||
return this.OriginalName == that.OriginalName &&
|
||||
this.OriginalFileName == that.OriginalFileName &&
|
||||
this.GeneratedSourcePosition.Equals(that.GeneratedSourcePosition) &&
|
||||
this.OriginalSourcePosition.Equals(that.OriginalSourcePosition);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is MappingEntry mappingEntry) ? Equals(mappingEntry) : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of Josh Bloch's hashing algorithm from Effective Java.
|
||||
/// It is fast, offers a good distribution (with primes 23 and 31), and allocation free.
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Wrap to protect overflow
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash * 31 + GeneratedSourcePosition.GetHashCode();
|
||||
hash = hash * 31 + OriginalSourcePosition.GetHashCode();
|
||||
hash = hash * 31 + (OriginalName ?? "").GetHashCode();
|
||||
hash = hash * 31 + (OriginalFileName ?? "").GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// Corresponds to a single parsed entry in the source map mapping string that is used internally by the parser.
|
||||
/// The public API exposes the MappingEntry object, which is more useful to consumers of the library.
|
||||
/// </summary>
|
||||
internal class NumericMappingEntry
|
||||
internal struct NumericMappingEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The zero-based line number in the generated code that corresponds to this mapping segment.
|
||||
|
@ -39,44 +39,40 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// </summary>
|
||||
public int? OriginalNameIndex;
|
||||
|
||||
public MappingEntry ToMappingEntry(List<string> names, List<string> sources)
|
||||
public MappingEntry ToMappingEntry(IReadOnlyList<string> names, IReadOnlyList<string> sources)
|
||||
{
|
||||
MappingEntry result = new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedColumnNumber = GeneratedColumnNumber,
|
||||
ZeroBasedLineNumber = GeneratedLineNumber
|
||||
}
|
||||
};
|
||||
SourcePosition originalSourcePosition;
|
||||
|
||||
if (OriginalColumnNumber.HasValue && OriginalLineNumber.HasValue)
|
||||
{
|
||||
result.OriginalSourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedColumnNumber = OriginalColumnNumber.Value,
|
||||
ZeroBasedLineNumber = OriginalLineNumber.Value
|
||||
};
|
||||
originalSourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: OriginalLineNumber.Value,
|
||||
zeroBasedColumnNumber: OriginalColumnNumber.Value);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
originalSourcePosition = SourcePosition.NotFound;
|
||||
}
|
||||
|
||||
string originalName = null;
|
||||
if (OriginalNameIndex.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
result.OriginalName = names[OriginalNameIndex.Value];
|
||||
originalName = names[OriginalNameIndex.Value];
|
||||
}
|
||||
catch (IndexOutOfRangeException e)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Source map contains original name index that is outside the range of the provided names array" ,e);
|
||||
throw new IndexOutOfRangeException("Source map contains original name index that is outside the range of the provided names array", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string originalFileName = null;
|
||||
if (OriginalSourceFileIndex.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
result.OriginalFileName = sources[OriginalSourceFileIndex.Value];
|
||||
originalFileName = sources[OriginalSourceFileIndex.Value];
|
||||
}
|
||||
catch (IndexOutOfRangeException e)
|
||||
{
|
||||
|
@ -84,6 +80,14 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
}
|
||||
}
|
||||
|
||||
MappingEntry result = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(
|
||||
zeroBasedLineNumber: GeneratedLineNumber,
|
||||
zeroBasedColumnNumber: GeneratedColumnNumber),
|
||||
originalSourcePosition: originalSourcePosition,
|
||||
originalName: originalName,
|
||||
originalFileName: originalFileName);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +105,8 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
public readonly int OriginalSourceStartingColumnBase;
|
||||
public readonly int NamesListIndexBase;
|
||||
|
||||
public MappingsParserState(MappingsParserState previousMappingsParserState = new MappingsParserState(),
|
||||
public MappingsParserState(
|
||||
MappingsParserState previousMappingsParserState = new MappingsParserState(),
|
||||
int? newGeneratedLineNumber = null,
|
||||
int? newGeneratedColumnBase = null,
|
||||
int? newSourcesListIndexBase = null,
|
||||
|
@ -124,6 +129,8 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// </summary>
|
||||
internal class MappingsListParser
|
||||
{
|
||||
private static readonly char[] LineDelimiter = new[] { ',' };
|
||||
|
||||
/// <summary>
|
||||
/// Parses a single "segment" of the mapping field for a source map. A segment describes one piece of code in the generated source.
|
||||
/// In the mapping string "AAaAA,CAACC;", AAaAA and CAACC are both segments. This method assumes the segments have already been decoded
|
||||
|
@ -132,7 +139,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// <param name="segmentFields">The integer values for the segment fields</param>
|
||||
/// <param name="mappingsParserState">The current state of the state variables for the parser</param>
|
||||
/// <returns></returns>
|
||||
internal NumericMappingEntry ParseSingleMappingSegment(List<int> segmentFields, MappingsParserState mappingsParserState)
|
||||
internal NumericMappingEntry ParseSingleMappingSegment(IReadOnlyList<int> segmentFields, MappingsParserState mappingsParserState)
|
||||
{
|
||||
if (segmentFields == null)
|
||||
{
|
||||
|
@ -144,7 +151,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
throw new ArgumentOutOfRangeException(nameof(segmentFields));
|
||||
}
|
||||
|
||||
NumericMappingEntry numericMappingEntry = new NumericMappingEntry
|
||||
NumericMappingEntry numericMappingEntry = new NumericMappingEntry()
|
||||
{
|
||||
GeneratedLineNumber = mappingsParserState.CurrentGeneratedLineNumber,
|
||||
GeneratedColumnNumber = mappingsParserState.CurrentGeneratedColumnBase + segmentFields[0]
|
||||
|
@ -192,28 +199,34 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// Top level API that should be called for decoding the MappingsString element. It will convert the string containing Base64
|
||||
/// VLQ encoded segments into a list of MappingEntries.
|
||||
/// </summary>
|
||||
internal List<MappingEntry> ParseMappings(string mappingString, List<string> names, List<string> sources)
|
||||
internal List<MappingEntry> ParseMappings(string mappingString, IReadOnlyList<string> names, IReadOnlyList<string> sources)
|
||||
{
|
||||
List<MappingEntry> mappingEntries = new List<MappingEntry>();
|
||||
MappingsParserState currentMappingsParserState = new MappingsParserState();
|
||||
|
||||
// The V3 source map format calls for all Base64 VLQ segments to be seperated by commas.
|
||||
// Each line of generated code is separated using semicolons. The count of semicolons encountered gives the current line number.
|
||||
string[] lines = mappingString.Split(';');
|
||||
string[] lines = mappingString.SplitFast(';');
|
||||
|
||||
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber += 1)
|
||||
for (int lineNumber = 0; lineNumber < lines.Length; lineNumber++)
|
||||
{
|
||||
// The only value that resets when encountering a semicolon is the starting column.
|
||||
currentMappingsParserState = new MappingsParserState(currentMappingsParserState, newGeneratedLineNumber:lineNumber, newGeneratedColumnBase: 0);
|
||||
string[] segmentsForLine = lines[lineNumber].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
currentMappingsParserState = new MappingsParserState(
|
||||
currentMappingsParserState,
|
||||
newGeneratedLineNumber: lineNumber,
|
||||
newGeneratedColumnBase: 0);
|
||||
|
||||
string[] segmentsForLine = lines[lineNumber].Split(LineDelimiter, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string segment in segmentsForLine)
|
||||
{
|
||||
// Reuse the numericMappingEntry to ease GC allocations.
|
||||
NumericMappingEntry numericMappingEntry = ParseSingleMappingSegment(Base64VlqDecoder.Decode(segment), currentMappingsParserState);
|
||||
mappingEntries.Add(numericMappingEntry.ToMappingEntry(names, sources));
|
||||
|
||||
// Update the current MappingParserState based on the generated MappingEntry
|
||||
currentMappingsParserState = new MappingsParserState(currentMappingsParserState,
|
||||
currentMappingsParserState = new MappingsParserState(
|
||||
currentMappingsParserState,
|
||||
newGeneratedColumnBase: numericMappingEntry.GeneratedColumnNumber,
|
||||
newSourcesListIndexBase: numericMappingEntry.OriginalSourceFileIndex,
|
||||
newOriginalSourceStartingLineBase: numericMappingEntry.OriginalLineNumber,
|
||||
|
|
|
@ -35,4 +35,6 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
// Sees internals to share extension methods
|
||||
[assembly: InternalsVisibleTo("SourcemapToolkit.CallstackDeminifier, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100fb6b178a31a5d56c14ad5de5e8f471e4b37ef4291eb74544d7477a42ba0769e04230fada2df8722623a26b018ca2aeb66b01e5a456dc56194f0e9826837151906ca02f3158111e41c3dd770ca307825402ff75d9602929b5594fe9a91aff9093d19cb2b35313452b48ab8ef3b7a997a09ee5f8c7c5285c327a30e3f16ef422a4")]
|
||||
[assembly: InternalsVisibleTo("SourcemapToolkit.SourcemapParser.UnitTests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100fb6b178a31a5d56c14ad5de5e8f471e4b37ef4291eb74544d7477a42ba0769e04230fada2df8722623a26b018ca2aeb66b01e5a456dc56194f0e9826837151906ca02f3158111e41c3dd770ca307825402ff75d9602929b5594fe9a91aff9093d19cb2b35313452b48ab8ef3b7a997a09ee5f8c7c5285c327a30e3f16ef422a4")]
|
|
@ -2,64 +2,88 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
public class SourceMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache the comparer to save the allocation
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
private static Comparer<MappingEntry> _comparer = Comparer<MappingEntry>.Create((a, b) => a.GeneratedSourcePosition.CompareTo(b.GeneratedSourcePosition));
|
||||
|
||||
/// <summary>
|
||||
/// The version of the source map specification being used
|
||||
/// </summary>
|
||||
public int Version;
|
||||
public int Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the generated file to which this source map corresponds
|
||||
/// </summary>
|
||||
public string File;
|
||||
public string File { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw, unparsed mappings entry of the soure map
|
||||
/// </summary>
|
||||
public string Mappings;
|
||||
public string Mappings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of source files that were the inputs used to generate this output file
|
||||
/// </summary>
|
||||
public List<string> Sources;
|
||||
public IReadOnlyList<string> Sources { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of known original names for entries in this file
|
||||
/// </summary>
|
||||
public List<string> Names;
|
||||
public IReadOnlyList<string> Names { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parsed version of the mappings string that is used for getting original names and source positions
|
||||
/// </summary>
|
||||
public List<MappingEntry> ParsedMappings;
|
||||
public IReadOnlyList<MappingEntry> ParsedMappings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of content source files
|
||||
/// </summary>
|
||||
public List<string> SourcesContent;
|
||||
public IReadOnlyList<string> SourcesContent { get; }
|
||||
|
||||
public SourceMap Clone()
|
||||
{
|
||||
return new SourceMap
|
||||
{
|
||||
Version = this.Version,
|
||||
File = this.File,
|
||||
Mappings = this.Mappings,
|
||||
Sources = new List<string>(this.Sources),
|
||||
Names = new List<string>(this.Names),
|
||||
SourcesContent = new List<string>(this.SourcesContent),
|
||||
ParsedMappings = new List<MappingEntry>(this.ParsedMappings.Select(m => m.Clone()))
|
||||
};
|
||||
}
|
||||
public SourceMap(
|
||||
int version,
|
||||
string file,
|
||||
string mappings,
|
||||
IReadOnlyList<string> sources,
|
||||
IReadOnlyList<string> names,
|
||||
IReadOnlyList<MappingEntry> parsedMappings,
|
||||
IReadOnlyList<string> sourcesContent)
|
||||
{
|
||||
Version = version;
|
||||
File = file;
|
||||
Mappings = mappings;
|
||||
Sources = sources;
|
||||
Names = names;
|
||||
ParsedMappings = parsedMappings;
|
||||
SourcesContent = sourcesContent;
|
||||
}
|
||||
|
||||
public SourceMap Clone()
|
||||
{
|
||||
return new SourceMap(
|
||||
version: Version,
|
||||
file: File,
|
||||
mappings: Mappings,
|
||||
sources: Sources,
|
||||
names: Names,
|
||||
parsedMappings: ParsedMappings,
|
||||
sourcesContent: SourcesContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the mappings of a sub source map to the current source map
|
||||
/// Each mapping to the supplied source file is rewritten using the supplied source map
|
||||
/// This is useful in situations where we have a to b to c, with mappings ba.map and cb.map
|
||||
/// Calling cb.ApplySourceMap(ba) will return mappings from c to a (ca)
|
||||
/// This is useful in situations where we have a to b to c, with mappings ba.map and cb.map
|
||||
/// Calling cb.ApplySourceMap(ba) will return mappings from c to a (ca)
|
||||
/// <param name="submap">The submap to apply</param>
|
||||
/// <param name="sourceFile">The filename of the source file. If not specified, submap's File property will be used</param>
|
||||
/// <returns>A new source map</returns>
|
||||
|
@ -75,41 +99,33 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
{
|
||||
if (submap.File == null)
|
||||
{
|
||||
throw new Exception("ApplySourceMap expects either the explicit source file to the map, or submap's 'file' property");
|
||||
throw new Exception($"{nameof(ApplySourceMap)} expects either the explicit source file to the map, or submap's 'file' property");
|
||||
}
|
||||
|
||||
sourceFile = submap.File;
|
||||
}
|
||||
|
||||
SourceMap newSourceMap = new SourceMap
|
||||
{
|
||||
File = this.File,
|
||||
Version = this.Version,
|
||||
Sources = new List<string>(),
|
||||
Names = new List<string>(),
|
||||
SourcesContent = new List<string>(),
|
||||
ParsedMappings = new List<MappingEntry>()
|
||||
};
|
||||
HashSet<string> sources = new HashSet<string>(StringComparer.Ordinal);
|
||||
HashSet<string> names = new HashSet<string>(StringComparer.Ordinal);
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>(this.ParsedMappings.Count);
|
||||
|
||||
// transform mappings in this source map
|
||||
foreach (MappingEntry mappingEntry in this.ParsedMappings)
|
||||
{
|
||||
MappingEntry newMappingEntry = mappingEntry.Clone();
|
||||
MappingEntry newMappingEntry = mappingEntry;
|
||||
|
||||
if (mappingEntry.OriginalFileName == sourceFile && mappingEntry.OriginalSourcePosition != null)
|
||||
if (mappingEntry.OriginalFileName == sourceFile && mappingEntry.OriginalSourcePosition != SourcePosition.NotFound)
|
||||
{
|
||||
MappingEntry correspondingSubMapMappingEntry = submap.GetMappingEntryForGeneratedSourcePosition(mappingEntry.OriginalSourcePosition);
|
||||
MappingEntry? correspondingSubMapMappingEntry = submap.GetMappingEntryForGeneratedSourcePosition(mappingEntry.OriginalSourcePosition);
|
||||
|
||||
if (correspondingSubMapMappingEntry != null)
|
||||
{
|
||||
// Copy the mapping
|
||||
newMappingEntry = new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = mappingEntry.GeneratedSourcePosition.Clone(),
|
||||
OriginalSourcePosition = correspondingSubMapMappingEntry.OriginalSourcePosition.Clone(),
|
||||
OriginalName = correspondingSubMapMappingEntry.OriginalName?? mappingEntry.OriginalName,
|
||||
OriginalFileName = correspondingSubMapMappingEntry.OriginalFileName?? mappingEntry.OriginalFileName
|
||||
};
|
||||
newMappingEntry = new MappingEntry(
|
||||
generatedSourcePosition: mappingEntry.GeneratedSourcePosition,
|
||||
originalSourcePosition: correspondingSubMapMappingEntry.Value.OriginalSourcePosition,
|
||||
originalName: correspondingSubMapMappingEntry.Value.OriginalName ?? mappingEntry.OriginalName,
|
||||
originalFileName: correspondingSubMapMappingEntry.Value.OriginalFileName ?? mappingEntry.OriginalFileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,55 +133,62 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
string originalFileName = newMappingEntry.OriginalFileName;
|
||||
string originalName = newMappingEntry.OriginalName;
|
||||
|
||||
if (originalFileName != null && !newSourceMap.Sources.Contains(originalFileName))
|
||||
if (originalFileName != null)
|
||||
{
|
||||
newSourceMap.Sources.Add(originalFileName);
|
||||
sources.Add(originalFileName);
|
||||
}
|
||||
|
||||
if (originalName != null && !newSourceMap.Names.Contains(originalName))
|
||||
if (originalName != null)
|
||||
{
|
||||
newSourceMap.Names.Add(originalName);
|
||||
names.Add(originalName);
|
||||
}
|
||||
|
||||
newSourceMap.ParsedMappings.Add(newMappingEntry);
|
||||
};
|
||||
parsedMappings.Add(newMappingEntry);
|
||||
}
|
||||
|
||||
SourceMap newSourceMap = new SourceMap(
|
||||
version: Version,
|
||||
file: File,
|
||||
mappings: default,
|
||||
sources: sources.ToList(),
|
||||
names: names.ToList(),
|
||||
parsedMappings: parsedMappings,
|
||||
new List<string>());
|
||||
|
||||
return newSourceMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the mapping entry for the generated source position. If no exact match is found, it will attempt
|
||||
/// to return a nearby mapping that should map to the same piece of code.
|
||||
/// </summary>
|
||||
/// <param name="generatedSourcePosition">The location in generated code for which we want to discover a mapping entry</param>
|
||||
/// <returns>A mapping entry that is a close match for the desired generated code location</returns>
|
||||
public virtual MappingEntry GetMappingEntryForGeneratedSourcePosition(SourcePosition generatedSourcePosition)
|
||||
{
|
||||
if (ParsedMappings == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the mapping entry for the generated source position. If no exact match is found, it will attempt
|
||||
/// to return a nearby mapping that should map to the same piece of code.
|
||||
/// </summary>
|
||||
/// <param name="generatedSourcePosition">The location in generated code for which we want to discover a mapping entry</param>
|
||||
/// <returns>A mapping entry that is a close match for the desired generated code location</returns>
|
||||
public virtual MappingEntry? GetMappingEntryForGeneratedSourcePosition(SourcePosition generatedSourcePosition)
|
||||
{
|
||||
if (ParsedMappings == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MappingEntry mappingEntryToFind = new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = generatedSourcePosition
|
||||
};
|
||||
MappingEntry mappingEntryToFind = new MappingEntry(generatedSourcePosition: generatedSourcePosition);
|
||||
|
||||
int index = ParsedMappings.BinarySearch(mappingEntryToFind,
|
||||
Comparer<MappingEntry>.Create((a, b) => a.GeneratedSourcePosition.CompareTo(b.GeneratedSourcePosition)));
|
||||
int index = ParsedMappings.BinarySearch(mappingEntryToFind, _comparer);
|
||||
|
||||
// If we didn't get an exact match, let's try to return the closest piece of code to the given line
|
||||
if (index < 0)
|
||||
{
|
||||
// The BinarySearch method returns the bitwise complement of the nearest element that is larger than the desired element when there isn't a match.
|
||||
// Based on tests with source maps generated with the Closure Compiler, we should consider the closest source position that is smaller than the target value when we don't have a match.
|
||||
if (~index - 1 >= 0 && ParsedMappings[~index - 1].GeneratedSourcePosition.IsEqualish(generatedSourcePosition))
|
||||
{
|
||||
index = ~index - 1;
|
||||
}
|
||||
}
|
||||
// If we didn't get an exact match, let's try to return the closest piece of code to the given line
|
||||
if (index < 0)
|
||||
{
|
||||
// The BinarySearch method returns the bitwise complement of the nearest element that is larger than the desired element when there isn't a match.
|
||||
// Based on tests with source maps generated with the Closure Compiler, we should consider the closest source position that is smaller than the target value when we don't have a match.
|
||||
int correctIndex = ~index - 1;
|
||||
|
||||
return index >= 0 ? ParsedMappings[index] : null;
|
||||
}
|
||||
if (correctIndex >= 0 && ParsedMappings[correctIndex].GeneratedSourcePosition.IsEqualish(generatedSourcePosition))
|
||||
{
|
||||
index = correctIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return index >= 0 ? (MappingEntry?)ParsedMappings[index] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,22 +16,22 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// <summary>
|
||||
/// Last location of the code in the transformed code
|
||||
/// </summary>
|
||||
public readonly SourcePosition LastGeneratedPosition = new SourcePosition();
|
||||
public SourcePosition LastGeneratedPosition { get; private set; } = default;
|
||||
|
||||
/// <summary>
|
||||
/// Last location of the code in the source code
|
||||
/// </summary>
|
||||
public readonly SourcePosition LastOriginalPosition = new SourcePosition();
|
||||
public SourcePosition LastOriginalPosition { get; set; } = default;
|
||||
|
||||
/// <summary>
|
||||
/// List that contains the symbol names
|
||||
/// </summary>
|
||||
public readonly IList<string> Names;
|
||||
public readonly IReadOnlyList<string> Names;
|
||||
|
||||
/// <summary>
|
||||
/// List that contains the file sources
|
||||
/// </summary>
|
||||
public readonly IList<string> Sources;
|
||||
public readonly IReadOnlyList<string> Sources;
|
||||
|
||||
/// <summary>
|
||||
/// Index of last file source
|
||||
|
@ -48,12 +48,26 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// </summary>
|
||||
public bool IsFirstSegment { get; set; }
|
||||
|
||||
public MappingGenerateState(IList<string> names, IList<string> sources)
|
||||
public MappingGenerateState(IReadOnlyList<string> names, IReadOnlyList<string> sources)
|
||||
{
|
||||
Names = names;
|
||||
Sources = sources;
|
||||
IsFirstSegment = true;
|
||||
}
|
||||
|
||||
public void AdvanceLastGeneratedPositionLine()
|
||||
{
|
||||
LastGeneratedPosition = new SourcePosition(
|
||||
zeroBasedLineNumber: LastGeneratedPosition.ZeroBasedLineNumber + 1,
|
||||
zeroBasedColumnNumber: 0);
|
||||
}
|
||||
|
||||
public void UpdateLastGeneratedPositionColumn(int zeroBasedColumnNumber)
|
||||
{
|
||||
LastGeneratedPosition = new SourcePosition(
|
||||
zeroBasedLineNumber: LastGeneratedPosition.ZeroBasedLineNumber,
|
||||
zeroBasedColumnNumber: zeroBasedColumnNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public class SourceMapGenerator
|
||||
|
@ -81,15 +95,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
throw new ArgumentNullException(nameof(sourceMap));
|
||||
}
|
||||
|
||||
SourceMap mapToSerialize = new SourceMap()
|
||||
{
|
||||
File = sourceMap.File,
|
||||
Names = sourceMap.Names,
|
||||
Sources = sourceMap.Sources,
|
||||
Version = sourceMap.Version,
|
||||
SourcesContent = sourceMap.SourcesContent
|
||||
};
|
||||
|
||||
string mappings = null;
|
||||
if (sourceMap.ParsedMappings != null && sourceMap.ParsedMappings.Count > 0)
|
||||
{
|
||||
MappingGenerateState state = new MappingGenerateState(sourceMap.Names, sourceMap.Sources);
|
||||
|
@ -102,9 +108,18 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
|
||||
output.Append(';');
|
||||
|
||||
mapToSerialize.Mappings = output.ToString();
|
||||
mappings = output.ToString();
|
||||
}
|
||||
|
||||
SourceMap mapToSerialize = new SourceMap(
|
||||
version: sourceMap.Version,
|
||||
file: sourceMap.File,
|
||||
mappings: mappings,
|
||||
sources: sourceMap.Sources,
|
||||
names: sourceMap.Names,
|
||||
parsedMappings: default,
|
||||
sourcesContent: sourceMap.SourcesContent);
|
||||
|
||||
return JsonConvert.SerializeObject(mapToSerialize,
|
||||
jsonSerializerSettings ?? new JsonSerializerSettings
|
||||
{
|
||||
|
@ -126,8 +141,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
// Each line of generated code is separated using semicolons
|
||||
while (entry.GeneratedSourcePosition.ZeroBasedLineNumber != state.LastGeneratedPosition.ZeroBasedLineNumber)
|
||||
{
|
||||
state.LastGeneratedPosition.ZeroBasedColumnNumber = 0;
|
||||
state.LastGeneratedPosition.ZeroBasedLineNumber++;
|
||||
state.AdvanceLastGeneratedPositionLine();
|
||||
state.IsFirstSegment = true;
|
||||
output.Append(';');
|
||||
}
|
||||
|
@ -163,7 +177,7 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
*/
|
||||
|
||||
Base64VlqEncoder.Encode(output, entry.GeneratedSourcePosition.ZeroBasedColumnNumber - state.LastGeneratedPosition.ZeroBasedColumnNumber);
|
||||
state.LastGeneratedPosition.ZeroBasedColumnNumber = entry.GeneratedSourcePosition.ZeroBasedColumnNumber;
|
||||
state.UpdateLastGeneratedPositionColumn(entry.GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
|
||||
if (entry.OriginalFileName != null)
|
||||
{
|
||||
|
@ -177,10 +191,11 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
state.LastSourceIndex = sourceIndex;
|
||||
|
||||
Base64VlqEncoder.Encode(output, entry.OriginalSourcePosition.ZeroBasedLineNumber - state.LastOriginalPosition.ZeroBasedLineNumber);
|
||||
state.LastOriginalPosition.ZeroBasedLineNumber = entry.OriginalSourcePosition.ZeroBasedLineNumber;
|
||||
|
||||
Base64VlqEncoder.Encode(output, entry.OriginalSourcePosition.ZeroBasedColumnNumber - state.LastOriginalPosition.ZeroBasedColumnNumber);
|
||||
state.LastOriginalPosition.ZeroBasedColumnNumber = entry.OriginalSourcePosition.ZeroBasedColumnNumber;
|
||||
|
||||
state.LastOriginalPosition = new SourcePosition(
|
||||
zeroBasedLineNumber: entry.OriginalSourcePosition.ZeroBasedLineNumber,
|
||||
zeroBasedColumnNumber: entry.OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
|
||||
if (entry.OriginalName != null)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
|
@ -26,7 +28,22 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
SourceMap result = serializer.Deserialize<SourceMap>(jsonTextReader);
|
||||
result.ParsedMappings = _mappingsListParser.ParseMappings(result.Mappings, result.Names, result.Sources);
|
||||
|
||||
// Since SourceMap is immutable we need to allocate a new one and copy over all the information
|
||||
List<MappingEntry> parsedMappings = _mappingsListParser.ParseMappings(result.Mappings, result.Names, result.Sources);
|
||||
|
||||
// Resize to free unused memory
|
||||
parsedMappings.Capacity = parsedMappings.Count;
|
||||
|
||||
result = new SourceMap(
|
||||
version: result.Version,
|
||||
file: result.File,
|
||||
mappings: result.Mappings,
|
||||
sources: result.Sources,
|
||||
names: result.Names,
|
||||
parsedMappings: parsedMappings,
|
||||
sourcesContent: result.SourcesContent);
|
||||
|
||||
sourceMapStream.Close();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -2,44 +2,43 @@
|
|||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
public static class SourceMapTransformer
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes column information from a source map
|
||||
/// This can significantly reduce the size of source maps
|
||||
/// If there is a tie between mapping entries, the first generated line takes priority
|
||||
/// <returns>A new source map</returns>
|
||||
/// </summary>
|
||||
public static SourceMap Flatten(SourceMap sourceMap)
|
||||
{
|
||||
SourceMap newMap = new SourceMap
|
||||
{
|
||||
File = sourceMap.File,
|
||||
Version = sourceMap.Version,
|
||||
Mappings = sourceMap.Mappings,
|
||||
Sources = sourceMap.Sources == null ? null : new List<string>(sourceMap.Sources),
|
||||
SourcesContent = sourceMap.SourcesContent == null ? null : new List<string>(sourceMap.SourcesContent),
|
||||
Names = sourceMap.Names == null ? null : new List<string>(sourceMap.Names),
|
||||
ParsedMappings = new List<MappingEntry>()
|
||||
};
|
||||
public static class SourceMapTransformer
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes column information from a source map
|
||||
/// This can significantly reduce the size of source maps
|
||||
/// If there is a tie between mapping entries, the first generated line takes priority
|
||||
/// <returns>A new source map</returns>
|
||||
/// </summary>
|
||||
public static SourceMap Flatten(SourceMap sourceMap)
|
||||
{
|
||||
HashSet<int> visitedLines = new HashSet<int>();
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>(sourceMap.ParsedMappings.Count); // assume each line will not have been visited before
|
||||
|
||||
HashSet<int> visitedLines = new HashSet<int>();
|
||||
foreach (MappingEntry mapping in sourceMap.ParsedMappings)
|
||||
{
|
||||
int generatedLine = mapping.GeneratedSourcePosition.ZeroBasedLineNumber;
|
||||
|
||||
foreach (MappingEntry mapping in sourceMap.ParsedMappings)
|
||||
{
|
||||
int generatedLine = mapping.GeneratedSourcePosition.ZeroBasedLineNumber;
|
||||
if (visitedLines.Add(generatedLine))
|
||||
{
|
||||
MappingEntry newMapping = mapping.CloneWithResetColumnNumber();
|
||||
parsedMappings.Add(newMapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visitedLines.Contains(generatedLine))
|
||||
{
|
||||
visitedLines.Add(generatedLine);
|
||||
var newMapping = mapping.Clone();
|
||||
newMapping.GeneratedSourcePosition.ZeroBasedColumnNumber = 0;
|
||||
newMapping.OriginalSourcePosition.ZeroBasedColumnNumber = 0;
|
||||
newMap.ParsedMappings.Add(newMapping);
|
||||
}
|
||||
}
|
||||
// Free-up any unneeded space. This no-ops if we're already the right size.
|
||||
parsedMappings.Capacity = parsedMappings.Count;
|
||||
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
SourceMap newMap = new SourceMap(
|
||||
version: sourceMap.Version,
|
||||
file: sourceMap.File,
|
||||
mappings: sourceMap.Mappings,
|
||||
sources: sourceMap.Sources,
|
||||
names: sourceMap.Names,
|
||||
parsedMappings: parsedMappings,
|
||||
sourcesContent: sourceMap.SourcesContent);
|
||||
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,69 +2,93 @@
|
|||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies the location of a piece of code in a JavaScript file
|
||||
/// </summary>
|
||||
public class SourcePosition : IComparable<SourcePosition>
|
||||
{
|
||||
public int ZeroBasedLineNumber;
|
||||
/// <summary>
|
||||
/// Identifies the location of a piece of code in a JavaScript file
|
||||
/// </summary>
|
||||
public struct SourcePosition : IComparable<SourcePosition>, IEquatable<SourcePosition>
|
||||
{
|
||||
public static readonly SourcePosition NotFound = new SourcePosition(-1, -1);
|
||||
|
||||
public int ZeroBasedColumnNumber;
|
||||
public readonly int ZeroBasedLineNumber;
|
||||
public readonly int ZeroBasedColumnNumber;
|
||||
|
||||
public int CompareTo(SourcePosition other)
|
||||
{
|
||||
if (this.ZeroBasedLineNumber == other.ZeroBasedLineNumber)
|
||||
{
|
||||
return this.ZeroBasedColumnNumber.CompareTo(other.ZeroBasedColumnNumber);
|
||||
}
|
||||
public SourcePosition(int zeroBasedLineNumber, int zeroBasedColumnNumber)
|
||||
{
|
||||
ZeroBasedLineNumber = zeroBasedLineNumber;
|
||||
ZeroBasedColumnNumber = zeroBasedColumnNumber;
|
||||
}
|
||||
|
||||
return this.ZeroBasedLineNumber.CompareTo(other.ZeroBasedLineNumber);
|
||||
}
|
||||
public int CompareTo(SourcePosition other)
|
||||
{
|
||||
if (this.ZeroBasedLineNumber == other.ZeroBasedLineNumber)
|
||||
{
|
||||
return this.ZeroBasedColumnNumber.CompareTo(other.ZeroBasedColumnNumber);
|
||||
}
|
||||
|
||||
public static bool operator <(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return x.CompareTo(y) < 0;
|
||||
}
|
||||
return this.ZeroBasedLineNumber.CompareTo(other.ZeroBasedLineNumber);
|
||||
}
|
||||
|
||||
public static bool operator >(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return x.CompareTo(y) > 0;
|
||||
}
|
||||
public static bool operator <(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return x.CompareTo(y) < 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we think that the two source positions are close enough together that they may in fact be the referring to the same piece of code.
|
||||
/// </summary>
|
||||
public bool IsEqualish(SourcePosition other)
|
||||
{
|
||||
// If the column numbers differ by 1, we can say that the source code is approximately equal
|
||||
if (this.ZeroBasedLineNumber == other.ZeroBasedLineNumber && Math.Abs(this.ZeroBasedColumnNumber - other.ZeroBasedColumnNumber) <= 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public static bool operator >(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return x.CompareTo(y) > 0;
|
||||
}
|
||||
|
||||
// This handles the case where we are comparing code at the end of one line and the beginning of the next line.
|
||||
// If the column number on one of the entries is zero, it is ok for the line numbers to differ by 1, so long as the one that has a column number of zero is the one with the larger line number.
|
||||
// Since we don't have the number of columns in each line, we can't know for sure if these two pieces of code are actually near each other. This is an optimistic guess.
|
||||
if (Math.Abs(this.ZeroBasedLineNumber - other.ZeroBasedLineNumber) == 1)
|
||||
{
|
||||
SourcePosition largerLineNumber = this.ZeroBasedLineNumber > other.ZeroBasedLineNumber ? this : other;
|
||||
public static bool operator ==(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
|
||||
if (largerLineNumber.ZeroBasedColumnNumber == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public static bool operator !=(SourcePosition x, SourcePosition y)
|
||||
{
|
||||
return !x.Equals(y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public bool Equals(SourcePosition that)
|
||||
{
|
||||
return this.ZeroBasedLineNumber == that.ZeroBasedLineNumber
|
||||
&& this.ZeroBasedColumnNumber == that.ZeroBasedColumnNumber;
|
||||
}
|
||||
|
||||
public SourcePosition Clone()
|
||||
{
|
||||
return new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = this.ZeroBasedLineNumber,
|
||||
ZeroBasedColumnNumber = this.ZeroBasedColumnNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is SourcePosition otherSourcePosition) ? Equals(otherSourcePosition) : false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ZeroBasedColumnNumber.GetHashCode() ^ ZeroBasedColumnNumber.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we think that the two source positions are close enough together that they may in fact be the referring to the same piece of code.
|
||||
/// </summary>
|
||||
public bool IsEqualish(SourcePosition other)
|
||||
{
|
||||
// If the column numbers differ by 1, we can say that the source code is approximately equal
|
||||
if (this.ZeroBasedLineNumber == other.ZeroBasedLineNumber && Math.Abs(this.ZeroBasedColumnNumber - other.ZeroBasedColumnNumber) <= 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// This handles the case where we are comparing code at the end of one line and the beginning of the next line.
|
||||
// If the column number on one of the entries is zero, it is ok for the line numbers to differ by 1, so long as the one that has a column number of zero is the one with the larger line number.
|
||||
// Since we don't have the number of columns in each line, we can't know for sure if these two pieces of code are actually near each other. This is an optimistic guess.
|
||||
if (Math.Abs(this.ZeroBasedLineNumber - other.ZeroBasedLineNumber) == 1)
|
||||
{
|
||||
SourcePosition largerLineNumber = this.ZeroBasedLineNumber > other.ZeroBasedLineNumber ? this : other;
|
||||
|
||||
if (largerLineNumber.ZeroBasedColumnNumber == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<Compile Include="Base64VlqConstants.cs" />
|
||||
<Compile Include="Base64VlqDecoder.cs" />
|
||||
<Compile Include="Base64VlqEncoder.cs" />
|
||||
<Compile Include="IReadOnlyListExtensions.cs" />
|
||||
<Compile Include="MappingEntry.cs" />
|
||||
<Compile Include="MappingListParser.cs" />
|
||||
<Compile Include="SourceMap.cs" />
|
||||
|
@ -63,6 +64,7 @@
|
|||
<Compile Include="SourceMapParser.cs" />
|
||||
<Compile Include="SourceMapTransformer.cs" />
|
||||
<Compile Include="SourcePosition.cs" />
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
internal static class StringExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// String.Split() allocates an O(input.Length) int array, and
|
||||
/// is surprisingly expensive. For most cases this implementation
|
||||
/// is faster and does fewer allocations.
|
||||
/// </summary>
|
||||
public static string[] SplitFast(this string input, char delimiter)
|
||||
{
|
||||
int segmentCount = 1;
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
if (input[i] == delimiter)
|
||||
{
|
||||
segmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int segmentId = 0;
|
||||
int prevDelimiter = 0;
|
||||
string[] segments = new string[segmentCount];
|
||||
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
if (input[i] == delimiter)
|
||||
{
|
||||
segments[segmentId] = input.Substring(prevDelimiter, i - prevDelimiter);
|
||||
segmentId++;
|
||||
prevDelimiter = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
segments[segmentId] = input.Substring(prevDelimiter);
|
||||
|
||||
return segments;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,11 +11,9 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
public void GetWrappingFunctionForSourceLocation_EmptyFunctionMap_ReturnNull()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition sourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 3
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 3);
|
||||
List<FunctionMapEntry> functionMap = new List<FunctionMapEntry>();
|
||||
IFunctionMapConsumer functionMapConsumer = new FunctionMapConsumer();
|
||||
|
||||
|
@ -30,18 +28,17 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
public void GetWrappingFunctionForSourceLocation_SingleIrrelevantFunctionMapEntry_ReturnNull()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition sourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 3
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 3);
|
||||
List<FunctionMapEntry> functionMap = new List<FunctionMapEntry>
|
||||
{
|
||||
new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition {ZeroBasedLineNumber = 40, ZeroBasedColumnNumber = 10},
|
||||
EndSourcePosition = new SourcePosition {ZeroBasedLineNumber = 50, ZeroBasedColumnNumber = 10}
|
||||
}
|
||||
new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 40, zeroBasedColumnNumber: 10),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 50, zeroBasedColumnNumber: 10))
|
||||
|
||||
};
|
||||
IFunctionMapConsumer functionMapConsumer = new FunctionMapConsumer();
|
||||
|
||||
|
@ -56,16 +53,14 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
public void GetWrappingFunctionForSourceLocation_SingleRelevantFunctionMapEntry_ReturnWrappingFunction()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition sourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 41,
|
||||
ZeroBasedColumnNumber = 2
|
||||
};
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition { ZeroBasedLineNumber = 40, ZeroBasedColumnNumber = 10 },
|
||||
EndSourcePosition = new SourcePosition { ZeroBasedLineNumber = 50, ZeroBasedColumnNumber = 10 }
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: 41,
|
||||
zeroBasedColumnNumber: 2);
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 40, zeroBasedColumnNumber: 10),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 50, zeroBasedColumnNumber: 10));
|
||||
List<FunctionMapEntry> functionMap = new List<FunctionMapEntry>
|
||||
{
|
||||
functionMapEntry
|
||||
|
@ -83,21 +78,19 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
public void GetWrappingFunctionForSourceLocation_MultipleFunctionMapEntriesSingleRelevantFunctionMapEntry_ReturnWrappingFunction()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition sourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 31,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition { ZeroBasedLineNumber = 10, ZeroBasedColumnNumber = 10 },
|
||||
EndSourcePosition = new SourcePosition { ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 30 }
|
||||
};
|
||||
FunctionMapEntry functionMapEntry2 = new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition { ZeroBasedLineNumber = 30, ZeroBasedColumnNumber = 0 },
|
||||
EndSourcePosition = new SourcePosition { ZeroBasedLineNumber = 40, ZeroBasedColumnNumber = 2 }
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: 31,
|
||||
zeroBasedColumnNumber: 0);
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 10, zeroBasedColumnNumber: 10),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 20, zeroBasedColumnNumber: 30));
|
||||
FunctionMapEntry functionMapEntry2 = new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 30, zeroBasedColumnNumber: 0),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 40, zeroBasedColumnNumber: 2));
|
||||
List<FunctionMapEntry> functionMap = new List<FunctionMapEntry>
|
||||
{
|
||||
functionMapEntry,
|
||||
|
@ -116,21 +109,19 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
public void GetWrappingFunctionForSourceLocation_MultipleFunctionMapEntriesMultipleRelevantFunctionMapEntry_ReturnClosestWrappingFunction()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition sourcePosition = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 10,
|
||||
ZeroBasedColumnNumber = 25
|
||||
};
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition { ZeroBasedLineNumber = 5, ZeroBasedColumnNumber = 10 },
|
||||
EndSourcePosition = new SourcePosition { ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 30 }
|
||||
};
|
||||
FunctionMapEntry functionMapEntry2 = new FunctionMapEntry
|
||||
{
|
||||
StartSourcePosition = new SourcePosition { ZeroBasedLineNumber = 9, ZeroBasedColumnNumber = 0 },
|
||||
EndSourcePosition = new SourcePosition { ZeroBasedLineNumber = 15, ZeroBasedColumnNumber = 2 }
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition(
|
||||
zeroBasedLineNumber: 10,
|
||||
zeroBasedColumnNumber: 25);
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 5, zeroBasedColumnNumber: 10),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 20, zeroBasedColumnNumber: 30));
|
||||
FunctionMapEntry functionMapEntry2 = new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName: default,
|
||||
startSourcePosition: new SourcePosition(zeroBasedLineNumber: 9, zeroBasedColumnNumber: 0),
|
||||
endSourcePosition: new SourcePosition(zeroBasedLineNumber: 15, zeroBasedColumnNumber: 2));
|
||||
List<FunctionMapEntry> functionMap = new List<FunctionMapEntry>
|
||||
{
|
||||
functionMapEntry2,
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xunit;
|
||||
using SourcemapToolkit.SourcemapParser.UnitTests;
|
||||
|
||||
using Rhino.Mocks;
|
||||
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
using SourcemapToolkit.SourcemapParser.UnitTests;
|
||||
|
||||
namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
||||
{
|
||||
|
@ -18,7 +21,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
string sourceCode = "";
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.GenerateFunctionMap(UnitTestUtils.StreamReaderFromString(sourceCode), null);
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.GenerateFunctionMap(UnitTestUtils.StreamReaderFromString(sourceCode), null);
|
||||
|
||||
// Assert
|
||||
Assert.Null(functionMap);
|
||||
|
@ -30,9 +33,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(null);
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(null, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Null(functionMap);
|
||||
|
@ -44,12 +48,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "bar();";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, functionMap.Count);
|
||||
Assert.Empty(functionMap);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -58,12 +63,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "function foo(){bar();}";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, functionMap.Count);
|
||||
Assert.Single(functionMap);
|
||||
Assert.Equal("foo", functionMap[0].Bindings[0].Name);
|
||||
Assert.Equal(0, functionMap[0].Bindings[0].SourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(9, functionMap[0].Bindings[0].SourcePosition.ZeroBasedColumnNumber);
|
||||
|
@ -80,12 +86,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "function foo()" + Environment.NewLine + "{" + Environment.NewLine + "bar();" +
|
||||
Environment.NewLine + "}";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, functionMap.Count);
|
||||
Assert.Single(functionMap);
|
||||
Assert.Equal("foo", functionMap[0].Bindings[0].Name);
|
||||
Assert.Equal(0, functionMap[0].Bindings[0].SourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(9, functionMap[0].Bindings[0].SourcePosition.ZeroBasedColumnNumber);
|
||||
|
@ -101,9 +108,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "function foo(){bar();}function bar(){baz();}";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -131,9 +139,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "function foo(){function bar(){baz();}}";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -161,12 +170,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){bar();}";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, functionMap.Count);
|
||||
Assert.Single(functionMap);
|
||||
|
||||
Assert.Equal("foo", functionMap[0].Bindings[0].Name);
|
||||
Assert.Equal(0, functionMap[0].Bindings[0].SourcePosition.ZeroBasedLineNumber);
|
||||
|
@ -183,9 +193,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){};foo.bar = function() { baz(); }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -214,9 +225,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){} foo.prototype.bar = function () { baz(); }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -245,9 +257,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){} foo.prototype = { bar: function () { baz(); } }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -278,12 +291,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function myCoolFunctionName(){ bar(); }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, functionMap.Count);
|
||||
Assert.Single(functionMap);
|
||||
|
||||
Assert.Equal("foo", functionMap[0].Bindings[0].Name);
|
||||
Assert.Equal(0, functionMap[0].Bindings[0].SourcePosition.ZeroBasedLineNumber);
|
||||
|
@ -300,9 +314,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){};foo.bar = function myCoolFunctionName() { baz(); }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -331,9 +346,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){} foo.prototype.bar = function myCoolFunctionName() { baz(); } }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -362,9 +378,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Arrange
|
||||
FunctionMapGenerator functionMapGenerator = new FunctionMapGenerator();
|
||||
string sourceCode = "var foo = function(){} foo.prototype = { bar: function myCoolFunctionName() { baz(); } }";
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
List<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode));
|
||||
IReadOnlyList<FunctionMapEntry> functionMap = functionMapGenerator.ParseSourceCode(UnitTestUtils.StreamReaderFromString(sourceCode), sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, functionMap.Count);
|
||||
|
@ -389,193 +406,16 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
Assert.Equal(22, functionMap[1].EndSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_NullFunctionMapEntry_ThrowsException()
|
||||
private static SourceMap CreateSourceMapMock()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = null;
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>( ()=> FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_NullSourceMap_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry();
|
||||
SourceMap sourceMap = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>( ()=> FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_NoBinding_ReturnNullMethodName()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry();
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
|
||||
// Act
|
||||
string result = FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_HasSingleBindingNoMatchingMapping_ReturnNullMethodName()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
Bindings =
|
||||
new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 15}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
sourceMap.Stub(x => x.GetMappingEntryForGeneratedSourcePosition(Arg<SourcePosition>.Is.Anything)).Return(null);
|
||||
|
||||
// Act
|
||||
string result = FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_HasSingleBindingMatchingMapping_ReturnsMethodName()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
Bindings =
|
||||
new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 5, ZeroBasedColumnNumber = 8}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 8)))
|
||||
.Return(new MappingEntry
|
||||
{
|
||||
OriginalName = "foo",
|
||||
});
|
||||
|
||||
// Act
|
||||
string result = FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_MatchingMappingMultipleBindingsMissingPrototypeMapping_ReturnsMethodName()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
Bindings =
|
||||
new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 86, ZeroBasedColumnNumber = 52}
|
||||
},
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 88, ZeroBasedColumnNumber = 78}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 86 && y.ZeroBasedColumnNumber == 52)))
|
||||
.Return(null);
|
||||
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 88 && y.ZeroBasedColumnNumber == 78)))
|
||||
.Return(new MappingEntry
|
||||
{
|
||||
OriginalName = "baz",
|
||||
});
|
||||
|
||||
// Act
|
||||
string result = FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("baz", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodNameFromSourceMap_MatchingMappingMultipleBindings_ReturnsMethodNameWithFullBinding()
|
||||
{
|
||||
// Arrange
|
||||
FunctionMapEntry functionMapEntry = new FunctionMapEntry
|
||||
{
|
||||
Bindings =
|
||||
new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 5, ZeroBasedColumnNumber = 5}
|
||||
},
|
||||
new BindingInformation
|
||||
{
|
||||
SourcePosition = new SourcePosition {ZeroBasedLineNumber = 20, ZeroBasedColumnNumber = 10}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SourceMap sourceMap = MockRepository.GenerateStub<SourceMap>();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 5)))
|
||||
.Return(new MappingEntry
|
||||
{
|
||||
OriginalName = "bar"
|
||||
});
|
||||
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 20 && y.ZeroBasedColumnNumber == 10)))
|
||||
.Return(new MappingEntry
|
||||
{
|
||||
OriginalName = "baz",
|
||||
});
|
||||
|
||||
// Act
|
||||
string result = FunctionMapGenerator.GetDeminifiedMethodNameFromSourceMap(functionMapEntry, sourceMap);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar.baz", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
return MockRepository.GenerateStub<SourceMap>(
|
||||
0 /* version */,
|
||||
default(string) /* file */,
|
||||
default(string) /* mappings */,
|
||||
default(IReadOnlyList<string>) /* sources */,
|
||||
default(IReadOnlyList<string>) /* names */,
|
||||
default(IReadOnlyList<MappingEntry>) /* parsedMappings */,
|
||||
default(IReadOnlyList<string>) /* sourcesContent */);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
string result = keyValueCache.GetValue("bar");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(null, result);
|
||||
Assert.Null(result);
|
||||
valueGetter.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xunit;
|
||||
|
||||
using Rhino.Mocks;
|
||||
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
|
||||
namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
||||
{
|
||||
public class SourceMapExtensionsUnitTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_NullBindings_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<BindingInformation> bindings = null;
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
string deminifiedMethodName = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Null(deminifiedMethodName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_NullSourceMap_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<BindingInformation> bindings = null;
|
||||
SourceMap sourceMap = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>(() => SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_EmptyBinding_ReturnNullMethodName()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<BindingInformation> bindings = new List<BindingInformation>();
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
|
||||
// Act
|
||||
string result = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_HasSingleBindingNoMatchingMapping_ReturnNullMethodName()
|
||||
{
|
||||
// Arrange
|
||||
List<BindingInformation> bindings = new List<BindingInformation>()
|
||||
{
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 20, zeroBasedColumnNumber: 15))
|
||||
};
|
||||
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
sourceMap.Stub(x => x.GetMappingEntryForGeneratedSourcePosition(Arg<SourcePosition>.Is.Anything)).Return(null);
|
||||
|
||||
// Act
|
||||
string result = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_HasSingleBindingMatchingMapping_ReturnsMethodName()
|
||||
{
|
||||
// Arrange
|
||||
List<BindingInformation> bindings = new List<BindingInformation>()
|
||||
{
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 5, zeroBasedColumnNumber: 8))
|
||||
};
|
||||
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 8)))
|
||||
.Return(new MappingEntry(generatedSourcePosition: default, originalName: "foo"));
|
||||
|
||||
// Act
|
||||
string result = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_MatchingMappingMultipleBindingsMissingPrototypeMapping_ReturnsMethodName()
|
||||
{
|
||||
// Arrange
|
||||
List<BindingInformation> bindings = new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 86, zeroBasedColumnNumber: 52)),
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 88, zeroBasedColumnNumber: 78))
|
||||
};
|
||||
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 86 && y.ZeroBasedColumnNumber == 52)))
|
||||
.Return(null);
|
||||
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 88 && y.ZeroBasedColumnNumber == 78)))
|
||||
.Return(new MappingEntry(generatedSourcePosition: default, originalName: "baz"));
|
||||
|
||||
// Act
|
||||
string result = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("baz", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDeminifiedMethodName_MatchingMappingMultipleBindings_ReturnsMethodNameWithFullBinding()
|
||||
{
|
||||
// Arrange
|
||||
List<BindingInformation> bindings = new List<BindingInformation>
|
||||
{
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 5, zeroBasedColumnNumber: 5)),
|
||||
new BindingInformation(
|
||||
name: default,
|
||||
sourcePosition: new SourcePosition(zeroBasedLineNumber: 20, zeroBasedColumnNumber: 10))
|
||||
};
|
||||
|
||||
SourceMap sourceMap = CreateSourceMapMock();
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 5 && y.ZeroBasedColumnNumber == 5)))
|
||||
.Return(new MappingEntry(generatedSourcePosition: default, originalName: "bar"));
|
||||
|
||||
sourceMap.Stub(
|
||||
x =>
|
||||
x.GetMappingEntryForGeneratedSourcePosition(
|
||||
Arg<SourcePosition>.Matches(y => y.ZeroBasedLineNumber == 20 && y.ZeroBasedColumnNumber == 10)))
|
||||
.Return(new MappingEntry(generatedSourcePosition: default, originalName: "baz"));
|
||||
|
||||
// Act
|
||||
string result = SourceMapExtensions.GetDeminifiedMethodName(sourceMap, bindings);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar.baz", result);
|
||||
sourceMap.VerifyAllExpectations();
|
||||
}
|
||||
|
||||
private static SourceMap CreateSourceMapMock()
|
||||
{
|
||||
return MockRepository.GenerateStub<SourceMap>(
|
||||
0 /* version */,
|
||||
default(string) /* file */,
|
||||
default(string) /* mappings */,
|
||||
default(IReadOnlyList<string>) /* sources */,
|
||||
default(IReadOnlyList<string>) /* names */,
|
||||
default(IReadOnlyList<MappingEntry>) /* parsedMappings */,
|
||||
default(IReadOnlyList<string>) /* sourcesContent */);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@
|
|||
<Compile Include="FunctionMapConsumerUnitTests.cs" />
|
||||
<Compile Include="FunctionMapGeneratorUnitTests.cs" />
|
||||
<Compile Include="KeyValueCacheUnitTests.cs" />
|
||||
<Compile Include="SourceMapExtensionsUnitTests.cs" />
|
||||
<Compile Include="StackFrameDeminifierUnitTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierClosureEndToEndTests.cs" />
|
||||
<Compile Include="StackTraceDeminifierMapOnlyEndToEndTests.cs" />
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using Xunit;
|
||||
using Rhino.Mocks;
|
||||
using SourcemapToolkit.SourcemapParser;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
||||
|
@ -45,7 +46,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
StackFrame stackFrame = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>( ()=> stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null));
|
||||
Assert.Throws<ArgumentNullException>(() => stackFrameDeminifier.DeminifyStackFrame(stackFrame, callerSymbolName: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -60,7 +61,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
// Assert
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Assert
|
||||
Assert.Equal(DeminificationError.NoSourceCodeProvided, stackFrameDeminification.DeminificationError);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
// Assert
|
||||
Assert.Equal(DeminificationError.NoWrapingFunctionFound, stackFrameDeminification.DeminificationError);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -116,7 +117,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
string filePath = "foo";
|
||||
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry {DeminfifiedMethodName = "DeminifiedFoo"};
|
||||
FunctionMapEntry wrapingFunctionMapEntry = CreateFunctionMapEntry(deminifiedMethodName: "DeminifiedFoo");
|
||||
StackFrame stackFrame = new StackFrame { FilePath = filePath };
|
||||
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
|
||||
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
|
||||
|
@ -132,8 +133,8 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.None, stackFrameDeminification.DeminificationError);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
string filePath = "foo";
|
||||
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
|
||||
FunctionMapEntry wrapingFunctionMapEntry = CreateFunctionMapEntry(deminifiedMethodName: "DeminifiedFoo");
|
||||
StackFrame stackFrame = new StackFrame { FilePath = filePath };
|
||||
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
|
||||
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
|
||||
|
@ -159,8 +160,8 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoSourceMap, stackFrameDeminification.DeminificationError);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -169,7 +170,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
string filePath = "foo";
|
||||
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
|
||||
FunctionMapEntry wrapingFunctionMapEntry = CreateFunctionMapEntry(deminifiedMethodName: "DeminifiedFoo");
|
||||
StackFrame stackFrame = new StackFrame { FilePath = filePath };
|
||||
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
|
||||
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
|
||||
|
@ -178,7 +179,7 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
functionMapConsumer.Stub(c => c.GetWrappingFunctionForSourceLocation(Arg<SourcePosition>.Is.Anything, Arg<List<FunctionMapEntry>>.Is.Anything))
|
||||
.Return(wrapingFunctionMapEntry);
|
||||
ISourceMapStore sourceMapStore = MockRepository.GenerateStub<ISourceMapStore>();
|
||||
sourceMapStore.Stub(c => c.GetSourceMapForUrl(Arg<string>.Is.Anything)).Return(new SourceMap());
|
||||
sourceMapStore.Stub(c => c.GetSourceMapForUrl(Arg<string>.Is.Anything)).Return(CreateSourceMap());
|
||||
|
||||
IStackFrameDeminifier stackFrameDeminifier = GetStackFrameDeminifierWithMockDependencies(sourceMapStore: sourceMapStore,functionMapStore: functionMapStore, functionMapConsumer: functionMapConsumer);
|
||||
|
||||
|
@ -187,8 +188,8 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.SourceMapFailedToParse, stackFrameDeminification.DeminificationError);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
|
@ -197,13 +198,13 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
string filePath = "foo";
|
||||
FunctionMapEntry wrapingFunctionMapEntry = new FunctionMapEntry { DeminfifiedMethodName = "DeminifiedFoo" };
|
||||
FunctionMapEntry wrapingFunctionMapEntry = CreateFunctionMapEntry(deminifiedMethodName: "DeminifiedFoo");
|
||||
StackFrame stackFrame = new StackFrame { FilePath = filePath };
|
||||
IFunctionMapStore functionMapStore = MockRepository.GenerateStub<IFunctionMapStore>();
|
||||
functionMapStore.Stub(c => c.GetFunctionMapForSourceCode(filePath))
|
||||
.Return(new List<FunctionMapEntry>());
|
||||
ISourceMapStore sourceMapStore = MockRepository.GenerateStub<ISourceMapStore>();
|
||||
SourceMap sourceMap = new SourceMap() {ParsedMappings = new List<MappingEntry>()};
|
||||
SourceMap sourceMap = CreateSourceMap(parsedMappings: new List<MappingEntry>());
|
||||
|
||||
sourceMapStore.Stub(c => c.GetSourceMapForUrl(Arg<string>.Is.Anything)).Return(sourceMap);
|
||||
IFunctionMapConsumer functionMapConsumer = MockRepository.GenerateStub<IFunctionMapConsumer>();
|
||||
|
@ -217,10 +218,30 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
|
||||
// Assert
|
||||
Assert.Equal(DeminificationError.NoMatchingMapingInSourceMap, stackFrameDeminification.DeminificationError);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminfifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Equal(wrapingFunctionMapEntry.DeminifiedMethodName, stackFrameDeminification.DeminifiedStackFrame.MethodName);
|
||||
Assert.Equal(SourcePosition.NotFound, stackFrameDeminification.DeminifiedStackFrame.SourcePosition);
|
||||
Assert.Null(stackFrameDeminification.DeminifiedStackFrame.FilePath);
|
||||
}
|
||||
|
||||
private static FunctionMapEntry CreateFunctionMapEntry(string deminifiedMethodName)
|
||||
{
|
||||
return new FunctionMapEntry(
|
||||
bindings: default,
|
||||
deminifiedMethodName,
|
||||
startSourcePosition: default,
|
||||
endSourcePosition: default);
|
||||
}
|
||||
|
||||
private static SourceMap CreateSourceMap(List<MappingEntry> parsedMappings = default)
|
||||
{
|
||||
return new SourceMap(
|
||||
version: default,
|
||||
file: default,
|
||||
mappings: default,
|
||||
sources: default,
|
||||
names: default,
|
||||
parsedMappings: parsedMappings,
|
||||
sourcesContent: default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ namespace SourcemapToolkit.CallstackDeminifier.UnitTests
|
|||
at HTMLButtonElement.<anonymous> (http://localhost:19220/crashcauser.min.js:1:332)";
|
||||
|
||||
// Act
|
||||
List<StackFrame> stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
var stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(stackTrace.Count, 4);
|
||||
Assert.Equal(4, stackTrace.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -47,10 +47,10 @@ b@http://localhost:19220/crashcauser.min.js:1:14
|
|||
window.onload/<@http://localhost:19220/crashcauser.min.js:1:332";
|
||||
|
||||
// Act
|
||||
List<StackFrame> stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
var stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(stackTrace.Count, 4);
|
||||
Assert.Equal(4, stackTrace.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -64,10 +64,10 @@ window.onload/<@http://localhost:19220/crashcauser.min.js:1:332";
|
|||
at b (http://localhost:19220/crashcauser.min.js:1:14)";
|
||||
|
||||
// Act
|
||||
List<StackFrame> stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
var stackTrace = stackTraceParser.ParseStackTrace(browserStackTrace);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(stackTrace.Count, 3);
|
||||
Assert.Equal(3, stackTrace.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -78,7 +78,7 @@ window.onload/<@http://localhost:19220/crashcauser.min.js:1:332";
|
|||
string frame = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>( ()=> stackTraceParser.TryParseSingleStackFrame(frame));
|
||||
Assert.Throws<ArgumentNullException>(() => stackTraceParser.TryParseSingleStackFrame(frame));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser.UnitTests
|
||||
{
|
||||
public class IReadOnlyListExtensionsUnitTests
|
||||
{
|
||||
[Fact]
|
||||
public void IndexOf_NullList_ThrowsNullReferenceException()
|
||||
{
|
||||
// Arrange, Act, and Assert
|
||||
Assert.Throws<NullReferenceException>(() => IReadOnlyListExtensions.IndexOf(null, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndexOf_ValueInList_CorrectlyReturnsIndex()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<int> list = new[] { 6, 4, 1, 8 };
|
||||
|
||||
// Act
|
||||
int index = IReadOnlyListExtensions.IndexOf(list, 1);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndexOf_ValueNotInList_CorrectlyReturnsNegativeOne()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<int> list = new[] { 2, 4, 6, 8 };
|
||||
|
||||
// Act
|
||||
int index = IReadOnlyListExtensions.IndexOf(list, 1);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(-1, index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndexOf_ValueAppearsMultipleTimes_CorrectlyReturnsFirstInstance()
|
||||
{
|
||||
// Arrange
|
||||
IReadOnlyList<int> list = new[] { 2, 4, 6, 8, 4 };
|
||||
|
||||
// Act
|
||||
int index = IReadOnlyListExtensions.IndexOf(list, 4);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BinarySearch_NullList_ThrowsNullReferenceException()
|
||||
{
|
||||
// Arrange
|
||||
Comparer<int> comparer = Comparer<int>.Default;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<NullReferenceException>(() => IReadOnlyListExtensions.BinarySearch(null, 1, comparer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BinarySearch_EvenNumberOfElements_CorrectlyMatchesListImplementation()
|
||||
{
|
||||
// Arrange
|
||||
// 6 elements total
|
||||
const int minFillIndexInclusive = 1;
|
||||
const int maxFillIndexInclusive = 4;
|
||||
|
||||
Comparer<int> comparer = Comparer<int>.Default;
|
||||
List<int> list = new List<int>();
|
||||
|
||||
for (int i = minFillIndexInclusive; i <= maxFillIndexInclusive; i++)
|
||||
{
|
||||
list.Add(2 * i); // multiplying each entry by 2 to make sure there are gaps
|
||||
}
|
||||
|
||||
// Act & Assert
|
||||
for (int i = minFillIndexInclusive - 1; i <= maxFillIndexInclusive + 1; i++)
|
||||
{
|
||||
Assert.Equal(list.BinarySearch(i, comparer), IReadOnlyListExtensions.BinarySearch(list, i, comparer));
|
||||
Assert.Equal(list.BinarySearch(i + 1, comparer), IReadOnlyListExtensions.BinarySearch(list, i + 1, comparer));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BinarySearch_OddNumberOfElements_CorrectlyMatchesListImplementation()
|
||||
{
|
||||
// Arrange
|
||||
// 6 elements total
|
||||
const int minFillIndexInclusive = 1;
|
||||
const int maxFillIndexInclusive = 5;
|
||||
|
||||
Comparer<int> comparer = Comparer<int>.Default;
|
||||
List<int> list = new List<int>();
|
||||
|
||||
for (int i = minFillIndexInclusive; i <= maxFillIndexInclusive; i++)
|
||||
{
|
||||
list.Add(2 * i); // multiplying each entry by 2 to make sure there are gaps
|
||||
}
|
||||
|
||||
// Act & Assert
|
||||
for (int i = minFillIndexInclusive - 1; i <= maxFillIndexInclusive + 1; i++)
|
||||
{
|
||||
Assert.Equal(list.BinarySearch(i, comparer), IReadOnlyListExtensions.BinarySearch(list, i, comparer));
|
||||
Assert.Equal(list.BinarySearch(i + 1, comparer), IReadOnlyListExtensions.BinarySearch(list, i + 1, comparer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
// Assert
|
||||
Assert.Equal(12, mappingEntry.GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(13, mappingEntry.GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Null(mappingEntry.OriginalSourcePosition);
|
||||
Assert.Equal(SourcePosition.NotFound, mappingEntry.OriginalSourcePosition);
|
||||
Assert.Null(mappingEntry.OriginalFileName);
|
||||
Assert.Null(mappingEntry.OriginalName);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
// Assert
|
||||
Assert.Equal(8, mappingEntry.GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(48, mappingEntry.GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Null(mappingEntry.OriginalSourcePosition);
|
||||
Assert.Equal(SourcePosition.NotFound, mappingEntry.OriginalSourcePosition);
|
||||
Assert.Equal("three", mappingEntry.OriginalFileName);
|
||||
Assert.Equal("bar", mappingEntry.OriginalName);
|
||||
}
|
||||
|
|
|
@ -15,15 +15,13 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
state.LastGeneratedPosition.ZeroBasedColumnNumber = 1;
|
||||
state.UpdateLastGeneratedPositionColumn(zeroBasedColumnNumber: 1);
|
||||
|
||||
MappingEntry entry = new MappingEntry()
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 0 },
|
||||
OriginalFileName = state.Sources[0],
|
||||
OriginalName = state.Names[0],
|
||||
OriginalSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 0 },
|
||||
};
|
||||
MappingEntry entry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 0),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 0),
|
||||
originalName: state.Names[0],
|
||||
originalFileName: state.Sources[0]);
|
||||
|
||||
// Act
|
||||
var result = new StringBuilder();
|
||||
|
@ -41,11 +39,9 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
|
||||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
|
||||
MappingEntry entry = new MappingEntry()
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 10 },
|
||||
OriginalSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 1 },
|
||||
};
|
||||
MappingEntry entry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 10),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 1));
|
||||
|
||||
// Act
|
||||
var result = new StringBuilder();
|
||||
|
@ -64,12 +60,10 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
state.IsFirstSegment = false;
|
||||
|
||||
MappingEntry entry = new MappingEntry()
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() { ZeroBasedColumnNumber = 10 },
|
||||
OriginalFileName = state.Sources[0],
|
||||
OriginalSourcePosition = new SourcePosition() { ZeroBasedColumnNumber = 5 },
|
||||
};
|
||||
MappingEntry entry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 10),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 5),
|
||||
originalFileName: state.Sources[0]);
|
||||
|
||||
// Act
|
||||
var result = new StringBuilder();
|
||||
|
@ -86,15 +80,13 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
state.LastGeneratedPosition.ZeroBasedLineNumber = 1;
|
||||
state.AdvanceLastGeneratedPositionLine();
|
||||
|
||||
MappingEntry entry = new MappingEntry()
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 5 },
|
||||
OriginalSourcePosition = new SourcePosition() { ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 6 },
|
||||
OriginalFileName = state.Sources[0],
|
||||
OriginalName = state.Names[0],
|
||||
};
|
||||
MappingEntry entry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 5),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 6),
|
||||
originalName: state.Names[0],
|
||||
originalFileName: state.Sources[0]);
|
||||
|
||||
// Act
|
||||
var result = new StringBuilder();
|
||||
|
@ -120,73 +112,72 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = this.GetSimpleSourceMap();
|
||||
SourceMap input = this.GetSimpleSourceMap();
|
||||
|
||||
// Act
|
||||
string output = sourceMapGenerator.SerializeMapping(input);
|
||||
// Act
|
||||
string output = sourceMapGenerator.SerializeMapping(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("{\"version\":3,\"file\":\"CommonIntl\",\"mappings\":\"AACAA,aAAA,CAAc;\",\"sources\":[\"input/CommonIntl.js\"],\"names\":[\"CommonStrings\",\"afrikaans\"]}", output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializeMappingIntoBast64_NullInput_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = null;
|
||||
[Fact]
|
||||
public void SerializeMappingIntoBast64_NullInput_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = null;
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>(() => sourceMapGenerator.GenerateSourceMapInlineComment(input));
|
||||
}
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>(() => sourceMapGenerator.GenerateSourceMapInlineComment(input));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializeMappingBase64_SimpleSourceMap_CorrectlySerialized()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = this.GetSimpleSourceMap();
|
||||
[Fact]
|
||||
public void SerializeMappingBase64_SimpleSourceMap_CorrectlySerialized()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = this.GetSimpleSourceMap();
|
||||
|
||||
// Act
|
||||
string output = sourceMapGenerator.GenerateSourceMapInlineComment(input);
|
||||
// Act
|
||||
string output = sourceMapGenerator.GenerateSourceMapInlineComment(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tbW9uSW50bCIsIm1hcHBpbmdzIjoiQUFDQUEsYUFBQSxDQUFjOyIsInNvdXJjZXMiOlsiaW5wdXQvQ29tbW9uSW50bC5qcyJdLCJuYW1lcyI6WyJDb21tb25TdHJpbmdzIiwiYWZyaWthYW5zIl19", output);
|
||||
}
|
||||
// Assert
|
||||
Assert.Equal("//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tbW9uSW50bCIsIm1hcHBpbmdzIjoiQUFDQUEsYUFBQSxDQUFjOyIsInNvdXJjZXMiOlsiaW5wdXQvQ29tbW9uSW50bC5qcyJdLCJuYW1lcyI6WyJDb21tb25TdHJpbmdzIiwiYWZyaWthYW5zIl19", output);
|
||||
}
|
||||
|
||||
private SourceMap GetSimpleSourceMap()
|
||||
{
|
||||
SourceMap input = new SourceMap()
|
||||
{
|
||||
File = "CommonIntl",
|
||||
Names = new List<string>() { "CommonStrings", "afrikaans" },
|
||||
Sources = new List<string>() { "input/CommonIntl.js" },
|
||||
Version = 3,
|
||||
};
|
||||
input.ParsedMappings = new List<MappingEntry>()
|
||||
{
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 0 },
|
||||
OriginalFileName = input.Sources[0],
|
||||
OriginalName = input.Names[0],
|
||||
OriginalSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 0 },
|
||||
},
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 13 },
|
||||
OriginalFileName = input.Sources[0],
|
||||
OriginalSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 0 },
|
||||
},
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 14 },
|
||||
OriginalFileName = input.Sources[0],
|
||||
OriginalSourcePosition = new SourcePosition() {ZeroBasedLineNumber = 1, ZeroBasedColumnNumber = 14 },
|
||||
},
|
||||
};
|
||||
private SourceMap GetSimpleSourceMap()
|
||||
{
|
||||
List<string> sources = new List<string>() { "input/CommonIntl.js" };
|
||||
List<string> names = new List<string>() { "CommonStrings", "afrikaans" };
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
var parsedMappings = new List<MappingEntry>()
|
||||
{
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 0),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 0),
|
||||
originalName: names[0],
|
||||
originalFileName: sources[0]),
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 13),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 0),
|
||||
originalFileName: sources[0]),
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 14),
|
||||
originalSourcePosition: new SourcePosition(zeroBasedLineNumber: 1, zeroBasedColumnNumber: 14),
|
||||
originalFileName: sources[0]),
|
||||
};
|
||||
|
||||
SourceMap input = new SourceMap(
|
||||
version: 3,
|
||||
file: "CommonIntl",
|
||||
mappings: default,
|
||||
sources: sources,
|
||||
names: names,
|
||||
parsedMappings: parsedMappings,
|
||||
sourcesContent: default);
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
Assert.Equal(3, output.Version);
|
||||
Assert.Equal("CommonIntl", output.File);
|
||||
Assert.Equal("AACAA,aAAA,CAAc", output.Mappings);
|
||||
Assert.Equal(1, output.Sources.Count);
|
||||
Assert.Single(output.Sources);
|
||||
Assert.Equal("input/CommonIntl.js", output.Sources[0]);
|
||||
Assert.Equal(2, output.Names.Count);
|
||||
Assert.Equal("CommonStrings", output.Names[0]);
|
||||
|
|
|
@ -4,108 +4,111 @@ using Xunit;
|
|||
|
||||
namespace SourcemapToolkit.SourcemapParser.UnitTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for SourceMapTransformerUnitTests
|
||||
/// </summary>
|
||||
public class SourceMapTransformerUnitTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for SourceMapTransformerUnitTests
|
||||
/// </summary>
|
||||
public class SourceMapTransformerUnitTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public void FlattenMap_ReturnsOnlyLineInformation()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
[Fact]
|
||||
public void FlattenMap_ReturnsOnlyLineInformation()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
|
||||
SourceMap map = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mappingEntry },
|
||||
SourcesContent = new List<string>{"var a = b"}
|
||||
};
|
||||
SourceMap map = new SourceMap(
|
||||
version: default,
|
||||
file: "generated.js",
|
||||
mappings: default,
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
names: default,
|
||||
parsedMappings: new List<MappingEntry> { mappingEntry },
|
||||
sourcesContent: new List<string> { "var a = b" });
|
||||
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Equal(1, linesOnlyMap.Sources.Count);
|
||||
Assert.Equal(1, linesOnlyMap.SourcesContent.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Single(linesOnlyMap.Sources);
|
||||
Assert.Single(linesOnlyMap.SourcesContent);
|
||||
Assert.Single(linesOnlyMap.ParsedMappings);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FlattenMap_MultipleMappingsSameLine_ReturnsOnlyOneMappingPerLine()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
[Fact]
|
||||
public void FlattenMap_MultipleMappingsSameLine_ReturnsOnlyOneMappingPerLine()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 5);
|
||||
MappingEntry mappingEntry2 = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 5);
|
||||
MappingEntry mappingEntry2 = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap map = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mappingEntry, mappingEntry2 },
|
||||
SourcesContent = new List<string>{"var a = b"}
|
||||
};
|
||||
SourceMap map = new SourceMap(
|
||||
version: default,
|
||||
file: "generated.js",
|
||||
mappings: default,
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
names: default,
|
||||
parsedMappings: new List<MappingEntry> { mappingEntry, mappingEntry2 },
|
||||
sourcesContent: new List<string> { "var a = b" });
|
||||
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Equal(1, linesOnlyMap.Sources.Count);
|
||||
Assert.Equal(1, linesOnlyMap.SourcesContent.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Single(linesOnlyMap.Sources);
|
||||
Assert.Single(linesOnlyMap.SourcesContent);
|
||||
Assert.Single(linesOnlyMap.ParsedMappings);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FlattenMap_MultipleOriginalLineToSameGeneratedLine_ReturnsFirstOriginalLine()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
[Fact]
|
||||
public void FlattenMap_MultipleOriginalLineToSameGeneratedLine_ReturnsFirstOriginalLine()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceOne.js");
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 3);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
MappingEntry mappingEntry2 = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 3);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
MappingEntry mappingEntry2 = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap map = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mappingEntry, mappingEntry2 },
|
||||
SourcesContent = new List<string>{"var a = b"}
|
||||
};
|
||||
SourceMap map = new SourceMap(
|
||||
version: default,
|
||||
file: "generated.js",
|
||||
mappings: default,
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
names: default,
|
||||
parsedMappings: new List<MappingEntry> { mappingEntry, mappingEntry2 },
|
||||
sourcesContent: new List<string> { "var a = b" });
|
||||
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
// Act
|
||||
SourceMap linesOnlyMap = SourceMapTransformer.Flatten(map);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Equal(1, linesOnlyMap.Sources.Count);
|
||||
Assert.Equal(1, linesOnlyMap.SourcesContent.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings.Count);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
}
|
||||
// Assert
|
||||
Assert.NotNull(linesOnlyMap);
|
||||
Assert.Single(linesOnlyMap.Sources);
|
||||
Assert.Single(linesOnlyMap.SourcesContent);
|
||||
Assert.Single(linesOnlyMap.ParsedMappings);
|
||||
Assert.Equal(1, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].GeneratedSourcePosition.ZeroBasedColumnNumber);
|
||||
Assert.Equal(2, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedLineNumber);
|
||||
Assert.Equal(0, linesOnlyMap.ParsedMappings[0].OriginalSourcePosition.ZeroBasedColumnNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GetMappingEntryForGeneratedSourcePosition_NullMappingList_ReturnNull()
|
||||
{
|
||||
// Arrange
|
||||
SourceMap sourceMap = new SourceMap();
|
||||
SourcePosition sourcePosition = new SourcePosition {ZeroBasedColumnNumber = 3, ZeroBasedLineNumber = 4};
|
||||
SourceMap sourceMap = CreateSourceMap();
|
||||
SourcePosition sourcePosition = new SourcePosition(zeroBasedLineNumber: 4, zeroBasedColumnNumber: 3);
|
||||
|
||||
// Act
|
||||
MappingEntry result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
MappingEntry? result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
|
||||
// Asset
|
||||
Assert.Null(result);
|
||||
|
@ -25,18 +25,17 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GetMappingEntryForGeneratedSourcePosition_NoMatchingEntryInMappingList_ReturnNull()
|
||||
{
|
||||
// Arrange
|
||||
SourceMap sourceMap = new SourceMap();
|
||||
sourceMap.ParsedMappings = new List<MappingEntry>
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>
|
||||
{
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 0}
|
||||
}
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 0))
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition { ZeroBasedColumnNumber = 3, ZeroBasedLineNumber = 4 };
|
||||
|
||||
SourceMap sourceMap = CreateSourceMap(parsedMappings: parsedMappings);
|
||||
SourcePosition sourcePosition = new SourcePosition(zeroBasedLineNumber: 4, zeroBasedColumnNumber: 3);
|
||||
|
||||
// Act
|
||||
MappingEntry result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
MappingEntry? result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
|
||||
// Asset
|
||||
Assert.Null(result);
|
||||
|
@ -46,23 +45,20 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GetMappingEntryForGeneratedSourcePosition_MatchingEntryInMappingList_ReturnMatchingEntry()
|
||||
{
|
||||
// Arrange
|
||||
SourceMap sourceMap = new SourceMap();
|
||||
MappingEntry matchingMappingEntry = new MappingEntry
|
||||
MappingEntry matchingMappingEntry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 8, zeroBasedColumnNumber: 13));
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition {ZeroBasedLineNumber = 8, ZeroBasedColumnNumber = 13}
|
||||
};
|
||||
sourceMap.ParsedMappings = new List<MappingEntry>
|
||||
{
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 0}
|
||||
},
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 0)),
|
||||
matchingMappingEntry
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition { ZeroBasedLineNumber = 8, ZeroBasedColumnNumber = 13 };
|
||||
|
||||
SourceMap sourceMap = CreateSourceMap(parsedMappings: parsedMappings);
|
||||
SourcePosition sourcePosition = new SourcePosition(zeroBasedLineNumber: 8, zeroBasedColumnNumber: 13);
|
||||
|
||||
// Act
|
||||
MappingEntry result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
MappingEntry? result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
|
||||
// Asset
|
||||
Assert.Equal(matchingMappingEntry, result);
|
||||
|
@ -72,70 +68,60 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GetMappingEntryForGeneratedSourcePosition_NoExactMatchHasSimilarOnSameLine_ReturnSimilarEntry()
|
||||
{
|
||||
// Arrange
|
||||
SourceMap sourceMap = new SourceMap();
|
||||
MappingEntry matchingMappingEntry = new MappingEntry
|
||||
MappingEntry matchingMappingEntry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 10, zeroBasedColumnNumber: 13));
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition { ZeroBasedLineNumber = 10, ZeroBasedColumnNumber = 13 }
|
||||
};
|
||||
sourceMap.ParsedMappings = new List<MappingEntry>
|
||||
{
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 0}
|
||||
},
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 0)),
|
||||
matchingMappingEntry
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition { ZeroBasedLineNumber = 10, ZeroBasedColumnNumber = 14 };
|
||||
SourceMap sourceMap = CreateSourceMap(parsedMappings: parsedMappings);
|
||||
SourcePosition sourcePosition = new SourcePosition(zeroBasedLineNumber: 10, zeroBasedColumnNumber: 14);
|
||||
|
||||
// Act
|
||||
MappingEntry result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
MappingEntry? result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
|
||||
// Asset
|
||||
Assert.Equal(matchingMappingEntry, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMappingEntryForGeneratedSourcePosition_NoExactMatchHasSimilarOnDifferentLinesLine_ReturnSimilarEntry()
|
||||
{
|
||||
// Arrange
|
||||
SourceMap sourceMap = new SourceMap();
|
||||
MappingEntry matchingMappingEntry = new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition { ZeroBasedLineNumber = 23, ZeroBasedColumnNumber = 15 }
|
||||
};
|
||||
sourceMap.ParsedMappings = new List<MappingEntry>
|
||||
{
|
||||
new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = new SourcePosition {ZeroBasedLineNumber = 0, ZeroBasedColumnNumber = 0}
|
||||
},
|
||||
matchingMappingEntry
|
||||
};
|
||||
SourcePosition sourcePosition = new SourcePosition { ZeroBasedLineNumber = 24, ZeroBasedColumnNumber = 0 };
|
||||
[Fact]
|
||||
public void GetMappingEntryForGeneratedSourcePosition_NoExactMatchHasSimilarOnDifferentLinesLine_ReturnSimilarEntry()
|
||||
{
|
||||
// Arrange
|
||||
MappingEntry matchingMappingEntry = new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 23, zeroBasedColumnNumber: 15));
|
||||
List<MappingEntry> parsedMappings = new List<MappingEntry>
|
||||
{
|
||||
new MappingEntry(
|
||||
generatedSourcePosition: new SourcePosition(zeroBasedLineNumber: 0, zeroBasedColumnNumber: 0)),
|
||||
matchingMappingEntry
|
||||
};
|
||||
SourceMap sourceMap = CreateSourceMap(parsedMappings: parsedMappings);
|
||||
SourcePosition sourcePosition = new SourcePosition(zeroBasedLineNumber: 24, zeroBasedColumnNumber: 0);
|
||||
|
||||
// Act
|
||||
MappingEntry result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
// Act
|
||||
MappingEntry? result = sourceMap.GetMappingEntryForGeneratedSourcePosition(sourcePosition);
|
||||
|
||||
// Asset
|
||||
Assert.Equal(matchingMappingEntry, result);
|
||||
}
|
||||
// Asset
|
||||
Assert.Equal(matchingMappingEntry, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetRootMappingEntryForGeneratedSourcePosition_NoChildren_ReturnsSameEntry()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 5);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber:1, colNumber: 5);
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 5);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 5);
|
||||
MappingEntry mappingEntry = UnitTestUtils.getSimpleEntry(generated1, original1, "generated.js");
|
||||
|
||||
SourceMap sourceMap = new SourceMap
|
||||
{
|
||||
Sources = new List<string> { "generated.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mappingEntry }
|
||||
};
|
||||
SourceMap sourceMap = CreateSourceMap(
|
||||
sources: new List<string>() { "generated.js" },
|
||||
parsedMappings: new List<MappingEntry> { mappingEntry });
|
||||
|
||||
// Act
|
||||
MappingEntry rootEntry = sourceMap.GetMappingEntryForGeneratedSourcePosition(generated1);
|
||||
MappingEntry? rootEntry = sourceMap.GetMappingEntryForGeneratedSourcePosition(generated1);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(rootEntry, mappingEntry);
|
||||
|
@ -145,16 +131,14 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void ApplyMap_NullSubmap_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 5);
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 5);
|
||||
MappingEntry mapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap map = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mapping }
|
||||
};
|
||||
SourceMap map = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
parsedMappings: new List<MappingEntry> { mapping });
|
||||
|
||||
// Act
|
||||
Assert.Throws<ArgumentNullException>(() => map.ApplySourceMap(null));
|
||||
|
@ -166,27 +150,23 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void ApplyMap_NoMatchingSources_ReturnsSameMap()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 3);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber:1, colNumber: 2);
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 3);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 2);
|
||||
MappingEntry childMapping = UnitTestUtils.getSimpleEntry(generated1, original1, "someOtherSource.js");
|
||||
|
||||
SourceMap childMap = new SourceMap
|
||||
{
|
||||
File = "notSourceOne.js",
|
||||
Sources = new List<string> { "someOtherSource.js" },
|
||||
ParsedMappings = new List<MappingEntry> { childMapping }
|
||||
};
|
||||
SourceMap childMap = CreateSourceMap(
|
||||
file: "notSourceOne.js",
|
||||
sources: new List<string>() { "someOtherSource.js" },
|
||||
parsedMappings: new List<MappingEntry> { childMapping });
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber: 7);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 3);
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 7);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 3);
|
||||
MappingEntry parentMapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap parentMap = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { parentMapping }
|
||||
};
|
||||
SourceMap parentMap = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
parsedMappings: new List<MappingEntry> { parentMapping });
|
||||
|
||||
// Act
|
||||
SourceMap combinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
@ -194,115 +174,103 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
// Assert
|
||||
Assert.NotNull(combinedMap);
|
||||
MappingEntry firstMapping = combinedMap.ParsedMappings[0];
|
||||
Assert.True(firstMapping.IsValueEqual(parentMapping));
|
||||
Assert.True(firstMapping.Equals(parentMapping));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyMap_NoMatchingMappings_ReturnsSameMap()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber:2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber:10);
|
||||
MappingEntry childMapping = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceTwo.js");
|
||||
|
||||
SourceMap childMap = new SourceMap
|
||||
{
|
||||
File = "sourceOne.js",
|
||||
Sources = new List<string> { "sourceTwo.js" },
|
||||
ParsedMappings = new List<MappingEntry> { childMapping }
|
||||
};
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber:4);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber:5);
|
||||
MappingEntry parentMapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap parentMap = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { parentMapping }
|
||||
};
|
||||
|
||||
// Act
|
||||
SourceMap combinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(combinedMap);
|
||||
MappingEntry firstMapping = combinedMap.ParsedMappings[0];
|
||||
Assert.True(firstMapping.IsValueEqual(parentMapping));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyMap_MatchingSources_ReturnsCorrectMap()
|
||||
[Fact]
|
||||
public void ApplyMap_NoMatchingMappings_ReturnsSameMap()
|
||||
{
|
||||
// Expect mapping with same source filename as the applied source-map to be replaced
|
||||
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber:4);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber:1, colNumber:3);
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 2);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 10);
|
||||
MappingEntry childMapping = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceTwo.js");
|
||||
|
||||
SourceMap childMap = new SourceMap
|
||||
{
|
||||
File = "sourceOne.js",
|
||||
Sources = new List<string> { "sourceTwo.js" },
|
||||
ParsedMappings = new List<MappingEntry> { childMapping }
|
||||
};
|
||||
SourceMap childMap = CreateSourceMap(
|
||||
file: "sourceOne.js",
|
||||
sources: new List<string>() { "sourceTwo.js" },
|
||||
parsedMappings: new List<MappingEntry> { childMapping });
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 4);
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 4);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 5);
|
||||
MappingEntry parentMapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap parentMap = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { parentMapping }
|
||||
};
|
||||
SourceMap parentMap = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
parsedMappings: new List<MappingEntry> { parentMapping });
|
||||
|
||||
// Act
|
||||
SourceMap combinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(combinedMap);
|
||||
Assert.Equal(1, combinedMap.ParsedMappings.Count);
|
||||
Assert.Equal(1, combinedMap.Sources.Count);
|
||||
MappingEntry rootMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated2);
|
||||
Assert.Equal(0, rootMapping.OriginalSourcePosition.CompareTo(childMapping.OriginalSourcePosition));
|
||||
MappingEntry firstMapping = combinedMap.ParsedMappings[0];
|
||||
Assert.True(firstMapping.Equals(parentMapping));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyMap_MatchingSources_ReturnsCorrectMap()
|
||||
{
|
||||
// Expect mapping with same source filename as the applied source-map to be replaced
|
||||
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 4);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 3);
|
||||
MappingEntry childMapping = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceTwo.js");
|
||||
|
||||
SourceMap childMap = CreateSourceMap(
|
||||
file: "sourceOne.js",
|
||||
sources: new List<string>() { "sourceTwo.js" },
|
||||
parsedMappings: new List<MappingEntry> { childMapping });
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 4);
|
||||
MappingEntry parentMapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourceMap parentMap = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
parsedMappings: new List<MappingEntry> { parentMapping });
|
||||
|
||||
// Act
|
||||
SourceMap combinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(combinedMap);
|
||||
Assert.Single(combinedMap.ParsedMappings);
|
||||
Assert.Single(combinedMap.Sources);
|
||||
MappingEntry? rootMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated2);
|
||||
Assert.Equal(0, rootMapping.Value.OriginalSourcePosition.CompareTo(childMapping.OriginalSourcePosition));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyMap_PartialMatchingSources_ReturnsCorrectMap()
|
||||
{
|
||||
// Expect mappings with same source filename as the applied source-map to be replaced
|
||||
// mappings with a different source filename should stay the same
|
||||
// Expect mappings with same source filename as the applied source-map to be replaced
|
||||
// mappings with a different source filename should stay the same
|
||||
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber:10);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber:1, colNumber:5);
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 10);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 1, colNumber: 5);
|
||||
MappingEntry childMapping = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceTwo.js");
|
||||
|
||||
SourceMap childMap = new SourceMap
|
||||
{
|
||||
File = "sourceOne.js",
|
||||
Sources = new List<string> { "sourceTwo.js" },
|
||||
ParsedMappings = new List<MappingEntry> { childMapping }
|
||||
};
|
||||
SourceMap childMap = CreateSourceMap(
|
||||
file: "sourceOne.js",
|
||||
sources: new List<string>() { "sourceTwo.js" },
|
||||
parsedMappings: new List<MappingEntry> { childMapping });
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber:2);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber: 10);
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 2);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 10);
|
||||
MappingEntry mapping = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceOne.js");
|
||||
|
||||
SourcePosition generated3 = UnitTestUtils.generateSourcePosition(lineNumber:4, colNumber:3);
|
||||
SourcePosition original3 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber:2);
|
||||
SourcePosition generated3 = UnitTestUtils.generateSourcePosition(lineNumber: 4, colNumber: 3);
|
||||
SourcePosition original3 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 2);
|
||||
MappingEntry mapping2 = UnitTestUtils.getSimpleEntry(generated3, original3, "noMapForThis.js");
|
||||
|
||||
SourceMap parentMap = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js", "noMapForThis.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mapping, mapping2 }
|
||||
};
|
||||
SourceMap parentMap = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string> { "sourceOne.js", "noMapForThis.js" },
|
||||
parsedMappings: new List<MappingEntry> { mapping, mapping2 });
|
||||
|
||||
// Act
|
||||
SourceMap combinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
@ -311,48 +279,42 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
Assert.NotNull(combinedMap);
|
||||
Assert.Equal(2, combinedMap.ParsedMappings.Count);
|
||||
Assert.Equal(2, combinedMap.Sources.Count);
|
||||
MappingEntry firstCombinedMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated3);
|
||||
Assert.True(firstCombinedMapping.IsValueEqual(mapping2));
|
||||
MappingEntry secondCombinedMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated2);
|
||||
Assert.Equal(0, secondCombinedMapping.OriginalSourcePosition.CompareTo(childMapping.OriginalSourcePosition));
|
||||
MappingEntry? firstCombinedMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated3);
|
||||
Assert.True(firstCombinedMapping.Equals(mapping2));
|
||||
MappingEntry? secondCombinedMapping = combinedMap.GetMappingEntryForGeneratedSourcePosition(generated2);
|
||||
Assert.Equal(0, secondCombinedMapping.Value.OriginalSourcePosition.CompareTo(childMapping.OriginalSourcePosition));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyMap_ExactMatchDeep_ReturnsCorrectMappingEntry()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber:5);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber:2, colNumber:10);
|
||||
SourcePosition generated1 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
SourcePosition original1 = UnitTestUtils.generateSourcePosition(lineNumber: 2, colNumber: 10);
|
||||
MappingEntry mapLevel2 = UnitTestUtils.getSimpleEntry(generated1, original1, "sourceThree.js");
|
||||
|
||||
SourceMap grandChildMap = new SourceMap
|
||||
{
|
||||
File = "sourceTwo.js",
|
||||
Sources = new List<string> { "sourceThree.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mapLevel2 }
|
||||
};
|
||||
SourceMap grandChildMap = CreateSourceMap(
|
||||
file: "sourceTwo.js",
|
||||
sources: new List<string>() { "sourceThree.js" },
|
||||
parsedMappings: new List<MappingEntry> { mapLevel2 });
|
||||
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber:4, colNumber:3);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber:3, colNumber:5);
|
||||
SourcePosition generated2 = UnitTestUtils.generateSourcePosition(lineNumber: 4, colNumber: 3);
|
||||
SourcePosition original2 = UnitTestUtils.generateSourcePosition(lineNumber: 3, colNumber: 5);
|
||||
MappingEntry mapLevel1 = UnitTestUtils.getSimpleEntry(generated2, original2, "sourceTwo.js");
|
||||
|
||||
SourceMap childMap = new SourceMap
|
||||
{
|
||||
File = "sourceOne.js",
|
||||
Sources = new List<string> { "sourceTwo.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mapLevel1 }
|
||||
};
|
||||
SourceMap childMap = CreateSourceMap(
|
||||
file: "sourceOne.js",
|
||||
sources: new List<string>() { "sourceTwo.js" },
|
||||
parsedMappings: new List<MappingEntry> { mapLevel1 });
|
||||
|
||||
SourcePosition generated3 = UnitTestUtils.generateSourcePosition(lineNumber:5, colNumber:5);
|
||||
SourcePosition original3 = UnitTestUtils.generateSourcePosition(lineNumber:4, colNumber:3);
|
||||
SourcePosition generated3 = UnitTestUtils.generateSourcePosition(lineNumber: 5, colNumber: 5);
|
||||
SourcePosition original3 = UnitTestUtils.generateSourcePosition(lineNumber: 4, colNumber: 3);
|
||||
MappingEntry mapLevel0 = UnitTestUtils.getSimpleEntry(generated3, original3, "sourceOne.js");
|
||||
|
||||
SourceMap parentMap = new SourceMap
|
||||
{
|
||||
File = "generated.js",
|
||||
Sources = new List<string> { "sourceOne.js" },
|
||||
ParsedMappings = new List<MappingEntry> { mapLevel0 }
|
||||
};
|
||||
SourceMap parentMap = CreateSourceMap(
|
||||
file: "generated.js",
|
||||
sources: new List<string>() { "sourceOne.js" },
|
||||
parsedMappings: new List<MappingEntry> { mapLevel0 });
|
||||
|
||||
// Act
|
||||
SourceMap firstCombinedMap = parentMap.ApplySourceMap(childMap);
|
||||
|
@ -361,8 +323,27 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
Assert.NotNull(firstCombinedMap);
|
||||
SourceMap secondCombinedMap = firstCombinedMap.ApplySourceMap(grandChildMap);
|
||||
Assert.NotNull(secondCombinedMap);
|
||||
MappingEntry rootMapping = secondCombinedMap.GetMappingEntryForGeneratedSourcePosition(generated3);
|
||||
Assert.Equal(0, rootMapping.OriginalSourcePosition.CompareTo(mapLevel2.OriginalSourcePosition));
|
||||
MappingEntry? rootMapping = secondCombinedMap.GetMappingEntryForGeneratedSourcePosition(generated3);
|
||||
Assert.Equal(0, rootMapping.Value.OriginalSourcePosition.CompareTo(mapLevel2.OriginalSourcePosition));
|
||||
}
|
||||
}
|
||||
|
||||
private static SourceMap CreateSourceMap(
|
||||
int version = default,
|
||||
string file = default,
|
||||
string mappings = default,
|
||||
IReadOnlyList<string> sources = default,
|
||||
IReadOnlyList<string> names = default,
|
||||
IReadOnlyList<MappingEntry> parsedMappings = default,
|
||||
IReadOnlyList<string> sourcesContent = default)
|
||||
{
|
||||
return new SourceMap(
|
||||
version: version,
|
||||
file: file,
|
||||
mappings: mappings,
|
||||
sources: sources,
|
||||
names: names,
|
||||
parsedMappings: parsedMappings,
|
||||
sourcesContent: sourcesContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void CompareTo_SameLineAndColumn_Equal()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 6
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 6
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 6);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 6);
|
||||
|
||||
// Act
|
||||
int result = x.CompareTo(y);
|
||||
|
@ -31,16 +27,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void CompareTo_LargerZeroBasedLineNumber_ReturnLarger()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 4
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 4);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 8);
|
||||
|
||||
// Act
|
||||
int result = x.CompareTo(y);
|
||||
|
@ -53,16 +45,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void CompareTo_SmallerZeroBasedLineNumber_ReturnSmaller()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 4
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 4);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 8);
|
||||
|
||||
// Act
|
||||
int result = x.CompareTo(y);
|
||||
|
@ -75,16 +63,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void CompareTo_SameLineLargerColumn_ReturnLarger()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 6
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 8);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 6);
|
||||
|
||||
// Act
|
||||
int result = x.CompareTo(y);
|
||||
|
@ -97,16 +81,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void CompareTo_SameLineSmallerColumn_ReturnSmaller()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 4
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 4);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 8);
|
||||
|
||||
// Act
|
||||
int result = x.CompareTo(y);
|
||||
|
@ -119,16 +99,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void LessThanOverload_SameZeroBasedLineNumberXColumnSmaller_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 4
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 4);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 8);
|
||||
|
||||
// Act
|
||||
bool result = x < y;
|
||||
|
@ -141,16 +117,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void LessThanOverload_XZeroBasedLineNumberSmallerX_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 8);
|
||||
|
||||
// Act
|
||||
bool result = x < y;
|
||||
|
@ -163,16 +135,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void LessThanOverload_Equal_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 0,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 0,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 0,
|
||||
zeroBasedColumnNumber: 0);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 0,
|
||||
zeroBasedColumnNumber: 0);
|
||||
|
||||
// Act
|
||||
bool result = x < y;
|
||||
|
@ -185,16 +153,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void LessThanOverload_XColumnLarger_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 0,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 0,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 0,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 0,
|
||||
zeroBasedColumnNumber: 0);
|
||||
|
||||
// Act
|
||||
bool result = x < y;
|
||||
|
@ -207,16 +171,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GreaterThanOverload_SameLineXColumnLarger_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 3
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 3);
|
||||
|
||||
// Act
|
||||
bool result = x > y;
|
||||
|
@ -229,16 +189,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GreaterThanOverload_XZeroBasedLineNumberLarger_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 30
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 30);
|
||||
|
||||
// Act
|
||||
bool result = x > y;
|
||||
|
@ -251,16 +207,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GreaterThanOverload_Equal_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 10);
|
||||
|
||||
// Act
|
||||
bool result = x > y;
|
||||
|
@ -273,16 +225,12 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
public void GreaterThanOverload_XSmaller_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 9
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 3,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 9);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 3,
|
||||
zeroBasedColumnNumber: 10);
|
||||
|
||||
// Act
|
||||
bool result = x > y;
|
||||
|
@ -291,158 +239,130 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_XEqualsY_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 13,
|
||||
ZeroBasedColumnNumber = 5
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 13,
|
||||
ZeroBasedColumnNumber = 5
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_XEqualsY_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 13,
|
||||
zeroBasedColumnNumber: 5);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 13,
|
||||
zeroBasedColumnNumber: 5);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_XColumnNumberBiggerByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 8
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 2,
|
||||
ZeroBasedColumnNumber = 7
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_XColumnNumberBiggerByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 8);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 2,
|
||||
zeroBasedColumnNumber: 7);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberBiggerByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 10
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 1,
|
||||
ZeroBasedColumnNumber = 11
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberBiggerByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 10);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 1,
|
||||
zeroBasedColumnNumber: 11);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberBiggerByTwo_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 155,
|
||||
ZeroBasedColumnNumber = 100
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 155,
|
||||
ZeroBasedColumnNumber = 102
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberBiggerByTwo_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 155,
|
||||
zeroBasedColumnNumber: 100);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 155,
|
||||
zeroBasedColumnNumber: 102);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_XColumnNumberZeroLineNumbersDifferByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 235,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 234,
|
||||
ZeroBasedColumnNumber = 102
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_XColumnNumberZeroLineNumbersDifferByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 235,
|
||||
zeroBasedColumnNumber: 0);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 234,
|
||||
zeroBasedColumnNumber: 102);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberZeroLineNumbersDifferByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 458,
|
||||
ZeroBasedColumnNumber = 13
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 459,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberZeroLineNumbersDifferByOne_ReturnTrue()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 458,
|
||||
zeroBasedColumnNumber: 13);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 459,
|
||||
zeroBasedColumnNumber: 0);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberZeroLineNumbersDifferByTwo_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 5456,
|
||||
ZeroBasedColumnNumber = 13
|
||||
};
|
||||
SourcePosition y = new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = 5458,
|
||||
ZeroBasedColumnNumber = 0
|
||||
};
|
||||
[Fact]
|
||||
public void IsEqualish_YColumnNumberZeroLineNumbersDifferByTwo_ReturnFalse()
|
||||
{
|
||||
// Arrange
|
||||
SourcePosition x = new SourcePosition(
|
||||
zeroBasedLineNumber: 5456,
|
||||
zeroBasedColumnNumber: 13);
|
||||
SourcePosition y = new SourcePosition(
|
||||
zeroBasedLineNumber: 5458,
|
||||
zeroBasedColumnNumber: 0);
|
||||
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
// Act
|
||||
bool result = x.IsEqualish(y);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,6 +91,7 @@
|
|||
<Compile Include="Base64ConverterUnitTests.cs" />
|
||||
<Compile Include="Base64VlqDecoderUnitTests.cs" />
|
||||
<Compile Include="Base64VlqEncoderUnitTests.cs" />
|
||||
<Compile Include="IReadOnlyListExtensionsUnitTests.cs" />
|
||||
<Compile Include="NumericMappingEntryUnitTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="MappingsListParserUnitTests.cs" />
|
||||
|
@ -99,6 +100,7 @@
|
|||
<Compile Include="SourceMapTransformerUnitTests.cs" />
|
||||
<Compile Include="SourceMapUnitTests.cs" />
|
||||
<Compile Include="SourcePositionUnitTests.cs" />
|
||||
<Compile Include="StringExtensionsUnitTests.cs" />
|
||||
<Compile Include="UnitTestUtils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser.UnitTests
|
||||
{
|
||||
public class StringExtensionsUnitTests
|
||||
{
|
||||
[Fact]
|
||||
public void SplitFast_NullInput_Throws()
|
||||
{
|
||||
// Arrange
|
||||
const string input = null;
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
Action testAction = () => StringExtensions.SplitFast(input, delimiter);
|
||||
|
||||
//Throws Assert
|
||||
Assert.Throws<NullReferenceException>(testAction);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_EmptyInput_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = "";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_OneCharacterNotSplit_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = "A";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_OneCharacterDelimiter_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = ",";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_DelimiterAtStart_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = ",Hello";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_DelimiterAtEnd_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = "Hello,";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_BackToBack_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = "Hello,,World";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_LongSentence_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna. Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci. Aenean nec lorem. In porttitor. Donec laoreet nonummy augue. Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitFast_Complex_Matches()
|
||||
{
|
||||
// Arrange
|
||||
const string input = ",,Hello,World,How,,Are,You,Doing,,";
|
||||
const char delimiter = ',';
|
||||
|
||||
// Act
|
||||
string[] fastSplit = StringExtensions.SplitFast(input, delimiter);
|
||||
string[] normalSplit = input.Split(delimiter);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(normalSplit.Length, fastSplit.Length);
|
||||
|
||||
for (int i = 0; i < normalSplit.Length; i++)
|
||||
{
|
||||
Assert.Equal(normalSplit[i], fastSplit[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,23 +11,19 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
return new StreamReader(new MemoryStream(byteArray));
|
||||
}
|
||||
|
||||
public static MappingEntry getSimpleEntry(SourcePosition generatedSourcePosition, SourcePosition originalSourcePosition, string originalFileName)
|
||||
{
|
||||
return new MappingEntry
|
||||
{
|
||||
GeneratedSourcePosition = generatedSourcePosition,
|
||||
OriginalSourcePosition = originalSourcePosition,
|
||||
OriginalFileName = originalFileName
|
||||
};
|
||||
}
|
||||
public static MappingEntry getSimpleEntry(SourcePosition generatedSourcePosition, SourcePosition originalSourcePosition, string originalFileName)
|
||||
{
|
||||
return new MappingEntry(
|
||||
generatedSourcePosition: generatedSourcePosition,
|
||||
originalSourcePosition: originalSourcePosition,
|
||||
originalFileName: originalFileName);
|
||||
}
|
||||
|
||||
public static SourcePosition generateSourcePosition(int lineNumber, int colNumber = 0)
|
||||
{
|
||||
return new SourcePosition
|
||||
{
|
||||
ZeroBasedLineNumber = lineNumber,
|
||||
ZeroBasedColumnNumber = colNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
public static SourcePosition generateSourcePosition(int lineNumber, int colNumber = 0)
|
||||
{
|
||||
return new SourcePosition(
|
||||
zeroBasedLineNumber: lineNumber,
|
||||
zeroBasedColumnNumber: colNumber);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче