Skip to content

Commit

Permalink
Merge branch 'release/0.7.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
charlespascoe committed Feb 9, 2018
2 parents 399f40f + 0f48914 commit 35612a6
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 76 deletions.
69 changes: 69 additions & 0 deletions lib/formatting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as colors from 'colors/safe';
import { ValidationError } from './validation-result';
import { keysOf } from './utils';


export function setColours(enabled: boolean) {
(colors as any).enabled = enabled;
}


setColours(false);


export function repeat(text: string, count: number): string {
let result = '';

for (let i = 0; i < count; i++) {
result += text;
}

return result;
}


export function increaseIndent(text: string, indent: number): string {
const indentPadding = repeat(' ', indent);
return indentPadding + text.split('\n').join('\n' + indentPadding);
}


export function pluralise(count: number, singular: string, plural: string): string {
return `${count} ${count === 1 ? singular : plural}`;
}


export function formatPath(root: string, path: Array<string | number>): string {
return colors.magenta(root) + path
.map(component => {
if (typeof component === 'number') {
return colors.yellow('[') + colors.red(`${component}`) + colors.yellow(']');
} else if (/^[$a-z_][$a-z_0-9]*$/i.test(component)) {
return colors.yellow('.') + colors.cyan(component);
} else {
return colors.yellow('[') + colors.red(`'${component.replace('\\', '\\\\').replace('\'', '\\\'')}'`) + colors.yellow(']')
}
})
.join('');
}


export function formatErrorResultMessage(prefix: string, root: string, errors: ValidationError[]): string {
return colors.white(colors.bgRed(colors.bold(`${prefix}${errors.length} validation error${errors.length === 1 ? '' : 's'}:`))) + '\n' +
errors.map(error => increaseIndent(error.toString(root), 4)).join('\n');
}


export function formatEitherValidationErrorMessages(errorsPerType: {[description: string]: ValidationError[]}): string {
return keysOf(errorsPerType)
.map(desc => {
const errors = errorsPerType[desc];

return increaseIndent(
colors.bold(colors.red(`Not ${desc}, due to ${pluralise(errors.length, 'validation error', 'validation errors')}:`)) + '\n' +
errors.map(error => increaseIndent(error.toString(), 4)).join('\n'),
4
);
})
.join('\n');
}
8 changes: 4 additions & 4 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { keysOf, tryCatch, primitiveType } from './utils';
import {
ArrayIndexPathNode,
error,
errorFromException,
ErrorResult,
SuccessResult,
KeyPathNode,
success,
ValidationError,
ValidationResult,
EitherValidationError
} from './validation-result';
export * from './validation-result';
export { setColours } from './formatting';
import { setColours } from './formatting';


export type Validator<T> = {
Expand Down Expand Up @@ -79,7 +79,7 @@ export function conformsTo<T>(validator: Validator<T>, optionsOrNext?: IValidati
);

if (!result.success) {
return errors.concat(result.addPathNode(new KeyPathNode(key)).errors);
return errors.concat(result.addPathSegment(key).errors);
}

partiallyValidated[key] = result.value;
Expand Down Expand Up @@ -266,7 +266,7 @@ export function eachItem<T>(assertion: (arg: any) => ValidationResult<T>, next?:
return new ErrorResult(
results
.map((item, index) => {
if (!item.success) item.addPathNode(new ArrayIndexPathNode(index));
if (!item.success) item.addPathSegment(index);
return item;
})
.filter<ErrorResult>(ErrorResult.isErrorResult)
Expand Down
20 changes: 0 additions & 20 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,6 @@ export function keysOf<T>(arg: T): Array<keyof T> {
}


export function repeat(text: string, count: number): string {
let result = '';

for (let i = 0; i < count; i++) {
result += text;
}

return result;
}


export function increaseIndent(text: string, indent: number): string {
const indentPadding = repeat(' ', indent);
return indentPadding + text.split('\n').join('\n' + indentPadding);
}


export function pluralise(count: number, singular: string, plural: string): string {
return `${count} ${count === 1 ? singular : plural}`;
}


export function primitiveType(arg: any): string {
Expand Down
60 changes: 10 additions & 50 deletions lib/validation-result.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
import { increaseIndent, keysOf, pluralise } from './utils';
import { formatPath, formatErrorResultMessage, formatEitherValidationErrorMessages } from './formatting';


export type ValidationResult<T> = SuccessResult<T> | ErrorResult;


export abstract class PathNode { }


export class KeyPathNode extends PathNode {
constructor(public readonly key: string) {
super();
}

public toString(): string {
if (/^[$a-z_][$a-z0-9_]*$/i.test(this.key)) {
return `.${this.key}`;
} else {
return `['${this.key.replace('\\', '\\\\').replace("'", "\\'")}']`;
}
}
}


export class ArrayIndexPathNode extends PathNode {
constructor(public readonly index: number) {
super();
}

public toString(): string {
return `[${this.index}]`;
}
}


export class ValidationError {
public readonly path: PathNode[] = [];
public readonly path: Array<string | number> = [];

constructor(
public readonly errorCode: string,
public readonly message: string,
) { }

public addPathNode(node: PathNode): ValidationError {
this.path.unshift(node);
public addPathSegment(seg: string | number): ValidationError {
this.path.unshift(seg);
return this;
}

Expand All @@ -51,7 +22,7 @@ export class ValidationError {
}

public pathString(root: string = '$'): string {
return root + this.path.map(node => node.toString()).join('');
return formatPath(root, this.path);
}
}

Expand All @@ -64,18 +35,7 @@ export class EitherValidationError extends ValidationError {
}

public toString(root: string = '$'): string {
return `${this.pathString(root)}: ${this.message} - the following assertions failed:\n` +
keysOf(this.errors)
.map(desc => {
const errors = this.errors[desc];

return increaseIndent(
`Not ${desc}, due to ${pluralise(errors.length, 'validation error', 'validation errors')}:\n` +
errors.map(error => increaseIndent(error.toString(), 4)).join('\n'),
4
);
})
.join('\n');
return `${this.pathString(root)}: ${this.message} - the following assertions failed:\n` + formatEitherValidationErrorMessages(this.errors);
}
}

Expand All @@ -93,16 +53,16 @@ export class ErrorResult {
}
}

public addPathNode(node: PathNode): ErrorResult {
public addPathSegment(seg: string | number): ErrorResult {
for (const error of this.errors) {
error.addPathNode(node);
error.addPathSegment(seg);
}

return this;
}

public toString(root: string = '$'): string {
return `${this.errors.length} validation error${this.errors.length === 1 ? '' : 's'}:\n${this.errors.map(error => increaseIndent(error.toString(root), 4)).join('\n')}`;
public toString(root: string = '$', prefix: string = ''): string {
return formatErrorResultMessage(prefix, root, this.errors);
}

public static isErrorResult(arg: any): arg is ErrorResult {
Expand Down
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typed-validation",
"version": "0.7.5",
"version": "0.7.6",
"description": "Validate Objects Against TypeScript Interfaces",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -28,6 +28,10 @@
},
"homepage": "https://github.com/cpascoe95/typed-validation#readme",
"devDependencies": {
"@types/colors": "1.1.3",
"typescript": "2.5.2"
},
"dependencies": {
"colors": "1.1.2"
}
}

0 comments on commit 35612a6

Please sign in to comment.