1
0
Fork 0

allow using JSON, JSON5, Hjson and YAML in KeyValueEdit

This commit is contained in:
ChaotiCryptidz 2022-01-13 18:31:19 +00:00
parent 0547d2398f
commit b461169f2c
3 changed files with 63 additions and 28 deletions

View file

@ -2,13 +2,15 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.16.7", "@babel/core": "^7.16.7",
"@babel/eslint-parser": "^7.16.5", "@babel/eslint-parser": "^7.16.5",
"@babel/plugin-syntax-import-assertions": "^7.16.7",
"@babel/plugin-proposal-class-properties": "^7.16.7", "@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-decorators": "^7.16.7", "@babel/plugin-proposal-decorators": "^7.16.7",
"@babel/plugin-proposal-object-rest-spread": "^7.16.7", "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
"@babel/plugin-syntax-import-assertions": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.16.8", "@babel/plugin-transform-runtime": "^7.16.8",
"@babel/preset-env": "^7.16.8", "@babel/preset-env": "^7.16.8",
"@types/file-saver": "^2.0.4", "@types/file-saver": "^2.0.4",
"@types/hjson": "^2.4.3",
"@types/js-yaml": "^4.0.5",
"@types/prismjs": "^1.16.6", "@types/prismjs": "^1.16.6",
"@types/uikit": "^3.3.2", "@types/uikit": "^3.3.2",
"@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/eslint-plugin": "^5.9.1",
@ -41,6 +43,8 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"hjson": "^3.2.2", "hjson": "^3.2.2",
"i18next": "^21.6.5", "i18next": "^21.6.5",
"js-yaml": "^4.1.0",
"json5": "^2.2.0",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"preact": "^10.6.4", "preact": "^10.6.4",
"preact-router": "^4.0.0", "preact-router": "^4.0.0",

View file

@ -12,8 +12,10 @@ UIkit.use(Icons);
import Prism from "prismjs"; import Prism from "prismjs";
// Don't Sort These! // Don't Sort These!
import "prismjs/components/prism-hcl"; import "prismjs/components/prism-hcl";
import "prismjs/components/prism-javascript";
import "prismjs/components/prism-json"; import "prismjs/components/prism-json";
import "prismjs/components/prism-json5";
import "prismjs/components/prism-javascript";
import "prismjs/components/prism-yaml";
Prism.highlightAll(); Prism.highlightAll();
/* eslint-enable */ /* eslint-enable */

View file

@ -4,30 +4,42 @@ import { DefaultPageProps } from "../../../../types/DefaultPageProps";
import { SecretTitleElement } from "../SecretTitleElement"; import { SecretTitleElement } from "../SecretTitleElement";
import { setErrorText } from "../../../../pageUtils"; import { setErrorText } from "../../../../pageUtils";
import { sortedObjectMap } from "../../../../utils"; import { sortedObjectMap } from "../../../../utils";
import Hjson from "hjson";
import i18next from "i18next";
import { InputWithTitle } from "../../../elements/InputWithTitle"; import { InputWithTitle } from "../../../elements/InputWithTitle";
import Hjson from "hjson";
import JSON5 from "json5";
import yaml from "js-yaml";
import i18next from "i18next";
// todo: put this in settings
const defaultIndent = 2;
function parseJSON(data: string, hJSON = false): Record<string, unknown> { function parseData(data: string, syntax: string = "json"): Record<string, unknown> {
if (hJSON) { if (syntax == "json") {
return Hjson.parse(data);
} else {
return JSON.parse(data); return JSON.parse(data);
} else if (syntax == "json5") {
return JSON5.parse(data);
} else if (syntax == "hjson") {
return Hjson.parse(data);
} else if (syntax == "yaml") {
return yaml.load(data) as Record<string, unknown>;
} }
} }
function dumpJSON(data: Record<string, unknown>, space: number = 0, hJSON = false): string { function dumpData(data: Record<string, unknown>, space: number = defaultIndent, syntax: string = "json"): string {
if (hJSON) { if (syntax == "json") {
return Hjson.stringify(data, null, space);
} else {
return JSON.stringify(data, null, space); return JSON.stringify(data, null, space);
} else if (syntax == "json5") {
return JSON5.stringify(data, null, space);
} else if (syntax == "hjson") {
return Hjson.stringify(data, { space: space });
} else if (syntax == "yaml") {
return yaml.dump(data, { indent: space });
} }
} }
export function isValidJSON(str: string, hJSON = false): boolean { export function validateData(str: string, syntax: string = "json"): boolean {
try { try {
parseJSON(str, hJSON); parseData(str, syntax);
} catch (e) { } catch (e) {
return false; return false;
} }
@ -43,22 +55,22 @@ export type KVEditProps = DefaultPageProps & {
type KVEditState = type KVEditState =
| { | {
dataLoaded: false; dataLoaded: false;
useHJSON: boolean; syntax: string;
} }
| { | {
dataLoaded: true; dataLoaded: true;
kvData: Record<string, unknown>; kvData: Record<string, unknown>;
code: string; code: string;
useHJSON: boolean; syntax: string;
}; };
export class KVEditor extends Component<KVEditProps, KVEditState> { export class KVEditor extends Component<KVEditProps, KVEditState> {
constructor() { constructor() {
super(); super();
// TODO: add a global use Hjson option to settings for default // TODO: add a global syntax option to settings for default
this.state = { this.state = {
dataLoaded: false, dataLoaded: false,
useHJSON: false, syntax: "json",
}; };
} }
@ -66,7 +78,7 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
if (!this.state.dataLoaded) return; if (!this.state.dataLoaded) return;
const editorContent = this.state.code; const editorContent = this.state.code;
if (!isValidJSON(editorContent, this.state.useHJSON)) { if (!validateData(editorContent, this.state.syntax)) {
setErrorText(i18next.t("kv_sec_edit_invalid_json_err")); setErrorText(i18next.t("kv_sec_edit_invalid_json_err"));
return; return;
} }
@ -75,7 +87,7 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
this.props.baseMount, this.props.baseMount,
this.props.secretPath.map((e) => e + "/"), this.props.secretPath.map((e) => e + "/"),
this.props.secretItem, this.props.secretItem,
parseJSON(editorContent, this.hJSONToggleRef.current.checked), parseData(editorContent, this.state.syntax),
); );
window.history.back(); window.history.back();
} }
@ -106,28 +118,45 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
} }
getStringKVData(data: Record<string, unknown>): string { getStringKVData(data: Record<string, unknown>): string {
return dumpJSON(Object.fromEntries(sortedObjectMap(data)), 4, this.state.useHJSON); return dumpData(Object.fromEntries(sortedObjectMap(data)), defaultIndent, this.state.syntax);
} }
hJSONToggleRef = createRef<HTMLInputElement>() syntaxSelectRef = createRef<HTMLSelectElement>()
render(): JSX.Element { render(): JSX.Element {
if (!this.state.dataLoaded) { if (!this.state.dataLoaded) {
return <p>{i18next.t("content_loading")}</p>; return <p>{i18next.t("content_loading")}</p>;
} }
let codeEditorLanguage: string;
if (this.state.syntax == "json") {
codeEditorLanguage = "json"
} else if (this.state.syntax == "json5") {
codeEditorLanguage = "json5"
}else if (this.state.syntax == "hjson") {
codeEditorLanguage = "js"
} else if (this.state.syntax == "yaml") {
codeEditorLanguage = "yaml"
}
return ( return (
<div> <div>
<InputWithTitle title="Use Hjson"> <InputWithTitle title="Syntax">
<input ref={this.hJSONToggleRef} type="checkbox" class="uk-checkbox" onChange={() => { <select ref={this.syntaxSelectRef} class="uk-select uk-form-width-medium" onChange={() => {
this.setState({useHJSON: this.hJSONToggleRef.current.checked}) this.setState({ syntax: this.syntaxSelectRef.current.value })
}} />
}}>
<option label="JSON" value="json" />
<option label="JSON5" value="json5" />
<option label="Hjson" value="hjson" />
<option label="Yaml" value="yaml" />
</select>
</InputWithTitle> </InputWithTitle>
<p class="uk-text-danger" id="errorText" /> <p class="uk-text-danger" id="errorText" />
<CodeEditor <CodeEditor
language="js" language={codeEditorLanguage}
tabSize={4} tabSize={defaultIndent}
code={this.getStringKVData(this.state.kvData)} code={this.getStringKVData(this.state.kvData)}
onUpdate={(code) => this.onCodeUpdate(code)} onUpdate={(code) => this.onCodeUpdate(code)}
/> />