ejv 1.1.10 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +88 -0
- package/.mocharc.json +8 -0
- package/CHANGELOG.md +70 -29
- package/README-KR.md +6 -2
- package/README.md +6 -2
- package/build/{constants.js → cjs/constants.js} +117 -118
- package/build/cjs/constants.js.map +1 -0
- package/build/cjs/ejv.js +1263 -0
- package/build/cjs/ejv.js.map +1 -0
- package/build/{public_api.js → cjs/index.js} +14 -14
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/interfaces.js +29 -0
- package/build/cjs/interfaces.js.map +1 -0
- package/build/cjs/package.json +1 -0
- package/build/{tester.js → cjs/tester.js} +273 -268
- package/build/cjs/tester.js.map +1 -0
- package/build/cjs/util.js +103 -0
- package/build/cjs/util.js.map +1 -0
- package/build/constants.d.ts +101 -104
- package/build/ejv.d.ts +2 -2
- package/build/esm/constants.js +115 -0
- package/build/esm/constants.js.map +1 -0
- package/build/esm/ejv.js +1261 -0
- package/build/esm/ejv.js.map +1 -0
- package/build/esm/index.js +4 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/interfaces.js +33 -0
- package/build/esm/interfaces.js.map +1 -0
- package/build/esm/package.json +1 -0
- package/build/esm/tester.js +240 -0
- package/build/esm/tester.js.map +1 -0
- package/build/esm/util.js +96 -0
- package/build/esm/util.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/interfaces.d.ts +78 -38
- package/build/scripts/add-js-extensions.js +46 -0
- package/build/scripts/add-js-extensions.js.map +1 -0
- package/build/tester.d.ts +33 -34
- package/build/util.d.ts +7 -1
- package/package.json +48 -37
- package/scripts/add-js-extensions.ts +59 -0
- package/spec/ArrayScheme.ts +1021 -0
- package/spec/CommonScheme.ts +251 -0
- package/spec/DateScheme.ts +472 -0
- package/spec/NumberScheme.ts +1032 -0
- package/spec/ObjectScheme.ts +499 -0
- package/spec/RegExpScheme.ts +112 -0
- package/spec/StringScheme.ts +1239 -0
- package/spec/common-test-util.ts +63 -0
- package/spec/ejv.spec.ts +133 -4558
- package/spec/testers.spec.ts +17 -16
- package/src/constants.ts +41 -42
- package/src/ejv.ts +1141 -564
- package/src/index.ts +14 -0
- package/src/interfaces.ts +127 -41
- package/src/tester.ts +75 -69
- package/src/util.ts +106 -41
- package/tsconfig.cjs.json +8 -0
- package/tsconfig.esm.json +7 -0
- package/tsconfig.json +21 -18
- package/tsconfig.scripts.json +14 -0
- package/tsconfig.types.json +9 -0
- package/build/constants.js.map +0 -1
- package/build/ejv.js +0 -685
- package/build/ejv.js.map +0 -1
- package/build/interfaces.js +0 -15
- package/build/interfaces.js.map +0 -1
- package/build/public_api.d.ts +0 -3
- package/build/public_api.js.map +0 -1
- package/build/tester.js.map +0 -1
- package/build/util.js +0 -66
- package/build/util.js.map +0 -1
- package/spec/common-test-runner.ts +0 -17
- package/src/public_api.ts +0 -3
- package/tsconfig.spec.json +0 -19
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { ejv } from './ejv';
|
|
2
|
+
export { DataType, NumberFormat, StringFormat, ErrorMsg, ErrorType } from './constants';
|
|
3
|
+
export {
|
|
4
|
+
BooleanScheme,
|
|
5
|
+
NumberScheme,
|
|
6
|
+
StringScheme,
|
|
7
|
+
ObjectScheme,
|
|
8
|
+
ArrayScheme,
|
|
9
|
+
RegExpScheme,
|
|
10
|
+
DateScheme,
|
|
11
|
+
EjvError,
|
|
12
|
+
Scheme,
|
|
13
|
+
Options
|
|
14
|
+
} from './interfaces';
|
package/src/interfaces.ts
CHANGED
|
@@ -1,63 +1,149 @@
|
|
|
1
1
|
import { DataType, ErrorType, NumberFormat, StringFormat } from './constants';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
export interface Scheme {
|
|
5
|
-
// common
|
|
6
|
-
key? : string; // can be omitted in array items
|
|
7
|
-
type : string | string[] | DataType | DataType[];
|
|
8
|
-
optional? : boolean; // false
|
|
9
|
-
nullable? : boolean; // false
|
|
10
|
-
// reverse? not?
|
|
3
|
+
export type AllDataType = string | string[] | DataType | DataType[];
|
|
11
4
|
|
|
12
|
-
// common - number & Date (date string, Date)
|
|
13
|
-
min? : number | string | Date;
|
|
14
|
-
exclusiveMin? : boolean; // false
|
|
15
5
|
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
interface CommonScheme {
|
|
7
|
+
parent?: Scheme;
|
|
18
8
|
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
enumReverse? : number[] | string[];
|
|
9
|
+
key?: string; // can be omitted in array items
|
|
10
|
+
type?: AllDataType; // optional for not
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
optional?: boolean; // false
|
|
13
|
+
nullable?: boolean; // false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// no additional rule
|
|
17
|
+
export type BooleanScheme = CommonScheme;
|
|
18
|
+
|
|
19
|
+
export interface MinMax<T> {
|
|
20
|
+
min?: T;
|
|
21
|
+
exclusiveMin?: boolean; // default false
|
|
22
|
+
|
|
23
|
+
max?: T;
|
|
24
|
+
exclusiveMax?: boolean; // default false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MinMaxScheme<T> extends CommonScheme, MinMax<T> {
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface NumberScheme extends MinMaxScheme<number> {
|
|
31
|
+
value?: number; // TODO: need to add
|
|
32
|
+
|
|
33
|
+
enum?: number[];
|
|
34
|
+
|
|
35
|
+
format?: string | string[] | NumberFormat | NumberFormat[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface StringScheme extends CommonScheme {
|
|
39
|
+
value?: string; // TODO: need to add
|
|
40
|
+
|
|
41
|
+
enum?: string[];
|
|
42
|
+
|
|
43
|
+
format?: string | string[] | StringFormat | StringFormat[];
|
|
44
|
+
pattern?: string | string[] | RegExp | RegExp[];
|
|
45
|
+
|
|
46
|
+
length?: number;
|
|
47
|
+
minLength?: number;
|
|
48
|
+
maxLength?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ObjectScheme extends CommonScheme {
|
|
52
|
+
properties?: Scheme[];
|
|
53
|
+
allowNoProperty?: boolean; // true
|
|
54
|
+
}
|
|
25
55
|
|
|
26
|
-
// common - string & array
|
|
27
|
-
length? : number;
|
|
28
|
-
minLength? : number;
|
|
29
|
-
maxLength? : number;
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
|
|
57
|
+
/* eslint-disable @typescript-eslint/no-empty-interface */
|
|
58
|
+
export interface DateScheme extends MinMaxScheme<string | Date> {
|
|
59
|
+
// min, max string for date string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// no additional rule
|
|
63
|
+
export type RegExpScheme = CommonScheme;
|
|
33
64
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
65
|
+
export interface ArrayScheme extends CommonScheme {
|
|
66
|
+
unique?: boolean; // false
|
|
67
|
+
items?: AllDataType | Scheme | Scheme[];
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
69
|
+
length?: number;
|
|
70
|
+
minLength?: number;
|
|
71
|
+
maxLength?: number;
|
|
41
72
|
}
|
|
42
73
|
|
|
74
|
+
export type Scheme =
|
|
75
|
+
BooleanScheme
|
|
76
|
+
| NumberScheme
|
|
77
|
+
| StringScheme
|
|
78
|
+
| ObjectScheme
|
|
79
|
+
| DateScheme
|
|
80
|
+
| RegExpScheme
|
|
81
|
+
| ArrayScheme;
|
|
82
|
+
|
|
83
|
+
|
|
43
84
|
export interface Options {
|
|
44
|
-
customErrorMsg
|
|
45
|
-
[key in ErrorType]
|
|
85
|
+
customErrorMsg?: {
|
|
86
|
+
[key in ErrorType]?: string;
|
|
46
87
|
};
|
|
47
88
|
}
|
|
48
89
|
|
|
49
90
|
export interface InternalOptions extends Options {
|
|
50
|
-
path
|
|
91
|
+
path: string[];
|
|
51
92
|
}
|
|
52
93
|
|
|
53
94
|
export class EjvError {
|
|
54
|
-
public
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
95
|
+
public type: ErrorType;
|
|
96
|
+
public message: string;
|
|
97
|
+
|
|
98
|
+
public data: unknown;
|
|
99
|
+
public path: string | undefined;
|
|
100
|
+
|
|
101
|
+
public errorScheme: Scheme | undefined;
|
|
102
|
+
public errorData: unknown | undefined;
|
|
103
|
+
|
|
104
|
+
public isSchemeError: boolean;
|
|
105
|
+
public isDataError: boolean;
|
|
106
|
+
|
|
107
|
+
constructor (param: {
|
|
108
|
+
type: ErrorType,
|
|
109
|
+
message: string,
|
|
110
|
+
|
|
111
|
+
data: unknown,
|
|
112
|
+
path?: string[],
|
|
113
|
+
|
|
114
|
+
errorScheme?: Scheme,
|
|
115
|
+
errorData?: unknown,
|
|
116
|
+
|
|
117
|
+
isSchemeError?: boolean
|
|
118
|
+
}) {
|
|
119
|
+
this.type = param.type;
|
|
120
|
+
this.message = param.message;
|
|
121
|
+
|
|
122
|
+
this.data = param.data;
|
|
123
|
+
|
|
124
|
+
if ('path' in param && param.path !== undefined) {
|
|
125
|
+
this.path = param.path.join('/');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ('errorScheme' in param) {
|
|
129
|
+
this.errorScheme = param.errorScheme;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ('errorData' in param) {
|
|
133
|
+
this.errorData = param.errorData;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (param.isSchemeError) {
|
|
137
|
+
this.isSchemeError = true;
|
|
138
|
+
this.isDataError = false;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.isSchemeError = false;
|
|
142
|
+
this.isDataError = true;
|
|
143
|
+
}
|
|
62
144
|
}
|
|
63
145
|
}
|
|
146
|
+
|
|
147
|
+
export interface AnyObject {
|
|
148
|
+
[key: string]: unknown;
|
|
149
|
+
}
|
package/src/tester.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DataType } from './constants';
|
|
2
|
+
import { AnyObject } from './interfaces';
|
|
2
3
|
|
|
3
|
-
export const typeTester = (value
|
|
4
|
-
let valid
|
|
4
|
+
export const typeTester = (value: unknown, type: DataType): boolean => {
|
|
5
|
+
let valid: boolean;
|
|
5
6
|
|
|
6
7
|
switch (type) {
|
|
7
8
|
case DataType.BOOLEAN:
|
|
@@ -36,66 +37,66 @@ export const typeTester = (value : any, type : DataType) : boolean => {
|
|
|
36
37
|
return valid;
|
|
37
38
|
};
|
|
38
39
|
|
|
39
|
-
export const definedTester = (value
|
|
40
|
+
export const definedTester = (value: unknown): value is boolean => {
|
|
40
41
|
return value !== undefined;
|
|
41
42
|
};
|
|
42
43
|
|
|
43
|
-
export const enumTester = <T> (value
|
|
44
|
+
export const enumTester = <T> (value: T, arr: T[]): boolean => {
|
|
44
45
|
return arr.includes(value);
|
|
45
46
|
};
|
|
46
47
|
|
|
47
|
-
export const lengthTester = (value
|
|
48
|
+
export const lengthTester = (value: string | unknown[], length: number): boolean => {
|
|
48
49
|
return value.length === length;
|
|
49
50
|
};
|
|
50
51
|
|
|
51
|
-
export const minLengthTester = (value
|
|
52
|
+
export const minLengthTester = (value: string | unknown[], minLength: number): boolean => {
|
|
52
53
|
return value.length >= minLength;
|
|
53
54
|
};
|
|
54
55
|
|
|
55
|
-
export const maxLengthTester = (value
|
|
56
|
+
export const maxLengthTester = (value: string | unknown[], maxLength: number): boolean => {
|
|
56
57
|
return value.length <= maxLength;
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
export const booleanTester = (value
|
|
60
|
+
export const booleanTester = (value: unknown): value is boolean => {
|
|
60
61
|
return typeof value === 'boolean';
|
|
61
62
|
};
|
|
62
63
|
|
|
63
|
-
export const numberTester = (value
|
|
64
|
+
export const numberTester = (value: unknown): value is number => {
|
|
64
65
|
return typeof value === 'number' && !isNaN(value);
|
|
65
66
|
};
|
|
66
67
|
|
|
67
|
-
export const integerTester = (value
|
|
68
|
+
export const integerTester = (value: number): boolean => {
|
|
68
69
|
return +value.toFixed(0) === value;
|
|
69
70
|
};
|
|
70
71
|
|
|
71
|
-
export const indexTester = (value
|
|
72
|
+
export const indexTester = (value: number): value is number => {
|
|
72
73
|
return integerTester(value) && value >= 0;
|
|
73
74
|
};
|
|
74
75
|
|
|
75
|
-
export const minNumberTester = (value
|
|
76
|
+
export const minNumberTester = (value: number, min: number): boolean => {
|
|
76
77
|
return value >= min;
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
export const exclusiveMinNumberTester = (value
|
|
80
|
+
export const exclusiveMinNumberTester = (value: number, min: number): boolean => {
|
|
80
81
|
return value > min;
|
|
81
82
|
};
|
|
82
83
|
|
|
83
|
-
export const maxNumberTester = (value
|
|
84
|
+
export const maxNumberTester = (value: number, max: number): boolean => {
|
|
84
85
|
return value <= max;
|
|
85
86
|
};
|
|
86
87
|
|
|
87
|
-
export const exclusiveMaxNumberTester = (value
|
|
88
|
+
export const exclusiveMaxNumberTester = (value: number, max: number): boolean => {
|
|
88
89
|
return value < max;
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
export const stringTester = (value
|
|
92
|
+
export const stringTester = (value: unknown): value is string => {
|
|
92
93
|
return typeof value === 'string';
|
|
93
94
|
};
|
|
94
95
|
|
|
95
|
-
export const stringRegExpTester = (value
|
|
96
|
-
let valid
|
|
96
|
+
export const stringRegExpTester = (value: string, regExp: string | RegExp): boolean => {
|
|
97
|
+
let valid = false;
|
|
97
98
|
|
|
98
|
-
let _regExp
|
|
99
|
+
let _regExp: RegExp | undefined = undefined;
|
|
99
100
|
|
|
100
101
|
if (regExpTester(regExp)) {
|
|
101
102
|
_regExp = regExp as RegExp;
|
|
@@ -112,30 +113,30 @@ export const stringRegExpTester = (value : string, regExp : string | RegExp) : b
|
|
|
112
113
|
};
|
|
113
114
|
|
|
114
115
|
// RFC 5322, 3.4.1. spec
|
|
115
|
-
export const emailTester = (value
|
|
116
|
-
let valid
|
|
116
|
+
export const emailTester = (value: string): boolean => {
|
|
117
|
+
let valid = false;
|
|
117
118
|
|
|
118
119
|
if (stringTester(value) && stringRegExpTester(value, /^.+@.+$/)) {
|
|
119
|
-
const valueAsString
|
|
120
|
+
const valueAsString: string = value as string;
|
|
120
121
|
|
|
121
|
-
const atIndex
|
|
122
|
-
const localPart
|
|
123
|
-
const domain
|
|
122
|
+
const atIndex: number = valueAsString.lastIndexOf('@');
|
|
123
|
+
const localPart: string = valueAsString.substr(0, atIndex);
|
|
124
|
+
const domain: string = valueAsString.substr(atIndex + 1);
|
|
124
125
|
|
|
125
126
|
// regular expression sources
|
|
126
127
|
// const aTextRegExpStr : string = '[-a-zA-Z0-9!#$%&\\\'*+/=?^_`{|}~]+';
|
|
127
128
|
|
|
128
|
-
const dotAtomRegExp
|
|
129
|
-
const quotedStringRegExp
|
|
130
|
-
const domainLiteralRegExp
|
|
129
|
+
const dotAtomRegExp = /^(\.?[-a-zA-Z0-9!#$%&'*+/=?^_`{|}~]+)*$/;
|
|
130
|
+
const quotedStringRegExp = /^"[\u0020-\u005b\u005d-\u007e\\]*"$/; // include space (\u005b)
|
|
131
|
+
const domainLiteralRegExp = /^\[[\u0020-\u005a\u005c-\u007e\\]*]$/;
|
|
131
132
|
|
|
132
|
-
const validLocalPart
|
|
133
|
+
const validLocalPart: boolean = localPart.length <= 64
|
|
133
134
|
&& (
|
|
134
135
|
dotAtomRegExp.test(localPart)
|
|
135
136
|
|| quotedStringRegExp.test(localPart)
|
|
136
137
|
);
|
|
137
138
|
|
|
138
|
-
const validDomain
|
|
139
|
+
const validDomain: boolean = !domain.startsWith('.') && !domain.endsWith('.')
|
|
139
140
|
&& (
|
|
140
141
|
dotAtomRegExp.test(domain)
|
|
141
142
|
|| domainLiteralRegExp.test(domain)
|
|
@@ -148,17 +149,17 @@ export const emailTester = (value : string) : boolean => {
|
|
|
148
149
|
};
|
|
149
150
|
|
|
150
151
|
// RFC 3339 (https://www.ietf.org/rfc/rfc3339.txt) : YYYY-MM-DDThh:mm:ss[.SSSZ]
|
|
151
|
-
const rfc3339Tester = (value
|
|
152
|
+
const rfc3339Tester = (value: string): boolean => {
|
|
152
153
|
return /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3])(:([0-5][0-9])){2}(\.\d+)?(Z|[-+]\d{2}:\d{2})?$/.test(value);
|
|
153
154
|
};
|
|
154
155
|
|
|
155
|
-
const iso8601DateTester = (value
|
|
156
|
-
const years
|
|
157
|
-
const months
|
|
158
|
-
const dates
|
|
159
|
-
const dateOfYear
|
|
160
|
-
const weeks
|
|
161
|
-
const days
|
|
156
|
+
const iso8601DateTester = (value: string): boolean => {
|
|
157
|
+
const years = '(\\d{4})';
|
|
158
|
+
const months = '(0[1-9]|1[0-2])';
|
|
159
|
+
const dates = '(0[1-9]|[1-2][0-9]|3[0-1])';
|
|
160
|
+
const dateOfYear = '(00[1-9]|0[1-9][0-9]|[1-2]\\d{2}|3[0-5]\\d|36[0-6])'; // 366 for leap year
|
|
161
|
+
const weeks = '(W(0[1-9]|[2-4][0-9]|5[0-3]))';
|
|
162
|
+
const days = '[1-7]';
|
|
162
163
|
|
|
163
164
|
return [
|
|
164
165
|
new RegExp(`^[-+]?${ years }$`), // years : YYYY, +YYYY, -YYYY
|
|
@@ -168,45 +169,49 @@ const iso8601DateTester = (value : string) : boolean => {
|
|
|
168
169
|
new RegExp(`^${ years }-${ weeks }(-${ days })?$`), // week dates : YYYY-Www, YYYY-Www-D
|
|
169
170
|
new RegExp(`^${ years }${ weeks }(${ days })?$`), // week dates : YYYYWww, YYYYWwwD
|
|
170
171
|
new RegExp(`^${ years }-?${ dateOfYear }$`) // ordinal dates : YYYY-DDD, YYYYDDD
|
|
171
|
-
].some((regExp
|
|
172
|
+
].some((regExp: RegExp): boolean => {
|
|
172
173
|
return regExp.test(value);
|
|
173
174
|
});
|
|
174
175
|
};
|
|
175
176
|
|
|
176
|
-
const iso8601TimeTester = (value
|
|
177
|
-
const hours
|
|
178
|
-
const minutes
|
|
179
|
-
const seconds
|
|
180
|
-
const ms
|
|
177
|
+
const iso8601TimeTester = (value: string): boolean => {
|
|
178
|
+
const hours = '([0-1]\\d|2[0-3])';
|
|
179
|
+
const minutes = '([0-5]\\d)';
|
|
180
|
+
const seconds = '([0-5]\\d|60)'; // 60 for leap second
|
|
181
|
+
const ms = '(\\.[0-9]+)';
|
|
181
182
|
|
|
182
183
|
return [
|
|
183
184
|
new RegExp(`^(${ hours }|24)$`), // hh
|
|
184
185
|
new RegExp(`^((${ hours }:${ minutes })|24:00)$`), // hh:mm
|
|
185
186
|
new RegExp(`^((${ hours }:${ minutes }:${ seconds })|24:00:00)$`), // hh:mm:ss
|
|
186
|
-
new RegExp(`^((${ hours }:${ minutes }:${ seconds }${ ms })|24:00:00
|
|
187
|
+
new RegExp(`^((${ hours }:${ minutes }:${ seconds }${ ms })|24:00:00.0+)$`), // hh:mm:ss
|
|
187
188
|
|
|
188
189
|
new RegExp(`^(${ hours }${ minutes }|2400)$`), // hhmm
|
|
189
190
|
new RegExp(`^(${ hours }${ minutes }${ seconds }|240000)$`), // hhmmss
|
|
190
|
-
new RegExp(`^(${ hours }${ minutes }${ seconds }${ ms }|240000
|
|
191
|
+
new RegExp(`^(${ hours }${ minutes }${ seconds }${ ms }|240000.0+)$`) // hhmmss.sss
|
|
191
192
|
]
|
|
192
|
-
.some((regExp
|
|
193
|
+
.some((regExp: RegExp): boolean => {
|
|
193
194
|
return regExp.test(value);
|
|
194
195
|
});
|
|
195
196
|
};
|
|
196
197
|
|
|
197
|
-
const iso8601DateTimeTester = (value
|
|
198
|
-
let valid
|
|
198
|
+
const iso8601DateTimeTester = (value: string): boolean => {
|
|
199
|
+
let valid = false;
|
|
199
200
|
|
|
200
201
|
if (/.+T.+/.test(value) // should have 1 'T'
|
|
201
202
|
&& /(Z|[-+]\d{2}:?\d{2})$/.test(value) // should end with 'Z' or timezone
|
|
202
203
|
) {
|
|
203
|
-
|
|
204
|
+
const dateAndTime: string[] = value.split('T');
|
|
205
|
+
const date: string = dateAndTime[0];
|
|
206
|
+
let time: string = dateAndTime[1];
|
|
204
207
|
|
|
205
208
|
if (time.endsWith('Z')) {
|
|
206
209
|
time = time.replace('Z', '');
|
|
207
210
|
}
|
|
208
211
|
else {
|
|
209
|
-
const timezoneStartIndex
|
|
212
|
+
const timezoneStartIndex: number = time.includes('+')
|
|
213
|
+
? time.indexOf('+')
|
|
214
|
+
: time.indexOf('-');
|
|
210
215
|
|
|
211
216
|
time = time.substr(0, timezoneStartIndex);
|
|
212
217
|
}
|
|
@@ -217,15 +222,15 @@ const iso8601DateTimeTester = (value : string) : boolean => {
|
|
|
217
222
|
return valid;
|
|
218
223
|
};
|
|
219
224
|
|
|
220
|
-
export const dateFormatTester = (value
|
|
225
|
+
export const dateFormatTester = (value: string): boolean => {
|
|
221
226
|
return iso8601DateTester(value);
|
|
222
227
|
};
|
|
223
228
|
|
|
224
|
-
export const timeFormatTester = (value
|
|
229
|
+
export const timeFormatTester = (value: string): boolean => {
|
|
225
230
|
return iso8601TimeTester(value);
|
|
226
231
|
};
|
|
227
232
|
|
|
228
|
-
export const dateTimeFormatTester = (value
|
|
233
|
+
export const dateTimeFormatTester = (value: string): boolean => {
|
|
229
234
|
return rfc3339Tester(value) || iso8601DateTimeTester(value);
|
|
230
235
|
};
|
|
231
236
|
|
|
@@ -250,53 +255,54 @@ export const dateTimeFormatTester = (value : string) : boolean => {
|
|
|
250
255
|
// return ipv4Tester(value) || ipv6Tester(value);
|
|
251
256
|
// };
|
|
252
257
|
|
|
253
|
-
export const objectTester = (value
|
|
258
|
+
export const objectTester = (value: unknown): boolean => {
|
|
254
259
|
return typeof value === 'object';
|
|
255
260
|
};
|
|
256
261
|
|
|
257
|
-
export const hasPropertyTester = (value
|
|
262
|
+
export const hasPropertyTester = (value: AnyObject): boolean => {
|
|
258
263
|
return Object.keys(value).length > 0;
|
|
259
264
|
};
|
|
260
265
|
|
|
261
|
-
export const dateTester = (value
|
|
266
|
+
export const dateTester = (value: unknown): value is Date => {
|
|
262
267
|
return objectTester(value)
|
|
263
268
|
&& value !== null
|
|
264
|
-
&& typeof value
|
|
269
|
+
&& typeof value === 'object'
|
|
270
|
+
&& value instanceof Date
|
|
265
271
|
&& !isNaN(value.getFullYear());
|
|
266
272
|
};
|
|
267
273
|
|
|
268
|
-
export const minDateTester = (value
|
|
274
|
+
export const minDateTester = (value: Date, min: Date): boolean => {
|
|
269
275
|
return +value >= +min;
|
|
270
276
|
};
|
|
271
277
|
|
|
272
|
-
export const exclusiveMinDateTester = (value
|
|
278
|
+
export const exclusiveMinDateTester = (value: Date, min: Date): boolean => {
|
|
273
279
|
return +value > +min;
|
|
274
280
|
};
|
|
275
281
|
|
|
276
|
-
export const maxDateTester = (value
|
|
282
|
+
export const maxDateTester = (value: Date, max: Date): boolean => {
|
|
277
283
|
return +value <= +max;
|
|
278
284
|
};
|
|
279
285
|
|
|
280
|
-
export const exclusiveMaxDateTester = (value
|
|
286
|
+
export const exclusiveMaxDateTester = (value: Date, max: Date): boolean => {
|
|
281
287
|
return +value < +max;
|
|
282
288
|
};
|
|
283
289
|
|
|
284
|
-
export const arrayTester = (value
|
|
290
|
+
export const arrayTester = (value: unknown): value is unknown[] => {
|
|
285
291
|
return Array.isArray(value);
|
|
286
292
|
};
|
|
287
293
|
|
|
288
|
-
export const arrayTypeOfTester = (array
|
|
289
|
-
return array.every((item
|
|
294
|
+
export const arrayTypeOfTester = (array: unknown[], type: DataType): boolean => {
|
|
295
|
+
return array.every((item: unknown): boolean => {
|
|
290
296
|
return typeTester(item, type);
|
|
291
297
|
});
|
|
292
298
|
};
|
|
293
299
|
|
|
294
|
-
export const uniqueItemsTester = (array
|
|
295
|
-
return array.every(item => {
|
|
296
|
-
return array.filter((target
|
|
300
|
+
export const uniqueItemsTester = (array: unknown[]): boolean => {
|
|
301
|
+
return array.every((item: unknown): boolean => {
|
|
302
|
+
return array.filter((target: unknown): boolean => target === item).length === 1;
|
|
297
303
|
});
|
|
298
304
|
};
|
|
299
305
|
|
|
300
|
-
export const regExpTester = (value
|
|
306
|
+
export const regExpTester = (value: unknown): value is RegExp => {
|
|
301
307
|
return value instanceof RegExp;
|
|
302
308
|
};
|
package/src/util.ts
CHANGED
|
@@ -1,59 +1,124 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { AnyObject } from './interfaces';
|
|
2
|
+
import { ErrorMsg } from './constants';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
enum CloneDataType {
|
|
6
|
+
Boolean = 'boolean',
|
|
7
|
+
Number = 'number',
|
|
8
|
+
Function = 'function',
|
|
9
|
+
String = 'string',
|
|
10
|
+
Buffer = 'buffer',
|
|
11
|
+
Object = 'object',
|
|
12
|
+
Array = 'array',
|
|
13
|
+
Date = 'date',
|
|
14
|
+
RegExp = 'regexp'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const isArray = <T> (value: unknown): value is T[] => {
|
|
18
|
+
return value !== undefined
|
|
19
|
+
&& value !== null
|
|
20
|
+
&& Array.isArray(value);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// sanitize removes undefined & null fields from object. default false
|
|
25
|
+
export const clone = <T> (obj: T, sanitize?: boolean): T => {
|
|
26
|
+
let result !: T;
|
|
27
|
+
|
|
28
|
+
if (obj) {
|
|
29
|
+
let type: CloneDataType = typeof obj as CloneDataType;
|
|
30
|
+
|
|
31
|
+
if (type === CloneDataType.Object) {
|
|
32
|
+
const objAsObject: AnyObject = obj as unknown as AnyObject;
|
|
33
|
+
|
|
34
|
+
if (isArray(objAsObject)) {
|
|
35
|
+
type = CloneDataType.Array;
|
|
36
|
+
}
|
|
37
|
+
else if (objAsObject instanceof Date) {
|
|
38
|
+
type = CloneDataType.Date;
|
|
39
|
+
}
|
|
40
|
+
else if (objAsObject instanceof RegExp) {
|
|
41
|
+
type = CloneDataType.RegExp;
|
|
42
|
+
}
|
|
43
|
+
else if (objAsObject.byteLength
|
|
44
|
+
&& typeof objAsObject.byteLength === 'function') {
|
|
45
|
+
type = CloneDataType.Buffer;
|
|
16
46
|
}
|
|
17
47
|
}
|
|
18
48
|
|
|
19
49
|
switch (type) {
|
|
20
|
-
case
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
case 'string':
|
|
24
|
-
case 'buffer':
|
|
25
|
-
// ok with simple copy
|
|
26
|
-
result = obj;
|
|
27
|
-
break;
|
|
28
|
-
|
|
29
|
-
case 'regexp':
|
|
30
|
-
result = new RegExp(obj);
|
|
31
|
-
break;
|
|
32
|
-
|
|
33
|
-
case 'date':
|
|
34
|
-
result = new Date(obj);
|
|
50
|
+
case CloneDataType.Date: {
|
|
51
|
+
const objAsDate: Date = obj as unknown as Date;
|
|
52
|
+
result = new Date(objAsDate) as unknown as T;
|
|
35
53
|
break;
|
|
54
|
+
}
|
|
36
55
|
|
|
37
|
-
case
|
|
38
|
-
|
|
56
|
+
case CloneDataType.Array: {
|
|
57
|
+
const objAsArray: unknown[] = obj as unknown as unknown[];
|
|
58
|
+
result = objAsArray.map((one: unknown): unknown => {
|
|
39
59
|
return clone(one);
|
|
40
|
-
})
|
|
60
|
+
}) as unknown as T;
|
|
41
61
|
break;
|
|
62
|
+
}
|
|
42
63
|
|
|
43
|
-
case
|
|
64
|
+
case CloneDataType.Object: {
|
|
44
65
|
// sanitize default false
|
|
45
|
-
result = {};
|
|
66
|
+
result = {} as unknown as T;
|
|
46
67
|
|
|
47
|
-
Object.
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
const entries: [string, unknown][] = Object.entries(obj)
|
|
69
|
+
.filter(([, value]): boolean => {
|
|
70
|
+
return sanitize
|
|
71
|
+
? value !== undefined && value !== null
|
|
72
|
+
: true;
|
|
51
73
|
});
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
for (const [key, value] of entries) {
|
|
77
|
+
// call recursively
|
|
78
|
+
(result as unknown as AnyObject)[key] = clone(value, sanitize);
|
|
79
|
+
}
|
|
52
80
|
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
default:
|
|
84
|
+
// simple copy
|
|
85
|
+
result = obj;
|
|
53
86
|
}
|
|
54
|
-
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
55
89
|
result = obj; // do not copy null & undefined
|
|
56
90
|
}
|
|
57
91
|
|
|
58
92
|
return result;
|
|
59
|
-
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
export const sift = <T> (arr: T[]): T[] => {
|
|
97
|
+
return arr.reduce((acc: T[], cur: T) => {
|
|
98
|
+
if (cur !== null && cur !== undefined && !acc.includes(cur)) {
|
|
99
|
+
acc.push(cur);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return acc;
|
|
103
|
+
}, []);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
export const createErrorMsg = (errorMsg: ErrorMsg, param?: {
|
|
108
|
+
placeholders?: (string | number)[]
|
|
109
|
+
}): string => {
|
|
110
|
+
let result: string = errorMsg;
|
|
111
|
+
|
|
112
|
+
if (param?.placeholders) {
|
|
113
|
+
param.placeholders.forEach((strToReplace: string | number, i: number): void => {
|
|
114
|
+
result = result.replace(
|
|
115
|
+
`<<${ i + 1 }>>`,
|
|
116
|
+
typeof strToReplace === 'string'
|
|
117
|
+
? strToReplace
|
|
118
|
+
: '' + strToReplace
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
};
|