diff --git a/src/app/components/generator/McdocRenderer.tsx b/src/app/components/generator/McdocRenderer.tsx index 320662d5..11bdca9f 100644 --- a/src/app/components/generator/McdocRenderer.tsx +++ b/src/app/components/generator/McdocRenderer.tsx @@ -148,7 +148,7 @@ function StringHead({ type, optional, node, makeEdit, ctx }: StringHeadProps) { {completions.length > 0 && {completions.map(c => )} } - onChangeValue((e.target as HTMLInputElement).value)} list={completions.length > 0 ? datalistId : undefined} /> + onChangeValue((e.target as HTMLInputElement).value)} list={completions.length > 0 ? datalistId : undefined} /> {value && gen && {Octicon.link_external} } @@ -315,8 +315,12 @@ function UnionHead({ type, optional, node, makeEdit, ctx }: UnionHeadProps) { } -function StructHead({ type, optional, node, makeEdit, ctx }: HeadProps) { +interface StructHeadProps extends HeadProps { + type: SimplifiedStructType +} +function StructHead({ type: outerType, optional, node, makeEdit, ctx }: StructHeadProps) { const { locale } = useLocale() + const type = node?.typeDef?.kind === 'struct' ? node.typeDef : outerType const onRemove = useCallback(() => { makeEdit(() => { @@ -330,22 +334,22 @@ function StructHead({ type, optional, node, makeEdit, ctx }: HeadProps) { }) }, [type, ctx]) - if (optional) { - if (node && JsonObjectNode.is(node)) { - return - } else { - return - } - } else { - if (!node || !JsonObjectNode.is(node)) { - return - } - return <> - } + return <> + {optional + ? (JsonObjectNode.is(node) + ? + : ) + : (!JsonObjectNode.is(node) + ? + : <> + )} + } interface ListHeadProps extends Props { @@ -469,10 +473,6 @@ function Body({ type, optional, node, makeEdit, ctx }: BodyProps) { } - if (type.kind === 'boolean' || type.kind === 'byte' || type.kind === 'short' || type.kind === 'int' || type.kind === 'float' || type.kind === 'double') { - return <> - } - // console.warn('Unhandled body', type, node) return <> } @@ -496,19 +496,17 @@ function StructBody({ type: outerType, node, makeEdit, ctx }: StructBodyProps) { return <> } const type = node.typeDef?.kind === 'struct' ? node.typeDef : outerType - 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))) - } + const staticFields = type.fields.filter(field => field.key.kind === 'literal') + const dynamicFields = type.fields.filter(field => field.key.kind !== 'literal') + const staticChilds: core.PairNode[] = [] return <> {staticFields.map(field => { const key = (field.key as LiteralType).value.value.toString() const index = node.children.findIndex(p => p.key?.value === key) const pair = index === -1 ? undefined : node.children[index] + if (pair) { + staticChilds.push(pair) + } const child = pair?.value const childType = simplifyType(field.type, ctx) const makeFieldEdit: MakeEdit = (edit) => { @@ -559,6 +557,103 @@ function StructBody({ type: outerType, node, makeEdit, ctx }: StructBodyProps) { })} + {dynamicFields.map((field, index) => { + const incompletePairs = node.children.filter(pair => pair.value && core.Range.length(pair.value.range) === 0) + const pair = index < incompletePairs.length ? incompletePairs[index] : undefined + const keyType = simplifyType(field.key, ctx) + const makeKeyEdit: MakeEdit = (edit) => { + makeEdit(() => { + const newKey = edit(pair?.key?.range ?? core.Range.create(node.range.end)) + const index = pair ? node.children.indexOf(pair) : -1 + if (!newKey || !JsonStringNode.is(newKey) || newKey.value.length === 0) { + if (index !== -1) { + node.children.splice(index, 1) + } + return node + } + const newPair: core.PairNode = { + type: 'pair', + range: newKey?.range, + key: newKey, + } + newKey.parent = newPair + if (index !== -1) { + node.children.splice(index, 1, newPair) + } else { + node.children.push(newPair) + } + newPair.parent = node + return node + }) + } + const onAddKey = () => { + const keyNode = pair?.key + const index = pair ? node.children.indexOf(pair) : -1 + if (!pair || !keyNode || index === -1) { + return + } + makeEdit((range) => { + const valueNode = getDefault(simplifyType(field.type, ctx), range, ctx) + const newPair: core.PairNode = { + type: 'pair', + range: keyNode.range, + key: keyNode, + value: valueNode, + } + valueNode.parent = newPair + node.children.splice(index, 1, newPair) + newPair.parent = node + return node + }) + } + return
+
+ + + +
+
+ })} + {node.children.map((pair, index) => { + const key = pair.key?.value + if (staticChilds.includes(pair) || !key) { + return <> + } + if (pair.value && core.Range.length(pair.value.range) === 0) { + return <> + } + const child = pair.value + // TODO: correctly determine which dynamic field this is a key for + const fieldType = dynamicFields[0].type + const childType = simplifyType(dynamicFields[0].type, ctx) + const makeFieldEdit: MakeEdit = (edit) => { + makeEdit(() => { + const newChild = edit(child?.range ?? core.Range.create(pair.range.end)) + if (newChild === undefined) { + node.children.splice(index, 1) + } else { + node.children[index] = { + type: 'pair', + range: pair.range, + key: pair.key, + value: newChild, + } + } + return node + }) + } + return
+
+ + + + +
+ +
+ })} } @@ -888,6 +983,7 @@ function getCategory(type: McdocType) { case '::java::data::worldgen::template_pool::WeightedElement': return 'pool' case '::java::data::loot::LootCondition': + case '::java::data::advancement::AdvancementCriterion': case '::java::data::worldgen::dimension::biome_source::BiomeSource': case '::java::data::worldgen::processor_list::ProcessorRule': case '::java::data::worldgen::feature::placement::PlacementModifier': diff --git a/src/app/components/previews/LootTablePreview.tsx b/src/app/components/previews/LootTablePreview.tsx index 837f41c8..43eff887 100644 --- a/src/app/components/previews/LootTablePreview.tsx +++ b/src/app/components/previews/LootTablePreview.tsx @@ -40,7 +40,10 @@ export const LootTablePreview = ({ docAndNode }: PreviewProps) => { return [] } const [itemTags, lootTables, itemComponents, enchantments, enchantmentTags] = dependencies - const table = JSON.parse(text) + let table = {} + try { + table = JSON.parse(text) + } catch (e) {} if (use1204) { return generateLootTable1204(table, { version, seed, luck, daytime, weather, diff --git a/src/locales/en.json b/src/locales/en.json index 0806963b..6021ea6a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -3,6 +3,7 @@ "3d": "3D", "add": "Add", "add_bottom": "Add to bottom", + "add_key": "Add key", "add_top": "Add to top", "any_version": "Any", "assets": "Assets", diff --git a/src/styles/nodes.css b/src/styles/nodes.css index a8441b71..4fd8b835 100644 --- a/src/styles/nodes.css +++ b/src/styles/nodes.css @@ -137,14 +137,12 @@ } .node-warning ~ select:last-child, -.node-warning ~ input:last-child, -.node-warning ~ input[list]:nth-last-child(2) { +.node-warning ~ input:last-child { border-color: var(--node-selected) !important; } .node-error ~ select:last-child, -.node-error ~ input:last-child, -.node-error ~ input[list]:nth-last-child(2) { +.node-error ~ input:last-child { border-color: var(--node-remove) !important; } @@ -160,8 +158,7 @@ border-bottom-left-radius: 3px; } -.node-header > *:last-child, -.node-header > input[list]:nth-last-child(2) { +.node-header > *:last-child { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }