nhb-toolbox 4.28.1 → 4.28.4
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/CHANGELOG.md +8 -0
- package/dist/cjs/array/basics.js +1 -1
- package/dist/cjs/hash/core.js +2 -2
- package/dist/cjs/object/basics.js +16 -8
- package/dist/cjs/object/convert.js +7 -11
- package/dist/cjs/utils/index.js +4 -1
- package/dist/dts/hash/core.d.ts +3 -3
- package/dist/dts/hash/uuid.d.ts +1 -1
- package/dist/dts/object/basics.d.ts +40 -3
- package/dist/dts/utils/index.d.ts +7 -5
- package/dist/esm/array/basics.js +1 -1
- package/dist/esm/hash/core.js +2 -2
- package/dist/esm/object/basics.js +14 -5
- package/dist/esm/object/convert.js +7 -11
- package/dist/esm/utils/index.js +4 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ All notable changes to the package will be documented here.
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [4.28.4] - 2025-12-02
|
|
10
|
+
|
|
11
|
+
- **Updated** *implementation* and *tsdoc* for:
|
|
12
|
+
- `cloneObject`: used `structuredClone` and `stableStringify` (optionally force to use *deterministic serialization*) internally and falls back to *shallow cloning* if serialization fails.
|
|
13
|
+
- `stableStringify`: stringified value of *Date-like objects* (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) is converted to string representation (in the same way that `JSON.stringify` would serialize them).
|
|
14
|
+
- **Updated** `convertObjectValues` behaviour: *fields* configured for *number conversion* now return `NaN` when *parsing fails*.
|
|
15
|
+
- **Updated** *reference links* in *tsdoc* of some *hash* utilities.
|
|
16
|
+
|
|
9
17
|
## [4.28.1] - 2025-12-02
|
|
10
18
|
|
|
11
19
|
- **Updated** *type* names `TokenHeader` to `SignetHeader` and `TokenPayload` to `SignetPayload` and both are available to import.
|
package/dist/cjs/array/basics.js
CHANGED
|
@@ -34,7 +34,7 @@ exports.isInvalidOrEmptyArray = isInvalidOrEmptyArray;
|
|
|
34
34
|
const shuffleArray = (array) => {
|
|
35
35
|
if ((0, exports.isInvalidOrEmptyArray)(array))
|
|
36
36
|
return array;
|
|
37
|
-
const shuffled =
|
|
37
|
+
const shuffled = [...array];
|
|
38
38
|
for (let i = shuffled?.length - 1; i > 0; i--) {
|
|
39
39
|
const j = Math.floor(Math.random() * (i + 1));
|
|
40
40
|
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
package/dist/cjs/hash/core.js
CHANGED
|
@@ -15,9 +15,9 @@ function md5(str) {
|
|
|
15
15
|
const $str = str.substring(i - 64);
|
|
16
16
|
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
17
17
|
for (i = 0; i < $str.length; i++) {
|
|
18
|
-
tail[i >> 2] |= $str.charCodeAt(i) << (i % 4 << 3);
|
|
18
|
+
tail[i >> 2] |= $str.charCodeAt(i) << ((i % 4) << 3);
|
|
19
19
|
}
|
|
20
|
-
tail[i >> 2] |= 0x80 << (i % 4 << 3);
|
|
20
|
+
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
|
21
21
|
if (i > 55) {
|
|
22
22
|
(0, helpers_1._md5cycle)(state, tail);
|
|
23
23
|
for (let j = 0; j < 16; j++) {
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.cloneObject = cloneObject;
|
|
4
|
+
exports.countObjectFields = countObjectFields;
|
|
4
5
|
exports.extractObjectKeys = extractObjectKeys;
|
|
5
6
|
exports.extractObjectKeysDeep = extractObjectKeysDeep;
|
|
6
7
|
const non_primitives_1 = require("../guards/non-primitives");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const index_1 = require("../utils/index");
|
|
9
|
+
function cloneObject(obj, serialize = false) {
|
|
10
|
+
try {
|
|
11
|
+
if (!serialize && typeof structuredClone === 'function') {
|
|
12
|
+
return structuredClone(obj);
|
|
13
|
+
}
|
|
14
|
+
return JSON.parse((0, index_1.stableStringify)(obj));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return { ...obj };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function countObjectFields(obj) {
|
|
12
21
|
if (obj != null)
|
|
13
22
|
return Object.keys(obj)?.length;
|
|
14
23
|
return 0;
|
|
15
|
-
}
|
|
16
|
-
exports.countObjectFields = countObjectFields;
|
|
24
|
+
}
|
|
17
25
|
function extractObjectKeys(obj, tuple) {
|
|
18
26
|
const keys = (0, non_primitives_1.isNotEmptyObject)(obj) ? Object.keys(obj) : [];
|
|
19
27
|
return tuple ? keys : keys;
|
|
@@ -5,29 +5,25 @@ exports.pickFields = pickFields;
|
|
|
5
5
|
exports.deleteFields = deleteFields;
|
|
6
6
|
exports.pickObjectFieldsByCondition = pickObjectFieldsByCondition;
|
|
7
7
|
exports.remapFields = remapFields;
|
|
8
|
+
const non_primitives_1 = require("../guards/non-primitives");
|
|
9
|
+
const primitives_1 = require("../guards/primitives");
|
|
8
10
|
function convertObjectValues(data, options) {
|
|
9
|
-
const { keys, convertTo } = options;
|
|
10
|
-
const _shouldPreserveValue = (value) => convertTo === 'number' && (typeof value !== 'string' || isNaN(Number(value)));
|
|
11
|
+
const { keys, convertTo } = options || {};
|
|
11
12
|
const _setValueAtPath = (obj, path, convertTo) => {
|
|
12
13
|
const segments = path.split('.');
|
|
13
14
|
let current = obj;
|
|
14
15
|
segments?.forEach((key, index) => {
|
|
15
16
|
if (index === segments?.length - 1) {
|
|
16
17
|
const value = current?.[key];
|
|
17
|
-
if (
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (convertTo === 'string' && typeof value !== 'string') {
|
|
18
|
+
if (convertTo === 'string' && !(0, primitives_1.isString)(value)) {
|
|
21
19
|
current[key] = String(value);
|
|
22
20
|
}
|
|
23
|
-
else if (convertTo === 'number' &&
|
|
24
|
-
typeof value !== 'number' &&
|
|
25
|
-
!isNaN(Number(value))) {
|
|
21
|
+
else if (convertTo === 'number' && !(0, primitives_1.isNumber)(value)) {
|
|
26
22
|
current[key] = Number(value);
|
|
27
23
|
}
|
|
28
24
|
}
|
|
29
25
|
else {
|
|
30
|
-
if (
|
|
26
|
+
if ((0, non_primitives_1.isObject)(current?.[key])) {
|
|
31
27
|
current = current?.[key];
|
|
32
28
|
}
|
|
33
29
|
else {
|
|
@@ -39,7 +35,7 @@ function convertObjectValues(data, options) {
|
|
|
39
35
|
return obj;
|
|
40
36
|
};
|
|
41
37
|
const _convertValue = (obj) => {
|
|
42
|
-
let newObj =
|
|
38
|
+
let newObj = { ...obj };
|
|
43
39
|
keys?.forEach((key) => {
|
|
44
40
|
newObj = _setValueAtPath(newObj, key, convertTo);
|
|
45
41
|
});
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -17,6 +17,7 @@ exports.deepParsePrimitives = deepParsePrimitives;
|
|
|
17
17
|
exports.definePrototypeMethod = definePrototypeMethod;
|
|
18
18
|
const helpers_1 = require("../array/helpers");
|
|
19
19
|
const sort_1 = require("../array/sort");
|
|
20
|
+
const guards_1 = require("../date/guards");
|
|
20
21
|
const non_primitives_1 = require("../guards/non-primitives");
|
|
21
22
|
const primitives_1 = require("../guards/primitives");
|
|
22
23
|
const specials_1 = require("../guards/specials");
|
|
@@ -137,7 +138,9 @@ function stableStringify(obj) {
|
|
|
137
138
|
const keys = Object.keys(obj).sort();
|
|
138
139
|
return ('{' +
|
|
139
140
|
keys
|
|
140
|
-
.map((k) => JSON.stringify(k, _replacer) +
|
|
141
|
+
.map((k) => JSON.stringify(k, _replacer) +
|
|
142
|
+
':' +
|
|
143
|
+
((0, guards_1.isDateLike)(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k])))
|
|
141
144
|
.join(',') +
|
|
142
145
|
'}');
|
|
143
146
|
}
|
package/dist/dts/hash/core.d.ts
CHANGED
|
@@ -59,8 +59,8 @@ export declare function sha1(msg: string): string;
|
|
|
59
59
|
* // Returns: '7037e204b825b83553ba336a6ec35b796d505599286ae864729ed6cb33ae9fe1'
|
|
60
60
|
* ```
|
|
61
61
|
*
|
|
62
|
-
* @see {@link sha256Bytes} for hashing raw bytes
|
|
63
|
-
* @see {@link utf8ToBytes} for converting string to
|
|
64
|
-
* @see {@link bytesToHex} for converting bytes to a hexadecimal string
|
|
62
|
+
* @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/sha256Bytes sha256Bytes} for hashing raw bytes
|
|
63
|
+
* @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/encoding#utf8tobytes utf8ToBytes} for converting string to bytes
|
|
64
|
+
* @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/encoding#bytestotex bytesToHex} for converting bytes to a hexadecimal string
|
|
65
65
|
*/
|
|
66
66
|
export declare function sha256(msg: string): string;
|
package/dist/dts/hash/uuid.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ import type { DecodedUUID, SupportedVersion, UUID, UUIDOptions } from './types';
|
|
|
43
43
|
* - `v7`: Millisecond precision; extremely high throughput may still cause rare collisions.
|
|
44
44
|
* - `v8`: Uses a simple timestamp + randomness layout; custom layouts are not supported here.
|
|
45
45
|
*
|
|
46
|
-
* - Use {@link https://toolbox.nazmul-nhb.dev/docs/utilities/string/generateRandomID generateRandomID} for customized id generation or {@link randomHex} for hex-only string with custom length.
|
|
46
|
+
* - Use {@link https://toolbox.nazmul-nhb.dev/docs/utilities/string/generateRandomID generateRandomID} for customized id generation or {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/randomHex randomHex} for hex-only random string with custom length.
|
|
47
47
|
*/
|
|
48
48
|
export declare function uuid<V extends SupportedVersion = 'v4'>(options?: UUIDOptions<V>): UUID<V>;
|
|
49
49
|
/**
|
|
@@ -1,19 +1,56 @@
|
|
|
1
1
|
import type { Tuple } from '../utils/types';
|
|
2
2
|
import type { DeepKeys, GenericObject } from './types';
|
|
3
3
|
/**
|
|
4
|
-
* * Deep clone an object
|
|
4
|
+
* * Deep clone an object using `structuredClone` or deterministic *JSON serialization*.
|
|
5
5
|
*
|
|
6
6
|
* @param obj Object to clone.
|
|
7
|
+
* @param serialize Whether to force deterministic JSON serialization instead of using `structuredClone`. Defaults to `false`.
|
|
7
8
|
* @returns Deep cloned object.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* **Primary behavior**
|
|
12
|
+
* - By default (`serialize = false`), the function uses {@link https://developer.mozilla.org/docs/Web/API/Window/structuredClone structuredClone} when available. This supports:
|
|
13
|
+
* - Circular references
|
|
14
|
+
* - `Date` objects
|
|
15
|
+
* - `Map` / `Set`
|
|
16
|
+
* - `RegExp`
|
|
17
|
+
* - Typed arrays
|
|
18
|
+
* - Most built-in JavaScript types
|
|
19
|
+
* - Preserves `undefined` values
|
|
20
|
+
*
|
|
21
|
+
* - **Note:** `structuredClone` **does not preserve class prototypes**, even though it preserves data types like `Date`, `Map`, and `Set`.
|
|
22
|
+
*
|
|
23
|
+
* **Deterministic serialization mode**
|
|
24
|
+
* - When `serialize = true`, or when `structuredClone` is unavailable, the function falls back to **stable JSON serialization** via `stableStringify`. This guarantees:
|
|
25
|
+
* - All object keys are sorted alphabetically.
|
|
26
|
+
* - Consistent output across environments (deterministic).
|
|
27
|
+
* - All `undefined` values are converted to `null`.
|
|
28
|
+
* - Converting date-like objects (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) **in the same way that {@link JSON.stringify} would serialize them**, ensuring predictable and JSON-compliant output.
|
|
29
|
+
*
|
|
30
|
+
* - This mode is ideal for:
|
|
31
|
+
* - Hashing
|
|
32
|
+
* - Signature generation
|
|
33
|
+
* - Deep equality checks
|
|
34
|
+
* - Anything requiring deterministic, environment-neutral output
|
|
35
|
+
*
|
|
36
|
+
* **Deterministic mode limitations**
|
|
37
|
+
* - JSON serialization will:
|
|
38
|
+
* - Drop functions and `Symbol` values.
|
|
39
|
+
* - Lose prototype and class instance information.
|
|
40
|
+
* - Convert all date-like objects into strings.
|
|
41
|
+
* - Fail on circular references.
|
|
42
|
+
*
|
|
43
|
+
* **Final safety fallback**
|
|
44
|
+
* - If JSON serialization fails (e.g., due to circular references), the function returns a **shallow clone** (`{ ...obj }`) to ensure the cloning never throws.
|
|
8
45
|
*/
|
|
9
|
-
export declare
|
|
46
|
+
export declare function cloneObject<T extends GenericObject>(obj: T, serialize?: boolean): T;
|
|
10
47
|
/**
|
|
11
48
|
* * Count the number of fields in an object.
|
|
12
49
|
*
|
|
13
50
|
* @param obj Object to check.
|
|
14
51
|
* @returns Number of fields in the object.
|
|
15
52
|
*/
|
|
16
|
-
export declare
|
|
53
|
+
export declare function countObjectFields<T extends GenericObject>(obj: T): number;
|
|
17
54
|
/**
|
|
18
55
|
* * Extracts all the top-level keys of an object as an array.
|
|
19
56
|
*
|
|
@@ -129,14 +129,16 @@ export declare function getClassDetails(cls: Constructor): ClassDetails;
|
|
|
129
129
|
* - This function guarantees **stable, repeatable output** by:
|
|
130
130
|
* - Sorting all object keys alphabetically.
|
|
131
131
|
* - Recursively stabilizing nested objects and arrays.
|
|
132
|
-
* -
|
|
132
|
+
* - Converting all `undefined` values into `null` so the output remains valid JSON.
|
|
133
|
+
* - Converting date-like objects (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) **in the same way that {@link JSON.stringify} would serialize them**, ensuring predictable and JSON-compliant output.
|
|
133
134
|
* - Falling back to native JSON serialization for primitives.
|
|
134
|
-
*
|
|
135
|
+
*
|
|
136
|
+
* - **Useful for:**
|
|
135
137
|
* - Hash generation (e.g., signatures, cache keys)
|
|
136
138
|
* - Deep equality checks
|
|
137
139
|
* - Producing predictable output across environments
|
|
138
140
|
*
|
|
139
|
-
* @param obj - The value to stringify into a deterministic JSON
|
|
141
|
+
* @param obj - The value to stringify into a deterministic JSON string.
|
|
140
142
|
* @returns A stable, deterministic string representation of the input.
|
|
141
143
|
*/
|
|
142
144
|
export declare function stableStringify(obj: unknown): string;
|
|
@@ -155,12 +157,12 @@ export declare function stripJsonEdgeGarbage(str: string): string;
|
|
|
155
157
|
* @returns The parsed JSON value typed as `T`, or the original parsed value with optional primitive conversion.
|
|
156
158
|
* - Returns `{}` if parsing fails, such as when the input is malformed or invalid JSON or passing single quoted string.
|
|
157
159
|
*
|
|
158
|
-
* - *Unlike
|
|
160
|
+
* - *Unlike {@link https://toolbox.nazmul-nhb.dev/docs/utilities/object/parseJsonToObject parseJsonToObject}, which ensures the root value is an object,
|
|
159
161
|
* this function returns any valid JSON structure such as arrays, strings, numbers, or objects.*
|
|
160
162
|
*
|
|
161
163
|
* This is useful when you're not sure of the root structure of the JSON, or when you expect something other than an object.
|
|
162
164
|
*
|
|
163
|
-
* @see
|
|
165
|
+
* @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/object/parseJsonToObject parseJsonToObject} for strict object-only parsing.
|
|
164
166
|
*/
|
|
165
167
|
export declare const parseJSON: <T = unknown>(value: string, parsePrimitives?: boolean) => T;
|
|
166
168
|
/**
|
package/dist/esm/array/basics.js
CHANGED
|
@@ -28,7 +28,7 @@ export const isInvalidOrEmptyArray = (value) => {
|
|
|
28
28
|
export const shuffleArray = (array) => {
|
|
29
29
|
if (isInvalidOrEmptyArray(array))
|
|
30
30
|
return array;
|
|
31
|
-
const shuffled =
|
|
31
|
+
const shuffled = [...array];
|
|
32
32
|
for (let i = shuffled?.length - 1; i > 0; i--) {
|
|
33
33
|
const j = Math.floor(Math.random() * (i + 1));
|
|
34
34
|
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
package/dist/esm/hash/core.js
CHANGED
|
@@ -10,9 +10,9 @@ export function md5(str) {
|
|
|
10
10
|
const $str = str.substring(i - 64);
|
|
11
11
|
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
12
12
|
for (i = 0; i < $str.length; i++) {
|
|
13
|
-
tail[i >> 2] |= $str.charCodeAt(i) << (i % 4 << 3);
|
|
13
|
+
tail[i >> 2] |= $str.charCodeAt(i) << ((i % 4) << 3);
|
|
14
14
|
}
|
|
15
|
-
tail[i >> 2] |= 0x80 << (i % 4 << 3);
|
|
15
|
+
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
|
16
16
|
if (i > 55) {
|
|
17
17
|
_md5cycle(state, tail);
|
|
18
18
|
for (let j = 0; j < 16; j++) {
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { isNotEmptyObject } from '../guards/non-primitives.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { stableStringify } from '../utils/index.js';
|
|
3
|
+
export function cloneObject(obj, serialize = false) {
|
|
4
|
+
try {
|
|
5
|
+
if (!serialize && typeof structuredClone === 'function') {
|
|
6
|
+
return structuredClone(obj);
|
|
7
|
+
}
|
|
8
|
+
return JSON.parse(stableStringify(obj));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return { ...obj };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function countObjectFields(obj) {
|
|
6
15
|
if (obj != null)
|
|
7
16
|
return Object.keys(obj)?.length;
|
|
8
17
|
return 0;
|
|
9
|
-
}
|
|
18
|
+
}
|
|
10
19
|
export function extractObjectKeys(obj, tuple) {
|
|
11
20
|
const keys = isNotEmptyObject(obj) ? Object.keys(obj) : [];
|
|
12
21
|
return tuple ? keys : keys;
|
|
@@ -1,26 +1,22 @@
|
|
|
1
|
+
import { isObject } from '../guards/non-primitives.js';
|
|
2
|
+
import { isNumber, isString } from '../guards/primitives.js';
|
|
1
3
|
export function convertObjectValues(data, options) {
|
|
2
|
-
const { keys, convertTo } = options;
|
|
3
|
-
const _shouldPreserveValue = (value) => convertTo === 'number' && (typeof value !== 'string' || isNaN(Number(value)));
|
|
4
|
+
const { keys, convertTo } = options || {};
|
|
4
5
|
const _setValueAtPath = (obj, path, convertTo) => {
|
|
5
6
|
const segments = path.split('.');
|
|
6
7
|
let current = obj;
|
|
7
8
|
segments?.forEach((key, index) => {
|
|
8
9
|
if (index === segments?.length - 1) {
|
|
9
10
|
const value = current?.[key];
|
|
10
|
-
if (
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
if (convertTo === 'string' && typeof value !== 'string') {
|
|
11
|
+
if (convertTo === 'string' && !isString(value)) {
|
|
14
12
|
current[key] = String(value);
|
|
15
13
|
}
|
|
16
|
-
else if (convertTo === 'number' &&
|
|
17
|
-
typeof value !== 'number' &&
|
|
18
|
-
!isNaN(Number(value))) {
|
|
14
|
+
else if (convertTo === 'number' && !isNumber(value)) {
|
|
19
15
|
current[key] = Number(value);
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
else {
|
|
23
|
-
if (
|
|
19
|
+
if (isObject(current?.[key])) {
|
|
24
20
|
current = current?.[key];
|
|
25
21
|
}
|
|
26
22
|
else {
|
|
@@ -32,7 +28,7 @@ export function convertObjectValues(data, options) {
|
|
|
32
28
|
return obj;
|
|
33
29
|
};
|
|
34
30
|
const _convertValue = (obj) => {
|
|
35
|
-
let newObj =
|
|
31
|
+
let newObj = { ...obj };
|
|
36
32
|
keys?.forEach((key) => {
|
|
37
33
|
newObj = _setValueAtPath(newObj, key, convertTo);
|
|
38
34
|
});
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { _resolveNestedKey } from '../array/helpers.js';
|
|
2
2
|
import { sortAnArray } from '../array/sort.js';
|
|
3
|
+
import { isDateLike } from '../date/guards.js';
|
|
3
4
|
import { isArray, isArrayOfType, isMethodDescriptor, isNotEmptyObject, isObject, isValidArray, } from '../guards/non-primitives.js';
|
|
4
5
|
import { isNonEmptyString, isPrimitive, isString } from '../guards/primitives.js';
|
|
5
6
|
import { isNumericString } from '../guards/specials.js';
|
|
@@ -119,7 +120,9 @@ export function stableStringify(obj) {
|
|
|
119
120
|
const keys = Object.keys(obj).sort();
|
|
120
121
|
return ('{' +
|
|
121
122
|
keys
|
|
122
|
-
.map((k) => JSON.stringify(k, _replacer) +
|
|
123
|
+
.map((k) => JSON.stringify(k, _replacer) +
|
|
124
|
+
':' +
|
|
125
|
+
(isDateLike(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k])))
|
|
123
126
|
.join(',') +
|
|
124
127
|
'}');
|
|
125
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nhb-toolbox",
|
|
3
|
-
"version": "4.28.
|
|
3
|
+
"version": "4.28.4",
|
|
4
4
|
"description": "A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|