typescript-json-serializer
Advanced tools
Comparing version 3.4.5 to 4.0.0
@@ -0,1 +1,37 @@ | ||
<a name="4.0.0"></a> | ||
# 4.0.0 (2022-02-15) | ||
New major version comes with lot of breaking changes detailed below. | ||
The purpose was to reorganize the entire project, write more tests and above all improve the usage of the library. | ||
Check the new [README](./README.md) to understand how to use `typescript-json-serializer` now. | ||
### BREAKING CHANGES | ||
- `Serializable`: | ||
- the decorator was renamed to `JsonObject` to be more consistent | ||
- `formatPropertyNames` option has been moved to the new `JsonSerializerOptions` class. | ||
- `JsonProperty`: | ||
- `predicate` argument has been removed, now you can use the `type` argument | ||
- `names` argument has been removed, now you can use the `name` argument | ||
- `serialize` function has been moved to the new `JsonSerializer` class | ||
- `deserialize` function has been moved to the new `JsonSerializer` class | ||
### Build | ||
- replace `tsc` by `rollup` for types generation ([ca9f08](https://github.com/GillianPerard/typescript-json-serializer/commit/ca9f0829f557caeb35442abbd3169944edb71ceb)) | ||
- bump `tmpl` from version 1.0.4 to 1.0.5 | ||
### Features | ||
- **JsonSerializer**: new class was added to handle all the logic about serialization and deserialization ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
- **JsonSerializerOptions**: new class was added to handle all the `JsonSerializer` options as ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
- **errorCallback**: callback you can define to handle the errors, by default the library comes with 2 predefined callback `logError` and `throwError` but you can define your own | ||
- **nullishPolicy**: object to define what is the policy when the algorithm meet a `null` or an `undefined` value, the 3 choices are `allow`, `disallow` and `remove` | ||
- **formatPropertyName**: this option has been moved from `Serializable` decorator and keep the same behavior | ||
- **serializeObject**: new method added to `JsonSerializer` to serialize object only ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
- **serializeObjectArray**: new method added to `JsonSerializer` to serialize object object array only ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
- **deserializeObject**: new method added to `JsonSerializer` to deserialize object only ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
- **deserializeObjectArray**: new method added to `JsonSerializer` to deserialize object object array only ([bcc49e](https://github.com/GillianPerard/typescript-json-serializer/commit/bcc49e118e21d37f332dc6657ab94b8e25564b05)) | ||
<a name="3.4.5"></a> | ||
@@ -2,0 +38,0 @@ # 3.4.5 (2022-01-07) |
@@ -1,1 +0,1 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib");require("reflect-metadata");var r,t="api:map:";!function(e){e.Array="array",e.Boolean="boolean",e.Date="date",e.Number="number",e.Object="object",e.String="string"}(r||(r={}));var a=function(r){var t=Reflect.getPrototypeOf(r);return t&&t.name?e.__spreadArray(e.__spreadArray([],a(t)),[t.name]):[]},n=function(e,r){return e.map((function(e){return Reflect.getMetadata(""+t+e,r)}))},i=function(){for(var r=[],t=0;t<arguments.length;t++)r[t]=arguments[t];var a={};return r.forEach((function(r){r&&Object.keys(r).forEach((function(t){a[t]=e.__assign(e.__assign({},a[t]),r[t])}))})),a},o=function(a,o){var s;if([null,void 0].includes(a))return a;if(void 0===o)return p(typeof a,a);typeof a===r.String&&(a=JSON.parse(a));var c=new o({}),u=c.constructor.name,l=null!==(s=Reflect.getMetadata("api:map:serializable",o))&&void 0!==s?s:{},d=l.baseClassNames,v=l.options,y=""+t+u,m=Reflect.hasMetadata(y,c),g={};if(!(m||d&&d.length))return c;if(g=Reflect.getMetadata(y,c),d&&d.length){var b=n(d,c);g=i.apply(void 0,e.__spreadArray(e.__spreadArray([],b),[g]))}return Object.keys(g).forEach((function(e){var r=f(c,e,g[e],a,null==v?void 0:v.formatPropertyNames);if(null==r&&g[e].required)throw new Error("Property '"+e+"' is required in "+u+" "+JSON.stringify(a)+".");void 0!==r&&(c[e]=r)})),c},s=function(a,o){var s;if(void 0===o&&(o=!0),[void 0,null].includes(a)||typeof a!==r.Object)return a;var f=a.constructor.name,u=""+t+f,l=null!==(s=Reflect.getMetadata("api:map:serializable",a.constructor))&&void 0!==s?s:{},p=l.baseClassNames,d=l.options,v=p&&p.length,y=Reflect.hasMetadata(u,a),m={};if(!y&&!v)return a;if(m=Reflect.getMetadata(u,a),v){var g=n(p,a);m=i.apply(void 0,e.__spreadArray(e.__spreadArray([],g),[m]))}var b={},O=Object.keys(a);return Object.keys(m).forEach((function(e){if(O.includes(e)){var r=m[e],t=r.beforeSerialize,n=r.afterSerialize,i=void 0;t&&(i=a[e],a[e]=t(a[e],a));var s=c(a,e,r,o);if(n&&(s=n(s,a)),a[e]=i||a[e],r.names)r.names.forEach((function(e){(!o||o&&void 0!==s[e])&&(b[e]=s[e])}));else if(!o||o&&void 0!==s)if(!r.isNameOverridden&&(null==d?void 0:d.formatPropertyNames)){var f=d.formatPropertyNames(r.name);b[f]=s}else b[r.name]=s}})),b},c=function(e,t,a,n){var i=e[t],o=Reflect.getMetadata("design:type",e,t),c=!!o.name&&o.name.toLocaleLowerCase()===r.Array,f=a.predicate,l=a.type||o,p=u(l);if(i&&(p||f)){if(c)return i.map((function(e){return s(e,n)}));if(a.isDictionary){var d={};return Object.keys(i).forEach((function(e){d[e]=s(i[e],n)})),d}return s(i,n)}return l.name.toLocaleLowerCase()===r.Date&&typeof i===r.Object?i.toISOString():i},f=function(e,t,a,n,i){var s;if([null,void 0].includes(n))return n;if("names"in a){var c={};a.names.forEach((function(e){return c[e]=n[e]})),s=c}else if("name"in a&&!a.isNameOverridden&&i){var f=i(a.name);s=n[f]}else s=n[a.name];if([null,void 0].includes(s))return s;var l,d=Reflect.getMetadata("design:type",e,t),v=!!d.name&&d.name.toLowerCase()===r.Array,y=a.isDictionary,m=a.predicate,g=a.beforeDeserialize,b=a.afterDeserialize,O=a.type||d,h=u(O);if(g&&(s=g(s,e)),y){var N={};typeof s!==r.Object?(console.error("Type '"+typeof s+"' is not assignable to type 'Dictionary' for property '"+t+"' in '"+e.constructor.name+"'.\n","Received: "+JSON.stringify(s)),l=void 0):(Object.keys(s).forEach((function(r){h||m?(m&&(O=m(s[r],s)),N[r]=o(s[r],O)):N[r]=p(typeof s[r],s[r],t,e.constructor.name)})),l=N)}else if(v){var S=[];Array.isArray(s)?(s.forEach((function(r){h||m?(m&&(O=m(r,s)),S.push(o(r,O))):S.push(p(typeof r,r,t,e.constructor.name))})),l=S):(console.error("Type '"+typeof s+"' is not assignable to type 'Array' for property '"+t+"' in '"+e.constructor.name+"'.\n","Received: "+JSON.stringify(s)),l=void 0)}else h||m?(O=m?m(s,n):O,l=o(s,O)):l=p(O.name,s,t,e.constructor.name);return b&&(l=b(l,e)),l},u=function(e){return Reflect.hasOwnMetadata("api:map:serializable",e)},l=function(e,t){if(!t)return{name:e.toString(),isNameOverridden:!1};var a;a=typeof t===r.String?{name:t,isNameOverridden:!0}:t.name?{name:t.name,isNameOverridden:!0}:t.names&&t.names.length?{names:t.names}:{name:e.toString(),isNameOverridden:!1};return["isDictionary","required","beforeSerialize","afterSerialize","beforeDeserialize","afterDeserialize"].forEach((function(e){void 0!==t[e]&&null!==t[e]&&(a[e]=t[e])})),t.predicate?a.predicate=t.predicate:t.type&&(a.type=t.type),a},p=function(e,t,a,n){if(null==e)return t;if(e=e.toLowerCase(),(typeof t).toLowerCase()===e)return t;var i=function(){console.error("Type '"+typeof t+"' is not assignable to type '"+e+"' for property '"+a+"' in '"+n+"'.\n","Received: "+JSON.stringify(t))};switch(e){case r.String:var o=t.toString();return"[object Object]"===o?void i():o;case r.Number:var s=+t;return isNaN(s)?void i():s;case r.Boolean:return void i();case r.Date:return isNaN(Date.parse(t))?void i():new Date(t);default:return t}};exports.JsonProperty=function(e){return function(r,a,n){if(void 0===a&&r.prototype){var i=Reflect.getMetadata("design:paramtypes",r)[n];a=function(e){var r=e.toString().split("}")[0].replace(/(\/\*[\s\S]*?\*\/|\/\/.*$)/gm,"").replace(/[\r\t\n\v\f ]/g,""),t=/(?:this\.)([^,;\n}]+)/gm,a=new Map,n=/(?:.*(?:constructor|function).*?(?=\())(?:\()(.+?(?=\)))/m.exec(r);if(!n||!n.length)return a;for(var i,o=n[1].split(","),s=function(){var e=i[1].split("="),r=o.findIndex((function(r){return r===e[1]}));r>-1&&a.set(r,e[0])};i=t.exec(r);)s();return a}(r.prototype.constructor).get(n),r=r.prototype,Reflect.defineMetadata("design:type",i,r,a)}var o={},s=r.constructor.name,c=""+t+s;Reflect.hasMetadata(c,r)&&(o=Reflect.getMetadata(c,r)),o[a]=l(a,e),Reflect.defineMetadata(c,o,r)}},exports.Serializable=function(e){return function(r){var t=a(r);Reflect.defineMetadata("api:map:serializable",{baseClassNames:t,options:e},r)}},exports.deserialize=o,exports.serialize=s; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib");require("reflect-metadata");var t=function(){function e(){}return e.getBaseClass=function(e){return e?Reflect.getPrototypeOf(e):void 0},e.getJsonPropertiesMetadata=function(t,r){if(t){var i=""+e.apiMap+(r||t.constructor.name);return Reflect.getMetadata(i,t)}},e.getParamTypes=function(t){return t?Reflect.getMetadata(e.designParamTypes,t):void 0},e.getJsonObjectMetadata=function(t){return t?Reflect.getMetadata(e.apiMapJsonObject,t):void 0},e.getType=function(t,r){return t?Reflect.getMetadata(e.designType,t,r):void 0},e.isJsonObject=function(t){return!!t&&Reflect.hasOwnMetadata(e.apiMapJsonObject,t)},e.setJsonPropertiesMetadata=function(t,r){if(r){var i=""+e.apiMap+r.constructor.name;Reflect.defineMetadata(i,t,r)}},e.setJsonObject=function(t,r){r&&Reflect.defineMetadata(e.apiMapJsonObject,t,r)},e.setType=function(t,r,i){r&&t&&Reflect.defineMetadata(e.designType,t,r,i)},e.apiMap="api:map:",e.apiMapJsonObject=e.apiMap+"jsonObject",e.designType="design:type",e.designParamTypes="design:paramtypes",e}(),r=function(e){return"string"==typeof e},i=function(e){return null!==e&&"object"==typeof e&&!n(e)},n=function(e){return Array.isArray(e)},o=function(e){return"[object Date]"===toString.call(e)},a=function(e){return[null,void 0].includes(e)},s=function(e){return t.isJsonObject(e)},l=function(e){try{var t=JSON.parse(e);return"object"==typeof t?t:e}catch(t){return e}},u=function(){this.errorCallback=c,this.nullishPolicy={undefined:"remove",null:"allow"}},c=function(e){console.error(e)},p=function(){function c(t){this.options=new u,this.options=e.__assign(e.__assign({},this.options),t)}return c.prototype.deserialize=function(e,t){return r(e)&&(e=l(e)),n(e)?this.deserializeObjectArray(e,t):i(e)?this.deserializeObject(e,t):void this.error("Fail to deserialize: value is not an Array nor an Object.\nReceived: "+JSON.stringify(e)+".")},c.prototype.deserializeObject=function(e,t){var n=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to deserialize: null is not assignable to type Object."),null;if(void 0!==e){if(r(e)&&(e=l(e)),i(e)){var o=new t({}),s=this.getJsonPropertiesMetadata(o);return s?(Object.keys(s).forEach((function(t){var r=s[t],i=n.deserializeProperty(o,t,e,r);if(r.required&&a(i)){var l=o.constructor.name;n.error("Property '"+t+"' is required in "+l+" "+JSON.stringify(e)+".")}n.isAllowedProperty(i)&&(o[t]=i)})),o):o}this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Object'.\nReceived: "+JSON.stringify(e))}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to deserialize: undefined is not assignable to type Object.")},c.prototype.deserializeObjectArray=function(e,t){var i=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to deserialize: null is not assignable to type Array."),null;if(void 0!==e){if(r(e)&&(e=l(e)),n(e))return e.map((function(e){return i.deserializeObject(e,t)}));this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e))}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to deserialize: undefined is not assignable to type Array.")},c.prototype.serialize=function(e){return n(e)?this.serializeObjectArray(e):i(e)?this.serializeObject(e):void this.error("Fail to serialize: value is not an Array nor an Object.\nReceived: "+JSON.stringify(e)+".")},c.prototype.serializeObject=function(e){var t=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to serialize: null is not assignable to type Object."),null;if(void 0!==e){if(!i(e))return e;var r=this.getJsonPropertiesMetadata(e);if(!r)return e;var o={},a=Object.keys(e);return Object.keys(r).forEach((function(i){if(a.includes(i)){var s=r[i],l=void 0;s.beforeSerialize&&(l=e[i],e[i]=s.beforeSerialize(e[i],e));var u=t.serializeProperty(e,i,s);if(s.afterSerialize&&(u=s.afterSerialize(u,e)),e[i]=l||e[i],n(s.name))s.name.forEach((function(e){t.isAllowedProperty(u[e])&&(o[e]=u[e])}));else if(t.isAllowedProperty(u))if(s.isNameOverridden||void 0===t.options.formatPropertyName)o[s.name]=u;else{var c=t.options.formatPropertyName(s.name);o[c]=u}}})),o}"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to serialize: undefined is not assignable to type Object.")},c.prototype.serializeObjectArray=function(e){var t=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to serialize: null is not assignable to type Array."),null;if(void 0!==e){if(n(e))return e.map((function(e){return t.serializeObject(e)}));this.error("Fail to serialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e)+".")}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to serialize: undefined is not assignable to type Array.")},c.prototype.deserializeProperty=function(e,r,i,n){var o;if(!a(i)){var l=this.getDataSource(i,n,this.options.formatPropertyName);if(a(l))return l;var u,c=t.getType(e,r),p="array"===(null===(o=null==c?void 0:c.name)||void 0===o?void 0:o.toLowerCase()),f=n.type||c;n.beforeDeserialize&&(l=n.beforeDeserialize(l,e));var d=n.predicate;return n.isDictionary?u=this.deserializeDictionary(l,f,d):p?u=this.deserializeArray(l,f,d):!s(f)&&!d||d&&!d(l,i)?u=this.deserializePrimitive(l,f.name):(f=n.predicate?n.predicate(l,i):f,u=this.deserializeObject(l,f)),n.afterDeserialize&&(u=n.afterDeserialize(u,e)),u}},c.prototype.deserializePrimitive=function(e,t){if(a(t))return e;if(typeof e===(t=t.toLowerCase()))return e;var r="Fail to deserialize: type '"+typeof e+"' is not assignable to type '"+t+"'.\nReceived: "+JSON.stringify(e);switch(t){case"string":var i=e.toString();return"[object Object]"===i?void this.error(r):i;case"number":return function(e){return"number"==typeof e}(e)?+e:void this.error(r);case"boolean":return void this.error(r);case"date":return function(e){return!o(e)&&!n(e)&&!isNaN(Date.parse(e))}(e)?new Date(e):void this.error(r);default:return e}},c.prototype.deserializeDictionary=function(e,t,r){var n=this;if(i(e)){var o={};return Object.keys(e).forEach((function(i){var a=r?r(e[i],e):void 0;s(t)||a?o[i]=n.deserializeObject(e[i],a||t):o[i]=n.deserializePrimitive(e[i],typeof e[i])})),o}this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Dictionary'.\nReceived: "+JSON.stringify(e)+".")},c.prototype.deserializeArray=function(e,t,r){var i=this;if(n(e))return e.map((function(n){return s(t)||r?(t=r?r(n,e):t,i.deserializeObject(n,t)):i.deserializePrimitive(n,typeof n)}));this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e))},c.prototype.error=function(e){this.options.errorCallback&&this.options.errorCallback(e)},c.prototype.getClassesJsonPropertiesMetadata=function(e,r){return e?e.reduce((function(e,i){var n=t.getJsonPropertiesMetadata(r,i);return n&&e.push(n),e}),[]):[]},c.prototype.getDataSource=function(e,t,r){var i=t.name,o=t.isNameOverridden;if(n(i)){var a={};return i.forEach((function(t){return a[t]=e[t]})),a}return!o&&r?(i=r(i),e[i]):e[i]},c.prototype.getJsonPropertiesMetadata=function(r){var i,n=(null!==(i=t.getJsonObjectMetadata(r.constructor))&&void 0!==i?i:{}).baseClassNames,o=t.getJsonPropertiesMetadata(r);if(!(o||n&&n.length))return o;if(n&&n.length){var a=this.getClassesJsonPropertiesMetadata(n,r);return this.mergeJsonPropertiesMetadata.apply(this,e.__spreadArray(e.__spreadArray([],a),[o]))}return o},c.prototype.isAllowedProperty=function(e){if(a(e)){if("disallow"===this.options.nullishPolicy[""+e])return this.error("Disallowed "+e+" value detected."),!1;if("remove"===this.options.nullishPolicy[""+e])return!1}return!0},c.prototype.mergeJsonPropertiesMetadata=function(){for(var t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];var i={};return t.forEach((function(t){t&&Object.keys(t).forEach((function(r){i[r]=e.__assign(e.__assign({},i[r]),t[r])}))})),i},c.prototype.serializeDictionary=function(e){var t=this;if(i(e)){var r={};return Object.keys(e).forEach((function(i){r[i]=t.serializeObject(e[i])})),r}this.error("Fail to serialize: type '"+typeof e+"' is not assignable to type 'Dictionary'.\nReceived: "+JSON.stringify(e)+".")},c.prototype.serializeProperty=function(e,r,i){var n,a,l=e[r],u=t.getType(e,r),c="array"===(null===(n=null==u?void 0:u.name)||void 0===n?void 0:n.toLocaleLowerCase()),p=i.predicate,f=i.type||u,d=s(f);return l&&(d||p)?c?this.serializeObjectArray(l):i.isDictionary?this.serializeDictionary(l):this.serializeObject(l):"date"===(null===(a=null==f?void 0:f.name)||void 0===a?void 0:a.toLocaleLowerCase())&&o(l)?l.toISOString():l},c}(),f=function(r){var i=t.getBaseClass(r);return i&&i.name?e.__spreadArray(e.__spreadArray([],f(i)),[i.name]):[]},d=function(e){var t,r=e.toString().split("}")[0].replace(/(\/\*[\s\S]*?\*\/|\/\/.*$)/gm,"").replace(/[\r\t\n\v\f ]/g,""),i=r.length;","===r[i-2]&&(t=r[i-1]);var n=t?new RegExp("(?:(this|"+t+"|\\("+t+"=t.call\\(this(,.)*\\)\\))\\.)([^,;\n}]+)","gm"):new RegExp("(?:(this)\\.)([^,;\n}]+)","gm"),o=new Map,a=/(?:.*(?:constructor|function).*?(?=\())(?:\()(.+?(?=\)))/m.exec(r);if(!a||!a.length)return o;for(var s,l=a[1].split(","),u=function(){var e=s.length-1,t=s[e].split("="),r=l.findIndex((function(e){return e===t[1]}));r>-1&&o.set(r,t[0])};s=n.exec(r);)u();return o},y=function(n,o){var a={name:n.toString()};return o?r(o)?(a.name=o,a.isNameOverridden=!0,a):(i(o)&&(a=e.__assign(e.__assign({},a),o),o.name&&(a.name=o.name,a.isNameOverridden=!0),function(e){if(!e)return!1;var r=t.getParamTypes(e),i=e.length;return(1===i||2===i)&&!r}(o.type)&&(delete a.type,a.predicate=o.type)),a):a};exports.JsonObject=function(){return function(e){var r=f(e);t.setJsonObject({baseClassNames:r},e)}},exports.JsonProperty=function(e){return function(r,i,n){var o;if(void 0===i&&r.prototype){var a=t.getParamTypes(r)[n];i=d(r.prototype.constructor).get(n),r=r.prototype,t.setType(a,r,i)}var s=null!==(o=t.getJsonPropertiesMetadata(r))&&void 0!==o?o:{};s[i]=y(i,e),t.setJsonPropertiesMetadata(s,r)}},exports.JsonSerializer=p,exports.JsonSerializerOptions=u,exports.logError=c,exports.throwError=function(e){throw new Error(e)}; |
@@ -1,62 +0,4 @@ | ||
import 'reflect-metadata'; | ||
interface SerializableOptions { | ||
formatPropertyNames: FormatPropertyNameProto; | ||
} | ||
declare type IOProto = (property: any, currentInstance?: any) => any; | ||
declare type PredicateProto = (property: any, parentProperty?: any) => any; | ||
declare type FormatPropertyNameProto = (propertyName: string) => string; | ||
interface BeforeAfterProto { | ||
beforeSerialize?: IOProto; | ||
afterSerialize?: IOProto; | ||
beforeDeserialize?: IOProto; | ||
afterDeserialize?: IOProto; | ||
} | ||
declare type BaseMetadata = { | ||
required?: boolean; | ||
} & BeforeAfterProto; | ||
declare type Args = string | ({ | ||
name?: string; | ||
type?: Function; | ||
isDictionary?: boolean; | ||
} & BaseMetadata) | ({ | ||
name?: string; | ||
predicate?: PredicateProto; | ||
isDictionary?: boolean; | ||
} & BaseMetadata) | ({ | ||
names: Array<string>; | ||
type?: Function; | ||
} & BaseMetadata) | ({ | ||
names: Array<string>; | ||
predicate?: PredicateProto; | ||
} & BaseMetadata); | ||
/** | ||
* Decorator to take the property in account during the serialize and deserialize function | ||
* | ||
* @param {Args=} args Arguments to describe the property | ||
*/ | ||
export declare const JsonProperty: (args?: Args) => Function; | ||
/** | ||
* Decorator to make a class Serializable | ||
* | ||
* @param {{formatPropertyNames: FormatPropertyNameProto}=} options The options of the serializable class | ||
* | ||
* BREAKING CHANGE: Since version 2.0.0 the parameter `baseClassName` is not needed anymore | ||
*/ | ||
export declare const Serializable: (options?: SerializableOptions) => Function; | ||
/** | ||
* Function to deserialize json into a class | ||
* | ||
* @param {object} json The json to deserialize | ||
* @param {new (...params: Array<any>) => T} type The class in which we want to deserialize | ||
* @returns {T} The instance of the specified type containing all deserialized properties | ||
*/ | ||
export declare const deserialize: <T>(json: any, type: new (...params: Array<any>) => T) => T; | ||
/** | ||
* Function to serialize a class into json | ||
* | ||
* @param {any} instance Instance of the object to deserialize | ||
* @param {boolean} removeUndefined Indicates if you want to keep or remove undefined values | ||
* @returns {any} The json object | ||
*/ | ||
export declare const serialize: (instance: any, removeUndefined?: boolean) => any; | ||
export {}; | ||
export { JsonSerializer } from './json-serializer'; | ||
export { ErrorCallback, FormatPropertyNameProto, JsonSerializerOptions, NullishPolicy, Policy, logError, throwError } from './json-serializer-options'; | ||
export { JsonObject, JsonObjectMetadata } from './json-object'; | ||
export { JsonProperty } from './json-property'; |
@@ -1,1 +0,1 @@ | ||
import{__spreadArray as e,__assign as t}from"tslib";import"reflect-metadata";var r,a="api:map:";!function(e){e.Array="array",e.Boolean="boolean",e.Date="date",e.Number="number",e.Object="object",e.String="string"}(r||(r={}));var n=function(t){var r=Reflect.getPrototypeOf(t);return r&&r.name?e(e([],n(r)),[r.name]):[]},i=function(e){return function(t,r,n){if(void 0===r&&t.prototype){var i=Reflect.getMetadata("design:paramtypes",t)[n];r=function(e){var t=e.toString().split("}")[0].replace(/(\/\*[\s\S]*?\*\/|\/\/.*$)/gm,"").replace(/[\r\t\n\v\f ]/g,""),r=/(?:this\.)([^,;\n}]+)/gm,a=new Map,n=/(?:.*(?:constructor|function).*?(?=\())(?:\()(.+?(?=\)))/m.exec(t);if(!n||!n.length)return a;for(var i,o=n[1].split(","),c=function(){var e=i[1].split("="),t=o.findIndex((function(t){return t===e[1]}));t>-1&&a.set(t,e[0])};i=r.exec(t);)c();return a}(t.prototype.constructor).get(n),t=t.prototype,Reflect.defineMetadata("design:type",i,t,r)}var o={},c=t.constructor.name,f=""+a+c;Reflect.hasMetadata(f,t)&&(o=Reflect.getMetadata(f,t)),o[r]=m(r,e),Reflect.defineMetadata(f,o,t)}},o=function(e){return function(t){var r=n(t);Reflect.defineMetadata("api:map:serializable",{baseClassNames:r,options:e},t)}},c=function(e,t){return e.map((function(e){return Reflect.getMetadata(""+a+e,t)}))},f=function(){for(var e=[],r=0;r<arguments.length;r++)e[r]=arguments[r];var a={};return e.forEach((function(e){e&&Object.keys(e).forEach((function(r){a[r]=t(t({},a[r]),e[r])}))})),a},s=function(t,n){var i;if([null,void 0].includes(t))return t;if(void 0===n)return v(typeof t,t);typeof t===r.String&&(t=JSON.parse(t));var o=new n({}),s=o.constructor.name,u=null!==(i=Reflect.getMetadata("api:map:serializable",n))&&void 0!==i?i:{},l=u.baseClassNames,d=u.options,m=""+a+s,y=Reflect.hasMetadata(m,o),g={};if(!(y||l&&l.length))return o;if(g=Reflect.getMetadata(m,o),l&&l.length){var b=c(l,o);g=f.apply(void 0,e(e([],b),[g]))}return Object.keys(g).forEach((function(e){var r=p(o,e,g[e],t,null==d?void 0:d.formatPropertyNames);if(null==r&&g[e].required)throw new Error("Property '"+e+"' is required in "+s+" "+JSON.stringify(t)+".");void 0!==r&&(o[e]=r)})),o},u=function(t,n){var i;if(void 0===n&&(n=!0),[void 0,null].includes(t)||typeof t!==r.Object)return t;var o=t.constructor.name,s=""+a+o,u=null!==(i=Reflect.getMetadata("api:map:serializable",t.constructor))&&void 0!==i?i:{},p=u.baseClassNames,d=u.options,m=p&&p.length,v=Reflect.hasMetadata(s,t),y={};if(!v&&!m)return t;if(y=Reflect.getMetadata(s,t),m){var g=c(p,t);y=f.apply(void 0,e(e([],g),[y]))}var b={},h=Object.keys(t);return Object.keys(y).forEach((function(e){if(h.includes(e)){var r=y[e],a=r.beforeSerialize,i=r.afterSerialize,o=void 0;a&&(o=t[e],t[e]=a(t[e],t));var c=l(t,e,r,n);if(i&&(c=i(c,t)),t[e]=o||t[e],r.names)r.names.forEach((function(e){(!n||n&&void 0!==c[e])&&(b[e]=c[e])}));else if(!n||n&&void 0!==c)if(!r.isNameOverridden&&(null==d?void 0:d.formatPropertyNames)){var f=d.formatPropertyNames(r.name);b[f]=c}else b[r.name]=c}})),b},l=function(e,t,a,n){var i=e[t],o=Reflect.getMetadata("design:type",e,t),c=!!o.name&&o.name.toLocaleLowerCase()===r.Array,f=a.predicate,s=a.type||o,l=d(s);if(i&&(l||f)){if(c)return i.map((function(e){return u(e,n)}));if(a.isDictionary){var p={};return Object.keys(i).forEach((function(e){p[e]=u(i[e],n)})),p}return u(i,n)}return s.name.toLocaleLowerCase()===r.Date&&typeof i===r.Object?i.toISOString():i},p=function(e,t,a,n,i){var o;if([null,void 0].includes(n))return n;if("names"in a){var c={};a.names.forEach((function(e){return c[e]=n[e]})),o=c}else if("name"in a&&!a.isNameOverridden&&i){var f=i(a.name);o=n[f]}else o=n[a.name];if([null,void 0].includes(o))return o;var u,l=Reflect.getMetadata("design:type",e,t),p=!!l.name&&l.name.toLowerCase()===r.Array,m=a.isDictionary,y=a.predicate,g=a.beforeDeserialize,b=a.afterDeserialize,h=a.type||l,O=d(h);if(g&&(o=g(o,e)),m){var N={};typeof o!==r.Object?(console.error("Type '"+typeof o+"' is not assignable to type 'Dictionary' for property '"+t+"' in '"+e.constructor.name+"'.\n","Received: "+JSON.stringify(o)),u=void 0):(Object.keys(o).forEach((function(r){O||y?(y&&(h=y(o[r],o)),N[r]=s(o[r],h)):N[r]=v(typeof o[r],o[r],t,e.constructor.name)})),u=N)}else if(p){var R=[];Array.isArray(o)?(o.forEach((function(r){O||y?(y&&(h=y(r,o)),R.push(s(r,h))):R.push(v(typeof r,r,t,e.constructor.name))})),u=R):(console.error("Type '"+typeof o+"' is not assignable to type 'Array' for property '"+t+"' in '"+e.constructor.name+"'.\n","Received: "+JSON.stringify(o)),u=void 0)}else O||y?(h=y?y(o,n):h,u=s(o,h)):u=v(h.name,o,t,e.constructor.name);return b&&(u=b(u,e)),u},d=function(e){return Reflect.hasOwnMetadata("api:map:serializable",e)},m=function(e,t){if(!t)return{name:e.toString(),isNameOverridden:!1};var a;a=typeof t===r.String?{name:t,isNameOverridden:!0}:t.name?{name:t.name,isNameOverridden:!0}:t.names&&t.names.length?{names:t.names}:{name:e.toString(),isNameOverridden:!1};return["isDictionary","required","beforeSerialize","afterSerialize","beforeDeserialize","afterDeserialize"].forEach((function(e){void 0!==t[e]&&null!==t[e]&&(a[e]=t[e])})),t.predicate?a.predicate=t.predicate:t.type&&(a.type=t.type),a},v=function(e,t,a,n){if(null==e)return t;if(e=e.toLowerCase(),(typeof t).toLowerCase()===e)return t;var i=function(){console.error("Type '"+typeof t+"' is not assignable to type '"+e+"' for property '"+a+"' in '"+n+"'.\n","Received: "+JSON.stringify(t))};switch(e){case r.String:var o=t.toString();return"[object Object]"===o?void i():o;case r.Number:var c=+t;return isNaN(c)?void i():c;case r.Boolean:return void i();case r.Date:return isNaN(Date.parse(t))?void i():new Date(t);default:return t}};export{i as JsonProperty,o as Serializable,s as deserialize,u as serialize}; | ||
import{__spreadArray as e,__assign as t}from"tslib";import"reflect-metadata";var i=function(){function e(){}return e.getBaseClass=function(e){return e?Reflect.getPrototypeOf(e):void 0},e.getJsonPropertiesMetadata=function(t,i){if(t){var r=""+e.apiMap+(i||t.constructor.name);return Reflect.getMetadata(r,t)}},e.getParamTypes=function(t){return t?Reflect.getMetadata(e.designParamTypes,t):void 0},e.getJsonObjectMetadata=function(t){return t?Reflect.getMetadata(e.apiMapJsonObject,t):void 0},e.getType=function(t,i){return t?Reflect.getMetadata(e.designType,t,i):void 0},e.isJsonObject=function(t){return!!t&&Reflect.hasOwnMetadata(e.apiMapJsonObject,t)},e.setJsonPropertiesMetadata=function(t,i){if(i){var r=""+e.apiMap+i.constructor.name;Reflect.defineMetadata(r,t,i)}},e.setJsonObject=function(t,i){i&&Reflect.defineMetadata(e.apiMapJsonObject,t,i)},e.setType=function(t,i,r){i&&t&&Reflect.defineMetadata(e.designType,t,i,r)},e.apiMap="api:map:",e.apiMapJsonObject=e.apiMap+"jsonObject",e.designType="design:type",e.designParamTypes="design:paramtypes",e}(),r=function(e){return"string"==typeof e},n=function(e){return null!==e&&"object"==typeof e&&!o(e)},o=function(e){return Array.isArray(e)},a=function(e){return"[object Date]"===toString.call(e)},s=function(e){return[null,void 0].includes(e)},l=function(e){return i.isJsonObject(e)},u=function(e){try{var t=JSON.parse(e);return"object"==typeof t?t:e}catch(t){return e}},c=function(){this.errorCallback=f,this.nullishPolicy={undefined:"remove",null:"allow"}},p=function(e){throw new Error(e)},f=function(e){console.error(e)},d=function(){function p(e){this.options=new c,this.options=t(t({},this.options),e)}return p.prototype.deserialize=function(e,t){return r(e)&&(e=u(e)),o(e)?this.deserializeObjectArray(e,t):n(e)?this.deserializeObject(e,t):void this.error("Fail to deserialize: value is not an Array nor an Object.\nReceived: "+JSON.stringify(e)+".")},p.prototype.deserializeObject=function(e,t){var i=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to deserialize: null is not assignable to type Object."),null;if(void 0!==e){if(r(e)&&(e=u(e)),n(e)){var o=new t({}),a=this.getJsonPropertiesMetadata(o);return a?(Object.keys(a).forEach((function(t){var r=a[t],n=i.deserializeProperty(o,t,e,r);if(r.required&&s(n)){var l=o.constructor.name;i.error("Property '"+t+"' is required in "+l+" "+JSON.stringify(e)+".")}i.isAllowedProperty(n)&&(o[t]=n)})),o):o}this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Object'.\nReceived: "+JSON.stringify(e))}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to deserialize: undefined is not assignable to type Object.")},p.prototype.deserializeObjectArray=function(e,t){var i=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to deserialize: null is not assignable to type Array."),null;if(void 0!==e){if(r(e)&&(e=u(e)),o(e))return e.map((function(e){return i.deserializeObject(e,t)}));this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e))}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to deserialize: undefined is not assignable to type Array.")},p.prototype.serialize=function(e){return o(e)?this.serializeObjectArray(e):n(e)?this.serializeObject(e):void this.error("Fail to serialize: value is not an Array nor an Object.\nReceived: "+JSON.stringify(e)+".")},p.prototype.serializeObject=function(e){var t=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to serialize: null is not assignable to type Object."),null;if(void 0!==e){if(!n(e))return e;var i=this.getJsonPropertiesMetadata(e);if(!i)return e;var r={},a=Object.keys(e);return Object.keys(i).forEach((function(n){if(a.includes(n)){var s=i[n],l=void 0;s.beforeSerialize&&(l=e[n],e[n]=s.beforeSerialize(e[n],e));var u=t.serializeProperty(e,n,s);if(s.afterSerialize&&(u=s.afterSerialize(u,e)),e[n]=l||e[n],o(s.name))s.name.forEach((function(e){t.isAllowedProperty(u[e])&&(r[e]=u[e])}));else if(t.isAllowedProperty(u))if(s.isNameOverridden||void 0===t.options.formatPropertyName)r[s.name]=u;else{var c=t.options.formatPropertyName(s.name);r[c]=u}}})),r}"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to serialize: undefined is not assignable to type Object.")},p.prototype.serializeObjectArray=function(e){var t=this;if(null===e)return"disallow"===this.options.nullishPolicy.null&&this.error("Fail to serialize: null is not assignable to type Array."),null;if(void 0!==e){if(o(e))return e.map((function(e){return t.serializeObject(e)}));this.error("Fail to serialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e)+".")}else"disallow"===this.options.nullishPolicy.undefined&&this.error("Fail to serialize: undefined is not assignable to type Array.")},p.prototype.deserializeProperty=function(e,t,r,n){var o;if(!s(r)){var a=this.getDataSource(r,n,this.options.formatPropertyName);if(s(a))return a;var u,c=i.getType(e,t),p="array"===(null===(o=null==c?void 0:c.name)||void 0===o?void 0:o.toLowerCase()),f=n.type||c;n.beforeDeserialize&&(a=n.beforeDeserialize(a,e));var d=n.predicate;return n.isDictionary?u=this.deserializeDictionary(a,f,d):p?u=this.deserializeArray(a,f,d):!l(f)&&!d||d&&!d(a,r)?u=this.deserializePrimitive(a,f.name):(f=n.predicate?n.predicate(a,r):f,u=this.deserializeObject(a,f)),n.afterDeserialize&&(u=n.afterDeserialize(u,e)),u}},p.prototype.deserializePrimitive=function(e,t){if(s(t))return e;if(typeof e===(t=t.toLowerCase()))return e;var i="Fail to deserialize: type '"+typeof e+"' is not assignable to type '"+t+"'.\nReceived: "+JSON.stringify(e);switch(t){case"string":var r=e.toString();return"[object Object]"===r?void this.error(i):r;case"number":return function(e){return"number"==typeof e}(e)?+e:void this.error(i);case"boolean":return void this.error(i);case"date":return function(e){return!a(e)&&!o(e)&&!isNaN(Date.parse(e))}(e)?new Date(e):void this.error(i);default:return e}},p.prototype.deserializeDictionary=function(e,t,i){var r=this;if(n(e)){var o={};return Object.keys(e).forEach((function(n){var a=i?i(e[n],e):void 0;l(t)||a?o[n]=r.deserializeObject(e[n],a||t):o[n]=r.deserializePrimitive(e[n],typeof e[n])})),o}this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Dictionary'.\nReceived: "+JSON.stringify(e)+".")},p.prototype.deserializeArray=function(e,t,i){var r=this;if(o(e))return e.map((function(n){return l(t)||i?(t=i?i(n,e):t,r.deserializeObject(n,t)):r.deserializePrimitive(n,typeof n)}));this.error("Fail to deserialize: type '"+typeof e+"' is not assignable to type 'Array'.\nReceived: "+JSON.stringify(e))},p.prototype.error=function(e){this.options.errorCallback&&this.options.errorCallback(e)},p.prototype.getClassesJsonPropertiesMetadata=function(e,t){return e?e.reduce((function(e,r){var n=i.getJsonPropertiesMetadata(t,r);return n&&e.push(n),e}),[]):[]},p.prototype.getDataSource=function(e,t,i){var r=t.name,n=t.isNameOverridden;if(o(r)){var a={};return r.forEach((function(t){return a[t]=e[t]})),a}return!n&&i?(r=i(r),e[r]):e[r]},p.prototype.getJsonPropertiesMetadata=function(t){var r,n=(null!==(r=i.getJsonObjectMetadata(t.constructor))&&void 0!==r?r:{}).baseClassNames,o=i.getJsonPropertiesMetadata(t);if(!(o||n&&n.length))return o;if(n&&n.length){var a=this.getClassesJsonPropertiesMetadata(n,t);return this.mergeJsonPropertiesMetadata.apply(this,e(e([],a),[o]))}return o},p.prototype.isAllowedProperty=function(e){if(s(e)){if("disallow"===this.options.nullishPolicy[""+e])return this.error("Disallowed "+e+" value detected."),!1;if("remove"===this.options.nullishPolicy[""+e])return!1}return!0},p.prototype.mergeJsonPropertiesMetadata=function(){for(var e=[],i=0;i<arguments.length;i++)e[i]=arguments[i];var r={};return e.forEach((function(e){e&&Object.keys(e).forEach((function(i){r[i]=t(t({},r[i]),e[i])}))})),r},p.prototype.serializeDictionary=function(e){var t=this;if(n(e)){var i={};return Object.keys(e).forEach((function(r){i[r]=t.serializeObject(e[r])})),i}this.error("Fail to serialize: type '"+typeof e+"' is not assignable to type 'Dictionary'.\nReceived: "+JSON.stringify(e)+".")},p.prototype.serializeProperty=function(e,t,r){var n,o,s=e[t],u=i.getType(e,t),c="array"===(null===(n=null==u?void 0:u.name)||void 0===n?void 0:n.toLocaleLowerCase()),p=r.predicate,f=r.type||u,d=l(f);return s&&(d||p)?c?this.serializeObjectArray(s):r.isDictionary?this.serializeDictionary(s):this.serializeObject(s):"date"===(null===(o=null==f?void 0:f.name)||void 0===o?void 0:o.toLocaleLowerCase())&&a(s)?s.toISOString():s},p}(),y=function(t){var r=i.getBaseClass(t);return r&&r.name?e(e([],y(r)),[r.name]):[]},v=function(){return function(e){var t=y(e);i.setJsonObject({baseClassNames:t},e)}},h=function(e){return function(t,r,n){var o;if(void 0===r&&t.prototype){var a=i.getParamTypes(t)[n];r=g(t.prototype.constructor).get(n),t=t.prototype,i.setType(a,t,r)}var s=null!==(o=i.getJsonPropertiesMetadata(t))&&void 0!==o?o:{};s[r]=b(r,e),i.setJsonPropertiesMetadata(s,t)}},g=function(e){var t,i=e.toString().split("}")[0].replace(/(\/\*[\s\S]*?\*\/|\/\/.*$)/gm,"").replace(/[\r\t\n\v\f ]/g,""),r=i.length;","===i[r-2]&&(t=i[r-1]);var n=t?new RegExp("(?:(this|"+t+"|\\("+t+"=t.call\\(this(,.)*\\)\\))\\.)([^,;\n}]+)","gm"):new RegExp("(?:(this)\\.)([^,;\n}]+)","gm"),o=new Map,a=/(?:.*(?:constructor|function).*?(?=\())(?:\()(.+?(?=\)))/m.exec(i);if(!a||!a.length)return o;for(var s,l=a[1].split(","),u=function(){var e=s.length-1,t=s[e].split("="),i=l.findIndex((function(e){return e===t[1]}));i>-1&&o.set(i,t[0])};s=n.exec(i);)u();return o},b=function(e,o){var a={name:e.toString()};return o?r(o)?(a.name=o,a.isNameOverridden=!0,a):(n(o)&&(a=t(t({},a),o),o.name&&(a.name=o.name,a.isNameOverridden=!0),function(e){if(!e)return!1;var t=i.getParamTypes(e),r=e.length;return(1===r||2===r)&&!t}(o.type)&&(delete a.type,a.predicate=o.type)),a):a};export{v as JsonObject,h as JsonProperty,d as JsonSerializer,c as JsonSerializerOptions,f as logError,p as throwError}; |
{ | ||
"name": "typescript-json-serializer", | ||
"version": "3.4.5", | ||
"version": "4.0.0", | ||
"description": "Typescript library to serialize classes into json and deserialize json into classes.", | ||
@@ -11,10 +11,8 @@ "source": "src/index.ts", | ||
"build": "rollup -c", | ||
"cover": "jest --coverage", | ||
"cover": "rimraf coverage && jest --coverage", | ||
"lint": "eslint . --ext .ts --fix", | ||
"lint:ci": "eslint . --ext .ts", | ||
"postbuild": "npm run types", | ||
"prebuild": "rimraf dist", | ||
"test": "jest", | ||
"test:ci": "jest --reporters=default --reporters=jest-junit --coverage --coverageReporters=lcov --coverageReporters=text-lcov", | ||
"types": "tsc src/index.ts -d --emitDeclarationOnly --declarationDir dist" | ||
"test:ci": "jest --coverage" | ||
}, | ||
@@ -21,0 +19,0 @@ "repository": { |
603
README.md
@@ -5,3 +5,3 @@ # typescript-json-serializer | ||
![npm](https://img.shields.io/npm/dt/typescript-json-serializer) | ||
![npm bundle size (version)](https://img.shields.io/bundlephobia/minzip/typescript-json-serializer/3.4.4) | ||
![npm bundle size (version)](https://img.shields.io/bundlephobia/minzip/typescript-json-serializer/4.0.0) | ||
[![Coverage Status](https://coveralls.io/repos/github/GillianPerard/typescript-json-serializer/badge.svg)](https://coveralls.io/github/GillianPerard/typescript-json-serializer) | ||
@@ -12,2 +12,10 @@ [![Known Vulnerabilities](https://snyk.io/test/github/gillianperard/typescript-json-serializer/badge.svg?targetFile=package.json)](https://snyk.io/test/github/gillianperard/typescript-json-serializer?targetFile=package.json) | ||
## Summary | ||
1. [Installation](#installation) | ||
2. [Usage](#usage) | ||
3. [API](#api) | ||
4. [Development](#development) | ||
5. [Thanks to](#thanks-to) | ||
## Installation | ||
@@ -36,131 +44,42 @@ | ||
**WARNING:** If you use CRA (create-react-app) please refer to the [Using with Create React App](#using-with-create-react-app) section. | ||
## Usage | ||
## Import | ||
There are two decorators and two functions that you can import inside a typescript file. | ||
```typescript | ||
import { | ||
JsonProperty, | ||
Serializable, | ||
deserialize, | ||
serialize | ||
} from 'typescript-json-serializer'; | ||
``` | ||
import { JsonSerializer, throwError } from 'typescript-json-serializer'; | ||
## Library | ||
import { json } from '../json/data'; | ||
import { Organization } from '../models/organization'; | ||
### Decorators | ||
// Instantiate a default serializer | ||
const defaultSerializer = new JsonSerializer(); | ||
```typescript | ||
// Serializable decorator set a class as serializable. | ||
// It can take options as parameter: | ||
// - formatPropertyNames function to format the property names | ||
// provided by the json you want to serialize to match | ||
// with your class property names | ||
// Or you can instantiate a serializer with your custom options | ||
const customSerializer = new JsonSerializer({ | ||
// Throw errors instead of logging | ||
errorCallback: throwError, | ||
type FormatPropertyNameProto = (propertyName: string) => string; | ||
type SerializableOptions = { | ||
formatPropertyNames: FormatPropertyNameProto | ||
} | ||
// Allow all nullish values | ||
nullishPolicy: { | ||
undefined: 'allow', | ||
null: 'allow' | ||
}; | ||
@Serializable(options?: SerializableOptions) | ||
``` | ||
// e.g. if all the properties in the json object are prefixed by '_' | ||
formatPropertyName: (propertyName: string) => `_${propertyName}`; | ||
}) | ||
```typescript | ||
// JsonProperty decorator set metadata to the property. | ||
// It can take some optional parameters like: | ||
// - the name of json property if diverge from the class property | ||
// (this value override the `formatPropertyNames` option from | ||
// `Serializable` decorator) | ||
// - the type of the property (if needed) | ||
// - a predicate function that return a type (if needed) | ||
// - a function to transform data before serialize | ||
// - a function to transform data after serialize | ||
// - a function to transform data before deserialize | ||
// - a function to transform data after deserialize | ||
// - the names of properties to merge (the `formatPropertyNames` | ||
// from `Serializable` decorator is ignored) | ||
// - a boolean to tell that the property is a dictionary | ||
// - a boolean to tell that the property is required | ||
// (throw an error if undefined, null or missing) | ||
// Deserialize | ||
const organization = defaultSerializer.deserialize(json, Organization); | ||
// BREAKING CHANGES: since version 3.0.0 | ||
// - onSerialize has become afterSerialize | ||
// - onDeserialize has become beforeDeserialize | ||
// - postDeserialize has become afterDeserialize | ||
type IOProto = (property: any, currentInstance?: any) => {}; | ||
type PredicateProto = (property: any, parentProperty?: any) => {}; | ||
@JsonProperty(args?: | ||
| string | ||
| { | ||
name?: string, | ||
type?: Function, | ||
beforeSerialize?: IOProto, | ||
afterSerialize?: IOProto, | ||
beforeDeserialize?: IOProto, | ||
afterDeserialize?: IOProto, | ||
isDictionary?: boolean, | ||
required?: boolean | ||
} | ||
| { | ||
name?: string, | ||
predicate?: PredicateProto, | ||
beforeSerialize?: IOProto, | ||
afterSerialize?: IOProto, | ||
beforeDeserialize?: IOProto, | ||
afterDeserialize?: IOProto, | ||
isDictionary?: boolean, | ||
required?: boolean | ||
} | ||
| { | ||
names?: Array<string>, | ||
type?: Function, | ||
beforeSerialize?: IOProto, | ||
afterSerialize?: IOProto, | ||
beforeDeserialize?: IOProto, | ||
afterDeserialize?: IOProto, | ||
required?: boolean | ||
} | ||
| { | ||
names?: Array<string>, | ||
predicate?: PredicateProto, | ||
beforeSerialize?: IOProto, | ||
afterSerialize?: IOProto, | ||
beforeDeserialize?: IOProto, | ||
afterDeserialize?: IOProto, | ||
required?: boolean | ||
}) | ||
// Serialize | ||
const data = defaultSerializer.serialize(organization); | ||
``` | ||
### Functions | ||
### Examples | ||
```typescript | ||
// serialize function transform typescript class into json. | ||
// It takes two parameters: | ||
// - a instance of the class to serialize | ||
// - a boolean to remove undefined property (default true) | ||
#### Classes | ||
serialize(instance: any, removeUndefined: boolean = true): any | ||
``` | ||
```typescript | ||
// deserialize function transform json into typescript class. | ||
// It takes two parameters: | ||
// - json data | ||
// - the class you want to deserialize into | ||
deserialize<T>(json: any, type: new (...params) => T): T | ||
``` | ||
## Example | ||
### Classes | ||
```typescript | ||
// Import decorators from library | ||
import { Serializable, JsonProperty } from 'typescript-json-serializer'; | ||
import { JsonObject, JsonProperty } from 'typescript-json-serializer'; | ||
@@ -181,6 +100,6 @@ // Enums | ||
// Create a serializable class: LivingBeing | ||
// Create a JsonObject class: LivingBeing | ||
// Serializable decorator | ||
@Serializable() | ||
// JsonObject decorator | ||
@JsonObject() | ||
export class LivingBeing { | ||
@@ -193,5 +112,5 @@ | ||
// Create a serializable class that extends LivingBeing: Human | ||
// Create a JsonObject class that extends LivingBeing: Human | ||
@Serializable() | ||
@JsonObject() | ||
export class Human extends LivingBeing { | ||
@@ -215,5 +134,5 @@ constructor( | ||
// Create a serializable class: PhoneNumber | ||
// Create a JsonObject class: PhoneNumber | ||
@Serializable() | ||
@JsonObject() | ||
export class PhoneNumber { | ||
@@ -225,5 +144,5 @@ @JsonProperty() countryCode: string; | ||
// Create a serializable class that extends Human: Employee | ||
// Create a JsonObject class that extends Human: Employee | ||
@Serializable() | ||
@JsonObject() | ||
export class Employee extends Human { | ||
@@ -236,3 +155,3 @@ /** The employee's email */ | ||
@JsonProperty({ | ||
predicate: property => { | ||
type: property => { | ||
if (property && property.value !== undefined) { | ||
@@ -258,5 +177,5 @@ return PhoneNumber; | ||
// Create a serializable class: Animal | ||
// Create a JsonObject class: Animal | ||
@Serializable() | ||
@JsonObject() | ||
export class Animal { | ||
@@ -284,5 +203,5 @@ | ||
// Create a serializable class that extends Animal (which extends LivingBeing): Panther | ||
// Create a JsonObject class that extends Animal (which extends LivingBeing): Panther | ||
@Serializable() | ||
@JsonObject() | ||
export class Panther extends Animal { | ||
@@ -304,6 +223,6 @@ | ||
// Create a serializable class that extends Animal | ||
// Create a JsonObject class that extends Animal | ||
// (which extends LivingBeing): Snake | ||
@Serializable() | ||
@JsonObject() | ||
export class Snake extends Animal { | ||
@@ -321,6 +240,6 @@ | ||
// Create a serializable empty class that extends Animal | ||
// Create a JsonObject empty class that extends Animal | ||
// (which extends LivingBeing): UnknownAnimal | ||
@Serializable() | ||
@JsonObject() | ||
export class UnknownAnimal extends Animal { | ||
@@ -333,3 +252,3 @@ public constructor(name: string) { | ||
// Create a serializable class: Zoo | ||
// Create a JsonObject class: Zoo | ||
@@ -366,3 +285,3 @@ // Function to transform coordinates into an array | ||
@Serializable() | ||
@JsonObject() | ||
export class Zoo { | ||
@@ -396,3 +315,3 @@ | ||
// object into the correct child class | ||
@JsonProperty({ name: 'Animals', predicate: snakeOrPanther }) | ||
@JsonProperty({ name: 'Animals', type: snakeOrPanther }) | ||
animals: Array<Animal>; | ||
@@ -402,3 +321,3 @@ | ||
// Use again the predicate function | ||
@JsonProperty({ predicate: snakeOrPanther }) | ||
@JsonProperty({ type: snakeOrPanther }) | ||
mascot: Panther | Snake; | ||
@@ -413,3 +332,3 @@ | ||
isDictionary: true, | ||
predicate: property => { | ||
type: property => { | ||
if (property && property.value !== undefined) { | ||
@@ -427,18 +346,10 @@ return PhoneNumber; | ||
public constructor() { } | ||
} | ||
// Create a serializable class that extends Society: Organization | ||
// Create a JsonObject class that extends Society: Organization | ||
const prefixWithUnderscore = (propertyName: string) => `_${propertyName}` | ||
// Instead of defining the JsonProperty name for each property | ||
// just use a function to do it for all of them. | ||
// Warning: The properties of the base class will be formatted as well | ||
@Serializable({ formatPropertyNames: prefixWithUnderscore }) | ||
@JsonObject() | ||
export class Organization extends Society { | ||
// Override `formatPropertyNames` | ||
@JsonProperty({ name: 'zoos', type: Zoo }) zoos: Array<Zoo>; | ||
@JsonProperty({ type: Zoo }) zoos: Array<Zoo>; | ||
@JsonProperty({ isDictionary: true }) | ||
@@ -454,6 +365,6 @@ zoosName: { [id: string]: string }; | ||
@JsonProperty({ | ||
names: [ | ||
'_mainShareholder', | ||
'_secondaryShareholder', | ||
'_thirdShareholder' | ||
name: [ | ||
'mainShareholder', | ||
'secondaryShareholder', | ||
'thirdShareholder' | ||
], | ||
@@ -464,5 +375,5 @@ type: Human, | ||
return { | ||
_mainShareholder: value[0], | ||
_secondaryShareholder: value[1], | ||
_thirdShareholder: value[2] | ||
mainShareholder: value[0], | ||
secondaryShareholder: value[1], | ||
thirdShareholder: value[2] | ||
}; | ||
@@ -475,5 +386,5 @@ } | ||
// Create a serializable class: Society | ||
// Create a JsonObject class: Society | ||
@Serializable() | ||
@JsonObject() | ||
export class Organization { | ||
@@ -485,3 +396,3 @@ @JsonProperty() id: string; | ||
### Json data | ||
#### Json data | ||
@@ -491,5 +402,5 @@ ```typescript | ||
export const data: any = { | ||
_id: '1', | ||
_name: 'Zoos Organization', | ||
_zoosName: { | ||
id: '1', | ||
name: 'Zoos Organization', | ||
zoosName: { | ||
'15': 'The Greatest Zoo', | ||
@@ -635,3 +546,3 @@ '16': 'Zoo Zoo' | ||
], | ||
_mainShareholder: { | ||
mainShareholder: { | ||
humanId: 100, | ||
@@ -642,103 +553,341 @@ name: 'Elon Musk', | ||
}, | ||
_secondaryShareholder: null | ||
secondaryShareholder: null | ||
}; | ||
``` | ||
### Serialize & Deserialize | ||
## API | ||
```typescript | ||
// Import functions from library | ||
import { deserialize, serialize } from 'typescript-json-serializer'; | ||
### Decorators | ||
import { json } from '../json/data'; | ||
import { Organization } from '../models/organization'; | ||
**@JsonObject()** | ||
Used to make a class serializable. | ||
// deserialize | ||
const organization = deserialize<Organization>(json, Organization); | ||
##### **Example** | ||
// serialize | ||
const data = serialize(organization); | ||
// or | ||
const data = serialize(organization, false); | ||
```typescript | ||
@JsonObject() | ||
class MyClass {} | ||
``` | ||
## Using with Create React App | ||
**@JsonProperty()** | ||
Used to make a class property serializable, property will be ignored if not set. | ||
If you are using [CRA](https://create-react-app.dev/) to create your React App you will need to add a custom configuration in order to add `Decorator` and `Metadata` features (not supported by React) using [customize-cra](https://github.com/arackaf/customize-cra) and [react-app-rewired](https://github.com/timarney/react-app-rewired/). | ||
##### **Parameters** | ||
First, don't forget to add `emitDecoratorMetadata` and `experimentalDecorators` inside the `tsconfig.json` file (explain in the [Installation](#installation) section). | ||
**options** | ||
Type: `string` | [`JsonPropertyOptions`](#jsonpropertyoptions) | ||
Optional: `true` | ||
Description: The option to customize the serialization/deserialization of the target property. | ||
Next install the dependencies to override the React build config: | ||
##### **Example** | ||
```sh | ||
npm install -D customize-cra react-app-rewired | ||
# or | ||
yarn add -D customize-cra react-app-rewired | ||
```typescript | ||
@JsonProperty(options) myProperty: string; | ||
``` | ||
Replace the scripts using `react-scripts` in the `package.json` file by `react-app-rewired`: | ||
### JsonSerializer | ||
```json | ||
// example | ||
#### Constructor | ||
```typescript | ||
constructor(options?: Partial<JsonSerializerOptions>) {} | ||
``` | ||
##### **Parameters** | ||
**options** | ||
Type: <code>Partial<[JsonSerializerOptions](#jsonserializeroptions)></code> | ||
Optional: `true` | ||
Description: The options to customize the serializer. | ||
#### Properties | ||
**options** | ||
Type: <code>Partial<[JsonSerializerOptions](#jsonserializeroptions)></code> | ||
Optional: `false` | ||
Description: The options to customize the serializer. | ||
Default value: | ||
```typescript | ||
{ | ||
... | ||
"scripts": { | ||
... | ||
"start": "react-app-rewired start", | ||
"build": "react-app-rewired build", | ||
"test": "react-app-rewired test", | ||
"eject": "react-app-rewired eject" | ||
... | ||
}, | ||
... | ||
errorCallback: logError, | ||
nullishPolicy: { | ||
undefined: 'remove', | ||
null: 'allow' | ||
} | ||
} | ||
``` | ||
Install dependencies to add support for `Decorator` and `Metadata`: | ||
#### Methods | ||
**deserialize()** | ||
To use when you don't know if the value to deserialize is an object or an array. | ||
```typescript | ||
deserialize<T extends object>( | ||
value: string | object | Array<object>, | ||
type: Type<T> | ||
): T | Array<T|Nullish> | Nullish | ||
``` | ||
##### **Parameters** | ||
**value** | ||
Type: `string` | `object` | `Array<object>` | ||
Optional: `false` | ||
Description: The value to deserialize. | ||
**type** | ||
Type: [`Type<T>`](#typet) | ||
Optional: `false` | ||
Description: The constructor class to deserialize into. | ||
##### **Return** | ||
`T` or <code>Array<T|[Nullish](#nullish)></code> or [`Nullish`](#nullish) | ||
--- | ||
**deserializeObject()** | ||
To use when the value to deserialize is an object. | ||
```typescript | ||
deserializeObject<T extends object>( | ||
obj: string | object, | ||
type: Type<T> | ||
): T | Nullish | ||
``` | ||
##### **Parameters** | ||
**obj** | ||
Type: `string` | `object` | ||
Optional: `false` | ||
Description: The object to deserialize. | ||
**type** | ||
Type: [`Type<T>`](#typet) | ||
Optional: `false` | ||
Description: The constructor class to deserialize into. | ||
##### **Return** | ||
`T` or [`Nullish`](#nullish) | ||
--- | ||
**deserializeObjectArray()** | ||
To use when the value to deserialize is an array. | ||
```typescript | ||
deserializeObjectArray<T extends object>( | ||
array: string | Array<any>, | ||
type: Type<T> | ||
): Array<T|Nullish> | Nullish | ||
``` | ||
##### **Parameters** | ||
**array** | ||
Type: `string` | `Array<any>` | ||
Optional: `false` | ||
Description: The object to deserialize. | ||
**type** | ||
Type: [`Type<T>`](#typet) | ||
Optional: `false` | ||
Description: The constructor class to deserialize into. | ||
##### **Return** | ||
<code>Array<T|[Nullish](#nullish)></code> or [`Nullish`](#nullish) | ||
--- | ||
**serialize()** | ||
To use when you don't know if the value to serialize is an object or an array | ||
```typescript | ||
serialize(value: object | Array<object>): object | Array<object|Nullish> | Nullish | ||
``` | ||
##### **Parameters** | ||
**value** | ||
Type: `object` | `Array<object>` | ||
Optional: `false` | ||
Description: The object or the array of objects to serialize. | ||
##### **Return** | ||
`object` or <code>Array<object|[Nullish](#nullish)></code> or [`Nullish`](#nullish) | ||
--- | ||
**serializeObject()** | ||
To use when the value to serialize is an object. | ||
```typescript | ||
serializeObject(instance: object): object | Nullish | ||
``` | ||
##### **Parameters** | ||
**instance** | ||
Type: `object` | ||
Optional: `false` | ||
Description: The object to serialize. | ||
##### **Return** | ||
`object` or [`Nullish`](#nullish) | ||
--- | ||
**serializeObjectArray()** | ||
To use when the value to serialize is an array of objects. | ||
```typescript | ||
serializeObjectArray(array: Array<object>): Array<object|Nullish> | Nullish | ||
``` | ||
##### **Parameters** | ||
**array** | ||
Type: `Array<object>` | ||
Optional: `false` | ||
Description: The array of objects to serialize. | ||
##### **Return** | ||
<code>Array<object|[Nullish](#nullish)></code> or [`Nullish`](#nullish) | ||
### Definitions | ||
#### **Types** | ||
##### **JsonPropertyOptions** | ||
```typescript | ||
name?: string | Array<string>; | ||
type?: Function | PredicateProto; | ||
isDictionary?: boolean; | ||
required?: boolean; | ||
beforeSerialize?: IOProto; | ||
afterSerialize?: IOProto; | ||
beforeDeserialize?: IOProto; | ||
afterDeserialize?: IOProto; | ||
``` | ||
##### **JsonSerializerOptions** | ||
```typescript | ||
errorCallback?: ErrorCallback = logError; | ||
nullishPolicy: NullishPolicy = { | ||
undefined: 'remove', | ||
null: 'allow' | ||
}; | ||
formatPropertyName?: FormatPropertyNameProto; | ||
``` | ||
##### **NullishPolicy** | ||
```typescript | ||
undefined: Policy; | ||
null: Policy; | ||
``` | ||
#### **Value types** | ||
##### **Nullish** | ||
```typescript | ||
null | undefined | ||
``` | ||
##### **Policy** | ||
```typescript | ||
'allow' | 'disallow' | 'remove' | ||
``` | ||
#### **Functions types** | ||
##### **ErrorCallback** | ||
```typescript | ||
(message: string) => void | ||
``` | ||
The library provide two built-in methods: | ||
- `logError` that logs the error. | ||
- `throwError` that throws the error. | ||
##### **FormatPropertyNameProto** | ||
```typescript | ||
(propertyName: string) => string; | ||
``` | ||
##### **IOProto** | ||
```typescript | ||
(property: any, currentInstance?: any) => any | ||
``` | ||
##### **PredicateProto** | ||
```typescript | ||
(property: any, parentProperty?: any) => any | ||
``` | ||
##### **Type\<T>** | ||
```typescript | ||
new (...args: Array<any>) => T; | ||
``` | ||
Note: represent a `constructor`. | ||
## Development | ||
### Prerequisites | ||
- NodeJS: [https://nodejs.org](https://nodejs.org/en/) | ||
- Yarn: [https://yarnpkg.com](https://yarnpkg.com/) | ||
### Install dependencies | ||
```sh | ||
npm install -D @babel/plugin-proposal-decorators \ | ||
@babel/preset-typescript \ | ||
babel-plugin-parameter-decorator \ | ||
babel-plugin-transform-typescript-metadata | ||
# or | ||
yarn add -D @babel/plugin-proposal-decorators \ | ||
@babel/preset-typescript \ | ||
babel-plugin-parameter-decorator \ | ||
babel-plugin-transform-typescript-metadata | ||
yarn | ||
``` | ||
Create the `config-overrides.js` file in the root of your project | ||
with the following content: | ||
### Run build | ||
```js | ||
const { | ||
override, | ||
addDecoratorsLegacy, | ||
addBabelPlugin, | ||
addBabelPreset, | ||
} = require("customize-cra"); | ||
```sh | ||
yarn build | ||
``` | ||
module.exports = override( | ||
addDecoratorsLegacy(), | ||
addBabelPlugin("babel-plugin-parameter-decorator"), | ||
addBabelPlugin("babel-plugin-transform-typescript-metadata"), | ||
addBabelPreset(["@babel/preset-typescript"]) | ||
); | ||
### Run linter | ||
```sh | ||
yarn lint | ||
``` | ||
## Test | ||
### Run tests | ||
```sh | ||
npm run test | ||
# or | ||
yarn test | ||
``` | ||
## Author | ||
## Thanks to | ||
### Author | ||
Gillian Pérard - [@GillianPerard](https://github.com/GillianPerard) | ||
## Contributors | ||
### Contributors | ||
* Hyeonsoo David Lee - [@civilizeddev](https://github.com/civilizeddev) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
66353
13
181
869
1