@rslike/cmp
Version:
JavaScript Comparison package without undefined behavior!
177 lines (175 loc) • 5.03 kB
JavaScript
// src/symbols.ts
var kCompare = Symbol.for("Symbol.compare");
var kEquals = Symbol.for("Symbol.equals");
var kPartialEquals = Symbol.for("Symbol.partialEquals");
// src/utils.ts
import { UndefinedBehaviorError } from "@rslike/std";
function compare(a, b, compareFn) {
if (typeof a[kCompare] === "function") {
return a[kCompare](b);
}
if (typeof b[kCompare] === "function") {
return b[kCompare](a);
}
if (compareFn) {
if (typeof compareFn !== "function") {
throw new UndefinedBehaviorError(
`compareFn argument should be a function. Got "${typeof compareFn}"`,
{
cause: {
value: compareFn,
type: typeof compareFn
}
}
);
}
const res = compareFn(a, b);
if (typeof res !== "number") {
throw new UndefinedBehaviorError(
`"compareFn" function should return number. Got "${typeof res}"`,
{ cause: { value: res, type: typeof res } }
);
}
}
throw new UndefinedBehaviorError(
'At least 1 argument should implement "Symbol.compare" trait'
);
}
function partialEquals(a, b, equalityFn) {
if (typeof a[kPartialEquals] === "function") {
const res = Reflect.apply(a[kPartialEquals], a, [b]);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`Cannot call partialCompare for imcoming first argument. "Symbol.partialEquals" trait should returns boolean result. Got "${typeof res}"`,
{
cause: {
first: a,
typeFirst: typeof a,
ctorFirst: a?.constructor,
result: res,
typeResult: typeof res,
second: b,
typeSecond: typeof b,
ctorSecond: b?.constructor
}
}
);
}
if (typeof b[kPartialEquals] === "function") {
const res = Reflect.apply(b[kPartialEquals], b, [a]);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`Cannot call partialCompare for imcoming second argument. "Symbol.partialEquals" trait should returns boolean result. Got "${typeof res}"`,
{
cause: {
first: a,
typeFirst: typeof a,
ctorFirst: a?.constructor,
result: res,
typeResult: typeof res,
second: b,
typeSecond: typeof b,
ctorSecond: b?.constructor
}
}
);
}
if (equalityFn) {
if (typeof equalityFn === "function") {
const res = equalityFn(a, b);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`equalityFn should returns boolean. Got "${typeof res}"`,
{
cause: { value: res, type: typeof res }
}
);
}
throw new UndefinedBehaviorError(
`equalityFn argument should be a function. Got "${typeof equalityFn}"`,
{
cause: { value: equalityFn, type: typeof equalityFn }
}
);
}
return a == b;
}
function equals(a, b, equalityFn) {
if (typeof a === "object" && a !== null && kEquals in a && typeof a[kEquals] === "function") {
const res = Reflect.apply(a[kEquals], a, [b]);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`Cannot call equals for imcoming first argument. "Symbol.equals" trait should returns boolean result. Got "${typeof res}"`,
{
cause: {
first: a,
typeFirst: typeof a,
ctorFirst: a?.constructor,
result: res,
typeResult: typeof res,
second: b,
typeSecond: typeof b,
ctorSecond: b?.constructor
}
}
);
}
if (typeof b === "object" && b !== null && kEquals in b && typeof b[kEquals] === "function") {
const res = Reflect.apply(b[kEquals], b, [a]);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`Cannot call equals for imcoming second argument. "Symbol.equals" trait should returns boolean result. Got "${typeof res}"`,
{
cause: {
first: a,
typeFirst: typeof a,
ctorFirst: a?.constructor,
result: res,
typeResult: typeof res,
second: b,
typeSecond: typeof b,
ctorSecond: b?.constructor
}
}
);
}
if (equalityFn) {
if (typeof equalityFn === "function") {
const res = equalityFn(a, b);
if (typeof res === "boolean") {
return res;
}
throw new UndefinedBehaviorError(
`equalityFn should returns boolean. Got "${typeof res}"`,
{
cause: { value: res, type: typeof res }
}
);
}
throw new UndefinedBehaviorError(
`equalityFn argument should be a function. Got "${typeof equalityFn}"`,
{
cause: { value: equalityFn, type: typeof equalityFn }
}
);
}
return a === b;
}
export {
compare,
equals,
kCompare,
kEquals,
kPartialEquals,
partialEquals
};