Skip to content
Closed
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build/
.gradle/
.kotlin/
.idea/
.planning/
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
package com.avsystem.justworks.core.gen

import com.avsystem.justworks.core.model.PropertyModel
import com.avsystem.justworks.core.model.SchemaModel
import com.avsystem.justworks.core.model.TypeRef

/**
* Key for structural equality of inline schemas.
* Two inline schemas are considered equal if they have the same properties
* (name, type, required status) regardless of property order.
*/
data class InlineSchemaKey(val properties: Set<PropertyKey>) {
data class InlineSchemaKey(val properties: List<PropertyKey>, val requiredProperties: Set<String>,) {
data class PropertyKey(
val name: String,
val type: TypeRef,
val required: Boolean,
)

companion object {
fun from(properties: List<PropertyModel>, required: Set<String>) = InlineSchemaKey(
properties = properties.map { PropertyKey(it.name, it.type, it.name in required) }.toSet(),
)
/**
* Creates an InlineSchemaKey from properties and required set.
* Properties are sorted by name for deterministic equality.
*/
fun from(properties: List<PropertyModel>, required: Set<String>): InlineSchemaKey {
val propKeys = properties
.map { PropertyKey(it.name, it.type, it.name in required) }
.sortedBy { it.name } // Deterministic ordering
return InlineSchemaKey(properties = propKeys, requiredProperties = required)
}
}
}

Expand All @@ -27,24 +35,48 @@ data class InlineSchemaKey(val properties: Set<PropertyKey>) {
* Ensures that structurally identical inline schemas generate only one class,
* and handles name collisions with component schemas.
*/
class InlineSchemaDeduplicator(private val componentSchemaNames: Set<String>) {
class InlineSchemaDeduplicator {
// Maps structural key to the first generated name for that structure
private val namesByKey = mutableMapOf<InlineSchemaKey, String>()

// Names of all component schemas (from components/schemas in OpenAPI spec)
private val componentSchemaNames = mutableSetOf<String>()

/**
* Registers component schema names to detect collisions.
*/
fun registerComponentSchemas(schemas: List<SchemaModel>) {
componentSchemaNames.addAll(schemas.map { it.name })
}

/**
* Gets or generates a name for an inline schema.
* If a structurally identical schema was already seen, returns its name (deduplication).
* If the context name collides with a component schema or another inline schema,
* appends "Inline" suffix.
*
* @param properties The properties of the inline schema
* @param requiredProps The set of required property names
* @param contextName The base name derived from context (e.g., "PostPetRequest")
* @return The final name to use for this inline schema
*/
fun getOrGenerateName(
properties: List<PropertyModel>,
requiredProps: Set<String>,
contextName: String,
): String = namesByKey.getOrPut(InlineSchemaKey.from(properties, requiredProps)) {
val inlineName = contextName.toInlinedName()
val candidates = sequence {
yield(inlineName)
yield("${inlineName}Inline")
generateSequence(2) { it + 1 }.forEach {
yield("${inlineName}${it}Inline")
}
): String {
val key = InlineSchemaKey.from(properties, requiredProps)

// Check if we've already generated a name for this structure
namesByKey[key]?.let { return it }

// Generate new name, handling collisions
var finalName = contextName
if (finalName in componentSchemaNames || finalName in namesByKey.values) {
finalName = "${contextName}Inline"
}

val existingNames = (componentSchemaNames + namesByKey.values).toSet()
candidates.first { it !in existingNames }
namesByKey[key] = finalName
return finalName
}
}
Loading