1- import { json as jsonLang } from "@codemirror/lang-json" ;
2- import type { ViewUpdate } from "@codemirror/view" ;
1+ import { json as jsonLang , jsonParseLinter } from "@codemirror/lang-json" ;
2+ import type { EditorView , ViewUpdate } from "@codemirror/view" ;
33import { CheckIcon , ClipboardIcon , TrashIcon } from "@heroicons/react/20/solid" ;
44import type { ReactCodeMirrorProps , UseCodeMirror } from "@uiw/react-codemirror" ;
55import { useCodeMirror } from "@uiw/react-codemirror" ;
@@ -8,6 +8,7 @@ import { cn } from "~/utils/cn";
88import { Button } from "../primitives/Buttons" ;
99import { getEditorSetup } from "./codeMirrorSetup" ;
1010import { darkTheme } from "./codeMirrorTheme" ;
11+ import { linter , lintGutter , type Diagnostic } from "@codemirror/lint" ;
1112
1213export interface JSONEditorProps extends Omit < ReactCodeMirrorProps , "onBlur" > {
1314 defaultValue ?: string ;
@@ -18,18 +19,35 @@ export interface JSONEditorProps extends Omit<ReactCodeMirrorProps, "onBlur"> {
1819 onBlur ?: ( code : string ) => void ;
1920 showCopyButton ?: boolean ;
2021 showClearButton ?: boolean ;
22+ linterEnabled ?: boolean ;
23+ allowEmpty ?: boolean ;
2124}
2225
2326const languages = {
2427 json : jsonLang ,
2528} ;
2629
30+ function emptyAwareJsonLinter ( ) {
31+ return ( view : EditorView ) : Diagnostic [ ] => {
32+ const content = view . state . doc . toString ( ) . trim ( ) ;
33+
34+ // return no errors if content is empty
35+ if ( ! content ) {
36+ return [ ] ;
37+ }
38+
39+ return jsonParseLinter ( ) ( view ) ;
40+ } ;
41+ }
42+
2743type JSONEditorDefaultProps = Partial < JSONEditorProps > ;
2844
2945const defaultProps : JSONEditorDefaultProps = {
3046 language : "json" ,
3147 readOnly : true ,
3248 basicSetup : false ,
49+ linterEnabled : true ,
50+ allowEmpty : true ,
3351} ;
3452
3553export function JSONEditor ( opts : JSONEditorProps ) {
@@ -44,6 +62,8 @@ export function JSONEditor(opts: JSONEditorProps) {
4462 autoFocus,
4563 showCopyButton = true ,
4664 showClearButton = true ,
65+ linterEnabled,
66+ allowEmpty,
4767 } = {
4868 ...defaultProps ,
4969 ...opts ,
@@ -56,6 +76,19 @@ export function JSONEditor(opts: JSONEditorProps) {
5676
5777 extensions . push ( languageExtension ( ) ) ;
5878
79+ if ( linterEnabled ) {
80+ extensions . push ( lintGutter ( ) ) ;
81+
82+ switch ( language ) {
83+ case "json" : {
84+ extensions . push ( allowEmpty ? linter ( emptyAwareJsonLinter ( ) ) : linter ( jsonParseLinter ( ) ) ) ;
85+ break ;
86+ }
87+ default :
88+ language satisfies never ;
89+ }
90+ }
91+
5992 const editor = useRef < HTMLDivElement > ( null ) ;
6093 const settings : Omit < UseCodeMirror , "onBlur" > = {
6194 ...opts ,
0 commit comments