| /** | |
| * Defines comparison functions for ordered values. | |
| * | |
| * An `Order<A>` compares two `A` values and returns whether the first is less | |
| * than, equal to, or greater than the second. Orders are used for sorting, | |
| * choosing minimum or maximum values, checking ranges, and building ordered data | |
| * structures. This module includes built-in orders, constructors for custom | |
| * orders, tools for reversing and combining comparisons, tuple and struct | |
| * helpers, comparison predicates, clamping, and reducer support. | |
| * | |
| * @since 2.0.0 | |
| */ | |
| import { dual } from "./Function.ts" | |
| import type { TypeLambda } from "./HKT.ts" | |
| import type { Ordering } from "./Ordering.ts" | |
| import * as Reducer from "./Reducer.ts" | |
| /** | |
| * Represents a total ordering for values of type `A`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to define how values of a type are compared. | |
| * | |
| * **Details** | |
| * | |
| * An order returns `-1` when the first value is less than the second, `0` when | |
| * the values are equal according to this ordering, and `1` when the first value | |
| * is greater than the second. It must satisfy total ordering laws: totality, | |
| * antisymmetry, and transitivity. | |
| * | |
| * **Example** (Custom Order) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge: Order.Order<{ name: string; age: number }> = (self, that) => { | |
| * if (self.age < that.age) return -1 | |
| * if (self.age > that.age) return 1 | |
| * return 0 | |
| * } | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 25 } | |
| * console.log(byAge(person1, person2)) // 1 | |
| * ``` | |
| * | |
| * @see {@link make} to create an order from a comparison function | |
| * @see {@link Ordering} for the result type of comparisons | |
| * @category type class | |
| * @since 2.0.0 | |
| */ | |
| export interface Order<in A> { | |
| (self: A, that: A): Ordering | |
| } | |
| /** | |
| * Type lambda for the `Order` type class, used internally for higher-kinded type operations. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to abstract over `Order` in higher-kinded type code. | |
| * | |
| * **Details** | |
| * | |
| * This is type-level only, has no runtime representation, and is used | |
| * internally by the Effect type system. | |
| * | |
| * @category type lambdas | |
| * @since 2.0.0 | |
| */ | |
| export interface OrderTypeLambda extends TypeLambda { | |
| readonly type: Order<this["Target"]> | |
| } | |
| /** | |
| * Creates a new `Order` instance from a comparison function. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a sorting rule not covered by the built-in orders or input | |
| * mapping helpers, and you can provide a total comparison. | |
| * | |
| * **Details** | |
| * | |
| * Uses reference equality (`===`) as a shortcut: if `self === that`, it returns | |
| * `0` without calling the comparison function. The comparison function should | |
| * return `-1`, `0`, or `1`, and the returned order satisfies total ordering | |
| * laws when the comparison function does. | |
| * | |
| * **Example** (Creating an Order) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge = Order.make<{ name: string; age: number }>((self, that) => { | |
| * if (self.age < that.age) return -1 | |
| * if (self.age > that.age) return 1 | |
| * return 0 | |
| * }) | |
| * | |
| * console.log(byAge({ name: "Alice", age: 30 }, { name: "Bob", age: 25 })) // 1 | |
| * console.log(byAge({ name: "Alice", age: 25 }, { name: "Bob", age: 30 })) // -1 | |
| * ``` | |
| * | |
| * @see {@link mapInput} to transform an order by mapping the input type | |
| * @see {@link combine} to combine multiple orders | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export function make<A>( | |
| compare: (self: A, that: A) => -1 | 0 | 1 | |
| ): Order<A> { | |
| return (self, that) => self === that ? 0 : compare(self, that) | |
| } | |
| /** | |
| * Order instance for strings that compares them lexicographically using JavaScript's `<` operator. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need lexicographic string ordering. | |
| * | |
| * **Details** | |
| * | |
| * Uses lexicographic dictionary ordering. The empty string is less than any | |
| * non-empty string, and comparisons are case-sensitive. | |
| * | |
| * **Example** (String Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * console.log(Order.String("apple", "banana")) // -1 | |
| * console.log(Order.String("banana", "apple")) // 1 | |
| * console.log(Order.String("apple", "apple")) // 0 | |
| * ``` | |
| * | |
| * @see {@link mapInput} to compare objects by a string property | |
| * @see {@link Struct} to combine with other orders for struct comparison | |
| * @category instances | |
| * @since 4.0.0 | |
| */ | |
| export const String: Order<string> = make((self, that) => self < that ? -1 : 1) | |
| /** | |
| * Order instance for numbers that compares them numerically. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need numeric ordering for numbers. | |
| * | |
| * **Details** | |
| * | |
| * `0` is considered equal to `-0`. All `NaN` values are considered equal to | |
| * each other, and any `NaN` is considered less than any non-`NaN` number. All | |
| * other values use standard numeric comparison. | |
| * | |
| * **Example** (Number Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * console.log(Order.Number(1, 1)) // 0 | |
| * console.log(Order.Number(1, 2)) // -1 | |
| * console.log(Order.Number(2, 1)) // 1 | |
| * | |
| * console.log(Order.Number(0, -0)) // 0 | |
| * console.log(Order.Number(NaN, 1)) // -1 | |
| * ``` | |
| * | |
| * @see {@link mapInput} to compare objects by a number property | |
| * @see {@link BigInt} for bigint comparisons | |
| * @category instances | |
| * @since 4.0.0 | |
| */ | |
| export const Number: Order<number> = make((self, that) => { | |
| if (globalThis.Number.isNaN(self) && globalThis.Number.isNaN(that)) return 0 | |
| if (globalThis.Number.isNaN(self)) return -1 // NaN < any number | |
| if (globalThis.Number.isNaN(that)) return 1 // any number > NaN | |
| return self < that ? -1 : 1 | |
| }) | |
| /** | |
| * Order instance for booleans where `false` is considered less than `true`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need boolean ordering where `false` comes before `true`. | |
| * | |
| * **Details** | |
| * | |
| * `false` is less than `true`, and equal values return `0`. | |
| * | |
| * **Example** (Boolean Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * console.log(Order.Boolean(false, true)) // -1 | |
| * console.log(Order.Boolean(true, false)) // 1 | |
| * console.log(Order.Boolean(true, true)) // 0 | |
| * ``` | |
| * | |
| * @see {@link mapInput} to compare objects by a boolean property | |
| * @category instances | |
| * @since 4.0.0 | |
| */ | |
| export const Boolean: Order<boolean> = make((self, that) => self < that ? -1 : 1) | |
| /** | |
| * Order instance for bigints that compares them numerically. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need numeric ordering for `bigint` values. | |
| * | |
| * **Details** | |
| * | |
| * Uses standard numeric comparison for bigint values and handles arbitrarily | |
| * large integers. | |
| * | |
| * **Example** (BigInt Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * console.log(Order.BigInt(1n, 2n)) // -1 | |
| * console.log(Order.BigInt(2n, 1n)) // 1 | |
| * console.log(Order.BigInt(1n, 1n)) // 0 | |
| * ``` | |
| * | |
| * @see {@link Number} for regular number comparisons | |
| * @see {@link mapInput} to compare objects by a bigint property | |
| * @category instances | |
| * @since 4.0.0 | |
| */ | |
| export const BigInt: Order<bigint> = make((self, that) => self < that ? -1 : 1) | |
| /** | |
| * Creates a new `Order` that reverses the comparison order of the input `Order`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need the reverse of an existing order. | |
| * | |
| * **Details** | |
| * | |
| * Returns a new order that swaps the arguments before comparison. If the | |
| * original order returns `-1`, the flipped order returns `1`, and vice versa. | |
| * Equal comparisons remain `0`. | |
| * | |
| * **Example** (Reversing Order) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const flip = Order.flip(Order.Number) | |
| * | |
| * console.log(flip(1, 2)) // 1 | |
| * console.log(flip(2, 1)) // -1 | |
| * console.log(flip(1, 1)) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine orders for multi-criteria comparison | |
| * @category combinators | |
| * @since 4.0.0 | |
| */ | |
| export function flip<A>(O: Order<A>): Order<A> { | |
| return make((self, that) => O(that, self)) | |
| } | |
| /** | |
| * Combines two `Order` instances to create a new `Order` that first compares using the first `Order`, | |
| * and if the values are equal, then compares using the second `Order`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need tie-breaking with exactly two orders. | |
| * | |
| * **Details** | |
| * | |
| * First applies the first order. If the result is non-zero, that result is | |
| * returned; otherwise, the second order is applied. The result is the first | |
| * non-zero comparison result, or `0` if both orders return `0`. | |
| * | |
| * **Example** (Combining Orders) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge = Order.mapInput( | |
| * Order.Number, | |
| * (person: { name: string; age: number }) => person.age | |
| * ) | |
| * const byName = Order.mapInput( | |
| * Order.String, | |
| * (person: { name: string; age: number }) => person.name | |
| * ) | |
| * const byAgeAndName = Order.combine(byAge, byName) | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 30 } | |
| * const person3 = { name: "Charlie", age: 25 } | |
| * | |
| * console.log(byAgeAndName(person1, person2)) // -1 (Same age, Alice < Bob) | |
| * console.log(byAgeAndName(person1, person3)) // 1 (Alice (30) > Charlie (25)) | |
| * ``` | |
| * | |
| * @see {@link combineAll} to combine multiple orders from a collection | |
| * @see {@link mapInput} to transform orders to work with different types | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export const combine: { | |
| /** | |
| * Combines two `Order` instances to create a new `Order` that first compares using the first `Order`, | |
| * and if the values are equal, then compares using the second `Order`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need tie-breaking with exactly two orders. | |
| * | |
| * **Details** | |
| * | |
| * First applies the first order. If the result is non-zero, that result is | |
| * returned; otherwise, the second order is applied. The result is the first | |
| * non-zero comparison result, or `0` if both orders return `0`. | |
| * | |
| * **Example** (Combining Orders) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge = Order.mapInput( | |
| * Order.Number, | |
| * (person: { name: string; age: number }) => person.age | |
| * ) | |
| * const byName = Order.mapInput( | |
| * Order.String, | |
| * (person: { name: string; age: number }) => person.name | |
| * ) | |
| * const byAgeAndName = Order.combine(byAge, byName) | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 30 } | |
| * const person3 = { name: "Charlie", age: 25 } | |
| * | |
| * console.log(byAgeAndName(person1, person2)) // -1 (Same age, Alice < Bob) | |
| * console.log(byAgeAndName(person1, person3)) // 1 (Alice (30) > Charlie (25)) | |
| * ``` | |
| * | |
| * @see {@link combineAll} to combine multiple orders from a collection | |
| * @see {@link mapInput} to transform orders to work with different types | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A>(that: Order<A>): (self: Order<A>) => Order<A> | |
| /** | |
| * Combines two `Order` instances to create a new `Order` that first compares using the first `Order`, | |
| * and if the values are equal, then compares using the second `Order`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need tie-breaking with exactly two orders. | |
| * | |
| * **Details** | |
| * | |
| * First applies the first order. If the result is non-zero, that result is | |
| * returned; otherwise, the second order is applied. The result is the first | |
| * non-zero comparison result, or `0` if both orders return `0`. | |
| * | |
| * **Example** (Combining Orders) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge = Order.mapInput( | |
| * Order.Number, | |
| * (person: { name: string; age: number }) => person.age | |
| * ) | |
| * const byName = Order.mapInput( | |
| * Order.String, | |
| * (person: { name: string; age: number }) => person.name | |
| * ) | |
| * const byAgeAndName = Order.combine(byAge, byName) | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 30 } | |
| * const person3 = { name: "Charlie", age: 25 } | |
| * | |
| * console.log(byAgeAndName(person1, person2)) // -1 (Same age, Alice < Bob) | |
| * console.log(byAgeAndName(person1, person3)) // 1 (Alice (30) > Charlie (25)) | |
| * ``` | |
| * | |
| * @see {@link combineAll} to combine multiple orders from a collection | |
| * @see {@link mapInput} to transform orders to work with different types | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| <A>(self: Order<A>, that: Order<A>): Order<A> | |
| } = dual(2, <A>(self: Order<A>, that: Order<A>): Order<A> => | |
| make((a1, a2) => { | |
| const out = self(a1, a2) | |
| if (out !== 0) { | |
| return out | |
| } | |
| return that(a1, a2) | |
| })) | |
| /** | |
| * Creates an `Order` that considers all values as equal. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need an order that treats all values as equal. | |
| * | |
| * **Details** | |
| * | |
| * Always returns `0` regardless of input values, making it useful as a neutral | |
| * element in order composition. | |
| * | |
| * **Example** (Always Equal Order) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const alwaysEqualOrder = Order.alwaysEqual<number>() | |
| * | |
| * console.log(alwaysEqualOrder(1, 2)) // 0 | |
| * console.log(alwaysEqualOrder(2, 1)) // 0 | |
| * console.log(alwaysEqualOrder(1, 1)) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine with other orders | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export function alwaysEqual<A>(): Order<A> { | |
| return make(() => 0) | |
| } | |
| /** | |
| * Combines all `Order` instances in the provided collection into a single `Order`. | |
| * The resulting `Order` compares using each `Order` in sequence until a non-zero result is found. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need tie-breaking across a variable number of orders. | |
| * | |
| * **Details** | |
| * | |
| * Applies orders in iteration order and short-circuits on the first non-zero | |
| * result. It returns `0` only if all orders return `0`. | |
| * | |
| * **Example** (Combining Multiple Orders) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byAge = Order.mapInput( | |
| * Order.Number, | |
| * (person: { name: string; age: number }) => person.age | |
| * ) | |
| * const byName = Order.mapInput( | |
| * Order.String, | |
| * (person: { name: string; age: number }) => person.name | |
| * ) | |
| * | |
| * const combinedOrder = Order.combineAll([byAge, byName]) | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 30 } | |
| * | |
| * console.log(combinedOrder(person1, person2)) // -1 (Same age, Alice < Bob) | |
| * ``` | |
| * | |
| * @see {@link combine} to combine two orders | |
| * @see {@link makeReducer} to create a reducer for combining orders | |
| * @category combining | |
| * @since 2.0.0 | |
| */ | |
| export function combineAll<A>(collection: Iterable<Order<A>>): Order<A> { | |
| return make((a1, a2) => { | |
| let out: Ordering = 0 | |
| for (const O of collection) { | |
| out = O(a1, a2) | |
| if (out !== 0) { | |
| return out | |
| } | |
| } | |
| return out | |
| }) | |
| } | |
| /** | |
| * Transforms an `Order` on type `A` into an `Order` on type `B` by providing a function that | |
| * maps values of type `B` to values of type `A`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to adapt an `Order` to compare a larger value by one | |
| * derived property. | |
| * | |
| * **Details** | |
| * | |
| * Applies the mapping function to both values before comparison. The mapping | |
| * function should be pure and not have side effects so the ordering properties | |
| * of the original order are preserved. | |
| * | |
| * **Example** (Mapping Input) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byLength = Order.mapInput(Order.Number, (s: string) => s.length) | |
| * | |
| * console.log(byLength("a", "bb")) // -1 | |
| * console.log(byLength("bb", "a")) // 1 | |
| * console.log(byLength("aa", "bb")) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine mapped orders for multi-criteria comparison | |
| * @see {@link Struct} to create orders for structs with multiple fields | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| export const mapInput: { | |
| /** | |
| * Transforms an `Order` on type `A` into an `Order` on type `B` by providing a function that | |
| * maps values of type `B` to values of type `A`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to adapt an `Order` to compare a larger value by one | |
| * derived property. | |
| * | |
| * **Details** | |
| * | |
| * Applies the mapping function to both values before comparison. The mapping | |
| * function should be pure and not have side effects so the ordering properties | |
| * of the original order are preserved. | |
| * | |
| * **Example** (Mapping Input) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byLength = Order.mapInput(Order.Number, (s: string) => s.length) | |
| * | |
| * console.log(byLength("a", "bb")) // -1 | |
| * console.log(byLength("bb", "a")) // 1 | |
| * console.log(byLength("aa", "bb")) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine mapped orders for multi-criteria comparison | |
| * @see {@link Struct} to create orders for structs with multiple fields | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| <B, A>(f: (b: B) => A): (self: Order<A>) => Order<B> | |
| /** | |
| * Transforms an `Order` on type `A` into an `Order` on type `B` by providing a function that | |
| * maps values of type `B` to values of type `A`. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to adapt an `Order` to compare a larger value by one | |
| * derived property. | |
| * | |
| * **Details** | |
| * | |
| * Applies the mapping function to both values before comparison. The mapping | |
| * function should be pure and not have side effects so the ordering properties | |
| * of the original order are preserved. | |
| * | |
| * **Example** (Mapping Input) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const byLength = Order.mapInput(Order.Number, (s: string) => s.length) | |
| * | |
| * console.log(byLength("a", "bb")) // -1 | |
| * console.log(byLength("bb", "a")) // 1 | |
| * console.log(byLength("aa", "bb")) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine mapped orders for multi-criteria comparison | |
| * @see {@link Struct} to create orders for structs with multiple fields | |
| * @category mapping | |
| * @since 2.0.0 | |
| */ | |
| <A, B>(self: Order<A>, f: (b: B) => A): Order<B> | |
| } = dual( | |
| 2, | |
| <A, B>(self: Order<A>, f: (b: B) => A): Order<B> => make((b1, b2) => self(f(b1), f(b2))) | |
| ) | |
| /** | |
| * Order instance for `Date` objects that compares them chronologically by their timestamp. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need chronological ordering for JavaScript date values. | |
| * | |
| * **Details** | |
| * | |
| * Compares dates by their underlying timestamp in milliseconds since the epoch. | |
| * Earlier dates are less than later dates. Invalid dates are compared through | |
| * their `getTime()` result. | |
| * | |
| * **Example** (Date Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const date1 = new Date("2023-01-01") | |
| * const date2 = new Date("2023-01-02") | |
| * | |
| * console.log(Order.Date(date1, date2)) // -1 | |
| * console.log(Order.Date(date2, date1)) // 1 | |
| * console.log(Order.Date(date1, date1)) // 0 | |
| * ``` | |
| * | |
| * @see {@link mapInput} to compare objects by a date property | |
| * @category instances | |
| * @since 2.0.0 | |
| */ | |
| export const Date: Order<Date> = mapInput(Number, (date) => date.getTime()) | |
| /** | |
| * Creates an `Order` for a tuple type based on orders for each element. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need fixed-length tuple ordering with per-position orders. | |
| * | |
| * **Details** | |
| * | |
| * Compares tuples element-by-element using the corresponding order and stops at | |
| * the first non-zero comparison result. Tuples must have the same length as the | |
| * order collection, and the result is `0` only if all elements are equal. | |
| * | |
| * **Example** (Tuple Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const tupleOrder = Order.Tuple([Order.Number, Order.String]) | |
| * | |
| * console.log(tupleOrder([1, "a"], [2, "b"])) // -1 | |
| * console.log(tupleOrder([1, "b"], [1, "a"])) // 1 | |
| * console.log(tupleOrder([1, "a"], [1, "a"])) // 0 | |
| * ``` | |
| * | |
| * @see {@link Array} to compare arrays with length consideration | |
| * @category combinators | |
| * @since 4.0.0 | |
| */ | |
| export function Tuple<const Elements extends ReadonlyArray<Order<any>>>( | |
| elements: Elements | |
| ): Order<{ readonly [I in keyof Elements]: [Elements[I]] extends [Order<infer A>] ? A : never }> { | |
| return make((self, that) => { | |
| const len = elements.length | |
| for (let i = 0; i < len; i++) { | |
| const o = elements[i](self[i], that[i]) | |
| if (o !== 0) { | |
| return o | |
| } | |
| } | |
| return 0 | |
| }) | |
| } | |
| /** | |
| * @since 4.0.0 | |
| */ | |
| function Array_<A>(O: Order<A>): Order<ReadonlyArray<A>> { | |
| return make((self, that) => { | |
| const aLen = self.length | |
| const bLen = that.length | |
| const len = Math.min(aLen, bLen) | |
| for (let i = 0; i < len; i++) { | |
| const o = O(self[i], that[i]) | |
| if (o !== 0) { | |
| return o | |
| } | |
| } | |
| return Number(aLen, bLen) | |
| }) | |
| } | |
| export { | |
| /** | |
| * Creates an `Order` for arrays by applying the given `Order` to each element, then comparing by length if all elements are equal. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need lexicographic ordering for arrays of one element type. | |
| * | |
| * **Details** | |
| * | |
| * Compares arrays element-by-element using the provided order and stops at the | |
| * first non-zero comparison result. If all elements are equal, shorter arrays | |
| * are less than longer arrays. The result is `0` only if arrays have the same | |
| * length and all elements are equal. | |
| * | |
| * **Example** (Array Element Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const arrayOrder = Order.Array(Order.Number) | |
| * | |
| * console.log(arrayOrder([1, 2], [1, 3])) // -1 | |
| * console.log(arrayOrder([1, 2], [1, 2, 3])) // -1 (shorter array is less) | |
| * console.log(arrayOrder([1, 2, 3], [1, 2])) // 1 (longer array is greater) | |
| * console.log(arrayOrder([1, 2], [1, 2])) // 0 | |
| * ``` | |
| * | |
| * @see {@link Tuple} for type-safe tuple ordering | |
| * @category combinators | |
| * @since 4.0.0 | |
| */ | |
| Array_ as Array | |
| } | |
| /** | |
| * Creates an `Order` for structs by applying the given `Order`s to each property in sequence. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need multi-field ordering for objects with known properties. | |
| * | |
| * **Details** | |
| * | |
| * Compares structs field-by-field in the key order of the fields object and | |
| * stops at the first non-zero comparison result. Field order matters: earlier | |
| * fields take precedence. The result is `0` only if all fields are equal. | |
| * | |
| * **Example** (Struct Ordering) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const personOrder = Order.Struct({ | |
| * name: Order.String, | |
| * age: Order.Number | |
| * }) | |
| * | |
| * const person1 = { name: "Alice", age: 30 } | |
| * const person2 = { name: "Bob", age: 25 } | |
| * const person3 = { name: "Alice", age: 25 } | |
| * | |
| * console.log(personOrder(person1, person2)) // -1 (Alice < Bob) | |
| * console.log(personOrder(person1, person3)) // 1 (same name, 30 > 25) | |
| * console.log(personOrder(person1, person1)) // 0 | |
| * ``` | |
| * | |
| * @see {@link combine} to combine orders manually | |
| * @see {@link mapInput} to extract and compare by a single property | |
| * @category combinators | |
| * @since 4.0.0 | |
| */ | |
| export function Struct<const R extends { readonly [x: string]: Order<any> }>( | |
| fields: R | |
| ): Order<{ [K in keyof R]: [R[K]] extends [Order<infer A>] ? A : never }> { | |
| const keys = Object.keys(fields) | |
| return make((self, that) => { | |
| for (const key of keys) { | |
| const o = fields[key](self[key], that[key]) | |
| if (o !== 0) { | |
| return o | |
| } | |
| } | |
| return 0 | |
| }) | |
| } | |
| /** | |
| * Checks whether one value is strictly less than another according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a boolean less-than predicate using an `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns `true` if the order returns `-1`, meaning the first value is less | |
| * than the second. Equal or greater values return `false`. | |
| * | |
| * **Example** (Less Than) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const isLessThanNumber = Order.isLessThan(Order.Number) | |
| * | |
| * console.log(isLessThanNumber(1, 2)) // true | |
| * console.log(isLessThanNumber(2, 1)) // false | |
| * console.log(isLessThanNumber(1, 1)) // false | |
| * ``` | |
| * | |
| * @see {@link isLessThanOrEqualTo} for non-strict less than or equal | |
| * @see {@link isGreaterThan} for strict greater than | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const isLessThan = <A>(O: Order<A>): { | |
| (that: A): (self: A) => boolean | |
| (self: A, that: A): boolean | |
| } => dual(2, (self: A, that: A) => O(self, that) === -1) | |
| /** | |
| * Checks whether one value is strictly greater than another according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a boolean greater-than predicate using an `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns `true` if the order returns `1`, meaning the first value is greater | |
| * than the second. Equal or lesser values return `false`. | |
| * | |
| * **Example** (Greater Than) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const isGreaterThanNumber = Order.isGreaterThan(Order.Number) | |
| * | |
| * console.log(isGreaterThanNumber(2, 1)) // true | |
| * console.log(isGreaterThanNumber(1, 2)) // false | |
| * console.log(isGreaterThanNumber(1, 1)) // false | |
| * ``` | |
| * | |
| * @see {@link isGreaterThanOrEqualTo} for non-strict greater than or equal | |
| * @see {@link isLessThan} for strict less than | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const isGreaterThan = <A>(O: Order<A>): { | |
| (that: A): (self: A) => boolean | |
| (self: A, that: A): boolean | |
| } => dual(2, (self: A, that: A) => O(self, that) === 1) | |
| /** | |
| * Checks whether one value is less than or equal to another according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a boolean less-than-or-equal predicate using an `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns `true` if the order returns `-1` or `0`, and returns `false` only if | |
| * the order returns `1`. | |
| * | |
| * **Example** (Less Than Or Equal) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const isLessThanOrEqualToNumber = Order.isLessThanOrEqualTo(Order.Number) | |
| * | |
| * console.log(isLessThanOrEqualToNumber(1, 2)) // true | |
| * console.log(isLessThanOrEqualToNumber(1, 1)) // true | |
| * console.log(isLessThanOrEqualToNumber(2, 1)) // false | |
| * ``` | |
| * | |
| * @see {@link isLessThan} for strict less than | |
| * @see {@link isGreaterThan} for strict greater than | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const isLessThanOrEqualTo = <A>(O: Order<A>): { | |
| (that: A): (self: A) => boolean | |
| (self: A, that: A): boolean | |
| } => dual(2, (self: A, that: A) => O(self, that) !== 1) | |
| /** | |
| * Checks whether one value is greater than or equal to another according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a boolean greater-than-or-equal predicate using an | |
| * `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns `true` if the order returns `1` or `0`, and returns `false` only if | |
| * the order returns `-1`. | |
| * | |
| * **Example** (Greater Than Or Equal) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const isGreaterThanOrEqualToNumber = Order.isGreaterThanOrEqualTo(Order.Number) | |
| * | |
| * console.log(isGreaterThanOrEqualToNumber(2, 1)) // true | |
| * console.log(isGreaterThanOrEqualToNumber(1, 1)) // true | |
| * console.log(isGreaterThanOrEqualToNumber(1, 2)) // false | |
| * ``` | |
| * | |
| * @see {@link isGreaterThan} for strict greater than | |
| * @see {@link isLessThanOrEqualTo} for less than or equal | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const isGreaterThanOrEqualTo = <A>(O: Order<A>): { | |
| (that: A): (self: A) => boolean | |
| (self: A, that: A): boolean | |
| } => dual(2, (self: A, that: A) => O(self, that) !== -1) | |
| /** | |
| * Returns the minimum of two values according to the given order. If they are equal, returns the first argument. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to select the smaller of two values according to an | |
| * `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns the value that compares as less than or equal to the other value. If | |
| * values are equal, the first argument is returned. | |
| * | |
| * **Example** (Minimum Value) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const minNumber = Order.min(Order.Number) | |
| * | |
| * console.log(minNumber(1, 2)) // 1 | |
| * console.log(minNumber(2, 1)) // 1 | |
| * console.log(minNumber(1, 1)) // 1 | |
| * ``` | |
| * | |
| * @see {@link max} for the maximum of two values | |
| * @see {@link clamp} to clamp a value between min and max | |
| * @category comparisons | |
| * @since 2.0.0 | |
| */ | |
| export const min = <A>(O: Order<A>): { | |
| (that: A): (self: A) => A | |
| (self: A, that: A): A | |
| } => dual(2, (self: A, that: A) => self === that || O(self, that) < 1 ? self : that) | |
| /** | |
| * Returns the maximum of two values according to the given order. If they are equal, returns the first argument. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to select the larger of two values according to an | |
| * `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns the value that compares as greater than or equal to the other value. | |
| * If values are equal, the first argument is returned. | |
| * | |
| * **Example** (Maximum Value) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const maxNumber = Order.max(Order.Number) | |
| * | |
| * console.log(maxNumber(1, 2)) // 2 | |
| * console.log(maxNumber(2, 1)) // 2 | |
| * console.log(maxNumber(1, 1)) // 1 | |
| * ``` | |
| * | |
| * @see {@link min} for the minimum of two values | |
| * @see {@link clamp} to clamp a value between min and max | |
| * @category comparisons | |
| * @since 2.0.0 | |
| */ | |
| export const max = <A>(O: Order<A>): { | |
| (that: A): (self: A) => A | |
| (self: A, that: A): A | |
| } => dual(2, (self: A, that: A) => self === that || O(self, that) > -1 ? self : that) | |
| /** | |
| * Restricts a value between a minimum and a maximum according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to clamp a value to an inclusive range according to an | |
| * `Order`. | |
| * | |
| * **Details** | |
| * | |
| * Returns the value itself when it is between minimum and maximum, inclusive. | |
| * Values below the range return minimum, and values above the range return | |
| * maximum. The minimum must be less than or equal to the maximum according to | |
| * the order. | |
| * | |
| * **Example** (Clamping Values) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const clamp = Order.clamp(Order.Number)({ minimum: 1, maximum: 5 }) | |
| * | |
| * console.log(clamp(3)) // 3 | |
| * console.log(clamp(0)) // 1 | |
| * console.log(clamp(6)) // 5 | |
| * ``` | |
| * | |
| * @see {@link min} for the minimum of two values | |
| * @see {@link max} for the maximum of two values | |
| * @see {@link isBetween} to check if a value is within a range | |
| * @category comparisons | |
| * @since 2.0.0 | |
| */ | |
| export const clamp = <A>(O: Order<A>): { | |
| (options: { | |
| minimum: A | |
| maximum: A | |
| }): (self: A) => A | |
| (self: A, options: { | |
| minimum: A | |
| maximum: A | |
| }): A | |
| } => | |
| dual( | |
| 2, | |
| (self: A, options: { | |
| minimum: A | |
| maximum: A | |
| }): A => min(O)(options.maximum, max(O)(options.minimum, self)) | |
| ) | |
| /** | |
| * Checks whether a value is between a minimum and a maximum (inclusive) according to the given order. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need range checks that respect domain-specific ordering, such as | |
| * dates, versions, or custom priorities, instead of JavaScript numeric | |
| * comparison. | |
| * | |
| * **Details** | |
| * | |
| * Returns `true` when the value is greater than or equal to minimum and less | |
| * than or equal to maximum. Values outside the range return `false`. Both | |
| * bounds are inclusive. | |
| * | |
| * **Example** (Checking Range) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const betweenNumber = Order.isBetween(Order.Number) | |
| * | |
| * console.log(betweenNumber(5, { minimum: 1, maximum: 10 })) // true | |
| * console.log(betweenNumber(1, { minimum: 1, maximum: 10 })) // true | |
| * console.log(betweenNumber(10, { minimum: 1, maximum: 10 })) // true | |
| * console.log(betweenNumber(0, { minimum: 1, maximum: 10 })) // false | |
| * console.log(betweenNumber(11, { minimum: 1, maximum: 10 })) // false | |
| * ``` | |
| * | |
| * @see {@link clamp} to clamp a value to a range | |
| * @see {@link isLessThanOrEqualTo} for less than or equal check | |
| * @see {@link isGreaterThanOrEqualTo} for greater than or equal check | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const isBetween = <A>(O: Order<A>): { | |
| (options: { | |
| minimum: A | |
| maximum: A | |
| }): (self: A) => boolean | |
| (self: A, options: { | |
| minimum: A | |
| maximum: A | |
| }): boolean | |
| } => | |
| dual( | |
| 2, | |
| (self: A, options: { | |
| minimum: A | |
| maximum: A | |
| }): boolean => !isLessThan(O)(self, options.minimum) && !isGreaterThan(O)(self, options.maximum) | |
| ) | |
| /** | |
| * Creates a `Reducer` for combining `Order` instances, useful for aggregating orders in collections. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a reducer that combines orders. | |
| * | |
| * **Details** | |
| * | |
| * Returns a reducer that combines orders using `combine`, uses `alwaysEqual` as | |
| * the identity element for empty collections, and uses `combineAll` for | |
| * combining collections of orders. The reducer can be used with fold operations | |
| * on collections. | |
| * | |
| * **Example** (Creating a Reducer) | |
| * | |
| * ```ts | |
| * import { Order } from "effect" | |
| * | |
| * const reducer = Order.makeReducer<number>() | |
| * const orders = [Order.Number, Order.flip(Order.Number)] | |
| * | |
| * const combined = reducer.combineAll(orders) | |
| * console.log(combined(1, 2)) // -1 (uses first order) | |
| * ``` | |
| * | |
| * @see {@link combine} to combine two orders | |
| * @see {@link combineAll} to combine multiple orders | |
| * @see {@link Reducer} for reducing orders as a collection operation | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export function makeReducer<A>() { | |
| return Reducer.make<Order<A>>( | |
| combine, | |
| () => 0, | |
| combineAll | |
| ) | |
| } | |
Xet Storage Details
- Size:
- 33 kB
- Xet hash:
- f57dc7d327c96686dd5ec84dbf8bbc9ca69aa52fda469986137eb3af9cc1a439
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.