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/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 >, 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/expression/getGroups.ts b/@coven/expression/getGroups.ts new file mode 100644 index 0000000..fc396c0 --- /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. + */ +export type WrapGroupKeys> = + GroupKeys extends ( + readonly [ + infer Head extends Stringable, + ...infer Tail extends ReadonlyArray, + ] + ) ? + readonly [`(?<${Head}>`, ...WrapGroupKeys] + : ReadonlyArray; + +/** + * 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( + * 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..5db261d --- /dev/null +++ b/@coven/expression/tests/getGroups.test.ts @@ -0,0 +1,25 @@ +import { EMPTY_OBJECT } from "@coven/constants"; +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( + buildUnicode(captureNamed("example")(WILDCARD)), + )("🔮"), + memo({ example: "🔮" }), + ), +); + +Deno.test("When not found, return empty object", () => + assertStrictEquals( + getGroups( + buildUnicode(captureNamed("example")(WILDCARD)), + )(""), + EMPTY_OBJECT, + ), +); 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/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", + ]), +); diff --git a/@coven/math/Calculation.ts b/@coven/math/Calculation.ts index 74ab220..6e8c77d 100644 --- a/@coven/math/Calculation.ts +++ b/@coven/math/Calculation.ts @@ -1,8 +1,10 @@ +import type { Precise } from "./precise.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 +29,11 @@ export type Calculation = Readonly<{ */ plus: (addend: number) => Calculation; + /** + * Current {@linkcode Precise} value (can be `NaN` or `Infinity`). + */ + precise: Precise | number; + /** * Multiplies previous `value` in calculation times the given `multiplier`. * @@ -36,7 +43,7 @@ export type Calculation = Readonly<{ times: (multiplier: number) => Calculation; /** - * Current value of the calculation. + * Current `number` value. */ - total: Value; + total: number; }>; 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..03e3926 --- /dev/null +++ b/@coven/math/PreciseFunction.ts @@ -0,0 +1,10 @@ +import type { Multary } from "@coven/types"; +import type { PreciseToTypeFunction } from "./PreciseToTypeFunction.ts"; +import type { Precise } from "./precise.ts"; + +/** + * Type to represent the curried functions for operations with + * {@linkcode Precise} values. + */ +export type PreciseFunction = + Multary>; diff --git a/@coven/math/PreciseToTypeFunction.ts b/@coven/math/PreciseToTypeFunction.ts new file mode 100644 index 0000000..baa7732 --- /dev/null +++ b/@coven/math/PreciseToTypeFunction.ts @@ -0,0 +1,7 @@ +import type { Multary } from "@coven/types"; +import type { Precise } from "./precise.ts"; + +/** + * Type used by functions that turn a {@linkcode Precise} into a different type. + */ +export type PreciseToTypeFunction = Multary; diff --git a/@coven/math/PreciseTuple.ts b/@coven/math/PreciseTuple.ts deleted file mode 100644 index 752d273..0000000 --- a/@coven/math/PreciseTuple.ts +++ /dev/null @@ -1,7 +0,0 @@ -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]>; 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..b8273c9 100644 --- a/@coven/math/add.ts +++ b/@coven/math/add.ts @@ -1,8 +1,9 @@ -import { pipe } from "./pipe.ts"; +import { fallbackAdd } from "./fallbackAdd.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseAdd } from "./preciseAdd.ts"; /** - * Curried add operation using {@linkcode pipe} with {@linkcode preciseAdd}. + * Curried add operation using {@linkcode preciseAdd}. * * @example * ```typescript @@ -11,10 +12,8 @@ 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: NumberFunction = numberFunction(preciseAdd, fallbackAdd); 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..85439a1 100644 --- a/@coven/math/calculate.ts +++ b/@coven/math/calculate.ts @@ -1,9 +1,18 @@ -import { memoFunction } from "@coven/memo"; -import { add } from "./add.ts"; import type { Calculation } from "./Calculation.ts"; -import { divide } from "./divide.ts"; -import { multiply } from "./multiply.ts"; -import { subtract } from "./subtract.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"; /** * A chainable set of operations. @@ -13,50 +22,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 left = 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 method = + ( + precise: PreciseFunction, + fallback: NumberFunction, + ) => + (right: number): Calculation => { + 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)), + left = + isPrecise(left) && isPrecise(preciseRight) ? + precise(...preciseRight)(...left) + : fallback(right)( + isPrecise(left) ? preciseToNumber(...left) : left, + ); - /** - * 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: method(preciseDivide, fallbackDivide), + minus: method(preciseSubtract, fallbackSubtract), + plus: method(preciseAdd, fallbackAdd), + precise: left, + times: method(preciseMultiply, fallbackMultiply), + get total() { + return isPrecise(left) ? preciseToNumber(...left) : left; + }, + }); + + return calculation; +}; 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/math/divide.ts b/@coven/math/divide.ts index 815a9db..56c4460 100644 --- a/@coven/math/divide.ts +++ b/@coven/math/divide.ts @@ -1,8 +1,9 @@ -import { pipe } from "./pipe.ts"; +import { fallbackDivide } from "./fallbackDivide.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseDivide } from "./preciseDivide.ts"; /** - * Curried divide operation using {@linkcode pipe} with {@linkcode preciseDivide}. + * Curried divide operation using {@linkcode preciseDivide}. * * @example * ```typescript @@ -11,9 +12,10 @@ import { preciseDivide } from "./preciseDivide.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: (divisor: number) => (dividend: number) => number = - pipe(preciseDivide); +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 new file mode 100644 index 0000000..4477aab --- /dev/null +++ b/@coven/math/getBaseAndZeroes.ts @@ -0,0 +1,39 @@ +import { + allow, + buildUnicode, + captureNamed, + complementClass, + disjunction, + END, + exists, + getGroups, + optional, + START, + WILDCARD, +} from "@coven/expression"; +import type { Stringable } from "@coven/types"; + +/** + * 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: ( + stringable: Stringable, +) => Partial>> = getGroups< + readonly ["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..c264620 --- /dev/null +++ b/@coven/math/getNumberParts.ts @@ -0,0 +1,50 @@ +import { + buildUnicode, + captureNamed, + DIGIT, + END, + escape, + exists, + getGroups, + group, + optional, + START, +} from "@coven/expression"; +import type { Stringable } from "@coven/types"; + +/** + * 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: ( + stringable: Stringable, +) => Partial>> = + getGroups( + 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/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 7c4f863..18efffa 100644 --- a/@coven/math/mod.ts +++ b/@coven/math/mod.ts @@ -1,17 +1,24 @@ 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 { 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 { pipe } from "./pipe.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"; 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 c371b7c..c76f02c 100644 --- a/@coven/math/multiply.ts +++ b/@coven/math/multiply.ts @@ -1,8 +1,9 @@ -import { pipe } from "./pipe.ts"; +import { fallbackMultiply } from "./fallbackMultiply.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseMultiply } from "./preciseMultiply.ts"; /** - * Curried multiply operation using {@linkcode pipe} with {@linkcode preciseMultiply}. + * Curried multiply operation using {@linkcode preciseMultiply}. * * @example * ```typescript @@ -11,10 +12,10 @@ import { preciseMultiply } from "./preciseMultiply.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: ( - multiplier: number, -) => (multiplicand: number) => number = pipe(preciseMultiply); +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 879500c..0b3df8e 100644 --- a/@coven/math/numberToPrecise.ts +++ b/@coven/math/numberToPrecise.ts @@ -1,34 +1,41 @@ import { memoFunction } from "@coven/memo"; +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}. * * @example * ```typescript - * numberToPrecise(13); // [13n] + * numberToPrecise(13); // [13n, 0n] * numberToPrecise(1.3); // [13n, -1n] * numberToPrecise(1300); // [13n, 2n] + * 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: (number: number) => Precise = memoFunction( - (number: number) => { +export const numberToPrecise: Unary<[number: number], Precise | number> = + memoFunction((number: number) => { if (Number.isFinite(number) && !Number.isInteger(number)) { - const [base = "0", exponent = "0"] = `${number}`.split("e"); - const [integral = "0", fractional = ""] = `${base}`.split("."); + 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 Number.isFinite(number) && !Number.isNaN(number) ? + precise(BigInt(number), 0n) + : number; } - }, -); + }); 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..48c7844 100644 --- a/@coven/math/precise.ts +++ b/@coven/math/precise.ts @@ -1,31 +1,17 @@ -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"; +import { getBaseAndZeroes } from "./getBaseAndZeroes.ts"; -const rightSideZeroes = buildUnicode( - START, - captureNamed("normalizedBase")(allow(WILDCARD), complementClass(0)), - captureNamed("zeroes")(allow(0)), - END, -); +/** + * 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}. * * @example * ```typescript - * precise(13n); // [13n] + * precise(13n, 0n); // [13n] * precise(13n, -1n); // [13n, -1n] * precise(1300n, 0n); // [13n, 2n] * ``` @@ -35,27 +21,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..fb2d438 100644 --- a/@coven/math/preciseDivide.ts +++ b/@coven/math/preciseDivide.ts @@ -1,40 +1,46 @@ import { memoFunction } from "@coven/memo"; import { always } from "@coven/utils"; -import type { MaybeInfinity } from "./MaybeInfinity.ts"; -import type { Precise } from "./PreciseTuple.ts"; -import { numberToPrecise } from "./numberToPrecise.ts"; +import type { Precise } from "./precise.ts"; import { precise } from "./precise.ts"; -import { preciseMultiply } from "./preciseMultiply.ts"; -import { preciseToNumber } from "./preciseToNumber.ts"; +import type { PreciseFunction } from "./PreciseFunction.ts"; + +const alwaysInfinity = always(Infinity); /** * Curried divide operation using the internal {@linkcode Precise} type. * * @example * ```typescript - * const half = preciseDivide(2n); + * const half = preciseDivide(2n, 0n); * - * half(1n); // [5n, -1n] + * half(1n, 0n); // [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 ? alwaysInfinity : ( + 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..3fbc3ee 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, 0n); // [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..ce84cae --- /dev/null +++ b/@coven/math/preciseToBigInt.ts @@ -0,0 +1,21 @@ +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, 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..e263176 100644 --- a/@coven/math/subtract.ts +++ b/@coven/math/subtract.ts @@ -1,4 +1,5 @@ -import { pipe } from "./pipe.ts"; +import { fallbackSubtract } from "./fallbackSubtract.ts"; +import { numberFunction, type NumberFunction } from "./numberFunction.ts"; import { preciseSubtract } from "./preciseSubtract.ts"; /** @@ -11,9 +12,10 @@ import { preciseSubtract } from "./preciseSubtract.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: (subtrahend: number) => (minuend: number) => number = - pipe(preciseSubtract); +export const subtract: NumberFunction = numberFunction( + preciseSubtract, + fallbackSubtract, +); diff --git a/@coven/math/tests/add.test.ts b/@coven/math/tests/add.test.ts index 5a0d2f8..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)); @@ -53,3 +55,29 @@ 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 + 2 = Infinity", () => + assertStrictEquals(addPositive(Infinity), 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 + Infinity = NaN", () => + assertStrictEquals(addInfinity(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 25d4110..7578c02 100644 --- a/@coven/math/tests/calculate.test.ts +++ b/@coven/math/tests/calculate.test.ts @@ -1,34 +1,72 @@ 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, ), ); + +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 d8fdb2b..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)); @@ -63,3 +65,27 @@ 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 / 2 = Infinity", () => + assertStrictEquals(dividePositive(Infinity), Infinity), +); + +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 / NaN = NaN", () => assertStrictEquals(divideNaN(NaN), NaN)); + +Deno.test("2 / NaN = NaN", () => assertStrictEquals(divideNaN(2), 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 76a62fe..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)); @@ -73,3 +75,31 @@ Deno.test("Infinity * Infinity = Infinity", () => Deno.test("13 * Infinity = Infinity", () => assertStrictEquals(multiply(Infinity)(13), Infinity), ); + +Deno.test("Infinity * 2 = Infinity", () => + assertStrictEquals(multiplyPositive(Infinity), Infinity), +); + +Deno.test("NaN * 2 = NaN", () => + assertStrictEquals(multiplyPositive(NaN), NaN), +); + +Deno.test("Infinity * Infinity = Infinity", () => + assertStrictEquals(multiplyInfinity(Infinity), Infinity), +); + +Deno.test("2 * Infinity = Infinity", () => + assertStrictEquals(multiplyInfinity(2), Infinity), +); + +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 573b200..8ec4f78 100644 --- a/@coven/math/tests/numberToPrecise.test.ts +++ b/@coven/math/tests/numberToPrecise.test.ts @@ -1,38 +1,53 @@ -import { assertEquals } from "@std/assert"; +import { assertStrictEquals } 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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(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)", () => + assertStrictEquals(numberToPrecise(-1300.1), precise(-13_001n, -1n)), ); + +Deno.test("10000000000000000 = precise(1n, 16n)", () => + assertStrictEquals(numberToPrecise(1e16), precise(1n, 16n)), +); + +Deno.test("-10000000000000000 = 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/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..55a35fc 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)), + assertStrictEquals(preciseDivide(0n, 0n)(1n, 0n), Infinity), ); 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..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)); @@ -65,3 +67,33 @@ 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 - 2 = Infinity", () => + assertStrictEquals(subtractPositive(Infinity), Infinity), +); + +Deno.test("NaN - 2 = NaN", () => + assertStrictEquals(subtractPositive(NaN), 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("2 - NaN = NaN", () => assertStrictEquals(subtractNaN(2), NaN)); + +Deno.test("Infinity - NaN = NaN", () => + assertStrictEquals(subtractNaN(Infinity), NaN), +); 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/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; }; diff --git a/@coven/pair/deno.json b/@coven/pair/deno.json index 67b7fc0..458ffd9 100644 --- a/@coven/pair/deno.json +++ b/@coven/pair/deno.json @@ -7,11 +7,11 @@ "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.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/ExpectedStringables.ts b/@coven/types/ExpectedStringables.ts new file mode 100644 index 0000000..81e771c --- /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 ( + readonly [ + infer Head extends Stringable, + ...infer Tail extends ReadonlyArray, + ] + ) ? + `${string}${Head}${ExpectedStringables}` + : `${string}`; 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/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"; 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/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/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/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..f72c499 --- /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 type { 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/deno.json b/@simulcast/preact/deno.json index de1a15e..5a5b500 100644 --- a/@simulcast/preact/deno.json +++ b/@simulcast/preact/deno.json @@ -8,8 +8,8 @@ "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.3" + "version": "0.9.4" } diff --git a/@simulcast/preact/getEventName.ts b/@simulcast/preact/getEventName.ts new file mode 100644 index 0000000..259ccba --- /dev/null +++ b/@simulcast/preact/getEventName.ts @@ -0,0 +1,32 @@ +import { + allow, + buildUnicode, + captureNamed, + characterClass, + END, + getGroups, + range, + START, + WORD, +} from "@coven/expression"; +import type { Stringable } from "@coven/types"; + +/** + * Get event name out of string (or undefined otherwise). + * + * @example + * ```typescript + * getEventName("onExample"); // { name: "Example" } + * getEventName("offExample"); // { name: undefined } + * ``` + */ +export const getEventName: ( + stringable: Stringable, +) => Partial>> = 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/react/deno.json b/@simulcast/react/deno.json index 6761497..20f51e4 100644 --- a/@simulcast/react/deno.json +++ b/@simulcast/react/deno.json @@ -9,8 +9,8 @@ "@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.3" + "version": "0.9.4" } diff --git a/@simulcast/vue/deno.json b/@simulcast/vue/deno.json index c873080..5b5215b 100644 --- a/@simulcast/vue/deno.json +++ b/@simulcast/vue/deno.json @@ -3,8 +3,8 @@ "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.3" + "version": "0.9.4" } 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); 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"],