Skip to content

Commit 00df0a9

Browse files
Expose finding ".swift-format" file
1 parent b6c05ed commit 00df0a9

File tree

2 files changed

+39
-39
lines changed

2 files changed

+39
-39
lines changed

Sources/SwiftFormatConfiguration/Configuration.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ public struct Configuration: Codable, Equatable {
120120
self.version = highestSupportedConfigurationVersion
121121
}
122122

123+
/// Constructs a Configuration using values from a JSON config file
124+
public init(configFile url: URL) throws {
125+
let data = try Data(contentsOf: url)
126+
self = try JSONDecoder().decode(Configuration.self, from: data)
127+
}
128+
123129
public init(from decoder: Decoder) throws {
124130
let container = try decoder.container(keyedBy: CodingKeys.self)
125131

@@ -189,6 +195,25 @@ public struct Configuration: Codable, Equatable {
189195
forKey: .lineBreakAroundMultilineExpressionChainComponents)
190196
try container.encode(rules, forKey: .rules)
191197
}
198+
199+
/// Configuration file associated with a swift file.
200+
///
201+
/// Looks for a ".swift-format" file in the same directory as the swift file, or its nearest parent.
202+
/// If one is not found, returns "nil".
203+
public static func configurationFile(forSwiftFile url: URL) -> URL? {
204+
var path = url.absoluteURL
205+
let configFilename = ".swift-format"
206+
207+
repeat {
208+
path = path.deletingLastPathComponent()
209+
let candidateFile = path.appendingPathComponent(configFilename)
210+
if FileManager.default.isReadableFile(atPath: candidateFile.path) {
211+
return candidateFile
212+
}
213+
} while path.path != "/"
214+
215+
return nil
216+
}
192217
}
193218

194219
/// Configuration for the NoPlaygroundLiterals rule.

Sources/swift-format/main.swift

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -89,53 +89,28 @@ fileprivate func loadConfiguration(
8989
forSwiftFile swiftFilePath: String?, configFilePath: String?
9090
) -> Configuration {
9191
if let path = configFilePath {
92-
return decodedConfiguration(fromFileAtPath: path)
92+
return decodedConfiguration(fromFile: URL(fileURLWithPath: path))
9393
}
94-
// Search for a ".swift-format" configuration file in the directory of the current .swift file,
95-
// or its nearest parent.
96-
var configurationFilePath: String? = nil
97-
if let swiftFilePath = swiftFilePath {
98-
configurationFilePath = findConfigurationFile(
99-
forSwiftFile: URL(fileURLWithPath: swiftFilePath).path)
100-
}
101-
return decodedConfiguration(fromFileAtPath: configurationFilePath)
102-
}
10394

104-
/// Look for a ".swift-format" configuration file in the same directory as "forSwiftFile", or its
105-
/// nearest parent. If one is not found, return "nil".
106-
fileprivate func findConfigurationFile(forSwiftFile: String) -> String? {
107-
let cwd = FileManager.default.currentDirectoryPath
108-
var path = URL(
109-
fileURLWithPath: AbsolutePath(forSwiftFile, relativeTo: AbsolutePath(cwd)).pathString)
110-
let configFilename = ".swift-format"
111-
112-
repeat {
113-
path = path.deletingLastPathComponent()
114-
let testPath = path.appendingPathComponent(configFilename).path
115-
if FileManager.default.isReadableFile(atPath: testPath) {
116-
return testPath
117-
}
118-
} while path.path != "/"
95+
if let swiftFileUrl = swiftFilePath.map(URL.init(fileURLWithPath:)),
96+
let configFileUrl = Configuration.configurationFile(forSwiftFile: swiftFileUrl) {
97+
return decodedConfiguration(fromFile: configFileUrl)
98+
}
11999

120-
return nil
100+
return Configuration()
121101
}
122102

103+
123104
/// Loads and returns a `Configuration` from the given JSON file if it is found and is valid. If the
124105
/// file does not exist or there was an error decoding it, the program exits with a non-zero exit
125106
/// code.
126-
fileprivate func decodedConfiguration(fromFileAtPath path: String?) -> Configuration {
127-
if let path = path {
128-
do {
129-
let url = URL(fileURLWithPath: path)
130-
let data = try Data(contentsOf: url)
131-
return try JSONDecoder().decode(Configuration.self, from: data)
132-
} catch {
133-
// TODO: Improve error message, write to stderr.
134-
print("Could not load configuration at \(path): \(error)")
135-
exit(1)
136-
}
137-
} else {
138-
return Configuration()
107+
fileprivate func decodedConfiguration(fromFile url: Foundation.URL) -> Configuration {
108+
do {
109+
return try Configuration(configFile: url)
110+
} catch {
111+
// TODO: Improve error message, write to stderr.
112+
print("Could not load configuration at \(url): \(error)")
113+
exit(1)
139114
}
140115
}
141116

0 commit comments

Comments
 (0)