-
Notifications
You must be signed in to change notification settings - Fork 0
/
JSON.swift
97 lines (86 loc) · 3.27 KB
/
JSON.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//
// JSON.swift
// SourceMapper
//
// Licensed under MIT (https://github.com/johnfairh/SourceMapper/blob/main/LICENSE
//
import Foundation
fileprivate struct SerializedSourceMap: Codable {
let version: Int
let file: String?
let sourceRoot: String?
let sources: [String]
let sourcesContent: [String?]?
let names: [String]
let mappings: String
}
extension SourceMap {
/// Decode a source map from JSON ``Data``.
/// - parameter data: The source map JSON.
/// - throws: If the JSON is bad, the version is bad, or if mandatory fields are missing.
public init(_ data: Data) throws {
let decoded = try JSONDecoder().decode(SerializedSourceMap.self, from: data)
if decoded.version != SourceMap.VERSION {
throw SourceMapError.invalidFormat(decoded.version)
}
self.init(version: decoded.version)
self.file = decoded.file
self.sourceRoot = decoded.sourceRoot
let contents: [String?]
if let decodedContents = decoded.sourcesContent {
guard decodedContents.count == decoded.sources.count else {
throw SourceMapError.inconsistentSources(sourcesCount: decoded.sources.count,
sourcesContentCount: decodedContents.count)
}
contents = decodedContents
} else {
contents = .init(repeating: nil, count: decoded.sources.count)
}
self.sources = zip(decoded.sources, contents).map {
SourceMap.Source(url: $0, content: $1)
}
self.names = decoded.names
self.mappings = decoded.mappings
}
/// Decode a source map from a JSON string.
///
/// See ``init(_:)``
public init(_ string: String) throws {
try self.init(string.data(using: .utf8)!)
}
/// Encode the source map as JSON
///
/// - throws: If JSON encoding fails for some JSON reason - does not perform any source-map validation.
public func encode() throws -> Data {
var anyContent = false
let sourceLists: ([String], [String?]) = sources.reduce(into: ([], [])) { r, s in
r.0.append(s.url)
r.1.append(s.content)
if s.content != nil {
anyContent = true
}
}
let serialized = SerializedSourceMap(version: version,
file: file,
sourceRoot: sourceRoot,
sources: sourceLists.0,
sourcesContent: anyContent ? sourceLists.1 : nil,
names: names,
mappings: mappings)
let encoder = JSONEncoder()
if #available(macOS 10.13, iOS 11.0, *) {
encoder.outputFormatting = .sortedKeys
}
// The #available above doesn't fire on Windows...
#if os(Windows)
encoder.outputFormatting = .sortedKeys
#endif
return try encoder.encode(serialized)
}
/// Encode the source map as JSON in a string
///
/// See `encode()`.
public func encodeString() throws -> String {
String(data: try encode(), encoding: .utf8)!
}
}