Browse Source

Improved validate.ts

Leszek Wiesner 4 years ago
parent
commit
add3aab297

+ 2 - 6
content-directory-schemas/README.md

@@ -46,13 +46,9 @@ Now all the json files matching `*Class.json`, `*Schema.json`, `*{EntityName}Bat
 
 For more context, see: https://code.visualstudio.com/docs/languages/json
 
-### Validate inputs via command
+### Validate inputs and `json-schemas` via a command
 
-Inpus inside `inputs/classes` and `inputs/schemas` can also be validated using `yarn workspace cd-schemas validate` command. _**NOTE:** Validation of inputs inside `inputs/entityBatches` via the command is not supported yet._
-
-The command also validates whether `json-schemas` inside `schemas/extrinsics` are actually valid `json-schemas`.
-
-In the future it is expected that this command will do a complete validation of the content and structure of all json files inside `content-directory-schemas`, which should facilitate checking the validity of `content-directory-schemas` through CI.
+All inputs inside `inputs` directory and `json-schemas` used to validate those inputs can also be validated using `yarn workspace cd-schemas validate` command. This is mainly to facilitate checking the validity of `.json` and `.schema.json` files inside `content-directory-schemas` through CI.
 
 ### Entity batches
 

+ 3 - 3
content-directory-schemas/scripts/inputSchemasToEntitySchemas.ts

@@ -111,7 +111,7 @@ inputFilenames.forEach((fileName) => {
 
     const EntitySchema = {
       '$schema': 'http://json-schema.org/draft-07/schema',
-      '$id': `https://joystream.org/${schemaName}Entity.schema.json`,
+      '$id': `https://joystream.org/entities/${schemaName}Entity.schema.json`,
       'title': `${schemaName}Entity`,
       'description': `JSON schema for entities based on ${schemaName} runtime schema`,
       ...strictObjectDef({
@@ -122,7 +122,7 @@ inputFilenames.forEach((fileName) => {
 
     const ReferenceSchema = {
       '$schema': 'http://json-schema.org/draft-07/schema',
-      '$id': `https://joystream.org/${schemaName}Reference.schema.json`,
+      '$id': `https://joystream.org/entityReferences/${schemaName}Ref.schema.json`,
       'title': `${schemaName}Reference`,
       'description': `JSON schema for reference to ${schemaName} entity based on runtime schema`,
       'anyOf': [
@@ -133,7 +133,7 @@ inputFilenames.forEach((fileName) => {
 
     const BatchSchema = {
       '$schema': 'http://json-schema.org/draft-07/schema',
-      '$id': `https://joystream.org/${schemaName}Batch.schema.json`,
+      '$id': `https://joystream.org/entityBatches/${schemaName}Batch.schema.json`,
       'title': `${schemaName}Batch`,
       'description': `JSON schema for batch of entities based on ${schemaName} runtime schema`,
       'type': 'array',

+ 68 - 26
content-directory-schemas/scripts/validate.ts

@@ -1,42 +1,84 @@
 // TODO: Add entity batches validation
 import Ajv from 'ajv'
-import CreateClassSchema from '../schemas/extrinsics/CreateClass.schema.json'
-import AddClassSchemaSchema from '../schemas/extrinsics/AddClassSchema.schema.json'
-import { getInputs, InputType } from './helpers/inputs'
-
-type JsonSchema = {
-  schemaName: string
-  jsonSchema: Record<string, unknown>
-  relatedInputType: InputType
-}
+import { FetchedInput, getInputs, InputType, INPUT_TYPES } from './helpers/inputs'
+import path from 'path'
+import fs from 'fs'
 
-const schemas: JsonSchema[] = [
-  { schemaName: 'CreateClass', jsonSchema: CreateClassSchema, relatedInputType: 'classes' },
-  { schemaName: 'AddClassSchema', jsonSchema: AddClassSchemaSchema, relatedInputType: 'schemas' },
-]
+const SCHEMAS_LOCATION = path.join(__dirname, '../schemas')
 
 const ajv = new Ajv({ allErrors: true })
+// Add all existing schemas to Ajv to allow them to reference each other
+fs.readdirSync(SCHEMAS_LOCATION)
+  .filter((subdir) => !subdir.includes('.'))
+  .forEach((subdir) => {
+    fs.readdirSync(path.join(SCHEMAS_LOCATION, subdir)).forEach((schemaFilename) => {
+      ajv.addSchema(JSON.parse(fs.readFileSync(path.join(SCHEMAS_LOCATION, subdir, schemaFilename)).toString()))
+    })
+  })
 
-schemas.forEach(({ schemaName, jsonSchema, relatedInputType }) => {
-  // Validate the schema itself
-  console.log(`Validating schema for ${schemaName}...`)
+const validateJsonSchema = (jsonSchemaShortPath: string, jsonSchema: Record<string, unknown>) => {
   if (!ajv.validateSchema(jsonSchema)) {
-    console.log(`\nERROR! ${schemaName} - schema validation failed!`)
+    console.log(`\nERROR! ${jsonSchemaShortPath} - schema validation failed!`)
     console.log(ajv.errorsText(undefined, { separator: '\n' }))
     console.log('\n')
     process.exitCode = 100
-    return
+
+    return false
+  }
+
+  return true
+}
+
+const validateInputAgainstSchema = (input: FetchedInput, jsonSchema: Record<string, unknown>) => {
+  if (!ajv.validate(jsonSchema, input.data)) {
+    console.log(`\nERROR! ${input.fileName} - validation failed!`)
+    console.log(ajv.errorsText(undefined, { separator: '\n' }))
+    console.log('\n')
+    process.exitCode = 100
+
+    return false
   }
 
-  // Validate inputs
-  console.log('Validating inputs...')
-  getInputs(relatedInputType).forEach(({ fileName, data }) => {
-    if (!ajv.validate(jsonSchema, data)) {
-      console.log(`\nERROR! ${relatedInputType}/${fileName} - validation failed!`)
-      console.log(ajv.errorsText(undefined, { separator: '\n' }))
-      console.log('\n')
-      process.exitCode = 100
+  return true
+}
+
+const getJsonSchemaForInput = (inputType: InputType, input: FetchedInput) => {
+  let schemaLocation = ''
+  if (inputType === 'classes') {
+    schemaLocation = path.join(SCHEMAS_LOCATION, 'extrinsics', 'CreateClass.schema.json')
+  }
+  if (inputType === 'schemas') {
+    schemaLocation = path.join(SCHEMAS_LOCATION, 'extrinsics', 'AddClassSchema.schema.json')
+  }
+  if (inputType === 'entityBatches') {
+    const jsonSchemaFilename = input.fileName.split('_')[1].replace('.json', '.schema.json')
+    schemaLocation = path.join(SCHEMAS_LOCATION, 'entityBatches', jsonSchemaFilename)
+  }
+
+  return {
+    jsonSchemaPath: schemaLocation,
+    jsonSchema: JSON.parse(fs.readFileSync(schemaLocation).toString()),
+  }
+}
+
+const alreadyValidatedJsonSchemas = new Map<string, boolean>()
+INPUT_TYPES.forEach((inputType) => {
+  console.log(`Validating inputs/${inputType} and related json-schemas...\n`)
+  getInputs(inputType).forEach((input) => {
+    const { jsonSchemaPath, jsonSchema } = getJsonSchemaForInput(inputType, input)
+    const jsonSchemaShortPath = path.relative(path.join(SCHEMAS_LOCATION, '..'), jsonSchemaPath)
+    // Validate the schema itself
+    let isJsonSchemaValid = alreadyValidatedJsonSchemas.get(jsonSchemaShortPath)
+    if (isJsonSchemaValid === undefined) {
+      console.log(`Validating ${jsonSchemaShortPath}...`)
+      isJsonSchemaValid = validateJsonSchema(jsonSchemaShortPath, jsonSchema)
+      alreadyValidatedJsonSchemas.set(jsonSchemaShortPath, isJsonSchemaValid)
+    }
+    if (!isJsonSchemaValid) {
+      return
     }
+    console.log(`Validating inputs/${inputType}/${input.fileName}...`)
+    validateInputAgainstSchema(input, jsonSchema)
   })
 
   console.log('\n\n')