/// <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), Names = sourceMap.Names == null ? null : new List <string>(sourceMap.Names), ParsedMappings = new List <MappingEntry>() }; HashSet <int> visitedLines = new HashSet <int>(); foreach (MappingEntry mapping in sourceMap.ParsedMappings) { int generatedLine = mapping.GeneratedSourcePosition.ZeroBasedLineNumber; if (!visitedLines.Contains(generatedLine)) { visitedLines.Add(generatedLine); var newMapping = mapping.Clone(); newMapping.GeneratedSourcePosition.ZeroBasedColumnNumber = 0; newMapping.OriginalSourcePosition.ZeroBasedColumnNumber = 0; newMap.ParsedMappings.Add(newMapping); } } return(newMap); }
/// <summary> /// Convenience wrapper around SerializeMapping, but returns a base 64 encoded string instead /// </summary> public string GenerateSourceMapInlineComment(SourceMap sourceMap, JsonSerializerSettings jsonSerializerSettings = null) { string mappings = SerializeMapping(sourceMap, jsonSerializerSettings); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(mappings); var encoded = Convert.ToBase64String(bytes); return(@"//# sourceMappingURL=data:application/json;base64," + encoded); }
/// <summary> /// Parses a stream representing a source map into a SourceMap object. /// </summary> public SourceMap ParseSourceMap(StreamReader sourceMapStream) { if (sourceMapStream == null) { return(null); } using (JsonTextReader jsonTextReader = new JsonTextReader(sourceMapStream)) { JsonSerializer serializer = new JsonSerializer(); SourceMap result = serializer.Deserialize <SourceMap>(jsonTextReader); result.ParsedMappings = _mappingsListParser.ParseMappings(result.Mappings, result.Names, result.Sources); sourceMapStream.Close(); return(result); } }
/// <summary> /// Serialize SourceMap object to json string with given serialize settings /// </summary> public string SerializeMapping(SourceMap sourceMap, JsonSerializerSettings jsonSerializerSettings = null) { if (sourceMap == null) { throw new ArgumentNullException(nameof(sourceMap)); } 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> /// 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) /// <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> /// </summary> public SourceMap ApplySourceMap(SourceMap submap, string sourceFile = null) { if (submap == null) { throw new ArgumentNullException(nameof(submap)); } if (sourceFile == null) { if (submap.File == null) { throw new Exception("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>(), ParsedMappings = new List <MappingEntry>() }; // transform mappings in this source map foreach (MappingEntry mappingEntry in this.ParsedMappings) { MappingEntry newMappingEntry = mappingEntry.Clone(); if (mappingEntry.OriginalFileName == sourceFile && mappingEntry.OriginalSourcePosition != null) { 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 }; } } // Copy into "Sources" and "Names" string originalFileName = newMappingEntry.OriginalFileName; string originalName = newMappingEntry.OriginalName; if (originalFileName != null && !newSourceMap.Sources.Contains(originalFileName)) { newSourceMap.Sources.Add(originalFileName); } if (originalName != null && !newSourceMap.Names.Contains(originalName)) { newSourceMap.Names.Add(originalName); } newSourceMap.ParsedMappings.Add(newMappingEntry); } ; return(newSourceMap); }