@codady/utils 0.0.39 → 0.0.40

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 (36) hide show
  1. package/CHANGELOG.md +21 -2
  2. package/dist/utils.cjs.js +110 -7
  3. package/dist/utils.cjs.min.js +3 -3
  4. package/dist/utils.esm.js +110 -7
  5. package/dist/utils.esm.min.js +3 -3
  6. package/dist/utils.umd.js +110 -7
  7. package/dist/utils.umd.min.js +3 -3
  8. package/dist.zip +0 -0
  9. package/examples/ajax-download.html +94 -0
  10. package/examples/ajax-hook.html +2 -2
  11. package/examples/ajax-signal.html +91 -0
  12. package/examples/ajax-timeout.html +85 -0
  13. package/examples/stringToEncodings-collision-test-registry.html +117 -0
  14. package/examples/stringToEncodings-collision-test.html +71 -0
  15. package/examples/stringToEncodings.html +138 -0
  16. package/examples/unicodeToEncodings.html +195 -0
  17. package/modules.js +5 -1
  18. package/modules.ts +5 -1
  19. package/package.json +1 -1
  20. package/src/ajax.js +23 -6
  21. package/src/ajax.ts +30 -10
  22. package/src/stringToEncodings.js +56 -0
  23. package/src/stringToEncodings.ts +110 -0
  24. package/src/unicodeToEncodings.js +51 -0
  25. package/src/unicodeToEncodings.ts +55 -0
  26. package/src/arrayMutableMethods - /345/211/257/346/234/254.js" +0 -5
  27. package/src/capitalize - /345/211/257/346/234/254.js" +0 -19
  28. package/src/comma - /345/211/257/346/234/254.js" +0 -2
  29. package/src/deepCloneToJSON - /345/211/257/346/234/254.js" +0 -47
  30. package/src/deepMergeMaps - /345/211/257/346/234/254.js" +0 -78
  31. package/src/escapeHTML - /345/211/257/346/234/254.js" +0 -29
  32. package/src/getDataType - /345/211/257/346/234/254.js" +0 -38
  33. package/src/isEmpty - /345/211/257/346/234/254.js" +0 -45
  34. package/src/mapMutableMethods - /345/211/257/346/234/254.js" +0 -5
  35. package/src/setMutableMethods - /345/211/257/346/234/254.js" +0 -5
  36. package/src/wrapMap - /345/211/257/346/234/254.js" +0 -119
package/modules.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2026/01/20 13:55:43
2
+ * Last modified: 2026/02/05 17:00:27
3
3
  */
4
4
  'use strict';
5
5
  import deepClone from './src/deepClone';
@@ -47,6 +47,8 @@ import buildUrl from './src/buildUrl';
47
47
  import ajax from './src/ajax';
48
48
  import capitalize from './src/capitalize';
49
49
  import cleanQueryString from './src/cleanQueryString';
50
+ import stringToEncodings from './src/stringToEncodings';
51
+ import unicodeToEncodings from './src/unicodeToEncodings';
50
52
  const utils = {
51
53
  //executeStr,
52
54
  getDataType,
@@ -96,5 +98,7 @@ const utils = {
96
98
  ajax,
97
99
  capitalize,
98
100
  cleanQueryString,
101
+ stringToEncodings,
102
+ unicodeToEncodings,
99
103
  };
100
104
  export default utils;
package/modules.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2026/01/20 13:55:43
2
+ * Last modified: 2026/02/05 17:00:27
3
3
  */
4
4
  'use strict'
5
5
  import deepClone from './src/deepClone';
@@ -54,6 +54,8 @@ import buildUrl from './src/buildUrl';
54
54
  import ajax from './src/ajax';
55
55
  import capitalize from './src/capitalize';
56
56
  import cleanQueryString from './src/cleanQueryString';
57
+ import stringToEncodings from './src/stringToEncodings';
58
+ import unicodeToEncodings from './src/unicodeToEncodings';
57
59
 
58
60
  const utils = {
59
61
  //executeStr,
@@ -104,6 +106,8 @@ const utils = {
104
106
  ajax,
105
107
  capitalize,
106
108
  cleanQueryString,
109
+ stringToEncodings,
110
+ unicodeToEncodings,
107
111
 
108
112
  };
109
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.39",
3
+ "version": "0.0.40",
4
4
  "author": "AXUI Development Team",
5
5
  "license": "MIT",
6
6
  "description": "This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.",
package/src/ajax.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2026/01/20 16:38:21
2
+ * @since Last modified: 2026/01/20 18:14:18
3
3
  * Sends an asynchronous HTTP request (AJAX).
4
4
  * @function ajax
5
5
  * @param {AjaxOptions} options - Configuration for the request.
@@ -37,6 +37,7 @@ const ajax = (options) => {
37
37
  signal: null,
38
38
  xhrFields: {},
39
39
  cacheBustKey: '_t',
40
+ precision: 2,
40
41
  //
41
42
  onAbort: null,
42
43
  onTimeout: null,
@@ -143,6 +144,10 @@ const ajax = (options) => {
143
144
  config?.onTimeout?.(resp);
144
145
  //reject只能接受一个参数
145
146
  config.catchError ? reject(resp) : resolve(resp);
147
+ //超时也是不能获得数据的行为,定义为failure
148
+ config?.onFailure?.(resp);
149
+ //timeout会经过onreadystatechange,但是被及时的return了,所以这里多加一行
150
+ config?.onFinish?.(resp);
146
151
  },
147
152
  //报错监听
148
153
  errorHandler = (resp) => {
@@ -168,6 +173,8 @@ const ajax = (options) => {
168
173
  config.catchError ? reject(resp) : resolve(resp);
169
174
  //回调,status和content在此确认
170
175
  config?.onAbort?.(resp);
176
+ //abort行为不会经过onreadystatechange,这里需要多这一行以表示xhr的完成(结束)
177
+ config?.onFinish?.(resp);
171
178
  }, abortHandlerWithSignal = () => {
172
179
  //先中止请求,防止触发其他 readystate 事件
173
180
  xhr.abort();
@@ -211,23 +218,26 @@ const ajax = (options) => {
211
218
  type: 'unset',
212
219
  //上传和下载进度
213
220
  progress: {}
221
+ }, getProgressValues = (ratio) => {
222
+ let text = (ratio * 100).toFixed(config.precision);
223
+ return { percent: parseFloat(text), text };
214
224
  },
215
225
  //定义进度函数
216
226
  progressHandler = (name, data, callback) => {
217
227
  if (data.lengthComputable) {
218
- const resp = { ...context, status: xhr.status }, ratio = data.loaded / data.total;
228
+ const resp = { ...context, status: xhr.status }, ratio = data.loaded / data.total, { percent, text } = getProgressValues(ratio);
219
229
  resp.progress = {
220
230
  name,
221
231
  loaded: data.loaded,
222
232
  total: data.total,
223
233
  timestamp: (new Date(data.timeStamp)).getTime(),
224
234
  ratio,
225
- percent: Math.round(ratio * 100),
235
+ percent,
236
+ text,
226
237
  };
227
238
  callback?.(resp);
228
- //到达100%执行complete
229
- if (resp.progress.percent >= 100) {
230
- resp.progress.percent = 100;
239
+ if (ratio >= 1) {
240
+ Object.assign(resp.progress, getProgressValues(1));
231
241
  config?.onComplete?.(resp);
232
242
  }
233
243
  }
@@ -265,8 +275,15 @@ const ajax = (options) => {
265
275
  config[`on${capitalize(context.type)}`]?.({ ...context });
266
276
  return;
267
277
  }
278
+ //tiemeout事件也会执行这里,此时需要让它触发onTimeout事件
279
+ //abort和timeout行为的status是0
280
+ //不过abort行为不会执行到这里
281
+ if (xhr.status === 0 && context.type !== 'abort') {
282
+ return;
283
+ }
268
284
  //已经请求成功,不会有timeout事件,也不需要abort了,所以移除abort事件
269
285
  cleanup();
286
+ //根据状态码判断响应结果
270
287
  const isInformation = xhr.status >= 100 && xhr.status < 200, isSuccess = (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304, isRedirection = xhr.status >= 300 && xhr.status < 400, isClientError = xhr.status >= 400 && xhr.status < 500, isServerError = xhr.status >= 500 && xhr.status < 600;
271
288
  //已经获得返回数据
272
289
  if (isSuccess) {
package/src/ajax.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2026/01/20 16:38:21
2
+ * @since Last modified: 2026/01/20 18:14:18
3
3
  * Sends an asynchronous HTTP request (AJAX).
4
4
  * @function ajax
5
5
  * @param {AjaxOptions} options - Configuration for the request.
@@ -34,6 +34,7 @@ interface AjaxOptions {
34
34
  signal?: AbortSignal; // AbortSignal for canceling the request
35
35
  xhrFields?: Record<string, any>; // Additional fields to set on the XHR object
36
36
  cacheBustKey?: string,
37
+ precision?: number,
37
38
  // Callbacks
38
39
  onAbort?: ((resp: AjaxResponse) => void) | null;
39
40
  onTimeout?: ((resp: AjaxResponse) => void) | null;
@@ -74,6 +75,7 @@ interface AjaxResponse {
74
75
  timestamp?: number;
75
76
  ratio?: number;
76
77
  percent?: number;
78
+ text?: string;
77
79
  };
78
80
  }
79
81
 
@@ -101,6 +103,7 @@ const ajax = (options: AjaxOptions) => {
101
103
  signal: null as any,
102
104
  xhrFields: {},
103
105
  cacheBustKey: '_t',
106
+ precision: 2,
104
107
  //
105
108
  onAbort: null,
106
109
  onTimeout: null,
@@ -212,6 +215,10 @@ const ajax = (options: AjaxOptions) => {
212
215
  config?.onTimeout?.(resp);
213
216
  //reject只能接受一个参数
214
217
  config.catchError ? reject(resp) : resolve(resp);
218
+ //超时也是不能获得数据的行为,定义为failure
219
+ config?.onFailure?.(resp);
220
+ //timeout会经过onreadystatechange,但是被及时的return了,所以这里多加一行
221
+ config?.onFinish?.(resp);
215
222
  },
216
223
  //报错监听
217
224
  errorHandler = (resp: any) => {
@@ -236,6 +243,8 @@ const ajax = (options: AjaxOptions) => {
236
243
  config.catchError ? reject(resp) : resolve(resp);
237
244
  //回调,status和content在此确认
238
245
  config?.onAbort?.(resp);
246
+ //abort行为不会经过onreadystatechange,这里需要多这一行以表示xhr的完成(结束)
247
+ config?.onFinish?.(resp);
239
248
  },
240
249
  abortHandlerWithSignal = () => {
241
250
  //先中止请求,防止触发其他 readystate 事件
@@ -281,25 +290,31 @@ const ajax = (options: AjaxOptions) => {
281
290
  //上传和下载进度
282
291
  progress: {}
283
292
  },
293
+ getProgressValues = (ratio: number) => {
294
+ let text = (ratio * 100).toFixed(config.precision);
295
+ return { percent: parseFloat(text), text }
296
+ },
284
297
  //定义进度函数
285
298
  progressHandler = (name: 'upload' | 'download', data: any, callback: Function) => {
286
299
  if (data.lengthComputable) {
287
300
  const resp = { ...context, status: xhr.status },
288
- ratio = data.loaded / data.total
301
+ ratio = data.loaded / data.total,
302
+ { percent, text } = getProgressValues(ratio);
289
303
  resp.progress = {
290
304
  name,
291
305
  loaded: data.loaded,
292
306
  total: data.total,
293
307
  timestamp: (new Date(data.timeStamp)).getTime(),
294
308
  ratio,
295
- percent: Math.round(ratio * 100),
309
+ percent,
310
+ text,
296
311
  }
297
312
  callback?.(resp);
298
- //到达100%执行complete
299
- if ((resp.progress.percent as number) >= 100) {
300
- resp.progress.percent = 100;
313
+ if (ratio >= 1) {
314
+ Object.assign(resp.progress, getProgressValues(1));
301
315
  config?.onComplete?.(resp);
302
316
  }
317
+
303
318
  }
304
319
  }, uploadProgressHandler = (data: any) => {
305
320
  progressHandler('upload', data, (resp: any) => (config.onUpload as Function)(resp));
@@ -329,8 +344,6 @@ const ajax = (options: AjaxOptions) => {
329
344
  // 手动触发 Created 状态
330
345
  config.onCreated?.({ ...context, type: 'created' });
331
346
 
332
-
333
-
334
347
  //状态判断
335
348
  xhr.onreadystatechange = function () {
336
349
  context.stage = xhr.readyState;
@@ -343,16 +356,24 @@ const ajax = (options: AjaxOptions) => {
343
356
  (config as any)[`on${capitalize(context.type)}`]?.({ ...context });
344
357
  return;
345
358
  }
359
+
360
+ //tiemeout事件也会执行这里,此时需要让它触发onTimeout事件
361
+ //abort和timeout行为的status是0
362
+ //不过abort行为不会执行到这里
363
+ if (xhr.status === 0 && context.type !== 'abort') {
364
+ return;
365
+ }
366
+
346
367
  //已经请求成功,不会有timeout事件,也不需要abort了,所以移除abort事件
347
368
  cleanup();
348
369
 
370
+ //根据状态码判断响应结果
349
371
  const isInformation = xhr.status >= 100 && xhr.status < 200,
350
372
  isSuccess = (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304,
351
373
  isRedirection = xhr.status >= 300 && xhr.status < 400,
352
374
  isClientError = xhr.status >= 400 && xhr.status < 500,
353
375
  isServerError = xhr.status >= 500 && xhr.status < 600;
354
376
 
355
-
356
377
  //已经获得返回数据
357
378
  if (isSuccess) {
358
379
  if (!config.responseType || xhr.responseType === 'text') {
@@ -446,5 +467,4 @@ const ajax = (options: AjaxOptions) => {
446
467
 
447
468
  ajax.all = (requests: AjaxOptions[]): Promise<AjaxResponse[]> => Promise.all(requests.map(ajax) as any);
448
469
 
449
-
450
470
  export default ajax;
@@ -0,0 +1,56 @@
1
+ const stringToEncodings = (name, options = {}) => {
2
+ // Default: Supplementary Private Use Area (Plane 15 and Plane 16)
3
+ //1,114,110 places,5000 strings => 0 collision
4
+ const start = options.start ?? 0xF0000, end = options.end ?? 0x10FFFD, range = BigInt(end - start + 1), registry = options.registryMap,
5
+ /** Format result */
6
+ formatResult = (name, codePoint, hash, collision) => {
7
+ const hex = codePoint.toString(16).toUpperCase();
8
+ return {
9
+ name,
10
+ unicode: `U+${hex}`,
11
+ htmlDec: `&#${codePoint};`,
12
+ htmlHex: `&#x${hex};`,
13
+ hex,
14
+ codePoint,
15
+ hash,
16
+ collision,
17
+ };
18
+ };
19
+ // -----------------------------
20
+ // 1. Compute FNV-1a 64-bit hash
21
+ // -----------------------------
22
+ let hash = BigInt("0xcbf29ce484222325");
23
+ const prime = BigInt("0x100000001b3");
24
+ for (const ch of name) {
25
+ hash ^= BigInt(ch.codePointAt(0));
26
+ hash *= prime;
27
+ }
28
+ const hashHex = hash.toString(16).toUpperCase();
29
+ // -----------------------------
30
+ // 2. Stateless mode (no registry)
31
+ // -----------------------------
32
+ if (!registry) {
33
+ const offset = Number(hash % range), codePoint = start + offset;
34
+ return formatResult(name, codePoint, hashHex, false);
35
+ }
36
+ // -----------------------------
37
+ // 3. Registry mode (0 collision)
38
+ // -----------------------------
39
+ // Already assigned → return stable mapping
40
+ if (registry.has(name)) {
41
+ return formatResult(name, registry.get(name), hashHex, false);
42
+ }
43
+ // Initial candidate from hash
44
+ let offset = Number(hash % range), codePoint = start + offset, collision = false;
45
+ const used = new Set(registry.values());
46
+ // Linear probing to resolve collisions
47
+ while (used.has(codePoint)) {
48
+ collision = true;
49
+ offset = (offset + 1) % Number(range);
50
+ codePoint = start + offset;
51
+ }
52
+ // Commit allocation
53
+ registry.set(name, codePoint);
54
+ return formatResult(name, codePoint, hashHex, collision);
55
+ };
56
+ export default stringToEncodings;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @since Last modified: 2026/02/05 15:12:33
3
+ * Generate a stable Unicode code point from a string.
4
+ * - Without registry: FNV-1a 64-bit hash mapping (fast, stateless)
5
+ * - With registry: Guaranteed zero-collision allocation
6
+ */
7
+ export type StringEncodingResult = {
8
+ unicode: string;
9
+ htmlDec: string;
10
+ htmlHex: string;
11
+ hex: string;
12
+ codePoint: number;
13
+ hash: string;
14
+ name: string;
15
+ collision?: boolean;
16
+ };
17
+
18
+ export type StringEncodingOptions = {
19
+ start?: number;
20
+ end?: number;
21
+ registryMap?: Map<string, number>; // optional
22
+ };
23
+
24
+
25
+ const stringToEncodings = (
26
+ name: string,
27
+ options: StringEncodingOptions = {}
28
+ ): StringEncodingResult => {
29
+
30
+ // Default: Supplementary Private Use Area (Plane 15 and Plane 16)
31
+ //1,114,110 places,5000 strings => 0 collision
32
+ const start = options.start ?? 0xF0000,
33
+ end = options.end ?? 0x10FFFD,
34
+ range = BigInt(end - start + 1),
35
+ registry = options.registryMap,
36
+ /** Format result */
37
+ formatResult = (
38
+ name: string,
39
+ codePoint: number,
40
+ hash: string,
41
+ collision: boolean
42
+ ): StringEncodingResult => {
43
+ const hex = codePoint.toString(16).toUpperCase();
44
+
45
+ return {
46
+ name,
47
+ unicode: `U+${hex}`,
48
+ htmlDec: `&#${codePoint};`,
49
+ htmlHex: `&#x${hex};`,
50
+ hex,
51
+ codePoint,
52
+ hash,
53
+ collision,
54
+ };
55
+ };
56
+
57
+
58
+ // -----------------------------
59
+ // 1. Compute FNV-1a 64-bit hash
60
+ // -----------------------------
61
+ let hash = BigInt("0xcbf29ce484222325");
62
+ const prime = BigInt("0x100000001b3");
63
+
64
+ for (const ch of name) {
65
+ hash ^= BigInt(ch.codePointAt(0)!);
66
+ hash *= prime;
67
+ }
68
+
69
+ const hashHex = hash.toString(16).toUpperCase();
70
+
71
+ // -----------------------------
72
+ // 2. Stateless mode (no registry)
73
+ // -----------------------------
74
+ if (!registry) {
75
+ const offset = Number(hash % range),
76
+ codePoint = start + offset;
77
+ return formatResult(name, codePoint, hashHex, false);
78
+ }
79
+
80
+ // -----------------------------
81
+ // 3. Registry mode (0 collision)
82
+ // -----------------------------
83
+
84
+ // Already assigned → return stable mapping
85
+ if (registry.has(name)) {
86
+ return formatResult(name, registry.get(name)!, hashHex, false);
87
+ }
88
+
89
+ // Initial candidate from hash
90
+ let offset = Number(hash % range),
91
+ codePoint = start + offset,
92
+ collision = false;
93
+
94
+ const used = new Set(registry.values());
95
+
96
+ // Linear probing to resolve collisions
97
+ while (used.has(codePoint)) {
98
+ collision = true;
99
+ offset = (offset + 1) % Number(range);
100
+ codePoint = start + offset;
101
+ }
102
+
103
+ // Commit allocation
104
+ registry.set(name, codePoint);
105
+
106
+ return formatResult(name, codePoint, hashHex, collision);
107
+ };
108
+
109
+
110
+ export default stringToEncodings;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @since Last modified: 2026/02/05 17:06:59
3
+ * Parses a Unicode input (string or number) and converts it into
4
+ * multiple encoding formats including Unicode notation, HTML entities,
5
+ * hexadecimal code, and decimal code point.
6
+ *
7
+ * Supported input formats:
8
+ * - Unicode string: "U+F123"
9
+ * - Hex string: "F123", "0xF123"
10
+ * - Decimal string: "61731"
11
+ * - Numeric code point: 61731
12
+ *
13
+ * This utility is useful for:
14
+ * - Icon font Unicode decoding
15
+ * - HTML entity generation
16
+ * - Unicode debugging and inspection
17
+ * - Glyph mapping and font tooling
18
+ * - PUA (Private Use Area) management workflows
19
+ *
20
+ * @param input - Unicode input as a string or numeric code point
21
+ * @returns An object containing Unicode, hex, decimal, and HTML encodings
22
+ * @throws Error if the input cannot be parsed into a valid Unicode code point
23
+ */
24
+ const unicodeToEncodings = (input) => {
25
+ let codePoint;
26
+ if (typeof input === "number") {
27
+ codePoint = input;
28
+ }
29
+ else {
30
+ const cleaned = input.trim()
31
+ .replace(/^U\+/i, "")
32
+ .replace(/^0x/i, "");
33
+ codePoint = /^[0-9A-F]+$/i.test(cleaned)
34
+ ? parseInt(cleaned, 16)
35
+ : parseInt(cleaned, 10);
36
+ }
37
+ // Validate parsed code point
38
+ if (!Number.isFinite(codePoint)) {
39
+ throw new Error("Invalid Unicode input");
40
+ }
41
+ // Convert code point to uppercase hexadecimal representation
42
+ const hex = codePoint.toString(16).toUpperCase();
43
+ return {
44
+ unicode: `U+${hex}`,
45
+ hex,
46
+ codePoint,
47
+ htmlDec: `&#${codePoint};`,
48
+ htmlHex: `&#x${hex};`,
49
+ };
50
+ };
51
+ export default unicodeToEncodings;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @since Last modified: 2026/02/05 17:06:59
3
+ * Parses a Unicode input (string or number) and converts it into
4
+ * multiple encoding formats including Unicode notation, HTML entities,
5
+ * hexadecimal code, and decimal code point.
6
+ *
7
+ * Supported input formats:
8
+ * - Unicode string: "U+F123"
9
+ * - Hex string: "F123", "0xF123"
10
+ * - Decimal string: "61731"
11
+ * - Numeric code point: 61731
12
+ *
13
+ * This utility is useful for:
14
+ * - Icon font Unicode decoding
15
+ * - HTML entity generation
16
+ * - Unicode debugging and inspection
17
+ * - Glyph mapping and font tooling
18
+ * - PUA (Private Use Area) management workflows
19
+ *
20
+ * @param input - Unicode input as a string or numeric code point
21
+ * @returns An object containing Unicode, hex, decimal, and HTML encodings
22
+ * @throws Error if the input cannot be parsed into a valid Unicode code point
23
+ */
24
+ const unicodeToEncodings = (input: string | number) => {
25
+ let codePoint: number;
26
+
27
+ if (typeof input === "number") {
28
+ codePoint = input;
29
+ } else {
30
+ const cleaned = input.trim()
31
+ .replace(/^U\+/i, "")
32
+ .replace(/^0x/i, "");
33
+
34
+ codePoint = /^[0-9A-F]+$/i.test(cleaned)
35
+ ? parseInt(cleaned, 16)
36
+ : parseInt(cleaned, 10);
37
+ }
38
+
39
+ // Validate parsed code point
40
+ if (!Number.isFinite(codePoint)) {
41
+ throw new Error("Invalid Unicode input");
42
+ }
43
+
44
+ // Convert code point to uppercase hexadecimal representation
45
+ const hex = codePoint.toString(16).toUpperCase();
46
+
47
+ return {
48
+ unicode: `U+${hex}`,
49
+ hex,
50
+ codePoint,
51
+ htmlDec: `&#${codePoint};`,
52
+ htmlHex: `&#x${hex};`,
53
+ };
54
+ };
55
+ export default unicodeToEncodings;
@@ -1,5 +0,0 @@
1
- const arrayMutableMethods = [
2
- 'push', 'pop', 'shift', 'unshift', 'splice',
3
- 'sort', 'reverse', 'copyWithin', 'fill'
4
- ];
5
- export default arrayMutableMethods;
@@ -1,19 +0,0 @@
1
- /**
2
- * @since Last modified: 2026/01/20 11:52:35
3
- * Capitalizes the first letter of the given string.
4
- *
5
- * This function takes a string as input and returns a new string with the first letter
6
- * capitalized, while leaving the rest of the string unchanged. If the input string is
7
- * empty or undefined, it returns the input string as is.
8
- *
9
- * @param str - The string whose first letter will be capitalized.
10
- * @returns A new string with the first letter capitalized, or the input string if it's empty.
11
- */
12
- const capitalize = (str) => {
13
- // Check if the input string is empty or undefined
14
- if (!str)
15
- return str;
16
- // Capitalize the first letter and return the new string
17
- return str.charAt(0).toUpperCase() + str.slice(1);
18
- };
19
- export default capitalize;
@@ -1,2 +0,0 @@
1
- const COMMA = ',';
2
- export default COMMA;
@@ -1,47 +0,0 @@
1
- /**
2
- * @since Last modified: 2025/12/16 14:43:51
3
- * Deep clone an array or object to a JSON-compatible structure.
4
- * Converts non-serializable types like functions, symbols, Date, RegExp to plain values.
5
- *
6
- * @template T
7
- * @param {T} data - Array or object to clone
8
- * @returns {T} - New object with different memory address, in a JSON-compatible structure
9
- *
10
- * @example
11
- * const obj = { a: '', b: 0, c: [] };
12
- * const cloned = deepCloneToJSON(obj);
13
- *
14
- * @example
15
- * const arr = [{}, {}, {}];
16
- * const cloned = deepCloneToJSON(arr);
17
- */
18
- 'use strict';
19
- import getDataType from './getDataType';
20
- const deepCloneToJSON = (data) => {
21
- const dataType = getDataType(data);
22
- // Handle objects
23
- if (dataType === 'Object') {
24
- const newObj = {};
25
- // Clone regular properties
26
- for (const key in data) {
27
- newObj[key] = deepCloneToJSON(data[key]);
28
- }
29
- for (const key in newObj) {
30
- newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
31
- }
32
- return newObj;
33
- // Handle arrays
34
- }
35
- else if (dataType === 'Array') {
36
- let tmp = data.map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
37
- return tmp;
38
- // Handle Date objects
39
- }
40
- else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
41
- return undefined;
42
- }
43
- else {
44
- return data;
45
- }
46
- };
47
- export default deepCloneToJSON;