"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var schema_exports = {};
__export(schema_exports, {
  isDiscriminatorForm: () => isDiscriminatorForm,
  isElementsForm: () => isElementsForm,
  isEmptyForm: () => isEmptyForm,
  isEnumForm: () => isEnumForm,
  isPropertiesForm: () => isPropertiesForm,
  isRefForm: () => isRefForm,
  isSchema: () => isSchema,
  isTypeForm: () => isTypeForm,
  isValidSchema: () => isValidSchema,
  isValuesForm: () => isValuesForm
});
module.exports = __toCommonJS(schema_exports);
function isEmptyForm(schema) {
  const { definitions, nullable, metadata, ...rest } = schema;
  return Object.keys(rest).length === 0;
}
function isRefForm(schema) {
  return "ref" in schema;
}
function isTypeForm(schema) {
  return "type" in schema;
}
function isEnumForm(schema) {
  return "enum" in schema;
}
function isElementsForm(schema) {
  return "elements" in schema;
}
function isPropertiesForm(schema) {
  return "properties" in schema || "optionalProperties" in schema;
}
function isValuesForm(schema) {
  return "values" in schema;
}
function isDiscriminatorForm(schema) {
  return "discriminator" in schema;
}
function isValidSchema(schema, path = [], skipRefCheck = false, root) {
  const err = (message) => ({ type: "error", message, path });
  if (root === void 0) {
    root = schema;
  }
  if (schema.definitions !== void 0) {
    if (root !== schema) {
      return err("non-root schema has definitions");
    }
    for (const subSchemaKey of Object.keys(schema.definitions)) {
      const result = isValidSchema(
        schema.definitions[subSchemaKey],
        path.concat("definitions", subSchemaKey),
        skipRefCheck,
        root
      );
      if (result.type === "error") {
        return result;
      }
    }
  }
  if (isRefForm(schema) && !skipRefCheck) {
    if (!(schema.ref in (root.definitions || {}))) {
      return err("ref does not point to a definition");
    }
  }
  if (isEnumForm(schema)) {
    if (schema.enum.length === 0) {
      return err("enum must be non-empty");
    }
    if (schema.enum.length !== new Set(schema.enum).size) {
      return err("enum must not contain duplicates");
    }
  }
  if (isElementsForm(schema)) {
    const result = isValidSchema(schema.elements, path.concat("elements"), skipRefCheck, root);
    if (result.type === "error") {
      return result;
    }
  }
  if (isPropertiesForm(schema)) {
    for (const subSchemaKey of Object.keys(schema.properties || {})) {
      const result = isValidSchema(
        schema.properties[subSchemaKey],
        path.concat("properties", subSchemaKey),
        skipRefCheck,
        root
      );
      if (result.type === "error") {
        return result;
      }
    }
    for (const subSchemaKey of Object.keys(schema.optionalProperties || {})) {
      const result = isValidSchema(
        schema.optionalProperties[subSchemaKey],
        path.concat("optionalProperties", subSchemaKey),
        skipRefCheck,
        root
      );
      if (result.type === "error") {
        return result;
      }
    }
    for (const key of Object.keys(schema.properties || {})) {
      if (key in (schema.optionalProperties || {})) {
        return err("properties and optionalProperties must not share properties: " + key);
      }
    }
    for (const key of Object.keys(schema.optionalProperties || {})) {
      if (key in (schema.properties || {})) {
        return err("properties and optionalProperties must not share properties: " + key);
      }
    }
  }
  if (isValuesForm(schema)) {
    const result = isValidSchema(schema.values, path.concat("values"), skipRefCheck, root);
    if (result.type === "error") {
      return result;
    }
  }
  if (isDiscriminatorForm(schema)) {
    for (const subSchemaKey of Object.keys(schema.mapping)) {
      const subSchema = schema.mapping[subSchemaKey];
      const result = isValidSchema(
        subSchema,
        path.concat("mapping", subSchemaKey),
        skipRefCheck,
        root
      );
      if (result.type === "error") {
        return result;
      }
      if (!isPropertiesForm(subSchema)) {
        return err("mapping values in discriminator form must be of the properties form");
      }
      if (subSchema.nullable) {
        return err("mapping values in discriminator form must not be nullable");
      }
      if (schema.discriminator in (subSchema.properties || {})) {
        return err("mapping values in discriminator form must not re-specify the discriminator");
      }
      if (schema.discriminator in (subSchema.optionalProperties || {})) {
        return err("mapping values in discriminator form must not re-specify the discriminator");
      }
    }
  }
  return ok();
}
const VALID_FORMS = [
  // Empty form
  [false, false, false, false, false, false, false, false, false, false],
  // Ref form
  [true, false, false, false, false, false, false, false, false, false],
  // Type form
  [false, true, false, false, false, false, false, false, false, false],
  // Enum form
  [false, false, true, false, false, false, false, false, false, false],
  // Elements form
  [false, false, false, true, false, false, false, false, false, false],
  // Properties form -- properties or optional properties or both, and never
  // additional properties on its own
  [false, false, false, false, true, false, false, false, false, false],
  [false, false, false, false, false, true, false, false, false, false],
  [false, false, false, false, true, true, false, false, false, false],
  [false, false, false, false, true, false, true, false, false, false],
  [false, false, false, false, false, true, true, false, false, false],
  [false, false, false, false, true, true, true, false, false, false],
  // Values form
  [false, false, false, false, false, false, false, true, false, false],
  // Discriminator form
  [false, false, false, false, false, false, false, false, true, true]
];
const VALID_TYPES = [
  "boolean",
  "float32",
  "float64",
  "int8",
  "uint8",
  "int16",
  "uint16",
  "int32",
  "uint32",
  "string",
  "timestamp"
];
const ok = () => ({ type: "ok" });
function isSchema(data, path = []) {
  const err = (message) => ({ type: "error", message, path });
  if (typeof data !== "object" || Array.isArray(data) || data === null) {
    return err("schema must be an object");
  }
  const obj = data;
  const {
    definitions = void 0,
    nullable = void 0,
    metadata = void 0,
    ref = void 0,
    type = void 0,
    enum: enum_ = void 0,
    elements = void 0,
    properties = void 0,
    optionalProperties = void 0,
    additionalProperties = void 0,
    values = void 0,
    discriminator = void 0,
    mapping = void 0,
    ...rest
  } = obj;
  const formSignature = [
    ref !== void 0,
    type !== void 0,
    enum_ !== void 0,
    elements !== void 0,
    properties !== void 0,
    optionalProperties !== void 0,
    additionalProperties !== void 0,
    values !== void 0,
    discriminator !== void 0,
    mapping !== void 0
  ];
  let formOk = false;
  for (const validForm of VALID_FORMS) {
    formOk = formOk || validForm.every((value, index) => value === formSignature[index]);
  }
  if (!formOk) {
    return err("schema doesn't match any valid form signature");
  }
  if (definitions !== void 0) {
    if (typeof definitions !== "object" || Array.isArray(definitions) || definitions === null) {
      return err("definitions must be an object");
    }
    for (const key of Object.keys(definitions)) {
      const result = isSchema(
        definitions[key],
        path.concat("definitions", key)
      );
      if (result.type === "error") {
        return result;
      }
    }
  }
  if (nullable !== void 0) {
    if (typeof nullable !== "boolean") {
      return err("nullable must be a boolean");
    }
  }
  if (metadata !== void 0) {
    if (typeof metadata !== "object" || Array.isArray(metadata) || metadata === null) {
      return err("metadata must be an object");
    }
  }
  if (ref !== void 0) {
    if (typeof ref !== "string") {
      return err("ref must be a string");
    }
  }
  if (type !== void 0) {
    if (typeof type !== "string" || !VALID_TYPES.includes(type)) {
      return err("type must be a string and one of the valid types");
    }
  }
  if (enum_ !== void 0) {
    if (!Array.isArray(enum_)) {
      return err("enum must be an array");
    }
    if (!enum_.every((elem) => typeof elem === "string")) {
      return err("enum must be an array of strings");
    }
  }
  if (elements !== void 0) {
    const result = isSchema(elements, path.concat("elements"));
    if (result.type === "error") {
      return result;
    }
  }
  if (properties !== void 0) {
    if (typeof properties !== "object" || Array.isArray(properties) || properties === null) {
      return err("properties must be an object");
    }
    for (const key of Object.keys(properties)) {
      const result = isSchema(
        properties[key],
        path.concat("properties", key)
      );
      if (result.type === "error") {
        return result;
      }
    }
  }
  if (optionalProperties !== void 0) {
    if (typeof optionalProperties !== "object" || Array.isArray(optionalProperties) || optionalProperties === null) {
      return err("optionalProperties must be an object");
    }
    for (const key of Object.keys(optionalProperties)) {
      const result = isSchema(
        optionalProperties[key],
        path.concat("optionalProperties", key)
      );
      if (result.type === "error") {
        return result;
      }
    }
  }
  if (additionalProperties !== void 0) {
    if (typeof additionalProperties !== "boolean") {
      return err("additionalProperties must be a boolean");
    }
  }
  if (values !== void 0) {
    const result = isSchema(values, path.concat("values"));
    if (result.type === "error") {
      return result;
    }
  }
  if (discriminator !== void 0) {
    if (typeof discriminator !== "string") {
      return err("discriminator must be a string");
    }
  }
  if (mapping !== void 0) {
    if (typeof mapping !== "object" || Array.isArray(mapping) || mapping === null) {
      return err("mapping must be an object");
    }
    for (const key of Object.keys(mapping)) {
      const result = isSchema(mapping[key], path.concat("mapping", key));
      if (result.type === "error") {
        return result;
      }
    }
  }
  if (Object.keys(rest).length !== 0) {
    return err("schema has unknown properties");
  }
  return ok();
}
//# sourceMappingURL=schema.js.map
