mirror of
https://github.com/hanzoai/babel.git
synced 2026-09-24 16:56:45 +00:00
99 lines
3.0 KiB
JavaScript
99 lines
3.0 KiB
JavaScript
import { inspect } from "node:util";
|
|
import Difference from "./difference.js";
|
|
|
|
const { isArray } = Array;
|
|
const { defineProperty, entries, fromEntries } = Object;
|
|
|
|
const named = (name, object) => defineProperty(object, "name", { value: name });
|
|
const mapEntries = (object, f) => fromEntries(entries(object).map(f));
|
|
const toContextError = error =>
|
|
isArray(error) ? error.map(toContextError) : error.context || error;
|
|
|
|
export default class FixtureError extends Error {
|
|
constructor(difference, { cause } = {}) {
|
|
super();
|
|
|
|
// Sigh, still have to manually set the name unfortunately...
|
|
named(this.constructor.name, this);
|
|
|
|
this.difference = difference;
|
|
|
|
// Set cause ourselves, since node < 17 has a bug where it won't show it
|
|
// otherwise. Technically, we display it ourselves, but best to be defensive
|
|
// in case we modify this implementation later.
|
|
if (cause) this.cause = cause;
|
|
}
|
|
|
|
static toMessage() {
|
|
return this.constructor.name;
|
|
}
|
|
|
|
get message() {
|
|
return this.constructor.toMessage(this.difference, this.cause);
|
|
}
|
|
|
|
// Don't show the stack of FixtureErrors, it's irrelevant.
|
|
// Instead, show the cause, if present.
|
|
[inspect.custom](depth, options) {
|
|
return this.cause
|
|
? `${this.message.replace(/(?<=error(s?))\.$/, ":\n")}\n${inspect(
|
|
toContextError(this.cause),
|
|
options,
|
|
)}`.replace(/\n/g, "\n ")
|
|
: this.message;
|
|
}
|
|
|
|
static fromDifference(difference, actual) {
|
|
return difference === Difference.None
|
|
? false
|
|
: difference.path[0] !== "threw"
|
|
? new FixtureError.DifferentAST(difference)
|
|
: !difference.expected
|
|
? new FixtureError.UnexpectedError(difference, {
|
|
cause: actual.threw,
|
|
})
|
|
: difference.actual
|
|
? new FixtureError.DifferentError(difference, {
|
|
cause: actual.threw,
|
|
})
|
|
: actual.ast && actual.ast.errors
|
|
? new FixtureError.UnexpectedRecovery(difference, {
|
|
cause: actual.ast.errors,
|
|
})
|
|
: new FixtureError.UnexpectedSuccess(difference);
|
|
}
|
|
}
|
|
|
|
Object.assign(
|
|
FixtureError,
|
|
mapEntries(
|
|
{
|
|
DifferentError: ({ expected }) =>
|
|
`Expected unrecoverable error: \n\n${expected}\n\n` +
|
|
`But instead encountered different unrecoverable error.`,
|
|
|
|
DifferentAST: ({ message }) => message,
|
|
|
|
UnexpectedError: ({ actual }) =>
|
|
`Encountered unexpected unrecoverable error:\n\n ${inspect(actual)}\n\n`,
|
|
|
|
UnexpectedSuccess: ({ expected }) =>
|
|
`Expected unrecoverable error:\n\n ${expected}\n\n` +
|
|
`But parsing succeeded without errors.`,
|
|
|
|
UnexpectedRecovery: ({ expected }, errors) =>
|
|
`Expected unrecoverable error:\n\n ${expected}\n\n` +
|
|
`But instead parsing recovered from ${errors.length} errors.`,
|
|
},
|
|
([name, toMessage]) => [
|
|
name,
|
|
named(
|
|
`FixtureError.${name}`,
|
|
class extends FixtureError {
|
|
static toMessage = toMessage;
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|