@@ -29,6 +29,7 @@ public static class Crds
29
29
private const string Int64 = "int64" ;
30
30
private const string Float = "float" ;
31
31
private const string Double = "double" ;
32
+ private const string Decimal = "decimal" ;
32
33
private const string DateTime = "date-time" ;
33
34
34
35
private static readonly string [ ] IgnoredToplevelProperties = { "metadata" , "apiversion" , "kind" } ;
@@ -77,8 +78,8 @@ public static V1CustomResourceDefinition Transpile(this MetadataLoadContext cont
77
78
Description =
78
79
type . GetCustomAttributeData < DescriptionAttribute > ( ) ? . GetCustomAttributeCtorArg < string > ( context , 0 ) ,
79
80
Properties = type . GetProperties ( )
80
- . Where ( p => ! IgnoredToplevelProperties . Contains ( p . Name . ToLowerInvariant ( ) ) )
81
- . Where ( p => p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
81
+ . Where ( p => ! IgnoredToplevelProperties . Contains ( p . Name . ToLowerInvariant ( ) )
82
+ && p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
82
83
. Select ( p => ( Name : p . GetPropertyName ( context ) , Schema : context . Map ( p ) ) )
83
84
. ToDictionary ( t => t . Name , t => t . Schema ) ,
84
85
} ) ;
@@ -105,9 +106,9 @@ public static IEnumerable<V1CustomResourceDefinition> Transpile(
105
106
IEnumerable < Type > types )
106
107
=> types
107
108
. Select ( context . GetContextType )
108
- . Where ( type => type . Assembly != context . GetContextType < KubernetesEntityAttribute > ( ) . Assembly )
109
- . Where ( type => type . GetCustomAttributesData < KubernetesEntityAttribute > ( ) . Any ( ) )
110
- . Where ( type => ! type . GetCustomAttributesData < IgnoreAttribute > ( ) . Any ( ) )
109
+ . Where ( type => type . Assembly != context . GetContextType < KubernetesEntityAttribute > ( ) . Assembly
110
+ && type . GetCustomAttributesData < KubernetesEntityAttribute > ( ) . Any ( )
111
+ && ! type . GetCustomAttributesData < IgnoreAttribute > ( ) . Any ( ) )
111
112
. Select ( type => ( Props : context . Transpile ( type ) ,
112
113
IsStorage : type . GetCustomAttributesData < StorageVersionAttribute > ( ) . Any ( ) ) )
113
114
. GroupBy ( grp => grp . Props . Metadata . Name )
@@ -278,199 +279,165 @@ private static V1JSONSchemaProps Map(this MetadataLoadContext context, PropertyI
278
279
279
280
private static V1JSONSchemaProps Map ( this MetadataLoadContext context , Type type )
280
281
{
281
- if ( type == context . GetContextType < V1ObjectMeta > ( ) )
282
+ if ( type . FullName == "System.String" )
282
283
{
283
- return new V1JSONSchemaProps { Type = Object } ;
284
+ return new V1JSONSchemaProps { Type = String , Nullable = false } ;
284
285
}
285
286
286
- if ( type . IsArray && type . GetElementType ( ) != null )
287
+ if ( type . Name == typeof ( Nullable < > ) . Name && type . GenericTypeArguments . Length == 1 )
287
288
{
288
- var items = context . Map ( type . GetElementType ( ) ! ) ;
289
- items . Nullable = type . GetElementType ( ) ! . IsNullable ( ) ;
290
- return new V1JSONSchemaProps { Type = Array , Items = items } ;
289
+ var props = context . Map ( type . GenericTypeArguments [ 0 ] ) ;
290
+ props . Nullable = true ;
291
+ return props ;
291
292
}
292
293
293
- if ( ! IsSimpleType ( type )
294
- && type . IsGenericType
295
- && type . GetGenericTypeDefinition ( ) == context . GetContextType ( typeof ( IDictionary < , > ) )
296
- && type . GenericTypeArguments . Contains ( context . GetContextType ( typeof ( ResourceQuantity ) ) ) )
297
- {
298
- return new V1JSONSchemaProps { Type = Object , XKubernetesPreserveUnknownFields = true } ;
299
- }
300
-
301
- if ( ! IsSimpleType ( type ) &&
302
- type . IsGenericType &&
303
- type . GetGenericTypeDefinition ( ) == context . GetContextType ( typeof ( IEnumerable < > ) ) &&
304
- type . GenericTypeArguments . Length == 1 &&
305
- type . GenericTypeArguments . Single ( ) . IsGenericType &&
306
- type . GenericTypeArguments . Single ( ) . GetGenericTypeDefinition ( ) ==
307
- context . GetContextType ( typeof ( KeyValuePair < , > ) ) )
308
- {
309
- var props = context . Map ( type . GenericTypeArguments . Single ( ) . GenericTypeArguments [ 1 ] ) ;
310
- props . Nullable = type . GenericTypeArguments . Single ( ) . GenericTypeArguments [ 1 ] . IsNullable ( ) ;
311
- return new V1JSONSchemaProps { Type = Object , AdditionalProperties = props , } ;
312
- }
313
-
314
- if ( ! IsSimpleType ( type )
315
- && type . IsGenericType
316
- && type . GetGenericTypeDefinition ( ) == context . GetContextType ( typeof ( IDictionary < , > ) ) )
317
- {
318
- var props = context . Map ( type . GenericTypeArguments [ 1 ] ) ;
319
- props . Nullable = type . GenericTypeArguments [ 1 ] . IsNullable ( ) ;
320
- return new V1JSONSchemaProps { Type = Object , AdditionalProperties = props , } ;
321
- }
294
+ var interfaces = type . IsInterface
295
+ ? type . GetInterfaces ( ) . Append ( type )
296
+ : type . GetInterfaces ( ) ;
322
297
323
- if ( ! IsSimpleType ( type ) &&
324
- ( context . GetContextType < IDictionary > ( ) . IsAssignableFrom ( type ) ||
325
- ( type . IsGenericType &&
326
- type . GetGenericArguments ( ) . FirstOrDefault ( ) ? . IsGenericType == true &&
327
- type . GetGenericArguments ( ) . FirstOrDefault ( ) ? . GetGenericTypeDefinition ( ) ==
328
- context . GetContextType ( typeof ( KeyValuePair < , > ) ) ) ) )
329
- {
330
- return new V1JSONSchemaProps { Type = Object , XKubernetesPreserveUnknownFields = true } ;
331
- }
298
+ var interfaceNames = interfaces . Select ( i =>
299
+ i . IsGenericType
300
+ ? i . GetGenericTypeDefinition ( ) . FullName
301
+ : i . FullName ) ;
332
302
333
- if ( ! IsSimpleType ( type ) && IsGenericEnumerableType ( type , out Type ? closingType ) )
303
+ if ( interfaceNames . Contains ( typeof ( IDictionary < , > ) . FullName ) )
334
304
{
335
- var items = context . Map ( closingType ) ;
336
- items . Nullable = closingType . IsNullable ( ) ;
337
- return new V1JSONSchemaProps { Type = Array , Items = items } ;
338
- }
305
+ var dictionaryImpl = interfaces
306
+ . First ( i => i . IsGenericType
307
+ && i . GetGenericTypeDefinition ( ) . FullName == typeof ( IDictionary < , > ) . FullName ) ;
339
308
340
- if ( type == context . GetContextType < IntstrIntOrString > ( ) )
341
- {
342
- return new V1JSONSchemaProps { XKubernetesIntOrString = true } ;
309
+ var addlProps = context . Map ( dictionaryImpl . GenericTypeArguments [ 1 ] ) ;
310
+ return new V1JSONSchemaProps
311
+ {
312
+ Type = Object ,
313
+ AdditionalProperties = addlProps ,
314
+ Nullable = false ,
315
+ } ;
343
316
}
344
317
345
- if ( context . GetContextType < IKubernetesObject > ( ) . IsAssignableFrom ( type ) &&
346
- type is { IsAbstract : false , IsInterface : false } &&
347
- type . Assembly == context . GetContextType < IKubernetesObject > ( ) . Assembly )
318
+ if ( interfaceNames . Contains ( typeof ( IDictionary ) . FullName ) )
348
319
{
349
320
return new V1JSONSchemaProps
350
321
{
351
322
Type = Object ,
352
- Properties = null ,
353
323
XKubernetesPreserveUnknownFields = true ,
354
- XKubernetesEmbeddedResource = true ,
324
+ Nullable = false ,
355
325
} ;
356
326
}
357
327
358
- if ( type == context . GetContextType < int > ( ) ||
359
- type == context . GetContextType < int ? > ( ) )
360
- {
361
- return new V1JSONSchemaProps { Type = Integer , Format = Int32 } ;
362
- }
363
-
364
- if ( type == context . GetContextType < long > ( ) ||
365
- type == context . GetContextType < long ? > ( ) )
366
- {
367
- return new V1JSONSchemaProps { Type = Integer , Format = Int64 } ;
368
- }
369
-
370
- if ( type == context . GetContextType < float > ( ) ||
371
- type == context . GetContextType < float ? > ( ) )
328
+ if ( interfaceNames . Contains ( typeof ( IEnumerable < > ) . FullName ) )
372
329
{
373
- return new V1JSONSchemaProps { Type = Number , Format = Float } ;
330
+ return context . MapEnumerationType ( type , interfaces ) ;
374
331
}
375
332
376
- if ( type == context . GetContextType < double > ( ) ||
377
- type == context . GetContextType < double ? > ( ) )
333
+ switch ( type . BaseType ? . FullName )
378
334
{
379
- return new V1JSONSchemaProps { Type = Number , Format = Double } ;
335
+ case "System.Object" :
336
+ return context . MapObjectType ( type ) ;
337
+ case "System.ValueType" :
338
+ return context . MapValueType ( type ) ;
339
+ case "System.Enum" :
340
+ return new V1JSONSchemaProps { Type = String , EnumProperty = Enum . GetNames ( type ) . Cast < object > ( ) . ToList ( ) } ;
341
+ default :
342
+ throw InvalidType ( type ) ;
380
343
}
344
+ }
381
345
382
- if ( type == context . GetContextType < string > ( ) ||
383
- type == context . GetContextType < string ? > ( ) ||
384
- type . FullName == "System.String" )
385
- {
386
- return new V1JSONSchemaProps { Type = String } ;
346
+ private static V1JSONSchemaProps MapObjectType ( this MetadataLoadContext context , Type type )
347
+ {
348
+ switch ( type . FullName )
349
+ {
350
+ case "k8s.Models.V1ObjectMeta" :
351
+ return new V1JSONSchemaProps { Type = Object , Nullable = false } ;
352
+ case "k8s.Models.IntstrIntOrString" :
353
+ return new V1JSONSchemaProps { XKubernetesIntOrString = true , Nullable = false } ;
354
+ default :
355
+ if ( context . GetContextType < IKubernetesObject > ( ) . IsAssignableFrom ( type ) &&
356
+ type is { IsAbstract : false , IsInterface : false } &&
357
+ type . Assembly == context . GetContextType < IKubernetesObject > ( ) . Assembly )
358
+ {
359
+ return new V1JSONSchemaProps
360
+ {
361
+ Type = Object ,
362
+ Properties = null ,
363
+ XKubernetesPreserveUnknownFields = true ,
364
+ XKubernetesEmbeddedResource = true ,
365
+ Nullable = false ,
366
+ } ;
367
+ }
368
+
369
+ return new V1JSONSchemaProps
370
+ {
371
+ Type = Object ,
372
+ Description =
373
+ type . GetCustomAttributeData < DescriptionAttribute > ( ) ? . GetCustomAttributeCtorArg < string > ( context , 0 ) ,
374
+ Properties = type
375
+ . GetProperties ( )
376
+ . Where ( p => p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
377
+ . Select ( p => ( Name : p . GetPropertyName ( context ) , Schema : context . Map ( p ) ) )
378
+ . ToDictionary ( t => t . Name , t => t . Schema ) ,
379
+ Required = type . GetProperties ( )
380
+ . Where ( p => p . GetCustomAttributeData < RequiredAttribute > ( ) != null
381
+ && p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
382
+ . Select ( p => p . GetPropertyName ( context ) )
383
+ . ToList ( ) switch
384
+ {
385
+ { Count : > 0 } p => p ,
386
+ _ => null ,
387
+ } ,
388
+ } ;
387
389
}
390
+ }
388
391
389
- if ( type == context . GetContextType < bool > ( ) ||
390
- type == context . GetContextType < bool ? > ( ) )
391
- {
392
- return new V1JSONSchemaProps { Type = Boolean } ;
393
- }
392
+ private static V1JSONSchemaProps MapEnumerationType ( this MetadataLoadContext context , Type type , IEnumerable < Type > interfaces )
393
+ {
394
+ Type ? enumerableType = interfaces
395
+ . FirstOrDefault ( i => i . IsGenericType
396
+ && i . GetGenericTypeDefinition ( ) . FullName == typeof ( IEnumerable < > ) . FullName
397
+ && i . GenericTypeArguments . Length == 1 ) ;
394
398
395
- if ( type == context . GetContextType < DateTime > ( ) ||
396
- type == context . GetContextType < DateTime ? > ( ) )
399
+ if ( enumerableType == null )
397
400
{
398
- return new V1JSONSchemaProps { Type = String , Format = DateTime } ;
401
+ throw InvalidType ( type ) ;
399
402
}
400
403
401
- if ( type . IsEnum )
404
+ Type listType = enumerableType . GenericTypeArguments [ 0 ] ;
405
+ if ( listType . IsGenericType && listType . GetGenericTypeDefinition ( ) . FullName == typeof ( KeyValuePair < , > ) . FullName )
402
406
{
403
- return new V1JSONSchemaProps { Type = String , EnumProperty = Enum . GetNames ( type ) . Cast < object > ( ) . ToList ( ) } ;
407
+ var addlProps = context . Map ( listType . GenericTypeArguments [ 1 ] ) ;
408
+ return new V1JSONSchemaProps { Type = Object , AdditionalProperties = addlProps , Nullable = false } ;
404
409
}
405
410
406
- if ( type . IsGenericType && type . FullName ? . Contains ( "Nullable" ) == true && type . GetGenericArguments ( ) [ 0 ] . IsEnum )
407
- {
408
- return new V1JSONSchemaProps
409
- {
410
- Type = String ,
411
- EnumProperty = Enum . GetNames ( type . GetGenericArguments ( ) [ 0 ] ) . Cast < object > ( ) . ToList ( ) ,
412
- } ;
413
- }
411
+ var items = context . Map ( listType ) ;
412
+ return new V1JSONSchemaProps { Type = Array , Items = items , Nullable = false } ;
413
+ }
414
414
415
- if ( ! IsSimpleType ( type ) )
416
- {
417
- return new V1JSONSchemaProps
418
- {
419
- Type = Object ,
420
- Description =
421
- type . GetCustomAttributeData < DescriptionAttribute > ( ) ? . GetCustomAttributeCtorArg < string > ( context , 0 ) ,
422
- Properties = type
423
- . GetProperties ( )
424
- . Where ( p => p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
425
- . Select ( p => ( Name : p . GetPropertyName ( context ) , Schema : context . Map ( p ) ) )
426
- . ToDictionary ( t => t . Name , t => t . Schema ) ,
427
- Required = type . GetProperties ( )
428
- . Where ( p => p . GetCustomAttributeData < RequiredAttribute > ( ) != null )
429
- . Where ( p => p . GetCustomAttributeData < IgnoreAttribute > ( ) == null )
430
- . Select ( p => p . GetPropertyName ( context ) )
431
- . ToList ( ) switch
432
- {
433
- { Count : > 0 } p => p ,
434
- _ => null ,
435
- } ,
436
- } ;
415
+ private static V1JSONSchemaProps MapValueType ( this MetadataLoadContext context , Type type )
416
+ {
417
+ switch ( type . FullName )
418
+ {
419
+ case "System.Int32" :
420
+ return new V1JSONSchemaProps { Type = Integer , Format = Int32 , Nullable = false } ;
421
+ case "System.Int64" :
422
+ return new V1JSONSchemaProps { Type = Integer , Format = Int64 , Nullable = false } ;
423
+ case "System.Single" :
424
+ return new V1JSONSchemaProps { Type = Number , Format = Float , Nullable = false } ;
425
+ case "System.Double" :
426
+ return new V1JSONSchemaProps { Type = Number , Format = Double , Nullable = false } ;
427
+ case "System.Decimal" :
428
+ return new V1JSONSchemaProps { Type = Number , Format = Decimal , Nullable = false } ;
429
+ case "System.Boolean" :
430
+ return new V1JSONSchemaProps { Type = Boolean , Nullable = false } ;
431
+ case "System.DateTime" :
432
+ case "System.DateTimeOffset" :
433
+ return new V1JSONSchemaProps { Type = String , Format = DateTime , Nullable = false } ;
434
+ default :
435
+ throw InvalidType ( type ) ;
437
436
}
437
+ }
438
438
439
- throw new ArgumentException ( $ "The given type { type . FullName } is not a valid Kubernetes entity.") ;
440
-
441
- bool IsSimpleType ( Type t ) =>
442
- t . IsPrimitive ||
443
- new [ ]
444
- {
445
- context . GetContextType < string > ( ) , context . GetContextType < decimal > ( ) ,
446
- context . GetContextType < DateTime > ( ) , context . GetContextType < DateTimeOffset > ( ) ,
447
- context . GetContextType < TimeSpan > ( ) , context . GetContextType < Guid > ( ) ,
448
- } . Contains ( t ) ||
449
- t . IsEnum ||
450
- Convert . GetTypeCode ( t ) != TypeCode . Object ||
451
- ( t . IsGenericType &&
452
- t . GetGenericTypeDefinition ( ) == context . GetContextType ( typeof ( Nullable < > ) ) &&
453
- IsSimpleType ( t . GetGenericArguments ( ) [ 0 ] ) ) ;
454
-
455
- bool IsGenericEnumerableType (
456
- Type theType ,
457
- [ NotNullWhen ( true ) ] out Type ? enclosingType )
458
- {
459
- if ( theType . IsGenericType && context . GetContextType ( typeof ( IEnumerable < > ) )
460
- . IsAssignableFrom ( theType . GetGenericTypeDefinition ( ) ) )
461
- {
462
- enclosingType = theType . GetGenericArguments ( ) [ 0 ] ;
463
- return true ;
464
- }
465
-
466
- enclosingType = theType
467
- . GetInterfaces ( )
468
- . Where ( t => t . IsGenericType &&
469
- t . GetGenericTypeDefinition ( ) == context . GetContextType ( typeof ( IEnumerable < > ) ) )
470
- . Select ( t => t . GetGenericArguments ( ) [ 0 ] )
471
- . FirstOrDefault ( ) ;
472
-
473
- return enclosingType != null ;
474
- }
439
+ private static ArgumentException InvalidType ( Type type )
440
+ {
441
+ return new ArgumentException ( $ "The given type { type . FullName } is not a valid Kubernetes entity.") ;
475
442
}
476
443
}
0 commit comments