Rendered from specs/F01-preview.md — edit it there, not here.
F01 — Schema Preview Panel
Overview
The extension renders a JSON Schema document as human-readable HTML documentation in a VS Code webview panel beside the editor. Rendering is delegated to the json-schema-for-humans Python tool.
User Stories
- As a schema author, I want to see a formatted view of my schema so I can review it without reading raw JSON or YAML.
- As a team lead, I want to share rendered schema documentation with colleagues who do not have the extension installed (via the Download button).
Functional Requirements
Activation
- F01-FR-01 The extension MUST activate on files with
languageIdinjson,jsonc,yaml,yml, orjsonl. - F01-FR-02 A file SHALL be considered a JSON Schema file if its parsed root object contains a
$schemakey (JSON/JSONC) or a line matching^\$schema:is present (YAML), and that key's value is a URL string whose hostname is exactlyjson-schema.org(the meta-schema host for every draft from draft-04 through 2020-12) — determined by parsing the value as a URL and comparing its hostname, not by a substring/includescheck, which would also match an unrelated or attacker-controlled host such asjson-schema.org.evil.comorevil.com/?x=json-schema.org. A$schemavalue that does not resolve to that hostname — e.g. a data file bound to a schema via its own inline$schemafield (F10), which points at a schema file rather than declaring itself to be one — MUST NOT be considered a JSON Schema file. - F01-FR-03 When a schema file is the active editor the VS Code context key
jsonschema.isJsonSchemaMUST be set totrue; it MUST be set tofalsefor all other files.
Preview Command
- F01-FR-04 The command
jsonschema.previewMUST open the preview panel inViewColumn.Two. - F01-FR-05 If the preview for a given file is already open the command MUST focus the existing panel rather than opening a duplicate.
- F01-FR-06 The panel title MUST be the basename of the schema file.
- F01-FR-07 While the Python tool is running the panel MUST display a loading message.
- F01-FR-08 The preview MUST be regenerated and the panel refreshed every time the schema file is saved.
Toolbar and Context Menu
- F01-FR-09 The Preview toolbar icon (eye) MUST appear in the editor title bar only when
jsonschema.isJsonSchemaistrue.
Config File Discovery
- F01-FR-10 The extension MUST search for
.json-schema-preview-config.jsonstarting from the workspace folder that owns the schema file, falling back to other workspace folders in order. - F01-FR-11 When no config file is found the extension MUST pass
--config template_name=flattojson-schema-for-humans.
Download Button
- F01-FR-12 The rendered preview MUST include a floating Download button in the bottom-right corner.
- F01-FR-13 Clicking Download MUST open a Save dialog pre-filled with the schema filename stem and the correct extension (
.htmlfor HTML templates,.mdfor Markdown templates). - F01-FR-14 The raw generated content MUST be written verbatim to the chosen path.
External Links
- F01-FR-15 Clicking any
<a href>in the rendered HTML that is not a fragment anchor (#…) MUST open the URL in the user's default browser viavscode.env.openExternal. - F01-FR-16 Fragment anchors MUST scroll within the webview normally.
Scroll Position
- F01-FR-17 When the preview panel is refreshed (on save) the webview MUST restore the previous scroll position.
Python Interpreter and Dependency Management
- F01-FR-23 The extension MUST resolve the Python interpreter in this order: the active environment reported by the VS Code Python extension (
ms-python.python, environments API with legacy-API fallback), then thepython.defaultInterpreterPath/python.pythonPathsetting, then plainpython3on thePATH. - F01-FR-24 Before rendering, if the
json_schema_for_humanspackage is not importable under the resolved interpreter, the extension MUST attempt to install it automatically via pip under a progress notification. Install attempts MUST try--userfirst and MUST include--break-system-packagesvariants so PEP 668 externally-managed system Pythons (Ubuntu 23.04+/Debian Bookworm+) are handled, before falling back topip3/pipexecutables. - F01-FR-25 Once the package is confirmed importable under an interpreter, the check MUST NOT re-run for that interpreter within the same extension-host session.
- F01-FR-26 If every automatic install attempt fails the resulting error MUST include manual installation instructions (a copy-pasteable
pipcommand and a virtual-environment alternative).
Error Handling
- F01-FR-18 If
json-schema-for-humansis not installed the error page MUST display a contextual hint with thepip installcommand. - F01-FR-19 If the Python interpreter is not found the error page MUST display a hint directing the user to install Python 3 or select an interpreter via the VS Code Python extension.
- F01-FR-20 If generation times out the error page MUST show a timeout hint.
Fallback Renderer
- F01-FR-21 When the Python interpreter or the
json-schema-for-humanspackage is unavailable, the extension MUST render a built-in, dependency-free HTML documentation page for the schema instead of only showing an error, so the schema remains previewable without Python. A schema-level error (as opposed to missing tooling) MUST still surface the error page. - F01-FR-22 The fallback page MUST be self-contained (inline styles, no scripts, a static
default-src 'none'CSP) and MUST HTML-escape every schema-derived string so schema content cannot inject markup. - F01-FR-27 A
jsonschema.preview.renderersetting MUST let the user choose the preview engine:"auto"(default) usesjson-schema-for-humanswhen available and falls back to the built-in renderer otherwise (the F01-FR-21 behaviour);"builtin"MUST always use the built-in renderer and MUST NOT invoke Python at all — so users who don't have (or don't want) Python get the built-in output directly, with no interpreter probe or install prompt. The setting's value MUST resolve through a pure, testable helper that defaults to"auto"for any missing or unrecognised value.
Non-Functional Requirements
- F01-NFR-01 The panel MUST use
retainContextWhenHidden: trueto avoid re-running the Python tool on every tab switch (accepted memory tradeoff). - F01-NFR-02 The webview's
localResourceRootsMUST be scoped to the directory of the schema file being rendered. - F01-NFR-03 The fallback page MUST expose the schema title as a top-level
<h1>and nested property groups as sub-headings, and MUST NOT convey the required/optional distinction by colour alone (see S06-SR-04 / S06-SR-07).
Acceptance Criteria
- Opening a
.jsonfile with"$schema": "http://json-schema.org/draft-07/schema#"and running JSON Schema: Preview shows a populated documentation panel within the timeout period. - Saving the schema file causes the preview to refresh automatically.
- The Download button produces a file whose content matches what the Python tool generated.
- Clicking an
http://…link inside the preview opens a browser tab. - A data file whose own
"$schema"value points at a schema path (e.g."$schema": "./schemas/person.schema.json", written by inline binding — F10) is NOT treated as a JSON Schema file:jsonschema.isJsonSchemastaysfalse, the Preview/Edit/Configure toolbar icons don't appear, and Validate/Infer icons show instead.
Requirement traceability
Status of each requirement in specs/traceability.json. Test coverage is auto-discovered from [ID] tags in test titles and is not listed here.
| Requirement | Status | Implementation | Note |
|---|---|---|---|
F01-FR-01 | implemented | package.json | activationEvents include onLanguage json/jsonc/yaml/yml/jsonl (manifest.test.ts) |
F01-FR-02 | implemented | src/PreviewWebPanel.ts | isJsonSchemaFile() requires the $schema value's URL hostname to be exactly json-schema.org (parsed via the URL constructor, not a substring/includes check — CodeQL js/incomplete-url-substring-sanitization), so an inline-bound data file (F10) isn't misclassified as a schema; unit-tested |
F01-FR-03 | implemented | src/extension.ts, src/PreviewWebPanel.ts | setContext jsonschema.isJsonSchema true/false (extension.test.ts) |
F01-FR-04 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-05 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-06 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-07 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-08 | manual | src/extension.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-09 | implemented | package.json | editor/title preview icon gated on jsonschema.isJsonSchema |
F01-FR-10 | implemented | src/PreviewWebPanel.ts | findConfigFile() unit-tested |
F01-FR-11 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-12 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-13 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-14 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-15 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-16 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-17 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-18 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-19 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-20 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-FR-21 | implemented | src/fallbackRenderer.ts, src/PreviewWebPanel.ts | renderSchemaHtml + isToolingUnavailable unit-tested; wired into generateDocHTML |
F01-FR-22 | implemented | src/fallbackRenderer.ts | static CSP, no scripts, sanitizeHtml on all schema text; unit-tested |
F01-FR-23 | manual | src/python.ts | getPythonInterpreter: Python-ext environments API -> legacy API -> settings -> python3; python.ts is subprocess-bound (coverage-excluded), verified manually |
F01-FR-24 | manual | src/python.ts | ensureInstalled: pip candidates incl. --user and --break-system-packages under withProgress; python.ts is subprocess-bound (coverage-excluded), verified manually |
F01-FR-25 | manual | src/python.ts | packageReadyFor per-interpreter set skips re-checking within the session; python.ts is subprocess-bound (coverage-excluded), verified manually |
F01-FR-26 | manual | src/python.ts | final throw includes pip command and venv alternative instructions; python.ts is subprocess-bound (coverage-excluded), verified manually |
F01-FR-27 | implemented | src/settings.ts, src/PreviewWebPanel.ts | jsonschema.preview.renderer setting; getPreviewRenderer() (auto|builtin, default auto) unit-tested in settings.test.ts; PreviewWebPanel.generateDocHTML short-circuits to the already-tested renderFallbackHTML when builtin, skipping the Python probe |
F01-NFR-01 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-NFR-02 | manual | src/PreviewWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F01-NFR-03 | implemented | src/fallbackRenderer.ts | h1 title + h3 nested groups + textual required marker; unit-tested |