-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #889 from jan-molak/features/to-json
feat(object): toJSON available as a standalone function
- Loading branch information
Showing
5 changed files
with
78 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* eslint-disable unicorn/filename-case */ | ||
import { JSONObject, JSONValue } from '../types'; | ||
import { isRecord } from './isRecord'; | ||
|
||
/** | ||
* Serialises the object to a JSON representation. | ||
* | ||
* @param value | ||
*/ | ||
export function toJSON(value: any): JSONValue | undefined { // eslint-disable-line @typescript-eslint/explicit-module-boundary-types | ||
switch (true) { | ||
case value && !! value.toJSON: | ||
return value.toJSON(); | ||
case value && Array.isArray(value): | ||
return value.map(v => { | ||
return v === undefined | ||
? null | ||
: toJSON(v) as JSONValue; | ||
}); | ||
case value && value instanceof Map: | ||
return mapToJSON(value); | ||
case value && value instanceof Set: | ||
return toJSON(Array.from(value)); | ||
case value && isRecord(value): | ||
return recordToJSON(value); | ||
case value && value instanceof Error: | ||
return errorToJSON(value); | ||
case isSerialisablePrimitive(value): | ||
return value; | ||
default: | ||
return JSON.stringify(value); | ||
} | ||
} | ||
|
||
function mapToJSON(map: Map<any, any>): JSONObject { | ||
const serialised = Array.from(map, ([key, value]) => [ toJSON(key), toJSON(value) ]); | ||
|
||
return Object.fromEntries(serialised); | ||
} | ||
|
||
function recordToJSON(value: Record<any, any>): JSONObject { | ||
const serialised = Object.entries(value) | ||
.map(([ k, v ]) => [ toJSON(k), toJSON(v) ]); | ||
|
||
return Object.fromEntries(serialised); | ||
} | ||
|
||
function errorToJSON(value: Error): JSONObject { | ||
return Object.getOwnPropertyNames(value) | ||
.reduce((serialised, key) => { | ||
serialised[key] = toJSON(value[key]) | ||
return serialised; | ||
}, { }) as JSONObject; | ||
} | ||
|
||
function isSerialisableNumber(value: unknown): value is number { | ||
return typeof value === 'number' | ||
&& ! Number.isNaN(value) | ||
&& value !== Number.NEGATIVE_INFINITY | ||
&& value !== Number.POSITIVE_INFINITY; | ||
} | ||
|
||
function isSerialisablePrimitive(value: unknown): value is string | boolean | number | null | undefined { | ||
if (['string', 'boolean'].includes(typeof value)) { | ||
return true; | ||
} | ||
|
||
if (value === null || value === undefined) { | ||
return true; | ||
} | ||
|
||
return isSerialisableNumber(value); | ||
} |