@bjesuiter/serializr-helpers
Version:
Provides some helper functions and serialization PropertySchemas for mobxjs/serializr - library
91 lines (90 loc) • 4.4 kB
JavaScript
/**
* This serializr PropertySchema can be used with @serializable(MomentSerializationSchema)
* to make moment.js Moment objects serializable
* @type {PropSchema}
*/
import { custom, SKIP } from 'serializr';
import moment from 'moment';
import { MomentSerializationDefaults } from "./moment-serialization-options";
import { log } from "./logger";
export function buildSerializer(valueIfUndefined, useUtc = false, serializationFormat = 'ISO') {
return (value) => {
//value.format is used here to output a datetime with attached offset to utc
//value.toJson would normalize the output to utc,
// which would make it impossible to reconstruct the original timezone
// intended use of == vs. === to include null when checking for undefined
if (value == undefined) {
if (!moment.isMoment(valueIfUndefined)) {
// Moment object will be skipped in serialization if no default value is set
// or json-compatible default value will be returned
return (valueIfUndefined) ? valueIfUndefined : SKIP;
}
else {
// default value is a moment object => serialize as normal moment object
value = valueIfUndefined;
}
}
if (serializationFormat === 'ISO') {
// see documentation for toISO String for keepOffset explanation:
// https://momentjs.com/docs/#/displaying/as-iso-string/
return (useUtc) ? value.toISOString() : value.toISOString(true);
}
value = (useUtc) ? value.utc() : value;
return value.format(serializationFormat);
};
}
export function validateDefaultDeserializeValue(defaultRestoreValue) {
if (!defaultRestoreValue.isValid()) {
throw new Error(`Default Moment deserialization value is invalid. ` +
`Got input string "${defaultRestoreValue.creationData().input}"`);
}
return true;
}
export function buildDeserializer(handleErrorPolicy = 'log-error', useUtc = false, defaultRestoreValue, logger) {
return (jsonValue, callback, context) => {
// const isoFormat = 'YYYY-MM-DDTHH:mm:ss.sssZZ';
// const isoUtcFormat = 'YYYY-MM-DDTHH:mm:ss.sssZ';
//Note: passing the iso format avoids deprecation notices about format detection
let restoredMoment = (useUtc) ? moment.utc(jsonValue) : moment(jsonValue);
if (logger === undefined) {
logger = log;
}
if (!restoredMoment.isValid()) {
if (defaultRestoreValue !== undefined && validateDefaultDeserializeValue(defaultRestoreValue)) {
// set the error Policy to silent when default value for decode was set explicitly.
handleErrorPolicy = 'silent';
restoredMoment = defaultRestoreValue;
}
const errorText = `Moment js serialized json value is invalid!
Got the value "${jsonValue}" which does not decode into a valid Moment object.
You can change the handling of this message by setting the 'deserializationErrorPolicy' in
MomentSerializationOptions`;
switch (handleErrorPolicy) {
case "throw":
throw new Error(errorText);
case "log-error":
logger.error(errorText);
break;
case "log-warn":
logger.warn(errorText);
break;
case "silent":
break;
}
}
return restoredMoment;
};
}
/**
* This factory function returns a serialization schema for Moment objects.
*
* @default The default schema skips undefined moment objects in serialization and
* keeps timezone offset while serialization and deserialization.
* This differs from default moment.toIsoString() behavior, which converts local timestamps (with like +02:00 offset)
* to UTC in serialization (Strings with Z as offset)
* @param options
* @constructor
*/
export function MomentSerializationSchema(options = MomentSerializationDefaults) {
return custom(buildSerializer(options.valueIfUndefined, options.useUtc, options.serializationFormat), buildDeserializer(options.deserializationErrorPolicy, options.useUtc, options.deserializationDefault));
}