Skip to content

Commit

Permalink
Merge pull request #117 from outfoxx/fix/obj-hier
Browse files Browse the repository at this point in the history
Fixes for hierarchies in Kotlin, Swift & Typescript
  • Loading branch information
kdubb authored Nov 14, 2024
2 parents 7e8bc9f + 866fde1 commit e6a46d8
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,21 @@ import amf.core.client.platform.model.domain.PropertyShape
import amf.core.client.platform.model.domain.Shape
import amf.core.internal.annotations.Aliases
import amf.shapes.client.platform.model.domain.NodeShape
import io.outfoxx.sunday.generator.utils.allUnits
import io.outfoxx.sunday.generator.utils.annotations
import io.outfoxx.sunday.generator.utils.declares
import io.outfoxx.sunday.generator.utils.id
import io.outfoxx.sunday.generator.utils.location
import io.outfoxx.sunday.generator.utils.name
import io.outfoxx.sunday.generator.utils.nonPatternProperties
import io.outfoxx.sunday.generator.utils.*
import scala.collection.JavaConverters

interface ResolutionContext {

val unit: BaseUnit
val shapeIndex: ShapeIndex

fun hasInherited(shape: Shape): Boolean = shapeIndex.hasInherited(shape)
fun hasInherited(shape: Shape): Boolean = shapeIndex.hasInherited(shape.nonNullableType)

fun hasNoInherited(shape: Shape): Boolean = shapeIndex.hasNoInherited(shape)
fun hasNoInherited(shape: Shape): Boolean = shapeIndex.hasNoInherited(shape.nonNullableType)

fun hasNoInheriting(shape: Shape): Boolean = shapeIndex.hasNoInheriting(shape)
fun hasNoInheriting(shape: Shape): Boolean = shapeIndex.hasNoInheriting(shape.nonNullableType)

fun findRootShape(shape: Shape): Shape = findSuperShapeOrNull(shape)?.let(this::findRootShape) ?: shape
fun findRootShape(shape: Shape): Shape = findSuperShapeOrNull(shape.nonNullableType)?.let(this::findRootShape) ?: shape

fun findSuperShapeOrNull(shape: Shape): Shape? {
val superShapeId = shapeIndex.findSuperShapeIdOrNull(shape) ?: return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ class KotlinTypeRegistry(
resolveReferencedTypeName(itemsShape, context)
}
?: ANY

val collectionType =
if (shape.uniqueItems == true) {
SET
Expand Down Expand Up @@ -612,7 +612,7 @@ class KotlinTypeRegistry(
}

var inheritedProperties = superShape?.let(context::findAllProperties) ?: emptyList()
var declaredProperties = context.findProperties(shape)
var declaredProperties = context.findProperties(shape).filter { dec -> dec.name !in inheritedProperties.map { it.name } }

val inheritingTypes = context.findInheritingShapes(shape)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ class SwiftTypeRegistry(
when {
!isLeaf -> {
propertyTypeName = if (isOptional) {
(propertyTypeName.makeNonOptional() as DeclaredTypeName).nestedType(ANY_REF_NAME).makeOptional()
(propertyTypeName.makeNonOptional() as DeclaredTypeName).nestedType(ANY_REF_NAME)
} else {
(propertyTypeName as DeclaredTypeName).nestedType(ANY_REF_NAME)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ val Shape.ifShape: Shape? get() = this.ifShape()
val Shape.thenShape: Shape? get() = this.thenShape()
val Shape.elseShape: Shape? get() = this.elseShape()
val Shape.inlined: Boolean get() = this.annotations.inlinedElement()
val Shape.nonNullableType: Shape get() = if (this is UnionShape) this.nullableType else this

//
val ShapeExtension.definedBy: PropertyShape get() = this.definedBy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ class RamlObjectTypesTest {
val typeRegistryOptions = setOf<Option>()
val typeRegistry = KotlinTypeRegistry("io.test", null, GenerationMode.Server, typeRegistryOptions)

val typeSpec = findType("io.test.Test", generateTypes(testUri, typeRegistry))
val types = generateTypes(testUri, typeRegistry)
val typeSpec = findType("io.test.Test", types)

assertEquals(
"""
Expand All @@ -97,6 +98,34 @@ class RamlObjectTypesTest {
.writeTo(this)
},
)


val typeSpec2 = findType("io.test.Test2", types)

assertEquals(
"""
package io.test
import kotlin.Any
import kotlin.String
import kotlin.collections.Map
public interface Test2 {
public val optionalObject: Map<String, Any>?
public val nillableObject: Map<String, Any>?
public val optionalHierarchy: Parent?
public val nillableHierarchy: Parent?
}
""".trimIndent(),
buildString {
FileSpec.get("io.test", typeSpec2)
.writeTo(this)
},
)
}

@Test
Expand All @@ -106,7 +135,8 @@ class RamlObjectTypesTest {

val typeRegistry = KotlinTypeRegistry("io.test", null, GenerationMode.Server, setOf(ImplementModel))

val typeSpec = findType("io.test.Test", generateTypes(testUri, typeRegistry))
val types = generateTypes(testUri, typeRegistry)
val typeSpec = findType("io.test.Test", types)

assertEquals(
"""
Expand Down Expand Up @@ -155,6 +185,70 @@ class RamlObjectTypesTest {
.writeTo(this)
},
)

val typeSpec2 = findType("io.test.Test2", types)

assertEquals(
"""
package io.test
import kotlin.Any
import kotlin.Boolean
import kotlin.Int
import kotlin.String
import kotlin.collections.Map
public class Test2(
public val optionalObject: Map<String, Any>? = null,
public val nillableObject: Map<String, Any>?,
public val optionalHierarchy: Parent? = null,
public val nillableHierarchy: Parent?,
) {
public fun copy(
optionalObject: Map<String, Any>? = null,
nillableObject: Map<String, Any>? = null,
optionalHierarchy: Parent? = null,
nillableHierarchy: Parent? = null,
): Test2 = Test2(optionalObject ?: this.optionalObject, nillableObject ?: this.nillableObject,
optionalHierarchy ?: this.optionalHierarchy, nillableHierarchy ?: this.nillableHierarchy)
override fun hashCode(): Int {
var result = 1
result = 31 * result + (optionalObject?.hashCode() ?: 0)
result = 31 * result + (nillableObject?.hashCode() ?: 0)
result = 31 * result + (optionalHierarchy?.hashCode() ?: 0)
result = 31 * result + (nillableHierarchy?.hashCode() ?: 0)
return result
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Test2
if (optionalObject != other.optionalObject) return false
if (nillableObject != other.nillableObject) return false
if (optionalHierarchy != other.optionalHierarchy) return false
if (nillableHierarchy != other.nillableHierarchy) return false
return true
}
override fun toString(): String = ""${'"'}
|Test2(optionalObject='${"$"}optionalObject',
| nillableObject='${"$"}nillableObject',
| optionalHierarchy='${"$"}optionalHierarchy',
| nillableHierarchy='${"$"}nillableHierarchy')
""${'"'}.trimMargin()
}
""".trimIndent(),
buildString {
FileSpec.get("io.test", typeSpec2)
.writeTo(this)
},
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,42 +180,71 @@ class RamlObjectTypesTest {
public var optionalObject: [String : Any]?
public var nillableObject: [String : Any]?
public var optionalHierarchy: Parent?
public var nillableHierarchy: Parent?
public var debugDescription: String {
return DescriptionBuilder(Test2.self)
.add(optionalObject, named: "optionalObject")
.add(nillableObject, named: "nillableObject")
.add(optionalHierarchy, named: "optionalHierarchy")
.add(nillableHierarchy, named: "nillableHierarchy")
.build()
}
public init(optionalObject: [String : Any]? = nil, nillableObject: [String : Any]?) {
public init(
optionalObject: [String : Any]? = nil,
nillableObject: [String : Any]?,
optionalHierarchy: Parent? = nil,
nillableHierarchy: Parent?
) {
self.optionalObject = optionalObject
self.nillableObject = nillableObject
self.optionalHierarchy = optionalHierarchy
self.nillableHierarchy = nillableHierarchy
}
public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.optionalObject = try container.decodeIfPresent([String : AnyValue].self, forKey: .optionalObject)?.mapValues { ${'$'}0.unwrapped }
self.nillableObject = try container.decodeIfPresent([String : AnyValue].self, forKey: .nillableObject)?.mapValues { ${'$'}0.unwrapped }
self.optionalHierarchy = try container.decodeIfPresent(Parent.AnyRef.self, forKey: .optionalHierarchy)?.value
self.nillableHierarchy = try container.decodeIfPresent(Parent.AnyRef.self, forKey: .nillableHierarchy)?.value
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(self.optionalObject?.mapValues { try AnyValue.wrapped(${'$'}0) }, forKey: .optionalObject)
try container.encodeIfPresent(self.nillableObject?.mapValues { try AnyValue.wrapped(${'$'}0) }, forKey: .nillableObject)
try container.encodeIfPresent(self.optionalHierarchy, forKey: .optionalHierarchy)
try container.encodeIfPresent(self.nillableHierarchy, forKey: .nillableHierarchy)
}
public func withOptionalObject(optionalObject: [String : Any]?) -> Test2 {
return Test2(optionalObject: optionalObject, nillableObject: nillableObject)
return Test2(optionalObject: optionalObject, nillableObject: nillableObject,
optionalHierarchy: optionalHierarchy, nillableHierarchy: nillableHierarchy)
}
public func withNillableObject(nillableObject: [String : Any]?) -> Test2 {
return Test2(optionalObject: optionalObject, nillableObject: nillableObject)
return Test2(optionalObject: optionalObject, nillableObject: nillableObject,
optionalHierarchy: optionalHierarchy, nillableHierarchy: nillableHierarchy)
}
public func withOptionalHierarchy(optionalHierarchy: Parent?) -> Test2 {
return Test2(optionalObject: optionalObject, nillableObject: nillableObject,
optionalHierarchy: optionalHierarchy, nillableHierarchy: nillableHierarchy)
}
public func withNillableHierarchy(nillableHierarchy: Parent?) -> Test2 {
return Test2(optionalObject: optionalObject, nillableObject: nillableObject,
optionalHierarchy: optionalHierarchy, nillableHierarchy: nillableHierarchy)
}
fileprivate enum CodingKeys : String, CodingKey {
case optionalObject = "optionalObject"
case nillableObject = "nillableObject"
case optionalHierarchy = "optionalHierarchy"
case nillableHierarchy = "nillableHierarchy"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ class RamlObjectTypesTest {

val typeRegistry = TypeScriptTypeRegistry(setOf())

val typeModSpec = findTypeMod("Test@!test", generateTypes(testUri, typeRegistry, compiler))
val types = generateTypes(testUri, typeRegistry, compiler)
val typeModSpec = findTypeMod("Test@!test", types)

assertEquals(
"""
Expand Down Expand Up @@ -131,6 +132,59 @@ class RamlObjectTypesTest {
.writeTo(this)
},
)

val typeModSpec2 = findTypeMod("Test2@!test2", types)

assertEquals(
"""
import {Parent} from './parent';
export interface Test2Spec {
optionalObject?: Record<string, unknown>;
nillableObject: Record<string, unknown> | null;
optionalHierarchy?: Parent;
nillableHierarchy: Parent | null;
}
export class Test2 implements Test2Spec {
optionalObject: Record<string, unknown> | undefined;
nillableObject: Record<string, unknown> | null;
optionalHierarchy: Parent | undefined;
nillableHierarchy: Parent | null;
constructor(init: Test2Spec) {
this.optionalObject = init.optionalObject;
this.nillableObject = init.nillableObject;
this.optionalHierarchy = init.optionalHierarchy;
this.nillableHierarchy = init.nillableHierarchy;
}
copy(changes: Partial<Test2Spec>): Test2 {
return new Test2(Object.assign({}, this, changes));
}
toString(): string {
return `Test2(optionalObject='${"$"}{this.optionalObject}', nillableObject='${"$"}{this.nillableObject}', optionalHierarchy='${"$"}{this.optionalHierarchy}', nillableHierarchy='${"$"}{this.nillableHierarchy}')`;
}
}
""".trimIndent(),
buildString {
FileSpec.get(typeModSpec2)
.writeTo(this)
},
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@

package io.outfoxx.sunday.generator.typescript.tools

import io.outfoxx.sunday.generator.utils.ShellProcess
import java.nio.file.Path

class LocalTypeScriptCompiler(private val command: String, workDir: Path) : TypeScriptCompiler(workDir) {

val env = ShellProcess.loadExtraEnvironment()

init {

val buildPkg =
ProcessBuilder()
.directory(workDir.toFile())
.command(command, "ci")
.apply {
environment().putAll(env)
}
.redirectErrorStream(true)
.start()

Expand All @@ -42,6 +48,9 @@ class LocalTypeScriptCompiler(private val command: String, workDir: Path) : Type
ProcessBuilder()
.directory(workDir.toFile())
.command(command, "run", "build")
.apply {
environment().putAll(env)
}
.redirectErrorStream(true)
.start()

Expand Down
Loading

0 comments on commit e6a46d8

Please sign in to comment.