Repository: prettier/plugin-xml
Pull request #717 (2023-09-08 12:13:40)

feat: error similar to the ones thrown by Prettier
Construct parse errors similar to the ones thrown by [Prettier](https://github.com/prettier/prettier/blob/fa48415/src/common/parser-create-error.js).

I'm using the Prettier API in [my project](https://github.com/regseb/metalint/blob/d84b3ba/src/core/wrapper/prettier.js#L88-L126) and I'd like to have a single treatment for all the syntax errors reported by Prettier and its plugins.


Patch:
diff --git a/src/parser.js b/src/parser.js
index 512c41b..cb3965c 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -1,5 +1,21 @@
 import { parse as xmlToolsParse } from "@xml-tools/parser";
 
+function createError(message, options) {
+  // TODO: Use `Error.prototype.cause` when we drop support for Node.js<18.7.0
+
+  // Construct an error similar to the ones thrown by Prettier.
+  const error = new SyntaxError(
+    message +
+      " (" +
+      options.loc.start.line +
+      ":" +
+      options.loc.start.column +
+      ")"
+  );
+
+  return Object.assign(error, options);
+}
+
 const parser = {
   parse(text) {
     const { lexErrors, parseErrors, cst } = xmlToolsParse(text);
@@ -7,28 +23,32 @@ const parser = {
     // If there are any lexical errors, throw the first of them as an error.
     if (lexErrors.length > 0) {
       const lexError = lexErrors[0];
-      const error = new Error(lexError.message);
-
-      error.loc = {
-        start: { line: lexError.line, column: lexError.column },
-        end: { line: lexError.line, column: lexError.column + lexError.length }
-      };
-
-      throw error;
+      throw createError(lexError.message, {
+        loc: {
+          start: { line: lexError.line, column: lexError.column },
+          end: {
+            line: lexError.line,
+            column: lexError.column + lexError.length
+          }
+        }
+      });
     }
 
     // If there are any parse errors, throw the first of them as an error.
     if (parseErrors.length > 0) {
       const parseError = parseErrors[0];
-      const error = new Error(parseError.message);
-
-      const { token } = parseError;
-      error.loc = {
-        start: { line: token.startLine, column: token.startColumn },
-        end: { line: token.endLine, column: token.endColumn }
-      };
-
-      throw error;
+      throw createError(parseError.message, {
+        loc: {
+          start: {
+            line: parseError.token.startLine,
+            column: parseError.token.startColumn
+          },
+          end: {
+            line: parseError.token.endLine,
+            column: parseError.token.endColumn
+          }
+        }
+      });
     }
 
     // Otherwise return the CST.


Test patch:
diff --git a/test/parser.test.js b/test/parser.test.js
new file mode 100644
index 0000000..20a126d
--- /dev/null
+++ b/test/parser.test.js
@@ -0,0 +1,12 @@
+import parser from "../src/parser.js";
+
+test("parseError", () => {
+  const expected = new SyntaxError(
+    "Expecting: one of these possible Token sequences:\n" +
+      "  1. [CLOSE]\n" +
+      "  2. [SLASH_CLOSE]\n" +
+      "but found: '/' (1:6)"
+  );
+
+  expect(() => parser.parse("<foo /")).toThrow(expected);
+});