@@ -44,71 +44,104 @@ export class Reflection extends Schema {
44
44
const rootType = context . schemas . get ( encoder . state . constructor ) ;
45
45
if ( rootType > 0 ) { reflection . rootType = rootType ; }
46
46
47
- const buildType = ( currentType : ReflectionType , metadata : Metadata ) => {
48
- for ( const fieldIndex in metadata ) {
49
- const index = Number ( fieldIndex ) ;
50
- const fieldName = metadata [ index ] . name ;
51
-
52
- // skip fields from parent classes
53
- if ( ! Object . prototype . hasOwnProperty . call ( metadata , fieldName ) ) {
54
- continue ;
47
+ const includedTypeIds = new Set < number > ( ) ;
48
+ const pendingReflectionTypes : { [ typeid : number ] : ReflectionType [ ] } = { } ;
49
+
50
+ // add type to reflection in a way that respects inheritance
51
+ // (parent types should be added before their children)
52
+ const addType = ( type : ReflectionType ) => {
53
+ if ( type . extendsId === undefined || includedTypeIds . has ( type . extendsId ) ) {
54
+ includedTypeIds . add ( type . id ) ;
55
+
56
+ reflection . types . push ( type ) ;
57
+
58
+ const deps = pendingReflectionTypes [ type . id ] ;
59
+ if ( deps !== undefined ) {
60
+ delete pendingReflectionTypes [ type . id ] ;
61
+ deps . forEach ( ( childType ) => addType ( childType ) ) ;
55
62
}
63
+ } else {
64
+ if ( pendingReflectionTypes [ type . extendsId ] === undefined ) {
65
+ pendingReflectionTypes [ type . extendsId ] = [ ] ;
66
+ }
67
+ pendingReflectionTypes [ type . extendsId ] . push ( type ) ;
68
+ }
69
+ } ;
56
70
57
- const field = new ReflectionField ( ) ;
58
- field . name = fieldName ;
71
+ context . schemas . forEach ( ( typeid , klass ) => {
72
+ const type = new ReflectionType ( ) ;
73
+ type . id = Number ( typeid ) ;
59
74
60
- let fieldType : string ;
75
+ // support inheritance
76
+ const inheritFrom = Object . getPrototypeOf ( klass ) ;
77
+ if ( inheritFrom !== Schema ) {
78
+ type . extendsId = context . schemas . get ( inheritFrom ) ;
79
+ }
61
80
62
- const type = metadata [ index ] . type ;
81
+ const metadata = klass [ Symbol . metadata ] ;
63
82
64
- if ( typeof ( type ) === "string" ) {
65
- fieldType = type ;
83
+ //
84
+ // FIXME: this is a workaround for inherited types without additional fields
85
+ // if metadata is the same reference as the parent class - it means the class has no own metadata
86
+ //
87
+ if ( metadata !== inheritFrom [ Symbol . metadata ] ) {
88
+ for ( const fieldIndex in metadata ) {
89
+ const index = Number ( fieldIndex ) ;
90
+ const fieldName = metadata [ index ] . name ;
66
91
67
- } else {
68
- let childTypeSchema : typeof Schema ;
92
+ // skip fields from parent classes
93
+ if ( ! Object . prototype . hasOwnProperty . call ( metadata , fieldName ) ) {
94
+ continue ;
95
+ }
96
+
97
+ const reflectionField = new ReflectionField ( ) ;
98
+ reflectionField . name = fieldName ;
99
+
100
+ let fieldType : string ;
69
101
70
- //
71
- // TODO: refactor below.
72
- //
73
- if ( Schema . is ( type ) ) {
74
- fieldType = "ref" ;
75
- childTypeSchema = type as typeof Schema ;
102
+ const field = metadata [ index ] ;
103
+
104
+ if ( typeof ( field . type ) === "string" ) {
105
+ fieldType = field . type ;
76
106
77
107
} else {
78
- fieldType = Object . keys ( type ) [ 0 ] ;
108
+ let childTypeSchema : typeof Schema ;
79
109
80
- if ( typeof ( type [ fieldType ] ) === "string" ) {
81
- fieldType += ":" + type [ fieldType ] ; // array:string
110
+ //
111
+ // TODO: refactor below.
112
+ //
113
+ if ( Schema . is ( field . type ) ) {
114
+ fieldType = "ref" ;
115
+ childTypeSchema = field . type as typeof Schema ;
82
116
83
117
} else {
84
- childTypeSchema = type [ fieldType ] ;
118
+ fieldType = Object . keys ( field . type ) [ 0 ] ;
119
+
120
+ if ( typeof ( field . type [ fieldType ] ) === "string" ) {
121
+ fieldType += ":" + field . type [ fieldType ] ; // array:string
122
+
123
+ } else {
124
+ childTypeSchema = field . type [ fieldType ] ;
125
+ }
85
126
}
127
+
128
+ reflectionField . referencedType = ( childTypeSchema )
129
+ ? context . getTypeId ( childTypeSchema )
130
+ : - 1 ;
86
131
}
87
132
88
- field . referencedType = ( childTypeSchema )
89
- ? context . getTypeId ( childTypeSchema )
90
- : - 1 ;
133
+ reflectionField . type = fieldType ;
134
+ type . fields . push ( reflectionField ) ;
91
135
}
92
-
93
- field . type = fieldType ;
94
- currentType . fields . push ( field ) ;
95
136
}
96
137
97
- reflection . types . push ( currentType ) ;
98
- }
99
-
100
- for ( let typeid in context . types ) {
101
- const klass = context . types [ typeid ] ;
102
- const type = new ReflectionType ( ) ;
103
- type . id = Number ( typeid ) ;
104
-
105
- // support inheritance
106
- const inheritFrom = Object . getPrototypeOf ( klass ) ;
107
- if ( inheritFrom !== Schema ) {
108
- type . extendsId = context . schemas . get ( inheritFrom ) ;
109
- }
138
+ addType ( type ) ;
139
+ } ) ;
110
140
111
- buildType ( type , klass [ Symbol . metadata ] ) ;
141
+ // in case there are types that were not added due to inheritance
142
+ for ( const typeid in pendingReflectionTypes ) {
143
+ pendingReflectionTypes [ typeid ] . forEach ( ( type ) =>
144
+ reflection . types . push ( type ) )
112
145
}
113
146
114
147
const buf = reflectionEncoder . encodeAll ( it ) ;
0 commit comments