const stringifyPath = require('objectpath').stringify
const utils = require('./performer/utils/utils.js')
const unroot = utils.unroot
/**
* @namespace ZCUSTOMERROR
*/
/**
* Custom Blueconfig errors are used to identify: Blueconfig internal error, Schema error or config error.
*
* This class is Parent of all other Blueconfig errors, all errors are inherited of this one.
*
* @example
* if (myError instanceof BLUECONFIG_ERROR) {
* console.log('is blueconfig error');
* }
*
* @extends Error
*
* @Memberof ZCUSTOMERROR
*/
class BLUECONFIG_ERROR extends Error {
/**
* @param {String} message Error message
*/
constructor(message) {
super(message)
return this
}
}
/**
* List of errors (should be loop/parsed on LISTOFERRORS.errors like an array). Can be usefull with custom format.
*
*
* ```text
* Validate failed because wrong value(s):
* - root: Custom format "children" tried to validate something and failed:
* 1) germany:
* - name: must be of type String: value was 1
* 2) italy:
* - subregion: must be of type String: value was 2
* ```
*
* @example
* blueconfig.addFormat({ // Allow to do: config.*.name, by example : config.app1.name, config.app2.name
* name: 'children',
* validate: function(children, schema, fullname) {
* Object.keys(children).forEach((keyname) => {
* try {
* const conf = blueconfig(schema.children).merge(children[keyname]).validate();
* this.set(keyname, conf.getProperties());
* } catch (err) { errors.push(err); }
* });
*
* if (errors.length !== 0) { throw new LISTOFERRORS(errors) }
* }
* });
*
* @extends BLUECONFIG_ERROR
*
*
* @Memberof ZCUSTOMERROR
*/
class LISTOFERRORS extends BLUECONFIG_ERROR {
/**
* @param {BLUECONFIG_ERROR[]} errors List of errors
*/
constructor(errors) {
super('List of several errors.')
/**
* List of errors
*
* @var errors
* @memberof LISTOFERRORS
*/
this.errors = errors
return this
}
}
// =========================================
// ============= BLUECONFIG ERROR =============
// =========================================
// new Error = Probably a blueconfig internal error
// =========================================
// ============= INSIDE ERROR ==============
// ============= SCHEMA ERROR ==============
// =========================================
// This is probably a js/application problem.
/**
* Fired when schema is not valid.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class SCHEMA_INVALID extends BLUECONFIG_ERROR {
/**
* @param {String} fullname Return the full selector (e.g.: `base.path.name`)
* @param {String} message Error message
*/
constructor(fullname, message) {
super(`${fullname}: ${message}`)
/**
* Return the full selector (e.g.: `base.path.name`)
*
* @var fullname
* @memberof SCHEMA_INVALID
*/
this.fullname = fullname
this.type = 'SCHEMA_INVALID'
this.doc = 'The schema is not valid, edit your schema to continue.'
return this
}
}
// =========================================
// ============= INSIDE ERROR ==============
// =============== JS ERROR ================ (with custom getter, format or parser)
// ========================================= or wrong path with get/set/default/reset/getOrigin function.
// This is probably a js/application problem.
/**
* Fired when adding custom getter/format/parser failed.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class CUSTOMISE_FAILED extends BLUECONFIG_ERROR {
/**
* @param {String} message Error message
*/
constructor(message) {
super(message)
this.type = 'CUSTOMISE_FAILED'
this.doc = 'You try to add a getter/format/parser but you failed, fix your javascript code to continue.'
return this
}
}
/**
* Fired when the usage of Blueconfig functions are wrong.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class INCORRECT_USAGE extends BLUECONFIG_ERROR {
/**
* @param {String} message Error message
*/
constructor(message) {
super(message)
this.type = 'INCORRECT_USAGE'
this.doc = 'Wrong usage of blueconfig function, maybe wrong parameter, fix your javascript code to continue.'
return this
}
}
/**
* Fired when we try to access to missed value (e.g.: `base.path.undefined.undefined.name` where `undefined` doesn't exist)
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class PATH_INVALID extends BLUECONFIG_ERROR {
/**
* @param {String} fullname Return the full selector of value missed (e.g.: `base.path.name`)
* @param {Array} path Return the nearest full selector before missed key (e.g.: `['base', 'path']`)
* @param {String} name Return the property name missing or invalid value
* @param {*} value Return the value (should be an object)
*/
constructor(fullname, path, name, value) {
const fullpath = unroot(stringifyPath([...path, name]))
const why = (() => {
const type = typeof value
if (type !== 'object') {
return `"${unroot(stringifyPath(path))}" is a ${type}`
} else if (value === null) {
return `"${unroot(stringifyPath(path))}" is null`
} else {
return `"${fullpath}" is not defined`
}
})()
super(`${fullname}: cannot find "${fullpath}" property because ${why}.`)
/**
* Return the full selector of value missed (e.g.: `base.path.name`)
*
* @var fullname
* @memberof PATH_INVALID
*/
this.fullname = fullname
/**
* Return the nearest full selector before missed key (e.g.: `base.path`)
*
* @var path
* @memberof PATH_INVALID
*/
this.path = path
/**
* Return the property name missing or invalid value
*
* @var name
* @memberof PATH_INVALID
*/
this.name = name
/**
* Return the value (should be an object)
*
* @var value
* @memberof PATH_INVALID
*/
this.value = value
/**
* Error explanation
*
* @var why
* @memberof PATH_INVALID
*/
this.why = why
this.type = 'PATH_INVALID'
this.doc = 'To fix this error you should try to use an existing property path (take a look on the schema), edit your javascript file to continue.'
return this
}
}
// =========================================
// ============== USER ERROR ===============
// === (values don't respect the schema) ===
// =========================================
// This is probably a config problem.
/**
* Validate failed because wrong value.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class VALUE_INVALID extends BLUECONFIG_ERROR {
/**
* @param {String} message Error message
*/
constructor(message) {
super(message)
this.type = 'VALUE_INVALID'
this.doc = 'You should try to change your config to respect the schema to continue.'
return this
}
}
/**
* Validate failed because wrong value.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class VALIDATE_FAILED extends BLUECONFIG_ERROR {
/**
* @param {String} explains List of explained error why validate failed
*/
constructor(explains) {
super('Validate failed because wrong value(s):\n' + explains)
/**
* List of explained error why validate failed (defined with the first argument of the constructor)
* @name why
* @memberof VALIDATE_FAILED
*/
this.why = explains
this.type = 'VALIDATE_FAILED'
this.doc = 'You should try to change your config to respect the schema to continue.'
return this
}
}
/**
* Value has wrong format.
*
* When an Error is caught in format function during the validation, FORMAT_INVALID is fired instead.
*
* @extends BLUECONFIG_ERROR
*
* @Memberof ZCUSTOMERROR
*/
class FORMAT_INVALID extends BLUECONFIG_ERROR {
/**
* @param {String} fullname Return the full selector (e.g.: `base.path.name`)
* @param {String} message Error message
* @param {Object} getter Getter
* @param {String} getter.name Getter name
* @param {String} getter.value Getter value (=Getter keyname)
* @param {String} getter Returned value by `Getter(keyname)`
*/
constructor(fullname, message, getter, value) {
super(message)
/**
* Return the full selector (e.g.: `base.path.name`)
*
* @var fullname
* @memberof FORMAT_INVALID
*/
this.fullname = fullname
/**
* Return the nearest full selector before missed key (e.g.: `base.path.name`)
*
* @var getter
* @typedef {Object}
* @property {string} name Getter name
* @property {string} value Getter keyname
* @memberof FORMAT_INVALID
*/
this.getter = {
name: getter.name,
keyname: getter.keyname
}
/**
* Returned value by `this.getter`
*
* @var value
* @memberof FORMAT_INVALID
*/
this.value = value
this.type = 'FORMAT_INVALID'
this.doc = 'You should try to change the property value to respect the schema to continue.'
return this
}
}
module.exports = {
BLUECONFIG_ERROR,
LISTOFERRORS,
// 1
SCHEMA_INVALID,
// 2
CUSTOMISE_FAILED,
INCORRECT_USAGE,
PATH_INVALID,
// 2
VALUE_INVALID,
VALIDATE_FAILED,
FORMAT_INVALID
}