rttc
Version:
Runtime type-checking for JavaScript.
128 lines (119 loc) • 4.43 kB
JavaScript
/**
* Module dependencies
*/
var _ = require('@sailshq/lodash');
var getRdt = require('./get-rdt');
var getDisplayTypeLabel = require('./get-display-type-label');
var getNounPhrase = require('./get-noun-phrase');
var GRAMMAR = require('./GRAMMAR');
var inferDisplayType = require('./infer-display-type');
var coerceExemplar = require('./coerce-exemplar');
/**
* getInvalidityMessage()
*
* Get a formatted message explaining exactly how some data was invalid vs. some type schema,
* using the specified invalidity error from `rttc.validate()`/`rttc.validateStrict()` for
* guidance.
*
* @param {Ref} expectedTypeSchema
* @param {Ref} invalidData
* @param {Error} eInvalid [« an E_INVALID Error from rttc.validate() etc.]
* @param {String?} optionalDataLabel
*
* @returns {String}
*/
module.exports = function getInvalidityMessage(expectedTypeSchema, invalidData, eInvalid, optionalDataLabel){
var originNounPhrase = (function _gettingOriginNounPhrase(){
if (!optionalDataLabel) {
return 'data';//« formerly `getDisplayType(invalidData)`
} else {
var wasExpectingArray = _.isArray(expectedTypeSchema);
var gotArray = _.isArray(invalidData);
var wasExpectingDictionary = _.isObject(expectedTypeSchema) && !wasExpectingDictionary;
var gotDictionary = _.isObject(invalidData) && !gotArray;
if ((wasExpectingArray&&gotArray) || (wasExpectingArray&&gotDictionary)) {
return optionalDataLabel+' '+getDisplayTypeLabel(expectedTypeSchema, GRAMMAR.FRAGMENT);
} else {
return String(optionalDataLabel);
}
}
})();//:= (†)
return 'Invalid '+originNounPhrase+':\n · ' + (
_.without(_.map(eInvalid.errors, function(subErr) {
if (subErr.hops.length === 0) {
var actualTopLvlType = inferDisplayType(coerceExemplar(subErr.actual));
return (
subErr.actual===undefined?
'Expecting'
:
'Expecting'
)+' '+getNounPhrase(subErr.expected, GRAMMAR.INDEFINITE)
+(
subErr.actual===undefined?
'.'
:
', but got '+(
subErr.actual===Infinity||subErr.actual===-Infinity||_.isNaN(subErr.actual)?
subErr.actual
:
actualTopLvlType==='json' || actualTopLvlType==='ref'?
'some other '+getNounPhrase(actualTopLvlType, GRAMMAR.UNPRECEDED_FRAGMENT)
:
getNounPhrase(actualTopLvlType, GRAMMAR.INDEFINITE_FRAGMENT)
)+'.'
);
}
else {
var parentHops = subErr.hops.slice(0, -1);
var parentHopsHash = parentHops.join('.');
var parentSubErr = _.find(eInvalid.errors, function(otherSubErr){
return otherSubErr.hops.join('.') === parentHopsHash;
});
if (parentSubErr) { return ''; }
var isArrayItem = !_.isNaN(+(subErr.hops.slice(-1)[0]));
var expectedRdt = getRdt(subErr.expected);
var actualType = inferDisplayType(coerceExemplar(subErr.actual));
return (
isArrayItem?
'@ `'+_.reduce(parentHops, function(prettiedParentHops, hop){
if (+hop===hop){
prettiedParentHops += '['+hop+']';
} else {
prettiedParentHops += '.'+hop;
}
return prettiedParentHops;
}, '')+'['+(subErr.hops.slice(-1))+']`: '
:
'@ `' + subErr.hops.join('.') + '`: '
)+''+
(
subErr.actual===undefined?
'Missing property (expecting '+getNounPhrase(expectedRdt, GRAMMAR.INDEFINITE)+')'
:
'Expecting '+(
isArrayItem?
'array to contain only '+getNounPhrase(expectedRdt, GRAMMAR.UNPRECEDED_PLURAL)
:
''+getNounPhrase(expectedRdt, GRAMMAR.INDEFINITE)
)
)+''+
(
subErr.actual===undefined?
'.'
:
', but '+
(isArrayItem?'this item is':'got')+' '+
(
subErr.actual===Infinity||subErr.actual===-Infinity||_.isNaN(subErr.actual)?
subErr.actual
:
actualType==='json' || actualType==='ref'?
'some other '+getNounPhrase(actualType,GRAMMAR.UNPRECEDED_FRAGMENT)
:
getNounPhrase(actualType,GRAMMAR.INDEFINITE_FRAGMENT)
)+'.'
);
}
}), '').join('\n · ')
);
};