Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare 0.2.0 release (API breaking changes) #218

Merged
merged 26 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bcaf21b
WIP on integrating the experimental URI coder
czechboy0 Aug 24, 2023
ce5b9dc
Merge branch 'main' into hd-uri-encoder-integration
czechboy0 Aug 24, 2023
2034dff
Prepare 0.2.0 release (API breaking changes)
czechboy0 Aug 24, 2023
e3b0b64
Testing on headers, seems to work
czechboy0 Aug 24, 2023
463cf3e
Prep 0.2.0 in docs
czechboy0 Aug 24, 2023
db20edd
Fix a warning
czechboy0 Aug 24, 2023
cf2e3e1
WIP
czechboy0 Aug 25, 2023
d64226f
Path params
czechboy0 Aug 25, 2023
b1376fc
Query params
czechboy0 Aug 25, 2023
1800097
Reformat
czechboy0 Aug 25, 2023
9fa8dbc
Request bodies working
czechboy0 Aug 25, 2023
dc2b652
More cleanup, update docs
czechboy0 Aug 25, 2023
bad6127
Support OpenAPI 3.1 in addition to 3.0
czechboy0 Aug 25, 2023
5e66c2e
No need for a feature flag
czechboy0 Aug 26, 2023
c722997
Update docs
czechboy0 Aug 26, 2023
89a93e5
Update docs
czechboy0 Aug 26, 2023
e669276
Also verify that the allOf workaround isn't necessary in 3.1 anymore,…
czechboy0 Aug 27, 2023
c420c47
Merge branch 'hd-openapi-31-support' into hd-uri-encoder-integration
czechboy0 Aug 28, 2023
6ae1b59
Fix up diagnostics
czechboy0 Aug 28, 2023
2b8f763
Integrated the new coder helpes
czechboy0 Aug 28, 2023
3a65c92
Merge branch 'main' into hd-uri-encoder-integration
czechboy0 Aug 29, 2023
b0a3a87
Fix up formatting
czechboy0 Aug 29, 2023
f99d46c
Merge from hd-uri-encoder-integration
czechboy0 Aug 29, 2023
ca84fdd
Merge branch 'main' into hd-prep-0.2.0
czechboy0 Aug 30, 2023
20362d6
Fix formatting
czechboy0 Aug 30, 2023
ff727ab
Fix up a few more references to versions
czechboy0 Aug 30, 2023
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
4 changes: 2 additions & 2 deletions IntegrationTest/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-openapi-generator", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/apple/swift-openapi-generator", .upToNextMinor(from: "0.2.0")),
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.2.0")),
],
targets: [
.target(
Expand Down
14 changes: 1 addition & 13 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ let package = Package(
// Tests-only: Runtime library linked by generated code, and also
// helps keep the runtime library new enough to work with the generated
// code.
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.1.11")),
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.2.0")),

// Build and preview docs
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
Expand Down Expand Up @@ -147,18 +147,6 @@ let package = Package(
swiftSettings: swiftSettings
),

// PetstoreConsumerTestsFFMultipleContentTypes
// Builds and tests the reference code from GeneratorReferenceTests
// to ensure it actually works correctly at runtime.
// Enabled feature flag: multipleContentTypes
.testTarget(
name: "PetstoreConsumerTestsFFMultipleContentTypes",
dependencies: [
"PetstoreConsumerTestCore"
],
swiftSettings: swiftSettings
),

// Generator CLI
.executableTarget(
name: "swift-openapi-generator",
Expand Down
26 changes: 3 additions & 23 deletions Sources/_OpenAPIGeneratorCore/FeatureFlags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,9 @@
/// 1.0 is released.)
public enum FeatureFlag: String, Hashable, Codable, CaseIterable {

/// Multiple request and response body content types.
///
/// Tracking issues:
/// - https://github.com/apple/swift-openapi-generator/issues/6
/// - https://github.com/apple/swift-openapi-generator/issues/7
case multipleContentTypes

/// SOAR-0001 Improved OpenAPI -> Swift name mapping
///
/// Tracking issues:
/// - https://github.com/apple/swift-openapi-generator/pull/95
case proposal0001

/// Stricted input OpenAPI document validation.
///
/// Check for structural issues and detect cycles proactively.
case strictOpenAPIValidation

/// Removed the generation of an undocumented case in enums/oneOfs.
///
/// Tracking issue:
/// - https://github.com/apple/swift-openapi-generator/issues/204
case closedEnumsAndOneOfs
/// Has to be here until we add more feature flags, otherwise the enum
/// doesn't compile.
case empty
}

/// A set of enabled feature flags.
Expand Down
3 changes: 0 additions & 3 deletions Sources/_OpenAPIGeneratorCore/Parser/validateDoc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
/// - config: The generator config.
/// - Throws: An error if a fatal issue is found.
func validateDoc(_ doc: ParsedOpenAPIRepresentation, config: Config) throws -> [Diagnostic] {
guard config.featureFlags.contains(.strictOpenAPIValidation) else {
return []
}
// Run OpenAPIKit's built-in validation.
// Pass `false` to `strict`, however, because we don't
// want to turn schema loading warnings into errors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,57 +19,12 @@ extension FileTranslator {
///
/// - Parameter string: The string to convert to be safe for Swift.
func swiftSafeName(for string: String) -> String {
guard config.featureFlags.contains(.proposal0001) else {
return string.safeForSwiftCode
}
return string.proposedSafeForSwiftCode
string.safeForSwiftCode
}
}

fileprivate extension String {

/// Returns a string sanitized to be usable as a Swift identifier.
///
/// For example, the string `$nake` would be returned as `_nake`, because
/// the dollar sign is not a valid character in a Swift identifier.
///
/// In addition to replacing illegal characters with an underscores, also
/// ensures that the identifier starts with a letter and not a number.
var safeForSwiftCode: String {
guard !isEmpty else {
return "_empty"
}

// Only allow [a-zA-Z][a-zA-Z0-9_]*
// This is bad, is there something like percent encoding functionality but for general "allowed chars only"?

let firstCharSet: CharacterSet = .letters
let numbers: CharacterSet = .decimalDigits
let otherCharSet: CharacterSet = .alphanumerics.union(.init(charactersIn: "_"))

var sanitizedScalars: [Unicode.Scalar] = []
for (index, scalar) in unicodeScalars.enumerated() {
let allowedSet = index == 0 ? firstCharSet : otherCharSet
let outScalar: Unicode.Scalar
if allowedSet.contains(scalar) {
outScalar = scalar
} else if index == 0 && numbers.contains(scalar) {
sanitizedScalars.append("_")
outScalar = scalar
} else {
outScalar = "_"
}
sanitizedScalars.append(outScalar)
}

let validString = String(UnicodeScalarView(sanitizedScalars))

guard Self.keywords.contains(validString) else {
return validString
}
return "_\(validString)"
}

/// Returns a string sanitized to be usable as a Swift identifier.
///
/// See the proposal SOAR-0001 for details.
Expand All @@ -81,7 +36,7 @@ fileprivate extension String {
///
/// In addition to replacing illegal characters, it also
/// ensures that the identifier starts with a letter and not a number.
var proposedSafeForSwiftCode: String {
var safeForSwiftCode: String {
guard !isEmpty else {
return "_empty"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,9 @@ extension FileTranslator {

let caseNames = cases.map(\.0)

let undocumentedType: TypeName
let codingKeysDecls: [Declaration]
let decoder: Declaration
if let discriminator {
undocumentedType = .objectContainer
let originalName = discriminator.propertyName
let swiftName = swiftSafeName(for: originalName)
codingKeysDecls = [
Expand All @@ -232,33 +230,12 @@ extension FileTranslator {
cases: cases.map { ($0.0, $0.1!) }
)
} else {
undocumentedType = .valueContainer
codingKeysDecls = []
decoder = translateOneOfWithoutDiscriminatorDecoder(
caseNames: caseNames
)
}

let generateUndocumentedCase = shouldGenerateUndocumentedCaseForEnumsAndOneOfs

let otherCases: [Declaration]
if generateUndocumentedCase {
let undocumentedCase: Declaration = .commentable(
.doc("Parsed a case that was not defined in the OpenAPI document."),
.enumCase(
name: Constants.OneOf.undocumentedCaseName,
kind: .nameWithAssociatedValues([
.init(type: undocumentedType.fullyQualifiedSwiftName)
])
)
)
otherCases = [
undocumentedCase
]
} else {
otherCases = []
}

let encoder = translateOneOfEncoder(caseNames: caseNames)

let comment: Comment? =
Expand All @@ -269,7 +246,7 @@ extension FileTranslator {
accessModifier: config.access,
name: typeName.shortSwiftName,
conformances: Constants.ObjectStruct.conformances,
members: caseDecls + otherCases + codingKeysDecls + [
members: caseDecls + codingKeysDecls + [
decoder,
encoder,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,61 +339,11 @@ extension FileTranslator {
)
}

let generateUndocumentedCase = shouldGenerateUndocumentedCaseForEnumsAndOneOfs
let otherExprs: [CodeBlock]
if generateUndocumentedCase {
otherExprs = [
.declaration(
.variable(
kind: .let,
left: "container",
right: .try(
.identifier("decoder")
.dot("singleValueContainer")
.call([])
)
)
),
.declaration(
.variable(
kind: .let,
left: "value",
right: .try(
.identifier("container")
.dot("decode")
.call([
.init(
label: nil,
expression:
.identifier(
TypeName
.valueContainer
.fullyQualifiedSwiftName
)
.dot("self")
)
])
)
)
),
.expression(
.assignment(
left: .identifier("self"),
right: .dot(Constants.OneOf.undocumentedCaseName)
.call([
.init(label: nil, expression: .identifier("value"))
])
)
),
]
} else {
otherExprs = [
.expression(
translateOneOfDecoderThrowOnUnknownExpr()
)
]
}

let otherExprs: [CodeBlock] = [
.expression(
translateOneOfDecoderThrowOnUnknownExpr()
)
]
return decoderInitializer(
body: (assignExprs).map { .expression($0) } + otherExprs
)
Expand Down Expand Up @@ -447,60 +397,11 @@ extension FileTranslator {
]
)
}
let generateUndocumentedCase = shouldGenerateUndocumentedCaseForEnumsAndOneOfs
let otherExprs: [CodeBlock]
if generateUndocumentedCase {
otherExprs = [
.declaration(
.variable(
kind: .let,
left: "container",
right: .try(
.identifier("decoder")
.dot("singleValueContainer")
.call([])
)
)
),
.declaration(
.variable(
kind: .let,
left: "value",
right: .try(
.identifier("container")
.dot("decode")
.call([
.init(
label: nil,
expression:
.identifier(
TypeName
.objectContainer
.fullyQualifiedSwiftName
)
.dot("self")
)
])
)
)
),
.expression(
.assignment(
left: .identifier("self"),
right: .dot(Constants.OneOf.undocumentedCaseName)
.call([
.init(label: nil, expression: .identifier("value"))
])
)
),
]
} else {
otherExprs = [
.expression(
translateOneOfDecoderThrowOnUnknownExpr()
)
]
}
let otherExprs: [CodeBlock] = [
.expression(
translateOneOfDecoderThrowOnUnknownExpr()
)
]
let body: [CodeBlock] = [
.declaration(.decoderContainerOfKeysVar()),
.declaration(
Expand Down Expand Up @@ -546,27 +447,19 @@ extension FileTranslator {
func translateOneOfEncoder(
caseNames: [String]
) -> Declaration {
let generateUndocumentedCase = shouldGenerateUndocumentedCaseForEnumsAndOneOfs
let otherCaseNames: [String]
if generateUndocumentedCase {
otherCaseNames = [Constants.OneOf.undocumentedCaseName]
} else {
otherCaseNames = []
}
let switchExpr: Expression = .switch(
switchedExpression: .identifier("self"),
cases: (caseNames + otherCaseNames)
.map { caseName in
.init(
kind: .case(.dot(caseName), ["value"]),
body: [
.expression(
.identifier("value")
.encodeExpr()
)
]
)
}
cases: caseNames.map { caseName in
.init(
kind: .case(.dot(caseName), ["value"]),
body: [
.expression(
.identifier("value")
.encodeExpr()
)
]
)
}
)
return encoderFunction(body: [.expression(switchExpr)])
}
Expand Down
Loading