3.0.2 • Published 4 months ago

extended-serializer v3.0.2

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

Extended Serializer

Install

npm install extended-serializer

About

  • link to documentation
  • Extends JSON serialization to support almost all data types.
  • Validates all input data to ensure that it is serializable.
  • Doesn't rely on a nonce like other solutions, so no chance of collisions.
  • Never calls toJSON methods.
  • Well tested with 100% coverage.

Transforms

This is an exhastive list of all possible values in JavaScript, and the applicable transforms to make them serializable.

TypeValuesApplicable transformNotes
null valuenullnone needed
boolean primitive typetrue or falsenone needed
string primitive typee.g. "hello"none needed
number primitive typee.g. 5none neededexcept NaN, Infinity, -0
Object instancee.g. {a: 1, b: 2, c: 3}none neededexcept complex Object instances or repeated references
Array instancee.g. [1, 2, 3]none neededexcept complex Array instances or repeated references
-0 value-0negativeZeroTransform
NaN valueNaNnanTransform
Infinity valueInfinity or -InfinityinfinityTransform
undefined primitive typeundefinedundefinedTransform
bigint primitive typee.g. 5nbigIntTransform
complex Object instancee.g. {[Symbol.toStringTag]: "something"}complexObjectTransforman object with symbol keys, or non standard property descriptors
complex Array instancee.g. Object.assign([1, 2, 3], {a: 1, b: 2, c: 3})complexArrayTransforman array with extra or missing properties
repeated and circular referencese.g. [value, value]repeatedReferencesTransformNOT FINISHED should be first transform included
global registry symbol primitive typee.g. Symbol.for("something")registrySymbolTransformyou may want to omit this transform if encoding and decoding in different environments
well known symbol primitive typee.g. Symbol.iteratorwellKnownSymbolTransform
local symbol primitive typee.g. Symbol("something")requires custom transform
function primitive typee.g. () => truerequires custom transform
class instancee.g. new CustomClass()requires custom transform

JS built-in class instances

ClassTransformNotes
SetsetTransform
MapmapTransform
DatedateTransform
RegExpregExpTransform
ArrayBufferarrayBufferTransform
DataViewdataViewTransform
Boolean, Number, StringprimitiveClassTransform
Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateErrorerrorClassTransformwon't encode not standard properties
Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, BigUint64ArraytypedArrayTransformwill need arrayBufferTransform

Notes

  • Proxies will be flattened, without being flagged by the validator as these can only be detected in node, see example for custom validator to reject proxies in node.
  • When writing custom transforms, to test for custom class instances, use isInstanceOf instead of instanceof to prevent capturing instances of subclasses.

Example

import util from "node:util";
import {
	type Serializable,
	transforms,
	transform,
	classTransform,
	classGroupTransform,
	stringify,
	parse
} from "extended-serializer";

const options = {
	validate: value => !util.types.isProxy(value),
	transforms: [
		...transforms,
		customSymbol: makeTransform({
			test: (value) => value === customSymbol,
			decode: () => customSymbol,
		}),
		customFunction: makeTransform({
			test: (value) => value === customFunction,
			decode: () => customFunction,
		}),
		customClass: makeClassTransform({
			constructor: CustomClass,
			encode: ({ a, b }) => [a, b],
		}),
		customClassGroup: makeClassGroupTransform({
			key: "customClassGroup",
			classes: [IntVector, FloatVector, BooleanVector],
			encode: ({ x, y, z }) => [x, y, z],
		}),
	],
} satisfies SerializeOptions;

type Primitive = Serializable<typeof options>;

const value = {
  a: NaN,
  b: Infinity,
  c: new Set([1, 2, 3]),
  d: customSymbol,
  e: customFunction,
  f: new CustomClass(1, 2),
} satisfies Primitive;

const str = stringify(value, options);
const clone = parse(encoded, options);

//clone is now a deep clone of value

//or can use clone
const clone = clone(value, options);

Alternative Work

devalue

https://github.com/Rich-Harris/devalue

  • Can't pick and choose transforms
  • Doesn't fully validate serializable values
  • Unflexible custom transforms

oson

https://github.com/KnorpelSenf/oson?tab=readme-ov-file

  • Only supports class instances custom transforms
  • Doesn't support NaN, Infinity, -0
  • Doesn't support well known symbols or symbols in global registry
  • Doesn't fully validate serializable values

superjson

https://github.com/flightcontrolhq/superjson

  • Globally defined transforms
  • Doesn't fully validate serializable values

next-json

https://github.com/iccicci/next-json?tab=readme-ov-file

  • Non JSON output
  • Doesn't support ArrayBuffer or TypedArrays
  • Doesn't support well known symbols or symbols in global registry
  • Doesn't support Error instances
  • Doesn't support complex objects

arson

https://github.com/benjamn/arson

  • Doesn't fully validate serializable values
  • Doesn't fully restore serialized values (e.g RegExp missing lastIndex)

tRPC/tupleSON

https://github.com/trpc/tupleson

  • Relies on a nonce to prevent collisions
  • Doesn't support NaN or Infinity
  • Archived

ScaleForge/joser

https://github.com/ScaleForge/joser

  • Relies on a nonce to prevent collisions
  • Only supports class types, that must be in global scope
  • Doesn't fully validate serializable values

tosource

https://github.com/marcello3d/node-tosource

  • Non JSON output
  • Not extendable
  • Doesn't fully validate serializable values (by design, e.g. attempts to serialize functions with toString)

serialize-javascript

https://github.com/yahoo/serialize-javascript

  • Creates a JS script requiring dangerous eval

Lave

https://github.com/jed/lave

  • Creates a JS script requiring dangerous eval
  • Archived
3.0.2

4 months ago

3.0.1

4 months ago

3.0.0

4 months ago

2.0.0

4 months ago

1.0.4

4 months ago

1.0.3

4 months ago

1.0.2

4 months ago

1.0.1

4 months ago

1.0.0

4 months ago