Skip to content

Commit 0964f1c

Browse files
Add support for configurable comments in generated files
Users want the ability to add custom comments to generated files. One concrete use case is adding directives like `swift-format-ignore-file` and `swiftlint:disable all` to prevent these tools from processing generated code. - Added `additionalFileComments` property to `Config` and `UserConfig` structs - Modified `FileTranslator` to include additional comments along with the do-not-edit comment - Added CLI support with `--additional-file-comment` option - Added config tests to confirm the option propagates and the default is empty - Added snippet tests to validate the actual rendering - Updated documentation with examples and usage instructions Users can now configure additional comments to be added to generated files using either the config file or a command line option. Fixes #738. - Added unit tests for `Config` - Added snippet tests for rendering - Manual tests of generator using config and CLI on real OpenAPI doc: ```console % swift run swift-openapi-generator generate openapi-documents/petstore.yaml \ --mode types \ --output-directory test-output-cli \ --additional-file-comment "hello world" \ --additional-file-comment "testing, testing, 1, 2, 3" Build of product 'swift-openapi-generator' complete! (3.27s) Swift OpenAPI Generator is running with the following configuration: - OpenAPI document path: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/openapi-documents/petstore.yaml - Configuration path: <none> - Generator modes: types - Access modifier: internal - Naming strategy: defensive - Name overrides: <none> - Feature flags: <none> - Output file names: Types.swift - Output directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/test-output-cli - Diagnostics output path: <none - logs to stderr> - Current directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator - Plugin source: <none> - Is dry run: false - Additional imports: <none> - Additional file comments: hello world, testing, testing, 1, 2, 3 Writing data to file Types.swift... % head -5 test-output-cli/Types.swift // Generated by swift-openapi-generator, do not modify. // hello world // testing, testing, 1, 2, 3 @_spi(Generated) import OpenAPIRuntime ```
1 parent 0bd6d84 commit 0964f1c

File tree

11 files changed

+109
-4
lines changed

11 files changed

+109
-4
lines changed

Sources/_OpenAPIGeneratorCore/Config.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public struct Config: Sendable {
4646
/// Additional imports to add to each generated file.
4747
public var additionalImports: [String]
4848

49+
/// Additional comments to add to the top of each generated file.
50+
public var additionalFileComments: [String]
51+
4952
/// Filter to apply to the OpenAPI document before generation.
5053
public var filter: DocumentFilter?
5154

@@ -68,6 +71,7 @@ public struct Config: Sendable {
6871
/// - mode: The mode to use for generation.
6972
/// - access: The access modifier to use for generated declarations.
7073
/// - additionalImports: Additional imports to add to each generated file.
74+
/// - additionalFileComments: Additional comments to add to the top of each generated file.
7175
/// - filter: Filter to apply to the OpenAPI document before generation.
7276
/// - namingStrategy: The naming strategy to use for deriving Swift identifiers from OpenAPI identifiers.
7377
/// Defaults to `defensive`.
@@ -78,6 +82,7 @@ public struct Config: Sendable {
7882
mode: GeneratorMode,
7983
access: AccessModifier,
8084
additionalImports: [String] = [],
85+
additionalFileComments: [String] = [],
8186
filter: DocumentFilter? = nil,
8287
namingStrategy: NamingStrategy,
8388
nameOverrides: [String: String] = [:],
@@ -86,6 +91,7 @@ public struct Config: Sendable {
8691
self.mode = mode
8792
self.access = access
8893
self.additionalImports = additionalImports
94+
self.additionalFileComments = additionalFileComments
8995
self.filter = filter
9096
self.namingStrategy = namingStrategy
9197
self.nameOverrides = nameOverrides

Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/ClientTranslator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct ClientFileTranslator: FileTranslator {
3232

3333
let doc = parsedOpenAPI
3434

35-
let topComment: Comment = .inline(Constants.File.topComment)
35+
let topComment = self.topComment
3636

3737
let imports =
3838
Constants.File.clientServerImports + config.additionalImports.map { ImportDescription(moduleName: $0) }

Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ extension FileTranslator {
8383
)
8484
return TranslatorContext(safeNameGenerator: overridingGenerator)
8585
}
86+
87+
/// Creates a top comment that includes the default "do not modify" comment
88+
/// and any additional file comments from the configuration.
89+
var topComment: Comment {
90+
.inline(([Constants.File.topComment] + config.additionalFileComments).joined(separator: "\n"))
91+
}
8692
}
8793

8894
/// A set of configuration values for concrete file translators.

Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct ServerFileTranslator: FileTranslator {
3030

3131
let doc = parsedOpenAPI
3232

33-
let topComment: Comment = .inline(Constants.File.topComment)
33+
let topComment = self.topComment
3434

3535
let imports =
3636
Constants.File.clientServerImports + config.additionalImports.map { ImportDescription(moduleName: $0) }

Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/TypesFileTranslator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct TypesFileTranslator: FileTranslator {
3232

3333
let doc = parsedOpenAPI
3434

35-
let topComment: Comment = .inline(Constants.File.topComment)
35+
let topComment = self.topComment
3636

3737
let imports = Constants.File.imports + config.additionalImports.map { ImportDescription(moduleName: $0) }
3838

Sources/swift-openapi-generator/Documentation.docc/Articles/Configuring-the-generator.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The configuration file has the following keys:
3535
- `package`: Generated API is accessible from other modules within the same package or project.
3636
- `internal` (default): Generated API is accessible from the containing module only.
3737
- `additionalImports` (optional): array of strings. Each string value is a Swift module name. An import statement will be added to the generated source files for each module.
38+
- `additionalFileComments` (optional): array of strings. Each string value is a comment that will be added to the top of each generated file (after the do-not-edit comment). Useful for adding directives like `swift-format-ignore-file` or `swiftlint:disable all`.
3839
- `filter` (optional): Filters to apply to the OpenAPI document before generation.
3940
- `operations`: Operations with these operation IDs will be included in the filter.
4041
- `tags`: Operations tagged with these tags will be included in the filter.
@@ -95,6 +96,18 @@ additionalImports:
9596
accessModifier: public
9697
```
9798

99+
To add file comments to exclude generated files from formatting tools:
100+
101+
```yaml
102+
generate:
103+
- types
104+
- client
105+
namingStrategy: idiomatic
106+
additionalFileComments:
107+
- "swift-format-ignore-file"
108+
- "swiftlint:disable all"
109+
```
110+
98111
### Document filtering
99112

100113
The generator supports filtering the OpenAPI document prior to generation, which can be useful when

Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extension _GenerateOptions {
3232
let sortedModes = try resolvedModes(config)
3333
let resolvedAccessModifier = resolvedAccessModifier(config)
3434
let resolvedAdditionalImports = resolvedAdditionalImports(config)
35+
let resolvedAdditionalFileComments = resolvedAdditionalFileComments(config)
3536
let resolvedNamingStragy = resolvedNamingStrategy(config)
3637
let resolvedNameOverrides = resolvedNameOverrides(config)
3738
let resolvedFeatureFlags = resolvedFeatureFlags(config)
@@ -40,6 +41,7 @@ extension _GenerateOptions {
4041
mode: $0,
4142
access: resolvedAccessModifier,
4243
additionalImports: resolvedAdditionalImports,
44+
additionalFileComments: resolvedAdditionalFileComments,
4345
filter: config?.filter,
4446
namingStrategy: resolvedNamingStragy,
4547
nameOverrides: resolvedNameOverrides,
@@ -67,6 +69,7 @@ extension _GenerateOptions {
6769
- Plugin source: \(pluginSource?.rawValue ?? "<none>")
6870
- Is dry run: \(isDryRun)
6971
- Additional imports: \(resolvedAdditionalImports.isEmpty ? "<none>" : resolvedAdditionalImports.joined(separator: ", "))
72+
- Additional file comments: \(resolvedAdditionalFileComments.isEmpty ? "<none>" : resolvedAdditionalFileComments.joined(separator: ", "))
7073
"""
7174
)
7275
do {

Sources/swift-openapi-generator/GenerateOptions.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct _GenerateOptions: ParsableArguments {
4040

4141
@Option(help: "Additional import to add to all generated files.") var additionalImport: [String] = []
4242

43+
@Option(help: "Additional file comment to add to all generated files.") var additionalFileComment: [String] = []
44+
4345
@Option(help: "Pre-release feature to enable. Options: \(FeatureFlag.prettyListing).") var featureFlag:
4446
[FeatureFlag] = []
4547

@@ -81,6 +83,17 @@ extension _GenerateOptions {
8183
return []
8284
}
8385

86+
/// Returns a list of additional file comments requested by the user.
87+
/// - Parameter config: The configuration specified by the user.
88+
/// - Returns: A list of additional file comments requested by the user.
89+
func resolvedAdditionalFileComments(_ config: _UserConfig?) -> [String] {
90+
if !additionalFileComment.isEmpty { return additionalFileComment }
91+
if let additionalFileComments = config?.additionalFileComments, !additionalFileComments.isEmpty {
92+
return additionalFileComments
93+
}
94+
return []
95+
}
96+
8497
/// Returns the naming strategy requested by the user.
8598
/// - Parameter config: The configuration specified by the user.
8699
/// - Returns: The naming strategy requestd by the user.

Sources/swift-openapi-generator/UserConfig.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ struct _UserConfig: Codable {
3030
/// generated Swift file.
3131
var additionalImports: [String]?
3232

33+
/// A list of additional comments that are added to the top of every
34+
/// generated Swift file.
35+
var additionalFileComments: [String]?
36+
3337
/// Filter to apply to the OpenAPI document before generation.
3438
var filter: DocumentFilter?
3539

@@ -51,6 +55,7 @@ struct _UserConfig: Codable {
5155
case generate
5256
case accessModifier
5357
case additionalImports
58+
case additionalFileComments
5459
case filter
5560
case namingStrategy
5661
case nameOverrides

Tests/OpenAPIGeneratorCoreTests/Test_Config.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,17 @@ import OpenAPIKit
1717

1818
final class Test_Config: Test_Core {
1919
func testDefaultAccessModifier() { XCTAssertEqual(Config.defaultAccessModifier, .internal) }
20+
func testAdditionalFileComments() {
21+
let config = Config(
22+
mode: .types,
23+
access: .public,
24+
additionalFileComments: ["swift-format-ignore-file", "swiftlint:disable all"],
25+
namingStrategy: .defensive
26+
)
27+
XCTAssertEqual(config.additionalFileComments, ["swift-format-ignore-file", "swiftlint:disable all"])
28+
}
29+
func testEmptyAdditionalFileComments() {
30+
let config = Config(mode: .types, access: .public, namingStrategy: .defensive)
31+
XCTAssertEqual(config.additionalFileComments, [])
32+
}
2033
}

0 commit comments

Comments
 (0)