YAML Linter for @uiw/react-codemirror or codemirror v6

I am trying to build a YAML code editor. I have all my features required but one, which is linting. I have looked at several examples, but YAML linting support for v6 has really been scarce. I have followed docs and looked out for some third-party linters but with no success, I have either found examples for codemirror v5 which I was not able to reproduce in v6. Can someone please guide me with a blog post or some reference docs.

The CodeMirror 5 YAML linter seems to use nodeca/js-yaml as its underlying lint implementation. It is probably possible to wire that up as a CodeMirror 6 lint source.

How do I set up a lint source. Becuase the CodeMirror Lint Example doesn’t have anyway to setup a lint source

According to the docs - “Find a linter that you can run in the browser, run it on the content, and translate its output into the expected format”

I have written my code like this

const extensionList = [
    // ...basicSetup(), //including all the basic setup plus the extra setup below
    keymap.of([indentWithTab]),
    StreamLanguage.define(yaml),
    linter(lintErrors), //acc. to [docs](https://codemirror.net/docs/ref/#lint.linter)
    // yamlTest(),
  ];

  const onChange = (e) => {
    setCode(e);
  };

  const lintErrors = () => {
    // find lint errors and construct a array of Diagnostics from the errors of the 'js-yaml'
    const errors = parseYAML(code);
    const diagnostics =
      errors?.length > 0
        ? errors?.map((errorItem) => {
            return {
              from: errorItem?.mark?.line,
              to: errorItem?.mark?.column,
              severity: 'error',
              message: errorItem?.reason || errorItem?.message,
              // renderMessage? optional,
              // actions?:
            };
          })
        : [];
    return diagnostics;
  };
...
...
return (
...
<ReactCodeMirror
        basicSetup={{ lineNumbers: true }}
        value={code}
        readOnly={readOnly}
        // theme={editorTheme}//TODO: change when extra customization is needed
        extensions={extensionList}
        onChange={readOnly ? () => {} : onChange}
        autoFocus
        placeholder={'Enter a new yaml here'}
      />
...
)

This code at linter(lintErrors) throws an error - “source is not a function”

I’m not sure if this is the reason for the error but you have to convert line/column to a character position for your “from:” and “to:”

It looks like you’re currently using the mark.line for “from:” and mark.column for “to:”. You’re going to want to convert your start and end lines/columns to character offsets for both your start mark and end mark (if those are provided by the parser) and use those character offsets instead. If not, convert your mark.line and mark.column to a character offset and use that for your “to:” and set the “from:” to that - 1 with a minimum value of 0.

Check out the functions in the documentation under “Positions” to convert:
https://codemirror.net/docs/migration/

1 Like

@saiyerniakhil
did you find a solution for this ? I am stuck exactly at the same point.

I successfully wired nodeca/js-yaml as CodeMirror 6 YAML lint source.
Below is a YAML editor component which I created :

import React from "react";
import { StreamLanguage } from "@codemirror/language"
import { linter, lintGutter } from "@codemirror/lint"
import { yaml } from "@codemirror/legacy-modes/mode/yaml"
import { EditorView, basicSetup } from "codemirror"
import { Column } from '@innovaccer/design-system'

function YamlEditor(props) {
    React.useEffect(() => {
        const jsyaml = require('js-yaml');

        const yamlLinter = linter(view => {
            let diagnostics = [];
            // console.log(view); This is the EditorView
            // console.log(view.state); This is the EditorState
            // console.log(view.state.doc); This is the object type Textleaf containing Editor text and related info.
            try {
                jsyaml.load(view.state.doc)
            }
            catch (e) {
                var loc = e.mark;
                var from = loc ? loc.position : 0;
                var to = from;
                var severity = "error";
                diagnostics.push({ from: from, to: to, message: e.message, severity: severity });
            }
            return diagnostics
        });



        new EditorView({
            doc: "",
            extensions: [basicSetup, StreamLanguage.define(yaml), lintGutter(), yamlLinter],
            parent: document.querySelector("#editor")
        })
    }, []);

    return (
        <Column id="editor"
            style={{ boxShadow: "0 0 2px 2px #999" }}>
        </Column>
    )
}

export default YamlEditor;
1 Like

A humble request:
please do link my reference, if someone happens to use this code.
It took me a hug effort to create this. Thanks.

Linkedin : https://www.linkedin.com/in/satyam-nitsxr/
Github : saty2103 (SATYAM CHATTERJEE) · GitHub

Here’s an example of how to create a YAML editor with linting using CodeMirror React

2 Likes