apple_kit

Apple-native services for Radroots iOS and macOS apps
git clone https://radroots.dev/git/apple_kit.git
Log | Files | Refs | README | LICENSE

normalize-public-api.swift (3022B)


      1 import Foundation
      2 
      3 private func fail(_ message: String) -> Never {
      4     FileHandle.standardError.write(Data("api_baseline_invalid: \(message)\n".utf8))
      5     exit(1)
      6 }
      7 
      8 private func string(_ object: [String: Any], _ key: String, _ context: String) -> String {
      9     guard let value = object[key] as? String else {
     10         fail("\(context) omits \(key)")
     11     }
     12     return value
     13 }
     14 
     15 private func escaped(_ value: String) -> String {
     16     value
     17         .replacingOccurrences(of: "\\", with: "\\\\")
     18         .replacingOccurrences(of: "\t", with: "\\t")
     19         .replacingOccurrences(of: "\n", with: "\\n")
     20         .replacingOccurrences(of: "\r", with: "\\r")
     21 }
     22 
     23 private func fields(_ values: [String]) -> String {
     24     values
     25         .map { "\($0.utf8.count):\(escaped($0))" }
     26         .joined(separator: "\t")
     27 }
     28 
     29 let paths = Array(CommandLine.arguments.dropFirst())
     30 guard !paths.isEmpty else {
     31     fail("at least one symbol graph is required")
     32 }
     33 
     34 var modules = Set<String>()
     35 var rows = Set<String>()
     36 
     37 for path in paths.sorted() {
     38     let data: Data
     39     do {
     40         data = try Data(contentsOf: URL(fileURLWithPath: path))
     41     } catch {
     42         fail("symbol graph could not be read")
     43     }
     44     guard
     45         let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
     46         let module = root["module"] as? [String: Any],
     47         let symbols = root["symbols"] as? [[String: Any]],
     48         let relationships = root["relationships"] as? [[String: Any]]
     49     else {
     50         fail("symbol graph shape is invalid")
     51     }
     52 
     53     let moduleName = string(module, "name", "module")
     54     modules.insert(moduleName)
     55 
     56     func record(_ row: String) {
     57         rows.insert(row)
     58     }
     59 
     60     for symbol in symbols {
     61         guard
     62             let kind = symbol["kind"] as? [String: Any],
     63             let identifier = symbol["identifier"] as? [String: Any],
     64             let names = symbol["names"] as? [String: Any]
     65         else {
     66             fail("symbol shape is invalid")
     67         }
     68         let declaration = (symbol["declarationFragments"] as? [[String: Any]] ?? [])
     69             .map { string($0, "spelling", "declaration fragment") }
     70             .joined()
     71         record(fields([
     72             "symbol",
     73             moduleName,
     74             string(kind, "identifier", "symbol kind"),
     75             string(identifier, "precise", "symbol identifier"),
     76             string(names, "title", "symbol names"),
     77             declaration,
     78         ]))
     79     }
     80 
     81     for relationship in relationships {
     82         record(fields([
     83             "relationship",
     84             moduleName,
     85             string(relationship, "kind", "relationship"),
     86             string(relationship, "source", "relationship"),
     87             string(relationship, "target", "relationship"),
     88             relationship["targetFallback"] as? String ?? "",
     89         ]))
     90     }
     91 }
     92 
     93 guard modules == ["RadrootsKit", "RadrootsKitTesting"] else {
     94     fail("module inventory is not exact")
     95 }
     96 
     97 print("radroots.apple-kit.public-api.v1")
     98 let sortedRows = rows.sorted()
     99 for row in sortedRows {
    100     print(row)
    101 }