11import { ObjectSerializer as InternalSerializer , V1ObjectMeta } from './gen/models/ObjectSerializer.js' ;
22
3+ type KubernetesObjectHeader = {
4+ apiVersion : string ;
5+ kind : string ;
6+ } ;
7+
8+ const isKubernetesObject = ( data : unknown ) : data is KubernetesObjectHeader =>
9+ ! ! data && typeof data === 'object' && 'apiVersion' in data && 'kind' in data ;
10+
311type AttributeType = {
412 name : string ;
513 baseName : string ;
@@ -38,30 +46,38 @@ class KubernetesObject {
3846 format : '' ,
3947 } ,
4048 ] ;
41- }
42-
43- const isKubernetesObject = ( data : unknown ) : boolean =>
44- ! ! data && typeof data === 'object' && 'apiVersion' in data && 'kind' in data ;
4549
46- /**
47- * Wraps the ObjectSerializer to support custom resources and generic Kubernetes objects.
48- */
49- export class ObjectSerializer extends InternalSerializer {
50- public static serialize ( data : any , type : string , format : string = '' ) : any {
51- const obj = InternalSerializer . serialize ( data , type , format ) ;
52- if ( obj !== data ) {
53- return obj ;
50+ public serialize ( ) : any {
51+ const instance : Record < string , any > = { } ;
52+ for ( const attributeType of KubernetesObject . attributeTypeMap ) {
53+ const value = this [ attributeType . baseName ] ;
54+ if ( value !== undefined ) {
55+ instance [ attributeType . name ] = InternalSerializer . serialize (
56+ this [ attributeType . baseName ] ,
57+ attributeType . type ,
58+ attributeType . format ,
59+ ) ;
60+ }
61+ }
62+ // add all unknown properties as is.
63+ for ( const [ key , value ] of Object . entries ( this ) ) {
64+ if ( KubernetesObject . attributeTypeMap . find ( ( t ) => t . name === key ) ) {
65+ continue ;
66+ }
67+ instance [ key ] = value ;
5468 }
69+ return instance ;
70+ }
5571
72+ public static fromUnknown ( data : unknown ) : KubernetesObject {
5673 if ( ! isKubernetesObject ( data ) ) {
57- return obj ;
74+ throw new Error ( `Unable to deseriliaze non-Kubernetes object ${ data } .` ) ;
5875 }
59-
60- const instance : Record < string , any > = { } ;
76+ const instance = new KubernetesObject ( ) ;
6177 for ( const attributeType of KubernetesObject . attributeTypeMap ) {
6278 const value = data [ attributeType . baseName ] ;
6379 if ( value !== undefined ) {
64- instance [ attributeType . name ] = InternalSerializer . serialize (
80+ instance [ attributeType . name ] = InternalSerializer . deserialize (
6581 data [ attributeType . baseName ] ,
6682 attributeType . type ,
6783 attributeType . format ,
@@ -77,23 +93,114 @@ export class ObjectSerializer extends InternalSerializer {
7793 }
7894 return instance ;
7995 }
96+ }
8097
81- public static deserialize ( data : any , type : string , format : string = '' ) : any {
82- const obj = InternalSerializer . deserialize ( data , type , format ) ;
98+ export interface Serializer {
99+ serialize ( data : any , type : string , format ?: string ) : any ;
100+ deserialize ( data : any , type : string , format ?) : any ;
101+ }
102+
103+ export type GroupVersionKind = {
104+ group : string ;
105+ version : string ;
106+ kind : string ;
107+ } ;
108+
109+ type ModelRegistry = {
110+ [ gv : string ] : {
111+ [ kind : string ] : Serializer ;
112+ } ;
113+ } ;
114+
115+ const gvString = ( { group, version } : GroupVersionKind ) : string => [ group , version ] . join ( '/' ) ;
116+
117+ const gvkFromObject = ( obj : KubernetesObjectHeader ) : GroupVersionKind => {
118+ const [ g , v ] = obj . apiVersion . split ( '/' ) ;
119+ return {
120+ kind : obj . kind ,
121+ group : v ? g : '' ,
122+ version : v ? v : g ,
123+ } ;
124+ } ;
125+
126+ /**
127+ * Default serializer that uses the KubernetesObject to serialize and deserialize
128+ * any object using only the minimum required attributes.
129+ */
130+ export const defaultSerializer : Serializer = {
131+ serialize : ( data : any , type : string , format ?: string ) : any => {
132+ if ( data instanceof KubernetesObject ) {
133+ return data . serialize ( ) ;
134+ }
135+ return KubernetesObject . fromUnknown ( data ) . serialize ( ) ;
136+ } ,
137+ deserialize : ( data : any , type : string , format ?) : any => {
138+ return KubernetesObject . fromUnknown ( data ) ;
139+ } ,
140+ } ;
141+
142+ /**
143+ * Wraps the ObjectSerializer to support custom resources and generic Kubernetes objects.
144+ *
145+ * CustomResources that are unknown to the ObjectSerializer can be registered
146+ * by using ObjectSerializer.registerModel().
147+ */
148+ export class ObjectSerializer extends InternalSerializer {
149+ private static modelRegistry : ModelRegistry = { } ;
150+
151+ /**
152+ * Adds a dedicated seriliazer for a Kubernetes resource.
153+ * Every resource is uniquly identified using its group, version and kind.
154+ * @param gvk
155+ * @param serializer
156+ */
157+ public static registerModel ( gvk : GroupVersionKind , serializer : Serializer ) {
158+ const gv = gvString ( gvk ) ;
159+ const kinds = ( this . modelRegistry [ gv ] ??= { } ) ;
160+ if ( kinds [ gvk . kind ] ) {
161+ throw new Error ( `Kind ${ gvk . kind } of ${ gv } is already defined` ) ;
162+ }
163+ kinds [ gvk . kind ] = serializer ;
164+ }
165+
166+ /**
167+ * Removes all registered models from the registry.
168+ */
169+ public static clearModelRegistry ( ) : void {
170+ this . modelRegistry = { } ;
171+ }
172+
173+ private static getSerializerForObject ( obj : unknown ) : undefined | Serializer {
174+ if ( ! isKubernetesObject ( obj ) ) {
175+ return undefined ;
176+ }
177+ const gvk = gvkFromObject ( obj ) ;
178+ return ObjectSerializer . modelRegistry [ gvString ( gvk ) ] ?. [ gvk . kind ] ;
179+ }
180+
181+ public static serialize ( data : any , type : string , format : string = '' ) : any {
182+ const serializer = ObjectSerializer . getSerializerForObject ( data ) ;
183+ if ( serializer ) {
184+ return serializer . serialize ( data , type , format ) ;
185+ }
186+ if ( data instanceof KubernetesObject ) {
187+ return data . serialize ( ) ;
188+ }
189+
190+ const obj = InternalSerializer . serialize ( data , type , format ) ;
83191 if ( obj !== data ) {
84- // the serializer knows the type and already deserialized it.
85192 return obj ;
86193 }
87194
88195 if ( ! isKubernetesObject ( data ) ) {
89196 return obj ;
90197 }
91198
92- const instance = new KubernetesObject ( ) ;
199+ const instance : Record < string , any > = { } ;
93200 for ( const attributeType of KubernetesObject . attributeTypeMap ) {
94201 const value = data [ attributeType . baseName ] ;
95202 if ( value !== undefined ) {
96- instance [ attributeType . name ] = InternalSerializer . deserialize (
203+ instance [ attributeType . name ] = InternalSerializer . serialize (
97204 data [ attributeType . baseName ] ,
98205 attributeType . type ,
99206 attributeType . format ,
@@ -109,4 +216,22 @@ export class ObjectSerializer extends InternalSerializer {
109216 }
110217 return instance ;
111218 }
219+
220+ public static deserialize ( data : any , type : string , format : string = '' ) : any {
221+ const serializer = ObjectSerializer . getSerializerForObject ( data ) ;
222+ if ( serializer ) {
223+ return serializer . deserialize ( data , type , format ) ;
224+ }
225+ const obj = InternalSerializer . deserialize ( data , type , format ) ;
226+ if ( obj !== data ) {
227+ // the serializer knows the type and already deserialized it.
228+ return obj ;
229+ }
230+
231+ if ( ! isKubernetesObject ( data ) ) {
232+ return obj ;
233+ }
234+
235+ return KubernetesObject . fromUnknown ( data ) ;
236+ }
112237}
0 commit comments