UNPKG

@ts-java/comparator

Version:

A pure Typescript implementation of the Java `Comparator` functional interface.

241 lines (235 loc) 7.54 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { Comparator: () => Comparator }); module.exports = __toCommonJS(index_exports); // ../common/src/exception/null-pointer.ts var NullPointerException = class extends Error { constructor(message) { super(message); this.name = "NullPointerException"; } }; // ../common/src/typeguards/index.ts function isBoolean(input) { return typeof input === "boolean"; } function isDate(input) { return input instanceof Date; } function isFunction(input) { return typeof input === "function"; } function isPresent(input) { return input !== null && input !== void 0; } function isNull(input) { return input === null; } function isNumber(input) { return typeof input === "number"; } function isString(input) { return typeof input === "string"; } function isUndefined(input) { return typeof input === "undefined"; } // src/typeguards.ts function isComparable(value) { return typeof value === "object" && value !== null && "compareTo" in value && isFunction(value.compareTo); } function isClass(value) { return typeof value === "object" && value !== null && typeof value.constructor === "function"; } function isSameClass(value, other) { return isClass(value) && isClass(other) && value.constructor === other.constructor; } function isSameType(value, other) { return isSameClass(value, other) || typeof value === typeof other; } // src/comparator.ts var Comparator = class _Comparator { static comparing(keyExtractor, keyComparator) { return new _Comparator.#Impl((a, b) => { const valueOfA = keyExtractor(a); const valueOfB = keyExtractor(b); if (isUndefined(keyComparator)) { return _Comparator.naturalOrder().compare(valueOfA, valueOfB); } return keyComparator.compare(valueOfA, valueOfB); }); } /** * Returns a Comparator that compares {@link ComparableValue Comparable} objects by their natural order. * @returns a new Comparator that compares objects by their natural order. * @throws a {@link NullPointerException} if either of the objects is null. * @throws an Error if the objects are not of the same type or are not comparable by natural order. * * @example * ```typescript * const numbers = [1,5,3,2,4]; * numbers.toSorted(Comparator.naturalOrder().compare); // [1,2,3,4,5] * ``` */ static naturalOrder() { return new _Comparator.#Impl((a, b) => { if (isNull(a) || isNull(b)) { throw new NullPointerException(); } if (!isSameType(a, b) || !isSameType(b, a)) { throw new TypeError("Cannot compare objects of different types"); } if (isString(a) && isString(b)) { return a.localeCompare(b); } if (isNumber(a) && isNumber(b)) { return a - b; } if (isBoolean(a) && isBoolean(b)) { return Number(b) - Number(a); } if (isDate(a) && isDate(b)) { return a.getTime() - b.getTime(); } if (isComparable(a) && isComparable(b)) { return a.compareTo(b); } throw new TypeError("Objects must be comparable by natural order"); }); } /** * Returns a Comparator that compares {@link ComparableValue Comparable} objects by their reverse order. * This is equivalent to calling `Comparator.naturalOrder().reversed()`. * @returns a new Comparator that compares objects by their reverse order. * @see {@link Comparator.naturalOrder} * @example * ```typescript * const numbers = [1,5,3,2,4]; * numbers.toSorted(Comparator.reverseOrder().compare); // [5,4,3,2,1] * ``` */ static reverseOrder() { return _Comparator.naturalOrder().reversed(); } /** * A null-friendly comparator that compares objects using the given Comparator, putting null values first. * @param comparator the comparator that will be used to compare the objects. * @returns a new Comparator that compares objects using the given Comparator, with nulls first. * @example * ```typescript * const numbers = [1,5,3,2,4,null]; * numbers.toSorted( * Comparator.nullFirst( * Comparator.naturalOrder() * ).compare * ); // [null,1,2,3,4,5] * ``` */ static nullFirst(comparator) { return new _Comparator.#Impl((a, b) => { if (isPresent(a) && isPresent(b)) { return comparator.compare(a, b); } if (isNull(a) && isNull(b)) { return 0; } if (isNull(a)) { return -1; } return 1; }); } /** * A null-friendly comparator that compares objects using the given Comparator, putting null values last. * @param comparator the comparator that will be used to compare the objects. * @returns a new Comparator that compares objects using the given Comparator, with nulls last. * @example * ```typescript * const numbers = [1,5,null,3,2,4]; * numbers.toSorted( * Comparator.nullLast( * Comparator.naturalOrder() * ).compare * ); // [1,2,3,4,5,null] */ static nullLast(comparator) { return new _Comparator.#Impl((a, b) => { if (isPresent(a) && isPresent(b)) { return comparator.compare(a, b); } if (isNull(a) && isNull(b)) { return 0; } if (isNull(a)) { return 1; } return -1; }); } /** * An internal class that implements the abstract Comparator. * Used for the static methods of this class. */ static #Impl = class ComparatorImpl extends _Comparator { constructor(compare) { super(); this.compare = compare; } }; /** * Returns a new Comparator that imposes the reverse ordering of this Comparator. * @returns a Comparator that imposes the reverse ordering of this Comparator. * @example * ```typescript * const comparator = Comparator.naturalOrder(); * const numbers = [1,5,3,2,4]; * numbers.toSorted( * comparator.reversed().compare * ); // [5,4,3,2,1] */ reversed() { return new _Comparator.#Impl((b, a) => this.compare(a, b)); } thenComparing(keyExtractorOrComparator, keyComparator) { return new _Comparator.#Impl((a, b) => { const result = this.compare(a, b); if (result !== 0) { return result; } if (keyExtractorOrComparator instanceof _Comparator) { return keyExtractorOrComparator.compare(a, b); } if (isUndefined(keyComparator)) { return _Comparator.comparing(keyExtractorOrComparator).compare(a, b); } return _Comparator.comparing( keyExtractorOrComparator, keyComparator ).compare(a, b); }); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Comparator });