Rendered from specs/F09-configuration.md — edit it there, not here.
F09 — Preview Configuration: File and Settings
Overview
json-schema-for-humans rendering (F01) is controlled by configuration that can live in either of two places, checked in this order:
- A standalone, workspace-discovered file (
.json-schema-preview-config.json) — portable, git-committable, shared by every contributor who opens the repo. - The
jsonschema.configVS Code setting — no file to commit, and it can be set at User (global), Workspace, or Workspace Folder scope, with VS Code's native scope precedence (Workspace Folder > Workspace > User) resolving which value applies.
The file always wins when both are present (F09-FR-13): teams with a committed config file keep deterministic, machine-independent output, while individual contributors without one can still configure the renderer per-machine or per-workspace through ordinary settings.
User Stories
- As a schema author, I want to switch the preview template to Markdown without editing JSON manually.
- As a team, we want to commit a shared config file so all contributors see the same rendered output.
- As an individual contributor without a committed config file, I want to set my preferred template and options in my own VS Code settings — globally, or just for one workspace — without creating a file the rest of the team didn't ask for.
Functional Requirements
Configure Command (Settings-Based)
- F09-FR-01 The command
jsonschema.configureMUST prompt the user to choose a settings scope (F09-FR-14), then open that scope'ssettings.jsonwith thejsonschema.configkey ready to edit (creating it as{}first if the scope doesn't already declare it). - F09-FR-02 The configuration toolbar icon (gear) MUST appear only when
jsonschema.isJsonSchemaistrue.
jsonschema.config Setting
- F09-FR-12 A
jsonschema.configobject setting (scoperesource, so it can be set per Workspace Folder) lets users configurejson-schema-for-humansdirectly in VS Code settings instead of the standalone file. Its shape MUST be declared undercontributes.configurationinpackage.json, mirroring the well-known properties of the upstreamjson-schema-for-humansconfig schema (template_nameas an enum of the supported templates, and the other documented boolean/string/object options) withadditionalPropertiesleft open for forward compatibility with tool options this extension doesn't yet know about. This is the only way to enforce a data model on a settings value in VS Code — an inline$schemakey has no meaning inside a nested settings value, since$schemais resolved at the document level andsettings.jsonis already validated against VS Code's own generated meta-schema. - F09-FR-13 Reading precedence: if
.json-schema-preview-config.json(F09-FR-06/07/08) is found, it MUST be used andjsonschema.configMUST be ignored entirely; only when no file is found does the extension fall back tojsonschema.config, resolved for the schema file's own resource so VS Code's native Workspace Folder > Workspace > User precedence applies (a folder/workspace value always overrides a user/global one, matching the file's own local-over-global principle). - F09-FR-14 The scope picker (used by F09-FR-01) MUST offer User (global
settings.json), Workspace (the.code-workspacefile, only when one is active), and Workspace Folder (the.vscode/settings.jsonof the workspace folder that owns the active editor's document, falling back to the first workspace folder when there is no active document) — mirroring the scope picker already used by Bind Schema… (F04), which likewise resolves a single contextual folder rather than enumerating every folder in a multi-root workspace.
Open Config File Command (File-Based)
- F09-FR-04 The command
jsonschema.openConfigMUST open the.json-schema-preview-config.jsonfile in the editor. - F09-FR-05 If no config file exists the command MUST create an empty one at the workspace root before opening it.
- F09-FR-03 Opening an existing config file MUST show its current on-disk content unmodified — the command MUST NOT overwrite existing values.
Config File Discovery (Multi-Root)
- F09-FR-06 The config file MUST be searched for starting from the workspace folder that contains the active schema file.
- F09-FR-07 If no config file is found in the schema's folder the extension MUST fall back to the other workspace folders in order.
- F09-FR-08 When no config file is found in any workspace folder, and the
jsonschema.configsetting (F09-FR-12/13) is also unset or empty, the Python tool MUST be called with--config template_name=flat.
Saving (File-Based)
- F09-FR-09 Editing
.json-schema-preview-config.jsondirectly in the editor and saving it MUST be reflected on the next preview render — there is no separate form to keep in sync, the file on disk is the source of truth. - F09-FR-10 After saving the config file, the preview panel for the schema that owns it SHOULD refresh to reflect the new template.
Security
- F09-FR-11 Any webview this feature opens (none currently — both commands operate on plain text editors) MUST use a nonce-based CSP (see S01) if one is ever added.
Acceptance Criteria
- Running JSON Schema: Configure Preview with no workspace folders open still offers User Settings and lands in the global
settings.jsonwithjsonschema.configready to edit. - In a project with no
.json-schema-preview-config.json, setting"jsonschema.config": {"template_name": "md"}in.vscode/settings.jsonand re-running the preview renders Markdown output. - Adding a
.json-schema-preview-config.jsonfile to that same project makes the file'stemplate_namewin over thejsonschema.configsetting. - Running Open Config File opens the
.json-schema-preview-config.jsonin the editor, creating it first if absent. settings.jsonshows autocomplete/validation forjsonschema.config.template_namerestricted to the known template names.
History
- 2026-09-09 —
openConfigFilecreated the config withexistsSync-then-writeFileSync, a check-then-act race (CodeQLjs/file-system-race). Anything creating the file between the two steps — a second window of this extension, a generator, the user — lost its content to the truncating write, which contradicts F09-FR-03's "MUST NOT overwrite existing values". Replaced with a singlewxwrite that failsEEXISTinstead of truncating; the loser of the race then takes the same inject-$schemapath it would have taken had the file been there all along. Worth recording because the fix is not a hardening nicety: the failure mode was silent data loss in a file users are told they can commit and share.
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 |
|---|---|---|---|
F09-FR-01 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-02 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-03 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-04 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-05 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-06 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-07 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-08 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-09 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-10 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-11 | manual | src/ConfigWebPanel.ts | VS Code API-bound; verified by manual / E2E testing |
F09-FR-12 | implemented | package.json, src/PreviewWebPanel.ts | jsonschema.config declared under contributes.configuration; getSettingsConfig() unit-tested in preview.test.ts |
F09-FR-13 | implemented | src/PreviewWebPanel.ts | resolveConfigSource() precedence unit-tested in preview.test.ts |
F09-FR-14 | implemented | src/ConfigWebPanel.ts | pickConfigScope() (private) exercised via configurePreview() unit tests in configWebPanel.test.ts |
Documented in
Documentation sections tagged spec:F09 (or one of its requirement ids) — 638 of ~562 expected words (100%). The expectation comes from this spec's evaluated complexity of 14.1 (14 documentable requirements — 14 FR — weighted by kind and by each definition's length).