@ntnyq/utils 0.1.3 → 0.3.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.cjs CHANGED
@@ -21,43 +21,64 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  NOOP: () => NOOP,
24
+ at: () => at,
24
25
  cAF: () => cAF,
25
26
  camelCase: () => camelCase,
26
27
  capitalize: () => capitalize,
27
28
  chunk: () => chunk,
28
29
  clamp: () => clamp,
29
30
  days: () => days,
31
+ debounce: () => debounce,
32
+ ensurePrefix: () => ensurePrefix,
33
+ ensureSuffix: () => ensureSuffix,
30
34
  flatCase: () => flatCase,
35
+ flattenArrayable: () => flattenArrayable,
31
36
  getObjectType: () => getObjectType,
32
- hasOwnProperty: () => hasOwnProperty,
37
+ hasOwn: () => hasOwn,
33
38
  hours: () => hours,
34
39
  isArray: () => isArray,
40
+ isArrayEqual: () => isArrayEqual,
35
41
  isBoolean: () => isBoolean,
36
42
  isBrowser: () => isBrowser,
43
+ isEmptyString: () => isEmptyString,
44
+ isEmptyStringOrWhitespace: () => isEmptyStringOrWhitespace,
37
45
  isFunction: () => isFunction,
38
46
  isInteger: () => isInteger,
39
47
  isNativePromise: () => isNativePromise,
48
+ isNil: () => isNil,
40
49
  isNull: () => isNull,
41
50
  isNumber: () => isNumber,
51
+ isNumbericString: () => isNumbericString,
52
+ isObject: () => isObject,
42
53
  isPromise: () => isPromise,
54
+ isRegExp: () => isRegExp,
55
+ isSet: () => isSet,
43
56
  isString: () => isString,
44
57
  isUndefined: () => isUndefined,
45
58
  isUppercase: () => isUppercase,
59
+ isWhitespaceString: () => isWhitespaceString,
46
60
  join: () => join,
47
61
  kebabCase: () => kebabCase,
62
+ last: () => last,
48
63
  lowerFirst: () => lowerFirst,
64
+ mergeArrayable: () => mergeArrayable,
49
65
  minutes: () => minutes,
50
66
  noop: () => noop,
51
67
  omit: () => omit,
68
+ once: () => once,
52
69
  pascalCase: () => pascalCase,
53
70
  pick: () => pick,
54
71
  rAF: () => rAF,
55
72
  seconds: () => seconds,
73
+ slash: () => slash,
56
74
  snakeCase: () => snakeCase,
75
+ sortObject: () => sortObject,
57
76
  splitByCase: () => splitByCase,
77
+ throttle: () => throttle,
58
78
  titleCase: () => titleCase,
59
79
  toArray: () => toArray,
60
80
  trainCase: () => trainCase,
81
+ unindent: () => unindent,
61
82
  unique: () => unique,
62
83
  uniqueBy: () => uniqueBy,
63
84
  upperFirst: () => upperFirst,
@@ -77,6 +98,18 @@ function isString(value) {
77
98
  function isNumber(value) {
78
99
  return typeof value === "number";
79
100
  }
101
+ function isEmptyString(value) {
102
+ return isString(value) && value.length === 0;
103
+ }
104
+ function isWhitespaceString(value) {
105
+ return isString(value) && /^\s*$/.test(value);
106
+ }
107
+ function isEmptyStringOrWhitespace(value) {
108
+ return isEmptyString(value) || isWhitespaceString(value);
109
+ }
110
+ function isNumbericString(value) {
111
+ return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
112
+ }
80
113
  function isInteger(value) {
81
114
  return Number.isInteger(value);
82
115
  }
@@ -95,6 +128,18 @@ function isUndefined(value) {
95
128
  function isNull(value) {
96
129
  return value === null;
97
130
  }
131
+ function isNil(value) {
132
+ return isNull(value) || isUndefined(value);
133
+ }
134
+ function isObject(value) {
135
+ return getObjectType(value) === "Object";
136
+ }
137
+ function isRegExp(value) {
138
+ return getObjectType(value) === "RegExp";
139
+ }
140
+ function isSet(value) {
141
+ return getObjectType(value) === "Set";
142
+ }
98
143
  function isNativePromise(value) {
99
144
  return getObjectType(value) === "Promise";
100
145
  }
@@ -110,6 +155,19 @@ var noop = () => {
110
155
  };
111
156
  var NOOP = noop;
112
157
 
158
+ // src/fn/once.ts
159
+ function once(func) {
160
+ let called = false;
161
+ return function(...args) {
162
+ if (called) {
163
+ return false;
164
+ }
165
+ called = true;
166
+ func.apply(this, args);
167
+ return true;
168
+ };
169
+ }
170
+
113
171
  // src/env/isBrowser.ts
114
172
  var isBrowser = () => typeof document !== "undefined";
115
173
 
@@ -247,6 +305,53 @@ function waitFor(ms) {
247
305
  return new Promise((resolve) => setTimeout(resolve, ms));
248
306
  }
249
307
 
308
+ // src/misc/throttle.ts
309
+ function throttle(delay, callback, options = {}) {
310
+ const { isDebounce } = options;
311
+ let lastExec = 0;
312
+ let cancelled = false;
313
+ let timeoutId;
314
+ function clearExistingTimeout() {
315
+ if (timeoutId) {
316
+ clearTimeout(timeoutId);
317
+ }
318
+ }
319
+ function cancel() {
320
+ clearExistingTimeout();
321
+ cancelled = true;
322
+ }
323
+ function wrapper(...args) {
324
+ if (cancelled) return;
325
+ const _this = this;
326
+ const now = Date.now();
327
+ const elapsed = now - lastExec;
328
+ function clear() {
329
+ timeoutId = void 0;
330
+ }
331
+ function exec(cur) {
332
+ lastExec = cur || Date.now();
333
+ callback.apply(_this, args);
334
+ }
335
+ if (isDebounce && !timeoutId) {
336
+ exec(now);
337
+ }
338
+ clearExistingTimeout();
339
+ if (!isDebounce && elapsed > delay) {
340
+ exec(now);
341
+ } else {
342
+ timeoutId = setTimeout(isDebounce ? clear : exec, isDebounce ? delay : delay - elapsed);
343
+ }
344
+ }
345
+ wrapper.cancel = cancel;
346
+ return wrapper;
347
+ }
348
+ function debounce(delay, callback, options = {}) {
349
+ return throttle(delay, callback, {
350
+ ...options,
351
+ isDebounce: true
352
+ });
353
+ }
354
+
250
355
  // src/misc/warnOnce.ts
251
356
  var warned = /* @__PURE__ */ new Set();
252
357
  var warnOnce = (message) => {
@@ -257,6 +362,19 @@ var warnOnce = (message) => {
257
362
  console.warn(message);
258
363
  };
259
364
 
365
+ // src/array/at.ts
366
+ function at(array, index) {
367
+ const length = array.length;
368
+ if (!length) return void 0;
369
+ if (index < 0) {
370
+ index += length;
371
+ }
372
+ return array[index];
373
+ }
374
+ function last(array) {
375
+ return at(array, -1);
376
+ }
377
+
260
378
  // src/array/chunk.ts
261
379
  function chunk(array, size) {
262
380
  const result = [];
@@ -286,6 +404,22 @@ function toArray(array) {
286
404
  return Array.isArray(array) ? array : [array];
287
405
  }
288
406
 
407
+ // src/array/arrayable.ts
408
+ function flattenArrayable(array) {
409
+ return toArray(array).flat(1);
410
+ }
411
+ function mergeArrayable(...args) {
412
+ return args.flatMap((i) => toArray(i));
413
+ }
414
+
415
+ // src/array/isArrayEqual.ts
416
+ function isArrayEqual(array1, array2) {
417
+ if (array1.length !== array2.length) {
418
+ return false;
419
+ }
420
+ return array1.every((item, idx) => item === array2[idx]);
421
+ }
422
+
289
423
  // src/string/join.ts
290
424
  function join(array, options = {}) {
291
425
  const { separator = "" } = options;
@@ -293,14 +427,52 @@ function join(array, options = {}) {
293
427
  return array.filter((v) => Boolean(v) || v === 0).join(separator);
294
428
  }
295
429
 
430
+ // src/string/slash.ts
431
+ function slash(input) {
432
+ return input.replace(/\\/g, "/");
433
+ }
434
+
435
+ // src/string/unindent.ts
436
+ var _RE_FULL_WS = /^\s*$/;
437
+ function unindent(input) {
438
+ const lines = (typeof input === "string" ? input : input[0]).split("\n");
439
+ const whitespaceLines = lines.map((line) => _RE_FULL_WS.test(line));
440
+ const commonIndent = lines.reduce((min, line, idx) => {
441
+ if (!whitespaceLines[idx]) {
442
+ return min;
443
+ }
444
+ const indent = line.match(/^\s/)?.[0].length;
445
+ return indent === void 0 ? min : Math.min(min, indent);
446
+ }, Number.POSITIVE_INFINITY);
447
+ let emptylinesHead = 0;
448
+ while (emptylinesHead < lines.length && whitespaceLines[emptylinesHead]) {
449
+ emptylinesHead++;
450
+ }
451
+ let emptylinesTail = 0;
452
+ while (emptylinesTail < lines.length && whitespaceLines[lines.length - emptylinesTail - 1]) {
453
+ emptylinesTail++;
454
+ }
455
+ return lines.slice(emptylinesHead, lines.length - emptylinesTail).map((line) => line.slice(commonIndent)).join("\n");
456
+ }
457
+
458
+ // src/string/ensurePrefix.ts
459
+ function ensurePrefix(input, prefix) {
460
+ return input.startsWith(prefix) ? input : `${prefix}${input}`;
461
+ }
462
+
463
+ // src/string/ensureSuffix.ts
464
+ function ensureSuffix(input, suffix) {
465
+ return input.endsWith(suffix) ? input : `${input}${suffix}`;
466
+ }
467
+
296
468
  // src/object/omit.ts
297
469
  function omit(object, ...keys) {
298
470
  keys.forEach((key) => delete object[key]);
299
471
  return object;
300
472
  }
301
473
 
302
- // src/object/hasOwnProperty.ts
303
- function hasOwnProperty(object, key) {
474
+ // src/object/hasOwn.ts
475
+ function hasOwn(object, key) {
304
476
  return Object.prototype.hasOwnProperty.call(object, key);
305
477
  }
306
478
 
@@ -309,52 +481,104 @@ function pick(object, keys) {
309
481
  return Object.assign(
310
482
  {},
311
483
  ...keys.map((key) => {
312
- if (object && hasOwnProperty(object, key)) {
484
+ if (object && hasOwn(object, key)) {
313
485
  return { [key]: object[key] };
314
486
  }
315
487
  })
316
488
  );
317
489
  }
490
+
491
+ // src/object/isPlainObject.ts
492
+ function isPlainObject(value) {
493
+ if (!isObject(value)) return false;
494
+ const prototype = Object.getPrototypeOf(value);
495
+ return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
496
+ }
497
+
498
+ // src/object/sortObject.ts
499
+ function sortObject(obj, options = {}) {
500
+ const { compareFn = (a, b) => a.localeCompare(b) } = options;
501
+ function sortKeys(obj2) {
502
+ const sortedKeys = Object.keys(obj2).sort(compareFn);
503
+ const result = {};
504
+ for (const key of sortedKeys) {
505
+ const value = obj2[key];
506
+ let newValue;
507
+ if (options.deep && isPlainObject(value)) {
508
+ newValue = sortKeys(value);
509
+ } else {
510
+ newValue = value;
511
+ }
512
+ Object.defineProperty(result, key, {
513
+ ...Object.getOwnPropertyDescriptor(obj2, key),
514
+ value: newValue
515
+ });
516
+ }
517
+ return result;
518
+ }
519
+ return sortKeys(obj);
520
+ }
318
521
  // Annotate the CommonJS export names for ESM import in node:
319
522
  0 && (module.exports = {
320
523
  NOOP,
524
+ at,
321
525
  cAF,
322
526
  camelCase,
323
527
  capitalize,
324
528
  chunk,
325
529
  clamp,
326
530
  days,
531
+ debounce,
532
+ ensurePrefix,
533
+ ensureSuffix,
327
534
  flatCase,
535
+ flattenArrayable,
328
536
  getObjectType,
329
- hasOwnProperty,
537
+ hasOwn,
330
538
  hours,
331
539
  isArray,
540
+ isArrayEqual,
332
541
  isBoolean,
333
542
  isBrowser,
543
+ isEmptyString,
544
+ isEmptyStringOrWhitespace,
334
545
  isFunction,
335
546
  isInteger,
336
547
  isNativePromise,
548
+ isNil,
337
549
  isNull,
338
550
  isNumber,
551
+ isNumbericString,
552
+ isObject,
339
553
  isPromise,
554
+ isRegExp,
555
+ isSet,
340
556
  isString,
341
557
  isUndefined,
342
558
  isUppercase,
559
+ isWhitespaceString,
343
560
  join,
344
561
  kebabCase,
562
+ last,
345
563
  lowerFirst,
564
+ mergeArrayable,
346
565
  minutes,
347
566
  noop,
348
567
  omit,
568
+ once,
349
569
  pascalCase,
350
570
  pick,
351
571
  rAF,
352
572
  seconds,
573
+ slash,
353
574
  snakeCase,
575
+ sortObject,
354
576
  splitByCase,
577
+ throttle,
355
578
  titleCase,
356
579
  toArray,
357
580
  trainCase,
581
+ unindent,
358
582
  unique,
359
583
  uniqueBy,
360
584
  upperFirst,
package/dist/index.d.cts CHANGED
@@ -9,12 +9,24 @@ export * from 'scule';
9
9
  declare function getObjectType(value: unknown): string;
10
10
  declare function isString(value: unknown): value is string;
11
11
  declare function isNumber(value: unknown): value is number;
12
+ declare function isEmptyString(value: unknown): value is '';
13
+ type Whitespace = ' ';
14
+ type NonEmptyString = string & {
15
+ 0: '';
16
+ };
17
+ declare function isWhitespaceString(value: unknown): value is Whitespace;
18
+ declare function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitespace;
19
+ declare function isNumbericString(value: unknown): value is `${number}`;
12
20
  declare function isInteger(value: unknown): value is number;
13
21
  declare function isBoolean(value: unknown): value is boolean;
14
22
  declare function isFunction(value: unknown): value is Function;
15
23
  declare function isArray(value: unknown): value is unknown[];
16
24
  declare function isUndefined(value: unknown): value is undefined;
17
25
  declare function isNull(value: unknown): value is null;
26
+ declare function isNil(value: unknown): value is null | undefined;
27
+ declare function isObject(value: unknown): value is object;
28
+ declare function isRegExp(value: unknown): value is RegExp;
29
+ declare function isSet<Value = unknown>(value: unknown): value is Set<Value>;
18
30
  declare function isNativePromise<T = unknown>(value: unknown): value is Promise<T>;
19
31
  declare function isPromise<T = unknown>(value: unknown): value is Promise<T>;
20
32
 
@@ -27,6 +39,8 @@ declare const noop: () => void;
27
39
  */
28
40
  declare const NOOP: () => void;
29
41
 
42
+ declare function once<T extends unknown[]>(func: (...args: T) => void): (this: unknown, ...args: T) => boolean;
43
+
30
44
  /**
31
45
  * @file env.ts
32
46
  */
@@ -98,8 +112,43 @@ declare function clamp(value: number, min?: number, max?: number): number;
98
112
  */
99
113
  declare function waitFor(ms: number): Promise<unknown>;
100
114
 
115
+ interface ThrottleDebounceOptions {
116
+ /**
117
+ * @default false
118
+ */
119
+ isDebounce?: boolean;
120
+ }
121
+ /**
122
+ * Throttle a function to limit its execution to a maximum of once per a specified time interval.
123
+ *
124
+ * @param delay - Zero or greater delay in milliseconds
125
+ * @param callback - A function to be throttled
126
+ * @param options - throttle options
127
+ * @returns A throttled function
128
+ */
129
+ declare function throttle<T extends ((...args: any[]) => undefined | void) | undefined | null>(delay: number, callback: Exclude<T, undefined | null>, options?: ThrottleDebounceOptions): T & {
130
+ cancel: () => void;
131
+ };
132
+ declare function debounce<T extends ((...args: any[]) => undefined | void) | undefined | null>(delay: number, callback: Exclude<T, undefined | null>, options?: ThrottleDebounceOptions): T & {
133
+ cancel: () => void;
134
+ };
135
+
101
136
  declare const warnOnce: (message: string) => void;
102
137
 
138
+ /**
139
+ * Get array item by index, negative for backward
140
+ * @param array - given array
141
+ * @param index - index of item
142
+ * @returns undefined if not match, otherwise matched item
143
+ */
144
+ declare function at<T>(array: readonly T[], index: number): T | undefined;
145
+ /**
146
+ * Get the last item of given array
147
+ * @param array - given array
148
+ * @returns undefined if empty array, otherwise last item
149
+ */
150
+ declare function last<T>(array: readonly T[]): T | undefined;
151
+
103
152
  /**
104
153
  * Splits an array into smaller chunks of a given size.
105
154
  * @param array The array to split
@@ -127,7 +176,11 @@ type MayBe<T> = T | undefined;
127
176
  type AnyFn<T = any, R = any> = (...args: T[]) => R;
128
177
  type Arrayable<T> = T | T[];
129
178
  type Awaitable<T> = T | Promise<T>;
130
- type Prettify<T> = Omit<T, never>;
179
+ type Prettify<T> = {
180
+ [K in keyof T]: T[K];
181
+ } & {};
182
+ type PrettifyV2<T> = Omit<T, never>;
183
+ type PrimitiveType = number | bigint | string | boolean | symbol | null | undefined;
131
184
 
132
185
  /**
133
186
  * Converts a value to an array.
@@ -136,10 +189,25 @@ type Prettify<T> = Omit<T, never>;
136
189
  */
137
190
  declare function toArray<T>(array?: Nullable<Arrayable<T>>): T[];
138
191
 
192
+ /**
193
+ * Convert `Arrayable<T>` to `Array<T>` and flatten the result
194
+ * @param array - given array
195
+ * @returns Array<T>
196
+ */
197
+ declare function flattenArrayable<T>(array?: Nullable<Arrayable<T | Array<T>>>): Array<T>;
198
+ /**
199
+ * Use rest arguments to merge arrays
200
+ * @param args - rest arguments
201
+ * @returns Array<T>
202
+ */
203
+ declare function mergeArrayable<T>(...args: Nullable<Arrayable<T>>[]): Array<T>;
204
+
205
+ declare function isArrayEqual(array1: unknown[], array2: unknown[]): boolean;
206
+
139
207
  type JoinableValue = string | number | null | undefined;
140
208
  interface JoinOptions {
141
209
  /**
142
- * @default '''
210
+ * @default ''
143
211
  */
144
212
  separator?: string;
145
213
  }
@@ -151,10 +219,52 @@ interface JoinOptions {
151
219
  */
152
220
  declare function join(array: JoinableValue[], options?: JoinOptions): string;
153
221
 
222
+ /**
223
+ * Replace backslash to slash
224
+ */
225
+ declare function slash(input: string): string;
226
+
227
+ /**
228
+ * Remove leading whitespace from a template string
229
+ * Empty lines at the beginning and end of the template string are also removed.
230
+ * @param input template string
231
+ *
232
+ * @example
233
+ *
234
+ * ```ts
235
+ * const str = unindent`
236
+ * if (foo) {
237
+ * bar()
238
+ * }
239
+ * `
240
+ * ```
241
+ */
242
+ declare function unindent(input: TemplateStringsArray | string): string;
243
+
244
+ declare function ensurePrefix(input: string, prefix: string): string;
245
+
246
+ declare function ensureSuffix(input: string, suffix: string): string;
247
+
154
248
  declare function omit<T, K extends keyof T>(object: T, ...keys: K[]): Omit<T, K>;
155
249
 
156
250
  declare function pick<T, K extends keyof T>(object: T, keys: K[]): Pick<T, K>;
157
251
 
158
- declare function hasOwnProperty<T, K extends keyof T>(object: T, key: K): boolean;
252
+ declare function hasOwn<T, K extends keyof T>(object: T, key: K): boolean;
253
+
254
+ interface SortObjectOptions {
255
+ /**
256
+ * Recursive sorting
257
+ * @default false
258
+ */
259
+ deep?: boolean;
260
+ /**
261
+ * Compare function
262
+ */
263
+ compareFn?: (left: string, right: string) => number;
264
+ }
265
+ /**
266
+ * Sort object properties
267
+ */
268
+ declare function sortObject<T extends Record<string, any>>(obj: T, options?: SortObjectOptions): T;
159
269
 
160
- export { type AnyFn, type Arrayable, type Awaitable, type MayBe, NOOP, type Nullable, type Prettify, cAF, capitalize, chunk, clamp, days, getObjectType, hasOwnProperty, hours, isArray, isBoolean, isBrowser, isFunction, isInteger, isNativePromise, isNull, isNumber, isPromise, isString, isUndefined, join, minutes, noop, omit, pick, rAF, seconds, toArray, unique, uniqueBy, waitFor, warnOnce, weeks };
270
+ export { type AnyFn, type Arrayable, type Awaitable, type MayBe, NOOP, type NonEmptyString, type Nullable, type Prettify, type PrettifyV2, type PrimitiveType, type SortObjectOptions, type ThrottleDebounceOptions, type Whitespace, at, cAF, capitalize, chunk, clamp, days, debounce, ensurePrefix, ensureSuffix, flattenArrayable, getObjectType, hasOwn, hours, isArray, isArrayEqual, isBoolean, isBrowser, isEmptyString, isEmptyStringOrWhitespace, isFunction, isInteger, isNativePromise, isNil, isNull, isNumber, isNumbericString, isObject, isPromise, isRegExp, isSet, isString, isUndefined, isWhitespaceString, join, last, mergeArrayable, minutes, noop, omit, once, pick, rAF, seconds, slash, sortObject, throttle, toArray, unindent, unique, uniqueBy, waitFor, warnOnce, weeks };
package/dist/index.d.ts CHANGED
@@ -9,12 +9,24 @@ export * from 'scule';
9
9
  declare function getObjectType(value: unknown): string;
10
10
  declare function isString(value: unknown): value is string;
11
11
  declare function isNumber(value: unknown): value is number;
12
+ declare function isEmptyString(value: unknown): value is '';
13
+ type Whitespace = ' ';
14
+ type NonEmptyString = string & {
15
+ 0: '';
16
+ };
17
+ declare function isWhitespaceString(value: unknown): value is Whitespace;
18
+ declare function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitespace;
19
+ declare function isNumbericString(value: unknown): value is `${number}`;
12
20
  declare function isInteger(value: unknown): value is number;
13
21
  declare function isBoolean(value: unknown): value is boolean;
14
22
  declare function isFunction(value: unknown): value is Function;
15
23
  declare function isArray(value: unknown): value is unknown[];
16
24
  declare function isUndefined(value: unknown): value is undefined;
17
25
  declare function isNull(value: unknown): value is null;
26
+ declare function isNil(value: unknown): value is null | undefined;
27
+ declare function isObject(value: unknown): value is object;
28
+ declare function isRegExp(value: unknown): value is RegExp;
29
+ declare function isSet<Value = unknown>(value: unknown): value is Set<Value>;
18
30
  declare function isNativePromise<T = unknown>(value: unknown): value is Promise<T>;
19
31
  declare function isPromise<T = unknown>(value: unknown): value is Promise<T>;
20
32
 
@@ -27,6 +39,8 @@ declare const noop: () => void;
27
39
  */
28
40
  declare const NOOP: () => void;
29
41
 
42
+ declare function once<T extends unknown[]>(func: (...args: T) => void): (this: unknown, ...args: T) => boolean;
43
+
30
44
  /**
31
45
  * @file env.ts
32
46
  */
@@ -98,8 +112,43 @@ declare function clamp(value: number, min?: number, max?: number): number;
98
112
  */
99
113
  declare function waitFor(ms: number): Promise<unknown>;
100
114
 
115
+ interface ThrottleDebounceOptions {
116
+ /**
117
+ * @default false
118
+ */
119
+ isDebounce?: boolean;
120
+ }
121
+ /**
122
+ * Throttle a function to limit its execution to a maximum of once per a specified time interval.
123
+ *
124
+ * @param delay - Zero or greater delay in milliseconds
125
+ * @param callback - A function to be throttled
126
+ * @param options - throttle options
127
+ * @returns A throttled function
128
+ */
129
+ declare function throttle<T extends ((...args: any[]) => undefined | void) | undefined | null>(delay: number, callback: Exclude<T, undefined | null>, options?: ThrottleDebounceOptions): T & {
130
+ cancel: () => void;
131
+ };
132
+ declare function debounce<T extends ((...args: any[]) => undefined | void) | undefined | null>(delay: number, callback: Exclude<T, undefined | null>, options?: ThrottleDebounceOptions): T & {
133
+ cancel: () => void;
134
+ };
135
+
101
136
  declare const warnOnce: (message: string) => void;
102
137
 
138
+ /**
139
+ * Get array item by index, negative for backward
140
+ * @param array - given array
141
+ * @param index - index of item
142
+ * @returns undefined if not match, otherwise matched item
143
+ */
144
+ declare function at<T>(array: readonly T[], index: number): T | undefined;
145
+ /**
146
+ * Get the last item of given array
147
+ * @param array - given array
148
+ * @returns undefined if empty array, otherwise last item
149
+ */
150
+ declare function last<T>(array: readonly T[]): T | undefined;
151
+
103
152
  /**
104
153
  * Splits an array into smaller chunks of a given size.
105
154
  * @param array The array to split
@@ -127,7 +176,11 @@ type MayBe<T> = T | undefined;
127
176
  type AnyFn<T = any, R = any> = (...args: T[]) => R;
128
177
  type Arrayable<T> = T | T[];
129
178
  type Awaitable<T> = T | Promise<T>;
130
- type Prettify<T> = Omit<T, never>;
179
+ type Prettify<T> = {
180
+ [K in keyof T]: T[K];
181
+ } & {};
182
+ type PrettifyV2<T> = Omit<T, never>;
183
+ type PrimitiveType = number | bigint | string | boolean | symbol | null | undefined;
131
184
 
132
185
  /**
133
186
  * Converts a value to an array.
@@ -136,10 +189,25 @@ type Prettify<T> = Omit<T, never>;
136
189
  */
137
190
  declare function toArray<T>(array?: Nullable<Arrayable<T>>): T[];
138
191
 
192
+ /**
193
+ * Convert `Arrayable<T>` to `Array<T>` and flatten the result
194
+ * @param array - given array
195
+ * @returns Array<T>
196
+ */
197
+ declare function flattenArrayable<T>(array?: Nullable<Arrayable<T | Array<T>>>): Array<T>;
198
+ /**
199
+ * Use rest arguments to merge arrays
200
+ * @param args - rest arguments
201
+ * @returns Array<T>
202
+ */
203
+ declare function mergeArrayable<T>(...args: Nullable<Arrayable<T>>[]): Array<T>;
204
+
205
+ declare function isArrayEqual(array1: unknown[], array2: unknown[]): boolean;
206
+
139
207
  type JoinableValue = string | number | null | undefined;
140
208
  interface JoinOptions {
141
209
  /**
142
- * @default '''
210
+ * @default ''
143
211
  */
144
212
  separator?: string;
145
213
  }
@@ -151,10 +219,52 @@ interface JoinOptions {
151
219
  */
152
220
  declare function join(array: JoinableValue[], options?: JoinOptions): string;
153
221
 
222
+ /**
223
+ * Replace backslash to slash
224
+ */
225
+ declare function slash(input: string): string;
226
+
227
+ /**
228
+ * Remove leading whitespace from a template string
229
+ * Empty lines at the beginning and end of the template string are also removed.
230
+ * @param input template string
231
+ *
232
+ * @example
233
+ *
234
+ * ```ts
235
+ * const str = unindent`
236
+ * if (foo) {
237
+ * bar()
238
+ * }
239
+ * `
240
+ * ```
241
+ */
242
+ declare function unindent(input: TemplateStringsArray | string): string;
243
+
244
+ declare function ensurePrefix(input: string, prefix: string): string;
245
+
246
+ declare function ensureSuffix(input: string, suffix: string): string;
247
+
154
248
  declare function omit<T, K extends keyof T>(object: T, ...keys: K[]): Omit<T, K>;
155
249
 
156
250
  declare function pick<T, K extends keyof T>(object: T, keys: K[]): Pick<T, K>;
157
251
 
158
- declare function hasOwnProperty<T, K extends keyof T>(object: T, key: K): boolean;
252
+ declare function hasOwn<T, K extends keyof T>(object: T, key: K): boolean;
253
+
254
+ interface SortObjectOptions {
255
+ /**
256
+ * Recursive sorting
257
+ * @default false
258
+ */
259
+ deep?: boolean;
260
+ /**
261
+ * Compare function
262
+ */
263
+ compareFn?: (left: string, right: string) => number;
264
+ }
265
+ /**
266
+ * Sort object properties
267
+ */
268
+ declare function sortObject<T extends Record<string, any>>(obj: T, options?: SortObjectOptions): T;
159
269
 
160
- export { type AnyFn, type Arrayable, type Awaitable, type MayBe, NOOP, type Nullable, type Prettify, cAF, capitalize, chunk, clamp, days, getObjectType, hasOwnProperty, hours, isArray, isBoolean, isBrowser, isFunction, isInteger, isNativePromise, isNull, isNumber, isPromise, isString, isUndefined, join, minutes, noop, omit, pick, rAF, seconds, toArray, unique, uniqueBy, waitFor, warnOnce, weeks };
270
+ export { type AnyFn, type Arrayable, type Awaitable, type MayBe, NOOP, type NonEmptyString, type Nullable, type Prettify, type PrettifyV2, type PrimitiveType, type SortObjectOptions, type ThrottleDebounceOptions, type Whitespace, at, cAF, capitalize, chunk, clamp, days, debounce, ensurePrefix, ensureSuffix, flattenArrayable, getObjectType, hasOwn, hours, isArray, isArrayEqual, isBoolean, isBrowser, isEmptyString, isEmptyStringOrWhitespace, isFunction, isInteger, isNativePromise, isNil, isNull, isNumber, isNumbericString, isObject, isPromise, isRegExp, isSet, isString, isUndefined, isWhitespaceString, join, last, mergeArrayable, minutes, noop, omit, once, pick, rAF, seconds, slash, sortObject, throttle, toArray, unindent, unique, uniqueBy, waitFor, warnOnce, weeks };
package/dist/index.js CHANGED
@@ -8,6 +8,18 @@ function isString(value) {
8
8
  function isNumber(value) {
9
9
  return typeof value === "number";
10
10
  }
11
+ function isEmptyString(value) {
12
+ return isString(value) && value.length === 0;
13
+ }
14
+ function isWhitespaceString(value) {
15
+ return isString(value) && /^\s*$/.test(value);
16
+ }
17
+ function isEmptyStringOrWhitespace(value) {
18
+ return isEmptyString(value) || isWhitespaceString(value);
19
+ }
20
+ function isNumbericString(value) {
21
+ return isString(value) && !isEmptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
22
+ }
11
23
  function isInteger(value) {
12
24
  return Number.isInteger(value);
13
25
  }
@@ -26,6 +38,18 @@ function isUndefined(value) {
26
38
  function isNull(value) {
27
39
  return value === null;
28
40
  }
41
+ function isNil(value) {
42
+ return isNull(value) || isUndefined(value);
43
+ }
44
+ function isObject(value) {
45
+ return getObjectType(value) === "Object";
46
+ }
47
+ function isRegExp(value) {
48
+ return getObjectType(value) === "RegExp";
49
+ }
50
+ function isSet(value) {
51
+ return getObjectType(value) === "Set";
52
+ }
29
53
  function isNativePromise(value) {
30
54
  return getObjectType(value) === "Promise";
31
55
  }
@@ -41,6 +65,19 @@ var noop = () => {
41
65
  };
42
66
  var NOOP = noop;
43
67
 
68
+ // src/fn/once.ts
69
+ function once(func) {
70
+ let called = false;
71
+ return function(...args) {
72
+ if (called) {
73
+ return false;
74
+ }
75
+ called = true;
76
+ func.apply(this, args);
77
+ return true;
78
+ };
79
+ }
80
+
44
81
  // src/env/isBrowser.ts
45
82
  var isBrowser = () => typeof document !== "undefined";
46
83
 
@@ -178,6 +215,53 @@ function waitFor(ms) {
178
215
  return new Promise((resolve) => setTimeout(resolve, ms));
179
216
  }
180
217
 
218
+ // src/misc/throttle.ts
219
+ function throttle(delay, callback, options = {}) {
220
+ const { isDebounce } = options;
221
+ let lastExec = 0;
222
+ let cancelled = false;
223
+ let timeoutId;
224
+ function clearExistingTimeout() {
225
+ if (timeoutId) {
226
+ clearTimeout(timeoutId);
227
+ }
228
+ }
229
+ function cancel() {
230
+ clearExistingTimeout();
231
+ cancelled = true;
232
+ }
233
+ function wrapper(...args) {
234
+ if (cancelled) return;
235
+ const _this = this;
236
+ const now = Date.now();
237
+ const elapsed = now - lastExec;
238
+ function clear() {
239
+ timeoutId = void 0;
240
+ }
241
+ function exec(cur) {
242
+ lastExec = cur || Date.now();
243
+ callback.apply(_this, args);
244
+ }
245
+ if (isDebounce && !timeoutId) {
246
+ exec(now);
247
+ }
248
+ clearExistingTimeout();
249
+ if (!isDebounce && elapsed > delay) {
250
+ exec(now);
251
+ } else {
252
+ timeoutId = setTimeout(isDebounce ? clear : exec, isDebounce ? delay : delay - elapsed);
253
+ }
254
+ }
255
+ wrapper.cancel = cancel;
256
+ return wrapper;
257
+ }
258
+ function debounce(delay, callback, options = {}) {
259
+ return throttle(delay, callback, {
260
+ ...options,
261
+ isDebounce: true
262
+ });
263
+ }
264
+
181
265
  // src/misc/warnOnce.ts
182
266
  var warned = /* @__PURE__ */ new Set();
183
267
  var warnOnce = (message) => {
@@ -188,6 +272,19 @@ var warnOnce = (message) => {
188
272
  console.warn(message);
189
273
  };
190
274
 
275
+ // src/array/at.ts
276
+ function at(array, index) {
277
+ const length = array.length;
278
+ if (!length) return void 0;
279
+ if (index < 0) {
280
+ index += length;
281
+ }
282
+ return array[index];
283
+ }
284
+ function last(array) {
285
+ return at(array, -1);
286
+ }
287
+
191
288
  // src/array/chunk.ts
192
289
  function chunk(array, size) {
193
290
  const result = [];
@@ -217,6 +314,22 @@ function toArray(array) {
217
314
  return Array.isArray(array) ? array : [array];
218
315
  }
219
316
 
317
+ // src/array/arrayable.ts
318
+ function flattenArrayable(array) {
319
+ return toArray(array).flat(1);
320
+ }
321
+ function mergeArrayable(...args) {
322
+ return args.flatMap((i) => toArray(i));
323
+ }
324
+
325
+ // src/array/isArrayEqual.ts
326
+ function isArrayEqual(array1, array2) {
327
+ if (array1.length !== array2.length) {
328
+ return false;
329
+ }
330
+ return array1.every((item, idx) => item === array2[idx]);
331
+ }
332
+
220
333
  // src/string/join.ts
221
334
  function join(array, options = {}) {
222
335
  const { separator = "" } = options;
@@ -224,14 +337,52 @@ function join(array, options = {}) {
224
337
  return array.filter((v) => Boolean(v) || v === 0).join(separator);
225
338
  }
226
339
 
340
+ // src/string/slash.ts
341
+ function slash(input) {
342
+ return input.replace(/\\/g, "/");
343
+ }
344
+
345
+ // src/string/unindent.ts
346
+ var _RE_FULL_WS = /^\s*$/;
347
+ function unindent(input) {
348
+ const lines = (typeof input === "string" ? input : input[0]).split("\n");
349
+ const whitespaceLines = lines.map((line) => _RE_FULL_WS.test(line));
350
+ const commonIndent = lines.reduce((min, line, idx) => {
351
+ if (!whitespaceLines[idx]) {
352
+ return min;
353
+ }
354
+ const indent = line.match(/^\s/)?.[0].length;
355
+ return indent === void 0 ? min : Math.min(min, indent);
356
+ }, Number.POSITIVE_INFINITY);
357
+ let emptylinesHead = 0;
358
+ while (emptylinesHead < lines.length && whitespaceLines[emptylinesHead]) {
359
+ emptylinesHead++;
360
+ }
361
+ let emptylinesTail = 0;
362
+ while (emptylinesTail < lines.length && whitespaceLines[lines.length - emptylinesTail - 1]) {
363
+ emptylinesTail++;
364
+ }
365
+ return lines.slice(emptylinesHead, lines.length - emptylinesTail).map((line) => line.slice(commonIndent)).join("\n");
366
+ }
367
+
368
+ // src/string/ensurePrefix.ts
369
+ function ensurePrefix(input, prefix) {
370
+ return input.startsWith(prefix) ? input : `${prefix}${input}`;
371
+ }
372
+
373
+ // src/string/ensureSuffix.ts
374
+ function ensureSuffix(input, suffix) {
375
+ return input.endsWith(suffix) ? input : `${input}${suffix}`;
376
+ }
377
+
227
378
  // src/object/omit.ts
228
379
  function omit(object, ...keys) {
229
380
  keys.forEach((key) => delete object[key]);
230
381
  return object;
231
382
  }
232
383
 
233
- // src/object/hasOwnProperty.ts
234
- function hasOwnProperty(object, key) {
384
+ // src/object/hasOwn.ts
385
+ function hasOwn(object, key) {
235
386
  return Object.prototype.hasOwnProperty.call(object, key);
236
387
  }
237
388
 
@@ -240,51 +391,103 @@ function pick(object, keys) {
240
391
  return Object.assign(
241
392
  {},
242
393
  ...keys.map((key) => {
243
- if (object && hasOwnProperty(object, key)) {
394
+ if (object && hasOwn(object, key)) {
244
395
  return { [key]: object[key] };
245
396
  }
246
397
  })
247
398
  );
248
399
  }
400
+
401
+ // src/object/isPlainObject.ts
402
+ function isPlainObject(value) {
403
+ if (!isObject(value)) return false;
404
+ const prototype = Object.getPrototypeOf(value);
405
+ return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
406
+ }
407
+
408
+ // src/object/sortObject.ts
409
+ function sortObject(obj, options = {}) {
410
+ const { compareFn = (a, b) => a.localeCompare(b) } = options;
411
+ function sortKeys(obj2) {
412
+ const sortedKeys = Object.keys(obj2).sort(compareFn);
413
+ const result = {};
414
+ for (const key of sortedKeys) {
415
+ const value = obj2[key];
416
+ let newValue;
417
+ if (options.deep && isPlainObject(value)) {
418
+ newValue = sortKeys(value);
419
+ } else {
420
+ newValue = value;
421
+ }
422
+ Object.defineProperty(result, key, {
423
+ ...Object.getOwnPropertyDescriptor(obj2, key),
424
+ value: newValue
425
+ });
426
+ }
427
+ return result;
428
+ }
429
+ return sortKeys(obj);
430
+ }
249
431
  export {
250
432
  NOOP,
433
+ at,
251
434
  cAF,
252
435
  camelCase,
253
436
  capitalize,
254
437
  chunk,
255
438
  clamp,
256
439
  days,
440
+ debounce,
441
+ ensurePrefix,
442
+ ensureSuffix,
257
443
  flatCase,
444
+ flattenArrayable,
258
445
  getObjectType,
259
- hasOwnProperty,
446
+ hasOwn,
260
447
  hours,
261
448
  isArray,
449
+ isArrayEqual,
262
450
  isBoolean,
263
451
  isBrowser,
452
+ isEmptyString,
453
+ isEmptyStringOrWhitespace,
264
454
  isFunction,
265
455
  isInteger,
266
456
  isNativePromise,
457
+ isNil,
267
458
  isNull,
268
459
  isNumber,
460
+ isNumbericString,
461
+ isObject,
269
462
  isPromise,
463
+ isRegExp,
464
+ isSet,
270
465
  isString,
271
466
  isUndefined,
272
467
  isUppercase,
468
+ isWhitespaceString,
273
469
  join,
274
470
  kebabCase,
471
+ last,
275
472
  lowerFirst,
473
+ mergeArrayable,
276
474
  minutes,
277
475
  noop,
278
476
  omit,
477
+ once,
279
478
  pascalCase,
280
479
  pick,
281
480
  rAF,
282
481
  seconds,
482
+ slash,
283
483
  snakeCase,
484
+ sortObject,
284
485
  splitByCase,
486
+ throttle,
285
487
  titleCase,
286
488
  toArray,
287
489
  trainCase,
490
+ unindent,
288
491
  unique,
289
492
  uniqueBy,
290
493
  upperFirst,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ntnyq/utils",
3
3
  "type": "module",
4
- "version": "0.1.3",
4
+ "version": "0.3.0",
5
5
  "description": "Common used utils.",
6
6
  "keywords": [
7
7
  "utils"
@@ -12,10 +12,10 @@
12
12
  "email": "ntnyq13@gmail.com"
13
13
  },
14
14
  "homepage": "https://github.com/ntnyq/utils#readme",
15
+ "repository": "ntnyq/utils",
15
16
  "bugs": {
16
17
  "url": "https://github.com/ntnyq/utils/issues"
17
18
  },
18
- "repository": "ntnyq/utils",
19
19
  "exports": {
20
20
  "./package.json": "./package.json",
21
21
  ".": {
@@ -40,19 +40,18 @@
40
40
  "scule": "^1.3.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@ntnyq/eslint-config": "^3.0.0-beta.19",
43
+ "@ntnyq/eslint-config": "^3.2.2",
44
44
  "@ntnyq/prettier-config": "^1.21.3",
45
- "@vitest/coverage-v8": "^2.1.2",
46
- "bumpp": "^9.7.1",
47
- "eslint": "^9.12.0",
45
+ "@vitest/coverage-v8": "^2.1.5",
46
+ "bumpp": "^9.8.1",
47
+ "eslint": "^9.14.0",
48
48
  "husky": "^9.1.6",
49
49
  "nano-staged": "^0.8.0",
50
- "npm-run-all2": "^6.2.3",
51
- "pnpm": "^9.12.1",
50
+ "npm-run-all2": "^7.0.1",
52
51
  "prettier": "^3.3.3",
53
- "tsup": "^8.3.0",
52
+ "tsup": "^8.3.5",
54
53
  "typescript": "^5.6.3",
55
- "vitest": "^2.1.2"
54
+ "vitest": "^2.1.5"
56
55
  },
57
56
  "engines": {
58
57
  "node": ">=18.18.0"