monaco-react icon indicating copy to clipboard operation
monaco-react copied to clipboard

YAML validation for Monaco Editor

Open vrabota opened this issue 4 years ago • 17 comments

For YAML seems like we have indentation and code highlighting, but unfortunately, we can't validate the code (indentation format or naming, duplications of the fields).

I found a library (https://github.com/pengx17/monaco-yaml) that can maybe help, but I have issues to integrate with create-react-app.

I also tried this solution (https://github.com/suren-atoyan/monaco-react/issues/68#issuecomment-770205419) but unfortunately nothing works for create-react-app application.

Maybe someone integrated YAML validations and can share some knowledge.

vrabota avatar Apr 16 '21 09:04 vrabota

this can be helpful. I'll try to find some time to make a working example

suren-atoyan avatar Apr 17 '21 12:04 suren-atoyan

It's hard to understand something in this example and how to integrate with monaco-react. Seems like all the code should be placed in public/index.html and we don't need monaco-react at all.

vrabota avatar Apr 18 '21 06:04 vrabota

An update on this would be greatly appreciated

efreila avatar Jun 09 '21 02:06 efreila

@suren-atoyan could you please provide an update on this.

Chethannp avatar Sep 20 '21 06:09 Chethannp

@suren-atoyan Did you manage to get some time to look into it? :)

Nivl avatar Oct 15 '21 20:10 Nivl

@Nivl @Chethannp @efreila guys sorry, but this package isn't compatible with this yaml-monaco implmenetation. To avoid using webpack configuration in this package we download monaco sources from CDN. The mentioned yaml-monaco implementation heavily depends on the ESM version of monaco, which requires a specific webpack configuration

suren-atoyan avatar Oct 15 '21 21:10 suren-atoyan

@suren-atoyan Is there a workaround that let us use https://github.com/remcohaszing/monaco-yaml with https://github.com/suren-atoyan/monaco-react ?

mohdashraf010897 avatar Feb 18 '22 17:02 mohdashraf010897

is there any example with monaco-yaml?

huruji avatar Jun 12 '22 11:06 huruji

this might make it possible to use monaco-yaml with monaco-react

suren-atoyan avatar Jun 12 '22 14:06 suren-atoyan

@suren-atoyan Cheers for the suggestion. I did manage to get it working using the webpack config from https://github.com/remcohaszing/monaco-yaml and the following component:

import React, {FC, useEffect} from 'react';

import * as monaco from "monaco-editor";
import Editor, { loader } from "@monaco-editor/react";
loader.config({ monaco });
import {setDiagnosticsOptions} from 'monaco-yaml';

// @ts-ignore
window.MonacoEnvironment = {
    getWorker(moduleId: any, label: string) {
        switch (label) {
            case 'editorWorkerService':
                // @ts-ignore
                return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url));
            case 'css':
            case 'less':
            case 'scss':
                // @ts-ignore
                return new Worker(new URL('monaco-editor/esm/vs/language/css/css.worker', import.meta.url));
            case 'handlebars':
            case 'html':
            case 'razor':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/html/html.worker', import.meta.url),
                );
            case 'json':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/json/json.worker', import.meta.url),
                );
            case 'javascript':
            case 'typescript':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/typescript/ts.worker', import.meta.url),
                );
            case 'yaml':
                // @ts-ignore
                return new Worker(new URL('monaco-yaml/yaml.worker', import.meta.url));
            default:
                throw new Error(`Unknown label ${label}`);
        }
    },
};

interface CodeEditorProps {
    language: string;
    value: any;
    disabled?: boolean;
    onChange(value: string|undefined): void;
    className?: string;
    width?: string;
    height?: string;
}

export const CodeEditor: FC<CodeEditorProps> = (props) => {
    const {language, value, disabled, onChange, className, width, height} = props;

    const handleOnChange = (value: string|undefined) => {
        onChange(value);
    }

    const handleEditorValidation = (markers: any) => {
        // model markers
        markers.forEach((marker: any) => console.log("onValidate:", marker.message));
    }

    useEffect(() => {
        setDiagnosticsOptions({
            // Have to set an empty Diagnostics options to get syntax checking
        });
    }, [])

    return (
        <div style={{border: "1px solid #ccc"}} className={className}>
            <Editor
                options={{
                    readOnly: disabled,
                    lineDecorationsWidth: 5,
                    lineNumbersMinChars: 0,
                    glyphMargin: false,
                    folding: false,
                    lineNumbers: 'off',
                    minimap: {
                        enabled: false
                    },
                    fontSize: 11,
                }}
                width={width}
                height={height}
                language={language}
                value={value}
                onValidate={handleEditorValidation}
                onChange={handleOnChange}
            />
        </div>
    );
}

jasoncodes42 avatar Jun 18 '22 05:06 jasoncodes42

@suren-atoyan Cheers for the suggestion. I did manage to get it working using the webpack config from https://github.com/remcohaszing/monaco-yaml and the following component:

import React, {FC, useEffect} from 'react';

import * as monaco from "monaco-editor";
import Editor, { loader } from "@monaco-editor/react";
loader.config({ monaco });
import {setDiagnosticsOptions} from 'monaco-yaml';

// @ts-ignore
window.MonacoEnvironment = {
    getWorker(moduleId: any, label: string) {
        switch (label) {
            case 'editorWorkerService':
                // @ts-ignore
                return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url));
            case 'css':
            case 'less':
            case 'scss':
                // @ts-ignore
                return new Worker(new URL('monaco-editor/esm/vs/language/css/css.worker', import.meta.url));
            case 'handlebars':
            case 'html':
            case 'razor':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/html/html.worker', import.meta.url),
                );
            case 'json':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/json/json.worker', import.meta.url),
                );
            case 'javascript':
            case 'typescript':
                return new Worker(
                    // @ts-ignore
                    new URL('monaco-editor/esm/vs/language/typescript/ts.worker', import.meta.url),
                );
            case 'yaml':
                // @ts-ignore
                return new Worker(new URL('monaco-yaml/yaml.worker', import.meta.url));
            default:
                throw new Error(`Unknown label ${label}`);
        }
    },
};

interface CodeEditorProps {
    language: string;
    value: any;
    disabled?: boolean;
    onChange(value: string|undefined): void;
    className?: string;
    width?: string;
    height?: string;
}

export const CodeEditor: FC<CodeEditorProps> = (props) => {
    const {language, value, disabled, onChange, className, width, height} = props;

    const handleOnChange = (value: string|undefined) => {
        onChange(value);
    }

    const handleEditorValidation = (markers: any) => {
        // model markers
        markers.forEach((marker: any) => console.log("onValidate:", marker.message));
    }

    useEffect(() => {
        setDiagnosticsOptions({
            // Have to set an empty Diagnostics options to get syntax checking
        });
    }, [])

    return (
        <div style={{border: "1px solid #ccc"}} className={className}>
            <Editor
                options={{
                    readOnly: disabled,
                    lineDecorationsWidth: 5,
                    lineNumbersMinChars: 0,
                    glyphMargin: false,
                    folding: false,
                    lineNumbers: 'off',
                    minimap: {
                        enabled: false
                    },
                    fontSize: 11,
                }}
                width={width}
                height={height}
                language={language}
                value={value}
                onValidate={handleEditorValidation}
                onChange={handleOnChange}
            />
        </div>
    );
}

Throws:

Error: Target container is not a DOM element.

In a Next.js app :(

josiext avatar Aug 02 '23 17:08 josiext