Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Foundation
package import Foundation
import HTTPTypes
import OpenAPIRuntime
package import OpenAPIRuntime

package struct HeaderFieldMiddleware: ClientMiddleware {
var name: HTTPField.Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ struct ImportDescription: Equatable, Codable {
/// would be `@_spi(Secret) import Foo`.
var spi: String? = nil

/// The access modifier to apply to the import statement.
///
/// When set to `.public` or `.package`, the modifier is prepended to the
/// import statement (e.g. `public import Foo`).
var accessModifier: AccessModifier? = nil

/// Whether the global access modifier from the generator config should be
/// applied to this import.
///
/// Set to `false` for modules whose types don't appear in public
/// declarations (e.g. implementation-only imports), so that
/// `public import` or `package import` is not incorrectly emitted.
var setsAccessModifier: Bool = true

/// Requirements for the `@preconcurrency` attribute.
var preconcurrency: PreconcurrencyRequirement = .never

Expand Down
12 changes: 10 additions & 2 deletions Sources/_OpenAPIGeneratorCore/Renderer/TextBasedRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,21 @@ struct TextBasedRenderer: RendererProtocol {

/// Renders a single import statement.
func renderImport(_ description: ImportDescription) {
let accessModifierPrefix: String
switch description.accessModifier {
case .public: accessModifierPrefix = renderedAccessModifier(.public) + " "
case .package: accessModifierPrefix = renderedAccessModifier(.package) + " "
default: accessModifierPrefix = ""
}

func render(preconcurrency: Bool) {
let spiPrefix = description.spi.map { "@_spi(\($0)) " } ?? ""
let preconcurrencyPrefix = preconcurrency ? "@preconcurrency " : ""
let attributePrefix = "\(preconcurrencyPrefix)\(spiPrefix)"
if let moduleTypes = description.moduleTypes {
for type in moduleTypes { writer.writeLine("\(preconcurrencyPrefix)\(spiPrefix)import \(type)") }
for type in moduleTypes { writer.writeLine("\(attributePrefix)\(accessModifierPrefix)import \(type)") }
} else {
writer.writeLine("\(preconcurrencyPrefix)\(spiPrefix)import \(description.moduleName)")
writer.writeLine("\(attributePrefix)\(accessModifierPrefix)import \(description.moduleName)")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ struct ClientFileTranslator: FileTranslator {

let topComment = self.topComment

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

let clientMethodDecls = try OperationDescription.all(from: doc.paths, in: components, context: context)
.map(translateClientMethod(_:))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ enum Constants {

/// The descriptions of modules imported by client and server files.
static let clientServerImports: [ImportDescription] =
imports + [ImportDescription(moduleName: Constants.Import.httpTypes)]
imports + [ImportDescription(moduleName: Constants.Import.httpTypes, setsAccessModifier: false)]
}

/// Constants related to the OpenAPI server object.
Expand Down
25 changes: 25 additions & 0 deletions Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,31 @@ extension FileTranslator {
var topComment: Comment {
.inline(([Constants.File.topComment] + config.additionalFileComments).joined(separator: "\n"))
}

/// Returns the imports for the generated file, with access modifiers applied.
///
/// The configured access modifier is propagated to the built-in imports so
/// that, under Swift 6's `InternalImportsByDefault` flag, generated
/// declarations can re-export the symbols they depend on.
/// `additionalImports` from the configuration are also given the same
/// access modifier so they are visible to consumers of the generated code.
/// - Parameter baseImports: the base set of imports for the file (e.g.
/// ``Constants/File/imports`` or ``Constants/File/clientServerImports``).
/// - Returns: An array of ``ImportDescription`` values with appropriate
/// access modifier set.
func importDescriptions(adding baseImports: [ImportDescription]) -> [ImportDescription] {
let accessModifier: AccessModifier?
switch config.access {
case .public, .package: accessModifier = config.access
default: accessModifier = nil
}
let allImports = baseImports + config.additionalImports.map { ImportDescription(moduleName: $0) }
return allImports.map { original in
var description = original
description.accessModifier = original.setsAccessModifier ? accessModifier : nil
return description
}
}
}

/// A set of configuration values for concrete file translators.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ struct ServerFileTranslator: FileTranslator {

let topComment = self.topComment

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

let allOperations = try OperationDescription.all(from: doc.paths, in: components, context: context)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct TypesFileTranslator: FileTranslator {

let topComment = self.topComment

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

let apiProtocol = try translateAPIProtocol(doc.paths)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,76 @@ final class Test_TextBasedRenderer: XCTestCase {
)
}

func testImportsWithPublicAccessModifier() throws {
try _test(
[ImportDescription(moduleName: "Foo", accessModifier: .public)],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
public import Foo
"""#
)
}

func testImportsWithPackageAccessModifier() throws {
try _test(
[ImportDescription(moduleName: "Foo", accessModifier: .package)],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
package import Foo
"""#
)
}

func testImportsWithInternalAccessModifier() throws {
try _test(
[ImportDescription(moduleName: "Foo", accessModifier: .internal)],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
import Foo
"""#
)
}

func testImportsWithAccessModifierAndAttributes() throws {
try _test(
[ImportDescription(moduleName: "Foo", spi: "Secret", accessModifier: .public, preconcurrency: .always)],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
@preconcurrency @_spi(Secret) public import Foo
"""#
)
}

func testImportsWithAccessModifierAndModuleTypes() throws {
try _test(
[
ImportDescription(
moduleName: "Foundation",
moduleTypes: ["struct Foundation.URL"],
accessModifier: .public
)
],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
public import struct Foundation.URL
"""#
)
}

func testImportsWithAccessModifierAndPreconcurrencyOnOS() throws {
try _test(
[ImportDescription(moduleName: "Foo", accessModifier: .public, preconcurrency: .onOS(["Linux"]))],
renderedBy: TextBasedRenderer.renderImports,
rendersAs: #"""
#if os(Linux)
@preconcurrency public import Foo
#else
public import Foo
#endif
"""#
)
}

func testAccessModifiers() throws {
try _test(
.public,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Generated by swift-openapi-generator, do not modify.
@_spi(Generated) import OpenAPIRuntime
@_spi(Generated) public import OpenAPIRuntime
#if os(Linux)
@preconcurrency import struct Foundation.URL
@preconcurrency import struct Foundation.Data
@preconcurrency import struct Foundation.Date
@preconcurrency public import struct Foundation.URL
@preconcurrency public import struct Foundation.Data
@preconcurrency public import struct Foundation.Date
#else
import struct Foundation.URL
import struct Foundation.Data
import struct Foundation.Date
public import struct Foundation.URL
public import struct Foundation.Data
public import struct Foundation.Date
#endif
import HTTPTypes
/// Service for managing pet metadata.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Generated by swift-openapi-generator, do not modify.
@_spi(Generated) import OpenAPIRuntime
@_spi(Generated) public import OpenAPIRuntime
#if os(Linux)
@preconcurrency import struct Foundation.URL
@preconcurrency import struct Foundation.Data
@preconcurrency import struct Foundation.Date
@preconcurrency public import struct Foundation.URL
@preconcurrency public import struct Foundation.Data
@preconcurrency public import struct Foundation.Date
#else
import struct Foundation.URL
import struct Foundation.Data
import struct Foundation.Date
public import struct Foundation.URL
public import struct Foundation.Data
public import struct Foundation.Date
#endif
import HTTPTypes
extension APIProtocol {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Generated by swift-openapi-generator, do not modify.
@_spi(Generated) import OpenAPIRuntime
@_spi(Generated) public import OpenAPIRuntime
#if os(Linux)
@preconcurrency import struct Foundation.URL
@preconcurrency import struct Foundation.Data
@preconcurrency import struct Foundation.Date
@preconcurrency public import struct Foundation.URL
@preconcurrency public import struct Foundation.Data
@preconcurrency public import struct Foundation.Date
#else
import struct Foundation.URL
import struct Foundation.Data
import struct Foundation.Date
public import struct Foundation.URL
public import struct Foundation.Data
public import struct Foundation.Date
#endif
/// A type that performs HTTP operations defined by the OpenAPI document.
public protocol APIProtocol: Sendable {
Expand Down