An open API service indexing awesome lists of open source software.

https://github.com/jsonnext/codemirror-json-schema

A JSONSchema enabled mode for codemirror 6, for json4 and json5, inspired by monaco-json
https://github.com/jsonnext/codemirror-json-schema

codemirror-mode codemirror6 json json-schema json5

Last synced: 8 months ago
JSON representation

A JSONSchema enabled mode for codemirror 6, for json4 and json5, inspired by monaco-json

Awesome Lists containing this project

README

          

Codemirror 6 extensions that provide full [JSON Schema](https://json-schema.org/) support for `@codemirror/lang-json` & `codemirror-json5` language modes


npm

![screenshot of the examples with json4 and json5 support enabled](./dev/public/example.png)

## Features

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

## Resources

- [Changelog](./CHANGELOG.md)
- [Comprehensive example](https://github.com/acao/cm6-json-schema/blob/main/dev/index.ts)
- [API Docs](./docs/)

## Usage

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.

### Breaking Changes:

- 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.

### json4

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)
];
})
```

### json5

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),
],
});
```

### Dynamic 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,
})
];
}
```

## Current Constraints:

- 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

## Inspiration

`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!