How to enable linting for a handlebars React editor?

I have an editor component that I would like to modify to have custom variable linting for handlebars. Namely, if a variable is added to the handlebars template that is not in the known list, show an error. However, I’m not able to trigger linting at all on my component (have a test function that doesn’t do anything currently). I’m using syntax that seems identical to what I’ve seen in other examples, but I haven’t been able to figure out what configuration I’m missing to have my linting function (testLinter) trigger. This is true regardless of the preset language, but my end goal is to have the custom linting function be for handlebars. Below is the setup code for the component:

import { CodeDisplay, CodeDisplayProps } from './CodeDisplay';
import { javascript } from '@codemirror/lang-javascript';
import { json } from '@codemirror/lang-json';
import { markdown } from '@codemirror/lang-markdown';
import { python } from '@codemirror/lang-python';
import { foldGutter } from '@codemirror/language';
import { Diagnostic, linter, LintSource } from '@codemirror/lint';
import { EditorState, Extension } from '@codemirror/state';
import { handlebarsLanguage } from '@gentrace/codemirror-lang-handlebars';
import CodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror';
import { EditorView } from 'codemirror';
import { KeyboardEventHandler, useCallback } from 'react';
import { monoFontFamily } from '~/pages/_app';
import { styled } from '~/stitches.config';
import { githubDarkModified, handlebarsTheme } from '~/utils/utils';

export type CodeEditorProps = Pick<
  ReactCodeMirrorProps,
  | 'extensions'
  | 'basicSetup'
  | 'autoFocus'
  | 'onChange'
  | 'onBlur'
  | 'readOnly'
  | 'onCreateEditor'
> & { forceBorder?: boolean };

const presetExtensions: Record<CodeDisplayProps['preset'], Extension[]> = {
  handlebars: [handlebarsLanguage],
  javascript: [javascript({ jsx: true })],
  json: [json()],
  markdown: [markdown()],
  plain: [],
  python: [python()],
  typescript: [javascript({ jsx: true, typescript: true })],
};

const presetThemes: Partial<Record<CodeDisplayProps['preset'], Extension>> = {
  handlebars: handlebarsTheme,
};

export const testLinter: LintSource = (view) => {
  // This is never called
  console.log('test linter');
  const diagnostics: Diagnostic[] = [];
  diagnostics.push({
    from: 0,
    message: 'test',
    severity: 'error',
    to: 1,
  });
  return diagnostics;
};

export const CodeEditor: CodeDisplay<CodeEditorProps> = ({
  placeholder,
  preset,
  basicSetup = {},
  extensions = [],
  readOnly = false,
  forceBorder = false,
  style,
  ...rest
}) => {
  const languageExtensions = presetExtensions[preset];
  const compoundExtensions = [
    ...extensions,
    ...languageExtensions,
    readOnly
      ? [EditorState.readOnly.of(true), EditorView.lineWrapping]
      : [EditorView.lineWrapping],
    linter(testLinter),
  ];

  const overrideBasicSetup = {
    ...(typeof basicSetup === 'object' ? basicSetup : {}),
    highlightActiveLine: false,
    // We don't want the default fold gutter since we're overriding it
    foldGutter: false,
  };
  if (readOnly) {
    overrideBasicSetup.highlightActiveLineGutter = false;
  }

  const handleKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(
    (event) => {
      if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
        event.stopPropagation();
        event.preventDefault();
      }
    },
    [],
  );

  return (
      <CodeMirror
        style={{
          width: '100%',
          fontFamily: monoFontFamily,
          ...style,
        }}
        placeholder={placeholder}
        readOnly={readOnly}
        basicSetup={overrideBasicSetup}
        extensions={compoundExtensions}
        theme={presetThemes[preset] ?? githubDarkModified}
        {...rest}
      />
  );
};

Appreciate any help!

1 Like

For posterity, this code works as is. I deleted node_modules and reinstalled and then it started working for me.