@rslike/cmp
Version:
JavaScript Comparison package without undefined behavior!
293 lines (289 loc) • 9.89 kB
JavaScript
;
// src/symbols.ts
var kCompare = Symbol.for("Symbol.compare");
var kEquals = Symbol.for("Symbol.equals");
var kPartialEquals = Symbol.for("Symbol.partialEquals");
// src/primitives.ts
var import_std = require("@rslike/std");
Number.prototype[kCompare] = function(another) {
if (typeof another === "object" && another !== null && Symbol.compare in another && typeof another[Symbol.compare] === "function") {
const res = Reflect.apply(another[Symbol.compare], another, [
this.valueOf()
]);
if (typeof res === "number") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`[Symbol.compare] should returns number type. Got "${typeof res}"`,
{ cause: { value: res, type: typeof res } }
);
}
if (typeof another === "number") {
if (!Number.isFinite(this.valueOf()) || !Number.isFinite(another)) {
return Number.NaN;
}
const res = this.valueOf() - another;
if (res > 0) {
return 1;
} else if (res < 0) {
return -1;
}
return res;
}
throw new import_std.UndefinedBehaviorError(
"[Symbol.compare] can acept numeric value or object with implementation of [Symbol.compare]",
{
cause: {
value: another,
type: typeof another
}
}
);
};
Number.prototype[kPartialEquals] = function(another) {
if (typeof another === "object" && another !== null && Symbol.partialEquals in another && typeof another[Symbol.partialEquals] === "function") {
const res = Reflect.apply(another[Symbol.partialEquals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.partialEquals trait expected to returns boolean type. Got "${typeof res}"`,
{
cause: {
value: res,
type: typeof res
}
}
);
}
return this.valueOf() == another;
};
Number.prototype[kEquals] = function(another) {
if (typeof another === "object" && another !== null && Symbol.equals in another && typeof another[Symbol.equals] === "function") {
const res = Reflect.apply(another[Symbol.equals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`[Symbol.equals] trait expected to returns number type. Got "${typeof res}"`,
{
cause: {
value: res,
type: typeof res
}
}
);
}
return this.valueOf() === another;
};
String.prototype[kCompare] = function(another, locales, options) {
if (typeof another === "object" && another !== null && Symbol.compare in another && typeof another[Symbol.compare] === "function") {
const res = Reflect.apply(another[Symbol.compare], another, [
this.valueOf()
]);
if (typeof res === "number") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.compare trait expected to returns number type. Got "${typeof res}"`
);
}
if (typeof another === "number" || typeof another === "boolean") {
const asStr = String(another);
return this.toString().localeCompare(asStr, locales, options);
}
if (typeof another === "string") {
return this.toString().localeCompare(another, locales, options);
}
throw new import_std.UndefinedBehaviorError(
'"Symbol.compare" can acept string value or object with implementation of "Symbol.compare" trait',
{
cause: {
value: another,
type: typeof another
}
}
);
};
String.prototype[kPartialEquals] = function(another) {
if (typeof another === "object" && another !== null && Symbol.partialEquals in another && typeof another[Symbol.partialEquals] === "function") {
const res = Reflect.apply(another[Symbol.partialEquals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.partialEquals trait expected to returns number type. Got "${typeof res}"`
);
}
return this.valueOf() == another;
};
String.prototype[kEquals] = function(another) {
if (typeof another === "object" && another !== null && Symbol.equals in another && typeof another[Symbol.equals] === "function") {
const res = Reflect.apply(another[Symbol.equals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.equals trait expected to returns number type. Got "${typeof res}"`
);
}
return this.valueOf() === another;
};
Boolean.prototype[kCompare] = function(another) {
if (typeof another === "boolean") {
if (this.valueOf() > another) {
return 1;
} else if (this.valueOf() < another) {
return -1;
}
return 0;
} else if (typeof another === "number") {
return another[Symbol.compare](Number(this.valueOf()));
} else if (typeof another === "string") {
return this[Symbol.compare](!!another);
}
if (typeof another === "object" && another !== null && typeof another[Symbol.compare] === "function") {
const res = Reflect.apply(another[Symbol.compare], another, [
this.valueOf()
]);
if (typeof res === "number") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.compare trait expected to returns number type. Got "${typeof res}"`
);
}
throw new import_std.UndefinedBehaviorError(
'"Symbol.compare" can acept only another string value or object with implementation of "Symbol.compare"',
{
cause: {
value: another,
type: typeof another
}
}
);
};
Boolean.prototype[kEquals] = function(another) {
if (typeof another === "object" && another !== null && typeof another[Symbol.equals] === "function") {
if (typeof another === "object" && another !== null && Symbol.equals in another && typeof another[Symbol.equals] === "function") {
const res = Reflect.apply(another[Symbol.equals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`"Symbol.equals" trait expected to returns boolean type. Got "${typeof res}"`
);
}
}
return this.valueOf() === another;
};
Boolean.prototype[kPartialEquals] = function(another) {
if (typeof another === "object" && another !== null && Symbol.partialEquals in another && typeof another[Symbol.partialEquals] === "function") {
const res = Reflect.apply(another[Symbol.partialEquals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.partialEquals trait expected to returns boolean type. Got "${typeof res}"`
);
}
if (typeof another === "boolean" || typeof another === "string" || typeof another === "number") {
return this.valueOf() == another;
}
return false;
};
Date.prototype[kCompare] = function(another) {
if (typeof another === "number" || typeof another === "string" || another instanceof Date) {
const asDate = new Date(another);
if (!Number.isFinite(asDate.valueOf())) {
throw new import_std.UndefinedBehaviorError(
"Incoming primitive is not finite after parsing to Date.",
{
cause: {
value: another,
type: typeof another
}
}
);
}
if (this.valueOf() > asDate.valueOf()) {
return 1;
} else if (this.valueOf() < asDate.valueOf()) {
return -1;
} else {
return 0;
}
}
if (typeof another === "object" && another !== null && typeof another[Symbol.compare] === "function") {
const res = Reflect.apply(another[Symbol.compare], another, [
this.valueOf()
]);
if (typeof res === "number") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.equals trait expected to returns boolean type. Got "${typeof res}"`
);
}
throw new import_std.UndefinedBehaviorError(
'"Symbol.compare" can acept only string, number, Date value or object with implementation of "Symbol.compare"',
{
cause: {
value: another,
type: typeof another
}
}
);
};
Date.prototype[kEquals] = function(another) {
if (typeof another === "string" || typeof another === "number" || another instanceof Date) {
const asDate = new Date(another);
return this.valueOf()[Symbol.equals](asDate.valueOf());
}
if (typeof another === "object" && another !== null && typeof another[Symbol.equals] === "function") {
const res = Reflect.apply(another[Symbol.equals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`Symbol.equals trait expected to returns boolean type. Got "${typeof res}"`
);
}
return this.valueOf() === another;
};
Date.prototype[kPartialEquals] = function(another) {
if (typeof another === "string" || typeof another === "number" || another instanceof Date) {
const asDate = new Date(another);
return this.valueOf()[Symbol.partialEquals](asDate.valueOf());
}
if (typeof another === "object" && another !== null && Symbol.partialEquals in another && typeof another[Symbol.partialEquals] === "function") {
const res = Reflect.apply(another[Symbol.partialEquals], another, [
this.valueOf()
]);
if (typeof res === "boolean") {
return res;
}
throw new import_std.UndefinedBehaviorError(
`"Symbol.partialEquals" trait expected to returns boolean type. Got "${typeof res}"`
);
}
return this.valueOf() == another;
};
// src/globals.ts
Symbol.compare = kCompare;
Symbol.partialEquals = kPartialEquals;
Symbol.equals = kEquals;