| 2929 | const identifierRegex = /^[A-Za-z_$][A-Za-z0-9_$]*$/; |
| 2930 | |
| 2931 | const serialize = (value: unknown): string => { |
| 2932 | if (typeof value === "bigint") return `${value as any}n`; |
| 2933 | if (typeof value === "function") |
| 2934 | return value.name ? `[Function: ${value.name}]` : "[Function (anonymous)]"; |
| 2935 | if (typeof value === "symbol") return value.toString(); |
| 2936 | if (value === undefined) return "undefined"; |
| 2937 | if (value === null) return "null"; |
| 2938 | |
| 2939 | if (typeof value === "object") { |
| 2940 | if (seen.has(value)) return "[Circular]"; |
| 2941 | seen.add(value); |
| 2942 | |
| 2943 | // Handle special object types |
| 2944 | if (value instanceof Date) return value.toISOString(); |
| 2945 | |
| 2946 | if (value instanceof RegExp) return value.toString(); |
| 2947 | |
| 2948 | if (value instanceof Map) { |
| 2949 | const entries = Array.from(value.entries()) |
| 2950 | .map(([k, v]) => `${serialize(k)} => ${serialize(v)}`) |
| 2951 | .join(", "); |
| 2952 | return `Map(${value.size}) ` + (entries ? `{ ${entries} }` : "{}"); |
| 2953 | } |
| 2954 | |
| 2955 | if (value instanceof Set) { |
| 2956 | const values = Array.from(value) |
| 2957 | .map((v) => serialize(v)) |
| 2958 | .join(", "); |
| 2959 | return `Set(${value.size}) ` + (values ? `{ ${values} }` : "{}"); |
| 2960 | } |
| 2961 | |
| 2962 | // Handle arrays and objects |
| 2963 | const isClassInstance = |
| 2964 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 2965 | value.constructor && value.constructor.name && value.constructor.name !== "Object"; |
| 2966 | const className = isClassInstance ? value.constructor.name : ""; |
| 2967 | |
| 2968 | if (Array.isArray(value)) { |
| 2969 | const arrayItems = value.map((item) => serialize(item)).join(", "); |
| 2970 | let result = `[${arrayItems}]`; |
| 2971 | if (className !== "Array") result = `${className}(${value.length}) ${result}`; |
| 2972 | return result; |
| 2973 | } |
| 2974 | |
| 2975 | const objectEntries = Reflect.ownKeys(value) |
| 2976 | .map((key) => { |
| 2977 | const keyDisplay = |
| 2978 | typeof key === "symbol" ? `[${key.toString()}]` |
| 2979 | : identifierRegex.test(key) ? key |
| 2980 | : JSON.stringify(key); |
| 2981 | const val = (value as Record<string, unknown>)[key as any]; |
| 2982 | return `${keyDisplay}: ${serialize(val)}`; |
| 2983 | }) |
| 2984 | .join(", "); |
| 2985 | |
| 2986 | return (className ? `${className} ` : "") + (objectEntries ? `{ ${objectEntries} }` : "{}"); |
| 2987 | } |
| 2988 | |