diff --git a/src/JsonSchema/Generate.elm b/src/JsonSchema/Generate.elm index e8ce9db..f9d2f61 100644 --- a/src/JsonSchema/Generate.elm +++ b/src/JsonSchema/Generate.elm @@ -21,227 +21,253 @@ schemaToDeclarations component name schema = SchemaUtils.schemaToType [] schema |> CliMonad.andThen (\{ type_, documentation } -> - let - typeName : Common.TypeName - typeName = - Common.toTypeName name - in case type_ of Common.Enum enumVariants -> - [ { moduleName = Common.Types component - , name = typeName - , declaration = - enumVariants - |> NonEmpty.toList - |> List.map (\variantName -> Elm.variant (SchemaUtils.toVariantName typeName variantName)) - |> Elm.customType typeName - |> (case documentation of - Nothing -> - identity + enumToDeclarations component name documentation enumVariants - Just doc -> - Elm.withDocumentation doc - ) - |> Elm.exposeConstructor - , group = "Enum" - } - |> CliMonad.succeed - , { moduleName = Common.Types component - , name = Common.toValueName name ++ "ToString" - , declaration = - Elm.fn (Elm.Arg.var "value") - (\value -> - enumVariants - |> NonEmpty.toList - |> List.map - (\variant -> - Elm.Case.branch - (Elm.Arg.customType (SchemaUtils.toVariantName typeName variant) - (Elm.string (Common.unwrapUnsafe variant)) - ) - identity - ) - |> Elm.Case.custom value (Elm.Annotation.named [] typeName) - ) - |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named [] typeName ] Elm.Annotation.string) - |> Elm.declaration (Common.toValueName name ++ "ToString") - |> Elm.expose - , group = "Enum" - } - |> CliMonad.succeed - , { moduleName = Common.Types component - , name = Common.toValueName name ++ "FromString" - , declaration = - Elm.fn (Elm.Arg.varWith "value" Elm.Annotation.string) - (\value -> - Elm.Case.string value - { cases = - enumVariants - |> NonEmpty.toList - |> List.map - (\variant -> - ( Common.unwrapUnsafe variant - , Gen.Maybe.make_.just - (Elm.value - { name = SchemaUtils.toVariantName typeName variant - , importFrom = [] - , annotation = Just (Elm.Annotation.named [] typeName) - } - ) - ) - ) - , otherwise = Gen.Maybe.make_.nothing - } + _ -> + nonEnumToDeclarations component name schema documentation type_ + ) + |> CliMonad.withPath name + + +enumToDeclarations : + Common.Component + -> Common.UnsafeName + -> Maybe String + -> NonEmpty.NonEmpty Common.UnsafeName + -> CliMonad (List CliMonad.Declaration) +enumToDeclarations component name documentation enumVariants = + let + typeName : Common.TypeName + typeName = + Common.toTypeName name + in + [ { moduleName = Common.Types component + , name = typeName + , declaration = + enumVariants + |> NonEmpty.toList + |> List.map (\variantName -> Elm.variant (SchemaUtils.toVariantName typeName variantName)) + |> Elm.customType typeName + |> (case documentation of + Nothing -> + identity + + Just doc -> + Elm.withDocumentation doc + ) + |> Elm.exposeConstructor + , group = "Enum" + } + |> CliMonad.succeed + , { moduleName = Common.Types component + , name = Common.toValueName name ++ "ToString" + , declaration = + Elm.fn (Elm.Arg.var "value") + (\value -> + enumVariants + |> NonEmpty.toList + |> List.map + (\variant -> + Elm.Case.branch + (Elm.Arg.customType (SchemaUtils.toVariantName typeName variant) + (Elm.string (Common.unwrapUnsafe variant)) ) - |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.string ] (Elm.Annotation.maybe (Elm.Annotation.named [] typeName))) - |> Elm.declaration (Common.toValueName name ++ "FromString") - |> Elm.expose - , group = "Enum" - } - |> CliMonad.succeed - , { moduleName = Common.Types component - , name = Common.toValueName name ++ "Variants" - , declaration = - enumVariants - |> NonEmpty.toList - |> List.map - (\variant -> - Elm.value + identity + ) + |> Elm.Case.custom value (Elm.Annotation.named [] typeName) + ) + |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named [] typeName ] Elm.Annotation.string) + |> Elm.declaration (Common.toValueName name ++ "ToString") + |> Elm.expose + , group = "Enum" + } + |> CliMonad.succeed + , { moduleName = Common.Types component + , name = Common.toValueName name ++ "FromString" + , declaration = + Elm.fn (Elm.Arg.varWith "value" Elm.Annotation.string) + (\value -> + Elm.Case.string value + { cases = + enumVariants + |> NonEmpty.toList + |> List.map + (\variant -> + ( Common.unwrapUnsafe variant + , Gen.Maybe.make_.just + (Elm.value { name = SchemaUtils.toVariantName typeName variant , importFrom = [] , annotation = Just (Elm.Annotation.named [] typeName) } + ) ) - |> Elm.list - |> Elm.declaration (Common.toValueName name ++ "Variants") - |> Elm.expose - , group = "Enum" - } - |> CliMonad.succeed - , CliMonad.map - (\importFrom -> - { moduleName = Common.Json component - , name = "decode" ++ typeName - , declaration = - Elm.declaration - ("decode" ++ typeName) - (Gen.Json.Decode.string - |> Gen.Json.Decode.andThen - (\str -> - Gen.Maybe.caseOf_.maybe - (Elm.apply - (Elm.value - { importFrom = importFrom - , name = Common.toValueName name ++ "FromString" - , annotation = Nothing - } - ) - [ str ] - ) - { just = Gen.Json.Decode.succeed - , nothing = - Gen.Json.Decode.call_.fail - (Elm.Op.append - str - (Elm.string (" is not a valid " ++ typeName)) - ) - } - ) - |> Elm.withType (Gen.Json.Decode.annotation_.decoder (Elm.Annotation.named importFrom typeName)) + ) + , otherwise = Gen.Maybe.make_.nothing + } + ) + |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.string ] (Elm.Annotation.maybe (Elm.Annotation.named [] typeName))) + |> Elm.declaration (Common.toValueName name ++ "FromString") + |> Elm.expose + , group = "Enum" + } + |> CliMonad.succeed + , { moduleName = Common.Types component + , name = Common.toValueName name ++ "Variants" + , declaration = + enumVariants + |> NonEmpty.toList + |> List.map + (\variant -> + Elm.value + { name = SchemaUtils.toVariantName typeName variant + , importFrom = [] + , annotation = Just (Elm.Annotation.named [] typeName) + } + ) + |> Elm.list + |> Elm.declaration (Common.toValueName name ++ "Variants") + |> Elm.expose + , group = "Enum" + } + |> CliMonad.succeed + , CliMonad.map + (\importFrom -> + { moduleName = Common.Json component + , name = "decode" ++ typeName + , declaration = + Elm.declaration + ("decode" ++ typeName) + (Gen.Json.Decode.string + |> Gen.Json.Decode.andThen + (\str -> + Gen.Maybe.caseOf_.maybe + (Elm.apply + (Elm.value + { importFrom = importFrom + , name = Common.toValueName name ++ "FromString" + , annotation = Nothing + } ) - |> Elm.expose - , group = "Decoders" - } - ) - (CliMonad.moduleToNamespace (Common.Types component)) - , CliMonad.map - (\importFrom -> - { moduleName = Common.Json component - , name = "encode" ++ typeName - , declaration = - Elm.declaration ("encode" ++ typeName) - (Elm.functionReduced "rec" - (\value -> - Elm.apply - (Elm.value - { importFrom = importFrom - , name = Common.toValueName name ++ "ToString" - , annotation = Nothing - } - ) - [ value ] - |> Gen.Json.Encode.call_.string + [ str ] + ) + { just = Gen.Json.Decode.succeed + , nothing = + Gen.Json.Decode.call_.fail + (Elm.Op.append + str + (Elm.string (" is not a valid " ++ typeName)) ) - |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named importFrom typeName ] Gen.Json.Encode.annotation_.value) - ) - |> Elm.expose - , group = "Encoders" - } + } ) - (CliMonad.moduleToNamespace (Common.Types component)) - ] - |> CliMonad.combine + |> Elm.withType (Gen.Json.Decode.annotation_.decoder (Elm.Annotation.named importFrom typeName)) + ) + |> Elm.expose + , group = "Decoders" + } + ) + (CliMonad.moduleToNamespace (Common.Types component)) + , CliMonad.map + (\importFrom -> + { moduleName = Common.Json component + , name = "encode" ++ typeName + , declaration = + Elm.declaration ("encode" ++ typeName) + (Elm.functionReduced "rec" + (\value -> + Elm.apply + (Elm.value + { importFrom = importFrom + , name = Common.toValueName name ++ "ToString" + , annotation = Nothing + } + ) + [ value ] + |> Gen.Json.Encode.call_.string + ) + |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named importFrom typeName ] Gen.Json.Encode.annotation_.value) + ) + |> Elm.expose + , group = "Encoders" + } + ) + (CliMonad.moduleToNamespace (Common.Types component)) + ] + |> CliMonad.combine - _ -> - type_ - |> SchemaUtils.typeToAnnotationWithNullable - |> CliMonad.andThen - (\annotation -> - if (Elm.ToString.annotation annotation).signature == typeName then - CliMonad.succeed [] - else - [ { moduleName = Common.Types component - , name = typeName - , declaration = - Elm.alias typeName annotation - |> (case documentation of - Nothing -> - identity +nonEnumToDeclarations : + Common.Component + -> Common.UnsafeName + -> Json.Schema.Definitions.Schema + -> Maybe String + -> Common.Type + -> CliMonad (List CliMonad.Declaration) +nonEnumToDeclarations component name schema documentation type_ = + let + typeName : Common.TypeName + typeName = + Common.toTypeName name + in + type_ + |> SchemaUtils.typeToAnnotationWithNullable + |> CliMonad.andThen + (\annotation -> + if (Elm.ToString.annotation annotation).signature == typeName then + CliMonad.succeed [] - Just doc -> - Elm.withDocumentation doc - ) - |> Elm.expose - , group = "Aliases" - } - |> CliMonad.succeed - , CliMonad.map2 - (\importFrom schemaDecoder -> - { moduleName = Common.Json component - , name = "decode" ++ typeName - , declaration = - Elm.declaration - ("decode" ++ typeName) - (schemaDecoder - |> Elm.withType (Gen.Json.Decode.annotation_.decoder (Elm.Annotation.named importFrom typeName)) - ) - |> Elm.expose - , group = "Decoders" - } - ) - (CliMonad.moduleToNamespace (Common.Types component)) - (schemaToDecoder schema) - , CliMonad.map2 - (\importFrom encoder -> - { moduleName = Common.Json component - , name = "encode" ++ typeName - , declaration = - Elm.declaration ("encode" ++ typeName) - (Elm.functionReduced "rec" encoder - |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named importFrom typeName ] Gen.Json.Encode.annotation_.value) - ) - |> Elm.expose - , group = "Encoders" - } - ) - (CliMonad.moduleToNamespace (Common.Types component)) - (schemaToEncoder schema) - ] - |> CliMonad.combine - ) + else + [ { moduleName = Common.Types component + , name = typeName + , declaration = + Elm.alias typeName annotation + |> (case documentation of + Nothing -> + identity + + Just doc -> + Elm.withDocumentation doc + ) + |> Elm.expose + , group = "Aliases" + } + |> CliMonad.succeed + , CliMonad.map2 + (\importFrom schemaDecoder -> + { moduleName = Common.Json component + , name = "decode" ++ typeName + , declaration = + Elm.declaration + ("decode" ++ typeName) + (schemaDecoder + |> Elm.withType (Gen.Json.Decode.annotation_.decoder (Elm.Annotation.named importFrom typeName)) + ) + |> Elm.expose + , group = "Decoders" + } + ) + (CliMonad.moduleToNamespace (Common.Types component)) + (schemaToDecoder schema) + , CliMonad.map2 + (\importFrom encoder -> + { moduleName = Common.Json component + , name = "encode" ++ typeName + , declaration = + Elm.declaration ("encode" ++ typeName) + (Elm.functionReduced "rec" encoder + |> Elm.withType (Elm.Annotation.function [ Elm.Annotation.named importFrom typeName ] Gen.Json.Encode.annotation_.value) + ) + |> Elm.expose + , group = "Encoders" + } + ) + (CliMonad.moduleToNamespace (Common.Types component)) + (schemaToEncoder schema) + ] + |> CliMonad.combine ) - |> CliMonad.withPath name schemaToDecoder : Json.Schema.Definitions.Schema -> CliMonad Elm.Expression