Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 28 additions & 54 deletions javascript/processingFunctions/processExerciseJson.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,31 @@
import { recursiveProcessTextJson } from "../parseXmlJson";
import { missingExerciseWarning } from "./warnings.js";
import { referenceStore } from "./processReferenceJson";

let unlabeledEx = 0;
const processExerciseJson = (node, obj) => {
const label = node.getElementsByTagName("LABEL")[0];
let labelName = "";
const solution = node.getElementsByTagName("SOLUTION")[0];

if (!label) {
unlabeledEx++;
labelName = "ex:unlabeled" + unlabeledEx;
} else {
labelName = label.getAttribute("NAME");
}

if (!referenceStore[labelName]) {
missingExerciseWarning(labelName);
return;
}

const displayName = referenceStore[labelName].displayName;

obj["tag"] = "EXERCISE";
obj["title"] = "Exercise " + displayName;
obj["id"] = `#ex-${displayName}`;

recursiveProcessTextJson(node.firstChild, obj);

if (solution) {
const childObj = {};
recursiveProcessTextJson(solution.firstChild, childObj);
obj["solution"] = childObj["child"];
}
};

export const getIdForExerciseJson = node => {
const label = node.getElementsByTagName("LABEL")[0];
let labelName = "";

if (!label) {
labelName = "ex:unlabeled" + unlabeledEx;
} else {
labelName = label.getAttribute("NAME");
}

if (!referenceStore[labelName]) {
missingExerciseWarning(labelName);
return undefined;
import { getChildrenByTagName } from "../utilityFunctions.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The import getChildrenByTagName is unused in this file and can be removed to improve code cleanliness.

import { recursivelyProcessTextSnippetJson } from "./processSnippetJson.js";

const processExerciseJson = (node, writeTo) => {
const exercise = {
type: "exercise",
content: []
};
const children = Array.from(node.childNodes);
for (const child of children) {
if (child.nodeName === "SNIPPET") {
const snippet = [];
recursivelyProcessTextSnippetJson(child.firstChild, snippet);
const code = snippet.join("").trim();
exercise.content.push({
type: "snippet",
code: code.replace(/const\s+(\w+)\s*=\s*/g, "$1 = ")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The regular expression /const\s+(\w+)\s*=\s*/g is not robust enough. It has two main issues:

  1. It only supports simple variable declarations (e.g., const x = ...) and will not work for declarations that use destructuring, such as const { a, b } = ....
  2. It can incorrectly modify occurrences of "const" inside string literals, as it is not anchored.

A safer and more robust approach is to anchor the regex to the beginning of a line and preserve leading whitespace. This will correctly handle all forms of const declarations without affecting string contents.

Suggested change
code: code.replace(/const\s+(\w+)\s*=\s*/g, "$1 = ")
code: code.replace(/^(\s*)const\s+/gm, "$1")

});
} else if (child.nodeName === "TEXT") {
const text = [];
recursivelyProcessTextSnippetJson(child.firstChild, text);
exercise.content.push({
type: "text",
content: text.join("").trim()
});
}
}

const displayName = referenceStore[labelName].displayName;
return `#ex-${displayName}`;
writeTo.push(exercise);
};
Comment on lines +4 to 29
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This pull request introduces breaking changes that will likely cause the application to crash at runtime.

  1. Removed getIdForExerciseJson: The function getIdForExerciseJson has been removed from this file, but it is still imported and called in javascript/parseXmlJson.js (e.g., on line 219). This will cause a ReferenceError.
  2. Incompatible processExerciseJson signature: The signature and implementation of processExerciseJson have been completely changed.
    • It is called from parseXmlJson.js with an object as the second argument, but the new implementation expects an array and calls .push() on it, which will result in a TypeError.
    • The old function was called with more arguments which are now ignored.
  3. Loss of functionality: The previous implementation of processExerciseJson handled exercise labels, solutions, and references. This logic has been removed entirely. This is a significant change that seems to go beyond the scope of replacing const declarations and may have unintended side effects on how exercises are processed.

It appears that javascript/parseXmlJson.js and potentially other files need to be updated to be compatible with these changes. Due to the high risk of breaking the application, this is a critical issue.


export default processExerciseJson;
export default processExerciseJson;