Skip to content

Commit

Permalink
feat: improve hints
Browse files Browse the repository at this point in the history
  • Loading branch information
vankop authored May 18, 2020
1 parent d4bfe21 commit a36e535
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 84 deletions.
36 changes: 18 additions & 18 deletions declarations/ValidationError.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ export default ValidationError;
export type JSONSchema6 = import('json-schema').JSONSchema6;
export type JSONSchema7 = import('json-schema').JSONSchema7;
export type Schema =
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7;
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend);
export type ValidationErrorConfiguration = {
name?: string | undefined;
baseDataPath?: string | undefined;
Expand All @@ -31,9 +31,9 @@ declare class ValidationError extends Error {
children?: import('ajv').ErrorObject[] | undefined;
})[],
schema:
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7,
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend),
configuration?: import('./validate').ValidationErrorConfiguration
);
/** @type {Array<SchemaUtilErrorObject>} */
Expand All @@ -53,19 +53,19 @@ declare class ValidationError extends Error {
getSchemaPart(
path: string
):
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7;
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend);
/**
* @param {Schema} schema
* @param {Array<Object>} prevSchemas
* @returns {string}
*/
formatSchema(
schema:
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7,
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend),
prevSchemas?: Object[]
): string;
/**
Expand All @@ -76,9 +76,9 @@ declare class ValidationError extends Error {
*/
getSchemaPartText(
schemaPart?:
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend)
| undefined,
additionalPath?: boolean | string[] | undefined,
needDot?: boolean | undefined
Expand All @@ -89,9 +89,9 @@ declare class ValidationError extends Error {
*/
getSchemaPartDescription(
schemaPart?:
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend)
| undefined
): string;
/**
Expand Down
18 changes: 18 additions & 0 deletions declarations/util/hints.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function stringHints(
schema:
| (import('json-schema').JSONSchema4 & import('../validate').Extend)
| (import('json-schema').JSONSchema6 & import('../validate').Extend)
| (import('json-schema').JSONSchema7 & import('../validate').Extend),
logic: boolean
): string[];
export function numberHints(
schema:
| (import('json-schema').JSONSchema4 & import('../validate').Extend)
| (import('json-schema').JSONSchema6 & import('../validate').Extend)
| (import('json-schema').JSONSchema7 & import('../validate').Extend),
logic: boolean
): string[];
export type Schema =
| (import('json-schema').JSONSchema4 & import('../validate').Extend)
| (import('json-schema').JSONSchema6 & import('../validate').Extend)
| (import('json-schema').JSONSchema7 & import('../validate').Extend);
18 changes: 12 additions & 6 deletions declarations/validate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ export type JSONSchema4 = import('json-schema').JSONSchema4;
export type JSONSchema6 = import('json-schema').JSONSchema6;
export type JSONSchema7 = import('json-schema').JSONSchema7;
export type ErrorObject = Ajv.ErrorObject;
export type Extend = {
formatMinimum?: number | undefined;
formatMaximum?: number | undefined;
formatExclusiveMinimum?: boolean | undefined;
formatExclusiveMaximum?: boolean | undefined;
};
export type Schema =
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7;
| (import('json-schema').JSONSchema4 & Extend)
| (import('json-schema').JSONSchema6 & Extend)
| (import('json-schema').JSONSchema7 & Extend);
export type SchemaUtilErrorObject = Ajv.ErrorObject & {
children?: Ajv.ErrorObject[] | undefined;
};
Expand All @@ -29,9 +35,9 @@ export type ValidationErrorConfiguration = {
*/
declare function validate(
schema:
| import('json-schema').JSONSchema4
| import('json-schema').JSONSchema6
| import('json-schema').JSONSchema7,
| (import('json-schema').JSONSchema4 & Extend)
| (import('json-schema').JSONSchema6 & Extend)
| (import('json-schema').JSONSchema7 & Extend),
options: object | object[],
configuration?: ValidationErrorConfiguration | undefined
): void;
Expand Down
69 changes: 16 additions & 53 deletions src/ValidationError.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Range = require('./util/Range');
const { stringHints, numberHints } = require('./util/hints');

/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
Expand Down Expand Up @@ -224,7 +224,7 @@ function likeInteger(schema) {
}

/**
* @param {Schema & {formatMinimum?: string; formatMaximum?: string;}} schema
* @param {Schema} schema
* @returns {boolean}
*/
function likeString(schema) {
Expand Down Expand Up @@ -332,47 +332,6 @@ function getSchemaNonTypes(schema) {
return '';
}

/**
* @param {Schema=} schema
* @returns {Array<string>}
*/
function numberHints(schema) {
if (!schema) {
return [];
}

const hints = [];
const range = new Range();

if (typeof schema.minimum === 'number') {
range.left(schema.minimum);
}

if (typeof schema.exclusiveMinimum === 'number') {
range.left(schema.exclusiveMinimum, true);
}

if (typeof schema.maximum === 'number') {
range.right(schema.maximum);
}

if (typeof schema.exclusiveMaximum === 'number') {
range.right(schema.exclusiveMaximum, true);
}

const rangeFormat = range.format();

if (rangeFormat) {
hints.push(rangeFormat);
}

if (typeof schema.multipleOf === 'number') {
hints.push(`should be multiple of ${schema.multipleOf}`);
}

return hints;
}

/**
* @param {Array<string>} hints
* @returns {string}
Expand All @@ -383,14 +342,16 @@ function formatHints(hints) {

/**
* @param {Schema} schema
* @returns {string}
* @returns {string[]}
*/
function getHints(schema) {
if (likeNumber(schema) || likeInteger(schema)) {
return formatHints(numberHints(schema));
return numberHints(schema, true);
} else if (likeString(schema)) {
return stringHints(schema, true);
}

return '';
return [];
}

class ValidationError extends Error {
Expand Down Expand Up @@ -563,10 +524,10 @@ class ValidationError extends Error {
}

if (likeNumber(schema) || likeInteger(schema)) {
const type = schema.type === 'integer' ? 'integer' : 'number';
const hints = getHints(schema);
const [type, ...hints] = getHints(schema);
const str = `${type}${hints.length > 0 ? ` ${formatHints(hints)}` : ''}`;

return `${type}${hints.length > 0 ? ` ${hints}` : ''}`;
return str;
}

if (likeString(schema)) {
Expand Down Expand Up @@ -1017,7 +978,7 @@ class ValidationError extends Error {
comparison,
limit,
} = /** @type {import("ajv").ComparisonParams} */ (params);
const hints = numberHints(parentSchema);
const [, ...hints] = getHints(/** @type {Schema} */ (parentSchema));

if (hints.length === 0) {
hints.push(`should be ${comparison} ${limit}`);
Expand Down Expand Up @@ -1099,11 +1060,13 @@ class ValidationError extends Error {
case 'maxLength': {
const { params, parentSchema } = error;
const { limit } = /** @type {import("ajv").LimitParams} */ (params);
const max = limit + 1;

return `${dataPath} should be shorter than ${limit +
1} characters${getSchemaNonTypes(
return `${dataPath} should be shorter than ${max} character${
max > 1 ? 's' : ''
}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(
parentSchema
)}.${this.getSchemaPartDescription(parentSchema)}`;
)}`;
}
case 'maxItems': {
const { params, parentSchema } = error;
Expand Down
123 changes: 123 additions & 0 deletions src/util/hints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const Range = require('./Range');

/** @typedef {import("../validate").Schema} Schema */

/**
* @param {Schema} schema
* @param {boolean} logic
* @return {string[]}
*/
module.exports.stringHints = function stringHints(schema, logic) {
const hints = [];
let type = 'string';
const currentSchema = { ...schema };

This comment has been minimized.

Copy link
@Dante040591

Dante040591 May 29, 2020

has error on webpack build:
Module build failed (from ./node_modules/babel-loader/lib/index.js):
/Users/andrew/Projects/.....com/app/Resources/frontend/webpack/node_modules/schema-utils/dist/util/hints.js:16
const currentSchema = {...schema};
^^^
SyntaxError: Unexpected token ...

This comment has been minimized.

Copy link
@alexander-akait

alexander-akait May 29, 2020

Member

Update node to 8.9

This comment has been minimized.

Copy link
@alexander-akait

alexander-akait May 29, 2020

Member

Better to 10.13

This comment has been minimized.

Copy link
@akeinhell

akeinhell Jun 5, 2020

@evilebottnawi in semver idealogy - its a breaking change

This comment has been minimized.

Copy link
@alexander-akait

alexander-akait Jun 5, 2020

Member

@akeinhell no, we don't support node < 8, open CHANGELOG and read it for 2 version


if (!logic) {
const tmpLength = currentSchema.minLength;
const tmpFormat = currentSchema.formatMinimum;
const tmpExclusive = currentSchema.formatExclusiveMaximum;

currentSchema.minLength = currentSchema.maxLength;
currentSchema.maxLength = tmpLength;
currentSchema.formatMinimum = currentSchema.formatMaximum;
currentSchema.formatMaximum = tmpFormat;
currentSchema.formatExclusiveMaximum = !currentSchema.formatExclusiveMinimum;
currentSchema.formatExclusiveMinimum = !tmpExclusive;
}

if (typeof currentSchema.minLength === 'number') {
if (currentSchema.minLength === 1) {
type = 'non-empty string';
} else {
const length = Math.max(currentSchema.minLength - 1, 0);
hints.push(
`should be longer than ${length} character${length > 1 ? 's' : ''}`
);
}
}

if (typeof currentSchema.maxLength === 'number') {
if (currentSchema.maxLength === 0) {
type = 'empty string';
} else {
const length = currentSchema.maxLength + 1;
hints.push(
`should be shorter than ${length} character${length > 1 ? 's' : ''}`
);
}
}

if (currentSchema.pattern) {
hints.push(
`should${logic ? '' : ' not'} match pattern ${JSON.stringify(
currentSchema.pattern
)}`
);
}

if (currentSchema.format) {
hints.push(
`should${logic ? '' : ' not'} match format ${JSON.stringify(
currentSchema.format
)}`
);
}

if (currentSchema.formatMinimum) {
hints.push(
`should be ${
currentSchema.formatExclusiveMinimum ? '>' : '>='
} ${JSON.stringify(currentSchema.formatMinimum)}`
);
}

if (currentSchema.formatMaximum) {
hints.push(
`should be ${
currentSchema.formatExclusiveMaximum ? '<' : '<='
} ${JSON.stringify(currentSchema.formatMaximum)}`
);
}

return [type].concat(hints);
};

/**
* @param {Schema} schema
* @param {boolean} logic
* @return {string[]}
*/
module.exports.numberHints = function numberHints(schema, logic) {
const hints = [schema.type === 'integer' ? 'integer' : 'number'];
const range = new Range();

if (typeof schema.minimum === 'number') {
range.left(schema.minimum);
}

if (typeof schema.exclusiveMinimum === 'number') {
range.left(schema.exclusiveMinimum, true);
}

if (typeof schema.maximum === 'number') {
range.right(schema.maximum);
}

if (typeof schema.exclusiveMaximum === 'number') {
range.right(schema.exclusiveMaximum, true);
}

const rangeFormat = range.format(logic);

if (rangeFormat) {
hints.push(rangeFormat);
}

if (typeof schema.multipleOf === 'number') {
hints.push(
`should${logic ? '' : ' not'} be multiple of ${schema.multipleOf}`
);
}

return hints;
};
10 changes: 9 additions & 1 deletion src/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import ValidationError from './ValidationError';
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
/** @typedef {import("ajv").ErrorObject} ErrorObject */

/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7)} Schema */
/**
* @typedef {Object} Extend
* @property {number=} formatMinimum
* @property {number=} formatMaximum
* @property {boolean=} formatExclusiveMinimum
* @property {boolean=} formatExclusiveMaximum
*/

/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7) & Extend} Schema */

/** @typedef {ErrorObject & { children?: Array<ErrorObject>}} SchemaUtilErrorObject */

Expand Down
Loading

0 comments on commit a36e535

Please sign in to comment.