@devp0nt/error0 1.0.0-next.46 → 1.0.0-next.47

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 (57) hide show
  1. package/dist/cjs/index.cjs +80 -49
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.d.cts +32 -12
  4. package/dist/cjs/plugins/cause-serialize.cjs +38 -0
  5. package/dist/cjs/plugins/cause-serialize.cjs.map +1 -0
  6. package/dist/cjs/plugins/cause-serialize.d.cts +5 -0
  7. package/dist/cjs/plugins/expected.cjs +49 -0
  8. package/dist/cjs/plugins/expected.cjs.map +1 -0
  9. package/dist/cjs/plugins/expected.d.cts +5 -0
  10. package/dist/cjs/plugins/message-merge.cjs +36 -0
  11. package/dist/cjs/plugins/message-merge.cjs.map +1 -0
  12. package/dist/cjs/plugins/message-merge.d.cts +5 -0
  13. package/dist/cjs/plugins/meta.cjs +73 -0
  14. package/dist/cjs/plugins/meta.cjs.map +1 -0
  15. package/dist/cjs/plugins/meta.d.cts +5 -0
  16. package/dist/cjs/plugins/stack-merge.cjs +39 -0
  17. package/dist/cjs/plugins/stack-merge.cjs.map +1 -0
  18. package/dist/cjs/plugins/stack-merge.d.cts +5 -0
  19. package/dist/cjs/plugins/tags.cjs +48 -0
  20. package/dist/cjs/plugins/tags.cjs.map +1 -0
  21. package/dist/cjs/plugins/tags.d.cts +5 -0
  22. package/dist/esm/index.d.ts +32 -12
  23. package/dist/esm/index.js +80 -49
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/plugins/cause-serialize.d.ts +5 -0
  26. package/dist/esm/plugins/cause-serialize.js +14 -0
  27. package/dist/esm/plugins/cause-serialize.js.map +1 -0
  28. package/dist/esm/plugins/expected.d.ts +5 -0
  29. package/dist/esm/plugins/expected.js +25 -0
  30. package/dist/esm/plugins/expected.js.map +1 -0
  31. package/dist/esm/plugins/message-merge.d.ts +5 -0
  32. package/dist/esm/plugins/message-merge.js +12 -0
  33. package/dist/esm/plugins/message-merge.js.map +1 -0
  34. package/dist/esm/plugins/meta.d.ts +5 -0
  35. package/dist/esm/plugins/meta.js +49 -0
  36. package/dist/esm/plugins/meta.js.map +1 -0
  37. package/dist/esm/plugins/stack-merge.d.ts +5 -0
  38. package/dist/esm/plugins/stack-merge.js +15 -0
  39. package/dist/esm/plugins/stack-merge.js.map +1 -0
  40. package/dist/esm/plugins/tags.d.ts +5 -0
  41. package/dist/esm/plugins/tags.js +24 -0
  42. package/dist/esm/plugins/tags.js.map +1 -0
  43. package/package.json +9 -1
  44. package/src/index.test.ts +56 -79
  45. package/src/index.ts +117 -64
  46. package/src/plugins/cause-serialize.test.ts +51 -0
  47. package/src/plugins/cause-serialize.ts +11 -0
  48. package/src/plugins/expected.test.ts +47 -0
  49. package/src/plugins/expected.ts +25 -0
  50. package/src/plugins/message-merge.test.ts +32 -0
  51. package/src/plugins/message-merge.ts +15 -0
  52. package/src/plugins/meta.test.ts +32 -0
  53. package/src/plugins/meta.ts +53 -0
  54. package/src/plugins/stack-merge.test.ts +64 -0
  55. package/src/plugins/stack-merge.ts +16 -0
  56. package/src/plugins/tags.test.ts +22 -0
  57. package/src/plugins/tags.ts +21 -0
@@ -0,0 +1,49 @@
1
+ import { Error0 } from "../index.js";
2
+ const toJsonSafe = (input) => {
3
+ if (input === null) {
4
+ return null;
5
+ }
6
+ if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") {
7
+ return input;
8
+ }
9
+ if (Array.isArray(input)) {
10
+ return input.map((value) => toJsonSafe(value));
11
+ }
12
+ if (typeof input === "object") {
13
+ const output = {};
14
+ for (const [key, value] of Object.entries(input)) {
15
+ const jsonValue = toJsonSafe(value);
16
+ if (jsonValue !== void 0) {
17
+ output[key] = jsonValue;
18
+ }
19
+ }
20
+ return output;
21
+ }
22
+ return void 0;
23
+ };
24
+ const isMetaRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25
+ const metaPlugin = Error0.plugin().use("prop", "meta", {
26
+ init: (input) => input,
27
+ resolve: ({ flow }) => {
28
+ const values = flow.filter(isMetaRecord);
29
+ if (values.length === 0) {
30
+ return void 0;
31
+ }
32
+ const merged = {};
33
+ for (const value of [...values].reverse()) {
34
+ Object.assign(merged, value);
35
+ }
36
+ return merged;
37
+ },
38
+ serialize: ({ value, isPublic }) => isPublic ? void 0 : toJsonSafe(value),
39
+ deserialize: ({ value }) => {
40
+ if (!isMetaRecord(value)) {
41
+ return void 0;
42
+ }
43
+ return value;
44
+ }
45
+ });
46
+ export {
47
+ metaPlugin
48
+ };
49
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/plugins/meta.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json }\n\nconst toJsonSafe = (input: unknown): Json | undefined => {\n if (input === null) {\n return null\n }\n if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {\n return input\n }\n if (Array.isArray(input)) {\n return input.map((value) => toJsonSafe(value)) as Json[]\n }\n if (typeof input === 'object') {\n const output: Record<string, Json> = {}\n for (const [key, value] of Object.entries(input as Record<string, unknown>)) {\n const jsonValue = toJsonSafe(value)\n if (jsonValue !== undefined) {\n output[key] = jsonValue\n }\n }\n return output\n }\n return undefined\n}\n\nconst isMetaRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nexport const metaPlugin = Error0.plugin().use('prop', 'meta', {\n init: (input: Record<string, unknown>) => input,\n resolve: ({ flow }) => {\n const values = flow.filter(isMetaRecord)\n if (values.length === 0) {\n return undefined\n }\n\n // Merge cause meta into the current error; nearer errors win on conflicts.\n const merged: Record<string, unknown> = {}\n for (const value of [...values].reverse()) {\n Object.assign(merged, value)\n }\n return merged\n },\n serialize: ({ value, isPublic }) => (isPublic ? undefined : toJsonSafe(value)),\n deserialize: ({ value }) => {\n if (!isMetaRecord(value)) {\n return undefined\n }\n return value\n },\n})\n"],"mappings":"AAAA,SAAS,cAAc;AAIvB,MAAM,aAAa,CAAC,UAAqC;AACvD,MAAI,UAAU,MAAM;AAClB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AACxF,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,UAAU,WAAW,KAAK,CAAC;AAAA,EAC/C;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAA+B,CAAC;AACtC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC3E,YAAM,YAAY,WAAW,KAAK;AAClC,UAAI,cAAc,QAAW;AAC3B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,eAAe,CAAC,UACpB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAE9D,MAAM,aAAa,OAAO,OAAO,EAAE,IAAI,QAAQ,QAAQ;AAAA,EAC5D,MAAM,CAAC,UAAmC;AAAA,EAC1C,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,UAAM,SAAS,KAAK,OAAO,YAAY;AACvC,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO;AAAA,IACT;AAGA,UAAM,SAAkC,CAAC;AACzC,eAAW,SAAS,CAAC,GAAG,MAAM,EAAE,QAAQ,GAAG;AACzC,aAAO,OAAO,QAAQ,KAAK;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAAA,EACA,WAAW,CAAC,EAAE,OAAO,SAAS,MAAO,WAAW,SAAY,WAAW,KAAK;AAAA,EAC5E,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF,CAAC;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { PluginError0 } from '../index.js';
2
+
3
+ declare const stackMergePlugin: PluginError0<Record<never, never>, Record<never, never>>;
4
+
5
+ export { stackMergePlugin };
@@ -0,0 +1,15 @@
1
+ import { Error0 } from "../index.js";
2
+ const stackMergePlugin = Error0.plugin().use("stack", {
3
+ serialize: ({ error, isPublic }) => {
4
+ if (isPublic) {
5
+ return void 0;
6
+ }
7
+ return error.causes().map((cause) => {
8
+ return cause instanceof Error ? cause.stack : void 0;
9
+ }).filter((value) => typeof value === "string").join("\n");
10
+ }
11
+ });
12
+ export {
13
+ stackMergePlugin
14
+ };
15
+ //# sourceMappingURL=stack-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/plugins/stack-merge.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const stackMergePlugin = Error0.plugin().use('stack', {\n serialize: ({ error, isPublic }) => {\n if (isPublic) {\n return undefined\n }\n return error\n .causes()\n .map((cause) => {\n return cause instanceof Error ? cause.stack : undefined\n })\n .filter((value): value is string => typeof value === 'string')\n .join('\\n')\n },\n})\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,mBAAmB,OAAO,OAAO,EAAE,IAAI,SAAS;AAAA,EAC3D,WAAW,CAAC,EAAE,OAAO,SAAS,MAAM;AAClC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,WAAO,MACJ,OAAO,EACP,IAAI,CAAC,UAAU;AACd,aAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,IAChD,CAAC,EACA,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,EAC5D,KAAK,IAAI;AAAA,EACd;AACF,CAAC;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
2
+
3
+ declare const tagsPlugin: PluginError0<Record<never, never> & Record<"tags", ErrorPluginPropOptions<string[], string[], Error0, string[] | undefined>>, Record<never, never>>;
4
+
5
+ export { tagsPlugin };
@@ -0,0 +1,24 @@
1
+ import { Error0 } from "../index.js";
2
+ const tagsPlugin = Error0.plugin().use("prop", "tags", {
3
+ init: (input) => input,
4
+ resolve: ({ flow }) => {
5
+ const merged = [];
6
+ for (const value of flow) {
7
+ if (Array.isArray(value)) {
8
+ merged.push(...value.filter((item) => typeof item === "string"));
9
+ }
10
+ }
11
+ return merged.length > 0 ? Array.from(new Set(merged)) : void 0;
12
+ },
13
+ serialize: ({ value, isPublic }) => isPublic ? void 0 : value,
14
+ deserialize: ({ value }) => {
15
+ if (!Array.isArray(value)) {
16
+ return void 0;
17
+ }
18
+ return value.filter((item) => typeof item === "string");
19
+ }
20
+ });
21
+ export {
22
+ tagsPlugin
23
+ };
24
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/plugins/tags.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const tagsPlugin = Error0.plugin().use('prop', 'tags', {\n init: (input: string[]) => input,\n resolve: ({ flow }) => {\n const merged: string[] = []\n for (const value of flow) {\n if (Array.isArray(value)) {\n merged.push(...value.filter((item): item is string => typeof item === 'string'))\n }\n }\n return merged.length > 0 ? Array.from(new Set(merged)) : undefined\n },\n serialize: ({ value, isPublic }) => (isPublic ? undefined : value),\n deserialize: ({ value }) => {\n if (!Array.isArray(value)) {\n return undefined\n }\n return value.filter((item): item is string => typeof item === 'string')\n },\n})\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,aAAa,OAAO,OAAO,EAAE,IAAI,QAAQ,QAAQ;AAAA,EAC5D,MAAM,CAAC,UAAoB;AAAA,EAC3B,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,UAAM,SAAmB,CAAC;AAC1B,eAAW,SAAS,MAAM;AACxB,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAO,KAAK,GAAG,MAAM,OAAO,CAAC,SAAyB,OAAO,SAAS,QAAQ,CAAC;AAAA,MACjF;AAAA,IACF;AACA,WAAO,OAAO,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI;AAAA,EAC3D;AAAA,EACA,WAAW,CAAC,EAAE,OAAO,SAAS,MAAO,WAAW,SAAY;AAAA,EAC5D,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,QAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,aAAO;AAAA,IACT;AACA,WAAO,MAAM,OAAO,CAAC,SAAyB,OAAO,SAAS,QAAQ;AAAA,EACxE;AACF,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devp0nt/error0",
3
- "version": "1.0.0-next.46",
3
+ "version": "1.0.0-next.47",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Sergei Dmitriev",
@@ -23,12 +23,20 @@
23
23
  "types": "./dist/esm/index.d.ts",
24
24
  "require": "./dist/cjs/index.cjs",
25
25
  "import": "./dist/esm/index.js"
26
+ },
27
+ "./plugins/*": {
28
+ "types": "./dist/esm/plugins/*.d.ts",
29
+ "require": "./dist/cjs/plugins/*.cjs",
30
+ "import": "./dist/esm/plugins/*.js"
26
31
  }
27
32
  },
28
33
  "typesVersions": {
29
34
  "*": {
30
35
  "": [
31
36
  "./dist/esm/index.d.ts"
37
+ ],
38
+ "plugins/*": [
39
+ "./dist/esm/plugins/*"
32
40
  ]
33
41
  }
34
42
  },
package/src/index.test.ts CHANGED
@@ -185,27 +185,35 @@ describe('Error0', () => {
185
185
  })
186
186
 
187
187
  it('stack plugin can customize stack serialization without defining prop plugin', () => {
188
- const AppError = Error0.use('stack', ({ value }) => (value ? `custom:${value}` : undefined))
188
+ const AppError = Error0.use('stack', { serialize: ({ value }) => (value ? `custom:${value}` : undefined) })
189
189
  const error = new AppError('test')
190
190
  const json = AppError.serialize(error)
191
191
  expect(typeof json.stack).toBe('string')
192
192
  expect((json.stack as string).startsWith('custom:')).toBe(true)
193
193
  })
194
194
 
195
- it('stack plugin serialize true keeps default stack', () => {
196
- const AppError = Error0.use('stack', true)
195
+ it('stack plugin can keep default stack via identity function', () => {
196
+ const AppError = Error0.use('stack', { serialize: ({ value }) => value })
197
197
  const error = new AppError('test')
198
198
  const json = AppError.serialize(error)
199
199
  expect(json.stack).toBe(error.stack)
200
200
  })
201
201
 
202
- it('stack plugin serialize false disables stack serialization', () => {
203
- const AppError = Error0.use('stack', false)
202
+ it('stack plugin can disable stack serialization via function', () => {
203
+ const AppError = Error0.use('stack', { serialize: () => undefined })
204
204
  const error = new AppError('test')
205
205
  const json = AppError.serialize(error)
206
206
  expect('stack' in json).toBe(false)
207
207
  })
208
208
 
209
+ it('stack plugin rejects boolean config', () => {
210
+ expect(() => Error0.use('stack', true as any)).toThrow('expects { serialize: function }')
211
+ })
212
+
213
+ it('message plugin rejects boolean config', () => {
214
+ expect(() => Error0.use('message', true as any)).toThrow('expects { serialize: function }')
215
+ })
216
+
209
217
  it('prop("stack") throws and suggests using stack plugin', () => {
210
218
  expect(() =>
211
219
  Error0.use('prop', 'stack', {
@@ -228,6 +236,26 @@ describe('Error0', () => {
228
236
  ).toThrow('reserved prop key')
229
237
  })
230
238
 
239
+ it('prop("message") throws and suggests using message plugin', () => {
240
+ expect(() =>
241
+ Error0.use('prop', 'message', {
242
+ resolve: ({ own }) => own as string,
243
+ serialize: ({ value }) => value,
244
+ deserialize: ({ value }) => (typeof value === 'string' ? value : undefined),
245
+ }),
246
+ ).toThrow('reserved prop key')
247
+ })
248
+
249
+ it('plugin builder also rejects prop("message") as reserved key', () => {
250
+ expect(() =>
251
+ Error0.plugin().prop('message', {
252
+ resolve: ({ own }) => own as string,
253
+ serialize: ({ value }) => value,
254
+ deserialize: ({ value }) => (typeof value === 'string' ? value : undefined),
255
+ }),
256
+ ).toThrow('reserved prop key')
257
+ })
258
+
231
259
  it('.serialize() -> .from() roundtrip keeps plugin values', () => {
232
260
  const AppError = Error0.use(statusPlugin).use(codePlugin)
233
261
  const error = new AppError('test', { status: 409, code: 'NOT_FOUND' })
@@ -249,22 +277,12 @@ describe('Error0', () => {
249
277
  expect('cause' in json).toBe(false)
250
278
  })
251
279
 
252
- it('cause plugin true serializes and deserializes nested Error0 causes', () => {
253
- const AppError = Error0.use(statusPlugin).use(codePlugin).use('cause', true)
254
- const causeError = new AppError('cause', { status: 409, code: 'NOT_FOUND' })
255
- const error = new AppError('root', { status: 500, cause: causeError })
256
280
 
281
+ it('by default causes not serialized', () => {
282
+ const AppError = Error0.use(statusPlugin).use(codePlugin)
283
+ const error = new AppError('test', { status: 400, code: 'NOT_FOUND' })
257
284
  const json = AppError.serialize(error, false)
258
- expect(typeof json.cause).toBe('object')
259
- expect((json.cause as Record<string, unknown>).message).toBe('cause')
260
- expect((json.cause as Record<string, unknown>).status).toBe(409)
261
- expect((json.cause as Record<string, unknown>).code).toBe('NOT_FOUND')
262
-
263
- const recreated = AppError.from(json)
264
- expect(recreated).toBeInstanceOf(AppError)
265
- expect(recreated.cause).toBeInstanceOf(AppError)
266
- expect((recreated.cause as InstanceType<typeof AppError>).status).toBe(409)
267
- expect((recreated.cause as InstanceType<typeof AppError>).code).toBe('NOT_FOUND')
285
+ expect('cause' in json).toBe(false)
268
286
  })
269
287
 
270
288
  it('serialize can hide props for public output', () => {
@@ -536,41 +554,19 @@ describe('Error0', () => {
536
554
  expect(error1.code).toBe(undefined)
537
555
  })
538
556
 
539
- it('expected prop can be realized to send or not to send error to your error tracker', () => {
540
- const AppError = Error0.use(statusPlugin)
541
- .use('prop', 'expected', {
542
- init: (input: boolean) => input,
543
- resolve: ({ flow }) => flow.find((value) => typeof value === 'boolean'),
544
- serialize: ({ value }) => value,
545
- deserialize: ({ value }) => (typeof value === 'boolean' ? value : undefined),
546
- })
547
- .use('method', 'isExpected', (error) => {
548
- return error.expected ?? false
549
- })
550
- const errorExpected = new AppError('test', { status: 400, expected: true })
551
- const errorUnexpected = new AppError('test', { status: 400, expected: false })
552
- const usualError = new Error('test')
553
- const errorFromUsualError = AppError.from(usualError)
554
- const errorWithExpectedErrorAsCause = new AppError('test', { status: 400, cause: errorExpected })
555
- const errorWithUnexpectedErrorAsCause = new AppError('test', { status: 400, cause: errorUnexpected })
556
- expect(errorExpected.expected).toBe(true)
557
- expect(errorUnexpected.expected).toBe(false)
558
- expect(AppError.isExpected(usualError)).toBe(false)
559
- expect(errorFromUsualError.expected).toBe(undefined)
560
- expect(errorFromUsualError.isExpected()).toBe(false)
561
- expect(errorWithExpectedErrorAsCause.expected).toBe(true)
562
- expect(errorWithExpectedErrorAsCause.isExpected()).toBe(true)
563
- expect(errorWithUnexpectedErrorAsCause.expected).toBe(false)
564
- expect(errorWithUnexpectedErrorAsCause.isExpected()).toBe(false)
565
- })
566
557
 
567
558
  it('messages can be combined on serialization', () => {
568
559
  const AppError = Error0.use(statusPlugin)
569
560
  .use(codePlugin)
570
- .use('prop', 'message', {
571
- resolve: ({ own }) => own as string,
572
- serialize: ({ value, error }) => error.flow('message').join(': '),
573
- deserialize: ({ value }) => (typeof value === 'string' ? value : undefined),
561
+ .use('message', {
562
+ serialize: ({ error }) =>
563
+ error
564
+ .causes()
565
+ .map((cause) => {
566
+ return cause instanceof Error ? cause.message : undefined
567
+ })
568
+ .filter((value): value is string => typeof value === 'string')
569
+ .join(': '),
574
570
  })
575
571
  const error1 = new AppError('test1', { status: 400, code: 'NOT_FOUND' })
576
572
  const error2 = new AppError({ message: 'test2', status: 401, cause: error1 })
@@ -584,15 +580,16 @@ describe('Error0', () => {
584
580
  it('stack plugin can merge stack across causes in one serialized value', () => {
585
581
  const AppError = Error0.use(statusPlugin)
586
582
  .use(codePlugin)
587
- .use('stack', ({ error }) =>
588
- error
589
- .causes()
590
- .map((cause) => {
591
- return cause instanceof Error ? cause.stack : undefined
592
- })
593
- .filter((value): value is string => typeof value === 'string')
594
- .join('\n'),
595
- )
583
+ .use('stack', {
584
+ serialize: ({ error }) =>
585
+ error
586
+ .causes()
587
+ .map((cause) => {
588
+ return cause instanceof Error ? cause.stack : undefined
589
+ })
590
+ .filter((value): value is string => typeof value === 'string')
591
+ .join('\n'),
592
+ })
596
593
  const error1 = new AppError('test1', { status: 400, code: 'NOT_FOUND' })
597
594
  const error2 = new AppError('test2', { status: 401, cause: error1 })
598
595
  const mergedStack1 = error1.serialize().stack as string
@@ -612,26 +609,6 @@ describe('Error0', () => {
612
609
  `)
613
610
  })
614
611
 
615
- it('stack plugin can merge stack across causes in one serialized value by helper "merge"', () => {
616
- const AppError = Error0.use(statusPlugin).use(codePlugin).use('stack', 'merge')
617
- const error1 = new AppError('test1', { status: 400, code: 'NOT_FOUND' })
618
- const error2 = new AppError('test2', { status: 401, cause: error1 })
619
- const mergedStack1 = error1.serialize().stack as string
620
- const mergedStack2 = error2.serialize().stack as string
621
- expect(mergedStack1).toContain('Error0: test1')
622
- expect(mergedStack2).toContain('Error0: test2')
623
- expect(mergedStack2).toContain('Error0: test1')
624
- expect(fixStack(mergedStack1)).toMatchInlineSnapshot(`
625
- "Error0: test1
626
- at <anonymous> (...)"
627
- `)
628
- expect(fixStack(mergedStack2)).toMatchInlineSnapshot(`
629
- "Error0: test2
630
- at <anonymous> (...)
631
- Error0: test1
632
- at <anonymous> (...)"
633
- `)
634
- })
635
612
 
636
613
  it('Error0 assignable to LikeError0', () => {
637
614
  type LikeError0 = {