From f39ffacee048f86c331514b89fa08fb24565e429 Mon Sep 17 00:00:00 2001 From: omercelikdev Date: Fri, 28 Aug 2026 14:10:12 +0300 Subject: [PATCH] fix(json-editor): an empty document is never a lint error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A blank editor is an invitation, not a mistake — the linter answers no diagnostics for a zero-length document and stays exactly as strict the moment content appears. Consumers no longer toggle `lint` for the empty state, which recreated the editor mid-typing (lint participates in the setup effect) and stole the cursor on the first keystroke. Co-Authored-By: Claude Fable 5 --- .changeset/calm-empty-editor.md | 11 +++++++++++ src/json-editor/index.tsx | 8 ++++++-- src/json-editor/json-editor.test.tsx | 11 +++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .changeset/calm-empty-editor.md diff --git a/.changeset/calm-empty-editor.md b/.changeset/calm-empty-editor.md new file mode 100644 index 0000000..6e7a73c --- /dev/null +++ b/.changeset/calm-empty-editor.md @@ -0,0 +1,11 @@ +--- +"@qorpe/ui": patch +--- + +fix(json-editor): an empty document is never a lint error + +The JSON linter flagged an empty editor as a parse error — a red dot on line 1 of +nothing. A blank editor is an invitation, not a mistake; the linter now answers no +diagnostics for a zero-length document and stays exactly as strict the moment content +appears. Consumers no longer need to toggle `lint` off for the empty state — which +also recreated the editor mid-typing, since `lint` participates in the setup effect. diff --git a/src/json-editor/index.tsx b/src/json-editor/index.tsx index a34b4a8..6cd1736 100644 --- a/src/json-editor/index.tsx +++ b/src/json-editor/index.tsx @@ -51,8 +51,12 @@ const extensions = (readOnly: boolean, onChange: ((v: string) => void) | undefin bracketMatching(), keymap.of([...defaultKeymap, ...historyKeymap, ...foldKeymap, indentWithTab]), json(), - // Bodies may hold template syntax ({{…}}), so linting is opt-out — no false parse errors. - ...(lint ? [linter(jsonParseLinter()), lintGutter()] : []), + // Bodies may hold template syntax ({{…}}), so linting is opt-out — no false parse + // errors. An EMPTY document is never an error either: a blank editor is an invitation, + // and a red parse dot on line 1 of nothing teaches only confusion. + ...(lint + ? [linter((view) => (view.state.doc.length === 0 ? [] : jsonParseLinter()(view))), lintGutter()] + : []), syntaxHighlighting(highlight), theme, EditorState.readOnly.of(readOnly), diff --git a/src/json-editor/json-editor.test.tsx b/src/json-editor/json-editor.test.tsx index b1ca402..b8bf366 100644 --- a/src/json-editor/json-editor.test.tsx +++ b/src/json-editor/json-editor.test.tsx @@ -17,6 +17,17 @@ describe("the json editor subpath (RFC D6) — CodeMirror stays out of the main expect(container.textContent).not.toContain('"a"'); }); + it("an EMPTY document is never a lint error — broken JSON still is", async () => { + // A blank editor is an invitation, not a mistake: no red dot on line 1 of nothing. + const empty = render(); + const broken = render(); + // CodeMirror's linter runs on a delay; the broken editor's marker is the clock. + await vi.waitFor(() => { + expect(broken.container.querySelector(".cm-lint-marker")).toBeTruthy(); + }, { timeout: 3000 }); + expect(empty.container.querySelector(".cm-lint-marker")).toBeNull(); + }); + it("Beautify pretty-prints valid JSON and leaves templated bodies untouched", async () => { const onChange = vi.fn(); render();