From ee7898570f5740723d20da3d426d671cb0120665 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Fri, 2 Aug 2024 17:21:41 +0300 Subject: [PATCH 01/11] Create DiagnosticSubmitter wrapper --- .../_OpenAPIGeneratorCore/Diagnostics.swift | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift index 1108d298..e76f7eba 100644 --- a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift +++ b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift @@ -168,6 +168,127 @@ public protocol DiagnosticCollector { func emit(_ diagnostic: Diagnostic) } +final class DiagnosticSubmitter { + private let collector: any DiagnosticCollector + + init(collector: any DiagnosticCollector) { self.collector = collector } + + /// Submits a diagnostic to the collector. + /// + /// - Parameter diagnostic: The diagnostic to be submitted. + /// - Throws: The diagnostic itself if its severity is `.error`. + func submit(_ diagnostic: Diagnostic) throws { + collector.emit(diagnostic) + if diagnostic.severity == .error { throw diagnostic } + } + + /// Submits a diagnostic for an unsupported feature found in the specified + /// string location. + /// + /// Recoverable, the generator skips the unsupported feature. + /// - Parameters: + /// - feature: A human-readable name of the feature. + /// - foundIn: A description of the location in which the unsupported + /// feature was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) throws { + try submit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context)) + } + + /// Submits a diagnostic for an unsupported schema found in the specified + /// string location. + /// - Parameters: + /// - reason: A human-readable reason. + /// - schema: The unsupported JSON schema. + /// - foundIn: A description of the location in which the unsupported + /// schema was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:]) + throws + { try submit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context)) } + + /// Submits a diagnostic for an unsupported feature found in the specified + /// type name. + /// + /// Recoverable, the generator skips the unsupported feature. + /// - Parameters: + /// - feature: A human-readable name of the feature. + /// - foundIn: The type name related to where the issue was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) throws { + try submit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context)) + } + + /// Submints a diagnostic for an unsupported feature found in the specified + /// string location when the test closure returns a non-nil value. + /// + /// Recoverable, the generator skips the unsupported feature. + /// - Parameters: + /// - test: A closure that returns a non-nil value when an unsupported + /// feature is specified in the OpenAPI document. + /// - feature: A human-readable name of the feature. + /// - foundIn: A description of the location in which the unsupported + /// feature was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:]) + throws + { + if test == nil { return } + try submitUnsupported(feature, foundIn: foundIn, context: context) + } + + /// Submits a diagnostic for an unsupported feature found in the specified + /// string location when the test collection is not empty. + /// + /// Recoverable, the generator skips the unsupported feature. + /// - Parameters: + /// - test: A collection that is not empty if the unsupported feature + /// is specified in the OpenAPI document. + /// - feature: A human-readable name of the feature. + /// - foundIn: A description of the location in which the unsupported + /// feature was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupportedIfNotEmpty( + _ test: C?, + _ feature: String, + foundIn: String, + context: [String: String] = [:] + ) throws { + guard let test = test, !test.isEmpty else { return } + try submitUnsupported(feature, foundIn: foundIn, context: context) + } + + /// Submits a diagnostic for an unsupported feature found in the specified + /// string location when the test Boolean value is true. + /// + /// Recoverable, the generator skips the unsupported feature. + /// - Parameters: + /// - test: A Boolean value that indicates whether the unsupported + /// feature is specified in the OpenAPI document. + /// - feature: A human-readable name of the feature. + /// - foundIn: A description of the location in which the unsupported + /// feature was detected. + /// - context: A set of key-value pairs that help the user understand + /// where the warning occurred. + /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. + func submitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) + throws + { + if !test { return } + try submitUnsupported(feature, foundIn: foundIn, context: context) + } +} + extension DiagnosticCollector { /// Emits a diagnostic for an unsupported feature found in the specified From 7fba3b9ed854a089025e7d91a3ecc845ea126bfc Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Mon, 5 Aug 2024 00:24:43 +0300 Subject: [PATCH 02/11] Make emit throwable --- .../_OpenAPIGeneratorCore/Diagnostics.swift | 164 +++++------------- .../GeneratorPipeline.swift | 4 +- .../translateObjectStruct.swift | 6 +- .../CommonTranslations/translateSchema.swift | 3 +- .../Translator/Content/ContentInspector.swift | 14 +- .../Multipart/MultipartContentInspector.swift | 3 +- .../Parameters/TypedParameter.swift | 7 +- .../Parameters/translateParameter.swift | 12 +- .../TypeAssignment/isSchemaSupported.swift | 9 +- .../TypesTranslator/translateBoxedTypes.swift | 11 +- .../GenerateOptions+runGenerator.swift | 2 +- 11 files changed, 78 insertions(+), 157 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift index e76f7eba..ad96ab91 100644 --- a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift +++ b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift @@ -165,24 +165,38 @@ public protocol DiagnosticCollector { /// Submits a diagnostic to the collector. /// - Parameter diagnostic: The diagnostic to submit. - func emit(_ diagnostic: Diagnostic) + /// - Throws: An error if the implementing type determines that one should be thrown. + func emit(_ diagnostic: Diagnostic) throws } -final class DiagnosticSubmitter { - private let collector: any DiagnosticCollector +/// A type that conforms to the `DiagnosticCollector` protocol. +/// +/// It receives diagnostics and forwards them to an upstream `DiagnosticCollector`. +/// +/// If a diagnostic with a severity of `.error` is emitted, this collector will throw the diagnostic as an error. +public struct ErrorThrowingDiagnosticCollector: DiagnosticCollector { + private let upstream: any DiagnosticCollector - init(collector: any DiagnosticCollector) { self.collector = collector } + /// Initializes a new `ErrorThrowingDiagnosticCollector` with an upstream `DiagnosticCollector`. + /// + /// The upstream collector is where this collector will forward all received diagnostics. + /// + /// - Parameter upstream: The `DiagnosticCollector` to which this collector will forward diagnostics. + public init(upstream: any DiagnosticCollector) { self.upstream = upstream } - /// Submits a diagnostic to the collector. + /// Emits a diagnostic to the collector. /// /// - Parameter diagnostic: The diagnostic to be submitted. /// - Throws: The diagnostic itself if its severity is `.error`. - func submit(_ diagnostic: Diagnostic) throws { - collector.emit(diagnostic) + public func emit(_ diagnostic: Diagnostic) throws { + try upstream.emit(diagnostic) if diagnostic.severity == .error { throw diagnostic } } +} - /// Submits a diagnostic for an unsupported feature found in the specified +extension DiagnosticCollector { + + /// Emits a diagnostic for an unsupported feature found in the specified /// string location. /// /// Recoverable, the generator skips the unsupported feature. @@ -193,11 +207,11 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) throws { - try submit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context)) + func emitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) throws { + try emit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context)) } - /// Submits a diagnostic for an unsupported schema found in the specified + /// Emits a diagnostic for an unsupported schema found in the specified /// string location. /// - Parameters: /// - reason: A human-readable reason. @@ -207,11 +221,11 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:]) + func emitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:]) throws - { try submit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context)) } + { try emit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context)) } - /// Submits a diagnostic for an unsupported feature found in the specified + /// Emits a diagnostic for an unsupported feature found in the specified /// type name. /// /// Recoverable, the generator skips the unsupported feature. @@ -221,11 +235,11 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) throws { - try submit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context)) + func emitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) throws { + try emit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context)) } - /// Submints a diagnostic for an unsupported feature found in the specified + /// Emits a diagnostic for an unsupported feature found in the specified /// string location when the test closure returns a non-nil value. /// /// Recoverable, the generator skips the unsupported feature. @@ -238,14 +252,14 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:]) + func emitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:]) throws { if test == nil { return } - try submitUnsupported(feature, foundIn: foundIn, context: context) + try emitUnsupported(feature, foundIn: foundIn, context: context) } - /// Submits a diagnostic for an unsupported feature found in the specified + /// Emits a diagnostic for an unsupported feature found in the specified /// string location when the test collection is not empty. /// /// Recoverable, the generator skips the unsupported feature. @@ -258,17 +272,17 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupportedIfNotEmpty( + func emitUnsupportedIfNotEmpty( _ test: C?, _ feature: String, foundIn: String, context: [String: String] = [:] ) throws { guard let test = test, !test.isEmpty else { return } - try submitUnsupported(feature, foundIn: foundIn, context: context) + try emitUnsupported(feature, foundIn: foundIn, context: context) } - /// Submits a diagnostic for an unsupported feature found in the specified + /// Emits a diagnostic for an unsupported feature found in the specified /// string location when the test Boolean value is true. /// /// Recoverable, the generator skips the unsupported feature. @@ -281,110 +295,10 @@ final class DiagnosticSubmitter { /// - context: A set of key-value pairs that help the user understand /// where the warning occurred. /// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`. - func submitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) - throws + func emitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) throws { if !test { return } - try submitUnsupported(feature, foundIn: foundIn, context: context) - } -} - -extension DiagnosticCollector { - - /// Emits a diagnostic for an unsupported feature found in the specified - /// string location. - /// - /// Recoverable, the generator skips the unsupported feature. - /// - Parameters: - /// - feature: A human-readable name of the feature. - /// - foundIn: A description of the location in which the unsupported - /// feature was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) { - emit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context)) - } - - /// Emits a diagnostic for an unsupported schema found in the specified - /// string location. - /// - Parameters: - /// - reason: A human-readable reason. - /// - schema: The unsupported JSON schema. - /// - foundIn: A description of the location in which the unsupported - /// schema was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:]) { - emit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context)) - } - - /// Emits a diagnostic for an unsupported feature found in the specified - /// type name. - /// - /// Recoverable, the generator skips the unsupported feature. - /// - Parameters: - /// - feature: A human-readable name of the feature. - /// - foundIn: The type name related to where the issue was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) { - emit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context)) - } - - /// Emits a diagnostic for an unsupported feature found in the specified - /// string location when the test closure returns a non-nil value. - /// - /// Recoverable, the generator skips the unsupported feature. - /// - Parameters: - /// - test: A closure that returns a non-nil value when an unsupported - /// feature is specified in the OpenAPI document. - /// - feature: A human-readable name of the feature. - /// - foundIn: A description of the location in which the unsupported - /// feature was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:]) { - if test == nil { return } - emitUnsupported(feature, foundIn: foundIn, context: context) - } - - /// Emits a diagnostic for an unsupported feature found in the specified - /// string location when the test collection is not empty. - /// - /// Recoverable, the generator skips the unsupported feature. - /// - Parameters: - /// - test: A collection that is not empty if the unsupported feature - /// is specified in the OpenAPI document. - /// - feature: A human-readable name of the feature. - /// - foundIn: A description of the location in which the unsupported - /// feature was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupportedIfNotEmpty( - _ test: C?, - _ feature: String, - foundIn: String, - context: [String: String] = [:] - ) { - guard let test = test, !test.isEmpty else { return } - emitUnsupported(feature, foundIn: foundIn, context: context) - } - - /// Emits a diagnostic for an unsupported feature found in the specified - /// string location when the test Boolean value is true. - /// - /// Recoverable, the generator skips the unsupported feature. - /// - Parameters: - /// - test: A Boolean value that indicates whether the unsupported - /// feature is specified in the OpenAPI document. - /// - feature: A human-readable name of the feature. - /// - foundIn: A description of the location in which the unsupported - /// feature was detected. - /// - context: A set of key-value pairs that help the user understand - /// where the warning occurred. - func emitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) { - if !test { return } - emitUnsupported(feature, foundIn: foundIn, context: context) + try emitUnsupported(feature, foundIn: foundIn, context: context) } } diff --git a/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift b/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift index e38df8d2..8a749fff 100644 --- a/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift +++ b/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift @@ -110,7 +110,9 @@ func makeGeneratorPipeline( } let validateDoc = { (doc: OpenAPI.Document) -> OpenAPI.Document in let validationDiagnostics = try validator(doc, config) - for diagnostic in validationDiagnostics { diagnostics.emit(diagnostic) } + for diagnostic in validationDiagnostics { + try ErrorThrowingDiagnosticCollector(upstream: diagnostics).emit(diagnostic) + } return doc } return .init( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift index a55517b4..6a835fce 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift @@ -32,7 +32,7 @@ extension TypesFileTranslator { objectContext: JSONSchema.ObjectContext, isDeprecated: Bool ) throws -> Declaration { - + let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) let documentedProperties: [PropertyBlueprint] = try objectContext.properties .filter { key, value in @@ -42,7 +42,7 @@ extension TypesFileTranslator { // have a proper definition in the `properties` map are skipped, as they // often imply a typo or a mistake in the document. So emit a diagnostic as well. guard !value.inferred else { - diagnostics.emit( + try collector.emit( .warning( message: "A property name only appears in the required list, but not in the properties map - this is likely a typo; skipping this property.", @@ -63,7 +63,7 @@ extension TypesFileTranslator { // allowed in object properties, explicitly filter these out // here. if value.isString && value.formatString == "binary" { - diagnostics.emitUnsupportedSchema( + try collector.emitUnsupportedSchema( reason: "Binary properties in object schemas.", schema: value, foundIn: foundIn diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift index f7668e4f..0486a3b5 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift @@ -76,7 +76,8 @@ extension TypesFileTranslator { // Attach any warnings from the parsed schema as a diagnostic. for warning in schema.warnings { - diagnostics.emit( + let errorThrowing = ErrorThrowingDiagnosticCollector(upstream: diagnostics) + try errorThrowing.emit( .warning( message: "Schema warning: \(warning.description)", context: [ diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift index b8df47b5..c3463cce 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift @@ -123,7 +123,8 @@ extension FileTranslator { -> SchemaContent? { guard !map.isEmpty else { return nil } - if map.count > 1 { diagnostics.emitUnsupported("Multiple content types", foundIn: foundIn) } + let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) + if map.count > 1 { try collector.emitUnsupported("Multiple content types", foundIn: foundIn) } let mapWithContentTypes = try map.map { key, content in try (type: key.asGeneratorContentType, value: content) } let chosenContent: (type: ContentType, schema: SchemaContent, content: OpenAPI.Content)? @@ -137,7 +138,7 @@ extension FileTranslator { contentValue ) } else { - diagnostics.emitUnsupported("Unsupported content", foundIn: foundIn) + try collector.emitUnsupported("Unsupported content", foundIn: foundIn) chosenContent = nil } if let chosenContent { @@ -145,7 +146,7 @@ extension FileTranslator { if contentType.lowercasedType == "multipart" || contentType.lowercasedTypeAndSubtype.contains("application/x-www-form-urlencoded") { - diagnostics.emitUnsupportedIfNotNil( + try collector.emitUnsupportedIfNotNil( chosenContent.content.encoding, "Custom encoding for multipart/formEncoded content", foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" @@ -180,8 +181,9 @@ extension FileTranslator { foundIn: String ) throws -> SchemaContent? { let contentType = try contentKey.asGeneratorContentType + let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) if contentType.lowercasedTypeAndSubtype.contains("application/x-www-form-urlencoded") { - diagnostics.emitUnsupportedIfNotNil( + try collector.emitUnsupportedIfNotNil( contentValue.encoding, "Custom encoding for formEncoded content", foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" @@ -191,7 +193,7 @@ extension FileTranslator { if contentType.isUrlEncodedForm { return .init(contentType: contentType, schema: contentValue.schema) } if contentType.isMultipart { guard isRequired else { - diagnostics.emit( + try collector.emit( .warning( message: "Multipart request bodies must always be required, but found an optional one - skipping. Mark as `required: true` to get this body generated.", @@ -205,7 +207,7 @@ extension FileTranslator { if !excludeBinary, contentType.isBinary { return .init(contentType: contentType, schema: .b(.string(contentEncoding: .binary))) } - diagnostics.emitUnsupported("Unsupported content", foundIn: foundIn) + try collector.emitUnsupported("Unsupported content", foundIn: foundIn) return nil } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift index b9edc3b8..207fa796 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift @@ -312,7 +312,8 @@ extension FileTranslator { } let contentType = finalContentTypeSource.contentType if finalContentTypeSource.contentType.isMultipart { - diagnostics.emitUnsupported("Multipart part cannot nest another multipart content.", foundIn: foundIn) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupported("Multipart part cannot nest another multipart content.", foundIn: foundIn) return nil } let info = MultipartPartInfo(repetition: repetitionKind, contentTypeSource: finalContentTypeSource) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index d84f9d3d..5e127516 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -121,6 +121,7 @@ extension FileTranslator { } } + let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) let locationTypeName = parameter.location.typeName(in: parent) let foundIn = "\(locationTypeName.description)/\(parameter.name)" @@ -140,7 +141,7 @@ extension FileTranslator { switch location { case .query: guard case .form = style else { - diagnostics.emitUnsupported( + try collector.emitUnsupported( "Query params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) @@ -148,14 +149,14 @@ extension FileTranslator { } case .header, .path: guard case .simple = style else { - diagnostics.emitUnsupported( + try collector.emitUnsupported( "\(location.rawValue) params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) return nil } case .cookie: - diagnostics.emitUnsupported("Cookie params", foundIn: foundIn) + try collector.emitUnsupported("Cookie params", foundIn: foundIn) return nil } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift index c422bec0..1d606f66 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift @@ -114,10 +114,8 @@ extension ClientFileTranslator { containerExpr = .identifierPattern(requestVariableName) supportsStyleAndExplode = true default: - diagnostics.emitUnsupported( - "Parameter of type \(parameter.location.rawValue)", - foundIn: parameter.description - ) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupported("Parameter of type \(parameter.location.rawValue)", foundIn: parameter.description) return nil } let styleAndExplodeArgs: [FunctionArgumentDescription] @@ -198,10 +196,8 @@ extension ServerFileTranslator { ]) ) default: - diagnostics.emitUnsupported( - "Parameter of type \(parameter.location)", - foundIn: "\(typedParameter.description)" - ) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupported("Parameter of type \(parameter.location)", foundIn: "\(typedParameter.description)") return nil } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift index e4735b0b..87236299 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift @@ -64,7 +64,8 @@ extension FileTranslator { switch try isSchemaSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } @@ -82,7 +83,8 @@ extension FileTranslator { switch try isSchemaSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } @@ -100,7 +102,8 @@ extension FileTranslator { switch try isObjectOrRefToObjectSchemaAndSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift index 02921018..432b9f41 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift @@ -33,12 +33,13 @@ extension TypesFileTranslator { var decls = decls for (index, decl) in decls.enumerated() { guard let name = decl.name, boxedNames.contains(name) else { continue } - diagnostics.emit( - .note( - message: "Detected a recursive type; it will be boxed to break the reference cycle.", - context: ["name": name] + try ErrorThrowingDiagnosticCollector(upstream: diagnostics) + .emit( + .note( + message: "Detected a recursive type; it will be boxed to break the reference cycle.", + context: ["name": name] + ) ) - ) decls[index] = boxedType(decl) } return decls diff --git a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift index 06b02d09..7d8f29b9 100644 --- a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift +++ b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift @@ -83,7 +83,7 @@ extension _GenerateOptions { try finalizeDiagnostics() } catch let error as Diagnostic { // Emit our nice Diagnostics message instead of relying on ArgumentParser output. - diagnostics.emit(error) + try ErrorThrowingDiagnosticCollector(upstream: diagnostics).emit(error) try finalizeDiagnostics() throw ExitCode.failure } catch { From d71f2cf8124a6baa3e55cc933aa21e5164c3e04f Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Mon, 5 Aug 2024 13:56:31 +0300 Subject: [PATCH 03/11] Create ErrorThrowingDiagnosticCollector diagnostics before code generation --- .../_OpenAPIGeneratorCore/GeneratorPipeline.swift | 4 +--- .../CommonTranslations/translateObjectStruct.swift | 5 ++--- .../CommonTranslations/translateSchema.swift | 3 +-- .../Translator/Content/ContentInspector.swift | 14 ++++++-------- .../Multipart/MultipartContentInspector.swift | 3 +-- .../Translator/Parameters/TypedParameter.swift | 7 +++---- .../Translator/Parameters/translateParameter.swift | 12 ++++++++---- .../TypeAssignment/isSchemaSupported.swift | 9 +++------ .../TypesTranslator/translateBoxedTypes.swift | 11 +++++------ .../GenerateOptions+runGenerator.swift | 10 +++++----- 10 files changed, 35 insertions(+), 43 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift b/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift index 8a749fff..8f4a8cf1 100644 --- a/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift +++ b/Sources/_OpenAPIGeneratorCore/GeneratorPipeline.swift @@ -110,9 +110,7 @@ func makeGeneratorPipeline( } let validateDoc = { (doc: OpenAPI.Document) -> OpenAPI.Document in let validationDiagnostics = try validator(doc, config) - for diagnostic in validationDiagnostics { - try ErrorThrowingDiagnosticCollector(upstream: diagnostics).emit(diagnostic) - } + for diagnostic in validationDiagnostics { try diagnostics.emit(diagnostic) } return doc } return .init( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift index 6a835fce..4b48e2e1 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift @@ -32,7 +32,6 @@ extension TypesFileTranslator { objectContext: JSONSchema.ObjectContext, isDeprecated: Bool ) throws -> Declaration { - let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) let documentedProperties: [PropertyBlueprint] = try objectContext.properties .filter { key, value in @@ -42,7 +41,7 @@ extension TypesFileTranslator { // have a proper definition in the `properties` map are skipped, as they // often imply a typo or a mistake in the document. So emit a diagnostic as well. guard !value.inferred else { - try collector.emit( + try diagnostics.emit( .warning( message: "A property name only appears in the required list, but not in the properties map - this is likely a typo; skipping this property.", @@ -63,7 +62,7 @@ extension TypesFileTranslator { // allowed in object properties, explicitly filter these out // here. if value.isString && value.formatString == "binary" { - try collector.emitUnsupportedSchema( + try diagnostics.emitUnsupportedSchema( reason: "Binary properties in object schemas.", schema: value, foundIn: foundIn diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift index 0486a3b5..e92b5605 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift @@ -76,8 +76,7 @@ extension TypesFileTranslator { // Attach any warnings from the parsed schema as a diagnostic. for warning in schema.warnings { - let errorThrowing = ErrorThrowingDiagnosticCollector(upstream: diagnostics) - try errorThrowing.emit( + try diagnostics.emit( .warning( message: "Schema warning: \(warning.description)", context: [ diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift index c3463cce..f78f5e9f 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift @@ -123,8 +123,7 @@ extension FileTranslator { -> SchemaContent? { guard !map.isEmpty else { return nil } - let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) - if map.count > 1 { try collector.emitUnsupported("Multiple content types", foundIn: foundIn) } + if map.count > 1 { try diagnostics.emitUnsupported("Multiple content types", foundIn: foundIn) } let mapWithContentTypes = try map.map { key, content in try (type: key.asGeneratorContentType, value: content) } let chosenContent: (type: ContentType, schema: SchemaContent, content: OpenAPI.Content)? @@ -138,7 +137,7 @@ extension FileTranslator { contentValue ) } else { - try collector.emitUnsupported("Unsupported content", foundIn: foundIn) + try diagnostics.emitUnsupported("Unsupported content", foundIn: foundIn) chosenContent = nil } if let chosenContent { @@ -146,7 +145,7 @@ extension FileTranslator { if contentType.lowercasedType == "multipart" || contentType.lowercasedTypeAndSubtype.contains("application/x-www-form-urlencoded") { - try collector.emitUnsupportedIfNotNil( + try diagnostics.emitUnsupportedIfNotNil( chosenContent.content.encoding, "Custom encoding for multipart/formEncoded content", foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" @@ -181,9 +180,8 @@ extension FileTranslator { foundIn: String ) throws -> SchemaContent? { let contentType = try contentKey.asGeneratorContentType - let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) if contentType.lowercasedTypeAndSubtype.contains("application/x-www-form-urlencoded") { - try collector.emitUnsupportedIfNotNil( + try diagnostics.emitUnsupportedIfNotNil( contentValue.encoding, "Custom encoding for formEncoded content", foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" @@ -193,7 +191,7 @@ extension FileTranslator { if contentType.isUrlEncodedForm { return .init(contentType: contentType, schema: contentValue.schema) } if contentType.isMultipart { guard isRequired else { - try collector.emit( + try diagnostics.emit( .warning( message: "Multipart request bodies must always be required, but found an optional one - skipping. Mark as `required: true` to get this body generated.", @@ -207,7 +205,7 @@ extension FileTranslator { if !excludeBinary, contentType.isBinary { return .init(contentType: contentType, schema: .b(.string(contentEncoding: .binary))) } - try collector.emitUnsupported("Unsupported content", foundIn: foundIn) + try diagnostics.emitUnsupported("Unsupported content", foundIn: foundIn) return nil } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift index 207fa796..1c27dbd9 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Multipart/MultipartContentInspector.swift @@ -312,8 +312,7 @@ extension FileTranslator { } let contentType = finalContentTypeSource.contentType if finalContentTypeSource.contentType.isMultipart { - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupported("Multipart part cannot nest another multipart content.", foundIn: foundIn) + try diagnostics.emitUnsupported("Multipart part cannot nest another multipart content.", foundIn: foundIn) return nil } let info = MultipartPartInfo(repetition: repetitionKind, contentTypeSource: finalContentTypeSource) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index 5e127516..66a0ce26 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -121,7 +121,6 @@ extension FileTranslator { } } - let collector = ErrorThrowingDiagnosticCollector(upstream: diagnostics) let locationTypeName = parameter.location.typeName(in: parent) let foundIn = "\(locationTypeName.description)/\(parameter.name)" @@ -141,7 +140,7 @@ extension FileTranslator { switch location { case .query: guard case .form = style else { - try collector.emitUnsupported( + try diagnostics.emitUnsupported( "Query params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) @@ -149,14 +148,14 @@ extension FileTranslator { } case .header, .path: guard case .simple = style else { - try collector.emitUnsupported( + try diagnostics.emitUnsupported( "\(location.rawValue) params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) return nil } case .cookie: - try collector.emitUnsupported("Cookie params", foundIn: foundIn) + try diagnostics.emitUnsupported("Cookie params", foundIn: foundIn) return nil } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift index 1d606f66..0176a8cd 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift @@ -114,8 +114,10 @@ extension ClientFileTranslator { containerExpr = .identifierPattern(requestVariableName) supportsStyleAndExplode = true default: - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupported("Parameter of type \(parameter.location.rawValue)", foundIn: parameter.description) + try diagnostics.emitUnsupported( + "Parameter of type \(parameter.location.rawValue)", + foundIn: parameter.description + ) return nil } let styleAndExplodeArgs: [FunctionArgumentDescription] @@ -196,8 +198,10 @@ extension ServerFileTranslator { ]) ) default: - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupported("Parameter of type \(parameter.location)", foundIn: "\(typedParameter.description)") + try diagnostics.emitUnsupported( + "Parameter of type \(parameter.location)", + foundIn: "\(typedParameter.description)" + ) return nil } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift index 87236299..49fb4466 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypeAssignment/isSchemaSupported.swift @@ -64,8 +64,7 @@ extension FileTranslator { switch try isSchemaSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } @@ -83,8 +82,7 @@ extension FileTranslator { switch try isSchemaSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } @@ -102,8 +100,7 @@ extension FileTranslator { switch try isObjectOrRefToObjectSchemaAndSupported(schema, referenceStack: &referenceStack) { case .supported: return true case .unsupported(reason: let reason, schema: let schema): - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) + try diagnostics.emitUnsupportedSchema(reason: reason.description, schema: schema, foundIn: foundIn) return false } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift index 432b9f41..ce2da20d 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateBoxedTypes.swift @@ -33,13 +33,12 @@ extension TypesFileTranslator { var decls = decls for (index, decl) in decls.enumerated() { guard let name = decl.name, boxedNames.contains(name) else { continue } - try ErrorThrowingDiagnosticCollector(upstream: diagnostics) - .emit( - .note( - message: "Detected a recursive type; it will be boxed to break the reference cycle.", - context: ["name": name] - ) + try diagnostics.emit( + .note( + message: "Detected a recursive type; it will be boxed to break the reference cycle.", + context: ["name": name] ) + ) decls[index] = boxedType(decl) } return decls diff --git a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift index 7d8f29b9..a247104b 100644 --- a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift +++ b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift @@ -42,17 +42,17 @@ extension _GenerateOptions { featureFlags: resolvedFeatureFlags ) } - let diagnostics: any DiagnosticCollector & Sendable + let innerDiagnostics: any DiagnosticCollector & Sendable let finalizeDiagnostics: () throws -> Void if let diagnosticsOutputPath { let _diagnostics = _YamlFileDiagnosticsCollector(url: diagnosticsOutputPath) finalizeDiagnostics = _diagnostics.finalize - diagnostics = _diagnostics + innerDiagnostics = _diagnostics } else { - diagnostics = StdErrPrintingDiagnosticCollector() + innerDiagnostics = StdErrPrintingDiagnosticCollector() finalizeDiagnostics = {} } - + let diagnostics = ErrorThrowingDiagnosticCollector(upstream: innerDiagnostics) let doc = self.docPath print( """ @@ -83,7 +83,7 @@ extension _GenerateOptions { try finalizeDiagnostics() } catch let error as Diagnostic { // Emit our nice Diagnostics message instead of relying on ArgumentParser output. - try ErrorThrowingDiagnosticCollector(upstream: diagnostics).emit(error) + try diagnostics.emit(error) try finalizeDiagnostics() throw ExitCode.failure } catch { From 3d37c20243c44a9835704d2c2b32b834cbdc8390 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Sat, 10 Aug 2024 00:40:47 +0300 Subject: [PATCH 04/11] Add test for runGenerator function --- Package.swift | 8 +++ .../FileBasedReferenceTests.swift | 2 +- .../Resources/Docs/malformed-openapi.yaml | 4 ++ .../Docs/openapi-generator-config.yaml | 4 ++ .../Test_GenerateOptions.swift | 53 +++++++++++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 Tests/OpenAPIGeneratorTests/Resources/Docs/malformed-openapi.yaml create mode 100644 Tests/OpenAPIGeneratorTests/Resources/Docs/openapi-generator-config.yaml create mode 100644 Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift diff --git a/Package.swift b/Package.swift index 7b90240a..3df32167 100644 --- a/Package.swift +++ b/Package.swift @@ -114,6 +114,14 @@ let package = Package( swiftSettings: swiftSettings ), + // New Test Target for swift-openapi-generator + .testTarget( + name: "OpenAPIGeneratorTests", + dependencies: ["swift-openapi-generator"], + resources: [.copy("Resources")], + swiftSettings: swiftSettings + ), + // Generator CLI .executableTarget( name: "swift-openapi-generator", diff --git a/Tests/OpenAPIGeneratorReferenceTests/FileBasedReferenceTests.swift b/Tests/OpenAPIGeneratorReferenceTests/FileBasedReferenceTests.swift index 1e9e6786..75b8be78 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/FileBasedReferenceTests.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/FileBasedReferenceTests.swift @@ -31,7 +31,7 @@ extension TestConfig { } /// Tests that the generator produces Swift files that match a reference. -class FileBasedReferenceTests: XCTestCase { +final class FileBasedReferenceTests: XCTestCase { /// Setup method called before the invocation of each test method in the class. override func setUp() { diff --git a/Tests/OpenAPIGeneratorTests/Resources/Docs/malformed-openapi.yaml b/Tests/OpenAPIGeneratorTests/Resources/Docs/malformed-openapi.yaml new file mode 100644 index 00000000..a31882d7 --- /dev/null +++ b/Tests/OpenAPIGeneratorTests/Resources/Docs/malformed-openapi.yaml @@ -0,0 +1,4 @@ +# openapi: '3.1.0' -> Missing openapi version +info: + title: MalformedDocument + version: 1.0.0 diff --git a/Tests/OpenAPIGeneratorTests/Resources/Docs/openapi-generator-config.yaml b/Tests/OpenAPIGeneratorTests/Resources/Docs/openapi-generator-config.yaml new file mode 100644 index 00000000..f68d9c85 --- /dev/null +++ b/Tests/OpenAPIGeneratorTests/Resources/Docs/openapi-generator-config.yaml @@ -0,0 +1,4 @@ +generate: + - types + - server +accessModifier: internal diff --git a/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift new file mode 100644 index 00000000..1421f293 --- /dev/null +++ b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 XCTest +import _OpenAPIGeneratorCore +import OpenAPIKit +import ArgumentParser +@testable import swift_openapi_generator + +final class Test_GenerateOptions: XCTestCase { + + var resourcesDirectory: URL! = nil + + /// Setup method called before the invocation of each test method in the class. + override func setUpWithError() throws { + resourcesDirectory = try XCTUnwrap( + Bundle.module.url(forResource: "Resources", withExtension: nil), + "Could not find reference test resources directory." + ) + } + + func testRunGeneratorThrowsErrorDiagnostic() async throws { + let outputDirectory = URL(fileURLWithPath: "/invalid/path") + let docsDirectory = resourcesDirectory.appendingPathComponent("Docs") + let docPath = docsDirectory.appendingPathComponent("malformed-openapi.yaml") + let configPath = docsDirectory.appendingPathComponent("openapi-generator-config.yaml") + + let arguments = [docPath.path(), "--config", configPath.path] + + let originalArguments = CommandLine.arguments + defer { CommandLine.arguments = originalArguments } + CommandLine.arguments = arguments + + let generator = try _GenerateOptions.parse(arguments) + + do { + try await generator.runGenerator(outputDirectory: outputDirectory, pluginSource: nil, isDryRun: false) + XCTFail("Expected to throw an error, but it did not throw") + } catch let diagnostic as Diagnostic { + XCTAssertEqual(diagnostic.severity, .error, "Expected diagnostic severity to be `.error`") + } catch { XCTFail("Expected to throw a Diagnostic `.error`, but threw a different error: \(error)") } + } +} From 15277ed3ce26de4e9c42187bdf09389cf9f4aa82 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Sat, 10 Aug 2024 00:42:58 +0300 Subject: [PATCH 05/11] Update comment --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 3df32167..4c2b6125 100644 --- a/Package.swift +++ b/Package.swift @@ -114,7 +114,7 @@ let package = Package( swiftSettings: swiftSettings ), - // New Test Target for swift-openapi-generator + // Test Target for swift-openapi-generator .testTarget( name: "OpenAPIGeneratorTests", dependencies: ["swift-openapi-generator"], From 388287259f760fe23263482c59e6ea158753d1ac Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Mon, 12 Aug 2024 00:22:21 +0300 Subject: [PATCH 06/11] Remove unused code --- Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift index 1421f293..3be88be3 100644 --- a/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift +++ b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift @@ -36,11 +36,6 @@ final class Test_GenerateOptions: XCTestCase { let configPath = docsDirectory.appendingPathComponent("openapi-generator-config.yaml") let arguments = [docPath.path(), "--config", configPath.path] - - let originalArguments = CommandLine.arguments - defer { CommandLine.arguments = originalArguments } - CommandLine.arguments = arguments - let generator = try _GenerateOptions.parse(arguments) do { From 038a428058c1d7b3b3c770b12bbbfe0dc69bf28f Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Mon, 12 Aug 2024 11:13:11 +0300 Subject: [PATCH 07/11] Fix linux failures --- Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift index 3be88be3..6d73da7e 100644 --- a/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift +++ b/Tests/OpenAPIGeneratorTests/Test_GenerateOptions.swift @@ -35,11 +35,11 @@ final class Test_GenerateOptions: XCTestCase { let docPath = docsDirectory.appendingPathComponent("malformed-openapi.yaml") let configPath = docsDirectory.appendingPathComponent("openapi-generator-config.yaml") - let arguments = [docPath.path(), "--config", configPath.path] + let arguments = [docPath.path, "--config", configPath.path] let generator = try _GenerateOptions.parse(arguments) do { - try await generator.runGenerator(outputDirectory: outputDirectory, pluginSource: nil, isDryRun: false) + try await generator.runGenerator(outputDirectory: outputDirectory, pluginSource: .build, isDryRun: false) XCTFail("Expected to throw an error, but it did not throw") } catch let diagnostic as Diagnostic { XCTAssertEqual(diagnostic.severity, .error, "Expected diagnostic severity to be `.error`") From f2c4b431b247ca882aea3771e41e062c711f4b61 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Mon, 12 Aug 2024 15:02:05 +0300 Subject: [PATCH 08/11] Move YamlFileDiagnosticsCollector.swift to _OpenAPIGeneratorCore module --- .../YamlFileDiagnosticsCollector.swift | 18 ++++++++---- .../GenerateOptions+runGenerator.swift | 8 ++++-- .../Test_preparedDiagnosticsCollector.swift | 28 +++++++++++++++++++ scripts/check-license-headers.sh | 1 + 4 files changed, 48 insertions(+), 7 deletions(-) rename Sources/{swift-openapi-generator => _OpenAPIGeneratorCore}/YamlFileDiagnosticsCollector.swift (72%) create mode 100644 Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift diff --git a/Sources/swift-openapi-generator/YamlFileDiagnosticsCollector.swift b/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift similarity index 72% rename from Sources/swift-openapi-generator/YamlFileDiagnosticsCollector.swift rename to Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift index 5035d7cb..520854c6 100644 --- a/Sources/swift-openapi-generator/YamlFileDiagnosticsCollector.swift +++ b/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// import Foundation import Yams -import _OpenAPIGeneratorCore struct _DiagnosticsYamlFileContent: Encodable { var uniqueMessages: [String] @@ -21,7 +20,7 @@ struct _DiagnosticsYamlFileContent: Encodable { } /// A collector that writes diagnostics to a YAML file. -final class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Sendable { +final public class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Sendable { /// Protects `diagnostics`. private let lock = NSLock() @@ -33,9 +32,11 @@ final class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Senda /// Creates a new collector. /// - Parameter url: A file path where to persist the YAML file. - init(url: URL) { self.url = url } + public init(url: URL) { self.url = url } - func emit(_ diagnostic: Diagnostic) { + /// Emits a diagnostic message to the collector. + /// - Parameter diagnostic: The diagnostic message to be collected. + public func emit(_ diagnostic: Diagnostic) { lock.lock() defer { lock.unlock() } diagnostics.append(diagnostic) @@ -43,7 +44,7 @@ final class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Senda /// Finishes writing to the collector by persisting the accumulated /// diagnostics to a YAML file. - func finalize() throws { + public func finalize() throws { lock.lock() defer { lock.unlock() } let sortedDiagnostics = diagnostics.sorted(by: { a, b in a.description < b.description }) @@ -54,3 +55,10 @@ final class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Senda try encoder.encode(container).write(to: url, atomically: true, encoding: .utf8) } } + +/// Prepares a diagnostics collector. +/// - Parameter url: A file path where to persist the YAML file. +/// - Returns: An instance of `DiagnosticCollector` conforming to `Sendable`. +public func preparedDiagnosticsCollector(url: URL) -> any DiagnosticCollector & Sendable { + _YamlFileDiagnosticsCollector(url: url) +} diff --git a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift index a247104b..9e261905 100644 --- a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift +++ b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift @@ -45,8 +45,12 @@ extension _GenerateOptions { let innerDiagnostics: any DiagnosticCollector & Sendable let finalizeDiagnostics: () throws -> Void if let diagnosticsOutputPath { - let _diagnostics = _YamlFileDiagnosticsCollector(url: diagnosticsOutputPath) - finalizeDiagnostics = _diagnostics.finalize + let _diagnostics = preparedDiagnosticsCollector(url: diagnosticsOutputPath) + if let yamlCollector = _diagnostics as? _YamlFileDiagnosticsCollector { + finalizeDiagnostics = { try yamlCollector.finalize() } + } else { + finalizeDiagnostics = {} + } innerDiagnostics = _diagnostics } else { innerDiagnostics = StdErrPrintingDiagnosticCollector() diff --git a/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift b/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift new file mode 100644 index 00000000..fb27e2dc --- /dev/null +++ b/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 XCTest +@testable import _OpenAPIGeneratorCore + +final class Test_preparedDiagnosticsCollector: XCTestCase { + func testPreparedDiagnosticsCollector() { + let url = URL(fileURLWithPath: "/path/to/test-diagnostics.yaml") + let collector = preparedDiagnosticsCollector(url: url) + + XCTAssertTrue( + collector is _YamlFileDiagnosticsCollector, + "Expected collector to be of type _YamlFileDiagnosticsCollector" + ) + } +} diff --git a/scripts/check-license-headers.sh b/scripts/check-license-headers.sh index 2061f591..17fa54bf 100644 --- a/scripts/check-license-headers.sh +++ b/scripts/check-license-headers.sh @@ -61,6 +61,7 @@ read -ra PATHS_TO_CHECK_FOR_LICENSE <<< "$( \ ":(exclude)**/Package.swift" \ ":(exclude)**/Package.resolved" \ ":(exclude)**/README.md" \ + ":(exclude)**/malformed-openapi.yaml" \ ":(exclude)**/openapi.yaml" \ ":(exclude)**/openapi.yml" \ ":(exclude)**/petstore.yaml" \ From 4c1d3237d6d73f92d0db8705b82f224d560a1feb Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Thu, 15 Aug 2024 23:08:31 +0300 Subject: [PATCH 09/11] Move diagnostics collector logic into prepare function --- .../_OpenAPIGeneratorCore/Diagnostics.swift | 2 +- .../DiagnosticsCollectorProvider.swift | 49 +++++++++++++++++++ .../YamlFileDiagnosticsCollector.swift | 17 ++----- .../GenerateOptions+runGenerator.swift | 16 +----- .../Test_DiagnosticsCollectorProvider.swift | 42 ++++++++++++++++ .../Test_preparedDiagnosticsCollector.swift | 28 ----------- 6 files changed, 97 insertions(+), 57 deletions(-) create mode 100644 Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift create mode 100644 Tests/OpenAPIGeneratorCoreTests/Test_DiagnosticsCollectorProvider.swift delete mode 100644 Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift diff --git a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift index ad96ab91..f85c991d 100644 --- a/Sources/_OpenAPIGeneratorCore/Diagnostics.swift +++ b/Sources/_OpenAPIGeneratorCore/Diagnostics.swift @@ -175,7 +175,7 @@ public protocol DiagnosticCollector { /// /// If a diagnostic with a severity of `.error` is emitted, this collector will throw the diagnostic as an error. public struct ErrorThrowingDiagnosticCollector: DiagnosticCollector { - private let upstream: any DiagnosticCollector + let upstream: any DiagnosticCollector /// Initializes a new `ErrorThrowingDiagnosticCollector` with an upstream `DiagnosticCollector`. /// diff --git a/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift b/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift new file mode 100644 index 00000000..376976b2 --- /dev/null +++ b/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +/// A feature that can be explicitly enabled before being released. +/// +/// Commonly used to get early feedback on breaking changes, before +/// they are enabled by default, which can only be done in a major version. +/// +/// Once a feature is enabled unconditionally in the next major version, +/// the corresponding feature flag should be removed at the same time. +/// +/// For example: a breaking feature is being built while version 0.1 is out, +/// and is hidden behind a feature flag. Once ready, the feature is +/// enabled unconditionally on main and the feature flag removed, and version +/// 0.2 is tagged. (This is for pre-1.0 versioning, would be 1.0 and 2.0 after +/// 1.0 is released.) +import Foundation + +/// Prepares a diagnostics collector. +/// - Parameter outputPath: A file path where to persist the YAML file. If `nil`, diagnostics will be printed to stderr. +/// - Returns: A tuple containing: +/// - An instance of `DiagnosticCollector` conforming to `Sendable`. +/// - A closure to finalize the diagnostics collection +public func preparedDiagnosticsCollector(outputPath: URL?) -> (any DiagnosticCollector & Sendable, () throws -> Void) { + let innerDiagnostics: any DiagnosticCollector & Sendable + let finalizeDiagnostics: () throws -> Void + + if let outputPath { + let _diagnostics = _YamlFileDiagnosticsCollector(url: outputPath) + finalizeDiagnostics = _diagnostics.finalize + innerDiagnostics = _diagnostics + } else { + innerDiagnostics = StdErrPrintingDiagnosticCollector() + finalizeDiagnostics = {} + } + let diagnostics = ErrorThrowingDiagnosticCollector(upstream: innerDiagnostics) + return (diagnostics, finalizeDiagnostics) +} diff --git a/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift b/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift index 520854c6..17e65726 100644 --- a/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift +++ b/Sources/_OpenAPIGeneratorCore/YamlFileDiagnosticsCollector.swift @@ -20,7 +20,7 @@ struct _DiagnosticsYamlFileContent: Encodable { } /// A collector that writes diagnostics to a YAML file. -final public class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Sendable { +final class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecked Sendable { /// Protects `diagnostics`. private let lock = NSLock() @@ -32,11 +32,9 @@ final public class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecke /// Creates a new collector. /// - Parameter url: A file path where to persist the YAML file. - public init(url: URL) { self.url = url } + init(url: URL) { self.url = url } - /// Emits a diagnostic message to the collector. - /// - Parameter diagnostic: The diagnostic message to be collected. - public func emit(_ diagnostic: Diagnostic) { + func emit(_ diagnostic: Diagnostic) { lock.lock() defer { lock.unlock() } diagnostics.append(diagnostic) @@ -44,7 +42,7 @@ final public class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecke /// Finishes writing to the collector by persisting the accumulated /// diagnostics to a YAML file. - public func finalize() throws { + func finalize() throws { lock.lock() defer { lock.unlock() } let sortedDiagnostics = diagnostics.sorted(by: { a, b in a.description < b.description }) @@ -55,10 +53,3 @@ final public class _YamlFileDiagnosticsCollector: DiagnosticCollector, @unchecke try encoder.encode(container).write(to: url, atomically: true, encoding: .utf8) } } - -/// Prepares a diagnostics collector. -/// - Parameter url: A file path where to persist the YAML file. -/// - Returns: An instance of `DiagnosticCollector` conforming to `Sendable`. -public func preparedDiagnosticsCollector(url: URL) -> any DiagnosticCollector & Sendable { - _YamlFileDiagnosticsCollector(url: url) -} diff --git a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift index 9e261905..9f3fe83b 100644 --- a/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift +++ b/Sources/swift-openapi-generator/GenerateOptions+runGenerator.swift @@ -42,21 +42,7 @@ extension _GenerateOptions { featureFlags: resolvedFeatureFlags ) } - let innerDiagnostics: any DiagnosticCollector & Sendable - let finalizeDiagnostics: () throws -> Void - if let diagnosticsOutputPath { - let _diagnostics = preparedDiagnosticsCollector(url: diagnosticsOutputPath) - if let yamlCollector = _diagnostics as? _YamlFileDiagnosticsCollector { - finalizeDiagnostics = { try yamlCollector.finalize() } - } else { - finalizeDiagnostics = {} - } - innerDiagnostics = _diagnostics - } else { - innerDiagnostics = StdErrPrintingDiagnosticCollector() - finalizeDiagnostics = {} - } - let diagnostics = ErrorThrowingDiagnosticCollector(upstream: innerDiagnostics) + let (diagnostics, finalizeDiagnostics) = preparedDiagnosticsCollector(outputPath: diagnosticsOutputPath) let doc = self.docPath print( """ diff --git a/Tests/OpenAPIGeneratorCoreTests/Test_DiagnosticsCollectorProvider.swift b/Tests/OpenAPIGeneratorCoreTests/Test_DiagnosticsCollectorProvider.swift new file mode 100644 index 00000000..d66169cb --- /dev/null +++ b/Tests/OpenAPIGeneratorCoreTests/Test_DiagnosticsCollectorProvider.swift @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 XCTest +@testable import _OpenAPIGeneratorCore + +final class Test_DiagnosticsCollectorProvider: XCTestCase { + + func testPreparedDiagnosticsCollectorWithOutputPath() throws { + let outputPath = URL(fileURLWithPath: "/path/to/diagnostics.yaml") + let (diagnostics, _) = preparedDiagnosticsCollector(outputPath: outputPath) + XCTAssertTrue(diagnostics is ErrorThrowingDiagnosticCollector) + + if let errorThrowingCollector = diagnostics as? ErrorThrowingDiagnosticCollector { + XCTAssertTrue(errorThrowingCollector.upstream is _YamlFileDiagnosticsCollector) + } else { + XCTFail("Expected diagnostics to be `ErrorThrowingDiagnosticCollector`") + } + } + + func testPreparedDiagnosticsCollectorWithoutOutputPath() throws { + let outputPath: URL? = nil + let (diagnostics, _) = preparedDiagnosticsCollector(outputPath: outputPath) + XCTAssertTrue(diagnostics is ErrorThrowingDiagnosticCollector) + if let errorThrowingCollector = diagnostics as? ErrorThrowingDiagnosticCollector { + XCTAssertTrue(errorThrowingCollector.upstream is StdErrPrintingDiagnosticCollector) + } else { + XCTFail("Expected diagnostics to be `ErrorThrowingDiagnosticCollector`") + } + } +} diff --git a/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift b/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift deleted file mode 100644 index fb27e2dc..00000000 --- a/Tests/OpenAPIGeneratorCoreTests/Test_preparedDiagnosticsCollector.swift +++ /dev/null @@ -1,28 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 XCTest -@testable import _OpenAPIGeneratorCore - -final class Test_preparedDiagnosticsCollector: XCTestCase { - func testPreparedDiagnosticsCollector() { - let url = URL(fileURLWithPath: "/path/to/test-diagnostics.yaml") - let collector = preparedDiagnosticsCollector(url: url) - - XCTAssertTrue( - collector is _YamlFileDiagnosticsCollector, - "Expected collector to be of type _YamlFileDiagnosticsCollector" - ) - } -} From 28091be98a7ab9d2603ba310a7ee6d86140cafa0 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Thu, 15 Aug 2024 23:12:06 +0300 Subject: [PATCH 10/11] Remove unnecessary text from header --- .../DiagnosticsCollectorProvider.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift b/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift index 376976b2..965eebb0 100644 --- a/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift +++ b/Sources/_OpenAPIGeneratorCore/DiagnosticsCollectorProvider.swift @@ -12,19 +12,6 @@ // //===----------------------------------------------------------------------===// -/// A feature that can be explicitly enabled before being released. -/// -/// Commonly used to get early feedback on breaking changes, before -/// they are enabled by default, which can only be done in a major version. -/// -/// Once a feature is enabled unconditionally in the next major version, -/// the corresponding feature flag should be removed at the same time. -/// -/// For example: a breaking feature is being built while version 0.1 is out, -/// and is hidden behind a feature flag. Once ready, the feature is -/// enabled unconditionally on main and the feature flag removed, and version -/// 0.2 is tagged. (This is for pre-1.0 versioning, would be 1.0 and 2.0 after -/// 1.0 is released.) import Foundation /// Prepares a diagnostics collector. From 40e92e037f7a53aa7b7f943b5617b3915c95e2d7 Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN Date: Sat, 24 Aug 2024 00:13:35 +0300 Subject: [PATCH 11/11] Add ArgumentParser explicit dependency --- Package.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 4c2b6125..1b8c7565 100644 --- a/Package.swift +++ b/Package.swift @@ -117,7 +117,9 @@ let package = Package( // Test Target for swift-openapi-generator .testTarget( name: "OpenAPIGeneratorTests", - dependencies: ["swift-openapi-generator"], + dependencies: [ + "swift-openapi-generator", .product(name: "ArgumentParser", package: "swift-argument-parser"), + ], resources: [.copy("Resources")], swiftSettings: swiftSettings ),