UNPKG

@zag-js/json-tree-utils

Version:

Utilities for building json tree data

1,491 lines (1,485 loc) 47.3 kB
// src/json-to-tree.ts var MAX_DEPTH = 20; var jsonToTree = (data, props = {}) => { const { visited = /* @__PURE__ */ new WeakSet(), keyPath = [ROOT_KEY], depth = 0 } = props; const options = getPreviewOptions(props.options); if (depth > MAX_DEPTH) { return { value: "[Max Depth Reached]", type: "string", keyPath }; } if (data && typeof data === "object") { if (visited.has(data)) { return { value: "[Circular Reference]", type: "circular", keyPath }; } visited.add(data); } const dataType2 = dataTypes.find((dataType3) => dataType3.check(data)) || PrimitiveType; return dataType2.node({ value: data, createNode: (nestedKeyPath, value) => jsonToTree(value, { visited, keyPath: [...keyPath, ...nestedKeyPath], options, depth: depth + 1 }), keyPath, options }); }; // src/shared.ts var regexReturnCharacters = /\r/g; function hash(str) { const v = str.replace(regexReturnCharacters, ""); let hash2 = 5381; let i = v.length; while (i--) hash2 = (hash2 << 5) - hash2 ^ v.charCodeAt(i); return (hash2 >>> 0).toString(36); } function getProp(value, key) { return value[key]; } function defu(a, b) { const res = { ...a }; for (const key in b) { if (b[key] !== void 0) res[key] = b[key]; } return res; } var isObj = (v) => v != null && typeof v === "object" && !Array.isArray(v); var typeOf = (value) => Object.prototype.toString.call(value); // src/node-conversion.ts var ROOT_KEY = "$"; var PATH_SEP = "."; function isRootKeyPath(keyPath) { return keyPath.length === 1 && keyPath[0] === ROOT_KEY; } function keyPathToId(keyPath) { return keyPath.join(PATH_SEP); } function keyPathToKey(keyPath, opts) { if (keyPath.length === 0) return ""; if (opts?.excludeRoot && isRootKeyPath(keyPath)) return ""; return String(keyPath[keyPath.length - 1]); } function nodeToValue(node) { return hash(keyPathToId(node.keyPath)); } function jsonPathToValue(path) { return hash(path); } function nodeToString(node) { return keyPathToKey(node.keyPath) || "root"; } function getRootNode(data, opts) { return { value: "", type: "object", keyPath: [], children: [ jsonToTree(data, { visited: /* @__PURE__ */ new WeakSet(), keyPath: [ROOT_KEY], options: getPreviewOptions(opts) }) ] }; } var DEFAULT_PREVIEW_OPTIONS = { maxPreviewItems: 3, collapseStringsAfterLength: 30, groupArraysAfterLength: 100, showNonenumerable: true }; var getPreviewOptions = (opts) => { if (!opts) return DEFAULT_PREVIEW_OPTIONS; return defu(DEFAULT_PREVIEW_OPTIONS, opts); }; // src/data-type.ts var generatePreviewText = (items, hasMore) => { return ` ${items.join(", ")}${hasMore ? ", \u2026 " : " "}`; }; var ENTRIES_KEY = "[[Entries]]"; var txt = (value) => ({ type: "text", value }); var jsx = (tagName, properties = {}, children = []) => ({ type: "element", tagName, properties, children }); var formatValueMini = (child) => { if (child.type === "string") return `"${child.value}"`; if (child.type === "null") return "null"; if (child.type === "undefined" || child.type === "symbol") return "undefined"; if (child.type === "object") return "{\u2026}"; if (child.type === "array") return "[\u2026]"; if (child.type === "set") return "Set(\u2026)"; if (child.type === "map") return "Map(\u2026)"; if (child.type === "iterable") return "Iterable(\u2026)"; if (child.type === "function") return "\u0192(\u2026)"; return String(child.value); }; var formatValue = (value) => { if (value === null) return "null"; if (value === void 0) return "undefined"; if (typeof value === "string") return `"${value}"`; if (typeof value === "number" || typeof value === "boolean") return String(value); if (value instanceof Date) return value.toISOString(); if (value instanceof Set) return `Set(${value.size})`; if (value instanceof Map) return `Map(${value.size})`; if (Array.isArray(value)) return `Array(${value.length})`; if (typeof value === "object") return "Object"; return String(value); }; function dataType(opts) { return opts; } var NullType = dataType({ type: "null", description: "null", check(value) { return value === null; }, previewElement() { return jsx("span", {}, [txt("null")]); }, node({ value, keyPath }) { return { value, type: "null", keyPath }; } }); var UndefinedType = dataType({ type: "undefined", description: "undefined", check(value) { return value === void 0; }, previewElement() { return jsx("span", {}, [txt("undefined")]); }, node({ value, keyPath }) { return { type: "undefined", value, keyPath }; } }); var SymbolType = dataType({ type: "symbol", description(node) { return String(node.value); }, check(value) { return typeof value === "symbol"; }, previewElement(node) { return jsx("span", {}, [txt(node.value.toString())]); }, node({ value, keyPath }) { return { type: "symbol", value, keyPath }; } }); var BigIntType = dataType({ type: "bigint", description(node) { return `${node.value}n`; }, check(value) { return typeof value === "bigint"; }, previewElement(node) { return jsx("span", {}, [txt(`${node.value}n`)]); }, node({ value, keyPath }) { return { type: "bigint", value, keyPath }; } }); var SetType = dataType({ type: "set", description(node) { return `Set(${node.value.size})`; }, check(value) { return value instanceof Set; }, previewText(node, opts) { const maxItems = opts.maxPreviewItems; const entries = Array.from(node.value); const values = entries.slice(0, maxItems).map(formatValue); const hasMore = entries.length > maxItems; return generatePreviewText(values, hasMore); }, previewElement(node, opts) { const preview = this.previewText?.(node, opts) ?? ""; const size = node.value.size; const children = [ jsx("span", { kind: "constructor" }, [txt(`Set(${size})`)]), jsx("span", { kind: "brace" }, [txt(" {")]) ]; if (preview) { children.push(jsx("span", { kind: "preview-text" }, [txt(preview)])); } children.push(jsx("span", { kind: "brace" }, [txt("}")])); return jsx("span", {}, children); }, node({ value, keyPath, createNode }) { const entriesChildren = Array.from(value).map((item, index) => createNode([ENTRIES_KEY, index.toString()], item)); const entriesNode = { value: Array.from(value), keyPath: [...keyPath, ENTRIES_KEY], type: "array", children: entriesChildren, isNonEnumerable: true }; const sizeNode = createNode(["size"], value.size); return { type: "set", value, keyPath, children: [entriesNode, sizeNode] }; } }); var WeakSetType = dataType({ type: "weakset", description: "WeakSet", check(value) { return value instanceof WeakSet; }, previewElement() { return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("WeakSet")]), jsx("span", { kind: "brace" }, [txt(" {")]), jsx("span", { kind: "preview" }, [txt(" [[Entries]]: not enumerable ")]), jsx("span", { kind: "brace" }, [txt("}")]) ]); }, node({ value, keyPath }) { return { type: "weakset", value, keyPath }; } }); var WeakMapType = dataType({ type: "weakmap", description: "WeakMap", check(value) { return value instanceof WeakMap; }, previewElement() { return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("WeakMap")]), jsx("span", { kind: "brace" }, [txt(" {")]), jsx("span", { kind: "preview" }, [txt(" [[Entries]]: not enumerable ")]), jsx("span", { kind: "brace" }, [txt("}")]) ]); }, node({ value, keyPath }) { return { type: "weakmap", value, keyPath }; } }); var REGEX_KEYS = [ "lastIndex", "dotAll", "flags", "global", "hasIndices", "ignoreCase", "multiline", "source", "sticky", "unicode" ]; var RegexType = dataType({ type: "regex", description(node) { return String(node.value); }, check(value) { return value instanceof RegExp; }, previewElement(node) { return jsx("span", {}, [txt(String(node.value))]); }, node({ value, keyPath, createNode }) { const children = REGEX_KEYS.map((key) => createNode([key], getProp(value, key))); return { value, type: "regex", keyPath, children }; } }); var DATA_VIEW_KEYS = ["byteLength", "byteOffset", "buffer"]; var DataViewType = dataType({ type: "dataview", description(node) { return `DataView(${node.value.byteLength})`; }, check(value) { return value instanceof DataView; }, previewElement(node) { const dataView = node.value; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(`DataView(${dataView.byteLength})`)]), jsx("span", { kind: "brace" }, [txt(" { ")]), jsx("span", { kind: "preview" }, [ txt(` buffer: ArrayBuffer(${dataView.buffer.byteLength}), byteOffset: ${dataView.byteOffset} `) ]), jsx("span", { kind: "brace" }, [txt(" }")]) ]); }, node({ value, keyPath, createNode }) { const children = DATA_VIEW_KEYS.map((key) => createNode([key], getProp(value, key))); return { value, keyPath, type: "dataview", children }; } }); var URL_KEYS = [ "href", "origin", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search", "searchParams", "hash" ]; var UrlType = dataType({ type: "url", description: "URL", check(value) { return typeOf(value) === "[object URL]"; }, previewElement(node, opts) { const url = node.value; const maxItems = opts.maxPreviewItems; const previewKeys = URL_KEYS.slice(0, maxItems); const preview = previewKeys.map((key) => `${key}: '${url[key]}'`).join(", "); const hasMore = URL_KEYS.length > maxItems; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("URL")]), jsx("span", { kind: "brace" }, [txt(" { ")]), jsx("span", { kind: "preview-text" }, [txt(` ${preview}${hasMore ? ", \u2026" : ""} `)]), jsx("span", { kind: "brace" }, [txt(" }")]) ]); }, node({ value, keyPath, createNode }) { const children = URL_KEYS.map((key) => createNode([key], Reflect.get(value, key))); return { value, keyPath, type: "url", children }; } }); var URLSearchParamsType = dataType({ type: "urlsearchparams", description: "URLSearchParams", check(value) { return typeOf(value) === "[object URLSearchParams]"; }, previewElement(node) { const params = node.value; const paramsArray = Array.from(params.entries()); return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("URLSearchParams")]), jsx("span", { kind: "brace" }, [txt(" { ")]), jsx("span", { kind: "preview" }, [txt(`size: ${paramsArray.length}`)]), jsx("span", { kind: "brace" }, [txt(" }")]) ]); }, node({ value, keyPath, createNode }) { const entriesChildren = Array.from(value.entries()).map(([key, value2], index) => { const keyStr = String(key); const keyNode = createNode([ENTRIES_KEY, keyStr, "key"], key); const valueNode = createNode([ENTRIES_KEY, keyStr, "value"], value2); return { keyPath: [...keyPath, ENTRIES_KEY, index], value: { [key]: value2 }, type: "object", children: [keyNode, valueNode] }; }); const entriesNode = { keyPath: [...keyPath, "[[Entries]]"], value: Array.from(value.entries()), type: "array", children: entriesChildren, isNonEnumerable: true }; const sizeNode = createNode(["size"], Array.from(value.entries()).length); return { value, keyPath, type: "urlsearchparams", children: [entriesNode, sizeNode] }; } }); var BLOB_KEYS = ["size", "type"]; var BlobType = dataType({ type: "blob", description(node) { return `Blob(${node.value.size})`; }, check(value) { return typeOf(value) === "[object Blob]"; }, previewElement(node) { const blob = node.value; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("Blob")]), jsx("span", { kind: "brace" }, [txt(" { ")]), jsx("span", { kind: "preview" }, [txt(`size: ${blob.size}, type: '${blob.type || "application/octet-stream"}'`)]), jsx("span", { kind: "brace" }, [txt(" }")]) ]); }, node({ value, keyPath, createNode }) { const blobProperties = BLOB_KEYS.map((key) => ({ key, value: Reflect.get(value, key) })); const children = blobProperties.map(({ key, value: value2 }) => createNode([key], value2)); return { value, keyPath, type: "blob", children }; } }); var FILE_KEYS = ["name", "size", "type", "lastModified", "webkitRelativePath"]; var FileType = dataType({ type: "file", description(node) { return `File(${node.value.size})`; }, check(value) { return typeOf(value) === "[object File]"; }, previewElement(node) { const file = node.value; const maxItems = 2; const hasMore = FILE_KEYS.length > maxItems; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("File")]), jsx("span", { kind: "brace" }, [txt(" { ")]), jsx("span", { kind: "preview" }, [ txt(`name: '${file.name}', lastModified: ${file.lastModified}${hasMore ? ", \u2026" : ""}`) ]), jsx("span", { kind: "brace" }, [txt(" }")]) ]); }, node({ value, keyPath, createNode }) { const fileProperties = FILE_KEYS.map((key) => ({ key, value: getProp(value, key) || "" })); const children = fileProperties.map(({ key, value: value2 }) => createNode([key], value2)); return { value, keyPath, type: "file", children }; } }); var getFunctionString = (func) => { try { return func.toString(); } catch { switch (func.constructor.name) { case "AsyncFunction": return "async function () {}"; case "AsyncGeneratorFunction": return "async function * () {}"; case "GeneratorFunction": return "function * () {}"; default: return "function () {}"; } } }; var FUNCTION_SIGNATURE_REGEX = /(?:async\s+)?(?:function\s*\*?\s*)?([^(]*\([^)]*\))/; var getFunctionSignature = (func) => { const funcString = getFunctionString(func); const signatureMatch = funcString.match(FUNCTION_SIGNATURE_REGEX); return signatureMatch ? signatureMatch[1] : `${func.name || "anonymous"}()`; }; var FUNC_KEYS = ["name", "length", "prototype", "caller", "arguments"]; var FunctionType = dataType({ type: "function", description(node) { const func = node.value; const name = func.name || "anonymous"; const constructorName = func.constructor.name; switch (constructorName) { case "AsyncFunction": return `async \u0192 ${name}()`; case "AsyncGeneratorFunction": return `async \u0192* ${name}()`; case "GeneratorFunction": return `\u0192* ${name}()`; default: return `\u0192 ${name}()`; } }, check(value) { return typeof value === "function"; }, previewElement(node) { const func = node.value; const signature = getFunctionSignature(func); const constructorName = func.constructor.name; const preview = signature.length > 50 ? `${signature.substring(0, 47)}...` : signature; let functionTypePrefix = ""; if (constructorName === "AsyncFunction") functionTypePrefix += "async "; if (constructorName === "AsyncGeneratorFunction") functionTypePrefix += "async "; if (constructorName === "GeneratorFunction" || constructorName === "AsyncGeneratorFunction") functionTypePrefix += "\u0192* "; if (!constructorName.includes("Generator")) functionTypePrefix += "\u0192 "; return jsx("span", {}, [ jsx("span", { kind: "function-type" }, [txt(functionTypePrefix)]), jsx("span", { kind: "function-body" }, [txt(preview)]) ]); }, node({ value, keyPath, createNode, options }) { const funcName = value.name || "anonymous"; const constructorName = value.constructor.name; const enumerableProperties = []; const nonEnumerableProperties = []; const funcString = getFunctionString(value); nonEnumerableProperties.push({ key: "[[Function]]", value: funcString }); enumerableProperties.push({ key: "name", value: funcName }); enumerableProperties.push({ key: "length", value: value.length }); enumerableProperties.push({ key: "constructor", value: constructorName }); const additionalProps = Object.getOwnPropertyNames(value).filter((key) => !FUNC_KEYS.includes(key)).map((key) => ({ key, value: Reflect.get(value, key) })); enumerableProperties.push(...additionalProps); const enumerableChildren = enumerableProperties.map(({ key, value: value2 }) => createNode([key], value2)); const nonEnumerableChildren = options?.showNonenumerable ? nonEnumerableProperties.map(({ key, value: value2 }) => { const node = createNode([key], value2); node.isNonEnumerable = true; return node; }) : []; const children = [...enumerableChildren, ...nonEnumerableChildren]; return { value, type: "function", keyPath, children }; } }); var ArrayBufferType = dataType({ type: "arraybuffer", description(node) { return `ArrayBuffer(${node.value.byteLength})`; }, check(value) { return value instanceof ArrayBuffer; }, previewElement(node) { return jsx("span", { nodeType: "arraybuffer" }, [txt(node.value.toString())]); }, node({ value, keyPath }) { return { value, keyPath, type: "arraybuffer" }; } }); var SharedArrayBufferType = dataType({ type: "sharedarraybuffer", description(node) { return `SharedArrayBuffer(${node.value.byteLength})`; }, check(value) { return typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer; }, previewElement() { return jsx("span", { nodeType: "sharedarraybuffer" }, [txt("sharedarraybuffer")]); }, node({ value, keyPath }) { return { value, keyPath, type: "sharedarraybuffer" }; } }); var BufferType = dataType({ type: "buffer", description(node) { return `Buffer(${node.value.length})`; }, check(value) { return typeof Buffer !== "undefined" && value instanceof Buffer; }, previewElement(node) { const buffer = node.value; const preview = Array.from(new Uint8Array(buffer).slice(0, 8)).map((byte) => byte.toString(16).padStart(2, "0")).join(" "); const hasMore = buffer.length > 8; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(`Buffer(${buffer.length})`)]), jsx("span", { kind: "brace" }, [txt(" ['")]), jsx("span", { kind: "preview-text" }, [txt(preview + (hasMore ? " \u2026" : ""))]), jsx("span", { kind: "brace" }, [txt("']")]) ]); }, node({ value, keyPath }) { return { value, keyPath, type: "buffer" }; } }); var DateType = dataType({ type: "date", description(node) { return String(node.value); }, check(value) { return value instanceof Date; }, previewElement(node) { return jsx("span", {}, [txt(node.value.toISOString())]); }, node({ value, keyPath }) { return { value, keyPath, type: "date" }; } }); var MapType = dataType({ type: "map", description(node) { return `Map(${node.value.size})`; }, check(value) { return value instanceof Map; }, previewText(node, opts) { const maxItems = opts.maxPreviewItems; const entries = Array.from(node.value.entries()); const previews = entries.slice(0, maxItems).map(([key, value]) => { const valueDesc = formatValue(value); const keyStr = typeof key === "string" ? `"${key}"` : String(key); return `${keyStr} => ${valueDesc}`; }); const hasMore = entries.length > maxItems; return generatePreviewText(previews, hasMore); }, previewElement(node, opts) { const preview = this.previewText?.(node, opts) || ""; const size = node.value.size; const children = [ jsx("span", { kind: "constructor" }, [txt(`Map(${size})`)]), jsx("span", { kind: "brace" }, [txt(" {")]) ]; if (preview) { children.push(jsx("span", { kind: "preview-text" }, [txt(preview)])); } children.push(jsx("span", { kind: "brace" }, [txt("}")])); return jsx("span", {}, children); }, node({ value, keyPath, createNode }) { const entriesChildren = Array.from(value.entries()).map(([key, value2], index) => { const keyStr = String(key); const keyNode = createNode([ENTRIES_KEY, keyStr, "key"], key); const valueNode = createNode([ENTRIES_KEY, keyStr, "value"], value2); return { keyPath: [...keyPath, ENTRIES_KEY, index], value: { [keyStr]: value2 }, type: "object", children: [keyNode, valueNode] }; }); const entriesNode = { keyPath: [...keyPath, ENTRIES_KEY], value: Array.from(value.entries()), type: "array", children: entriesChildren, isNonEnumerable: true }; const sizeNode = createNode(["size"], value.size); return { value, keyPath, type: "map", children: [entriesNode, sizeNode] }; } }); var ERROR_KEYS = ["name", "message", "stack"]; var ErrorType = dataType({ type: "error", description(node) { const err = node.value; return `${err.name}: ${err.message}`; }, check(value) { return value instanceof Error; }, previewElement(node) { const err = node.value; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(err.name)]), jsx("span", { kind: "colon" }, [txt(": ")]), jsx("span", {}, [txt(err.message)]) ]); }, node({ value, keyPath, createNode }) { const errorProperties = ERROR_KEYS.map((key) => ({ key, value: Reflect.get(value, key) })); const additionalProps = Object.getOwnPropertyNames(value).filter((key) => !ERROR_KEYS.includes(key)).map((key) => ({ key, value: getProp(value, key) })); const allProperties = [...errorProperties, ...additionalProps]; const children = allProperties.map(({ key, value: value2 }) => createNode([key], value2)); return { value, keyPath, type: "error", children }; } }); function errorStackToElement(stack) { const stackLines = stack?.split("\n").filter((line) => line.trim()) || []; return jsx( "span", {}, stackLines.map((line, index) => { const appendNewLine = index < stackLines.length - 1; return jsx( "span", { nodeType: "string", kind: "error-stack" }, [ jsx("span", {}, [txt(line + (appendNewLine ? "\\n" : ""))]), jsx("span", { kind: "operator" }, [txt(appendNewLine ? " +" : "")]) ] ); }) ); } var HeadersType = dataType({ type: "headers", description: "Headers", check(value) { return typeOf(value) === "[object Headers]"; }, previewElement(node) { const headers = node.value; const entriesArray = Array.from(headers.entries()); const preview = entriesArray.slice(0, 2).map(([key, value]) => `${key}: ${value}`).join(", "); const hasMore = entriesArray.length > 2; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(`Headers(${entriesArray.length})`)]), jsx("span", { kind: "brace" }, [txt(" {")]), jsx("span", { kind: "preview-text" }, [txt(` ${preview}${hasMore ? ", \u2026" : ""} `)]), jsx("span", { kind: "brace" }, [txt("}")]) ]); }, node({ value, keyPath, createNode }) { const entriesChildren = Array.from(value.entries()).map(([key, value2], index) => { const keyStr = String(key); const keyNode = createNode([ENTRIES_KEY, keyStr, "key"], key); const valueNode = createNode([ENTRIES_KEY, keyStr, "value"], value2); return { keyPath: [...keyPath, ENTRIES_KEY, index], value: { [key]: value2 }, type: "object", children: [keyNode, valueNode] }; }); const entriesNode = { keyPath: [...keyPath, ENTRIES_KEY], value: Array.from(value.entries()), type: "array", children: entriesChildren, isNonEnumerable: true }; return { value, keyPath, type: "headers", children: [entriesNode] }; } }); var FormDataType = dataType({ type: "formdata", description: "FormData", check(value) { return typeOf(value) === "[object FormData]"; }, previewElement(node) { const formData = node.value; const entriesArray = Array.from(formData.entries()); const preview = entriesArray.slice(0, 2).map(([key, value]) => { const valueStr = FileType.check(value) ? `File(${value.size})` : String(value); return `${key}: ${valueStr}`; }).join(", "); const hasMore = entriesArray.length > 2; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(`FormData(${entriesArray.length})`)]), jsx("span", { kind: "brace" }, [txt(" {")]), jsx("span", { kind: "preview-text" }, [txt(` ${preview}${hasMore ? ", \u2026" : ""} `)]), jsx("span", { kind: "brace" }, [txt("}")]) ]); }, node({ value, keyPath, createNode }) { const entriesChildren = Array.from(value.entries()).map(([key, value2], index) => { const keyNode = createNode([ENTRIES_KEY, index, "key"], key); const valueNode = createNode([ENTRIES_KEY, index, "value"], value2); return { keyPath: [...keyPath, ENTRIES_KEY, index], value: { [key]: value2 }, type: "object", children: [keyNode, valueNode] }; }); const entriesNode = { keyPath: [...keyPath, ENTRIES_KEY], value: Array.from(value.entries()), type: "array", children: entriesChildren, isNonEnumerable: true }; return { value, keyPath, type: "formdata", children: [entriesNode] }; } }); var ArrayType = dataType({ type: "array", description(node) { return `Array(${node.value.length})`; }, check(value) { return Array.isArray(value); }, previewText(node, opts) { const maxItems = opts.maxPreviewItems; const children = node.children || []; const enumerableChildren = children.filter( (child) => !child.isNonEnumerable && keyPathToKey(child.keyPath) !== "length" ); const values = enumerableChildren.slice(0, maxItems).map(formatValueMini); const hasMore = enumerableChildren.length > maxItems; return generatePreviewText(values, hasMore); }, previewElement(node, opts) { const preview = this.previewText?.(node, opts) || ""; const count = node.value.length; const children = []; if (count > 0) { children.push(jsx("span", { kind: "constructor" }, [txt(`(${count}) `)])); } children.push(jsx("span", { kind: "brace" }, [txt("[")])); if (preview) { children.push(jsx("span", { kind: "preview-text" }, [txt(preview)])); } children.push(jsx("span", { kind: "brace" }, [txt("]")])); return jsx("span", {}, children); }, node({ value, keyPath, createNode, options }) { const arrayChildren = []; const definedIndices = Object.keys(value).filter((key) => !Number.isNaN(Number(key))).map(Number).sort((a, b) => a - b); const chunkSize = options?.groupArraysAfterLength; const shouldGroup = chunkSize && definedIndices.length > chunkSize; if (shouldGroup) { const chunks = []; for (let i = 0; i < definedIndices.length; i += chunkSize) { chunks.push(definedIndices.slice(i, i + chunkSize)); } for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) { const chunk = chunks[chunkIndex]; const startIndex = chunk[0]; const endIndex = chunk[chunk.length - 1]; const groupKey = `[${startIndex}\u2026${endIndex}]`; const groupChildren = chunk.map((index) => createNode([index.toString()], value[index])); const groupNode = { keyPath: [...keyPath, groupKey], value: chunk.map((index) => value[index]), type: "array", children: groupChildren, isNonEnumerable: false }; arrayChildren.push(groupNode); } } else { for (const index of definedIndices) { arrayChildren.push(createNode([index.toString()], value[index])); } } const lengthChild = createNode(["length"], value.length); const propertyNames = Object.getOwnPropertyNames(value); const enumerableKeys = Object.keys(value).filter((key) => !Number.isNaN(Number(key))); const nonEnumerableKeys = propertyNames.filter( (key) => !enumerableKeys.includes(key) && key !== "length" && // length is already handled above Number.isNaN(Number(key)) // exclude numeric indices ); const nonEnumerableChildren = options?.showNonenumerable ? nonEnumerableKeys.map((key) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); const node = createNode([key], Reflect.get(value, key)); node.isNonEnumerable = true; node.propertyDescriptor = descriptor; return node; }) : []; const children = [...arrayChildren, lengthChild, ...nonEnumerableChildren]; return { value, type: "array", children, keyPath }; } }); var typedArrayConstructors = { Int8Array: "int8array", Uint8Array: "uint8array", Uint8ClampedArray: "uint8clampedarray", Int16Array: "int16array", Uint16Array: "uint16array", Int32Array: "int32array", Uint32Array: "uint32array", Float32Array: "float32array", Float64Array: "float64array", BigInt64Array: "bigint64array", BigUint64Array: "biguint64array" }; var revertTypedArrayConstructors = Object.fromEntries( Object.entries(typedArrayConstructors).map(([key, value]) => [value, key]) ); var TYPED_ARRAY_KEYS = ["length", "byteLength", "byteOffset", "buffer"]; var TypedArrayType = dataType({ type: (value) => Reflect.get(typedArrayConstructors, value.constructor.name), description(node) { const typedArray = node.value; const constructorName = typedArray.constructor.name; return `${revertTypedArrayConstructors[constructorName]}(${typedArray.length})`; }, check(value) { return isObj(value) && value.constructor.name in typedArrayConstructors; }, previewElement(node) { const typedArray = node.value; const constructorName = typedArray.constructor.name; const preview = Array.from(typedArray).slice(0, 5).join(", "); const hasMore = typedArray.length > 5; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(`${constructorName}(${typedArray.length})`)]), jsx("span", { kind: "brace" }, [txt(" [ ")]), jsx("span", { kind: "preview-text" }, [txt(preview + (hasMore ? ", \u2026" : ""))]), jsx("span", { kind: "brace" }, [txt(" ]")]) ]); }, node({ value, keyPath, createNode, options }) { const typedArray = value; const enumerableProperties = TYPED_ARRAY_KEYS.map((key) => ({ key, value: Reflect.get(typedArray, key) })); const enumerableChildren = enumerableProperties.map(({ key, value: value2 }) => createNode([key], value2)); const nonEnumerableChildren = options?.showNonenumerable ? (() => { const values = Array.from(typedArray).slice(0, 100); const node = createNode(["[[Values]]"], values); node.isNonEnumerable = true; return [node]; })() : []; const children = [...enumerableChildren, ...nonEnumerableChildren]; return { value, keyPath, type: Reflect.get(typedArrayConstructors, value.constructor.name), children }; } }); var IterableType = dataType({ type: "iterable", description: "Iterable", check(value) { return Boolean( value && typeof value === "object" && typeof value[Symbol.iterator] === "function" && !(value instanceof Set) && !(value instanceof Map) && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof ArrayBuffer) ); }, previewElement(node, opts) { const preview = SetType.previewText?.(node, opts) ?? ""; const entriesArray = Array.from(node.value); const size = node.value.size ?? node.value.length ?? entriesArray.length; const children = [ jsx("span", { kind: "constructor" }, [txt(`Iterable(${size})`)]), jsx("span", { kind: "brace" }, [txt(" {")]) ]; if (preview) { children.push(jsx("span", { kind: "preview-text" }, [txt(preview)])); } children.push(jsx("span", { kind: "brace" }, [txt("}")])); return jsx("span", {}, children); }, node({ value, keyPath, createNode }) { const entriesArray = Array.from(value); const entriesChildren = entriesArray.map((item, index) => createNode([ENTRIES_KEY, index], item)); const entriesNode = { keyPath: [...keyPath, ENTRIES_KEY], value: entriesArray, type: "array", children: entriesChildren, isNonEnumerable: true }; const sizeValue = value.size ?? value.length ?? entriesArray.length; const sizeNode = createNode(["size"], sizeValue); return { value, type: "iterable", children: [entriesNode, sizeNode], keyPath }; } }); var ClassType = dataType({ type: "object", description(node) { return node.constructorName || "Object"; }, check(value) { return typeof value === "object" && value !== null && value.constructor !== Object; }, previewText(node, opts) { return ObjectType.previewText?.(node, opts) || ""; }, previewElement(node, opts) { return ObjectType.previewElement(node, opts); }, node({ value, keyPath, createNode, options }) { const constructorName = value.constructor.name; const allPropertyNames = Object.getOwnPropertyNames(value); const enumerableKeys = Object.keys(value); const nonEnumerableKeys = allPropertyNames.filter((key) => !enumerableKeys.includes(key)); const enumerableChildren = enumerableKeys.map((key) => createNode([key], Reflect.get(value, key))); const nonEnumerableChildren = options?.showNonenumerable ? nonEnumerableKeys.map((key) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); const node = createNode([`[[${key}]]`], getProp(value, key)); node.isNonEnumerable = true; node.propertyDescriptor = descriptor; return node; }) : []; const children = [...enumerableChildren, ...nonEnumerableChildren]; return { value, keyPath, type: "object", constructorName, children }; } }); var ObjectType = dataType({ type: "object", description: "Object", check(value) { return typeof value === "object" && value !== null; }, previewText(node, opts) { const maxItems = opts.maxPreviewItems; const children = node.children || []; const previews = children.slice(0, maxItems).map((child) => { const valueDesc = getNodeTypeDescription(child); return `${keyPathToKey(child.keyPath)}: ${valueDesc}`; }); const hasMore = children.length > maxItems; return generatePreviewText(previews, hasMore); }, previewElement(node, opts) { const preview = this.previewText?.(node, opts) ?? ""; const children = []; if (node.constructorName) { children.push(jsx("span", { kind: "constructor" }, [txt(`${node.constructorName} `)])); } children.push(jsx("span", { kind: "brace" }, [txt("{")])); if (preview) { children.push(jsx("span", { kind: "preview-text" }, [txt(preview)])); } children.push(jsx("span", { kind: "brace" }, [txt("}")])); return jsx("span", {}, children); }, node({ value, keyPath, createNode, options }) { const allPropertyNames = Object.getOwnPropertyNames(value); const enumerableKeys = Object.keys(value); const nonEnumerableKeys = allPropertyNames.filter((key) => !enumerableKeys.includes(key)); const enumerableChildren = enumerableKeys.map((key) => createNode([key], getProp(value, key))); const nonEnumerableChildren = options?.showNonenumerable ? nonEnumerableKeys.map((key) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); const node = createNode([`[[${key}]]`], getProp(value, key)); node.isNonEnumerable = true; node.propertyDescriptor = descriptor; return node; }) : []; const children = [...enumerableChildren, ...nonEnumerableChildren]; return { value, type: "object", children, keyPath }; } }); var ELEMENT_KEYS = [ "attributes", "childElementCount", "className", "dataset", "hidden", "id", "inert", "isConnected", "isContentEditable", "nodeType", "style", "tabIndex", "tagName" ]; var isSvg = (el) => typeof el === "object" && el.tagName === "svg" && el.namespaceURI === "http://www.w3.org/2000/svg"; var isHTML = (el) => typeof el === "object" && el.namespaceURI === "http://www.w3.org/1999/xhtml"; var ElementType = dataType({ type: "element", description(node) { return typeOf(node.value); }, check(value) { return isSvg(value) || isHTML(value); }, previewElement(node) { const el = node.value; const classList = Array.from(el.classList).slice(0, 3); return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt(el.constructor.name)]), jsx("span", {}, [txt(" ")]), jsx("span", { kind: "preview-text" }, [ txt(`<${el.localName}${el.id ? `#${el.id}` : ""}${classList.length > 0 ? "." + classList.join(".") : ""}>`) ]) ]); }, node({ value, keyPath, createNode }) { const children = ELEMENT_KEYS.reduce((acc, key) => { let childValue = Reflect.get(value, key); if (key === "attributes") { const attrs = Array.from(value.attributes); childValue = attrs.length ? Object.fromEntries(attrs.map((attr) => [attr.name, attr.value])) : void 0; } if (key === "style") { const style = Array.from(value.style); childValue = style.length ? Object.fromEntries(style.map((key2) => [key2, value.style.getPropertyValue(key2)])) : void 0; } acc.push(createNode([key], childValue)); return acc; }, []); return { value, keyPath, type: "element", children }; } }); var DOCUMENT_KEYS = ["title", "URL", "documentElement", "head", "body", "contentType", "readyState"]; var DocumentType = dataType({ type: "document", description: "Document", check(value) { return typeOf(value) === "[object HTMLDocument]"; }, previewElement(node) { const doc = node.value; const url = doc.URL || "unknown"; return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("#document")]), jsx("span", { kind: "preview-text" }, [txt(` (${url})`)]) ]); }, node({ value, keyPath, createNode }) { const children = DOCUMENT_KEYS.map((key) => createNode([key], Reflect.get(value, key))); return { value, keyPath, type: "document", children }; } }); var WINDOW_KEYS = ["location", "navigator", "document", "innerWidth", "innerHeight", "devicePixelRatio", "origin"]; var WindowType = dataType({ type: "window", description: "Window", check(value) { return typeOf(value) === "[object Window]"; }, previewElement() { return jsx("span", {}, [ jsx("span", { kind: "constructor" }, [txt("Window")]), jsx("span", { kind: "preview-text" }, [txt(" { \u2026 }")]) ]); }, node({ value, keyPath, createNode }) { const children = WINDOW_KEYS.map((key) => { const childValue = Reflect.get(value, key); return createNode([key], childValue); }); return { value, keyPath, type: "window", children }; } }); var REACT_ELEMENT_KEYS = ["$$typeof", "type", "key", "ref", "props"]; var getElementTypeName = (type) => { if (typeof type === "string") return type; if (typeof type === "function") return type.displayName || type.name || "Component"; return type?.toString() || "Component"; }; var ReactElementType = dataType({ type: "react-element", description(node) { const el = node.value; return getElementTypeName(el.type); }, check(value) { return isObj(value) && "$$typeof" in value && "props" in value; }, previewElement(node, opts) { const el = node.value; const elName = getElementTypeName(el.type); const props = Object.entries(el.props); const hasMore = props.length > opts.maxPreviewItems; return jsx("span", {}, [ txt(`<${elName} `), ...props.slice(0, opts.maxPreviewItems).reduce((acc, [key, value]) => { if (key === "children") return acc; acc.push(jsx("span", {}, [txt(` ${key}=${typeof value === "string" ? `"${value}"` : `{${value}}`}`)])); return acc; }, []), ...hasMore ? [txt(" \u2026")] : [], txt(el.children ? `> {\u2026} </${elName}>` : ` />`) ]); }, node({ value, keyPath, createNode }) { const children = REACT_ELEMENT_KEYS.reduce((acc, key) => { let childValue = Reflect.get(value, key); if (key === "type") { childValue = getElementTypeName(childValue); } acc.push(createNode([key], childValue)); return acc; }, []); return { value, type: "react-element", keyPath, children }; } }); var map = { "\n": "\\n", " ": "\\t", "\r": "\\r" }; var STRING_ESCAPE_REGEXP = /[\n\t\r]/g; var StringType = dataType({ type: "string", description(node, opts) { return `"${this.previewText?.(node, opts) ?? node.value}"`; }, check(value) { return typeof value === "string"; }, previewText(node, opts) { const serialised = node.value.replace(STRING_ESCAPE_REGEXP, (_) => map[_]); const preview = serialised.slice(0, opts.collapseStringsAfterLength) + (serialised.length > opts.collapseStringsAfterLength ? "\u2026" : ""); return preview; }, previewElement(node) { const serialised = node.value.replace(STRING_ESCAPE_REGEXP, (_) => map[_]); return jsx("span", {}, [txt(`"${serialised}"`)]); }, node({ value, keyPath }) { return { value, type: "string", keyPath }; } }); var PrimitiveType = dataType({ type(value) { return typeof value; }, description(node) { return String(node.value); }, check(value) { return value !== null && value !== void 0; }, previewElement(node) { return jsx("span", {}, [txt(String(node.value))]); }, node({ value, keyPath }) { return { value, type: typeof value, keyPath }; } }); var dataTypes = [ NullType, UndefinedType, SymbolType, BigIntType, FunctionType, ArrayBufferType, SharedArrayBufferType, BufferType, DataViewType, ErrorType, DateType, RegexType, SetType, MapType, WeakMapType, WeakSetType, FileType, BlobType, ReactElementType, WindowType, DocumentType, ElementType, UrlType, URLSearchParamsType, HeadersType, FormDataType, ArrayType, TypedArrayType, IterableType, ClassType, ObjectType, StringType, PrimitiveType ]; var jsonNodeToElement = (node, opts) => { const options = getPreviewOptions(opts); const key = keyPathToKey(node.keyPath, { excludeRoot: true }); if (key === "stack" && typeof node.value === "string") { return errorStackToElement(node.value); } const dataType2 = dataTypes.find((dataType3) => dataType3.check(node.value)); if (!dataType2) { return jsx("span", {}, [txt(String(node.value))]); } const element = dataType2.previewElement(node, options); if (!key) { element.properties.root = true; } element.properties.kind = "preview"; element.properties.nodeType = typeof dataType2.type === "function" ? dataType2.type(node.value) : dataType2.type; return element; }; var getNodeTypeDescription = (node, opts) => { const options = getPreviewOptions(opts); const dataType2 = dataTypes.find((dataType3) => dataType3.check(node.value)); if (dataType2) { return typeof dataType2.description === "function" ? dataType2.description(node, options) : dataType2.description; } return String(node.value); }; // src/accessibility.ts var propertyWord = (count) => count === 1 ? "property" : "properties"; var isPrimitive = (node) => { return node.type === "string" || node.type === "number" || node.type === "boolean"; }; var getAccessibleDescription = (node, opts) => { const typeDescription = getNodeTypeDescription(node, opts); const key = keyPathToKey(node.keyPath, { excludeRoot: true }); const nonEnumerablePrefix = node.isNonEnumerable ? "non-enumerable " : ""; const format = (text) => { return [key, `${nonEnumerablePrefix}${text}`].filter(Boolean).join(": "); }; if (node.children && node.children.length > 0) { const childCount = node.children.length; if (key === "[[Entries]]") { return format(`${childCount} ${propertyWord(childCount)}`); } return format(`${typeDescription}, expandable with ${childCount} ${propertyWord(childCount)}`); } if (isPrimitive(node)) { if (key === "stack") { return format(node.value.split("\n")[1]?.trim() || "trace"); } if (key === "[[Function]]") { return format("function implementation"); } const value = typeof node.value === "string" ? `"${node.value}"` : String(node.value); const info2 = node.isNonEnumerable && node.propertyDescriptor ? `, ${getDescriptorInfo(node.propertyDescriptor)}` : ""; return format(`${value}${info2}`); } if (node.type === "null") { return format("null"); } if (node.type === "undefined") { return format("undefined"); } if (node.type === "circular") { return format("circular reference"); } const info = node.isNonEnumerable && node.propertyDescriptor ? `, ${getDescriptorInfo(node.propertyDescriptor)}` : ""; return format(`${nonEnumerablePrefix}${typeDescription}${info}`); }; var getDescriptorInfo = (descriptor) => { const parts = []; if (!descriptor.writable) parts.push("read-only"); if (!descriptor.configurable) parts.push("non-configurable"); return parts.length > 0 ? parts.join(", ") : "non-enumerable"; }; export { ArrayBufferType, ArrayType, BigIntType, BlobType, BufferType, ClassType, DEFAULT_PREVIEW_OPTIONS, DataViewType, DateType, DocumentType, ElementType, ErrorType, FileType, FormDataType, FunctionType, HeadersType, IterableType, MapType, NullType, ObjectType, PATH_SEP, PrimitiveType, ROOT_KEY, ReactElementType, RegexType, SetType, SharedArrayBufferType, StringType, SymbolType, TypedArrayType, URLSearchParamsType, UndefinedType, UrlType, WeakMapType, WeakSetType, WindowType, dataTypes, getAccessibleDescription, getNodeTypeDescription, getPreviewOptions, getRootNode, isRootKeyPath, jsonNodeToElement, jsonPathToValue, jsonToTree, keyPathToId, keyPathToKey, nodeToString, nodeToValue };