@bquery/bquery 1.2.0 → 1.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/README.md +501 -427
- package/dist/batch-4LAvfLE7.js +13 -0
- package/dist/batch-4LAvfLE7.js.map +1 -0
- package/dist/component/component.d.ts +69 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/html.d.ts +35 -0
- package/dist/component/html.d.ts.map +1 -0
- package/dist/component/index.d.ts +3 -126
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/props.d.ts +18 -0
- package/dist/component/props.d.ts.map +1 -0
- package/dist/component/types.d.ts +77 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component.es.mjs +90 -59
- package/dist/component.es.mjs.map +1 -1
- package/dist/core/collection.d.ts +36 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/dom.d.ts +6 -0
- package/dist/core/dom.d.ts.map +1 -0
- package/dist/core/element.d.ts +8 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/utils/array.d.ts +74 -0
- package/dist/core/utils/array.d.ts.map +1 -0
- package/dist/core/utils/function.d.ts +70 -0
- package/dist/core/utils/function.d.ts.map +1 -0
- package/dist/core/utils/index.d.ts +70 -0
- package/dist/core/utils/index.d.ts.map +1 -0
- package/dist/core/utils/misc.d.ts +63 -0
- package/dist/core/utils/misc.d.ts.map +1 -0
- package/dist/core/utils/number.d.ts +65 -0
- package/dist/core/utils/number.d.ts.map +1 -0
- package/dist/core/utils/object.d.ts +133 -0
- package/dist/core/utils/object.d.ts.map +1 -0
- package/dist/core/utils/string.d.ts +80 -0
- package/dist/core/utils/string.d.ts.map +1 -0
- package/dist/core/utils/type-guards.d.ts +79 -0
- package/dist/core/utils/type-guards.d.ts.map +1 -0
- package/dist/core-COenAZjD.js +145 -0
- package/dist/core-COenAZjD.js.map +1 -0
- package/dist/core.es.mjs +411 -448
- package/dist/core.es.mjs.map +1 -1
- package/dist/full.d.ts +2 -2
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +87 -64
- package/dist/full.es.mjs.map +1 -1
- package/dist/full.iife.js +2 -2
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +2 -2
- package/dist/full.umd.js.map +1 -1
- package/dist/index.es.mjs +138 -68
- package/dist/index.es.mjs.map +1 -1
- package/dist/motion/animate.d.ts +25 -0
- package/dist/motion/animate.d.ts.map +1 -0
- package/dist/motion/easing.d.ts +30 -0
- package/dist/motion/easing.d.ts.map +1 -0
- package/dist/motion/flip.d.ts +55 -0
- package/dist/motion/flip.d.ts.map +1 -0
- package/dist/motion/index.d.ts +11 -138
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/keyframes.d.ts +21 -0
- package/dist/motion/keyframes.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +12 -0
- package/dist/motion/reduced-motion.d.ts.map +1 -0
- package/dist/motion/scroll.d.ts +15 -0
- package/dist/motion/scroll.d.ts.map +1 -0
- package/dist/motion/spring.d.ts +42 -0
- package/dist/motion/spring.d.ts.map +1 -0
- package/dist/motion/stagger.d.ts +22 -0
- package/dist/motion/stagger.d.ts.map +1 -0
- package/dist/motion/timeline.d.ts +21 -0
- package/dist/motion/timeline.d.ts.map +1 -0
- package/dist/motion/transition.d.ts +22 -0
- package/dist/motion/transition.d.ts.map +1 -0
- package/dist/motion/types.d.ts +182 -0
- package/dist/motion/types.d.ts.map +1 -0
- package/dist/motion.es.mjs +320 -61
- package/dist/motion.es.mjs.map +1 -1
- package/dist/persisted-Dz_ryNuC.js +278 -0
- package/dist/persisted-Dz_ryNuC.js.map +1 -0
- package/dist/reactive/batch.d.ts +13 -0
- package/dist/reactive/batch.d.ts.map +1 -0
- package/dist/reactive/computed.d.ts +50 -0
- package/dist/reactive/computed.d.ts.map +1 -0
- package/dist/reactive/core.d.ts +60 -0
- package/dist/reactive/core.d.ts.map +1 -0
- package/dist/reactive/effect.d.ts +15 -0
- package/dist/reactive/effect.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/internals.d.ts +36 -0
- package/dist/reactive/internals.d.ts.map +1 -0
- package/dist/reactive/linked.d.ts +36 -0
- package/dist/reactive/linked.d.ts.map +1 -0
- package/dist/reactive/persisted.d.ts +14 -0
- package/dist/reactive/persisted.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +26 -0
- package/dist/reactive/readonly.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +13 -312
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/type-guards.d.ts +20 -0
- package/dist/reactive/type-guards.d.ts.map +1 -0
- package/dist/reactive/untrack.d.ts +29 -0
- package/dist/reactive/untrack.d.ts.map +1 -0
- package/dist/reactive/watch.d.ts +42 -0
- package/dist/reactive/watch.d.ts.map +1 -0
- package/dist/reactive.es.mjs +30 -163
- package/dist/reactive.es.mjs.map +1 -1
- package/dist/router/index.d.ts +6 -252
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/links.d.ts +44 -0
- package/dist/router/links.d.ts.map +1 -0
- package/dist/router/match.d.ts +20 -0
- package/dist/router/match.d.ts.map +1 -0
- package/dist/router/navigation.d.ts +45 -0
- package/dist/router/navigation.d.ts.map +1 -0
- package/dist/router/query.d.ts +16 -0
- package/dist/router/query.d.ts.map +1 -0
- package/dist/router/router.d.ts +34 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/state.d.ts +27 -0
- package/dist/router/state.d.ts.map +1 -0
- package/dist/router/types.d.ts +88 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/utils.d.ts +65 -0
- package/dist/router/utils.d.ts.map +1 -0
- package/dist/router.es.mjs +168 -132
- package/dist/router.es.mjs.map +1 -1
- package/dist/sanitize-1FBEPAFH.js +272 -0
- package/dist/sanitize-1FBEPAFH.js.map +1 -0
- package/dist/security/constants.d.ts +42 -0
- package/dist/security/constants.d.ts.map +1 -0
- package/dist/security/csp.d.ts +24 -0
- package/dist/security/csp.d.ts.map +1 -0
- package/dist/security/index.d.ts +4 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/sanitize-core.d.ts +13 -0
- package/dist/security/sanitize-core.d.ts.map +1 -0
- package/dist/security/sanitize.d.ts +5 -57
- package/dist/security/sanitize.d.ts.map +1 -1
- package/dist/security/trusted-types.d.ts +25 -0
- package/dist/security/trusted-types.d.ts.map +1 -0
- package/dist/security/types.d.ts +36 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security.es.mjs +50 -277
- package/dist/security.es.mjs.map +1 -1
- package/dist/store/create-store.d.ts +15 -0
- package/dist/store/create-store.d.ts.map +1 -0
- package/dist/store/define-store.d.ts +28 -0
- package/dist/store/define-store.d.ts.map +1 -0
- package/dist/store/devtools.d.ts +22 -0
- package/dist/store/devtools.d.ts.map +1 -0
- package/dist/store/index.d.ts +10 -286
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/mapping.d.ts +28 -0
- package/dist/store/mapping.d.ts.map +1 -0
- package/dist/store/persisted.d.ts +13 -0
- package/dist/store/persisted.d.ts.map +1 -0
- package/dist/store/plugins.d.ts +13 -0
- package/dist/store/plugins.d.ts.map +1 -0
- package/dist/store/registry.d.ts +28 -0
- package/dist/store/registry.d.ts.map +1 -0
- package/dist/store/types.d.ts +71 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/utils.d.ts +28 -0
- package/dist/store/utils.d.ts.map +1 -0
- package/dist/store/watch.d.ts +23 -0
- package/dist/store/watch.d.ts.map +1 -0
- package/dist/store.es.mjs +22 -224
- package/dist/store.es.mjs.map +1 -1
- package/dist/type-guards-DRma3-Kc.js +16 -0
- package/dist/type-guards-DRma3-Kc.js.map +1 -0
- package/dist/untrack-BuEQKH7_.js +6 -0
- package/dist/untrack-BuEQKH7_.js.map +1 -0
- package/dist/view/directives/bind.d.ts +7 -0
- package/dist/view/directives/bind.d.ts.map +1 -0
- package/dist/view/directives/class.d.ts +8 -0
- package/dist/view/directives/class.d.ts.map +1 -0
- package/dist/view/directives/for.d.ts +23 -0
- package/dist/view/directives/for.d.ts.map +1 -0
- package/dist/view/directives/html.d.ts +7 -0
- package/dist/view/directives/html.d.ts.map +1 -0
- package/dist/view/directives/if.d.ts +7 -0
- package/dist/view/directives/if.d.ts.map +1 -0
- package/dist/view/directives/index.d.ts +12 -0
- package/dist/view/directives/index.d.ts.map +1 -0
- package/dist/view/directives/model.d.ts +7 -0
- package/dist/view/directives/model.d.ts.map +1 -0
- package/dist/view/directives/on.d.ts +7 -0
- package/dist/view/directives/on.d.ts.map +1 -0
- package/dist/view/directives/ref.d.ts +7 -0
- package/dist/view/directives/ref.d.ts.map +1 -0
- package/dist/view/directives/show.d.ts +7 -0
- package/dist/view/directives/show.d.ts.map +1 -0
- package/dist/view/directives/style.d.ts +7 -0
- package/dist/view/directives/style.d.ts.map +1 -0
- package/dist/view/directives/text.d.ts +7 -0
- package/dist/view/directives/text.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts +43 -0
- package/dist/view/evaluate.d.ts.map +1 -0
- package/dist/view/index.d.ts +3 -93
- package/dist/view/index.d.ts.map +1 -1
- package/dist/view/mount.d.ts +69 -0
- package/dist/view/mount.d.ts.map +1 -0
- package/dist/view/process.d.ts +26 -0
- package/dist/view/process.d.ts.map +1 -0
- package/dist/view/types.d.ts +36 -0
- package/dist/view/types.d.ts.map +1 -0
- package/dist/view.es.mjs +368 -267
- package/dist/view.es.mjs.map +1 -1
- package/dist/watch-CXyaBC_9.js +58 -0
- package/dist/watch-CXyaBC_9.js.map +1 -0
- package/package.json +132 -132
- package/src/component/component.ts +289 -0
- package/src/component/html.ts +53 -0
- package/src/component/index.ts +40 -414
- package/src/component/props.ts +116 -0
- package/src/component/types.ts +85 -0
- package/src/core/collection.ts +588 -454
- package/src/core/dom.ts +38 -0
- package/src/core/element.ts +746 -740
- package/src/core/index.ts +43 -0
- package/src/core/utils/array.ts +102 -0
- package/src/core/utils/function.ts +110 -0
- package/src/core/utils/index.ts +83 -0
- package/src/core/utils/misc.ts +82 -0
- package/src/core/utils/number.ts +78 -0
- package/src/core/utils/object.ts +206 -0
- package/src/core/utils/string.ts +112 -0
- package/src/core/utils/type-guards.ts +112 -0
- package/src/full.ts +187 -150
- package/src/index.ts +36 -36
- package/src/motion/animate.ts +113 -0
- package/src/motion/easing.ts +40 -0
- package/src/motion/flip.ts +176 -0
- package/src/motion/index.ts +41 -358
- package/src/motion/keyframes.ts +46 -0
- package/src/motion/reduced-motion.ts +17 -0
- package/src/motion/scroll.ts +57 -0
- package/src/motion/spring.ts +150 -0
- package/src/motion/stagger.ts +43 -0
- package/src/motion/timeline.ts +246 -0
- package/src/motion/transition.ts +51 -0
- package/src/motion/types.ts +198 -0
- package/src/reactive/batch.ts +22 -0
- package/src/reactive/computed.ts +92 -0
- package/src/reactive/core.ts +93 -0
- package/src/reactive/effect.ts +43 -0
- package/src/reactive/index.ts +23 -22
- package/src/reactive/internals.ts +105 -0
- package/src/reactive/linked.ts +56 -0
- package/src/reactive/persisted.ts +74 -0
- package/src/reactive/readonly.ts +35 -0
- package/src/reactive/signal.ts +20 -520
- package/src/reactive/type-guards.ts +22 -0
- package/src/reactive/untrack.ts +31 -0
- package/src/reactive/watch.ts +73 -0
- package/src/router/index.ts +41 -718
- package/src/router/links.ts +130 -0
- package/src/router/match.ts +106 -0
- package/src/router/navigation.ts +71 -0
- package/src/router/query.ts +35 -0
- package/src/router/router.ts +211 -0
- package/src/router/state.ts +46 -0
- package/src/router/types.ts +93 -0
- package/src/router/utils.ts +116 -0
- package/src/security/constants.ts +209 -0
- package/src/security/csp.ts +77 -0
- package/src/security/index.ts +4 -12
- package/src/security/sanitize-core.ts +343 -0
- package/src/security/sanitize.ts +66 -625
- package/src/security/trusted-types.ts +69 -0
- package/src/security/types.ts +40 -0
- package/src/store/create-store.ts +329 -0
- package/src/store/define-store.ts +48 -0
- package/src/store/devtools.ts +45 -0
- package/src/store/index.ts +22 -848
- package/src/store/mapping.ts +73 -0
- package/src/store/persisted.ts +61 -0
- package/src/store/plugins.ts +32 -0
- package/src/store/registry.ts +51 -0
- package/src/store/types.ts +94 -0
- package/src/store/utils.ts +141 -0
- package/src/store/watch.ts +52 -0
- package/src/view/directives/bind.ts +23 -0
- package/src/view/directives/class.ts +70 -0
- package/src/view/directives/for.ts +275 -0
- package/src/view/directives/html.ts +19 -0
- package/src/view/directives/if.ts +30 -0
- package/src/view/directives/index.ts +11 -0
- package/src/view/directives/model.ts +56 -0
- package/src/view/directives/on.ts +41 -0
- package/src/view/directives/ref.ts +41 -0
- package/src/view/directives/show.ts +26 -0
- package/src/view/directives/style.ts +47 -0
- package/src/view/directives/text.ts +15 -0
- package/src/view/evaluate.ts +274 -0
- package/src/view/index.ts +112 -1041
- package/src/view/mount.ts +200 -0
- package/src/view/process.ts +92 -0
- package/src/view/types.ts +44 -0
- package/dist/core/utils.d.ts +0 -313
- package/dist/core/utils.d.ts.map +0 -1
- package/src/core/utils.ts +0 -444
package/src/core/index.ts
CHANGED
|
@@ -1,4 +1,47 @@
|
|
|
1
1
|
export { BQueryCollection } from './collection';
|
|
2
2
|
export { BQueryElement } from './element';
|
|
3
3
|
export { $, $$ } from './selector';
|
|
4
|
+
// Re-export the utils namespace for backward compatibility
|
|
4
5
|
export { utils } from './utils';
|
|
6
|
+
// Export individual utilities (except internal helpers)
|
|
7
|
+
export {
|
|
8
|
+
chunk,
|
|
9
|
+
compact,
|
|
10
|
+
ensureArray,
|
|
11
|
+
flatten,
|
|
12
|
+
unique,
|
|
13
|
+
debounce,
|
|
14
|
+
noop,
|
|
15
|
+
once,
|
|
16
|
+
throttle,
|
|
17
|
+
isEmpty,
|
|
18
|
+
parseJson,
|
|
19
|
+
sleep,
|
|
20
|
+
uid,
|
|
21
|
+
clamp,
|
|
22
|
+
inRange,
|
|
23
|
+
randomInt,
|
|
24
|
+
toNumber,
|
|
25
|
+
clone,
|
|
26
|
+
hasOwn,
|
|
27
|
+
isPlainObject,
|
|
28
|
+
merge,
|
|
29
|
+
omit,
|
|
30
|
+
pick,
|
|
31
|
+
capitalize,
|
|
32
|
+
escapeRegExp,
|
|
33
|
+
slugify,
|
|
34
|
+
toCamelCase,
|
|
35
|
+
toKebabCase,
|
|
36
|
+
truncate,
|
|
37
|
+
isArray,
|
|
38
|
+
isBoolean,
|
|
39
|
+
isCollection,
|
|
40
|
+
isDate,
|
|
41
|
+
isElement,
|
|
42
|
+
isFunction,
|
|
43
|
+
isNumber,
|
|
44
|
+
isObject,
|
|
45
|
+
isPromise,
|
|
46
|
+
isString,
|
|
47
|
+
} from './utils';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Array-focused utility helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/core/utils/array
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensures the input is always returned as an array.
|
|
9
|
+
*
|
|
10
|
+
* @template T - The item type
|
|
11
|
+
* @param value - A single value, array, or nullish value
|
|
12
|
+
* @returns An array (empty if nullish)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* ensureArray('a'); // ['a']
|
|
17
|
+
* ensureArray(['a', 'b']); // ['a', 'b']
|
|
18
|
+
* ensureArray(null); // []
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function ensureArray<T>(value: T | T[] | null | undefined): T[] {
|
|
22
|
+
if (value == null) return [];
|
|
23
|
+
return Array.isArray(value) ? value : [value];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Removes duplicate entries from an array.
|
|
28
|
+
*
|
|
29
|
+
* @template T - The item type
|
|
30
|
+
* @param items - The array to deduplicate
|
|
31
|
+
* @returns A new array with unique items
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* unique([1, 2, 2, 3]); // [1, 2, 3]
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function unique<T>(items: T[]): T[] {
|
|
39
|
+
return Array.from(new Set(items));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Splits an array into chunks of a given size.
|
|
44
|
+
*
|
|
45
|
+
* @template T - The item type
|
|
46
|
+
* @param items - The array to chunk
|
|
47
|
+
* @param size - The maximum size of each chunk
|
|
48
|
+
* @returns An array of chunks
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function chunk<T>(items: T[], size: number): T[][] {
|
|
56
|
+
if (size <= 0) return [];
|
|
57
|
+
const result: T[][] = [];
|
|
58
|
+
for (let i = 0; i < items.length; i += size) {
|
|
59
|
+
result.push(items.slice(i, i + size));
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Removes falsy values from an array.
|
|
66
|
+
*
|
|
67
|
+
* @template T - The item type
|
|
68
|
+
* @param items - The array to compact
|
|
69
|
+
* @returns A new array without falsy values
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* compact([0, 1, '', 'ok', null]); // [1, 'ok']
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function compact<T>(items: Array<T | null | undefined | false | 0 | ''>): T[] {
|
|
77
|
+
return items.filter(Boolean) as T[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Flattens a single level of nested arrays.
|
|
82
|
+
*
|
|
83
|
+
* @template T - The item type
|
|
84
|
+
* @param items - The array to flatten
|
|
85
|
+
* @returns A new flattened array
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* flatten([1, [2, 3], 4]); // [1, 2, 3, 4]
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export function flatten<T>(items: Array<T | T[]>): T[] {
|
|
93
|
+
const result: T[] = [];
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
if (Array.isArray(item)) {
|
|
96
|
+
result.push(...item);
|
|
97
|
+
} else {
|
|
98
|
+
result.push(item);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function-focused utility helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/core/utils/function
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a debounced function that delays execution until after
|
|
9
|
+
* the specified delay has elapsed since the last call.
|
|
10
|
+
*
|
|
11
|
+
* @template TArgs - The argument types of the function
|
|
12
|
+
* @param fn - The function to debounce
|
|
13
|
+
* @param delayMs - Delay in milliseconds
|
|
14
|
+
* @returns A debounced version of the function
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const search = debounce((query: string) => {
|
|
19
|
+
* console.log('Searching:', query);
|
|
20
|
+
* }, 300);
|
|
21
|
+
*
|
|
22
|
+
* search('h');
|
|
23
|
+
* search('he');
|
|
24
|
+
* search('hello'); // Only this call executes after 300ms
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function debounce<TArgs extends unknown[]>(
|
|
28
|
+
fn: (...args: TArgs) => void,
|
|
29
|
+
delayMs: number
|
|
30
|
+
): (...args: TArgs) => void {
|
|
31
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
32
|
+
return (...args: TArgs) => {
|
|
33
|
+
if (timeoutId) {
|
|
34
|
+
clearTimeout(timeoutId);
|
|
35
|
+
}
|
|
36
|
+
timeoutId = setTimeout(() => fn(...args), delayMs);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a throttled function that runs at most once per interval.
|
|
42
|
+
*
|
|
43
|
+
* @template TArgs - The argument types of the function
|
|
44
|
+
* @param fn - The function to throttle
|
|
45
|
+
* @param intervalMs - Minimum interval between calls in milliseconds
|
|
46
|
+
* @returns A throttled version of the function
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const handleScroll = throttle(() => {
|
|
51
|
+
* console.log('Scroll position:', window.scrollY);
|
|
52
|
+
* }, 100);
|
|
53
|
+
*
|
|
54
|
+
* window.addEventListener('scroll', handleScroll);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function throttle<TArgs extends unknown[]>(
|
|
58
|
+
fn: (...args: TArgs) => void,
|
|
59
|
+
intervalMs: number
|
|
60
|
+
): (...args: TArgs) => void {
|
|
61
|
+
let lastRun = 0;
|
|
62
|
+
return (...args: TArgs) => {
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
if (now - lastRun >= intervalMs) {
|
|
65
|
+
lastRun = now;
|
|
66
|
+
fn(...args);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Ensures a function only runs once. Subsequent calls return the first result.
|
|
73
|
+
*
|
|
74
|
+
* @template TArgs - The argument types of the function
|
|
75
|
+
* @template TResult - The return type of the function
|
|
76
|
+
* @param fn - The function to wrap
|
|
77
|
+
* @returns A function that only runs once
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const init = once(() => ({ ready: true }));
|
|
82
|
+
* init();
|
|
83
|
+
* init(); // only runs once
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export function once<TArgs extends unknown[], TResult>(
|
|
87
|
+
fn: (...args: TArgs) => TResult
|
|
88
|
+
): (...args: TArgs) => TResult {
|
|
89
|
+
let hasRun = false;
|
|
90
|
+
let result!: TResult;
|
|
91
|
+
return (...args: TArgs) => {
|
|
92
|
+
if (!hasRun) {
|
|
93
|
+
result = fn(...args);
|
|
94
|
+
hasRun = true;
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A no-operation function.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* noop();
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export function noop(): void {
|
|
109
|
+
// Intentionally empty
|
|
110
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility helpers used across the framework.
|
|
3
|
+
* These are intentionally small and framework-agnostic to keep the core tiny.
|
|
4
|
+
*
|
|
5
|
+
* @module bquery/core/utils
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export * from './array';
|
|
9
|
+
export * from './function';
|
|
10
|
+
export * from './misc';
|
|
11
|
+
export * from './number';
|
|
12
|
+
export * from './object';
|
|
13
|
+
export * from './string';
|
|
14
|
+
export * from './type-guards';
|
|
15
|
+
|
|
16
|
+
import { chunk, compact, ensureArray, flatten, unique } from './array';
|
|
17
|
+
import { debounce, noop, once, throttle } from './function';
|
|
18
|
+
import { isEmpty, parseJson, sleep, uid } from './misc';
|
|
19
|
+
import { clamp, inRange, randomInt, toNumber } from './number';
|
|
20
|
+
import { clone, hasOwn, isPlainObject, merge, omit, pick } from './object';
|
|
21
|
+
import { capitalize, escapeRegExp, slugify, toCamelCase, toKebabCase, truncate } from './string';
|
|
22
|
+
import {
|
|
23
|
+
isArray,
|
|
24
|
+
isBoolean,
|
|
25
|
+
isCollection,
|
|
26
|
+
isDate,
|
|
27
|
+
isElement,
|
|
28
|
+
isFunction,
|
|
29
|
+
isNumber,
|
|
30
|
+
isObject,
|
|
31
|
+
isPromise,
|
|
32
|
+
isString,
|
|
33
|
+
} from './type-guards';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Utility object containing common helper functions.
|
|
37
|
+
* All utilities are designed to be tree-shakeable and have zero dependencies.
|
|
38
|
+
*
|
|
39
|
+
* Note: `isPrototypePollutionKey` is intentionally excluded from this namespace
|
|
40
|
+
* as it is an internal security helper. It remains available as a named export
|
|
41
|
+
* for internal framework use.
|
|
42
|
+
*/
|
|
43
|
+
export const utils = {
|
|
44
|
+
clone,
|
|
45
|
+
merge,
|
|
46
|
+
pick,
|
|
47
|
+
omit,
|
|
48
|
+
hasOwn,
|
|
49
|
+
debounce,
|
|
50
|
+
throttle,
|
|
51
|
+
once,
|
|
52
|
+
noop,
|
|
53
|
+
uid,
|
|
54
|
+
isElement,
|
|
55
|
+
isCollection,
|
|
56
|
+
isEmpty,
|
|
57
|
+
isPlainObject,
|
|
58
|
+
isFunction,
|
|
59
|
+
isString,
|
|
60
|
+
isNumber,
|
|
61
|
+
isBoolean,
|
|
62
|
+
isArray,
|
|
63
|
+
isDate,
|
|
64
|
+
isPromise,
|
|
65
|
+
isObject,
|
|
66
|
+
parseJson,
|
|
67
|
+
sleep,
|
|
68
|
+
randomInt,
|
|
69
|
+
clamp,
|
|
70
|
+
inRange,
|
|
71
|
+
toNumber,
|
|
72
|
+
capitalize,
|
|
73
|
+
toKebabCase,
|
|
74
|
+
toCamelCase,
|
|
75
|
+
truncate,
|
|
76
|
+
slugify,
|
|
77
|
+
escapeRegExp,
|
|
78
|
+
ensureArray,
|
|
79
|
+
unique,
|
|
80
|
+
chunk,
|
|
81
|
+
compact,
|
|
82
|
+
flatten,
|
|
83
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miscellaneous utility helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/core/utils/misc
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a stable unique ID for DOM usage.
|
|
9
|
+
*
|
|
10
|
+
* @param prefix - Optional prefix for the ID (default: 'bQuery')
|
|
11
|
+
* @returns A unique identifier string
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const id = uid('modal'); // 'modal_x7k2m9p'
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function uid(prefix = 'bQuery'): string {
|
|
19
|
+
return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Delays execution for a specified number of milliseconds.
|
|
24
|
+
*
|
|
25
|
+
* @param ms - Milliseconds to delay
|
|
26
|
+
* @returns A promise that resolves after the delay
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* await sleep(1000); // Wait 1 second
|
|
31
|
+
* console.log('Done!');
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function sleep(ms: number): Promise<void> {
|
|
35
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Safely parses a JSON string, returning a default value on error.
|
|
40
|
+
*
|
|
41
|
+
* @template T - The expected type of the parsed value
|
|
42
|
+
* @param json - The JSON string to parse
|
|
43
|
+
* @param fallback - The default value if parsing fails
|
|
44
|
+
* @returns The parsed value or the fallback
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* parseJson('{"name":"bQuery"}', {}); // { name: 'bQuery' }
|
|
49
|
+
* parseJson('invalid', {}); // {}
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function parseJson<T>(json: string, fallback: T): T {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(json) as T;
|
|
55
|
+
} catch {
|
|
56
|
+
return fallback;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Checks for emptiness across common value types.
|
|
62
|
+
*
|
|
63
|
+
* @param value - The value to check
|
|
64
|
+
* @returns True if the value is empty (null, undefined, empty string, empty array, or empty object)
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* isEmpty(''); // true
|
|
69
|
+
* isEmpty([]); // true
|
|
70
|
+
* isEmpty({}); // true
|
|
71
|
+
* isEmpty(null); // true
|
|
72
|
+
* isEmpty('hello'); // false
|
|
73
|
+
* isEmpty([1, 2]); // false
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function isEmpty(value: unknown): boolean {
|
|
77
|
+
if (value == null) return true;
|
|
78
|
+
if (typeof value === 'string') return value.trim().length === 0;
|
|
79
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
80
|
+
if (typeof value === 'object') return Object.keys(value as object).length === 0;
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Number-focused utility helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/core/utils/number
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generates a random integer between min and max (inclusive).
|
|
9
|
+
*
|
|
10
|
+
* @param min - Minimum value
|
|
11
|
+
* @param max - Maximum value
|
|
12
|
+
* @returns A random integer in the range [min, max]
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const roll = randomInt(1, 6); // Random dice roll
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function randomInt(min: number, max: number): number {
|
|
20
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Clamps a number between a minimum and maximum value.
|
|
25
|
+
*
|
|
26
|
+
* @param value - The value to clamp
|
|
27
|
+
* @param min - Minimum value
|
|
28
|
+
* @param max - Maximum value
|
|
29
|
+
* @returns The clamped value
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* clamp(150, 0, 100); // 100
|
|
34
|
+
* clamp(-10, 0, 100); // 0
|
|
35
|
+
* clamp(50, 0, 100); // 50
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function clamp(value: number, min: number, max: number): number {
|
|
39
|
+
return Math.min(Math.max(value, min), max);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a number is within a range.
|
|
44
|
+
*
|
|
45
|
+
* @param value - The value to check
|
|
46
|
+
* @param min - Minimum value
|
|
47
|
+
* @param max - Maximum value
|
|
48
|
+
* @param inclusive - Whether the range is inclusive (default: true)
|
|
49
|
+
* @returns True if the value is within the range
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* inRange(5, 1, 10); // true
|
|
54
|
+
* inRange(10, 1, 10, false); // false
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function inRange(value: number, min: number, max: number, inclusive = true): boolean {
|
|
58
|
+
if (inclusive) return value >= min && value <= max;
|
|
59
|
+
return value > min && value < max;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Converts a value to a number with a fallback on NaN.
|
|
64
|
+
*
|
|
65
|
+
* @param value - The value to convert
|
|
66
|
+
* @param fallback - The fallback value if conversion fails (default: 0)
|
|
67
|
+
* @returns The parsed number or the fallback
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* toNumber('42'); // 42
|
|
72
|
+
* toNumber('nope', 10); // 10
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function toNumber(value: unknown, fallback = 0): number {
|
|
76
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
77
|
+
return Number.isNaN(parsed) ? fallback : parsed;
|
|
78
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object-focused utility helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/core/utils/object
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Checks if a value is a plain object (not null, array, or class instance).
|
|
9
|
+
*
|
|
10
|
+
* @param value - The value to check
|
|
11
|
+
* @returns True if the value is a plain object
|
|
12
|
+
*/
|
|
13
|
+
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
14
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks if a key could cause prototype pollution.
|
|
19
|
+
* These keys are dangerous when used in object merging operations.
|
|
20
|
+
*
|
|
21
|
+
* @param key - The key to check
|
|
22
|
+
* @returns True if the key is a prototype pollution vector
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export function isPrototypePollutionKey(key: string): boolean {
|
|
27
|
+
return key === '__proto__' || key === 'constructor' || key === 'prototype';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a deep clone using structuredClone if available, otherwise fallback to JSON.
|
|
32
|
+
*
|
|
33
|
+
* @template T - The type of value being cloned
|
|
34
|
+
* @param value - The value to clone
|
|
35
|
+
* @returns A deep copy of the value
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* When `structuredClone` is available (modern browsers, Node 17+, Bun), this function
|
|
39
|
+
* provides full deep cloning including circular references, Date, Map, Set, ArrayBuffer, etc.
|
|
40
|
+
*
|
|
41
|
+
* **JSON fallback limitations** (older environments without `structuredClone`):
|
|
42
|
+
* - **Throws** on circular references
|
|
43
|
+
* - **Drops** functions, `undefined`, and Symbol properties
|
|
44
|
+
* - **Transforms** Date → ISO string, Map/Set → empty object, BigInt → throws
|
|
45
|
+
* - **Loses** prototype chains and non-enumerable properties
|
|
46
|
+
*
|
|
47
|
+
* For guaranteed safe cloning of arbitrary data, ensure your environment supports
|
|
48
|
+
* `structuredClone` or pre-validate your data structure.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const original = { nested: { value: 1 } };
|
|
53
|
+
* const copy = clone(original);
|
|
54
|
+
* copy.nested.value = 2;
|
|
55
|
+
* console.log(original.nested.value); // 1
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function clone<T>(value: T): T {
|
|
59
|
+
if (typeof structuredClone === 'function') {
|
|
60
|
+
return structuredClone(value);
|
|
61
|
+
}
|
|
62
|
+
return JSON.parse(JSON.stringify(value)) as T;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Deep-merges plain objects into a new object.
|
|
67
|
+
* Later sources override earlier ones for primitive values.
|
|
68
|
+
* Objects are recursively merged.
|
|
69
|
+
*
|
|
70
|
+
* @param sources - Objects to merge
|
|
71
|
+
* @returns A new object with all sources merged as an intersection type
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* This function uses overloads to provide accurate intersection types for up to 5 sources.
|
|
75
|
+
* For more than 5 sources, the return type falls back to `Record<string, unknown>`.
|
|
76
|
+
*
|
|
77
|
+
* Note that deep merging creates a shallow intersection at the type level. Nested objects
|
|
78
|
+
* are merged at runtime, but TypeScript sees them as intersected types which may not
|
|
79
|
+
* perfectly represent the merged structure for deeply nested conflicting types.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const result = merge(
|
|
84
|
+
* { a: 1, nested: { x: 1 } },
|
|
85
|
+
* { b: 2, nested: { y: 2 } }
|
|
86
|
+
* );
|
|
87
|
+
* // Result: { a: 1, b: 2, nested: { x: 1, y: 2 } }
|
|
88
|
+
* // Type: { a: number; nested: { x: number } } & { b: number; nested: { y: number } }
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @security This method is protected against prototype pollution attacks.
|
|
92
|
+
* Keys like `__proto__`, `constructor`, and `prototype` are ignored.
|
|
93
|
+
*/
|
|
94
|
+
export function merge<T1 extends Record<string, unknown>>(source1: T1): T1;
|
|
95
|
+
export function merge<T1 extends Record<string, unknown>, T2 extends Record<string, unknown>>(
|
|
96
|
+
source1: T1,
|
|
97
|
+
source2: T2
|
|
98
|
+
): T1 & T2;
|
|
99
|
+
export function merge<
|
|
100
|
+
T1 extends Record<string, unknown>,
|
|
101
|
+
T2 extends Record<string, unknown>,
|
|
102
|
+
T3 extends Record<string, unknown>,
|
|
103
|
+
>(source1: T1, source2: T2, source3: T3): T1 & T2 & T3;
|
|
104
|
+
export function merge<
|
|
105
|
+
T1 extends Record<string, unknown>,
|
|
106
|
+
T2 extends Record<string, unknown>,
|
|
107
|
+
T3 extends Record<string, unknown>,
|
|
108
|
+
T4 extends Record<string, unknown>,
|
|
109
|
+
>(source1: T1, source2: T2, source3: T3, source4: T4): T1 & T2 & T3 & T4;
|
|
110
|
+
export function merge<
|
|
111
|
+
T1 extends Record<string, unknown>,
|
|
112
|
+
T2 extends Record<string, unknown>,
|
|
113
|
+
T3 extends Record<string, unknown>,
|
|
114
|
+
T4 extends Record<string, unknown>,
|
|
115
|
+
T5 extends Record<string, unknown>,
|
|
116
|
+
>(source1: T1, source2: T2, source3: T3, source4: T4, source5: T5): T1 & T2 & T3 & T4 & T5;
|
|
117
|
+
export function merge(...sources: Record<string, unknown>[]): Record<string, unknown>;
|
|
118
|
+
export function merge(...sources: Record<string, unknown>[]): Record<string, unknown> {
|
|
119
|
+
const result: Record<string, unknown> = {};
|
|
120
|
+
for (const source of sources) {
|
|
121
|
+
for (const [key, value] of Object.entries(source)) {
|
|
122
|
+
if (isPrototypePollutionKey(key)) continue;
|
|
123
|
+
|
|
124
|
+
if (isPlainObject(value) && isPlainObject(result[key])) {
|
|
125
|
+
result[key] = merge(
|
|
126
|
+
result[key] as Record<string, unknown>,
|
|
127
|
+
value as Record<string, unknown>
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
result[key] = value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Picks specified keys from an object.
|
|
139
|
+
*
|
|
140
|
+
* @template T - The object type
|
|
141
|
+
* @template K - The key type
|
|
142
|
+
* @param obj - The source object
|
|
143
|
+
* @param keys - Keys to pick
|
|
144
|
+
* @returns A new object with only the specified keys
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const user = { name: 'John', age: 30, email: 'john@example.com' };
|
|
149
|
+
* pick(user, ['name', 'email']); // { name: 'John', email: 'john@example.com' }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export function pick<T extends Record<string, unknown>, K extends keyof T>(
|
|
153
|
+
obj: T,
|
|
154
|
+
keys: K[]
|
|
155
|
+
): Pick<T, K> {
|
|
156
|
+
const result = {} as Pick<T, K>;
|
|
157
|
+
for (const key of keys) {
|
|
158
|
+
if (key in obj) {
|
|
159
|
+
result[key] = obj[key];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Omits specified keys from an object.
|
|
167
|
+
*
|
|
168
|
+
* @template T - The object type
|
|
169
|
+
* @template K - The key type
|
|
170
|
+
* @param obj - The source object
|
|
171
|
+
* @param keys - Keys to omit
|
|
172
|
+
* @returns A new object without the specified keys
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* const user = { name: 'John', age: 30, password: 'secret' };
|
|
177
|
+
* omit(user, ['password']); // { name: 'John', age: 30 }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
export function omit<T extends Record<string, unknown>, K extends keyof T>(
|
|
181
|
+
obj: T,
|
|
182
|
+
keys: K[]
|
|
183
|
+
): Omit<T, K> {
|
|
184
|
+
const result = { ...obj };
|
|
185
|
+
for (const key of keys) {
|
|
186
|
+
delete result[key];
|
|
187
|
+
}
|
|
188
|
+
return result as Omit<T, K>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Checks if an object has a given own property.
|
|
193
|
+
*
|
|
194
|
+
* @template T - The object type
|
|
195
|
+
* @param obj - The object to check
|
|
196
|
+
* @param key - The property key
|
|
197
|
+
* @returns True if the property exists on the object
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* hasOwn({ a: 1 }, 'a'); // true
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function hasOwn<T extends object>(obj: T, key: PropertyKey): key is keyof T {
|
|
205
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
206
|
+
}
|