From 6e8e07b0e6f337f953a75f90ad65b262d2a02c0f Mon Sep 17 00:00:00 2001 From: Jan Molak <1089173+jan-molak@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:57:47 +0200 Subject: [PATCH 1/2] feat(object): toJSON available as a standalone function --- src/TinyType.ts | 69 ++-------------------------------------- src/objects/index.ts | 1 + src/objects/toJSON.ts | 73 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 67 deletions(-) create mode 100644 src/objects/toJSON.ts diff --git a/src/TinyType.ts b/src/TinyType.ts index 4f6e2263..596e1488 100644 --- a/src/TinyType.ts +++ b/src/TinyType.ts @@ -1,7 +1,7 @@ import { ensure } from './ensure'; -import { equal, isRecord, significantFieldsOf, stringify } from './objects'; +import { equal, significantFieldsOf, stringify, toJSON } from './objects'; import { isDefined } from './predicates'; -import { JSONObject, JSONValue, Serialisable } from './types'; +import { JSONValue, Serialisable } from './types'; /** * @desc The {@link TinyTypeOf} can be used to define simple @@ -137,68 +137,3 @@ export abstract class TinyType implements Serialisable { }, {}) as JSONValue; } } - -function toJSON(value: any): JSONValue | undefined { - 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): JSONObject { - const serialised = Array.from(map, ([key, value]) => [ toJSON(key), toJSON(value) ]); - - return Object.fromEntries(serialised); -} - -function recordToJSON(value: Record): 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); -} diff --git a/src/objects/index.ts b/src/objects/index.ts index f340c175..be367368 100644 --- a/src/objects/index.ts +++ b/src/objects/index.ts @@ -4,3 +4,4 @@ export * from './isObject'; export * from './isRecord'; export * from './significantFields'; export * from './stringify'; +export * from './toJSON'; diff --git a/src/objects/toJSON.ts b/src/objects/toJSON.ts new file mode 100644 index 00000000..a452a421 --- /dev/null +++ b/src/objects/toJSON.ts @@ -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): JSONObject { + const serialised = Array.from(map, ([key, value]) => [ toJSON(key), toJSON(value) ]); + + return Object.fromEntries(serialised); +} + +function recordToJSON(value: Record): 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); +} From 82f2da62858195c65ca45606298532641f907eeb Mon Sep 17 00:00:00 2001 From: Jan Molak <1089173+jan-molak@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:03:22 +0200 Subject: [PATCH 2/2] feat(tiny-types): support for Node 22 --- .github/workflows/main.yaml | 2 +- package.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2c92fb4c..e9558e0d 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [ 16.x, 18.x, 20.x ] + node-version: [ 16.x, 18.x, 20.x, 22.x ] steps: - uses: actions/checkout@v4 diff --git a/package.json b/package.json index b974b6bc..f909f09f 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,7 @@ }, "homepage": "https://jan-molak.github.io/tiny-types/", "engines": { - "node": "^16 || ^18 || ^20", - "npm": "^8 || ^9 || ^10" + "node": "^16 || ^18 || ^20 || ^22" }, "devDependencies": { "@types/chai": "4.3.17",