From cf9c5898570aa55bf2c35af579d5f28a8d02540a Mon Sep 17 00:00:00 2001 From: Louis-Dominique Dubeau Date: Fri, 6 Jul 2018 14:12:14 -0400 Subject: [PATCH] feat: revamped error messages The error messages now show: filename:line:column: message The character being processed is no longer shown. The language was also cleaned up to avoid talking about "validity" since we don't validate XML against a schema and some messages have been made clearer. --- README.md | 13 ++- lib/saxes.js | 132 ++++++++++++++-------------- test/attribute-no-space.js | 2 +- test/attribute-unquoted.js | 5 +- test/bad-entities.js | 6 +- test/bom.js | 4 +- test/duplicate-attribute.js | 2 +- test/end_empty_stream.js | 5 +- test/entity-nan.js | 5 +- test/index.js | 7 +- test/issue-86.js | 4 +- test/parser-position.js | 12 +++ test/trailing-attribute-no-value.js | 5 +- test/trailing-non-whitespace.js | 5 +- test/unclosed-root.js | 2 +- test/xml-internal-entities.js | 5 +- test/xmlns-unbound.js | 4 +- test/xmlns-xml-default-prefix.js | 5 +- 18 files changed, 113 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index 5d53f507..3618d674 100644 --- a/README.md +++ b/README.md @@ -77,12 +77,19 @@ fs.createReadStream("file.xml") Pass the following arguments to the parser function. All are optional. -`opt` - Object bag of settings regarding string formatting. All default to `false`. +`opt` - Object bag of settings regarding string formatting. Settings supported: -* `xmlns` - Boolean. If true, then namespaces are supported. -* `position` - Boolean. If false, then don't track line/col/position. +* `xmlns` - Boolean. If true, then namespaces are supported. Default + is `false`. + +* `position` - Boolean. If false, then don't track + line/col/position. Unset is treated as `true`. Default is unset.x + +* `fileName` - String. Set a file name for error reporting. This is + useful only when tracking positions. You may leave it unset, in + which case the file name in error messages will be `undefined`. ## Methods diff --git a/lib/saxes.js b/lib/saxes.js index ba1e67ec..0478808f 100644 --- a/lib/saxes.js +++ b/lib/saxes.js @@ -148,10 +148,11 @@ class SAXParser { this.ns = Object.create(rootNS); } - // mostly just for error reporting this.trackPosition = this.opt.position !== false; if (this.trackPosition) { - this.position = this.line = this.column = 0; + this.line = 1; + this.position = this.column = 0; + this.fileName = this.opt.fileName; } this.onready(); } @@ -178,15 +179,15 @@ class SAXParser { end() { if (!this.sawRoot) { - this.fail("Document must contain a root element"); + this.fail("document must contain a root element."); } if (this.sawRoot && !this.closedRoot) { - this.fail("Unclosed root tag"); + this.fail("unclosed root tag."); } if ((this.state !== S_BEGIN) && (this.state !== S_BEGIN_WHITESPACE) && (this.state !== S_TEXT)) { - this.fail("Unexpected end"); + this.fail("unexpected end."); } this.closeText(); this.c = ""; @@ -198,13 +199,10 @@ class SAXParser { fail(er) { this.closeText(); - if (this.trackPosition) { - er += `\nLine: ${this.line - }\nColumn: ${this.column - }\nChar: ${this.c}`; - } - er = new Error(er); - this.error = er; + const message = (this.trackPosition) ? + `${this.fileName}:${this.line}:${this.column}: ${er}` : er; + + this.error = er = new Error(message); this.onerror(er); return this; } @@ -214,7 +212,7 @@ class SAXParser { throw this.error; } if (this.closed) { - return this.fail("Cannot write after close. Assign an onready handler."); + return this.fail("cannot write after close; assign an onready handler."); } if (chunk === null) { return this.end(); @@ -242,7 +240,7 @@ class SAXParser { } if (!CHAR.test(c)) { - this.fail("Invalid character"); + this.fail("disallowed character."); } switch (this.state) { @@ -261,7 +259,7 @@ class SAXParser { // have to process this as a text node. // weird, but happens. if (!this.reportedTextBeforeRoot) { - this.fail("Text data outside of root node."); + this.fail("text data outside of root node."); this.reportedTextBeforeRoot = true; } this.textNode = c; @@ -277,7 +275,7 @@ class SAXParser { i += c.length; if (!CHAR.test(c)) { - this.fail("Invalid character"); + this.fail("disallowed character."); } if (c && this.trackPosition) { @@ -293,7 +291,7 @@ class SAXParser { } const fragment = chunk.substring(starti, i - 1); if (fragment.includes("]]>")) { - this.fail("The string \"]]>\" is disallowed in char data."); + this.fail("the string \"]]>\" is disallowed in char data."); } this.textNode += fragment; } @@ -307,12 +305,12 @@ class SAXParser { // to avoid reporting errors for every single character that is out // of place. if (!this.sawRoot && !this.reportedTextBeforeRoot) { - this.fail("Text data outside of root node."); + this.fail("text data outside of root node."); this.reportedTextBeforeRoot = true; } if (this.closedRoot && !this.reportedTextAfterRoot) { - this.fail("Text data outside of root node."); + this.fail("text data outside of root node."); this.reportedTextAfterRoot = true; } } @@ -344,7 +342,7 @@ class SAXParser { this.piTarget = this.piBody = ""; } else { - this.fail("Unencoded <"); + this.fail("unencoded <."); // if there was some whitespace, then add that in. if (this.startTagPosition + 1 < this.position) { const pad = this.position - this.startTagPosition; @@ -358,12 +356,12 @@ class SAXParser { case S_OPEN_WAKA_BANG: if ((this.openWakaBang + c) === CDATA) { if (!this.sawRoot && !this.reportedTextBeforeRoot) { - this.fail("Text data outside of root node."); + this.fail("text data outside of root node."); this.reportedTextBeforeRoot = true; } if (this.closedRoot && !this.reportedTextAfterRoot) { - this.fail("Text data outside of root node."); + this.fail("text data outside of root node."); this.reportedTextAfterRoot = true; } this.emitNode("onopencdata"); @@ -379,7 +377,7 @@ class SAXParser { else if ((this.openWakaBang + c).toUpperCase() === DOCTYPE) { this.state = S_DOCTYPE; if (this.doctype || this.sawRoot) { - this.fail("Inappropriately located doctype declaration"); + this.fail("inappropriately located doctype declaration."); } this.doctype = ""; this.openWakaBang = ""; @@ -389,7 +387,7 @@ class SAXParser { // 7 happens to be the maximum length of the string that can possibly // match one of the cases above. if (this.openWakaBang.length >= 7) { - this.fail("Incorrect syntax"); + this.fail("incorrect syntax."); } } continue; @@ -464,7 +462,7 @@ class SAXParser { case S_COMMENT_ENDED: if (c !== ">") { - this.fail("Malformed comment"); + this.fail("malformed comment."); // will be recorded as // a comment of " blah -- bloo " this.comment += `--${c}`; @@ -522,12 +520,12 @@ class SAXParser { else { if (!(isMatch(this.piTarget.length ? NAME_CHAR : NAME_START_CHAR, c) && - // When namespaces are used, colons are not valid in entity + // When namespaces are used, colons are not allowed in entity // names. // https://www.w3.org/XML/xml-names-19990114-errata.html // NE08 (!this.opt.xmlns || c !== ":"))) { - this.fail("Invalid characer in processing instruction name."); + this.fail("disallowed characer in processing instruction name."); } this.piTarget += c; } @@ -548,7 +546,7 @@ class SAXParser { case S_PI_ENDING: if (c === ">") { if (this.piTarget.trim() === "") { - this.fail("Processing instruction without a target"); + this.fail("processing instruction without a target."); } this.emitNode("onprocessinginstruction", { target: this.piTarget, @@ -584,7 +582,7 @@ class SAXParser { } else { if (!isWhitespace(c)) { - this.fail("Invalid character in tag name"); + this.fail("disallowed character in tag name."); } this.state = S_ATTRIB; } @@ -597,7 +595,7 @@ class SAXParser { this.closeTag(); } else { - this.fail("Forward-slash in opening tag not followed by >"); + this.fail("forward-slash in opening tag not followed by >."); this.state = S_ATTRIB; } continue; @@ -619,7 +617,7 @@ class SAXParser { this.state = S_ATTRIB_NAME; } else { - this.fail("Invalid attribute name"); + this.fail("disallowed character in attribute name."); } continue; @@ -628,7 +626,7 @@ class SAXParser { this.state = S_ATTRIB_VALUE; } else if (c === ">") { - this.fail("Attribute without value"); + this.fail("attribute without value."); this.attribList.push([this.attribName, this.attribName]); this.attribName = this.attribValue = ""; this.openTag(); @@ -640,7 +638,7 @@ class SAXParser { this.attribName += c; } else { - this.fail("Invalid attribute name"); + this.fail("disallowed character in attribute name."); } continue; @@ -652,7 +650,7 @@ class SAXParser { continue; } else { - this.fail("Attribute without value"); + this.fail("attribute without value."); this.tag.attributes[this.attribName] = ""; this.attribValue = ""; this.emitNode("onattribute", { @@ -668,7 +666,7 @@ class SAXParser { this.state = S_ATTRIB_NAME; } else { - this.fail("Invalid attribute name"); + this.fail("disallowed character in attribute name."); this.state = S_ATTRIB; } } @@ -683,7 +681,7 @@ class SAXParser { this.state = S_ATTRIB_VALUE_QUOTED; } else { - this.fail("Unquoted attribute value"); + this.fail("unquoted attribute value."); this.state = S_ATTRIB_VALUE_UNQUOTED; this.attribValue = c; } @@ -695,7 +693,7 @@ class SAXParser { this.state = S_ATTRIB_VALUE_ENTITY_Q; } else if (c === "<") { - this.fail("Invalid character."); + this.fail("disallowed character."); } else { this.attribValue += c; @@ -703,7 +701,7 @@ class SAXParser { continue; } if (this.attribValue.includes("]]>")) { - this.fail("The string \"]]>\" is disallowed in char data."); + this.fail("the string \"]]>\" is disallowed in char data."); } this.attribList.push([this.attribName, this.attribValue]); this.attribName = this.attribValue = ""; @@ -722,13 +720,13 @@ class SAXParser { this.state = S_OPEN_TAG_SLASH; } else if (isMatch(NAME_START_CHAR, c)) { - this.fail("No whitespace between attributes"); + this.fail("no whitespace between attributes."); this.attribName = c; this.attribValue = ""; this.state = S_ATTRIB_NAME; } else { - this.fail("Invalid attribute name"); + this.fail("disallowed character in attribute name."); } continue; @@ -738,7 +736,7 @@ class SAXParser { this.state = S_ATTRIB_VALUE_ENTITY_U; } else if (c === "<") { - this.fail("Invalid character."); + this.fail("disallowed character."); } else { this.attribValue += c; @@ -746,7 +744,7 @@ class SAXParser { continue; } if (this.attribValue.includes("]]>")) { - this.fail("The string \"]]>\" is disallowed in char data."); + this.fail("the string \"]]>\" is disallowed in char data."); } this.attribList.push([this.attribName, this.attribValue]); this.attribName = this.attribValue = ""; @@ -761,7 +759,7 @@ class SAXParser { case S_CLOSE_TAG: if (!this.tagName) { if (notMatch(NAME_START_CHAR, c)) { - this.fail("Invalid tagname in closing tag."); + this.fail("disallowed character in closing tag name."); } else { this.tagName = c; @@ -775,7 +773,7 @@ class SAXParser { } else { if (!isWhitespace(c)) { - this.fail("Invalid tagname in closing tag"); + this.fail("disallowed character in closing tag name."); } this.state = S_CLOSE_TAG_SAW_WHITE; } @@ -789,7 +787,7 @@ class SAXParser { this.closeTag(); } else { - this.fail("Invalid characters in closing tag"); + this.fail("disallowed character in closing tag."); } continue; @@ -832,7 +830,7 @@ class SAXParser { this.entity += c; } else { - this.fail("Invalid character in entity name"); + this.fail("disallowed character in entity name."); this[buffer] += `&${this.entity}${c}`; this.entity = ""; this.state = returnState; @@ -900,7 +898,7 @@ class SAXParser { else { // A colon at the start of the name is illegal. if (colon === 0) { - this.fail(`Invalid name: ${name}`); + this.fail(`malformed name: ${name}.`); } prefix = name.substr(0, colon); local = name.substr(colon + 1); @@ -938,33 +936,31 @@ class SAXParser { uri = uri.trim(); // namespace binding attribute. push the binding into scope if (local === "xml" && uri !== XML_NAMESPACE) { - this.fail(`xml: prefix must be bound to ${XML_NAMESPACE}\n` + - `Actual: ${uri}`); + this.fail(`xml prefix must be bound to ${XML_NAMESPACE}.`); } else if (local === "xmlns" && uri !== XMLNS_NAMESPACE) { - this.fail(`xmlns: prefix must be bound to ${XMLNS_NAMESPACE}\n` + - `Actual: ${uri}`); + this.fail(`xmlns prefix must be bound to ${XMLNS_NAMESPACE}.`); } else { switch (uri) { case XMLNS_NAMESPACE: if (local === "") { - this.fail(`The default namespace may not be set to + this.fail(`the default namespace may not be set to ${XMLNS_NAMESPACE}.`); } else { - this.fail(`May not assign a prefix (even "xmlns") to the URI \ + this.fail(`may not assign a prefix (even "xmlns") to the URI \ ${XMLNS_NAMESPACE}.`); } break; case XML_NAMESPACE: if (local === "") { - this.fail(`The default namespace may not be set to + this.fail(`the default namespace may not be set to ${XML_NAMESPACE}.`); } else if (local !== "xml") { this.fail( - "May not assign the xml namespace to another prefix."); + "may not assign the xml namespace to another prefix."); } break; default: @@ -988,12 +984,12 @@ ${XML_NAMESPACE}.`); if (tag.prefix) { if (tag.prefix === "xmlns") { - this.fail("Tags may not have \"xmlns\" as prefix."); + this.fail("tags may not have \"xmlns\" as prefix."); } if (!tag.uri) { - this.fail(`Unbound namespace prefix: ${ - JSON.stringify(this.tagName)}`); + this.fail(`unbound namespace prefix: \ +${JSON.stringify(this.tagName)}.`); tag.uri = qn.prefix; } } @@ -1014,15 +1010,15 @@ ${XML_NAMESPACE}.`); const eqname = `{${uri}}${local}`; if (seen.has(eqname)) { - this.fail(`Duplicate attribute: ${eqname}`); + this.fail(`duplicate attribute: ${eqname}.`); } seen.add(eqname); // if there's any attributes with an undefined namespace, // then fail on them now. if (prefix && prefix !== "xmlns" && !uri) { - this.fail(`Unbound namespace prefix: ${ - JSON.stringify(prefix)}`); + this.fail(`unbound namespace prefix: ${ + JSON.stringify(prefix)}.`); a.uri = prefix; } tag.attributes[name] = a; @@ -1033,7 +1029,7 @@ ${XML_NAMESPACE}.`); for (const [name, value] of this.attribList) { const a = { name, value }; if (this.tag.attributes[name]) { - this.fail(`Duplicate attribute: ${name}.`); + this.fail(`duplicate attribute: ${name}.`); } this.tag.attributes[name] = value; this.emitNode("onattribute", a); @@ -1045,7 +1041,7 @@ ${XML_NAMESPACE}.`); // process the tag if (this.closedRoot) { - this.fail("Documents may contain only one root."); + this.fail("documents may contain only one root."); } this.sawRoot = true; this.tags.push(tag); @@ -1060,7 +1056,7 @@ ${XML_NAMESPACE}.`); closeTag() { if (!this.tagName) { - this.fail("Weird empty close tag."); + this.fail("weird empty close tag."); this.textNode += ""; this.state = S_TEXT; return; @@ -1075,7 +1071,7 @@ ${XML_NAMESPACE}.`); while (t--) { const close = tags[t]; if (close.name !== closeTo) { - this.fail("Unexpected close tag"); + this.fail("unexpected close tag."); } else { break; @@ -1083,7 +1079,7 @@ ${XML_NAMESPACE}.`); } if (t < 0) { - this.fail(`Unmatched closing tag: ${tagName}`); + this.fail(`unmatched closing tag: ${tagName}.`); this.textNode += ``; this.state = S_TEXT; return; @@ -1129,14 +1125,14 @@ ${XML_NAMESPACE}.`); } if (Number.isNaN(num) || num > 0x10FFFF) { - this.fail("Invalid character entity"); + this.fail("malformed character entity."); return `&${this.entity};`; } const char = String.fromCodePoint(num); // The character reference is required to match the CHAR production. if (!CHAR.test(char)) { - this.fail("Invalid character entity"); + this.fail("malformed character entity."); return `&${this.entity};`; } diff --git a/test/attribute-no-space.js b/test/attribute-no-space.js index a7aeccc5..05dd877c 100644 --- a/test/attribute-no-space.js +++ b/test/attribute-no-space.js @@ -6,7 +6,7 @@ require(".").test({ xml: "", expect: [ ["opentagstart", { name: "root", attributes: {} }], - ["error", "No whitespace between attributes\nLine: 0\nColumn: 20\nChar: a"], + ["error", "undefined:1:20: no whitespace between attributes."], ["attribute", { name: "attr1", value: "first" }], ["attribute", { name: "attr2", value: "second" }], ["opentag", { name: "root", attributes: { attr1: "first", attr2: "second" }, isSelfClosing: true }], diff --git a/test/attribute-unquoted.js b/test/attribute-unquoted.js index eccad451..b4b6ab79 100644 --- a/test/attribute-unquoted.js +++ b/test/attribute-unquoted.js @@ -4,10 +4,7 @@ require(".").test({ name: "attribute unquoted", expect: [ ["opentagstart", { name: "root", attributes: {}, ns: {} }], - ["error", "Unquoted attribute value\n\ -Line: 0\n\ -Column: 14\n\ -Char: 1"], + ["error", "undefined:1:14: unquoted attribute value."], ["attribute", { name: "length", value: "12345", diff --git a/test/bad-entities.js b/test/bad-entities.js index 30a534fd..e7723b21 100644 --- a/test/bad-entities.js +++ b/test/bad-entities.js @@ -6,7 +6,7 @@ require(".").test({ expect: [ ["opentagstart", { name: "r", attributes: {} }], ["opentag", { name: "r", attributes: {}, isSelfClosing: false }], - ["error", "Invalid character entity\nLine: 0\nColumn: 5\nChar: ;"], + ["error", "undefined:1:5: malformed character entity."], ["text", "&;"], ["closetag", "r"], ], @@ -18,7 +18,7 @@ require(".").test({ expect: [ ["opentagstart", { name: "r", attributes: {} }], ["opentag", { name: "r", attributes: {}, isSelfClosing: false }], - ["error", "Invalid character entity\nLine: 0\nColumn: 6\nChar: ;"], + ["error", "undefined:1:6: malformed character entity."], ["text", "&#;"], ["closetag", "r"], ], @@ -30,7 +30,7 @@ require(".").test({ expect: [ ["opentagstart", { name: "r", attributes: {} }], ["opentag", { name: "r", attributes: {}, isSelfClosing: false }], - ["error", "Invalid character entity\nLine: 0\nColumn: 7\nChar: ;"], + ["error", "undefined:1:7: malformed character entity."], ["text", "&#x;"], ["closetag", "r"], ], diff --git a/test/bom.js b/test/bom.js index 82147eaa..54ed8c62 100644 --- a/test/bom.js +++ b/test/bom.js @@ -29,7 +29,7 @@ require(".").test({ name: "BOM outside of root, but not initial", xml: " \uFEFF

", expect: [ - ["error", "Text data outside of root node.\nLine: 0\nColumn: 2\nChar: \uFEFF"], + ["error", "undefined:1:2: text data outside of root node."], ["text", "\uFEFF"], ["opentagstart", { name: "P", attributes: {} }], ["opentag", { name: "P", attributes: {}, isSelfClosing: false }], @@ -42,7 +42,7 @@ require(".").test({ name: "multiple BOMs", xml: "\uFEFF\uFEFF

", expect: [ - ["error", "Text data outside of root node.\nLine: 0\nColumn: 2\nChar: \uFEFF"], + ["error", "undefined:1:2: text data outside of root node."], ["text", "\uFEFF"], ["opentagstart", { name: "P", attributes: {} }], ["opentag", { name: "P", attributes: {}, isSelfClosing: false }], diff --git a/test/duplicate-attribute.js b/test/duplicate-attribute.js index d86caaf2..6c1fb13e 100644 --- a/test/duplicate-attribute.js +++ b/test/duplicate-attribute.js @@ -9,7 +9,7 @@ require(".").test({ attributes: {}, }], ["attribute", { name: "id", value: "hello" }], - ["error", "Duplicate attribute: id.\nLine: 0\nColumn: 28\nChar: >"], + ["error", "undefined:1:28: duplicate attribute: id."], ["attribute", { name: "id", value: "there" }], ["opentag", { name: "span", diff --git a/test/end_empty_stream.js b/test/end_empty_stream.js index dc916b0a..54c13502 100644 --- a/test/end_empty_stream.js +++ b/test/end_empty_stream.js @@ -6,6 +6,7 @@ const saxes = require("../lib/saxes"); it("end empty stream", () => { const saxesStream = saxes.createStream(); // It musn't throw. - expect(() => saxesStream.end()).to.throw(Error, - /Document must contain a root element/); + expect(() => saxesStream.end()).to.throw( + Error, + /^undefined:1:0: document must contain a root element.$/); }); diff --git a/test/entity-nan.js b/test/entity-nan.js index 3dda933a..ec9e609e 100644 --- a/test/entity-nan.js +++ b/test/entity-nan.js @@ -6,10 +6,7 @@ require(".").test({ expect: [ ["opentagstart", { name: "r", attributes: {} }], ["opentag", { name: "r", attributes: {}, isSelfClosing: false }], - ["error", "Invalid character entity\n\ -Line: 0\n\ -Column: 9\n\ -Char: ;"], + ["error", "undefined:1:9: malformed character entity."], ["text", "&#NaN;"], ["closetag", "r"], ], diff --git a/test/index.js b/test/index.js index 240e1db8..98492cf8 100644 --- a/test/index.js +++ b/test/index.js @@ -53,13 +53,14 @@ exports.test = function test(options) { }; } - expect(xml || fn, "must use xml or fn").to.not.be.undefined; + expect(xml !== undefined || fn !== undefined, + "must use xml or fn").to.be.true; - if (xml) { + if (xml !== undefined) { parser.write(xml).close(); } - if (fn) { + if (fn !== undefined) { fn(parser); } diff --git a/test/issue-86.js b/test/issue-86.js index e801c2b7..a245ec81 100644 --- a/test/issue-86.js +++ b/test/issue-86.js @@ -29,7 +29,7 @@ require(".").test({ ], [ "error", - "Text data outside of root node.\nLine: 0\nColumn: 17\nChar: d", + "undefined:1:17: text data outside of root node.", ], [ "text", @@ -37,7 +37,7 @@ require(".").test({ ], [ "error", - "Unexpected end\nLine: 0\nColumn: 20\nChar: f", + "undefined:1:20: unexpected end.", ], ], opt: {}, diff --git a/test/parser-position.js b/test/parser-position.js index c31b3fa1..4ec37c54 100644 --- a/test/parser-position.js +++ b/test/parser-position.js @@ -2,6 +2,7 @@ const { expect } = require("chai"); const saxes = require("../lib/saxes"); +const { test } = require("."); function testPosition(name, chunks, expectedEvents) { it(name, () => { @@ -38,4 +39,15 @@ describe("parser position", () => { ["text", { position: 19, startTagPosition: 14 }], ["closetag", { position: 19, startTagPosition: 14 }], ]); + + test({ + name: "pi before root", + xml: "", + expect: [ + ["error", "fnord.xml:1:0: document must contain a root element."], + ], + opt: { + fileName: "fnord.xml", + }, + }); }); diff --git a/test/trailing-attribute-no-value.js b/test/trailing-attribute-no-value.js index 03f23567..9ba1c382 100644 --- a/test/trailing-attribute-no-value.js +++ b/test/trailing-attribute-no-value.js @@ -5,10 +5,7 @@ require(".").test({ xml: "", expect: [ ["opentagstart", { name: "root", attributes: {} }], - ["error", "Attribute without value\n\ -Line: 0\n\ -Column: 13\n\ -Char: >"], + ["error", "undefined:1:13: attribute without value."], ["attribute", { name: "attrib", value: "attrib" }], ["opentag", { name: "root", attributes: { attrib: "attrib" }, isSelfClosing: false }], ["closetag", "root"], diff --git a/test/trailing-non-whitespace.js b/test/trailing-non-whitespace.js index 4658bc66..81eb1cec 100644 --- a/test/trailing-non-whitespace.js +++ b/test/trailing-non-whitespace.js @@ -16,10 +16,7 @@ require(".").test({ ["text", "Welcome,"], ["closetag", "span"], ["text", " "], - ["error", "Text data outside of root node.\n\ -Line: 0\n\ -Column: 23\n\ -Char: t"], + ["error", "undefined:1:23: text data outside of root node."], ["text", "to monkey land"], ["end", undefined], ["ready", undefined], diff --git a/test/unclosed-root.js b/test/unclosed-root.js index 11398fae..2f7f291a 100644 --- a/test/unclosed-root.js +++ b/test/unclosed-root.js @@ -21,7 +21,7 @@ require(".").test({ ], [ "error", - "Unclosed root tag\nLine: 0\nColumn: 6\nChar: >", + "undefined:1:6: unclosed root tag.", ], ], opt: {}, diff --git a/test/xml-internal-entities.js b/test/xml-internal-entities.js index 0ee47a16..a4612d59 100644 --- a/test/xml-internal-entities.js +++ b/test/xml-internal-entities.js @@ -43,9 +43,8 @@ for (const entity in entitiesToTest) { if (typeof entitiesToTest[entity] === "object") { attributeErrors.push([ "error", - `Invalid character in entity name\nLine: 0\nColumn: ${ - xmlStart.length + entitiesToTest[entity][0] + 1 - }\nChar: ${entitiesToTest[entity][1]}`, + `undefined:1:${xmlStart.length + entitiesToTest[entity][0] + 1}: disallowed \ +character in entity name.`, ]); attributeEvents.push([ "attribute", diff --git a/test/xmlns-unbound.js b/test/xmlns-unbound.js index e6ba0c81..a198b947 100644 --- a/test/xmlns-unbound.js +++ b/test/xmlns-unbound.js @@ -17,7 +17,7 @@ describe("xmlns unbound prefixes", () => { ], [ "error", - "Unbound namespace prefix: \"unbound:root\"\nLine: 0\nColumn: 15\nChar: >", + "undefined:1:15: unbound namespace prefix: \"unbound:root\".", ], [ "opentag", @@ -125,7 +125,7 @@ describe("xmlns unbound prefixes", () => { ], [ "error", - "Unbound namespace prefix: \"unbound\"\nLine: 0\nColumn: 28\nChar: >", + "undefined:1:28: unbound namespace prefix: \"unbound\".", ], [ "attribute", diff --git a/test/xmlns-xml-default-prefix.js b/test/xmlns-xml-default-prefix.js index 0fc2f55b..e629772c 100644 --- a/test/xmlns-xml-default-prefix.js +++ b/test/xmlns-xml-default-prefix.js @@ -99,9 +99,8 @@ describe("xml default prefix", () => { ], [ "error", - "xml: prefix must be bound to http://www.w3.org/XML/1998/namespace\n" + - "Actual: ERROR\n" + - "Line: 0\nColumn: 29\nChar: >", + "undefined:1:29: xml prefix must be bound to \ +http://www.w3.org/XML/1998/namespace.", ], [ "attribute",