Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for hierarchies in Kotlin, Swift & Typescript #117

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading