-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinclude.js
182 lines (141 loc) · 3.81 KB
/
include.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
const plainObj = {}
const { iterator } = Symbol
export const { assign } = Object
/** @type {(arg: unknown) => arg is unknown[]} */
export const isArray = Array.isArray
export const {
toString,
hasOwnProperty: has,
} = Object.prototype
export const {
isExtensible: isExt,
getOwnPropertyDescriptor: getDesc,
defineProperty: define,
} = Reflect
export function isDefined(value) {
return (value !== null) && (value !== undefined)
}
/** @return {value is (...args: unknown[]) => unknown} */
export function isFunction(value) {
return (typeof value) === "function"
}
/** @return {value is object} */
export function isObject(value) {
return (value !== null) && ((typeof value) === "object")
}
/** @return {value is number} */
export function isNumber(value) {
return isFinite(value) && ((typeof value) === "number")
}
/** @return {value is Iterable} */
export function isIterable(value) {
return isDefined(value) && isFunction(value[iterator])
}
function defaultValidatorError(value) {
throw new TypeError(
"The `" + value +
"` being checked did not pass the check successfully."
)
}
/** @typedef {"number"|"string"|"boolean"|"object"|"symbol"|"function"} NativeTypes */
/**
* @param {NativeTypes | (value: unknown) => boolean} type
* @param {unknown} source
* @param {() => Error} err
* @return {boolean}
*/
export function validate(type, source, err) {
if (((typeof source) === type) || (isFunction(type) && type(source))) {
return source
}
if (isFunction(err)) throw err()
defaultValidatorError(source)
}
/**
* @param {string | (value: unknown) => boolean} type
* @param {...unknown} sources
*/
validate.any = function (type, ...sources) {
if ((typeof type) === "string") {
type = ((value) => ((typeof value) === type))
}
validate("function", type)
let i = sources.length
while (--i) (validate(type, sources[i], type))
return true
}
export const validateType = validate
/**
* @param {(value: unknown) => boolean} exec
* @param {(value: unknown, fn: exec) => throw} onerror
* @return {((value: unknown) => void) & {any: (...values: unknown[]) => void}}
*/
export function makeValidator(exec, onerror) {
if (!isFunction(onerror)) onerror = defaultValidatorError
const out = (value) => (validate(exec, value, onerror))
out.any = function (...values) { each(values, out, false) }
return out
}
/**
* @param {unknown[]} arr
* @param {(value: unknown, index: number, array: arr) => void} fn
* @param {{stoppable: ?boolean, ?ctx}} [config]
*/
export function each(arr, fn, config) {
validate(isIterable, arr)
validate(isFunction, fn)
const {
stoppable = false,
ctx = null,
} = (config || plainObj)
let index = 0
for (const item of arr) {
if ((fn.call(ctx, item, index++, arr) === false) && stoppable) {
break
}
}
return arr
}
/**
* @param {unknown[]} arr
* @param {(value: unknown, index: number, array: arr) => void} fn
* @param {{stoppable: ?boolean, ?ctx}} [config]
*/
each.reverse = function (arr, fn, config = plainObj) {
validate(isArray, arr)
validate(isFunction, fn)
const {
stoppable = false,
ctx = null,
} = (config || plainObj)
let index = arr.length
while (index--) {
if ((fn.call(ctx, arr[index], index, arr) === false) && stoppable) {
break
}
}
return arr
}
/**
* @param {object} obj
* @param {(value: unknown, index: number, self: obj) => void} fn
* @param {{stoppable: ?boolean, ?ctx}} [config]
*/
each.obj = function (obj, fn, config) {
validate(isDefined, obj)
validate(isFunction, fn)
const {
stoppable = false,
ctx = null,
} = (config || plainObj)
const keys = Object.keys(obj)
let i = keys.length, k;
while (i--) {
if (
has.call(obj, k = keys[i])
&& (fn.call(ctx, obj[k], k, obj) === false)
&& stoppable
) break
}
return obj
}