All files / lib/joi-to-json-schema index.ts

88.24% Statements 30/34
80.49% Branches 66/82
100% Functions 1/1
88.24% Lines 30/34

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 83 84 85 86 87 88 89 90 91 92 93 94 951x 1x 1x                                                 1x 69x 69x   69x       69x         69x   69x 4x   69x 69x   1x     69x 1x       69x   69x 1x     69x 8x   69x         4x 1x                   3x     68x   68x       68x   1x 1x  
import assert from "assert";
import Joi from "@hapi/joi";
import * as TYPES from "./types";
 
/**
 * Converts the supplied joi validation object into a JSON schema object,
 * optionally applying a transformation.
 *
 * @param {JoiValidation} joi
 * @param {TransformFunction} [transformer=null]
 * @returns {JSONSchema}
 */
/**
 * Joi Validation Object
 * @typedef {object} JoiValidation
 */
 
/**
 * Transformation Function - applied just before `convert()` returns and called as `function(object):object`
 * @typedef {function} TransformFunction
 */
 
/**
 * JSON Schema Object
 * @typedef {object} JSONSchema
 */
 
const convert = (joi, transformer = null) => {
  assert("object" === typeof joi && true === Joi.isSchema(joi), "requires a joi schema object");
  assert(joi.type, "joi schema object must have a type");
 
  Iif (!TYPES[joi.type]) {
    throw new Error(`sorry, do not know how to convert unknown joi type: "${joi.type}"`);
  }
 
  Iif (transformer) {
    assert("function" === typeof transformer, "transformer must be a function");
  }
 
  // JSON Schema root for this type.
  const schema: any = {};
  // Copy over the details that all schemas may have...
  if (joi?._flags?.description) {
    schema.description = joi?._flags?.description;
  }
  const joiExamples = joi?.$_terms?.examples;
  if (joiExamples && joiExamples.length > 0) {
    // schema.examples = joiExamples.map(e => e.value)
    schema.examples = joiExamples;
  }
 
  if (joiExamples && joiExamples.length === 1) {
    schema.example = joiExamples[0];
  }
 
  // Add the label as a title if it exists
  Iif (joi?._settings?.language?.label) {
    schema.title = joi._settings.language.label;
  } else if (joi?._flags?.label) {
    schema.title = joi._flags.label;
  }
  // Checking for undefined and null explicitly to allow false and 0 values
  if (joi._flags && joi._flags.default !== undefined && joi._flags.default !== null) {
    schema["default"] = joi._flags.default;
  }
  if (
    joi._valids &&
    joi._valids._values &&
    (joi._valids._values.size || joi._valids._values.length)
  ) {
    if (Array.isArray(joi.$_terms.items) || !joi._flags.only) {
      return {
        anyOf: [
          {
            type: joi.type,
            enum: [...joi._valids._values],
          },
          TYPES[joi.type](convert, schema, joi, transformer),
        ],
      };
    }
    schema["enum"] = [...joi._valids._values];
  }
 
  let result = TYPES[joi.type](convert, schema, joi, transformer);
 
  Iif (transformer) {
    result = transformer(result, joi);
  }
 
  return result;
};
convert.TYPES = TYPES;
export { convert };