From 6ea832f002bc5cebceb575059a4913b6fb7f99ef Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 19:41:49 -0500 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=8E=A8=20(@coven/iterables)=20impro?= =?UTF-8?q?ve=20`repeat`=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/iterables/repeat.ts | 3 ++- @coven/iterables/tests/repeat.test.ts | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/@coven/iterables/repeat.ts b/@coven/iterables/repeat.ts index 5fa1018..16e6660 100644 --- a/@coven/iterables/repeat.ts +++ b/@coven/iterables/repeat.ts @@ -1,3 +1,4 @@ +import type { Numeric } from "@coven/types"; import { iteratorFunctionToIterableIterator } from "./iteratorFunctionToIterableIterator.ts"; /** @@ -13,7 +14,7 @@ import { iteratorFunctionToIterableIterator } from "./iteratorFunctionToIterable * @returns Curried function with `item` in context. */ export const repeat = - (times: number): ((item: Item) => IterableIterator) => + (times: Numeric): ((item: Item) => IterableIterator) => (item: Item) => iteratorFunctionToIterableIterator(function* (): Generator { if (times === Infinity) { diff --git a/@coven/iterables/tests/repeat.test.ts b/@coven/iterables/tests/repeat.test.ts index 3f997b9..f63b993 100644 --- a/@coven/iterables/tests/repeat.test.ts +++ b/@coven/iterables/tests/repeat.test.ts @@ -3,6 +3,7 @@ import { iterableToArray } from "../iterableToArray.ts"; import { repeat } from "../repeat.ts"; const repeat3Times = repeat(3); +const repeat3nTimes = repeat(3n); Deno.test( 'a call to repeat with the string "test" and the number 3 returns an array with 3 strings "test" on it', @@ -13,3 +14,13 @@ Deno.test( "test", ]), ); + +Deno.test( + 'a call to repeat with the string "test" and the bigint 3n returns an array with 3 strings "test" on it', + () => + assertEquals(iterableToArray(repeat3nTimes("test")), [ + "test", + "test", + "test", + ]), +); From cdfd09c888d2f0baf0943abd50e7988e07256faa Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 19:46:42 -0500 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20(@coven/memo)=20m?= =?UTF-8?q?ake=20`memoFunction`=20freeze=20the=20generated=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/memo/memoFunction.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/@coven/memo/memoFunction.ts b/@coven/memo/memoFunction.ts index d13fab0..faa824d 100644 --- a/@coven/memo/memoFunction.ts +++ b/@coven/memo/memoFunction.ts @@ -31,9 +31,10 @@ export const memoFunction = ( ...(parameters as ReadonlyArray), ) as ReturnType; - return ((...parameters: MemoizableTuple) => + return Object.freeze((...parameters: MemoizableTuple) => memoizedOutputCache.getOrInsertComputed( memo(parameters), cacheReturnValue, - )) as unknown as Cacheable; + ), + ) as unknown as Cacheable; }; From 0eeba528819f30a124bc4995376e57244dfc5485 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 20:55:08 -0500 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9C=A8=20(@coven/types)=20add=20new=20?= =?UTF-8?q?`ExpectedStringables`=20type.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/types/ExpectedStringables.ts | 21 +++++++++++++++++++++ @coven/types/mod.ts | 1 + 2 files changed, 22 insertions(+) create mode 100644 @coven/types/ExpectedStringables.ts diff --git a/@coven/types/ExpectedStringables.ts b/@coven/types/ExpectedStringables.ts new file mode 100644 index 0000000..6b7256d --- /dev/null +++ b/@coven/types/ExpectedStringables.ts @@ -0,0 +1,21 @@ +import type { Stringable } from "./Stringable.ts"; + +/** + * Given an array of {@linkcode Stringable}, generate a type that will expect + * those {@linkcode Stringable}s in the given order in a string. + * + * @example + * ```typescript + * type Example = ExpectedStringables<["a, b"]>; // `${string}a${string}b${string}` + * ``` + * @template Stringables Expected {@linkcode Stringable}s. + */ +export type ExpectedStringables = + Stringables extends ( + [ + infer Head extends Stringable, + ...infer Tail extends readonly Stringable[], + ] + ) ? + `${string}${Head}${ExpectedStringables}` + : `${string}`; diff --git a/@coven/types/mod.ts b/@coven/types/mod.ts index 5202e90..4c5453c 100644 --- a/@coven/types/mod.ts +++ b/@coven/types/mod.ts @@ -20,6 +20,7 @@ export type { EntryKey } from "./EntryKey.ts"; export type { EntryOf } from "./EntryOf.ts"; export type { EntryValue } from "./EntryValue.ts"; export type { Enumerate } from "./Enumerate.ts"; +export type { ExpectedStringables } from "./ExpectedStringables.ts"; export type { Fallback } from "./Fallback.ts"; export type { Falsy } from "./Falsy.ts"; export type { Filter } from "./Filter.ts"; From 9248fab487812a24f9cbab5aa6eb3ca208759be8 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 21:04:11 -0500 Subject: [PATCH 04/14] =?UTF-8?q?=E2=9C=A8=20(@coven/expression)=20add=20n?= =?UTF-8?q?ew=20`getGroups`=20util.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/expression/getGroups.ts | 55 +++++++++++++++++++++++ @coven/expression/mod.ts | 1 + @coven/expression/tests/getGroups.test.ts | 15 +++++++ 3 files changed, 71 insertions(+) create mode 100644 @coven/expression/getGroups.ts create mode 100644 @coven/expression/tests/getGroups.test.ts diff --git a/@coven/expression/getGroups.ts b/@coven/expression/getGroups.ts new file mode 100644 index 0000000..492fe1e --- /dev/null +++ b/@coven/expression/getGroups.ts @@ -0,0 +1,55 @@ +import { EMPTY_OBJECT } from "@coven/constants"; +import { memo } from "@coven/memo"; +import type { + ExpectedStringables, + ReadonlyRecord, + RegularExpressionFlags, + Stringable, +} from "@coven/types"; + +/** + * @internal Small type to work with {@linkcode ExpectedStringables} to add + * the expected parts of a group name to the given strings. + */ +type WrapGroupKeys = + GroupKeys extends ( + [ + infer Head extends Stringable, + ...infer Tail extends readonly Stringable[], + ] + ) ? + [`(?<${Head}>`, ...WrapGroupKeys] + : readonly []; + +/** + * Given a regular expression (ideally generated by `@coven/expression`'s `build` + * or `buildUnicode`), extract only the groups on it. + * + * @example Escape given value + * ```typescript + * import { buildUnicode, captureNamed, WILDCARD } from "@coven/expression"; + * + * const getExample = getGroups<["example"]>( + * buildUnicode(captureNamed("example")(WILDCARD)) // /(?.)/ + * ); + * + * getExample("🔮"); // { example: "🔮" } + * ``` + * @param escaped Value to escape. + * @returns Escaped value. + */ +export const getGroups = + ({ + flags, + source, + }: { + flags: RegularExpressionFlags; + source: ExpectedStringables>; + }): (( + stringable: Stringable, + ) => Partial>) => + (stringable) => + memo( + new RegExp(source, flags).exec(`${stringable}`)?.groups + ?? EMPTY_OBJECT, + ) as ReadonlyRecord<`${GroupKeys[number]}`, string>; diff --git a/@coven/expression/mod.ts b/@coven/expression/mod.ts index f90050c..98a8009 100644 --- a/@coven/expression/mod.ts +++ b/@coven/expression/mod.ts @@ -33,6 +33,7 @@ export { controlCharacter } from "./controlCharacter.ts"; export { disjunction } from "./disjunction.ts"; export { escape } from "./escape.ts"; export { exists } from "./exists.ts"; +export { getGroups } from "./getGroups.ts"; export { group } from "./group.ts"; export { hexadecimal } from "./hexadecimal.ts"; export type { HexadecimalDigit } from "./HexadecimalDigit.ts"; diff --git a/@coven/expression/tests/getGroups.test.ts b/@coven/expression/tests/getGroups.test.ts new file mode 100644 index 0000000..2d3b118 --- /dev/null +++ b/@coven/expression/tests/getGroups.test.ts @@ -0,0 +1,15 @@ +import { memo } from "@coven/memo"; +import { assertStrictEquals } from "@std/assert"; +import { buildUnicode } from "../buildUnicode.ts"; +import { captureNamed } from "../captureNamed.ts"; +import { getGroups } from "../getGroups.ts"; +import { WILDCARD } from "../WILDCARD.ts"; + +Deno.test("Groups captured correctly", () => + assertStrictEquals( + getGroups<["example"]>(buildUnicode(captureNamed("example")(WILDCARD)))( + "🔮", + ), + memo({ example: "🔮" }), + ), +); From d5878814e33077a0bf83df077596f5b7e1d03736 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 22:37:42 -0500 Subject: [PATCH 05/14] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(@coven/math)=20refa?= =?UTF-8?q?ctor=20to=20be=20more=20robust=20and=20fast.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/math/Calculation.ts | 14 +++- @coven/math/MaybeInfinity.ts | 4 - @coven/math/PreciseFunction.ts | 6 ++ @coven/math/PreciseToTypeFunction.ts | 4 + @coven/math/PreciseTuple.ts | 5 +- @coven/math/README.md | 1 + @coven/math/add.ts | 33 +++++++-- @coven/math/bigIntMin.ts | 14 ---- @coven/math/calculate.ts | 89 +++++++++++------------ @coven/math/divide.ts | 42 ++++++++++- @coven/math/getBaseAndZeroes.ts | 34 +++++++++ @coven/math/getNumberParts.ts | 40 ++++++++++ @coven/math/mod.ts | 7 +- @coven/math/multiply.ts | 37 ++++++++-- @coven/math/numberToPrecise.ts | 43 ++++++----- @coven/math/pipe.ts | 35 --------- @coven/math/precise.ts | 47 ++---------- @coven/math/preciseAdd.ts | 45 +++++------- @coven/math/preciseDivide.ts | 51 +++++++------ @coven/math/preciseMultiply.ts | 31 +++----- @coven/math/preciseSubtract.ts | 22 +++--- @coven/math/preciseToBigInt.ts | 22 ++++++ @coven/math/preciseToNumber.ts | 13 +++- @coven/math/subtract.ts | 32 +++++++- @coven/math/tests/add.test.ts | 12 +++ @coven/math/tests/calculate.test.ts | 30 +++++--- @coven/math/tests/divide.test.ts | 12 +++ @coven/math/tests/multiply.test.ts | 12 +++ @coven/math/tests/numberToPrecise.test.ts | 45 +++++++----- @coven/math/tests/precise.test.ts | 14 ++-- @coven/math/tests/preciseAdd.test.ts | 33 +++++---- @coven/math/tests/preciseDivide.test.ts | 33 +++++---- @coven/math/tests/preciseMultiply.test.ts | 37 ++++------ @coven/math/tests/preciseSubtract.test.ts | 42 +++++++---- @coven/math/tests/preciseToNumber.test.ts | 42 +++++------ @coven/math/tests/subtract.test.ts | 14 ++++ 36 files changed, 600 insertions(+), 397 deletions(-) delete mode 100644 @coven/math/MaybeInfinity.ts create mode 100644 @coven/math/PreciseFunction.ts create mode 100644 @coven/math/PreciseToTypeFunction.ts delete mode 100644 @coven/math/bigIntMin.ts create mode 100644 @coven/math/getBaseAndZeroes.ts create mode 100644 @coven/math/getNumberParts.ts delete mode 100644 @coven/math/pipe.ts create mode 100644 @coven/math/preciseToBigInt.ts diff --git a/@coven/math/Calculation.ts b/@coven/math/Calculation.ts index 74ab220..ea69acd 100644 --- a/@coven/math/Calculation.ts +++ b/@coven/math/Calculation.ts @@ -1,8 +1,11 @@ +import { Maybe } from "@coven/types"; +import { Precise } from "./PreciseTuple.ts"; + /** * Object returned by the `calculate` function, which recursively returns itself * from all its methods. To get the value the dev has to run `toValue()`. */ -export type Calculation = Readonly<{ +export type Calculation = Readonly<{ /** * Divide previous `value` in calculation by the given `divisor`. * @@ -27,6 +30,11 @@ export type Calculation = Readonly<{ */ plus: (addend: number) => Calculation; + /** + * Current {@linkcode Precise} value. + */ + precise: Maybe; + /** * Multiplies previous `value` in calculation times the given `multiplier`. * @@ -36,7 +44,7 @@ export type Calculation = Readonly<{ times: (multiplier: number) => Calculation; /** - * Current value of the calculation. + * Current `number` value. */ - total: Value; + total: Maybe; }>; diff --git a/@coven/math/MaybeInfinity.ts b/@coven/math/MaybeInfinity.ts deleted file mode 100644 index 22c514b..0000000 --- a/@coven/math/MaybeInfinity.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Dividing by zero would yield `Infinity`. - */ -export type MaybeInfinity = bigint | typeof Infinity; diff --git a/@coven/math/PreciseFunction.ts b/@coven/math/PreciseFunction.ts new file mode 100644 index 0000000..09577a0 --- /dev/null +++ b/@coven/math/PreciseFunction.ts @@ -0,0 +1,6 @@ +import type { Maybe, Multary } from "@coven/types"; +import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; +import type { Precise } from "./PreciseTuple.ts"; + +export type PreciseFunction = Precise> = + Multary>; diff --git a/@coven/math/PreciseToTypeFunction.ts b/@coven/math/PreciseToTypeFunction.ts new file mode 100644 index 0000000..4162269 --- /dev/null +++ b/@coven/math/PreciseToTypeFunction.ts @@ -0,0 +1,4 @@ +import type { Multary } from "@coven/types"; +import type { Precise } from "./PreciseTuple.ts"; + +export type PreciseToTypeFunction = Multary; diff --git a/@coven/math/PreciseTuple.ts b/@coven/math/PreciseTuple.ts index 752d273..2545d0b 100644 --- a/@coven/math/PreciseTuple.ts +++ b/@coven/math/PreciseTuple.ts @@ -1,7 +1,4 @@ -import type { MaybeInfinity } from "./MaybeInfinity.ts"; - /** * Type to precisely represent a number as a tuple `[base, exponent]`. - * It can be `[Infinity]`. */ -export type Precise = Readonly<[base: MaybeInfinity, exponent?: bigint]>; +export type Precise = Readonly<[base: bigint, exponent: bigint]>; diff --git a/@coven/math/README.md b/@coven/math/README.md index 8a102ab..5d0466d 100644 --- a/@coven/math/README.md +++ b/@coven/math/README.md @@ -31,6 +31,7 @@ JavaScript runtimes. import { calculate } from "@coven/math"; calculate(0.1).plus(0.2).total; // 0.3 🤯 +calculate(1e20).plus(0.1).minus(1e20).total; // 0.1 🤯 ``` ## Other links diff --git a/@coven/math/add.ts b/@coven/math/add.ts index 972aca8..be7628d 100644 --- a/@coven/math/add.ts +++ b/@coven/math/add.ts @@ -1,8 +1,13 @@ -import { pipe } from "./pipe.ts"; +import { memoFunction } from "@coven/memo"; +import { isUndefined } from "@coven/predicates"; +import type { Unary } from "@coven/types"; +import { always } from "@coven/utils"; +import { numberToPrecise } from "./numberToPrecise.ts"; import { preciseAdd } from "./preciseAdd.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; /** - * Curried add operation using {@linkcode pipe} with {@linkcode preciseAdd}. + * Curried add operation using {@linkcode preciseAdd}. * * @example * ```typescript @@ -11,10 +16,28 @@ import { preciseAdd } from "./preciseAdd.ts"; * addDot2(0.1); // 0.3 * ``` * @see {@linkcode preciseAdd} - * @see {@linkcode pipe} * * @param augend Augend value to be on the right side. * @returns Curried function with `augend` in context. */ -export const add: (augend: number) => (addend: number) => number = - pipe(preciseAdd); +export const add: Unary< + [augend: number], + Unary<[addend: number], number> +> = memoFunction((augend) => { + const preciseAugend = numberToPrecise(augend); + const preciseAddAugend = + isUndefined(preciseAugend) ? undefined : preciseAdd(...preciseAugend); + + return isUndefined(preciseAugend) ? + always(augend) + : memoFunction((addend) => { + const preciseAddend = numberToPrecise(addend); + + return ( + isUndefined(preciseAddend) + || isUndefined(preciseAddAugend) + ) ? + addend + : preciseToNumber(...preciseAddAugend(...preciseAddend)); + }); +}); diff --git a/@coven/math/bigIntMin.ts b/@coven/math/bigIntMin.ts deleted file mode 100644 index f481fc5..0000000 --- a/@coven/math/bigIntMin.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Like `Math.min` but for `bigint` values. - * - * @example - * ```typescript - * bigIntMin(5n, 1n, 10n); // 1n - * ``` - * @see {@linkcode https://coven.to/mdn/Math/min Math.min} - * - * @param bigInts Array of `bigint` values to compare. - * @returns Minimum value of the `bigint` array. - */ -export const bigIntMin = (...bigints: ReadonlyArray): bigint => - bigints.reduce((min, bigint) => (bigint < min ? bigint : min)); diff --git a/@coven/math/calculate.ts b/@coven/math/calculate.ts index a113630..415bbaa 100644 --- a/@coven/math/calculate.ts +++ b/@coven/math/calculate.ts @@ -1,9 +1,14 @@ -import { memoFunction } from "@coven/memo"; -import { add } from "./add.ts"; +import { isUndefined } from "@coven/predicates"; +import type { Maybe } from "@coven/types"; import type { Calculation } from "./Calculation.ts"; -import { divide } from "./divide.ts"; -import { multiply } from "./multiply.ts"; -import { subtract } from "./subtract.ts"; +import { numberToPrecise } from "./numberToPrecise.ts"; +import { preciseAdd } from "./preciseAdd.ts"; +import { preciseDivide } from "./preciseDivide.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; +import { preciseMultiply } from "./preciseMultiply.ts"; +import { preciseSubtract } from "./preciseSubtract.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; +import type { Precise } from "./PreciseTuple.ts"; /** * A chainable set of operations. @@ -13,50 +18,44 @@ import { subtract } from "./subtract.ts"; * calculate(0.1).plus(0.2).total; // 0.3 * calculate(0.7).plus(0.3).dividedBy(4).times(2).minus(0.2).total; // 0.3 * ``` - * @see {@linkcode add} - * @see {@linkcode divide} - * @see {@linkcode multiply} - * @see {@linkcode subtract} + * @see {@linkcode preciseAdd} + * @see {@linkcode preciseDivide} + * @see {@linkcode preciseMultiply} + * @see {@linkcode preciseSubtract} * @param value Value to run operations on. * @returns An object with `divideBy`, `minus`, `plus` and `times` methods and a `value` property. */ -export const calculate: ( - value: Value, -) => Calculation = memoFunction((value) => ({ - /** - * Divide previous `value` in calculation by the given `divisor`. - * - * @param divisor Value to divide by. - * @returns Calculation (use `toValue()` to get the final value). - */ - dividedBy: (divisor: number) => calculate(divide(divisor)(value)), +export const calculate = (value: number): Calculation => { + let precise = numberToPrecise(value); - /** - * Subtracts given `subtrahend` to the current `value` in the calculation. - * - * @param subtrahend Value to subtract. - * @returns Calculation (use `toValue()` to get the final value). - */ - minus: (subtrahend: number) => calculate(subtract(subtrahend)(value)), + const calculationMethod = + >( + preciseFunction: PreciseFunction, + ) => + (right: number): Calculation => { + if (!isUndefined(precise)) { + const preciseRight = numberToPrecise(right); - /** - * Adds given `addend` to the current `value` in the calculation. - * - * @param subtrahend Value to add. - * @returns Calculation (use `toValue()` to get the final value). - */ - plus: (augend: number) => calculate(add(augend)(value)), + if (!isUndefined(preciseRight)) { + precise = preciseFunction(...preciseRight)(...precise); + } + } - /** - * Multiplies previous `value` in calculation times the given `multiplier`. - * - * @param divisor Value to multiply by. - * @returns Calculation (use `toValue()` to get the final value). - */ - times: (multiplier: number) => calculate(multiply(multiplier)(value)), + return calculation; + }; - /** - * Current value of the calculation. - */ - total: value, -})); + const calculation = Object.freeze({ + dividedBy: calculationMethod(preciseDivide), + minus: calculationMethod(preciseSubtract), + plus: calculationMethod(preciseAdd), + precise, + times: calculationMethod(preciseMultiply), + get total() { + return isUndefined(precise) ? undefined : ( + preciseToNumber(...precise) + ); + }, + }); + + return calculation; +}; diff --git a/@coven/math/divide.ts b/@coven/math/divide.ts index 815a9db..cfe2735 100644 --- a/@coven/math/divide.ts +++ b/@coven/math/divide.ts @@ -1,8 +1,13 @@ -import { pipe } from "./pipe.ts"; +import { memoFunction } from "@coven/memo"; +import { isUndefined } from "@coven/predicates"; +import type { Maybe, Unary } from "@coven/types"; +import { always } from "@coven/utils"; +import { numberToPrecise } from "./numberToPrecise.ts"; import { preciseDivide } from "./preciseDivide.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; /** - * Curried divide operation using {@linkcode pipe} with {@linkcode preciseDivide}. + * Curried divide operation using {@linkcode preciseDivide}. * * @example * ```typescript @@ -15,5 +20,34 @@ import { preciseDivide } from "./preciseDivide.ts"; * @param divisor Divisor to be used in the division. * @returns Curried function with `divisor` in context. */ -export const divide: (divisor: number) => (dividend: number) => number = - pipe(preciseDivide); +export const divide: Unary< + [augend: number], + Unary<[addend: number], Maybe> +> = memoFunction((divisor) => { + const preciseDivisor = numberToPrecise(divisor); + const preciseDivideDivisor = + isUndefined(preciseDivisor) ? undefined : ( + preciseDivide(...preciseDivisor) + ); + + return ( + isUndefined(preciseDivisor) ? + Number.isNaN(divisor) ? + always(NaN) + : (addend) => (Number.isFinite(addend) ? 0 : NaN) + : memoFunction((addend) => { + const preciseAddend = numberToPrecise(addend); + const preciseResult = + ( + isUndefined(preciseAddend) + || isUndefined(preciseDivideDivisor) + ) ? + undefined + : preciseDivideDivisor(...preciseAddend); + + return isUndefined(preciseResult) ? addend : ( + preciseToNumber(...preciseResult) + ); + }) + ); +}); diff --git a/@coven/math/getBaseAndZeroes.ts b/@coven/math/getBaseAndZeroes.ts new file mode 100644 index 0000000..fc272a1 --- /dev/null +++ b/@coven/math/getBaseAndZeroes.ts @@ -0,0 +1,34 @@ +import { + allow, + buildUnicode, + captureNamed, + complementClass, + disjunction, + END, + exists, + getGroups, + optional, + START, + WILDCARD, +} from "@coven/expression"; + +/** + * Get right side zeroes (to be added to the exponent). + * + * @example + * ```typescript + * getBaseAndZeroes(1000n); // { normalizedBase: "1", zeroes: "000" } + * getBaseAndZeroes(1n); // { normalizedBase: "1", zeroes: undefined } + * ``` + */ +export const getBaseAndZeroes = getGroups<["normalizedBase", "zeroes"]>( + buildUnicode( + START, + captureNamed("normalizedBase")( + allow(WILDCARD), + disjunction(complementClass(0), 0), + ), + optional(captureNamed("zeroes")(exists(0))), + END, + ), +); diff --git a/@coven/math/getNumberParts.ts b/@coven/math/getNumberParts.ts new file mode 100644 index 0000000..d01b480 --- /dev/null +++ b/@coven/math/getNumberParts.ts @@ -0,0 +1,40 @@ +import { + buildUnicode, + captureNamed, + DIGIT, + END, + escape, + exists, + getGroups, + group, + optional, + START, +} from "@coven/expression"; + +/** + * Get number parts {integral, fractional and exponent}. + * + * @example + * ```typescript + * getNumberParts("13"); // { integral: 13, fractional: undefined, exponent: undefined } + * getNumberParts("13.42"); // { integral: 13, fractional: 42, exponent: undefined } + * getNumberParts("13e42"); // { integral: 13, fractional: undefined, exponent: 42 } + * getNumberParts("13.42e42"); // { integral: 13, fractional: 42, exponent: 42 } + * getNumberParts("-13"); // { integral: -13, fractional: undefined, exponent: undefined } + * ``` + */ +export const getNumberParts = getGroups<["integral", "fractional", "exponent"]>( + buildUnicode( + START, + group( + captureNamed("integral")(optional("-"), exists(DIGIT)), + optional( + group(escape("."), captureNamed("fractional")(exists(DIGIT))), + ), + ), + optional( + group("e", captureNamed("exponent")(optional("-"), exists(DIGIT))), + ), + END, + ), +); diff --git a/@coven/math/mod.ts b/@coven/math/mod.ts index 7c4f863..ed0cf51 100644 --- a/@coven/math/mod.ts +++ b/@coven/math/mod.ts @@ -1,17 +1,18 @@ export { add } from "./add.ts"; -export { bigIntMin } from "./bigIntMin.ts"; export { calculate } from "./calculate.ts"; export type { Calculation } from "./Calculation.ts"; export { divide } from "./divide.ts"; -export type { MaybeInfinity } from "./MaybeInfinity.ts"; +export { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; +export { getNumberParts } from "./getNumberParts.ts"; export { multiply } from "./multiply.ts"; export { numberToPrecise } from "./numberToPrecise.ts"; -export { pipe } from "./pipe.ts"; export { precise } from "./precise.ts"; export { preciseAdd } from "./preciseAdd.ts"; export { preciseDivide } from "./preciseDivide.ts"; +export type { PreciseFunction } from "./PreciseFunction.ts"; export { preciseMultiply } from "./preciseMultiply.ts"; export { preciseSubtract } from "./preciseSubtract.ts"; +export { preciseToBigInt } from "./preciseToBigInt.ts"; export { preciseToNumber } from "./preciseToNumber.ts"; export type { Precise } from "./PreciseTuple.ts"; export { subtract } from "./subtract.ts"; diff --git a/@coven/math/multiply.ts b/@coven/math/multiply.ts index c371b7c..bd87ae9 100644 --- a/@coven/math/multiply.ts +++ b/@coven/math/multiply.ts @@ -1,8 +1,13 @@ -import { pipe } from "./pipe.ts"; +import { memoFunction } from "@coven/memo"; +import { isUndefined } from "@coven/predicates"; +import type { Unary } from "@coven/types"; +import { always } from "@coven/utils"; +import { numberToPrecise } from "./numberToPrecise.ts"; import { preciseMultiply } from "./preciseMultiply.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; /** - * Curried multiply operation using {@linkcode pipe} with {@linkcode preciseMultiply}. + * Curried multiply operation using {@linkcode preciseMultiply}. * * @example * ```typescript @@ -15,6 +20,28 @@ import { preciseMultiply } from "./preciseMultiply.ts"; * @param multiplier Multiplier value to be used in the multiplication. * @returns Curried function with `multiplier` in context. */ -export const multiply: ( - multiplier: number, -) => (multiplicand: number) => number = pipe(preciseMultiply); +export const multiply: Unary< + [multiplier: number], + Unary<[addend: number], number> +> = memoFunction((multiplier) => { + const preciseMultiplier = numberToPrecise(multiplier); + const preciseAddAugend = + isUndefined(preciseMultiplier) ? undefined : ( + preciseMultiply(...preciseMultiplier) + ); + + return isUndefined(preciseMultiplier) ? + always(multiplier) + : memoFunction((multiplicand) => { + const preciseMultiplicand = numberToPrecise(multiplicand); + + return ( + isUndefined(preciseMultiplicand) + || isUndefined(preciseAddAugend) + ) ? + multiplicand + : preciseToNumber( + ...preciseAddAugend(...preciseMultiplicand), + ); + }); +}); diff --git a/@coven/math/numberToPrecise.ts b/@coven/math/numberToPrecise.ts index 879500c..2aa845f 100644 --- a/@coven/math/numberToPrecise.ts +++ b/@coven/math/numberToPrecise.ts @@ -1,4 +1,6 @@ import { memoFunction } from "@coven/memo"; +import type { Maybe, Unary } from "@coven/types"; +import { getNumberParts } from "./getNumberParts.ts"; import { precise } from "./precise.ts"; import type { Precise } from "./PreciseTuple.ts"; @@ -7,28 +9,35 @@ import type { Precise } from "./PreciseTuple.ts"; * * @example * ```typescript - * numberToPrecise(13); // [13n] + * numberToPrecise(13); // [13n, 0n] * numberToPrecise(1.3); // [13n, -1n] * numberToPrecise(1300); // [13n, 2n] + * numberToPrecise(Infinity); // undefined + * numberToPrecise(-Infinity); // undefined + * numberToPrecise(NaN); // undefined * ``` * @see {@linkcode precise} * @param number Number to convert. * @returns A {@linkcode Precise} representation of the given `number`. */ -export const numberToPrecise: (number: number) => Precise = memoFunction( - (number: number) => { - if (Number.isFinite(number) && !Number.isInteger(number)) { - const [base = "0", exponent = "0"] = `${number}`.split("e"); - const [integral = "0", fractional = ""] = `${base}`.split("."); +export const numberToPrecise: Unary< + [number: number], + Maybe +> = memoFunction((number: number) => { + if (Number.isFinite(number) && !Number.isInteger(number)) { + const { + integral = "", + fractional = "", + exponent = "0", + } = getNumberParts(number); - return precise( - BigInt(`${integral}${fractional}`), - -(BigInt(fractional.length) - BigInt(exponent)), - ); - } else { - return precise( - (Number.isInteger(number) ? BigInt(number) : number) as number, - ); - } - }, -); + return precise( + BigInt(`${integral}${fractional}`), + -(BigInt(fractional.length) - BigInt(exponent)), + ); + } else { + return Number.isFinite(number) && !Number.isNaN(number) ? + precise(BigInt(number), 0n) + : undefined; + } +}); diff --git a/@coven/math/pipe.ts b/@coven/math/pipe.ts deleted file mode 100644 index 52fa77c..0000000 --- a/@coven/math/pipe.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Precise } from "./PreciseTuple.ts"; -import { numberToPrecise } from "./numberToPrecise.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; - -/** - * Turns a {@linkcode Precise} operation into a number operation. - * - * @example - * ```typescript - * import { preciseAdd } from "@coven/math"; - * - * const add = pipe(preciseAdd); - * - * add(0.1)(0.2); // 0.3 - * ``` - * @see {@linkcode numberToPrecise} - * @see {@linkcode Precise} - * @see {@linkcode preciseToNumber} - * @param preciseOperation {@linkcode Precise} operation function. - * @returns Number to number operation generated from `preciseOperation`. - */ -export const pipe = - < - PreciseOperation extends ( - ...right: Precise - ) => (...left: Precise) => Precise, - >( - preciseOperation: PreciseOperation, - ): ((right: number) => (left: number) => number) => - (right) => { - const rightOperation = preciseOperation(...numberToPrecise(right)); - - return (left) => - preciseToNumber(...rightOperation(...numberToPrecise(left))); - }; diff --git a/@coven/math/precise.ts b/@coven/math/precise.ts index 0ca6e84..76fd8b8 100644 --- a/@coven/math/precise.ts +++ b/@coven/math/precise.ts @@ -1,24 +1,6 @@ -import { EMPTY_ARRAY } from "@coven/constants"; -import { - allow, - buildUnicode, - captureNamed, - complementClass, - END, - START, - WILDCARD, -} from "@coven/expression"; import { memo, memoFunction } from "@coven/memo"; -import { isBigInt } from "@coven/predicates"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; import type { Precise } from "./PreciseTuple.ts"; - -const rightSideZeroes = buildUnicode( - START, - captureNamed("normalizedBase")(allow(WILDCARD), complementClass(0)), - captureNamed("zeroes")(allow(0)), - END, -); +import { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; /** * Takes a `base` and `exponent` and normalizes it returning a {@linkcode Precise}. @@ -35,27 +17,12 @@ const rightSideZeroes = buildUnicode( * @returns A normalized {@linkcode Precise} value. */ export const precise: { - (base: bigint, exponent?: bigint): Precise; - (base: number): Precise; -} = memoFunction<(base: MaybeInfinity, exponent?: bigint) => Precise>( - (base, exponent = 0n) => { - if (isBigInt(base)) { - const { normalizedBase, zeroes } = rightSideZeroes.exec(`${base}`) - ?.groups as Readonly<{ - normalizedBase: `${bigint}`; - zeroes: `${bigint}`; - }>; - const normalizedExponent = - BigInt(zeroes.length) + (exponent as bigint); + (base: bigint, exponent: bigint): Precise; +} = memoFunction<(base: bigint, exponent: bigint) => Precise>( + (base, exponent) => { + const { normalizedBase = "0", zeroes = "" } = getBaseAndZeroes(base); + const normalizedExponent = BigInt(zeroes.length) + exponent; - return memo([ - BigInt(normalizedBase), - ...(normalizedExponent === 0n ? EMPTY_ARRAY : ( - [normalizedExponent] - )), - ]) as Precise; - } else { - return memo([base]) as Precise; - } + return memo([BigInt(normalizedBase), normalizedExponent]); }, ); diff --git a/@coven/math/preciseAdd.ts b/@coven/math/preciseAdd.ts index 7693df2..fc868ff 100644 --- a/@coven/math/preciseAdd.ts +++ b/@coven/math/preciseAdd.ts @@ -1,50 +1,39 @@ import { memoFunction } from "@coven/memo"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; -import type { Precise } from "./PreciseTuple.ts"; -import { bigIntMin } from "./bigIntMin.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; import { precise } from "./precise.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; +import { preciseToBigInt } from "./preciseToBigInt.ts"; /** - * Curried add operation using the internal {@linkcode Precise} type. + * Curried add operation using the internal `Precise` type. * * @example * ```typescript - * const addDot2 = preciseAdd(2n); + * const addDot2 = preciseAdd(2n, 0n); * * addDot2(1n, -1n); // [3n, -1n] * ``` - * @see {@linkcode bigIntMin} * @see {@linkcode precise} - * @see {@linkcode Precise} - * @see {@linkcode preciseToNumber} + * @see {@linkcode PreciseFunction} + * @see {@linkcode preciseToBigInt} * @param augendBase Augend base to use in the right side of the addition. * @param augendExponent Augend exponent to use in the right side of the addition. * @returns Curried function with `augendBase` and `augendExponent` in context. */ -export const preciseAdd: ( - augendBase: MaybeInfinity, - augendExponent?: bigint, -) => (addendBase: MaybeInfinity, addendExponent?: bigint) => Precise = - memoFunction((augendBase, augendExponent) => +export const preciseAdd: PreciseFunction = memoFunction( + (augendBase, augendExponent) => memoFunction((addendBase, addendExponent) => { - const commonExponent = bigIntMin( - addendExponent ?? 0n, - augendExponent ?? 0n, - ); + const commonExponent = + addendExponent < augendExponent ? addendExponent : ( + augendExponent + ); return precise( - BigInt( - preciseToNumber( + preciseToBigInt(augendBase, augendExponent - commonExponent) + + preciseToBigInt( addendBase, - (addendExponent ?? 0n) - commonExponent, - ) - + preciseToNumber( - augendBase, - (augendExponent ?? 0n) - commonExponent, - ), - ), + addendExponent - commonExponent, + ), commonExponent, ); }), - ); +); diff --git a/@coven/math/preciseDivide.ts b/@coven/math/preciseDivide.ts index 4868814..67f0088 100644 --- a/@coven/math/preciseDivide.ts +++ b/@coven/math/preciseDivide.ts @@ -1,11 +1,11 @@ import { memoFunction } from "@coven/memo"; +import type { Maybe } from "@coven/types"; import { always } from "@coven/utils"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; -import type { Precise } from "./PreciseTuple.ts"; -import { numberToPrecise } from "./numberToPrecise.ts"; import { precise } from "./precise.ts"; -import { preciseMultiply } from "./preciseMultiply.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; +import type { Precise } from "./PreciseTuple.ts"; + +const alwaysUndefined = always(undefined); /** * Curried divide operation using the internal {@linkcode Precise} type. @@ -16,25 +16,32 @@ import { preciseToNumber } from "./preciseToNumber.ts"; * * half(1n); // [5n, -1n] * ``` - * @see {@linkcode numberToPrecise} * @see {@linkcode Precise} - * @see {@linkcode preciseMultiply} - * @see {@linkcode preciseToNumber} + * @see {@linkcode PreciseFunction} * @param divisorBase Divisor base to use in the division. * @param divisorExponent Divisor exponent to use in the division. * @returns Curried function with `divisorBase` and `divisorExponent` in context. */ -export const preciseDivide: ( - divisorBase: MaybeInfinity, - divisorExponent?: bigint, -) => (dividendBase: MaybeInfinity, dividendExponent?: bigint) => Precise = - memoFunction((divisorBase, divisorExponent) => - divisorBase === 0n ? - always(precise(Infinity)) - : preciseMultiply( - ...numberToPrecise( - preciseToNumber(1n, -(divisorExponent ?? 0n)) - / preciseToNumber(divisorBase, 0n), - ), - ), - ); +export const preciseDivide: PreciseFunction> = memoFunction( + (divisorBase, divisorExponent) => + divisorBase === 0n ? alwaysUndefined : ( + memoFunction((dividendBase, dividendExponent) => { + let exponent = 0n; + let base = dividendBase / divisorBase; + + for ( + let dividend = dividendBase; + base * divisorBase !== dividend; + ) { + exponent += 1n; + dividend = dividendBase * 10n ** exponent; + base = dividend / divisorBase; + } + + return precise( + base, + dividendExponent - exponent - divisorExponent, + ); + }) + ), +); diff --git a/@coven/math/preciseMultiply.ts b/@coven/math/preciseMultiply.ts index 37a8b30..1f760d5 100644 --- a/@coven/math/preciseMultiply.ts +++ b/@coven/math/preciseMultiply.ts @@ -1,37 +1,28 @@ import { memoFunction } from "@coven/memo"; -import { isBigInt } from "@coven/predicates"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; -import type { Precise } from "./PreciseTuple.ts"; import { precise } from "./precise.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; /** - * Curried multiply operation using the internal {@linkcode Precise} type. + * Curried multiply operation using the internal `Precise` type. * * @example * ```typescript - * const double = preciseMultiply(2n); + * const double = preciseMultiply(2n, 0n); * - * double(65n, -1n); // [13n] + * double(65n, -1n); // [13n, 0n] * ``` * @see {@linkcode precise} - * @see {@linkcode Precise} + * @see {@linkcode PreciseFunction} * @param multiplierBase Multiplier base to use in the multiplication. * @param multiplierExponent Multiplier exponent to use in the multiplication. * @returns Curried function with `multiplierBase` and `multiplierExponent` in context. */ -export const preciseMultiply: ( - multiplierBase: MaybeInfinity, - multiplierExponent?: bigint, -) => ( - multiplicandBase: MaybeInfinity, - multiplicandExponent?: bigint, -) => Precise = memoFunction((multiplierBase, multiplierExponent) => - memoFunction((multiplicandBase, multiplicandExponent) => - isBigInt(multiplicandBase) && isBigInt(multiplierBase) ? +export const preciseMultiply: PreciseFunction = memoFunction( + (multiplierBase, multiplierExponent) => + memoFunction((multiplicandBase, multiplicandExponent) => precise( multiplicandBase * multiplierBase, - (multiplicandExponent ?? 0n) + (multiplierExponent ?? 0n), - ) - : precise(Infinity), - ), + multiplicandExponent + multiplierExponent, + ), + ), ); diff --git a/@coven/math/preciseSubtract.ts b/@coven/math/preciseSubtract.ts index 69888bb..0eaad88 100644 --- a/@coven/math/preciseSubtract.ts +++ b/@coven/math/preciseSubtract.ts @@ -1,27 +1,23 @@ import { memoFunction } from "@coven/memo"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; -import type { Precise } from "./PreciseTuple.ts"; import { preciseAdd } from "./preciseAdd.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; /** - * Curried subtract operation using the internal {@linkcode Precise} type. + * Curried subtract operation using the internal `Precise` type. * * @example * ```typescript - * const previous = preciseSubtract(1n); + * const previous = preciseSubtract(1n, 0n); * - * previous(14n); // [13n] + * previous(14n); // [13n, 0n] * ``` - * @see {@linkcode Precise} + * @see {@linkcode PreciseFunction} * @see {@linkcode preciseAdd} * @param subtrahendBase Subtrahend base to use in the subtraction. * @param subtrahendExponent Subtrahend exponent to use in the subtraction. * @returns Curried function with `subtrahendBase` and `subtrahendExponent` in context. */ -export const preciseSubtract: ( - subtrahendBase: MaybeInfinity, - subtrahendExponent?: bigint, -) => (minuendBase: MaybeInfinity, minuendExponent?: bigint) => Precise = - memoFunction((subtrahendBase, subtrahendExponent) => - preciseAdd(-subtrahendBase, subtrahendExponent ?? 0n), - ); +export const preciseSubtract: PreciseFunction = memoFunction( + (subtrahendBase, subtrahendExponent) => + preciseAdd(-subtrahendBase, subtrahendExponent), +); diff --git a/@coven/math/preciseToBigInt.ts b/@coven/math/preciseToBigInt.ts new file mode 100644 index 0000000..a5d7f27 --- /dev/null +++ b/@coven/math/preciseToBigInt.ts @@ -0,0 +1,22 @@ +import { memoFunction } from "@coven/memo"; +import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; + +/** + * Given a precise value (base, exponent pair), return a BigInt. If the exponent + * is lower than zero, then the exponent is asumed to be zero because BigInt + * doesn't support float values. + * + * ```typescript + * preciseToBigInt(13n, 5n); // 1300000n + * preciseToBigInt(13n); // 13n + * preciseToBigInt(13n, 0n); // 13n + * preciseToBigInt(13n, -5n); // 13n + * ``` + * @param base Base of the precise value. + * @param exponent Exponent of the precise value. + * @returns BigInt equivalent value to the given precise. If Infinity is passed, + * the returned value is Infinity too. + */ +export const preciseToBigInt: PreciseToTypeFunction = memoFunction( + (base, exponent) => (exponent >= 0n ? base * 10n ** exponent : exponent), +); diff --git a/@coven/math/preciseToNumber.ts b/@coven/math/preciseToNumber.ts index 87a6cd6..2691ca8 100644 --- a/@coven/math/preciseToNumber.ts +++ b/@coven/math/preciseToNumber.ts @@ -1,3 +1,6 @@ +import { memoFunction } from "@coven/memo"; +import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; + /** * Turns a `Precise` into a `number`. * @@ -8,7 +11,9 @@ * @param precise `Precise` to convert. * @returns Number represented by the passed `Precise` value. */ -export const preciseToNumber = ( - base: bigint | typeof Infinity, - exponent?: bigint, -): number => parseFloat(`${base}e${exponent ?? 0n}`); +export const preciseToNumber: PreciseToTypeFunction = memoFunction( + (base, exponent) => + exponent === 0n ? Number(base) + : exponent > 0n ? Number(base) * 10 ** Number(exponent) + : Number(base) / 10 ** Number(-exponent), +); diff --git a/@coven/math/subtract.ts b/@coven/math/subtract.ts index d136578..62b8e46 100644 --- a/@coven/math/subtract.ts +++ b/@coven/math/subtract.ts @@ -1,5 +1,10 @@ -import { pipe } from "./pipe.ts"; +import { memoFunction } from "@coven/memo"; +import { isUndefined } from "@coven/predicates"; +import type { Unary } from "@coven/types"; +import { always } from "@coven/utils"; +import { numberToPrecise } from "./numberToPrecise.ts"; import { preciseSubtract } from "./preciseSubtract.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; /** * Curried subtract operation using {@linkcode pipe} with {@linkcode preciseSubtract}. @@ -15,5 +20,26 @@ import { preciseSubtract } from "./preciseSubtract.ts"; * @param subtrahend Subtrahend value to be used in the subtraction. * @returns Curried function with `subtrahend` in context. */ -export const subtract: (subtrahend: number) => (minuend: number) => number = - pipe(preciseSubtract); +export const subtract: Unary< + [subtrahend: number], + Unary<[minuend: number], number> +> = memoFunction((subtrahend) => { + const preciseSubtrahend = numberToPrecise(subtrahend); + const preciseAddAugend = + isUndefined(preciseSubtrahend) ? undefined : ( + preciseSubtract(...preciseSubtrahend) + ); + + return isUndefined(preciseSubtrahend) ? + always(subtrahend) + : memoFunction((minuend) => { + const preciseMinuend = numberToPrecise(minuend); + + return ( + isUndefined(preciseMinuend) + || isUndefined(preciseAddAugend) + ) ? + minuend + : preciseToNumber(...preciseAddAugend(...preciseMinuend)); + }); +}); diff --git a/@coven/math/tests/add.test.ts b/@coven/math/tests/add.test.ts index 5a0d2f8..dd29a04 100644 --- a/@coven/math/tests/add.test.ts +++ b/@coven/math/tests/add.test.ts @@ -53,3 +53,15 @@ Deno.test("5 + 0.00001 = 5.00001", () => Deno.test("0.00001 + 5 = 5.00001", () => assertStrictEquals(add(5)(0.000_01), 5.000_01), ); + +Deno.test("Infinity + 13 = Infinity", () => + assertStrictEquals(add(13)(Infinity), Infinity), +); + +Deno.test("13 + Infinity = Infinity", () => + assertStrictEquals(add(Infinity)(13), Infinity), +); + +Deno.test("NaN + 13 = NaN", () => assertStrictEquals(add(NaN)(13), NaN)); + +Deno.test("13 + NaN = NaN", () => assertStrictEquals(add(13)(NaN), NaN)); diff --git a/@coven/math/tests/calculate.test.ts b/@coven/math/tests/calculate.test.ts index 25d4110..0b3afa2 100644 --- a/@coven/math/tests/calculate.test.ts +++ b/@coven/math/tests/calculate.test.ts @@ -1,32 +1,38 @@ import { assertStrictEquals } from "@std/assert"; import { calculate } from "../calculate.ts"; -Deno.test("Simple addition returns correct value", () => +Deno.test("0.1 + 0.2 = 0.3", () => assertStrictEquals(calculate(0.1).plus(0.2).total, 0.3), ); -Deno.test("Simple division returns correct value", () => +Deno.test("0.6 / 2 = 0.3", () => assertStrictEquals(calculate(0.6).dividedBy(2).total, 0.3), ); -Deno.test("Simple multiplication returns correct value", () => +Deno.test("0.1 * 3 = 0.3", () => assertStrictEquals(calculate(0.1).times(3).total, 0.3), ); -Deno.test("Simple subtraction returns correct value", () => +Deno.test("0.5 - 0.2 = 0.3", () => assertStrictEquals(calculate(0.5).minus(0.2).total, 0.3), ); -Deno.test( - "Complex operation combining all operations returns correct value", - () => - assertStrictEquals( - calculate(0.7).plus(0.3).dividedBy(4).times(2).minus(0.2).total, - 0.3, - ), +Deno.test("1 + 0.1 - 1 = 0.1", () => + assertStrictEquals(calculate(1).plus(0.1).minus(1).total, 0.1), ); -Deno.test("Memoized value isn't broken", () => +Deno.test("1e16 + 0.1 - 1e16 = 0.1", () => + assertStrictEquals(calculate(1e16).plus(0.1).minus(1e16).total, 0.1), +); + +Deno.test("((0.7 + 0.3) / 4 * 2) - 0.2 = 0.3", () => + assertStrictEquals( + calculate(0.7).plus(0.3).dividedBy(4).times(2).minus(0.2).total, + 0.3, + ), +); + +Deno.test("((2 + 2) / 2 * 2) - 2 = 2", () => assertStrictEquals( calculate(2).plus(2).dividedBy(2).times(2).minus(2).total, 2, diff --git a/@coven/math/tests/divide.test.ts b/@coven/math/tests/divide.test.ts index d8fdb2b..73a8b83 100644 --- a/@coven/math/tests/divide.test.ts +++ b/@coven/math/tests/divide.test.ts @@ -63,3 +63,15 @@ Deno.test("5 / 0.00001 = 500000", () => Deno.test("0.00001 / 5 = 0.000002", () => assertStrictEquals(divide(5)(0.000_01), 0.000_002), ); + +Deno.test("Infinity / 13 = Infinity", () => + assertStrictEquals(divide(13)(Infinity), Infinity), +); + +Deno.test("13 / Infinity = Infinity", () => + assertStrictEquals(divide(Infinity)(13), 0), +); + +Deno.test("NaN / 13 = NaN", () => assertStrictEquals(divide(NaN)(13), NaN)); + +Deno.test("13 / NaN = NaN", () => assertStrictEquals(divide(13)(NaN), NaN)); diff --git a/@coven/math/tests/multiply.test.ts b/@coven/math/tests/multiply.test.ts index 76a62fe..ac5cbf6 100644 --- a/@coven/math/tests/multiply.test.ts +++ b/@coven/math/tests/multiply.test.ts @@ -73,3 +73,15 @@ Deno.test("Infinity * Infinity = Infinity", () => Deno.test("13 * Infinity = Infinity", () => assertStrictEquals(multiply(Infinity)(13), Infinity), ); + +Deno.test("Infinity * 13 = Infinity", () => + assertStrictEquals(multiply(13)(Infinity), Infinity), +); + +Deno.test("13 * Infinity = Infinity", () => + assertStrictEquals(multiply(Infinity)(13), Infinity), +); + +Deno.test("NaN * 13 = NaN", () => assertStrictEquals(multiply(NaN)(13), NaN)); + +Deno.test("13 * NaN = NaN", () => assertStrictEquals(multiply(13)(NaN), NaN)); diff --git a/@coven/math/tests/numberToPrecise.test.ts b/@coven/math/tests/numberToPrecise.test.ts index 573b200..5b4313e 100644 --- a/@coven/math/tests/numberToPrecise.test.ts +++ b/@coven/math/tests/numberToPrecise.test.ts @@ -1,38 +1,43 @@ import { assertEquals } from "@std/assert"; import { numberToPrecise } from "../numberToPrecise.ts"; +import { precise } from "../precise.ts"; -Deno.test( - "Positive integer without zeroes on the right returns a that number in a single", - () => assertEquals(numberToPrecise(13), [13n]), +Deno.test("13 = precise(13n)", () => + assertEquals(numberToPrecise(13), precise(13n, 0n)), ); -Deno.test( - "Positive integer with zeroes on the right returns a that number in a tuple with the zero count", - () => assertEquals(numberToPrecise(1300), [13n, 2n]), +Deno.test("1300 = precise(13n, 2n)", () => + assertEquals(numberToPrecise(1300), precise(13n, 2n)), ); -Deno.test( - "Negative integer without zeroes on the right returns a that number in a single", - () => assertEquals(numberToPrecise(-13), [-13n]), +Deno.test("-13 = precise(-13n)", () => + assertEquals(numberToPrecise(-13), precise(-13n, 0n)), ); -Deno.test( - "Negative integer with zeroes on the right returns a that number in a tuple with the zero count", - () => assertEquals(numberToPrecise(-1300), [-13n, 2n]), +Deno.test("-1300 = precise(-13n, 2n)", () => + assertEquals(numberToPrecise(-1300), precise(-13n, 2n)), ); -Deno.test("Positive float without zeroes on the right returns a tuple", () => - assertEquals(numberToPrecise(13.1), [131n, -1n]), +Deno.test("13.1 = precise(131n, -1n)", () => + assertEquals(numberToPrecise(13.1), precise(131n, -1n)), ); -Deno.test("Positive float with zeroes on the right returns a tuple", () => - assertEquals(numberToPrecise(1300.1), [13_001n, -1n]), +Deno.test("1300.1 = precise(13_001n, -1n)", () => + assertEquals(numberToPrecise(1300.1), precise(13_001n, -1n)), ); -Deno.test("Negative float without zeroes on the right returns tuple", () => - assertEquals(numberToPrecise(-13.1), [-131n, -1n]), +Deno.test("-13.1 = precise(-131n, -1n)", () => + assertEquals(numberToPrecise(-13.1), precise(-131n, -1n)), ); -Deno.test("Negative float with zeroes on the right returns a tuple", () => - assertEquals(numberToPrecise(-1300.1), [-13_001n, -1n]), +Deno.test("-1300.1 = precise(-13_001n, -1n)", () => + assertEquals(numberToPrecise(-1300.1), precise(-13_001n, -1n)), +); + +Deno.test("10000000000000000 = precise(1n, 16n)", () => + assertEquals(numberToPrecise(1e16), precise(1n, 16n)), +); + +Deno.test("-10000000000000000 = precise(-1n, 16n)", () => + assertEquals(numberToPrecise(-1e16), precise(-1n, 16n)), ); diff --git a/@coven/math/tests/precise.test.ts b/@coven/math/tests/precise.test.ts index 38e4245..c7a4dc0 100644 --- a/@coven/math/tests/precise.test.ts +++ b/@coven/math/tests/precise.test.ts @@ -2,18 +2,14 @@ import { memo } from "@coven/memo"; import { assertStrictEquals } from "@std/assert"; import { precise } from "../precise.ts"; -Deno.test("Infinity returns Infinity", () => - assertStrictEquals(precise(Infinity), memo([Infinity])), -); - -Deno.test("Number valid tuple returns said tuple", () => +Deno.test("precise(1n, 5n) = [1n, 5n]", () => assertStrictEquals(precise(1n, 5n), memo([1n, 5n])), ); -Deno.test("Number with 0 exponent returns only base", () => - assertStrictEquals(precise(1n, 0n), memo([1n])), +Deno.test("precise(1n, 0n) = [1n]", () => + assertStrictEquals(precise(1n, 0n), memo([1n, 0n])), ); -Deno.test("Number with no exponent returns only base", () => - assertStrictEquals(precise(1n), memo([1n])), +Deno.test("precise(1n) = [1n]", () => + assertStrictEquals(precise(1n, 0n), memo([1n, 0n])), ); diff --git a/@coven/math/tests/preciseAdd.test.ts b/@coven/math/tests/preciseAdd.test.ts index 1ac86fe..e8b29be 100644 --- a/@coven/math/tests/preciseAdd.test.ts +++ b/@coven/math/tests/preciseAdd.test.ts @@ -2,17 +2,17 @@ import { assertStrictEquals } from "@std/assert"; import { precise } from "../precise.ts"; import { preciseAdd } from "../preciseAdd.ts"; -const preciseAddPositive = preciseAdd(2n); -const preciseAddNegative = preciseAdd(-2n); +const preciseAddPositive = preciseAdd(2n, 0n); +const preciseAddNegative = preciseAdd(-2n, 0n); const preciseAddFloat = preciseAdd(2n, -1n); const preciseAddNegativeFloat = preciseAdd(-2n, -1n); Deno.test("1 + 2 = 3", () => - assertStrictEquals(preciseAddPositive(1n), precise(3n)), + assertStrictEquals(preciseAddPositive(1n, 0n), precise(3n, 0n)), ); Deno.test("-1 + 2 = 1", () => - assertStrictEquals(preciseAddPositive(-1n), precise(1n)), + assertStrictEquals(preciseAddPositive(-1n, 0n), precise(1n, 0n)), ); Deno.test("0.1 + 2 = 2.1", () => @@ -24,11 +24,11 @@ Deno.test("-0.1 + 2 = 1.9", () => ); Deno.test("1 + -2 = -1", () => - assertStrictEquals(preciseAddNegative(1n), precise(-1n)), + assertStrictEquals(preciseAddNegative(1n, 0n), precise(-1n, 0n)), ); Deno.test("-1 + -2 = -3", () => - assertStrictEquals(preciseAddNegative(-1n), precise(-3n)), + assertStrictEquals(preciseAddNegative(-1n, 0n), precise(-3n, 0n)), ); Deno.test("0.1 + -2 = -1.9", () => @@ -40,11 +40,11 @@ Deno.test("-0.1 + -2 = -2.1", () => ); Deno.test("1 + 0.2 = 1.2", () => - assertStrictEquals(preciseAddFloat(1n), precise(12n, -1n)), + assertStrictEquals(preciseAddFloat(1n, 0n), precise(12n, -1n)), ); Deno.test("-1 + 0.2 = -0.8", () => - assertStrictEquals(preciseAddFloat(-1n), precise(-8n, -1n)), + assertStrictEquals(preciseAddFloat(-1n, 0n), precise(-8n, -1n)), ); Deno.test("0.1 + 0.2 = 0.3", () => @@ -56,11 +56,11 @@ Deno.test("-0.1 + 0.2 = 0.1", () => ); Deno.test("1 + -0.2 = 0.8", () => - assertStrictEquals(preciseAddNegativeFloat(1n), precise(8n, -1n)), + assertStrictEquals(preciseAddNegativeFloat(1n, 0n), precise(8n, -1n)), ); Deno.test("-1 + -0.2 = -1.2", () => - assertStrictEquals(preciseAddNegativeFloat(-1n), precise(-12n, -1n)), + assertStrictEquals(preciseAddNegativeFloat(-1n, 0n), precise(-12n, -1n)), ); Deno.test("0.1 + -0.2 = -0.1", () => @@ -72,13 +72,20 @@ Deno.test("-0.1 + -0.2 = -0.3", () => ); Deno.test("5 + 0.00001 = 5.00001", () => - assertStrictEquals(preciseAdd(1n, -5n)(5n), precise(500_001n, -5n)), + assertStrictEquals(preciseAdd(1n, -5n)(5n, 0n), precise(500_001n, -5n)), ); Deno.test("0.00001 + 5 = 5.00001", () => - assertStrictEquals(preciseAdd(5n)(1n, -5n), precise(500_001n, -5n)), + assertStrictEquals(preciseAdd(5n, 0n)(1n, -5n), precise(500_001n, -5n)), +); + +Deno.test("1e16 + 0.1 = 100000000000000001e-1", () => + assertStrictEquals( + preciseAdd(1n, 16n)(1n, -1n), + precise(100000000000000001n, -1n), + ), ); Deno.test("Same Precise returned with same values", () => - assertStrictEquals(preciseAdd(2n)(3n), preciseAdd(2n)(3n)), + assertStrictEquals(preciseAdd(2n, 0n)(3n, 0n), preciseAdd(2n, 0n)(3n, 0n)), ); diff --git a/@coven/math/tests/preciseDivide.test.ts b/@coven/math/tests/preciseDivide.test.ts index 6baaab7..a472039 100644 --- a/@coven/math/tests/preciseDivide.test.ts +++ b/@coven/math/tests/preciseDivide.test.ts @@ -2,17 +2,17 @@ import { assertStrictEquals } from "@std/assert"; import { precise } from "../precise.ts"; import { preciseDivide } from "../preciseDivide.ts"; -const preciseDividePositive = preciseDivide(2n); -const preciseDivideNegative = preciseDivide(-2n); +const preciseDividePositive = preciseDivide(2n, 0n); +const preciseDivideNegative = preciseDivide(-2n, 0n); const preciseDivideFloat = preciseDivide(2n, -1n); const preciseDivideNegativeFloat = preciseDivide(-2n, -1n); Deno.test("1 / 2 = 0.5", () => - assertStrictEquals(preciseDividePositive(1n), precise(5n, -1n)), + assertStrictEquals(preciseDividePositive(1n, 0n), precise(5n, -1n)), ); Deno.test("-1 / 2 = -0.5", () => - assertStrictEquals(preciseDividePositive(-1n), precise(-5n, -1n)), + assertStrictEquals(preciseDividePositive(-1n, 0n), precise(-5n, -1n)), ); Deno.test("0.1 / 2 = 0.05", () => @@ -24,11 +24,11 @@ Deno.test("-0.1 / 2 = 0.05", () => ); Deno.test("1 / -2 = -0.5", () => - assertStrictEquals(preciseDivideNegative(1n, 1n), precise(-5n)), + assertStrictEquals(preciseDivideNegative(1n, 1n), precise(-5n, 0n)), ); Deno.test("-1 / -2 = 0.5", () => - assertStrictEquals(preciseDivideNegative(-1n), precise(5n, -1n)), + assertStrictEquals(preciseDivideNegative(-1n, 0n), precise(5n, -1n)), ); Deno.test("0.1 / -2 = 0.05", () => @@ -40,11 +40,11 @@ Deno.test("-0.1 / -2 = 0.05", () => ); Deno.test("1 / 0.2 = 5", () => - assertStrictEquals(preciseDivideFloat(1n), precise(5n)), + assertStrictEquals(preciseDivideFloat(1n, 0n), precise(5n, 0n)), ); Deno.test("-1 / 0.2 = -5", () => - assertStrictEquals(preciseDivideFloat(-1n), precise(-5n)), + assertStrictEquals(preciseDivideFloat(-1n, 0n), precise(-5n, 0n)), ); Deno.test("0.1 / 0.2 = 0.5", () => @@ -56,11 +56,11 @@ Deno.test("-0.1 / 0.2 = -0.5", () => ); Deno.test("1 / -0.2 = -5", () => - assertStrictEquals(preciseDivideNegativeFloat(1n), precise(-5n)), + assertStrictEquals(preciseDivideNegativeFloat(1n, 0n), precise(-5n, 0n)), ); Deno.test("-1 / -0.2 = 5", () => - assertStrictEquals(preciseDivideNegativeFloat(-1n), precise(5n)), + assertStrictEquals(preciseDivideNegativeFloat(-1n, 0n), precise(5n, 0n)), ); Deno.test("0.1 / -0.2 = -0.5", () => @@ -72,17 +72,20 @@ Deno.test("-0.1 / -0.2 = 0.5", () => ); Deno.test("5 / 0.00001 = 500000", () => - assertStrictEquals(preciseDivide(1n, -5n)(5n), precise(5n, 5n)), + assertStrictEquals(preciseDivide(1n, -5n)(5n, 0n), precise(5n, 5n)), ); Deno.test("0.00001 / 5 = 0.000002", () => - assertStrictEquals(preciseDivide(5n)(1n, -5n), precise(2n, -6n)), + assertStrictEquals(preciseDivide(5n, 0n)(1n, -5n), precise(2n, -6n)), ); -Deno.test("1 / 0 = Infinity", () => - assertStrictEquals(preciseDivide(0n)(1n), precise(Infinity)), +Deno.test("1 / 0 = undefined", () => + assertStrictEquals(preciseDivide(0n, 0n)(1n, 0n), undefined), ); Deno.test("Same Precise returned with same values", () => - assertStrictEquals(preciseDivide(2n)(3n), preciseDivide(2n)(3n)), + assertStrictEquals( + preciseDivide(2n, 0n)(3n, 0n), + preciseDivide(2n, 0n)(3n, 0n), + ), ); diff --git a/@coven/math/tests/preciseMultiply.test.ts b/@coven/math/tests/preciseMultiply.test.ts index 538e14c..cb72746 100644 --- a/@coven/math/tests/preciseMultiply.test.ts +++ b/@coven/math/tests/preciseMultiply.test.ts @@ -2,17 +2,17 @@ import { assertStrictEquals } from "@std/assert"; import { precise } from "../precise.ts"; import { preciseMultiply } from "../preciseMultiply.ts"; -const preciseMultiplyPositive = preciseMultiply(2n); -const preciseMultiplyNegative = preciseMultiply(-2n); +const preciseMultiplyPositive = preciseMultiply(2n, 0n); +const preciseMultiplyNegative = preciseMultiply(-2n, 0n); const preciseMultiplyFloat = preciseMultiply(2n, -1n); const preciseMultiplyNegativeFloat = preciseMultiply(-2n, -1n); Deno.test("1 * 2 = 2", () => - assertStrictEquals(preciseMultiplyPositive(1n), precise(2n)), + assertStrictEquals(preciseMultiplyPositive(1n, 0n), precise(2n, 0n)), ); Deno.test("-1 * 2 = -2", () => - assertStrictEquals(preciseMultiplyPositive(-1n), precise(-2n)), + assertStrictEquals(preciseMultiplyPositive(-1n, 0n), precise(-2n, 0n)), ); Deno.test("0.1 * 2 = 0.2", () => @@ -24,11 +24,11 @@ Deno.test("-0.1 * 2 = -0.2", () => ); Deno.test("1 * -2 = -2", () => - assertStrictEquals(preciseMultiplyNegative(1n), precise(-2n)), + assertStrictEquals(preciseMultiplyNegative(1n, 0n), precise(-2n, 0n)), ); Deno.test("-1 * -2 = 2", () => - assertStrictEquals(preciseMultiplyNegative(-1n), precise(2n)), + assertStrictEquals(preciseMultiplyNegative(-1n, 0n), precise(2n, 0n)), ); Deno.test("0.1 * -2 = -0.2", () => @@ -40,11 +40,11 @@ Deno.test("-0.1 * -2 = 0.2", () => ); Deno.test("1 * 0.2 = 0.2", () => - assertStrictEquals(preciseMultiplyFloat(1n), precise(2n, -1n)), + assertStrictEquals(preciseMultiplyFloat(1n, 0n), precise(2n, -1n)), ); Deno.test("-1 * 0.2 = -0.2", () => - assertStrictEquals(preciseMultiplyFloat(-1n), precise(-2n, -1n)), + assertStrictEquals(preciseMultiplyFloat(-1n, 0n), precise(-2n, -1n)), ); Deno.test("0.1 * 0.2 = 0.02", () => @@ -56,11 +56,11 @@ Deno.test("-0.1 * 0.2 = -0.02", () => ); Deno.test("1 * -0.2 = -0.2", () => - assertStrictEquals(preciseMultiplyNegativeFloat(1n), precise(-2n, -1n)), + assertStrictEquals(preciseMultiplyNegativeFloat(1n, 0n), precise(-2n, -1n)), ); Deno.test("-1 * -0.2 = 0.2", () => - assertStrictEquals(preciseMultiplyNegativeFloat(-1n), precise(2n, -1n)), + assertStrictEquals(preciseMultiplyNegativeFloat(-1n, 0n), precise(2n, -1n)), ); Deno.test("0.1 * -0.2 = -0.02", () => @@ -78,21 +78,16 @@ Deno.test("-0.1 * -0.2 = 0.02", () => ); Deno.test("5 * 0.00001 = 0.00005", () => - assertStrictEquals(preciseMultiply(1n, -5n)(5n), precise(5n, -5n)), + assertStrictEquals(preciseMultiply(1n, -5n)(5n, 0n), precise(5n, -5n)), ); Deno.test("0.00001 * 5 = 0.00005", () => - assertStrictEquals(preciseMultiply(5n)(1n, -5n), precise(5n, -5n)), -); - -Deno.test("Infinity * Infinity = [Infinity]", () => - assertStrictEquals(preciseMultiply(Infinity)(Infinity), precise(Infinity)), -); - -Deno.test("13 * Infinity = [Infinity]", () => - assertStrictEquals(preciseMultiply(Infinity)(13), precise(Infinity)), + assertStrictEquals(preciseMultiply(5n, 0n)(1n, -5n), precise(5n, -5n)), ); Deno.test("Same Precise returned with same values", () => - assertStrictEquals(preciseMultiply(2n)(3n), preciseMultiply(2n)(3n)), + assertStrictEquals( + preciseMultiply(2n, 0n)(3n, 0n), + preciseMultiply(2n, 0n)(3n, 0n), + ), ); diff --git a/@coven/math/tests/preciseSubtract.test.ts b/@coven/math/tests/preciseSubtract.test.ts index 9dfe695..d76a9ea 100644 --- a/@coven/math/tests/preciseSubtract.test.ts +++ b/@coven/math/tests/preciseSubtract.test.ts @@ -2,17 +2,17 @@ import { assertStrictEquals } from "@std/assert"; import { precise } from "../precise.ts"; import { preciseSubtract } from "../preciseSubtract.ts"; -const preciseSubtractPositive = preciseSubtract(2n); -const preciseSubtractNegative = preciseSubtract(-2n); +const preciseSubtractPositive = preciseSubtract(2n, 0n); +const preciseSubtractNegative = preciseSubtract(-2n, 0n); const preciseSubtractFloat = preciseSubtract(2n, -1n); const preciseSubtractNegativeFloat = preciseSubtract(-2n, -1n); Deno.test("1 - 2 = -1", () => - assertStrictEquals(preciseSubtractPositive(1n), precise(-1n)), + assertStrictEquals(preciseSubtractPositive(1n, 0n), precise(-1n, 0n)), ); Deno.test("-1 - 2 = -3", () => - assertStrictEquals(preciseSubtractPositive(-1n), precise(-3n)), + assertStrictEquals(preciseSubtractPositive(-1n, 0n), precise(-3n, 0n)), ); Deno.test("0.1 - 2 = -1.9", () => @@ -24,11 +24,11 @@ Deno.test("-0.1 - 2 = -2.1", () => ); Deno.test("1 - -2 = 3", () => - assertStrictEquals(preciseSubtractNegative(1n), precise(3n)), + assertStrictEquals(preciseSubtractNegative(1n, 0n), precise(3n, 0n)), ); Deno.test("-1 - -2 = 1", () => - assertStrictEquals(preciseSubtractNegative(-1n), precise(1n)), + assertStrictEquals(preciseSubtractNegative(-1n, 0n), precise(1n, 0n)), ); Deno.test("0.1 - -2 = 2.1", () => @@ -40,11 +40,11 @@ Deno.test("-0.1 - -2 = 1.9", () => ); Deno.test("1 - 0.2 = 0.8", () => - assertStrictEquals(preciseSubtractFloat(1n), precise(8n, -1n)), + assertStrictEquals(preciseSubtractFloat(1n, 0n), precise(8n, -1n)), ); Deno.test("-1 - 0.2 = -1.2", () => - assertStrictEquals(preciseSubtractFloat(-1n), precise(-12n, -1n)), + assertStrictEquals(preciseSubtractFloat(-1n, 0n), precise(-12n, -1n)), ); Deno.test("0.1 - 0.2 = -0.1", () => @@ -56,11 +56,14 @@ Deno.test("-0.1 - 0.2 = -0.3", () => ); Deno.test("1 - -0.2 = 1.2", () => - assertStrictEquals(preciseSubtractNegativeFloat(1n), precise(12n, -1n)), + assertStrictEquals(preciseSubtractNegativeFloat(1n, 0n), precise(12n, -1n)), ); Deno.test("-1 - -0.2 = -0.8", () => - assertStrictEquals(preciseSubtractNegativeFloat(-1n), precise(-8n, -1n)), + assertStrictEquals( + preciseSubtractNegativeFloat(-1n, 0n), + precise(-8n, -1n), + ), ); Deno.test("0.1 - -0.2 = 0.3", () => @@ -75,13 +78,26 @@ Deno.test("-0.1 - -0.2 = 0.1", () => ); Deno.test("5 - 0.00001 = 4.99999", () => - assertStrictEquals(preciseSubtract(1n, -5n)(5n), precise(499_999n, -5n)), + assertStrictEquals( + preciseSubtract(1n, -5n)(5n, 0n), + precise(499_999n, -5n), + ), ); Deno.test("0.00001 - 5 = -4.99999", () => - assertStrictEquals(preciseSubtract(5n)(1n, -5n), precise(-499_999n, -5n)), + assertStrictEquals( + preciseSubtract(5n, 0n)(1n, -5n), + precise(-499_999n, -5n), + ), ); Deno.test("Same Precise returned with same values", () => - assertStrictEquals(preciseSubtract(2n)(3n), preciseSubtract(2n)(3n)), + assertStrictEquals( + preciseSubtract(2n, 0n)(3n, 0n), + preciseSubtract(2n, 0n)(3n, 0n), + ), +); + +Deno.test("1 - 1 = 0", () => + assertStrictEquals(preciseSubtract(1n, 0n)(1n, 0n), precise(0n, 0n)), ); diff --git a/@coven/math/tests/preciseToNumber.test.ts b/@coven/math/tests/preciseToNumber.test.ts index 93946fd..ced434c 100644 --- a/@coven/math/tests/preciseToNumber.test.ts +++ b/@coven/math/tests/preciseToNumber.test.ts @@ -1,46 +1,38 @@ import { assertStrictEquals } from "@std/assert"; import { preciseToNumber } from "../preciseToNumber.ts"; -Deno.test( - "Tuple of a positive integer without zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(13n), 13), +Deno.test("precise(13n) = 13", () => + assertStrictEquals(preciseToNumber(13n, 0n), 13), ); -Deno.test( - "Tuple of a positive integer with zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(13n, 2n), 1300), +Deno.test("precise(13n, 2n) = 1300", () => + assertStrictEquals(preciseToNumber(13n, 2n), 1300), ); -Deno.test( - "Tuple of a negative integer without zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(-13n), -13), +Deno.test("precise(-13n) = -13", () => + assertStrictEquals(preciseToNumber(-13n, 0n), -13), ); -Deno.test( - "Tuple of a negative integer with zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(-13n, 2n), -1300), +Deno.test("precise(-13n, 2n) = -1300", () => + assertStrictEquals(preciseToNumber(-13n, 2n), -1300), ); -Deno.test( - "Tuple of a positive float without zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(131n, -1n), 13.1), +Deno.test("precise(131n, -1n) = 13.1", () => + assertStrictEquals(preciseToNumber(131n, -1n), 13.1), ); -Deno.test( - "Tuple of a positive float with zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(13_001n, -1n), 1300.1), +Deno.test("precise(13_001n, -1n) = 1300.1", () => + assertStrictEquals(preciseToNumber(13_001n, -1n), 1300.1), ); -Deno.test( - "Tuple of a negative float without zeroes on the right returns number", - () => assertStrictEquals(preciseToNumber(-131n, -1n), -13.1), +Deno.test("precise(-131n, -1n) = -13.1", () => + assertStrictEquals(preciseToNumber(-131n, -1n), -13.1), ); -Deno.test( - "Tuple of a negative float with zeroes on the right returns a number", - () => assertStrictEquals(preciseToNumber(-13_001n, -1n), -1300.1), +Deno.test("precise(-13_001n, -1n) = -1300.1", () => + assertStrictEquals(preciseToNumber(-13_001n, -1n), -1300.1), ); -Deno.test("Tuple of not normalized values returns number", () => +Deno.test("precise(-13_000n, 0n) = -13_000", () => assertStrictEquals(preciseToNumber(-13_000n, 0n), -13_000), ); diff --git a/@coven/math/tests/subtract.test.ts b/@coven/math/tests/subtract.test.ts index 9225c40..16787df 100644 --- a/@coven/math/tests/subtract.test.ts +++ b/@coven/math/tests/subtract.test.ts @@ -65,3 +65,17 @@ Deno.test("5 - 0.00001 = 4.99999", () => Deno.test("0.00001 - 5 = -4.99999", () => assertStrictEquals(subtract(5)(0.000_01), -4.999_99), ); + +Deno.test("1 - 1 = 0", () => assertStrictEquals(subtract(1)(1), 0)); + +Deno.test("Infinity - 13 = Infinity", () => + assertStrictEquals(subtract(13)(Infinity), Infinity), +); + +Deno.test("13 - Infinity = Infinity", () => + assertStrictEquals(subtract(Infinity)(13), Infinity), +); + +Deno.test("NaN - 13 = NaN", () => assertStrictEquals(subtract(NaN)(13), NaN)); + +Deno.test("13 - NaN = NaN", () => assertStrictEquals(subtract(13)(NaN), NaN)); From 14a5e8e55aed9e8ca36a729bc661a1b8f29fa6c7 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Thu, 16 Apr 2026 22:42:19 -0500 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=9A=A8=20(@coven/math)=20fix=20lint?= =?UTF-8?q?ing=20issues.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/math/Calculation.ts | 4 ++-- @coven/math/PreciseFunction.ts | 4 ++++ @coven/math/PreciseToTypeFunction.ts | 3 +++ @coven/math/getBaseAndZeroes.ts | 7 +++++- @coven/math/getNumberParts.ts | 34 ++++++++++++++++++---------- @coven/math/precise.ts | 2 +- @coven/math/preciseDivide.ts | 4 ++-- @coven/math/preciseSubtract.ts | 2 +- @coven/math/preciseToBigInt.ts | 1 - 9 files changed, 41 insertions(+), 20 deletions(-) diff --git a/@coven/math/Calculation.ts b/@coven/math/Calculation.ts index ea69acd..e8fd25c 100644 --- a/@coven/math/Calculation.ts +++ b/@coven/math/Calculation.ts @@ -1,5 +1,5 @@ -import { Maybe } from "@coven/types"; -import { Precise } from "./PreciseTuple.ts"; +import type { Maybe } from "@coven/types"; +import type { Precise } from "./PreciseTuple.ts"; /** * Object returned by the `calculate` function, which recursively returns itself diff --git a/@coven/math/PreciseFunction.ts b/@coven/math/PreciseFunction.ts index 09577a0..e79e8d1 100644 --- a/@coven/math/PreciseFunction.ts +++ b/@coven/math/PreciseFunction.ts @@ -2,5 +2,9 @@ import type { Maybe, Multary } from "@coven/types"; import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; import type { Precise } from "./PreciseTuple.ts"; +/** + * Type to represent the curried functions for operations with + * {@linkcode Precise} values. + */ export type PreciseFunction = Precise> = Multary>; diff --git a/@coven/math/PreciseToTypeFunction.ts b/@coven/math/PreciseToTypeFunction.ts index 4162269..4e25a84 100644 --- a/@coven/math/PreciseToTypeFunction.ts +++ b/@coven/math/PreciseToTypeFunction.ts @@ -1,4 +1,7 @@ import type { Multary } from "@coven/types"; import type { Precise } from "./PreciseTuple.ts"; +/** + * Type used by functions that turn a {@linkcode Precise} into a different type. + */ export type PreciseToTypeFunction = Multary; diff --git a/@coven/math/getBaseAndZeroes.ts b/@coven/math/getBaseAndZeroes.ts index fc272a1..8a94f2b 100644 --- a/@coven/math/getBaseAndZeroes.ts +++ b/@coven/math/getBaseAndZeroes.ts @@ -11,6 +11,7 @@ import { START, WILDCARD, } from "@coven/expression"; +import type { Stringable } from "@coven/types"; /** * Get right side zeroes (to be added to the exponent). @@ -21,7 +22,11 @@ import { * getBaseAndZeroes(1n); // { normalizedBase: "1", zeroes: undefined } * ``` */ -export const getBaseAndZeroes = getGroups<["normalizedBase", "zeroes"]>( +export const getBaseAndZeroes: ( + stringable: Stringable, +) => Partial>> = getGroups< + ["normalizedBase", "zeroes"] +>( buildUnicode( START, captureNamed("normalizedBase")( diff --git a/@coven/math/getNumberParts.ts b/@coven/math/getNumberParts.ts index d01b480..3e89e9d 100644 --- a/@coven/math/getNumberParts.ts +++ b/@coven/math/getNumberParts.ts @@ -10,6 +10,7 @@ import { optional, START, } from "@coven/expression"; +import type { Stringable } from "@coven/types"; /** * Get number parts {integral, fractional and exponent}. @@ -23,18 +24,27 @@ import { * getNumberParts("-13"); // { integral: -13, fractional: undefined, exponent: undefined } * ``` */ -export const getNumberParts = getGroups<["integral", "fractional", "exponent"]>( - buildUnicode( - START, - group( - captureNamed("integral")(optional("-"), exists(DIGIT)), +export const getNumberParts: ( + stringable: Stringable, +) => Partial>> = + getGroups<["integral", "fractional", "exponent"]>( + buildUnicode( + START, + group( + captureNamed("integral")(optional("-"), exists(DIGIT)), + optional( + group( + escape("."), + captureNamed("fractional")(exists(DIGIT)), + ), + ), + ), optional( - group(escape("."), captureNamed("fractional")(exists(DIGIT))), + group( + "e", + captureNamed("exponent")(optional("-"), exists(DIGIT)), + ), ), + END, ), - optional( - group("e", captureNamed("exponent")(optional("-"), exists(DIGIT))), - ), - END, - ), -); + ); diff --git a/@coven/math/precise.ts b/@coven/math/precise.ts index 76fd8b8..ef80705 100644 --- a/@coven/math/precise.ts +++ b/@coven/math/precise.ts @@ -7,7 +7,7 @@ import { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; * * @example * ```typescript - * precise(13n); // [13n] + * precise(13n, 0n); // [13n] * precise(13n, -1n); // [13n, -1n] * precise(1300n, 0n); // [13n, 2n] * ``` diff --git a/@coven/math/preciseDivide.ts b/@coven/math/preciseDivide.ts index 67f0088..fa142c0 100644 --- a/@coven/math/preciseDivide.ts +++ b/@coven/math/preciseDivide.ts @@ -12,9 +12,9 @@ const alwaysUndefined = always(undefined); * * @example * ```typescript - * const half = preciseDivide(2n); + * const half = preciseDivide(2n, 0n); * - * half(1n); // [5n, -1n] + * half(1n, 0n); // [5n, -1n] * ``` * @see {@linkcode Precise} * @see {@linkcode PreciseFunction} diff --git a/@coven/math/preciseSubtract.ts b/@coven/math/preciseSubtract.ts index 0eaad88..3fbc3ee 100644 --- a/@coven/math/preciseSubtract.ts +++ b/@coven/math/preciseSubtract.ts @@ -9,7 +9,7 @@ import type { PreciseFunction } from "./PreciseFunction.ts"; * ```typescript * const previous = preciseSubtract(1n, 0n); * - * previous(14n); // [13n, 0n] + * previous(14n, 0n); // [13n, 0n] * ``` * @see {@linkcode PreciseFunction} * @see {@linkcode preciseAdd} diff --git a/@coven/math/preciseToBigInt.ts b/@coven/math/preciseToBigInt.ts index a5d7f27..ce84cae 100644 --- a/@coven/math/preciseToBigInt.ts +++ b/@coven/math/preciseToBigInt.ts @@ -8,7 +8,6 @@ import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; * * ```typescript * preciseToBigInt(13n, 5n); // 1300000n - * preciseToBigInt(13n); // 13n * preciseToBigInt(13n, 0n); // 13n * preciseToBigInt(13n, -5n); // 13n * ``` From 407db9ba6059146b8f987bcf949444c2384fefc4 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:02:54 -0500 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=8E=A8=20(@coven/expression)=20impr?= =?UTF-8?q?ove=20`getGroups`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/expression/getGroups.ts | 12 ++++++------ @coven/expression/tests/getGroups.test.ts | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/@coven/expression/getGroups.ts b/@coven/expression/getGroups.ts index 492fe1e..3ba94d8 100644 --- a/@coven/expression/getGroups.ts +++ b/@coven/expression/getGroups.ts @@ -11,15 +11,15 @@ import type { * @internal Small type to work with {@linkcode ExpectedStringables} to add * the expected parts of a group name to the given strings. */ -type WrapGroupKeys = +export type WrapGroupKeys> = GroupKeys extends ( - [ + readonly [ infer Head extends Stringable, - ...infer Tail extends readonly Stringable[], + ...infer Tail extends ReadonlyArray, ] ) ? - [`(?<${Head}>`, ...WrapGroupKeys] - : readonly []; + readonly [`(?<${Head}>`, ...WrapGroupKeys] + : ReadonlyArray; /** * Given a regular expression (ideally generated by `@coven/expression`'s `build` @@ -29,7 +29,7 @@ type WrapGroupKeys = * ```typescript * import { buildUnicode, captureNamed, WILDCARD } from "@coven/expression"; * - * const getExample = getGroups<["example"]>( + * const getExample = getGroups( * buildUnicode(captureNamed("example")(WILDCARD)) // /(?.)/ * ); * diff --git a/@coven/expression/tests/getGroups.test.ts b/@coven/expression/tests/getGroups.test.ts index 2d3b118..5db261d 100644 --- a/@coven/expression/tests/getGroups.test.ts +++ b/@coven/expression/tests/getGroups.test.ts @@ -1,3 +1,4 @@ +import { EMPTY_OBJECT } from "@coven/constants"; import { memo } from "@coven/memo"; import { assertStrictEquals } from "@std/assert"; import { buildUnicode } from "../buildUnicode.ts"; @@ -7,9 +8,18 @@ import { WILDCARD } from "../WILDCARD.ts"; Deno.test("Groups captured correctly", () => assertStrictEquals( - getGroups<["example"]>(buildUnicode(captureNamed("example")(WILDCARD)))( - "🔮", - ), + getGroups( + buildUnicode(captureNamed("example")(WILDCARD)), + )("🔮"), memo({ example: "🔮" }), ), ); + +Deno.test("When not found, return empty object", () => + assertStrictEquals( + getGroups( + buildUnicode(captureNamed("example")(WILDCARD)), + )(""), + EMPTY_OBJECT, + ), +); From 04bbd22304da2a0e1792c93a23afbd3cd2570c95 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:04:42 -0500 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20(@simulcast)=20up?= =?UTF-8?q?date=20to=20use=20new=20`getGroups`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @simulcast/core/broadcastProxyHandler.ts | 7 ++-- @simulcast/core/eventRegExp.ts | 36 ------------------ @simulcast/core/getEventTypeAndName.ts | 37 +++++++++++++++++++ @simulcast/core/mod.ts | 2 +- @simulcast/preact/getEventName.ts | 29 +++++++++++++++ @simulcast/preact/mod.ts | 2 +- @simulcast/preact/onRegExp.ts | 24 ------------ @simulcast/preact/useBroadcastProxyHandler.ts | 5 +-- @simulcast/vue/useBroadcastProxyHandler.ts | 5 +-- 9 files changed, 76 insertions(+), 71 deletions(-) delete mode 100644 @simulcast/core/eventRegExp.ts create mode 100644 @simulcast/core/getEventTypeAndName.ts create mode 100644 @simulcast/preact/getEventName.ts delete mode 100644 @simulcast/preact/onRegExp.ts diff --git a/@simulcast/core/broadcastProxyHandler.ts b/@simulcast/core/broadcastProxyHandler.ts index 1aade87..25ab99b 100644 --- a/@simulcast/core/broadcastProxyHandler.ts +++ b/@simulcast/core/broadcastProxyHandler.ts @@ -2,7 +2,7 @@ import { EMPTY_OBJECT } from "@coven/constants"; import { createObject, get, mutate, set } from "@coven/utils"; import type { BroadcastObject } from "./BroadcastObject.ts"; import type { EventTypeDictionary } from "./EventTypeDictionary.ts"; -import { eventRegExp } from "./eventRegExp.ts"; +import { getEventTypeAndName } from "./getEventTypeAndName.ts"; /** * Proxy handler that enables the aliasing of `on("event")` as `onEvent`. @@ -15,8 +15,9 @@ export const broadcastProxyHandler: Readonly<{ }> = createObject({ get: (broadcast, property) => { const { name, type } = - (!(property in broadcast) && eventRegExp.exec(property)?.groups) - || EMPTY_OBJECT; + property in broadcast ? EMPTY_OBJECT : ( + getEventTypeAndName(property) + ); if (name && type) { const setProperty = set(property); diff --git a/@simulcast/core/eventRegExp.ts b/@simulcast/core/eventRegExp.ts deleted file mode 100644 index 026d45b..0000000 --- a/@simulcast/core/eventRegExp.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - allow, - buildUnicode, - captureNamed, - characterClass, - disjunction, - END, - range, - START, - WORD, -} from "@coven/expression"; -import type { Replace } from "@coven/types"; - -/** - * Regular expression to detect `on` and `emit` event aliases. - * - * @example - * ```typescript - * eventRegExp.test("onExample"); // true - * eventRegExp.test("on"); // false - * eventRegExp.test("emitExample"); // true - * eventRegExp.test("example"); // false - * ``` - */ -export const eventRegExp: Replace< - RegExp, - Readonly<{ - flags: "u"; - source: "^(?emit|on)(?[A-Z]\\w*)$"; - }> -> = buildUnicode( - START, - captureNamed("type")(disjunction("emit", "on")), - captureNamed("name")(characterClass(range("A")("Z")), allow(WORD)), - END, -); diff --git a/@simulcast/core/getEventTypeAndName.ts b/@simulcast/core/getEventTypeAndName.ts new file mode 100644 index 0000000..81e77bc --- /dev/null +++ b/@simulcast/core/getEventTypeAndName.ts @@ -0,0 +1,37 @@ +import { + allow, + buildUnicode, + captureNamed, + characterClass, + disjunction, + END, + getGroups, + range, + START, + WORD, +} from "@coven/expression"; +import { Stringable } from "@coven/types"; + +/** + * Get `on` and `emit` type from event aliases and name.. + * + * @example + * ```typescript + * getEventTypeAndName("onExample"); // { type:"on", name: "Example" } + * getEventTypeAndName("on"); // { type:undefined, name: undefined } + * getEventTypeAndName("emitExample"); // { type:"emit", name: "Example" } + * getEventTypeAndName("example"); // { type:undefined, name: undefined } + * ``` + */ +export const getEventTypeAndName: ( + stringable: Stringable, +) => Partial>> = getGroups< + readonly ["type", "name"] +>( + buildUnicode( + START, + captureNamed("type")(disjunction("emit", "on")), + captureNamed("name")(characterClass(range("A")("Z")), allow(WORD)), + END, + ), +); diff --git a/@simulcast/core/mod.ts b/@simulcast/core/mod.ts index 4f14a6f..e43f22b 100644 --- a/@simulcast/core/mod.ts +++ b/@simulcast/core/mod.ts @@ -5,7 +5,7 @@ export type { BroadcastOn } from "./BroadcastOn.ts"; export { broadcastProxyHandler } from "./broadcastProxyHandler.ts"; export { emit } from "./emit.ts"; export type { EventHandler } from "./EventHandler.ts"; -export { eventRegExp } from "./eventRegExp.ts"; export type { EventRegistry } from "./EventRegistry.ts"; export type { EventTypeDictionary } from "./EventTypeDictionary.ts"; +export { getEventTypeAndName } from "./getEventTypeAndName.ts"; export { on } from "./on.ts"; diff --git a/@simulcast/preact/getEventName.ts b/@simulcast/preact/getEventName.ts new file mode 100644 index 0000000..74408b6 --- /dev/null +++ b/@simulcast/preact/getEventName.ts @@ -0,0 +1,29 @@ +import { + allow, + buildUnicode, + captureNamed, + characterClass, + END, + getGroups, + range, + START, + WORD, +} from "@coven/expression"; + +/** + * Get event name out of string (or undefined otherwise). + * + * @example + * ```typescript + * getEventName("onExample"); // { name: "Example" } + * getEventName("offExample"); // { name: undefined } + * ``` + */ +export const getEventName = getGroups( + buildUnicode( + START, + "on", + captureNamed("name")(characterClass(range("A")("Z")), allow(WORD)), + END, + ), +); diff --git a/@simulcast/preact/mod.ts b/@simulcast/preact/mod.ts index 915451c..793aab9 100644 --- a/@simulcast/preact/mod.ts +++ b/@simulcast/preact/mod.ts @@ -1,4 +1,4 @@ -export { onRegExp } from "./onRegExp.ts"; +export { getEventName } from "./getEventName.ts"; export { useBroadcast } from "./useBroadcast.ts"; export type { UseBroadcastObject } from "./UseBroadcastObject.ts"; export type { UseBroadcastOn } from "./UseBroadcastOn.ts"; diff --git a/@simulcast/preact/onRegExp.ts b/@simulcast/preact/onRegExp.ts deleted file mode 100644 index fb329ce..0000000 --- a/@simulcast/preact/onRegExp.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - allow, - buildUnicode, - captureNamed, - characterClass, - END, - range, - START, - WORD, -} from "@coven/expression"; -import type { Replace } from "@coven/types"; - -/** - * Regular expression to capture properties starting with `"on"`. - */ -export const onRegExp: Replace< - RegExp, - Readonly<{ flags: "u"; source: "^on(?[A-Z]\\w*)$" }> -> = buildUnicode( - START, - "on", - captureNamed("name")(characterClass(range("A")("Z")), allow(WORD)), - END, -); diff --git a/@simulcast/preact/useBroadcastProxyHandler.ts b/@simulcast/preact/useBroadcastProxyHandler.ts index 2a19fd1..0df45af 100644 --- a/@simulcast/preact/useBroadcastProxyHandler.ts +++ b/@simulcast/preact/useBroadcastProxyHandler.ts @@ -2,7 +2,7 @@ import { EMPTY_ARRAY, EMPTY_OBJECT } from "@coven/constants"; import { createObject, mutate, set } from "@coven/utils"; import type { EventHandler, EventTypeDictionary } from "@simulcast/core"; -import { onRegExp } from "./onRegExp.ts"; +import { getEventName } from "./getEventName.ts"; import type { UseBroadcastObject } from "./UseBroadcastObject.ts"; /** @@ -16,8 +16,7 @@ export const useBroadcastProxyHandler: Readonly<{ }> = createObject({ get: (broadcast, property) => { const { name } = - (!(property in broadcast) && onRegExp.exec(property)?.groups) - || EMPTY_OBJECT; + property in broadcast ? EMPTY_OBJECT : getEventName(property); if (name) { const setProperty = set(property); diff --git a/@simulcast/vue/useBroadcastProxyHandler.ts b/@simulcast/vue/useBroadcastProxyHandler.ts index 16c2c35..bdd0cd5 100644 --- a/@simulcast/vue/useBroadcastProxyHandler.ts +++ b/@simulcast/vue/useBroadcastProxyHandler.ts @@ -2,7 +2,7 @@ import { EMPTY_OBJECT } from "@coven/constants"; import { createObject, mutate, set } from "@coven/utils"; import type { EventHandler, EventTypeDictionary } from "@simulcast/core"; -import { onRegExp } from "@simulcast/preact"; +import { getEventName } from "@simulcast/preact"; import type { UseBroadcastObject } from "./UseBroadcastObject.ts"; /** @@ -16,8 +16,7 @@ export const useBroadcastProxyHandler: Readonly<{ }> = createObject({ get: (broadcast, property) => { const { name } = - (!(property in broadcast) && onRegExp.exec(property)?.groups) - || EMPTY_OBJECT; + property in broadcast ? EMPTY_OBJECT : getEventName(property); if (name) { const setProperty = set(property); From 83e52ee9ef7b3364aef529028334bfd34b1bd582 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:07:24 -0500 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20(@coven/cron)=20u?= =?UTF-8?q?pdate=20to=20use=20new=20`getGroups`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/cron/parse.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/@coven/cron/parse.ts b/@coven/cron/parse.ts index b342942..dcba1e0 100644 --- a/@coven/cron/parse.ts +++ b/@coven/cron/parse.ts @@ -1,5 +1,4 @@ -import { EMPTY_OBJECT } from "@coven/constants"; -import { build } from "@coven/expression"; +import { build, getGroups } from "@coven/expression"; import { entriesToObject, length, objectToEntries } from "@coven/iterables"; import { memoFunction } from "@coven/memo"; import type { KeyOf, Maybe, ReadonlyRecord } from "@coven/types"; @@ -33,8 +32,9 @@ export const parse: (expression: CronString) => Maybe = memoFunction((expression: CronString) => { const entries = parseFieldTuplesMap( objectToEntries( - (buildIU(cronRegExp).exec(normalizeAliases(expression))?.groups - ?? EMPTY_OBJECT) as ReadonlyRecord< + getGroups>>( + buildIU(cronRegExp), + )(normalizeAliases(expression)) as ReadonlyRecord< KeyOf, string >, From 1a0fef76135459c3e2be72f3478e07c974cfec72 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:09:10 -0500 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20(@coven/expression,@?= =?UTF-8?q?coven/types)=20Fix=20typos=20on=20ReadonlyArrays.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/expression/getGroups.ts | 2 +- @coven/types/ExpectedStringables.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/@coven/expression/getGroups.ts b/@coven/expression/getGroups.ts index 3ba94d8..fc396c0 100644 --- a/@coven/expression/getGroups.ts +++ b/@coven/expression/getGroups.ts @@ -39,7 +39,7 @@ export type WrapGroupKeys> = * @returns Escaped value. */ export const getGroups = - ({ + >({ flags, source, }: { diff --git a/@coven/types/ExpectedStringables.ts b/@coven/types/ExpectedStringables.ts index 6b7256d..81e771c 100644 --- a/@coven/types/ExpectedStringables.ts +++ b/@coven/types/ExpectedStringables.ts @@ -10,11 +10,11 @@ import type { Stringable } from "./Stringable.ts"; * ``` * @template Stringables Expected {@linkcode Stringable}s. */ -export type ExpectedStringables = +export type ExpectedStringables> = Stringables extends ( - [ + readonly [ infer Head extends Stringable, - ...infer Tail extends readonly Stringable[], + ...infer Tail extends ReadonlyArray, ] ) ? `${string}${Head}${ExpectedStringables}` From df2ca8600807e2bd8720b1e6223ea3e0dede0279 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:10:22 -0500 Subject: [PATCH 11/14] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(@coven/math)=20even?= =?UTF-8?q?=20more=20refactoring.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/math/Calculation.ts | 9 ++-- @coven/math/PreciseFunction.ts | 6 +-- @coven/math/PreciseToTypeFunction.ts | 2 +- @coven/math/PreciseTuple.ts | 4 -- @coven/math/add.ts | 30 ++---------- @coven/math/calculate.ts | 46 +++++++++-------- @coven/math/divide.ts | 44 +++-------------- @coven/math/fallbackAdd.ts | 15 ++++++ @coven/math/fallbackDivide.ts | 15 ++++++ @coven/math/fallbackMultiply.ts | 15 ++++++ @coven/math/fallbackSubtract.ts | 15 ++++++ @coven/math/getBaseAndZeroes.ts | 2 +- @coven/math/getNumberParts.ts | 2 +- @coven/math/isPrecise.ts | 23 +++++++++ @coven/math/mod.ts | 10 +++- @coven/math/multiply.ts | 38 +++----------- @coven/math/numberFunction.ts | 60 +++++++++++++++++++++++ @coven/math/numberToPrecise.ts | 48 +++++++++--------- @coven/math/precise.ts | 6 ++- @coven/math/preciseDivide.ts | 9 ++-- @coven/math/subtract.ts | 36 +++----------- @coven/math/tests/add.test.ts | 28 ++++++++--- @coven/math/tests/calculate.test.ts | 32 ++++++++++++ @coven/math/tests/divide.test.ts | 26 +++++++--- @coven/math/tests/multiply.test.ts | 30 +++++++++--- @coven/math/tests/numberToPrecise.test.ts | 32 +++++++----- @coven/math/tests/preciseDivide.test.ts | 4 +- @coven/math/tests/subtract.test.ts | 30 +++++++++--- 28 files changed, 384 insertions(+), 233 deletions(-) delete mode 100644 @coven/math/PreciseTuple.ts create mode 100644 @coven/math/fallbackAdd.ts create mode 100644 @coven/math/fallbackDivide.ts create mode 100644 @coven/math/fallbackMultiply.ts create mode 100644 @coven/math/fallbackSubtract.ts create mode 100644 @coven/math/isPrecise.ts create mode 100644 @coven/math/numberFunction.ts diff --git a/@coven/math/Calculation.ts b/@coven/math/Calculation.ts index e8fd25c..6e8c77d 100644 --- a/@coven/math/Calculation.ts +++ b/@coven/math/Calculation.ts @@ -1,5 +1,4 @@ -import type { Maybe } from "@coven/types"; -import type { Precise } from "./PreciseTuple.ts"; +import type { Precise } from "./precise.ts"; /** * Object returned by the `calculate` function, which recursively returns itself @@ -31,9 +30,9 @@ export type Calculation = Readonly<{ plus: (addend: number) => Calculation; /** - * Current {@linkcode Precise} value. + * Current {@linkcode Precise} value (can be `NaN` or `Infinity`). */ - precise: Maybe; + precise: Precise | number; /** * Multiplies previous `value` in calculation times the given `multiplier`. @@ -46,5 +45,5 @@ export type Calculation = Readonly<{ /** * Current `number` value. */ - total: Maybe; + total: number; }>; diff --git a/@coven/math/PreciseFunction.ts b/@coven/math/PreciseFunction.ts index e79e8d1..03e3926 100644 --- a/@coven/math/PreciseFunction.ts +++ b/@coven/math/PreciseFunction.ts @@ -1,10 +1,10 @@ -import type { Maybe, Multary } from "@coven/types"; +import type { Multary } from "@coven/types"; import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; -import type { Precise } from "./PreciseTuple.ts"; +import type { Precise } from "./precise.ts"; /** * Type to represent the curried functions for operations with * {@linkcode Precise} values. */ -export type PreciseFunction = Precise> = +export type PreciseFunction = Multary>; diff --git a/@coven/math/PreciseToTypeFunction.ts b/@coven/math/PreciseToTypeFunction.ts index 4e25a84..baa7732 100644 --- a/@coven/math/PreciseToTypeFunction.ts +++ b/@coven/math/PreciseToTypeFunction.ts @@ -1,5 +1,5 @@ import type { Multary } from "@coven/types"; -import type { Precise } from "./PreciseTuple.ts"; +import type { Precise } from "./precise.ts"; /** * Type used by functions that turn a {@linkcode Precise} into a different type. diff --git a/@coven/math/PreciseTuple.ts b/@coven/math/PreciseTuple.ts deleted file mode 100644 index 2545d0b..0000000 --- a/@coven/math/PreciseTuple.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Type to precisely represent a number as a tuple `[base, exponent]`. - */ -export type Precise = Readonly<[base: bigint, exponent: bigint]>; diff --git a/@coven/math/add.ts b/@coven/math/add.ts index be7628d..b8273c9 100644 --- a/@coven/math/add.ts +++ b/@coven/math/add.ts @@ -1,10 +1,6 @@ -import { memoFunction } from "@coven/memo"; -import { isUndefined } from "@coven/predicates"; -import type { Unary } from "@coven/types"; -import { always } from "@coven/utils"; -import { numberToPrecise } from "./numberToPrecise.ts"; +import { fallbackAdd } from "./fallbackAdd.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseAdd } from "./preciseAdd.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; /** * Curried add operation using {@linkcode preciseAdd}. @@ -20,24 +16,4 @@ import { preciseToNumber } from "./preciseToNumber.ts"; * @param augend Augend value to be on the right side. * @returns Curried function with `augend` in context. */ -export const add: Unary< - [augend: number], - Unary<[addend: number], number> -> = memoFunction((augend) => { - const preciseAugend = numberToPrecise(augend); - const preciseAddAugend = - isUndefined(preciseAugend) ? undefined : preciseAdd(...preciseAugend); - - return isUndefined(preciseAugend) ? - always(augend) - : memoFunction((addend) => { - const preciseAddend = numberToPrecise(addend); - - return ( - isUndefined(preciseAddend) - || isUndefined(preciseAddAugend) - ) ? - addend - : preciseToNumber(...preciseAddAugend(...preciseAddend)); - }); -}); +export const add: NumberFunction = numberFunction(preciseAdd, fallbackAdd); diff --git a/@coven/math/calculate.ts b/@coven/math/calculate.ts index 415bbaa..85439a1 100644 --- a/@coven/math/calculate.ts +++ b/@coven/math/calculate.ts @@ -1,14 +1,18 @@ -import { isUndefined } from "@coven/predicates"; -import type { Maybe } from "@coven/types"; import type { Calculation } from "./Calculation.ts"; +import { fallbackAdd } from "./fallbackAdd.ts"; +import { fallbackDivide } from "./fallbackDivide.ts"; +import { fallbackMultiply } from "./fallbackMultiply.ts"; +import { fallbackSubtract } from "./fallbackSubtract.ts"; +import { isPrecise } from "./isPrecise.ts"; +import type { NumberFunction } from "./numberFunction.ts"; import { numberToPrecise } from "./numberToPrecise.ts"; +import type { Precise } from "./precise.ts"; import { preciseAdd } from "./preciseAdd.ts"; import { preciseDivide } from "./preciseDivide.ts"; import type { PreciseFunction } from "./PreciseFunction.ts"; import { preciseMultiply } from "./preciseMultiply.ts"; import { preciseSubtract } from "./preciseSubtract.ts"; import { preciseToNumber } from "./preciseToNumber.ts"; -import type { Precise } from "./PreciseTuple.ts"; /** * A chainable set of operations. @@ -26,34 +30,34 @@ import type { Precise } from "./PreciseTuple.ts"; * @returns An object with `divideBy`, `minus`, `plus` and `times` methods and a `value` property. */ export const calculate = (value: number): Calculation => { - let precise = numberToPrecise(value); + let left = numberToPrecise(value); - const calculationMethod = - >( - preciseFunction: PreciseFunction, + const method = + ( + precise: PreciseFunction, + fallback: NumberFunction, ) => (right: number): Calculation => { - if (!isUndefined(precise)) { - const preciseRight = numberToPrecise(right); + const preciseRight = numberToPrecise(right); - if (!isUndefined(preciseRight)) { - precise = preciseFunction(...preciseRight)(...precise); - } - } + left = + isPrecise(left) && isPrecise(preciseRight) ? + precise(...preciseRight)(...left) + : fallback(right)( + isPrecise(left) ? preciseToNumber(...left) : left, + ); return calculation; }; const calculation = Object.freeze({ - dividedBy: calculationMethod(preciseDivide), - minus: calculationMethod(preciseSubtract), - plus: calculationMethod(preciseAdd), - precise, - times: calculationMethod(preciseMultiply), + dividedBy: method(preciseDivide, fallbackDivide), + minus: method(preciseSubtract, fallbackSubtract), + plus: method(preciseAdd, fallbackAdd), + precise: left, + times: method(preciseMultiply, fallbackMultiply), get total() { - return isUndefined(precise) ? undefined : ( - preciseToNumber(...precise) - ); + return isPrecise(left) ? preciseToNumber(...left) : left; }, }); diff --git a/@coven/math/divide.ts b/@coven/math/divide.ts index cfe2735..56c4460 100644 --- a/@coven/math/divide.ts +++ b/@coven/math/divide.ts @@ -1,10 +1,6 @@ -import { memoFunction } from "@coven/memo"; -import { isUndefined } from "@coven/predicates"; -import type { Maybe, Unary } from "@coven/types"; -import { always } from "@coven/utils"; -import { numberToPrecise } from "./numberToPrecise.ts"; +import { fallbackDivide } from "./fallbackDivide.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseDivide } from "./preciseDivide.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; /** * Curried divide operation using {@linkcode preciseDivide}. @@ -16,38 +12,10 @@ import { preciseToNumber } from "./preciseToNumber.ts"; * half(1); // 0.5 * ``` * @see {@linkcode preciseDivide} - * @see {@linkcode pipe} * @param divisor Divisor to be used in the division. * @returns Curried function with `divisor` in context. */ -export const divide: Unary< - [augend: number], - Unary<[addend: number], Maybe> -> = memoFunction((divisor) => { - const preciseDivisor = numberToPrecise(divisor); - const preciseDivideDivisor = - isUndefined(preciseDivisor) ? undefined : ( - preciseDivide(...preciseDivisor) - ); - - return ( - isUndefined(preciseDivisor) ? - Number.isNaN(divisor) ? - always(NaN) - : (addend) => (Number.isFinite(addend) ? 0 : NaN) - : memoFunction((addend) => { - const preciseAddend = numberToPrecise(addend); - const preciseResult = - ( - isUndefined(preciseAddend) - || isUndefined(preciseDivideDivisor) - ) ? - undefined - : preciseDivideDivisor(...preciseAddend); - - return isUndefined(preciseResult) ? addend : ( - preciseToNumber(...preciseResult) - ); - }) - ); -}); +export const divide: NumberFunction = numberFunction( + preciseDivide, + fallbackDivide, +); diff --git a/@coven/math/fallbackAdd.ts b/@coven/math/fallbackAdd.ts new file mode 100644 index 0000000..f976f3a --- /dev/null +++ b/@coven/math/fallbackAdd.ts @@ -0,0 +1,15 @@ +import { memoFunction } from "@coven/memo"; +import type { NumberFunction } from "./numberFunction.ts"; + +/** + * Fallkack function for `add` when the given numbers produce errors (like + * `NaN` or `Infinity`). + * + * @example + * ```typescript + * fallbackAdd(13)(42); // 55 + * ``` + */ +export const fallbackAdd: NumberFunction = memoFunction((augend) => + memoFunction((addend) => addend + augend), +); diff --git a/@coven/math/fallbackDivide.ts b/@coven/math/fallbackDivide.ts new file mode 100644 index 0000000..c0fa36e --- /dev/null +++ b/@coven/math/fallbackDivide.ts @@ -0,0 +1,15 @@ +import { memoFunction } from "@coven/memo"; +import type { NumberFunction } from "./numberFunction.ts"; + +/** + * Fallkack function for `divide` when the given numbers produce errors (like + * `NaN` or `Infinity`). + * + * @example + * ```typescript + * fallbackDivide(13)(42); // ~3.23 + * ``` + */ +export const fallbackDivide: NumberFunction = memoFunction((divisor) => + memoFunction((dividend) => dividend / divisor), +); diff --git a/@coven/math/fallbackMultiply.ts b/@coven/math/fallbackMultiply.ts new file mode 100644 index 0000000..dd312c0 --- /dev/null +++ b/@coven/math/fallbackMultiply.ts @@ -0,0 +1,15 @@ +import { memoFunction } from "@coven/memo"; +import type { NumberFunction } from "./numberFunction.ts"; + +/** + * Fallkack function for `multiply` when the given numbers produce errors (like + * `NaN` or `Infinity`). + * + * @example + * ```typescript + * fallbackMultiply(13)(42); // 546 + * ``` + */ +export const fallbackMultiply: NumberFunction = memoFunction((multiplier) => + memoFunction((multiplicand) => multiplicand + multiplier), +); diff --git a/@coven/math/fallbackSubtract.ts b/@coven/math/fallbackSubtract.ts new file mode 100644 index 0000000..ab9105a --- /dev/null +++ b/@coven/math/fallbackSubtract.ts @@ -0,0 +1,15 @@ +import { memoFunction } from "@coven/memo"; +import type { NumberFunction } from "./numberFunction.ts"; + +/** + * Fallkack function for `subtract` when the given numbers produce errors (like + * `NaN` or `Infinity`). + * + * @example + * ```typescript + * fallbackSubtract(13)(42); // 29 + * ``` + */ +export const fallbackSubtract: NumberFunction = memoFunction((subtrahend) => + memoFunction((minuend) => minuend - subtrahend), +); diff --git a/@coven/math/getBaseAndZeroes.ts b/@coven/math/getBaseAndZeroes.ts index 8a94f2b..4477aab 100644 --- a/@coven/math/getBaseAndZeroes.ts +++ b/@coven/math/getBaseAndZeroes.ts @@ -25,7 +25,7 @@ import type { Stringable } from "@coven/types"; export const getBaseAndZeroes: ( stringable: Stringable, ) => Partial>> = getGroups< - ["normalizedBase", "zeroes"] + readonly ["normalizedBase", "zeroes"] >( buildUnicode( START, diff --git a/@coven/math/getNumberParts.ts b/@coven/math/getNumberParts.ts index 3e89e9d..c264620 100644 --- a/@coven/math/getNumberParts.ts +++ b/@coven/math/getNumberParts.ts @@ -27,7 +27,7 @@ import type { Stringable } from "@coven/types"; export const getNumberParts: ( stringable: Stringable, ) => Partial>> = - getGroups<["integral", "fractional", "exponent"]>( + getGroups( buildUnicode( START, group( diff --git a/@coven/math/isPrecise.ts b/@coven/math/isPrecise.ts new file mode 100644 index 0000000..941e99b --- /dev/null +++ b/@coven/math/isPrecise.ts @@ -0,0 +1,23 @@ +import { isArray, isBigInt } from "@coven/predicates"; +import type { Precise } from "./precise.ts"; + +/** + * Predicate to determine if the given value is a {@linkcode Precise}. + * + * @example + * ```typescript + * isPrecise([]); // false + * isPrecise(13); // false + * isPrecise([13, 42]); // false + * isPrecise([13n, 42]); // false + * isPrecise([13, 42n]); // false + * isPrecise([13n, 42n]); // true + * ``` + * @param value Value to check. + * @returns `true` if value is a `Precise`, `false` otherwise. + */ +export const isPrecise = (value: unknown): value is Precise => + isArray(value) + && value.length === 2 + && isBigInt(value[0]) + && isBigInt(value[1]); diff --git a/@coven/math/mod.ts b/@coven/math/mod.ts index ed0cf51..18efffa 100644 --- a/@coven/math/mod.ts +++ b/@coven/math/mod.ts @@ -2,11 +2,17 @@ export { add } from "./add.ts"; export { calculate } from "./calculate.ts"; export type { Calculation } from "./Calculation.ts"; export { divide } from "./divide.ts"; +export { fallbackAdd } from "./fallbackAdd.ts"; +export { fallbackDivide } from "./fallbackDivide.ts"; +export { fallbackMultiply } from "./fallbackMultiply.ts"; +export { fallbackSubtract } from "./fallbackSubtract.ts"; export { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; export { getNumberParts } from "./getNumberParts.ts"; +export { isPrecise } from "./isPrecise.ts"; export { multiply } from "./multiply.ts"; +export { numberFunction, type NumberFunction } from "./numberFunction.ts"; export { numberToPrecise } from "./numberToPrecise.ts"; -export { precise } from "./precise.ts"; +export { precise, type Precise } from "./precise.ts"; export { preciseAdd } from "./preciseAdd.ts"; export { preciseDivide } from "./preciseDivide.ts"; export type { PreciseFunction } from "./PreciseFunction.ts"; @@ -14,5 +20,5 @@ export { preciseMultiply } from "./preciseMultiply.ts"; export { preciseSubtract } from "./preciseSubtract.ts"; export { preciseToBigInt } from "./preciseToBigInt.ts"; export { preciseToNumber } from "./preciseToNumber.ts"; -export type { Precise } from "./PreciseTuple.ts"; +export type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; export { subtract } from "./subtract.ts"; diff --git a/@coven/math/multiply.ts b/@coven/math/multiply.ts index bd87ae9..c76f02c 100644 --- a/@coven/math/multiply.ts +++ b/@coven/math/multiply.ts @@ -1,10 +1,6 @@ -import { memoFunction } from "@coven/memo"; -import { isUndefined } from "@coven/predicates"; -import type { Unary } from "@coven/types"; -import { always } from "@coven/utils"; -import { numberToPrecise } from "./numberToPrecise.ts"; +import { fallbackMultiply } from "./fallbackMultiply.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseMultiply } from "./preciseMultiply.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; /** * Curried multiply operation using {@linkcode preciseMultiply}. @@ -16,32 +12,10 @@ import { preciseToNumber } from "./preciseToNumber.ts"; * double(6.5); // 13 * ``` * @see {@linkcode preciseMultiply} - * @see {@linkcode pipe} * @param multiplier Multiplier value to be used in the multiplication. * @returns Curried function with `multiplier` in context. */ -export const multiply: Unary< - [multiplier: number], - Unary<[addend: number], number> -> = memoFunction((multiplier) => { - const preciseMultiplier = numberToPrecise(multiplier); - const preciseAddAugend = - isUndefined(preciseMultiplier) ? undefined : ( - preciseMultiply(...preciseMultiplier) - ); - - return isUndefined(preciseMultiplier) ? - always(multiplier) - : memoFunction((multiplicand) => { - const preciseMultiplicand = numberToPrecise(multiplicand); - - return ( - isUndefined(preciseMultiplicand) - || isUndefined(preciseAddAugend) - ) ? - multiplicand - : preciseToNumber( - ...preciseAddAugend(...preciseMultiplicand), - ); - }); -}); +export const multiply: NumberFunction = numberFunction( + preciseMultiply, + fallbackMultiply, +); diff --git a/@coven/math/numberFunction.ts b/@coven/math/numberFunction.ts new file mode 100644 index 0000000..5196703 --- /dev/null +++ b/@coven/math/numberFunction.ts @@ -0,0 +1,60 @@ +import { memoFunction } from "@coven/memo"; +import { isFunction } from "@coven/predicates"; +import type { Unary } from "@coven/types"; +import { always } from "../utils/always.ts"; +import { isPrecise } from "./isPrecise.ts"; +import { numberToPrecise } from "./numberToPrecise.ts"; +import type { Precise } from "./precise.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; +import { preciseToNumber } from "./preciseToNumber.ts"; + +/** + * Type to represent curried math functions. + */ +export type NumberFunction = Unary< + [right: number], + Unary<[left: number], number> +>; + +/** + * Curried function to generate number to number math functions out of precies + * functions. + * + * @example + * ```typescript + * import { preciseDivide } from "@coven/math"; + * + * const divide = numberFunction(preciseDivide, (right) => (left) => left / right); + * const half = divide(2); + * + * half(1); // 0.5 + * ``` + * @param preciseFunction Precise function to be used. + * @param fallback Optional fallback function for NaN/Infinite values. + * @returns Curried function number to number operations. + */ +export const numberFunction = ( + preciseFunction: PreciseFunction, + fallback: NumberFunction = always, +): NumberFunction => + memoFunction((right) => { + const preciseRight = numberToPrecise(right); + const preciseOperationRight = + isPrecise(preciseRight) ? + preciseFunction(...preciseRight) + : preciseRight; + + return isFunction(preciseOperationRight) ? + memoFunction((left) => { + const preciseLeft = numberToPrecise(left); + const result = + isPrecise(preciseLeft) ? + preciseOperationRight(...preciseLeft) + : left; + + return isPrecise(result) ? + preciseToNumber(...result) + : result; + }) + : fallback(right); + }); diff --git a/@coven/math/numberToPrecise.ts b/@coven/math/numberToPrecise.ts index 2aa845f..0b3df8e 100644 --- a/@coven/math/numberToPrecise.ts +++ b/@coven/math/numberToPrecise.ts @@ -1,8 +1,8 @@ import { memoFunction } from "@coven/memo"; -import type { Maybe, Unary } from "@coven/types"; +import type { Unary } from "@coven/types"; import { getNumberParts } from "./getNumberParts.ts"; +import type { Precise } from "./precise.ts"; import { precise } from "./precise.ts"; -import type { Precise } from "./PreciseTuple.ts"; /** * Turns a `number` into a {@linkcode Precise}. @@ -12,32 +12,30 @@ import type { Precise } from "./PreciseTuple.ts"; * numberToPrecise(13); // [13n, 0n] * numberToPrecise(1.3); // [13n, -1n] * numberToPrecise(1300); // [13n, 2n] - * numberToPrecise(Infinity); // undefined - * numberToPrecise(-Infinity); // undefined - * numberToPrecise(NaN); // undefined + * numberToPrecise(Infinity); // Infinity + * numberToPrecise(-Infinity); // -Infinity + * numberToPrecise(NaN); // NaN * ``` * @see {@linkcode precise} * @param number Number to convert. * @returns A {@linkcode Precise} representation of the given `number`. */ -export const numberToPrecise: Unary< - [number: number], - Maybe -> = memoFunction((number: number) => { - if (Number.isFinite(number) && !Number.isInteger(number)) { - const { - integral = "", - fractional = "", - exponent = "0", - } = getNumberParts(number); +export const numberToPrecise: Unary<[number: number], Precise | number> = + memoFunction((number: number) => { + if (Number.isFinite(number) && !Number.isInteger(number)) { + const { + integral = "", + fractional = "", + exponent = "0", + } = getNumberParts(number); - return precise( - BigInt(`${integral}${fractional}`), - -(BigInt(fractional.length) - BigInt(exponent)), - ); - } else { - return Number.isFinite(number) && !Number.isNaN(number) ? - precise(BigInt(number), 0n) - : undefined; - } -}); + return precise( + BigInt(`${integral}${fractional}`), + -(BigInt(fractional.length) - BigInt(exponent)), + ); + } else { + return Number.isFinite(number) && !Number.isNaN(number) ? + precise(BigInt(number), 0n) + : number; + } + }); diff --git a/@coven/math/precise.ts b/@coven/math/precise.ts index ef80705..48c7844 100644 --- a/@coven/math/precise.ts +++ b/@coven/math/precise.ts @@ -1,7 +1,11 @@ import { memo, memoFunction } from "@coven/memo"; -import type { Precise } from "./PreciseTuple.ts"; import { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; +/** + * Type to precisely represent a number as a tuple `[base, exponent]`. + */ +export type Precise = Readonly<[base: bigint, exponent: bigint]>; + /** * Takes a `base` and `exponent` and normalizes it returning a {@linkcode Precise}. * diff --git a/@coven/math/preciseDivide.ts b/@coven/math/preciseDivide.ts index fa142c0..fb2d438 100644 --- a/@coven/math/preciseDivide.ts +++ b/@coven/math/preciseDivide.ts @@ -1,11 +1,10 @@ import { memoFunction } from "@coven/memo"; -import type { Maybe } from "@coven/types"; import { always } from "@coven/utils"; +import type { Precise } from "./precise.ts"; import { precise } from "./precise.ts"; import type { PreciseFunction } from "./PreciseFunction.ts"; -import type { Precise } from "./PreciseTuple.ts"; -const alwaysUndefined = always(undefined); +const alwaysInfinity = always(Infinity); /** * Curried divide operation using the internal {@linkcode Precise} type. @@ -22,9 +21,9 @@ const alwaysUndefined = always(undefined); * @param divisorExponent Divisor exponent to use in the division. * @returns Curried function with `divisorBase` and `divisorExponent` in context. */ -export const preciseDivide: PreciseFunction> = memoFunction( +export const preciseDivide: PreciseFunction = memoFunction( (divisorBase, divisorExponent) => - divisorBase === 0n ? alwaysUndefined : ( + divisorBase === 0n ? alwaysInfinity : ( memoFunction((dividendBase, dividendExponent) => { let exponent = 0n; let base = dividendBase / divisorBase; diff --git a/@coven/math/subtract.ts b/@coven/math/subtract.ts index 62b8e46..e263176 100644 --- a/@coven/math/subtract.ts +++ b/@coven/math/subtract.ts @@ -1,10 +1,6 @@ -import { memoFunction } from "@coven/memo"; -import { isUndefined } from "@coven/predicates"; -import type { Unary } from "@coven/types"; -import { always } from "@coven/utils"; -import { numberToPrecise } from "./numberToPrecise.ts"; +import { fallbackSubtract } from "./fallbackSubtract.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseSubtract } from "./preciseSubtract.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; /** * Curried subtract operation using {@linkcode pipe} with {@linkcode preciseSubtract}. @@ -16,30 +12,10 @@ import { preciseToNumber } from "./preciseToNumber.ts"; * previous(14); // 13 * ``` * @see {@linkcode preciseSubtract} - * @see {@linkcode pipe} * @param subtrahend Subtrahend value to be used in the subtraction. * @returns Curried function with `subtrahend` in context. */ -export const subtract: Unary< - [subtrahend: number], - Unary<[minuend: number], number> -> = memoFunction((subtrahend) => { - const preciseSubtrahend = numberToPrecise(subtrahend); - const preciseAddAugend = - isUndefined(preciseSubtrahend) ? undefined : ( - preciseSubtract(...preciseSubtrahend) - ); - - return isUndefined(preciseSubtrahend) ? - always(subtrahend) - : memoFunction((minuend) => { - const preciseMinuend = numberToPrecise(minuend); - - return ( - isUndefined(preciseMinuend) - || isUndefined(preciseAddAugend) - ) ? - minuend - : preciseToNumber(...preciseAddAugend(...preciseMinuend)); - }); -}); +export const subtract: NumberFunction = numberFunction( + preciseSubtract, + fallbackSubtract, +); diff --git a/@coven/math/tests/add.test.ts b/@coven/math/tests/add.test.ts index dd29a04..874d58a 100644 --- a/@coven/math/tests/add.test.ts +++ b/@coven/math/tests/add.test.ts @@ -5,6 +5,8 @@ const addPositive = add(2); const addNegative = add(-2); const addFloat = add(0.2); const addNegativeFloat = add(-0.2); +const addInfinity = add(Infinity); +const addNaN = add(NaN); Deno.test("1 + 2 = 3", () => assertStrictEquals(addPositive(1), 3)); @@ -54,14 +56,28 @@ Deno.test("0.00001 + 5 = 5.00001", () => assertStrictEquals(add(5)(0.000_01), 5.000_01), ); -Deno.test("Infinity + 13 = Infinity", () => - assertStrictEquals(add(13)(Infinity), Infinity), +Deno.test("Infinity + 2 = Infinity", () => + assertStrictEquals(addPositive(Infinity), Infinity), ); -Deno.test("13 + Infinity = Infinity", () => - assertStrictEquals(add(Infinity)(13), Infinity), +Deno.test("NaN + 2 = NaN", () => assertStrictEquals(addPositive(NaN), NaN)); + +Deno.test("Infinity + Infinity = Infinity", () => + assertStrictEquals(addInfinity(Infinity), Infinity), +); + +Deno.test("2 + Infinity = Infinity", () => + assertStrictEquals(addInfinity(2), Infinity), ); -Deno.test("NaN + 13 = NaN", () => assertStrictEquals(add(NaN)(13), NaN)); +Deno.test("NaN + Infinity = NaN", () => + assertStrictEquals(addInfinity(NaN), NaN), +); -Deno.test("13 + NaN = NaN", () => assertStrictEquals(add(13)(NaN), NaN)); +Deno.test("NaN + NaN = NaN", () => assertStrictEquals(addNaN(NaN), NaN)); + +Deno.test("2 + NaN = NaN", () => assertStrictEquals(addNaN(2), NaN)); + +Deno.test("Infinity + NaN = NaN", () => + assertStrictEquals(addNaN(Infinity), NaN), +); diff --git a/@coven/math/tests/calculate.test.ts b/@coven/math/tests/calculate.test.ts index 0b3afa2..7578c02 100644 --- a/@coven/math/tests/calculate.test.ts +++ b/@coven/math/tests/calculate.test.ts @@ -38,3 +38,35 @@ Deno.test("((2 + 2) / 2 * 2) - 2 = 2", () => 2, ), ); + +Deno.test("Infinity + 2 = Infinity", () => + assertStrictEquals(calculate(Infinity).plus(2).total, Infinity), +); + +Deno.test("NaN + 2 = NaN", () => + assertStrictEquals(calculate(NaN).plus(2).total, NaN), +); + +Deno.test("Infinity + Infinity = Infinity", () => + assertStrictEquals(calculate(Infinity).plus(Infinity).total, Infinity), +); + +Deno.test("2 + Infinity = Infinity", () => + assertStrictEquals(calculate(2).plus(Infinity).total, Infinity), +); + +Deno.test("NaN + Infinity = NaN", () => + assertStrictEquals(calculate(NaN).plus(Infinity).total, NaN), +); + +Deno.test("NaN + NaN = NaN", () => + assertStrictEquals(calculate(NaN).plus(NaN).total, NaN), +); + +Deno.test("2 + NaN = NaN", () => + assertStrictEquals(calculate(2).plus(NaN).total, NaN), +); + +Deno.test("Infinity + NaN = NaN", () => + assertStrictEquals(calculate(Infinity).plus(NaN).total, NaN), +); diff --git a/@coven/math/tests/divide.test.ts b/@coven/math/tests/divide.test.ts index 73a8b83..0328d62 100644 --- a/@coven/math/tests/divide.test.ts +++ b/@coven/math/tests/divide.test.ts @@ -5,6 +5,8 @@ const dividePositive = divide(2); const divideNegative = divide(-2); const divideFloat = divide(0.2); const divideNegativeFloat = divide(-0.2); +const divideInfinity = divide(Infinity); +const divideNaN = divide(NaN); Deno.test("1 / 2 = 0.5", () => assertStrictEquals(dividePositive(1), 0.5)); @@ -64,14 +66,26 @@ Deno.test("0.00001 / 5 = 0.000002", () => assertStrictEquals(divide(5)(0.000_01), 0.000_002), ); -Deno.test("Infinity / 13 = Infinity", () => - assertStrictEquals(divide(13)(Infinity), Infinity), +Deno.test("Infinity / 2 = Infinity", () => + assertStrictEquals(dividePositive(Infinity), Infinity), ); -Deno.test("13 / Infinity = Infinity", () => - assertStrictEquals(divide(Infinity)(13), 0), +Deno.test("NaN / 2 = NaN", () => assertStrictEquals(dividePositive(NaN), NaN)); + +Deno.test("Infinity / Infinity = NaN", () => + assertStrictEquals(divideInfinity(Infinity), NaN), +); + +Deno.test("2 / Infinity = 0", () => assertStrictEquals(divideInfinity(2), 0)); + +Deno.test("NaN / Infinity = NaN", () => + assertStrictEquals(divideInfinity(NaN), NaN), ); -Deno.test("NaN / 13 = NaN", () => assertStrictEquals(divide(NaN)(13), NaN)); +Deno.test("NaN / NaN = NaN", () => assertStrictEquals(divideNaN(NaN), NaN)); + +Deno.test("2 / NaN = NaN", () => assertStrictEquals(divideNaN(2), NaN)); -Deno.test("13 / NaN = NaN", () => assertStrictEquals(divide(13)(NaN), NaN)); +Deno.test("Infinity / NaN = NaN", () => + assertStrictEquals(divideNaN(Infinity), NaN), +); diff --git a/@coven/math/tests/multiply.test.ts b/@coven/math/tests/multiply.test.ts index ac5cbf6..66ae9a4 100644 --- a/@coven/math/tests/multiply.test.ts +++ b/@coven/math/tests/multiply.test.ts @@ -5,6 +5,8 @@ const multiplyPositive = multiply(2); const multiplyNegative = multiply(-2); const multiplyFloat = multiply(0.2); const multiplyNegativeFloat = multiply(-0.2); +const multiplyInfinity = multiply(Infinity); +const multiplyNaN = multiply(NaN); Deno.test("1 * 2 = 2", () => assertStrictEquals(multiplyPositive(1), 2)); @@ -74,14 +76,30 @@ Deno.test("13 * Infinity = Infinity", () => assertStrictEquals(multiply(Infinity)(13), Infinity), ); -Deno.test("Infinity * 13 = Infinity", () => - assertStrictEquals(multiply(13)(Infinity), Infinity), +Deno.test("Infinity * 2 = Infinity", () => + assertStrictEquals(multiplyPositive(Infinity), Infinity), ); -Deno.test("13 * Infinity = Infinity", () => - assertStrictEquals(multiply(Infinity)(13), Infinity), +Deno.test("NaN * 2 = NaN", () => + assertStrictEquals(multiplyPositive(NaN), NaN), +); + +Deno.test("Infinity * Infinity = Infinity", () => + assertStrictEquals(multiplyInfinity(Infinity), Infinity), ); -Deno.test("NaN * 13 = NaN", () => assertStrictEquals(multiply(NaN)(13), NaN)); +Deno.test("2 * Infinity = Infinity", () => + assertStrictEquals(multiplyInfinity(2), Infinity), +); -Deno.test("13 * NaN = NaN", () => assertStrictEquals(multiply(13)(NaN), NaN)); +Deno.test("NaN * Infinity = NaN", () => + assertStrictEquals(multiplyInfinity(NaN), NaN), +); + +Deno.test("NaN * NaN = NaN", () => assertStrictEquals(multiplyNaN(NaN), NaN)); + +Deno.test("2 * NaN = NaN", () => assertStrictEquals(multiplyNaN(2), NaN)); + +Deno.test("Infinity * NaN = NaN", () => + assertStrictEquals(multiplyNaN(Infinity), NaN), +); diff --git a/@coven/math/tests/numberToPrecise.test.ts b/@coven/math/tests/numberToPrecise.test.ts index 5b4313e..8ec4f78 100644 --- a/@coven/math/tests/numberToPrecise.test.ts +++ b/@coven/math/tests/numberToPrecise.test.ts @@ -1,43 +1,53 @@ -import { assertEquals } from "@std/assert"; +import { assertStrictEquals } from "@std/assert"; import { numberToPrecise } from "../numberToPrecise.ts"; import { precise } from "../precise.ts"; Deno.test("13 = precise(13n)", () => - assertEquals(numberToPrecise(13), precise(13n, 0n)), + assertStrictEquals(numberToPrecise(13), precise(13n, 0n)), ); Deno.test("1300 = precise(13n, 2n)", () => - assertEquals(numberToPrecise(1300), precise(13n, 2n)), + assertStrictEquals(numberToPrecise(1300), precise(13n, 2n)), ); Deno.test("-13 = precise(-13n)", () => - assertEquals(numberToPrecise(-13), precise(-13n, 0n)), + assertStrictEquals(numberToPrecise(-13), precise(-13n, 0n)), ); Deno.test("-1300 = precise(-13n, 2n)", () => - assertEquals(numberToPrecise(-1300), precise(-13n, 2n)), + assertStrictEquals(numberToPrecise(-1300), precise(-13n, 2n)), ); Deno.test("13.1 = precise(131n, -1n)", () => - assertEquals(numberToPrecise(13.1), precise(131n, -1n)), + assertStrictEquals(numberToPrecise(13.1), precise(131n, -1n)), ); Deno.test("1300.1 = precise(13_001n, -1n)", () => - assertEquals(numberToPrecise(1300.1), precise(13_001n, -1n)), + assertStrictEquals(numberToPrecise(1300.1), precise(13_001n, -1n)), ); Deno.test("-13.1 = precise(-131n, -1n)", () => - assertEquals(numberToPrecise(-13.1), precise(-131n, -1n)), + assertStrictEquals(numberToPrecise(-13.1), precise(-131n, -1n)), ); Deno.test("-1300.1 = precise(-13_001n, -1n)", () => - assertEquals(numberToPrecise(-1300.1), precise(-13_001n, -1n)), + assertStrictEquals(numberToPrecise(-1300.1), precise(-13_001n, -1n)), ); Deno.test("10000000000000000 = precise(1n, 16n)", () => - assertEquals(numberToPrecise(1e16), precise(1n, 16n)), + assertStrictEquals(numberToPrecise(1e16), precise(1n, 16n)), ); Deno.test("-10000000000000000 = precise(-1n, 16n)", () => - assertEquals(numberToPrecise(-1e16), precise(-1n, 16n)), + assertStrictEquals(numberToPrecise(-1e16), precise(-1n, 16n)), ); + +Deno.test("Infinity = Infinity", () => + assertStrictEquals(numberToPrecise(Infinity), Infinity), +); + +Deno.test("-Infinity = -Infinity", () => + assertStrictEquals(numberToPrecise(-Infinity), -Infinity), +); + +Deno.test("NaN = NaN", () => assertStrictEquals(numberToPrecise(NaN), NaN)); diff --git a/@coven/math/tests/preciseDivide.test.ts b/@coven/math/tests/preciseDivide.test.ts index a472039..55a35fc 100644 --- a/@coven/math/tests/preciseDivide.test.ts +++ b/@coven/math/tests/preciseDivide.test.ts @@ -79,8 +79,8 @@ Deno.test("0.00001 / 5 = 0.000002", () => assertStrictEquals(preciseDivide(5n, 0n)(1n, -5n), precise(2n, -6n)), ); -Deno.test("1 / 0 = undefined", () => - assertStrictEquals(preciseDivide(0n, 0n)(1n, 0n), undefined), +Deno.test("1 / 0 = Infinity", () => + assertStrictEquals(preciseDivide(0n, 0n)(1n, 0n), Infinity), ); Deno.test("Same Precise returned with same values", () => diff --git a/@coven/math/tests/subtract.test.ts b/@coven/math/tests/subtract.test.ts index 16787df..d675f24 100644 --- a/@coven/math/tests/subtract.test.ts +++ b/@coven/math/tests/subtract.test.ts @@ -5,6 +5,8 @@ const subtractPositive = subtract(2); const subtractNegative = subtract(-2); const subtractFloat = subtract(0.2); const subtractNegativeFloat = subtract(-0.2); +const subtractInfinity = subtract(Infinity); +const subtractNaN = subtract(NaN); Deno.test("1 - 2 = -1", () => assertStrictEquals(subtractPositive(1), -1)); @@ -68,14 +70,30 @@ Deno.test("0.00001 - 5 = -4.99999", () => Deno.test("1 - 1 = 0", () => assertStrictEquals(subtract(1)(1), 0)); -Deno.test("Infinity - 13 = Infinity", () => - assertStrictEquals(subtract(13)(Infinity), Infinity), +Deno.test("Infinity - 2 = Infinity", () => + assertStrictEquals(subtractPositive(Infinity), Infinity), ); -Deno.test("13 - Infinity = Infinity", () => - assertStrictEquals(subtract(Infinity)(13), Infinity), +Deno.test("NaN - 2 = NaN", () => + assertStrictEquals(subtractPositive(NaN), NaN), ); -Deno.test("NaN - 13 = NaN", () => assertStrictEquals(subtract(NaN)(13), NaN)); +Deno.test("Infinity - Infinity = NaN", () => + assertStrictEquals(subtractInfinity(Infinity), NaN), +); + +Deno.test("2 - Infinity = -Infinity", () => + assertStrictEquals(subtractInfinity(2), -Infinity), +); + +Deno.test("NaN - Infinity = NaN", () => + assertStrictEquals(subtractInfinity(NaN), NaN), +); + +Deno.test("NaN - NaN = NaN", () => assertStrictEquals(subtractNaN(NaN), NaN)); -Deno.test("13 - NaN = NaN", () => assertStrictEquals(subtract(13)(NaN), NaN)); +Deno.test("2 - NaN = NaN", () => assertStrictEquals(subtractNaN(2), NaN)); + +Deno.test("Infinity - NaN = NaN", () => + assertStrictEquals(subtractNaN(Infinity), NaN), +); From 4f7ce5c48c6b028800f05a0740a5be1a491718bc Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:13:10 -0500 Subject: [PATCH 12/14] =?UTF-8?q?=F0=9F=94=96=20(shared)=20version=20bump.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/compare/deno.json | 2 +- @coven/constants/deno.json | 2 +- @coven/cron/deno.json | 2 +- @coven/expression/deno.json | 2 +- @coven/iterables/deno.json | 2 +- @coven/math/deno.json | 2 +- @coven/memo/deno.json | 2 +- @coven/pair/deno.json | 2 +- @coven/parsers/deno.json | 2 +- @coven/predicates/deno.json | 2 +- @coven/rules/deno.json | 2 +- @coven/template/deno.json | 2 +- @coven/terminal/deno.json | 2 +- @coven/types/deno.json | 2 +- @coven/utils/deno.json | 2 +- @simulcast/core/deno.json | 2 +- @simulcast/preact/deno.json | 2 +- @simulcast/react/deno.json | 2 +- @simulcast/vue/deno.json | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/@coven/compare/deno.json b/@coven/compare/deno.json index b9fbceb..48c6f06 100644 --- a/@coven/compare/deno.json +++ b/@coven/compare/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/compare", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/constants/deno.json b/@coven/constants/deno.json index 1cdba8b..da8bf78 100644 --- a/@coven/constants/deno.json +++ b/@coven/constants/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/constants", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/cron/deno.json b/@coven/cron/deno.json index 09190d5..1e964c6 100644 --- a/@coven/cron/deno.json +++ b/@coven/cron/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/cron", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/expression/deno.json b/@coven/expression/deno.json index 0a58ffd..af89608 100644 --- a/@coven/expression/deno.json +++ b/@coven/expression/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/expression", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/iterables/deno.json b/@coven/iterables/deno.json index 745549d..fcce8a7 100644 --- a/@coven/iterables/deno.json +++ b/@coven/iterables/deno.json @@ -5,5 +5,5 @@ "./async": "./async/mod.ts" }, "name": "@coven/iterables", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/math/deno.json b/@coven/math/deno.json index f7a2010..7f6366b 100644 --- a/@coven/math/deno.json +++ b/@coven/math/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/math", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/memo/deno.json b/@coven/memo/deno.json index 85d7ea9..7e691a9 100644 --- a/@coven/memo/deno.json +++ b/@coven/memo/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/memo", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/pair/deno.json b/@coven/pair/deno.json index 67b7fc0..4609986 100644 --- a/@coven/pair/deno.json +++ b/@coven/pair/deno.json @@ -13,5 +13,5 @@ "react-dom": "npm:react-dom@^19.2.4" }, "name": "@coven/pair", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/parsers/deno.json b/@coven/parsers/deno.json index ef3160f..679d20e 100644 --- a/@coven/parsers/deno.json +++ b/@coven/parsers/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/parsers", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/predicates/deno.json b/@coven/predicates/deno.json index 5dbbe3f..69347d7 100644 --- a/@coven/predicates/deno.json +++ b/@coven/predicates/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/predicates", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/rules/deno.json b/@coven/rules/deno.json index 14f5da2..c59c683 100644 --- a/@coven/rules/deno.json +++ b/@coven/rules/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/rules", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/template/deno.json b/@coven/template/deno.json index 4e218ba..bc44615 100644 --- a/@coven/template/deno.json +++ b/@coven/template/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/template", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/terminal/deno.json b/@coven/terminal/deno.json index 82d2f5c..427006b 100644 --- a/@coven/terminal/deno.json +++ b/@coven/terminal/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/terminal", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/types/deno.json b/@coven/types/deno.json index 3ee4925..e7ec612 100644 --- a/@coven/types/deno.json +++ b/@coven/types/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/types", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@coven/utils/deno.json b/@coven/utils/deno.json index ec983d7..b21613c 100644 --- a/@coven/utils/deno.json +++ b/@coven/utils/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@coven/utils", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@simulcast/core/deno.json b/@simulcast/core/deno.json index b08dafb..d452fb5 100644 --- a/@simulcast/core/deno.json +++ b/@simulcast/core/deno.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json", "exports": "./mod.ts", "name": "@simulcast/core", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@simulcast/preact/deno.json b/@simulcast/preact/deno.json index de1a15e..f925eb2 100644 --- a/@simulcast/preact/deno.json +++ b/@simulcast/preact/deno.json @@ -11,5 +11,5 @@ "preact": "npm:preact@^10.29.0" }, "name": "@simulcast/preact", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@simulcast/react/deno.json b/@simulcast/react/deno.json index 6761497..187fa09 100644 --- a/@simulcast/react/deno.json +++ b/@simulcast/react/deno.json @@ -12,5 +12,5 @@ "react": "npm:react@^19.2.4" }, "name": "@simulcast/react", - "version": "0.9.3" + "version": "0.9.4" } diff --git a/@simulcast/vue/deno.json b/@simulcast/vue/deno.json index c873080..97f127a 100644 --- a/@simulcast/vue/deno.json +++ b/@simulcast/vue/deno.json @@ -6,5 +6,5 @@ "vue": "npm:vue@^3.5.31" }, "name": "@simulcast/vue", - "version": "0.9.3" + "version": "0.9.4" } From 2a2a36e3b1594f780ce4d42377e592874c849be3 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:13:57 -0500 Subject: [PATCH 13/14] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20(shared)=20dependenc?= =?UTF-8?q?y=20upgrade.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @coven/pair/deno.json | 6 +++--- @simulcast/preact/deno.json | 2 +- @simulcast/react/deno.json | 2 +- @simulcast/vue/deno.json | 2 +- deno.json | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/@coven/pair/deno.json b/@coven/pair/deno.json index 4609986..458ffd9 100644 --- a/@coven/pair/deno.json +++ b/@coven/pair/deno.json @@ -7,10 +7,10 @@ "imports": { "@types/react": "npm:@types/react@^19.2.14", "@types/react-dom": "npm:@types/react-dom@^19.2.3", - "preact": "npm:preact@^10.29.0", + "preact": "npm:preact@^10.29.1", "preact-render-to-string": "npm:preact-render-to-string@^6.6.7", - "react": "npm:react@^19.2.4", - "react-dom": "npm:react-dom@^19.2.4" + "react": "npm:react@^19.2.5", + "react-dom": "npm:react-dom@^19.2.5" }, "name": "@coven/pair", "version": "0.9.4" diff --git a/@simulcast/preact/deno.json b/@simulcast/preact/deno.json index f925eb2..5a5b500 100644 --- a/@simulcast/preact/deno.json +++ b/@simulcast/preact/deno.json @@ -8,7 +8,7 @@ "imports": { "@testing-library/preact": "npm:@testing-library/preact@^3.2.4", "@testing-library/user-event": "npm:@testing-library/user-event@^14.6.1", - "preact": "npm:preact@^10.29.0" + "preact": "npm:preact@^10.29.1" }, "name": "@simulcast/preact", "version": "0.9.4" diff --git a/@simulcast/react/deno.json b/@simulcast/react/deno.json index 187fa09..20f51e4 100644 --- a/@simulcast/react/deno.json +++ b/@simulcast/react/deno.json @@ -9,7 +9,7 @@ "@testing-library/react": "npm:@testing-library/react@^16.3.2", "@testing-library/user-event": "npm:@testing-library/user-event@^14.6.1", "@types/react": "npm:@types/react@^19.2.14", - "react": "npm:react@^19.2.4" + "react": "npm:react@^19.2.5" }, "name": "@simulcast/react", "version": "0.9.4" diff --git a/@simulcast/vue/deno.json b/@simulcast/vue/deno.json index 97f127a..5b5215b 100644 --- a/@simulcast/vue/deno.json +++ b/@simulcast/vue/deno.json @@ -3,7 +3,7 @@ "exports": "./mod.ts", "imports": { "@vue/test-utils": "npm:@vue/test-utils@^2.4.6", - "vue": "npm:vue@^3.5.31" + "vue": "npm:vue@^3.5.32" }, "name": "@simulcast/vue", "version": "0.9.4" diff --git a/deno.json b/deno.json index 8b5ca9e..b4048d7 100644 --- a/deno.json +++ b/deno.json @@ -34,8 +34,8 @@ }, "imports": { "@std/assert": "jsr:@std/assert@^1.0.19", - "happy-dom": "npm:happy-dom@^20.8.9", - "prettier": "npm:prettier@^3.8.1" + "happy-dom": "npm:happy-dom@^20.9.0", + "prettier": "npm:prettier@^3.8.3" }, "lint": { "plugins": ["jsr:@coven/rules"], From 513237fdaa2b71c4978d9b6448d6ea020938e954 Mon Sep 17 00:00:00 2001 From: Lou Cyx Date: Fri, 17 Apr 2026 02:21:09 -0500 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=9A=A8=20(@simulcast)=20fix=20linti?= =?UTF-8?q?ng=20errors.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @simulcast/core/getEventTypeAndName.ts | 2 +- @simulcast/preact/getEventName.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/@simulcast/core/getEventTypeAndName.ts b/@simulcast/core/getEventTypeAndName.ts index 81e77bc..f72c499 100644 --- a/@simulcast/core/getEventTypeAndName.ts +++ b/@simulcast/core/getEventTypeAndName.ts @@ -10,7 +10,7 @@ import { START, WORD, } from "@coven/expression"; -import { Stringable } from "@coven/types"; +import type { Stringable } from "@coven/types"; /** * Get `on` and `emit` type from event aliases and name.. diff --git a/@simulcast/preact/getEventName.ts b/@simulcast/preact/getEventName.ts index 74408b6..259ccba 100644 --- a/@simulcast/preact/getEventName.ts +++ b/@simulcast/preact/getEventName.ts @@ -9,6 +9,7 @@ import { START, WORD, } from "@coven/expression"; +import type { Stringable } from "@coven/types"; /** * Get event name out of string (or undefined otherwise). @@ -19,7 +20,9 @@ import { * getEventName("offExample"); // { name: undefined } * ``` */ -export const getEventName = getGroups( +export const getEventName: ( + stringable: Stringable, +) => Partial>> = getGroups( buildUnicode( START, "on",