Skip to content
This repository was archived by the owner on Oct 7, 2021. It is now read-only.

Commit 0cabea4

Browse files
committed
Updated from version 1.1.0 to 1.2.0
1 parent b634d5e commit 0cabea4

20 files changed

+515
-245
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212

1313
---
1414

15-
## [next](https://github.com/foxifyjs/schema/releases/tag/next) - _(2018-**-**)_
15+
## [v1.2.0](https://github.com/foxifyjs/schema/releases/tag/v1.2.0) - _(2018-07-02)_
1616

1717
- :boom: All methods are functions now (`.required` => `.required()`)
18+
- :boom: All error messages are changed
19+
- :zap: Made `validate` method in all schema types publicly accessible
20+
- :zap: Added `details` property to all schema types to make some inside details publicly accessible
21+
- :zap: Added `unknown` method to object schema type
1822
- :zap: Added `min` method to object schema type
1923
- :zap: Added `max` method to object schema type
2024
- :zap: Added `length` method to object schema type

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,15 @@ npm i -s @foxify/schema
4848
const Schema = require("@foxify/schema");
4949

5050
const schema = {
51-
username: Schema.string().alphanum().required(),
51+
username: Schema.string()
52+
.alphanum()
53+
.required(),
5254
name: {
53-
first: Schema.string().min(3).required(),
55+
first: Schema.string()
56+
.min(3)
57+
.required(),
5458
last: Schema.string().min(3),
55-
},
59+
}, // since "name" has a required field, "name" itself would become required too
5660
datetime: Schema.date().default(Date.now),
5761
};
5862

@@ -70,7 +74,7 @@ We use [SemVer](http://semver.org) for versioning. For the versions available, s
7074

7175
## Authors
7276

73-
- **Ardalan Amini** - *Core Maintainer* - [@ardalanamini](https://github.com/ardalanamini)
77+
- **Ardalan Amini** - _Core Maintainer_ - [@ardalanamini](https://github.com/ardalanamini)
7478

7579
See also the list of [contributors](https://github.com/foxifyjs/schema/contributors) who participated in this project.
7680

docs/README.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ TypeScript ready object schema validation
2727
- [`.multipliedBy(num: number)`](#multipliedBynum-number)
2828
- [Object](#Object)
2929
- [`object(obj: object)`](#objectobj-object)
30+
- [`unknown()`](#unknown)
3031
- [`min(n: number)`](#minn-number)
3132
- [`max(n: number)`](#maxn-number)
3233
- [`length(n: number)`](#lengthn-number)
@@ -282,6 +283,24 @@ const schema = {
282283
};
283284
```
284285

286+
##### `unknown()`
287+
288+
Determines that the unknown keys should be included in the resulted object too (without any validation of course)
289+
290+
```typescript
291+
const schema = {
292+
foo: Schema.object({ bar: Schema.number() }).unknown(),
293+
};
294+
```
295+
296+
Please note that it won't be necessary if you're not specifying the object keys like the example below:
297+
298+
```typescript
299+
const schema = {
300+
foo: Schema.object(),
301+
};
302+
```
303+
285304
##### `min(n: number)`
286305

287306
Insures that the given object has at least `n` key(s)
@@ -479,9 +498,24 @@ Validates the given value according to the given schema
479498
```typescript
480499
const result = Schema.validate(schema, value);
481500
/*
482-
* {
501+
* interface {
483502
* errors: { [path to the wrong value]: Array<error string> } | null,
484503
* value: object,
485504
* }
486505
*/
487506
```
507+
508+
You can also validate any schema type directly like the example below
509+
510+
```typescript
511+
const result = Schema.number()
512+
.min(22)
513+
.required()
514+
.validate(value);
515+
/*
516+
* interface {
517+
* errors: { [path to the wrong value]: Array<error string> } | null,
518+
* value: number,
519+
* }
520+
*/
521+
```

package.json

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@foxify/schema",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "TypeScript schema validation",
55
"author": {
66
"name": "Ardalan Amini",
@@ -21,7 +21,41 @@
2121
"javascript",
2222
"typescript",
2323
"schema",
24-
"validation"
24+
"validation",
25+
"default",
26+
"required",
27+
"array",
28+
"min",
29+
"max",
30+
"length",
31+
"items",
32+
"boolean",
33+
"date",
34+
"number",
35+
"port",
36+
"integer",
37+
"positive",
38+
"negative",
39+
"precision",
40+
"multipliedBy",
41+
"object",
42+
"keys",
43+
"unknown",
44+
"string",
45+
"token",
46+
"alphanum",
47+
"numeral",
48+
"ip",
49+
"ipv4",
50+
"ipv6",
51+
"email",
52+
"credit",
53+
"card",
54+
"credit-card",
55+
"regex",
56+
"enum",
57+
"truncate",
58+
"replace"
2559
],
2660
"main": "dist/index.js",
2761
"types": "dist/index.d.ts",

src/Any.ts

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,106 @@
11
import assert from "assert";
2-
import { func, object, string, TYPE } from "./utils";
2+
import { func, mergeErrors, NULL, TYPE } from "./utils";
33

44
const { isFunction } = func;
5-
const { forEach } = object;
6-
const { isString } = string;
75

86
namespace Type {
9-
export type PipelineItem<T> = (
10-
value: T,
11-
path: string,
12-
) => { value: T; errors: string | { [key: string]: string } };
7+
export type Error<T> =
8+
| string[]
9+
| string
10+
| null
11+
| (T extends object
12+
? { [key in string | number]: string[] }
13+
: T extends any[]
14+
? { [key: string]: string[] }
15+
: null);
16+
17+
export type PipelineItem<T> = (value: T) => { value: T; errors: Error<T> };
18+
19+
export interface ValidationResult<T> {
20+
value: T;
21+
errors: Error<T>;
22+
}
1323

1424
export interface Options<T> {
1525
def: () => T | undefined;
1626
required: boolean;
1727
}
1828
}
1929

20-
abstract class Type<T = any> {
30+
abstract class Type<T = any, O extends object = {}> {
2131
public static isType = (value: any): value is Type => value instanceof Type;
2232

2333
protected static type: string = TYPE.ANY;
2434

25-
protected _options: Type.Options<T> = {
35+
public details: Type.Options<T> & O = {
2636
def: () => undefined,
2737
required: false,
28-
};
38+
} as Type.Options<T> & O;
2939

3040
protected _pipeline: Array<Type.PipelineItem<T>> = [];
3141

3242
public default(value: T | (() => T)) {
3343
if (isFunction(value)) {
34-
this._options.def = value;
44+
this.details.def = value;
3545

3646
return this;
3747
}
3848

3949
assert(
4050
!this._base(value),
41-
`The given value must be of "${
42-
(this.constructor as typeof Type).type
43-
}" type`,
51+
`Expected value to be ${(this.constructor as typeof Type).type}`,
4452
);
4553

46-
this._options.def = () => value;
54+
this.details.def = () => value;
4755

4856
return this;
4957
}
5058

5159
public required(required = true) {
52-
this._options.required = required;
60+
this.details.required = required;
5361

5462
return this;
5563
}
5664

57-
protected _pipe(...items: Array<Type.PipelineItem<T>>) {
58-
this._pipeline = this._pipeline.concat(items);
59-
60-
return this;
61-
}
62-
63-
protected _validate(
64-
path: string,
65-
value: any,
66-
): { value: T; errors: { [key: string]: string[] } } {
67-
const { def, required } = this._options;
65+
public validate(value: any): Type.ValidationResult<T> {
66+
const { def, required } = this.details;
6867

6968
if (value == null) {
7069
value = def();
7170

7271
if (value == null) {
7372
if (required) {
74-
return { value, errors: { [path]: ["Must be provided"] } };
73+
return {
74+
value,
75+
errors: ["Expected to be provided"],
76+
};
7577
}
7678

77-
return { value, errors: {} };
79+
return { value, errors: NULL };
7880
}
7981
}
8082

8183
const baseError = this._base(value);
82-
if (baseError) return { value, errors: { [path]: [baseError] } };
84+
if (baseError) return { value, errors: [baseError] };
8385

84-
const errors = this._pipeline.reduce(
86+
return this._pipeline.reduce(
8587
(prev, tester) => {
86-
const result = tester(value, path);
87-
88-
value = result.value;
89-
90-
let errs = result.errors;
88+
const result = tester(prev.value);
9189

92-
if (isString(errs)) errs = { [path]: errs };
90+
prev.value = result.value;
9391

94-
forEach(errs, (err: any, key) => {
95-
if (!Array.isArray(err)) err = [err];
96-
97-
if (prev[key]) {
98-
prev[key] = prev[key].concat(err);
99-
100-
return;
101-
}
102-
103-
prev[key] = err;
104-
});
92+
prev.errors = mergeErrors<T>(prev.errors, result.errors);
10593

10694
return prev;
10795
},
108-
{} as { [key: string]: string[] },
96+
{ value, errors: NULL as Type.ValidationResult<T>["errors"] },
10997
);
98+
}
11099

111-
return {
112-
errors,
113-
value,
114-
};
100+
protected _pipe(...items: Array<Type.PipelineItem<T>>) {
101+
this._pipeline = this._pipeline.concat(items);
102+
103+
return this;
115104
}
116105

117106
protected abstract _base(value: any): string | null;

0 commit comments

Comments
 (0)