diff --git a/src/app/components/generator/SourcePanel.tsx b/src/app/components/generator/SourcePanel.tsx index b50de2b4..221e25b8 100644 --- a/src/app/components/generator/SourcePanel.tsx +++ b/src/app/components/generator/SourcePanel.tsx @@ -1,10 +1,10 @@ import { DataModel } from '@mcschema/core' import { useCallback, useEffect, useRef, useState } from 'preact/hooks' import { useLocale } from '../../contexts/index.js' -import { useModel } from '../../hooks/index.js' +import { useLocalStorage, useModel } from '../../hooks/index.js' import { getOutput } from '../../schema/transformOutput.js' import type { BlockStateRegistry } from '../../services/index.js' -import { getSourceFormats, getSourceIndent, getSourceIndents, parseSource, stringifySource } from '../../services/index.js' +import { getSourceFormats, getSourceIndent, getSourceIndents, parseSource, sortData, stringifySource } from '../../services/index.js' import { Store } from '../../Store.js' import { message } from '../../Utils.js' import { Btn, BtnMenu } from '../index.js' @@ -30,6 +30,7 @@ export function SourcePanel({ name, model, blockStates, doCopy, doDownload, doIm const { locale } = useLocale() const [indent, setIndent] = useState(Store.getIndent()) const [format, setFormat] = useState(Store.getFormat()) + const [sort, setSort] = useLocalStorage('misode_output_sort', 'schema') const [highlighting, setHighlighting] = useState(Store.getHighlighting()) const [braceLoaded, setBraceLoaded] = useState(false) const download = useRef(null) @@ -40,9 +41,12 @@ export function SourcePanel({ name, model, blockStates, doCopy, doDownload, doIm const editor = useRef() const getSerializedOutput = useCallback((model: DataModel, blockStates: BlockStateRegistry) => { - const data = getOutput(model, blockStates) + let data = getOutput(model, blockStates) + if (sort === 'alphabetically') { + data = sortData(data) + } return stringifySource(data, format, indent) - }, [indent, format]) + }, [indent, format, sort]) useEffect(() => { retransform.current = () => { @@ -80,7 +84,7 @@ export function SourcePanel({ name, model, blockStates, doCopy, doDownload, doIm console.error(e) } } - }, [model, blockStates, indent, format, highlighting]) + }, [model, blockStates, indent, format, sort, highlighting]) useEffect(() => { if (highlighting) { @@ -156,7 +160,7 @@ export function SourcePanel({ name, model, blockStates, doCopy, doDownload, doIm editor.current.configure(indent, format === 'snbt' ? 'yaml' : format) retransform.current() } - }, [indent, format, highlighting, braceLoaded]) + }, [indent, format, sort, highlighting, braceLoaded]) useEffect(() => { if (doCopy && model && blockStates) { @@ -210,6 +214,8 @@ export function SourcePanel({ name, model, blockStates, doCopy, doDownload, doIm changeFormat(key)} />)}
+ setSort(sort === 'alphabetically' ? 'schema' : 'alphabetically')} /> changeHighlighting(!highlighting)} /> diff --git a/src/app/services/Source.ts b/src/app/services/Source.ts index 6206b71b..b8c6adc3 100644 --- a/src/app/services/Source.ts +++ b/src/app/services/Source.ts @@ -60,3 +60,27 @@ export function getSourceIndents() { export function getSourceFormats() { return Object.keys(FORMATS) } + +export function sortData(data: any): any { + if (typeof data !== 'object' || data === null) { + return data + } + if (Array.isArray(data)) { + return data.map(sortData) + } + const ordered = Object.create(null) + for (const symbol of Object.getOwnPropertySymbols(data)) { + ordered[symbol] = data[symbol] + } + const orderedKeys = Object.keys(data).sort(customOrder) + for (const key of orderedKeys) { + ordered[key] = sortData(data[key]) + } + return ordered +} + +const priority = ['type', 'parent'] +function customOrder(a: string, b: string) { + return (priority.indexOf(a) + 1 || Infinity) - (priority.indexOf(b) + 1 || Infinity) + || a.localeCompare(b) +} diff --git a/src/locales/en.json b/src/locales/en.json index d258a8f3..54c70095 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -235,6 +235,7 @@ "show_output": "Show output", "show_preview": "Show preview", "show_project": "Show project", + "sort_alphabetically": "Sort alphabetically", "sounds.add_sound": "Add sound", "sounds.copy_command": "Copy command", "sounds.delay": "Delay",