pino-std 0.0.0-stage → 7.2.0

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.
@@ -0,0 +1,48 @@
1
+ 'use strict'
2
+
3
+ module.exports = errWithCauseSerializer
4
+
5
+ const { isErrorLike } = require('./err-helpers')
6
+ const { pinoErrProto, pinoErrorSymbols } = require('./err-proto')
7
+ const { seen } = pinoErrorSymbols
8
+
9
+ const { toString } = Object.prototype
10
+
11
+ function errWithCauseSerializer (err) {
12
+ if (!isErrorLike(err)) {
13
+ return err
14
+ }
15
+
16
+ err[seen] = undefined // tag to prevent re-looking at this
17
+ const _err = Object.create(pinoErrProto)
18
+ _err.type = toString.call(err.constructor) === '[object Function]'
19
+ ? err.constructor.name
20
+ : err.name
21
+ _err.message = err.message
22
+ _err.stack = err.stack
23
+
24
+ if (Array.isArray(err.errors)) {
25
+ _err.aggregateErrors = err.errors.map(err => errWithCauseSerializer(err))
26
+ }
27
+
28
+ if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) {
29
+ _err.cause = errWithCauseSerializer(err.cause)
30
+ }
31
+
32
+ for (const key in err) {
33
+ if (_err[key] === undefined) {
34
+ const val = err[key]
35
+ if (isErrorLike(val)) {
36
+ if (!Object.prototype.hasOwnProperty.call(val, seen)) {
37
+ _err[key] = errWithCauseSerializer(val)
38
+ }
39
+ } else {
40
+ _err[key] = val
41
+ }
42
+ }
43
+ }
44
+
45
+ delete err[seen] // clean up tag in case err is serialized again later
46
+ _err.raw = err
47
+ return _err
48
+ }
package/lib/err.js ADDED
@@ -0,0 +1,45 @@
1
+ 'use strict'
2
+
3
+ module.exports = errSerializer
4
+
5
+ const { messageWithCauses, stackWithCauses, isErrorLike } = require('./err-helpers')
6
+ const { pinoErrProto, pinoErrorSymbols } = require('./err-proto')
7
+ const { seen } = pinoErrorSymbols
8
+
9
+ const { toString } = Object.prototype
10
+
11
+ function errSerializer (err) {
12
+ if (!isErrorLike(err)) {
13
+ return err
14
+ }
15
+
16
+ err[seen] = undefined // tag to prevent re-looking at this
17
+ const _err = Object.create(pinoErrProto)
18
+ _err.type = toString.call(err.constructor) === '[object Function]'
19
+ ? err.constructor.name
20
+ : err.name
21
+ _err.message = messageWithCauses(err)
22
+ _err.stack = stackWithCauses(err)
23
+
24
+ if (Array.isArray(err.errors)) {
25
+ _err.aggregateErrors = err.errors.map(err => errSerializer(err))
26
+ }
27
+
28
+ for (const key in err) {
29
+ if (_err[key] === undefined) {
30
+ const val = err[key]
31
+ if (isErrorLike(val)) {
32
+ // We append cause messages and stacks to _err, therefore skipping causes here
33
+ if (key !== 'cause' && !Object.prototype.hasOwnProperty.call(val, seen)) {
34
+ _err[key] = errSerializer(val)
35
+ }
36
+ } else {
37
+ _err[key] = val
38
+ }
39
+ }
40
+ }
41
+
42
+ delete err[seen] // clean up tag in case err is serialized again later
43
+ _err.raw = err
44
+ return _err
45
+ }
package/lib/req.js ADDED
@@ -0,0 +1,100 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ mapHttpRequest,
5
+ reqSerializer
6
+ }
7
+
8
+ const rawSymbol = Symbol('pino-raw-req-ref')
9
+ const pinoReqProto = Object.create({}, {
10
+ id: {
11
+ enumerable: true,
12
+ writable: true,
13
+ value: ''
14
+ },
15
+ method: {
16
+ enumerable: true,
17
+ writable: true,
18
+ value: ''
19
+ },
20
+ url: {
21
+ enumerable: true,
22
+ writable: true,
23
+ value: ''
24
+ },
25
+ query: {
26
+ enumerable: true,
27
+ writable: true,
28
+ value: ''
29
+ },
30
+ params: {
31
+ enumerable: true,
32
+ writable: true,
33
+ value: ''
34
+ },
35
+ headers: {
36
+ enumerable: true,
37
+ writable: true,
38
+ value: {}
39
+ },
40
+ remoteAddress: {
41
+ enumerable: true,
42
+ writable: true,
43
+ value: ''
44
+ },
45
+ remotePort: {
46
+ enumerable: true,
47
+ writable: true,
48
+ value: ''
49
+ },
50
+ raw: {
51
+ enumerable: false,
52
+ get: function () {
53
+ return this[rawSymbol]
54
+ },
55
+ set: function (val) {
56
+ this[rawSymbol] = val
57
+ }
58
+ }
59
+ })
60
+ Object.defineProperty(pinoReqProto, rawSymbol, {
61
+ writable: true,
62
+ value: {}
63
+ })
64
+
65
+ function reqSerializer (req) {
66
+ // req.info is for hapi compat.
67
+ const connection = req.info || req.socket
68
+ const _req = Object.create(pinoReqProto)
69
+ _req.id = (typeof req.id === 'function' ? req.id() : (req.id || (req.info ? req.info.id : undefined)))
70
+ _req.method = req.method
71
+ // req.originalUrl is for expressjs compat.
72
+ if (req.originalUrl) {
73
+ _req.url = req.originalUrl
74
+ } else {
75
+ const path = req.path
76
+ // path for safe hapi compat.
77
+ _req.url = typeof path === 'string' ? path : (req.url ? req.url.path || req.url : undefined)
78
+ }
79
+
80
+ if (req.query) {
81
+ _req.query = req.query
82
+ }
83
+
84
+ if (req.params) {
85
+ _req.params = req.params
86
+ }
87
+
88
+ _req.headers = req.headers
89
+ _req.remoteAddress = connection && connection.remoteAddress
90
+ _req.remotePort = connection && connection.remotePort
91
+ // req.raw is for hapi compat/equivalence
92
+ _req.raw = req.raw || req
93
+ return _req
94
+ }
95
+
96
+ function mapHttpRequest (req) {
97
+ return {
98
+ req: reqSerializer(req)
99
+ }
100
+ }
package/lib/res.js ADDED
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ mapHttpResponse,
5
+ resSerializer
6
+ }
7
+
8
+ const rawSymbol = Symbol('pino-raw-res-ref')
9
+ const pinoResProto = Object.create({}, {
10
+ statusCode: {
11
+ enumerable: true,
12
+ writable: true,
13
+ value: 0
14
+ },
15
+ headers: {
16
+ enumerable: true,
17
+ writable: true,
18
+ value: ''
19
+ },
20
+ raw: {
21
+ enumerable: false,
22
+ get: function () {
23
+ return this[rawSymbol]
24
+ },
25
+ set: function (val) {
26
+ this[rawSymbol] = val
27
+ }
28
+ }
29
+ })
30
+ Object.defineProperty(pinoResProto, rawSymbol, {
31
+ writable: true,
32
+ value: {}
33
+ })
34
+
35
+ function resSerializer (res) {
36
+ const _res = Object.create(pinoResProto)
37
+ _res.statusCode = res.headersSent ? res.statusCode : null
38
+ _res.headers = res.getHeaders ? res.getHeaders() : res._headers
39
+ _res.raw = res
40
+ return _res
41
+ }
42
+
43
+ function mapHttpResponse (res) {
44
+ return {
45
+ res: resSerializer(res)
46
+ }
47
+ }
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "pino-std",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "7.2.0",
4
+ "description": "A collection of standard object serializers for Pino",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "types": "index.d.ts",
8
+ "scripts": {
9
+ "lint": "eslint .",
10
+ "lint:fix": "eslint --fix .",
11
+ "lint-ci": "eslint --max-warnings=0 .",
12
+ "test": "borp -p 'test/**/*.js'",
13
+ "test-ci": "borp --coverage -p 'test/**/*.js'",
14
+ "test-types": "tsc && tsd"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+ssh://git@github.com/pinojs/pino-std-serializers.git"
19
+ },
20
+ "keywords": [
21
+ "pino",
22
+ "logging"
23
+ ],
24
+ "author": "James Sumners <james.sumners@gmail.com>",
25
+ "license": "MIT",
26
+ "bugs": {
27
+ "url": "https://github.com/pinojs/pino-std-serializers/issues"
28
+ },
29
+ "homepage": "https://github.com/pinojs/pino-std-serializers#readme",
30
+ "devDependencies": {
31
+ "@matteo.collina/tspl": "^0.2.0",
32
+ "@types/node": "^25.0.3",
33
+ "borp": "^0.21.0",
34
+ "eslint": "^9.39.2",
35
+ "neostandard": "^0.12.2",
36
+ "tsd": "^0.33.0",
37
+ "typescript": "~5.9.3"
38
+ },
39
+ "tsd": {
40
+ "directory": "test/types"
41
+ }
42
+ }
@@ -0,0 +1,187 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
5
+ const serializer = require('../lib/err-with-cause')
6
+ const { wrapErrorSerializer } = require('../')
7
+
8
+ test('serializes Error objects', () => {
9
+ const serialized = serializer(Error('foo'))
10
+ assert.strictEqual(serialized.type, 'Error')
11
+ assert.strictEqual(serialized.message, 'foo')
12
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
13
+ })
14
+
15
+ test('serializes Error objects with extra properties', () => {
16
+ const err = Error('foo')
17
+ err.statusCode = 500
18
+ const serialized = serializer(err)
19
+ assert.strictEqual(serialized.type, 'Error')
20
+ assert.strictEqual(serialized.message, 'foo')
21
+ assert.ok(serialized.statusCode)
22
+ assert.strictEqual(serialized.statusCode, 500)
23
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
24
+ })
25
+
26
+ test('serializes Error objects with subclass "type"', () => {
27
+ class MyError extends Error {}
28
+
29
+ const err = new MyError('foo')
30
+ const serialized = serializer(err)
31
+ assert.strictEqual(serialized.type, 'MyError')
32
+ })
33
+
34
+ test('serializes nested errors', () => {
35
+ const err = Error('foo')
36
+ err.inner = Error('bar')
37
+ const serialized = serializer(err)
38
+ assert.strictEqual(serialized.type, 'Error')
39
+ assert.strictEqual(serialized.message, 'foo')
40
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
41
+ assert.strictEqual(serialized.inner.type, 'Error')
42
+ assert.strictEqual(serialized.inner.message, 'bar')
43
+ assert.match(serialized.inner.stack, /Error: bar/)
44
+ assert.match(serialized.inner.stack, /err-with-cause\.test\.js:/)
45
+ })
46
+
47
+ test('serializes error causes', () => {
48
+ const innerErr = Error('inner')
49
+ const middleErr = Error('middle')
50
+ middleErr.cause = innerErr
51
+ const outerErr = Error('outer')
52
+ outerErr.cause = middleErr
53
+
54
+ const serialized = serializer(outerErr)
55
+
56
+ assert.strictEqual(serialized.type, 'Error')
57
+ assert.strictEqual(serialized.message, 'outer')
58
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
59
+
60
+ assert.strictEqual(serialized.cause.type, 'Error')
61
+ assert.strictEqual(serialized.cause.message, 'middle')
62
+ assert.match(serialized.cause.stack, /err-with-cause\.test\.js:/)
63
+
64
+ assert.strictEqual(serialized.cause.cause.type, 'Error')
65
+ assert.strictEqual(serialized.cause.cause.message, 'inner')
66
+ assert.match(serialized.cause.cause.stack, /err-with-cause\.test\.js:/)
67
+ })
68
+
69
+ test('keeps non-error cause', () => {
70
+ const err = Error('foo')
71
+ err.cause = 'abc'
72
+ const serialized = serializer(err)
73
+ assert.strictEqual(serialized.type, 'Error')
74
+ assert.strictEqual(serialized.message, 'foo')
75
+ assert.strictEqual(serialized.cause, 'abc')
76
+ })
77
+
78
+ test('prevents infinite recursion', () => {
79
+ const err = Error('foo')
80
+ err.inner = err
81
+ const serialized = serializer(err)
82
+ assert.strictEqual(serialized.type, 'Error')
83
+ assert.strictEqual(serialized.message, 'foo')
84
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
85
+ assert.ok(!serialized.inner)
86
+ })
87
+
88
+ test('cleans up infinite recursion tracking', () => {
89
+ const err = Error('foo')
90
+ const bar = Error('bar')
91
+ err.inner = bar
92
+ bar.inner = err
93
+
94
+ serializer(err)
95
+ const serialized = serializer(err)
96
+
97
+ assert.strictEqual(serialized.type, 'Error')
98
+ assert.strictEqual(serialized.message, 'foo')
99
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
100
+ assert.ok(serialized.inner)
101
+ assert.strictEqual(serialized.inner.type, 'Error')
102
+ assert.strictEqual(serialized.inner.message, 'bar')
103
+ assert.match(serialized.inner.stack, /Error: bar/)
104
+ assert.ok(!serialized.inner.inner)
105
+ })
106
+
107
+ test('err.raw is available', () => {
108
+ const err = Error('foo')
109
+ const serialized = serializer(err)
110
+ assert.strictEqual(serialized.raw, err)
111
+ })
112
+
113
+ test('redefined err.constructor doesnt crash serializer', () => {
114
+ function check (a, name) {
115
+ assert.strictEqual(a.type, name)
116
+ assert.strictEqual(a.message, 'foo')
117
+ }
118
+
119
+ const err1 = TypeError('foo')
120
+ err1.constructor = '10'
121
+
122
+ const err2 = TypeError('foo')
123
+ err2.constructor = undefined
124
+
125
+ const err3 = Error('foo')
126
+ err3.constructor = null
127
+
128
+ const err4 = Error('foo')
129
+ err4.constructor = 10
130
+
131
+ class MyError extends Error {}
132
+
133
+ const err5 = new MyError('foo')
134
+ err5.constructor = undefined
135
+
136
+ check(serializer(err1), 'TypeError')
137
+ check(serializer(err2), 'TypeError')
138
+ check(serializer(err3), 'Error')
139
+ check(serializer(err4), 'Error')
140
+ // We do not expect 'MyError' because err5.constructor has been blown away.
141
+ // `err5.name` is 'Error' from the base class prototype.
142
+ check(serializer(err5), 'Error')
143
+ })
144
+
145
+ test('pass through anything that does not look like an Error', () => {
146
+ function check (a) {
147
+ assert.strictEqual(serializer(a), a)
148
+ }
149
+
150
+ check('foo')
151
+ check({ hello: 'world' })
152
+ check([1, 2])
153
+ })
154
+
155
+ test('can wrap err serializers', () => {
156
+ const err = Error('foo')
157
+ err.foo = 'foo'
158
+ const serializer = wrapErrorSerializer(function (err) {
159
+ delete err.foo
160
+ err.bar = 'bar'
161
+ return err
162
+ })
163
+ const serialized = serializer(err)
164
+ assert.strictEqual(serialized.type, 'Error')
165
+ assert.strictEqual(serialized.message, 'foo')
166
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
167
+ assert.ok(!serialized.foo)
168
+ assert.strictEqual(serialized.bar, 'bar')
169
+ })
170
+
171
+ test('serializes aggregate errors', { skip: !global.AggregateError }, () => {
172
+ const foo = new Error('foo')
173
+ const bar = new Error('bar')
174
+ for (const aggregate of [
175
+ new AggregateError([foo, bar], 'aggregated message'),
176
+ { errors: [foo, bar], message: 'aggregated message', stack: 'err-with-cause.test.js:' }
177
+ ]) {
178
+ const serialized = serializer(aggregate)
179
+ assert.strictEqual(serialized.message, 'aggregated message')
180
+ assert.strictEqual(serialized.aggregateErrors.length, 2)
181
+ assert.strictEqual(serialized.aggregateErrors[0].message, 'foo')
182
+ assert.strictEqual(serialized.aggregateErrors[1].message, 'bar')
183
+ assert.match(serialized.aggregateErrors[0].stack, /^Error: foo/)
184
+ assert.match(serialized.aggregateErrors[1].stack, /^Error: bar/)
185
+ assert.match(serialized.stack, /err-with-cause\.test\.js:/)
186
+ }
187
+ })
@@ -0,0 +1,200 @@
1
+ 'use strict'
2
+
3
+ const assert = require('node:assert')
4
+ const { test } = require('node:test')
5
+ const serializer = require('../lib/err')
6
+ const { wrapErrorSerializer } = require('../')
7
+
8
+ test('serializes Error objects', () => {
9
+ const serialized = serializer(Error('foo'))
10
+ assert.strictEqual(serialized.type, 'Error')
11
+ assert.strictEqual(serialized.message, 'foo')
12
+ assert.match(serialized.stack, /err\.test\.js:/)
13
+ })
14
+
15
+ test('serializes Error objects with extra properties', () => {
16
+ const err = Error('foo')
17
+ err.statusCode = 500
18
+ const serialized = serializer(err)
19
+ assert.strictEqual(serialized.type, 'Error')
20
+ assert.strictEqual(serialized.message, 'foo')
21
+ assert.ok(serialized.statusCode)
22
+ assert.strictEqual(serialized.statusCode, 500)
23
+ assert.match(serialized.stack, /err\.test\.js:/)
24
+ })
25
+
26
+ test('serializes Error objects with subclass "type"', () => {
27
+ class MyError extends Error {}
28
+ const err = new MyError('foo')
29
+ const serialized = serializer(err)
30
+ assert.strictEqual(serialized.type, 'MyError')
31
+ })
32
+
33
+ test('serializes nested errors', () => {
34
+ const err = Error('foo')
35
+ err.inner = Error('bar')
36
+ const serialized = serializer(err)
37
+ assert.strictEqual(serialized.type, 'Error')
38
+ assert.strictEqual(serialized.message, 'foo')
39
+ assert.match(serialized.stack, /err\.test\.js:/)
40
+ assert.strictEqual(serialized.inner.type, 'Error')
41
+ assert.strictEqual(serialized.inner.message, 'bar')
42
+ assert.match(serialized.inner.stack, /Error: bar/)
43
+ assert.match(serialized.inner.stack, /err\.test\.js:/)
44
+ })
45
+
46
+ test('serializes error causes', () => {
47
+ for (const cause of [
48
+ Error('bar'),
49
+ { message: 'bar', stack: 'Error: bar: err.test.js:' }
50
+ ]) {
51
+ const err = Error('foo')
52
+ err.cause = cause
53
+ err.cause.cause = Error('abc')
54
+ const serialized = serializer(err)
55
+ assert.strictEqual(serialized.type, 'Error')
56
+ assert.strictEqual(serialized.message, 'foo: bar: abc')
57
+ assert.match(serialized.stack, /err\.test\.js:/)
58
+ assert.match(serialized.stack, /Error: foo/)
59
+ assert.match(serialized.stack, /Error: bar/)
60
+ assert.match(serialized.stack, /Error: abc/)
61
+ assert.ok(!serialized.cause)
62
+ }
63
+ })
64
+
65
+ test('serializes error causes with VError support', function (t) {
66
+ // Fake VError-style setup
67
+ const err = Error('foo: bar')
68
+ err.foo = 'abc'
69
+ err.cause = function () {
70
+ const err = Error('bar')
71
+ err.cause = Error(this.foo)
72
+ return err
73
+ }
74
+ const serialized = serializer(err)
75
+ assert.strictEqual(serialized.type, 'Error')
76
+ assert.strictEqual(serialized.message, 'foo: bar: abc')
77
+ assert.match(serialized.stack, /err\.test\.js:/)
78
+ assert.match(serialized.stack, /Error: foo/)
79
+ assert.match(serialized.stack, /Error: bar/)
80
+ assert.match(serialized.stack, /Error: abc/)
81
+ })
82
+
83
+ test('keeps non-error cause', () => {
84
+ const err = Error('foo')
85
+ err.cause = 'abc'
86
+ const serialized = serializer(err)
87
+ assert.strictEqual(serialized.type, 'Error')
88
+ assert.strictEqual(serialized.message, 'foo')
89
+ assert.strictEqual(serialized.cause, 'abc')
90
+ })
91
+
92
+ test('prevents infinite recursion', () => {
93
+ const err = Error('foo')
94
+ err.inner = err
95
+ const serialized = serializer(err)
96
+ assert.strictEqual(serialized.type, 'Error')
97
+ assert.strictEqual(serialized.message, 'foo')
98
+ assert.match(serialized.stack, /err\.test\.js:/)
99
+ assert.ok(!serialized.inner)
100
+ })
101
+
102
+ test('cleans up infinite recursion tracking', () => {
103
+ const err = Error('foo')
104
+ const bar = Error('bar')
105
+ err.inner = bar
106
+ bar.inner = err
107
+
108
+ serializer(err)
109
+ const serialized = serializer(err)
110
+
111
+ assert.strictEqual(serialized.type, 'Error')
112
+ assert.strictEqual(serialized.message, 'foo')
113
+ assert.match(serialized.stack, /err\.test\.js:/)
114
+ assert.ok(serialized.inner)
115
+ assert.strictEqual(serialized.inner.type, 'Error')
116
+ assert.strictEqual(serialized.inner.message, 'bar')
117
+ assert.match(serialized.inner.stack, /Error: bar/)
118
+ assert.ok(!serialized.inner.inner)
119
+ })
120
+
121
+ test('err.raw is available', () => {
122
+ const err = Error('foo')
123
+ const serialized = serializer(err)
124
+ assert.strictEqual(serialized.raw, err)
125
+ })
126
+
127
+ test('redefined err.constructor doesnt crash serializer', () => {
128
+ function check (a, name) {
129
+ assert.strictEqual(a.type, name)
130
+ assert.strictEqual(a.message, 'foo')
131
+ }
132
+
133
+ const err1 = TypeError('foo')
134
+ err1.constructor = '10'
135
+
136
+ const err2 = TypeError('foo')
137
+ err2.constructor = undefined
138
+
139
+ const err3 = Error('foo')
140
+ err3.constructor = null
141
+
142
+ const err4 = Error('foo')
143
+ err4.constructor = 10
144
+
145
+ class MyError extends Error {}
146
+ const err5 = new MyError('foo')
147
+ err5.constructor = undefined
148
+
149
+ check(serializer(err1), 'TypeError')
150
+ check(serializer(err2), 'TypeError')
151
+ check(serializer(err3), 'Error')
152
+ check(serializer(err4), 'Error')
153
+ // We do not expect 'MyError' because err5.constructor has been blown away.
154
+ // `err5.name` is 'Error' from the base class prototype.
155
+ check(serializer(err5), 'Error')
156
+ })
157
+
158
+ test('pass through anything that does not look like an Error', () => {
159
+ function check (a) {
160
+ assert.strictEqual(serializer(a), a)
161
+ }
162
+
163
+ check('foo')
164
+ check({ hello: 'world' })
165
+ check([1, 2])
166
+ })
167
+
168
+ test('can wrap err serializers', () => {
169
+ const err = Error('foo')
170
+ err.foo = 'foo'
171
+ const serializer = wrapErrorSerializer(function (err) {
172
+ delete err.foo
173
+ err.bar = 'bar'
174
+ return err
175
+ })
176
+ const serialized = serializer(err)
177
+ assert.strictEqual(serialized.type, 'Error')
178
+ assert.strictEqual(serialized.message, 'foo')
179
+ assert.match(serialized.stack, /err\.test\.js:/)
180
+ assert.ok(!serialized.foo)
181
+ assert.strictEqual(serialized.bar, 'bar')
182
+ })
183
+
184
+ test('serializes aggregate errors', { skip: !global.AggregateError }, () => {
185
+ const foo = new Error('foo')
186
+ const bar = new Error('bar')
187
+ for (const aggregate of [
188
+ new AggregateError([foo, bar], 'aggregated message'),
189
+ { errors: [foo, bar], message: 'aggregated message', stack: 'err.test.js:' }
190
+ ]) {
191
+ const serialized = serializer(aggregate)
192
+ assert.strictEqual(serialized.message, 'aggregated message')
193
+ assert.strictEqual(serialized.aggregateErrors.length, 2)
194
+ assert.strictEqual(serialized.aggregateErrors[0].message, 'foo')
195
+ assert.strictEqual(serialized.aggregateErrors[1].message, 'bar')
196
+ assert.match(serialized.aggregateErrors[0].stack, /^Error: foo/)
197
+ assert.match(serialized.aggregateErrors[1].stack, /^Error: bar/)
198
+ assert.match(serialized.stack, /err\.test\.js:/)
199
+ }
200
+ })