Fix crash when deserializing from Stream into SourceMap (#85)

* Json.net is throwing an exception when trying to deserialize into an IReadOnlyList using a stream deserializer

* Remove ParsedMappings from serialization/deserialization code on SourceMap
This commit is contained in:
Rob Rolnick 2021-02-17 09:49:01 -08:00 коммит произвёл GitHub
Родитель 38362c5ed1
Коммит c129b3d21e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 53 добавлений и 10 удалений

Просмотреть файл

@ -6,6 +6,36 @@ using Newtonsoft.Json;
namespace SourcemapToolkit.SourcemapParser
{
/// <summary>
/// A seemingly silly class, but unfortunately one which appears necessary.
/// While the SourceMap class is serializable, it is not deserializable directly.
/// The problem is that the IReadOnlyList generics throw the following exception:
/// 'Newtonsoft.Json.JsonSerializationException: Cannot create and populate list type'
/// when attempting to deserialize from a stream using a JsonTextReader. This
/// intermediary class mitigates the problem by reading the data into a mutable list
/// first.
/// </summary>
internal class SourceMapDeserializable
{
/// <summary><see cref="SourceMap.Version"/></summary>
public int Version;
/// <summary><see cref="SourceMap.File"/></summary>
public string File;
/// <summary><see cref="SourceMap.Mappings"/></summary>
public string Mappings;
/// <summary><see cref="SourceMap.Sources"/></summary>
public List<string> Sources;
/// <summary><see cref="SourceMap.Names"/></summary>
public List<string> Names;
/// <summary><see cref="SourceMap.SourcesContent"/></summary>
public List<string> SourcesContent;
}
public class SourceMap
{
/// <summary>
@ -42,6 +72,8 @@ namespace SourcemapToolkit.SourcemapParser
/// <summary>
/// Parsed version of the mappings string that is used for getting original names and source positions
/// </summary>
/// <remarks>Marked as JsonIgnore to because it isn't part of the actual format. See: https://sourcemaps.info/spec.html#h.mofvlxcwqzej </remarks>
[JsonIgnore]
public IReadOnlyList<MappingEntry> ParsedMappings { get; }
/// <summary>

Просмотреть файл

@ -27,26 +27,37 @@ namespace SourcemapToolkit.SourcemapParser
{
JsonSerializer serializer = new JsonSerializer();
SourceMap result = serializer.Deserialize<SourceMap>(jsonTextReader);
SourceMapDeserializable deserializedSourceMap = serializer.Deserialize<SourceMapDeserializable>(jsonTextReader);
// 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);
List<MappingEntry> parsedMappings = _mappingsListParser.ParseMappings(deserializedSourceMap.Mappings, deserializedSourceMap.Names, deserializedSourceMap.Sources);
// Resize to free unused memory
parsedMappings.Capacity = parsedMappings.Count;
RemoveExtraSpaceFromList(parsedMappings);
RemoveExtraSpaceFromList(deserializedSourceMap.Sources);
RemoveExtraSpaceFromList(deserializedSourceMap.Names);
RemoveExtraSpaceFromList(deserializedSourceMap.SourcesContent);
result = new SourceMap(
version: result.Version,
file: result.File,
mappings: result.Mappings,
sources: result.Sources,
names: result.Names,
SourceMap result = new SourceMap(
version: deserializedSourceMap.Version,
file: deserializedSourceMap.File,
mappings: deserializedSourceMap.Mappings,
sources: deserializedSourceMap.Sources,
names: deserializedSourceMap.Names,
parsedMappings: parsedMappings,
sourcesContent: result.SourcesContent);
sourcesContent: deserializedSourceMap.SourcesContent);
sourceMapStream.Close();
return result;
}
}
private void RemoveExtraSpaceFromList<T>(List<T> list)
{
if (list != null)
{
list.Capacity = list.Count;
}
}
}
}