import { throwInvalidType, assertObject } from "./asserts.js";
import { isProd } from "./config.js";
import { hasOwn } from "./has-own.js";
function deepEqual(a, b) {
  if (a === b) {
    return true;
  }
  if (typeof a !== typeof b) {
    return false;
  }
  switch (typeof a) {
    case "boolean":
    case "number":
    case "string":
      return false;
  }
  a = a;
  if (Array.isArray(a)) {
    if (!Array.isArray(b)) {
      return false;
    }
    if (a.length !== b.length) {
      return false;
    }
    for (let i = 0; i < a.length; i++) {
      if (!deepEqual(a[i], b[i])) {
        return false;
      }
    }
    return true;
  }
  if (a === null || b === null) {
    return false;
  }
  if (Array.isArray(b)) {
    return false;
  }
  a = a;
  b = b;
  let aSize = 0;
  for (const key in a) {
    if (hasOwn(a, key)) {
      if (!deepEqual(a[key], b[key])) {
        return false;
      }
      aSize++;
    }
  }
  let bSize = 0;
  for (const key in b) {
    if (hasOwn(b, key)) {
      bSize++;
    }
  }
  return aSize === bSize;
}
function assertJSONValue(v) {
  if (isProd) {
    return;
  }
  switch (typeof v) {
    case "boolean":
    case "number":
    case "string":
      return;
    case "object":
      if (v === null) {
        return;
      }
      if (Array.isArray(v)) {
        return assertJSONArray(v);
      }
      return assertObjectIsJSONObject(v);
  }
  throwInvalidType(v, "JSON value");
}
function assertJSONObject(v) {
  assertObject(v);
  assertObjectIsJSONObject(v);
}
function assertObjectIsJSONObject(v) {
  for (const k in v) {
    if (hasOwn(v, k)) {
      const value = v[k];
      if (value !== void 0) {
        assertJSONValue(value);
      }
    }
  }
}
function assertJSONArray(v) {
  for (const item of v) {
    assertJSONValue(item);
  }
}
function isJSONValue(v, path) {
  switch (typeof v) {
    case "boolean":
    case "number":
    case "string":
      return true;
    case "object":
      if (v === null) {
        return true;
      }
      if (Array.isArray(v)) {
        return isJSONArray(v, path);
      }
      return objectIsJSONObject(v, path);
  }
  return false;
}
function isJSONObject(v, path) {
  if (typeof v !== "object" || v === null) {
    return false;
  }
  return objectIsJSONObject(v, path);
}
function objectIsJSONObject(v, path) {
  for (const k in v) {
    if (hasOwn(v, k)) {
      path.push(k);
      const value = v[k];
      if (value !== void 0 && !isJSONValue(value, path)) {
        return false;
      }
      path.pop();
    }
  }
  return true;
}
function isJSONArray(v, path) {
  for (let i = 0; i < v.length; i++) {
    path.push(i);
    if (!isJSONValue(v[i], path)) {
      return false;
    }
    path.pop();
  }
  return true;
}
export {
  assertJSONObject,
  assertJSONValue,
  deepEqual,
  isJSONObject,
  isJSONValue
};
//# sourceMappingURL=json.js.map
