diff --git a/docs/configure-coderabbit.md b/docs/configure-coderabbit.md index a2b35f10..e44c3936 100644 --- a/docs/configure-coderabbit.md +++ b/docs/configure-coderabbit.md @@ -10,6 +10,7 @@ sidebar_position: 3 ```mdx-code-block import SchemaViewer from "@site/src/components/SchemaViewer"; +import YamlEditor from "/src/components/YamlEditor/YamlEditor"; ``` CodeRabbit offers various configuration options to tailor the reviews to your @@ -56,6 +57,12 @@ chat: auto_reply: true ``` +Write your configuration file in the below editor to validate: + +```mdx-code-block + +``` + The configuration file can be used to set the following options: ```mdx-code-block diff --git a/package-lock.json b/package-lock.json index b7c323c4..a0f1c019 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "postcss": "^8.4.32", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", + "react-ace": "^12.0.0", "react-dom": "^18.0.0", "tailwindcss": "^3.4.0" }, @@ -3988,6 +3989,12 @@ "node": ">= 0.6" } }, + "node_modules/ace-builds": { + "version": "1.35.4", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.4.tgz", + "integrity": "sha512-r0KQclhZ/uk5a4zOqRYQkJuQuu4vFMiA6VTj54Tk4nI1TUR3iEMMppZkWbNoWEgWwv4ciDloObb9Rf4V55Qgjw==", + "license": "BSD-3-Clause" + }, "node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", @@ -5747,6 +5754,12 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8316,6 +8329,18 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -12216,6 +12241,23 @@ "node": ">=0.10.0" } }, + "node_modules/react-ace": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-12.0.0.tgz", + "integrity": "sha512-PstU6CSMfYIJknb4su2Fa0WgLXzq2ufQgR6fjcSWuGT1hGTHkBzuKw+SncV8PuLCdSJBJc1VehPhyeXlWByG/g==", + "license": "MIT", + "dependencies": { + "ace-builds": "^1.32.8", + "diff-match-patch": "^1.0.5", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", diff --git a/package.json b/package.json index 3c82d516..4f257c51 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "postcss": "^8.4.32", "prism-react-renderer": "^2.3.0", "react": "^18.0.0", + "react-ace": "^12.0.0", "react-dom": "^18.0.0", "tailwindcss": "^3.4.0" }, diff --git a/src/components/YamlEditor/YamlEditor.jsx b/src/components/YamlEditor/YamlEditor.jsx new file mode 100644 index 00000000..a60564ba --- /dev/null +++ b/src/components/YamlEditor/YamlEditor.jsx @@ -0,0 +1,103 @@ +import { React, useState } from "react"; + +import AceEditor from "react-ace"; +import "ace-builds/src-noconflict/theme-github"; +import "ace-builds/src-noconflict/ext-language_tools"; + +import "ace-builds/webpack-resolver"; +import "ace-builds/src-noconflict/mode-yaml"; + +import jsYaml from "js-yaml"; + +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); + +import Schema from "../../../static/schema/schema.v2.json"; + +export default function YamlEditor() { + const [annotations, setAnnotations] = useState([]); + const [value, setValue] = useState( + "# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json\n" + ); + const validate = ajv.compile(Schema.definitions.schema); + function getRowFromPath(path) { + // Convert path to row number (0-based) + return path.split("/").length - 1; + } + function getLineNumber(yaml, path) { + const lines = yaml.split("\n"); + const pathParts = path.split("/").filter(Boolean); + let currentObj = jsYaml.load(yaml); + let lineNumber = 0; + + for (const part of pathParts) { + for (let i = lineNumber; i < lines.length; i++) { + if (lines[i].trim().startsWith(part + ":")) { + lineNumber = i; + break; + } + } + currentObj = currentObj[part]; + } + + return lineNumber; + } + function onChange(newValue) { + setValue(newValue); + try { + const doc = jsYaml.load(newValue, { strict: true }); + const valid = validate(doc); + + if (!valid && validate.errors) { + setAnnotations( + validate.errors.map((err) => ({ + row: err.instancePath + ? getLineNumber(newValue, err.instancePath) + : 0, + column: 0, + text: `${err.keyword}: ${err.message} ${ + err?.params?.allowedValues + ? `Allowed values: ${err.params.allowedValues.join(", ")}` + : "" + }`, + type: "error", + })) + ); + } else { + setAnnotations([]); + } + } catch (err) { + setAnnotations([ + { + row: err.instancePath ? getLineNumber(newValue, err.instancePath) : 0, + column: 0, + text: + `${err.keyword}: ${err.message} ${ + err?.params?.allowedValues + ? `Allowed values: ${err.params.allowedValues.join(", ")}` + : "" + }` || "YAML parsing error", + type: "error", + }, + ]); + } + } + return ( + + ); +}