1.0.4 • Published 5 years ago

jtclass v1.0.4

Weekly downloads
-
License
ISC
Repository
-
Last release
5 years ago

Introduction

JTClass is a library made for those who simly wants to map their JSON data into defined class. Also JTClass provides strong debug log if any problems were encountered during mapping, like:

  • Field had not appropriate type.
  • Required fields were not present.
  • Some additional fields were present.

Usage

In order to perform mapping you need to create JTClass instanse, as first argument you should pass a function which will return sample array of expected class objects. Keep in mind that all fields inside sample objects should be initialized by some meaningfull value, which will be used as default in case of trouble (null and undefined are not accepted). There are two mapping functions "single" and "array", they return object with field 'data' - your mapped data.

const usersJTC = new JTClass(() => [ new User() ]);
const user = usersJTC.single(income).data;
const users = usersJTC.array(incomeArray).data;

Example

import { JTClass } from 'JTClass';

class User {
   public name = '';
   public age = 0;
   public phone = new Phone();

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

class Phone {
   public country = '';
   public number = 0;
   public code = 0;
   
   getFullNumber() {
      return `+${this.code} ${this.number}`;
   }
}

const usersJTC = new JTClass(() => [ new User() ]);
const income = {
   name: 'Grathan Muller',
   age: 21,
   phone: {
      country: 'Germany',
      number: 1111111,
      code: 49,
   }
} as any;

const user = usersJTC.single(income).data;

console.log(income, user);
console.log(user.sayHello());
console.log(user.phone.getFullNumber());

Array

If there are some arrays inside your json data you need to provide sample of what do you expect inside them, you can do this inside sample function

import { JTClass } from 'JTClass';

class User {
   public name = '';
   public age = 0;
   public notes: Note[] = [];
   public remarks: string[] = [];

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

class Note {
   public text = '';
   public timestamp = 0;
   public isDone = false;

   getSatus() {
      return `I planned ${this.text} on ${new Date(this.timestamp).toLocaleString()} and this is ${this.isDone ? '' : 'not yet '} done`;
   }
}

const usersJTC = new JTClass(() => {
    const user = new User();
    user.notes = [ new Note() ];
    user.remarks = [''];
    return [ user ];
});

const income = {
   name: 'Grathan Muller',
   age: 21,
   notes: [
      { text: 'Go to shop',  timestamp: 1552170070897, isDone: false },
      { text: 'Feed the dog',  timestamp: 1552170020897, isDone: true },
   ],
   remarks: [`What a beatful day`]
} as any;

const user = usersJTC.single(income).data;

console.log(income, user)
console.log(user.sayHello());
user.notes.forEach(note => console.log(note.getSatus()));
console.log(user.remarks.join(', '));

Map

In order to let JTClass undestand that some object is a map you should use JTC.map decorator on class field, and as for arrays sample of inner value should be provided

import { JTClass, JTC } from 'JTClass';

class User {
   public name = '';
   public age = 0;
   @JTC.map public drinked: Drink = {};

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

interface Drink {
   [drink: string]: number;
}

 const usersJTC = new JTClass(() => {
    const user = new User();
    user.drinked = {
        'drink': 0,
    };
    return [ user ];
});

const income = {
   name: 'Grathan Muller',
   age: 21,
   drinked: {
      'coffe': 4,
      'beer': 8,
      'vine': 12
   },
} as any;

const user = usersJTC.single(income).data;

console.log(income, user);
console.log(user.sayHello());
console.log(user.phone.getFullNumber());
console.log(user.drinked);

Inheritance

You probably wondering 'Why sample function must return an array?', it because JTClass can determine inheritance inside your json. Meaning if in your income array some inhereted objects are present, JTClass can distinguish them (objects must have unique fields) and map to appropriate object

import { JTClass, JTC } from 'JTClass';

class User {
   public name = '';
   public age = 0;

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

class SuperUser extends User {
   public isSuper = true;
}

const usersJTC = new JTClass(() => [ new User(), new SuperUser() ]);

const income = [
   {
      name: 'Grathan Muller',
      age: 21,
   }, 
   {
      name: 'Steven Gatz',
      age: 25,
      isSuper: true
   }
] as any;

const users = usersJTC.array(income).data;

console.log(income, users)

Unexpected field type

If there are situation when inside your json data some values are not of expected type they will be

  • If it's primitive - will be replaced by default value, provided in the sample
  • If it's an object - will be replaced by new instanse of class, provided in the sample
  • If value inside array or map - will be excluded
  • If object have not enought fields - this fields will be added with default values from sample
import { JTClass, JTC } from 'JTClass';

class User {
   public name = '';
   public age = 0;
   public phone = new Phone();
   public notes: Note[] = [];
   public remarks: string[] = [];
   @JTC.map public drinked: Drink = {};

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

class Phone {
   public country = '';
   public number = 0;
   public code = 0;
   
   getFullNumber() {
      return `+${this.code} ${this.number}`;
   }
}

class Note {
   public text = '';
   public timestamp = 0;
   public isDone = false;

   getSatus() {
      return `I planned ${this.text} on ${new Date(this.timestamp).toLocaleString()} and this is ${this.isDone ? '' : 'not yet '} done`;
   }
}

interface Drink {
   [drink: string]: number;
}

const usersJTC = new JTClass(() => {
      const user = new User();
      user.notes = [ new Note() ];
      user.remarks = [''];
      user.drinked = {
         'drink': 0,
      };
      return [ user ];
});

const income = {
   name: 0,
   age: '21',
   phone: null,
   notes: [
      { text: 'Go to shop',  timestamp: 1552170070897 },
      null, 
      { text: 'Feed the dog',  timestamp: undefined, isDone: true },
      { junk: '......' },
      null
   ],
   remarks: [`What a beatful day`, 23, {  }],
   drinked: {
      'coffe': { number: 4 },
      'beer': 8,
      'vine': '12'
   },
   ghost: 'booooo'
} as any;

const user = usersJTC.single(income).data;

console.log(income, user);
console.log(user.sayHello());
console.log(user.phone.getFullNumber());
user.notes.forEach(note => console.log(note.getSatus()));
console.log(user.remarks.join(', '));
console.log(user.drinked)

Debug Log

In situations when any repairs been done to your json you will see debug log in the console, you can disable it by passing second argument to JTClass instanse as 'false'. You probably will have many instanses of JTClass and don't want your users to see log in production, so the way to disable logging in all instanses is to access static member JTClass.globalLogging and set it to 'false'. Also you can find some additional debug fields on object returned by 'single' / 'array' functions

  • isValid - boolean, will be true only if there were no fields that needed repairs
  • timestamt - Date, date when mapping been called
  • repairTree - object, based on which you see debug log in the console
// Disable logging for current instanse
const usersJTC = new JTClass(() =>  [ new User() ], false);

// Disable logging for all instanses
JTClass.globalLogging = false;

Null

If you are expecting some values to be null, you can decorate class fields with JTC.null, in that case values will be left nulls as is.

import { JTClass, JTC } from 'JTClass';

class User {
   public name = '';
   public age = 0;
   @JTC.null public phone = new Phone();

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

class Phone {
   public country = '';
   public number = 0;
   public code = 0;
   
   getFullNumber() {
      return `+${this.code} ${this.number}`;
   }
}

 const usersJTC = new JTClass(() => [ new User() ]);

const income = {
   name: 'Grathan Muller',
   age: 21,
   phone: null,
} as any;

const user = usersJTC.single(income).data;

console.log(income, user);
console.log(user.sayHello());
console.log(user.phone);

Ignore

If there are situation when some value keep coming invalid, you cant't do nothing about it, but don't want to see it in debug log you can decorate class field with JTC.ignore. In that case value will still be restored to default if it's not valid, but this action will not be shown in log

import { JTClass, JTC } from 'JTClass';

class User {
   @JTC.ignore public name = '';
   public age = 0;

   sayHello() {
      return `Hello, my name is ${this.name}`;
   }
}

const usersJTC = new JTClass(() => [ new User() ]);

const income = {
   name: undefined,
   age: 21,
} as any;

const user = usersJTC.single(income).data;

console.log(income, user);
console.log(user.sayHello());

Errors

JTClass - samples function should return array with at least one value!

Invalid

const usersJTC = new JTClass(() => []);

Valid

const usersJTC = new JTClass(() => [ new User() ]);

JTClass - only custom class instanses inside sample array are allowed!

Invalid

const usersJTC = new JTClass(() => [ { name: '', age: 0 } ]);

Valid

class User {
   public name = '';
   public age = 0;
}

const usersJTC = new JTClass(() => [ new User() ]);

JTClass - Functions are not allowed inside simple objects, use class instead, function under key: key

Invalid

const usersJTC = new JTClass(() => {
   const user = new User();
   user.notes = [{
      text: '',
      timestamp: 0,
      isDone: false,
      getSatus: () => {
         return `I planned ${this.text} on ${new Date(this.timestamp).toLocaleString()} and this is ${this.isDone ? '' : 'not yet '} done`;
      }
   }];

   return [ user ];
});

Valid

class Note {
   public text = '';
   public timestamp = 0;
   public isDone = false;

   getSatus() {
      return `I planned ${this.text} on ${new Date(this.timestamp).toLocaleString()} and this is ${this.isDone ? '' : 'not yet '} done`;
   }
}

const usersJTC = new JTClass(() => {
   const user = new User();
   user.notes = [ new Note() ];

   return [ user ];
});

JTClass - Undefined or null are not allowed inside sample, bad value under key: key

Invalid

class User {
   public name = null;
   public age = undefined;
}

const usersJTC = new JTClass(() => [ new User() ]);

Valid

class User {
   public name = '';
   public age = 0;
}

const usersJTC = new JTClass(() => [ new User() ]);

JTClass - Arrays inside sample should have at least one value to detrmine what is expected, empty array under key: key

Invalid

class User {
   public name = '';
   public age = 0;
   public remarks: string[] = [];
}

const usersJTC = new JTClass(() => [ new User() ]);

Valid

class User {
   public name = '';
   public age = 0;
   public remarks: string[] = [];
}

const usersJTC = new JTClass(() => {
   const user = new User();
   user.remarks = [ '' ];

   return [ user ];
});

JTClass - Maps inside sample should have at least one value, bad value under key: key

Invalid

class User {
   public name = '';
   public age = 0;
   @JTC.map public drinks: Drink = {};
}

interface Drink {
   [drink: string]: number;
}

const usersJTC = new JTClass(() => [ new User() ]);

Valid

class User {
   public name = '';
   public age = 0;
   @JTC.map public drinks: Drink = {};
}
const usersJTC = new JTClass(() => {
   const user = new User();
   user.drinks['drink'] = 0;

   return [ user ];
});
1.0.4

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago