better-ajv-errors
Advanced tools
Comparing version 0.4.4 to 0.5.0-0
@@ -5,6 +5,2 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
@@ -26,4 +22,2 @@ | ||
var _debug = require('./debug'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -99,3 +93,3 @@ | ||
function createErrorInstances(root, indent) { | ||
function createErrorInstances(root, options) { | ||
var errors = (0, _utils.getErrors)(root); | ||
@@ -109,3 +103,3 @@ if (errors.length && errors.every(_utils.isEnumError)) { | ||
params: { allowedValues } | ||
}), indent)]; | ||
}), options)]; | ||
} else { | ||
@@ -115,10 +109,10 @@ return (0, _utils.concatAll)(errors.reduce(function (ret, error) { | ||
case 'additionalProperties': | ||
return ret.concat(new _validationErrors.AdditionalPropValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.AdditionalPropValidationError(error, options)); | ||
case 'required': | ||
return ret.concat(new _validationErrors.RequiredValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.RequiredValidationError(error, options)); | ||
default: | ||
return ret.concat(new _validationErrors.DefaultValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.DefaultValidationError(error, options)); | ||
} | ||
}, []))((0, _utils.getChildren)(root).map(function (child) { | ||
return createErrorInstances(child, indent); | ||
return createErrorInstances(child, options); | ||
})); | ||
@@ -128,10 +122,6 @@ } | ||
exports.default = function (ajvErrors, indent) { | ||
exports.default = function (ajvErrors, options) { | ||
var tree = makeTree(ajvErrors || []); | ||
filterRedundantErrors(tree); | ||
var errors = createErrorInstances(tree, indent); | ||
if (!errors) { | ||
(0, _debug.debug)((0, _stringify2.default)(tree)); | ||
} | ||
return errors; | ||
return createErrorInstances(tree, options); | ||
}; |
@@ -5,2 +5,10 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _jsonToAst = require('json-to-ast'); | ||
var _jsonToAst2 = _interopRequireDefault(_jsonToAst); | ||
var _helpers = require('./helpers'); | ||
@@ -10,34 +18,35 @@ | ||
var _debug = require('./debug'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.default = function () { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { schema, mode, indent }; | ||
return function () { | ||
var schema = options.schema, | ||
_options$mode = options.mode, | ||
mode = _options$mode === undefined ? 'print' : _options$mode, | ||
_options$indent = options.indent, | ||
indent = _options$indent === undefined ? 2 : _options$indent; | ||
exports.default = function (schema, data, errors) { | ||
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
var _options$format = options.format, | ||
format = _options$format === undefined ? 'cli' : _options$format, | ||
_options$indent = options.indent, | ||
indent = _options$indent === undefined ? null : _options$indent; | ||
return function (data, errors) { | ||
var customErrorToText = function customErrorToText(error) { | ||
return error.print(schema, data).join('\n'); | ||
}; | ||
var customErrorToStructure = function customErrorToStructure(error) { | ||
return error.getError(schema, data); | ||
}; | ||
var customErrors = (0, _helpers2.default)(errors, indent); | ||
var jsonRaw = (0, _stringify2.default)(data, null, indent); | ||
var jsonAst = (0, _jsonToAst2.default)(jsonRaw, { loc: true }); | ||
if (mode === 'print') { | ||
(0, _debug.log)(customErrors.map(customErrorToText).join()); | ||
} else { | ||
return customErrors.map(customErrorToStructure); | ||
} | ||
}; | ||
}(); | ||
var customErrorToText = function customErrorToText(error) { | ||
return error.print().join('\n'); | ||
}; | ||
var customErrorToStructure = function customErrorToStructure(error) { | ||
return error.getError(); | ||
}; | ||
var customErrors = (0, _helpers2.default)(errors, { | ||
data, | ||
schema, | ||
jsonAst, | ||
jsonRaw | ||
}); | ||
if (format === 'cli') { | ||
return customErrors.map(customErrorToText).join(); | ||
} else { | ||
return customErrors.map(customErrorToStructure); | ||
} | ||
}; | ||
module.exports = exports['default']; |
@@ -5,15 +5,30 @@ 'use strict'; | ||
exports.default = getMetaFromPath; | ||
function getMetaFromPath(jsonAst, dataPath, isIdentifierLocation) { | ||
// TODO: Handle json pointer escape notation and better error handling | ||
var pointers = dataPath.split('/').slice(1); | ||
var lastPointerIndex = pointers.length - 1; | ||
return pointers.reduce(function (obj, pointer, idx) { | ||
switch (obj.type) { | ||
case 'Object': | ||
{ | ||
var filtered = obj.children.filter(function (child) { | ||
return child.key.value === pointer; | ||
}); | ||
if (filtered.length !== 1) { | ||
throw new Error(`Couldn't find property ${pointer} of ${dataPath}`); | ||
} | ||
var _filtered$ = filtered[0], | ||
key = _filtered$.key, | ||
value = _filtered$.value; | ||
var _parse = require('./parse'); | ||
var _parse2 = _interopRequireDefault(_parse); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function getMetaFromPath(jsonString, dataPath) { | ||
// TODO: Handle json pointer escape notation and better error handling | ||
return (0, _parse.getMeta)(dataPath.split('/').slice(1).reduce(function (obj, pointer) { | ||
return (0, _parse.getValue)(obj, pointer); | ||
}, (0, _parse2.default)(jsonString))); | ||
return isIdentifierLocation && idx === lastPointerIndex ? key : value; | ||
} | ||
case 'Array': | ||
return obj.children[pointer]; | ||
default: | ||
// eslint-disable-next-line no-console | ||
console.log(obj); | ||
} | ||
}, jsonAst); | ||
} | ||
module.exports = exports['default']; |
@@ -5,20 +5,2 @@ 'use strict'; | ||
var _parse = require('./parse'); | ||
Object.defineProperty(exports, 'parse', { | ||
enumerable: true, | ||
get: function get() { | ||
return _interopRequireDefault(_parse).default; | ||
} | ||
}); | ||
var _print = require('./print'); | ||
Object.defineProperty(exports, 'print', { | ||
enumerable: true, | ||
get: function get() { | ||
return _interopRequireDefault(_print).default; | ||
} | ||
}); | ||
var _getMetaFromPath = require('./get-meta-from-path'); | ||
@@ -25,0 +7,0 @@ |
@@ -5,5 +5,5 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
@@ -26,4 +26,2 @@ var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -40,7 +38,14 @@ | ||
(0, _classCallCheck3.default)(this, AdditionalPropValidationError); | ||
return (0, _possibleConstructorReturn3.default)(this, _BaseValidationError.apply(this, arguments)); | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var _this = (0, _possibleConstructorReturn3.default)(this, _BaseValidationError.call.apply(_BaseValidationError, [this].concat(args))); | ||
_this.options.isIdentifierLocation = true; | ||
return _this; | ||
} | ||
AdditionalPropValidationError.prototype.print = function print(schema, data) { | ||
var output = []; | ||
AdditionalPropValidationError.prototype.print = function print() { | ||
var _options = this.options, | ||
@@ -51,27 +56,16 @@ message = _options.message, | ||
output.push(_chalk2.default`{red {bold ADDTIONAL PROPERTY} ${message}}\n`); | ||
var output = [_chalk2.default`{red {bold ADDTIONAL PROPERTY} ${message}}\n`]; | ||
return output.concat((0, _json.print)(data, `${dataPath}/${params.additionalProperty}`, { | ||
indent: this.indent | ||
})(function () { | ||
return _chalk2.default`đ˛ {bold ${params.additionalProperty}} is not expected to be here!`; | ||
})); | ||
return output.concat(this.getCodeFrame(_chalk2.default`đ˛ {magentaBright ${params.additionalProperty}} is not expected to be here!`, `${dataPath}/${params.additionalProperty}`)); | ||
}; | ||
AdditionalPropValidationError.prototype.getError = function getError(schema, data) { | ||
AdditionalPropValidationError.prototype.getError = function getError() { | ||
var _options2 = this.options, | ||
dataPath = _options2.dataPath, | ||
params = _options2.params; | ||
params = _options2.params, | ||
dataPath = _options2.dataPath; | ||
var jsonString = (0, _stringify2.default)(data, null, this.indent); | ||
var _getMetaFromPath = (0, _json.getMetaFromPath)(jsonString, dataPath), | ||
line = _getMetaFromPath.line, | ||
column = _getMetaFromPath.column; | ||
return { | ||
line, | ||
column, | ||
return (0, _assign2.default)({}, this.getLocation(`${dataPath}/${params.additionalProperty}`), { | ||
error: `Property ${params.additionalProperty} is not expected to be here` | ||
}; | ||
}); | ||
}; | ||
@@ -78,0 +72,0 @@ |
@@ -1,9 +0,13 @@ | ||
"use strict"; | ||
'use strict'; | ||
exports.__esModule = true; | ||
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _codeFrame = require('@babel/code-frame'); | ||
var _json = require('../json'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -13,10 +17,41 @@ | ||
function BaseValidationError() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var indent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2; | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { isIdentifierLocation: false }; | ||
var _ref = arguments[1]; | ||
var data = _ref.data, | ||
schema = _ref.schema, | ||
jsonAst = _ref.jsonAst, | ||
jsonRaw = _ref.jsonRaw; | ||
(0, _classCallCheck3.default)(this, BaseValidationError); | ||
this.options = options; | ||
this.indent = indent; | ||
this.data = data; | ||
this.schema = schema; | ||
this.jsonAst = jsonAst; | ||
this.jsonRaw = jsonRaw; | ||
} | ||
BaseValidationError.prototype.getLocation = function getLocation() { | ||
var dataPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.dataPath; | ||
var _options = this.options, | ||
isIdentifierLocation = _options.isIdentifierLocation, | ||
isSkipEndLocation = _options.isSkipEndLocation; | ||
var _getMetaFromPath = (0, _json.getMetaFromPath)(this.jsonAst, dataPath, isIdentifierLocation), | ||
loc = _getMetaFromPath.loc; | ||
return { | ||
start: loc.start, | ||
end: isSkipEndLocation ? undefined : loc.end | ||
}; | ||
}; | ||
BaseValidationError.prototype.getCodeFrame = function getCodeFrame(message) { | ||
var dataPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.dataPath; | ||
return (0, _codeFrame.codeFrameColumns)(this.jsonRaw, this.getLocation(dataPath), { | ||
highlightCode: true, | ||
message | ||
}); | ||
}; | ||
BaseValidationError.prototype.print = function print() { | ||
@@ -34,2 +69,2 @@ throw new Error(`Implement the 'print' method inside ${this.constructor.name}!`); | ||
exports.default = BaseValidationError; | ||
module.exports = exports["default"]; | ||
module.exports = exports['default']; |
@@ -5,5 +5,5 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
@@ -26,4 +26,2 @@ var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -43,17 +41,13 @@ | ||
DefaultValidationError.prototype.print = function print(schema, data) { | ||
var output = []; | ||
DefaultValidationError.prototype.print = function print() { | ||
var _options = this.options, | ||
keyword = _options.keyword, | ||
message = _options.message, | ||
dataPath = _options.dataPath; | ||
message = _options.message; | ||
output.push(_chalk2.default`{red {bold ${keyword}} ${message}}\n`); | ||
var output = [_chalk2.default`{red {bold ${keyword.toUpperCase()}} ${message}}\n`]; | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(function () { | ||
return _chalk2.default`âđŊ ${keyword} ${message}`; | ||
})); | ||
return output.concat(this.getCodeFrame(_chalk2.default`đđŊ {magentaBright ${keyword}} ${message}`)); | ||
}; | ||
DefaultValidationError.prototype.getError = function getError(schema, data) { | ||
DefaultValidationError.prototype.getError = function getError() { | ||
var _options2 = this.options, | ||
@@ -64,13 +58,6 @@ keyword = _options2.keyword, | ||
var jsonString = (0, _stringify2.default)(data, null, this.indent); | ||
var _getMetaFromPath = (0, _json.getMetaFromPath)(jsonString, dataPath), | ||
line = _getMetaFromPath.line, | ||
column = _getMetaFromPath.column; | ||
return { | ||
line, | ||
column, | ||
return (0, _assign2.default)({}, this.getLocation(), { | ||
error: `${dataPath}: ${keyword} ${message}` | ||
}; | ||
}); | ||
}; | ||
@@ -77,0 +64,0 @@ |
@@ -5,5 +5,5 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
@@ -34,4 +34,2 @@ var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -51,24 +49,15 @@ | ||
EnumValidationError.prototype.print = function print(schema, data) { | ||
var output = []; | ||
EnumValidationError.prototype.print = function print() { | ||
var _options = this.options, | ||
message = _options.message, | ||
dataPath = _options.dataPath, | ||
allowedValues = _options.params.allowedValues; | ||
var bestMatch = this.findBestMatch(data); | ||
var bestMatch = this.findBestMatch(); | ||
output.push(_chalk2.default`{red {bold ENUM} ${message}}`); | ||
output.push(_chalk2.default`{red (${allowedValues.join(', ')})}\n`); | ||
var output = [_chalk2.default`{red {bold ENUM} ${message}}`, _chalk2.default`{red (${allowedValues.join(', ')})}\n`]; | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(function () { | ||
if (bestMatch !== null) { | ||
return _chalk2.default`âđŊ Did you mean {bold ${bestMatch}} here?`; | ||
} else { | ||
return _chalk2.default`âđŊ Unexpected value, should be equal to one of the allowed values`; | ||
} | ||
})); | ||
return output.concat(this.getCodeFrame(bestMatch !== null ? _chalk2.default`đđŊ Did you mean {magentaBright ${bestMatch}} here?` : _chalk2.default`đđŊ Unexpected value, should be equal to one of the allowed values`)); | ||
}; | ||
EnumValidationError.prototype.getError = function getError(schema, data) { | ||
EnumValidationError.prototype.getError = function getError() { | ||
var _options2 = this.options, | ||
@@ -79,15 +68,7 @@ message = _options2.message, | ||
var jsonString = (0, _stringify2.default)(data, null, this.indent); | ||
var bestMatch = this.findBestMatch(); | ||
var _getMetaFromPath = (0, _json.getMetaFromPath)(jsonString, dataPath), | ||
line = _getMetaFromPath.line, | ||
column = _getMetaFromPath.column; | ||
var bestMatch = this.findBestMatch(data); | ||
var output = { | ||
line, | ||
column, | ||
var output = (0, _assign2.default)({}, this.getLocation(), { | ||
error: `${dataPath} ${message}: ${params.allowedValues.join(', ')}` | ||
}; | ||
}); | ||
@@ -101,3 +82,3 @@ if (bestMatch !== null) { | ||
EnumValidationError.prototype.findBestMatch = function findBestMatch(data) { | ||
EnumValidationError.prototype.findBestMatch = function findBestMatch() { | ||
var _options3 = this.options, | ||
@@ -107,3 +88,3 @@ dataPath = _options3.dataPath, | ||
var currentValue = _jsonpointer2.default.get(data, dataPath); | ||
var currentValue = _jsonpointer2.default.get(this.data, dataPath); | ||
@@ -110,0 +91,0 @@ if (!currentValue) { |
@@ -5,5 +5,5 @@ 'use strict'; | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _assign = require('babel-runtime/core-js/object/assign'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _assign2 = _interopRequireDefault(_assign); | ||
@@ -26,4 +26,2 @@ var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -43,32 +41,28 @@ | ||
RequiredValidationError.prototype.print = function print(schema, data) { | ||
var output = []; | ||
RequiredValidationError.prototype.getLocation = function getLocation() { | ||
var dataPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.dataPath; | ||
var _BaseValidationError$ = _BaseValidationError.prototype.getLocation.call(this, dataPath), | ||
start = _BaseValidationError$.start; | ||
return { start }; | ||
}; | ||
RequiredValidationError.prototype.print = function print() { | ||
var _options = this.options, | ||
message = _options.message, | ||
dataPath = _options.dataPath, | ||
params = _options.params; | ||
output.push(_chalk2.default`{red {bold REQUIRED} ${message}}\n`); | ||
var output = [_chalk2.default`{red {bold REQUIRED} ${message}}\n`]; | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(function () { | ||
return _chalk2.default`âšī¸ {bold ${params.missingProperty}} is missing here!`; | ||
})); | ||
return output.concat(this.getCodeFrame(_chalk2.default`âšī¸ {magentaBright ${params.missingProperty}} is missing here!`)); | ||
}; | ||
RequiredValidationError.prototype.getError = function getError(schema, data) { | ||
var _options2 = this.options, | ||
dataPath = _options2.dataPath, | ||
params = _options2.params; | ||
RequiredValidationError.prototype.getError = function getError() { | ||
var params = this.options.params; | ||
var jsonString = (0, _stringify2.default)(data, null, this.indent); | ||
var _getMetaFromPath = (0, _json.getMetaFromPath)(jsonString, dataPath), | ||
line = _getMetaFromPath.line, | ||
column = _getMetaFromPath.column; | ||
return { | ||
line, | ||
column, | ||
return (0, _assign2.default)({}, this.getLocation(), { | ||
error: `Required property ${params.missingProperty} is missing` | ||
}; | ||
}); | ||
}; | ||
@@ -75,0 +69,0 @@ |
@@ -12,4 +12,2 @@ 'use strict'; | ||
var _debug = require('./debug'); | ||
const JSON_POINTERS_REGEX = /\/[\w_-]+(\/\d+)?/g; | ||
@@ -76,3 +74,3 @@ | ||
function createErrorInstances(root, indent) { | ||
function createErrorInstances(root, options) { | ||
const errors = (0, _utils.getErrors)(root); | ||
@@ -84,3 +82,3 @@ if (errors.length && errors.every(_utils.isEnumError)) { | ||
params: { allowedValues } | ||
}), indent)]; | ||
}), options)]; | ||
} else { | ||
@@ -90,10 +88,10 @@ return (0, _utils.concatAll)(errors.reduce((ret, error) => { | ||
case 'additionalProperties': | ||
return ret.concat(new _validationErrors.AdditionalPropValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.AdditionalPropValidationError(error, options)); | ||
case 'required': | ||
return ret.concat(new _validationErrors.RequiredValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.RequiredValidationError(error, options)); | ||
default: | ||
return ret.concat(new _validationErrors.DefaultValidationError(error, indent)); | ||
return ret.concat(new _validationErrors.DefaultValidationError(error, options)); | ||
} | ||
}, []))((0, _utils.getChildren)(root).map(child => { | ||
return createErrorInstances(child, indent); | ||
return createErrorInstances(child, options); | ||
})); | ||
@@ -103,10 +101,6 @@ } | ||
exports.default = (ajvErrors, indent) => { | ||
exports.default = (ajvErrors, options) => { | ||
const tree = makeTree(ajvErrors || []); | ||
filterRedundantErrors(tree); | ||
const errors = createErrorInstances(tree, indent); | ||
if (!errors) { | ||
(0, _debug.debug)(JSON.stringify(tree)); | ||
} | ||
return errors; | ||
return createErrorInstances(tree, options); | ||
}; |
@@ -5,2 +5,6 @@ 'use strict'; | ||
var _jsonToAst = require('json-to-ast'); | ||
var _jsonToAst2 = _interopRequireDefault(_jsonToAst); | ||
var _helpers = require('./helpers'); | ||
@@ -10,22 +14,26 @@ | ||
var _debug = require('./debug'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
exports.default = (options = { schema, mode, indent }) => { | ||
const { schema, mode = 'print', indent = 2 } = options; | ||
exports.default = (schema, data, errors, options = {}) => { | ||
const { format = 'cli', indent = null } = options; | ||
return (data, errors) => { | ||
const customErrorToText = error => error.print(schema, data).join('\n'); | ||
const customErrorToStructure = error => error.getError(schema, data); | ||
const customErrors = (0, _helpers2.default)(errors, indent); | ||
const jsonRaw = JSON.stringify(data, null, indent); | ||
const jsonAst = (0, _jsonToAst2.default)(jsonRaw, { loc: true }); | ||
if (mode === 'print') { | ||
(0, _debug.log)(customErrors.map(customErrorToText).join()); | ||
} else { | ||
return customErrors.map(customErrorToStructure); | ||
} | ||
}; | ||
const customErrorToText = error => error.print().join('\n'); | ||
const customErrorToStructure = error => error.getError(); | ||
const customErrors = (0, _helpers2.default)(errors, { | ||
data, | ||
schema, | ||
jsonAst, | ||
jsonRaw | ||
}); | ||
if (format === 'cli') { | ||
return customErrors.map(customErrorToText).join(); | ||
} else { | ||
return customErrors.map(customErrorToStructure); | ||
} | ||
}; | ||
module.exports = exports['default']; |
@@ -5,13 +5,25 @@ 'use strict'; | ||
exports.default = getMetaFromPath; | ||
var _parse = require('./parse'); | ||
var _parse2 = _interopRequireDefault(_parse); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function getMetaFromPath(jsonString, dataPath) { | ||
function getMetaFromPath(jsonAst, dataPath, isIdentifierLocation) { | ||
// TODO: Handle json pointer escape notation and better error handling | ||
return (0, _parse.getMeta)(dataPath.split('/').slice(1).reduce((obj, pointer) => (0, _parse.getValue)(obj, pointer), (0, _parse2.default)(jsonString))); | ||
const pointers = dataPath.split('/').slice(1); | ||
const lastPointerIndex = pointers.length - 1; | ||
return pointers.reduce((obj, pointer, idx) => { | ||
switch (obj.type) { | ||
case 'Object': | ||
{ | ||
const filtered = obj.children.filter(child => child.key.value === pointer); | ||
if (filtered.length !== 1) { | ||
throw new Error(`Couldn't find property ${pointer} of ${dataPath}`); | ||
} | ||
const { key, value } = filtered[0]; | ||
return isIdentifierLocation && idx === lastPointerIndex ? key : value; | ||
} | ||
case 'Array': | ||
return obj.children[pointer]; | ||
default: | ||
// eslint-disable-next-line no-console | ||
console.log(obj); | ||
} | ||
}, jsonAst); | ||
} | ||
module.exports = exports['default']; |
@@ -5,20 +5,2 @@ 'use strict'; | ||
var _parse = require('./parse'); | ||
Object.defineProperty(exports, 'parse', { | ||
enumerable: true, | ||
get: function () { | ||
return _interopRequireDefault(_parse).default; | ||
} | ||
}); | ||
var _print = require('./print'); | ||
Object.defineProperty(exports, 'print', { | ||
enumerable: true, | ||
get: function () { | ||
return _interopRequireDefault(_print).default; | ||
} | ||
}); | ||
var _getMetaFromPath = require('./get-meta-from-path'); | ||
@@ -25,0 +7,0 @@ |
@@ -9,4 +9,2 @@ 'use strict'; | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -19,24 +17,20 @@ | ||
class AdditionalPropValidationError extends _base2.default { | ||
print(schema, data) { | ||
const output = []; | ||
constructor(...args) { | ||
super(...args); | ||
this.options.isIdentifierLocation = true; | ||
} | ||
print() { | ||
const { message, dataPath, params } = this.options; | ||
output.push(_chalk2.default`{red {bold ADDTIONAL PROPERTY} ${message}}\n`); | ||
const output = [_chalk2.default`{red {bold ADDTIONAL PROPERTY} ${message}}\n`]; | ||
return output.concat((0, _json.print)(data, `${dataPath}/${params.additionalProperty}`, { | ||
indent: this.indent | ||
})(() => { | ||
return _chalk2.default`đ˛ {bold ${params.additionalProperty}} is not expected to be here!`; | ||
})); | ||
return output.concat(this.getCodeFrame(_chalk2.default`đ˛ {magentaBright ${params.additionalProperty}} is not expected to be here!`, `${dataPath}/${params.additionalProperty}`)); | ||
} | ||
getError(schema, data) { | ||
const { dataPath, params } = this.options; | ||
const jsonString = JSON.stringify(data, null, this.indent); | ||
const { line, column } = (0, _json.getMetaFromPath)(jsonString, dataPath); | ||
getError() { | ||
const { params, dataPath } = this.options; | ||
return { | ||
line, | ||
column, | ||
return Object.assign({}, this.getLocation(`${dataPath}/${params.additionalProperty}`), { | ||
error: `Property ${params.additionalProperty} is not expected to be here` | ||
}; | ||
}); | ||
} | ||
@@ -43,0 +37,0 @@ } |
@@ -1,10 +0,34 @@ | ||
"use strict"; | ||
'use strict'; | ||
exports.__esModule = true; | ||
var _codeFrame = require('@babel/code-frame'); | ||
var _json = require('../json'); | ||
class BaseValidationError { | ||
constructor(options = {}, indent = 2) { | ||
constructor(options = { isIdentifierLocation: false }, { data, schema, jsonAst, jsonRaw }) { | ||
this.options = options; | ||
this.indent = indent; | ||
this.data = data; | ||
this.schema = schema; | ||
this.jsonAst = jsonAst; | ||
this.jsonRaw = jsonRaw; | ||
} | ||
getLocation(dataPath = this.options.dataPath) { | ||
const { isIdentifierLocation, isSkipEndLocation } = this.options; | ||
const { loc } = (0, _json.getMetaFromPath)(this.jsonAst, dataPath, isIdentifierLocation); | ||
return { | ||
start: loc.start, | ||
end: isSkipEndLocation ? undefined : loc.end | ||
}; | ||
} | ||
getCodeFrame(message, dataPath = this.options.dataPath) { | ||
return (0, _codeFrame.codeFrameColumns)(this.jsonRaw, this.getLocation(dataPath), { | ||
highlightCode: true, | ||
message | ||
}); | ||
} | ||
print() { | ||
@@ -19,2 +43,2 @@ throw new Error(`Implement the 'print' method inside ${this.constructor.name}!`); | ||
exports.default = BaseValidationError; | ||
module.exports = exports["default"]; | ||
module.exports = exports['default']; |
@@ -9,4 +9,2 @@ 'use strict'; | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -19,22 +17,15 @@ | ||
class DefaultValidationError extends _base2.default { | ||
print(schema, data) { | ||
const output = []; | ||
const { keyword, message, dataPath } = this.options; | ||
output.push(_chalk2.default`{red {bold ${keyword}} ${message}}\n`); | ||
print() { | ||
const { keyword, message } = this.options; | ||
const output = [_chalk2.default`{red {bold ${keyword.toUpperCase()}} ${message}}\n`]; | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(() => { | ||
return _chalk2.default`âđŊ ${keyword} ${message}`; | ||
})); | ||
return output.concat(this.getCodeFrame(_chalk2.default`đđŊ {magentaBright ${keyword}} ${message}`)); | ||
} | ||
getError(schema, data) { | ||
getError() { | ||
const { keyword, message, dataPath } = this.options; | ||
const jsonString = JSON.stringify(data, null, this.indent); | ||
const { line, column } = (0, _json.getMetaFromPath)(jsonString, dataPath); | ||
return { | ||
line, | ||
column, | ||
return Object.assign({}, this.getLocation(), { | ||
error: `${dataPath}: ${keyword} ${message}` | ||
}; | ||
}); | ||
} | ||
@@ -41,0 +32,0 @@ } |
@@ -17,4 +17,2 @@ 'use strict'; | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -27,30 +25,18 @@ | ||
class EnumValidationError extends _base2.default { | ||
print(schema, data) { | ||
const output = []; | ||
const { message, dataPath, params: { allowedValues } } = this.options; | ||
const bestMatch = this.findBestMatch(data); | ||
print() { | ||
const { message, params: { allowedValues } } = this.options; | ||
const bestMatch = this.findBestMatch(); | ||
output.push(_chalk2.default`{red {bold ENUM} ${message}}`); | ||
output.push(_chalk2.default`{red (${allowedValues.join(', ')})}\n`); | ||
const output = [_chalk2.default`{red {bold ENUM} ${message}}`, _chalk2.default`{red (${allowedValues.join(', ')})}\n`]; | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(() => { | ||
if (bestMatch !== null) { | ||
return _chalk2.default`âđŊ Did you mean {bold ${bestMatch}} here?`; | ||
} else { | ||
return _chalk2.default`âđŊ Unexpected value, should be equal to one of the allowed values`; | ||
} | ||
})); | ||
return output.concat(this.getCodeFrame(bestMatch !== null ? _chalk2.default`đđŊ Did you mean {magentaBright ${bestMatch}} here?` : _chalk2.default`đđŊ Unexpected value, should be equal to one of the allowed values`)); | ||
} | ||
getError(schema, data) { | ||
getError() { | ||
const { message, dataPath, params } = this.options; | ||
const jsonString = JSON.stringify(data, null, this.indent); | ||
const { line, column } = (0, _json.getMetaFromPath)(jsonString, dataPath); | ||
const bestMatch = this.findBestMatch(data); | ||
const bestMatch = this.findBestMatch(); | ||
const output = { | ||
line, | ||
column, | ||
const output = Object.assign({}, this.getLocation(), { | ||
error: `${dataPath} ${message}: ${params.allowedValues.join(', ')}` | ||
}; | ||
}); | ||
@@ -64,5 +50,5 @@ if (bestMatch !== null) { | ||
findBestMatch(data) { | ||
findBestMatch() { | ||
const { dataPath, params: { allowedValues } } = this.options; | ||
const currentValue = _jsonpointer2.default.get(data, dataPath); | ||
const currentValue = _jsonpointer2.default.get(this.data, dataPath); | ||
@@ -69,0 +55,0 @@ if (!currentValue) { |
@@ -9,4 +9,2 @@ 'use strict'; | ||
var _json = require('../json'); | ||
var _base = require('./base'); | ||
@@ -19,22 +17,20 @@ | ||
class RequiredValidationError extends _base2.default { | ||
print(schema, data) { | ||
const output = []; | ||
const { message, dataPath, params } = this.options; | ||
output.push(_chalk2.default`{red {bold REQUIRED} ${message}}\n`); | ||
getLocation(dataPath = this.options.dataPath) { | ||
const { start } = super.getLocation(dataPath); | ||
return { start }; | ||
} | ||
return output.concat((0, _json.print)(data, dataPath, { indent: this.indent })(() => { | ||
return _chalk2.default`âšī¸ {bold ${params.missingProperty}} is missing here!`; | ||
})); | ||
print() { | ||
const { message, params } = this.options; | ||
const output = [_chalk2.default`{red {bold REQUIRED} ${message}}\n`]; | ||
return output.concat(this.getCodeFrame(_chalk2.default`âšī¸ {magentaBright ${params.missingProperty}} is missing here!`)); | ||
} | ||
getError(schema, data) { | ||
const { dataPath, params } = this.options; | ||
const jsonString = JSON.stringify(data, null, this.indent); | ||
const { line, column } = (0, _json.getMetaFromPath)(jsonString, dataPath); | ||
getError() { | ||
const { params } = this.options; | ||
return { | ||
line, | ||
column, | ||
return Object.assign({}, this.getLocation(), { | ||
error: `Required property ${params.missingProperty} is missing` | ||
}; | ||
}); | ||
} | ||
@@ -41,0 +37,0 @@ } |
{ | ||
"name": "better-ajv-errors", | ||
"version": "0.4.4", | ||
"version": "0.5.0-0", | ||
"description": "JSON Schema validation for Human", | ||
@@ -26,3 +26,5 @@ "repository": "torifat/better-ajv-errors", | ||
"dependencies": { | ||
"chalk": "^2.3.0", | ||
"@babel/code-frame": "^7.0.0-beta.39", | ||
"chalk": "^2.3.1", | ||
"json-to-ast": "^2.0.2", | ||
"jsonpointer": "^4.0.1", | ||
@@ -34,3 +36,3 @@ "leven": "^2.1.0" | ||
"babel-core": "^6.26.0", | ||
"babel-jest": "^22.1.0", | ||
"babel-jest": "^22.2.2", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
@@ -41,10 +43,10 @@ "babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"codecov": "^3.0.0", | ||
"eslint": "^4.16.0", | ||
"eslint": "^4.17.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-plugin-jest": "^21.7.0", | ||
"flow-bin": "^0.63.1", | ||
"eslint-plugin-jest": "^21.8.0", | ||
"flow-bin": "^0.65.0", | ||
"husky": "^0.14.3", | ||
"jest": "^22.1.4", | ||
"jest": "^22.2.2", | ||
"jest-fixtures": "^0.6.0", | ||
"lint-staged": "^6.0.1", | ||
"lint-staged": "^6.1.0", | ||
"prettier": "^1.7.4" | ||
@@ -51,0 +53,0 @@ }, |
# better-ajv-errors | ||
JSON Schema validation for Human | ||
> JSON Schema validation for Human | ||
@@ -12,6 +12,4 @@ [![npm](https://img.shields.io/npm/v/better-ajv-errors.svg?style=flat-square)](https://www.npmjs.com/package/better-ajv-errors) | ||
![Enum Validation Error](https://user-images.githubusercontent.com/208544/32481143-2b4a529a-c3e6-11e7-9797-bb65e9886bce.png) | ||
<img width="539" alt="Enum Validation Error" src="https://user-images.githubusercontent.com/208544/36072188-6f559ed4-0f6f-11e8-9a23-0c0477ca7f58.png"> | ||
You can also use it in "return" mode when library returns structured errors. | ||
## Installation | ||
@@ -29,8 +27,8 @@ | ||
You need to validate data first with ajv. Then you can pass `validate.errors` object into `better-ajv-errors`. | ||
First, you need to validate your payload with `ajv`. If it's invalid then you can pass `validate.errors` object into `better-ajv-errors`. | ||
```js | ||
import Ajv from 'ajv'; | ||
import betterAjvErrors from 'better-ajv-errors'; | ||
// const Ajv = require('ajv'); | ||
import betterAjvErrors from 'better-ajv-errors'; | ||
// const betterAjvErrors = require('better-ajv-errors'); | ||
@@ -47,35 +45,65 @@ | ||
const valid = validate(data); | ||
``` | ||
### "Print" mode | ||
```js | ||
// ...validate data first | ||
const print = betterAjvErrors({ schema, mode: 'print', indent: 2 }); | ||
if (!valid) { | ||
print(data, validate.errors); | ||
const output = betterAjvErrors(schema, data, validate.errors); | ||
console.log(output); | ||
} | ||
``` | ||
### "Return" mode | ||
## API | ||
```js | ||
// ...validate data first | ||
const getHumanErrors = betterAjvErrors({ schema, mode: 'return', indent: 2 }); | ||
### betterAjvErrors(schema, data, errors, [options]) | ||
if (!valid) { | ||
const errors = getHumanErrors(data, validate.errors); | ||
Returns formatted validation error to **print** in `console`. See [`options.format`](#format) for further details. | ||
/* | ||
errors is array: [ | ||
{ | ||
"error": "You're using invalid field FOO", | ||
"line": 14, | ||
"column": 75, | ||
"suggestion": "Maybe you meant BAR?" | ||
} | ||
] | ||
*/ | ||
} | ||
#### schema | ||
Type: `Object` | ||
The JSON Schema you used for validation with `ajv` | ||
#### data | ||
Type: `Object` | ||
The JSON payload you validate against using `ajv` | ||
#### errors | ||
Type: `Array` | ||
Array of [ajv validation errors](https://github.com/epoberezkin/ajv#validation-errors) | ||
#### options | ||
Type: `Object` | ||
##### format | ||
Type: `string` | ||
Default: `cli` | ||
Values: `cli` `js` | ||
Use default `cli` output format if you want to **print** beautiful validation errors like following: | ||
<img width="539" alt="Enum Validation Error" src="https://user-images.githubusercontent.com/208544/36072188-6f559ed4-0f6f-11e8-9a23-0c0477ca7f58.png"> | ||
Or, use `js` if you are planning to use this with some API. Your output will look like following: | ||
```javascript | ||
[ | ||
{ | ||
start: { line: 6, column: 15, offset: 70 }, | ||
end: { line: 6, column: 26, offset: 81 }, | ||
error: | ||
'/content/0/type should be equal to one of the allowed values: panel, paragraph, ...', | ||
suggestion: 'Did you mean paragraph?' | ||
} | ||
]; | ||
``` | ||
##### indent | ||
Type: `number` `null` | ||
Default: `null` | ||
If you have an unindented JSON payload and you want the error output indented |
@@ -10,11 +10,10 @@ import { ErrorObject } from 'ajv'; | ||
export interface IInputOptions { | ||
schema: any; | ||
mode?: 'print' | 'return'; | ||
indent?: number; | ||
format?: 'cli' | 'js'; | ||
indent?: number | null; | ||
} | ||
export interface IOutputError { | ||
start: { line: number; column: number; offset: number }; | ||
end?: { line: number; column: number; offset: number }; | ||
error: string; | ||
line: number; | ||
column: number; | ||
suggestion?: string; | ||
@@ -24,8 +23,9 @@ } | ||
export interface IBetterAjvErrors { | ||
(options: betterAjvErrors.IInputOptions): betterAjvErrors.IPrintErrors; | ||
( | ||
schema: any, | ||
data: any, | ||
errors: ErrorObject[], | ||
options: betterAjvErrors.IInputOptions | ||
): betterAjvErrors.IOutputError[] | void; | ||
} | ||
export interface IPrintErrors { | ||
(data: any, errors: ErrorObject[]): betterAjvErrors.IOutputError[] | void; | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
107
45110
6
29
921
+ Addedjson-to-ast@^2.0.2
+ Added@babel/code-frame@7.24.7(transitive)
+ Added@babel/helper-validator-identifier@7.24.7(transitive)
+ Added@babel/highlight@7.24.7(transitive)
+ Addedcode-error-fragment@0.0.230(transitive)
+ Addedgrapheme-splitter@1.0.4(transitive)
+ Addedjs-tokens@4.0.0(transitive)
+ Addedjson-to-ast@2.1.0(transitive)
+ Addedpicocolors@1.1.0(transitive)
Updatedchalk@^2.3.1