1- import { Ono } from "@jsdevtools/ono" ;
21import { getHash , stripHash , toFileSystemPath } from "./url.js" ;
32import type $RefParser from "../index.js" ;
43import type { ParserOptions } from "../index.js" ;
@@ -14,7 +13,57 @@ export type JSONParserErrorType =
1413 | "EUNMATCHEDRESOLVER"
1514 | "EMISSINGPOINTER"
1615 | "EINVALIDPOINTER" ;
16+ const nonJsonTypes = [ "function" , "symbol" , "undefined" ] ;
17+ const protectedProps = [ "constructor" , "prototype" , "__proto__" ] ;
18+ const objectPrototype = Object . getPrototypeOf ( { } ) ;
19+
20+ /**
21+ * Custom JSON serializer for Error objects.
22+ * Returns all built-in error properties, as well as extended properties.
23+ */
24+ export function toJSON < T extends Error > ( this : T ) : Error & T {
25+ // HACK: We have to cast the objects to `any` so we can use symbol indexers.
26+ // see https://github.com/Microsoft/TypeScript/issues/1863
27+ const pojo : any = { } ;
28+ const error = this as any ;
29+
30+ for ( const key of getDeepKeys ( error ) ) {
31+ if ( typeof key === "string" ) {
32+ const value = error [ key ] ;
33+ const type = typeof value ;
34+
35+ if ( ! nonJsonTypes . includes ( type ) ) {
36+ pojo [ key ] = value ;
37+ }
38+ }
39+ }
40+
41+ return pojo as Error & T ;
42+ }
43+
44+ /**
45+ * Returns own, inherited, enumerable, non-enumerable, string, and symbol keys of `obj`.
46+ * Does NOT return members of the base Object prototype, or the specified omitted keys.
47+ */
48+ export function getDeepKeys ( obj : object , omit : Array < string | symbol > = [ ] ) : Set < string | symbol > {
49+ let keys : Array < string | symbol > = [ ] ;
50+
51+ // Crawl the prototype chain, finding all the string and symbol keys
52+ while ( obj && obj !== objectPrototype ) {
53+ keys = keys . concat ( Object . getOwnPropertyNames ( obj ) , Object . getOwnPropertySymbols ( obj ) ) ;
54+ obj = Object . getPrototypeOf ( obj ) as object ;
55+ }
1756
57+ // De-duplicate the list of keys
58+ const uniqueKeys = new Set ( keys ) ;
59+
60+ // Remove any omitted keys
61+ for ( const key of omit . concat ( protectedProps ) ) {
62+ uniqueKeys . delete ( key ) ;
63+ }
64+
65+ return uniqueKeys ;
66+ }
1867export class JSONParserError extends Error {
1968 public readonly name : string ;
2069 public readonly message : string ;
@@ -29,10 +78,10 @@ export class JSONParserError extends Error {
2978 this . message = message ;
3079 this . source = source ;
3180 this . path = null ;
32-
33- Ono . extend ( this ) ;
3481 }
3582
83+ toJSON = toJSON . bind ( this ) ;
84+
3685 get footprint ( ) {
3786 return `${ this . path } +${ this . source } +${ this . code } +${ this . message } ` ;
3887 }
@@ -52,9 +101,8 @@ export class JSONParserErrorGroup<
52101 this . message = `${ this . errors . length } error${
53102 this . errors . length > 1 ? "s" : ""
54103 } occurred while reading '${ toFileSystemPath ( parser . $refs . _root$Ref ! . path ) } '`;
55-
56- Ono . extend ( this ) ;
57104 }
105+ toJSON = toJSON . bind ( this ) ;
58106
59107 static getParserErrors < S extends object = JSONSchema , O extends ParserOptions < S > = ParserOptions < S > > (
60108 parser : $RefParser < S , O > ,
0 commit comments