UNPKG

@rslike/cmp

Version:

JavaScript Comparison package without undefined behavior!

291 lines (288 loc) 9.7 kB
// src/symbols.ts var kCompare = Symbol.for("Symbol.compare"); var kEquals = Symbol.for("Symbol.equals"); var kPartialEquals = Symbol.for("Symbol.partialEquals"); // src/primitives.ts import { UndefinedBehaviorError } from "@rslike/std"; Number.prototype[Symbol.compare] = 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 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 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 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 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 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 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 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 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 UndefinedBehaviorError( `Symbol.compare trait expected to returns number type. Got "${typeof res}"` ); } throw new 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 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 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 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 UndefinedBehaviorError( `Symbol.equals trait expected to returns boolean type. Got "${typeof res}"` ); } throw new 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 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 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;