import { cloneDeep, isArray, isString, isPlainObject, forOwn } from "lodash-es";
export function isClassConstructor(arg) {
  return typeof arg === "function" && /^class\s/.test(arg.toString());
}
export function onlyClassAttributes(cls, object) {
  return onlyAttributes(classAttributes(cls), object);
}
export function classAttributes(cls) {
  return Object.keys(new cls());
}
export function onlyAttributes(keys, object) {
  const returnObject = cloneDeep(object);
  Object.keys(object).forEach((localKey) => {
    if (!keys.includes(localKey)) delete returnObject[localKey];
  });
  return returnObject;
}
export function renameAttributes(object, mapper) {
  const returnObject = cloneDeep(object);
  Object.keys(mapper).forEach((key) => {
    if (returnObject.hasOwnProperty(key)) {
      returnObject[mapper[key]] = cloneDeep(returnObject[key]);
      delete returnObject[key];
    }
  });
  return returnObject;
}
export function stableStringify(obj) {
  const seen = /* @__PURE__ */ new WeakSet();
  const inner = (value) => {
    if (value === null) return "null";
    if (typeof value === "number") return isFinite(value) ? String(value) : "null";
    if (typeof value === "boolean") return String(value);
    if (typeof value === "string") return JSON.stringify(value);
    if (typeof value === "function" || typeof value === "undefined") return "null";
    if (Array.isArray(value)) {
      return `[${value.map((v) => inner(v)).join(",")}]`;
    }
    if (typeof value === "object") {
      if (seen.has(value)) throw new TypeError("Converting circular structure to JSON");
      seen.add(value);
      const keys = Object.keys(value).sort();
      const props = keys.map((key) => {
        const val = inner(value[key]);
        return `"${key}":${val}`;
      });
      return `{${props.join(",")}}`;
    }
    return "null";
  };
  return inner(obj);
}
export function safeParseJSONDeep(input, childKeys = ["children"], keysToParse) {
  const shouldParseKey = !keysToParse || keysToParse.length === 0 ? () => true : (k) => keysToParse.includes(k);
  const looksLikeJSON = (s) => {
    const t = s.trim();
    if (t.length === 0) return false;
    const c = t[0];
    return c === "{" || c === "[" || c === '"' || c === "-" || c >= "0" && c <= "9" || t.startsWith("true") || t.startsWith("false") || t.startsWith("null");
  };
  const tryParse = (s) => {
    try {
      return JSON.parse(s);
    } catch {
      return s;
    }
  };
  const walk = (node) => {
    if (isString(node)) {
      return looksLikeJSON(node) ? tryParse(node) : node;
    }
    if (isArray(node)) {
      return node.map(walk);
    }
    if (isPlainObject(node)) {
      const out = {};
      forOwn(node, (val, key) => {
        if (isString(val) && shouldParseKey(key)) {
          const parsed = looksLikeJSON(val) ? tryParse(val) : val;
          out[key] = walk(parsed);
        } else if (isArray(val) || isPlainObject(val)) {
          out[key] = walk(val);
        } else {
          out[key] = val;
        }
      });
      childKeys.forEach((ck) => {
        if (isArray(out[ck])) {
          out[ck] = out[ck].map(walk);
        }
      });
      return out;
    }
    return node;
  };
  return walk(cloneDeep(input));
}
