Skip to content

Commit

Permalink
Merge branch 'main' into proposal/generate-server-variable-enums
Browse files Browse the repository at this point in the history
  • Loading branch information
czechboy0 authored Oct 11, 2024
2 parents 9db3c2f + ef6d07f commit 39319d6
Show file tree
Hide file tree
Showing 57 changed files with 911 additions and 226 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ on:
jobs:
soundness:
name: Soundness
uses: apple/swift-nio/.github/workflows/soundness.yml@main
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
with:
api_breakage_check_enabled: true
api_breakage_check_enabled: false
broken_symlink_check_enabled: true
docs_check_enabled: true
format_check_enabled: true
license_header_check_enabled: true
license_header_check_project_name: "SwiftOpenAPIGenerator"
shell_check_enabled: true
unacceptable_language_check_enabled: true
yamllint_check_enabled: false

unit-tests:
name: Unit tests
Expand All @@ -33,7 +34,7 @@ jobs:
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
with:
name: "Integration test"
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && ./scripts/run-integration-test.sh"
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && SWIFT_OPENAPI_GENERATOR_REPO_URL=file://${GITHUB_WORKSPACE} ./scripts/run-integration-test.sh"
matrix_linux_5_8_enabled: false
matrix_linux_nightly_main_enabled: false

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
with:
name: "Integration test"
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && ./scripts/run-integration-test.sh"
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && SWIFT_OPENAPI_GENERATOR_REPO_URL=file://${GITHUB_WORKSPACE} ./scripts/run-integration-test.sh"
matrix_linux_5_8_enabled: false

example-packages:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1628,9 +1628,15 @@ extension KeywordKind {
}

extension Declaration {
/// Returns a new deprecated variant of the declaration if the provided `description` is not `nil`.
func deprecate(if description: DeprecationDescription?) -> Self {
if let description { return .deprecated(description, self) }
return self
}

/// Returns a new deprecated variant of the declaration if `shouldDeprecate` is true.
func deprecate(if shouldDeprecate: Bool) -> Self {
if shouldDeprecate { return .deprecated(.init(), self) }
func deprecate(if shouldDeprecate: Bool, description: @autoclosure () -> DeprecationDescription = .init()) -> Self {
if shouldDeprecate { return .deprecated(description(), self) }
return self
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ struct ClientFileTranslator: FileTranslator {
let imports =
Constants.File.clientServerImports + config.additionalImports.map { ImportDescription(moduleName: $0) }

let clientMethodDecls =
try OperationDescription.all(from: doc.paths, in: components, asSwiftSafeName: swiftSafeName)
let clientMethodDecls = try OperationDescription.all(from: doc.paths, in: components, context: context)
.map(translateClientMethod(_:))

let clientStructPropertyDecl: Declaration = .commentable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,7 @@
//===----------------------------------------------------------------------===//
import Foundation

extension FileTranslator {

/// Returns a copy of the string modified to be a valid Swift identifier.
///
/// - Parameter string: The string to convert to be safe for Swift.
/// - Returns: A Swift-safe version of the input string.
func swiftSafeName(for string: String) -> String { string.safeForSwiftCode }
}

fileprivate extension String {
extension String {

/// Returns a string sanitized to be usable as a Swift identifier.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ extension TypesFileTranslator {
parent: typeName
)
let associatedDeclarations: [Declaration]
if TypeMatcher.isInlinable(schema) {
if typeMatcher.isInlinable(schema) {
associatedDeclarations = try translateSchema(
typeName: propertyType.typeName,
schema: schema,
Expand All @@ -78,10 +78,10 @@ extension TypesFileTranslator {
originalName: key,
typeUsage: propertyType,
associatedDeclarations: associatedDeclarations,
asSwiftSafeName: swiftSafeName
context: context
)
var referenceStack = ReferenceStack.empty
let isKeyValuePairSchema = try TypeMatcher.isKeyValuePair(
let isKeyValuePairSchema = try typeMatcher.isKeyValuePair(
schema,
referenceStack: &referenceStack,
components: components
Expand Down Expand Up @@ -173,7 +173,7 @@ extension TypesFileTranslator {
parent: typeName
)
let associatedDeclarations: [Declaration]
if TypeMatcher.isInlinable(schema) {
if typeMatcher.isInlinable(schema) {
associatedDeclarations = try translateSchema(
typeName: childType.typeName,
schema: schema,
Expand All @@ -183,7 +183,7 @@ extension TypesFileTranslator {
associatedDeclarations = []
}
var referenceStack = ReferenceStack.empty
let isKeyValuePair = try TypeMatcher.isKeyValuePair(
let isKeyValuePair = try typeMatcher.isKeyValuePair(
schema,
referenceStack: &referenceStack,
components: components
Expand All @@ -209,7 +209,7 @@ extension TypesFileTranslator {
let decoder: Declaration
if let discriminator {
let originalName = discriminator.propertyName
let swiftName = swiftSafeName(for: originalName)
let swiftName = context.asSwiftSafeName(originalName)
codingKeysDecls = [
.enum(
accessModifier: config.access,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ extension TypesFileTranslator {
parent: typeName
)
let associatedDeclarations: [Declaration]
if TypeMatcher.isInlinable(value) {
if typeMatcher.isInlinable(value) {
associatedDeclarations = try translateSchema(
typeName: propertyType.typeName,
schema: value,
Expand All @@ -100,7 +100,7 @@ extension TypesFileTranslator {
originalName: key,
typeUsage: propertyType,
associatedDeclarations: associatedDeclarations,
asSwiftSafeName: swiftSafeName
context: context
)
}

Expand Down Expand Up @@ -153,7 +153,7 @@ extension TypesFileTranslator {
components: components,
inParent: parent
)
if TypeMatcher.isInlinable(schema) {
if typeMatcher.isInlinable(schema) {
associatedDeclarations = try translateSchema(
typeName: valueTypeUsage.typeName,
schema: schema,
Expand All @@ -175,7 +175,7 @@ extension TypesFileTranslator {
default: .emptyInit,
isSerializedInTopLevelDictionary: false,
associatedDeclarations: associatedDeclarations,
asSwiftSafeName: swiftSafeName
context: context
)
return (.allowingAdditionalProperties, extraProperty)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ extension FileTranslator {
// In nullable enum schemas, empty strings are parsed as Void.
// This is unlikely to be fixed, so handling that case here.
// https://github.com/apple/swift-openapi-generator/issues/118
if isNullable && anyValue is Void { return (swiftSafeName(for: ""), .string("")) }
if isNullable && anyValue is Void { return (context.asSwiftSafeName(""), .string("")) }
guard let rawValue = anyValue as? String else {
throw GenericError(message: "Disallowed value for a string enum '\(typeName)': \(anyValue)")
}
let caseName = swiftSafeName(for: rawValue)
let caseName = context.asSwiftSafeName(rawValue)
return (caseName, .string(rawValue))
case .integer:
let rawValue: Int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ enum Constants {

/// The prefix of each generated method name.
static let propertyPrefix: String = "server"
/// The name of each generated static function.
static let urlStaticFunc: String = "url"

/// The prefix of the namespace that contains server specific variables.
static let serverNamespacePrefix: String = "Server"

/// Constants related to the OpenAPI server variable object.
enum Variable {

/// The types that the protocol conforms to.
static let conformances: [String] = [TypeName.string.fullyQualifiedSwiftName, "Sendable"]
}
}

/// Constants related to the configuration type, which is used by both
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ extension FileTranslator {
/// component.
/// - Parameter type: The `OneOfMappedType` for which to determine the case name.
/// - Returns: A string representing the safe Swift name for the specified `OneOfMappedType`.
func safeSwiftNameForOneOfMappedType(_ type: OneOfMappedType) -> String { swiftSafeName(for: type.rawNames[0]) }
func safeSwiftNameForOneOfMappedType(_ type: OneOfMappedType) -> String {
context.asSwiftSafeName(type.rawNames[0])
}
}

extension OpenAPI.Discriminator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,14 @@ struct PropertyBlueprint {
/// referring to them in the property.
var associatedDeclarations: [Declaration] = []

/// A converted function from user-provided strings to strings
/// safe to be used as a Swift identifier.
var asSwiftSafeName: (String) -> String
/// A set of configuration values that inform translation.
var context: TranslatorContext
}

extension PropertyBlueprint {

/// A name that is verified to be a valid Swift identifier.
var swiftSafeName: String { asSwiftSafeName(originalName) }
var swiftSafeName: String { context.asSwiftSafeName(originalName) }

/// The JSON path to the property.
///
Expand Down
16 changes: 16 additions & 0 deletions Sources/_OpenAPIGeneratorCore/Translator/FileTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,19 @@ protocol FileTranslator {
/// - Throws: An error if translation encounters issues or errors during the process.
func translateFile(parsedOpenAPI: ParsedOpenAPIRepresentation) throws -> StructuredSwiftRepresentation
}

extension FileTranslator {

/// A new context from the file translator.
var context: TranslatorContext { TranslatorContext(asSwiftSafeName: { $0.safeForSwiftCode }) }
}

/// A set of configuration values for concrete file translators.
struct TranslatorContext {

/// A closure that returns a copy of the string modified to be a valid Swift identifier.
///
/// - Parameter string: The string to convert to be safe for Swift.
/// - Returns: A Swift-safe version of the input string.
var asSwiftSafeName: (String) -> String
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ extension MultipartSchemaTypedContent {
}
}

extension SchemaContent {
extension TypeMatcher {
/// Returns a Boolean value whether the schema is a multipart content type and is referenceable.
var isReferenceableMultipart: Bool {
guard contentType.isMultipart else { return false }
let ref = TypeMatcher.multipartElementTypeReferenceIfReferenceable(schema: schema, encoding: encoding)
func isReferenceableMultipart(_ content: SchemaContent) -> Bool {
guard content.contentType.isMultipart else { return false }
let ref = multipartElementTypeReferenceIfReferenceable(schema: content.schema, encoding: content.encoding)
return ref == nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ extension FileTranslator {
}
var parts: [MultipartSchemaTypedContent] = try topLevelObject.properties.compactMap {
(key, value) -> MultipartSchemaTypedContent? in
let swiftSafeName = swiftSafeName(for: key)
let swiftSafeName = context.asSwiftSafeName(key)
let typeName = typeName.appending(
swiftComponent: swiftSafeName + Constants.Global.inlineTypeSuffix,
jsonComponent: key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ extension TypesFileTranslator {
typeUsage: headersTypeName.asUsage,
default: headersStructBlueprint.hasEmptyInit ? .emptyInit : nil,
associatedDeclarations: [headersStructDecl],
asSwiftSafeName: swiftSafeName
context: context
)
} else {
headersProperty = nil
Expand All @@ -76,7 +76,7 @@ extension TypesFileTranslator {
inParent: typeName.appending(swiftComponent: nil, jsonComponent: "content")
)
let associatedDeclarations: [Declaration]
if TypeMatcher.isInlinable(schema) {
if typeMatcher.isInlinable(schema) {
associatedDeclarations = try translateSchema(
typeName: bodyTypeUsage.typeName,
schema: schema,
Expand All @@ -90,7 +90,7 @@ extension TypesFileTranslator {
originalName: Constants.Operation.Body.variableName,
typeUsage: bodyTypeUsage,
associatedDeclarations: associatedDeclarations,
asSwiftSafeName: swiftSafeName
context: context
)
let structDecl = translateStructBlueprint(
.init(
Expand All @@ -117,7 +117,7 @@ extension TypesFileTranslator {
schema: JSONSchema
) throws -> [Declaration] {
let associatedDeclarations: [Declaration]
if TypeMatcher.isInlinable(schema) {
if typeMatcher.isInlinable(schema) {
associatedDeclarations = try translateSchema(typeName: typeName, schema: schema, overrides: .none)
} else {
associatedDeclarations = []
Expand All @@ -137,7 +137,7 @@ extension TypesFileTranslator {
switch part {
case .documentedTyped(let documentedPart):
let caseDecl: Declaration = .enumCase(
name: swiftSafeName(for: documentedPart.originalName),
name: context.asSwiftSafeName(documentedPart.originalName),
kind: .nameWithAssociatedValues([.init(type: .init(part.wrapperTypeUsage))])
)
let decl = try translateMultipartPartContent(
Expand Down Expand Up @@ -404,7 +404,7 @@ extension FileTranslator {
switch part {
case .documentedTyped(let part):
let originalName = part.originalName
let identifier = swiftSafeName(for: originalName)
let identifier = context.asSwiftSafeName(originalName)
let contentType = part.partInfo.contentType
let partTypeName = part.typeName
let schema = part.schema
Expand Down Expand Up @@ -613,7 +613,7 @@ extension FileTranslator {
switch part {
case .documentedTyped(let part):
let originalName = part.originalName
let identifier = swiftSafeName(for: originalName)
let identifier = context.asSwiftSafeName(originalName)
let contentType = part.partInfo.contentType
let headersTypeName = part.typeName.appending(
swiftComponent: Constants.Operation.Output.Payload.Headers.typeName,
Expand Down
Loading

0 comments on commit 39319d6

Please sign in to comment.