@nocobase/plugin-auth 0.17.0-alpha.7 → 0.18.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/client/authenticator.d.ts +13 -0
  2. package/dist/client/basic/SignInForm.d.ts +9 -0
  3. package/dist/client/basic/SignUpForm.d.ts +13 -0
  4. package/dist/client/basic/index.d.ts +3 -0
  5. package/dist/client/index.d.ts +21 -0
  6. package/dist/client/index.js +12 -2
  7. package/dist/client/pages/AuthLayout.d.ts +2 -0
  8. package/dist/client/pages/SignInPage.d.ts +16 -0
  9. package/dist/client/pages/SignUpPage.d.ts +21 -0
  10. package/dist/client/pages/index.d.ts +3 -0
  11. package/dist/client/settings/Options.d.ts +3 -2
  12. package/dist/externalVersion.js +14 -12
  13. package/dist/locale/en-US.json +4 -1
  14. package/dist/locale/zh-CN.json +4 -1
  15. package/dist/node_modules/cron/LICENSE +0 -0
  16. package/dist/node_modules/cron/lib/cron.js +1 -1
  17. package/dist/node_modules/cron/lib/job.js +0 -0
  18. package/dist/node_modules/cron/lib/time.js +33 -20
  19. package/dist/node_modules/cron/node_modules/luxon/build/amd/luxon.js +7826 -0
  20. package/dist/node_modules/cron/node_modules/luxon/build/cjs-browser/luxon.js +7824 -0
  21. package/dist/node_modules/cron/node_modules/luxon/build/es6/luxon.js +7217 -0
  22. package/dist/node_modules/cron/node_modules/luxon/build/global/luxon.js +7829 -0
  23. package/dist/node_modules/cron/node_modules/luxon/build/global/luxon.min.js +1 -0
  24. package/dist/node_modules/cron/node_modules/luxon/build/node/luxon.js +6932 -0
  25. package/dist/node_modules/cron/node_modules/luxon/package.json +85 -0
  26. package/dist/node_modules/cron/node_modules/luxon/src/datetime.js +2248 -0
  27. package/dist/node_modules/cron/node_modules/luxon/src/duration.js +948 -0
  28. package/dist/node_modules/cron/node_modules/luxon/src/errors.js +61 -0
  29. package/dist/node_modules/cron/node_modules/luxon/src/impl/conversions.js +161 -0
  30. package/dist/node_modules/cron/node_modules/luxon/src/impl/diff.js +75 -0
  31. package/dist/node_modules/cron/node_modules/luxon/src/impl/digits.js +75 -0
  32. package/dist/node_modules/cron/node_modules/luxon/src/impl/english.js +233 -0
  33. package/dist/node_modules/cron/node_modules/luxon/src/impl/formats.js +176 -0
  34. package/dist/node_modules/cron/node_modules/luxon/src/impl/formatter.js +400 -0
  35. package/dist/node_modules/cron/node_modules/luxon/src/impl/invalid.js +14 -0
  36. package/dist/node_modules/cron/node_modules/luxon/src/impl/locale.js +494 -0
  37. package/dist/node_modules/cron/node_modules/luxon/src/impl/regexParser.js +335 -0
  38. package/dist/node_modules/cron/node_modules/luxon/src/impl/tokenParser.js +444 -0
  39. package/dist/node_modules/cron/node_modules/luxon/src/impl/util.js +274 -0
  40. package/dist/node_modules/cron/node_modules/luxon/src/impl/zoneUtil.js +34 -0
  41. package/dist/node_modules/cron/node_modules/luxon/src/info.js +169 -0
  42. package/dist/node_modules/cron/node_modules/luxon/src/interval.js +637 -0
  43. package/dist/node_modules/cron/node_modules/luxon/src/luxon.js +26 -0
  44. package/dist/node_modules/cron/node_modules/luxon/src/package.json +4 -0
  45. package/dist/node_modules/cron/node_modules/luxon/src/settings.js +148 -0
  46. package/dist/node_modules/cron/node_modules/luxon/src/zone.js +91 -0
  47. package/dist/node_modules/cron/node_modules/luxon/src/zones/IANAZone.js +189 -0
  48. package/dist/node_modules/cron/node_modules/luxon/src/zones/fixedOffsetZone.js +102 -0
  49. package/dist/node_modules/cron/node_modules/luxon/src/zones/invalidZone.js +53 -0
  50. package/dist/node_modules/cron/node_modules/luxon/src/zones/systemZone.js +61 -0
  51. package/dist/node_modules/cron/package.json +1 -1
  52. package/dist/node_modules/cron/types/index.d.ts +181 -0
  53. package/dist/node_modules/cron/types/index.test-d.ts +85 -0
  54. package/dist/server/actions/authenticators.js +3 -0
  55. package/dist/server/basic-auth.js +5 -2
  56. package/dist/server/migrations/20231218132032-fix-allow-signup.d.ts +5 -0
  57. package/dist/server/migrations/20231218132032-fix-allow-signup.js +54 -0
  58. package/dist/server/model/authenticator.d.ts +5 -2
  59. package/dist/server/model/authenticator.js +2 -2
  60. package/package.json +2 -2
  61. package/dist/client/AuthPluginProvider.d.ts +0 -2
  62. package/dist/client/basic/SigninPage.d.ts +0 -6
  63. package/dist/client/basic/SignupPage.d.ts +0 -5
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @private
3
+ */
4
+
5
+ const n = "numeric",
6
+ s = "short",
7
+ l = "long";
8
+
9
+ export const DATE_SHORT = {
10
+ year: n,
11
+ month: n,
12
+ day: n,
13
+ };
14
+
15
+ export const DATE_MED = {
16
+ year: n,
17
+ month: s,
18
+ day: n,
19
+ };
20
+
21
+ export const DATE_MED_WITH_WEEKDAY = {
22
+ year: n,
23
+ month: s,
24
+ day: n,
25
+ weekday: s,
26
+ };
27
+
28
+ export const DATE_FULL = {
29
+ year: n,
30
+ month: l,
31
+ day: n,
32
+ };
33
+
34
+ export const DATE_HUGE = {
35
+ year: n,
36
+ month: l,
37
+ day: n,
38
+ weekday: l,
39
+ };
40
+
41
+ export const TIME_SIMPLE = {
42
+ hour: n,
43
+ minute: n,
44
+ };
45
+
46
+ export const TIME_WITH_SECONDS = {
47
+ hour: n,
48
+ minute: n,
49
+ second: n,
50
+ };
51
+
52
+ export const TIME_WITH_SHORT_OFFSET = {
53
+ hour: n,
54
+ minute: n,
55
+ second: n,
56
+ timeZoneName: s,
57
+ };
58
+
59
+ export const TIME_WITH_LONG_OFFSET = {
60
+ hour: n,
61
+ minute: n,
62
+ second: n,
63
+ timeZoneName: l,
64
+ };
65
+
66
+ export const TIME_24_SIMPLE = {
67
+ hour: n,
68
+ minute: n,
69
+ hourCycle: "h23",
70
+ };
71
+
72
+ export const TIME_24_WITH_SECONDS = {
73
+ hour: n,
74
+ minute: n,
75
+ second: n,
76
+ hourCycle: "h23",
77
+ };
78
+
79
+ export const TIME_24_WITH_SHORT_OFFSET = {
80
+ hour: n,
81
+ minute: n,
82
+ second: n,
83
+ hourCycle: "h23",
84
+ timeZoneName: s,
85
+ };
86
+
87
+ export const TIME_24_WITH_LONG_OFFSET = {
88
+ hour: n,
89
+ minute: n,
90
+ second: n,
91
+ hourCycle: "h23",
92
+ timeZoneName: l,
93
+ };
94
+
95
+ export const DATETIME_SHORT = {
96
+ year: n,
97
+ month: n,
98
+ day: n,
99
+ hour: n,
100
+ minute: n,
101
+ };
102
+
103
+ export const DATETIME_SHORT_WITH_SECONDS = {
104
+ year: n,
105
+ month: n,
106
+ day: n,
107
+ hour: n,
108
+ minute: n,
109
+ second: n,
110
+ };
111
+
112
+ export const DATETIME_MED = {
113
+ year: n,
114
+ month: s,
115
+ day: n,
116
+ hour: n,
117
+ minute: n,
118
+ };
119
+
120
+ export const DATETIME_MED_WITH_SECONDS = {
121
+ year: n,
122
+ month: s,
123
+ day: n,
124
+ hour: n,
125
+ minute: n,
126
+ second: n,
127
+ };
128
+
129
+ export const DATETIME_MED_WITH_WEEKDAY = {
130
+ year: n,
131
+ month: s,
132
+ day: n,
133
+ weekday: s,
134
+ hour: n,
135
+ minute: n,
136
+ };
137
+
138
+ export const DATETIME_FULL = {
139
+ year: n,
140
+ month: l,
141
+ day: n,
142
+ hour: n,
143
+ minute: n,
144
+ timeZoneName: s,
145
+ };
146
+
147
+ export const DATETIME_FULL_WITH_SECONDS = {
148
+ year: n,
149
+ month: l,
150
+ day: n,
151
+ hour: n,
152
+ minute: n,
153
+ second: n,
154
+ timeZoneName: s,
155
+ };
156
+
157
+ export const DATETIME_HUGE = {
158
+ year: n,
159
+ month: l,
160
+ day: n,
161
+ weekday: l,
162
+ hour: n,
163
+ minute: n,
164
+ timeZoneName: l,
165
+ };
166
+
167
+ export const DATETIME_HUGE_WITH_SECONDS = {
168
+ year: n,
169
+ month: l,
170
+ day: n,
171
+ weekday: l,
172
+ hour: n,
173
+ minute: n,
174
+ second: n,
175
+ timeZoneName: l,
176
+ };
@@ -0,0 +1,400 @@
1
+ import * as English from "./english.js";
2
+ import * as Formats from "./formats.js";
3
+ import { padStart } from "./util.js";
4
+
5
+ function stringifyTokens(splits, tokenToString) {
6
+ let s = "";
7
+ for (const token of splits) {
8
+ if (token.literal) {
9
+ s += token.val;
10
+ } else {
11
+ s += tokenToString(token.val);
12
+ }
13
+ }
14
+ return s;
15
+ }
16
+
17
+ const macroTokenToFormatOpts = {
18
+ D: Formats.DATE_SHORT,
19
+ DD: Formats.DATE_MED,
20
+ DDD: Formats.DATE_FULL,
21
+ DDDD: Formats.DATE_HUGE,
22
+ t: Formats.TIME_SIMPLE,
23
+ tt: Formats.TIME_WITH_SECONDS,
24
+ ttt: Formats.TIME_WITH_SHORT_OFFSET,
25
+ tttt: Formats.TIME_WITH_LONG_OFFSET,
26
+ T: Formats.TIME_24_SIMPLE,
27
+ TT: Formats.TIME_24_WITH_SECONDS,
28
+ TTT: Formats.TIME_24_WITH_SHORT_OFFSET,
29
+ TTTT: Formats.TIME_24_WITH_LONG_OFFSET,
30
+ f: Formats.DATETIME_SHORT,
31
+ ff: Formats.DATETIME_MED,
32
+ fff: Formats.DATETIME_FULL,
33
+ ffff: Formats.DATETIME_HUGE,
34
+ F: Formats.DATETIME_SHORT_WITH_SECONDS,
35
+ FF: Formats.DATETIME_MED_WITH_SECONDS,
36
+ FFF: Formats.DATETIME_FULL_WITH_SECONDS,
37
+ FFFF: Formats.DATETIME_HUGE_WITH_SECONDS,
38
+ };
39
+
40
+ /**
41
+ * @private
42
+ */
43
+
44
+ export default class Formatter {
45
+ static create(locale, opts = {}) {
46
+ return new Formatter(locale, opts);
47
+ }
48
+
49
+ static parseFormat(fmt) {
50
+ // white-space is always considered a literal in user-provided formats
51
+ // the " " token has a special meaning (see unitForToken)
52
+
53
+ let current = null,
54
+ currentFull = "",
55
+ bracketed = false;
56
+ const splits = [];
57
+ for (let i = 0; i < fmt.length; i++) {
58
+ const c = fmt.charAt(i);
59
+ if (c === "'") {
60
+ if (currentFull.length > 0) {
61
+ splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
62
+ }
63
+ current = null;
64
+ currentFull = "";
65
+ bracketed = !bracketed;
66
+ } else if (bracketed) {
67
+ currentFull += c;
68
+ } else if (c === current) {
69
+ currentFull += c;
70
+ } else {
71
+ if (currentFull.length > 0) {
72
+ splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
73
+ }
74
+ currentFull = c;
75
+ current = c;
76
+ }
77
+ }
78
+
79
+ if (currentFull.length > 0) {
80
+ splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
81
+ }
82
+
83
+ return splits;
84
+ }
85
+
86
+ static macroTokenToFormatOpts(token) {
87
+ return macroTokenToFormatOpts[token];
88
+ }
89
+
90
+ constructor(locale, formatOpts) {
91
+ this.opts = formatOpts;
92
+ this.loc = locale;
93
+ this.systemLoc = null;
94
+ }
95
+
96
+ formatWithSystemDefault(dt, opts) {
97
+ if (this.systemLoc === null) {
98
+ this.systemLoc = this.loc.redefaultToSystem();
99
+ }
100
+ const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts });
101
+ return df.format();
102
+ }
103
+
104
+ formatDateTime(dt, opts = {}) {
105
+ const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts });
106
+ return df.format();
107
+ }
108
+
109
+ formatDateTimeParts(dt, opts = {}) {
110
+ const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts });
111
+ return df.formatToParts();
112
+ }
113
+
114
+ formatInterval(interval, opts = {}) {
115
+ const df = this.loc.dtFormatter(interval.start, { ...this.opts, ...opts });
116
+ return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
117
+ }
118
+
119
+ resolvedOptions(dt, opts = {}) {
120
+ const df = this.loc.dtFormatter(dt, { ...this.opts, ...opts });
121
+ return df.resolvedOptions();
122
+ }
123
+
124
+ num(n, p = 0) {
125
+ // we get some perf out of doing this here, annoyingly
126
+ if (this.opts.forceSimple) {
127
+ return padStart(n, p);
128
+ }
129
+
130
+ const opts = { ...this.opts };
131
+
132
+ if (p > 0) {
133
+ opts.padTo = p;
134
+ }
135
+
136
+ return this.loc.numberFormatter(opts).format(n);
137
+ }
138
+
139
+ formatDateTimeFromString(dt, fmt) {
140
+ const knownEnglish = this.loc.listingMode() === "en",
141
+ useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
142
+ string = (opts, extract) => this.loc.extract(dt, opts, extract),
143
+ formatOffset = (opts) => {
144
+ if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
145
+ return "Z";
146
+ }
147
+
148
+ return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
149
+ },
150
+ meridiem = () =>
151
+ knownEnglish
152
+ ? English.meridiemForDateTime(dt)
153
+ : string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"),
154
+ month = (length, standalone) =>
155
+ knownEnglish
156
+ ? English.monthForDateTime(dt, length)
157
+ : string(standalone ? { month: length } : { month: length, day: "numeric" }, "month"),
158
+ weekday = (length, standalone) =>
159
+ knownEnglish
160
+ ? English.weekdayForDateTime(dt, length)
161
+ : string(
162
+ standalone ? { weekday: length } : { weekday: length, month: "long", day: "numeric" },
163
+ "weekday"
164
+ ),
165
+ maybeMacro = (token) => {
166
+ const formatOpts = Formatter.macroTokenToFormatOpts(token);
167
+ if (formatOpts) {
168
+ return this.formatWithSystemDefault(dt, formatOpts);
169
+ } else {
170
+ return token;
171
+ }
172
+ },
173
+ era = (length) =>
174
+ knownEnglish ? English.eraForDateTime(dt, length) : string({ era: length }, "era"),
175
+ tokenToString = (token) => {
176
+ // Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
177
+ switch (token) {
178
+ // ms
179
+ case "S":
180
+ return this.num(dt.millisecond);
181
+ case "u":
182
+ // falls through
183
+ case "SSS":
184
+ return this.num(dt.millisecond, 3);
185
+ // seconds
186
+ case "s":
187
+ return this.num(dt.second);
188
+ case "ss":
189
+ return this.num(dt.second, 2);
190
+ // fractional seconds
191
+ case "uu":
192
+ return this.num(Math.floor(dt.millisecond / 10), 2);
193
+ case "uuu":
194
+ return this.num(Math.floor(dt.millisecond / 100));
195
+ // minutes
196
+ case "m":
197
+ return this.num(dt.minute);
198
+ case "mm":
199
+ return this.num(dt.minute, 2);
200
+ // hours
201
+ case "h":
202
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
203
+ case "hh":
204
+ return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
205
+ case "H":
206
+ return this.num(dt.hour);
207
+ case "HH":
208
+ return this.num(dt.hour, 2);
209
+ // offset
210
+ case "Z":
211
+ // like +6
212
+ return formatOffset({ format: "narrow", allowZ: this.opts.allowZ });
213
+ case "ZZ":
214
+ // like +06:00
215
+ return formatOffset({ format: "short", allowZ: this.opts.allowZ });
216
+ case "ZZZ":
217
+ // like +0600
218
+ return formatOffset({ format: "techie", allowZ: this.opts.allowZ });
219
+ case "ZZZZ":
220
+ // like EST
221
+ return dt.zone.offsetName(dt.ts, { format: "short", locale: this.loc.locale });
222
+ case "ZZZZZ":
223
+ // like Eastern Standard Time
224
+ return dt.zone.offsetName(dt.ts, { format: "long", locale: this.loc.locale });
225
+ // zone
226
+ case "z":
227
+ // like America/New_York
228
+ return dt.zoneName;
229
+ // meridiems
230
+ case "a":
231
+ return meridiem();
232
+ // dates
233
+ case "d":
234
+ return useDateTimeFormatter ? string({ day: "numeric" }, "day") : this.num(dt.day);
235
+ case "dd":
236
+ return useDateTimeFormatter ? string({ day: "2-digit" }, "day") : this.num(dt.day, 2);
237
+ // weekdays - standalone
238
+ case "c":
239
+ // like 1
240
+ return this.num(dt.weekday);
241
+ case "ccc":
242
+ // like 'Tues'
243
+ return weekday("short", true);
244
+ case "cccc":
245
+ // like 'Tuesday'
246
+ return weekday("long", true);
247
+ case "ccccc":
248
+ // like 'T'
249
+ return weekday("narrow", true);
250
+ // weekdays - format
251
+ case "E":
252
+ // like 1
253
+ return this.num(dt.weekday);
254
+ case "EEE":
255
+ // like 'Tues'
256
+ return weekday("short", false);
257
+ case "EEEE":
258
+ // like 'Tuesday'
259
+ return weekday("long", false);
260
+ case "EEEEE":
261
+ // like 'T'
262
+ return weekday("narrow", false);
263
+ // months - standalone
264
+ case "L":
265
+ // like 1
266
+ return useDateTimeFormatter
267
+ ? string({ month: "numeric", day: "numeric" }, "month")
268
+ : this.num(dt.month);
269
+ case "LL":
270
+ // like 01, doesn't seem to work
271
+ return useDateTimeFormatter
272
+ ? string({ month: "2-digit", day: "numeric" }, "month")
273
+ : this.num(dt.month, 2);
274
+ case "LLL":
275
+ // like Jan
276
+ return month("short", true);
277
+ case "LLLL":
278
+ // like January
279
+ return month("long", true);
280
+ case "LLLLL":
281
+ // like J
282
+ return month("narrow", true);
283
+ // months - format
284
+ case "M":
285
+ // like 1
286
+ return useDateTimeFormatter
287
+ ? string({ month: "numeric" }, "month")
288
+ : this.num(dt.month);
289
+ case "MM":
290
+ // like 01
291
+ return useDateTimeFormatter
292
+ ? string({ month: "2-digit" }, "month")
293
+ : this.num(dt.month, 2);
294
+ case "MMM":
295
+ // like Jan
296
+ return month("short", false);
297
+ case "MMMM":
298
+ // like January
299
+ return month("long", false);
300
+ case "MMMMM":
301
+ // like J
302
+ return month("narrow", false);
303
+ // years
304
+ case "y":
305
+ // like 2014
306
+ return useDateTimeFormatter ? string({ year: "numeric" }, "year") : this.num(dt.year);
307
+ case "yy":
308
+ // like 14
309
+ return useDateTimeFormatter
310
+ ? string({ year: "2-digit" }, "year")
311
+ : this.num(dt.year.toString().slice(-2), 2);
312
+ case "yyyy":
313
+ // like 0012
314
+ return useDateTimeFormatter
315
+ ? string({ year: "numeric" }, "year")
316
+ : this.num(dt.year, 4);
317
+ case "yyyyyy":
318
+ // like 000012
319
+ return useDateTimeFormatter
320
+ ? string({ year: "numeric" }, "year")
321
+ : this.num(dt.year, 6);
322
+ // eras
323
+ case "G":
324
+ // like AD
325
+ return era("short");
326
+ case "GG":
327
+ // like Anno Domini
328
+ return era("long");
329
+ case "GGGGG":
330
+ return era("narrow");
331
+ case "kk":
332
+ return this.num(dt.weekYear.toString().slice(-2), 2);
333
+ case "kkkk":
334
+ return this.num(dt.weekYear, 4);
335
+ case "W":
336
+ return this.num(dt.weekNumber);
337
+ case "WW":
338
+ return this.num(dt.weekNumber, 2);
339
+ case "o":
340
+ return this.num(dt.ordinal);
341
+ case "ooo":
342
+ return this.num(dt.ordinal, 3);
343
+ case "q":
344
+ // like 1
345
+ return this.num(dt.quarter);
346
+ case "qq":
347
+ // like 01
348
+ return this.num(dt.quarter, 2);
349
+ case "X":
350
+ return this.num(Math.floor(dt.ts / 1000));
351
+ case "x":
352
+ return this.num(dt.ts);
353
+ default:
354
+ return maybeMacro(token);
355
+ }
356
+ };
357
+
358
+ return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
359
+ }
360
+
361
+ formatDurationFromString(dur, fmt) {
362
+ const tokenToField = (token) => {
363
+ switch (token[0]) {
364
+ case "S":
365
+ return "millisecond";
366
+ case "s":
367
+ return "second";
368
+ case "m":
369
+ return "minute";
370
+ case "h":
371
+ return "hour";
372
+ case "d":
373
+ return "day";
374
+ case "w":
375
+ return "week";
376
+ case "M":
377
+ return "month";
378
+ case "y":
379
+ return "year";
380
+ default:
381
+ return null;
382
+ }
383
+ },
384
+ tokenToString = (lildur) => (token) => {
385
+ const mapped = tokenToField(token);
386
+ if (mapped) {
387
+ return this.num(lildur.get(mapped), token.length);
388
+ } else {
389
+ return token;
390
+ }
391
+ },
392
+ tokens = Formatter.parseFormat(fmt),
393
+ realTokens = tokens.reduce(
394
+ (found, { literal, val }) => (literal ? found : found.concat(val)),
395
+ []
396
+ ),
397
+ collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t));
398
+ return stringifyTokens(tokens, tokenToString(collapsed));
399
+ }
400
+ }
@@ -0,0 +1,14 @@
1
+ export default class Invalid {
2
+ constructor(reason, explanation) {
3
+ this.reason = reason;
4
+ this.explanation = explanation;
5
+ }
6
+
7
+ toMessage() {
8
+ if (this.explanation) {
9
+ return `${this.reason}: ${this.explanation}`;
10
+ } else {
11
+ return this.reason;
12
+ }
13
+ }
14
+ }