error-serializer
Advanced tools
Comparing version 1.2.1 to 1.3.0
@@ -1,2 +0,2 @@ | ||
import{safeGetProp}from"./safe.js"; | ||
import{safeGetProp}from"./check.js"; | ||
@@ -30,4 +30,4 @@ | ||
const getNonCoreProp=function(errorOrObject,propName){ | ||
const value=safeGetProp(errorOrObject,propName); | ||
return value===undefined?undefined:[propName,value]; | ||
const{safe,value}=safeGetProp(errorOrObject,propName); | ||
return safe&&value!==undefined?[propName,value]:undefined; | ||
}; | ||
@@ -34,0 +34,0 @@ |
@@ -12,15 +12,37 @@ /** | ||
interface MinimalErrorObject { | ||
name: string | ||
message: string | ||
stack: string | ||
[key: PropertyKey]: JSONValue | ||
} | ||
/** | ||
* Error instance converted to a plain object | ||
*/ | ||
export interface ErrorObject { | ||
name: string | ||
message: string | ||
stack: string | ||
export interface ErrorObject extends MinimalErrorObject { | ||
cause?: ErrorObject | ||
errors?: ErrorObject[] | ||
[key: PropertyKey]: JSONValue | ||
} | ||
/** | ||
* `error-serializer` `serialize()` options | ||
*/ | ||
export interface SerializeOptions { | ||
/** | ||
* If this option is `true` and `errorInstance` is not an `Error` instance, | ||
* it is returned as is, instead of being converted to a plain object. | ||
* | ||
* @default false | ||
* | ||
* @example | ||
* ```js | ||
* console.log(serialize('example')) // { name: 'Error', message: 'example', ... } | ||
* console.log(serialize('example', { loose: true })) // 'example' | ||
* ``` | ||
*/ | ||
readonly loose?: boolean | ||
} | ||
/** | ||
* Convert an `Error` instance into a plain object. | ||
@@ -41,3 +63,10 @@ * | ||
*/ | ||
export function serialize(errorInstance: unknown): ErrorObject | ||
export function serialize<ArgType, Options extends SerializeOptions>( | ||
errorInstance: ArgType, | ||
options?: Options, | ||
): Options['loose'] extends true | ||
? ArgType extends Error | ||
? ErrorObject | ||
: ArgType | ||
: ErrorObject | ||
@@ -49,2 +78,16 @@ /** | ||
/** | ||
* If this option is `true` and `errorObject` is not an error plain object, | ||
* it is returned as is, instead of being converted to an `Error` instance. | ||
* | ||
* @default false | ||
* | ||
* @example | ||
* ```js | ||
* console.log(parse('example')) // Error: example | ||
* console.log(parse('example', { loose: true })) // 'example' | ||
* ``` | ||
*/ | ||
readonly loose?: boolean | ||
/** | ||
* Custom error types to keep when parsing. | ||
@@ -88,2 +131,9 @@ * | ||
*/ | ||
export function parse(errorObject: unknown, options?: ParseOptions): Error | ||
export function parse<ArgType, Options extends ParseOptions>( | ||
errorObject: ArgType, | ||
options?: Options, | ||
): Options['loose'] extends true | ||
? ArgType extends MinimalErrorObject | ||
? Error | ||
: ArgType | ||
: Error |
import normalizeException from"normalize-exception"; | ||
import safeJsonValue from"safe-json-value"; | ||
import{isErrorInstance,isErrorObject}from"./check.js"; | ||
import{parseError}from"./parse/main.js"; | ||
@@ -14,7 +15,11 @@ import{serializeError}from"./serialize.js"; | ||
export const serialize=function(error){ | ||
const errorA=normalizeException(error); | ||
const object=serializeError(errorA); | ||
const{value}=safeJsonValue(object); | ||
export const serialize=function(value,{loose=false}={}){ | ||
if(loose&&!isErrorInstance(value)){ | ||
return value; | ||
} | ||
const error=normalizeException(value); | ||
const object=serializeError(error); | ||
const{value:objectA}=safeJsonValue(object); | ||
return objectA; | ||
}; | ||
@@ -25,22 +30,14 @@ | ||
export const parse=function(value,{types={}}={}){ | ||
const object=normalizeObject(value); | ||
const error=parseError(object,types); | ||
const errorA=normalizeException(error); | ||
return errorA; | ||
}; | ||
export const parse=function(value,{loose=false,types={}}={}){ | ||
if(loose&&!isErrorObject(value)){ | ||
return value; | ||
} | ||
const normalizeObject=function(value){ | ||
return isObject(value)?value:{message:String(value)}; | ||
const error=parseError(value,types); | ||
const errorA=normalizeException(error); | ||
return errorA; | ||
}; | ||
const isObject=function(value){ | ||
return( | ||
(typeof value==="object"||typeof value==="function")&&value!==null); | ||
}; | ||
//# sourceMappingURL=main.js.map |
@@ -1,9 +0,6 @@ | ||
import{safeGetProp}from"../safe.js"; | ||
export const createError=function({name,message},types){ | ||
const ErrorType=getErrorType(name,types); | ||
export const createError=function(object,types){ | ||
const ErrorType=getErrorType(object,types); | ||
const message=getMessage(object); | ||
try{ | ||
@@ -25,9 +22,3 @@ return ErrorType===globalThis.AggregateError? | ||
const getErrorType=function(object,types){ | ||
const name=safeGetProp(object,"name"); | ||
if(typeof name!=="string"){ | ||
return Error; | ||
} | ||
const getErrorType=function(name,types){ | ||
if(typeof types[name]==="function"){ | ||
@@ -55,17 +46,2 @@ return types[name]; | ||
"DOMException"]); | ||
const getMessage=function(object){ | ||
const message=safeGetProp(object,"message"); | ||
if(typeof message==="string"){ | ||
return message; | ||
} | ||
try{ | ||
return String(message); | ||
}catch{ | ||
return""; | ||
} | ||
}; | ||
//# sourceMappingURL=create.js.map |
@@ -0,3 +1,3 @@ | ||
import{isErrorObject,safeGetProp}from"../check.js"; | ||
import{UNSET_CORE_PROPS,getNonCoreProps}from"../core.js"; | ||
import{safeGetProp}from"../safe.js"; | ||
@@ -11,4 +11,8 @@ import{createError}from"./create.js"; | ||
export const parseError=function(object,types){ | ||
if(Object.prototype.toString.call(object)==="[object Error]"){ | ||
if(!isErrorObject(object)){ | ||
return object; | ||
@@ -32,5 +36,5 @@ } | ||
const setCoreProp=function({error,object,propName,types}){ | ||
const value=safeGetProp(object,propName); | ||
const{safe,value}=safeGetProp(object,propName); | ||
if(value===undefined){ | ||
if(!safe||value===undefined){ | ||
return; | ||
@@ -56,3 +60,3 @@ } | ||
if(propName==="errors"){ | ||
if(propName==="errors"&&Array.isArray(value)){ | ||
return value.map((item)=>parseError(item,types)); | ||
@@ -59,0 +63,0 @@ } |
{ | ||
"name": "error-serializer", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"type": "module", | ||
@@ -49,2 +49,3 @@ "exports": "./build/src/main.js", | ||
"dependencies": { | ||
"is-plain-obj": "^4.1.0", | ||
"normalize-exception": "^1.6.0", | ||
@@ -55,4 +56,3 @@ "safe-json-value": "^1.6.0" | ||
"@ehmicky/dev-tasks": "^1.0.84", | ||
"is-plain-obj": "^4.1.0", | ||
"test-each": "^5.2.0" | ||
"test-each": "^5.2.1" | ||
}, | ||
@@ -59,0 +59,0 @@ "engines": { |
@@ -12,3 +12,5 @@ [](https://codecov.io/gh/ehmicky/error-serializer) | ||
- Ensures errors are [safe to serialize with JSON](#json-safety) | ||
- [Custom serialization logic](#custom-serialization) (e.g. YAML or | ||
- Can be used as [`error.toJSON()`](#errortojson) | ||
- [Deep serialization/parsing](#deep-serializationparsing) | ||
- [Custom serialization/parsing](#custom-serializationparsing) (e.g. YAML or | ||
`process.send()`) | ||
@@ -52,5 +54,6 @@ - Keeps both native (`TypeError`, etc.) and [custom](#types) error types | ||
## serialize(errorInstance) | ||
## serialize(errorInstance, options?) | ||
`errorInstance` `any`\ | ||
`options` [`Options?`](#options)\ | ||
_Return value_: `object` | ||
@@ -60,2 +63,19 @@ | ||
### Options | ||
Object with the following optional properties. | ||
#### loose | ||
_Type_: `boolean`\ | ||
_Default_: `false` | ||
If this option is `true` and `errorInstance` is not an `Error` instance, it is | ||
returned as is, instead of being converted to a plain object. | ||
```js | ||
console.log(serialize('example')) // { name: 'Error', message: 'example', ... } | ||
console.log(serialize('example', { loose: true })) // 'example' | ||
``` | ||
## parse(errorObject, options?) | ||
@@ -92,2 +112,15 @@ | ||
#### loose | ||
_Type_: `boolean`\ | ||
_Default_: `false` | ||
If this option is `true` and `errorObject` is not an error plain object, it is | ||
returned as is, instead of being converted to an `Error` instance. | ||
```js | ||
console.log(parse('example')) // Error: example | ||
console.log(parse('example', { loose: true })) // 'example' | ||
``` | ||
# Usage | ||
@@ -108,10 +141,52 @@ | ||
## Custom serialization | ||
## `error.toJSON()` | ||
[`serialize()`](#serializeerrorinstance) returns a plain object, not a string. | ||
This allows any serialization logic to be performed. | ||
[`serialize()`](#serializeerrorinstance) can be used as | ||
[`error.toJSON()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#tojson_behavior). | ||
<!-- eslint-disable fp/no-class, fp/no-this --> | ||
```js | ||
import { dump } from 'js-yaml' | ||
class CustomError extends Error { | ||
/* constructor(...) { ... } */ | ||
toJSON() { | ||
return serialize(this) | ||
} | ||
} | ||
const error = new CustomError('example') | ||
console.log(error.toJSON()) | ||
// { name: 'CustomError', message: 'example', stack: '...' } | ||
console.log(JSON.stringify(error)) | ||
// '{"name":"CustomError","message":"example","stack":"..."}' | ||
``` | ||
## Deep serialization/parsing | ||
Objects and arrays containing errors can be deeply serialized/parsed using the | ||
[`loose` option](#loose) combined with | ||
[`JSON.stringify()`'s replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter) | ||
and | ||
[`JSON.parse()`'s reviver](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#using_the_reviver_parameter). | ||
```js | ||
const deepObject = [{}, { error: new Error('example') }] | ||
const jsonString = JSON.stringify(deepObject, (key, value) => | ||
serialize(value, { loose: true }), | ||
) | ||
const newDeepObject = JSON.parse(jsonString, (key, value) => | ||
parse(value, { loose: true }), | ||
) | ||
console.log(newDeepObject[1].error) // Error: example | ||
``` | ||
## Custom serialization/parsing | ||
Errors are converted to/from plain objects, not strings. This allows any | ||
serialization/parsing logic to be performed. | ||
```js | ||
import { dump, load } from 'js-yaml' | ||
const error = new Error('example') | ||
@@ -123,2 +198,4 @@ const errorObject = serialize(error) | ||
// stack: Error: example ... | ||
const newErrorObject = load(errorYamlString) | ||
const newError = parse(newErrorObject) // Error: example | ||
``` | ||
@@ -168,4 +245,4 @@ | ||
// Normalizes `error.message`: not a string | ||
console.log(parse({ message: false })) // Error: false | ||
// Normalizes `error.name`: not a string | ||
console.log(parse({ name: false, message: 'example' })) // Error: example | ||
``` | ||
@@ -172,0 +249,0 @@ |
30497
2
285
290
3
+ Addedis-plain-obj@^4.1.0