Skip to content

Commit

Permalink
[org.json_schema.contrib] Handle if name conflicts with built-in type
Browse files Browse the repository at this point in the history
For example, handles if a class name would otherwise be generated as `Mapping`.
This instead turns it into `Mapping1`.
  • Loading branch information
bioball committed Feb 27, 2025
1 parent e08bb69 commit c4a51bb
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/org.json_schema.contrib/PklProject
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ dependencies {
}

package {
version = "1.1.2"
version = "1.1.3"
}
29 changes: 27 additions & 2 deletions packages/org.json_schema.contrib/internal/ModuleGenerator.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -206,20 +206,45 @@ function isClassLike(schema: JsonSchema.Schema): Boolean =
// Edge case: if `$ref` exists, any other property should be ignored.
schema.$ref == null && schema.properties != null

// only need to include stdlib names that would be used by the code generator
const local builtInNames = Set(
"Mapping",
"Listing",
"Dynamic",
"String",
"Boolean",
"Int",
"Int16",
"Int32",
"UInt",
"UInt8",
"UInt16",
"UInt32",
"Float",
"Null",
"Number",
"Deprecated"
)

local function normalizeTypeName(name: String) =
let (capitalized = utils.pascalCase(name))
if (builtInNames.contains(capitalized)) "\(capitalized)1"
else capitalized

/// Determine the name of a type.
///
/// Try to use the parent property's name as part of the class name in case of conflict.
/// If already at the root, add a number at the end.
local function determineTypeName(path: List<String>, candidateName: String, existingTypeNames: Set<Type>, index: Int): Type =
let (candidateType = new Type { name = utils.pascalCase(candidateName); moduleName = module.moduleName })
let (candidateType = new Type { name = normalizeTypeName(candidateName); moduleName = module.moduleName })
if (existingTypeNames.contains(candidateType))
if (path.isEmpty)
determineTypeName(path, candidateName + index.toString(), existingTypeNames, index + 1)
else
let (newPath = dropLast(path))
determineTypeName(
newPath,
getCandidateName(newPath) + utils.pascalCase(candidateName),
getCandidateName(newPath) + normalizeTypeName(candidateName),
existingTypeNames,
index
)
Expand Down
63 changes: 63 additions & 0 deletions packages/org.json_schema.contrib/tests/ModuleGenerator.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,67 @@ examples {
local schema = Parser.parse(read("fixtures/test_conflicts.json")) as JsonSchema
new ModuleGenerator { rootSchema = schema; moduleName = "com.Example" }.moduleNode.render("")
}
["name conflicts with built-in class name"] {
local schema: JsonSchema = new {
type = "object"
additionalProperties = false
properties {
["int"] {
type = "object"
properties {
["res1"] {
type = "string"
}
}
additionalProperties = false
}
["boolean"] {
type = "object"
properties {
["res2"] {
type = "string"
}
}
additionalProperties = false
}
["mapping"] {
type = "object"
properties {
["res3"] {
type = "string"
}
}
additionalProperties = false
}
["listing"] {
type = "object"
properties {
["res4"] {
type = "string"
}
}
additionalProperties = false
}
["dynamic"] {
type = "object"
properties {
["res5"] {
type = "string"
}
}
additionalProperties = false
}
["null"] {
type = "object"
properties {
["res6"] {
type = "string"
}
}
additionalProperties = false
}
}
}
new ModuleGenerator { rootSchema = schema; moduleName = "com.Example" }.moduleNode.output.text
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,49 @@ examples {
nestedListItemField: String?
}

"""
}
["name conflicts with built-in class name"] {
"""
/// This module was generated from JSON Schema from <>.
module com.Example

int: Int1?

boolean: Boolean1?

mapping: Mapping1?

listing: Listing1?

dynamic: Dynamic1?

`null`: Null1?

class Int1 {
res1: String?
}

class Boolean1 {
res2: String?
}

class Mapping1 {
res3: String?
}

class Listing1 {
res4: String?
}

class Dynamic1 {
res5: String?
}

class Null1 {
res6: String?
}

"""
}
}

0 comments on commit c4a51bb

Please sign in to comment.