From 5ea549cf54ce0de22e2c10b1c470406cb90f4725 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 2 Jun 2026 19:07:15 -0700 Subject: [PATCH] XML: fixed exception classes Report XML API misuse as TypeError and XML parse failures as SyntaxError, aligning njs and QuickJS behavior. The QuickJS message "'this' is not XMLNode or XMLDoc" is changed to "value is not XMLNode or XMLDoc" because qjs_xml_node() is not always validating this. --- external/njs_xml_module.c | 2 +- external/qjs_xml_module.c | 20 ++++++++++---------- test/xml/xml.t.mjs | 12 ++++++++++++ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/external/njs_xml_module.c b/external/njs_xml_module.c index f1d275aa..4736c3ac 100644 --- a/external/njs_xml_module.c +++ b/external/njs_xml_module.c @@ -2022,7 +2022,7 @@ njs_xml_error(njs_vm_t *vm, njs_xml_doc_t *current, const char *fmt, ...) err->int2); } - njs_vm_error(vm, "%*s", p - errstr, errstr); + njs_vm_syntax_error(vm, "%*s", p - errstr, errstr); } diff --git a/external/qjs_xml_module.c b/external/qjs_xml_module.c index af297e5b..36dfdba8 100644 --- a/external/qjs_xml_module.c +++ b/external/qjs_xml_module.c @@ -384,7 +384,7 @@ qjs_xml_doc_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, tree = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_DOC); if (tree == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLDoc"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLDoc"); return -1; } @@ -469,7 +469,7 @@ qjs_xml_doc_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, tree = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_DOC); if (tree == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLDoc"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLDoc"); return -1; } @@ -741,9 +741,9 @@ qjs_xml_node_tag_modify(JSContext *cx, JSValue obj, njs_str_t *name, } if (!JS_IsNullOrUndefined(setval)) { - JS_ThrowInternalError(cx, "XMLNode.$tag$xxx is not assignable, " - "use addChild() or node.$tags = [node1, node2, ..] " - "syntax"); + JS_ThrowTypeError(cx, "XMLNode.$tag$xxx is not assignable, " + "use addChild() or node.$tags = [node1, node2, ..] " + "syntax"); return -1; } @@ -929,7 +929,7 @@ qjs_xml_node_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, current = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_NODE); if (current == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLNode"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLNode"); return -1; } @@ -1173,7 +1173,7 @@ qjs_xml_node_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, tree = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_NODE); if (tree == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLNode"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLNode"); return -1; } @@ -1552,7 +1552,7 @@ qjs_xml_node(JSContext *cx, JSValueConst val, xmlDoc **doc) if (current == NULL) { tree = JS_GetOpaque(val, QJS_CORE_CLASS_ID_XML_DOC); if (tree == NULL) { - JS_ThrowInternalError(cx, "'this' is not XMLNode or XMLDoc"); + JS_ThrowTypeError(cx, "value is not XMLNode or XMLDoc"); return NULL; } @@ -1611,7 +1611,7 @@ qjs_xml_attr_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, current = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_ATTR); if (current == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLAttr"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLAttr"); return -1; } @@ -1675,7 +1675,7 @@ qjs_xml_attr_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, current = JS_GetOpaque(obj, QJS_CORE_CLASS_ID_XML_ATTR); if (current == NULL) { - (void) JS_ThrowInternalError(cx, "\"this\" is not an XMLAttr"); + (void) JS_ThrowTypeError(cx, "\"this\" is not an XMLAttr"); return -1; } diff --git a/test/xml/xml.t.mjs b/test/xml/xml.t.mjs index 4533c8ad..8590bddc 100644 --- a/test/xml/xml.t.mjs +++ b/test/xml/xml.t.mjs @@ -366,6 +366,18 @@ let modify_tsuite = { return xml.serializeToString(doc); }, expected: `ToveJani` }, + { get: (doc) => { + try { + doc.note.$tag$xxx = doc.note.to; + } catch (e) { + if (e instanceof TypeError) { + return 'OK'; + } + } + + throw Error('unexpected exception'); + }, + expected: 'OK' }, { doc: `ABC`, get: (doc) => { doc.$root.removeChildren('a'); -- 2.47.3