I am working on a project using Nextjs, Reactjs and TypeScript. I have integrated Monaco editor in the website and want to validate the user provided JSON code against the draft 2020-12. I am using ajv for validation.
But it is not working as excepted.
Here is the React code I am using:
This is the Output component:
import React, { useState } from "react";
import * as schema from "~/_includes/draft/2020-12/schema.json";
import Ajv from "ajv/dist/2020";
const ajv = new Ajv({strict: false, allErrors: true });
interface OutputProps {
editorRef: React.RefObject<any>; // Adjust type as per your editorRef
language: string; // Adjust type as per your language
}
const Output: React.FC<OutputProps> = ({ editorRef, language }) => {
const [output, setOutput] = useState<string[] | null>(null);
const sourceCode = editorRef.current?.getValue();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);
const runCode = async () => {
const sourceCode = editorRef.current.getValue();
setIsLoading(true);
if (!sourceCode) return;
try {
const validate = ajv.compile(schema);
const userSchema = JSON.parse(sourceCode);
const valid = validate(userSchema);
if (!valid) {
console.log("wrong");
// throw new Error("Invalid JSON code: " + validate.errors);
throw new Error("Invalid JSON code: ");
}
else{
setOutput(["Valid JSON"]);
console.log("correct");
}
} catch (error: any) {
console.error("Validation error:", error);
setOutput([error.message]); // Display the validation error
setIsError(true);
}
finally {
setIsLoading(false);
}
};
return (
<div style={{ width: "50%" }}>
<h2 style={{ fontSize: "1.5rem", marginBottom: "0.5rem" }}>Output</h2>
<button
style={{
padding: "0.5rem 1rem",
fontSize: "1rem",
marginBottom: "1rem",
backgroundColor: isLoading ? "#ccc" : "#4caf50",
color: "#fff",
border: "none",
borderRadius: "4px",
cursor: "pointer",
}}
disabled={isLoading}
onClick={runCode}
>
{isLoading ? "Running..." : "Run Code"}
</button>
<div
style={{
height: "75vh",
padding: "0.5rem",
border: `1px solid ${isError ? "red" : "#333"}`,
borderRadius: "9px",
overflowY: "auto",
backgroundColor: isError ? "#ffcdd2" : "#f5f5f5",
}}
>
{output
? output.map((line, i) => <p key={i}>{line}</p>)
: 'Click "Run Code" to see the output here'}
</div>
</div>
);
};
export default Output;
This is the Code editor component:
import React, { useRef, useState } from "react";
// import { Box, HStack } from "@chakra-ui/react";
import { Editor } from "@monaco-editor/react";
import LanguageSelector from "./LanguageSelector";
import Output from "./Output";
import Ajv from "ajv";
import { LANGUAGE_VERSIONS, CODE_SNIPPETS } from "~/constants/languages";
const ajv = new Ajv();
const CodeEditor: React.FC = () => {
const editorRef = useRef<any>(null);
const [value, setValue] = useState<string>("");
const [language, setLanguage] = useState<string>("json");
const onMount = (editor: any) => {
editorRef.current = editor;
editor.focus();
};
// type Language = keyof typeof CODE_SNIPPETS;
const onSelect = (language: string) => {
setLanguage(language);
setValue(CODE_SNIPPETS[language]);
};
return (
<div className="flex w-full">
<div className="w-1/2">
{/* <LanguageSelector language={language} onSelect={onSelect}/> */}
<Editor
options={{
minimap: {
enabled: false,
},
}}
height="75vh"
width="80%"
theme="vs-dark"
language={language}
defaultValue={CODE_SNIPPETS[language]}
onMount={onMount}
value={value}
onChange={(value) => setValue(value || '')}
/>
</div>
<Output editorRef={editorRef} language={language} />
<div><LanguageSelector language={language} onSelect={onSelect}/></div>
</div>
);
};
export default CodeEditor;
I have tried using the URI for importing the JSON schema file as well as added the draft 2020-12 file in my project. Both of them are giving the same error as
schema with key or id "https://json-schema.org/draft/2020-12/schema" already exists
If anyone has any suggestion please help.