diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/JavaEmitter.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/JavaEmitter.kt index fb23bdb6..3df78054 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/JavaEmitter.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/JavaEmitter.kt @@ -81,6 +81,7 @@ class JavaEmitter( is Reference.Primitive -> when (type) { Reference.Primitive.Type.String -> "String" Reference.Primitive.Type.Integer -> "Integer" + Reference.Primitive.Type.Number -> "Double" Reference.Primitive.Type.Boolean -> "Boolean" } }.sanitizeSymbol() @@ -89,10 +90,17 @@ class JavaEmitter( override fun Reference.emit() = withLogging(logger) { emitSymbol() .let { if (isIterable) "java.util.List<$it>" else it } + .let { if (isMap) "java.util.Map" else it } } override fun Enum.emit() = withLogging(logger) { - fun String.sanitizeEnum() = replace("-", "_").let { if (it.first().isDigit()) "_$it" else it } + fun String.sanitizeEnum() = this + .replace("/", "_") + .replace(" ", "_") + .replace("-", "_") + .replace("–", "_") + .let { if (it.first().isDigit()) "_$it" else it } + val body = """ |${SPACER}public final String label; |${SPACER}${name.sanitizeSymbol()}(String label) { @@ -179,7 +187,7 @@ class JavaEmitter( """.trimMargin() private fun List.emitResponseMapper() = """ - |${SPACER}static > Function, Res> RESPONSE_MAPPER(Wirespec.ContentMapper contentMapper) { + |${SPACER}static > Function, Res> RESPONSE_MAPPER(Wirespec.ContentMapper contentMapper) { |return response -> { |${distinctBy { it.status to it.content?.type }.joinToString("") { it.emitResponseMapperCondition() }} |${SPACER}${SPACER}throw new IllegalStateException("Unknown response type"); @@ -248,7 +256,7 @@ class JavaEmitter( fun String.sanitizeKeywords() = if (reservedKeywords.contains(this)) "_$this" else this - fun String.sanitizeSymbol() = replace(".", "") + fun String.sanitizeSymbol() = replace(".", "").replace(" ", "_") companion object { private val reservedKeywords = listOf( "abstract", "continue", "for", "new", "switch", diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/KotlinEmitter.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/KotlinEmitter.kt index f2d9e390..5cbecd5a 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/KotlinEmitter.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/KotlinEmitter.kt @@ -92,6 +92,7 @@ class KotlinEmitter( is Reference.Primitive -> when (type) { Reference.Primitive.Type.String -> "String" Reference.Primitive.Type.Integer -> "Int" + Reference.Primitive.Type.Number -> "Double" Reference.Primitive.Type.Boolean -> "Boolean" } }.sanitizeSymbol() diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/ScalaEmitter.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/ScalaEmitter.kt index 208b0248..2eb669f4 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/ScalaEmitter.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/ScalaEmitter.kt @@ -48,6 +48,7 @@ class ScalaEmitter( is Reference.Primitive -> when (type) { Reference.Primitive.Type.String -> "String" Reference.Primitive.Type.Integer -> "Int" + Reference.Primitive.Type.Number -> "Double" Reference.Primitive.Type.Boolean -> "Boolean" } }.let { if (isIterable) "List[$it]" else it } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/TypeScriptEmitter.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/TypeScriptEmitter.kt index 0e83d247..9d56a709 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/TypeScriptEmitter.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/TypeScriptEmitter.kt @@ -56,6 +56,7 @@ class TypeScriptEmitter(logger: Logger = noLogger) : Emitter(logger) { is Reference.Primitive -> when (type) { Reference.Primitive.Type.String -> "string" Reference.Primitive.Type.Integer -> "number" + Reference.Primitive.Type.Number -> "number" Reference.Primitive.Type.Boolean -> "boolean" } } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/WirespecEmitter.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/WirespecEmitter.kt index 6cf3b102..c6e6a9dc 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/WirespecEmitter.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/emit/WirespecEmitter.kt @@ -37,6 +37,7 @@ class WirespecEmitter(logger: Logger = noLogger) : Emitter(logger) { is Reference.Primitive -> when (type) { Reference.Primitive.Type.String -> "String" Reference.Primitive.Type.Integer -> "Integer" + Reference.Primitive.Type.Number -> "Number" Reference.Primitive.Type.Boolean -> "Boolean" } }.let { if (isIterable) "$it[]" else it } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt index 8a4911b3..1ce70521 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt @@ -27,6 +27,7 @@ import community.flock.wirespec.compiler.core.tokenize.types.TRACE import community.flock.wirespec.compiler.core.tokenize.types.WirespecType import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean import community.flock.wirespec.compiler.core.tokenize.types.WsInteger +import community.flock.wirespec.compiler.core.tokenize.types.WsNumber import community.flock.wirespec.compiler.core.tokenize.types.WsString import community.flock.wirespec.compiler.utils.Logger @@ -131,6 +132,7 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { is WsString -> Primitive(Primitive.Type.String, isIterable) is WsInteger -> Primitive(Primitive.Type.Integer, isIterable) + is WsNumber -> Primitive(Primitive.Type.Number, isIterable) is WsBoolean -> Primitive(Primitive.Type.Boolean, isIterable) diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt index ec075ec3..85e11a99 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt @@ -16,6 +16,7 @@ import community.flock.wirespec.compiler.core.tokenize.types.RightCurly import community.flock.wirespec.compiler.core.tokenize.types.WirespecType import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean import community.flock.wirespec.compiler.core.tokenize.types.WsInteger +import community.flock.wirespec.compiler.core.tokenize.types.WsNumber import community.flock.wirespec.compiler.core.tokenize.types.WsString import community.flock.wirespec.compiler.utils.Logger @@ -96,6 +97,11 @@ class TypeParser(logger: Logger) : AbstractParser(logger) { isIterable ) + is WsNumber -> Type.Shape.Field.Reference.Primitive( + Type.Shape.Field.Reference.Primitive.Type.Number, + isIterable + ) + is WsBoolean -> Type.Shape.Field.Reference.Primitive( Type.Shape.Field.Reference.Primitive.Type.Boolean, isIterable diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/nodes/Type.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/nodes/Type.kt index 997034ae..3fa06d4f 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/nodes/Type.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/nodes/Type.kt @@ -20,7 +20,7 @@ data class Type(val name: String, val shape: Shape) : Definition { override val isIterable: Boolean, override val isMap: Boolean = false ) : Reference { - enum class Type { String, Integer, Boolean } + enum class Type { String, Integer, Number, Boolean } } } } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt index 93de0136..bb92ac4f 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt @@ -31,6 +31,7 @@ data object WsEndpointDef : WirespecDefinition sealed interface WirespecType : Keyword data object WsString : WirespecType data object WsInteger : WirespecType +data object WsNumber : WirespecType data object WsBoolean : WirespecType data object CustomType : WirespecType diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt index b44d7804..95a47fa0 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt @@ -23,6 +23,7 @@ import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean import community.flock.wirespec.compiler.core.tokenize.types.WsEndpointDef import community.flock.wirespec.compiler.core.tokenize.types.WsEnumTypeDef import community.flock.wirespec.compiler.core.tokenize.types.WsInteger +import community.flock.wirespec.compiler.core.tokenize.types.WsNumber import community.flock.wirespec.compiler.core.tokenize.types.WsRefinedTypeDef import community.flock.wirespec.compiler.core.tokenize.types.WsString import community.flock.wirespec.compiler.core.tokenize.types.WsTypeDef @@ -59,6 +60,7 @@ class Lexer : IntellijLexer() { is CustomType -> Types.CUSTOM_TYPE is WsBoolean -> Types.BOOLEAN is WsInteger -> Types.INTEGER + is WsNumber -> Types.NUMBER is WsString -> Types.STRING is LeftCurly -> Types.LEFT_CURLY is QuestionMark -> Types.QUESTION_MARK diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt index 1441cb58..3d5d8873 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt @@ -12,6 +12,7 @@ interface Types { val CUSTOM_TYPE = ElementType("CUSTOM_TYPE") val BOOLEAN = ElementType("BOOLEAN") val INTEGER = ElementType("INTEGER") + val NUMBER = ElementType("NUMBER") val STRING = ElementType("STRING") val TYPE_DEF = ElementType("TYPE_DEF") val ENUM_DEF = ElementType("ENUM_DEF") diff --git a/src/openapi/build.gradle.kts b/src/openapi/build.gradle.kts index 5deb6dfa..c0505bbc 100644 --- a/src/openapi/build.gradle.kts +++ b/src/openapi/build.gradle.kts @@ -33,7 +33,7 @@ kotlin { dependencies { implementation(project(":src:compiler:core")) implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") - implementation("community.flock.kotlinx.openapi.bindings:kotlin-openapi-bindings:0.0.17") + implementation("community.flock.kotlinx.openapi.bindings:kotlin-openapi-bindings:0.0.19") } } commonTest { diff --git a/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v2/OpenApiParser.kt b/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v2/OpenApiParser.kt index cb91872f..5d109852 100644 --- a/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v2/OpenApiParser.kt +++ b/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v2/OpenApiParser.kt @@ -20,6 +20,7 @@ import community.flock.kotlinx.openapi.bindings.v2.SwaggerObject import community.flock.wirespec.compiler.core.parse.nodes.Definition import community.flock.wirespec.compiler.core.parse.nodes.Endpoint import community.flock.wirespec.compiler.core.parse.nodes.Enum +import community.flock.wirespec.compiler.core.parse.nodes.Refined import community.flock.wirespec.compiler.core.parse.nodes.Type import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Reference @@ -231,10 +232,14 @@ class OpenApiParser(private val openApi: SwaggerObject) { ): List = when { additionalProperties != null -> when (additionalProperties) { is BooleanObject -> emptyList() - else -> additionalProperties!!.resolve().flatten(name) + else -> additionalProperties + ?.resolve() + ?.takeIf { it.properties != null } + ?.flatten(name) + ?: emptyList() } - allOf != null -> listOf(Type(name, Type.Shape(allOf.orEmpty().flatMap { it.resolve().toField(name) }))) + allOf != null -> listOf(Type(name, Type.Shape(allOf.orEmpty().flatMap { it.resolve().toField(name) }.distinctBy { it.identifier }))) .plus(allOf!!.flatMap { when (it) { is ReferenceObject -> emptyList() @@ -264,14 +269,9 @@ class OpenApiParser(private val openApi: SwaggerObject) { } OpenapiType.ARRAY -> when (val it = this.items) { - is ReferenceObject -> - emptyList() - - is SchemaObject -> - it.flatten(className(name, "Array")) - - null -> - emptyList() + is ReferenceObject -> emptyList() + is SchemaObject -> it.flatten(className(name, "Array")) + null -> emptyList() } else -> emptyList() @@ -321,7 +321,7 @@ class OpenApiParser(private val openApi: SwaggerObject) { is BooleanObject -> Reference.Any(false, true) is ReferenceObject -> additionalProperties.toReference().toMap() is SchemaObject -> additionalProperties - .takeIf { it.type != null } + .takeIf { it.type.isPrimitive() || it.properties != null} ?.run { toReference(name).toMap() } ?: Reference.Any(false, true) } @@ -369,7 +369,7 @@ class OpenApiParser(private val openApi: SwaggerObject) { private fun OpenapiType.toPrimitive() = when (this) { OpenapiType.STRING -> Reference.Primitive.Type.String OpenapiType.INTEGER -> Reference.Primitive.Type.Integer - OpenapiType.NUMBER -> Reference.Primitive.Type.Integer + OpenapiType.NUMBER -> Reference.Primitive.Type.Number OpenapiType.BOOLEAN -> Reference.Primitive.Type.Boolean else -> error("Type is not a primitive") } diff --git a/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v3/OpenApiParser.kt b/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v3/OpenApiParser.kt index c47a78e3..1226c933 100644 --- a/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v3/OpenApiParser.kt +++ b/src/openapi/src/commonMain/kotlin/community/flock/wirespec/openapi/v3/OpenApiParser.kt @@ -323,7 +323,7 @@ class OpenApiParser(private val openApi: OpenAPIObject) { oneOf != null -> TODO("oneOf is not implemented") anyOf != null -> TODO("anyOf is not implemented") - allOf != null -> listOf(Type(name, Type.Shape(allOf.orEmpty().flatMap { it.resolve().toField(name) }))) + allOf != null -> listOf(Type(name, Type.Shape(allOf.orEmpty().flatMap { it.resolve().toField(name) }.distinctBy { it.identifier }))) .plus(allOf!!.flatMap { when (it) { is ReferenceObject -> emptyList() @@ -406,7 +406,7 @@ class OpenApiParser(private val openApi: OpenAPIObject) { is BooleanObject -> Reference.Any(false, true) is ReferenceObject -> additionalProperties.toReference().toMap() is SchemaObject -> additionalProperties - .takeIf { it.type != null } + .takeIf { it.type.isPrimitive() || it.properties != null} ?.run { toReference(name).toMap() } ?: Reference.Any(false, true) } @@ -457,7 +457,7 @@ class OpenApiParser(private val openApi: OpenAPIObject) { private fun OpenapiType.toPrimitive() = when (this) { OpenapiType.STRING -> Primitive.Type.String OpenapiType.INTEGER -> Primitive.Type.Integer - OpenapiType.NUMBER -> Primitive.Type.Integer + OpenapiType.NUMBER -> Primitive.Type.Number OpenapiType.BOOLEAN -> Primitive.Type.Boolean else -> error("Type is not a primitive") } diff --git a/src/openapi/src/jvmTest/kotlin/community/flock/wirespec/openapi/common/Expected.kt b/src/openapi/src/jvmTest/kotlin/community/flock/wirespec/openapi/common/Expected.kt index 1df53177..85da6632 100644 --- a/src/openapi/src/jvmTest/kotlin/community/flock/wirespec/openapi/common/Expected.kt +++ b/src/openapi/src/jvmTest/kotlin/community/flock/wirespec/openapi/common/Expected.kt @@ -59,12 +59,12 @@ object Expected { value = listOf( Type.Shape.Field( identifier = Identifier(value = "a"), - reference = Reference.Primitive(type = Reference.Primitive.Type.Integer, isIterable = false), + reference = Reference.Primitive(type = Reference.Primitive.Type.Number, isIterable = false), isNullable = true ), Type.Shape.Field( identifier = Identifier(value = "b"), - reference = Reference.Primitive(type = Reference.Primitive.Type.Integer, isIterable = false), + reference = Reference.Primitive(type = Reference.Primitive.Type.Number, isIterable = false), isNullable = true ) ) @@ -128,7 +128,7 @@ object Expected { Type.Shape.Field( identifier = Identifier(value = "a"), reference = Reference.Primitive( - type = Reference.Primitive.Type.Integer, + type = Reference.Primitive.Type.Number, isIterable = false ), isNullable = true @@ -136,7 +136,7 @@ object Expected { Type.Shape.Field( identifier = Identifier(value = "b"), reference = Reference.Primitive( - type = Reference.Primitive.Type.Integer, + type = Reference.Primitive.Type.Number, isIterable = false ), isNullable = true @@ -294,7 +294,7 @@ object Expected { Type.Shape.Field( identifier = Identifier(value = "code"), reference = Reference.Primitive( - type = Reference.Primitive.Type.Integer, + type = Reference.Primitive.Type.Number, isIterable = false ), isNullable = true @@ -317,7 +317,7 @@ object Expected { Type.Shape.Field( identifier = Identifier(value = "code"), reference = Reference.Primitive( - type = Reference.Primitive.Type.Integer, + type = Reference.Primitive.Type.Number, isIterable = false ), isNullable = true