@ntnyq/utils 0.6.4 → 0.7.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/dist/index.js CHANGED
@@ -1,811 +1,1030 @@
1
- // src/fn/noop.ts
2
- function noop() {
3
- }
4
- var NOOP = noop;
1
+ //#region src/fn/noop.ts
2
+ /**
3
+ * A function that does nothing.
4
+ */
5
+ function noop() {}
6
+ /**
7
+ * Alias of {@link noop}.
8
+ */
9
+ const NOOP = noop;
5
10
 
6
- // src/fn/once.ts
11
+ //#endregion
12
+ //#region src/fn/once.ts
7
13
  function once(func) {
8
- let called = false;
9
- return function(...args) {
10
- if (called) {
11
- return false;
12
- }
13
- called = true;
14
- func.apply(this, args);
15
- return true;
16
- };
17
- }
18
-
19
- // src/is/dom.ts
14
+ let called = false;
15
+ return function(...args) {
16
+ if (called) return false;
17
+ called = true;
18
+ func.apply(this, args);
19
+ return true;
20
+ };
21
+ }
22
+
23
+ //#endregion
24
+ //#region src/is/dom.ts
25
+ /**
26
+ * @file is/dom.ts
27
+ */
28
+ /**
29
+ * Check if given value is an HTMLElement
30
+ * @param value - The value to check
31
+ * @returns True if the value is an HTMLElement, false otherwise
32
+ */
20
33
  function isHTMLElement(value) {
21
- return typeof value === "object" && value !== null && "nodeType" in value && value.nodeType === Node.ELEMENT_NODE && value instanceof HTMLElement;
34
+ return typeof value === "object" && value !== null && "nodeType" in value && value.nodeType === Node.ELEMENT_NODE && value instanceof HTMLElement;
22
35
  }
23
36
 
24
- // src/is/core.ts
37
+ //#endregion
38
+ //#region src/is/core.ts
25
39
  function getObjectType(value) {
26
- return Object.prototype.toString.call(value).slice(8, -1);
40
+ return Object.prototype.toString.call(value).slice(8, -1);
27
41
  }
28
42
  function isUndefined(value) {
29
- return value === void 0;
43
+ return value === void 0;
30
44
  }
31
45
  function isNull(value) {
32
- return value === null;
46
+ return value === null;
33
47
  }
34
48
  function isNil(value) {
35
- return isNull(value) || isUndefined(value);
49
+ return isNull(value) || isUndefined(value);
36
50
  }
37
- var isNullOrUndefined = isNil;
51
+ const isNullOrUndefined = isNil;
38
52
  function isString(value) {
39
- return typeof value === "string";
53
+ return typeof value === "string";
40
54
  }
41
55
  function isEmptyString(value) {
42
- return isString(value) && value.length === 0;
56
+ return isString(value) && value.length === 0;
43
57
  }
44
58
  function isNonEmptyString(value) {
45
- return isString(value) && value.length > 0;
59
+ return isString(value) && value.length > 0;
46
60
  }
47
61
  function isWhitespaceString(value) {
48
- return isString(value) && /^\s*$/.test(value);
62
+ return isString(value) && /^\s*$/.test(value);
49
63
  }
50
64
  function isEmptyStringOrWhitespace(value) {
51
- return isEmptyString(value) || isWhitespaceString(value);
65
+ return isEmptyString(value) || isWhitespaceString(value);
52
66
  }
53
67
  function isNumbericString(value) {
54
- return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
68
+ return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
55
69
  }
56
70
  function isNumber(value) {
57
- return typeof value === "number";
71
+ return typeof value === "number";
58
72
  }
59
73
  function isZero(value) {
60
- return value === 0;
74
+ return value === 0;
61
75
  }
62
76
  function isNaN(value) {
63
- return Number.isNaN(value);
77
+ return Number.isNaN(value);
64
78
  }
65
79
  function isInteger(value) {
66
- return Number.isInteger(value);
80
+ return Number.isInteger(value);
67
81
  }
68
82
  function isBigInt(value) {
69
- return typeof value === "bigint";
83
+ return typeof value === "bigint";
70
84
  }
71
85
  function isBoolean(value) {
72
- return typeof value === "boolean";
86
+ return typeof value === "boolean";
73
87
  }
74
88
  function isTruthy(value) {
75
- return Boolean(value);
89
+ return Boolean(value);
76
90
  }
77
91
  function isFunction(value) {
78
- return typeof value === "function";
92
+ return typeof value === "function";
79
93
  }
80
94
  function isArray(value) {
81
- return Array.isArray(value);
95
+ return Array.isArray(value);
82
96
  }
83
97
  function isEmptyArray(value) {
84
- return isArray(value) && value.length === 0;
98
+ return isArray(value) && value.length === 0;
85
99
  }
86
100
  function isNonEmptyArray(value) {
87
- return isArray(value) && value.length > 0;
101
+ return isArray(value) && value.length > 0;
88
102
  }
89
103
  function isObject(value) {
90
- return (typeof value === "object" || isFunction(value)) && !isNull(value);
104
+ return (typeof value === "object" || isFunction(value)) && !isNull(value);
91
105
  }
92
106
  function isEmptyObject(value) {
93
- return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
107
+ return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
94
108
  }
95
109
  function isMap(value) {
96
- return getObjectType(value) === "Map";
110
+ return getObjectType(value) === "Map";
97
111
  }
98
112
  function isEmptyMap(value) {
99
- return isMap(value) && value.size === 0;
113
+ return isMap(value) && value.size === 0;
100
114
  }
101
115
  function isSet(value) {
102
- return getObjectType(value) === "Set";
116
+ return getObjectType(value) === "Set";
103
117
  }
104
118
  function isEmptySet(value) {
105
- return isSet(value) && value.size === 0;
119
+ return isSet(value) && value.size === 0;
106
120
  }
107
121
  function isRegExp(value) {
108
- return getObjectType(value) === "RegExp";
122
+ return getObjectType(value) === "RegExp";
109
123
  }
110
124
  function isError(value) {
111
- return getObjectType(value) === "Error";
125
+ return getObjectType(value) === "Error";
112
126
  }
127
+ /**
128
+ * @internal
129
+ */
113
130
  function hasPromiseApi(value) {
114
- return (
115
- // eslint-disable-next-line @typescript-eslint/unbound-method
116
- isFunction(value?.then) && isFunction(value?.catch)
117
- );
131
+ return isFunction(value?.then) && isFunction(value?.catch);
118
132
  }
119
133
  function isNativePromise(value) {
120
- return getObjectType(value) === "Promise";
134
+ return getObjectType(value) === "Promise";
121
135
  }
122
136
  function isPromise(value) {
123
- return isNativePromise(value) || hasPromiseApi(value);
137
+ return isNativePromise(value) || hasPromiseApi(value);
124
138
  }
125
139
  function isIterable(value) {
126
- return isFunction(value?.[Symbol.iterator]);
140
+ return isFunction(value?.[Symbol.iterator]);
127
141
  }
128
142
 
129
- // src/is/isDeepEqual.ts
143
+ //#endregion
144
+ //#region src/is/isDeepEqual.ts
145
+ /**
146
+ * check if two values are deeply equal
147
+ */
130
148
  function isDeepEqual(value1, value2) {
131
- const type1 = getObjectType(value1);
132
- const type2 = getObjectType(value2);
133
- if (type1 !== type2) {
134
- return false;
135
- }
136
- if (isArray(value1) && isArray(value2)) {
137
- if (value1.length !== value2.length) {
138
- return false;
139
- }
140
- return value1.every((item, index) => isDeepEqual(item, value2[index]));
141
- }
142
- if (isObject(value1) && isObject(value2)) {
143
- const keys = Object.keys(value1);
144
- if (keys.length !== Object.keys(value2).length) {
145
- return false;
146
- }
147
- return keys.every(
148
- (key) => isDeepEqual(
149
- value1[key],
150
- value2[key]
151
- )
152
- );
153
- }
154
- return Object.is(value1, value2);
155
- }
156
-
157
- // src/dom/scrollIntoView.ts
149
+ const type1 = getObjectType(value1);
150
+ const type2 = getObjectType(value2);
151
+ if (type1 !== type2) return false;
152
+ if (isArray(value1) && isArray(value2)) {
153
+ if (value1.length !== value2.length) return false;
154
+ return value1.every((item, index) => isDeepEqual(item, value2[index]));
155
+ }
156
+ if (isObject(value1) && isObject(value2)) {
157
+ const keys = Object.keys(value1);
158
+ if (keys.length !== Object.keys(value2).length) return false;
159
+ return keys.every((key) => isDeepEqual(value1[key], value2[key]));
160
+ }
161
+ return Object.is(value1, value2);
162
+ }
163
+
164
+ //#endregion
165
+ //#region src/dom/scrollIntoView.ts
166
+ /**
167
+ * Scroll element into view if it is out of view.
168
+ *
169
+ * @param element - element to scroll
170
+ * @param options - scroll options
171
+ */
158
172
  function scrollElementIntoView(element, options = {}) {
159
- const body = document.body;
160
- const { parent = body, ...scrollIntoViewOptions } = options;
161
- if (parent === body) {
162
- parent.scrollIntoView(scrollIntoViewOptions);
163
- return;
164
- }
165
- const parentRect = parent.getBoundingClientRect();
166
- const elementRect = element.getBoundingClientRect();
167
- const isHorizontal = parent.scrollWidth > parent.scrollHeight;
168
- const isOutOfView = isHorizontal ? elementRect.left < parentRect.left || elementRect.right > parentRect.right : elementRect.top < parentRect.top || elementRect.bottom > parentRect.bottom;
169
- if (isOutOfView) {
170
- parent.scrollIntoView(scrollIntoViewOptions);
171
- }
172
- }
173
-
174
- // src/dom/openExternalURL.ts
173
+ const body = document.body;
174
+ const { parent = body,...scrollIntoViewOptions } = options;
175
+ if (parent === body) {
176
+ parent.scrollIntoView(scrollIntoViewOptions);
177
+ return;
178
+ }
179
+ const parentRect = parent.getBoundingClientRect();
180
+ const elementRect = element.getBoundingClientRect();
181
+ const isHorizontal = parent.scrollWidth > parent.scrollHeight;
182
+ const isOutOfView = isHorizontal ? elementRect.left < parentRect.left || elementRect.right > parentRect.right : elementRect.top < parentRect.top || elementRect.bottom > parentRect.bottom;
183
+ if (isOutOfView) parent.scrollIntoView(scrollIntoViewOptions);
184
+ }
185
+
186
+ //#endregion
187
+ //#region src/dom/openExternalURL.ts
188
+ /**
189
+ * Open external url
190
+ * @param url - URL to open
191
+ * @param options - open options
192
+ * @returns window proxy
193
+ */
175
194
  function openExternalURL(url, options = {}) {
176
- const { target = "_blank" } = options;
177
- const proxy = window.open(url, target);
178
- return proxy;
195
+ const { target = "_blank" } = options;
196
+ const proxy = window.open(url, target);
197
+ return proxy;
179
198
  }
180
199
 
181
- // src/dom/isVisibleInViewport.ts
200
+ //#endregion
201
+ //#region src/dom/isVisibleInViewport.ts
202
+ /**
203
+ * Check if element is in viewport
204
+ * @param element - checked element
205
+ * @param targetWindow - window
206
+ * @returns true if element is in viewport, false otherwise
207
+ */
182
208
  function isElementVisibleInViewport(element, targetWindow = window) {
183
- const { top, left, bottom, right } = element.getBoundingClientRect();
184
- const { innerWidth, innerHeight } = targetWindow;
185
- return (top >= 0 && top <= innerHeight || bottom >= 0 && bottom <= innerHeight) && (left >= 0 && left <= innerWidth || right >= 0 && right <= innerWidth);
209
+ const { top, left, bottom, right } = element.getBoundingClientRect();
210
+ const { innerWidth, innerHeight } = targetWindow;
211
+ return (top >= 0 && top <= innerHeight || bottom >= 0 && bottom <= innerHeight) && (left >= 0 && left <= innerWidth || right >= 0 && right <= innerWidth);
186
212
  }
187
213
 
188
- // src/env/isBrowser.ts
189
- var isBrowser = () => typeof document !== "undefined";
214
+ //#endregion
215
+ //#region src/env/isBrowser.ts
216
+ /**
217
+ * @file env.ts
218
+ */
219
+ /**
220
+ * Checks if the code is running in a browser
221
+ *
222
+ * @returns boolean - true if the code is running in a browser
223
+ */
224
+ const isBrowser = () => typeof document !== "undefined";
190
225
 
191
- // src/html/escape.ts
192
- var htmlEscapeMap = {
193
- "&": "&amp;",
194
- "<": "&lt;",
195
- ">": "&gt;",
196
- "'": "&#39;",
197
- '"': "&quot;"
226
+ //#endregion
227
+ //#region src/html/escape.ts
228
+ const htmlEscapeMap = {
229
+ "&": "&amp;",
230
+ "<": "&lt;",
231
+ ">": "&gt;",
232
+ "'": "&#39;",
233
+ "\"": "&quot;"
198
234
  };
199
- var htmlEscapeRegexp = /[&<>'"]/g;
235
+ const htmlEscapeRegexp = /[&<>'"]/g;
236
+ /**
237
+ * Escape html chars
238
+ */
200
239
  function escapeHTML(str) {
201
- return str.replace(
202
- htmlEscapeRegexp,
203
- (char) => htmlEscapeMap[char]
204
- );
205
- }
206
- var htmlUnescapeMap = {
207
- "&amp;": "&",
208
- "&#38;": "&",
209
- "&lt;": "<",
210
- "&#60;": "<",
211
- "&gt;": ">",
212
- "&#62;": ">",
213
- "&apos;": "'",
214
- "&#39;": "'",
215
- "&quot;": '"',
216
- "&#34;": '"'
240
+ return str.replace(htmlEscapeRegexp, (char) => htmlEscapeMap[char]);
241
+ }
242
+ const htmlUnescapeMap = {
243
+ "&amp;": "&",
244
+ "&#38;": "&",
245
+ "&lt;": "<",
246
+ "&#60;": "<",
247
+ "&gt;": ">",
248
+ "&#62;": ">",
249
+ "&apos;": "'",
250
+ "&#39;": "'",
251
+ "&quot;": "\"",
252
+ "&#34;": "\""
217
253
  };
218
- var htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
254
+ const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
255
+ /**
256
+ * Unescape html chars
257
+ */
219
258
  function unescapeHTML(str) {
220
- return str.replace(
221
- htmlUnescapeRegexp,
222
- (char) => htmlUnescapeMap[char]
223
- );
259
+ return str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
224
260
  }
225
261
 
226
- // src/misc/raf.ts
227
- var root = isBrowser() ? window : globalThis;
228
- var prev = Date.now();
262
+ //#endregion
263
+ //#region src/misc/raf.ts
264
+ const root = isBrowser() ? window : globalThis;
265
+ let prev = Date.now();
229
266
  function mockRAF(fn) {
230
- const curr = Date.now();
231
- const ms = Math.max(0, 16 - (curr - prev));
232
- const id = setTimeout(fn, ms);
233
- prev = curr + ms;
234
- return id;
235
- }
267
+ const curr = Date.now();
268
+ const ms = Math.max(0, 16 - (curr - prev));
269
+ const id = setTimeout(fn, ms);
270
+ prev = curr + ms;
271
+ return id;
272
+ }
273
+ /**
274
+ * Request animation frame
275
+ *
276
+ * @param fn - callback
277
+ * @returns id
278
+ */
236
279
  function rAF(fn) {
237
- const raf = root.requestAnimationFrame || mockRAF;
238
- return raf.call(root, fn);
239
- }
280
+ const raf = root.requestAnimationFrame || mockRAF;
281
+ return raf.call(root, fn);
282
+ }
283
+ /**
284
+ * Cancel animation frame
285
+ *
286
+ * @param id - id
287
+ * @returns void
288
+ */
240
289
  function cAF(id) {
241
- const caf = root.cancelAnimationFrame || root.clearTimeout;
242
- return caf.call(root, id);
290
+ const caf = root.cancelAnimationFrame || root.clearTimeout;
291
+ return caf.call(root, id);
243
292
  }
244
293
 
245
- // src/misc/time.ts
246
- var ONE_SECOND = 1e3;
247
- var ONE_MINUTE = 60 * ONE_SECOND;
248
- var ONE_HOUR = 60 * ONE_MINUTE;
249
- var ONE_DAY = 24 * ONE_HOUR;
250
- var ONE_WEEK = 7 * ONE_DAY;
294
+ //#endregion
295
+ //#region src/misc/time.ts
296
+ /**
297
+ * @file time utils
298
+ * @module Time
299
+ */
300
+ const ONE_SECOND = 1e3;
301
+ const ONE_MINUTE = 60 * ONE_SECOND;
302
+ const ONE_HOUR = 60 * ONE_MINUTE;
303
+ const ONE_DAY = 24 * ONE_HOUR;
304
+ const ONE_WEEK = 7 * ONE_DAY;
251
305
  function seconds(count) {
252
- return count * ONE_SECOND;
306
+ return count * ONE_SECOND;
253
307
  }
254
308
  function minutes(count) {
255
- return count * ONE_MINUTE;
309
+ return count * ONE_MINUTE;
256
310
  }
257
311
  function hours(count) {
258
- return count * ONE_HOUR;
312
+ return count * ONE_HOUR;
259
313
  }
260
314
  function days(count) {
261
- return count * ONE_DAY;
315
+ return count * ONE_DAY;
262
316
  }
263
317
  function weeks(count) {
264
- return count * ONE_WEEK;
318
+ return count * ONE_WEEK;
265
319
  }
266
320
 
267
- // src/misc/clamp.ts
321
+ //#endregion
322
+ //#region src/misc/clamp.ts
323
+ /**
324
+ * Clamps a number between a minimum and maximum value
325
+ * @param value - the value to clamp within the given range
326
+ * @param min - the minimum value to clamp
327
+ * @param max - the maximum value to clamp
328
+ * @returns the new value
329
+ */
268
330
  function clamp(value, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY) {
269
- return Math.min(Math.max(value, min), max);
331
+ return Math.min(Math.max(value, min), max);
270
332
  }
271
333
 
272
- // src/misc/waitFor.ts
334
+ //#endregion
335
+ //#region src/misc/waitFor.ts
336
+ /**
337
+ * Wait for a number of milliseconds
338
+ *
339
+ * @param ms - millseconds to wait
340
+ * @returns a promise that resolves after ms milliseconds
341
+ *
342
+ * @example
343
+ * ```
344
+ * import { waitFor } from '@ntnyq/utils'
345
+ * await waitFor(3e3)
346
+ * // do somthing after 3 seconds
347
+ * ```
348
+ */
273
349
  async function waitFor(ms) {
274
- return new Promise((resolve) => setTimeout(resolve, ms));
350
+ return new Promise((resolve) => setTimeout(resolve, ms));
275
351
  }
276
352
 
277
- // src/misc/throttle.ts
353
+ //#endregion
354
+ //#region src/misc/throttle.ts
355
+ /**
356
+ * Throttle a function to limit its execution to a maximum of once per a specified time interval.
357
+ *
358
+ * @param delay - Zero or greater delay in milliseconds
359
+ * @param callback - A function to be throttled
360
+ * @param options - throttle options
361
+ * @returns A throttled function
362
+ */
278
363
  function throttle(delay, callback, options = {}) {
279
- const { isDebounce } = options;
280
- let lastExec = 0;
281
- let cancelled = false;
282
- let timeoutId;
283
- function clearExistingTimeout() {
284
- if (timeoutId) {
285
- clearTimeout(timeoutId);
286
- }
287
- }
288
- function cancel() {
289
- clearExistingTimeout();
290
- cancelled = true;
291
- }
292
- function wrapper(...args) {
293
- if (cancelled) return;
294
- const _this = this;
295
- const now = Date.now();
296
- const elapsed = now - lastExec;
297
- function clear() {
298
- timeoutId = void 0;
299
- }
300
- function exec(cur) {
301
- lastExec = cur || Date.now();
302
- callback.apply(_this, args);
303
- }
304
- if (isDebounce && !timeoutId) {
305
- exec(now);
306
- }
307
- clearExistingTimeout();
308
- if (!isDebounce && elapsed > delay) {
309
- exec(now);
310
- } else {
311
- timeoutId = setTimeout(
312
- isDebounce ? clear : exec,
313
- isDebounce ? delay : delay - elapsed
314
- );
315
- }
316
- }
317
- wrapper.cancel = cancel;
318
- return wrapper;
364
+ const { isDebounce } = options;
365
+ /**
366
+ * Track the last time `callback` was executed
367
+ */
368
+ let lastExec = 0;
369
+ let cancelled = false;
370
+ let timeoutId;
371
+ function clearExistingTimeout() {
372
+ if (timeoutId) clearTimeout(timeoutId);
373
+ }
374
+ function cancel() {
375
+ clearExistingTimeout();
376
+ cancelled = true;
377
+ }
378
+ function wrapper(...args) {
379
+ if (cancelled) return;
380
+ const _this = this;
381
+ const now = Date.now();
382
+ const elapsed = now - lastExec;
383
+ function clear() {
384
+ timeoutId = void 0;
385
+ }
386
+ function exec(cur) {
387
+ lastExec = cur || Date.now();
388
+ callback.apply(_this, args);
389
+ }
390
+ if (isDebounce && !timeoutId) exec(now);
391
+ clearExistingTimeout();
392
+ if (!isDebounce && elapsed > delay) exec(now);
393
+ else timeoutId = setTimeout(isDebounce ? clear : exec, isDebounce ? delay : delay - elapsed);
394
+ }
395
+ wrapper.cancel = cancel;
396
+ return wrapper;
319
397
  }
320
398
  function debounce(delay, callback, options = {}) {
321
- return throttle(delay, callback, {
322
- ...options,
323
- isDebounce: true
324
- });
399
+ return throttle(delay, callback, {
400
+ ...options,
401
+ isDebounce: true
402
+ });
325
403
  }
326
404
 
327
- // src/misc/warnOnce.ts
328
- var warned = /* @__PURE__ */ new Set();
405
+ //#endregion
406
+ //#region src/misc/warnOnce.ts
407
+ /**
408
+ * Cached warnings
409
+ */
410
+ const warned = new Set();
411
+ /**
412
+ * Warn message only once
413
+ *
414
+ * @param message - warning message
415
+ */
329
416
  function warnOnce(message) {
330
- if (warned.has(message)) {
331
- return;
332
- }
333
- warned.add(message);
334
- console.warn(message);
417
+ if (warned.has(message)) return;
418
+ warned.add(message);
419
+ console.warn(message);
335
420
  }
336
421
 
337
- // src/array/at.ts
422
+ //#endregion
423
+ //#region src/array/at.ts
424
+ /**
425
+ * Get array item by index, negative for backward
426
+ * @param array - given array
427
+ * @param index - index of item
428
+ * @returns undefined if not match, otherwise matched item
429
+ */
338
430
  function at(array, index) {
339
- const length = array.length;
340
- if (!length) return void 0;
341
- if (index < 0) {
342
- index += length;
343
- }
344
- return array[index];
345
- }
431
+ const length = array.length;
432
+ if (!length) return void 0;
433
+ if (index < 0) index += length;
434
+ return array[index];
435
+ }
436
+ /**
437
+ * Get the last item of given array
438
+ * @param array - given array
439
+ * @returns undefined if empty array, otherwise last item
440
+ */
346
441
  function last(array) {
347
- return at(array, -1);
442
+ return at(array, -1);
348
443
  }
349
444
 
350
- // src/array/chunk.ts
445
+ //#endregion
446
+ //#region src/array/chunk.ts
447
+ /**
448
+ * Splits an array into smaller chunks of a given size.
449
+ * @param array - The array to split
450
+ * @param size - The size of each chunk
451
+ * @returns An array of arrays, where each sub-array has `size` elements from the original array.
452
+ */
351
453
  function chunk(array, size) {
352
- const result = [];
353
- for (let i = 0; i < array.length; i += size) {
354
- result.push(array.slice(i, i + size));
355
- }
356
- return result;
454
+ const result = [];
455
+ for (let i = 0; i < array.length; i += size) result.push(array.slice(i, i + size));
456
+ return result;
357
457
  }
358
458
 
359
- // src/array/unique.ts
459
+ //#endregion
460
+ //#region src/array/unique.ts
461
+ /**
462
+ * Returns a new array with unique values.
463
+ * @param array - The array to process.
464
+ * @returns The new array.
465
+ */
360
466
  function unique(array) {
361
- return Array.from(new Set(array));
362
- }
467
+ return Array.from(new Set(array));
468
+ }
469
+ /**
470
+ * Returns a new array with unique values.
471
+ * @param array - The array to process.
472
+ * @param equalFn - The function to compare values.
473
+ * @returns The new array.
474
+ */
363
475
  function uniqueBy(array, equalFn) {
364
- return array.reduce((acc, cur) => {
365
- const idx = acc.findIndex((item) => equalFn(item, cur));
366
- if (idx === -1) {
367
- acc.push(cur);
368
- }
369
- return acc;
370
- }, []);
476
+ return array.reduce((acc, cur) => {
477
+ const idx = acc.findIndex((item) => equalFn(item, cur));
478
+ if (idx === -1) acc.push(cur);
479
+ return acc;
480
+ }, []);
371
481
  }
372
482
 
373
- // src/array/toArray.ts
483
+ //#endregion
484
+ //#region src/array/toArray.ts
485
+ /**
486
+ * Converts a value to an array.
487
+ * @param array - The value to convert.
488
+ * @returns The array.
489
+ */
374
490
  function toArray(array) {
375
- array = array ?? [];
376
- return Array.isArray(array) ? array : [array];
491
+ array = array ?? [];
492
+ return Array.isArray(array) ? array : [array];
377
493
  }
378
494
 
379
- // src/array/arrayable.ts
495
+ //#endregion
496
+ //#region src/array/arrayable.ts
497
+ /**
498
+ * Convert `Arrayable<T>` to `Array<T>` and flatten the result
499
+ * @param array - given array
500
+ * @returns Array<T>
501
+ */
380
502
  function flattenArrayable(array) {
381
- return toArray(array).flat(1);
503
+ return toArray(array).flat();
382
504
  }
505
+ /**
506
+ * Use rest arguments to merge arrays
507
+ * @param args - rest arguments
508
+ * @returns Array<T>
509
+ */
383
510
  function mergeArrayable(...args) {
384
- return args.flatMap((i) => toArray(i));
511
+ return args.flatMap((i) => toArray(i));
385
512
  }
386
513
 
387
- // src/array/intersect.ts
514
+ //#endregion
515
+ //#region src/array/intersect.ts
516
+ /**
517
+ * Get intersect items
518
+ *
519
+ * @returns intersect items
520
+ */
388
521
  function intersect(a, b) {
389
- return a.filter((item) => b.includes(item));
522
+ return a.filter((item) => b.includes(item));
390
523
  }
391
524
 
392
- // src/array/isArrayEqual.ts
525
+ //#endregion
526
+ //#region src/array/isArrayEqual.ts
527
+ /**
528
+ * Check if values of two arrays are equal
529
+ * @param array1 - array 1
530
+ * @param array2 - array 2
531
+ * @returns `true` if equal
532
+ */
393
533
  function isArrayEqual(array1, array2) {
394
- if (array1.length !== array2.length) {
395
- return false;
396
- }
397
- return array1.every((item, idx) => item === array2[idx]);
534
+ if (array1.length !== array2.length) return false;
535
+ return array1.every((item, idx) => item === array2[idx]);
398
536
  }
399
537
 
400
- // src/string/pad.ts
538
+ //#endregion
539
+ //#region src/string/pad.ts
401
540
  function createPadString(options) {
402
- const { length, char } = options;
403
- return (value) => (char.repeat(length) + value).slice(-length);
541
+ const { length, char } = options;
542
+ return (value) => (char.repeat(length) + value).slice(-length);
404
543
  }
405
544
 
406
- // src/string/join.ts
545
+ //#endregion
546
+ //#region src/string/join.ts
547
+ /**
548
+ * Joins an array of strings or numbers into a single string.
549
+ * @param array - An array of strings or numbers.
550
+ * @param options - An object of options.
551
+ * @returns A string.
552
+ */
407
553
  function join(array, options = {}) {
408
- const { separator = "" } = options;
409
- if (!Array.isArray(array) || !array.length) return "";
410
- return array.filter((v) => Boolean(v) || v === 0).join(separator);
554
+ const { separator = "" } = options;
555
+ if (!Array.isArray(array) || !array.length) return "";
556
+ return array.filter((v) => Boolean(v) || v === 0).join(separator);
411
557
  }
412
558
 
413
- // src/string/slash.ts
559
+ //#endregion
560
+ //#region src/string/slash.ts
561
+ /**
562
+ * Replace backslash to slash
563
+ */
414
564
  function slash(input) {
415
- return input.replace(/\\/g, "/");
565
+ return input.replace(/\\/g, "/");
416
566
  }
417
567
 
418
- // src/number/random.ts
568
+ //#endregion
569
+ //#region src/number/random.ts
570
+ /**
571
+ * random an integer by given range
572
+ *
573
+ * @param min - min value
574
+ * @param max - max value
575
+ * @returns random integer in range
576
+ */
419
577
  function randomNumber(min, max = 0, options = {}) {
420
- if (max === 0) {
421
- max = min;
422
- min = 0;
423
- }
424
- if (min > max) {
425
- ;
426
- [min, max] = [max, min];
427
- }
428
- return Math.trunc(
429
- Math.random() * (max - min + (options.includeMax ? 1 : 0)) + min
430
- );
431
- }
432
-
433
- // src/string/random.ts
578
+ if (max === 0) {
579
+ max = min;
580
+ min = 0;
581
+ }
582
+ if (min > max) [min, max] = [max, min];
583
+ return Math.trunc(Math.random() * (max - min + (options.includeMax ? 1 : 0)) + min);
584
+ }
585
+
586
+ //#endregion
587
+ //#region src/number/toInteger.ts
588
+ /**
589
+ * Transforms a value to an integer.
590
+ * @param value - The value to convert to an integer.
591
+ * @param options - Options for the conversion.
592
+ * @returns The converted integer.
593
+ */
594
+ function toInteger(value, options = {}) {
595
+ const { defaultValue = 0, allowDecimal = false, allowNaN = false, onError = "useDefault", min, max, outOfRange = "clamp" } = options;
596
+ let numberValue;
597
+ let result;
598
+ if (isNumber(value)) numberValue = value;
599
+ else if (isString(value)) {
600
+ const trimmed = value.trim();
601
+ if (isEmptyString(trimmed)) {
602
+ if (onError === "throwError") throw new TypeError("Cannot convert empty string to an integer");
603
+ return onError === "returnOriginal" ? value : defaultValue;
604
+ }
605
+ numberValue = Number(trimmed);
606
+ } else if (isNullOrUndefined(value)) {
607
+ if (onError === "throwError") throw new TypeError(`Cannot convert ${value} to an integer`);
608
+ return onError === "useDefault" ? value : defaultValue;
609
+ } else numberValue = Number(value);
610
+ if (isNaN(numberValue)) {
611
+ if (allowNaN) return numberValue;
612
+ if (onError === "throwError") throw new TypeError(`Cannot convert NaN to an integer`);
613
+ return onError === "returnOriginal" ? value : defaultValue;
614
+ }
615
+ if (allowDecimal) result = Math.floor(numberValue);
616
+ else {
617
+ if (numberValue % 1 !== 0) {
618
+ if (onError === "throwError") throw new Error("Decimal values are not allowed");
619
+ return onError === "returnOriginal" ? value : defaultValue;
620
+ }
621
+ result = numberValue;
622
+ }
623
+ if (!isUndefined(min) || !isUndefined(max)) {
624
+ const minVal = min ?? -Infinity;
625
+ const maxVal = max ?? Infinity;
626
+ if (result < minVal || result > maxVal) {
627
+ if (outOfRange === "throwError") throw new RangeError(`Value ${result} is out of range [${minVal}, ${maxVal}]`);
628
+ if (outOfRange === "useDefault") return defaultValue;
629
+ if (outOfRange === "clamp") result = Math.max(minVal, Math.min(maxVal, numberValue));
630
+ }
631
+ }
632
+ return result;
633
+ }
634
+
635
+ //#endregion
636
+ //#region src/string/random.ts
637
+ /**
638
+ * randome a string useing given chars
639
+ *
640
+ * @param length - string length
641
+ * @param chars - string chars
642
+ * @returns random string
643
+ */
434
644
  function randomString(length = 16, chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") {
435
- const result = [];
436
- for (let i = length; i > 0; --i) {
437
- result.push(chars[randomNumber(chars.length)]);
438
- }
439
- return result.join("");
645
+ const result = [];
646
+ for (let i = length; i > 0; --i) result.push(chars[randomNumber(chars.length)]);
647
+ return result.join("");
440
648
  }
441
649
 
442
- // src/string/slugify.ts
443
- var rControl = /[\u0000-\u001F]/g;
444
- var rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
445
- var rCombining = /[\u0300-\u036F]/g;
650
+ //#endregion
651
+ //#region src/string/slugify.ts
652
+ const rControl = /[\u0000-\u001F]/g;
653
+ const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
654
+ const rCombining = /[\u0300-\u036F]/g;
655
+ /**
656
+ * Default slugify function
657
+ */
446
658
  function slugify(str) {
447
- return str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
659
+ return str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
448
660
  }
449
661
 
450
- // src/string/unindent.ts
451
- var _RE_FULL_WS = /^\s*$/;
662
+ //#endregion
663
+ //#region src/string/unindent.ts
664
+ const _RE_FULL_WS = /^\s*$/;
665
+ /**
666
+ * Remove common leading whitespace from a template string
667
+ * Empty lines at the beginning and end of the template string are also removed.
668
+ * @param input - template string
669
+ *
670
+ * @example
671
+ *
672
+ * ```ts
673
+ * const str = unindent`
674
+ * if (foo) {
675
+ * bar()
676
+ * }
677
+ * `
678
+ * ```
679
+ */
452
680
  function unindent(input) {
453
- const lines = (typeof input === "string" ? input : input[0]).split("\n");
454
- const whitespaceLines = lines.map((line) => _RE_FULL_WS.test(line));
455
- const commonIndent = lines.reduce((min, line, idx) => {
456
- if (whitespaceLines[idx]) {
457
- return min;
458
- }
459
- const indent = line.match(/^\s*/)?.[0].length;
460
- return indent === void 0 ? min : Math.min(min, indent);
461
- }, Number.POSITIVE_INFINITY);
462
- let emptylinesHead = 0;
463
- while (emptylinesHead < lines.length && whitespaceLines[emptylinesHead]) {
464
- emptylinesHead++;
465
- }
466
- let emptylinesTail = 0;
467
- while (emptylinesTail < lines.length && whitespaceLines[lines.length - emptylinesTail - 1]) {
468
- emptylinesTail++;
469
- }
470
- return lines.slice(emptylinesHead, lines.length - emptylinesTail).map((line) => line.slice(commonIndent)).join("\n");
471
- }
472
-
473
- // src/string/ensurePrefix.ts
681
+ const lines = (typeof input === "string" ? input : input[0]).split("\n");
682
+ const whitespaceLines = lines.map((line) => _RE_FULL_WS.test(line));
683
+ const commonIndent = lines.reduce((min, line, idx) => {
684
+ if (whitespaceLines[idx]) return min;
685
+ const indent = line.match(/^\s*/)?.[0].length;
686
+ return indent === void 0 ? min : Math.min(min, indent);
687
+ }, Number.POSITIVE_INFINITY);
688
+ let emptylinesHead = 0;
689
+ while (emptylinesHead < lines.length && whitespaceLines[emptylinesHead]) emptylinesHead++;
690
+ let emptylinesTail = 0;
691
+ while (emptylinesTail < lines.length && whitespaceLines[lines.length - emptylinesTail - 1]) emptylinesTail++;
692
+ return lines.slice(emptylinesHead, lines.length - emptylinesTail).map((line) => line.slice(commonIndent)).join("\n");
693
+ }
694
+
695
+ //#endregion
696
+ //#region src/string/getLength.ts
697
+ let segmenter;
698
+ function isASCII(value) {
699
+ return /^[\u0020-\u007F]*$/u.test(value);
700
+ }
701
+ /**
702
+ * Counts graphemes in a given string
703
+ * @param value - A string to count graphemes.
704
+ * @returns The number of graphemes in `value`.
705
+ */
706
+ function getStringLength(value) {
707
+ if (isASCII(value)) return value.length;
708
+ segmenter ??= new Intl.Segmenter();
709
+ return [...segmenter.segment(value)].length;
710
+ }
711
+
712
+ //#endregion
713
+ //#region src/string/ensurePrefix.ts
474
714
  function ensurePrefix(input, prefix) {
475
- return input.startsWith(prefix) ? input : `${prefix}${input}`;
715
+ return input.startsWith(prefix) ? input : `${prefix}${input}`;
476
716
  }
477
717
 
478
- // src/string/ensureSuffix.ts
718
+ //#endregion
719
+ //#region src/string/ensureSuffix.ts
479
720
  function ensureSuffix(input, suffix) {
480
- return input.endsWith(suffix) ? input : `${input}${suffix}`;
721
+ return input.endsWith(suffix) ? input : `${input}${suffix}`;
481
722
  }
482
723
 
483
- // src/color/color.ts
484
- var pad2 = createPadString({ length: 2, char: "0" });
485
- var RE_VALID_HEX_COLOR = /^#(?:[0-9a-f]{6}|[0-9a-f]{3})$/i;
724
+ //#endregion
725
+ //#region src/color/color.ts
726
+ const pad2 = createPadString({
727
+ length: 2,
728
+ char: "0"
729
+ });
730
+ const RE_VALID_HEX_COLOR = /^#(?:[0-9a-f]{6}|[0-9a-f]{3})$/i;
486
731
  function validateHexColor(hex) {
487
- if (hex.length !== 4 && hex.length !== 7) return false;
488
- if (!hex.startsWith("#")) return false;
489
- return RE_VALID_HEX_COLOR.test(hex);
732
+ if (hex.length !== 4 && hex.length !== 7) return false;
733
+ if (!hex.startsWith("#")) return false;
734
+ return RE_VALID_HEX_COLOR.test(hex);
490
735
  }
491
736
  function normalizeHexString(hex) {
492
- return hex.length === 6 ? hex : hex.replace(/./g, "$&$&");
493
- }
494
- var Color = class _Color {
495
- red = 0;
496
- green = 0;
497
- blue = 0;
498
- alpha = 1;
499
- constructor(red = 0, green = 0, blue = 0, alpha = 1) {
500
- this.red = red;
501
- this.green = green;
502
- this.blue = blue;
503
- this.alpha = alpha;
504
- }
505
- static fromRGB(red, green, blue) {
506
- return new _Color(red, green, blue);
507
- }
508
- static fromRGBA(red, green, blue, alpha) {
509
- return new _Color(red, green, blue, alpha);
510
- }
511
- static fromHex(hex) {
512
- if (!validateHexColor(hex)) {
513
- throw new Error("Invalid hex color");
514
- }
515
- const [red, green, blue] = normalizeHexString(hex.slice(1)).match(/.{2}/g)?.map((value) => Number.parseInt(value, 16)) ?? [0, 0, 0];
516
- return new _Color(red, green, blue);
517
- }
518
- get brightness() {
519
- return (this.red * 299 + this.green * 587 + this.blue * 114) / 1e3;
520
- }
521
- get isDark() {
522
- return this.brightness < 128;
523
- }
524
- get isLight() {
525
- return !this.isDark;
526
- }
527
- toHexString(isUpperCase = true) {
528
- const hexString = `#${pad2(this.red.toString(16))}${pad2(this.green.toString(16))}${pad2(this.blue.toString(16))}`;
529
- return isUpperCase ? hexString.toUpperCase() : hexString;
530
- }
531
- toRGBAString() {
532
- return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
533
- }
534
- /**
535
- * add alpha value to {@link Color}
536
- *
537
- * @param alpha - alpha value
538
- * @returns instance of {@link Color}
539
- */
540
- withAlpha(alpha = 1) {
541
- return new _Color(this.red, this.green, this.blue, alpha);
542
- }
543
- /**
544
- * lighten the color by percentage
545
- *
546
- * @param percentage - percentage to lighten
547
- */
548
- lighten(percentage = 0) {
549
- const amount = Math.round(percentage / 100 * 255);
550
- return new _Color(
551
- Math.min(this.red + amount, 255),
552
- Math.min(this.green + amount, 255),
553
- Math.min(this.blue + amount, 255),
554
- this.alpha
555
- );
556
- }
557
- /**
558
- * darken the color by percentage
559
- *
560
- * @param percentage - percentage to darken
561
- */
562
- darken(percentage = 0) {
563
- const amount = Math.round(percentage / 100 * 255);
564
- return new _Color(
565
- Math.max(this.red - amount, 0),
566
- Math.max(this.green - amount, 0),
567
- Math.max(this.blue - amount, 0),
568
- this.alpha
569
- );
570
- }
737
+ return hex.length === 6 ? hex : hex.replace(/./g, "$&$&");
738
+ }
739
+ var Color = class Color {
740
+ red = 0;
741
+ green = 0;
742
+ blue = 0;
743
+ alpha = 1;
744
+ constructor(red = 0, green = 0, blue = 0, alpha = 1) {
745
+ this.red = red;
746
+ this.green = green;
747
+ this.blue = blue;
748
+ this.alpha = alpha;
749
+ }
750
+ static fromRGB(red, green, blue) {
751
+ return new Color(red, green, blue);
752
+ }
753
+ static fromRGBA(red, green, blue, alpha) {
754
+ return new Color(red, green, blue, alpha);
755
+ }
756
+ static fromHex(hex) {
757
+ if (!validateHexColor(hex)) throw new Error("Invalid hex color");
758
+ const [red, green, blue] = normalizeHexString(hex.slice(1)).match(/.{2}/g)?.map((value) => Number.parseInt(value, 16)) ?? [
759
+ 0,
760
+ 0,
761
+ 0
762
+ ];
763
+ return new Color(red, green, blue);
764
+ }
765
+ get brightness() {
766
+ return (this.red * 299 + this.green * 587 + this.blue * 114) / 1e3;
767
+ }
768
+ get isDark() {
769
+ return this.brightness < 128;
770
+ }
771
+ get isLight() {
772
+ return !this.isDark;
773
+ }
774
+ toHexString(isUpperCase = true) {
775
+ const hexString = `#${pad2(this.red.toString(16))}${pad2(this.green.toString(16))}${pad2(this.blue.toString(16))}`;
776
+ return isUpperCase ? hexString.toUpperCase() : hexString;
777
+ }
778
+ toRGBAString() {
779
+ return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
780
+ }
781
+ /**
782
+ * add alpha value to {@link Color}
783
+ *
784
+ * @param alpha - alpha value
785
+ * @returns instance of {@link Color}
786
+ */
787
+ withAlpha(alpha = 1) {
788
+ return new Color(this.red, this.green, this.blue, alpha);
789
+ }
790
+ /**
791
+ * lighten the color by percentage
792
+ *
793
+ * @param percentage - percentage to lighten
794
+ */
795
+ lighten(percentage = 0) {
796
+ const amount = Math.round(percentage / 100 * 255);
797
+ return new Color(Math.min(this.red + amount, 255), Math.min(this.green + amount, 255), Math.min(this.blue + amount, 255), this.alpha);
798
+ }
799
+ /**
800
+ * darken the color by percentage
801
+ *
802
+ * @param percentage - percentage to darken
803
+ */
804
+ darken(percentage = 0) {
805
+ const amount = Math.round(percentage / 100 * 255);
806
+ return new Color(Math.max(this.red - amount, 0), Math.max(this.green - amount, 0), Math.max(this.blue - amount, 0), this.alpha);
807
+ }
571
808
  };
572
809
 
573
- // src/color/random.ts
574
- var MAX_RGB = 255;
810
+ //#endregion
811
+ //#region src/color/random.ts
812
+ /**
813
+ * the maximum value of RGB
814
+ */
815
+ const MAX_RGB = 255;
816
+ /**
817
+ * get a random RGB color
818
+ * @returns a random RGB color
819
+ */
575
820
  function randomRGBColor() {
576
- return `rgb(${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)})`;
821
+ return `rgb(${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)})`;
577
822
  }
823
+ /**
824
+ * get a random RGBA color
825
+ * @returns a random RGBA color
826
+ */
578
827
  function randomRGBAColor() {
579
- return `rgba(${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${Math.random().toFixed(1)})`;
828
+ return `rgba(${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${randomNumber(MAX_RGB)}, ${Math.random().toFixed(1)})`;
580
829
  }
830
+ /**
831
+ * get a random hex color
832
+ * @returns a random hex color
833
+ */
581
834
  function randomHexColor() {
582
- return `#${Math.random().toString(16).slice(2, 8)}`;
835
+ return `#${Math.random().toString(16).slice(2, 8)}`;
583
836
  }
584
837
 
585
- // src/proxy/enhance.ts
838
+ //#endregion
839
+ //#region src/proxy/enhance.ts
840
+ /**
841
+ * enhance object
842
+ * @module proxy
843
+ */
586
844
  function enhance(module, extra) {
587
- return new Proxy(module, {
588
- get(target, key, receiver) {
589
- if (Reflect.has(extra, key)) {
590
- return Reflect.get(extra, key, receiver);
591
- }
592
- return Reflect.get(target, key, receiver);
593
- },
594
- has(target, key) {
595
- return Reflect.has(extra, key) || Reflect.has(target, key);
596
- }
597
- });
598
- }
599
-
600
- // src/module/interopDefault.ts
845
+ return new Proxy(module, {
846
+ get(target, key, receiver) {
847
+ if (Reflect.has(extra, key)) return Reflect.get(extra, key, receiver);
848
+ return Reflect.get(target, key, receiver);
849
+ },
850
+ has(target, key) {
851
+ return Reflect.has(extra, key) || Reflect.has(target, key);
852
+ }
853
+ });
854
+ }
855
+
856
+ //#endregion
857
+ //#region src/module/interopDefault.ts
858
+ /**
859
+ * Interop default export from a module
860
+ *
861
+ * @param mod - The module
862
+ * @returns The default export
863
+ *
864
+ * @example
865
+ *
866
+ * ```ts
867
+ * import { interopDefault } from '@ntnyq/utils'
868
+ *
869
+ * const { unindent } = await interopDefault(import('@ntnyq/utils'))
870
+ * ```
871
+ */
601
872
  async function interopDefault(mod) {
602
- const resolved = await mod;
603
- return resolved.default || resolved;
873
+ const resolved = await mod;
874
+ return resolved.default || resolved;
604
875
  }
605
876
 
606
- // src/module/resolveSubOptions.ts
877
+ //#endregion
878
+ //#region src/module/resolveSubOptions.ts
879
+ /**
880
+ * Resolve sub options `boolean | Options` to `Options`
881
+ * @param options - core options
882
+ * @param key - sub options key
883
+ * @returns resolved sub options
884
+ *
885
+ * @example
886
+ *
887
+ * ```ts
888
+ * import { resolveSubOptions } from '@ntnyq/utils'
889
+ *
890
+ * interface Options {
891
+ * compile?: boolean | {
892
+ * include?: string[]
893
+ * exclude?: string[]
894
+ * }
895
+ * }
896
+ *
897
+ * const options: Options = {
898
+ * compile: true
899
+ * }
900
+ *
901
+ * console.log(resolveSubOptions(options, 'compile'))
902
+ *
903
+ * // => {}
904
+ * ```
905
+ */
607
906
  function resolveSubOptions(options, key) {
608
- return typeof options[key] === "boolean" ? {} : options[key] || {};
907
+ return typeof options[key] === "boolean" ? {} : options[key] || {};
609
908
  }
610
909
 
611
- // src/object/omit.ts
910
+ //#endregion
911
+ //#region src/object/omit.ts
612
912
  function omit(object, ...keys) {
613
- keys.forEach((key) => delete object[key]);
614
- return object;
913
+ keys.forEach((key) => delete object[key]);
914
+ return object;
615
915
  }
616
916
 
617
- // src/object/hasOwn.ts
917
+ //#endregion
918
+ //#region src/object/hasOwn.ts
919
+ /**
920
+ * check object has a property with given key
921
+ * @param object - the object to check
922
+ * @param key - the key to check
923
+ * @returns true if object has a property with given key, false otherwise
924
+ */
618
925
  function hasOwn(object, key) {
619
- if (object === null) {
620
- return false;
621
- }
622
- return Object.prototype.hasOwnProperty.call(object, key);
926
+ if (object === null) return false;
927
+ return Object.prototype.hasOwnProperty.call(object, key);
623
928
  }
624
929
 
625
- // src/object/pick.ts
930
+ //#endregion
931
+ //#region src/object/pick.ts
626
932
  function pick(object, keys) {
627
- return Object.assign(
628
- {},
629
- ...keys.map((key) => {
630
- if (object && hasOwn(object, key)) {
631
- return { [key]: object[key] };
632
- }
633
- })
634
- );
933
+ return Object.assign(
934
+ {},
935
+ // eslint-disable-next-line array-callback-return
936
+ ...keys.map((key) => {
937
+ if (object && hasOwn(object, key)) return { [key]: object[key] };
938
+ })
939
+ );
635
940
  }
636
941
 
637
- // src/object/clean.ts
942
+ //#endregion
943
+ //#region src/object/clean.ts
944
+ /**
945
+ * clean undefined, null, zero, empty string, empty array, empty object from object
946
+ * @param obj - object to be cleaned
947
+ * @param options - clean options
948
+ * @returns cleaned object
949
+ */
638
950
  function cleanObject(obj, options = {}) {
639
- const {
640
- cleanUndefined = true,
641
- cleanNull = true,
642
- cleanNaN = true,
643
- cleanZero = false,
644
- cleanEmptyString = false,
645
- cleanEmptyArray = false,
646
- cleanEmptyObject = false,
647
- recursive = true
648
- } = options;
649
- Object.keys(obj).forEach((key) => {
650
- const v = obj[key];
651
- if (cleanUndefined && isUndefined(v)) {
652
- delete obj[key];
653
- }
654
- if (cleanNull && isNull(v)) {
655
- delete obj[key];
656
- }
657
- if (cleanZero && isZero(v)) {
658
- delete obj[key];
659
- }
660
- if (cleanNaN && isZero(v)) {
661
- delete obj[key];
662
- }
663
- if (cleanEmptyString && isEmptyString(v)) {
664
- delete obj[key];
665
- }
666
- if (cleanEmptyArray && isEmptyArray(v)) {
667
- delete obj[key];
668
- }
669
- if (cleanEmptyObject && isEmptyObject(v)) {
670
- delete obj[key];
671
- }
672
- if (recursive && isObject(v)) {
673
- cleanObject(v, options);
674
- }
675
- });
676
- return obj;
677
- }
678
-
679
- // src/object/isPlainObject.ts
951
+ const { cleanUndefined = true, cleanNull = true, cleanNaN = true, cleanZero = false, cleanEmptyString = false, cleanEmptyArray = false, cleanEmptyObject = false, recursive = true } = options;
952
+ Object.keys(obj).forEach((key) => {
953
+ const v = obj[key];
954
+ if (cleanUndefined && isUndefined(v)) delete obj[key];
955
+ if (cleanNull && isNull(v)) delete obj[key];
956
+ if (cleanZero && isZero(v)) delete obj[key];
957
+ if (cleanNaN && isZero(v)) delete obj[key];
958
+ if (cleanEmptyString && isEmptyString(v)) delete obj[key];
959
+ if (cleanEmptyArray && isEmptyArray(v)) delete obj[key];
960
+ if (cleanEmptyObject && isEmptyObject(v)) delete obj[key];
961
+ if (recursive && isObject(v)) cleanObject(v, options);
962
+ });
963
+ return obj;
964
+ }
965
+
966
+ //#endregion
967
+ //#region src/object/isPlainObject.ts
968
+ /**
969
+ * Check if a value is a plain object (not an array, Date, RegExp, Map, Set, etc.)
970
+ *
971
+ * @param value - Checked value
972
+ * @copyright {@link https://github.com/sindresorhus/is/blob/main/source/index.ts}
973
+ */
680
974
  function isPlainObject(value) {
681
- if (!isObject(value)) return false;
682
- const prototype = Object.getPrototypeOf(value);
683
- return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
975
+ if (!isObject(value)) return false;
976
+ const prototype = Object.getPrototypeOf(value);
977
+ return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
684
978
  }
685
979
 
686
- // src/object/sortObject.ts
980
+ //#endregion
981
+ //#region src/object/sortObject.ts
982
+ /**
983
+ * Sort object properties
984
+ */
687
985
  function sortObject(obj, options = {}) {
688
- const { compareFn = (a, b) => a.localeCompare(b) } = options;
689
- function sortKeys(obj2) {
690
- const sortedKeys = Object.keys(obj2).sort(compareFn);
691
- const result = {};
692
- for (const key of sortedKeys) {
693
- const value = obj2[key];
694
- let newValue;
695
- if (options.deep && isPlainObject(value)) {
696
- newValue = sortKeys(value);
697
- } else {
698
- newValue = value;
699
- }
700
- Object.defineProperty(result, key, {
701
- ...Object.getOwnPropertyDescriptor(obj2, key),
702
- value: newValue
703
- });
704
- }
705
- return result;
706
- }
707
- return sortKeys(obj);
708
- }
709
-
710
- // src/constants/char.ts
711
- var SPECIAL_CHAR = {
712
- newline: "\n"
713
- };
986
+ const { compareFn = (a, b) => a.localeCompare(b) } = options;
987
+ function sortKeys(obj$1) {
988
+ const sortedKeys = Object.keys(obj$1).sort(compareFn);
989
+ const result = {};
990
+ for (const key of sortedKeys) {
991
+ const value = obj$1[key];
992
+ let newValue;
993
+ if (options.deep && isPlainObject(value)) newValue = sortKeys(value);
994
+ else newValue = value;
995
+ Object.defineProperty(result, key, {
996
+ ...Object.getOwnPropertyDescriptor(obj$1, key),
997
+ value: newValue
998
+ });
999
+ }
1000
+ return result;
1001
+ }
1002
+ return sortKeys(obj);
1003
+ }
714
1004
 
715
- // src/constants/regexp.ts
716
- var RE_COMMENTS = /(?:<!--|\/\*)([\s\S]*?)(?:-->|\*\/)/g;
717
- var RE_LINE_COMMENT = /\/\/.*/;
718
- var RE_BLOCK_COMMENT = /\/\*[\s\S]*?\*\//g;
719
- export {
720
- Color,
721
- NOOP,
722
- RE_BLOCK_COMMENT,
723
- RE_COMMENTS,
724
- RE_LINE_COMMENT,
725
- SPECIAL_CHAR,
726
- at,
727
- cAF,
728
- chunk,
729
- clamp,
730
- cleanObject,
731
- createPadString,
732
- days,
733
- debounce,
734
- enhance,
735
- ensurePrefix,
736
- ensureSuffix,
737
- escapeHTML,
738
- flattenArrayable,
739
- getObjectType,
740
- hasOwn,
741
- hours,
742
- interopDefault,
743
- intersect,
744
- isArray,
745
- isArrayEqual,
746
- isBigInt,
747
- isBoolean,
748
- isBrowser,
749
- isDeepEqual,
750
- isElementVisibleInViewport,
751
- isEmptyArray,
752
- isEmptyMap,
753
- isEmptyObject,
754
- isEmptySet,
755
- isEmptyString,
756
- isEmptyStringOrWhitespace,
757
- isError,
758
- isFunction,
759
- isHTMLElement,
760
- isInteger,
761
- isIterable,
762
- isMap,
763
- isNaN,
764
- isNativePromise,
765
- isNil,
766
- isNonEmptyArray,
767
- isNonEmptyString,
768
- isNull,
769
- isNullOrUndefined,
770
- isNumber,
771
- isNumbericString,
772
- isObject,
773
- isPromise,
774
- isRegExp,
775
- isSet,
776
- isString,
777
- isTruthy,
778
- isUndefined,
779
- isWhitespaceString,
780
- isZero,
781
- join,
782
- last,
783
- mergeArrayable,
784
- minutes,
785
- noop,
786
- omit,
787
- once,
788
- openExternalURL,
789
- pick,
790
- rAF,
791
- randomHexColor,
792
- randomNumber,
793
- randomRGBAColor,
794
- randomRGBColor,
795
- randomString,
796
- resolveSubOptions,
797
- scrollElementIntoView,
798
- seconds,
799
- slash,
800
- slugify,
801
- sortObject,
802
- throttle,
803
- toArray,
804
- unescapeHTML,
805
- unindent,
806
- unique,
807
- uniqueBy,
808
- waitFor,
809
- warnOnce,
810
- weeks
811
- };
1005
+ //#endregion
1006
+ //#region src/constants/char.ts
1007
+ /**
1008
+ * Special chars
1009
+ */
1010
+ const SPECIAL_CHAR = { newline: "\n" };
1011
+
1012
+ //#endregion
1013
+ //#region src/constants/regexp.ts
1014
+ /**
1015
+ * 注释正则
1016
+ *
1017
+ * 匹配 \<!-- 或 /* 开头的注释,直到 --> 或 *\/ 结尾
1018
+ */
1019
+ const RE_COMMENTS = /(?:<!--|\/\*)([\s\S]*?)(?:-->|\*\/)/g;
1020
+ /**
1021
+ * JavaScript line comment
1022
+ */
1023
+ const RE_LINE_COMMENT = /\/\/.*/;
1024
+ /**
1025
+ * JavaScript block comment
1026
+ */
1027
+ const RE_BLOCK_COMMENT = /\/\*[\s\S]*?\*\//g;
1028
+
1029
+ //#endregion
1030
+ export { Color, NOOP, RE_BLOCK_COMMENT, RE_COMMENTS, RE_LINE_COMMENT, SPECIAL_CHAR, at, cAF, chunk, clamp, cleanObject, createPadString, days, debounce, enhance, ensurePrefix, ensureSuffix, escapeHTML, flattenArrayable, getObjectType, getStringLength, hasOwn, hours, interopDefault, intersect, isArray, isArrayEqual, isBigInt, isBoolean, isBrowser, isDeepEqual, isElementVisibleInViewport, isEmptyArray, isEmptyMap, isEmptyObject, isEmptySet, isEmptyString, isEmptyStringOrWhitespace, isError, isFunction, isHTMLElement, isInteger, isIterable, isMap, isNaN, isNativePromise, isNil, isNonEmptyArray, isNonEmptyString, isNull, isNullOrUndefined, isNumber, isNumbericString, isObject, isPromise, isRegExp, isSet, isString, isTruthy, isUndefined, isWhitespaceString, isZero, join, last, mergeArrayable, minutes, noop, omit, once, openExternalURL, pick, rAF, randomHexColor, randomNumber, randomRGBAColor, randomRGBColor, randomString, resolveSubOptions, scrollElementIntoView, seconds, slash, slugify, sortObject, throttle, toArray, toInteger, unescapeHTML, unindent, unique, uniqueBy, waitFor, warnOnce, weeks };