@develia/commons 0.4.9 → 0.4.13

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 (271) hide show
  1. package/dist/cjs/array.js +0 -0
  2. package/dist/cjs/array.js.map +0 -0
  3. package/dist/cjs/async-pool-executor.js +0 -0
  4. package/dist/cjs/async-pool-executor.js.map +0 -0
  5. package/dist/cjs/browser/form-utilities.js +23 -18
  6. package/dist/cjs/browser/form-utilities.js.map +1 -1
  7. package/dist/cjs/browser/geo-location.js +60 -36
  8. package/dist/cjs/browser/geo-location.js.map +1 -1
  9. package/dist/cjs/browser/index.js +73 -0
  10. package/dist/cjs/browser/index.js.map +1 -1
  11. package/dist/cjs/browser/native-bridge.js +0 -0
  12. package/dist/cjs/browser/native-bridge.js.map +0 -0
  13. package/dist/cjs/cancellable-promise.js +0 -0
  14. package/dist/cjs/cancellable-promise.js.map +0 -0
  15. package/dist/cjs/clean-url-search-params.js +0 -0
  16. package/dist/cjs/clean-url-search-params.js.map +0 -0
  17. package/dist/cjs/collections/cache-dictionary.js +0 -0
  18. package/dist/cjs/collections/cache-dictionary.js.map +0 -0
  19. package/dist/cjs/collections/default-map.js +0 -0
  20. package/dist/cjs/collections/default-map.js.map +0 -0
  21. package/dist/cjs/collections/default-weak-map.js +0 -0
  22. package/dist/cjs/collections/default-weak-map.js.map +0 -0
  23. package/dist/cjs/collections/index.js +0 -0
  24. package/dist/cjs/collections/index.js.map +0 -0
  25. package/dist/cjs/draft.js +149 -0
  26. package/dist/cjs/draft.js.map +1 -0
  27. package/dist/cjs/event-bus.js +70 -0
  28. package/dist/cjs/event-bus.js.map +1 -0
  29. package/dist/cjs/from.js +0 -0
  30. package/dist/cjs/from.js.map +0 -0
  31. package/dist/cjs/index.js +6 -1
  32. package/dist/cjs/index.js.map +1 -1
  33. package/dist/cjs/key-value-pair.js +0 -0
  34. package/dist/cjs/key-value-pair.js.map +0 -0
  35. package/dist/cjs/lazy.js +0 -0
  36. package/dist/cjs/lazy.js.map +0 -0
  37. package/dist/cjs/math.js +0 -0
  38. package/dist/cjs/math.js.map +0 -0
  39. package/dist/cjs/order.js +0 -0
  40. package/dist/cjs/order.js.map +0 -0
  41. package/dist/cjs/parse.js +0 -0
  42. package/dist/cjs/parse.js.map +0 -0
  43. package/dist/cjs/patch.js +0 -0
  44. package/dist/cjs/patch.js.map +0 -0
  45. package/dist/cjs/stopwatch.js +0 -0
  46. package/dist/cjs/stopwatch.js.map +0 -0
  47. package/dist/cjs/string.js +39 -0
  48. package/dist/cjs/string.js.map +1 -1
  49. package/dist/cjs/timer.js +0 -0
  50. package/dist/cjs/timer.js.map +0 -0
  51. package/dist/cjs/timespan.js +0 -0
  52. package/dist/cjs/timespan.js.map +0 -0
  53. package/dist/cjs/type-code.js +0 -0
  54. package/dist/cjs/type-code.js.map +0 -0
  55. package/dist/cjs/type.js +0 -0
  56. package/dist/cjs/type.js.map +0 -0
  57. package/dist/cjs/types.js +0 -0
  58. package/dist/cjs/types.js.map +0 -0
  59. package/dist/cjs/utilities.js +61 -34
  60. package/dist/cjs/utilities.js.map +1 -1
  61. package/dist/esm/array.js +0 -0
  62. package/dist/esm/array.js.map +0 -0
  63. package/dist/esm/async-pool-executor.js +0 -0
  64. package/dist/esm/async-pool-executor.js.map +0 -0
  65. package/dist/esm/browser/form-utilities.js +23 -18
  66. package/dist/esm/browser/form-utilities.js.map +1 -1
  67. package/dist/esm/browser/geo-location.js +60 -36
  68. package/dist/esm/browser/geo-location.js.map +1 -1
  69. package/dist/esm/browser/index.js +71 -0
  70. package/dist/esm/browser/index.js.map +1 -1
  71. package/dist/esm/browser/native-bridge.js +0 -0
  72. package/dist/esm/browser/native-bridge.js.map +0 -0
  73. package/dist/esm/cancellable-promise.js +0 -0
  74. package/dist/esm/cancellable-promise.js.map +0 -0
  75. package/dist/esm/clean-url-search-params.js +0 -0
  76. package/dist/esm/clean-url-search-params.js.map +0 -0
  77. package/dist/esm/collections/cache-dictionary.js +0 -0
  78. package/dist/esm/collections/cache-dictionary.js.map +0 -0
  79. package/dist/esm/collections/default-map.js +0 -0
  80. package/dist/esm/collections/default-map.js.map +0 -0
  81. package/dist/esm/collections/default-weak-map.js +0 -0
  82. package/dist/esm/collections/default-weak-map.js.map +0 -0
  83. package/dist/esm/collections/index.js +0 -0
  84. package/dist/esm/collections/index.js.map +0 -0
  85. package/dist/esm/draft.js +146 -0
  86. package/dist/esm/draft.js.map +1 -0
  87. package/dist/esm/event-bus.js +65 -0
  88. package/dist/esm/event-bus.js.map +1 -0
  89. package/dist/esm/from.js +0 -0
  90. package/dist/esm/from.js.map +0 -0
  91. package/dist/esm/index.js +2 -0
  92. package/dist/esm/index.js.map +1 -1
  93. package/dist/esm/key-value-pair.js +0 -0
  94. package/dist/esm/key-value-pair.js.map +0 -0
  95. package/dist/esm/lazy.js +0 -0
  96. package/dist/esm/lazy.js.map +0 -0
  97. package/dist/esm/math.js +0 -0
  98. package/dist/esm/math.js.map +0 -0
  99. package/dist/esm/order.js +0 -0
  100. package/dist/esm/order.js.map +0 -0
  101. package/dist/esm/parse.js +0 -0
  102. package/dist/esm/parse.js.map +0 -0
  103. package/dist/esm/patch.js +0 -0
  104. package/dist/esm/patch.js.map +0 -0
  105. package/dist/esm/stopwatch.js +0 -0
  106. package/dist/esm/stopwatch.js.map +0 -0
  107. package/dist/esm/string.js +34 -0
  108. package/dist/esm/string.js.map +1 -1
  109. package/dist/esm/timer.js +0 -0
  110. package/dist/esm/timer.js.map +0 -0
  111. package/dist/esm/timespan.js +0 -0
  112. package/dist/esm/timespan.js.map +0 -0
  113. package/dist/esm/type-code.js +0 -0
  114. package/dist/esm/type-code.js.map +0 -0
  115. package/dist/esm/type.js +0 -0
  116. package/dist/esm/type.js.map +0 -0
  117. package/dist/esm/types.js +0 -0
  118. package/dist/esm/types.js.map +0 -0
  119. package/dist/esm/utilities.js +61 -34
  120. package/dist/esm/utilities.js.map +1 -1
  121. package/dist/types/array.d.ts +0 -0
  122. package/dist/types/array.d.ts.map +0 -0
  123. package/dist/types/async-pool-executor.d.ts +0 -0
  124. package/dist/types/async-pool-executor.d.ts.map +0 -0
  125. package/dist/types/browser/form-utilities.d.ts +2 -2
  126. package/dist/types/browser/form-utilities.d.ts.map +1 -1
  127. package/dist/types/browser/geo-location.d.ts +0 -0
  128. package/dist/types/browser/geo-location.d.ts.map +1 -1
  129. package/dist/types/browser/index.d.ts +10 -0
  130. package/dist/types/browser/index.d.ts.map +1 -1
  131. package/dist/types/browser/native-bridge.d.ts +0 -0
  132. package/dist/types/browser/native-bridge.d.ts.map +0 -0
  133. package/dist/types/cancellable-promise.d.ts +0 -0
  134. package/dist/types/cancellable-promise.d.ts.map +0 -0
  135. package/dist/types/clean-url-search-params.d.ts +0 -0
  136. package/dist/types/clean-url-search-params.d.ts.map +0 -0
  137. package/dist/types/collections/cache-dictionary.d.ts +0 -0
  138. package/dist/types/collections/cache-dictionary.d.ts.map +0 -0
  139. package/dist/types/collections/default-map.d.ts +0 -0
  140. package/dist/types/collections/default-map.d.ts.map +0 -0
  141. package/dist/types/collections/default-weak-map.d.ts +0 -0
  142. package/dist/types/collections/default-weak-map.d.ts.map +0 -0
  143. package/dist/types/collections/index.d.ts +0 -0
  144. package/dist/types/collections/index.d.ts.map +0 -0
  145. package/dist/types/draft.d.ts +17 -0
  146. package/dist/types/draft.d.ts.map +1 -0
  147. package/dist/types/event-bus.d.ts +21 -0
  148. package/dist/types/event-bus.d.ts.map +1 -0
  149. package/dist/types/from.d.ts +0 -0
  150. package/dist/types/from.d.ts.map +0 -0
  151. package/dist/types/index.d.ts +2 -0
  152. package/dist/types/index.d.ts.map +1 -1
  153. package/dist/types/key-value-pair.d.ts +0 -0
  154. package/dist/types/key-value-pair.d.ts.map +0 -0
  155. package/dist/types/lazy.d.ts +0 -0
  156. package/dist/types/lazy.d.ts.map +0 -0
  157. package/dist/types/math.d.ts +0 -0
  158. package/dist/types/math.d.ts.map +0 -0
  159. package/dist/types/order.d.ts +0 -0
  160. package/dist/types/order.d.ts.map +0 -0
  161. package/dist/types/parse.d.ts +0 -0
  162. package/dist/types/parse.d.ts.map +0 -0
  163. package/dist/types/patch.d.ts +0 -0
  164. package/dist/types/patch.d.ts.map +0 -0
  165. package/dist/types/stopwatch.d.ts +0 -0
  166. package/dist/types/stopwatch.d.ts.map +0 -0
  167. package/dist/types/string.d.ts +5 -0
  168. package/dist/types/string.d.ts.map +1 -1
  169. package/dist/types/timer.d.ts +0 -0
  170. package/dist/types/timer.d.ts.map +0 -0
  171. package/dist/types/timespan.d.ts +0 -0
  172. package/dist/types/timespan.d.ts.map +0 -0
  173. package/dist/types/type-code.d.ts +0 -0
  174. package/dist/types/type-code.d.ts.map +0 -0
  175. package/dist/types/type.d.ts +0 -0
  176. package/dist/types/type.d.ts.map +0 -0
  177. package/dist/types/types.d.ts +0 -0
  178. package/dist/types/types.d.ts.map +0 -0
  179. package/dist/types/utilities.d.ts +2 -2
  180. package/dist/types/utilities.d.ts.map +1 -1
  181. package/dist/web/array.js +0 -0
  182. package/dist/web/array.js.map +0 -0
  183. package/dist/web/async-pool-executor.js +0 -0
  184. package/dist/web/async-pool-executor.js.map +0 -0
  185. package/dist/web/browser/form-utilities.js +23 -18
  186. package/dist/web/browser/form-utilities.js.map +1 -1
  187. package/dist/web/browser/geo-location.js +60 -36
  188. package/dist/web/browser/geo-location.js.map +1 -1
  189. package/dist/web/browser/index.js +71 -0
  190. package/dist/web/browser/index.js.map +1 -1
  191. package/dist/web/browser/native-bridge.js +0 -0
  192. package/dist/web/browser/native-bridge.js.map +0 -0
  193. package/dist/web/cancellable-promise.js +0 -0
  194. package/dist/web/cancellable-promise.js.map +0 -0
  195. package/dist/web/clean-url-search-params.js +0 -0
  196. package/dist/web/clean-url-search-params.js.map +0 -0
  197. package/dist/web/collections/cache-dictionary.js +0 -0
  198. package/dist/web/collections/cache-dictionary.js.map +0 -0
  199. package/dist/web/collections/default-map.js +0 -0
  200. package/dist/web/collections/default-map.js.map +0 -0
  201. package/dist/web/collections/default-weak-map.js +0 -0
  202. package/dist/web/collections/default-weak-map.js.map +0 -0
  203. package/dist/web/collections/index.js +0 -0
  204. package/dist/web/collections/index.js.map +0 -0
  205. package/dist/web/draft.js +146 -0
  206. package/dist/web/draft.js.map +1 -0
  207. package/dist/web/event-bus.js +65 -0
  208. package/dist/web/event-bus.js.map +1 -0
  209. package/dist/web/from.js +0 -0
  210. package/dist/web/from.js.map +0 -0
  211. package/dist/web/index.js +2 -0
  212. package/dist/web/index.js.map +1 -1
  213. package/dist/web/key-value-pair.js +0 -0
  214. package/dist/web/key-value-pair.js.map +0 -0
  215. package/dist/web/lazy.js +0 -0
  216. package/dist/web/lazy.js.map +0 -0
  217. package/dist/web/math.js +0 -0
  218. package/dist/web/math.js.map +0 -0
  219. package/dist/web/order.js +0 -0
  220. package/dist/web/order.js.map +0 -0
  221. package/dist/web/parse.js +0 -0
  222. package/dist/web/parse.js.map +0 -0
  223. package/dist/web/patch.js +0 -0
  224. package/dist/web/patch.js.map +0 -0
  225. package/dist/web/stopwatch.js +0 -0
  226. package/dist/web/stopwatch.js.map +0 -0
  227. package/dist/web/string.js +34 -0
  228. package/dist/web/string.js.map +1 -1
  229. package/dist/web/timer.js +0 -0
  230. package/dist/web/timer.js.map +0 -0
  231. package/dist/web/timespan.js +0 -0
  232. package/dist/web/timespan.js.map +0 -0
  233. package/dist/web/type-code.js +0 -0
  234. package/dist/web/type-code.js.map +0 -0
  235. package/dist/web/type.js +0 -0
  236. package/dist/web/type.js.map +0 -0
  237. package/dist/web/types.js +0 -0
  238. package/dist/web/types.js.map +0 -0
  239. package/dist/web/utilities.js +61 -34
  240. package/dist/web/utilities.js.map +1 -1
  241. package/package.json +8 -4
  242. package/src/array.ts +0 -0
  243. package/src/async-pool-executor.ts +0 -0
  244. package/src/browser/form-utilities.ts +179 -173
  245. package/src/browser/geo-location.ts +88 -54
  246. package/src/browser/index.ts +115 -4
  247. package/src/browser/native-bridge.ts +0 -0
  248. package/src/cancellable-promise.ts +0 -0
  249. package/src/clean-url-search-params.ts +0 -0
  250. package/src/collections/cache-dictionary.ts +0 -0
  251. package/src/collections/default-map.ts +0 -0
  252. package/src/collections/default-weak-map.ts +0 -0
  253. package/src/collections/index.ts +0 -0
  254. package/src/draft.ts +264 -0
  255. package/src/event-bus.ts +84 -0
  256. package/src/from.ts +0 -0
  257. package/src/index.ts +6 -0
  258. package/src/key-value-pair.ts +0 -0
  259. package/src/lazy.ts +0 -0
  260. package/src/math.ts +0 -0
  261. package/src/order.ts +0 -0
  262. package/src/parse.ts +0 -0
  263. package/src/patch.ts +0 -0
  264. package/src/stopwatch.ts +0 -0
  265. package/src/string.ts +128 -48
  266. package/src/timer.ts +0 -0
  267. package/src/timespan.ts +0 -0
  268. package/src/type-code.ts +0 -0
  269. package/src/type.ts +0 -0
  270. package/src/types.ts +0 -0
  271. package/src/utilities.ts +82 -50
package/src/draft.ts ADDED
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Methods injected into a draft proxy in addition to the original object's properties.
3
+ *
4
+ * @template T - The shape of the wrapped object.
5
+ */
6
+ type DraftMethods<T> = {
7
+ /**
8
+ * Apply pending changes to the original object.
9
+ *
10
+ * @param key - Optional property key. If provided, commits only that property.
11
+ * If omitted, commits every modified property recursively.
12
+ * @returns `true` when a single-property commit was applied,
13
+ * `false` when the property was not modified,
14
+ * `void` when committing the whole draft.
15
+ */
16
+ commit(key?: keyof T): boolean | void;
17
+
18
+ /**
19
+ * Discard pending changes, restoring values from the original object.
20
+ *
21
+ * @param key - Optional property key. If provided, rolls back only that property.
22
+ * If omitted, rolls back every modified property recursively.
23
+ * @returns `true` when a single-property rollback was applied,
24
+ * `false` when the property was not modified,
25
+ * `void` when rolling back the whole draft.
26
+ */
27
+ rollback(key?: keyof T): boolean | void;
28
+
29
+ /**
30
+ * Check whether the draft (or a specific property) has pending changes.
31
+ *
32
+ * @param key - Optional property key. If omitted, checks the whole draft.
33
+ * @returns `true` if there are pending changes.
34
+ */
35
+ isModified(key?: keyof T): boolean;
36
+
37
+ /**
38
+ * Get the list of property keys with pending changes at this draft level.
39
+ *
40
+ * @returns Array of modified property keys (does not recurse into children).
41
+ */
42
+ modifiedProps(): (keyof T)[];
43
+
44
+ /**
45
+ * Manually mark (or unmark) a property as modified.
46
+ * Primarily used by child drafts to notify their parent, but also
47
+ * available for advanced manual control.
48
+ *
49
+ * @param key - Property key to flag.
50
+ * @param modified - `true` to mark as modified (default), `false` to clear.
51
+ */
52
+ setModified(key: keyof T, modified?: boolean): void;
53
+ };
54
+
55
+ /**
56
+ * A draft proxy: the original object's properties plus draft control methods.
57
+ *
58
+ * @template T - The shape of the wrapped object.
59
+ */
60
+ export type Draft<T extends object> = T & DraftMethods<T>;
61
+
62
+ /**
63
+ * Link from a child draft to its parent, used to propagate modification status.
64
+ */
65
+ type ParentLink = {
66
+ /** Parent draft methods reference (we only need `setModified`). */
67
+ parent: { setModified(key: PropertyKey, modified?: boolean): void };
68
+ /** Key under which this draft is stored in the parent. */
69
+ keyInParent: PropertyKey;
70
+ };
71
+
72
+ // ─────────────────────────────────────────────
73
+ // deepDraft (internal)
74
+ // ─────────────────────────────────────────────
75
+
76
+ /**
77
+ * Recursively wrap a value so that nested objects/arrays become child drafts
78
+ * linked to a parent. Primitives, `Date`, `RegExp`, `Map` and `Set` instances
79
+ * are cloned but not wrapped.
80
+ *
81
+ * @param value - The value to process.
82
+ * @param parentLink - Optional link to a parent draft for change propagation.
83
+ * @returns A drafted value (or a plain clone for non-wrappable types).
84
+ */
85
+ function deepDraft(value: any, parentLink?: ParentLink): any {
86
+ if (value === null || typeof value !== "object") return value;
87
+ if (value instanceof Date) return new Date(value);
88
+ if (value instanceof RegExp) return new RegExp(value);
89
+
90
+ if (value instanceof Map) {
91
+ const copy = new Map();
92
+ value.forEach((v, k) => copy.set(deepDraft(k), deepDraft(v)));
93
+ return copy;
94
+ }
95
+ if (value instanceof Set) {
96
+ const copy = new Set();
97
+ value.forEach((v) => copy.add(deepDraft(v)));
98
+ return copy;
99
+ }
100
+
101
+ return draft(value, parentLink);
102
+ }
103
+
104
+ /**
105
+ * Create a draft proxy over `original`. The proxy exposes the same properties
106
+ * as the original (with nested objects wrapped as child drafts) plus the
107
+ * control methods `commit`, `rollback`, `isModified`, `modifiedProps` and
108
+ * `setModified`.
109
+ *
110
+ * Mutations on the draft do not affect the original until `commit()` is called.
111
+ * Nested mutations bubble up: modifying a deep property marks every ancestor
112
+ * draft as modified at the corresponding key.
113
+ *
114
+ * @template T - The shape of the wrapped object.
115
+ * @param original - The object to wrap. It will only be mutated on `commit()`.
116
+ * @param parentLink - Internal link used when this draft is a child of another.
117
+ * Do not pass manually.
118
+ * @returns A draft proxy over a deep copy of `original`.
119
+ */
120
+ export default function draft<T extends object>(
121
+ original: T,
122
+ parentLink?: ParentLink
123
+ ): Draft<T> {
124
+ const copy: any = Array.isArray(original)
125
+ ? []
126
+ : Object.create(Object.getPrototypeOf(original));
127
+
128
+ const touched = new Set<PropertyKey>();
129
+
130
+ const notifyParent = (modified: boolean): void => {
131
+ if (parentLink) {
132
+ parentLink.parent.setModified(parentLink.keyInParent, modified);
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Apply commit for a single key: delegate to the child draft if present,
138
+ * otherwise copy the value into `original`.
139
+ */
140
+ const applyCommit = (key: PropertyKey): void => {
141
+ const val = copy[key];
142
+ if (
143
+ val !== null &&
144
+ typeof val === "object" &&
145
+ "commit" in val
146
+ ) {
147
+ (val as Draft<any>).commit();
148
+ return;
149
+ }
150
+ if (key in copy) {
151
+ (original as any)[key] = copy[key];
152
+ } else {
153
+ delete (original as any)[key];
154
+ }
155
+ };
156
+ /**
157
+ * Apply rollback for a single key: delegate to the child draft if present,
158
+ * otherwise restore the value from `original`.
159
+ */
160
+ const applyRollback = (key: PropertyKey): void => {
161
+ const val = copy[key];
162
+ if (
163
+ val !== null &&
164
+ typeof val === "object" &&
165
+ "rollback" in val
166
+ ) {
167
+ (val as Draft<any>).rollback();
168
+ return;
169
+ }
170
+ if (key in original) {
171
+ copy[key] = (original as any)[key];
172
+ } else {
173
+ delete copy[key];
174
+ }
175
+ };
176
+
177
+ const methods: DraftMethods<T> = {
178
+ commit(key) {
179
+ if (key === undefined) {
180
+ for (const k of touched) applyCommit(k);
181
+ touched.clear();
182
+ notifyParent(false);
183
+ return;
184
+ }
185
+ if (!touched.has(key)) return false;
186
+ applyCommit(key);
187
+ touched.delete(key);
188
+ if (touched.size === 0) notifyParent(false);
189
+ return true;
190
+ },
191
+
192
+ rollback(key) {
193
+ if (key === undefined) {
194
+ for (const k of touched) applyRollback(k);
195
+ touched.clear();
196
+ notifyParent(false);
197
+ return;
198
+ }
199
+ if (!touched.has(key)) return false;
200
+ applyRollback(key);
201
+ touched.delete(key);
202
+ if (touched.size === 0) notifyParent(false);
203
+ return true;
204
+ },
205
+
206
+ isModified(key) {
207
+ return key === undefined ? touched.size > 0 : touched.has(key);
208
+ },
209
+
210
+ modifiedProps() {
211
+ return [...touched] as (keyof T)[];
212
+ },
213
+
214
+ setModified(key, modified = true) {
215
+ if (modified) {
216
+ touched.add(key);
217
+ notifyParent(true);
218
+ } else {
219
+ touched.delete(key);
220
+ if (touched.size === 0) notifyParent(false);
221
+ }
222
+ },
223
+ };
224
+
225
+ const isMethodKey = (prop: PropertyKey): prop is keyof DraftMethods<T> =>
226
+ typeof prop === "string" && prop in methods;
227
+
228
+ // Populate `copy` with child drafts linked to this draft.
229
+ for (const key of Reflect.ownKeys(original)) {
230
+ copy[key] = deepDraft((original as any)[key], {
231
+ parent: methods,
232
+ keyInParent: key,
233
+ });
234
+ }
235
+
236
+ return new Proxy(copy, {
237
+ get(target, prop, receiver) {
238
+ if (isMethodKey(prop)) return (methods as any)[prop];
239
+ return Reflect.get(target, prop, receiver);
240
+ },
241
+
242
+ set(target, prop, value, receiver) {
243
+ if (isMethodKey(prop)) {
244
+ throw new Error(`"${String(prop)}" is a reserved draft property`);
245
+ }
246
+ const wrapped = deepDraft(value, {
247
+ parent: methods,
248
+ keyInParent: prop,
249
+ });
250
+ touched.add(prop);
251
+ notifyParent(true);
252
+ return Reflect.set(target, prop, wrapped, receiver);
253
+ },
254
+
255
+ deleteProperty(target, prop) {
256
+ if (isMethodKey(prop)) {
257
+ throw new Error(`"${String(prop)}" is a reserved draft property`);
258
+ }
259
+ touched.add(prop);
260
+ notifyParent(true);
261
+ return Reflect.deleteProperty(target, prop);
262
+ },
263
+ }) as Draft<T>;
264
+ }
@@ -0,0 +1,84 @@
1
+ // event.ts
2
+
3
+ export abstract class Event {
4
+ readonly timestamp: Date;
5
+
6
+ protected constructor() {
7
+ this.timestamp = new Date();
8
+ }
9
+
10
+ toString(): string {
11
+ return `${this.constructor.name}(${this.timestamp.toISOString()})`;
12
+ }
13
+ }
14
+
15
+ type EventClass<T extends Event> = new (...args: any[]) => T;
16
+ type Handler<T extends Event> = (event: T) => void;
17
+
18
+ interface HandlerWrapper {
19
+ original: Function;
20
+ wrapped: (event: Event) => void;
21
+ }
22
+
23
+ export class EventBus {
24
+ private static _instance: EventBus | null = null;
25
+
26
+ static get shared(): EventBus {
27
+ return this._instance ??= new EventBus();
28
+ }
29
+
30
+ private _handlers = new Map<Function, HandlerWrapper[]>();
31
+
32
+ on<T extends Event>(type: EventClass<T>, handler: Handler<T>): void {
33
+ if (!this._handlers.has(type)) {
34
+ this._handlers.set(type, []);
35
+ }
36
+ this._handlers.get(type)!.push({
37
+ original: handler,
38
+ wrapped: (event: Event) => handler(event as T),
39
+ });
40
+ }
41
+
42
+ off<T extends Event>(type: EventClass<T>, handler: Handler<T>): void {
43
+ const handlers = this._handlers.get(type);
44
+ if (!handlers) return;
45
+
46
+ let index = handlers.findIndex((h) => h.original === handler);
47
+ if (index !== -1) {
48
+ handlers.splice(index, 1);
49
+ }
50
+ }
51
+
52
+ emit<T extends Event>(event: T): void {
53
+ const handlers = this._handlers.get(event.constructor);
54
+ if (!handlers) return;
55
+
56
+ for (const handler of [...handlers]) {
57
+ try {
58
+ handler.wrapped(event);
59
+ } catch (e) {
60
+ console.error(`[EventBus] Error en handler de ${event.constructor.name}:`, e);
61
+ }
62
+ }
63
+ }
64
+
65
+ once<T extends Event>(type: EventClass<T>, handler: Handler<T>): void {
66
+ const wrapper: Handler<T> = (event: T) => {
67
+ handler(event);
68
+ this.off(type, wrapper);
69
+ };
70
+ this.on(type, wrapper);
71
+ }
72
+
73
+ clear<T extends Event>(type: EventClass<T>): void {
74
+ this._handlers.delete(type);
75
+ }
76
+
77
+ clearAll(): void {
78
+ this._handlers.clear();
79
+ }
80
+
81
+ hasListeners<T extends Event>(type: EventClass<T>): boolean {
82
+ return (this._handlers.get(type)?.length ?? 0) > 0;
83
+ }
84
+ }
package/src/from.ts CHANGED
File without changes
package/src/index.ts CHANGED
@@ -24,12 +24,18 @@ export {default as AsyncPoolExecutor} from './async-pool-executor.js';
24
24
  // ─── Patterns ────────────────────────────────────────
25
25
  export {default as Lazy} from './lazy.js';
26
26
  export {default as from, From} from './from.js';
27
+ export {EventBus, Event} from './event-bus.js';
28
+
29
+ // ─── Draft ────────────────────────────────────────
30
+ export {default as draft} from './draft.js';
27
31
 
28
32
  // ─── Web ─────────────────────────────────────────────
29
33
  export {default as CleanURLSearchParams} from './clean-url-search-params.js';
30
34
  /** @deprecated */
31
35
  export {ajaxSubmit, ajaxSubmission, submitForm, formToObject} from './browser/index.js';
32
36
 
37
+
38
+
33
39
  // ─── Deprecated ──────────────────────────────────────
34
40
  /** @deprecated */
35
41
  export * from './array.js';
File without changes
package/src/lazy.ts CHANGED
File without changes
package/src/math.ts CHANGED
File without changes
package/src/order.ts CHANGED
File without changes
package/src/parse.ts CHANGED
File without changes
package/src/patch.ts CHANGED
File without changes
package/src/stopwatch.ts CHANGED
File without changes
package/src/string.ts CHANGED
@@ -1,49 +1,129 @@
1
-
2
- /**
3
- * Ensures that a given string has a specific prefix.
4
- *
5
- * @param {string} str - The string to ensure the prefix on.
6
- * @param {string} prefix - The prefix to ensure on the string.
7
- * @return {string} - The resulting string with the ensured prefix.
8
- */
9
- export function ensurePrefix(str: string, prefix: string) {
10
- if (!str.startsWith(prefix))
11
- return prefix + str
12
- return str
13
- }
14
-
15
-
16
- /**
17
- * Ensures that a string ends with a specified suffix.
18
- *
19
- * @param {string} str - The original string.
20
- * @param {string} suffix - The suffix to ensure.
21
- * @return {string} - The modified string with the suffix added if it was not already present.
22
- */
23
- export function ensureSuffix(str: string, suffix: string) {
24
- if (!str.endsWith(suffix))
25
- return str + suffix
26
- return str
27
- }
28
-
29
- /**
30
- * Formats a string using a template and provided arguments.
31
- *
32
- * @param {string} template - The template string containing placeholders.
33
- * @param {any[]} args - Optional arguments to replace the placeholders in the template.
34
- * @return {string} The formatted string.
35
- */
36
- export function format(template: string, ...args: any[]): string {
37
-
38
- let regex: RegExp;
39
- if (args.length === 1 && typeof args[0] === 'object') {
40
- args = args[0];
41
- regex = /{(.+?)}/g;
42
- } else {
43
- regex = /{(\d+?)}/g;
44
- }
45
-
46
- return template.replace(regex, (match, key) => {
47
- return typeof args[key] !== 'undefined' ? args[key] : "";
48
- });
1
+
2
+ /**
3
+ * Ensures that a given string has a specific prefix.
4
+ *
5
+ * @param {string} str - The string to ensure the prefix on.
6
+ * @param {string} prefix - The prefix to ensure on the string.
7
+ * @return {string} - The resulting string with the ensured prefix.
8
+ */
9
+ export function ensurePrefix(str: string, prefix: string): string {
10
+ if (!str.startsWith(prefix))
11
+ return prefix + str
12
+ return str
13
+ }
14
+
15
+
16
+ /**
17
+ * Ensures that a string ends with a specified suffix.
18
+ *
19
+ * @param {string} str - The original string.
20
+ * @param {string} suffix - The suffix to ensure.
21
+ * @return {string} - The modified string with the suffix added if it was not already present.
22
+ */
23
+ export function ensureSuffix(str: string, suffix: string): string {
24
+ if (!str.endsWith(suffix))
25
+ return str + suffix
26
+ return str
27
+ }
28
+
29
+ /**
30
+ * Formats a string using a template and provided arguments.
31
+ *
32
+ * @param {string} template - The template string containing placeholders.
33
+ * @param {any[]} args - Optional arguments to replace the placeholders in the template.
34
+ * @return {string} The formatted string.
35
+ */
36
+ export function format(template: string, ...args: any[]): string {
37
+
38
+ let regex: RegExp;
39
+ if (args.length === 1 && typeof args[0] === 'object') {
40
+ args = args[0];
41
+ regex = /{(.+?)}/g;
42
+ } else {
43
+ regex = /{(\d+?)}/g;
44
+ }
45
+
46
+ return template.replace(regex, (match, key) => {
47
+ return typeof args[key] !== 'undefined' ? args[key] : "";
48
+ });
49
+ }
50
+
51
+ /**
52
+ * Splits a string into its constituent words, regardless of the original case
53
+ * style (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE,
54
+ * space-separated, etc.).
55
+ *
56
+ * @param {string} str - The string to split into words.
57
+ * @return {string[]} - The list of lowercase words extracted from the input.
58
+ */
59
+ function toWords(str: string): string[] {
60
+ if (!str) return [];
61
+
62
+ return str
63
+ // Insert a space between a lowercase/digit and an uppercase letter (camelCase -> camel Case)
64
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
65
+ // Insert a space between consecutive uppercase letters followed by a lowercase letter (XMLParser -> XML Parser)
66
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
67
+ // Replace any non-alphanumeric character with a space
68
+ .replace(/[^a-zA-Z0-9]+/g, ' ')
69
+ .trim()
70
+ .toLowerCase()
71
+ .split(/\s+/)
72
+ .filter(Boolean);
73
+ }
74
+
75
+ /**
76
+ * Converts a string to snake_case.
77
+ *
78
+ * @param {string} str - The string to convert.
79
+ * @return {string} - The string converted to snake_case.
80
+ */
81
+ export function toSnakeCase(str: string): string {
82
+ return toWords(str).join('_');
83
+ }
84
+
85
+ /**
86
+ * Converts a string to kebab-case.
87
+ *
88
+ * @param {string} str - The string to convert.
89
+ * @return {string} - The string converted to kebab-case.
90
+ */
91
+ export function toKebabCase(str: string): string {
92
+ return toWords(str).join('-');
93
+ }
94
+
95
+ /**
96
+ * Converts a string to camelCase.
97
+ *
98
+ * @param {string} str - The string to convert.
99
+ * @return {string} - The string converted to camelCase.
100
+ */
101
+ export function toCamelCase(str: string): string {
102
+ const words = toWords(str);
103
+ if (words.length === 0) return '';
104
+ return words
105
+ .map((word, i) => i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))
106
+ .join('');
107
+ }
108
+
109
+ /**
110
+ * Converts a string to PascalCase.
111
+ *
112
+ * @param {string} str - The string to convert.
113
+ * @return {string} - The string converted to PascalCase.
114
+ */
115
+ export function toPascalCase(str: string): string {
116
+ return toWords(str)
117
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
118
+ .join('');
119
+ }
120
+
121
+ /**
122
+ * Converts a string to CONSTANT_CASE (a.k.a. SCREAMING_SNAKE_CASE).
123
+ *
124
+ * @param {string} str - The string to convert.
125
+ * @return {string} - The string converted to CONSTANT_CASE.
126
+ */
127
+ export function toConstantCase(str: string): string {
128
+ return toWords(str).join('_').toUpperCase();
49
129
  }
package/src/timer.ts CHANGED
File without changes
package/src/timespan.ts CHANGED
File without changes
package/src/type-code.ts CHANGED
File without changes
package/src/type.ts CHANGED
File without changes
package/src/types.ts CHANGED
File without changes