Skip to content

Commit 05f12c2

Browse files
fix: yaml editor
1 parent 8e2c75c commit 05f12c2

File tree

2 files changed

+96
-62
lines changed

2 files changed

+96
-62
lines changed

docs/configure-coderabbit.md

-18
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,6 @@ You can add a `.coderabbit.yaml` configuration file to the root of your
3939
repositories. Below is a sample YAML file that can be used as a starting point
4040
and changed as needed:
4141

42-
```yaml
43-
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
44-
language: "en-US"
45-
early_access: false
46-
reviews:
47-
profile: "chill"
48-
request_changes_workflow: false
49-
high_level_summary: true
50-
poem: true
51-
review_status: true
52-
collapse_walkthrough: false
53-
auto_review:
54-
enabled: true
55-
drafts: false
56-
chat:
57-
auto_reply: true
58-
```
59-
6042
Write your configuration file in the below editor to validate:
6143

6244
```mdx-code-block

src/components/YamlEditor/YamlEditor.jsx

+96-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { React, useState } from "react";
1+
import { React, useState, useEffect } from "react";
22

33
import AceEditor from "react-ace";
44
import "ace-builds/src-noconflict/theme-github";
@@ -14,65 +14,70 @@ const ajv = new Ajv({ allErrors: true });
1414

1515
import Schema from "../../../static/schema/schema.v2.json";
1616

17+
const validate = ajv.compile(Schema.definitions.schema);
18+
1719
export default function YamlEditor() {
20+
const [value, setValue] = useState("");
1821
const [annotations, setAnnotations] = useState([]);
19-
const [value, setValue] = useState(
20-
"# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json\n"
21-
);
22-
const validate = ajv.compile(Schema.definitions.schema);
23-
function getRowFromPath(path) {
24-
// Convert path to row number (0-based)
25-
return path.split("/").length - 1;
26-
}
27-
function getLineNumber(yaml, path) {
28-
const lines = yaml.split("\n");
29-
const pathParts = path.split("/").filter(Boolean);
30-
let currentObj = jsYaml.load(yaml);
31-
let lineNumber = 0;
3222

33-
for (const part of pathParts) {
34-
for (let i = lineNumber; i < lines.length; i++) {
35-
if (lines[i].trim().startsWith(part + ":")) {
36-
lineNumber = i;
37-
break;
38-
}
39-
}
40-
currentObj = currentObj[part];
41-
}
23+
useEffect(() => {
24+
const initialValue = `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
25+
language: "en-US"
26+
early_access: false
27+
reviews:
28+
profile: "chill"
29+
request_changes_workflow: false
30+
high_level_summary: true
31+
poem: true
32+
review_status: true
33+
collapse_walkthrough: false
34+
auto_review:
35+
enabled: true
36+
drafts: false
37+
chat:
38+
auto_reply: true
4239
43-
return lineNumber;
44-
}
45-
function onChange(newValue) {
46-
setValue(newValue);
40+
`;
41+
setValue(initialValue);
42+
validateAndSetAnnotations(initialValue);
43+
}, []);
44+
function validateAndSetAnnotations(yaml) {
4745
try {
48-
const doc = jsYaml.load(newValue, { strict: true });
49-
const valid = validate(doc);
46+
const doc = jsYaml.load(yaml, { strict: true });
47+
const isValid = validate(doc);
5048

51-
if (!valid && validate.errors) {
49+
if (!isValid && validate.errors) {
5250
setAnnotations(
53-
validate.errors.map((err) => ({
54-
row: err.instancePath
55-
? getLineNumber(newValue, err.instancePath)
56-
: 0,
57-
column: 0,
58-
text: `${err.keyword}: ${err.message} ${
59-
err?.params?.allowedValues
60-
? `Allowed values: ${err.params.allowedValues.join(", ")}`
61-
: ""
62-
}`,
63-
type: "error",
64-
}))
51+
validate.errors.map((err) => {
52+
const instancePathArr = err?.instancePath?.split("/");
53+
const key =
54+
instancePathArr && instancePathArr[instancePathArr.length - 1];
55+
return {
56+
row: err.instancePath ? getLineNumber(yaml, err.instancePath) : 0,
57+
column: 0,
58+
text: `${key}: ${err.message} ${
59+
err?.params?.allowedValues
60+
? `Allowed values: ${err.params.allowedValues.join(", ")}`
61+
: ""
62+
}`,
63+
type: "error",
64+
};
65+
})
6566
);
6667
} else {
6768
setAnnotations([]);
6869
}
6970
} catch (err) {
71+
const instancePathArr = err?.instancePath?.split("/");
72+
const key =
73+
instancePathArr && instancePathArr[instancePathArr.length - 1];
74+
7075
setAnnotations([
7176
{
72-
row: err.instancePath ? getLineNumber(newValue, err.instancePath) : 0,
77+
row: err.instancePath ? getLineNumber(yaml, err.instancePath) : 0,
7378
column: 0,
7479
text:
75-
`${err.keyword}: ${err.message} ${
80+
`${key}: ${err.message} ${
7681
err?.params?.allowedValues
7782
? `Allowed values: ${err.params.allowedValues.join(", ")}`
7883
: ""
@@ -82,6 +87,53 @@ export default function YamlEditor() {
8287
]);
8388
}
8489
}
90+
function getLineNumber(yaml, instancePath) {
91+
const lines = yaml.split("\n");
92+
const pathParts = instancePath.split("/").filter(Boolean);
93+
let currentObj = jsYaml.load(yaml);
94+
let lineNumber = 0;
95+
96+
const lastPathPart = pathParts[pathParts.length - 1];
97+
const lastPathPartIndex = pathParts.length - 1;
98+
99+
for (let i = 0; i < lines.length; i++) {
100+
if (lines[i].trim().startsWith(pathParts[0] + ":")) {
101+
// Found the top-level field
102+
lineNumber = i;
103+
currentObj = currentObj[pathParts[0]];
104+
105+
for (let j = 1; j < lastPathPartIndex; j++) {
106+
// Go through the nested fields
107+
for (let k = lineNumber + 1; k < lines.length; k++) {
108+
if (lines[k].trim().startsWith(pathParts[j] + ":")) {
109+
lineNumber = k;
110+
currentObj = currentObj[pathParts[j]];
111+
break;
112+
}
113+
}
114+
}
115+
116+
// look for the last path part with array syntax as well as object syntax
117+
for (let l = lineNumber + 1; l < lines.length; l++) {
118+
if (lines[l].trim().startsWith(`- ${lastPathPart}:`)) {
119+
lineNumber = l;
120+
break;
121+
} else if (lines[l].trim().startsWith(lastPathPart + ":")) {
122+
lineNumber = l;
123+
break;
124+
}
125+
}
126+
break;
127+
}
128+
}
129+
130+
return lineNumber;
131+
}
132+
function onChange(newValue) {
133+
setValue(newValue);
134+
validateAndSetAnnotations(newValue);
135+
}
136+
85137
return (
86138
<AceEditor
87139
mode="yaml"

0 commit comments

Comments
 (0)