From d2487324691bbc9ce2c3f61d02575affb5a501f9 Mon Sep 17 00:00:00 2001
From: Misode
Date: Thu, 17 Oct 2024 15:14:30 +0200
Subject: [PATCH] Basic mcdoc tree rendering
---
.../components/generator/McdocRenderer.tsx | 182 ++++++++++++++++++
src/app/components/generator/Tree.tsx | 14 +-
src/app/contexts/Spyglass.tsx | 8 +-
src/app/services/Spyglass.ts | 11 +-
src/styles/nodes.css | 20 +-
5 files changed, 214 insertions(+), 21 deletions(-)
create mode 100644 src/app/components/generator/McdocRenderer.tsx
diff --git a/src/app/components/generator/McdocRenderer.tsx b/src/app/components/generator/McdocRenderer.tsx
new file mode 100644
index 00000000..9b572007
--- /dev/null
+++ b/src/app/components/generator/McdocRenderer.tsx
@@ -0,0 +1,182 @@
+import type { JsonNode } from '@spyglassmc/json'
+import { JsonArrayNode, JsonBooleanNode, JsonNumberNode, JsonObjectNode, JsonStringNode } from '@spyglassmc/json'
+import type { ListType, LiteralType, McdocType } from '@spyglassmc/mcdoc'
+import type { SimplifiedStructType } from '@spyglassmc/mcdoc/lib/runtime/checker/index.js'
+import { useLocale } from '../../contexts/Locale.jsx'
+import { Octicon } from '../Octicon.jsx'
+
+interface Props {
+ node: JsonNode | undefined
+}
+export function McdocRoot({ node } : Props) {
+ const type = node?.typeDef ?? { kind: 'unsafe' }
+
+ if (type.kind === 'struct') {
+ return
+ }
+
+ return <>
+
+
+
+ >
+}
+
+interface HeadProps extends Props {
+ simpleType: McdocType
+ optional?: boolean
+}
+function Head({ simpleType, optional, node }: HeadProps) {
+ const { locale } = useLocale()
+ const type = node?.typeDef ?? simpleType
+ if (type.kind === 'string') {
+ const value = JsonStringNode.is(node) ? node.value : undefined
+
+ return
+ }
+ if (type.kind === 'enum') {
+ const value = JsonStringNode.is(node) ? node.value : undefined
+ return
+ }
+ if (type.kind === 'byte' || type.kind === 'short' || type.kind === 'int' || type.kind === 'long' || type.kind === 'float' || type.kind === 'double') {
+ const value = node && JsonNumberNode.is(node) ? Number(node.value.value) : undefined
+ return
+ }
+ if (type.kind === 'boolean') {
+ const value = node && JsonBooleanNode.is(node) ? node.value : undefined
+ return <>
+
+
+ >
+ }
+ if (type.kind === 'union') {
+ return
+ }
+ if (type.kind === 'struct' && optional) {
+ console.log(type, node)
+ if (node && JsonObjectNode.is(node)) {
+ return
+ } else {
+ return
+ }
+ }
+ if (type.kind === 'list' || type.kind === 'byte_array' || type.kind === 'int_array' || type.kind === 'long_array') {
+ const fixedRange = type.lengthRange?.min !== undefined && type.lengthRange.min === type.lengthRange.max
+ if (fixedRange) {
+ return <>>
+ }
+ return
+ }
+ console.warn('Unhandled head', type)
+ return <>>
+}
+
+interface BodyProps extends Props {
+ simpleType: McdocType
+}
+function Body({ simpleType, node }: BodyProps) {
+ const type = node?.typeDef ?? simpleType
+ if (node?.typeDef?.kind === 'struct') {
+ if (node.typeDef.fields.length === 0) {
+ return <>>
+ }
+ return
+
+
+ }
+ if (node?.typeDef?.kind === 'list') {
+ return
+
+
+ }
+ if (type.kind === 'byte' || type.kind === 'short' || type.kind === 'int' || type.kind === 'boolean') {
+ return <>>
+ }
+ console.warn('Unhandled body', type, node)
+ return <>>
+}
+
+interface StructBodyProps extends Props {
+ type: SimplifiedStructType
+}
+function StructBody({ type, node }: StructBodyProps) {
+ if (!JsonObjectNode.is(node)) {
+ return <>>
+ }
+ const staticFields = type.fields.filter(field =>
+ field.key.kind === 'literal' && field.key.value.kind === 'string')
+ const dynamicFields = type.fields.filter(field =>
+ field.key.kind === 'string')
+ if (type.fields.length !== staticFields.length + dynamicFields.length) {
+ console.warn('Missed struct fields', type.fields.filter(field =>
+ !staticFields.includes(field) && !dynamicFields.includes(field)))
+ }
+ return <>
+ {staticFields.map(field => {
+ const key = (field.key as LiteralType).value.value
+ const child = node.children.find(p => p.key?.value === key)?.value
+ return
+
+
+