Merge pull request #34 from nileliao/niliao-sourcemap-toolkit
Add support for Base64Vlq encode and source map serialize
This commit is contained in:
Коммит
05836f3348
|
@ -2,7 +2,8 @@
|
|||
This is a C# library for working with JavaScript source maps and deminifying JavaScript callstacks.
|
||||
|
||||
## Source Map Parsing
|
||||
The `SourcemapToolkit.SourcemapParser.dll` provides an API for parsing a souce map into an object that is easy to work with. The source map class has a method `GetMappingEntryForGeneratedSourcePosition`, which can be used to find a source map mapping entry that likely corresponds to a piece of generated code.
|
||||
The `SourcemapToolkit.SourcemapParser.dll` provides an API for parsing a souce map into an object that is easy to work with and an API for serializing source map object back to json string.
|
||||
The source map class has a method `GetMappingEntryForGeneratedSourcePosition`, which can be used to find a source map mapping entry that likely corresponds to a piece of generated code.
|
||||
|
||||
## Call Stack Deminification
|
||||
The `SourcemapToolkit.CallstackDeminifier.dll` allows for the deminification of JavaScript call stacks.
|
||||
|
|
|
@ -26,11 +26,24 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
{
|
||||
int result;
|
||||
if (!_base64DecodeMap.TryGetValue(base64Value, out result))
|
||||
{
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(base64Value), "Tried to convert an invalid base64 value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a integer to base64 value
|
||||
/// </summary>
|
||||
internal static char ToBase64(int value)
|
||||
{
|
||||
if (value < 0 || value >= Base64Alphabet.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
|
||||
return Base64Alphabet[value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* Based on the Base 64 VLQ implementation in Closure Compiler:
|
||||
* https://github.com/google/closure-compiler/blob/master/src/com/google/debugging/sourcemap/Base64VLQ.java
|
||||
*
|
||||
* Copyright 2011 The Closure Compiler Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants used in Base64 VLQ encode/decode
|
||||
/// </summary>
|
||||
internal static class Base64VlqConstants
|
||||
{
|
||||
// A Base64 VLQ digit can represent 5 bits, so it is base-32.
|
||||
public const int VlqBaseShift = 5;
|
||||
public const int VlqBase = 1 << VlqBaseShift;
|
||||
|
||||
// A mask of bits for a VLQ digit (11111), 31 decimal.
|
||||
public const int VlqBaseMask = VlqBase - 1;
|
||||
|
||||
// The continuation bit is the 6th bit.
|
||||
public const int VlqContinuationBit = VlqBase;
|
||||
}
|
||||
}
|
|
@ -26,16 +26,6 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
/// </summary>
|
||||
internal static class Base64VlqDecoder
|
||||
{
|
||||
// A Base64 VLQ digit can represent 5 bits, so it is base-32.
|
||||
private const int VlqBaseShift = 5;
|
||||
private const int VlqBase = 1 << VlqBaseShift;
|
||||
|
||||
// A mask of bits for a VLQ digit (11111), 31 decimal.
|
||||
private static readonly int VlqBaseMask = VlqBase - 1;
|
||||
|
||||
// The continuation bit is the 6th bit.
|
||||
private static readonly int VlqContinuationBit = VlqBase;
|
||||
|
||||
/// <summary>
|
||||
/// Converts to a two-complement value from a value where the sign bit is
|
||||
/// is placed in the least significant bit.For example, as decimals:
|
||||
|
@ -103,10 +93,10 @@ namespace SourcemapToolkit.SourcemapParser
|
|||
{
|
||||
char c = charProvider.GetNextCharacter();
|
||||
int digit = Base64Converter.FromBase64(c);
|
||||
continuation = (digit & VlqContinuationBit) != 0;
|
||||
digit &= VlqBaseMask;
|
||||
continuation = (digit & Base64VlqConstants.VlqContinuationBit) != 0;
|
||||
digit &= Base64VlqConstants.VlqBaseMask;
|
||||
result = result + (digit << shift);
|
||||
shift = shift + VlqBaseShift;
|
||||
shift = shift + Base64VlqConstants.VlqBaseShift;
|
||||
} while (continuation);
|
||||
|
||||
return FromVlqSigned(result);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* Based on the Base 64 VLQ implementation in Closure Compiler:
|
||||
* https://github.com/google/closure-compiler/blob/master/src/com/google/debugging/sourcemap/Base64VLQ.java
|
||||
*
|
||||
* Copyright 2011 The Closure Compiler Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
/// <summary>
|
||||
/// This class provides a mechanism for converting an interger to Base64 Variable-length quantity (VLQ)
|
||||
/// </summary>
|
||||
internal static class Base64VlqEncoder
|
||||
{
|
||||
public static void Encode(ICollection<char> output, int value)
|
||||
{
|
||||
int vlq = ToVlqSigned(value);
|
||||
|
||||
do
|
||||
{
|
||||
int maskResult = vlq & Base64VlqConstants.VlqBaseMask;
|
||||
vlq = vlq >> Base64VlqConstants.VlqBaseShift;
|
||||
if (vlq > 0)
|
||||
{
|
||||
maskResult |= Base64VlqConstants.VlqContinuationBit;
|
||||
}
|
||||
output.Add(Base64Converter.ToBase64(maskResult));
|
||||
} while (vlq > 0);
|
||||
}
|
||||
|
||||
private static int ToVlqSigned(int value)
|
||||
{
|
||||
return value < 0 ? ((-value << 1) + 1) : (value << 1) + 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to track the internal state during source map serialize
|
||||
/// </summary>
|
||||
internal class MappingGenerateState
|
||||
{
|
||||
/// <summary>
|
||||
/// Last location of the code in the transformed code
|
||||
/// </summary>
|
||||
public readonly SourcePosition LastGeneratedPosition = new SourcePosition();
|
||||
|
||||
/// <summary>
|
||||
/// Last location of the code in the source code
|
||||
/// </summary>
|
||||
public readonly SourcePosition LastOriginalPosition = new SourcePosition();
|
||||
|
||||
/// <summary>
|
||||
/// List that contains the symbol names
|
||||
/// </summary>
|
||||
public readonly IList<string> Names;
|
||||
|
||||
/// <summary>
|
||||
/// List that contains the file sources
|
||||
/// </summary>
|
||||
public readonly IList<string> Sources;
|
||||
|
||||
/// <summary>
|
||||
/// Index of last file source
|
||||
/// </summary>
|
||||
public int LastSourceIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index of last symbol name
|
||||
/// </summary>
|
||||
public int LastNameIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this is the first segment in current line
|
||||
/// </summary>
|
||||
public bool IsFirstSegment { get; set; }
|
||||
|
||||
public MappingGenerateState(IList<string> names, IList<string> sources)
|
||||
{
|
||||
Names = names;
|
||||
Sources = sources;
|
||||
IsFirstSegment = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class SourceMapGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialize SourceMap object to json string
|
||||
/// </summary>
|
||||
public string SerializeMapping(SourceMap sourceMap)
|
||||
{
|
||||
return SerializeMapping(sourceMap, null /* jsonSerializerSettings */ );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize SourceMap object to json string with given serialize settings
|
||||
/// </summary>
|
||||
public string SerializeMapping(SourceMap sourceMap, JsonSerializerSettings jsonSerializerSettings)
|
||||
{
|
||||
if (sourceMap == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
SourceMap mapToSerialize = new SourceMap()
|
||||
{
|
||||
File = sourceMap.File,
|
||||
Names = sourceMap.Names,
|
||||
Sources = sourceMap.Sources,
|
||||
Version = sourceMap.Version,
|
||||
};
|
||||
|
||||
if (sourceMap.ParsedMappings != null && sourceMap.ParsedMappings.Count > 0)
|
||||
{
|
||||
MappingGenerateState state = new MappingGenerateState(sourceMap.Names, sourceMap.Sources);
|
||||
List<char> output = new List<char>();
|
||||
|
||||
foreach (MappingEntry entry in sourceMap.ParsedMappings)
|
||||
{
|
||||
SerializeMappingEntry(entry, state, output);
|
||||
}
|
||||
|
||||
output.Add(';');
|
||||
|
||||
mapToSerialize.Mappings = new string(output.ToArray());
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(mapToSerialize,
|
||||
jsonSerializerSettings ?? new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert each mapping entry to VLQ encoded segments
|
||||
/// </summary>
|
||||
internal void SerializeMappingEntry(MappingEntry entry, MappingGenerateState state, ICollection<char> output)
|
||||
{
|
||||
// Each line of generated code is separated using semicolons
|
||||
while (entry.GeneratedSourcePosition.ZeroBasedLineNumber != state.LastGeneratedPosition.ZeroBasedLineNumber)
|
||||
{
|
||||
state.LastGeneratedPosition.ZeroBasedColumnNumber = 0;
|
||||
state.LastGeneratedPosition.ZeroBasedLineNumber++;
|
||||
state.IsFirstSegment = true;
|
||||
output.Add(';');
|
||||
}
|
||||
|
||||
// The V3 source map format calls for all Base64 VLQ segments to be seperated by commas.
|
||||
if (!state.IsFirstSegment)
|
||||
output.Add(',');
|
||||
|
||||
state.IsFirstSegment = false;
|
||||
|
||||
/*
|
||||
* The following description was taken from the Sourcemap V3 spec https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/mobilebasic?pref=2&pli=1
|
||||
* The Sourcemap V3 spec is under a Creative Commons Attribution-ShareAlike 3.0 Unported License. https://creativecommons.org/licenses/by-sa/3.0/
|
||||
*
|
||||
* Each VLQ segment has 1, 4, or 5 variable length fields.
|
||||
* The fields in each segment are:
|
||||
* 1. The zero-based starting column of the line in the generated code that the segment represents.
|
||||
* If this is the first field of the first segment, or the first segment following a new generated line(“;”),
|
||||
* then this field holds the whole base 64 VLQ.Otherwise, this field contains a base 64 VLQ that is relative to
|
||||
* the previous occurrence of this field.Note that this is different than the fields below because the previous
|
||||
* value is reset after every generated line.
|
||||
* 2. If present, an zero - based index into the “sources” list.This field is a base 64 VLQ relative to the previous
|
||||
* occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is represented.
|
||||
* 3. If present, the zero-based starting line in the original source represented. This field is a base 64 VLQ relative to the
|
||||
* previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is
|
||||
* represented.Always present if there is a source field.
|
||||
* 4. If present, the zero - based starting column of the line in the source represented.This field is a base 64 VLQ relative to
|
||||
* the previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is
|
||||
* represented.Always present if there is a source field.
|
||||
* 5. If present, the zero - based index into the “names” list associated with this segment.This field is a base 64 VLQ relative
|
||||
* to the previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value
|
||||
* is represented.
|
||||
*/
|
||||
|
||||
Base64VlqEncoder.Encode(output, entry.GeneratedSourcePosition.ZeroBasedColumnNumber - state.LastGeneratedPosition.ZeroBasedColumnNumber);
|
||||
state.LastGeneratedPosition.ZeroBasedColumnNumber = entry.GeneratedSourcePosition.ZeroBasedColumnNumber;
|
||||
|
||||
if (entry.OriginalFileName != null)
|
||||
{
|
||||
int sourceIndex = state.Sources.IndexOf(entry.OriginalFileName);
|
||||
if (sourceIndex < 0)
|
||||
{
|
||||
throw new SerializationException("Source map contains original source that cannot be found in provided sources array");
|
||||
}
|
||||
|
||||
Base64VlqEncoder.Encode(output, sourceIndex - state.LastSourceIndex);
|
||||
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;
|
||||
|
||||
if (entry.OriginalName != null)
|
||||
{
|
||||
int nameIndex = state.Names.IndexOf(entry.OriginalName);
|
||||
if (nameIndex < 0)
|
||||
{
|
||||
throw new SerializationException("Source map contains original name that cannot be found in provided names array");
|
||||
}
|
||||
|
||||
Base64VlqEncoder.Encode(output, nameIndex - state.LastNameIndex);
|
||||
state.LastNameIndex = nameIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,11 +52,14 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Base64Converter.cs" />
|
||||
<Compile Include="Base64VlqConstants.cs" />
|
||||
<Compile Include="Base64VlqDecoder.cs" />
|
||||
<Compile Include="Base64VlqEncoder.cs" />
|
||||
<Compile Include="MappingEntry.cs" />
|
||||
<Compile Include="MappingListParser.cs" />
|
||||
<Compile Include="SourceMap.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SourceMapGenerator.cs" />
|
||||
<Compile Include="SourceMapParser.cs" />
|
||||
<Compile Include="SourcePosition.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -33,5 +33,31 @@ namespace SourcemapToolkit.SourcemapParser.UnitTests
|
|||
// Act
|
||||
Base64Converter.FromBase64('@');
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ToBase64_ValidIntegerInput61_CorrectBase64Output9()
|
||||
{
|
||||
// Act
|
||||
char value = Base64Converter.ToBase64(61);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual('9', value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ToBase64_NegativeIntegerInput_ThrowsException()
|
||||
{
|
||||
// Act
|
||||
Base64Converter.ToBase64(-1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArgumentOutOfRangeException))]
|
||||
public void ToBase64_InvalidIntegerInput_ThrowsException()
|
||||
{
|
||||
// Act
|
||||
Base64Converter.ToBase64(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class Base64VlqEncoderUnitTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Base64VlqEncoder_SmallValue_ListWithOnlyOneValue()
|
||||
{
|
||||
// Act
|
||||
List<char> result = new List<char>();
|
||||
Base64VlqEncoder.Encode(result, 15);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("e", new string(result.ToArray()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Base64VlqEncoder_LargeValue_ListWithOnlyMultipleValues()
|
||||
{
|
||||
// Act
|
||||
List<char> result = new List<char>();
|
||||
Base64VlqEncoder.Encode(result, 701);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("6rB", new string(result.ToArray()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Base64VlqEncoder_NegativeValue_ListWithCorrectValue()
|
||||
{
|
||||
// Act
|
||||
List<char> result = new List<char>();
|
||||
Base64VlqEncoder.Encode(result, -15);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("f", new string(result.ToArray()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SourcemapToolkit.SourcemapParser.UnitTests
|
||||
{
|
||||
[TestClass]
|
||||
public class SourceMapGeneratorUnitTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SerializeMappingEntry_DifferentLineNumber_SemicolonAdded()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
state.LastGeneratedPosition.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 },
|
||||
};
|
||||
|
||||
// Act
|
||||
List<char> output = new List<char>();
|
||||
sourceMapGenerator.SerializeMappingEntry(entry, state, output);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(output.IndexOf(';') >= 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SerializeMappingEntry_NoOriginalFileName_OneSegment()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
// Act
|
||||
List<char> output = new List<char>();
|
||||
sourceMapGenerator.SerializeMappingEntry(entry, state, output);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("U", new string(output.ToArray()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SerializeMappingEntry_WithOriginalFileNameNoOriginalName_FourSegment()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
// Act
|
||||
List<char> output = new List<char>();
|
||||
sourceMapGenerator.SerializeMappingEntry(entry, state, output);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(",UAAK", new string(output.ToArray()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SerializeMappingEntry_WithOriginalFileNameAndOriginalName_FiveSegment()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
|
||||
MappingGenerateState state = new MappingGenerateState(new List<string>() { "Name" }, new List<string>() { "Source" });
|
||||
state.LastGeneratedPosition.ZeroBasedLineNumber = 1;
|
||||
|
||||
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],
|
||||
};
|
||||
|
||||
// Act
|
||||
List<char> output = new List<char>();
|
||||
sourceMapGenerator.SerializeMappingEntry(entry, state, output);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("KACMA", new string(output.ToArray()));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SerializeMapping_NullInput_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
SourceMap input = null;
|
||||
|
||||
// Act
|
||||
string output = sourceMapGenerator.SerializeMapping(input);
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(output);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SerializeMapping_SimpleSourceMap_CorrectlySerialized()
|
||||
{
|
||||
// Arrange
|
||||
SourceMapGenerator sourceMapGenerator = new SourceMapGenerator();
|
||||
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 },
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
string output = sourceMapGenerator.SerializeMapping(input);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("{\"version\":3,\"file\":\"CommonIntl\",\"mappings\":\"AACAA,aAAA,CAAc;\",\"sources\":[\"input/CommonIntl.js\"],\"names\":[\"CommonStrings\",\"afrikaans\"]}", output);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,9 +60,11 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Base64ConverterUnitTests.cs" />
|
||||
<Compile Include="Base64VlqDecoderUnitTests.cs" />
|
||||
<Compile Include="Base64VlqEncoderUnitTests.cs" />
|
||||
<Compile Include="NumericMappingEntryUnitTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="MappingsListParserUnitTests.cs" />
|
||||
<Compile Include="SourceMapGeneratorUnitTests.cs" />
|
||||
<Compile Include="SourceMapParserUnitTests.cs" />
|
||||
<Compile Include="SourceMapUnitTests.cs" />
|
||||
<Compile Include="SourcePositionUnitTests.cs" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче