Skip to content

Commit 458485e

Browse files
committed
Improved validation handling, tokenizer, and drawing logic per CodeRabbit review
1 parent d5aa4cb commit 458485e

File tree

2 files changed

+46
-20
lines changed

2 files changed

+46
-20
lines changed

kidcode-web/src/main/resources/static/app.js

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const closeButton = document.querySelector(".close-button");
1313
// --- MONACO: Global variable to hold the editor instance ---
1414
let editor;
1515
let validationTimeout;
16+
let validationController;
1617

1718
// --- MONACO: Function to define and register our custom language ---
1819
function registerKidCodeLanguage() {
@@ -48,14 +49,14 @@ function registerKidCodeLanguage() {
4849
},
4950
},
5051
],
51-
[/\d+/, "number"],
52+
[/-?\d+(?:\.\d+)?/, "number"], // supports decimals & negatives
5253
[/#.*$/, "comment"],
5354
[/"([^"\\]|\\.)*$/, "string.invalid"],
5455
[/"/, { token: "string.quote", bracket: "@open", next: "@string" }],
5556
],
5657
string: [
5758
[/[^\\"]+/, "string"],
58-
[/\\./, "string.escape.invalid"],
59+
[/\\./, "string.escape"], // valid generic escapes
5960
[/"/, { token: "string.quote", bracket: "@close", next: "@pop" }],
6061
],
6162
},
@@ -160,17 +161,24 @@ function initializeExamples() {
160161
// --- 2. ADD EVENT LISTENER TO THE RUN BUTTON ---
161162
runButton.addEventListener("click", async () => {
162163
const code = editor.getValue();
164+
165+
// 🧹 Ensure a clean slate even if backend omits ClearEvent
166+
drawnLines = [];
167+
codyState = { x: 250, y: 250, direction: 0, color: "blue" };
163168
clearCanvas();
164169
outputArea.textContent = "";
170+
165171
try {
166172
const response = await fetch("/api/execute", {
167173
method: "POST",
168174
headers: { "Content-Type": "application/json" },
169-
body: JSON.stringify({ code: code }),
175+
body: JSON.stringify({ code }),
170176
});
177+
171178
if (!response.ok) {
172179
throw new Error(`HTTP error! status: ${response.status}`);
173180
}
181+
174182
const events = await response.json();
175183
renderEvents(events);
176184
} catch (error) {
@@ -181,24 +189,47 @@ runButton.addEventListener("click", async () => {
181189
// --- NEW: Function to handle validation ---
182190
async function validateCode() {
183191
const code = editor.getValue();
192+
193+
// Cancel any in-flight validation to prevent stale results
194+
if (validationController) {
195+
validationController.abort();
196+
}
197+
const controller = new AbortController();
198+
validationController = controller;
199+
184200
try {
185201
const response = await fetch("/api/validate", {
186202
method: "POST",
187203
headers: { "Content-Type": "application/json" },
188-
body: JSON.stringify({ code: code }),
204+
body: JSON.stringify({ code }),
205+
signal: controller.signal,
189206
});
207+
208+
if (!response.ok) {
209+
throw new Error(`HTTP error ${response.status}`);
210+
}
211+
190212
const errors = await response.json();
191-
const markers = errors.map((err) => ({
192-
message: err.message,
193-
severity: monaco.MarkerSeverity.Error,
194-
startLineNumber: err.lineNumber,
195-
endLineNumber: err.lineNumber,
196-
startColumn: 1,
197-
endColumn: 100,
198-
}));
199-
monaco.editor.setModelMarkers(editor.getModel(), "kidcode", markers);
213+
const model = editor.getModel();
214+
const markers = (Array.isArray(errors) ? errors : []).map((err) => {
215+
const line = Number(err.lineNumber) > 0 ? Number(err.lineNumber) : 1;
216+
const endCol = model ? model.getLineMaxColumn(line) : 100;
217+
return {
218+
message: String(err.message || "Syntax error"),
219+
severity: monaco.MarkerSeverity.Error,
220+
startLineNumber: line,
221+
endLineNumber: line,
222+
startColumn: 1,
223+
endColumn: endCol,
224+
};
225+
});
226+
227+
monaco.editor.setModelMarkers(model, "kidcode", markers);
200228
} catch (error) {
229+
if (error.name === "AbortError") return; // ignore outdated requests
201230
console.error("Validation request failed:", error);
231+
} finally {
232+
if (validationController === controller) validationController = null;
202233
}
203234
}
204235

@@ -262,14 +293,14 @@ function renderEvents(events) {
262293
fromY: event.fromY,
263294
toX: event.toX,
264295
toY: event.toY,
265-
color: event.color,
296+
color: event.color ?? codyState.color,
266297
});
267298
}
268299
codyState = {
269300
x: event.toX,
270301
y: event.toY,
271302
direction: event.newDirection,
272-
color: event.color,
303+
color: event.color ?? codyState.color,
273304
};
274305
break;
275306
case "SayEvent":

kidcode-web/src/main/resources/static/style.css

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,10 @@ header {
9595
box-shadow: 0 0 4px rgba(52, 152, 219, 0.3);
9696
}
9797

98-
/* 🖲️ Right side: Buttons stay aligned */
9998
.panel-controls {
10099
display: flex;
101100
align-items: center;
102101
gap: 14px;
103-
}
104-
105-
/* Ensure controls don't wrap and keep their size */
106-
.panel-controls {
107102
flex-shrink: 0;
108103
white-space: nowrap;
109104
}

0 commit comments

Comments
 (0)