You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue was researched and drafted by Claude (via Claude Code), and reviewed by @brian-smith-tcril before filing.
Summary
fast-xml-parser introduces two separate behavior changes in its XML builder — in the patch release 5.3.8 and the patch release 5.7.3 — that break the Problem Editor's OLX serialization/parsing. Both are breaking changes shipped in non-major releases, i.e. semver violations. Our package.json declares "fast-xml-parser": "^5.0.0", an honest range that (correctly, per semver) permits these releases, so a from-scratch package-lock.json regeneration floats the dependency up to the latest 5.x and the ProblemEditor test suites start failing. This currently blocks the security update in #3175 (bump to 5.7.0) and any lockfile regeneration.
The committed lockfile currently snapshots 5.3.6, which is why CI is green today. That snapshot is a known-working resolution, not a version policy — a lockfile regen should reproduce working behavior, and would if the dependency followed semver. It doesn't here, so any regen legitimately resolves to a broken version.
Impact
6 test failures surface on a fresh regen, across the two OLX suites:
src/editors/containers/ProblemEditor/data/ReactStateOLXParser.test.js (4 failures) — empty elements serialize as [object Object]:
Test numerical response with feedback and hints problem type
Test numerical response with isAnswerRange true
Test string response with feedback and hints problem type
Test string response with feedback and hints, multiple answers
c13a961 — "handle non-array input for XML builder when preserveOrder is true"
' → ' encoding
5.7.3
f9c9a2c — "update builder to 1.1.7", pulling in fast-xml-builderfddfaf31 — "escape quotes in attribute value"
Version-by-version (both ProblemEditor suites):
Version
ReactStateOLXParser
OLXParser
5.3.7
✅
✅
5.3.8
❌ (4)
✅
5.7.2
❌ (4)
✅
5.7.3
❌ (4)
❌ (2)
5.10.1
❌ (4)
❌ (2)
Regression 1 — [object Object] (5.3.8)
The ordered (preserveOrder: true) builder's arrToStr gained a non-array guard in commit c13a961 (v5.3.7...v5.3.8):
function arrToStr(arr, options, jPath, indentation) {
let xmlStr = "";
let isPreviousElementTag = false;
+ if (!Array.isArray(arr)) {+ // Non-array values (e.g. string tag values) should be treated as text content+ if (arr !== undefined && arr !== null) {+ let text = arr.toString();+ text = replaceEntitiesValue(text, options);+ return text;+ }+ return "";+ }
for (let i = 0; i < arr.length; i++) {
Our OLX code builds empty nodes as a bare object rather than the array preserveOrder expects:
Before 5.3.8, arrToStr iterated for (i=0; i<arr.length; …) over that object; .length is undefined, so zero iterations ran and it returned "". Since 5.3.8 the new branch runs arr.toString(), and ({ '#text': '' }).toString() is "[object Object]". This is a latent bug in our code (we pass an object where preserveOrder requires an array) that the library previously tolerated silently.
Regression 2 — ' encoding (5.7.3)
fast-xml-parser commit f9c9a2c ("update builder to 1.1.7", in v5.7.2...v5.7.3) bumped the bundled fast-xml-builder from 1.1.6 → 1.1.7. The actual behavior change is fast-xml-builder commit fddfaf31 — "escape quotes in attribute value" — which added:
and applied it to attribute values in the preserveOrder builder (all three attr_to_str* paths in src/orderedJs2Xml.js). It's a security fix — escaping " prevents attribute-injection payloads like " onClick="alert(1) — but it also escapes ', and crucially it runs unconditionally, independent of processEntities.
Our builder sets processEntities: false (OLXParser.js:127) precisely to avoid entity encoding, but escapeAttribute bypasses that opt-out. Our OLX carries apostrophes inside a style attribute (style="font-family: 'courier new', courier;"), so they now serialize as '. ' is valid XML, but it changes our OLX output and breaks the OLXParser round-trip expectations.
Recommended fixes
Regression 1 (correct fix): wrap the empty nodes in arrays so they conform to preserveOrder — textline: [{ '#text': '' }], formulaequationinput: [{ '#text': '' }]. This is version-agnostic (passes on all versions) and is a genuine bug fix.
Regression 2 (decision needed): the escapeAttribute change is intentional upstream security hardening and runs unconditionally (no opt-out), so the realistic path is to accept ' as valid output and update the OLXParser expectations accordingly.
Fix #1 is required for the security bump in #3175 (5.7.0) — Regression 1 (5.3.8) already affects that version. Fix #2 only becomes necessary at 5.7.3+, so it is additionally required to move to the latest release.
Note
This issue was researched and drafted by Claude (via Claude Code), and reviewed by @brian-smith-tcril before filing.
Summary
fast-xml-parserintroduces two separate behavior changes in its XML builder — in the patch release5.3.8and the patch release5.7.3— that break the Problem Editor's OLX serialization/parsing. Both are breaking changes shipped in non-major releases, i.e. semver violations. Ourpackage.jsondeclares"fast-xml-parser": "^5.0.0", an honest range that (correctly, per semver) permits these releases, so a from-scratchpackage-lock.jsonregeneration floats the dependency up to the latest 5.x and the ProblemEditor test suites start failing. This currently blocks the security update in #3175 (bump to5.7.0) and any lockfile regeneration.The committed lockfile currently snapshots
5.3.6, which is why CI is green today. That snapshot is a known-working resolution, not a version policy — a lockfile regen should reproduce working behavior, and would if the dependency followed semver. It doesn't here, so any regen legitimately resolves to a broken version.Impact
6 test failures surface on a fresh regen, across the two OLX suites:
src/editors/containers/ProblemEditor/data/ReactStateOLXParser.test.js(4 failures) — empty elements serialize as[object Object]:Test numerical response with feedback and hints problem typeTest numerical response with isAnswerRange trueTest string response with feedback and hints problem typeTest string response with feedback and hints, multiple answersExample:
src/editors/containers/ProblemEditor/data/OLXParser.test.js(2 failures) — apostrophes are entity-encoded as':parseMultipleChoiceAnswers() › given multiple choice olx with hex numbers and leading zeros › should not parse hex numbers and leading zerosparseQuestions() › given olx with html entities › should not encode html entitiesExample:
Root cause — two distinct regressions
We bisected each failure to an exact release:
[object Object]for empty nodesc13a961— "handle non-array input for XML builder when preserveOrder is true"'→'encodingf9c9a2c— "update builder to 1.1.7", pulling infast-xml-builderfddfaf31— "escape quotes in attribute value"Version-by-version (both ProblemEditor suites):
Regression 1 —
[object Object](5.3.8)The ordered (
preserveOrder: true) builder'sarrToStrgained a non-array guard in commitc13a961(v5.3.7...v5.3.8):function arrToStr(arr, options, jPath, indentation) { let xmlStr = ""; let isPreviousElementTag = false; + if (!Array.isArray(arr)) { + // Non-array values (e.g. string tag values) should be treated as text content + if (arr !== undefined && arr !== null) { + let text = arr.toString(); + text = replaceEntitiesValue(text, options); + return text; + } + return ""; + } for (let i = 0; i < arr.length; i++) {Our OLX code builds empty nodes as a bare object rather than the array
preserveOrderexpects:ReactStateOLXParser.js:380→textline: { '#text': '' }ReactStateOLXParser.js:492→formulaequationinput: { '#text': '' }Before 5.3.8,
arrToStriteratedfor (i=0; i<arr.length; …)over that object;.lengthisundefined, so zero iterations ran and it returned"". Since 5.3.8 the new branch runsarr.toString(), and({ '#text': '' }).toString()is"[object Object]". This is a latent bug in our code (we pass an object wherepreserveOrderrequires an array) that the library previously tolerated silently.Regression 2 —
'encoding (5.7.3)fast-xml-parser commit
f9c9a2c("update builder to 1.1.7", in v5.7.2...v5.7.3) bumped the bundledfast-xml-builderfrom 1.1.6 → 1.1.7. The actual behavior change isfast-xml-buildercommitfddfaf31— "escape quotes in attribute value" — which added:and applied it to attribute values in the
preserveOrderbuilder (all threeattr_to_str*paths insrc/orderedJs2Xml.js). It's a security fix — escaping"prevents attribute-injection payloads like" onClick="alert(1)— but it also escapes', and crucially it runs unconditionally, independent ofprocessEntities.Our builder sets
processEntities: false(OLXParser.js:127) precisely to avoid entity encoding, butescapeAttributebypasses that opt-out. Our OLX carries apostrophes inside astyleattribute (style="font-family: 'courier new', courier;"), so they now serialize as'.'is valid XML, but it changes our OLX output and breaks theOLXParserround-trip expectations.Recommended fixes
preserveOrder—textline: [{ '#text': '' }],formulaequationinput: [{ '#text': '' }]. This is version-agnostic (passes on all versions) and is a genuine bug fix.escapeAttributechange is intentional upstream security hardening and runs unconditionally (no opt-out), so the realistic path is to accept'as valid output and update theOLXParserexpectations accordingly.Fix #1 is required for the security bump in #3175 (
5.7.0) — Regression 1 (5.3.8) already affects that version. Fix #2 only becomes necessary at5.7.3+, so it is additionally required to move to the latest release.