@@ -3,6 +3,8 @@ import forEach from "lodash/forEach";
3
3
import hasProperty from "lodash/has" ;
4
4
import isEmpty from "lodash/isEmpty" ;
5
5
6
+ import { JSONSchema7Definition } from "json-schema" ;
7
+
6
8
import { JSONSchemasInterface } from "../JSONSchemasInterface" ;
7
9
8
10
export * from "@exabyte-io/esse.js/lib/js/esse/schemaUtils" ;
@@ -170,3 +172,123 @@ export function getSchemaWithDependencies({
170
172
...buildDependencies ( nodes ) ,
171
173
} ;
172
174
}
175
+
176
+ const DEFAULT_GENERATIVE_KEYS = [ "name" ] ;
177
+
178
+ interface NamedEntity {
179
+ name : string ;
180
+ }
181
+
182
+ const baseSchema = ( definitionName : string , enforceUnique = true ) : JSONSchema => {
183
+ return {
184
+ type : "array" ,
185
+ items : {
186
+ $ref : `#/definitions/${ definitionName } ` ,
187
+ } ,
188
+ uniqueItems : enforceUnique ,
189
+ } ;
190
+ } ;
191
+
192
+ const defaultNamedEntitySchema = ( name : string ) => {
193
+ return {
194
+ properties : {
195
+ name : {
196
+ type : "string" ,
197
+ enum : [ name ] ,
198
+ } ,
199
+ } ,
200
+ } as JSONSchema ;
201
+ } ;
202
+
203
+ /**
204
+ * Retrieves an RJSF schema with an id matching the provided name
205
+ */
206
+ export const schemaByNamedEntityName = ( name : string ) : JSONSchema | undefined => {
207
+ const translatedName = name . replace ( / _ / g, "-" ) ;
208
+ const schema = JSONSchemasInterface . matchSchema ( {
209
+ $id : {
210
+ $regex : `${ translatedName } $` ,
211
+ } ,
212
+ } ) ;
213
+ return schema ;
214
+ } ;
215
+
216
+ /*
217
+ * Filters an RJSF schema for all the properties used to generate a new schema
218
+ */
219
+ const filterForGenerativeProperties = ( schema : JSONSchema ) => {
220
+ if ( ! schema . properties || typeof schema . properties !== "object" ) return { } ;
221
+ const generativeFilter = ( [ propertyKey , property ] : [ string , JSONSchema7Definition ] ) => {
222
+ return (
223
+ ( typeof property === "object" && // JSONSchema7Definition type allows for boolean
224
+ property ?. $comment &&
225
+ property . $comment . includes ( "isGenerative:true" ) ) ||
226
+ DEFAULT_GENERATIVE_KEYS . includes ( propertyKey )
227
+ ) ;
228
+ } ;
229
+ // @ts -ignore : JSONSchema6 and JSONSchema7 are incompatible
230
+ const generativeProperties = Object . entries ( schema . properties ) . filter ( generativeFilter ) ;
231
+ const properties = Object . fromEntries ( generativeProperties ) ;
232
+ return { properties, required : Object . keys ( properties ) } as JSONSchema ; // all included fields are required based on isGenerative flag
233
+ } ;
234
+
235
+ /*
236
+ * Filters an RJSF schema for all the properties used to generate a new schema
237
+ */
238
+ const buildNamedEntitiesDependencies = ( entities : NamedEntity [ ] ) => {
239
+ return {
240
+ dependencies : {
241
+ name : {
242
+ oneOf : entities . map ( ( entity ) => {
243
+ const schema =
244
+ schemaByNamedEntityName ( entity . name ) ||
245
+ defaultNamedEntitySchema ( entity . name ) ;
246
+ return {
247
+
248
+ ...filterForGenerativeProperties ( schema ) ,
249
+ } ;
250
+ } ) ,
251
+ } ,
252
+ } ,
253
+ } ;
254
+ } ;
255
+
256
+ /**
257
+ * Generates an RJSF definition with a list of subschemas as enumerated options
258
+ */
259
+ const buildNamedEntitiesDefinitions = (
260
+ entities : NamedEntity [ ] ,
261
+ defaultEntity : NamedEntity ,
262
+ entityType : string ,
263
+ ) => {
264
+ if ( ! Array . isArray ( entities ) || entities . length < 1 ) return { } ;
265
+ return {
266
+ definitions : {
267
+ [ entityType ] : {
268
+ properties : {
269
+ name : {
270
+ type : "string" ,
271
+ enum : entities . map ( ( entity ) => entity . name ) ,
272
+ default : defaultEntity . name || entities [ 0 ] . name ,
273
+ } ,
274
+ } ,
275
+ ...buildNamedEntitiesDependencies ( entities ) ,
276
+ } ,
277
+ } ,
278
+ } ;
279
+ } ;
280
+
281
+ /*
282
+ * Generates an RJSF scheme with a list of subschemas as enumerated options
283
+ */
284
+ export const buildNamedEntitySchema = (
285
+ entities : NamedEntity [ ] ,
286
+ defaultEntity : NamedEntity ,
287
+ entityType : string ,
288
+ enforceUnique = true ,
289
+ ) : JSONSchema => {
290
+ return {
291
+ ...buildNamedEntitiesDefinitions ( entities , defaultEntity , entityType ) ,
292
+ ...baseSchema ( entityType , enforceUnique ) ,
293
+ } as JSONSchema ;
294
+ } ;
0 commit comments