11import { XMLParser } from "fast-xml-parser"
22
33/**
4- * Encapsulated XML parser with circuit breaker pattern
4+ * Encapsulated XML parser with fallback mechanism
55 *
66 * This dual-parser system handles interference from external XML parsers (like xml2js)
77 * that may be loaded globally by other VSCode extensions. When the primary parser
88 * (fast-xml-parser) fails due to external interference, it automatically falls back
99 * to a regex-based parser.
10- *
11- * Note: This parser instance should not be used concurrently as parseFailureCount
12- * is not thread-safe. However, this is not an issue in practice since JavaScript
13- * is single-threaded.
1410 */
1511class XmlParserWithFallback {
16- private parseFailureCount = 0
17- private readonly MAX_FAILURES = 3
1812 private readonly MAX_XML_SIZE = 10 * 1024 * 1024 // 10MB limit for fallback parser
1913
2014 /**
@@ -118,14 +112,7 @@ class XmlParserWithFallback {
118112 stopNodes : _stopNodes ,
119113 } )
120114
121- const result = parser . parse ( xmlString )
122-
123- // Reset failure count on success
124- if ( this . parseFailureCount > 0 ) {
125- this . parseFailureCount = 0
126- }
127-
128- return result
115+ return parser . parse ( xmlString )
129116 } catch ( error ) {
130117 // Enhance error message for better debugging
131118 // Handle cases where error might not be an Error instance (e.g., strings, objects)
@@ -140,41 +127,23 @@ class XmlParserWithFallback {
140127 errorMessage = "Unknown error"
141128 }
142129
143- // Check for xml2js specific error patterns - IMMEDIATELY use fallback
144- if ( errorMessage . includes ( "addChild" ) ) {
145- // Don't wait for multiple failures - use fallback immediately for addChild errors
146- try {
147- const result = this . fallbackXmlParse ( xmlString )
148- return result
149- } catch ( fallbackError ) {
150- const fallbackErrorMsg = fallbackError instanceof Error ? fallbackError . message : "Unknown error"
151- // Still throw the error but make it clear we tried the fallback
152- throw new Error (
153- `XML parsing failed with fallback parser. Fallback parser also failed: ${ fallbackErrorMsg } ` ,
154- )
155- }
130+ // Try fallback parser for any parsing error
131+ // This handles both xml2js interference (addChild errors) and other parse failures
132+ try {
133+ const result = this . fallbackXmlParse ( xmlString )
134+ return result
135+ } catch ( fallbackError ) {
136+ const fallbackErrorMsg = fallbackError instanceof Error ? fallbackError . message : "Unknown error"
137+ // Provide context about which error was from xml2js interference
138+ const isXml2jsError = errorMessage . includes ( "addChild" )
139+ const errorContext = isXml2jsError
140+ ? "XML parsing failed due to external parser interference (xml2js)."
141+ : "XML parsing failed."
142+
143+ throw new Error (
144+ `${ errorContext } Fallback parser also failed. Original: ${ errorMessage } , Fallback: ${ fallbackErrorMsg } ` ,
145+ )
156146 }
157-
158- // For other errors, also consider using fallback after repeated failures
159- this . parseFailureCount ++
160-
161- if ( this . parseFailureCount >= this . MAX_FAILURES ) {
162- try {
163- const result = this . fallbackXmlParse ( xmlString )
164- // Reset counter on successful fallback
165- this . parseFailureCount = 0
166- return result
167- } catch ( fallbackError ) {
168- // Reset counter after fallback attempt
169- this . parseFailureCount = 0
170- const fallbackErrorMsg = fallbackError instanceof Error ? fallbackError . message : "Unknown error"
171- throw new Error (
172- `XML parsing failed with both parsers. Original: ${ errorMessage } , Fallback: ${ fallbackErrorMsg } ` ,
173- )
174- }
175- }
176-
177- throw new Error ( `Failed to parse XML: ${ errorMessage } ` )
178147 }
179148 }
180149}
0 commit comments