forked from babel/babel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fixture-error.js
97 lines (82 loc) 路 2.95 KB
/
fixture-error.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { inspect } from "util";
import Difference from "./difference.js";
import "./polyfill.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));
// eslint-disable-next-line no-confusing-arrow
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.message.replace(/(?<=error(s?))\.$/, ":\n")}${
this.cause
? `\n${inspect(toContextError(this.cause), options)}`.replace(
/\n/g,
"\n ",
)
: ""
}`;
}
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: () => `Encountered unexpected unrecoverable error.`,
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;
},
),
],
),
);