Hello from MCP server
<script lang="ts">
import { ref, defineComponent, h, type VNode } from "vue";
const JsonNode = defineComponent({
name: "JsonNode",
props: {
data: { required: true },
indent: { type: Number, default: 0 },
keyName: { type: String, default: "" },
startCollapsed: { type: Boolean, default: true },
expandAll: { type: Boolean, default: false },
onCopy: { type: Function, default: null },
},
setup(props) {
const collapsed = ref(props.startCollapsed);
const wasManuallyExpanded = ref(false);
const handleToggle = (e: Event) => {
e.stopPropagation();
if (collapsed.value) {
wasManuallyExpanded.value = true;
}
collapsed.value = !collapsed.value;
};
const copyValue = (value: unknown) => {
let text: string;
if (value === null) {
text = "null";
} else if (typeof value === "string") {
text = value;
} else if (typeof value === "object") {
text = JSON.stringify(value);
} else {
text = String(value);
}
navigator.clipboard.writeText(text);
if (props.onCopy) {
props.onCopy(text);
}
};
return (): VNode => {
const childStartCollapsed = props.expandAll ? props.startCollapsed : (wasManuallyExpanded.value ? false : true);
const childExpandAll = props.expandAll;
const data = props.data;
const indent = props.indent;
const pad = " ".repeat(indent);
const keyPrefix = props.keyName ? `"${props.keyName}": ` : "";
if (data === null) {
return h("span", { class: "json-null json-clickable", onClick: () => copyValue(data) }, keyPrefix + "null");
}
if (typeof data === "boolean") {
return h("span", { class: "json-bool json-clickable", onClick: () => copyValue(data) }, keyPrefix + String(data));
}
if (typeof data === "number") {
return h("span", { class: "json-num json-clickable", onClick: () => copyValue(data) }, keyPrefix + String(data));
}
if (typeof data === "string") {
return h("span", { class: "json-str json-clickable", onClick: () => copyValue(data) }, keyPrefix + `"${data}"`);
}
if (Array.isArray(data)) {
if (data.length === 0) {
return h("span", { class: "json-clickable", onClick: () => copyValue(data) }, keyPrefix + "[]");
}
const toggle = h(
"span",
{
class: "json-toggle",
onClick: handleToggle,
},
collapsed.value ? "+" : "-"
);
if (collapsed.value) {
return h("span", { class: "json-clickable", onClick: () => copyValue(data) }, [
keyPrefix,
toggle,
` [${data.length} items]`,
]);
}
const children: VNode[] = data.map((item: unknown, i: number) =>
h("div", { key: i }, [
pad + " ",
h(JsonNode, { data: item, indent: indent + 1, startCollapsed: childStartCollapsed, expandAll: childExpandAll, onCopy: props.onCopy }),
i < data.length - 1 ? "," : "",
])
);
return h("span", {}, [
keyPrefix,
toggle,
" [\n",
...children,
"\n" + pad + "]",
]);
}
if (typeof data === "object") {
const keys = Object.keys(data);
if (keys.length === 0) {
return h("span", { class: "json-clickable", onClick: () => copyValue(data) }, keyPrefix + "{}");
}
const toggle = h(
"span",
{
class: "json-toggle",
onClick: handleToggle,
},
collapsed.value ? "+" : "-"
);
if (collapsed.value) {
return h("span", { class: "json-clickable", onClick: () => copyValue(data) }, [
keyPrefix,
toggle,
` {${keys.length} keys}`,
]);
}
const children: VNode[] = keys.map((key: string, i: number) =>
h("div", { key }, [
pad + " ",
h(JsonNode, { data: (data as Record<string, unknown>)[key], indent: indent + 1, keyName: key, startCollapsed: childStartCollapsed, expandAll: childExpandAll, onCopy: props.onCopy }),
i < keys.length - 1 ? "," : "",
])
);
return h("span", {}, [
keyPrefix,
toggle,
" {\n",
...children,
"\n" + pad + "}",
]);
}
return h("span", {}, String(data));
};
},
});
export default JsonNode;
</script>
<style>
.json-clickable {
cursor: pointer;
color: #000;
}
.json-clickable:hover {
background: #e8e8e8;
}
.json-toggle {
cursor: pointer;
color: #666;
font-weight: bold;
user-select: none;
display: inline-block;
width: 1em;
text-align: center;
}
.json-toggle:hover {
color: #000;
}
.json-str {
color: #000;
}
.json-num {
color: #005cc5;
}
.json-bool {
color: #d73a49;
}
.json-null {
color: #6a737d;
}
</style>