# json4all JSON para todos los propósitos y todas las plataformas [![npm-version](https://img.shields.io/npm/v/json4all.svg)](https://npmjs.org/package/json4all) [![downloads](https://img.shields.io/npm/dm/json4all.svg)](https://npmjs.org/package/json4all) [![build](https://github.com/codenautas/json4all/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/codenautas/json4all/actions/workflows/build-and-test.yml) [![coverage](https://img.shields.io/coveralls/codenautas/json4all/master.svg)](https://coveralls.io/r/codenautas/json4all) [![security](https://socket.dev/api/badge/npm/package/json4all)](https://socket.dev/npm/package/json4all) [![qa-control](https://github.com/codenautas/json4all/actions/workflows/qa-control.yml/badge.svg)](https://github.com/codenautas/json4all/actions/workflows/qa-control.yml) idioma: ![castellano](https://raw.githubusercontent.com/codenautas/multilang/master/img/lang-es.png) también disponible en: [![inglés](https://raw.githubusercontent.com/codenautas/multilang/master/img/lang-en.png)](README.md) # Instalación ```sh $ npm install json4all ``` # Objetivo Reemplazar **JSON** por una función que * pueda codificar/decodificar: * Fechas del tipo nativo **Date** * Expresiones regulares del tipo **Regexp** * Objetos y arreglos que contengan *undefined* * Tipos definidos por el usuario * sea seguro, o sea no codifique funciones (**Function**) * tenga un mecanismo para intercambiar objetos entre el frontend y el backend que: * Envíe al frontend una copia del objeto que tenga solo las propiedades que correponda, para esconder la implementación o información que no debe salir del backend * Envíe al frontend una referencia de objeto que permita identificar la instancia precisa dentro del backend. Así el frontend recibe una copia de las propiedades que correspondan y un modo de identificar al objeto preciso del backend. ```js var JSON4all = require('json4all'); var today = new Date(); var tansDate = JSON4all.parse(JSON4all.stringify(today)); console.log(transDate.constructor.name); // Date ``` ## JSON4all.addType(Constructor) Registra la clase definida por el constructor. La clase debe tener definidas las funciones: * JSON4replacer (a nivel de la instancia de objeto o del prototipo) que devuelve un valor que sirve para recrear el objeto * JSON4reviver (a nivel de la clase) que recive el valor para recrear el objeto y devuelve el nuevo objeto recreado ```js var JSON4all = require('json4all'); function Point(x, y, z) { this.klass = 'Point'; this.x = x; this.y = y; this.z = z; } Point.prototype.JSON4replacer=function(){ return {x:this.x, y:this.y, z:this.z}; } Point.JSON4reviver=function(o){ return new Point(o.x, o.y, o.z); } JSON4all.addType(Point); var p = new Point(); var q = JSON4all.parse(JSON4all.stingify(p)); console.log(q instanceof Point); // true ``` ## @JSON4all.addClass Decorator que registra la clase definida. Se deben indicar qué propiedades deben serializarse con `addProperty`. Cuando una propiedad es parámetro del constructor principal de la clase hay que indicar el orden (comenzando en 1) con `addProperty(n)` ```ts var JSON4all = require('json4all'); @JSON4all.addClass class Point { @JSON4all.addProperty(1) public x: number @JSON4all.addProperty(2) public y: number @JSON4all.addProperty(3) public z: number @JSON4all.addProperty public color: string | undefined public internal: number | undefined constructor(x, y, z){ this.x = x; this.y = y; this.z = z; } } var p = new Point(1.1, 2.3, 3.14); p.internal = 7; var q = JSON4all.parse(JSON4all.stingify(p)); console.log(q.internal); // undefined console.log(q instanceof Point); // true console.log(q.z); // 3.14 ``` ## JSON4all.RefStore Registra un objeto como repositorio de instancias referenciables en el backend y copias en el frontend (las modificación copias en el frontend no impactan en el backend). Cuando el objeto es serializado en el backend se le agrega una referencia. Al llegar al frontend el objeto es revivido y conservada la referencia. Cuando el objeto se envía del backend al frontend, al serializarlo solo se envía la referencia (porque al ser una copia no es necesario pasar los datos porque ya están en el backend) ```ts // in the back-end import * as JSON4all from 'json4all'; import { Point } from './common/my-classes'; JSON4all.RefStoreSpace(global.mySpace) var points = JSON4all.RefStore(['points']); var center = new Point(100,200,-50); points['x3298484'] = center; console.log(points[JSON4all.RefKey]) // 'x3298484' var str = JSON4all.stringify(center); var center2 = JSON4all.parse(str); console.log( center === center2 ); // true the same instance!!!! res.send(JSON4all.stringify(center)); // IN THE FRONT-END: import * as JSON4all from 'json4all'; import { Point } from './common/my-classes'; var pointStr = await simpleFetch('https://..../center') var point = JSON4all.parse() console.log(point.x, point.y, point.z); // 100,200,-50 point.x = 999; simpleFetch('https://..../set-center?point='+JSON4all.stringify(point)); // only the ref is sended // IN THE BACK-END: app.get('/set-center',(req)=>{ // with the ref the object is retrived from the collection var point = JSON4all.parse(req.query('point')); console.log(point.x, point.y, point.z); // 100,200,-50 console.log(points['x3298484'] === point) // the same instance }) ``` ## JSON4all.pretendClass(object, classConstructor) Interviene un objeto plano para que la llamada a `JSON.stringify(object)` devuelva el mismo valor que la llamada a una instancia de clase que tenga sus mismos valores (`JSON.stringify(object) === JSON.object(instance)`). ```ts var point = new Point({x:7, y:8}); var object = {x:7, y:8}; JSON4all.pretendClass(object, Point); console.log(JSON4all.stringify(object) == JSON4all.stringify(point)); // true var restoredPoint = JSON4all.parse(JSON4all.stringify(object)); console.log(restoredPoint instanceof Point); // true ``` ## Pruebas con dispositivos reales NPM version | Device | OS | nav ------------|------------------------|---------------|---------------- 0.1.4 | Samsung SM-T560 | Android 4.4.4 | Firefox 49.0.0 0.1.4 | Samsung SM-T560 | Android 4.4.4 | Chrome 53.0.2785 0.1.4 | Samsung SM-T560 | Android 4.4.4 | Opera 37.0.2192 0.1.4 | Samsung S5 | Android 4.4.2 | Firefox 49.0.0 0.1.4 | Samsung S5 | Android 4.4.2 | Opera Mobile 37.1.2192 ## Licencia [MIT](LICENSE)