@art-suite/art-core-ts-compare 0.0.2 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.cjs +27 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +27 -9
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -114,13 +114,16 @@ Compared element by element:
|
|
|
114
114
|
- If both objects have the key, their values are compared recursively.
|
|
115
115
|
- If all keys and values are equal, objects are equal.
|
|
116
116
|
|
|
117
|
+
**Key Comparison Process**: When objects have different keys, the keys are converted to an array of strings, sorted lexicographically, and then compared as arrays. This ensures consistent ordering regardless of the original key order in the objects.
|
|
118
|
+
|
|
117
119
|
**Examples:**
|
|
118
120
|
|
|
119
121
|
- `{a: 1}` vs `{a: 1, b: 2}` → first is less (missing `b`)
|
|
120
122
|
- `{a: 1, b: 0}` vs `{a: 1}` → second is less (missing `b`)
|
|
121
123
|
- `{}` vs `{a: undefined}` → first is less (missing `a`)
|
|
122
124
|
- `{a: null}` vs `{}` → second is less (missing `a`)
|
|
123
|
-
- `{x: 1}` vs `{y: 1}` → `
|
|
125
|
+
- `{x: 1}` vs `{y: 1}` → `[x]` < `[y]`, so `compare({x: 1}, {y: 1})` returns `-1`
|
|
126
|
+
- `{y: 1}` vs `{x: 1}` → `[y]` > `[x]`, so `compare({y: 1}, {x: 1})` returns `1`
|
|
124
127
|
|
|
125
128
|
#### Incompatible Comparisons
|
|
126
129
|
|
package/dist/index.cjs
CHANGED
|
@@ -41,16 +41,33 @@ var compareArrays = (a, b) => {
|
|
|
41
41
|
return a.length - b.length;
|
|
42
42
|
};
|
|
43
43
|
var comparePlainObjects = (a, b) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
let differentKeys = false;
|
|
45
|
+
let leastDifferentKey;
|
|
46
|
+
let leastDifferentKeyResult = 0;
|
|
47
|
+
for (const key in a) {
|
|
48
|
+
if (!(key in b)) differentKeys = true;
|
|
49
|
+
else {
|
|
50
|
+
const result = compare(a[key], b[key]);
|
|
51
|
+
if (result !== 0) {
|
|
52
|
+
if (!leastDifferentKey || leastDifferentKey > key) {
|
|
53
|
+
leastDifferentKey = key;
|
|
54
|
+
leastDifferentKeyResult = result;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!differentKeys) {
|
|
60
|
+
for (const key in b) {
|
|
61
|
+
if (!(key in a)) {
|
|
62
|
+
differentKeys = true;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (differentKeys) {
|
|
68
|
+
return compareArrays(Object.keys(a), Object.keys(b));
|
|
52
69
|
}
|
|
53
|
-
return
|
|
70
|
+
return leastDifferentKeyResult;
|
|
54
71
|
};
|
|
55
72
|
var compareCustomComparableHelper = (a, b) => {
|
|
56
73
|
if (a !== null && a !== void 0 && typeof a === "object") {
|
|
@@ -91,6 +108,7 @@ var comparePrimitives = (a, b) => {
|
|
|
91
108
|
return NaN;
|
|
92
109
|
};
|
|
93
110
|
var compare = (a, b) => {
|
|
111
|
+
if (a === b) return 0;
|
|
94
112
|
const customResult = compareCustomComparable(a, b);
|
|
95
113
|
if (!Number.isNaN(customResult)) return customResult;
|
|
96
114
|
if ((0, import_art_core_ts_types.isArray)(a) && (0, import_art_core_ts_types.isArray)(b)) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/compare.ts","../src/equality.ts"],"sourcesContent":["export * from './compare'\nexport * from './equality'","import { isArray, isPlainObject, isFunction } from '@art-suite/art-core-ts-types'\n\nexport interface CustomComparableInterface {\n\n /**\n * Compares `this` with `b`\n * @param b - The value to compare `this` with\n * @returns A number greater than zero if `this` is greater than `b`, less than zero if `this` is less than `b`, and zero if `this` is equal to `b`\n */\n compare(b: any): number\n}\n\nexport interface CustomEqualityInterface {\n /**\n * Checks if `this` equals `b`\n * @param b - The value to compare `this` with\n * @returns true if equal, false otherwise\n */\n eq(b: any): boolean\n}\n\nexport interface CustomInequalityInterface extends CustomEqualityInterface {\n /**\n * Checks if `this` is not equal to `b`\n * @param b - The value to compare `this` with\n * @returns true if not equal, false otherwise\n */\n lt(b: any): boolean\n gt(b: any): boolean\n lte(b: any): boolean\n gte(b: any): boolean\n}\n\nconst compareArrays = (a: any[], b: any[]): number => {\n const minLength = Math.min(a.length, b.length)\n\n for (let i = 0; i < minLength; i++) {\n const result = compare(a[i], b[i])\n if (result !== 0) return result\n }\n\n return a.length - b.length\n}\n\nconst comparePlainObjects = (a: Record<string, any>, b: Record<string, any>): number => {\n // Create a merged list of all unique keys and sort it\n const allKeys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort()\n\n // Iterate through the sorted keys to find the first non-zero comparison result\n for (const key of allKeys) {\n const aHas = key in a\n const bHas = key in b\n if (!aHas && bHas) return -1 // a is missing the key, so a is less\n if (aHas && !bHas) return 1 // b is missing the key, so b is less\n // Both have the key, compare their values\n const result = compare(a[key], b[key])\n if (result !== 0) return result\n }\n\n return 0 // All keys and values are equal\n}\n\nconst compareCustomComparableHelper = (a: any, b: any): number => {\n // Only check for custom methods if a is not null/undefined and is an object\n if (a !== null && a !== undefined && typeof a === 'object') {\n // Check if left operand supports any of the custom methods (highest priority)\n if (isFunction(a.compare)) return a.compare(b);\n if (isFunction(a.eq) && a?.eq(b)) return 0;\n if (isFunction(a.lt) && a?.lt(b)) return -1;\n if (isFunction(a.gt) && a?.gt(b)) return 1;\n if (isFunction(a.lte) && a?.lte(b)) return -1;\n if (isFunction(a.gte) && a?.gte(b)) return 1;\n }\n return NaN\n}\n\nconst compareCustomComparable = (a: any, b: any): number => {\n const customResult = compareCustomComparableHelper(a, b)\n if (!Number.isNaN(customResult)) return customResult\n return -compareCustomComparableHelper(b, a)\n}\n\nconst comparePrimitives = (a: any, b: any): number => {\n // Handle null\n if (a === null && b === null) return 0\n if (a === null) return -1\n if (b === null) return 1\n\n // Handle undefined\n if (a === undefined && b === undefined) return 0\n if (a === undefined) return 1\n if (b === undefined) return -1\n\n // Handle NaN\n if (Number.isNaN(a) && Number.isNaN(b)) return 0\n if (Number.isNaN(a)) return -1\n if (Number.isNaN(b)) return 1\n\n // Handle numbers - use subtraction for efficiency\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b\n }\n\n // Handle strings - use localeCompare for proper string comparison\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b)\n }\n\n // Handle booleans - convert to numbers for comparison\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b)\n }\n\n // Return NaN for different types or incompatible comparisons\n if (typeof a !== typeof b) return NaN\n\n // For same types that aren't numbers, strings, or booleans, return NaN\n return NaN\n}\n\n/**\n * deep structural comparison\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns A number indicating the comparison result:\n * - **< 0**: `a` is less than `b`\n * - **== 0**: `a` is equal to `b` (deep structural equality)\n * - **> 0**: `a` is greater than `b`\n * - **NaN**: Values cannot be compared (incompatible types or custom comparison failed)\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const compare = (a: any, b: any): number => {\n // Handle custom comparables first\n const customResult = compareCustomComparable(a, b)\n if (!Number.isNaN(customResult)) return customResult\n\n // Handle arrays\n if (isArray(a) && isArray(b)) {\n return compareArrays(a, b)\n }\n\n // Handle plain objects\n if (isPlainObject(a) && isPlainObject(b)) {\n return comparePlainObjects(a, b)\n }\n\n // Handle primitives\n return comparePrimitives(a, b)\n}","import { compare } from './compare'\n\n/**\n * deep structural == test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are deeply equal (compare returns 0), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const eq = (a: any, b: any): boolean => compare(a, b) === 0;\n\n/**\n * deep structural != test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are not deeply equal (compare returns non-zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const neq = (a: any, b: any): boolean => compare(a, b) !== 0;\n\n/**\n * deep structural < test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than `b` (compare returns negative), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lt = (a: any, b: any): boolean => compare(a, b) < 0;\n\n/**\n * deep structural > test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than `b` (compare returns positive), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gt = (a: any, b: any): boolean => compare(a, b) > 0;\n\n/**\n * deep structural <= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than or equal to `b` (compare returns negative or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lte = (a: any, b: any): boolean => compare(a, b) <= 0;\n\n/**\n * deep structural >= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than or equal to `b` (compare returns positive or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gte = (a: any, b: any): boolean => compare(a, b) >= 0;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/compare.ts","../src/equality.ts"],"sourcesContent":["export * from './compare'\nexport * from './equality'","import { isArray, isPlainObject, isFunction } from '@art-suite/art-core-ts-types'\nimport { objectKeyCount } from '@art-suite/art-core-ts-containers'\n\nexport interface CustomComparableInterface {\n\n /**\n * Compares `this` with `b`\n * @param b - The value to compare `this` with\n * @returns A number greater than zero if `this` is greater than `b`, less than zero if `this` is less than `b`, and zero if `this` is equal to `b`\n */\n compare(b: any): number\n}\n\nexport interface CustomEqualityInterface {\n /**\n * Checks if `this` equals `b`\n * @param b - The value to compare `this` with\n * @returns true if equal, false otherwise\n */\n eq(b: any): boolean\n}\n\nexport interface CustomInequalityInterface extends CustomEqualityInterface {\n /**\n * Checks if `this` is not equal to `b`\n * @param b - The value to compare `this` with\n * @returns true if not equal, false otherwise\n */\n lt(b: any): boolean\n gt(b: any): boolean\n lte(b: any): boolean\n gte(b: any): boolean\n}\n\nconst compareArrays = (a: any[], b: any[]): number => {\n const minLength = Math.min(a.length, b.length)\n\n for (let i = 0; i < minLength; i++) {\n const result = compare(a[i], b[i])\n if (result !== 0) return result\n }\n\n return a.length - b.length\n}\n\n/**\n * Compares two plain objects. If the keys are different, the two key sets are sorted and compared as arrays of strings.\n * If the keys are the same, the values are compared recursively.\n * @param a - The first object to compare\n * @param b - The second object to compare\n * @returns A number indicating the comparison result\n */\nconst comparePlainObjects = (a: Record<string, any>, b: Record<string, any>): number => {\n // Create a merged list of all unique keys and sort it\n // const allKeys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort()\n\n // Compare values for keys in A that are also in B\n let differentKeys = false\n let leastDifferentKey: string | undefined\n let leastDifferentKeyResult: number = 0\n for (const key in a) {\n if (!(key in b)) differentKeys = true;\n else {\n // Both have the key, compare their values\n const result = compare(a[key], b[key])\n if (result !== 0) {\n if (!leastDifferentKey || leastDifferentKey > key) {\n leastDifferentKey = key\n leastDifferentKeyResult = result\n }\n }\n }\n }\n\n // if B had all As keys, we need to check if B has any keys that A doesn't have\n if (!differentKeys) {\n for (const key in b) {\n if (!(key in a)) { differentKeys = true; break }\n }\n }\n\n // if the keys are different, compare the keys\n if (differentKeys) {\n return compareArrays(Object.keys(a), Object.keys(b))\n }\n\n return leastDifferentKeyResult // All keys and values are equal\n}\n\nconst compareCustomComparableHelper = (a: any, b: any): number => {\n // Only check for custom methods if a is not null/undefined and is an object\n if (a !== null && a !== undefined && typeof a === 'object') {\n // Check if left operand supports any of the custom methods (highest priority)\n if (isFunction(a.compare)) return a.compare(b);\n if (isFunction(a.eq) && a?.eq(b)) return 0;\n if (isFunction(a.lt) && a?.lt(b)) return -1;\n if (isFunction(a.gt) && a?.gt(b)) return 1;\n if (isFunction(a.lte) && a?.lte(b)) return -1;\n if (isFunction(a.gte) && a?.gte(b)) return 1;\n }\n return NaN\n}\n\nconst compareCustomComparable = (a: any, b: any): number => {\n const customResult = compareCustomComparableHelper(a, b)\n if (!Number.isNaN(customResult)) return customResult\n return -compareCustomComparableHelper(b, a)\n}\n\nconst comparePrimitives = (a: any, b: any): number => {\n // Handle null\n if (a === null && b === null) return 0\n if (a === null) return -1\n if (b === null) return 1\n\n // Handle undefined\n if (a === undefined && b === undefined) return 0\n if (a === undefined) return 1\n if (b === undefined) return -1\n\n // Handle NaN\n if (Number.isNaN(a) && Number.isNaN(b)) return 0\n if (Number.isNaN(a)) return -1\n if (Number.isNaN(b)) return 1\n\n // Handle numbers - use subtraction for efficiency\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b\n }\n\n // Handle strings - use localeCompare for proper string comparison\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b)\n }\n\n // Handle booleans - convert to numbers for comparison\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b)\n }\n\n // Return NaN for different types or incompatible comparisons\n if (typeof a !== typeof b) return NaN\n\n // For same types that aren't numbers, strings, or booleans, return NaN\n return NaN\n}\n\n/**\n * deep structural comparison\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns A number indicating the comparison result:\n * - **< 0**: `a` is less than `b`\n * - **== 0**: `a` is equal to `b` (deep structural equality)\n * - **> 0**: `a` is greater than `b`\n * - **NaN**: Values cannot be compared (incompatible types or custom comparison failed)\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const compare = (a: any, b: any): number => {\n if (a === b) return 0;\n // Handle custom comparable first\n const customResult = compareCustomComparable(a, b)\n if (!Number.isNaN(customResult)) return customResult\n\n // Handle arrays\n if (isArray(a) && isArray(b)) {\n return compareArrays(a, b)\n }\n\n // Handle plain objects\n if (isPlainObject(a) && isPlainObject(b)) {\n return comparePlainObjects(a, b)\n }\n\n // Handle primitives\n return comparePrimitives(a, b)\n}","import { compare } from './compare'\n\n/**\n * deep structural == test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are deeply equal (compare returns 0), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const eq = (a: any, b: any): boolean => compare(a, b) === 0;\n\n/**\n * deep structural != test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are not deeply equal (compare returns non-zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const neq = (a: any, b: any): boolean => compare(a, b) !== 0;\n\n/**\n * deep structural < test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than `b` (compare returns negative), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lt = (a: any, b: any): boolean => compare(a, b) < 0;\n\n/**\n * deep structural > test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than `b` (compare returns positive), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gt = (a: any, b: any): boolean => compare(a, b) > 0;\n\n/**\n * deep structural <= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than or equal to `b` (compare returns negative or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lte = (a: any, b: any): boolean => compare(a, b) <= 0;\n\n/**\n * deep structural >= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than or equal to `b` (compare returns positive or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gte = (a: any, b: any): boolean => compare(a, b) >= 0;\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -9,16 +9,33 @@ var compareArrays = (a, b) => {
|
|
|
9
9
|
return a.length - b.length;
|
|
10
10
|
};
|
|
11
11
|
var comparePlainObjects = (a, b) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
let differentKeys = false;
|
|
13
|
+
let leastDifferentKey;
|
|
14
|
+
let leastDifferentKeyResult = 0;
|
|
15
|
+
for (const key in a) {
|
|
16
|
+
if (!(key in b)) differentKeys = true;
|
|
17
|
+
else {
|
|
18
|
+
const result = compare(a[key], b[key]);
|
|
19
|
+
if (result !== 0) {
|
|
20
|
+
if (!leastDifferentKey || leastDifferentKey > key) {
|
|
21
|
+
leastDifferentKey = key;
|
|
22
|
+
leastDifferentKeyResult = result;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!differentKeys) {
|
|
28
|
+
for (const key in b) {
|
|
29
|
+
if (!(key in a)) {
|
|
30
|
+
differentKeys = true;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (differentKeys) {
|
|
36
|
+
return compareArrays(Object.keys(a), Object.keys(b));
|
|
20
37
|
}
|
|
21
|
-
return
|
|
38
|
+
return leastDifferentKeyResult;
|
|
22
39
|
};
|
|
23
40
|
var compareCustomComparableHelper = (a, b) => {
|
|
24
41
|
if (a !== null && a !== void 0 && typeof a === "object") {
|
|
@@ -59,6 +76,7 @@ var comparePrimitives = (a, b) => {
|
|
|
59
76
|
return NaN;
|
|
60
77
|
};
|
|
61
78
|
var compare = (a, b) => {
|
|
79
|
+
if (a === b) return 0;
|
|
62
80
|
const customResult = compareCustomComparable(a, b);
|
|
63
81
|
if (!Number.isNaN(customResult)) return customResult;
|
|
64
82
|
if (isArray(a) && isArray(b)) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/compare.ts","../src/equality.ts"],"sourcesContent":["import { isArray, isPlainObject, isFunction } from '@art-suite/art-core-ts-types'\n\nexport interface CustomComparableInterface {\n\n /**\n * Compares `this` with `b`\n * @param b - The value to compare `this` with\n * @returns A number greater than zero if `this` is greater than `b`, less than zero if `this` is less than `b`, and zero if `this` is equal to `b`\n */\n compare(b: any): number\n}\n\nexport interface CustomEqualityInterface {\n /**\n * Checks if `this` equals `b`\n * @param b - The value to compare `this` with\n * @returns true if equal, false otherwise\n */\n eq(b: any): boolean\n}\n\nexport interface CustomInequalityInterface extends CustomEqualityInterface {\n /**\n * Checks if `this` is not equal to `b`\n * @param b - The value to compare `this` with\n * @returns true if not equal, false otherwise\n */\n lt(b: any): boolean\n gt(b: any): boolean\n lte(b: any): boolean\n gte(b: any): boolean\n}\n\nconst compareArrays = (a: any[], b: any[]): number => {\n const minLength = Math.min(a.length, b.length)\n\n for (let i = 0; i < minLength; i++) {\n const result = compare(a[i], b[i])\n if (result !== 0) return result\n }\n\n return a.length - b.length\n}\n\nconst comparePlainObjects = (a: Record<string, any>, b: Record<string, any>): number => {\n // Create a merged list of all unique keys and sort it\n const allKeys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort()\n\n // Iterate through the sorted keys to find the first non-zero comparison result\n for (const key of allKeys) {\n const aHas = key in a\n const bHas = key in b\n if (!aHas && bHas) return -1 // a is missing the key, so a is less\n if (aHas && !bHas) return 1 // b is missing the key, so b is less\n // Both have the key, compare their values\n const result = compare(a[key], b[key])\n if (result !== 0) return result\n }\n\n return 0 // All keys and values are equal\n}\n\nconst compareCustomComparableHelper = (a: any, b: any): number => {\n // Only check for custom methods if a is not null/undefined and is an object\n if (a !== null && a !== undefined && typeof a === 'object') {\n // Check if left operand supports any of the custom methods (highest priority)\n if (isFunction(a.compare)) return a.compare(b);\n if (isFunction(a.eq) && a?.eq(b)) return 0;\n if (isFunction(a.lt) && a?.lt(b)) return -1;\n if (isFunction(a.gt) && a?.gt(b)) return 1;\n if (isFunction(a.lte) && a?.lte(b)) return -1;\n if (isFunction(a.gte) && a?.gte(b)) return 1;\n }\n return NaN\n}\n\nconst compareCustomComparable = (a: any, b: any): number => {\n const customResult = compareCustomComparableHelper(a, b)\n if (!Number.isNaN(customResult)) return customResult\n return -compareCustomComparableHelper(b, a)\n}\n\nconst comparePrimitives = (a: any, b: any): number => {\n // Handle null\n if (a === null && b === null) return 0\n if (a === null) return -1\n if (b === null) return 1\n\n // Handle undefined\n if (a === undefined && b === undefined) return 0\n if (a === undefined) return 1\n if (b === undefined) return -1\n\n // Handle NaN\n if (Number.isNaN(a) && Number.isNaN(b)) return 0\n if (Number.isNaN(a)) return -1\n if (Number.isNaN(b)) return 1\n\n // Handle numbers - use subtraction for efficiency\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b\n }\n\n // Handle strings - use localeCompare for proper string comparison\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b)\n }\n\n // Handle booleans - convert to numbers for comparison\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b)\n }\n\n // Return NaN for different types or incompatible comparisons\n if (typeof a !== typeof b) return NaN\n\n // For same types that aren't numbers, strings, or booleans, return NaN\n return NaN\n}\n\n/**\n * deep structural comparison\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns A number indicating the comparison result:\n * - **< 0**: `a` is less than `b`\n * - **== 0**: `a` is equal to `b` (deep structural equality)\n * - **> 0**: `a` is greater than `b`\n * - **NaN**: Values cannot be compared (incompatible types or custom comparison failed)\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const compare = (a: any, b: any): number => {\n // Handle custom comparables first\n const customResult = compareCustomComparable(a, b)\n if (!Number.isNaN(customResult)) return customResult\n\n // Handle arrays\n if (isArray(a) && isArray(b)) {\n return compareArrays(a, b)\n }\n\n // Handle plain objects\n if (isPlainObject(a) && isPlainObject(b)) {\n return comparePlainObjects(a, b)\n }\n\n // Handle primitives\n return comparePrimitives(a, b)\n}","import { compare } from './compare'\n\n/**\n * deep structural == test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are deeply equal (compare returns 0), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const eq = (a: any, b: any): boolean => compare(a, b) === 0;\n\n/**\n * deep structural != test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are not deeply equal (compare returns non-zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const neq = (a: any, b: any): boolean => compare(a, b) !== 0;\n\n/**\n * deep structural < test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than `b` (compare returns negative), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lt = (a: any, b: any): boolean => compare(a, b) < 0;\n\n/**\n * deep structural > test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than `b` (compare returns positive), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gt = (a: any, b: any): boolean => compare(a, b) > 0;\n\n/**\n * deep structural <= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than or equal to `b` (compare returns negative or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lte = (a: any, b: any): boolean => compare(a, b) <= 0;\n\n/**\n * deep structural >= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than or equal to `b` (compare returns positive or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gte = (a: any, b: any): boolean => compare(a, b) >= 0;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/compare.ts","../src/equality.ts"],"sourcesContent":["import { isArray, isPlainObject, isFunction } from '@art-suite/art-core-ts-types'\nimport { objectKeyCount } from '@art-suite/art-core-ts-containers'\n\nexport interface CustomComparableInterface {\n\n /**\n * Compares `this` with `b`\n * @param b - The value to compare `this` with\n * @returns A number greater than zero if `this` is greater than `b`, less than zero if `this` is less than `b`, and zero if `this` is equal to `b`\n */\n compare(b: any): number\n}\n\nexport interface CustomEqualityInterface {\n /**\n * Checks if `this` equals `b`\n * @param b - The value to compare `this` with\n * @returns true if equal, false otherwise\n */\n eq(b: any): boolean\n}\n\nexport interface CustomInequalityInterface extends CustomEqualityInterface {\n /**\n * Checks if `this` is not equal to `b`\n * @param b - The value to compare `this` with\n * @returns true if not equal, false otherwise\n */\n lt(b: any): boolean\n gt(b: any): boolean\n lte(b: any): boolean\n gte(b: any): boolean\n}\n\nconst compareArrays = (a: any[], b: any[]): number => {\n const minLength = Math.min(a.length, b.length)\n\n for (let i = 0; i < minLength; i++) {\n const result = compare(a[i], b[i])\n if (result !== 0) return result\n }\n\n return a.length - b.length\n}\n\n/**\n * Compares two plain objects. If the keys are different, the two key sets are sorted and compared as arrays of strings.\n * If the keys are the same, the values are compared recursively.\n * @param a - The first object to compare\n * @param b - The second object to compare\n * @returns A number indicating the comparison result\n */\nconst comparePlainObjects = (a: Record<string, any>, b: Record<string, any>): number => {\n // Create a merged list of all unique keys and sort it\n // const allKeys = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort()\n\n // Compare values for keys in A that are also in B\n let differentKeys = false\n let leastDifferentKey: string | undefined\n let leastDifferentKeyResult: number = 0\n for (const key in a) {\n if (!(key in b)) differentKeys = true;\n else {\n // Both have the key, compare their values\n const result = compare(a[key], b[key])\n if (result !== 0) {\n if (!leastDifferentKey || leastDifferentKey > key) {\n leastDifferentKey = key\n leastDifferentKeyResult = result\n }\n }\n }\n }\n\n // if B had all As keys, we need to check if B has any keys that A doesn't have\n if (!differentKeys) {\n for (const key in b) {\n if (!(key in a)) { differentKeys = true; break }\n }\n }\n\n // if the keys are different, compare the keys\n if (differentKeys) {\n return compareArrays(Object.keys(a), Object.keys(b))\n }\n\n return leastDifferentKeyResult // All keys and values are equal\n}\n\nconst compareCustomComparableHelper = (a: any, b: any): number => {\n // Only check for custom methods if a is not null/undefined and is an object\n if (a !== null && a !== undefined && typeof a === 'object') {\n // Check if left operand supports any of the custom methods (highest priority)\n if (isFunction(a.compare)) return a.compare(b);\n if (isFunction(a.eq) && a?.eq(b)) return 0;\n if (isFunction(a.lt) && a?.lt(b)) return -1;\n if (isFunction(a.gt) && a?.gt(b)) return 1;\n if (isFunction(a.lte) && a?.lte(b)) return -1;\n if (isFunction(a.gte) && a?.gte(b)) return 1;\n }\n return NaN\n}\n\nconst compareCustomComparable = (a: any, b: any): number => {\n const customResult = compareCustomComparableHelper(a, b)\n if (!Number.isNaN(customResult)) return customResult\n return -compareCustomComparableHelper(b, a)\n}\n\nconst comparePrimitives = (a: any, b: any): number => {\n // Handle null\n if (a === null && b === null) return 0\n if (a === null) return -1\n if (b === null) return 1\n\n // Handle undefined\n if (a === undefined && b === undefined) return 0\n if (a === undefined) return 1\n if (b === undefined) return -1\n\n // Handle NaN\n if (Number.isNaN(a) && Number.isNaN(b)) return 0\n if (Number.isNaN(a)) return -1\n if (Number.isNaN(b)) return 1\n\n // Handle numbers - use subtraction for efficiency\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b\n }\n\n // Handle strings - use localeCompare for proper string comparison\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b)\n }\n\n // Handle booleans - convert to numbers for comparison\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b)\n }\n\n // Return NaN for different types or incompatible comparisons\n if (typeof a !== typeof b) return NaN\n\n // For same types that aren't numbers, strings, or booleans, return NaN\n return NaN\n}\n\n/**\n * deep structural comparison\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns A number indicating the comparison result:\n * - **< 0**: `a` is less than `b`\n * - **== 0**: `a` is equal to `b` (deep structural equality)\n * - **> 0**: `a` is greater than `b`\n * - **NaN**: Values cannot be compared (incompatible types or custom comparison failed)\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const compare = (a: any, b: any): number => {\n if (a === b) return 0;\n // Handle custom comparable first\n const customResult = compareCustomComparable(a, b)\n if (!Number.isNaN(customResult)) return customResult\n\n // Handle arrays\n if (isArray(a) && isArray(b)) {\n return compareArrays(a, b)\n }\n\n // Handle plain objects\n if (isPlainObject(a) && isPlainObject(b)) {\n return comparePlainObjects(a, b)\n }\n\n // Handle primitives\n return comparePrimitives(a, b)\n}","import { compare } from './compare'\n\n/**\n * deep structural == test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are deeply equal (compare returns 0), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const eq = (a: any, b: any): boolean => compare(a, b) === 0;\n\n/**\n * deep structural != test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are not deeply equal (compare returns non-zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const neq = (a: any, b: any): boolean => compare(a, b) !== 0;\n\n/**\n * deep structural < test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than `b` (compare returns negative), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lt = (a: any, b: any): boolean => compare(a, b) < 0;\n\n/**\n * deep structural > test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than `b` (compare returns positive), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gt = (a: any, b: any): boolean => compare(a, b) > 0;\n\n/**\n * deep structural <= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is less than or equal to `b` (compare returns negative or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const lte = (a: any, b: any): boolean => compare(a, b) <= 0;\n\n/**\n * deep structural >= test\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if `a` is greater than or equal to `b` (compare returns positive or zero), `false` otherwise\n *\n * For more details on comparison behavior, see the art-core-ts-compare README.\n */\nexport const gte = (a: any, b: any): boolean => compare(a, b) >= 0;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@art-suite/art-core-ts-compare",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "A TypeScript comparison utility library",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -26,14 +26,18 @@
|
|
|
26
26
|
"prebuild": "npm run clean",
|
|
27
27
|
"build": "npx sort-package-json;tsup src/index.ts --format esm,cjs --dts --sourcemap",
|
|
28
28
|
"build:clean": "npm run clean && npm run build",
|
|
29
|
+
"check:types": "tsc --noEmit",
|
|
30
|
+
"check:types:fast": "tsc --noEmit --incremental",
|
|
29
31
|
"clean": "rm -rf dist",
|
|
32
|
+
"perf": "node performance-test.js",
|
|
30
33
|
"prepublishOnly": "npm run build",
|
|
31
34
|
"test": "vitest run",
|
|
32
35
|
"test:coverage": "vitest run --coverage",
|
|
33
36
|
"test:watch": "vitest"
|
|
34
37
|
},
|
|
35
38
|
"dependencies": {
|
|
36
|
-
"@art-suite/art-core-ts-
|
|
39
|
+
"@art-suite/art-core-ts-containers": "^0.9.4",
|
|
40
|
+
"@art-suite/art-core-ts-types": "^0.3.6"
|
|
37
41
|
},
|
|
38
42
|
"devDependencies": {
|
|
39
43
|
"@vitest/coverage-v8": "^3.1.4"
|