From d3c9c216864e0cae61337aef278fa8e1b499646b Mon Sep 17 00:00:00 2001 From: Michael Sampson Date: Sun, 31 Oct 2021 11:04:17 -0500 Subject: [PATCH] Support for decimal.js. Support for Prisma.Decimal. --- README.md | 1 + package.json | 1 + src/index.test.ts | 15 +++++++++++++++ src/is.test.ts | 4 ++++ src/is.ts | 5 +++++ src/transformer.ts | 11 +++++++++-- src/types.ts | 4 +++- yarn.lock | 5 +++++ 8 files changed, 43 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0ab25b5..4377ad8 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,7 @@ Superjson supports many extra types which JSON does not. You can serialize all t | `Set` | ❌ | ✅ | | `Map` | ❌ | ✅ | | `Error` | ❌ | ✅ | +| `Decimal` | ❌ | ✅ | ## Contributors ✨ diff --git a/package.json b/package.json index 3e9850c..b18bcd8 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ }, "dependencies": { "debug": "^4.3.1", + "decimal.js": "^10.3.1", "lodash.clonedeep": "^4.5.0" }, "resolutions": { diff --git a/src/index.test.ts b/src/index.test.ts index 9af1f3d..7dcfd31 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -13,6 +13,7 @@ import { } from './is'; import { ObjectID } from 'mongodb'; +import Decimal from 'decimal.js'; const isNode10 = process.version.indexOf('v10') === 0; @@ -192,6 +193,20 @@ describe('stringify & parse', () => { }, }, + 'works for Decimals': { + input: { + totalCost: new Decimal('199.99'), + }, + output: { + totalCost: new Decimal('199.99').toJSON(), + }, + outputAnnotations: { + values: { + totalCost: ['Decimal'], + }, + }, + }, + 'works for Errors': { input: { e: new Error('epic fail'), diff --git a/src/is.test.ts b/src/is.test.ts index 8dba1e7..16057be 100644 --- a/src/is.test.ts +++ b/src/is.test.ts @@ -1,3 +1,4 @@ +import Decimal from 'decimal.js'; import { isArray, isBoolean, @@ -11,6 +12,7 @@ import { isUndefined, isPlainObject, isTypedArray, + isDecimal, } from './is'; test('Basic true tests', () => { @@ -29,6 +31,7 @@ test('Basic true tests', () => { expect(isNumber(0)).toBe(true); expect(isNumber(1)).toBe(true); expect(isDate(new Date())).toBe(true); + expect(isDecimal(new Decimal('100.1'))).toBe(true); expect(isSymbol(Symbol())).toBe(true); expect(isTypedArray(new Uint8Array())).toBe(true); }); @@ -37,6 +40,7 @@ test('Basic false tests', () => { expect(isNumber(NaN)).toBe(false); expect(isDate(new Date('_'))).toBe(false); expect(isDate(NaN)).toBe(false); + expect(isDecimal(NaN)).toBe(false); expect(isUndefined(NaN)).toBe(false); expect(isNull(NaN)).toBe(false); diff --git a/src/is.ts b/src/is.ts index c6ddff7..d5d475a 100644 --- a/src/is.ts +++ b/src/is.ts @@ -1,3 +1,5 @@ +import Decimal from 'decimal.js'; + const getType = (payload: any): string => Object.prototype.toString.call(payload).slice(8, -1); @@ -84,3 +86,6 @@ export type TypedArray = InstanceType; export const isTypedArray = (payload: any): payload is TypedArray => ArrayBuffer.isView(payload) && !(payload instanceof DataView); + +export const isDecimal = (payload: any): payload is Decimal => + Decimal.isDecimal(payload); diff --git a/src/transformer.ts b/src/transformer.ts index c19b817..065a96d 100644 --- a/src/transformer.ts +++ b/src/transformer.ts @@ -11,6 +11,7 @@ import { isArray, isError, isTypedArray, + isDecimal, TypedArrayConstructor, } from './is'; import { ClassRegistry } from './class-registry'; @@ -18,6 +19,7 @@ import { SymbolRegistry } from './symbol-registry'; import { CustomTransformerRegistry } from './custom-transformer-registry'; import { allowedErrorProps } from './error-props'; import { findArr } from './util'; +import Decimal from 'decimal.js'; export type PrimitiveTypeAnnotation = 'number' | 'undefined' | 'bigint'; @@ -28,7 +30,7 @@ type ClassTypeAnnotation = ['class', string]; type SymbolTypeAnnotation = ['symbol', string]; type CustomTypeAnnotation = ['custom', string]; -type SimpleTypeAnnotation = LeafTypeAnnotation | 'map' | 'set'; +type SimpleTypeAnnotation = LeafTypeAnnotation | 'map' | 'set' | 'Decimal'; type CompositeTypeAnnotation = | TypedArrayAnnotation @@ -79,7 +81,12 @@ const simpleRules = [ v => v.toISOString(), v => new Date(v) ), - + simpleTransformation( + isDecimal, + 'Decimal', + v => v.toJSON(), + v => new Decimal(v) + ), simpleTransformation( isError, 'Error', diff --git a/src/types.ts b/src/types.ts index 10883b4..3df09fe 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,6 @@ import { TypeAnnotation } from './transformer'; import { MinimisedTree, ReferentialEqualityAnnotations } from './plainer'; +import Decimal from 'decimal.js'; export type Class = { new (...args: any[]): any }; @@ -23,7 +24,8 @@ export type SerializableJSONValue = | bigint | Date | ClassInstance - | RegExp; + | RegExp + | typeof Decimal; export type SuperJSONValue = | JSONValue diff --git a/yarn.lock b/yarn.lock index ff941e6..0f52374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2507,6 +2507,11 @@ decimal.js@^10.2.0: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== +decimal.js@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz"