inputSchemasToEntitySchemas.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import fs from 'fs'
  2. import path from 'path'
  3. import {
  4. AddClassSchema,
  5. HashProperty,
  6. Property,
  7. ReferenceProperty,
  8. SinglePropertyVariant,
  9. TextProperty,
  10. VecPropertyVariant,
  11. } from '../types/extrinsics/AddClassSchema'
  12. import PRIMITIVE_PROPERTY_DEFS from '../schemas/propertyValidationDefs.schema.json'
  13. import { getInputs } from '../src/helpers/inputs'
  14. import { getSchemasLocation, SCHEMA_TYPES } from '../src/helpers/schemas'
  15. import { JSONSchema7, JSONSchema7TypeName } from 'json-schema'
  16. const schemaInputs = getInputs<AddClassSchema>('schemas')
  17. const strictObjectDef = (def: Record<string, any>): JSONSchema7 => ({
  18. type: 'object',
  19. additionalProperties: false,
  20. ...def,
  21. })
  22. const onePropertyObjectDef = (propertyName: string, propertyDef: Record<string, any>): JSONSchema7 =>
  23. strictObjectDef({
  24. required: [propertyName],
  25. properties: {
  26. [propertyName]: propertyDef,
  27. },
  28. })
  29. const TextPropertyDef = ({ Text: maxLength }: TextProperty): JSONSchema7 => ({
  30. type: 'string',
  31. maxLength,
  32. })
  33. const HashPropertyDef = ({ Hash: maxLength }: HashProperty): JSONSchema7 => ({
  34. type: 'string',
  35. maxLength,
  36. })
  37. const ReferencePropertyDef = ({ Reference: ref }: ReferenceProperty): JSONSchema7 => ({
  38. 'oneOf': [
  39. onePropertyObjectDef('new', { '$ref': `../entities/${ref.className}Entity.schema.json` }),
  40. onePropertyObjectDef('existing', { '$ref': `../entityReferences/${ref.className}Ref.schema.json` }),
  41. PRIMITIVE_PROPERTY_DEFS.definitions.Uint64 as JSONSchema7,
  42. ],
  43. })
  44. const SinglePropertyDef = ({ Single: singlePropType }: SinglePropertyVariant): JSONSchema7 => {
  45. if (typeof singlePropType === 'string') {
  46. return PRIMITIVE_PROPERTY_DEFS.definitions[singlePropType] as JSONSchema7
  47. } else if ((singlePropType as TextProperty).Text) {
  48. return TextPropertyDef(singlePropType as TextProperty)
  49. } else if ((singlePropType as HashProperty).Hash) {
  50. return HashPropertyDef(singlePropType as HashProperty)
  51. } else if ((singlePropType as ReferenceProperty).Reference) {
  52. return ReferencePropertyDef(singlePropType as ReferenceProperty)
  53. }
  54. throw new Error(`Unknown single proprty type: ${JSON.stringify(singlePropType)}`)
  55. }
  56. const VecPropertyDef = ({ Vector: vec }: VecPropertyVariant): JSONSchema7 => ({
  57. type: 'array',
  58. maxItems: vec.max_length,
  59. 'items': SinglePropertyDef({ Single: vec.vec_type }),
  60. })
  61. const PropertyDef = ({ property_type: propertyType, description, required }: Property): JSONSchema7 => {
  62. const def = {
  63. ...((propertyType as SinglePropertyVariant).Single
  64. ? SinglePropertyDef(propertyType as SinglePropertyVariant)
  65. : VecPropertyDef(propertyType as VecPropertyVariant)),
  66. description,
  67. }
  68. // Non-required fields:
  69. // Simple fields:
  70. if (!required && def.type) {
  71. def.type = [def.type as JSONSchema7TypeName, 'null']
  72. }
  73. // Relationships:
  74. else if (!required && def.oneOf) {
  75. def.oneOf = [...def.oneOf, { type: 'null' }]
  76. }
  77. return def
  78. }
  79. // Mkdir entity schemas directories if they do not exist
  80. SCHEMA_TYPES.forEach((type) => {
  81. if (!fs.existsSync(getSchemasLocation(type))) {
  82. fs.mkdirSync(getSchemasLocation(type))
  83. }
  84. })
  85. // Run schema conversion:
  86. schemaInputs.forEach(({ fileName, data: inputData }) => {
  87. const schemaName = fileName.replace('Schema.json', '')
  88. if (inputData.newProperties && !inputData.existingProperties) {
  89. const properites = inputData.newProperties
  90. const propertiesObj = properites.reduce((pObj, p) => {
  91. pObj[p.name] = PropertyDef(p)
  92. return pObj
  93. }, {} as Record<string, ReturnType<typeof PropertyDef>>)
  94. const EntitySchema: JSONSchema7 = {
  95. $schema: 'http://json-schema.org/draft-07/schema',
  96. $id: `https://joystream.org/entities/${schemaName}Entity.schema.json`,
  97. title: `${schemaName}Entity`,
  98. description: `JSON schema for entities based on ${schemaName} runtime schema`,
  99. ...strictObjectDef({
  100. required: properites.filter((p) => p.required).map((p) => p.name),
  101. properties: propertiesObj,
  102. }),
  103. }
  104. const ReferenceSchema: JSONSchema7 = {
  105. $schema: 'http://json-schema.org/draft-07/schema',
  106. $id: `https://joystream.org/entityReferences/${schemaName}Ref.schema.json`,
  107. title: `${schemaName}Reference`,
  108. description: `JSON schema for reference to ${schemaName} entity based on runtime schema`,
  109. anyOf: [
  110. ...properites.filter((p) => p.required && p.unique).map((p) => onePropertyObjectDef(p.name, PropertyDef(p))),
  111. PRIMITIVE_PROPERTY_DEFS.definitions.Uint64 as JSONSchema7,
  112. ],
  113. }
  114. const BatchSchema: JSONSchema7 = {
  115. $schema: 'http://json-schema.org/draft-07/schema',
  116. $id: `https://joystream.org/entityBatches/${schemaName}Batch.schema.json`,
  117. title: `${schemaName}Batch`,
  118. description: `JSON schema for batch of entities based on ${schemaName} runtime schema`,
  119. ...strictObjectDef({
  120. required: ['className', 'entries'],
  121. properties: {
  122. className: { type: 'string' },
  123. entries: {
  124. type: 'array',
  125. items: { '$ref': `../entities/${schemaName}Entity.schema.json` },
  126. },
  127. },
  128. }),
  129. }
  130. const entitySchemaPath = path.join(getSchemasLocation('entities'), `${schemaName}Entity.schema.json`)
  131. fs.writeFileSync(entitySchemaPath, JSON.stringify(EntitySchema, undefined, 4))
  132. console.log(`${entitySchemaPath} succesfully generated!`)
  133. const entityReferenceSchemaPath = path.join(getSchemasLocation('entityReferences'), `${schemaName}Ref.schema.json`)
  134. fs.writeFileSync(entityReferenceSchemaPath, JSON.stringify(ReferenceSchema, undefined, 4))
  135. console.log(`${entityReferenceSchemaPath} succesfully generated!`)
  136. const batchOfEntitiesSchemaPath = path.join(getSchemasLocation('entityBatches'), `${schemaName}Batch.schema.json`)
  137. fs.writeFileSync(batchOfEntitiesSchemaPath, JSON.stringify(BatchSchema, undefined, 4))
  138. console.log(`${batchOfEntitiesSchemaPath} succesfully generated!`)
  139. } else {
  140. console.log('WARNING: Schemas with "existingProperties" not supported yet!')
  141. console.log('Skipping...')
  142. }
  143. })