UNPKG

3.7 kBJavaScriptView Raw
1/**
2 * Common functions and function call helpers.
3 *
4 * @module function
5 */
6
7import * as array from './array.js'
8import * as object from './object.js'
9
10/**
11 * Calls all functions in `fs` with args. Only throws after all functions were called.
12 *
13 * @param {Array<function>} fs
14 * @param {Array<any>} args
15 */
16export const callAll = (fs, args, i = 0) => {
17 try {
18 for (; i < fs.length; i++) {
19 fs[i](...args)
20 }
21 } finally {
22 if (i < fs.length) {
23 callAll(fs, args, i + 1)
24 }
25 }
26}
27
28export const nop = () => {}
29
30/**
31 * @template T
32 * @param {function():T} f
33 * @return {T}
34 */
35export const apply = f => f()
36
37/**
38 * @template A
39 *
40 * @param {A} a
41 * @return {A}
42 */
43export const id = a => a
44
45/**
46 * @template T
47 *
48 * @param {T} a
49 * @param {T} b
50 * @return {boolean}
51 */
52export const equalityStrict = (a, b) => a === b
53
54/**
55 * @template T
56 *
57 * @param {Array<T>|object} a
58 * @param {Array<T>|object} b
59 * @return {boolean}
60 */
61export const equalityFlat = (a, b) => a === b || (a != null && b != null && a.constructor === b.constructor && ((array.isArray(a) && array.equalFlat(a, /** @type {Array<T>} */ (b))) || (typeof a === 'object' && object.equalFlat(a, b))))
62
63/* c8 ignore start */
64
65/**
66 * @param {any} a
67 * @param {any} b
68 * @return {boolean}
69 */
70export const equalityDeep = (a, b) => {
71 if (a == null || b == null) {
72 return equalityStrict(a, b)
73 }
74 if (a.constructor !== b.constructor) {
75 return false
76 }
77 if (a === b) {
78 return true
79 }
80 switch (a.constructor) {
81 case ArrayBuffer:
82 a = new Uint8Array(a)
83 b = new Uint8Array(b)
84 // eslint-disable-next-line no-fallthrough
85 case Uint8Array: {
86 if (a.byteLength !== b.byteLength) {
87 return false
88 }
89 for (let i = 0; i < a.length; i++) {
90 if (a[i] !== b[i]) {
91 return false
92 }
93 }
94 break
95 }
96 case Set: {
97 if (a.size !== b.size) {
98 return false
99 }
100 for (const value of a) {
101 if (!b.has(value)) {
102 return false
103 }
104 }
105 break
106 }
107 case Map: {
108 if (a.size !== b.size) {
109 return false
110 }
111 for (const key of a.keys()) {
112 if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
113 return false
114 }
115 }
116 break
117 }
118 case Object:
119 if (object.length(a) !== object.length(b)) {
120 return false
121 }
122 for (const key in a) {
123 if (!object.hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
124 return false
125 }
126 }
127 break
128 case Array:
129 if (a.length !== b.length) {
130 return false
131 }
132 for (let i = 0; i < a.length; i++) {
133 if (!equalityDeep(a[i], b[i])) {
134 return false
135 }
136 }
137 break
138 default:
139 return false
140 }
141 return true
142}
143
144/**
145 * @template V
146 * @template {V} OPTS
147 *
148 * @param {V} value
149 * @param {Array<OPTS>} options
150 */
151// @ts-ignore
152export const isOneOf = (value, options) => options.includes(value)
153/* c8 ignore stop */
154
155export const isArray = array.isArray
156
157/**
158 * @param {any} s
159 * @return {s is String}
160 */
161export const isString = (s) => s && s.constructor === String
162
163/**
164 * @param {any} n
165 * @return {n is Number}
166 */
167export const isNumber = n => n != null && n.constructor === Number
168
169/**
170 * @template {abstract new (...args: any) => any} TYPE
171 * @param {any} n
172 * @param {TYPE} T
173 * @return {n is InstanceType<TYPE>}
174 */
175export const is = (n, T) => n && n.constructor === T
176
177/**
178 * @template {abstract new (...args: any) => any} TYPE
179 * @param {TYPE} T
180 */
181export const isTemplate = (T) =>
182 /**
183 * @param {any} n
184 * @return {n is InstanceType<TYPE>}
185 **/
186 n => n && n.constructor === T