From ea873cae226dbc3ca5f977e200e6660bfd51e7df Mon Sep 17 00:00:00 2001 From: Misode Date: Thu, 31 Oct 2024 00:09:37 +0100 Subject: [PATCH] Move stuff around to group mcdoc types --- .../components/generator/McdocRenderer.tsx | 424 +++++++++--------- 1 file changed, 211 insertions(+), 213 deletions(-) diff --git a/src/app/components/generator/McdocRenderer.tsx b/src/app/components/generator/McdocRenderer.tsx index a2af7dfd..7502a9e0 100644 --- a/src/app/components/generator/McdocRenderer.tsx +++ b/src/app/components/generator/McdocRenderer.tsx @@ -17,15 +17,6 @@ import { ItemDisplay } from '../ItemDisplay.jsx' import { Octicon } from '../Octicon.jsx' import { formatIdentifier, getCategory, getDefault, getItemType, isSelectRegistry, quickEqualTypes, simplifyType } from './McdocHelpers.js' -const SPECIAL_UNSET = '__unset__' -const ANY_TYPES: SimplifiedMcdocType[] = [ - { kind: 'boolean' }, - { kind: 'double' }, - { kind: 'string' }, - { kind: 'list', item: { kind: 'any' } }, - { kind: 'struct', fields: [ { kind: 'pair', key: { kind: 'string' }, type: { kind: 'any' } }] }, -] - export interface McdocContext extends core.CheckerContext {} type MakeEdit = (edit: (range: core.Range) => JsonNode | undefined) => void @@ -91,6 +82,47 @@ function Head({ type, optional, node, makeEdit, ctx }: Props) { return <> } +function Body({ type, optional, node, makeEdit, ctx }: Props) { + if (type.kind === 'union') { + return + } + if (type.kind === 'struct') { + if (!JsonObjectNode.is(node) || type.fields.length === 0) { + return <> + } + return
+ +
+ } + if (type.kind === 'list' || type.kind === 'byte_array' || type.kind === 'int_array' || type.kind === 'long_array') { + if (!JsonArrayNode.is(node)) { + return <> + } + if (type.lengthRange?.min !== undefined && type.lengthRange.min === type.lengthRange.max) { + return
+ getItemType(type)), attributes: type.attributes }} node={node} makeEdit={makeEdit} ctx={ctx} /> +
+ } + if (node.children?.length === 0) { + return <> + } + return
+ +
+ } + if (type.kind === 'tuple') { + return
+ +
+ } + if (type.kind === 'any' || type.kind === 'unsafe') { + return + } + return <> +} + +const SPECIAL_UNSET = '__unset__' + function StringHead({ type, optional, node, makeEdit, ctx }: Props) { const { locale } = useLocale() @@ -301,7 +333,7 @@ function UnionHead({ type, optional, node, makeEdit, ctx }: Props } - const selectedType = findSelectedMember(type, node) + const selectedType = selectUnionMember(type, node) const onSelect = useCallback((newValue: string) => { makeEdit((range) => { @@ -326,6 +358,46 @@ function UnionHead({ type, optional, node, makeEdit, ctx }: Props } +function formatUnionMember(type: SimplifiedMcdocTypeNoUnion, others: SimplifiedMcdocTypeNoUnion[]): string { + if (type.kind === 'literal') { + return formatIdentifier(type.value.value.toString()) + } + if (!others.some(o => o.kind === type.kind)) { + // No other member is of this kind + return formatIdentifier(type.kind) + } + if (type.kind === 'struct') { + // Show the first literal key + const firstKey = type.fields.find(f => f.key.kind === 'literal')?.key + if (firstKey) { + return formatUnionMember(firstKey, []) + } + } + return formatIdentifier(type.kind) +} + +function UnionBody({ type, optional, node, makeEdit, ctx }: Props>) { + const selectedType = selectUnionMember(type, node) + if (selectedType === undefined) { + return <> + } + return +} + +function selectUnionMember(union: UnionType, node: JsonNode | undefined) { + const selectedType = node?.typeDef + if (!selectedType || selectedType.kind === 'any' || selectedType.kind === 'unsafe') { + return undefined + } + if (selectedType.kind === 'union') { + // Find the first selected type that is also part of the original definition. + // The node technically matches all members of this union, + // ideally the editor should show a combination of all members + return selectedType.members.find(m1 => union.members.find(m2 => quickEqualTypes(m1, m2))) + } + return selectedType +} + function StructHead({ type: outerType, optional, node, makeEdit, ctx }: Props) { const { locale } = useLocale() const type = node?.typeDef?.kind === 'struct' ? node.typeDef : outerType @@ -360,158 +432,7 @@ function StructHead({ type: outerType, optional, node, makeEdit, ctx }: Props } -function ListHead({ type, node, makeEdit, ctx }: Props) { - const { locale } = useLocale() - - const canAdd = (type.lengthRange?.max ?? Infinity) > (node?.children?.length ?? 0) - - const onAddTop = useCallback(() => { - if (canAdd) { - makeEdit((range) => { - const itemType = simplifyType(getItemType(type), ctx) - const newValue = getDefault(itemType, range, ctx) - const newItem: core.ItemNode = { - type: 'item', - range, - children: [newValue], - value: newValue, - } - newValue.parent = newItem - if (JsonArrayNode.is(node)) { - node.children.unshift(newItem) - newItem.parent = node - return node - } - const newArray: JsonArrayNode = { - type: 'json:array', - range, - children: [newItem], - } - newItem.parent = newArray - return newArray - }) - } - }, [type, node, makeEdit, ctx, canAdd]) - - return -} - -function TupleHead({ type, optional, node, makeEdit, ctx }: Props) { - const { locale } = useLocale() - - const onRemove = useCallback(() => { - makeEdit(() => { - return undefined - }) - }, [makeEdit]) - - const onSetDefault = useCallback(() => { - makeEdit((range) => { - return getDefault(type, range, ctx) - }) - }, [type, ctx]) - - if (optional) { - if (node && JsonArrayNode.is(node)) { - return - } else { - return - } - } else { - if (!node || !JsonArrayNode.is(node)) { - return - } - return <> - } -} - -function LiteralHead({ type, optional, node, makeEdit, ctx }: Props) { - return -} - -function AnyHead({ optional, node, makeEdit, ctx }: Props) { - const { locale } = useLocale() - - const selectedType = findSelectedAnyType(node) - - const onSelect = useCallback((newValue: string) => { - makeEdit((range) => { - const newSelected = ANY_TYPES.find(t => t.kind === newValue) - if (!newSelected) { - return undefined - } - return getDefault(newSelected, range, ctx) - }) - }, [makeEdit, ctx]) - - return <> - - {selectedType && } - -} - -function Body({ type, optional, node, makeEdit, ctx }: Props) { - if (type.kind === 'union') { - return - } - if (type.kind === 'struct') { - if (!JsonObjectNode.is(node) || type.fields.length === 0) { - return <> - } - return
- -
- } - if (type.kind === 'list' || type.kind === 'byte_array' || type.kind === 'int_array' || type.kind === 'long_array') { - if (!JsonArrayNode.is(node)) { - return <> - } - if (type.lengthRange?.min !== undefined && type.lengthRange.min === type.lengthRange.max) { - return
- getItemType(type)), attributes: type.attributes }} node={node} makeEdit={makeEdit} ctx={ctx} /> -
- } - if (node.children?.length === 0) { - return <> - } - return
- -
- } - if (type.kind === 'tuple') { - return
- -
- } - if (type.kind === 'any' || type.kind === 'unsafe') { - return - } - return <> -} - -function UnionBody({ type, optional, node, makeEdit, ctx }: Props>) { - const selectedType = findSelectedMember(type, node) - if (selectedType === undefined) { - return <> - } - return -} - -interface StructBodyProps extends Props { - type: SimplifiedStructType -} -function StructBody({ type: outerType, node, makeEdit, ctx }: StructBodyProps) { +function StructBody({ type: outerType, node, makeEdit, ctx }: Props) { const { locale } = useLocale() if (!JsonObjectNode.is(node)) { return <> @@ -697,12 +618,42 @@ function StructBody({ type: outerType, node, makeEdit, ctx }: StructBodyProps) { } -interface KeyProps { - label: string | number | boolean - raw?: boolean -} -function Key({ label, raw }: KeyProps) { - return +function ListHead({ type, node, makeEdit, ctx }: Props) { + const { locale } = useLocale() + + const canAdd = (type.lengthRange?.max ?? Infinity) > (node?.children?.length ?? 0) + + const onAddTop = useCallback(() => { + if (canAdd) { + makeEdit((range) => { + const itemType = simplifyType(getItemType(type), ctx) + const newValue = getDefault(itemType, range, ctx) + const newItem: core.ItemNode = { + type: 'item', + range, + children: [newValue], + value: newValue, + } + newValue.parent = newItem + if (JsonArrayNode.is(node)) { + node.children.unshift(newItem) + newItem.parent = node + return node + } + const newArray: JsonArrayNode = { + type: 'json:array', + range, + children: [newItem], + } + newItem.parent = newArray + return newArray + }) + } + }, [type, node, makeEdit, ctx, canAdd]) + + return } function ListBody({ type: outerType, node, makeEdit, ctx }: Props) { @@ -820,6 +771,39 @@ function ListBody({ type: outerType, node, makeEdit, ctx }: Props } +function TupleHead({ type, optional, node, makeEdit, ctx }: Props) { + const { locale } = useLocale() + + const onRemove = useCallback(() => { + makeEdit(() => { + return undefined + }) + }, [makeEdit]) + + const onSetDefault = useCallback(() => { + makeEdit((range) => { + return getDefault(type, range, ctx) + }) + }, [type, ctx]) + + if (optional) { + if (node && JsonArrayNode.is(node)) { + return + } else { + return + } + } else { + if (!node || !JsonArrayNode.is(node)) { + return + } + return <> + } +} + function TupleBody({ type, node, makeEdit, ctx }: Props) { if (!JsonArrayNode.is(node)) { return <> @@ -855,8 +839,46 @@ function TupleBody({ type, node, makeEdit, ctx }: Props) { } +function LiteralHead({ type, optional, node, makeEdit, ctx }: Props) { + return +} + +const ANY_TYPES: SimplifiedMcdocType[] = [ + { kind: 'boolean' }, + { kind: 'double' }, + { kind: 'string' }, + { kind: 'list', item: { kind: 'any' } }, + { kind: 'struct', fields: [ { kind: 'pair', key: { kind: 'string' }, type: { kind: 'any' } }] }, +] + +function AnyHead({ optional, node, makeEdit, ctx }: Props) { + const { locale } = useLocale() + + const selectedType = selectAnyType(node) + + const onSelect = useCallback((newValue: string) => { + makeEdit((range) => { + const newSelected = ANY_TYPES.find(t => t.kind === newValue) + if (!newSelected) { + return undefined + } + return getDefault(newSelected, range, ctx) + }) + }, [makeEdit, ctx]) + + return <> + + {selectedType && } + +} + function AnyBody({ optional, node, makeEdit, ctx }: Props) { - const selectedType = findSelectedAnyType(node) + const selectedType = selectAnyType(node) if (!selectedType) { return <> @@ -865,6 +887,25 @@ function AnyBody({ optional, node, makeEdit, ctx }: Props) { return } +function selectAnyType(node: JsonNode | undefined) { + switch (node?.type) { + case 'json:boolean': return ANY_TYPES[0] + case 'json:number': return ANY_TYPES[1] + case 'json:string': return ANY_TYPES[2] + case 'json:array': return ANY_TYPES[3] + case 'json:object': return ANY_TYPES[4] + default: return undefined + } +} + +interface KeyProps { + label: string | number | boolean + raw?: boolean +} +function Key({ label, raw }: KeyProps) { + return +} + interface ErrorsProps { type: SimplifiedMcdocType node: JsonNode | undefined @@ -881,7 +922,7 @@ function Errors({ type, node, ctx }: ErrorsProps) { // Unless they are inside a child node .filter(e => !node.children?.some(c => (c.type === 'item' || c.type === 'pair') && core.Range.containsRange(c.range, e.range, true))) // Filter out "Missing key" errors - .filter(e => !(core.Range.length(e.range) === 1 && (type.kind === 'struct' || (type.kind === 'union' && (findSelectedMember(type, node) ?? type.members[0]).kind === 'struct')))) + .filter(e => !(core.Range.length(e.range) === 1 && (type.kind === 'struct' || (type.kind === 'union' && (selectUnionMember(type, node) ?? type.members[0]).kind === 'struct')))) // Hide warnings if there are errors return errors.find(e => e.severity === 3) ? errors.filter(e => e.severity === 3) @@ -920,46 +961,3 @@ function Docs({ desc }: DocsProps) { {desc} } - -function formatUnionMember(type: SimplifiedMcdocTypeNoUnion, others: SimplifiedMcdocTypeNoUnion[]): string { - if (type.kind === 'literal') { - return formatIdentifier(type.value.value.toString()) - } - if (!others.some(o => o.kind === type.kind)) { - // No other member is of this kind - return formatIdentifier(type.kind) - } - if (type.kind === 'struct') { - // Show the first literal key - const firstKey = type.fields.find(f => f.key.kind === 'literal')?.key - if (firstKey) { - return formatUnionMember(firstKey, []) - } - } - return formatIdentifier(type.kind) -} - -function findSelectedMember(union: UnionType, node: JsonNode | undefined) { - const selectedType = node?.typeDef - if (!selectedType || selectedType.kind === 'any' || selectedType.kind === 'unsafe') { - return undefined - } - if (selectedType.kind === 'union') { - // Find the first selected type that is also part of the original definition. - // The node technically matches all members of this union, - // ideally the editor should show a combination of all members - return selectedType.members.find(m1 => union.members.find(m2 => quickEqualTypes(m1, m2))) - } - return selectedType -} - -function findSelectedAnyType(node: JsonNode | undefined) { - switch (node?.type) { - case 'json:boolean': return ANY_TYPES[0] - case 'json:number': return ANY_TYPES[1] - case 'json:string': return ANY_TYPES[2] - case 'json:array': return ANY_TYPES[3] - case 'json:object': return ANY_TYPES[4] - default: return undefined - } -}