Codemirror 6 extensions that provide full JSONSchema support for `@codemirror/lang-json` and `codemirror-json5`
npm install codemirror-json-schemaCodemirror 6 extensions that provide full JSON Schema support for @codemirror/lang-json & codemirror-json5 language modes
!screenshot of the examples with json4 and json5 support enabled
This is now a full-featured library for json schema for json, json5 and yaml as cm6 extensions!
- ✅ lint validation messages from json schema
- ✅ autocompletion with insert text from json schema
- ✅ hover tooltips
- ✅ dynamic, per-editor-instance schemas using codemirror StateField and linting refresh
- ✅ markdown rendering for schema.description and custom formatHover and formatError configuration
- Changelog
- Comprehensive example
- API Docs
To give you as much flexibility as possible, everything codemirror related is a peer or optional dependency
Based on whether you want to support json4, json5 or both, you will need to install the relevant language mode for our library to use.
- 0.7.0 - this version introduces markdown rendering in place of returning html strings, so any usage of formatHover and/or formatError configuration will be passed to markdown-it which doesn't handle html by default.
- 0.5.0 - this breaking change only impacts those following the "custom usage" approach, it _does not_ effect users using the high level, "bundled" jsonSchema() or json5Schema() modes. See the custom usages below to learn how to use the new stateExtensions and handleRefresh exports.
with auto-install-peers true or similar:
```
npm install --save @codemirror/lang-json codemirror-json-schema
without auto-install-peers true:
``
npm install --save @codemirror/lang-json codemirror-json-schema @codemirror/language @codemirror/lint @codemirror/view @codemirror/state @lezer/common
#### Minimal Usage
This sets up @codemirror/lang-json and our extension for you.
If you'd like to have more control over the related configurations, see custom usage below
`ts
import { EditorState } from "@codemirror/state";
import { jsonSchema } from "codemirror-json-schema";
const schema = {
type: "object",
properties: {
example: {
type: "boolean",
},
},
};
const json5State = EditorState.create({
doc: "{ example: true }",
extensions: [jsonSchema(schema)],
});
`
#### Custom Usage
This approach allows you to configure the json mode and parse linter, as well as our linter, hovers, etc more specifically.
`ts
import { EditorState } from "@codemirror/state";
import { linter } from "@codemirror/lint";
import { hoverTooltip } from "@codemirror/view";
import { json, jsonParseLinter, jsonLanguage } from "@codemirror/lang-json";
import {
jsonSchemaLinter,
jsonSchemaHover,
jsonCompletion,
stateExtensions,
handleRefresh
} from "codemirror-json-schema";
const schema = {
type: "object",
properties: {
example: {
type: "boolean",
},
},
};
const state = EditorState.create({
doc: { "example": true },`
extensions: [
json(),
linter(jsonParseLinter(), {
// default is 750ms
delay: 300
}),
linter(jsonSchemaLinter(), {
needsRefresh: handleRefresh,
}),
jsonLanguage.data.of({
autocomplete: jsonCompletion(),
}),
hoverTooltip(jsonSchemaHover()),
stateExtensions(schema)
];
})
with auto-install-peers true or similar:
``
npm install --save codemirror-json5 codemirror-json-schema
without auto-install-peers true:
``
npm install --save codemirror-json5 codemirror-json-schema @codemirror/language @codemirror/lint @codemirror/view @codemirror/state @lezer/common
#### Minimal Usage
This sets up codemirror-json5 mode for you.
If you'd like to have more control over the related configurations, see custom usage below
`ts
import { EditorState } from "@codemirror/state";
import { json5Schema } from "codemirror-json-schema/json5";
const schema = {
type: "object",
properties: {
example: {
type: "boolean",
},
},
};
const json5State = EditorState.create({
doc: {
example: true,
// json5 is awesome!
},`
extensions: [json5Schema(schema)],
});
#### Custom Usage
This approach allows you to configure the json5 mode and parse linter, as well as our linter, hovers, etc more specifically.
`ts
import { EditorState } from "@codemirror/state";
import { linter } from "@codemirror/lint";
import { json5, json5ParseLinter, json5Language } from "codemirror-json5";
import {
json5SchemaLinter,
json5SchemaHover,
json5Completion,
} from "codemirror-json-schema/json5";
import { stateExtensions, handleRefresh } from "codemirror-json-schema";
const schema = {
type: "object",
properties: {
example: {
type: "boolean",
},
},
};
const json5State = EditorState.create({
doc: {
example: true,
// json5 is awesome!
},`
extensions: [
json5(),
linter(json5ParseLinter(), {
// the default linting delay is 750ms
delay: 300,
}),
linter(
json5SchemaLinter({
needsRefresh: handleRefresh,
})
),
hoverTooltip(json5SchemaHover()),
json5Language.data.of({
autocomplete: json5Completion(),
}),
stateExtensions(schema),
],
});
If you want to, you can provide schema dynamically, in several ways.
This works the same for either json or json5, using the underlying codemirror 6 StateFields, via the updateSchema method export.
In this example
- the initial schema state is empty
- schema is loaded dynamically based on user input
- the linting refresh will be handled automatically, because it's built into our bundled jsonSchema() and json5Schema() modes
`ts
import { EditorState } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { json5Schema } from "codemirror-json-schema/json5";
import { updateSchema } from "codemirror-json-schema";
const json5State = EditorState.create({
doc: {
example: true,
// json5 is awesome!
},
// note: you can still provide initial
// schema when creating state
extensions: [json5Schema()],
});
const editor = new EditorView({ state: json5State });
const schemaSelect = document.getElementById("schema-selection");
schemaSelect!.onchange = async (e) => {
const val = e.target!.value!;
if (!val) {
return;
}
// parse the remote schema spec to json
const data = await (
await fetch(https://json.schemastore.org/${val})`
).json();
// this will update the schema state field, in an editor specific way
updateSchema(editor, data);
};
if you are using the "custom path" with this approach, you will need to configure linting refresh as well:
`ts
import { linter } from "@codemirror/lint";
import { json5SchemaLinter } from "codemirror-json-schema/json5";
import { handleRefresh } from "codemirror-json-schema";
const state = EditorState.create({
// ...
extensions: [
linter(json5SchemaLinter(), {
needsRefresh: handleRefresh,
})
];
}
`
- currently only tested with standard schemas using json4 spec. results may vary
- doesn't place cursor inside known insert text yet
- currently you can only override the texts and rendering of a hover. we plan to add the same for validation errors and autocomplete
monaco-json and monaco-yaml` both provide json schema features for json, cson and yaml, and we want the nascent codemirror 6 to have them as well!
Also, json5 is slowly growing in usage, and it needs full language support for the browser!