1
1
//===----------------------------------------------------------------------===//
2
- // Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
2
+ // Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3
3
//
4
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
5
// you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import "pkl:reflect"
22
22
import "@jsonschema.contrib/internal/Type.pkl"
23
23
import "@jsonschema.contrib/internal/TypesGenerator.pkl"
24
24
import "@jsonschema.contrib/internal/utils.pkl"
25
+ import "@jsonschema.contrib/internal/singularize.pkl"
25
26
import "@jsonschema/JsonSchema.pkl"
26
27
import "@jsonschema/Parser.pkl"
27
28
import "@k8s/apiextensions-apiserver/pkg/apis/apiextensions/v1/CustomResourceDefinition.pkl"
@@ -54,7 +55,7 @@ local schema: CustomResourceDefinition.CustomResourceValidation|BetaCRD.CustomRe
54
55
(if (crd is BetaCRD) version.schema ?? crd.spec.validation else version.schema)!!
55
56
56
57
/// The Schema
57
- rootSchema : JsonSchema((s) -> validCRDSchema(s )) = Parser.parse(new JsonRenderer {}.renderDocument(schema.openAPIV3Schema)) as JsonSchema
58
+ rootSchema : JsonSchema(validCRDSchema(this ) ) = Parser.parse(new JsonRenderer {}.renderDocument(schema.openAPIV3Schema)) as JsonSchema
58
59
59
60
local ignoreProperties = Set("apiVersion" , "kind" , "metadata" )
60
61
local filteredRootSchema = (rootSchema) {
@@ -280,31 +281,59 @@ function isClassLike(schema: JsonSchema.Schema): Boolean =
280
281
///
281
282
/// Try to use the parent property's name as part of the class name in case of conflict.
282
283
/// If already at the root, add a number at the end.
283
- local function determineTypeName (path : List<String> , candidateName : String , existingTypeNames : Set<Type> , index : Int ): Type =
284
- if (existingTypeNames.contains(utils.pascalCase(candidateName)))
285
- if (path.isEmpty)
286
- determineTypeName(path, candidateName + index.toString(), existingTypeNames, index + 1 )
284
+ local function determineTypeName (
285
+ path : List<String> ,
286
+ candidateName : String ,
287
+ existingTypeNames : Set<Type> ,
288
+ index : Int
289
+ ): Type =
290
+ let (candidate = utils.pascalCase(candidateName))
291
+ if (existingTypeNames.findOrNull((it) -> it.name == candidate) != null )
292
+ if (path.isEmpty)
293
+ determineTypeName(
294
+ path,
295
+ candidateName + index.toString(),
296
+ existingTypeNames,
297
+ index + 1
298
+ )
299
+ else
300
+ let (newPath = dropLast(path))
301
+ determineTypeName(
302
+ newPath,
303
+ getCandidateName(newPath) + candidate,
304
+ existingTypeNames,
305
+ index
306
+ )
287
307
else
288
- determineTypeName(
289
- path.dropLast(1 ),
290
- utils.pascalCase(path.last.capitalize()) + utils.pascalCase(candidateName),
291
- existingTypeNames,
292
- index
293
- )
308
+ new { name = candidate; moduleName = module .moduleName }
309
+
310
+ // noinspection TypeMismatch
311
+ local function getCandidateName (path : List<String> ) =
312
+ if (path.isEmpty)
313
+ "Item"
314
+ else if (path.last == "[]" )
315
+ path.dropLast(1 ).lastOrNull?.ifNonNull((it) -> utils.pascalCase(singularize.singularize(it))) ?? "Item"
316
+ else
317
+ utils.pascalCase(path.last)
318
+
319
+ local function dropLast (path : List<String> ) =
320
+ if (path.last == "[]" )
321
+ path.dropLast(2 )
294
322
else
295
- new { name = utils.pascalCase(candidateName); moduleName = module .moduleName }
323
+ path.dropLast( 1 )
296
324
297
325
/// The schemas that should be rendered as classes.
298
326
///
299
327
/// Classes get rendered for any subschema that has [JsonSchema.properties] defined, and does not show up in converters
300
328
local classSchemas : Type .TypeNames =
301
329
utils._findMatchingSubSchemas(filteredRootSchema, List(), (elem) -> elem != filteredRootSchema && isClassLike(elem))
302
- .filter((path, _) -> ! pathPrefixes(path).any((prefix) -> converters.containsKey(prefix))) // path or prefix are not explicitly in converters
330
+ // path or prefix are not explicitly in converters
331
+ .filter((path, _) -> ! pathPrefixes(path).any((prefix) -> converters.containsKey(prefix)))
303
332
.entries
304
333
.fold(Map(), (accumulator : Type .TypeNames, pair) ->
305
334
let (path = pair.first)
306
335
let (schema = pair.second)
307
- let (typeName = determineTypeName(path, path.lastOrNull?.capitalize() ?? "Item" , accumulator.values.toSet(), 0 ))
336
+ let (typeName = determineTypeName(path, getCandidateName(path) , accumulator.values.toSet(), 0 ))
308
337
accumulator.put(schema, typeName)
309
338
)
310
339
0 commit comments