@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.
Files changed (305) hide show
  1. package/README.md +501 -427
  2. package/dist/batch-4LAvfLE7.js +13 -0
  3. package/dist/batch-4LAvfLE7.js.map +1 -0
  4. package/dist/component/component.d.ts +69 -0
  5. package/dist/component/component.d.ts.map +1 -0
  6. package/dist/component/html.d.ts +35 -0
  7. package/dist/component/html.d.ts.map +1 -0
  8. package/dist/component/index.d.ts +3 -126
  9. package/dist/component/index.d.ts.map +1 -1
  10. package/dist/component/props.d.ts +18 -0
  11. package/dist/component/props.d.ts.map +1 -0
  12. package/dist/component/types.d.ts +77 -0
  13. package/dist/component/types.d.ts.map +1 -0
  14. package/dist/component.es.mjs +90 -59
  15. package/dist/component.es.mjs.map +1 -1
  16. package/dist/core/collection.d.ts +36 -0
  17. package/dist/core/collection.d.ts.map +1 -1
  18. package/dist/core/dom.d.ts +6 -0
  19. package/dist/core/dom.d.ts.map +1 -0
  20. package/dist/core/element.d.ts +8 -0
  21. package/dist/core/element.d.ts.map +1 -1
  22. package/dist/core/index.d.ts +1 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/core/utils/array.d.ts +74 -0
  25. package/dist/core/utils/array.d.ts.map +1 -0
  26. package/dist/core/utils/function.d.ts +70 -0
  27. package/dist/core/utils/function.d.ts.map +1 -0
  28. package/dist/core/utils/index.d.ts +70 -0
  29. package/dist/core/utils/index.d.ts.map +1 -0
  30. package/dist/core/utils/misc.d.ts +63 -0
  31. package/dist/core/utils/misc.d.ts.map +1 -0
  32. package/dist/core/utils/number.d.ts +65 -0
  33. package/dist/core/utils/number.d.ts.map +1 -0
  34. package/dist/core/utils/object.d.ts +133 -0
  35. package/dist/core/utils/object.d.ts.map +1 -0
  36. package/dist/core/utils/string.d.ts +80 -0
  37. package/dist/core/utils/string.d.ts.map +1 -0
  38. package/dist/core/utils/type-guards.d.ts +79 -0
  39. package/dist/core/utils/type-guards.d.ts.map +1 -0
  40. package/dist/core-COenAZjD.js +145 -0
  41. package/dist/core-COenAZjD.js.map +1 -0
  42. package/dist/core.es.mjs +411 -448
  43. package/dist/core.es.mjs.map +1 -1
  44. package/dist/full.d.ts +2 -2
  45. package/dist/full.d.ts.map +1 -1
  46. package/dist/full.es.mjs +87 -64
  47. package/dist/full.es.mjs.map +1 -1
  48. package/dist/full.iife.js +2 -2
  49. package/dist/full.iife.js.map +1 -1
  50. package/dist/full.umd.js +2 -2
  51. package/dist/full.umd.js.map +1 -1
  52. package/dist/index.es.mjs +138 -68
  53. package/dist/index.es.mjs.map +1 -1
  54. package/dist/motion/animate.d.ts +25 -0
  55. package/dist/motion/animate.d.ts.map +1 -0
  56. package/dist/motion/easing.d.ts +30 -0
  57. package/dist/motion/easing.d.ts.map +1 -0
  58. package/dist/motion/flip.d.ts +55 -0
  59. package/dist/motion/flip.d.ts.map +1 -0
  60. package/dist/motion/index.d.ts +11 -138
  61. package/dist/motion/index.d.ts.map +1 -1
  62. package/dist/motion/keyframes.d.ts +21 -0
  63. package/dist/motion/keyframes.d.ts.map +1 -0
  64. package/dist/motion/reduced-motion.d.ts +12 -0
  65. package/dist/motion/reduced-motion.d.ts.map +1 -0
  66. package/dist/motion/scroll.d.ts +15 -0
  67. package/dist/motion/scroll.d.ts.map +1 -0
  68. package/dist/motion/spring.d.ts +42 -0
  69. package/dist/motion/spring.d.ts.map +1 -0
  70. package/dist/motion/stagger.d.ts +22 -0
  71. package/dist/motion/stagger.d.ts.map +1 -0
  72. package/dist/motion/timeline.d.ts +21 -0
  73. package/dist/motion/timeline.d.ts.map +1 -0
  74. package/dist/motion/transition.d.ts +22 -0
  75. package/dist/motion/transition.d.ts.map +1 -0
  76. package/dist/motion/types.d.ts +182 -0
  77. package/dist/motion/types.d.ts.map +1 -0
  78. package/dist/motion.es.mjs +320 -61
  79. package/dist/motion.es.mjs.map +1 -1
  80. package/dist/persisted-Dz_ryNuC.js +278 -0
  81. package/dist/persisted-Dz_ryNuC.js.map +1 -0
  82. package/dist/reactive/batch.d.ts +13 -0
  83. package/dist/reactive/batch.d.ts.map +1 -0
  84. package/dist/reactive/computed.d.ts +50 -0
  85. package/dist/reactive/computed.d.ts.map +1 -0
  86. package/dist/reactive/core.d.ts +60 -0
  87. package/dist/reactive/core.d.ts.map +1 -0
  88. package/dist/reactive/effect.d.ts +15 -0
  89. package/dist/reactive/effect.d.ts.map +1 -0
  90. package/dist/reactive/index.d.ts +2 -2
  91. package/dist/reactive/index.d.ts.map +1 -1
  92. package/dist/reactive/internals.d.ts +36 -0
  93. package/dist/reactive/internals.d.ts.map +1 -0
  94. package/dist/reactive/linked.d.ts +36 -0
  95. package/dist/reactive/linked.d.ts.map +1 -0
  96. package/dist/reactive/persisted.d.ts +14 -0
  97. package/dist/reactive/persisted.d.ts.map +1 -0
  98. package/dist/reactive/readonly.d.ts +26 -0
  99. package/dist/reactive/readonly.d.ts.map +1 -0
  100. package/dist/reactive/signal.d.ts +13 -312
  101. package/dist/reactive/signal.d.ts.map +1 -1
  102. package/dist/reactive/type-guards.d.ts +20 -0
  103. package/dist/reactive/type-guards.d.ts.map +1 -0
  104. package/dist/reactive/untrack.d.ts +29 -0
  105. package/dist/reactive/untrack.d.ts.map +1 -0
  106. package/dist/reactive/watch.d.ts +42 -0
  107. package/dist/reactive/watch.d.ts.map +1 -0
  108. package/dist/reactive.es.mjs +30 -163
  109. package/dist/reactive.es.mjs.map +1 -1
  110. package/dist/router/index.d.ts +6 -252
  111. package/dist/router/index.d.ts.map +1 -1
  112. package/dist/router/links.d.ts +44 -0
  113. package/dist/router/links.d.ts.map +1 -0
  114. package/dist/router/match.d.ts +20 -0
  115. package/dist/router/match.d.ts.map +1 -0
  116. package/dist/router/navigation.d.ts +45 -0
  117. package/dist/router/navigation.d.ts.map +1 -0
  118. package/dist/router/query.d.ts +16 -0
  119. package/dist/router/query.d.ts.map +1 -0
  120. package/dist/router/router.d.ts +34 -0
  121. package/dist/router/router.d.ts.map +1 -0
  122. package/dist/router/state.d.ts +27 -0
  123. package/dist/router/state.d.ts.map +1 -0
  124. package/dist/router/types.d.ts +88 -0
  125. package/dist/router/types.d.ts.map +1 -0
  126. package/dist/router/utils.d.ts +65 -0
  127. package/dist/router/utils.d.ts.map +1 -0
  128. package/dist/router.es.mjs +168 -132
  129. package/dist/router.es.mjs.map +1 -1
  130. package/dist/sanitize-1FBEPAFH.js +272 -0
  131. package/dist/sanitize-1FBEPAFH.js.map +1 -0
  132. package/dist/security/constants.d.ts +42 -0
  133. package/dist/security/constants.d.ts.map +1 -0
  134. package/dist/security/csp.d.ts +24 -0
  135. package/dist/security/csp.d.ts.map +1 -0
  136. package/dist/security/index.d.ts +4 -2
  137. package/dist/security/index.d.ts.map +1 -1
  138. package/dist/security/sanitize-core.d.ts +13 -0
  139. package/dist/security/sanitize-core.d.ts.map +1 -0
  140. package/dist/security/sanitize.d.ts +5 -57
  141. package/dist/security/sanitize.d.ts.map +1 -1
  142. package/dist/security/trusted-types.d.ts +25 -0
  143. package/dist/security/trusted-types.d.ts.map +1 -0
  144. package/dist/security/types.d.ts +36 -0
  145. package/dist/security/types.d.ts.map +1 -0
  146. package/dist/security.es.mjs +50 -277
  147. package/dist/security.es.mjs.map +1 -1
  148. package/dist/store/create-store.d.ts +15 -0
  149. package/dist/store/create-store.d.ts.map +1 -0
  150. package/dist/store/define-store.d.ts +28 -0
  151. package/dist/store/define-store.d.ts.map +1 -0
  152. package/dist/store/devtools.d.ts +22 -0
  153. package/dist/store/devtools.d.ts.map +1 -0
  154. package/dist/store/index.d.ts +10 -286
  155. package/dist/store/index.d.ts.map +1 -1
  156. package/dist/store/mapping.d.ts +28 -0
  157. package/dist/store/mapping.d.ts.map +1 -0
  158. package/dist/store/persisted.d.ts +13 -0
  159. package/dist/store/persisted.d.ts.map +1 -0
  160. package/dist/store/plugins.d.ts +13 -0
  161. package/dist/store/plugins.d.ts.map +1 -0
  162. package/dist/store/registry.d.ts +28 -0
  163. package/dist/store/registry.d.ts.map +1 -0
  164. package/dist/store/types.d.ts +71 -0
  165. package/dist/store/types.d.ts.map +1 -0
  166. package/dist/store/utils.d.ts +28 -0
  167. package/dist/store/utils.d.ts.map +1 -0
  168. package/dist/store/watch.d.ts +23 -0
  169. package/dist/store/watch.d.ts.map +1 -0
  170. package/dist/store.es.mjs +22 -224
  171. package/dist/store.es.mjs.map +1 -1
  172. package/dist/type-guards-DRma3-Kc.js +16 -0
  173. package/dist/type-guards-DRma3-Kc.js.map +1 -0
  174. package/dist/untrack-BuEQKH7_.js +6 -0
  175. package/dist/untrack-BuEQKH7_.js.map +1 -0
  176. package/dist/view/directives/bind.d.ts +7 -0
  177. package/dist/view/directives/bind.d.ts.map +1 -0
  178. package/dist/view/directives/class.d.ts +8 -0
  179. package/dist/view/directives/class.d.ts.map +1 -0
  180. package/dist/view/directives/for.d.ts +23 -0
  181. package/dist/view/directives/for.d.ts.map +1 -0
  182. package/dist/view/directives/html.d.ts +7 -0
  183. package/dist/view/directives/html.d.ts.map +1 -0
  184. package/dist/view/directives/if.d.ts +7 -0
  185. package/dist/view/directives/if.d.ts.map +1 -0
  186. package/dist/view/directives/index.d.ts +12 -0
  187. package/dist/view/directives/index.d.ts.map +1 -0
  188. package/dist/view/directives/model.d.ts +7 -0
  189. package/dist/view/directives/model.d.ts.map +1 -0
  190. package/dist/view/directives/on.d.ts +7 -0
  191. package/dist/view/directives/on.d.ts.map +1 -0
  192. package/dist/view/directives/ref.d.ts +7 -0
  193. package/dist/view/directives/ref.d.ts.map +1 -0
  194. package/dist/view/directives/show.d.ts +7 -0
  195. package/dist/view/directives/show.d.ts.map +1 -0
  196. package/dist/view/directives/style.d.ts +7 -0
  197. package/dist/view/directives/style.d.ts.map +1 -0
  198. package/dist/view/directives/text.d.ts +7 -0
  199. package/dist/view/directives/text.d.ts.map +1 -0
  200. package/dist/view/evaluate.d.ts +43 -0
  201. package/dist/view/evaluate.d.ts.map +1 -0
  202. package/dist/view/index.d.ts +3 -93
  203. package/dist/view/index.d.ts.map +1 -1
  204. package/dist/view/mount.d.ts +69 -0
  205. package/dist/view/mount.d.ts.map +1 -0
  206. package/dist/view/process.d.ts +26 -0
  207. package/dist/view/process.d.ts.map +1 -0
  208. package/dist/view/types.d.ts +36 -0
  209. package/dist/view/types.d.ts.map +1 -0
  210. package/dist/view.es.mjs +368 -267
  211. package/dist/view.es.mjs.map +1 -1
  212. package/dist/watch-CXyaBC_9.js +58 -0
  213. package/dist/watch-CXyaBC_9.js.map +1 -0
  214. package/package.json +132 -132
  215. package/src/component/component.ts +289 -0
  216. package/src/component/html.ts +53 -0
  217. package/src/component/index.ts +40 -414
  218. package/src/component/props.ts +116 -0
  219. package/src/component/types.ts +85 -0
  220. package/src/core/collection.ts +588 -454
  221. package/src/core/dom.ts +38 -0
  222. package/src/core/element.ts +746 -740
  223. package/src/core/index.ts +43 -0
  224. package/src/core/utils/array.ts +102 -0
  225. package/src/core/utils/function.ts +110 -0
  226. package/src/core/utils/index.ts +83 -0
  227. package/src/core/utils/misc.ts +82 -0
  228. package/src/core/utils/number.ts +78 -0
  229. package/src/core/utils/object.ts +206 -0
  230. package/src/core/utils/string.ts +112 -0
  231. package/src/core/utils/type-guards.ts +112 -0
  232. package/src/full.ts +187 -150
  233. package/src/index.ts +36 -36
  234. package/src/motion/animate.ts +113 -0
  235. package/src/motion/easing.ts +40 -0
  236. package/src/motion/flip.ts +176 -0
  237. package/src/motion/index.ts +41 -358
  238. package/src/motion/keyframes.ts +46 -0
  239. package/src/motion/reduced-motion.ts +17 -0
  240. package/src/motion/scroll.ts +57 -0
  241. package/src/motion/spring.ts +150 -0
  242. package/src/motion/stagger.ts +43 -0
  243. package/src/motion/timeline.ts +246 -0
  244. package/src/motion/transition.ts +51 -0
  245. package/src/motion/types.ts +198 -0
  246. package/src/reactive/batch.ts +22 -0
  247. package/src/reactive/computed.ts +92 -0
  248. package/src/reactive/core.ts +93 -0
  249. package/src/reactive/effect.ts +43 -0
  250. package/src/reactive/index.ts +23 -22
  251. package/src/reactive/internals.ts +105 -0
  252. package/src/reactive/linked.ts +56 -0
  253. package/src/reactive/persisted.ts +74 -0
  254. package/src/reactive/readonly.ts +35 -0
  255. package/src/reactive/signal.ts +20 -520
  256. package/src/reactive/type-guards.ts +22 -0
  257. package/src/reactive/untrack.ts +31 -0
  258. package/src/reactive/watch.ts +73 -0
  259. package/src/router/index.ts +41 -718
  260. package/src/router/links.ts +130 -0
  261. package/src/router/match.ts +106 -0
  262. package/src/router/navigation.ts +71 -0
  263. package/src/router/query.ts +35 -0
  264. package/src/router/router.ts +211 -0
  265. package/src/router/state.ts +46 -0
  266. package/src/router/types.ts +93 -0
  267. package/src/router/utils.ts +116 -0
  268. package/src/security/constants.ts +209 -0
  269. package/src/security/csp.ts +77 -0
  270. package/src/security/index.ts +4 -12
  271. package/src/security/sanitize-core.ts +343 -0
  272. package/src/security/sanitize.ts +66 -625
  273. package/src/security/trusted-types.ts +69 -0
  274. package/src/security/types.ts +40 -0
  275. package/src/store/create-store.ts +329 -0
  276. package/src/store/define-store.ts +48 -0
  277. package/src/store/devtools.ts +45 -0
  278. package/src/store/index.ts +22 -848
  279. package/src/store/mapping.ts +73 -0
  280. package/src/store/persisted.ts +61 -0
  281. package/src/store/plugins.ts +32 -0
  282. package/src/store/registry.ts +51 -0
  283. package/src/store/types.ts +94 -0
  284. package/src/store/utils.ts +141 -0
  285. package/src/store/watch.ts +52 -0
  286. package/src/view/directives/bind.ts +23 -0
  287. package/src/view/directives/class.ts +70 -0
  288. package/src/view/directives/for.ts +275 -0
  289. package/src/view/directives/html.ts +19 -0
  290. package/src/view/directives/if.ts +30 -0
  291. package/src/view/directives/index.ts +11 -0
  292. package/src/view/directives/model.ts +56 -0
  293. package/src/view/directives/on.ts +41 -0
  294. package/src/view/directives/ref.ts +41 -0
  295. package/src/view/directives/show.ts +26 -0
  296. package/src/view/directives/style.ts +47 -0
  297. package/src/view/directives/text.ts +15 -0
  298. package/src/view/evaluate.ts +274 -0
  299. package/src/view/index.ts +112 -1041
  300. package/src/view/mount.ts +200 -0
  301. package/src/view/process.ts +92 -0
  302. package/src/view/types.ts +44 -0
  303. package/dist/core/utils.d.ts +0 -313
  304. package/dist/core/utils.d.ts.map +0 -1
  305. 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
+ }