mobitel-json-schema-template
Version:
NodeJs module for helping creation JSON schemas
259 lines (218 loc) • 7.38 kB
JavaScript
/** @type {JSONSchemaTemplateError} */
const ErrorHandler = require('../error-handler.js');
/** Main class for extend other classes */
class MainTemplates {
/** Class constructor */
constructor() {
this.rule = {};
}
/**
* Generate and validate ENUM values list
* @param {*[]} args Values for ENUM
* @returns {Array} List of ENUM values
*/
_prepareEnum(...args) {
let source = [...args];
let list = [];
if (source.length > 0) {
for (let i = 0; i < source.length; i++) {
const val = source[i];
if (Array.isArray(val)) {
source = source.concat(val);
delete source[i];
continue;
}
let valType = typeof val;
valType = Array.isArray(val) ? 'array' : valType;
valType = null === val ? 'null' : valType;
valType = Number.isNaN(val) ? 'nan' : valType;
if (!['number', 'string', 'boolean', 'null'].includes(valType)) {
throw new ErrorHandler(`Has incorrect enum value: ${val.toString()} (${typeof val})`);
}
list.push(val);
}
list = list.filter(value => !(typeof value === 'undefined'));
}
if (list.length === 0) {
throw new ErrorHandler('Has no enum values');
}
return list;
}
/**
* Generate and validate values list for combining types like a allOf, anyOf, oneOf
* @param {Object[]} args Values for combining types
* @returns {Array} List with values
*/
_prepareCombining(...args) {
let source = [...args];
let list = [];
if (source.length > 0) {
for (let i = 0; i < source.length; i++) {
const val = source[i];
if (Array.isArray(val)) {
source = source.concat(val);
delete source[i];
continue;
}
if (!val || typeof val !== 'object' || Object.keys(val).length === 0) {
throw new ErrorHandler(`Has incorrect combining value: ${JSON.stringify(val)} (${typeof val})`);
}
list.push(val);
}
list = list.filter(value => !(typeof value === 'undefined'));
}
if (list.length === 0) {
throw new ErrorHandler('Has no combining values');
}
return list;
}
/**
* Generate and validate values list for combining type 'not'
* @param {*[]} args Values for combining type
* @returns {Array} Value for combining type 'not'
*/
_prepareCombiningNot(...args) {
if (args.length > 1) {
throw new ErrorHandler(`Too many arguments for 'not' combining type`);
}
const val = args[0];
if (!val || typeof val !== 'object' || Array.isArray(val) || Object.keys(val).length === 0) {
throw new ErrorHandler(`Has incorrect combining value: ${JSON.stringify(val)} (${typeof val})`);
}
return val;
}
/**
* Probably number is float
* @param {Number|String} value Number for check
* @returns {boolean} TRUE if number is probably float, or FALSE
*/
_isFloat(value) {
const num = parseFloat(String(value));
return !Number.isInteger(num);
}
/**
* Parsing integer numbers
* @param {Number|String} value Number for parsing
* @returns {Number} Parsed integer number
*/
_parseInteger(value) {
if (!['string', 'number'].includes(typeof value)) {
throw new ErrorHandler(`Argument has incorrect type '${typeof value}': ${JSON.stringify(value)}`);
}
const numStr = String(value);
if (numStr.length > 1 && numStr[0] === '0') {
throw new ErrorHandler(`Number is not a decimal: ${value}`);
}
const numParsed = parseFloat(value);
if (!Number.isInteger(numParsed)) {
throw new ErrorHandler(`Incorrect integer number: ${value}`);
}
return parseInt(value, 10);
}
/**
* Parsing float numbers
* @param {Number|String} value Number for parsing
* @returns {Number} Parsed float number
*/
_parseFloat(value) {
if (['object', 'symbol'].includes(typeof value)) {
throw new ErrorHandler(`Argument has type 'object': ${JSON.stringify(value)}`);
}
const num = parseFloat(value);
if (Number.isNaN(num)) {
throw new ErrorHandler(`Incorrect number: ${value}`);
}
return num;
}
/**
* Check integer for positive value
* @param {Number|String} value Number for check and parsing
* @return {Number} Parsed positive integer
*/
_getPositiveInteger(value) {
const num = this._parseInteger(value);
if (num < 0) {
throw new ErrorHandler(`Value must be positive: ${value}`);
}
return num;
}
/**
* Add exclusive minimum value into JSON-schema
* @returns {Object|MainTemplates} Current object
*/
_eMin() {
this.rule.exclusiveMinimum = true;
return this;
}
/**
* Add exclusive maximum value into JSON-schema
* @returns {Object|MainTemplates} Current object
*/
_eMax() {
this.rule.exclusiveMaximum = true;
return this;
}
/**
* Add multiplicator value into JSON-schema
* @param {Number} value Parameter value
* @returns {Object|MainTemplates} Current object
*/
_multipleOf(value) {
this.rule.multipleOf = this._getPositiveInteger(value);
return this;
}
/**
* Add enum value into JSON-schema
* @param {*[]} args ENUM values
* @returns {Object|MainTemplates} Current object
*/
_enum(...args) {
this.rule.enum = this._prepareEnum(...args);
return this;
}
/**
* Add list for 'anyOf' parameter
* @param {Object[]} args List of 'anyOf' parameters
* @returns {Object|MainTemplates} Current object
*/
_anyOf(...args) {
this.rule.anyOf = this._prepareCombining(...args);
return this;
}
/**
* Add list for 'allOf' parameter
* @param {Object[]} args List of 'allOf' parameters
* @returns {Object|MainTemplates} Current object
*/
_allOf(...args) {
this.rule.allOf = this._prepareCombining(...args);
return this;
}
/**
* Add list for 'oneOf' parameter
* @param {Object[]} args List of 'oneOf' parameters
* @returns {Object|MainTemplates} Current object
*/
_oneOf(...args) {
this.rule.oneOf = this._prepareCombining(...args);
return this;
}
/**
* Add list for 'not' parameter
* @param {Object} args List of 'not' parameters
* @returns {Object|MainTemplates} Current object
*/
_not(...args) {
this.rule.not = this._prepareCombiningNot(...args);
return this;
}
/**
* Get generated template for JSON-schema
* @returns {Object|MainTemplates} Object with template
*/
_done() {
return this.rule;
}
}
/** @type {MainTemplates} */
module.exports = MainTemplates;