Skip to content

Commit

Permalink
Merge branch 'main' into error_handling
Browse files Browse the repository at this point in the history
  • Loading branch information
czechboy0 authored Nov 22, 2024
2 parents 55bd604 + 31fa50a commit 42d6259
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 124 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Main

on:
push:
branches: [main]
schedule:
- cron: "0 8,20 * * *"

jobs:
unit-tests:
name: Unit tests
uses: apple/swift-nio/.github/workflows/unit_tests.yml@main
with:
linux_5_9_arguments_override: "--explicit-target-dependency-import-check error"
linux_5_10_arguments_override: "--explicit-target-dependency-import-check error"
linux_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error"

integration-test:
name: Integration test
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 && SWIFT_OPENAPI_GENERATOR_REPO_URL=file://${GITHUB_WORKSPACE} ./scripts/run-integration-test.sh"

example-packages:
name: Example packages
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
with:
name: "Example packages"
matrix_linux_command: "./scripts/test-examples.sh"
5 changes: 0 additions & 5 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,3 @@ jobs:
name: "Example packages"
matrix_linux_command: "./scripts/test-examples.sh"
matrix_linux_nightly_main_enabled: false

swift-6-language-mode:
name: Swift 6 Language Mode
uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main
if: false # Disabled for now.
30 changes: 0 additions & 30 deletions .github/workflows/scheduled.yml

This file was deleted.

5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ let package = Package(

// General algorithms
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"),
.package(url: "https://github.com/apple/swift-collections", from: "1.1.4"),

// Read OpenAPI documents
.package(url: "https://github.com/mattpolzin/OpenAPIKit", from: "3.3.0"),
Expand All @@ -72,7 +73,9 @@ let package = Package(
.product(name: "OpenAPIKit", package: "OpenAPIKit"),
.product(name: "OpenAPIKit30", package: "OpenAPIKit"),
.product(name: "OpenAPIKitCompat", package: "OpenAPIKit"),
.product(name: "Algorithms", package: "swift-algorithms"), .product(name: "Yams", package: "Yams"),
.product(name: "Algorithms", package: "swift-algorithms"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "Yams", package: "Yams"),
],
swiftSettings: swiftSettings
),
Expand Down
2 changes: 1 addition & 1 deletion Sources/_OpenAPIGeneratorCore/Parser/YamsParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ extension Diagnostic {
static func openAPIMissingVersionError(location: Location) -> Diagnostic {
error(
message:
"No openapi key found, please provide a valid OpenAPI document with OpenAPI versions in the 3.0.x or 3.1.x sets.",
"No key named openapi found. Please provide a valid OpenAPI document with OpenAPI versions in the 3.0.x or 3.1.x sets.",
location: location
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftOpenAPIGenerator open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import OpenAPIKit
import OrderedCollections

/// The backing type of a raw enum.
enum RawEnumBackingType {

/// Backed by a `String`.
case string

/// Backed by an `Int`.
case integer
}

/// The extracted enum value's identifier.
private enum EnumCaseID: Hashable, CustomStringConvertible {

/// A string value.
case string(String)

/// An integer value.
case integer(Int)

var description: String {
switch self {
case .string(let value): return "\"\(value)\""
case .integer(let value): return String(value)
}
}
}

/// A wrapper for the metadata about the raw enum case.
private struct EnumCase {

/// Used for checking uniqueness.
var id: EnumCaseID

/// The raw Swift-safe name for the case.
var caseName: String

/// The literal value of the enum case.
var literal: LiteralDescription
}

extension EnumCase: Equatable { static func == (lhs: EnumCase, rhs: EnumCase) -> Bool { lhs.id == rhs.id } }

extension EnumCase: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(id) } }

extension FileTranslator {

/// Returns a declaration of the specified raw value-based enum schema.
/// - Parameters:
/// - backingType: The backing type of the enum.
/// - typeName: The name of the type to give to the declared enum.
/// - userDescription: A user-specified description from the OpenAPI
/// document.
/// - isNullable: Whether the enum schema is nullable.
/// - allowedValues: The enumerated allowed values.
/// - Throws: A `GenericError` if a disallowed value is encountered.
/// - Returns: A declaration of the specified raw value-based enum schema.
func translateRawEnum(
backingType: RawEnumBackingType,
typeName: TypeName,
userDescription: String?,
isNullable: Bool,
allowedValues: [AnyCodable]
) throws -> Declaration {
var cases: OrderedSet<EnumCase> = []
func addIfUnique(id: EnumCaseID, caseName: String) throws {
let literal: LiteralDescription
switch id {
case .string(let string): literal = .string(string)
case .integer(let int): literal = .int(int)
}
guard cases.append(.init(id: id, caseName: caseName, literal: literal)).inserted else {
try diagnostics.emit(
.warning(
message: "Duplicate enum value, skipping",
context: ["id": "\(id)", "foundIn": typeName.description]
)
)
return
}
}
for anyValue in allowedValues.map(\.value) {
switch backingType {
case .string:
// 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 {
try addIfUnique(id: .string(""), caseName: context.asSwiftSafeName(""))
} else {
guard let rawValue = anyValue as? String else {
throw GenericError(message: "Disallowed value for a string enum '\(typeName)': \(anyValue)")
}
let caseName = context.asSwiftSafeName(rawValue)
try addIfUnique(id: .string(rawValue), caseName: caseName)
}
case .integer:
let rawValue: Int
if let intRawValue = anyValue as? Int {
rawValue = intRawValue
} else if let stringRawValue = anyValue as? String, let intRawValue = Int(stringRawValue) {
rawValue = intRawValue
} else {
throw GenericError(message: "Disallowed value for an integer enum '\(typeName)': \(anyValue)")
}
let caseName = rawValue < 0 ? "_n\(abs(rawValue))" : "_\(rawValue)"
try addIfUnique(id: .integer(rawValue), caseName: caseName)
}
}
let baseConformance: String
switch backingType {
case .string: baseConformance = Constants.RawEnum.baseConformanceString
case .integer: baseConformance = Constants.RawEnum.baseConformanceInteger
}
let conformances = [baseConformance] + Constants.RawEnum.conformances
return try translateRawRepresentableEnum(
typeName: typeName,
conformances: conformances,
userDescription: userDescription,
cases: cases.map { ($0.caseName, $0.literal) },
unknownCaseName: nil,
unknownCaseDescription: nil
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ final class Test_YamsParser: Test_Core {
"""

let expected =
"/foo.yaml: error: No openapi key found, please provide a valid OpenAPI document with OpenAPI versions in the 3.0.x or 3.1.x sets."
"/foo.yaml: error: No key named openapi found. Please provide a valid OpenAPI document with OpenAPI versions in the 3.0.x or 3.1.x sets."
assertThrownError(try _test(yaml), expectedDiagnostic: expected)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,33 @@ final class SnippetBasedReferenceTests: XCTestCase {
)
}

func testComponentsSchemasStringEnumWithDuplicates() throws {
try self.assertSchemasTranslation(
ignoredDiagnosticMessages: ["Duplicate enum value, skipping"],
"""
schemas:
MyEnum:
type: string
enum:
- one
- two
- three
- two
- four
""",
"""
public enum Schemas {
@frozen public enum MyEnum: String, Codable, Hashable, Sendable, CaseIterable {
case one = "one"
case two = "two"
case three = "three"
case four = "four"
}
}
"""
)
}

func testComponentsSchemasIntEnum() throws {
try self.assertSchemasTranslation(
"""
Expand Down

0 comments on commit 42d6259

Please sign in to comment.