mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
fix: address PR review feedback for XML parsing improvements
- Add comprehensive documentation explaining dual-parser system - Add size limit check (10MB) for fallback regex parser to prevent memory exhaustion - Improve error handling for non-Error types thrown by third-party code - Make path extraction throw explicit error instead of returning null - Improve tag balance validation to account for self-closing tags - Simplify error messages to be more user-friendly - Add thread-safety documentation note for parser instance
This commit is contained in:
parent
7ac12fdc95
commit
6f73937e39
2 changed files with 41 additions and 9 deletions
|
|
@ -59,12 +59,14 @@ function validateApplyDiffXml(xmlString: string): boolean {
|
|||
// Basic structure validation
|
||||
const hasRequiredTags = xmlString.includes("<file>") && xmlString.includes("<path>") && xmlString.includes("<diff>")
|
||||
|
||||
// Check for balanced tags (simple check)
|
||||
// Improved tag balance check: account for self-closing tags
|
||||
const selfClosingTags = (xmlString.match(/<[^>]+\/>/g) || []).length
|
||||
const openTags = (xmlString.match(/<[^/][^>]*>/g) || []).length
|
||||
const closeTags = (xmlString.match(/<\/[^>]+>/g) || []).length
|
||||
|
||||
// Allow for slight imbalance due to self-closing tags
|
||||
const tagBalance = Math.abs(openTags - closeTags) <= 1
|
||||
// Only count non-self-closing opening tags for balance
|
||||
const nonSelfClosingOpenTags = openTags - selfClosingTags
|
||||
const tagBalance = nonSelfClosingOpenTags === closeTags
|
||||
|
||||
return hasRequiredTags && tagBalance
|
||||
}
|
||||
|
|
@ -185,7 +187,7 @@ Expected structure:
|
|||
</args>
|
||||
|
||||
Original error: ${errorMessage}
|
||||
${hasAddChild ? '\n⚠️ NOTE: Detected "addChild" error which suggests interference from another XML parser (xml2js). This may be caused by a conflicting VSCode extension.' : ""}`
|
||||
${hasAddChild ? "\n⚠️ NOTE: There may be a conflict with another extension. If you have XML-related extensions installed in VSCode, try disabling them and retrying." : ""}`
|
||||
|
||||
cline.consecutiveMistakeCount++
|
||||
cline.recordToolError("apply_diff")
|
||||
|
|
|
|||
|
|
@ -2,10 +2,20 @@ import { XMLParser } from "fast-xml-parser"
|
|||
|
||||
/**
|
||||
* Encapsulated XML parser with circuit breaker pattern
|
||||
*
|
||||
* This dual-parser system handles interference from external XML parsers (like xml2js)
|
||||
* that may be loaded globally by other VSCode extensions. When the primary parser
|
||||
* (fast-xml-parser) fails due to external interference, it automatically falls back
|
||||
* to a regex-based parser.
|
||||
*
|
||||
* Note: This parser instance should not be used concurrently as parseFailureCount
|
||||
* is not thread-safe. However, this is not an issue in practice since JavaScript
|
||||
* is single-threaded.
|
||||
*/
|
||||
class XmlParserWithFallback {
|
||||
private parseFailureCount = 0
|
||||
private readonly MAX_FAILURES = 3
|
||||
private readonly MAX_XML_SIZE = 10 * 1024 * 1024 // 10MB limit for fallback parser
|
||||
|
||||
/**
|
||||
* Fallback XML parser for apply_diff structure when fast-xml-parser fails
|
||||
|
|
@ -14,6 +24,13 @@ class XmlParserWithFallback {
|
|||
* @returns Parsed object with file entries
|
||||
*/
|
||||
private fallbackXmlParse(xmlString: string): any {
|
||||
// Check size limit to prevent memory exhaustion on very large files
|
||||
if (xmlString.length > this.MAX_XML_SIZE) {
|
||||
throw new Error(
|
||||
`XML content exceeds maximum size limit of ${this.MAX_XML_SIZE / 1024 / 1024}MB for fallback parser`,
|
||||
)
|
||||
}
|
||||
|
||||
const result: any = { file: [] }
|
||||
|
||||
// Extract file entries
|
||||
|
|
@ -24,7 +41,10 @@ class XmlParserWithFallback {
|
|||
|
||||
// Extract path
|
||||
const pathMatch = fileContent.match(/<path>(.*?)<\/path>/)
|
||||
const path = pathMatch ? pathMatch[1].trim() : null
|
||||
if (!pathMatch) {
|
||||
throw new Error("Fallback parser: <file> entry missing <path> element")
|
||||
}
|
||||
const path = pathMatch[1].trim()
|
||||
|
||||
// Extract diff blocks
|
||||
const diffMatches = fileContent.matchAll(/<diff>([\s\S]*?)<\/diff>/g)
|
||||
|
|
@ -55,7 +75,7 @@ class XmlParserWithFallback {
|
|||
}
|
||||
}
|
||||
|
||||
if (path && diffs.length > 0) {
|
||||
if (diffs.length > 0) {
|
||||
result.file.push({
|
||||
path,
|
||||
diff: diffs.length === 1 ? diffs[0] : diffs,
|
||||
|
|
@ -68,7 +88,7 @@ class XmlParserWithFallback {
|
|||
result.file = result.file[0]
|
||||
} else if (result.file.length === 0) {
|
||||
// No valid files found
|
||||
throw new Error("Fallback parser: No valid file entries found in XML")
|
||||
throw new Error("No valid file entries found in XML structure")
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
@ -108,7 +128,17 @@ class XmlParserWithFallback {
|
|||
return result
|
||||
} catch (error) {
|
||||
// Enhance error message for better debugging
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error"
|
||||
// Handle cases where error might not be an Error instance (e.g., strings, objects)
|
||||
let errorMessage: string
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message
|
||||
} else if (typeof error === "string") {
|
||||
errorMessage = error
|
||||
} else if (error && typeof error === "object" && "toString" in error) {
|
||||
errorMessage = error.toString()
|
||||
} else {
|
||||
errorMessage = "Unknown error"
|
||||
}
|
||||
|
||||
// Check for xml2js specific error patterns - IMMEDIATELY use fallback
|
||||
if (errorMessage.includes("addChild")) {
|
||||
|
|
@ -120,7 +150,7 @@ class XmlParserWithFallback {
|
|||
const fallbackErrorMsg = fallbackError instanceof Error ? fallbackError.message : "Unknown error"
|
||||
// Still throw the error but make it clear we tried the fallback
|
||||
throw new Error(
|
||||
`XML parsing failed (external xml2js interference detected). Fallback parser also failed: ${fallbackErrorMsg}`,
|
||||
`XML parsing failed with fallback parser. Fallback parser also failed: ${fallbackErrorMsg}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue