1
1
import { createContext , useContext , useState , useEffect } from 'react' ;
2
2
import { compareVersions } from 'compare-versions' ;
3
3
4
- import { Model } from './metamodel' ;
4
+ import { Model , Endpoint , TypeName , ValueOf } from './metamodel' ;
5
+
6
+ export const SchemaContext = createContext < Context | undefined > ( undefined ) ;
5
7
6
8
type Context = {
7
9
schema : Model | { } ;
10
+ references : Record < string , Record < string , string [ ] > > ;
8
11
version : string ;
9
12
setVersion : ( version : string ) => void ;
10
13
allVersions : string [ ] ;
@@ -14,10 +17,181 @@ type Version = {
14
17
name : string ;
15
18
}
16
19
17
- export const SchemaContext = createContext < Context | undefined > ( undefined ) ;
20
+ const crossReference = ( schema : Model ) : Record < string , Record < string , string [ ] > > => {
21
+ const refs : Record < string , Record < string , string [ ] > > = { } ;
22
+
23
+ const addEndpointReference = ( source : Endpoint , type : TypeName , comment : string ) => {
24
+ const typeName = `${ type . namespace } ::${ type . name } ` ;
25
+ if ( ! ( typeName in refs ) ) {
26
+ refs [ typeName ] = { }
27
+ }
28
+ if ( ! ( 'endpoints' in refs [ typeName ] ) ) {
29
+ refs [ typeName ] . endpoints = [ ] ;
30
+ }
31
+ refs [ typeName ] . endpoints . push ( `${ source . name } ${ comment } ` ) ;
32
+ }
33
+
34
+ const addTypeReference = ( source : TypeName , type : TypeName , comment : string ) => {
35
+ const typeName = `${ type . namespace } ::${ type . name } ` ;
36
+ if ( ! ( typeName in refs ) ) {
37
+ refs [ typeName ] = { }
38
+ }
39
+ if ( refs [ typeName ] . types === undefined ) {
40
+ refs [ typeName ] . types = [ ] ;
41
+ }
42
+ refs [ typeName ] . types . push ( `${ source . namespace } ::${ source . name } ${ comment } ` ) ;
43
+ }
44
+
45
+ const addValueOfReferences = ( source : TypeName , valueOf : ValueOf , comment : string ) => {
46
+ switch ( valueOf . kind ) {
47
+ case 'instance_of' :
48
+ addTypeReference ( source , valueOf . type , comment ) ;
49
+ break ;
50
+ case 'array_of' :
51
+ addValueOfReferences ( source , valueOf . value , comment ) ;
52
+ break ;
53
+ case 'union_of' :
54
+ for ( const item of valueOf . items ) {
55
+ addValueOfReferences ( source , item , comment ) ;
56
+ }
57
+ break ;
58
+ case 'dictionary_of' :
59
+ addValueOfReferences ( source , valueOf . key , comment ) ;
60
+ addValueOfReferences ( source , valueOf . value , comment ) ;
61
+ break ;
62
+ }
63
+ }
64
+
65
+ // register types referenced in endpoints
66
+ for ( const e of schema . endpoints ) {
67
+ if ( e . request ) {
68
+ addEndpointReference ( e , e . request , 'Endpoint Request' ) ;
69
+ }
70
+ if ( e . response ) {
71
+ addEndpointReference ( e , e . response , 'Endpoint Response' ) ;
72
+ }
73
+ }
74
+
75
+ // register types references in other types
76
+ for ( const type of schema . types ) {
77
+ switch ( type . kind ) {
78
+ case 'interface' :
79
+ if ( type . generics ) {
80
+ for ( const t of type . generics ) {
81
+ addTypeReference ( type . name , t , 'Generic' ) ;
82
+ }
83
+ }
84
+ if ( type . inherits ) {
85
+ addTypeReference ( type . name , type . inherits . type , 'Inherits' ) ;
86
+ }
87
+ if ( type . behaviors ) {
88
+ for ( const t of type . behaviors ) {
89
+ addTypeReference ( type . name , t . type , 'Behavior' ) ;
90
+ }
91
+ }
92
+ if ( type . attachedBehaviors ) {
93
+ for ( const b of type . attachedBehaviors ) {
94
+ addTypeReference ( type . name , { namespace : '_spec_utils' , name : b } , 'Attached behavior' ) ;
95
+ }
96
+ }
97
+ for ( const p of type . properties ) {
98
+ addValueOfReferences ( type . name , p . type , `${ p . name } (Property)` ) ;
99
+ }
100
+ break ;
101
+ case 'request' :
102
+ if ( type . generics ) {
103
+ for ( const t of type . generics ) {
104
+ addTypeReference ( type . name , t , 'Generic' ) ;
105
+ }
106
+ }
107
+ if ( type . inherits ) {
108
+ addTypeReference ( type . name , type . inherits . type , 'Inherits' ) ;
109
+ }
110
+ if ( type . behaviors ) {
111
+ for ( const t of type . behaviors ) {
112
+ addTypeReference ( type . name , t . type , 'Behavior' ) ;
113
+ }
114
+ }
115
+ if ( type . attachedBehaviors ) {
116
+ for ( const b of type . attachedBehaviors ) {
117
+ addTypeReference ( type . name , { namespace : '_spec_utils' , name : b } , 'Attached behavior' ) ;
118
+ }
119
+ }
120
+ for ( const p of type . path ) {
121
+ addValueOfReferences ( type . name , p . type , `${ p . name } (path property)` ) ;
122
+ }
123
+ for ( const p of type . query ) {
124
+ addValueOfReferences ( type . name , p . type , `${ p . name } (Query property)` ) ;
125
+ }
126
+ if ( type . body . kind === "value" ) {
127
+ addValueOfReferences ( type . name , type . body . value , 'Body' ) ;
128
+ }
129
+ else if ( type . body . kind === "properties" ) {
130
+ for ( const p of type . body . properties ) {
131
+ addValueOfReferences ( type . name , p . type , `${ p . name } (Body property)` ) ;
132
+ }
133
+ }
134
+ if ( type . behaviors ) {
135
+ for ( const t of type . behaviors ) {
136
+ addTypeReference ( type . name , t . type , 'Behavior' ) ;
137
+ }
138
+ }
139
+ break ;
140
+ case 'response' :
141
+ if ( type . generics ) {
142
+ for ( const t of type . generics ) {
143
+ addTypeReference ( type . name , t , 'Generic' ) ;
144
+ }
145
+ }
146
+ if ( type . body . kind === "value" ) {
147
+ addValueOfReferences ( type . name , type . body . value , 'Body' ) ;
148
+ }
149
+ else if ( type . body . kind === "properties" ) {
150
+ for ( const p of type . body . properties ) {
151
+ addValueOfReferences ( type . name , p . type , `${ p . name } (Body property)` ) ;
152
+ }
153
+ }
154
+ if ( type . behaviors ) {
155
+ for ( const t of type . behaviors ) {
156
+ addTypeReference ( type . name , t . type , 'Behavior' ) ;
157
+ }
158
+ }
159
+ if ( type . attachedBehaviors ) {
160
+ for ( const b of type . attachedBehaviors ) {
161
+ addTypeReference ( type . name , { namespace : '_spec_utils' , name : b } , 'Attached behavior' ) ;
162
+ }
163
+ }
164
+ if ( type . exceptions ) {
165
+ for ( const e of type . exceptions ) {
166
+ if ( e . body . kind === "value" ) {
167
+ addValueOfReferences ( type . name , e . body . value , 'Exception body' ) ;
168
+ }
169
+ else if ( e . body . kind === "properties" ) {
170
+ for ( const p of e . body . properties ) {
171
+ addValueOfReferences ( type . name , p . type , `${ p . name } (Exception body property)` ) ;
172
+ }
173
+ }
174
+ }
175
+ }
176
+ break ;
177
+ case 'enum' :
178
+ break ;
179
+ case 'type_alias' :
180
+ addValueOfReferences ( type . name , type . type , 'Type' ) ;
181
+ if ( type . generics ) {
182
+ for ( const t of type . generics ) {
183
+ addTypeReference ( type . name , t , 'Generic' ) ;
184
+ }
185
+ }
186
+ break ;
187
+ }
188
+ }
189
+ return refs ;
190
+ } ;
18
191
19
192
export default function SchemaProvider ( { children } : React . PropsWithChildren < { } > ) {
20
193
const [ schema , setSchema ] = useState < Model | { } > ( { } ) ;
194
+ const [ references , setReferences ] = useState < Record < string , Record < string , string [ ] > > > ( { } ) ;
21
195
const [ version , setVersion ] = useState < string > ( '' ) ;
22
196
const [ allVersions , setAllVersions ] = useState < string [ ] > ( [ ] ) ;
23
197
@@ -41,13 +215,17 @@ export default function SchemaProvider({ children }: React.PropsWithChildren<{}>
41
215
}
42
216
( async ( ) => {
43
217
const r = await fetch ( `https://raw.githubusercontent.com/elastic/elasticsearch-specification/refs/heads/${ version } /output/schema/schema.json` ) ;
44
- const s = await r . json ( ) ;
45
- setSchema ( s ) ;
218
+ if ( r . status === 200 ) {
219
+ const s = await r . json ( ) ;
220
+ const refs = crossReference ( s ) ;
221
+ setSchema ( s ) ;
222
+ setReferences ( refs ) ;
223
+ }
46
224
} ) ( ) ;
47
225
} , [ version ] ) ;
48
226
49
227
return (
50
- < SchemaContext . Provider value = { { schema, version, setVersion, allVersions } } >
228
+ < SchemaContext . Provider value = { { schema, references , version, setVersion, allVersions } } >
51
229
{ children }
52
230
</ SchemaContext . Provider >
53
231
) ;
@@ -61,5 +239,5 @@ export function useSchema(): Model {
61
239
62
240
export function useSchemaContext ( ) : Context {
63
241
const ctx = useContext ( SchemaContext ) ;
64
- return ctx ? ctx : { schema : { } , version : 'main' , setVersion : ( v ) => { } , allVersions : [ ] } ;
242
+ return ctx ? ctx : { schema : { } , references : { } , version : 'main' , setVersion : ( v ) => { } , allVersions : [ ] } ;
65
243
}
0 commit comments