This repository has been archived by the owner on Jun 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 99
/
Generate.swift
143 lines (119 loc) · 4.88 KB
/
Generate.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import ArgumentParser
import Foundation
import SwiftDoc
import SwiftMarkup
import SwiftSemantics
import struct SwiftSemantics.Protocol
#if os(Linux)
import FoundationNetworking
#endif
extension SwiftDoc {
struct Generate: ParsableCommand {
enum Format: String, ExpressibleByArgument {
case commonmark
case html
}
struct Options: ParsableArguments {
@Argument(help: "One or more paths to Swift files")
var inputs: [String]
@Option(name: [.long, .customShort("n")],
help: "The name of the module")
var moduleName: String
@Option(name: .shortAndLong,
help: "The path for generated output")
var output: String = ".build/documentation"
@Option(name: .shortAndLong,
help: "The output format")
var format: Format = .commonmark
@Option(name: .customLong("base-url"),
help: "The base URL used for all relative URLs in generated documents.")
var baseURL: String = "/"
@Option(name: .long,
help: "The minimum access level of the symbols included in generated documentation.")
var minimumAccessLevel: AccessLevel = .public
}
static var configuration = CommandConfiguration(abstract: "Generates Swift documentation")
@OptionGroup()
var options: Options
func run() throws {
let module = try Module(name: options.moduleName, paths: options.inputs)
let baseURL = options.baseURL
let outputDirectoryURL = URL(fileURLWithPath: options.output)
try fileManager.createDirectory(at: outputDirectoryURL, withIntermediateDirectories: true)
do {
let format = options.format
var pages: [String: Page] = [:]
var globals: [String: [Symbol]] = [:]
let symbolFilter = options.minimumAccessLevel.includes(symbol:)
for symbol in module.interface.topLevelSymbols.filter(symbolFilter) {
switch symbol.api {
case is Class, is Enumeration, is Structure, is Protocol:
pages[route(for: symbol)] = TypePage(module: module, symbol: symbol, baseURL: baseURL, includingChildren: symbolFilter)
case let `typealias` as Typealias:
pages[route(for: `typealias`.name)] = TypealiasPage(module: module, symbol: symbol, baseURL: baseURL)
case let function as Function where !function.isOperator:
globals[function.name, default: []] += [symbol]
case let variable as Variable:
globals[variable.name, default: []] += [symbol]
default:
continue
}
}
for (name, symbols) in globals {
pages[route(for: name)] = GlobalPage(module: module, name: name, symbols: symbols, baseURL: baseURL)
}
guard !pages.isEmpty else {
logger.warning("No public API symbols were found at the specified path. No output was written.")
if options.minimumAccessLevel == .public {
logger.warning("By default, swift-doc only includes public declarations. Maybe you want to use --minimum-access-level to include non-public declarations?")
}
return
}
if pages.count == 1, let page = pages.first?.value {
let filename: String
switch format {
case .commonmark:
filename = "Home.md"
case .html:
filename = "index.html"
}
let url = outputDirectoryURL.appendingPathComponent(filename)
try page.write(to: url, format: format)
} else {
switch format {
case .commonmark:
pages["Home"] = HomePage(module: module, baseURL: baseURL, symbolFilter: symbolFilter)
pages["_Sidebar"] = SidebarPage(module: module, baseURL: baseURL, symbolFilter: symbolFilter)
pages["_Footer"] = FooterPage(baseURL: baseURL)
case .html:
pages["Home"] = HomePage(module: module, baseURL: baseURL, symbolFilter: symbolFilter)
}
try pages.map { $0 }.parallelForEach {
let filename: String
switch format {
case .commonmark:
filename = "\($0.key).md"
case .html where $0.key == "Home":
filename = "index.html"
case .html:
filename = "\($0.key)/index.html"
}
let url = outputDirectoryURL.appendingPathComponent(filename)
try $0.value.write(to: url, format: format)
}
}
if case .html = format {
let cssData = try fetchRemoteCSS()
let cssURL = outputDirectoryURL.appendingPathComponent("all.css")
try writeFile(cssData, to: cssURL)
}
} catch {
logger.error("\(error)")
}
}
}
}
func fetchRemoteCSS() throws -> Data {
let url = URL(string: "https://raw.githubusercontent.com/SwiftDocOrg/swift-doc/master/Resources/all.min.css")!
return try Data(contentsOf: url)
}