Skip to content

Commit 00494d4

Browse files
authored
Fixes #276 - Unknown configuration options should throw an error (#297)
1 parent 6db47f7 commit 00494d4

File tree

4 files changed

+86
-2
lines changed

4 files changed

+86
-2
lines changed

Sources/_OpenAPIGeneratorCore/Parser/YamsParser.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,27 @@ import Yams
1919

2020
/// A parser that uses the Yams library to parse the provided
2121
/// raw file into an OpenAPI document.
22-
struct YamsParser: ParserProtocol {
22+
public struct YamsParser: ParserProtocol {
23+
24+
/// Extracts the top-level keys from a YAML string.
25+
///
26+
/// - Parameter yamlString: The YAML string from which to extract keys.
27+
/// - Returns: An array of top-level keys as strings.
28+
/// - Throws: An error if there are any issues with parsing the YAML string.
29+
public static func extractTopLevelKeys(fromYAMLString yamlString: String) throws -> [String] {
30+
var yamlKeys = [String]()
31+
let parser = try Parser(yaml: yamlString)
32+
33+
if let rootNode = try parser.singleRoot(),
34+
case let .mapping(mapping) = rootNode
35+
{
36+
for (key, _) in mapping {
37+
yamlKeys.append(key.string ?? "")
38+
}
39+
}
40+
return yamlKeys
41+
}
42+
2343
func parseOpenAPI(
2444
_ input: InMemoryInputFile,
2545
config: Config,

Sources/swift-openapi-generator/GenerateOptions.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,20 @@ extension _GenerateOptions {
8686
if !featureFlag.isEmpty {
8787
return Set(featureFlag)
8888
}
89-
return Set(config?.featureFlags ?? [])
89+
return config?.featureFlags ?? []
90+
}
91+
92+
/// Validates a collection of keys against a predefined set of allowed keys.
93+
///
94+
/// - Parameter keys: A collection of keys to be validated.
95+
/// - Throws: A `ValidationError` if any key in the collection is not found in the
96+
/// allowed set of keys specified by `_UserConfig.codingKeysRawValues`.
97+
func validateKeys(_ keys: [String]) throws {
98+
for key in keys {
99+
if !_UserConfig.codingKeysRawValues.contains(key) {
100+
throw ValidationError("Unknown configuration key found in config file: \(key)")
101+
}
102+
}
90103
}
91104

92105
/// Returns the configuration requested by the user.
@@ -99,6 +112,16 @@ extension _GenerateOptions {
99112
}
100113
do {
101114
let data = try Data(contentsOf: config)
115+
let configAsString = String(decoding: data, as: UTF8.self)
116+
var yamlKeys = [String]()
117+
118+
do {
119+
yamlKeys = try YamsParser.extractTopLevelKeys(fromYAMLString: configAsString)
120+
} catch {
121+
throw ValidationError("The config isn't valid. \(error)")
122+
}
123+
try validateKeys(yamlKeys)
124+
102125
let config = try YAMLDecoder().decode(_UserConfig.self, from: data)
103126
return config
104127
} catch {

Sources/swift-openapi-generator/UserConfig.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,13 @@ struct _UserConfig: Codable {
2929

3030
/// A set of features to explicitly enable.
3131
var featureFlags: FeatureFlags?
32+
33+
/// A set of raw values corresponding to the coding keys of this struct.
34+
static let codingKeysRawValues = Set(CodingKeys.allCases.map({ $0.rawValue }))
35+
36+
enum CodingKeys: String, CaseIterable, CodingKey {
37+
case generate
38+
case additionalImports
39+
case featureFlags
40+
}
3241
}

Tests/OpenAPIGeneratorCoreTests/Parser/Test_YamsParser.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,38 @@ final class Test_YamsParser: Test_Core {
128128
assertThrownError(try _test(yaml), expectedDiagnostic: expected)
129129
}
130130

131+
func testExtractTopLevelKeysWithValidYAML() {
132+
let yaml = """
133+
generate:
134+
- types
135+
- server
136+
137+
featureFlags:
138+
- nullableSchemas
139+
140+
additionalImports:
141+
- Foundation
142+
"""
143+
let keys = try? YamsParser.extractTopLevelKeys(fromYAMLString: yaml)
144+
XCTAssertEqual(keys, ["generate", "featureFlags", "additionalImports"])
145+
}
146+
147+
func testExtractTopLevelKeysWithInvalidYAML() {
148+
// `additionalImports` is missing `:` at the end.
149+
let yaml = """
150+
generate:
151+
- types
152+
- server
153+
154+
featureFlags:
155+
- nullableSchemas
156+
157+
additionalImports
158+
- Foundation
159+
"""
160+
XCTAssertThrowsError(try YamsParser.extractTopLevelKeys(fromYAMLString: yaml))
161+
}
162+
131163
private func _test(_ yaml: String) throws -> ParsedOpenAPIRepresentation {
132164
try YamsParser()
133165
.parseOpenAPI(

0 commit comments

Comments
 (0)