From 5ea92609e069dc7b82336c916eda892a4380b3eb Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Thu, 12 Feb 2026 15:23:57 +0100 Subject: [PATCH 1/7] Fix nullable-enum.yaml syntax --- cli/example/nullable-enum.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cli/example/nullable-enum.yaml b/cli/example/nullable-enum.yaml index 3479158c..a57cc2f5 100644 --- a/cli/example/nullable-enum.yaml +++ b/cli/example/nullable-enum.yaml @@ -4,12 +4,15 @@ info: version: 1.0.0 paths: "/": - summary: Does stuff - responses: - 200: - description: Ok - schema: - "#ref": "#/components/schemas/NullableEnum" + get: + summary: Does stuff + responses: + 200: + description: Ok + content: + application/json: + schema: + "$ref": "#/components/schemas/NullableEnum" components: schemas: NullableEnum: From 2bc741a6170b904a963ea512d680a305d25461ca Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 19:56:30 +0100 Subject: [PATCH 2/7] Fix recursive-allof-refs.yaml syntax --- cli/example/recursive-allof-refs.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/example/recursive-allof-refs.yaml b/cli/example/recursive-allof-refs.yaml index bf2b5bc6..89fa2d56 100644 --- a/cli/example/recursive-allof-refs.yaml +++ b/cli/example/recursive-allof-refs.yaml @@ -35,9 +35,13 @@ components: paths: "/api/grand-child": summary: Get a GrandChild object. - description: + description: Example description get: operationId: getGrandChild responses: 200: - $ref: "#/components/schemas/GrandChild" + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/GrandChild" From 268ddcb33e3617a419a9ee2a7d2c6c6f32b23d6c Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 20:03:40 +0100 Subject: [PATCH 3/7] Fix overriding-global-security.yaml syntax --- cli/example/overriding-global-security.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cli/example/overriding-global-security.yaml b/cli/example/overriding-global-security.yaml index f7451979..5b91ecfc 100644 --- a/cli/example/overriding-global-security.yaml +++ b/cli/example/overriding-global-security.yaml @@ -7,6 +7,13 @@ components: Data: description: "Data" type: string + responses: + Data: + description: "Data" + content: + application/json: + schema: + $ref: "#/components/schemas/Data" securitySchemes: Token: type: apiKey @@ -22,7 +29,7 @@ paths: operationId: GetProtectedData responses: 200: - $ref: "#/components/schemas/Data" + $ref: "#/components/responses/Data" "/api/unprotected": get: @@ -32,7 +39,7 @@ paths: security: [] responses: 200: - $ref: "#/components/schemas/Data" + $ref: "#/components/responses/Data" post: summary: Unprotected endpoint to store data # Whoops! Security should be overridden here like for GET. Let's fix it @@ -41,7 +48,7 @@ paths: operationId: PostUnprotectedData responses: 200: - $ref: "#/components/schemas/Data" + $ref: "#/components/responses/Data" patch: summary: Unprotected endpoint to store data (again) # Whoops! This is supposed to be unprotected, like GET. Let's fix it @@ -52,4 +59,4 @@ paths: operationId: PatchUnprotectedData responses: 200: - $ref: "#/components/schemas/Data" + $ref: "#/components/responses/Data" From 165bb13e71e0e6e5e28b4c324c005dd544e4da92 Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 20:00:46 +0100 Subject: [PATCH 4/7] Fix error message --- src/Common.elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Common.elm b/src/Common.elm index 40ccd313..0d9470e4 100644 --- a/src/Common.elm +++ b/src/Common.elm @@ -576,7 +576,7 @@ parseRequestBodyRef ref = Ok (RefTo RequestBody res) else - Err ("Expected a reference to a schema, found a reference to " ++ ref) + Err ("Expected a reference to a request body, found a reference to " ++ ref) ) @@ -589,7 +589,7 @@ parseResponseRef ref = Ok (RefTo Response res) else - Err ("Expected a reference to a schema, found a reference to " ++ ref) + Err ("Expected a reference to a response, found a reference to " ++ ref) ) From 88321f418b813b7d9ff764027b7d2c8420bebe8f Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 16:05:06 +0100 Subject: [PATCH 5/7] Don't skip paths by default --- cli/src/Cli.elm | 5 +++++ src/CliMonad.elm | 30 +++++++++++++++++++++--------- src/OpenApi/Config.elm | 23 +++++++++++++++++++---- src/OpenApi/Generate.elm | 3 ++- tests/Test/OpenApi/Generate.elm | 2 ++ 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/cli/src/Cli.elm b/cli/src/Cli.elm index a1f91b4a..61299e6e 100644 --- a/cli/src/Cli.elm +++ b/cli/src/Cli.elm @@ -50,6 +50,7 @@ type alias CliOptions = , overrides : List OpenApi.Config.Path , writeMergedTo : Maybe String , noElmFormat : Bool + , keepGoing : Bool } @@ -96,6 +97,8 @@ program = (Cli.Option.optionalKeywordArg "write-merged-to") |> Cli.OptionsParser.with (Cli.Option.flag "no-elm-format") + |> Cli.OptionsParser.with + (Cli.Option.flag "keep-going") |> Cli.OptionsParser.withDoc ([ "" , """version: 0.7.0""" @@ -166,6 +169,7 @@ program = , formatOption "overrides" [ "Load an additional file to override parts of the original Open API file." ] , formatOption "write-merged-to" [ "Write the merged Open API spec to the given file." ] , formatOption "no-elm-format" [ "Don't run elm-format on the outputs." ] + , formatOption "keep-going" [ "If a route can't be generated, skip it instead of erroring out." ] ] |> String.join "\n\n" ) @@ -370,6 +374,7 @@ parseCliOptions cliOptions = |> OpenApi.Config.withGenerateTodos cliOptions.generateTodos |> OpenApi.Config.withAutoConvertSwagger cliOptions.autoConvertSwagger |> OpenApi.Config.withNoElmFormat cliOptions.noElmFormat + |> OpenApi.Config.withKeepGoing cliOptions.keepGoing |> maybe OpenApi.Config.withSwaggerConversionUrl cliOptions.swaggerConversionUrl |> maybe OpenApi.Config.withSwaggerConversionCommand (cliOptions.swaggerConversionCommand diff --git a/src/CliMonad.elm b/src/CliMonad.elm index 0ffd7205..dad0b4bf 100644 --- a/src/CliMonad.elm +++ b/src/CliMonad.elm @@ -44,6 +44,7 @@ import OpenApi exposing (OpenApi) import OpenApi.Config import Pretty import String.Extra +import Triple.Extra type alias Message = @@ -85,6 +86,7 @@ type alias Input = , namespace : List String , formats : FastDict.Dict InternalFormatName InternalFormat , warnOnMissingEnums : Bool + , keepGoing : Bool } @@ -126,6 +128,7 @@ run : , namespace : List String , formats : List OpenApi.Config.Format , warnOnMissingEnums : Bool + , keepGoing : Bool } -> CliMonad (List Declaration) -> @@ -148,6 +151,7 @@ run oneOfDeclarations input (CliMonad x) = |> List.map toInternalFormat |> FastDict.fromList , warnOnMissingEnums = input.warnOnMissingEnums + , keepGoing = input.keepGoing } res : Result Message ( List Declaration, Output, Cache ) @@ -570,20 +574,28 @@ getApiSpec = CliMonad (\input cache -> Ok ( input.openApi, emptyOutput, cache )) +{-| If the user has chosen to keep going in the face of errors, this will convert an error into a warning. Otherwise this returns the input +-} errorToWarning : CliMonad a -> CliMonad (Maybe a) errorToWarning (CliMonad f) = CliMonad (\input cache -> - case f input cache of - Ok ( res, output, cache2 ) -> - Ok ( Just res, output, cache2 ) + if input.keepGoing then + case f input cache of + Ok ( res, output, cache2 ) -> + Ok ( Just res, output, cache2 ) - Err { path, message } -> - ( Nothing - , { emptyOutput | warnings = [ { path = path, message = message, details = Pretty.empty } ] } - , cache - ) - |> Ok + Err { path, message } -> + ( Nothing + , { emptyOutput | warnings = [ { path = path, message = message, details = Pretty.empty } ] } + , cache + ) + |> Ok + + else + Result.map + (Triple.Extra.mapFirst Just) + (f input cache) ) diff --git a/src/OpenApi/Config.elm b/src/OpenApi/Config.elm index 0a9ea968..c8d9a31b 100644 --- a/src/OpenApi/Config.elm +++ b/src/OpenApi/Config.elm @@ -1,9 +1,9 @@ module OpenApi.Config exposing ( Config, EffectType(..), effectTypeToPackage, Format, Input, Path(..), Server(..) , init, inputFrom, pathFromString - , withAutoConvertSwagger, AutoConvertSwagger(..), withEffectTypes, withFormat, withFormats, withGenerateTodos, withInput, withSwaggerConversionCommand, withSwaggerConversionUrl, withNoElmFormat + , withAutoConvertSwagger, AutoConvertSwagger(..), withEffectTypes, withFormat, withFormats, withGenerateTodos, withInput, withSwaggerConversionCommand, withSwaggerConversionUrl, withNoElmFormat, withKeepGoing , withOutputModuleName, withOverrides, withServer, withWriteMergedTo, withWarnOnMissingEnums - , autoConvertSwagger, inputs, outputDirectory, swaggerConversionCommand, swaggerConversionUrl, noElmFormat + , autoConvertSwagger, inputs, outputDirectory, swaggerConversionCommand, swaggerConversionUrl, noElmFormat, keepGoing , oasPath, overrides, writeMergedTo , toGenerationConfig, Generate, pathToString , defaultFormats @@ -20,13 +20,13 @@ module OpenApi.Config exposing # Creation @docs init, inputFrom, pathFromString -@docs withAutoConvertSwagger, AutoConvertSwagger, withEffectTypes, withFormat, withFormats, withGenerateTodos, withInput, withSwaggerConversionCommand, withSwaggerConversionUrl, withNoElmFormat +@docs withAutoConvertSwagger, AutoConvertSwagger, withEffectTypes, withFormat, withFormats, withGenerateTodos, withInput, withSwaggerConversionCommand, withSwaggerConversionUrl, withNoElmFormat, withKeepGoing @docs withOutputModuleName, withOverrides, withServer, withWriteMergedTo, withWarnOnMissingEnums # Config properties -@docs autoConvertSwagger, inputs, outputDirectory, swaggerConversionCommand, swaggerConversionUrl, noElmFormat +@docs autoConvertSwagger, inputs, outputDirectory, swaggerConversionCommand, swaggerConversionUrl, noElmFormat, keepGoing # Input properties @@ -83,6 +83,7 @@ type Config , staticFormats : List Format , dynamicFormats : List { format : String, basicType : Common.BasicType } -> List Format , noElmFormat : Bool + , keepGoing : Bool } @@ -242,6 +243,7 @@ init initialOutputDirectory = , staticFormats = defaultFormats , dynamicFormats = \_ -> [] , noElmFormat = False + , keepGoing = False } |> Config @@ -550,6 +552,11 @@ withNoElmFormat newNoElmFormat (Config config) = Config { config | noElmFormat = newNoElmFormat } +withKeepGoing : Bool -> Config -> Config +withKeepGoing newKeepGoing (Config config) = + Config { config | keepGoing = newKeepGoing } + + ------------- -- Getters -- @@ -592,6 +599,12 @@ noElmFormat (Config config) = config.noElmFormat +{-| -} +keepGoing : Config -> Bool +keepGoing (Config config) = + config.keepGoing + + {-| -} oasPath : Input -> Path oasPath (Input input) = @@ -624,6 +637,7 @@ type alias Generate = , server : Server , formats : List Format , warnOnMissingEnums : Bool + , keepGoing : Bool } @@ -657,6 +671,7 @@ toGenerationConfig formatsInput (Config config) augmentedInputs = , server = input.server , warnOnMissingEnums = input.warnOnMissingEnums , formats = config.staticFormats ++ config.dynamicFormats formatsInput + , keepGoing = config.keepGoing } , spec ) diff --git a/src/OpenApi/Generate.elm b/src/OpenApi/Generate.elm index 6764ac52..3b7faf9c 100644 --- a/src/OpenApi/Generate.elm +++ b/src/OpenApi/Generate.elm @@ -119,7 +119,7 @@ files : , warnings : List Message , requiredPackages : FastSet.Set String } -files { namespace, generateTodos, effectTypes, server, formats, warnOnMissingEnums } apiSpec = +files { namespace, generateTodos, effectTypes, server, formats, warnOnMissingEnums, keepGoing } apiSpec = case extractEnums apiSpec of Err e -> Err e @@ -148,6 +148,7 @@ files { namespace, generateTodos, effectTypes, server, formats, warnOnMissingEnu , namespace = namespace , formats = formats , warnOnMissingEnums = warnOnMissingEnums + , keepGoing = keepGoing } |> Result.map (\{ declarations, warnings, requiredPackages } -> diff --git a/tests/Test/OpenApi/Generate.elm b/tests/Test/OpenApi/Generate.elm index 2fe60c42..cbd9f193 100644 --- a/tests/Test/OpenApi/Generate.elm +++ b/tests/Test/OpenApi/Generate.elm @@ -129,6 +129,7 @@ fuzzTitle = , server = OpenApi.Config.Default , formats = OpenApi.Config.defaultFormats , warnOnMissingEnums = True + , keepGoing = False } oas in @@ -257,6 +258,7 @@ pr267 = , server = OpenApi.Config.Default , formats = OpenApi.Config.defaultFormats , warnOnMissingEnums = True + , keepGoing = False } oas in From 98fb23f5d7d7a3e6ae4b12eec95cba5b3ea65556 Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 19:52:42 +0100 Subject: [PATCH 6/7] Keep adding documentation --- review/suppressed/Docs.NoMissing.json | 2 +- src/OpenApi/Config.elm | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/review/suppressed/Docs.NoMissing.json b/review/suppressed/Docs.NoMissing.json index 41df1d91..61b78459 100644 --- a/review/suppressed/Docs.NoMissing.json +++ b/review/suppressed/Docs.NoMissing.json @@ -3,7 +3,7 @@ "automatically created by": "elm-review suppress", "learn more": "elm-review suppress --help", "suppressions": [ - { "count": 30, "filePath": "src/OpenApi/Config.elm" }, + { "count": 29, "filePath": "src/OpenApi/Config.elm" }, { "count": 5, "filePath": "src/OpenApi/Generate.elm" } ] } diff --git a/src/OpenApi/Config.elm b/src/OpenApi/Config.elm index c8d9a31b..bb8779f3 100644 --- a/src/OpenApi/Config.elm +++ b/src/OpenApi/Config.elm @@ -209,7 +209,8 @@ type Path | Url Url.Url -- https://petstore3.swagger.io/api/v3/openapi.json -{-| -} +{-| Builds a `Path`. If the file is a valid URL, it will be used as such, otherwise it will be interpreted as a local file path. +-} pathFromString : String -> Path pathFromString path = case Url.fromString path of @@ -231,7 +232,15 @@ pathToString pathType = Url.toString url -{-| -} +{-| Create an empty `Config` with no inputs and a given output directory. + +The default options are to: + + - run elm-format; + - ask before converting Swagger specs to OpenAPI specs; + - fail rather than generating `Debug.todo` or skipping unimplemented paths. + +-} init : String -> Config init initialOutputDirectory = { inputs = [] @@ -268,7 +277,16 @@ inputFrom path = ------------- -{-| -} +{-| The built-in formats: + + - `date-time` + - `date` + - `uri` + - `uuid` + - `byte` + - `password` + +-} defaultFormats : List Format defaultFormats = [ dateTimeFormat From 9b7f2d5e1addf9646775a72adaf80efc4e271a36 Mon Sep 17 00:00:00 2001 From: Leonardo Taglialegne Date: Fri, 13 Feb 2026 20:08:38 +0100 Subject: [PATCH 7/7] I give up for now on having a perfect run. Let's merge this and keep chipping away at the problems later --- cli/src/TestGenScript.elm | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/src/TestGenScript.elm b/cli/src/TestGenScript.elm index 4eca14b6..3fe26ef8 100644 --- a/cli/src/TestGenScript.elm +++ b/cli/src/TestGenScript.elm @@ -119,6 +119,7 @@ run = -- Slimmed config for profiling OpenApi.Config.init "./generated" |> OpenApi.Config.withNoElmFormat True + |> OpenApi.Config.withKeepGoing True |> OpenApi.Config.withInput additionalProperties |> OpenApi.Config.withInput recursiveAllofRefs |> OpenApi.Config.withInput overridingGlobalSecurity