All files / src/codegen validateSchema.ts

85.71% Statements 24/28
63.63% Branches 7/11
100% Functions 2/2
85.71% Lines 24/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 831x 1x   1x 1x               1x 23x 23x 23x 23x     23x             23x 23x 1x         22x 1x           21x 21x             21x   21x 21x 21x   5x                           16x             7x              
import fs from 'fs';
import Ajv2019 from "ajv/dist/2019";
import { ErrorObject } from "ajv";
import { parseJson } from './contractSchemaJsonParser';
import { ContractSchemaImpl } from './contractSchema';
 
// Define a structured return type
interface ValidationResult {
  isValid: boolean;
  errors: ErrorObject[];
}
 
export function validateSchema(jsonData: unknown, schemaFile: string): ValidationResult {
  try {
    const schemaData: object = JSON.parse(fs.readFileSync(schemaFile, 'utf8'));
    const ajv: Ajv2019 = new Ajv2019();
    const validate = ajv.compile(schemaData);
    
    // Check if jsonData is an object and has the correct $schema value
    Iif (typeof jsonData !== 'object' || jsonData === null) {
      return {
        isValid: false,
        errors: [createErrorObject("type", "must be object", { type: "object" })]
      };
    }
 
    const schema = (jsonData as any).$schema;
    if (schema === undefined) {
      return {
        isValid: false,
        errors: [createErrorObject("required", "must have required property '$schema'", { missingProperty: '$schema' })]
      };
    }
    if (!(schema === "https://patchwork.dev/schema/patchwork-contract-config.schema.json" || schema === "https://patchwork.dev/schema/patchwork-project-config.schema.json")) {
      return {
        isValid: false,
        errors: [createErrorObject("const", "must be one of", { allowedValues: ["https://patchwork.dev/schema/patchwork-contract-config.schema.json", "https://patchwork.dev/schema/patchwork-project-config.schema.json"] })]
      };
    }
 
    const valid: boolean = validate(jsonData);
    Iif (!valid) {
      return {
        isValid: false,
        errors: validate.errors || []
      };
    }
 
    if (schema === "https://patchwork.dev/schema/patchwork-contract-config.schema.json") {
      // If JSON schema validation passes for a contract config, create ContractSchemaImpl and validate
      try {
        const contractSchema = parseJson(jsonData);
        new ContractSchemaImpl(contractSchema).validate();
      } catch (error) {
        return {
          isValid: false,
          errors: [createErrorObject("contractSchema", (error as Error).message, {})]
        };
      }
    }
    // TODO project validation
  } catch (error: unknown) {
    console.error("Error reading schema file:", (error as Error).message);
    return {
      isValid: false,
      errors: [createErrorObject("$schema", (error as Error).message, {})]
    };
  }
  return {
    isValid: true,
    errors: []
  };
}
 
function createErrorObject(keyword: string, message: string, params: Record<string, any>): ErrorObject {
  return {
    keyword,
    instancePath: "",
    schemaPath: `#/${keyword}`,
    params,
    message
  };
}