Example: Linter

The @codemirror/lint package provides a way to display errors and warnings in your editor. If you give it a source function that, when given an editor, produces an array of problems, it will call this function when changes are made to the document, and display its result.

The library does not come with a collection of lint sources. Some language packages (such as @codemirror/lang-javascript) may include integration with lint libraries, but usually setting up a source is something you have to do yourself.

There's two ways to do this:

In this example, we'll do the latter.

Assume for a second that the boss has decided that regular expressions are the work of the devil (to be fair, he's not entirely wrong), and should be forbidden in the entire codebase. We want a linter that highlights any use of a regular expression in JavaScript code.

Conveniently, the JavaScript parser emits a specific node type for regular expression literals, so all we have to do is iterate over the parse tree and emit a warning for every node like that we find.

import {syntaxTree} from "@codemirror/language"
import {linter, Diagnostic} from "@codemirror/lint"

const regexpLinter = linter(view => {
  let diagnostics: Diagnostic[] = []
  syntaxTree(view.state).cursor().iterate(node => {
    if (node.name == "RegExp") diagnostics.push({
      from: node.from,
      to: node.to,
      severity: "warning",
      message: "Regular expressions are FORBIDDEN",
      actions: [{
        name: "Remove",
        apply(view, from, to) { view.dispatch({changes: {from, to}}) }
      }]
    })
  })
  return diagnostics
})

Diagnostics (the objects returned by a lint source) must have from and to properties indicating the range they apply to, a severity field, and a message.

This one also uses the optional actions field to add an “action” for the diagnostic. This adds a button to the diagnostic that can be clicked to perform some effect, like automatically fixing the problem (which this does in a very crude way) or providing further context.

The result of a call to linter is an extension that you can include in a (JavaScript) editor to get a result like this:

The gutter only appears if you also include lintGutter. You can press Ctrl-Shift-m (Cmd-Shift-m on macOS) to show a list of diagnostics in a panel below the editor.