Skip to content

Releases: johannes-kaindl/json-editor

1.9.0

16 Jun 11:02
e8dd29d

Choose a tag to compare

Eval-free JSON Schema validation + a clean community-review report. Replaces the Ajv validator with the eval-free @cfworker/json-schema, and drives the type-aware ESLint findings from the community.obsidian.md review to zero. The plugin bundle is ~52% smaller.

Changed

  • JSON Schema validation now uses @cfworker/json-schema instead of Ajv. It is an eval-free, tree-walking validator (no new Function / no eval), so the automated review's "dynamic code execution" disclosure no longer applies. The bundle drops from ~176 KB to ~85 KB. Supported drafts are a superset of before (draft-04/07/2019-09/2020-12 vs. draft-07-only); the public validation contract (inline row errors + the error-count banner) is unchanged.
  • format keywords are now enforced. The previous Ajv build ran without ajv-formats, so format (email, uri, date-time, …) was a no-op annotation. The new validator enforces formats in draft-07 mode, so a value that violates a format constraint in an (opt-in) companion schema now reports an error. A structurally malformed companion schema (e.g. {"type": 123}) is still rejected via draft-07 meta-validation; a merely cosmetic, non-URI $id no longer disables validation for the whole file.

Fixed

  • The community-review ESLint warnings are now zero. The review's type-aware linter resolved obsidian to the Vitest mock (via a tsconfig.json paths alias), so every Obsidian-typed expression was flagged as no-unsafe-* and one assertion as no-unnecessary-type-assertion. The mock alias is gone from tsconfig.json (real Obsidian types now resolve), the Vitest mock moved to tests/__mocks__/, and the redundant assertions were removed. None of this changes runtime behavior. A committed npm run lint:portal guard now mirrors the review so the warnings cannot silently come back.

Internal

  • Added tsconfig.test.json (editor typing of tests against the mock), eslint.portal.config.mjs + npm run lint:portal, and src/core/draft07-meta-schema.ts. The Vitest suite (601 tests) pins the new validator's error granularity and format behavior.

1.8.2

15 Jun 22:55
78d308b

Choose a tag to compare

Lint follow-up. Fixes a regression in 1.8.1's review cleanup.

Fixed

  • 1.8.1 silenced the prefer-active-doc warnings by using the activeDocument global, but the community-review's type-aware linter sees activeDocument as any (it doesn't load Obsidian's ambient global declarations), which cascaded into many no-unsafe-* warnings across the UI components. DOM access now goes through a typed activeDoc(): Document helper, so call sites stay type-safe (prefer-active-doc remains satisfied). Functionally identical; our own tsc against the real Obsidian types was clean throughout.

1.8.1

15 Jun 22:28
94ecb93

Choose a tag to compare

Review cleanup. Addresses the recommendations and warnings from the Obsidian Community automated review (which had passed with no errors). No user-facing behavior changes — pop-out windows aside.

Fixed

  • Pop-out window correctness (audit §2.11). All DOM creation now uses Obsidian's activeDocument (or, in the pure core/render, a Document injected by the adapter) instead of the global document, and element type checks use Obsidian's cross-window-safe Node.instanceOf. Rendering a JSON view in a detached window now works correctly. (Resolves ~70 prefer-active-doc + 3 instanceof review warnings.)

Changed

  • Replaced the builtin-modules build dependency with Node's built-in module.builtinModules (one fewer dependency).
  • Removed !important from the stylesheet (uses selector specificity instead); made Settings onChange handlers non-async (no-misused-promises); dropped redundant type assertions.

Added

  • Build-provenance attestations for the release assets (actions/attest-build-provenance), so users can cryptographically verify the assets were built from this repo.

Documentation

  • SECURITY.md discloses Ajv's new Function schema-compilation (opt-in only; no plugin code uses eval/new Function) and the clipboard copy behavior.

1.8.0

15 Jun 11:28
9d4931d

Choose a tag to compare

Mobile interaction model. Tree-mode editing is now fully usable on touch devices, with no dead or invisible affordances. No desktop behavior changes beyond two additive improvements (keyboard reorder, focus-revealed copy button).

Added

  • Cmd/Ctrl+E toggles Tree/Source while a JSON view is focused. It's handled by the view-local keymap scope (not a global command hotkey), so it never shadows the core "Toggle reading view" binding in Markdown — and the Toggle tree/source view command remains for custom rebinding. (Same scope mechanism that already powers Cmd/Ctrl+F/Z/Shift+Z inside JSON views.)
  • Long-press action menu (mobile). On Obsidian mobile, long-pressing a tree row opens a consolidated menu with Copy value · Copy path · Rename key · Change type · Move up/down · Delete — replacing the hover-only inline buttons and drag-and-drop, which don't work on touch (audit §4.2, §4.3, §6.10).
  • Alt+ArrowUp / Alt+ArrowDown reorder the focused row within its parent — a keyboard path for reordering on every platform (previously only mouse drag-and-drop; audit §4.2).
  • Undo/Redo toolbar buttons on mobile, with a live disabled state, since there is no hardware Mod+Z on touch (audit §4.5).

Changed

  • On mobile, the hover-revealed inline row actions, copy button and drag handle are no longer rendered (they were invisible-but-tappable — a stray tap could fire an unconfirmed delete) and rows are not marked draggable (which collided with touch scroll/long-press); all actions come from the long-press menu instead (audit §4.3, §4.4, §4.8).
  • ≥44px touch targets on mobile across the UI (audit §4.4): the collapse toggle, toolbar icon buttons (undo/redo), search-clear, mode pills, and the value-editing controls (inline text/number/key-rename field, the boolean checkbox, and the "+ Add key/item" button). The undo/redo buttons use Obsidian's native clickable-icon class for consistent sizing/theming.

Fixed

  • The copy button is now revealed on :focus-within, not just :hover (keyboard / touch-laptop access; audit §4.3.1).
  • The type-change menu now also closes on pointerdown outside, not only mousedown, so it can't get stuck open on touch.
  • hidden-toggled elements stayed visible. The large-file banner, schema banner, search bar, match-count and search-clear (×) set a display value on their class, which overrode the UA [hidden] { display: none } (equal specificity) — so el.hidden = true didn't hide them (the "Load tree anyway" button showed on every file, including small ones; the × showed with an empty query). Added explicit [hidden] overrides (the fix already present for the tooltip).
  • The large-file banner's "Load tree anyway" button rendered in the wrong (UA-default) font because it set no font-family, and read as unstyled/unclear; it now uses the interface font + native Obsidian button styling (comfortable label padding + button shadow), carries an explanatory tooltip, and the banner wraps gracefully on narrow screens. The + Add affordance gained matching padding.

Toolbar polish (audit §6.1)

  • Removed the redundant Tree/Source view-header action — the labeled toolbar toggle and the toggle-tree-source command remain the toggle paths.
  • The breadcrumb's current segment is now emphasized by font weight instead of a filled accent chip, so it reads as a path location rather than a button.

Accessibility & polish (pre-publish pass)

  • Breadcrumb segments are now real <button>s — Tab-focusable and Enter/Space-operable with a visible focus ring (WCAG 2.1.1); previously they were <span>s with click-only handlers.
  • The copy button and tree row-action buttons now use the interface font (parity with the rest of the chrome), and the copy button gained an aria-label.

Notes

  • isDesktopOnly stays false (the plugin uses no Node/Electron APIs). Real pointer-events touch-drag and the broader mobile/perf items (virtualization, source-mode debounce) remain deferred to a later release.

1.7.0

13 Jun 14:55
936a633

Choose a tag to compare

Rename & submission-prep release. No functional changes to the editor — this renames the plugin for the Community Plugin Directory and completes the documentation/attribution pass.

Changed

  • Plugin ID renamed obsidian-json-editorjson-editor. The Obsidian guidelines disallow an obsidian--prefixed plugin id; the manifest id and the on-disk plugin folder change accordingly. The internal view type is unchanged, so existing layouts are unaffected. After updating, move/rename your plugin folder to .obsidian/plugins/json-editor/.
  • Manifest/package description tightened to "View and edit JSON files with a Tree/Source toggle. Renders JSON code blocks in Markdown notes."

Added

  • THIRD-PARTY-NOTICES.md — full license texts for the bundled dependencies (ajv + transitive fast-uri (BSD-3-Clause) / fast-deep-equal / json-schema-traverse, plus @codemirror/lang-json and @lezer/json, all MIT). Attribution is also carried in the main.js banner.

Documentation

  • README aligned to the actual 1.6.0 feature set (status, unified undo, tree-mode structural editing, schema validation, drag-drop, type-switching, large-file guard, all six settings, a Known conflicts section, shipped-vs-2.x roadmap), the dependency-license note corrected, and a documented tree-edit limitation (numeric-string object keys may reorder on save — audit 1.4).
  • SECURITY.md threat model updated — prototype-pollution fixed; ReDoS opt-in + heuristic guard + honest residual surface.
  • AGENTS.md submission path rewritten to the community.obsidian.md portal flow.

1.6.0

13 Jun 10:42
843fa14

Choose a tag to compare

Guideline & UX release. Aligns with the Obsidian plugin guidelines and ships the high-value editing/UX gaps from the pre-submission audit.

Heads-up: minAppVersion is now 1.5.7 (the new view-scoped keymap needs it).

Added

  • Tree/Source toggle command (Toggle tree/source view) plus a view-header icon — the mode toggle is now keyboard- and command-bindable (bind your own hotkey; no default is set to avoid clashing with the core Toggle reading view).
  • Search in Source modeCmd/Ctrl+F (focus-search) now opens CodeMirror's find panel when you're in source mode instead of yanking you to tree; tree mode still focuses the tree search bar.
  • Large-file guard — files above a render budget (~1 MB or ~15k nodes) open in Source mode with a Load tree anyway banner, so a multi-MB file no longer freezes the UI on open.

Changed

  • No more default hotkeys on commands. Focus search, Undo edit, Redo edit (renamed, sentence-case) carry no default hotkey, per the guidelines; a view-local keymap still handles Mod+F/Mod+Z/Mod+Shift+Z while the JSON view is focused — and now correctly falls through to native input undo while you're typing in an inline editor.
  • minAppVersion raised to 1.5.7 for the view-scoped keymap and view-header action APIs.
  • Various UI strings corrected to sentence case.

Fixed

  • Source-mode undo/redo no longer destroys and rebuilds the CodeMirror editor on every step — it dispatches a minimal change, preserving cursor, scroll, and focus.
  • Silent data loss / prototype reassignment when an object had a __proto__ (or other prototype-name) key and you deleted/renamed/reordered another key. Such keys are now preserved (and addable).
  • Pop-out windows: tooltips and the type-switch menu now resolve their document/window correctly instead of binding to the main window.
  • Lifecycle leaks: the Source editor and the type menu are now torn down on view unload.
  • Clipboard copy no longer throws (and now reports failure) on platforms without navigator.clipboard; companion-schema paths are normalized; window-bound timers; no hard-coded inline styles.

Internal

  • Added the official eslint-plugin-obsidianmd as a CI guideline gate (npm run lint:obsidian); Biome stays the formatter. Test count 478 → 537.

1.5.0

13 Jun 09:16
2d6a40a

Choose a tag to compare

Stability & data-integrity release. Fixes the data-loss and crash blockers found in a pre-submission audit. No new user-facing features — every change here protects your files.

Fixed

  • Cross-file undo data loss (critical). The undo history was not reset when you switched files in the same pane, so Cmd/Ctrl+Z in file B could restore — and save — file A's content over it. The same path silently reverted external/sync changes. History (and the schema, search query, and forced source mode) is now reset per file.
  • Large trees were clipped. A .json-content { max-height: 5000px } cap hid everything past roughly 200–250 expanded rows with no scrollbar. Removed.
  • Plugin death on .json conflict. If another plugin already handled .json, registerExtensions threw and the whole plugin failed to load (losing code-block rendering, settings, and commands). The claim is now guarded; on conflict you get a notice and code-block rendering keeps working.
  • Lost place after every edit. Re-rendering the tree reset manual expand/collapse, scroll position, and keyboard focus. These are now preserved across edits; after a delete, focus moves to the next sibling.
  • Big-integer corruption. Editing a number to a value beyond 2^53 silently truncated it; the tree editor now rejects such input (use source mode for big integers).

Changed

  • Schema validation is now opt-in (validateAgainstSchema defaults to false). A companion *.schema.json was previously auto-loaded and compiled on every file open; a malicious schema in a shared/synced vault could freeze Obsidian via a catastrophic-backtracking regex (ReDoS). Enable it explicitly if you trust your schema files. compileSchema now also rejects oversized schemas and obvious nested-quantifier patterns, and a stale companion-schema load can no longer apply to the wrong file.

Added

  • Lossy-number warning. When a file contains integers JSON can't represent exactly (e.g. 64-bit IDs > 2^53), a banner appears and the tree opens read-only so a tree edit can't silently rewrite them; source mode stays editable.

Internal

  • All innerHTML = "" DOM clears replaced with replaceChildren() (Community-Hub submission-gate requirement); a regression test enforces it across the source tree.
  • Test count 402 → 478 (+76), all green; build and Biome lint clean.

1.4.0

07 Jun 18:57
fd47246

Choose a tag to compare

Changed

  • Relicensed from GPL-3.0-or-later to AGPL-3.0-or-later. Documentation is now licensed separately under CC BY-SA 4.0 (see LICENSE-DOCS). Part of adopting the shared workspace conventions.
  • Adopted Biome for linting/formatting; added lint and typecheck npm scripts.
  • Convention alignment: shields.io badge row, AGENTS.md now committed with the standard section skeleton, .claude/ gitignored.

1.3.0

27 May 21:49

Choose a tag to compare

JSON Schema validation in real time. Drop a companion schema file next to any .json you edit, and the plugin highlights validation errors as you type. Closes the 1.x roadmap.

Added

  • JSON Schema validation via Ajv (v8). Default behavior: when you open data.json, the plugin looks for data.schema.json in the same folder; if found, every change in tree or source mode is validated against the schema.
  • Schema banner above the editor body shows the current error count ("3 schema errors — hover the red rows for details"). Hidden when the document is valid; switches to a yellow "schema not loaded" variant if the schema file itself is malformed.
  • Inline row markers — every tree row corresponding to a validation error gets a red outline + a hover-tooltip with the human-readable message.
  • Two new settings:
    • validateAgainstSchema (default true) — master switch.
    • companionSchemaSuffix (default .schema.json) — change to e.g. .json-schema if your conventions differ.
  • New runtime dependency: ajv@8.

Internal

  • New pure module src/core/schema.tscompileSchema(text) returns a discriminated union ({ok, schema} | {ok: false, error}); the compiled schema has a validate(value): PathError[] that converts Ajv's instancePath JSON-Pointer to our JsonPath segment array (including ~0/~1 decoding).
  • New src/obsidian/SchemaBanner.ts UI component with setErrors(n) + setSchemaParseError(msg) + hide().
  • TreeView.setValidationErrors(map) adds .json-row-error class + title attribute on offending rows; persists across re-renders.
  • JsonFileView gains setSchema(text) (public for tests/manual) and an async tryLoadCompanionSchema() that reads the sibling via app.vault.cachedRead on file open. Best-effort: silent failure if the vault is unavailable.
  • 33 new tests (12 schema core, 6 SchemaBanner, 5 TreeView row-marker, 6 JsonFileView integration, +4 settings extension). Total: 373 → 402.

Notes

  • Bundle size: main.js grows from ~37 KB to ~163 KB. The vast majority is Ajv; that is the cost of "real" JSON Schema. If you prefer the older lightweight bundle and don't need validation, turn the setting off — the validator code is still bundled but never runs.
  • $schema URL fetching is out of scope. The plugin treats $schema inside your data as metadata; it does not fetch remote schemas. Companion-file pattern is the canonical wire-up.

1.2.0

27 May 21:39

Choose a tag to compare

Unified cross-mode undo/redo. Tree mode and source mode now share a single 100-deep text-based history. Cmd/Ctrl+Z and Cmd/Ctrl+Shift+Z work in both modes; switching between tree and source no longer wipes the undo stack.

Changed

  • Unified history: every change — tree-mode mutation or source-mode text edit — pushes the pre-state TEXT onto a single shared stack. Undo/redo restore that text and refresh the active mode.
  • Mode-switch no longer clears the undo history.
  • Source mode no longer keeps a separate CodeMirror-local undo stack; the unified history captures every doc change. Trade-off: Cmd+Z in source mode now undoes per onChange event (roughly per keystroke) rather than via CodeMirror's character-grouping heuristic. In practice this is similar granularity.

Internal

  • History is now generic (History<T>). JsonFileView uses History<string> instead of the previous tree-only History<HistoryState>. The old HistoryState interface is gone; the new API takes and returns the raw T.
  • Plugin command IDs renamed: undo-tree-editundo-edit, redo-tree-editredo-edit. Hotkey bindings are unchanged.
  • 4 new integration tests in JsonFileView.undo.test.ts covering source-mode undo, source→tree cross-mode undo, tree→source cross-mode undo, and the canUndo / canRedo mode-independence guarantee.
  • Test count: 369 → 373 (existing tree-history tests reused as-is via generic typing).