From 51195f936490157bb333db324015d60204909f95 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Thu, 10 Feb 2022 10:31:55 +0000 Subject: [PATCH] Add Show to Json --- docs/modules/Json.ts.md | 102 ++++++++++++++++++++++++++-------------- dtslint/ts3.5/Json.ts | 15 ++++++ package-lock.json | 5 ++ package.json | 4 +- src/Json.ts | 40 +++++++++++++++- src/boolean.ts | 5 +- src/number.ts | 5 +- src/string.ts | 5 +- test/Json.ts | 25 ++++++++++ 9 files changed, 159 insertions(+), 47 deletions(-) diff --git a/docs/modules/Json.ts.md b/docs/modules/Json.ts.md index 2ecbffff8..6c2917c3c 100644 --- a/docs/modules/Json.ts.md +++ b/docs/modules/Json.ts.md @@ -12,48 +12,20 @@ Added in v2.10.0

Table of contents

-- [utils](#utils) +- [constructors](#constructors) + - [parse](#parse) +- [destructors](#destructors) + - [stringify](#stringify) +- [instances](#instances) + - [Show](#show) +- [model](#model) - [Json (type alias)](#json-type-alias) - [JsonArray (interface)](#jsonarray-interface) - [JsonRecord (interface)](#jsonrecord-interface) - - [parse](#parse) - - [stringify](#stringify) --- -# utils - -## Json (type alias) - -**Signature** - -```ts -export type Json = boolean | number | string | null | JsonArray | JsonRecord -``` - -Added in v2.10.0 - -## JsonArray (interface) - -**Signature** - -```ts -export interface JsonArray extends ReadonlyArray {} -``` - -Added in v2.10.0 - -## JsonRecord (interface) - -**Signature** - -```ts -export interface JsonRecord { - readonly [key: string]: Json -} -``` - -Added in v2.10.0 +# constructors ## parse @@ -78,6 +50,8 @@ assert.deepStrictEqual(pipe('{"a":}', J.parse), E.left(new SyntaxError('Unexpect Added in v2.10.0 +# destructors + ## stringify Converts a JavaScript value to a JavaScript Object Notation (JSON) string. @@ -108,3 +82,59 @@ assert.deepStrictEqual( ``` Added in v2.10.0 + +# instances + +## Show + +**Signature** + +```ts +export declare const Show: Sh.Show +``` + +**Example** + +```ts +import * as J from 'fp-ts/Json' + +const circular: any = { b: 1, a: 0 } +circular.circular = circular +assert.deepStrictEqual(J.Show.show(circular), '{"a":0,"b":1,"circular":"[Circular]"}') +``` + +Added in v2.11.9 + +# model + +## Json (type alias) + +**Signature** + +```ts +export type Json = boolean | number | string | null | JsonArray | JsonRecord +``` + +Added in v2.10.0 + +## JsonArray (interface) + +**Signature** + +```ts +export interface JsonArray extends ReadonlyArray {} +``` + +Added in v2.10.0 + +## JsonRecord (interface) + +**Signature** + +```ts +export interface JsonRecord { + readonly [key: string]: Json +} +``` + +Added in v2.10.0 diff --git a/dtslint/ts3.5/Json.ts b/dtslint/ts3.5/Json.ts index 8e568d1c8..6109ce403 100644 --- a/dtslint/ts3.5/Json.ts +++ b/dtslint/ts3.5/Json.ts @@ -2,6 +2,21 @@ import * as E from '../../src/Either' import { pipe } from '../../src/function' import * as _ from '../../src/Json' +// +// Show +// + +// $ExpectError +_.Show.show(undefined) +// $ExpectError +_.Show.show(() => {}) +// $ExpectError +_.Show.show(Symbol()) +// $ExpectError +_.Show.show({ a: undefined }) +// $ExpectError +_.Show.show({ ...{ a: undefined } }) + // // stringify // diff --git a/package-lock.json b/package-lock.json index dd6274cb1..fa44d7cf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6147,6 +6147,11 @@ "ret": "~0.1.10" } }, + "safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", diff --git a/package.json b/package.json index 2494a763d..33e456f35 100644 --- a/package.json +++ b/package.json @@ -67,5 +67,7 @@ "algebraic-data-types", "functional-programming" ], - "dependencies": {} + "dependencies": { + "safe-stable-stringify": "^2.3.1" + } } diff --git a/src/Json.ts b/src/Json.ts index 4a188af53..f1146d37f 100644 --- a/src/Json.ts +++ b/src/Json.ts @@ -1,15 +1,23 @@ /** * @since 2.10.0 */ +import safeStringify from 'safe-stable-stringify' import { Either, tryCatch } from './Either' import { identity } from './function' +import * as Sh from './Show' + +// ------------------------------------------------------------------------------------- +// model +// ------------------------------------------------------------------------------------- /** + * @category model * @since 2.10.0 */ export type Json = boolean | number | string | null | JsonArray | JsonRecord /** + * @category model * @since 2.10.0 */ export interface JsonRecord { @@ -17,10 +25,34 @@ export interface JsonRecord { } /** + * @category model * @since 2.10.0 */ export interface JsonArray extends ReadonlyArray {} +// ------------------------------------------------------------------------------------- +// instances +// ------------------------------------------------------------------------------------- + +/** + * @example + * import * as J from 'fp-ts/Json' + * + * const circular: any = { b: 1, a: 0 } + * circular.circular = circular + * assert.deepStrictEqual(J.Show.show(circular), '{"a":0,"b":1,"circular":"[Circular]"}') + * + * @category instances + * @since 2.11.9 + */ +export const Show: Sh.Show = { + show: safeStringify +} + +// ------------------------------------------------------------------------------------- +// constructors +// ------------------------------------------------------------------------------------- + /** * Converts a JavaScript Object Notation (JSON) string into a `Json` type. * @@ -32,10 +64,15 @@ export interface JsonArray extends ReadonlyArray {} * assert.deepStrictEqual(pipe('{"a":1}', J.parse), E.right({ a: 1 })) * assert.deepStrictEqual(pipe('{"a":}', J.parse), E.left(new SyntaxError('Unexpected token } in JSON at position 5'))) * + * @category constructors * @since 2.10.0 */ export const parse = (s: string): Either => tryCatch(() => JSON.parse(s), identity) +// ------------------------------------------------------------------------------------- +// destructors +// ------------------------------------------------------------------------------------- + /** * Converts a JavaScript value to a JavaScript Object Notation (JSON) string. * @@ -55,7 +92,8 @@ export const parse = (s: string): Either => tryCatch(() => JSON.p * E.left(true) * ) * - * @since 2.10.0 + * @category destructors + * @since 2.10.0 */ export const stringify = (a: A): Either => tryCatch(() => { diff --git a/src/boolean.ts b/src/boolean.ts index 8411912b8..30976c3f3 100644 --- a/src/boolean.ts +++ b/src/boolean.ts @@ -4,6 +4,7 @@ import * as BA from './BooleanAlgebra' import * as E from './Eq' import { Lazy } from './function' +import * as J from './Json' import { Monoid } from './Monoid' import * as O from './Ord' import { Refinement } from './Refinement' @@ -182,6 +183,4 @@ export const Ord: O.Ord = { * @category instances * @since 2.10.0 */ -export const Show: S.Show = { - show: (b) => JSON.stringify(b) -} +export const Show: S.Show = J.Show diff --git a/src/number.ts b/src/number.ts index 5ed8aef9c..9d7613fa8 100644 --- a/src/number.ts +++ b/src/number.ts @@ -4,6 +4,7 @@ import * as B from './Bounded' import * as E from './Eq' import * as F from './Field' +import * as J from './Json' import { Magma } from './Magma' import { Monoid } from './Monoid' import * as O from './Ord' @@ -57,9 +58,7 @@ export const Bounded: B.Bounded = { * @category instances * @since 2.10.0 */ -export const Show: S.Show = { - show: (n) => JSON.stringify(n) -} +export const Show: S.Show = J.Show /** * @category instances diff --git a/src/string.ts b/src/string.ts index 14196a414..c6ef0b60a 100644 --- a/src/string.ts +++ b/src/string.ts @@ -2,6 +2,7 @@ * @since 2.10.0 */ import * as E from './Eq' +import * as J from './Json' import * as M from './Monoid' import * as S from './Semigroup' import * as O from './Ord' @@ -86,9 +87,7 @@ export const Ord: O.Ord = { * @category instances * @since 2.10.0 */ -export const Show: Sh.Show = { - show: (s) => JSON.stringify(s) -} +export const Show: Sh.Show = J.Show // ------------------------------------------------------------------------------------- // refinements diff --git a/test/Json.ts b/test/Json.ts index 060baf731..4d8a099df 100644 --- a/test/Json.ts +++ b/test/Json.ts @@ -4,11 +4,36 @@ import * as _ from '../src/Json' import * as U from './util' describe('Json', () => { + // ------------------------------------------------------------------------------------- + // instances + // ------------------------------------------------------------------------------------- + + it('Show', () => { + U.deepStrictEqual(_.Show.show({ a: 1 }), '{"a":1}') + const circular: any = { ref: null } + circular.ref = circular + U.deepStrictEqual(_.Show.show(circular), '{"ref":"[Circular]"}') + type Person = { + readonly name: string + readonly age: number + } + const person: Person = { name: 'Giulio', age: 45 } + U.deepStrictEqual(_.Show.show(person), '{"age":45,"name":"Giulio"}') + }) + + // ------------------------------------------------------------------------------------- + // constructors + // ------------------------------------------------------------------------------------- + it('parse', () => { U.deepStrictEqual(pipe('{"a":1}', _.parse), E.right({ a: 1 })) U.deepStrictEqual(pipe('{"a":}', _.parse), E.left(new SyntaxError('Unexpected token } in JSON at position 5'))) }) + // ------------------------------------------------------------------------------------- + // destructors + // ------------------------------------------------------------------------------------- + it('stringify', () => { U.deepStrictEqual(pipe({ a: 1 }, _.stringify), E.right('{"a":1}')) const circular: any = { ref: null }