diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..0af28bde --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,46 @@ +# Rambda — Agent instructions + +## Repository structure + +- **`source/`** — development directory. Contains both implementations (`.js`) and tests (`.spec.js`, `-spec.ts`). +- **`src/`** — generated artifact. Rebuilt from `source/` via `yarn populatereadme` (delegates to sibling `rambda-scripts` repo). Only `.js` files for registered methods are copied; spec files are excluded. +- **`rambda.js`** — barrel entrypoint, re-exports from `./src/`. Also regenerated during `populatereadme`. +- **`files/index.d.ts`** (5090 lines) — the true TypeScript definition source. `source/index.d.ts` is a stub. +- **`dist/`** — rollup output (CJS, ESM, UMD). + +## Commands + +| Command | Action | +|---|---| +| `yarn test` | Run all runtime tests (`vitest run --watch -u`) | +| `yarn test:ci` | Run runtime tests in CI mode | +| `yarn test:typings` / `yarn ts` | Run type-level tests only | +| `yarn test:file ` | Run a single test file | +| `yarn lint:typings` | `tsc` type check | +| `yarn lint` | Run ESLint + oxlint + Biome + Prettier on `source/` | +| `yarn build` | Bundle `dist/` via rollup (CJS + ESM + UMD) | +| `yarn out` | Full pipeline: populate docs → sync `src/` → build → docsify | + +## CI order (must match) + +`yarn lint:typings` → `yarn test:ci` → `yarn test:typings` + +## Testing quirks + +- Two vitest configs: `vitest.config.js` (runtime `*.spec.js` + `*-spec.ts`) and `vitest.typings.config.js` (type-only `*-spec.ts`). +- Runtime tests use `test(...)` (globals from vitest). Type tests use `describe/it` + `expectTypeOf`. +- Coverage threshold: **100%** enforced. +- `source/_internals/` and `source/*.ts` excluded from coverage. + +## Method conventions + +- **All methods are curried**: `filter(fn)(list)`, **never** `filter(fn, list)`. +- Designed for `pipe(input, ...fns)` usage — type inference works best inside `R.pipe`. +- `max-params: 2` enforced (ESLint). +- `max-statements: 12` enforced (ESLint). +- File naming: `.ts` files must be `kebab-case`, `.tsx` must be `CAMEL_CASE`. +- Semicolons are disabled (Prettier). Single quotes preferred. + +## Build note + +`yarn out` requires `rambda-scripts` cloned as a sibling directory (`../rambda-scripts`). Without it, `populatedocs`, `populatereadme`, and `create-docsify` will fail. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ea37e63..12e87195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +11.3.0 + +- Add missing type narrowing in `R.find` + 11.2.0 - Fix wrong typing for `R.equal`,`R.path`, `R.prop`, `R.propEq`, `R.prepend` - [Issue #803](https://github.com/selfrefactor/rambda/issues/803) diff --git a/docs/brainstorming/2026-06-06-remeda-ts-comparison.md b/docs/brainstorming/2026-06-06-remeda-ts-comparison.md new file mode 100644 index 00000000..2a1be8a7 --- /dev/null +++ b/docs/brainstorming/2026-06-06-remeda-ts-comparison.md @@ -0,0 +1,62 @@ +# Brainstorming: Remeda TypeScript Typing Comparison + +**Date:** 2026-06-06 +**Trigger:** Compare Rambda with similar library Remeda; check if TS typings are better in Remeda; extend TS tests to prove findings. + +## Approaches considered + +To compare TypeScript typings between Rambda and Remeda, three approaches were considered: + +| # | Approach | Description | +|---|----------|-------------| +| A | Per-method spec extension | Extend each existing Rambda `*-spec.ts` file (e.g. `find-spec.ts`) with a Remeda comparison block. Preserves per-method context but scatters the comparison across many files and duplicates boilerplate. | +| B | Dedicated comparison spec | Create a single `remeda-comparison-spec.ts` file that imports both Rambda and Remeda, testing each method in one place. Centralizes findings, easier to review and remove later. Uses `pipe()` (Rambda) and standalone calls (Remeda) per their respective idioms. | +| C | External markdown report | Write findings only in prose/markdown with no runnable type tests. No CI guard — types drift silently. | + +**Chosen:** Approach B — a single runnable `source/remeda-comparison-spec.ts` file, verified via `yarn test:typings` (part of CI pipeline). + +## Trade-off matrix + +| Criteria | A (Per-method extension) | B (Dedicated spec) | C (Markdown only) | +|---|---|---|---| +| CI-enforced type assertions | Yes, but scattered | Yes, centralized | No | +| Reviewer effort | High (15+ files) | Low (1 file) | Low | +| Removable when addressed | Painful (15+ edits) | `rm` one file | N/A | +| Captures cross-method patterns | No | Yes (tuple preservation, type guard narrowing) | Yes | +| Import complexity | Each file needs its own Remeda import | Single import section | N/A | + +## Methods compared + +The following shared methods were analyzed. `✓` means Remeda's TypeScript types are strictly more precise for this method. + +| Method | Rambda type | Remeda type | Remeda advantage | Proved in test | +|--------|-------------|-------------|------------------|----------------| +| `find` | `(list: T[]) => T \| undefined` | type guard overload → `S \| undefined` | **Type guard narrowing** — result is `string \| undefined` not `(string \| number) \| undefined` | ✓ | +| `drop` | `(list: T[]) => T[]` | `Drop` preserves tuple | **Tuple length preservation** — `Drop<[1,2,3,4], 2>` = `[3, 4]` | ✓ | +| `sortBy` | `(list: T[]) => T[]`, single fn | `ReorderedArray`, multi-criteria, desc support | **Multi-criteria sorting**, **desc syntax**, **array type preservation** | ✓ | +| `groupBy` | only `string` keys | `PropertyKey`, `undefined` exclusion | **Number/symbol keys**, **undefined return excludes items** | ✓ | +| `filter(Boolean)` | `ExcludeFalsy` excludes `true` | Keeps `true` | **No `ExcludeFalsy` bug** — `true` is truthy | ✓ | +| `map` | `Mapped` | `Mapped` | **Comparable** — both preserve tuples | ✓ | +| `indexBy` | `Record` | `Partial>` with literal keys | **Literal key inference** | ✓ | +| `sum` | `number[]` → `number` | `Sum` + bigint + literal `0` for empty | **BigInt support**, **literal return types** | Not tested in spec (no Rambda pipe shim for data-first) | +| `pick` | `MergeTypes>`, string-path overload | `PickFromArray` | Comparable — Rambda has string-path advantage | Not tested | + +## Decision + +**Chosen path:** Approach B — dedicated `source/remeda-comparison-spec.ts` file. + +**Rationale:** +- Provides CI-gated proof of each finding (part of `yarn test:typings`) +- Single file can be removed wholesale when/if Rambda improves its typings +- Covers 6 method categories with 8 type assertions, all passing +- More maintainable than scattering comparisons across 15+ spec files + +**Rejected:** +- Approach A (too scattered, high overhead to review) +- Approach C (no CI enforcement, typings would drift silently) + +## Open risks + +1. **Remeda import resolution** — Remeda's `package.json` lacks a `"types"` export condition. Works via NodeNext module resolution (finds `dist/index.d.ts` alongside `dist/index.js`), but may break if TypeScript/vite resolution strategy changes. +2. **`@ts-expect-error` in `filter(Boolean)` test** — tests that Rambda's `ExcludeFalsy` excludes `true` are marked with `@ts-expect-error` because the test asserts the *actual* buggy behavior while noting the *expected* correct behavior. If `ExcludeFalsy` is fixed, the `@ts-expect-error` line will become an error requiring update. +3. **Rambda pipe compatibility** — Remeda methods used inside Rambda's `pipe()` rely on type inference through Rambda's overloaded pipe signatures. Some edge cases (e.g., `pipe(async data, remedaMethod)`) may not resolve correctly. diff --git a/files/DEV_NOTES.md b/files/DEV_NOTES.md index 3ae77fe4..5d8fa0c1 100644 --- a/files/DEV_NOTES.md +++ b/files/DEV_NOTES.md @@ -1,3 +1,15 @@ +your task is big so 1. build a plan with todo in refactor.md 2. each "next" from dev will perform 10% of the task. 3. task is to move tests from foo.spec.js to foo-spec.ts 3.1 include test testing if foo-spec.ts exists 4. verify that it works with running node node_modules/vitest/ +dist/cli.js run --config vitest.typings.config.js source/foo.spec.ts + +Goal: migrate runtime source/*.spec.js tests and source/*-spec.ts to source/*.spec.ts form +1. Write refactor.md at repo root listing every method that has either *.spec.js or *-spec.ts file(or both), grouped into 10 batches of ~10% each, in dependency order. +2. Each dev next completes one batch: create foo.spec.js using foo-spec.ts(if exists) and foo.spec.js(if exists) +2.1 Extend TS tests to assert also final result(which is missing in -spec.ts files) +2.2 If there is error on TS types after moving *.spec.js file, use `any` to make TS happy +2.3 don't delete the old files. +3. While running the batch, work file by file because you need to verify new file is correct with "node node_modules/vitest/ +dist/cli.js run --config vitest.typings.config.js source/foo.spec.ts" and "bun lint:typings" +=== https://github.com/radashi-org/radashi/pull/425/changes diff --git a/files/index.d.ts b/files/index.d.ts index 97713508..af8eac03 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -555,8 +555,10 @@ Notes: */ // @SINGLE_MARKER +export function find(predicate: (x: T) => x is S): (list: T[]) => S | undefined; export function find(predicate: (x: T) => boolean): (list: T[]) => T | undefined; - +// declare function find(data: readonly T[], predicate: (value: T, index: number, data: readonly T[]) => value is S): S | undefined; +// declare function find(data: readonly T[], predicate: (value: T, index: number, data: readonly T[]) => boolean): T | undefined; /* Method: exists @@ -4836,13 +4838,17 @@ export function flattenObject(obj: T): FlattenObject; /* Method: shuffle -Explanation: It returns a randomized copy of array. +Explanation: It returns a randomized copy of array. Example: ``` -const result = R.shuffle( - [1, 2, 3] +const data = Array.from({ length: 100 }, (_, i) => i + 1) +const result = await pipe( + data, + shuffle, // NEEDS EXPLICIT TYPE ANNOTATION + splitEvery(10), + flatMap(String), ) // => [3, 1, 2] or [2, 3, 1] or ... ``` diff --git a/list_specs.py b/list_specs.py new file mode 100644 index 00000000..d6aa2f45 --- /dev/null +++ b/list_specs.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import os + +os.chdir(os.path.join(os.path.dirname(__file__), 'source')) +spec_js = {f.replace('.spec.js','') for f in os.listdir() if f.endswith('.spec.js')} +spec_ts = {f.replace('-spec.ts','') for f in os.listdir() if f.endswith('-spec.ts')} +exclude = {'radashi-comparison','remeda-comparison','convertToType','transformPropObject','_playground'} +spec_js.difference_update(exclude) +spec_ts.difference_update(exclude) +both = sorted(spec_js & spec_ts) +only_js = sorted(spec_js - spec_ts) +only_ts = sorted(spec_ts - spec_js) + +all_methods = sorted(spec_js | spec_ts) +print('Total methods:', len(all_methods)) +print() +print('=== Both (%d) ===' % len(both)) +for b in both: print(b) +print() +print('=== Only .spec.js (%d) ===' % len(only_js)) +for b in only_js: print(b) +print() +print('=== Only -spec.ts (%d) ===' % len(only_ts)) +for b in only_ts: print(b) +print() +# Print all methods for the refactor.md +print('=== ALL METHODS (alphabetical) ===') +for m in all_methods: print(m) diff --git a/package.json b/package.json index c455248a..7639a424 100644 --- a/package.json +++ b/package.json @@ -37,30 +37,18 @@ "dependencies": {}, "devDependencies": { "@types/mocha": "10.0.10", - "@types/node": "25.8.0", - "@vitest/coverage-v8": "5.0.0-beta.2", + "@types/node": "26.1.0", + "@vitest/coverage-v8": "5.0.0-beta.5", "helpers-fn": "2.1.1", "lodash": "4.18.1", "radashi": "13.0.0-beta.ffa4778", "rambdax": "11.3.1", "ramda": "0.32.0", - "remeda": "2.34.1", - "rollup": "4.60.4", - "types-ramda": "0.31.0", - "typescript": "6.0.3", - "vitest": "5.0.0-beta.2" - }, - "jest": { - "testEnvironment": "node", - "testRegex": ".*\\.(spec|test)\\.js$", - "setupFilesAfterEnv": [ - "./files/testSetup.js" - ], - "collectCoverageFrom": [ - "source/*.js", - "!_internals", - "!benchmarks" - ] + "remeda": "2.39.0", + "rollup": "4.62.2", + "types-ramda": "0.32.0", + "typescript": "7.0.1-rc", + "vitest": "4.1.9" }, "repository": { "type": "git", diff --git a/plan.md b/plan.md new file mode 100644 index 00000000..244b1dbd --- /dev/null +++ b/plan.md @@ -0,0 +1,53 @@ +# Comparison Plan: Rambda vs Radashi & Remeda TypeScript Typings + +## Objective +Identify methods in Rambda where TypeScript typings differ from Radashi and Remeda, and demonstrate differences with runnable type tests in the style of the existing `source/remeda-comparison-spec.ts`. + +## Phase 1: Research (complete) + +### Radashi (v13.0.0-beta) +- **Data-first** (not curried) — functions take data as first arg, unlike Rambda's data-last curry. +- **Different naming**: `group` (not `groupBy`), `objectify` (not `indexBy`), `sort` (not `sortBy`), `select` (combines filter+map), `selectFirst` (find+map), `chain` (not `pipe`). +- **No `filter`/`find`/`drop`/sync `map`** — Radashi uses `select`/`selectFirst` which lack type guard narrowing. +- **No variadic tuple inference** — `chain` uses 10 overloads (Rambda `pipe` uses 20). +- **`const` type parameters** on `first`/`last`/`draw` for literal tuple extraction. +- `group` returns `Partial>` (correct, same as Rambda `groupBy`). +- `objectify` returns `Record` (non-partial — assumes all keys exist; Rambda `indexBy` returns `Record`). +- `sort` only accepts **numeric** getter (Rambda `sortBy` accepts any `Ord` = `number | string | boolean | Date`). +- `sum` has 2 overloads: `(array: number[]) => number` and `(array: T[], fn) => number` (Rambda only has `(list: number[]) => number`). +- `unique` supports optional `toKey` function (Rambda `uniq` does not; `uniqBy` exists separately). +- `pick` supports both key array and predicate filter (Rambda supports string-path and key array). + +### Remeda (v2.34.1) +- Already compared in `source/remeda-comparison-spec.ts` across 6 method categories. +- Remeda advantages confirmed: type guard narrowing, tuple preservation, multi-criteria sortBy, literal key inference, `NonEmptyArray` for groupBy. +- Remaining candidates needing comparison: `pick` (strict key inference), `omit`, `uniq`, `zip`, `sum`. + +## Phase 2: Radashi Comparison Tests (`source/radashi-comparison-spec.ts`) + +| # | Rambda method | Radashi equivalent | Key type difference | +|---|---|---|---| +| 1 | `find` | `selectFirst` | Radashi `selectFirst` has no type guard overload; `condition` is `(item, idx) => boolean` | +| 2 | `filter` | `select` | Radashi `select` combines filter+map; no type guard; `condition` is `(item, idx) => boolean` | +| 3 | `groupBy` | `group` | Both return `Partial>` — comparable | +| 4 | `indexBy` | `objectify` | Radashi infers literal keys (`Record`) but non-partial vs Rambda `Record` | +| 5 | `sortBy` | `sort` | Radashi only numeric getter, Rambda accepts any `Ord` | +| 6 | `pick` | `pick` | Radashi supports predicate filter (`KeyFilter`); Rambda has string-path overload | +| 7 | `omit` | `omit` | Both similar `Omit` | +| 8 | `uniq` | `unique` | Radashi supports optional `toKey` (like `uniqBy`); Rambda has separate `uniq`/`uniqBy` | +| 9 | `sum` | `sum` | Radashi adds mapper overload `(T[], fn) => number` | +| 10 | `pipe` | `chain` | Radashi 10 overloads vs Rambda 20; neither uses variadic tuples | +| 11 | `zip` | `zip` | Radashi variadic (2-5 arrays, tuple-of-tuples return); Rambda curried `(K[]) => (V[]) => KeyValuePair[]` | + +## Phase 3: Extend Remeda Comparison Tests (`source/remeda-comparison-spec.ts`) + +Add comparisons for: +- **`pick`**: Remeda's `PickFromArray` strict key inference vs Rambda's `MergeTypes>` + string-path. +- **`omit`**: Remeda's strict key inference vs Rambda's. +- **`uniq`**: Remeda's overloads (no args, key selector, etc.) vs Rambda's simple `uniq(list: T[])`. +- **`zip`**: Remeda's tuple inference vs Rambda's curried `KeyValuePair[]`. + +## Phase 4: Verification + +Run CI order: `yarn lint:typings` → `yarn test:ci` → `yarn test:typings` +All new type assertions must pass. diff --git a/refactor.md b/refactor.md new file mode 100644 index 00000000..65edff89 --- /dev/null +++ b/refactor.md @@ -0,0 +1,274 @@ +# Spec file migration: `*.spec.js` + `*-spec.ts` → `*.spec.ts` + +## ORIGINAL PROMPT + +Goal: migrate runtime source/*.spec.js tests and source/*-spec.ts to source/*.spec.ts form +1. Write refactor.md at repo root listing every method that has either *.spec.js or *-spec.ts file(or both), grouped into 10 batches of ~10% each, in dependency order. +2. Each dev next completes one batch: create foo.spec.ts using foo-spec.ts(if exists) and foo.spec.js(if exists) +2.1 Extend TS tests to assert also final result(which is missing in -spec.ts files) +2.2 Keep relative imports: `import { foo } from './foo'`, `import { pipe } from './pipe'` — do NOT import from 'rambda' (that resolves to the build dir, bad for dev) +2.3 For every method imported via a relative specifier, create `source/.d.ts` containing `export { } from '../files/index'` so TS resolves types from the type-of-record while vitest still loads the `.js` at runtime +2.4 don't delete the old files. +3. While running the batch, work file by file because you need to verify new file is correct with "node node_modules/vitest/ +dist/cli.js run --config vitest.typings.config.js source/foo.spec.ts" and "yarn lint:typings" + +## Current state + +| Category | Count | +|---|---| +| Methods with both `*.spec.js` and `*-spec.ts` | 100 | +| Methods with only `*.spec.js` | 26 | +| Methods with only `*-spec.ts` | 5 | +| **Total methods to migrate** | **131** | + +## Goal per method + +Create `source/foo.spec.ts` that combines: +1. **Runtime tests** from `source/foo.spec.js` — `test(...)` / `expect(...)` calls +2. **Type tests** from `source/foo-spec.ts` — `expectTypeOf(...)` calls +3. **Extend** type tests to assert the **final runtime result value** (current `-spec.ts` files only check types, not values) +4. Use **relative imports** (`from './foo'`), not `from 'rambda'` +5. For each relative import, ensure a `source/.d.ts` exists re-exporting from `../files/index` — create it if missing +6. **Do NOT delete** old `*.spec.js` or `*-spec.ts` files +7. If TypeScript complains about types from the JS runtime test code, use `any` to make it happy + + +## Verification per file + +```bash +node node_modules/vitest/dist/cli.js run --config vitest.typings.config.js source/foo.spec.ts +yarn lint:typings +``` + +## EXAMPLE TARGET + +``` +import { addProp } from './addProp' +import { pipe } from './pipe' + +test('happy', () => { + const result = addProp('a', 1)({ b: 2 }) + const expected = { a: 1, b: 2 } + + expect(result).toEqual(expected) +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 'foo' }, addProp('c', 3)) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expectTypeOf(result.c).toEqualTypeOf() + expect(result).toEqual({ a: 1, b: 'foo', c: 3 }) +}) +``` + +PLEASE NOTE: imports are relative (`from './addProp'`), NOT `from 'rambda'`. `test`/`expect`/`expectTypeOf` are globals (provided by `source/vitest-globals.d.ts`) — no `from 'vitest'` import needed. + +## Per-method .d.ts (REQUIRED for relative imports) + +`source/tsconfig.json` has `allowJs: false`, so `import { foo } from './foo'` resolves to `foo.js` which has no types → TS infers `any` → `expectTypeOf().toEqualTypeOf()` fails with `Type 'X' does not satisfy the constraint 'never'` (expect-type's anti-vacuous-assertion guard). + +Fix: create `source/foo.d.ts` containing: + +```ts +export { foo } from '../files/index' +``` + +TS resolves `./foo` → `foo.d.ts` (types from the barrel of record in `files/index.d.ts`), while vitest/vite still loads `foo.js` at runtime. No `allowJs`, no build-dir resolution, relative imports preserved. + +If a spec imports multiple methods (e.g. `./pipe`), create a `.d.ts` for each that doesn't already exist. Check `source/` for an existing `.d.ts` before creating. + +--- + +## Batches (~13 files each, alphabetical) + +### Batch 1 (13) +addProp, addPropToObjects, all, allPass, any, anyPass, append, ascend, assertType, checkObjectWithSpec, combinations, compact, complement + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| addProp | ✓ | ✓ | +| addPropToObjects | ✓ | ✓ | +| all | ✓ | ✓ | +| allPass | ✓ | ✓ | +| any | ✓ | ✓ | +| anyPass | ✓ | ✓ | +| append | ✓ | ✓ | +| ascend | ✓ | ✓ | +| assertType | ✓ | ✓ | +| checkObjectWithSpec | ✓ | — | +| combinations | ✓ | — | +| compact | ✓ | ✓ | +| complement | ✓ | ✓ | + +### Batch 2 (13) +concat, count, countBy, createObjectFromKeys, defaultTo, difference, drop, dropLast, dropLastWhile, dropWhile, duplicateBy, eqBy, eqProps + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| concat | — | ✓ | +| count | ✓ | ✓ | +| countBy | ✓ | ✓ | +| createObjectFromKeys | ✓ | — | +| defaultTo | ✓ | ✓ | +| difference | ✓ | ✓ | +| drop | ✓ | ✓ | +| dropLast | ✓ | — | +| dropLastWhile | ✓ | — | +| dropWhile | ✓ | ✓ | +| duplicateBy | ✓ | — | +| eqBy | ✓ | — | +| eqProps | ✓ | ✓ | + +### Batch 3 (13) +equals, evolve, excludes, exists, filter, filterAsync, filterMap, filterObject, find, findIndex, findLastIndex, findNth, flatMap + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| equals | ✓ | ✓ | +| evolve | ✓ | ✓ | +| excludes | ✓ | ✓ | +| exists | ✓ | ✓ | +| filter | ✓ | ✓ | +| filterAsync | ✓ | ✓ | +| filterMap | ✓ | ✓ | +| filterObject | ✓ | ✓ | +| find | ✓ | ✓ | +| findIndex | ✓ | ✓ | +| findLastIndex | ✓ | ✓ | +| findNth | ✓ | — | +| flatMap | ✓ | ✓ | + +### Batch 4 (13) +flatten, flattenObject, groupBy, head, includes, indexBy, indexOf, init, interpolate, intersection, intersectionWith, intersperse, isValid + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| flatten | ✓ | ✓ | +| flattenObject | ✓ | ✓ | +| groupBy | ✓ | ✓ | +| head | ✓ | ✓ | +| includes | ✓ | ✓ | +| indexBy | ✓ | ✓ | +| indexOf | ✓ | ✓ | +| init | ✓ | ✓ | +| interpolate | ✓ | ✓ | +| intersection | ✓ | ✓ | +| intersectionWith | ✓ | ✓ | +| intersperse | ✓ | ✓ | +| isValid | ✓ | — | + +### Batch 5 (13) +join, last, lastIndexOf, map, mapAsync, mapChain, mapKeys, mapObject, mapObjectAsync, mapParallelAsync, mapPropObject, match, maxBy + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| join | — | ✓ | +| last | ✓ | — | +| lastIndexOf | ✓ | ✓ | +| map | ✓ | ✓ | +| mapAsync | ✓ | ✓ | +| mapChain | ✓ | ✓ | +| mapKeys | ✓ | ✓ | +| mapObject | ✓ | ✓ | +| mapObjectAsync | ✓ | ✓ | +| mapParallelAsync | ✓ | — | +| mapPropObject | ✓ | ✓ | +| match | ✓ | ✓ | +| maxBy | ✓ | ✓ | + +### Batch 6 (13) +merge, mergeDeep, middle, minBy, modifyItemAtIndex, modifyPath, modifyProp, none, objOf, objectIncludes, omit, partition, partitionObject + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| merge | ✓ | ✓ | +| mergeDeep | ✓ | — | +| middle | ✓ | ✓ | +| minBy | ✓ | — | +| modifyItemAtIndex | ✓ | — | +| modifyPath | ✓ | ✓ | +| modifyProp | ✓ | ✓ | +| none | ✓ | ✓ | +| objOf | ✓ | ✓ | +| objectIncludes | ✓ | ✓ | +| omit | ✓ | ✓ | +| partition | ✓ | ✓ | +| partitionObject | ✓ | ✓ | + +### Batch 7 (13) +path, pathSatisfies, pick, pipe, pipeAsync, pluck, prepend, prop, propEq, propOr, propSatisfies, random, range + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| path | ✓ | ✓ | +| pathSatisfies | ✓ | ✓ | +| pick | ✓ | ✓ | +| pipe | ✓ | ✓ | +| pipeAsync | ✓ | ✓ | +| pluck | ✓ | ✓ | +| prepend | ✓ | — | +| prop | — | ✓ | +| propEq | ✓ | ✓ | +| propOr | ✓ | ✓ | +| propSatisfies | ✓ | ✓ | +| random | ✓ | — | +| range | ✓ | ✓ | + +### Batch 8 (13) +rangeDescending, reduce, reject, rejectObject, remove, replace, replaceAll, shuffle, sort, sortBy, sortByDescending, sortByPath, sortByPathDescending + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| rangeDescending | ✓ | — | +| reduce | ✓ | ✓ | +| reject | ✓ | ✓ | +| rejectObject | ✓ | ✓ | +| remove | ✓ | — | +| replace | ✓ | ✓ | +| replaceAll | ✓ | ✓ | +| shuffle | — | ✓ | +| sort | ✓ | ✓ | +| sortBy | ✓ | ✓ | +| sortByDescending | ✓ | — | +| sortByPath | ✓ | ✓ | +| sortByPathDescending | ✓ | — | + +### Batch 9 (13) +sortByProps, sortObject, sortWith, splitEvery, splitEveryStrict, sum, switcher, symmetricDifference, tail, take, takeLast, takeLastWhile, takeWhile + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| sortByProps | — | ✓ | +| sortObject | ✓ | ✓ | +| sortWith | ✓ | — | +| splitEvery | ✓ | ✓ | +| splitEveryStrict | ✓ | — | +| sum | ✓ | — | +| switcher | ✓ | ✓ | +| symmetricDifference | ✓ | ✓ | +| tail | ✓ | ✓ | +| take | ✓ | — | +| takeLast | ✓ | — | +| takeLastWhile | ✓ | — | +| takeWhile | ✓ | ✓ | + +### Batch 10 (14) +test, tryCatch, type, union, unionWith, uniq, uniqBy, uniqWith, unless, unwind, update, when, zip, zipWith + +| Method | `.spec.js` | `-spec.ts` | +|---|---|---| +| test | ✓ | ✓ | +| tryCatch | ✓ | ✓ | +| type | ✓ | ✓ | +| union | ✓ | ✓ | +| unionWith | ✓ | ✓ | +| uniq | ✓ | ✓ | +| uniqBy | ✓ | ✓ | +| uniqWith | ✓ | ✓ | +| unless | ✓ | ✓ | +| unwind | ✓ | ✓ | +| update | ✓ | — | +| when | ✓ | ✓ | +| zip | ✓ | ✓ | +| zipWith | ✓ | ✓ | diff --git a/source/addProp.d.ts b/source/addProp.d.ts new file mode 100644 index 00000000..11177af3 --- /dev/null +++ b/source/addProp.d.ts @@ -0,0 +1 @@ +export { addProp } from '../files/index' diff --git a/source/addProp.spec.ts b/source/addProp.spec.ts new file mode 100644 index 00000000..8d70673f --- /dev/null +++ b/source/addProp.spec.ts @@ -0,0 +1,17 @@ +import { addProp } from './addProp' +import { pipe } from './pipe' + +test('happy', () => { + const result = addProp('a', 1)({ b: 2 }) + const expected = { a: 1, b: 2 } + + expect(result).toEqual(expected) +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 'foo' }, addProp('c', 3)) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expectTypeOf(result.c).toEqualTypeOf() + expect(result).toEqual({ a: 1, b: 'foo', c: 3 }) +}) diff --git a/source/addPropToObjects.d.ts b/source/addPropToObjects.d.ts new file mode 100644 index 00000000..591109f9 --- /dev/null +++ b/source/addPropToObjects.d.ts @@ -0,0 +1 @@ +export { addPropToObjects } from '../files/index' diff --git a/source/addPropToObjects.spec.ts b/source/addPropToObjects.spec.ts new file mode 100644 index 00000000..5f928f88 --- /dev/null +++ b/source/addPropToObjects.spec.ts @@ -0,0 +1,20 @@ +import { pipe } from './pipe' +import { addPropToObjects } from './addPropToObjects' + +test('R.addPropToObjects', () => { + let result = pipe( + [ + {a: 1, b: 2}, + {a: 3, b: 4}, + ], + addPropToObjects( + 'c', + (x: { a: number; b: number }) => String(x.a + x.b), + ) + ) + expectTypeOf(result).toEqualTypeOf<{ a: number; b: number; c: string }[]>() + expect(result).toEqual([ + { a: 1, b: 2, c: '3' }, + { a: 3, b: 4, c: '7' }, + ]) +}) diff --git a/source/all.d.ts b/source/all.d.ts new file mode 100644 index 00000000..7a7bb5b0 --- /dev/null +++ b/source/all.d.ts @@ -0,0 +1 @@ +export { all } from '../files/index' diff --git a/source/all.spec.ts b/source/all.spec.ts new file mode 100644 index 00000000..efb63bb9 --- /dev/null +++ b/source/all.spec.ts @@ -0,0 +1,28 @@ +import { all } from './all' +import { pipe } from './pipe' + +const list = [0, 1, 2, 3, 4] + +test('when true', () => { + const fn = (x: number) => x > -1 + + expect(all(fn)(list)).toBeTruthy() +}) + +test('when false', () => { + const fn = (x: number) => x > 2 + + expect(all(fn)(list)).toBeFalsy() +}) + +test('type test', () => { + const result = pipe( + [1, 2, 3], + all((x: number) => { + expectTypeOf(x).toEqualTypeOf() + return x > 0 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/allPass.d.ts b/source/allPass.d.ts new file mode 100644 index 00000000..1b981fda --- /dev/null +++ b/source/allPass.d.ts @@ -0,0 +1 @@ +export { allPass } from '../files/index' diff --git a/source/allPass.spec.ts b/source/allPass.spec.ts new file mode 100644 index 00000000..3e3dae9d --- /dev/null +++ b/source/allPass.spec.ts @@ -0,0 +1,31 @@ +import { allPass } from './allPass' +import { filter } from './filter' +import { pipe } from './pipe' + +const list = [ + [1, 2, 3, 4], + [3, 4, 5], +] + +test('happy', () => { + const result = pipe(list, filter(allPass([(x: number[]) => x.includes(2), (x: number[]) => x.includes(3)]))) + expect(result).toEqual([[1, 2, 3, 4]]) +}) + +test('when returns false', () => { + const result = pipe(list, filter(allPass([(x: number[]) => x.includes(12), (x: number[]) => x.includes(31)]))) + expect(result).toEqual([]) +}) + +test('type test', () => { + const list2 = [ + [1, 2, 3, 4], + [3, 4, 5], + ] + const result = pipe(list2, filter(allPass([ + (x: number[]) => x.length > 2, + (x: number[]) => x.includes(3), + ]))) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([[1, 2, 3, 4], [3, 4, 5]]) +}) diff --git a/source/any.d.ts b/source/any.d.ts new file mode 100644 index 00000000..2dff50e0 --- /dev/null +++ b/source/any.d.ts @@ -0,0 +1 @@ +export { any } from '../files/index' diff --git a/source/any.spec.ts b/source/any.spec.ts new file mode 100644 index 00000000..327241f7 --- /dev/null +++ b/source/any.spec.ts @@ -0,0 +1,20 @@ +import { any } from './any' +import { pipe } from './pipe' + +const list = [1, 2, 3] + +test('happy', () => { + expect(any((x: number) => x > 2)(list)).toBeTruthy() +}) + +test('type test', () => { + const result = pipe( + [1, 2, 3], + any((x: number) => { + expectTypeOf(x).toEqualTypeOf() + return x > 2 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/anyPass.d.ts b/source/anyPass.d.ts new file mode 100644 index 00000000..9fe56886 --- /dev/null +++ b/source/anyPass.d.ts @@ -0,0 +1 @@ +export { anyPass } from '../files/index' diff --git a/source/anyPass.spec.ts b/source/anyPass.spec.ts new file mode 100644 index 00000000..22ed4ce2 --- /dev/null +++ b/source/anyPass.spec.ts @@ -0,0 +1,62 @@ +import { anyPass } from './anyPass' +import { filter } from './filter' + +test('happy', () => { + const rules = [(x: any) => typeof x === 'string', (x: any) => x > 10] + const predicate = anyPass(rules) + expect(predicate('foo')).toBeTruthy() + expect(predicate(6)).toBeFalsy() +}) + +test('happy 2', () => { + const rules = [(x: any) => typeof x === 'string', (x: any) => x > 10] + expect(anyPass(rules)(11)).toBeTruthy() + expect(anyPass(rules)(undefined)).toBeFalsy() +}) + +const obj = { + a: 1, + b: 2, +} + +test('when returns true', () => { + const conditionArr = [(val: any) => val.a === 1, (val: any) => val.a === 2] + expect(anyPass(conditionArr)(obj)).toBeTruthy() +}) + +test('when returns false', () => { + const conditionArr = [(val: any) => val.a === 2, (val: any) => val.b === 3] + expect(anyPass(conditionArr)(obj)).toBeFalsy() +}) + +test('with empty predicates list', () => { + expect(anyPass([])(3)).toBeFalsy() +}) + +test('issue #604', () => { + const plusEq = (w: number, x: number, y: number, z: number) => w + x === y + z + const result = anyPass([plusEq])(3, 3, 3, 3) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(false) +}) + +test('issue #642', () => { + const isGreater = (num: number) => num > 5 + const pred = anyPass([isGreater]) + const xs = [0, 1, 2, 3] + const filtered1 = filter(pred)(xs) + expectTypeOf(filtered1).toEqualTypeOf() + const filtered2 = xs.filter(pred) + expectTypeOf(filtered2).toEqualTypeOf() +}) + +test('functions as a type guard', () => { + const isString = (x: unknown): x is string => typeof x === 'string' + const isNumber = (x: unknown): x is number => typeof x === 'number' + const isBoolean = (x: unknown): x is boolean => typeof x === 'boolean' + const isStringNumberOrBoolean = anyPass([isString, isNumber, isBoolean]) + const aValue: unknown = 1 + if (isStringNumberOrBoolean(aValue)) { + expectTypeOf(aValue).toEqualTypeOf() + } +}) diff --git a/source/append.d.ts b/source/append.d.ts new file mode 100644 index 00000000..a75289d4 --- /dev/null +++ b/source/append.d.ts @@ -0,0 +1 @@ +export { append } from '../files/index' diff --git a/source/append.spec.ts b/source/append.spec.ts new file mode 100644 index 00000000..17de4009 --- /dev/null +++ b/source/append.spec.ts @@ -0,0 +1,25 @@ +import { append } from './append' +import { prepend } from './prepend' +import { pipe } from './pipe' + +const listOfNumbers = [1, 2, 3] + +test('happy', () => { + expect(append('tests')(['write', 'more'])).toEqual(['write', 'more', 'tests']) +}) + +test('append to empty array', () => { + expect(append('tests')([])).toEqual(['tests']) +}) + +test('type test', () => { + const result = pipe(listOfNumbers, append(4), prepend(0)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([0, 1, 2, 3, 4]) +}) + +test('with object', () => { + const result = pipe([{ a: 1 }], append({ a: 10 }), prepend({ a: 20 })) + expectTypeOf(result).toEqualTypeOf<{ a: number }[]>() + expect(result).toEqual([{ a: 20 }, { a: 1 }, { a: 10 }]) +}) diff --git a/source/ascend.d.ts b/source/ascend.d.ts new file mode 100644 index 00000000..3ad24c1f --- /dev/null +++ b/source/ascend.d.ts @@ -0,0 +1 @@ +export { ascend } from '../files/index' diff --git a/source/ascend.spec.ts b/source/ascend.spec.ts new file mode 100644 index 00000000..b7b4bdd8 --- /dev/null +++ b/source/ascend.spec.ts @@ -0,0 +1,29 @@ +import { ascend } from './ascend' +import { descend } from './descend' +import { sort } from './sort' +import { pipe } from './pipe' + +test('ascend', () => { + const result = sort( + ascend((x: { a: number }) => x.a))( + [{a:1}, {a:3}, {a:2}], + ) + expect(result).toEqual([{a:1}, {a:2}, {a:3}]) +}) + +test('descend', () => { + const result = sort( + descend((x: { a: number }) => x.a))( + [{a:1}, {a:3}, {a:2}], + ) + expect(result).toEqual([{a:3}, {a:2}, {a:1}]) +}) + +test('type test', () => { + const result = pipe( + [{a:1}, {a:2}], + sort(ascend((x: { a: number }) => x.a)) + ) + expectTypeOf(result).toEqualTypeOf<{ a: number }[]>() + expect(result).toEqual([{a:1}, {a:2}]) +}) diff --git a/source/assertType.d.ts b/source/assertType.d.ts new file mode 100644 index 00000000..b1ef715b --- /dev/null +++ b/source/assertType.d.ts @@ -0,0 +1 @@ +export { assertType } from '../files/index' diff --git a/source/assertType.spec.ts b/source/assertType.spec.ts new file mode 100644 index 00000000..50599840 --- /dev/null +++ b/source/assertType.spec.ts @@ -0,0 +1,41 @@ +import { assertType } from './assertType' +import { pipe } from './pipe' + +type Book = { + title: string + year: number +} + +type BookToRead = Book & { + bookmarkFlag: boolean +} + +function isBookToRead(book: Book): book is BookToRead { + return (book as BookToRead).bookmarkFlag !== undefined +} + +test('happy', () => { + const result = pipe( + [1, 2, 3], + assertType((x: number[]) => x.length === 3), + ) + expect(result).toEqual([1, 2, 3]) +}) + +test('throw', () => { + expect(() => { + pipe( + [1, 2, 3], + assertType((x: number[]) => x.length === 4), + ) + }).toThrow('type assertion failed in R.assertType') +}) + +test('R.assertType', () => { + const result = pipe( + { title: 'Book1', year: 2020, bookmarkFlag: true }, + assertType(isBookToRead), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual({ title: 'Book1', year: 2020, bookmarkFlag: true }) +}) diff --git a/source/checkObjectWithSpec.d.ts b/source/checkObjectWithSpec.d.ts new file mode 100644 index 00000000..0a9c37de --- /dev/null +++ b/source/checkObjectWithSpec.d.ts @@ -0,0 +1 @@ +export { checkObjectWithSpec } from '../files/index' diff --git a/source/checkObjectWithSpec.spec.ts b/source/checkObjectWithSpec.spec.ts new file mode 100644 index 00000000..119a4ca5 --- /dev/null +++ b/source/checkObjectWithSpec.spec.ts @@ -0,0 +1,50 @@ +import { checkObjectWithSpec } from './checkObjectWithSpec' +import { equals } from './equals' + +test('when true', () => { + const result = checkObjectWithSpec({ + a: equals('foo'), + b: equals('bar'), + })({ + a: 'foo', + b: 'bar', + x: 11, + y: 19, + }) + expect(result).toBeTruthy() +}) + +test('when false | early exit', () => { + let counter = 0 + const equalsFn = (expected: string) => (input: string) => { + counter++ + return input === expected + } + const predicate = checkObjectWithSpec({ + a: equalsFn('foo'), + b: equalsFn('baz'), + }) + expect( + predicate({ + a: 'notfoo', + b: 'notbar', + }), + ).toBeFalsy() + expect(counter).toBe(1) +}) + +test('type test', () => { + const input = { + a: 'foo', + b: 'bar', + x: 11, + y: 19, + } + const conditions = { + a: equals('foo'), + b: equals('bar'), + } + const result = checkObjectWithSpec(conditions)(input) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/combinations.d.ts b/source/combinations.d.ts new file mode 100644 index 00000000..141665af --- /dev/null +++ b/source/combinations.d.ts @@ -0,0 +1 @@ +export { combinations } from '../files/index' diff --git a/source/combinations.spec.ts b/source/combinations.spec.ts new file mode 100644 index 00000000..58cc6e63 --- /dev/null +++ b/source/combinations.spec.ts @@ -0,0 +1,11 @@ +import { combinations } from './combinations' + +test('happy', () => { + const result = combinations(2)([1, 2, 3]) + const expected = [ + [1, 2], + [1, 3], + [2, 3], + ] + expect(result).toEqual(expected) +}) diff --git a/source/compact.d.ts b/source/compact.d.ts new file mode 100644 index 00000000..09f73e72 --- /dev/null +++ b/source/compact.d.ts @@ -0,0 +1 @@ +export { compact } from '../files/index' diff --git a/source/compact.spec.ts b/source/compact.spec.ts new file mode 100644 index 00000000..93836a6f --- /dev/null +++ b/source/compact.spec.ts @@ -0,0 +1,41 @@ +import { compact } from './compact' +import { pipe } from './pipe' + +test('happy', () => { + const result = pipe( + { + a: [ undefined, 'a', 'b', 'c'], + b: [1,2, null, 0, undefined, 3], + c: { a: 1, b: 2, c: 0, d: undefined, e: null, f: false }, + }, + (x: { a: (string | undefined)[]; b: (number | null | undefined)[]; c: Record }) => ({ + a: compact(x.a), + b: compact(x.b), + c: compact(x.c), + }) + ) + expect(result.a).toEqual(['a', 'b', 'c']) + expect(result.b).toEqual([1,2,0,3]) + expect(result.c).toEqual({ a: 1, b: 2, c: 0, f: false }) +}) + +test('type test', () => { + const result = pipe( + { + a: [ undefined, '', 'a', 'b', 'c', null ], + b: [1,2, null, 0, undefined, 3], + c: { a: 1, b: 2, c: 0, d: undefined, e: null, f: false }, + }, + (x: { a: (string | undefined | null)[]; b: (number | null | undefined)[]; c: Record }) => ({ + a: compact(x.a), + b: compact(x.b), + c: compact(x.c), + }) + ) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expectTypeOf(result.c).toEqualTypeOf<{ a: number; b: number; c: number; f: boolean }>() + expect(result.a).toEqual(['', 'a', 'b', 'c']) + expect(result.b).toEqual([1,2,0,3]) + expect(result.c).toEqual({ a: 1, b: 2, c: 0, f: false }) +}) diff --git a/source/complement.d.ts b/source/complement.d.ts new file mode 100644 index 00000000..af2563ac --- /dev/null +++ b/source/complement.d.ts @@ -0,0 +1 @@ +export { complement } from '../files/index' diff --git a/source/complement.spec.ts b/source/complement.spec.ts new file mode 100644 index 00000000..259568e7 --- /dev/null +++ b/source/complement.spec.ts @@ -0,0 +1,20 @@ +import { complement } from './complement' + +test('happy', () => { + const fn = complement((x: string) => x.length === 0) + expect(fn([1, 2, 3])).toBeTruthy() +}) + +test('with multiple parameters', () => { + const between = (a: number, b: number, c: number) => a < b && b < c + const f = complement(between) + expect(f(4, 5, 11)).toBeFalsy() + expect(f(12, 2, 6)).toBeTruthy() +}) + +test('type test', () => { + const fn = complement((x: number) => x > 10) + const result = fn(1) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/concat.d.ts b/source/concat.d.ts new file mode 100644 index 00000000..2ba264c1 --- /dev/null +++ b/source/concat.d.ts @@ -0,0 +1 @@ +export { concat } from '../files/index' diff --git a/source/concat.spec.ts b/source/concat.spec.ts new file mode 100644 index 00000000..eb9872a1 --- /dev/null +++ b/source/concat.spec.ts @@ -0,0 +1,14 @@ +import { concat } from './concat' +import { pipe } from './pipe' + +const list1 = [1, 2, 3] +const list2 = [4, 5, 6] + +test('R.concat', () => { + const result = pipe(list1, concat(list2)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([4, 5, 6, 1, 2, 3]) + const resultString = pipe('foo', concat('list2')) + expectTypeOf(resultString).toEqualTypeOf() + expect(resultString).toBe('list2foo') +}) diff --git a/source/count.d.ts b/source/count.d.ts new file mode 100644 index 00000000..ea2e8505 --- /dev/null +++ b/source/count.d.ts @@ -0,0 +1 @@ +export { count } from '../files/index' diff --git a/source/count.spec.ts b/source/count.spec.ts new file mode 100644 index 00000000..7c5de157 --- /dev/null +++ b/source/count.spec.ts @@ -0,0 +1,20 @@ +import { count } from './count' +import { pipe } from './pipe' + +const predicate = (x: any) => x.a !== undefined + +test('with empty list', () => { + expect(count(predicate)([])).toBe(0) +}) + +test('happy', () => { + const list = [1, 2, { a: 1 }, 3, { a: 1 }] + expect(count(predicate)(list)).toBe(2) +}) + +test('type test', () => { + const list = [1, 2, 3] + const result = pipe(list, count((x: number) => x > 1)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/countBy.d.ts b/source/countBy.d.ts new file mode 100644 index 00000000..4b3186b1 --- /dev/null +++ b/source/countBy.d.ts @@ -0,0 +1 @@ +export { countBy } from '../files/index' diff --git a/source/countBy.spec.ts b/source/countBy.spec.ts new file mode 100644 index 00000000..bf2e9fb4 --- /dev/null +++ b/source/countBy.spec.ts @@ -0,0 +1,24 @@ +import { countBy } from './countBy' +import { pipe } from './pipe' + +const list = ['a', 'A', 'b', 'B', 'c', 'C'] + +test('happy', () => { + const result = countBy((x: string) => x.toLowerCase())(list) + expect(result).toEqual({ + a: 2, + b: 2, + c: 2, + }) +}) + +test('type test', () => { + const result = pipe( + list, + countBy((x: string) => x.toLowerCase()), + ) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.foo).toEqualTypeOf() + expectTypeOf(result).toEqualTypeOf<{ [index: string]: number }>() + expect(result).toEqual({ a: 2, b: 2, c: 2 }) +}) diff --git a/source/createObjectFromKeys.d.ts b/source/createObjectFromKeys.d.ts new file mode 100644 index 00000000..e8ddc5b8 --- /dev/null +++ b/source/createObjectFromKeys.d.ts @@ -0,0 +1 @@ +export { createObjectFromKeys } from '../files/index' diff --git a/source/createObjectFromKeys.spec.ts b/source/createObjectFromKeys.spec.ts new file mode 100644 index 00000000..7b381821 --- /dev/null +++ b/source/createObjectFromKeys.spec.ts @@ -0,0 +1,7 @@ +import { createObjectFromKeys } from './createObjectFromKeys' + +test('happy', () => { + const result = createObjectFromKeys((key: string, index: number) => key.toUpperCase() + index)(['a', 'b']) + const expected = { a: 'A0', b: 'B1' } + expect(result).toEqual(expected) +}) diff --git a/source/defaultTo.d.ts b/source/defaultTo.d.ts new file mode 100644 index 00000000..a8d4451c --- /dev/null +++ b/source/defaultTo.d.ts @@ -0,0 +1 @@ +export { defaultTo } from '../files/index' diff --git a/source/defaultTo.spec.ts b/source/defaultTo.spec.ts new file mode 100644 index 00000000..fa1820d3 --- /dev/null +++ b/source/defaultTo.spec.ts @@ -0,0 +1,32 @@ +import { defaultTo } from './defaultTo' +import { pipe } from './pipe' + +test('with undefined', () => { + expect(defaultTo('foo')(undefined)).toBe('foo') +}) + +test('with null', () => { + expect(defaultTo('foo')(null)).toBe('foo') +}) + +test('with NaN', () => { + expect(defaultTo('foo')(Number.NaN)).toBe('foo') +}) + +test('with empty string', () => { + expect(defaultTo('foo')('')).toBe('') +}) + +test('with false', () => { + expect(defaultTo('foo')(false)).toBeFalsy() +}) + +test('when inputArgument passes initial check', () => { + expect(defaultTo('foo')('bar')).toBe('bar') +}) + +test('type test', () => { + const result = pipe('bar' as unknown, defaultTo('foo')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('bar') +}) diff --git a/source/delay.d.ts b/source/delay.d.ts new file mode 100644 index 00000000..4c2b36e7 --- /dev/null +++ b/source/delay.d.ts @@ -0,0 +1 @@ +export { delay } from '../files/index' diff --git a/source/descend.d.ts b/source/descend.d.ts new file mode 100644 index 00000000..29e52558 --- /dev/null +++ b/source/descend.d.ts @@ -0,0 +1 @@ +export { descend } from '../files/index' diff --git a/source/difference.d.ts b/source/difference.d.ts new file mode 100644 index 00000000..4683a8cd --- /dev/null +++ b/source/difference.d.ts @@ -0,0 +1 @@ +export { difference } from '../files/index' diff --git a/source/difference.spec.ts b/source/difference.spec.ts new file mode 100644 index 00000000..2947353a --- /dev/null +++ b/source/difference.spec.ts @@ -0,0 +1,21 @@ +import { difference } from './difference' + +test('difference', () => { + const list1 = [1, 2, 3, 4] + const list2 = [3, 4, 5, 6] + expect(difference(list1)(list2)).toEqual([1, 2, 5, 6]) + expect(difference([])([])).toEqual([]) +}) + +test('difference with objects', () => { + const list1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }] + const list2 = [{ id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }] + const result = difference(list1)(list2) + expectTypeOf(result).toEqualTypeOf<{ id: number }[]>() + expect(result).toEqual([ + { id: 1 }, + { id: 2 }, + { id: 5 }, + { id: 6 }, + ]) +}) diff --git a/source/drop.d.ts b/source/drop.d.ts new file mode 100644 index 00000000..c05b6145 --- /dev/null +++ b/source/drop.d.ts @@ -0,0 +1 @@ +export { drop } from '../files/index' diff --git a/source/drop.spec.ts b/source/drop.spec.ts new file mode 100644 index 00000000..2862f46e --- /dev/null +++ b/source/drop.spec.ts @@ -0,0 +1,20 @@ +import { drop } from './drop' +import { pipe } from './pipe' + +test('with array', () => { + expect(drop(2)(['foo', 'bar', 'baz'])).toEqual(['baz']) + expect(drop(3)(['foo', 'bar', 'baz'])).toEqual([]) + expect(drop(4)(['foo', 'bar', 'baz'])).toEqual([]) +}) + +test('with non-positive count', () => { + expect(drop(0)([1, 2, 3])).toEqual([1, 2, 3]) + expect(drop(-1)([1, 2, 3])).toEqual([1, 2, 3]) + expect(drop(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3]) +}) + +test('type test', () => { + const result = pipe([1, 2, 3, 4], drop(2)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([3, 4]) +}) diff --git a/source/dropLast.d.ts b/source/dropLast.d.ts new file mode 100644 index 00000000..5c6ec1fb --- /dev/null +++ b/source/dropLast.d.ts @@ -0,0 +1 @@ +export { dropLast } from '../files/index' diff --git a/source/dropLast.spec.ts b/source/dropLast.spec.ts new file mode 100644 index 00000000..8b6e2a9b --- /dev/null +++ b/source/dropLast.spec.ts @@ -0,0 +1,13 @@ +import { dropLast } from './dropLast' + +test('with array', () => { + expect(dropLast(2)(['foo', 'bar', 'baz'])).toEqual(['foo']) + expect(dropLast(3)(['foo', 'bar', 'baz'])).toEqual([]) + expect(dropLast(4)(['foo', 'bar', 'baz'])).toEqual([]) +}) + +test('with non-positive count', () => { + expect(dropLast(0)([1, 2, 3])).toEqual([1, 2, 3]) + expect(dropLast(-1)([1, 2, 3])).toEqual([1, 2, 3]) + expect(dropLast(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3]) +}) diff --git a/source/dropLastWhile.d.ts b/source/dropLastWhile.d.ts new file mode 100644 index 00000000..e711ed60 --- /dev/null +++ b/source/dropLastWhile.d.ts @@ -0,0 +1 @@ +export { dropLastWhile } from '../files/index' diff --git a/source/dropLastWhile.spec.ts b/source/dropLastWhile.spec.ts new file mode 100644 index 00000000..5c087784 --- /dev/null +++ b/source/dropLastWhile.spec.ts @@ -0,0 +1,12 @@ +import { dropLastWhile } from './dropLastWhile' + +const list = [1, 2, 3, 4, 5] + +test('with list', () => { + const result = dropLastWhile((x: number) => x >= 3)(list) + expect(result).toEqual([1, 2]) +}) + +test('with empty list', () => { + expect(dropLastWhile(() => true)([])).toEqual([]) +}) diff --git a/source/dropWhile.d.ts b/source/dropWhile.d.ts new file mode 100644 index 00000000..c52864de --- /dev/null +++ b/source/dropWhile.d.ts @@ -0,0 +1 @@ +export { dropWhile } from '../files/index' diff --git a/source/dropWhile.spec.ts b/source/dropWhile.spec.ts new file mode 100644 index 00000000..a4e972a7 --- /dev/null +++ b/source/dropWhile.spec.ts @@ -0,0 +1,40 @@ +import { dropWhile } from './dropWhile' +import { pipe } from './pipe' + +const list = [1, 2, 3, 4] + +test('happy', () => { + const predicate = (x: number, i: number) => { + expect(typeof i).toBe('number') + return x < 3 + } + const result = dropWhile(predicate)(list) + expect(result).toEqual([3, 4]) +}) + +test('always false', () => { + const predicate = () => 0 + const result = dropWhile(predicate)(list) + expect(result).toEqual(list) +}) + +test('type test', () => { + const result = pipe( + [1, 2, 3], + dropWhile((x: number) => x < 3), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([3]) +}) + +test('with index', () => { + const result = pipe( + [1, 2, 3], + dropWhile((x: number, i: number) => { + expectTypeOf(i).toEqualTypeOf() + return x + i > 2 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 2, 3]) +}) diff --git a/source/duplicateBy.d.ts b/source/duplicateBy.d.ts new file mode 100644 index 00000000..8fcc6d9a --- /dev/null +++ b/source/duplicateBy.d.ts @@ -0,0 +1 @@ +export { duplicateBy } from '../files/index' diff --git a/source/duplicateBy.spec.ts b/source/duplicateBy.spec.ts new file mode 100644 index 00000000..6c9b0032 --- /dev/null +++ b/source/duplicateBy.spec.ts @@ -0,0 +1,15 @@ +import { duplicateBy } from './duplicateBy' + +test('happy', () => { + expect(duplicateBy(Math.abs)([-2, -1, 0, 1, 2])).toEqual([1, 2]) +}) + +test('returns an empty array for an empty array', () => { + expect(duplicateBy(Math.abs)([])).toEqual([]) +}) + +test('uses R.uniq', () => { + const list = [{ a: 1 }, { a: 2 }, { a: 1 }] + const expected = [{ a: 1 }] + expect(duplicateBy((x: any) => x)(list)).toEqual(expected) +}) diff --git a/source/eqBy.d.ts b/source/eqBy.d.ts new file mode 100644 index 00000000..b07f2bd3 --- /dev/null +++ b/source/eqBy.d.ts @@ -0,0 +1 @@ +export { eqBy } from '../files/index' diff --git a/source/eqBy.spec.ts b/source/eqBy.spec.ts new file mode 100644 index 00000000..e2df5eac --- /dev/null +++ b/source/eqBy.spec.ts @@ -0,0 +1,16 @@ +import { eqBy } from './eqBy' + +test('deteremines whether two values map to the same value in the codomain', () => { + expect(eqBy(Math.abs, 5)(5)).toBe(true) + expect(eqBy(Math.abs, 5)(-5)).toBe(true) + expect(eqBy(Math.abs, -5)(5)).toBe(true) + expect(eqBy(Math.abs, -5)(-5)).toBe(true) + expect(eqBy(Math.abs, 42)(99)).toBe(false) +}) + +test('has R.equals semantics', () => { + expect(eqBy(Math.abs, Number.NaN)(Number.NaN)).toBe(true) + expect(eqBy(Math.abs, [42])([42])).toBe(true) + expect(eqBy((x: any) => x, { a: 1 })({ a: 1 })).toBe(true) + expect(eqBy((x: any) => x, { a: 1 })({ a: 2 })).toBe(false) +}) diff --git a/source/eqProps.d.ts b/source/eqProps.d.ts new file mode 100644 index 00000000..63ce3b90 --- /dev/null +++ b/source/eqProps.d.ts @@ -0,0 +1 @@ +export { eqProps } from '../files/index' diff --git a/source/eqProps.spec.ts b/source/eqProps.spec.ts new file mode 100644 index 00000000..726b89e4 --- /dev/null +++ b/source/eqProps.spec.ts @@ -0,0 +1,34 @@ +import { eqProps } from './eqProps' +import { pipe } from './pipe' + +const obj1 = { + a: 1, + b: 2, +} +const obj2 = { + a: 1, + b: 3, +} + +test('props are equal', () => { + const result = eqProps('a', obj1)(obj2) + expect(result).toBeTruthy() +}) + +test('props are not equal', () => { + const result = eqProps('b', obj1)(obj2) + expect(result).toBeFalsy() +}) + +test('prop does not exist', () => { + const result = eqProps('c', obj1)(obj2) + expect(result).toBeTruthy() +}) + +test('type test', () => { + const objA = { a: { b: 1 }, c: 2 } + const objB = { a: { b: 1 }, c: 3 } + const result = pipe(objA, eqProps('a', objB)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/equals.d.ts b/source/equals.d.ts new file mode 100644 index 00000000..4bcf5521 --- /dev/null +++ b/source/equals.d.ts @@ -0,0 +1 @@ +export { equals } from '../files/index' diff --git a/source/equals.spec.ts b/source/equals.spec.ts new file mode 100644 index 00000000..a533c3a7 --- /dev/null +++ b/source/equals.spec.ts @@ -0,0 +1,208 @@ +// @ts-expect-error - equalsFn exists at runtime in equals.js +import { equalsFn } from './equals' +import { equals } from './equals' + +test('compare functions', () => { + function foo() {} + function bar() {} + const baz = () => {} + + const expectTrue = equalsFn(foo, foo) + const expectFalseFirst = equalsFn(foo, bar) + const expectFalseSecond = equalsFn(foo, baz) + + expect(expectTrue).toBeTruthy() + expect(expectFalseFirst).toBeFalsy() + expect(expectFalseSecond).toBeFalsy() +}) + +test('with array of objects', () => { + const list1 = [{ a: 1 }, [{ b: 2 }]] + const list2 = [{ a: 1 }, [{ b: 2 }]] + const list3 = [{ a: 1 }, [{ b: 3 }]] + + expect(equalsFn(list1, list2)).toBeTruthy() + expect(equalsFn(list1, list3)).toBeFalsy() +}) + +test('with regex', () => { + expect(equalsFn(/s/, /s/)).toBeTruthy() + expect(equalsFn(/s/, /d/)).toBeFalsy() + expect(equalsFn(/a/gi, /a/gi)).toBeTruthy() + expect(equalsFn(/a/gim, /a/gim)).toBeTruthy() + expect(equalsFn(/a/gi, /a/i)).toBeFalsy() +}) + +test('not a number', () => { + expect(equalsFn([Number.NaN], [Number.NaN])).toBeTruthy() +}) + +test('new number', () => { + expect(equalsFn(new Number(0), new Number(0))).toBeTruthy() + expect(equalsFn(new Number(0), new Number(1))).toBeFalsy() + expect(equalsFn(new Number(1), new Number(0))).toBeFalsy() +}) + +test('new string', () => { + expect(equalsFn(new String(''), new String(''))).toBeTruthy() + expect(equalsFn(new String(''), new String('x'))).toBeFalsy() + expect(equalsFn(new String('x'), new String(''))).toBeFalsy() + expect(equalsFn(new String('foo'), new String('foo'))).toBeTruthy() + expect(equalsFn(new String('foo'), new String('bar'))).toBeFalsy() + expect(equalsFn(new String('bar'), new String('foo'))).toBeFalsy() +}) + +test('new Boolean', () => { + expect(equalsFn(new Boolean(true), new Boolean(true))).toBeTruthy() + expect(equalsFn(new Boolean(false), new Boolean(false))).toBeTruthy() + expect(equalsFn(new Boolean(true), new Boolean(false))).toBeFalsy() + expect(equalsFn(new Boolean(false), new Boolean(true))).toBeFalsy() +}) + +test('new Error', () => { + expect(equalsFn(new Error('XXX'), {})).toBeFalsy() + expect(equalsFn(new Error('XXX'), new TypeError('XXX'))).toBeFalsy() + expect(equalsFn(new Error('XXX'), new Error('YYY'))).toBeFalsy() + expect(equalsFn(new Error('XXX'), new Error('XXX'))).toBeTruthy() + expect(equalsFn(new Error('XXX'), new TypeError('YYY'))).toBeFalsy() +}) + +test('with dates', () => { + expect(equalsFn(new Date(0), new Date(0))).toBeTruthy() + expect(equalsFn(new Date(1), new Date(1))).toBeTruthy() + expect(equalsFn(new Date(0), new Date(1))).toBeFalsy() + expect(equalsFn(new Date(1), new Date(0))).toBeFalsy() + expect(equalsFn(new Date(0), {})).toBeFalsy() + expect(equalsFn({}, new Date(0))).toBeFalsy() +}) + +test('ramda spec', () => { + expect(equalsFn({}, {})).toBeTruthy() + + expect( + equalsFn( + { + a: 1, + b: 2, + }, + { + a: 1, + b: 2, + }, + ), + ).toBeTruthy() + + expect( + equalsFn( + { + a: 2, + b: 3, + }, + { + a: 2, + b: 3, + }, + ), + ).toBeTruthy() + + expect( + equalsFn( + { + a: 2, + b: 3, + }, + { + a: 3, + b: 3, + }, + ), + ).toBeFalsy() + + expect( + equalsFn( + { + a: 2, + b: 3, + c: 1, + }, + { + a: 2, + b: 3, + }, + ), + ).toBeFalsy() +}) + +test('works with boolean tuple', () => { + expect(equalsFn([true, false], [true, false])).toBeTruthy() + expect(equalsFn([true, false], [true, true])).toBeFalsy() +}) + +test('works with equal objects within array', () => { + const objFirst = { + a: { + b: 1, + c: 2, + d: [1], + }, + } + const objSecond = { + a: { + b: 1, + c: 2, + d: [1], + }, + } + + const x = [1, 2, objFirst, null, '', []] + const y = [1, 2, objSecond, null, '', []] + expect(equalsFn(x, y)).toBeTruthy() +}) + +test('works with different objects within array', () => { + const objFirst = { a: { b: 1 } } + const objSecond = { a: { b: 2 } } + + const x = [1, 2, objFirst, null, '', []] + const y = [1, 2, objSecond, null, '', []] + expect(equalsFn(x, y)).toBeFalsy() +}) + +test('works with undefined as second argument', () => { + expect(equalsFn(1, undefined)).toBeFalsy() + expect(equalsFn(undefined, undefined)).toBeTruthy() +}) + +test('compare sets', () => { + const toCompareDifferent = new Set([{ a: 1 }, { a: 2 }]) + const toCompareSame = new Set([{ a: 1 }, { a: 2 }, { a: 1 }]) + const testSet = new Set([{ a: 1 }, { a: 2 }, { a: 1 }]) + expect(equalsFn(toCompareSame, testSet)).toBeTruthy() + expect(equalsFn(toCompareDifferent, testSet)).toBeFalsy() +}) + +test('compare simple sets', () => { + const testSet = new Set(['2', '3', '3', '2', '1']) + expect(equalsFn(new Set(['3', '2', '1']), testSet)).toBeTruthy() + expect(equalsFn(new Set(['3', '2', '0']), testSet)).toBeFalsy() +}) + +test('various examples', () => { + expect(equalsFn([1, 2, 3], [1, 2, 3])).toBeTruthy() + expect(equalsFn([1, 2, 3], [1, 2])).toBeFalsy() + expect(equalsFn({}, {})).toBeTruthy() +}) + +test('type test', () => { + const result = equals(4)(1) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(false) +}) + +test('with object', () => { + const foo = { a: 1 } + const bar = { a: 2 } + const result = equals(foo)(bar) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(false) +}) diff --git a/source/evolve.d.ts b/source/evolve.d.ts new file mode 100644 index 00000000..f97869c1 --- /dev/null +++ b/source/evolve.d.ts @@ -0,0 +1 @@ +export { evolve } from '../files/index' diff --git a/source/evolve.spec.ts b/source/evolve.spec.ts new file mode 100644 index 00000000..e2c83f16 --- /dev/null +++ b/source/evolve.spec.ts @@ -0,0 +1,43 @@ +import { evolve } from './evolve' +import { pipe } from './pipe' + +test('happy', () => { + const rules = { + foo: (x: number) => x + 1, + } + const input = { + a: 1, + foo: 2, + nested: { bar: { z: 3 } }, + } + const result = evolve(rules)(input) + expect(result).toEqual({ + a: 1, + foo: 3, + nested: { bar: { z: 3 } }, + }) +}) + +test('type test', () => { + const input = { + baz: 1, + foo: 2, + nested: { + a: 1, + bar: 3, + }, + } + const result = pipe(input, + evolve({ + foo: (x: number) => x + 1, + }) + ) + expectTypeOf(result.foo).toEqualTypeOf() + expectTypeOf(result.baz).toEqualTypeOf() + expectTypeOf(result.nested.a).toEqualTypeOf() + expect(result).toEqual({ + baz: 1, + foo: 3, + nested: { a: 1, bar: 3 }, + }) +}) diff --git a/source/excludes.d.ts b/source/excludes.d.ts new file mode 100644 index 00000000..ac878b23 --- /dev/null +++ b/source/excludes.d.ts @@ -0,0 +1 @@ +export { excludes } from '../files/index' diff --git a/source/excludes.spec.ts b/source/excludes.spec.ts new file mode 100644 index 00000000..5291530a --- /dev/null +++ b/source/excludes.spec.ts @@ -0,0 +1,27 @@ +import { excludes } from './excludes' +import { pipe } from './pipe' + +test('excludes with string', () => { + const str = 'more is less' + expect(excludes(str)('less')).toBeFalsy() + expect(excludes(str)('never')).toBeTruthy() +}) + +test('excludes with array', () => { + const arr = [1, 2, 3] + expect(excludes(arr)(2)).toBeFalsy() + expect(excludes(arr)(4)).toBeTruthy() +}) + +test('type test', () => { + const list = [{ a: { b: '1' } }, { a: { b: '2' } }, { a: { b: '3' } }] + const result = pipe({ a: { b: '1' } }, excludes(list)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(false) +}) + +test('with string', () => { + const result = pipe('foo', excludes('bar')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/exists.d.ts b/source/exists.d.ts new file mode 100644 index 00000000..ed3de6d9 --- /dev/null +++ b/source/exists.d.ts @@ -0,0 +1 @@ +export { exists } from '../files/index' diff --git a/source/exists.spec.ts b/source/exists.spec.ts new file mode 100644 index 00000000..3de10c79 --- /dev/null +++ b/source/exists.spec.ts @@ -0,0 +1,22 @@ +import { exists } from './exists' +import { propEq } from './propEq' +import { pipe } from './pipe' + +const list = [{ a: 1 }, { a: 2 }, { a: 3 }] + +test('happy', () => { + const fn = propEq(2, 'a') + expect(exists(fn)(list)).toBe(true) +}) + +test('nothing is found', () => { + const fn = propEq(4, 'a') + expect(exists(fn)(list)).toBe(false) +}) + +test('type test', () => { + const predicate = (x: number) => x > 2 + const result = pipe([1, 2, 3], exists(predicate)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/filter.d.ts b/source/filter.d.ts new file mode 100644 index 00000000..4151f2f8 --- /dev/null +++ b/source/filter.d.ts @@ -0,0 +1 @@ +export { filter } from '../files/index' diff --git a/source/filter.spec.ts b/source/filter.spec.ts new file mode 100644 index 00000000..18abfe94 --- /dev/null +++ b/source/filter.spec.ts @@ -0,0 +1,109 @@ +import { filter } from './filter' +import { includes } from './includes' +import { pipe } from './pipe' +import { reject } from './reject' +import { sort } from './sort' +import { split } from './split' +import { uniq } from './uniq' + +test('happy', () => { + const isEven = (n: number) => n % 2 === 0 + expect(filter(isEven)([1, 2, 3, 4])).toEqual([2, 4]) +}) + +test('using Boolean', () => { + expect(filter(Boolean)([null, 0, 1, 2])).toEqual([1, 2]) +}) + +test('within pipe', () => { + const result = pipe( + [1, 2, 3], + filter((x: number) => { + expectTypeOf(x).toEqualTypeOf() + return x > 1 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([2, 3]) +}) + +test('with index', () => { + const result = pipe( + [1, 2, 3], + filter((x: number, i: number) => { + expectTypeOf(x).toEqualTypeOf() + expectTypeOf(i).toEqualTypeOf() + return x > 1 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([2, 3]) +}) + +test('complex example', () => { + const text = `Dies ist ein einfacher Beispielsatz. Il fait beau aujourd'hui!` + const language = 'de' + const SENTENCE_END_CHARS = ['.', '!', '?', '।', '؟'] + const result = pipe( + text, + split(''), + uniq, + filter((char: string) => { + if (language === 'de') { + return /[A-Za-zäßüöÜÖÄ]/g.test(char) === false + } + if (language === 'fr') { + return /[A-Za-zÀÉàâçèéêîïôùû']/g.test(char) === false + } + throw new Error(`Language ${language} not supported`) + }), + sort((a: string, b: string) => (a === b ? 0 : a > b ? 1 : -1)), + filter((char: string) => char.trim().length > 0), + reject(includes(SENTENCE_END_CHARS)), + ) + expectTypeOf(result).toEqualTypeOf() +}) + +test('narrowing type', () => { + interface Foo { + a: number + } + interface Bar extends Foo { + b: string + } + type T = Foo | Bar + const testList: T[] = [{ a: 1 }, { a: 2 }, { a: 3 }] + const filterBar = (x: T): x is Bar => { + return typeof (x as Bar).b === 'string' + } + const result = pipe(testList, filter(filterBar)) + expectTypeOf(result).toEqualTypeOf() +}) + +test('narrowing type - readonly', () => { + interface Foo { + a: number + } + interface Bar extends Foo { + b: string + } + type T = Foo | Bar + const testList: T[] = [{ a: 1 }, { a: 2 }, { a: 3 }] as const + const filterBar = (x: T): x is Bar => { + return typeof (x as Bar).b === 'string' + } + const result = pipe(testList, filter(filterBar)) + expectTypeOf(result).toEqualTypeOf() +}) + +test('filtering NonNullable - list of objects', () => { + const testList = [{ a: 1 }, { a: 2 }, false, { a: 3 }] + const result = pipe(testList, filter(Boolean)) + expectTypeOf(result).toEqualTypeOf<{ a: number }[]>() +}) + +test('filtering NonNullable - readonly', () => { + const testList = [1, 2, true, false, null, undefined, 3] as const + const result = pipe(testList, filter(Boolean)) + expectTypeOf(result).toEqualTypeOf<1 | 2 | 3>() +}) diff --git a/source/filterAsync.d.ts b/source/filterAsync.d.ts new file mode 100644 index 00000000..05318986 --- /dev/null +++ b/source/filterAsync.d.ts @@ -0,0 +1 @@ +export { filterAsync } from '../files/index' diff --git a/source/filterAsync.spec.ts b/source/filterAsync.spec.ts new file mode 100644 index 00000000..2c03ba7c --- /dev/null +++ b/source/filterAsync.spec.ts @@ -0,0 +1,19 @@ +import { filterAsync } from './filterAsync' +import { pipeAsync } from './pipeAsync' + +test('happy', async () => { + const isEven = async (n: number) => n % 2 === 0 + expect(await filterAsync(isEven)([1, 2, 3, 4])).toEqual([2, 4]) +}) + +test('within pipe', async () => { + const result = await pipeAsync( + [1, 2, 3], + filterAsync(async (x: number) => { + expectTypeOf(x).toEqualTypeOf() + return x > 1 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([2, 3]) +}) diff --git a/source/filterMap.d.ts b/source/filterMap.d.ts new file mode 100644 index 00000000..ec53e5d9 --- /dev/null +++ b/source/filterMap.d.ts @@ -0,0 +1 @@ +export { filterMap } from '../files/index' diff --git a/source/filterMap.spec.ts b/source/filterMap.spec.ts new file mode 100644 index 00000000..f555da99 --- /dev/null +++ b/source/filterMap.spec.ts @@ -0,0 +1,24 @@ +import { filterMap } from './filterMap' +import { pipe } from './pipe' + +const double = (x: number) => x > 1 ? x * 2 : null + +test('happy', () => { + expect(filterMap(double)([1, 2, 3])).toEqual([4, 6]) +}) + +test('within pipe', () => { + const result = pipe( + [1, 2, 3], + (x: number[]) => x, + filterMap((x: number) => { + expectTypeOf(x).toEqualTypeOf() + return Math.random() > 0.5 ? String(x) : null + }), + filterMap((x: string) => { + expectTypeOf(x).toEqualTypeOf() + return Math.random() > 0.5 ? Number(x) : '' + }), + ) + expectTypeOf(result).toEqualTypeOf() +}) diff --git a/source/filterObject.d.ts b/source/filterObject.d.ts new file mode 100644 index 00000000..53769043 --- /dev/null +++ b/source/filterObject.d.ts @@ -0,0 +1 @@ +export { filterObject } from '../files/index' diff --git a/source/filterObject.spec.ts b/source/filterObject.spec.ts new file mode 100644 index 00000000..bfd7f6d2 --- /dev/null +++ b/source/filterObject.spec.ts @@ -0,0 +1,27 @@ +import { filterObject } from './filterObject' +import { pipe } from './pipe' + +test('happy', () => { + const testInput = { a: 1, b: 2, c: 3 } + const result = pipe( + testInput, + filterObject((x: number, prop: string, obj: typeof testInput) => { + expect(prop).toBeOneOf(['a', 'b', 'c']) + expect(obj).toBe(testInput) + return x > 1 + }) + ) + expect(result).toEqual({ b: 2, c: 3 }) +}) + +test('require explicit type', () => { + const result = pipe( + { a: 1, b: 2 }, + filterObject<{ b: number }>((a: number) => { + expectTypeOf(a).toEqualTypeOf() + return a > 1 + }), + ) + expectTypeOf(result.b).toEqualTypeOf() + expect(result).toEqual({ b: 2 }) +}) diff --git a/source/find-spec.ts b/source/find-spec.ts index 746bb15c..7ccb1f54 100644 --- a/source/find-spec.ts +++ b/source/find-spec.ts @@ -8,5 +8,15 @@ describe('R.find', () => { const predicate = (x: number) => x > 2 const result = pipe(list, find(predicate)) expectTypeOf(result).toEqualTypeOf() + }) + + it('has type guard narrowing', () => { + const items = ['hello', 'world', 42] as (string | number)[] + + const result = pipe( + items, + find((x): x is string => typeof x === 'string'), + ) + expectTypeOf(result).toEqualTypeOf() }) }) diff --git a/source/find.d.ts b/source/find.d.ts new file mode 100644 index 00000000..aa60b334 --- /dev/null +++ b/source/find.d.ts @@ -0,0 +1 @@ +export { find } from '../files/index' diff --git a/source/find.spec.ts b/source/find.spec.ts new file mode 100644 index 00000000..61bf9c22 --- /dev/null +++ b/source/find.spec.ts @@ -0,0 +1,36 @@ +import { find } from './find' +import { propEq } from './propEq' +import { pipe } from './pipe' + +const list = [{ a: 1 }, { a: 2 }, { a: 3 }] + +test('happy', () => { + const fn = propEq(2, 'a') + expect(find(fn)(list)).toEqual({ a: 2 }) +}) + +test('nothing is found', () => { + const fn = propEq(4, 'a') + expect(find(fn)(list)).toBeUndefined() +}) + +test('with empty list', () => { + expect(find(() => true)([])).toBeUndefined() +}) + +test('type test', () => { + const predicate = (x: number) => x > 2 + const result = pipe([1, 2, 3], find(predicate)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(3) +}) + +test('has type guard narrowing', () => { + const items = ['hello', 'world', 42] as (string | number)[] + const result = pipe( + items, + find((x): x is string => typeof x === 'string'), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('hello') +}) diff --git a/source/findIndex.d.ts b/source/findIndex.d.ts new file mode 100644 index 00000000..8fe50ed9 --- /dev/null +++ b/source/findIndex.d.ts @@ -0,0 +1 @@ +export { findIndex } from '../files/index' diff --git a/source/findIndex.spec.ts b/source/findIndex.spec.ts new file mode 100644 index 00000000..18b7b1b7 --- /dev/null +++ b/source/findIndex.spec.ts @@ -0,0 +1,20 @@ +import { findIndex } from './findIndex' +import { propEq } from './propEq' +import { pipe } from './pipe' + +const list = [{ a: 1 }, { a: 2 }, { a: 3 }] + +test('happy', () => { + expect(findIndex(propEq(2, 'a'))(list)).toBe(1) + expect(findIndex(propEq(1, 'a'))(list)).toBe(0) + expect(findIndex(propEq(4, 'a'))(list)).toBe(-1) +}) + +test('type test', () => { + const result = pipe( + [1, 2, 3], + findIndex((x: number) => x > 2), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/findLastIndex.d.ts b/source/findLastIndex.d.ts new file mode 100644 index 00000000..c56d7f42 --- /dev/null +++ b/source/findLastIndex.d.ts @@ -0,0 +1 @@ +export { findLastIndex } from '../files/index' diff --git a/source/findLastIndex.spec.ts b/source/findLastIndex.spec.ts new file mode 100644 index 00000000..464b6a88 --- /dev/null +++ b/source/findLastIndex.spec.ts @@ -0,0 +1,15 @@ +import { findLastIndex } from './findLastIndex' +import { pipe } from './pipe' + +test('happy', () => { + const result = findLastIndex((x: number) => x > 1)([1, 1, 1, 2, 3, 4, 1]) + expect(result).toBe(5) + expect(findLastIndex((x: number) => x === 0)([0, 1, 1, 2, 3, 4, 1])).toBe(0) +}) + +test('type test', () => { + const predicate = (x: number) => x > 2 + const result = pipe([1, 2, 3], findLastIndex(predicate)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/findNth.d.ts b/source/findNth.d.ts new file mode 100644 index 00000000..59db5673 --- /dev/null +++ b/source/findNth.d.ts @@ -0,0 +1 @@ +export { findNth } from '../files/index' diff --git a/source/findNth.spec.ts b/source/findNth.spec.ts new file mode 100644 index 00000000..59946945 --- /dev/null +++ b/source/findNth.spec.ts @@ -0,0 +1,13 @@ +import { findNth } from './findNth' + +const list = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }] + +test('happy', () => { + const fn = (x: { a: number }) => x.a > 1 + expect(findNth(fn, 1)(list)).toEqual({ a: 3 }) +}) + +test('nothing is found', () => { + const fn = (x: { a: number }) => x.a > 4 + expect(findNth(fn, 1)(list)).toBeUndefined() +}) diff --git a/source/flatMap.d.ts b/source/flatMap.d.ts new file mode 100644 index 00000000..22eb029e --- /dev/null +++ b/source/flatMap.d.ts @@ -0,0 +1 @@ +export { flatMap } from '../files/index' diff --git a/source/flatMap.spec.ts b/source/flatMap.spec.ts new file mode 100644 index 00000000..8f99f16d --- /dev/null +++ b/source/flatMap.spec.ts @@ -0,0 +1,48 @@ +import { flatMap } from './flatMap' +import { pipe } from './pipe' + +const duplicate = (n: number) => [n, n] + +test('happy', () => { + const fn = (x: number) => [x * 2] + const list = [1, 2, 3] + const result = flatMap(fn)(list) + expect(result).toEqual([2, 4, 6]) +}) + +test('maps then flattens one level', () => { + expect(flatMap(duplicate)([1, 2, 3])).toEqual([1, 1, 2, 2, 3, 3]) +}) + +test('flattens only one level', () => { + const nest = (n: number) => [[n]] + expect(flatMap(nest)([1, 2, 3])).toEqual([[1], [2], [3]]) +}) + +test('can compose', () => { + function dec(x: number) { + return [x - 1] + } + function times2(x: number) { + return [x * 2] + } + const mdouble = flatMap(times2) + const mdec = flatMap(dec) + expect(mdec(mdouble([10, 20, 30]))).toEqual([19, 39, 59]) +}) + +test('type test', () => { + const listOfLists: string[][] = [ + ['f', 'bar'], + ['baz', 'b'], + ] + const result = pipe( + listOfLists, + (x: string[][]) => x, + flatMap((x: string) => { + expectTypeOf(x).toEqualTypeOf() + return Number(x) + 1 + }), + ) + expectTypeOf(result).toEqualTypeOf() +}) diff --git a/source/flatten.d.ts b/source/flatten.d.ts new file mode 100644 index 00000000..fc9bf8ab --- /dev/null +++ b/source/flatten.d.ts @@ -0,0 +1 @@ +export { flatten } from '../files/index' diff --git a/source/flatten.spec.ts b/source/flatten.spec.ts new file mode 100644 index 00000000..0e74a5b0 --- /dev/null +++ b/source/flatten.spec.ts @@ -0,0 +1,17 @@ +import { flatten } from './flatten' +import { pipe } from './pipe' + +test('happy', () => { + expect(flatten([1, 2, 3, [[[[[4]]]]]])).toEqual([1, 2, 3, 4]) + expect(flatten([1, [2, [[3]]], [4]])).toEqual([1, 2, 3, 4]) + expect(flatten([1, [2, [[[3]]]], [4]])).toEqual([1, 2, 3, 4]) + expect(flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]])).toEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + ]) +}) + +test('type test', () => { + const result = pipe([1, 2, [3, [4]]], flatten) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 2, 3, 4]) +}) diff --git a/source/flattenObject.d.ts b/source/flattenObject.d.ts new file mode 100644 index 00000000..f4261f87 --- /dev/null +++ b/source/flattenObject.d.ts @@ -0,0 +1 @@ +export { flattenObject } from '../files/index' diff --git a/source/flattenObject.spec.ts b/source/flattenObject.spec.ts new file mode 100644 index 00000000..04d554fa --- /dev/null +++ b/source/flattenObject.spec.ts @@ -0,0 +1,41 @@ +import { flattenObject } from './flattenObject' +import { pipe } from './pipe' + +test('happy', () => { + const result = flattenObject({ + a: 1, + b: { + c: 3, + d: { + e: 5, + z: 4, + f: { + h: 6, + i: 7, + j: { + k: 8, + l: 9, + }, + }, + }, + }, + }) + const expected = { + 'a': 1, + 'b.c': 3, + 'b.d.e': 5, + 'b.d.z': 4, + 'b.d.f.h': 6, + 'b.d.f.i': 7, + 'b.d.f.j.k': 8, + 'b.d.f.j.l': 9, + } + expect(result).toEqual(expected) +}) + +test('type test', () => { + const result = pipe({ a: { b: 1, c: 2 } }, flattenObject) + expectTypeOf(result['a.b']).toEqualTypeOf() + expectTypeOf(result['a.c']).toEqualTypeOf() + expect(result).toEqual({ 'a.b': 1, 'a.c': 2 }) +}) diff --git a/source/groupBy.d.ts b/source/groupBy.d.ts new file mode 100644 index 00000000..c353a610 --- /dev/null +++ b/source/groupBy.d.ts @@ -0,0 +1 @@ +export { groupBy } from '../files/index' diff --git a/source/groupBy.spec.ts b/source/groupBy.spec.ts new file mode 100644 index 00000000..aff5c22e --- /dev/null +++ b/source/groupBy.spec.ts @@ -0,0 +1,30 @@ +import { groupBy } from './groupBy' +import { pipe } from './pipe' + +test('with list', () => { + const inventory = [ + { name: 'asparagus', type: 'vegetables', quantity: 9 }, + { name: 'bananas', type: 'fruit', quantity: 5 }, + { name: 'goat', type: 'meat', quantity: 23 }, + { name: 'cherries', type: 'fruit', quantity: 12 }, + { name: 'fish', type: 'meat', quantity: 22 }, + ] + const result = groupBy( + ({ quantity }: { quantity: number }) => + quantity < 6 ? 'restock' : 'sufficient' + )(inventory) + expect(result.restock).toEqual([ + { name: 'bananas', type: 'fruit', quantity: 5 }, + ]) + expect(result.sufficient[0]).toEqual( + { name: 'asparagus', type: 'vegetables', quantity: 9 } + ) +}) + +test('type test', () => { + const groupByFn = (x: string) => String(x.length) + const list = ['foo', 'bar'] + const result = pipe(list, groupBy(groupByFn)) + expectTypeOf(result).toEqualTypeOf>>() + expect(result).toEqual({ '3': ['foo', 'bar'] }) +}) diff --git a/source/head.d.ts b/source/head.d.ts new file mode 100644 index 00000000..2b368262 --- /dev/null +++ b/source/head.d.ts @@ -0,0 +1 @@ +export { head } from '../files/index' diff --git a/source/head.spec.ts b/source/head.spec.ts new file mode 100644 index 00000000..4c0b2106 --- /dev/null +++ b/source/head.spec.ts @@ -0,0 +1,17 @@ +import { head } from './head' + +test('head', () => { + expect(head(['fi', 'fo', 'fum'])).toBe('fi') + expect(head([])).toBeUndefined() + expect(head('foo')).toBe('f') + expect(head('')).toBe('') +}) + +test('type test', () => { + expectTypeOf(head('foo')).toEqualTypeOf() + expectTypeOf(head('')).toEqualTypeOf() + expectTypeOf(head([1, 2, 3])).toEqualTypeOf() + expectTypeOf(head([])).toEqualTypeOf() + expectTypeOf(head([1, 'foo', 3, 'bar'])).toEqualTypeOf() + expect(head(['fi', 'fo', 'fum'])).toBe('fi') +}) diff --git a/source/includes.d.ts b/source/includes.d.ts new file mode 100644 index 00000000..2301c400 --- /dev/null +++ b/source/includes.d.ts @@ -0,0 +1 @@ +export { includes } from '../files/index' diff --git a/source/includes.spec.ts b/source/includes.spec.ts new file mode 100644 index 00000000..a163a690 --- /dev/null +++ b/source/includes.spec.ts @@ -0,0 +1,34 @@ +import { includes } from './includes' +import { pipe } from './pipe' + +test('with string as iterable', () => { + const str = 'foo bar' + expect(includes(str)('foo')).toBeTruthy() + expect(includes(str)('never')).toBeFalsy() +}) + +test('with array as iterable', () => { + const arr = [1, 2, 3] + expect(includes(arr)(2)).toBeTruthy() + expect(includes(arr)(4)).toBeFalsy() +}) + +test('with list of objects as iterable', () => { + const arr = [{ a: 1 }, { b: 2 }, { c: 3 }] + expect(includes(arr)({ c: 3 })).toBeTruthy() +}) + +test('with NaN', () => { + expect(includes([Number.NaN])(Number.NaN)).toBeTruthy() +}) + +test('with wrong input that does not throw', () => { + expect(includes([1])(/foo/g)).toBeFalsy() +}) + +test('type test', () => { + const list = [{ a: { b: '1' } }, { a: { b: '2' } }, { a: { b: '3' } }] + const result = pipe({ a: { b: '1' } }, includes(list)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeTruthy() +}) diff --git a/source/indexBy.d.ts b/source/indexBy.d.ts new file mode 100644 index 00000000..4b9cd743 --- /dev/null +++ b/source/indexBy.d.ts @@ -0,0 +1 @@ +export { indexBy } from '../files/index' diff --git a/source/indexBy.spec.ts b/source/indexBy.spec.ts new file mode 100644 index 00000000..586079e6 --- /dev/null +++ b/source/indexBy.spec.ts @@ -0,0 +1,18 @@ +import { indexBy } from './indexBy' +import { pipe } from './pipe' + +test('happy', () => { + const list = [{ id: 'xyz', title: 'A' }, { id: 'abc', title: 'B' }] + expect( + indexBy('id')(list) + ).toEqual( + { abc: { id: 'abc', title: 'B' }, xyz: { id: 'xyz', title: 'A' } } + ) +}) + +test('type test', () => { + const list = [{ id: 'xyz', title: 'A' }, { id: 'abc', title: 'B' }] + const result = pipe(list, indexBy('id')) + expectTypeOf(result.abc).toEqualTypeOf<{ id: string; title: string; }>() + expect(result).toEqual({ abc: { id: 'abc', title: 'B' }, xyz: { id: 'xyz', title: 'A' } }) +}) diff --git a/source/indexOf.d.ts b/source/indexOf.d.ts new file mode 100644 index 00000000..bde8d01a --- /dev/null +++ b/source/indexOf.d.ts @@ -0,0 +1 @@ +export { indexOf } from '../files/index' diff --git a/source/indexOf.spec.ts b/source/indexOf.spec.ts new file mode 100644 index 00000000..3b1ef10c --- /dev/null +++ b/source/indexOf.spec.ts @@ -0,0 +1,35 @@ +import { indexOf } from './indexOf' + +test('with NaN', () => { + expect(indexOf(Number.NaN)([Number.NaN])).toBe(0) +}) + +test('will throw with bad input', () => { + expect(() => indexOf([])(true)).toThrow() +}) + +test('with numbers', () => { + expect(indexOf(3)([1, 2, 3, 4])).toBe(2) + expect(indexOf(10)([1, 2, 3, 4])).toBe(-1) +}) + +test('list of objects use R.equals', () => { + const listOfObjects = [{ a: 1 }, { b: 2 }, { c: 3 }] + expect(indexOf({ c: 4 })(listOfObjects)).toBe(-1) + expect(indexOf({ c: 3 })(listOfObjects)).toBe(2) +}) + +test('list of arrays use R.equals', () => { + const listOfLists = [[1], [2, 3], [2, 3, 4], [2, 3], [1], []] + expect(indexOf([])(listOfLists)).toBe(5) + expect(indexOf([1])(listOfLists)).toBe(0) + expect(indexOf([2, 3, 4])(listOfLists)).toBe(2) + expect(indexOf([2, 3, 5])(listOfLists)).toBe(-1) +}) + +test('type test', () => { + const list = [{ a: 1 }, { a: 2 }] + const result = indexOf({ a: 1 })(list) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(0) +}) diff --git a/source/init.d.ts b/source/init.d.ts new file mode 100644 index 00000000..86540d58 --- /dev/null +++ b/source/init.d.ts @@ -0,0 +1 @@ +export { init } from '../files/index' diff --git a/source/init.spec.ts b/source/init.spec.ts new file mode 100644 index 00000000..ed76f11a --- /dev/null +++ b/source/init.spec.ts @@ -0,0 +1,25 @@ +import { init } from './init' +import { pipe } from './pipe' +import { map } from './map' + +test('with array', () => { + expect(init([1, 2, 3])).toEqual([1, 2]) + expect(init([1, 2])).toEqual([1]) + expect(init([1])).toEqual([]) + expect(init([])).toEqual([]) +}) + +test('with string', () => { + expect(init('foo')).toBe('fo') + expect(init('f')).toBe('') + expect(init('')).toBe('') +}) + +test('type test', () => { + expectTypeOf(init('foo')).toEqualTypeOf() + expect(init('foo')).toBe('fo') + + const result = pipe(['foo', 'bar', 1, 2, 3], init) + expectTypeOf(result).toEqualTypeOf<(string | number)[]>() + expect(result).toEqual(['foo', 'bar', 1, 2]) +}) diff --git a/source/interpolate.d.ts b/source/interpolate.d.ts new file mode 100644 index 00000000..4a12c73c --- /dev/null +++ b/source/interpolate.d.ts @@ -0,0 +1 @@ +export { interpolate } from '../files/index' diff --git a/source/interpolate.spec.ts b/source/interpolate.spec.ts new file mode 100644 index 00000000..ba3b969d --- /dev/null +++ b/source/interpolate.spec.ts @@ -0,0 +1,18 @@ +import { interpolate } from './interpolate' +import { pipe } from './pipe' + +test('happy', () => { + const result = pipe( + { name: 'John', age: 30 }, + interpolate('My name is {{name}} and I am {{age}} years old') + ) + expect(result).toBe('My name is John and I am 30 years old') +}) + +test('type test', () => { + const templateInput = 'foo {{x}} baz' + const templateArguments = { x: 'led zeppelin' } + const result = interpolate(templateInput)(templateArguments) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('foo led zeppelin baz') +}) diff --git a/source/intersection.d.ts b/source/intersection.d.ts new file mode 100644 index 00000000..82930c50 --- /dev/null +++ b/source/intersection.d.ts @@ -0,0 +1 @@ +export { intersection } from '../files/index' diff --git a/source/intersection.spec.ts b/source/intersection.spec.ts new file mode 100644 index 00000000..481e5b7d --- /dev/null +++ b/source/intersection.spec.ts @@ -0,0 +1,28 @@ +import { intersection } from './intersection' + +test('intersection', () => { + const list1 = [1, 2, 3, 4] + const list2 = [3, 4, 5, 6] + expect(intersection(list1)(list2)).toEqual([3, 4]) + expect(intersection([])([])).toEqual([]) +}) + +test('intersection with objects', () => { + const list1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }] + const list2 = [{ id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }] + expect(intersection(list1)(list2)).toEqual([{ id: 3 }, { id: 4 }]) +}) + +test('order is the same as in Ramda', () => { + const list = ['a', 'b', 'c', 'd'] + expect(intersection(list)(['b', 'c'])).toEqual(['b', 'c']) + expect(intersection(list)(['c', 'b'])).toEqual(['c', 'b']) +}) + +test('type test', () => { + const list1 = [1, 2, 3] + const list2 = [1, 3, 5] + const result = intersection(list1)(list2) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 3]) +}) diff --git a/source/intersectionWith.d.ts b/source/intersectionWith.d.ts new file mode 100644 index 00000000..133cf1e2 --- /dev/null +++ b/source/intersectionWith.d.ts @@ -0,0 +1 @@ +export { intersectionWith } from '../files/index' diff --git a/source/intersectionWith.spec.ts b/source/intersectionWith.spec.ts new file mode 100644 index 00000000..1d3cd946 --- /dev/null +++ b/source/intersectionWith.spec.ts @@ -0,0 +1,18 @@ +import { intersectionWith } from './intersectionWith' +import { pipe } from './pipe' + +test('readme example', () => { + const list1 = [1, 2, 3, 4, 5] + const list2 = [4, 5, 6] + const predicate = (x: number, y: number) => x >= y + const result = intersectionWith(predicate, list1)(list2) + expect(result).toEqual([4, 5]) +}) + +test('type test', () => { + const list1 = [1, 2, 3] + const list2 = [1, 3, 5] + const result = pipe(list1, intersectionWith((x, y) => x === y, list2)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 3]) +}) diff --git a/source/intersperse.d.ts b/source/intersperse.d.ts new file mode 100644 index 00000000..8c4f65ec --- /dev/null +++ b/source/intersperse.d.ts @@ -0,0 +1 @@ +export { intersperse } from '../files/index' diff --git a/source/intersperse.spec.ts b/source/intersperse.spec.ts new file mode 100644 index 00000000..814bf441 --- /dev/null +++ b/source/intersperse.spec.ts @@ -0,0 +1,21 @@ +import { intersperse } from './intersperse' + +test('intersperse', () => { + const list = [{ id: 1 }, { id: 2 }, { id: 10 }, { id: 'a' }] + expect(intersperse('!')(list)).toEqual([ + { id: 1 }, + '!', + { id: 2 }, + '!', + { id: 10 }, + '!', + { id: 'a' }, + ]) + expect(intersperse('!')([])).toEqual([]) +}) + +test('type test', () => { + const result = intersperse('|')(['foo', 'bar']) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['foo', '|', 'bar']) +}) diff --git a/source/isValid.d.ts b/source/isValid.d.ts new file mode 100644 index 00000000..f85e033e --- /dev/null +++ b/source/isValid.d.ts @@ -0,0 +1 @@ +export { isValid } from '../files/index' diff --git a/source/isValid.spec.ts b/source/isValid.spec.ts new file mode 100644 index 00000000..7c55be66 --- /dev/null +++ b/source/isValid.spec.ts @@ -0,0 +1,410 @@ +import { isValid } from './isValid' +import { delay } from './delay' + +test('prototype inside array', () => { + const input = { a: [1, 2, 3, 4] } + const schema = { a: [Number] } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('with Promise prototype', () => { + const input = { a: [delay(1), delay(2)] } + const schema = { a: [Promise] } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('object prototype as rule - true', () => { + const input = { a: {} } + const schema = { a: Object } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('object prototype as rule - false', () => { + const input = { a: null } + const schema = { a: Object } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('number prototype as rule - true', () => { + const input = { a: 1 } + const schema = { a: Number } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('array prototype as rule - true', () => { + const input = { a: [1, 2, 3] } + const schema = { a: Array } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('array prototype as rule - false', () => { + const input = { a: null } + const schema = { a: Array } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('string prototype as rule - true', () => { + const input = { a: 'foo' } + const schema = { a: String } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('string prototype as rule - false', () => { + const input = { a: null } + const schema = { a: String } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('boolean prototype as rule - true', () => { + const input = { a: true } + const schema = { a: Boolean } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('boolean prototype as rule - false', () => { + const input = { a: null } + const schema = { a: Boolean } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('undefined as a rule - true', () => { + const input = { a: undefined } + const schema = { a: undefined } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('undefined as a rule - false', () => { + const input = { a: null } + const schema = { a: undefined } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('null as a rule - true', () => { + const input = { a: null } + const schema = { a: null } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('null as a rule - false', () => { + const input = { a: undefined } + const schema = { a: null } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('`any` safeguard against `null`', () => { + const input = { a: null } + const schema = { a: 'any' } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('`any` safeguard against `undefined`', () => { + const input = { a: undefined } + const schema = { a: 'any' } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('type can be `"any"`', () => { + const input = { a: () => {} } + const schema = { a: 'any' } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('type can be `"function"`', () => { + const input = { a: () => {} } + const schema = { a: 'function' } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('type can be `promise`', () => { + const input = { + a: delay(1999), + b: async () => {}, + } + const schema = { + a: 'promise', + b: 'promise', + } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('type can be `promise` list', () => { + const input = { a: [delay(1999)] } + const schema = { a: ['promise'] } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('function as schema - false', () => { + const input = { + a: { + ab: () => true, + ac: 3, + }, + c: [1, 2], + } + const schema = { + a: { + ab: /fo/, + ac: 'number', + }, + 'b?': 'string', + c: ['number'], + } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('optional props is missing', () => { + const input = { + a: { + ab: 'foo', + ac: 3, + }, + c: [1, 2], + } + const schema = { + a: { + ab: 'string', + ac: 'number', + }, + 'b?': 'string', + c: ['number'], + } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('optional props is wrong type', () => { + const input = { + a: { + ab: 'foo', + ac: 3, + }, + b: [], + c: [1, 2], + } + const schema = { + a: { + ab: 'string', + ac: 'number', + }, + 'b?': 'string', + c: ['number'], + } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('optional props - nested', () => { + const input = { + a: { + ab: 'foo', + ac: 3, + }, + b: [], + c: [1, 2], + } + const schema = { + a: { + ab: 'string', + 'ac?': 'number', + }, + b: 'array', + c: ['number'], + } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('optional props is missing - nested', () => { + const input = { + a: { ab: 'foo' }, + b: [], + c: [1, 2], + } + const schema = { + a: { + ab: 'string', + 'ac?': 'number', + }, + b: 'array', + c: ['number'], + } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('optional props is wrong type - nested', () => { + const input = { + a: { + ab: 'foo', + ac: 'bar', + }, + b: [], + c: [1, 2], + } + const schema = { + a: { + ab: 'string', + 'ac?': 'number', + }, + b: 'array', + c: ['number'], + } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('nested schema', () => { + const input = { + a: { + b: 'str', + c: 3, + d: 'str', + }, + b: 'foo', + } + const schema = { + a: { + b: 'string', + c: 'number', + d: 'string', + }, + b: 'string', + } + expect(isValid({ input, schema })).toBeTruthy() + + const invalidInputFirst = { + a: { + b: 'str', + c: 3, + d: 'str', + }, + b: 5, + } + expect(isValid({ input: invalidInputFirst, schema })).toBeFalsy() + + const invalidInputSecond = { + a: { + b: 'str', + c: 'str', + d: 'str', + }, + b: 5, + } + expect(isValid({ input: invalidInputSecond, schema })).toBeFalsy() + + const invalidInputThird = { + a: { b: 'str' }, + b: 5, + } + expect(isValid({ input: invalidInputThird, schema })).toBeFalsy() +}) + +test('array of type', () => { + const input = { + a: [1, 2], + b: 'foo', + } + const schema = { + a: ['number'], + b: 'string', + } + expect(isValid({ input, schema })).toBeTruthy() + + const invalidInput = { + a: [1, '1'], + b: 'foo', + } + expect(isValid({ input: invalidInput, schema })).toBeFalsy() +}) + +test('function as rule', () => { + const input = { + a: [1, 2, 3, 4], + b: 'foo', + } + const invalidInput = { + a: [4], + b: 'foo', + } + const schema = { + a: (x: number[]) => x.length > 2, + b: 'string', + } + expect(isValid({ input, schema })).toBeTruthy() + expect(isValid({ input: invalidInput, schema })).toBeFalsy() +}) + +test('input prop is undefined', () => { + const input = { b: 3 } + const schema = { a: 'number' } + expect(isValid({ input, schema })).toBeFalsy() +}) + +test('readme example', () => { + const basicSchema = { a: ['string'] } + const schema = { + b: [basicSchema], + c: { + d: { e: 'boolean' }, + f: 'array', + }, + g: ['foo', 'bar', 'baz'], + } + const input = { + b: [{ a: ['led', 'zeppelin'] }], + c: { + d: { e: true }, + f: ['any', 1, null, 'value'], + }, + g: 'foo', + } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('should allow additional properties', () => { + const input = { title: 'You shook me', year: 1969 } + expect(isValid({ input, schema: { title: 'string' } })).toBeTruthy() +}) + +test('accepts values as schemas', () => { + const input = { title: 'You shook me', genre: 'Blues', year: 1969 } + const schema = { title: 'You shook me', year: 1969 } + expect(isValid({ input, schema })).toBeTruthy() +}) + +test('compatible schemas with nested object', () => { + const input = { foo: 'bar', baz: { a: { b: 'c' } } } + const invalidInputFirst = { foo: 'bar', baz: { a: { b: 1 } } } + const invalidInputSecond = { foo: 'bar', baz: { a: { b: [] } } } + const invalidInputThird = { foo: 'bar', baz: { a: { b: null } } } + const schema = { foo: 'string', baz: { a: { b: 'string' } } } + + expect(isValid({ input, schema })).toBeTruthy() + expect(isValid({ input: invalidInputFirst, schema })).toBeFalsy() + expect(isValid({ input: invalidInputSecond, schema })).toBeFalsy() + expect(isValid({ input: invalidInputThird, schema })).toBeFalsy() +}) + +test('should return true when schema is empty object', () => { + expect(isValid({ input: { a: 1 }, schema: {} })).toBeTruthy() +}) + +test('when schema is undefined', () => { + expect(isValid({ input: { a: 1 }, schema: undefined })).toBeFalsy() +}) + +test('should return false with invalid schema rule', () => { + const input = { foo: 'bar', a: {} } + const inputSecond = { foo: 'bar' } + const schema = { foo: 'string', baz: { a: {} } } + + expect(isValid({ input, schema })).toBeFalsy() + expect(isValid({ input: inputSecond, schema })).toBeFalsy() +}) + +test('array of schemas', () => { + const input = { + b: [ + { a: 'led', b: 1 }, + { a: 'dancing', b: 1 }, + ], + } + const basicSchema = { a: String, b: Number } + const schema = { b: [basicSchema] } + expect(isValid({ input, schema })).toBeTruthy() +}) diff --git a/source/join.d.ts b/source/join.d.ts new file mode 100644 index 00000000..194bb2d1 --- /dev/null +++ b/source/join.d.ts @@ -0,0 +1 @@ +export { join } from '../files/index' diff --git a/source/join.spec.ts b/source/join.spec.ts new file mode 100644 index 00000000..0d067335 --- /dev/null +++ b/source/join.spec.ts @@ -0,0 +1,8 @@ +import { join } from './join' +import { pipe } from './pipe' + +test('type test', () => { + const result = pipe([1, 2, 3], join('|')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('1|2|3') +}) diff --git a/source/last.d.ts b/source/last.d.ts new file mode 100644 index 00000000..c17bc487 --- /dev/null +++ b/source/last.d.ts @@ -0,0 +1 @@ +export { last } from '../files/index' diff --git a/source/last.spec.ts b/source/last.spec.ts new file mode 100644 index 00000000..57ffd4af --- /dev/null +++ b/source/last.spec.ts @@ -0,0 +1,18 @@ +import { last } from './last' + +test('with list', () => { + expect(last([1, 2, 3])).toBe(3) + expect(last([])).toBeUndefined() +}) + +test('with string', () => { + expect(last('abc')).toBe('c') + expect(last('')).toBe('') +}) + +test('type test', () => { + expectTypeOf(last([1, 2, 3])).toEqualTypeOf() + expectTypeOf(last([])).toEqualTypeOf() + expectTypeOf(last('abc')).toEqualTypeOf() + expect(last([1, 2, 3])).toBe(3) +}) diff --git a/source/lastIndexOf.d.ts b/source/lastIndexOf.d.ts new file mode 100644 index 00000000..2cdf2273 --- /dev/null +++ b/source/lastIndexOf.d.ts @@ -0,0 +1 @@ +export { lastIndexOf } from '../files/index' diff --git a/source/lastIndexOf.spec.ts b/source/lastIndexOf.spec.ts new file mode 100644 index 00000000..740182a9 --- /dev/null +++ b/source/lastIndexOf.spec.ts @@ -0,0 +1,31 @@ +import { lastIndexOf } from './lastIndexOf' +import { pipe } from './pipe' + +test('with NaN', () => { + expect(lastIndexOf(Number.NaN)([Number.NaN])).toBe(0) +}) + +test('without list of objects - no R.equals', () => { + expect(lastIndexOf(3)([1, 2, 3, 4])).toBe(2) + expect(lastIndexOf(10)([1, 2, 3, 4])).toBe(-1) +}) + +test('list of objects uses R.equals', () => { + const listOfObjects = [{ a: 1 }, { b: 2 }, { c: 3 }] + expect(lastIndexOf({ c: 4 })(listOfObjects)).toBe(-1) + expect(lastIndexOf({ c: 3 })(listOfObjects)).toBe(2) +}) + +test('list of arrays uses R.equals', () => { + const listOfLists = [[1], [2, 3], [2, 3, 4], [2, 3], [1], []] + expect(lastIndexOf([])(listOfLists)).toBe(5) + expect(lastIndexOf([1])(listOfLists)).toBe(4) + expect(lastIndexOf([2, 3, 4])(listOfLists)).toBe(2) + expect(lastIndexOf([2, 3, 5])(listOfLists)).toBe(-1) +}) + +test('type test', () => { + const result = pipe([{ a: 1 }, { a: 2 }, { a: 3 }], lastIndexOf({ a: 2 })) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(1) +}) diff --git a/source/map.d.ts b/source/map.d.ts new file mode 100644 index 00000000..813dfb3f --- /dev/null +++ b/source/map.d.ts @@ -0,0 +1 @@ +export { map } from '../files/index' diff --git a/source/map.spec.ts b/source/map.spec.ts new file mode 100644 index 00000000..d59f306c --- /dev/null +++ b/source/map.spec.ts @@ -0,0 +1,15 @@ +import { map } from './map' +import { pipe } from './pipe' + +const double = (x: number) => x * 2 + +test('happy', () => { + expect(map(double)([1, 2, 3])).toEqual([2, 4, 6]) +}) + +test('type test', () => { + const list = [1, 2, 3] + const result = pipe(list, x => x, map(x => String(x))) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['1', '2', '3']) +}) diff --git a/source/mapAsync.d.ts b/source/mapAsync.d.ts new file mode 100644 index 00000000..b4f53f0d --- /dev/null +++ b/source/mapAsync.d.ts @@ -0,0 +1 @@ +export { mapAsync } from '../files/index' diff --git a/source/mapAsync.spec.ts b/source/mapAsync.spec.ts new file mode 100644 index 00000000..51807a6a --- /dev/null +++ b/source/mapAsync.spec.ts @@ -0,0 +1,65 @@ +import { delay } from './delay' +import { map } from './map' +import { mapAsync } from './mapAsync' +import { pipeAsync } from './pipeAsync' + +const rejectDelay = (a: number) => + new Promise((_, reject) => { + setTimeout(() => { + reject(a + 20) + }, 100) + }) + +test('happy', async () => { + const indexes: number[] = [] + const fn = async (x: number, prop: number) => { + await delay(100) + indexes.push(prop) + return x + 1 + } + const result = await mapAsync(fn)([1, 2, 3]) + expect(result).toEqual([2, 3, 4]) + expect(indexes).toEqual([0, 1, 2]) +}) + +test('with R.pipeAsync', async () => { + const fn = async (x: number) => x + 1 + const result = await pipeAsync( + [1, 2, 3], + map(x => x + 1), + mapAsync(async x => { + await delay(x) + return x + }), + mapAsync(fn), + map(x => x * 10), + ) + expect(result).toEqual([30, 40, 50]) +}) + +test('error', async () => { + try { + await mapAsync(rejectDelay)([1, 2, 3]) + } catch (err) { + expect(err).toBe(21) + } +}) + +test('type test', async () => { + const list = ['a', 'bc', 'def'] + const result = await pipeAsync( + list, + mapAsync(async x => { + await delay(100) + return x.length % 2 ? x.length + 1 : x.length + 10 + }), + x => x, + map(x => x + 1), + mapAsync(async x => { + await delay(100) + return x + 1 + }), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([4, 14, 6]) +}) diff --git a/source/mapChain.d.ts b/source/mapChain.d.ts new file mode 100644 index 00000000..4c1b998b --- /dev/null +++ b/source/mapChain.d.ts @@ -0,0 +1 @@ +export { mapChain } from '../files/index' diff --git a/source/mapChain.spec.ts b/source/mapChain.spec.ts new file mode 100644 index 00000000..79f5afb2 --- /dev/null +++ b/source/mapChain.spec.ts @@ -0,0 +1,21 @@ +import { mapChain } from './mapChain' +import { pipe } from './pipe' + +const double = (x: number) => x * 2 + +test('happy', () => { + expect(mapChain(double, double, double)([1, 2, 3])).toEqual([8, 16, 24]) +}) + +test('type test', () => { + const list = [1, 2, 3] + const result = pipe( + list, + mapChain( + x => String(x), + x => x !== 'foo', + ), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([true, true, true]) +}) diff --git a/source/mapKeys.d.ts b/source/mapKeys.d.ts new file mode 100644 index 00000000..fda5b38f --- /dev/null +++ b/source/mapKeys.d.ts @@ -0,0 +1 @@ +export { mapKeys } from '../files/index' diff --git a/source/mapKeys.spec.ts b/source/mapKeys.spec.ts new file mode 100644 index 00000000..439d3b93 --- /dev/null +++ b/source/mapKeys.spec.ts @@ -0,0 +1,18 @@ +import { mapKeys } from './mapKeys' +import { pipe } from './pipe' + +test('happy', () => { + const result = mapKeys((prop: string, x: number) => `${prop}-${x}`)({ a: 1, b: 2 }) + const expected = { 'a-1': 1, 'b-2': 2 } + expect(result).toEqual(expected) +}) + +test('type test', () => { + const result = pipe( + { a: 1, b: 2 }, + mapKeys((prop, x) => `${prop}-${x}`), + mapKeys(prop => `${prop}-${prop}`), + ) + expectTypeOf(result).toEqualTypeOf>() + expect(result).toEqual({ 'a-1-a-1': 1, 'b-2-b-2': 2 }) +}) diff --git a/source/mapObject.d.ts b/source/mapObject.d.ts new file mode 100644 index 00000000..b048a39e --- /dev/null +++ b/source/mapObject.d.ts @@ -0,0 +1 @@ +export { mapObject } from '../files/index' diff --git a/source/mapObject.spec.ts b/source/mapObject.spec.ts new file mode 100644 index 00000000..a251f727 --- /dev/null +++ b/source/mapObject.spec.ts @@ -0,0 +1,14 @@ +import { mapObject } from './mapObject' +import { pipe } from './pipe' + +const double = (x: number) => x * 2 + +test('happy', () => { + expect(mapObject(double)({ a: 1, b: 2, c: 3 })).toEqual({ a: 2, b: 4, c: 6 }) +}) + +test('type test', () => { + const result = pipe({ a: 1 }, mapObject(a => `${a}`)) + expectTypeOf(result).toEqualTypeOf<{ a: string }>() + expect(result).toEqual({ a: '1' }) +}) diff --git a/source/mapObjectAsync.d.ts b/source/mapObjectAsync.d.ts new file mode 100644 index 00000000..a1b6bd83 --- /dev/null +++ b/source/mapObjectAsync.d.ts @@ -0,0 +1 @@ +export { mapObjectAsync } from '../files/index' diff --git a/source/mapObjectAsync.spec.ts b/source/mapObjectAsync.spec.ts new file mode 100644 index 00000000..2eab5d5a --- /dev/null +++ b/source/mapObjectAsync.spec.ts @@ -0,0 +1,35 @@ +import { delay } from './delay' +import { mapObjectAsync } from './mapObjectAsync' +import { pipeAsync } from './pipeAsync' + +test('happy', async () => { + const indexes: string[] = [] + const result = await pipeAsync( + { a: 1, b: 2 }, + mapObjectAsync(async (x, i) => { + await delay(100) + indexes.push(i) + return x + 1 + }), + ) + expect(indexes).toEqual(['a', 'b']) + expect(result).toEqual({ a: 2, b: 3 }) +}) + +test('type test', async () => { + const result = await pipeAsync( + { a: 'foo', b: 'bar' }, + mapObjectAsync(async x => { + await delay(100) + return x.length % 2 ? x.length + 1 : x.length + 10 + }), + x => x, + mapObjectAsync(async x => { + await delay(100) + return x + 1 + }), + ) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expect(result).toEqual({ a: 5, b: 5 }) +}) diff --git a/source/mapParallelAsync.d.ts b/source/mapParallelAsync.d.ts new file mode 100644 index 00000000..49a55de3 --- /dev/null +++ b/source/mapParallelAsync.d.ts @@ -0,0 +1 @@ +export { mapParallelAsync } from '../files/index' diff --git a/source/mapParallelAsync.spec.ts b/source/mapParallelAsync.spec.ts new file mode 100644 index 00000000..6cb9875c --- /dev/null +++ b/source/mapParallelAsync.spec.ts @@ -0,0 +1,38 @@ +import { pipeAsync } from './pipeAsync' +import { delay } from './delay' +import { mapParallelAsync } from './mapParallelAsync' + +test('happy', async () => { + const fn = async (x: number, i: number) => { + await delay(100) + return x + i + } + const result = await mapParallelAsync(fn)([1, 2, 3]) + expect(result).toEqual([1, 3, 5]) +}) + +test('pipeAsync', async () => { + const result = await pipeAsync( + [1, 2, 3], + mapParallelAsync(async x => { + await delay(100) + return x + 1 + }) + ) + expect(result).toEqual([2, 3, 4]) +}) + +test('with batchSize', async () => { + const fn = async (x: number, i: number) => { + await delay(100) + return `${x}:${i}` + } + const result = await mapParallelAsync(fn, 2)([1, 2, 3, 4, 5]) + expect(result).toEqual(['1:0', '2:1', '3:2', '4:3', '5:4']) +}) + +test('type test', async () => { + const result = await mapParallelAsync(async (x: number) => x + 1)([1, 2, 3]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([2, 3, 4]) +}) diff --git a/source/mapPropObject.d.ts b/source/mapPropObject.d.ts new file mode 100644 index 00000000..445d4bef --- /dev/null +++ b/source/mapPropObject.d.ts @@ -0,0 +1 @@ +export { mapPropObject } from '../files/index' diff --git a/source/mapPropObject.spec.ts b/source/mapPropObject.spec.ts new file mode 100644 index 00000000..b3feb8fb --- /dev/null +++ b/source/mapPropObject.spec.ts @@ -0,0 +1,28 @@ +import { mapPropObject } from './mapPropObject' +import { pipe } from './pipe' + +const fn = (x: number) => ({ a: x, flag: x > 2 }) + +test('happy', () => { + const result = (pipe as any)( + { a: [1, 2, 3], b: 'foo' }, + (mapPropObject as any)(fn, 'a'), + ) + expect(result).toEqual({ + a: [ + { a: 1, flag: false }, + { a: 2, flag: false }, + { a: 3, flag: true }, + ], + b: 'foo', + }) +}) + +test('type test', () => { + const result = pipe( + { a: [1, 2, 3], b: 'foo' }, + mapPropObject('a', fn), + ) + expectTypeOf(result.a).toEqualTypeOf<{ a: number; flag: boolean }[]>() + expectTypeOf(result.b).toEqualTypeOf() +}) diff --git a/source/match.d.ts b/source/match.d.ts new file mode 100644 index 00000000..84b09a37 --- /dev/null +++ b/source/match.d.ts @@ -0,0 +1 @@ +export { match } from '../files/index' diff --git a/source/match.spec.ts b/source/match.spec.ts new file mode 100644 index 00000000..842584e8 --- /dev/null +++ b/source/match.spec.ts @@ -0,0 +1,20 @@ +import { match } from './match' + +test('happy', () => { + expect(match(/a./g)('foo bar baz')).toEqual(['ar', 'az']) +}) + +test('fallback', () => { + expect(match(/a./g)('foo')).toEqual([]) +}) + +test('with string', () => { + expect(match('a')('foo')).toEqual([]) +}) + +test('type test', () => { + const str = 'foo bar' + const result = match(/foo/)(str) + expectTypeOf(result).toEqualTypeOf() + expect(result).toContain('foo') +}) diff --git a/source/maxBy.d.ts b/source/maxBy.d.ts new file mode 100644 index 00000000..4599ae24 --- /dev/null +++ b/source/maxBy.d.ts @@ -0,0 +1 @@ +export { maxBy } from '../files/index' diff --git a/source/maxBy.spec.ts b/source/maxBy.spec.ts new file mode 100644 index 00000000..bad5e606 --- /dev/null +++ b/source/maxBy.spec.ts @@ -0,0 +1,15 @@ +import { maxBy } from './maxBy' +import { pipe } from './pipe' + +test('happy', () => { + expect(maxBy(Math.abs, 2)(-5)).toBe(-5) + expect(maxBy(Math.abs, -5)(2)).toBe(-5) +}) + +test('type test', () => { + const first = 1 + const second = 2 + const result = pipe(second, maxBy(x => (x % 2 === 0 ? 1 : -1), first)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/merge.d.ts b/source/merge.d.ts new file mode 100644 index 00000000..581e5f49 --- /dev/null +++ b/source/merge.d.ts @@ -0,0 +1 @@ +export { merge } from '../files/index' diff --git a/source/merge.spec.ts b/source/merge.spec.ts new file mode 100644 index 00000000..4e720437 --- /dev/null +++ b/source/merge.spec.ts @@ -0,0 +1,15 @@ +import { merge } from './merge' +import { mergeTypes } from './mergeTypes' +import { pipe } from './pipe' + +test('happy', () => { + const obj = { foo: 1, bar: 2 } + expect(merge(obj)({ bar: 20 })).toEqual({ foo: 1, bar: 20 }) +}) + +test('type test', () => { + const result = pipe({ foo: 1 }, merge({ bar: 2 }), mergeTypes) + expectTypeOf(result.foo).toEqualTypeOf() + expectTypeOf(result.bar).toEqualTypeOf() + expect(result).toEqual({ foo: 1, bar: 2 }) +}) diff --git a/source/mergeDeep.d.ts b/source/mergeDeep.d.ts new file mode 100644 index 00000000..bfeb05e7 --- /dev/null +++ b/source/mergeDeep.d.ts @@ -0,0 +1 @@ +export { mergeDeep } from '../files/index' diff --git a/source/mergeDeep.spec.ts b/source/mergeDeep.spec.ts new file mode 100644 index 00000000..22e908bc --- /dev/null +++ b/source/mergeDeep.spec.ts @@ -0,0 +1,15 @@ +import { mergeDeep } from './mergeDeep' + +test('happy', () => { + const source = { a: 1, b: [1, 2], c: { d: 1, f: 2, e: [1, 2], h: [1, 2] } } + const objectWithNewProps = { b: [3], c: { f: 3, s: 3, e: [3] }, q: 3 } + expect(mergeDeep(source)(objectWithNewProps)).toEqual({ + a: 1, b: [3], c: { d: 1, f: 3, e: [3], h: [1, 2], s: 3 }, q: 3, + }) +}) + +test('type test', () => { + const result = mergeDeep({ a: 1 })({ b: 2 }) + expectTypeOf(result).toEqualTypeOf<{ a: number; b: number }>() + expect(result).toEqual({ a: 1, b: 2 }) +}) diff --git a/source/mergeTypes.d.ts b/source/mergeTypes.d.ts new file mode 100644 index 00000000..15489865 --- /dev/null +++ b/source/mergeTypes.d.ts @@ -0,0 +1 @@ +export { mergeTypes } from '../files/index' diff --git a/source/middle.d.ts b/source/middle.d.ts new file mode 100644 index 00000000..1b2f413a --- /dev/null +++ b/source/middle.d.ts @@ -0,0 +1 @@ +export { middle } from '../files/index' diff --git a/source/middle.spec.ts b/source/middle.spec.ts new file mode 100644 index 00000000..b7e9d14e --- /dev/null +++ b/source/middle.spec.ts @@ -0,0 +1,19 @@ +import { middle } from './middle' + +test('middle', () => { + expect(middle([1, 2, 3])).toEqual([2]) + expect(middle([1, 2])).toEqual([]) + expect(middle([1])).toEqual([]) + expect(middle([])).toEqual([]) + expect(middle('abc')).toBe('b') + expect(middle('ab')).toBe('') + expect(middle('a')).toBe('') + expect(middle('')).toBe('') +}) + +test('type test', () => { + expectTypeOf(middle('foo')).toEqualTypeOf() + expectTypeOf(middle('')).toEqualTypeOf() + expectTypeOf(middle(['foo', 'bar', 1, 2, 3])).toEqualTypeOf<(string | number)[]>() + expect(middle('abc')).toBe('b') +}) diff --git a/source/minBy.d.ts b/source/minBy.d.ts new file mode 100644 index 00000000..cd0fb1ed --- /dev/null +++ b/source/minBy.d.ts @@ -0,0 +1 @@ +export { minBy } from '../files/index' diff --git a/source/minBy.spec.ts b/source/minBy.spec.ts new file mode 100644 index 00000000..83165051 --- /dev/null +++ b/source/minBy.spec.ts @@ -0,0 +1,12 @@ +import { minBy } from './minBy' + +test('happy', () => { + expect(minBy(Math.abs, -5)(2)).toBe(2) + expect(minBy(Math.abs, 2)(-5)).toBe(2) +}) + +test('type test', () => { + const result = minBy(Math.abs, -5)(2) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/modifyItemAtIndex.d.ts b/source/modifyItemAtIndex.d.ts new file mode 100644 index 00000000..12e7f33c --- /dev/null +++ b/source/modifyItemAtIndex.d.ts @@ -0,0 +1 @@ +export { modifyItemAtIndex } from '../files/index' diff --git a/source/modifyItemAtIndex.spec.ts b/source/modifyItemAtIndex.spec.ts new file mode 100644 index 00000000..4ef4f912 --- /dev/null +++ b/source/modifyItemAtIndex.spec.ts @@ -0,0 +1,22 @@ +import { modifyItemAtIndex } from './modifyItemAtIndex' + +const add10 = (x: number) => x + 10 + +test('happy', () => { + expect(modifyItemAtIndex(1, add10)([0, 1, 2])).toEqual([0, 11, 2]) +}) + +test('with negative index', () => { + expect(modifyItemAtIndex(-2, add10)([0, 1, 2])).toEqual([0, 11, 2]) +}) + +test('when index is out of bounds', () => { + expect(modifyItemAtIndex(4, add10)([0, 1, 2, 3])).toEqual([0, 1, 2, 3]) + expect(modifyItemAtIndex(-5, add10)([0, 1, 2, 3])).toEqual([0, 1, 2, 3]) +}) + +test('type test', () => { + const result = modifyItemAtIndex(1, add10)([0, 1, 2]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([0, 11, 2]) +}) diff --git a/source/modifyPath.d.ts b/source/modifyPath.d.ts new file mode 100644 index 00000000..80cedb5d --- /dev/null +++ b/source/modifyPath.d.ts @@ -0,0 +1 @@ +export { modifyPath } from '../files/index' diff --git a/source/modifyPath.spec.ts b/source/modifyPath.spec.ts new file mode 100644 index 00000000..54699dde --- /dev/null +++ b/source/modifyPath.spec.ts @@ -0,0 +1,20 @@ +import { modifyPath } from './modifyPath' +import { pipe } from './pipe' + +const obj = { a: { b: { c: 1 } } } + +test('happy', () => { + const result = modifyPath('a.b.c', (x: number) => x + 1)(obj) + expect(result).toEqual({ a: { b: { c: 2 } } }) +}) + +test('works only on existing paths', () => { + const result = modifyPath('a.b.d', (x: number) => x + 1)(obj) + expect(result).toEqual(obj) +}) + +test('type test', () => { + const result = pipe(obj, modifyPath(['a', 'b', 'c'], (x: number) => String(x))) + expectTypeOf(result.a.b.c).toEqualTypeOf() + expect(result).toEqual({ a: { b: { c: '1' } } }) +}) diff --git a/source/modifyProp.d.ts b/source/modifyProp.d.ts new file mode 100644 index 00000000..ca8274b7 --- /dev/null +++ b/source/modifyProp.d.ts @@ -0,0 +1 @@ +export { modifyProp } from '../files/index' diff --git a/source/modifyProp.spec.ts b/source/modifyProp.spec.ts new file mode 100644 index 00000000..b73914c9 --- /dev/null +++ b/source/modifyProp.spec.ts @@ -0,0 +1,22 @@ +import { modifyProp } from './modifyProp' +import { pipe } from './pipe' + +const person = { name: 'foo', age: 20 } + +test('happy', () => { + expect(modifyProp('age', (x: number) => x + 1)(person)).toEqual({ name: 'foo', age: 21 }) +}) + +test('property is missing', () => { + expect(modifyProp('foo', (x: number) => x + 1)(person)).toEqual(person) +}) + +test('adjust if `array` at the given key', () => { + expect(modifyProp(1, (x: number) => x + 1)([100, 1400])).toEqual([100, 1401]) +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 2, c: { d: 3 } }, modifyProp('a', val => val + 1)) + expectTypeOf(result).toEqualTypeOf<{ a: number; b: number; c: { d: number } }>() + expect(result).toEqual({ a: 2, b: 2, c: { d: 3 } }) +}) diff --git a/source/none.d.ts b/source/none.d.ts new file mode 100644 index 00000000..68d6b9ae --- /dev/null +++ b/source/none.d.ts @@ -0,0 +1 @@ +export { none } from '../files/index' diff --git a/source/none.spec.ts b/source/none.spec.ts new file mode 100644 index 00000000..05af66ce --- /dev/null +++ b/source/none.spec.ts @@ -0,0 +1,18 @@ +import { none } from './none' +import { pipe } from './pipe' + +const isEven = (n: number) => n % 2 === 0 + +test('when true', () => { + expect(none(isEven)([1, 3, 5, 7])).toBeTruthy() +}) + +test('when false', () => { + expect(none((input: number) => input > 1)([1, 2, 3])).toBeFalsy() +}) + +test('type test', () => { + const result = pipe([1, 2, 3], none(x => x > 0)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeFalsy() +}) diff --git a/source/objOf.d.ts b/source/objOf.d.ts new file mode 100644 index 00000000..4ef0874e --- /dev/null +++ b/source/objOf.d.ts @@ -0,0 +1 @@ +export { objOf } from '../files/index' diff --git a/source/objOf.spec.ts b/source/objOf.spec.ts new file mode 100644 index 00000000..a44d5224 --- /dev/null +++ b/source/objOf.spec.ts @@ -0,0 +1,12 @@ +import { objOf } from './objOf' +import { pipe } from './pipe' + +test('happy', () => { + expect(objOf('foo')(42)).toEqual({ foo: 42 }) +}) + +test('type test', () => { + const result = pipe(42, objOf('foo')) + expectTypeOf(result.foo).toEqualTypeOf() + expect(result).toEqual({ foo: 42 }) +}) diff --git a/source/objectIncludes.d.ts b/source/objectIncludes.d.ts new file mode 100644 index 00000000..9d54ded2 --- /dev/null +++ b/source/objectIncludes.d.ts @@ -0,0 +1 @@ +export { objectIncludes } from '../files/index' diff --git a/source/objectIncludes.spec.ts b/source/objectIncludes.spec.ts new file mode 100644 index 00000000..e03d028c --- /dev/null +++ b/source/objectIncludes.spec.ts @@ -0,0 +1,31 @@ +import { objectIncludes } from './objectIncludes' +import { pipe } from './pipe' + +test('when true', () => { + const condition = { a: 1 } + const input = { a: 1, b: 2 } + expect(objectIncludes(condition)(input)).toBeTruthy() +}) + +test('when false', () => { + const condition = { a: 1 } + const input = { b: 2 } + expect(objectIncludes(condition)(input)).toBeFalsy() +}) + +test('with nested object', () => { + const condition = { a: { b: 1 } } + const input = { a: { b: 1 }, c: 2 } + expect(objectIncludes(condition)(input)).toBeTruthy() +}) + +test('with wrong input', () => { + const condition = { a: { b: 1 } } + expect(() => objectIncludes(condition)(null)).toThrow() +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 2, c: { d: 3 } }, objectIncludes({ a: 2 })) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeFalsy() +}) diff --git a/source/omit.d.ts b/source/omit.d.ts new file mode 100644 index 00000000..d7880724 --- /dev/null +++ b/source/omit.d.ts @@ -0,0 +1 @@ +export { omit } from '../files/index' diff --git a/source/omit.spec.ts b/source/omit.spec.ts new file mode 100644 index 00000000..7d7aa725 --- /dev/null +++ b/source/omit.spec.ts @@ -0,0 +1,18 @@ +import { omit } from './omit' +import { pipe } from './pipe' + +test('with string as condition', () => { + const obj = { a: 1, b: 2, c: 3 } + expect(omit('a,c')(obj)).toEqual({ b: 2 }) +}) + +test('with array as condition', () => { + expect(omit(['a', 'c', 'd'])({ a: 'foo', b: 'bar', c: 'baz' })).toEqual({ b: 'bar' }) +}) + +test('type test', () => { + const input = { a: 'foo', b: 2, c: 3 } + const result = pipe(input, omit('a,b')) + expectTypeOf(result.c).toEqualTypeOf() + expect(result).toEqual({ c: 3 }) +}) diff --git a/source/partition.d.ts b/source/partition.d.ts new file mode 100644 index 00000000..77401274 --- /dev/null +++ b/source/partition.d.ts @@ -0,0 +1 @@ +export { partition } from '../files/index' diff --git a/source/partition.spec.ts b/source/partition.spec.ts new file mode 100644 index 00000000..8f87479d --- /dev/null +++ b/source/partition.spec.ts @@ -0,0 +1,16 @@ +import { partition } from './partition' +import { pipe } from './pipe' + +test('happy', () => { + const list = [1, 2, 3] + const predicate = (x: number) => x > 2 + const result = partition(predicate)(list) + expect(result).toEqual([[3], [1, 2]]) +}) + +test('type test', () => { + const list = [1, 2, 3, 4] + const result = pipe(list, partition((x: number) => x > 2)) + expectTypeOf(result).toEqualTypeOf<[number[], number[]]>() + expect(result).toEqual([[3, 4], [1, 2]]) +}) diff --git a/source/partitionObject.d.ts b/source/partitionObject.d.ts new file mode 100644 index 00000000..fe1ff252 --- /dev/null +++ b/source/partitionObject.d.ts @@ -0,0 +1 @@ +export { partitionObject } from '../files/index' diff --git a/source/partitionObject.spec.ts b/source/partitionObject.spec.ts new file mode 100644 index 00000000..e34f34f1 --- /dev/null +++ b/source/partitionObject.spec.ts @@ -0,0 +1,15 @@ +import { partitionObject } from './partitionObject' +import { pipe } from './pipe' + +test('happy', () => { + const predicate = (value: number) => value > 2 + const hash = { a: 1, b: 2, c: 3, d: 4 } + const result = partitionObject(predicate)(hash) + expect(result).toEqual([{ c: 3, d: 4 }, { a: 1, b: 2 }]) +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 2 }, partitionObject((x, prop) => x > 1 || prop === 'c')) + expectTypeOf(result).toEqualTypeOf<[Record, Record]>() + expect(result).toEqual([{ b: 2 }, { a: 1 }]) +}) diff --git a/source/path.d.ts b/source/path.d.ts new file mode 100644 index 00000000..c5184b66 --- /dev/null +++ b/source/path.d.ts @@ -0,0 +1 @@ +export { path } from '../files/index' diff --git a/source/path.spec.ts b/source/path.spec.ts new file mode 100644 index 00000000..fff209e4 --- /dev/null +++ b/source/path.spec.ts @@ -0,0 +1,37 @@ +import { path } from './path' +import { pipe } from './pipe' + +test('with array inside object', () => { + const obj = { a: { b: [1, { c: 1 }] } } + expect(path('a.b.1.c')(obj)).toBe(1) +}) + +test('works with undefined', () => { + const obj = { a: { b: { c: 1 } } } + expect(path('a.b.c.d.f')(obj)).toBeUndefined() + expect(path('foo.babaz')(undefined)).toBeUndefined() +}) + +test('works with string instead of array', () => { + expect(path('foo.bar.baz')({ foo: { bar: { baz: 'yes' } } })).toBe('yes') +}) + +test('path', () => { + expect(path(['foo', 'bar', 'baz'])({ foo: { bar: { baz: 'yes' } } })).toBe('yes') + expect(path(['foo', 'bar', 'baz'])(null)).toBeUndefined() +}) + +test('with number string in between', () => { + expect(path(['a', '1', 'b'])({ a: [{ b: 1 }, { b: 2 }] })).toBe(2) +}) + +test('null is not a valid path', () => { + expect(path('audio_tracks')({ a: 1, audio_tracks: null })).toBeUndefined() +}) + +test('type test', () => { + const input = { a: { b: { c: true } } } + const result = pipe(input, path(['a', 'b'])) + expectTypeOf(result.c).toEqualTypeOf() + expect(result).toEqual({ c: true }) +}) diff --git a/source/pathSatisfies.d.ts b/source/pathSatisfies.d.ts new file mode 100644 index 00000000..4d80c13e --- /dev/null +++ b/source/pathSatisfies.d.ts @@ -0,0 +1 @@ +export { pathSatisfies } from '../files/index' diff --git a/source/pathSatisfies.spec.ts b/source/pathSatisfies.spec.ts new file mode 100644 index 00000000..48d08a19 --- /dev/null +++ b/source/pathSatisfies.spec.ts @@ -0,0 +1,24 @@ +import { pathSatisfies } from './pathSatisfies' +import { pipe } from './pipe' + +const isPositive = (n: number) => n > 0 + +test('returns true if the specified object path satisfies the given predicate', () => { + expect(pathSatisfies(isPositive, ['x', 'y'])({ x: { y: 1 } })).toBe(true) +}) + +test('returns false if the specified path does not exist', () => { + expect(pathSatisfies(isPositive, ['x', 'y'])({ x: { z: 42 } })).toBe(false) + expect(pathSatisfies(isPositive, 'x.y')({ x: { z: 42 } })).toBe(false) +}) + +test('returns false otherwise', () => { + expect(pathSatisfies(isPositive, ['x', 'y'])({ x: { y: 0 } })).toBe(false) +}) + +test('type test', () => { + const input = { a: { b: { c: 'bar' } } } + const result = pipe(input, pathSatisfies(x => x !== 'foo', ['a', 'b', 'c'])) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeTruthy() +}) diff --git a/source/pick.d.ts b/source/pick.d.ts new file mode 100644 index 00000000..d6a64186 --- /dev/null +++ b/source/pick.d.ts @@ -0,0 +1 @@ +export { pick } from '../files/index' diff --git a/source/pick.spec.ts b/source/pick.spec.ts new file mode 100644 index 00000000..91d37acf --- /dev/null +++ b/source/pick.spec.ts @@ -0,0 +1,24 @@ +import { pick } from './pick' +import { pipe } from './pipe' + +test('props to pick is a string', () => { + const obj = { a: 1, b: 2, c: 3 } + expect(pick('a,c')(obj)).toEqual({ a: 1, c: 3 }) +}) + +test('when prop is missing', () => { + const obj = { a: 1, b: 2, c: 3 } + expect(pick('a,d,f')(obj)).toEqual({ a: 1 }) +}) + +test('props to pick is an array', () => { + expect(pick(['a', 'c'])({ a: 'foo', b: 'bar' })).toEqual({ a: 'foo' }) +}) + +test('type test', () => { + const input = { a: 'foo', c: 3 } + const result = pipe(input, pick('a,c')) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.c).toEqualTypeOf() + expect(result).toEqual({ a: 'foo', c: 3 }) +}) diff --git a/source/pipe.d.ts b/source/pipe.d.ts new file mode 100644 index 00000000..1cb2222f --- /dev/null +++ b/source/pipe.d.ts @@ -0,0 +1 @@ +export { pipe } from '../files/index' diff --git a/source/pipe.spec.ts b/source/pipe.spec.ts new file mode 100644 index 00000000..0720b688 --- /dev/null +++ b/source/pipe.spec.ts @@ -0,0 +1,44 @@ +import { filter } from './filter' +import { map } from './map' +import { pipe } from './pipe' +import { split } from './split' + +test('happy', () => { + const result = pipe( + [1, 2, 3], + filter(x => x > 1), + map(x => x * 10), + map(x => x + 1), + ) + expect(result).toEqual([21, 31]) +}) + +test('split test', () => { + const tableData = `id,title,year +1,The First,2001 +2,The Second,2020 +3,The Third,2018` + + const result = pipe(tableData, split('\n'), map(split(','))) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([ + ['id', 'title', 'year'], + ['1', 'The First', '2001'], + ['2', 'The Second', '2020'], + ['3', 'The Third', '2018'], + ]) +}) + +test('R.pipe type test', () => { + const obj = { a: 'foo', b: 'bar' } + const result = pipe( + obj, + x => ({ a: x.a.length + x.b.length }), + x => ({ ...x, b: x.a + 'foo' }), + x => ({ ...x, c: x.b + 'bar' }), + ) + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expectTypeOf(result.c).toEqualTypeOf() + expect(result.a > 0).toBeTruthy() +}) diff --git a/source/pipeAsync.d.ts b/source/pipeAsync.d.ts new file mode 100644 index 00000000..535ab6a9 --- /dev/null +++ b/source/pipeAsync.d.ts @@ -0,0 +1 @@ +export { pipeAsync } from '../files/index' diff --git a/source/pipeAsync.spec.ts b/source/pipeAsync.spec.ts new file mode 100644 index 00000000..a9919611 --- /dev/null +++ b/source/pipeAsync.spec.ts @@ -0,0 +1,26 @@ +import { delay } from './delay' +import { pipeAsync } from './pipeAsync' + +const fn1 = (x: number) => Promise.resolve(x + 2) +const fn2 = async (x: number) => { + await delay(1) + return x + 3 +} + +test('happy', async () => { + const result = await pipeAsync(1, fn1, x => x + 2, fn2) + expect(result).toBe(8) +}) + +test('type test', async () => { + const result = await pipeAsync( + 4, + async x => { + await delay(100) + return x + 1 + }, + x => Promise.resolve([x]), + ) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([5]) +}) diff --git a/source/pluck.d.ts b/source/pluck.d.ts new file mode 100644 index 00000000..bd3b5a88 --- /dev/null +++ b/source/pluck.d.ts @@ -0,0 +1 @@ +export { pluck } from '../files/index' diff --git a/source/pluck.spec.ts b/source/pluck.spec.ts new file mode 100644 index 00000000..7dc3f794 --- /dev/null +++ b/source/pluck.spec.ts @@ -0,0 +1,17 @@ +import { pluck } from './pluck' +import { pipe } from './pipe' + +test('happy', () => { + expect(pluck('a')([{ a: 1 }, { a: 2 }, { b: 1 }])).toEqual([1, 2]) +}) + +test('with undefined', () => { + expect(pluck(undefined)([{ a: 1 }, { a: 2 }, { b: 1 }])).toEqual([]) +}) + +test('type test', () => { + const input = [{ a: 1, b: 'foo' }, { a: 2, b: 'bar' }] + const result = pipe(input, pluck('b')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['foo', 'bar']) +}) diff --git a/source/prepend.d.ts b/source/prepend.d.ts new file mode 100644 index 00000000..39671fa9 --- /dev/null +++ b/source/prepend.d.ts @@ -0,0 +1 @@ +export { prepend } from '../files/index' diff --git a/source/prepend.spec.ts b/source/prepend.spec.ts new file mode 100644 index 00000000..c3dfeb47 --- /dev/null +++ b/source/prepend.spec.ts @@ -0,0 +1,15 @@ +import { prepend } from './prepend' + +test('happy', () => { + expect(prepend('yes')(['foo', 'bar', 'baz'])).toEqual(['yes', 'foo', 'bar', 'baz']) +}) + +test('with empty list', () => { + expect(prepend('foo')([])).toEqual(['foo']) +}) + +test('type test', () => { + const result = prepend('yes')(['foo', 'bar', 'baz']) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['yes', 'foo', 'bar', 'baz']) +}) diff --git a/source/prop.d.ts b/source/prop.d.ts new file mode 100644 index 00000000..480202ab --- /dev/null +++ b/source/prop.d.ts @@ -0,0 +1 @@ +export { prop } from '../files/index' diff --git a/source/prop.spec.ts b/source/prop.spec.ts new file mode 100644 index 00000000..f3254c9b --- /dev/null +++ b/source/prop.spec.ts @@ -0,0 +1,8 @@ +import { prop } from './prop' +import { pipe } from './pipe' + +test('type test', () => { + const result = pipe({ a: 1 }, prop('a')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(1) +}) diff --git a/source/propEq.d.ts b/source/propEq.d.ts new file mode 100644 index 00000000..d5053e2e --- /dev/null +++ b/source/propEq.d.ts @@ -0,0 +1 @@ +export { propEq } from '../files/index' diff --git a/source/propEq.spec.ts b/source/propEq.spec.ts new file mode 100644 index 00000000..54a2a765 --- /dev/null +++ b/source/propEq.spec.ts @@ -0,0 +1,24 @@ +import { propEq } from './propEq' +import { pipe } from './pipe' + +const FOO = 'foo' +const BAR = 'bar' + +test('happy', () => { + const obj = { [FOO]: BAR } + expect(propEq(BAR, FOO)(obj)).toBeTruthy() + expect(propEq(1, FOO)(obj)).toBeFalsy() + expect(propEq(1, 1)(null)).toBeFalsy() +}) + +test('returns false if called with a null or undefined object', () => { + expect(propEq('name', 'Abby')(null)).toBeFalsy() + expect(propEq('name', 'Abby')(undefined)).toBeFalsy() +}) + +test('type test', () => { + const obj = { foo: 'bar' } + const result = pipe(obj, propEq('bar', 'foo')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeTruthy() +}) diff --git a/source/propOr.d.ts b/source/propOr.d.ts new file mode 100644 index 00000000..dbd25e64 --- /dev/null +++ b/source/propOr.d.ts @@ -0,0 +1 @@ +export { propOr } from '../files/index' diff --git a/source/propOr.spec.ts b/source/propOr.spec.ts new file mode 100644 index 00000000..18810333 --- /dev/null +++ b/source/propOr.spec.ts @@ -0,0 +1,15 @@ +import { propOr } from './propOr' + +test('propOr', () => { + const obj = { a: 1 } + expect(propOr('a', 'default')(obj)).toBe(1) + expect(propOr('notExist', 'default')(obj)).toBe('default') + expect(propOr('notExist', 'default')(null)).toBe('default') +}) + +test('type test', () => { + const obj = { foo: 'bar' } + const result = propOr('foo', 'fallback')(obj) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('bar') +}) diff --git a/source/propSatisfies.d.ts b/source/propSatisfies.d.ts new file mode 100644 index 00000000..d6f50632 --- /dev/null +++ b/source/propSatisfies.d.ts @@ -0,0 +1 @@ +export { propSatisfies } from '../files/index' diff --git a/source/propSatisfies.spec.ts b/source/propSatisfies.spec.ts new file mode 100644 index 00000000..230f1337 --- /dev/null +++ b/source/propSatisfies.spec.ts @@ -0,0 +1,16 @@ +import { propSatisfies } from './propSatisfies' +import { pipe } from './pipe' + +test('when true', () => { + expect(propSatisfies(x => x > 0, 'a')({ a: 1 })).toBeTruthy() +}) + +test('when false', () => { + expect(propSatisfies(x => x < 0, 'a')({ a: 1 })).toBeFalsy() +}) + +test('type test', () => { + const result = pipe({ a: 1 }, propSatisfies(x => x > 0, 'a')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBeTruthy() +}) diff --git a/source/radashi-comparison-spec.ts b/source/radashi-comparison-spec.ts new file mode 100644 index 00000000..6c7a44f2 --- /dev/null +++ b/source/radashi-comparison-spec.ts @@ -0,0 +1,298 @@ +import { + filter, + find, + groupBy, + indexBy, + omit, + pick, + pipe, + sortBy, + sum, + uniq, + zip, +} from 'rambda' +import { describe, expectTypeOf, it } from 'vitest' +import { + chain as radashiChain, + group as radashiGroup, + objectify as radashiObjectify, + omit as radashiOmit, + pick as radashiPick, + select as radashiSelect, + selectFirst as radashiSelectFirst, + sort as radashiSort, + sum as radashiSum, + unique as radashiUnique, + zip as radashiZip, +} from 'radashi' + +describe('Radashi vs Rambda: API design', () => { + it('Radashi is data-first, Rambda is curried data-last', () => { + const items = [3, 1, 2] + + // Radashi: data-first, all args at once + const radashiResult = radashiSort(items, x => x) + expectTypeOf(radashiResult).toEqualTypeOf() + + // Rambda: curried data-last, designed for pipe + const rambdaResult = pipe(items, sortBy(x => x)) + expectTypeOf(rambdaResult).toEqualTypeOf() + }) +}) + +describe('Radashi vs Rambda: selectFirst vs find (type guard narrowing)', () => { + it('Rambda find supports type guard narrowing; Radashi selectFirst does not', () => { + const items = ['hello', 'world', 42] as (string | number)[] + + const radashiResult = radashiSelectFirst( + items, + x => String(x), + (x): x is string => typeof x === 'string', + ) + // Radashi condition is typed as (item: T, index: number) => boolean + // No type guard overload — result is still string | undefined + // because mapper returns string for all T, and condition narrows runtime only + expectTypeOf(radashiResult).toEqualTypeOf() + + const rambdaResult = pipe( + items, + find((x): x is string => typeof x === 'string'), + ) + // Rambda find has type guard overload: predicate(value is S) => S | undefined + expectTypeOf(rambdaResult).toEqualTypeOf() + }) +}) + +describe('Radashi vs Rambda: select vs filter (type guard narrowing)', () => { + it('Rambda filter supports type guard narrowing; Radashi select does not', () => { + interface Foo { a: number } + interface Bar extends Foo { b: string } + const items = [{ a: 1 }, { a: 2, b: 'x' }] as (Foo | Bar)[] + + const radashiResult = radashiSelect( + items, + x => x, + (x): x is Bar => 'b' in x, + ) + // Radashi condition is (item: T, index: number) => boolean — no narrowing + // Result type is (Foo | Bar)[] because condition doesn't narrow + expectTypeOf(radashiResult).toEqualTypeOf<(Foo | Bar)[]>() + + const rambdaResult = pipe( + items, + filter((x): x is Bar => 'b' in x), + ) + // Rambda filter supports type guard → Bar[] + expectTypeOf(rambdaResult).toEqualTypeOf() + }) +}) + +describe('Radashi vs Rambda: group vs groupBy (partial records)', () => { + it('Both return Partial>', () => { + const items = [ + { category: 'a', val: 1 }, + { category: 'b', val: 2 }, + { category: 'a', val: 3 }, + ] + + const radashiResult = radashiGroup(items, x => x.category) + // Radashi: { [K in Key]?: T[] } — equivalent to Partial> + expectTypeOf(radashiResult).toEqualTypeOf< + Partial> + >() + + const rambdaResult = pipe(items, groupBy(x => x.category)) + // Rambda: Partial> where K extends string + expectTypeOf(rambdaResult).toEqualTypeOf< + Partial> + >() + }) + + it('Both allow number/symbol keys via groupBy', () => { + const items = [1, 2, 3, 4] + + const radashiResult = radashiGroup(items, n => (n % 2 === 0 ? 'even' : 'odd')) + expectTypeOf(radashiResult).toEqualTypeOf< + Partial> + >() + }) +}) + +describe('Radashi vs Rambda: objectify vs indexBy (key inference)', () => { + it('Radashi objectify infers literal keys; Rambda indexBy returns wide Record', () => { + const list = [ + { id: 'a' as const, name: 'Alice' }, + { id: 'b' as const, name: 'Bob' }, + ] + + // Radashi objectify: Record with inferred literal keys + const radashiResult = radashiObjectify(list, x => x.id) + expectTypeOf(radashiResult).toEqualTypeOf< + Record<'a' | 'b', { id: 'a' | 'b'; name: string }> + >() + + // Rambda indexBy: takes property key string, returns Record + const rambdaResult = indexBy('id')(list) + expectTypeOf(rambdaResult).toEqualTypeOf< + Record + >() + }) + + it('Radashi objectify supports value mapper', () => { + const list = [ + { id: 'a' as const, name: 'Alice' }, + { id: 'b' as const, name: 'Bob' }, + ] + + // Radashi: objectify(array, getKey, getValue?) — can map values too + const radashiResult = radashiObjectify(list, x => x.id, x => x.name) + expectTypeOf(radashiResult).toEqualTypeOf>() + + // Rambda: indexBy only indexes by property — no value mapping overload + }) +}) + +describe('Radashi vs Rambda: sort vs sortBy (comparator types)', () => { + it('Radashi sort only accepts numeric getter; Rambda sortBy accepts any Ord', () => { + const items = [{ a: 2 }, { a: 1 }, { a: 0 }] + + // Radashi sort: getter must return number + const radashiResult = radashiSort(items, x => x.a) + expectTypeOf(radashiResult).toEqualTypeOf<{ a: number }[]>() + + // Radashi sort supports boolean desc flag + const radashiDesc = radashiSort(items, x => x.a, true) + expectTypeOf(radashiDesc).toEqualTypeOf<{ a: number }[]>() + + // Rambda sortBy: getter returns any Ord (number | string | boolean | Date) + const rambdaResult = pipe(items, sortBy(x => x.a)) + expectTypeOf(rambdaResult).toEqualTypeOf<{ a: number }[]>() + }) + + it('Rambda sortBy supports string and Date comparators; Radashi sort does not', () => { + const strItems = [{ name: 'Charlie' }, { name: 'Alice' }, { name: 'Bob' }] + + const rambdaResult = pipe(strItems, sortBy(x => x.name)) + expectTypeOf(rambdaResult).toEqualTypeOf<{ name: string }[]>() + + // Radashi sort: getter must return number — would error on string + // @ts-expect-error — Radashi sort getter requires number return + radashiSort(strItems, x => x.name) + }) +}) + +describe('Radashi vs Rambda: pick (key inference)', () => { + it('Radashi pick supports predicate filter; Rambda pick supports string-path', () => { + const input = { a: 'foo', b: 2, c: 3 } as const + + // Radashi pick with key array + const radashiArray = radashiPick(input, ['a', 'c']) + expectTypeOf(radashiArray).toEqualTypeOf<{ readonly a: 'foo'; readonly c: 3 }>() + + // Radashi pick with predicate filter + const radashiPredicate = radashiPick(input, (_value, key) => key !== 'b') + expectTypeOf(radashiPredicate).toEqualTypeOf<{ readonly a: 'foo'; readonly c: 3 }>() + + // Rambda pick with array + const rambdaArray = pipe(input, pick(['a', 'c'])) + expectTypeOf(rambdaArray.a).toEqualTypeOf<'foo'>() + + // Rambda pick with string-path + const rambdaString = pipe(input, pick('a,c')) + expectTypeOf(rambdaString.a).toEqualTypeOf<'foo'>() + }) +}) + +describe('Radashi vs Rambda: omit', () => { + it('Both infer remaining keys when omitting', () => { + const input = { a: 'foo', b: 2, c: 3 } as const + + const radashiResult = radashiOmit(input, ['b']) + expectTypeOf(radashiResult).toEqualTypeOf<{ readonly a: 'foo'; readonly c: 3 }>() + + const rambdaResult = pipe(input, omit(['b'])) + expectTypeOf(rambdaResult.a).toEqualTypeOf<'foo'>() + }) +}) + +describe('Radashi vs Rambda: unique vs uniq', () => { + it('Radashi unique supports optional toKey; Rambda uniq does not', () => { + const items = [1, 2, 1, 3] + + const rambdaResult = uniq(items) + expectTypeOf(rambdaResult).toEqualTypeOf() + + // Radashi unique with optional toKey (similar to uniqBy but combined) + const radashiResult = radashiUnique(items) + expectTypeOf(radashiResult).toEqualTypeOf() + + // Radashi unique with toKey function + const objItems = [{ id: 1 }, { id: 2 }, { id: 1 }] + const radashiKeyed = radashiUnique(objItems, x => x.id) + expectTypeOf(radashiKeyed).toEqualTypeOf<{ id: number }[]>() + }) +}) + +describe('Radashi vs Rambda: sum', () => { + it('Radashi sum has mapper overload; Rambda sum only accepts number[]', () => { + const numbers = [1, 2, 3] + + const radashiResult = radashiSum(numbers) + expectTypeOf(radashiResult).toEqualTypeOf() + + const rambdaResult = sum(numbers) + expectTypeOf(rambdaResult).toEqualTypeOf() + + // Radashi sum with mapper function + const items = [{ value: 1 }, { value: 2 }] + const radashiMapped = radashiSum(items, x => x.value) + expectTypeOf(radashiMapped).toEqualTypeOf() + }) +}) + +describe('Radashi vs Rambda: zip', () => { + it('Radashi zip is variadic multi-array; Rambda zip is curried pair', () => { + const keys = ['a', 'b'] + const vals = [1, 2] + + // Radashi zip: variadic, tuple-per-element return + const radashiResult = radashiZip(keys, vals) + expectTypeOf(radashiResult).toEqualTypeOf<[string, number][]>() + + // Rambda zip: curried, returns KeyValuePair[] + const rambdaResult = zip(keys)(vals) + expectTypeOf(rambdaResult).toEqualTypeOf<[string, number][]>() + }) +}) + +describe('Radashi vs Rambda: chain vs pipe (composition arity)', () => { + it('Rambda pipe supports up to 20 operations; Radashi chain supports 10', () => { + const add1 = (x: number) => x + 1 + const double = (x: number) => x * 2 + const toString = (x: number) => String(x) + + // Radashi: chain data-first, overload-based (10 max) + const radashiChained = radashiChain(add1, double, toString) + expectTypeOf(radashiChained(0)).toEqualTypeOf() + + // Rambda: pipe data-last, variadic-tuple-based (20 overloads) + const rambdaResult = pipe(0, add1, double, toString) + expectTypeOf(rambdaResult).toEqualTypeOf() + }) +}) + +describe('Radashi vs Rambda: generic type utilities', () => { + it('Radashi exposes Simplify, IsExactType, Falsy; Rambda does not export these', () => { + // Radashi exports advanced type utilities: + // Simplify — flattens intersection types + // IsExactType — exact type equality check + // Falsy — union of all falsy values + // These are not exported from Rambda. + // Test is structural: Radashi's types are ambient, verified at compile time. + + // Radashi Falsy type = null | undefined | false | '' | 0 | 0n + // Rambda has ExcludeFalsy in filter(Boolean) but doesn't export the type + const radashiFalsy: (typeof import('radashi'))['Falsy'] = false as any + expectTypeOf(radashiFalsy).not.toEqualTypeOf() + }) +}) diff --git a/source/random.d.ts b/source/random.d.ts new file mode 100644 index 00000000..0b001ae3 --- /dev/null +++ b/source/random.d.ts @@ -0,0 +1 @@ +export { random } from '../files/index' diff --git a/source/random.spec.ts b/source/random.spec.ts new file mode 100644 index 00000000..0ac9d17c --- /dev/null +++ b/source/random.spec.ts @@ -0,0 +1,14 @@ +import { random } from './random' +import { range } from './range' + +test('happy', () => { + const results = range(0, 100).map(() => random(0, 3)) + const uniqResults = [...new Set(results)].sort() + expect(uniqResults).toEqual([0, 1, 2, 3]) +}) + +test('type test', () => { + const result = random(0, 3) + expectTypeOf(result).toEqualTypeOf() + expect(result >= 0 && result <= 3).toBeTruthy() +}) diff --git a/source/range.d.ts b/source/range.d.ts new file mode 100644 index 00000000..791c2f31 --- /dev/null +++ b/source/range.d.ts @@ -0,0 +1 @@ +export { range } from '../files/index' diff --git a/source/range.spec.ts b/source/range.spec.ts new file mode 100644 index 00000000..aa1255a2 --- /dev/null +++ b/source/range.spec.ts @@ -0,0 +1,18 @@ +import { range } from './range' + +test('happy', () => { + expect(range(5)).toEqual([0, 1, 2, 3, 4, 5]) + expect(range(3, 5)).toEqual([3, 4, 5]) + expect(range(5, 3)).toEqual([]) + expect(range(5, 5)).toEqual([5]) + expect(range(0)).toEqual([0]) + expect(range(1)).toEqual([0, 1]) + expect(range(2)).toEqual([0, 1, 2]) +}) + +test('type test', () => { + const result = [range(1, 4), range(1)] + expectTypeOf(result).toEqualTypeOf() + expect(result[0]).toEqual([1, 2, 3, 4]) + expect(result[1]).toEqual([0, 1]) +}) diff --git a/source/rangeDescending.d.ts b/source/rangeDescending.d.ts new file mode 100644 index 00000000..d748b660 --- /dev/null +++ b/source/rangeDescending.d.ts @@ -0,0 +1 @@ +export { rangeDescending } from '../files/index' diff --git a/source/rangeDescending.spec.ts b/source/rangeDescending.spec.ts new file mode 100644 index 00000000..69a6e964 --- /dev/null +++ b/source/rangeDescending.spec.ts @@ -0,0 +1,17 @@ +import { rangeDescending } from './rangeDescending' + +test('happy', () => { + expect(rangeDescending(5)).toEqual([5, 4, 3, 2, 1, 0]) + expect(rangeDescending(7, 3)).toEqual([7, 6, 5, 4, 3]) + expect(rangeDescending(0)).toEqual([0]) + expect(rangeDescending(1)).toEqual([1, 0]) + expect(rangeDescending(2)).toEqual([2, 1, 0]) + expect(rangeDescending(5, 7)).toEqual([]) + expect(rangeDescending(5, 5)).toEqual([5]) +}) + +test('type test', () => { + const result = rangeDescending(5) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([5, 4, 3, 2, 1, 0]) +}) diff --git a/source/reduce.d.ts b/source/reduce.d.ts new file mode 100644 index 00000000..3efcd21d --- /dev/null +++ b/source/reduce.d.ts @@ -0,0 +1 @@ +export { reduce } from '../files/index' diff --git a/source/reduce.spec.ts b/source/reduce.spec.ts new file mode 100644 index 00000000..e81766ee --- /dev/null +++ b/source/reduce.spec.ts @@ -0,0 +1,32 @@ +import { concat } from './concat' +import { reduce } from './reduce' +import { pipe } from './pipe' + +const reducer = (prev: number, current: number, i: number) => { + return prev + current +} +const initialValue = 1 +const list = [1, 2, 3] +const ERROR = 'reduce: list must be array or iterable' + +test('happy', () => { + expect(reduce(reducer, initialValue)(list)).toBe(7) +}) + +test('with undefined as iterable', () => { + expect(() => reduce(reducer, 0)({} as any)).toThrowError(ERROR) +}) + +test('returns the accumulator for a null list', () => { + expect(reduce(concat, [])(null)).toEqual([]) +}) + +test('returns the accumulator for an undefined list', () => { + expect(reduce(concat, [])(undefined)).toEqual([]) +}) + +test('type test', () => { + const result = pipe([1, 2, 3], reduce((acc, val) => acc + val, 10)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(16) +}) diff --git a/source/reject.d.ts b/source/reject.d.ts new file mode 100644 index 00000000..7198551b --- /dev/null +++ b/source/reject.d.ts @@ -0,0 +1 @@ +export { reject } from '../files/index' diff --git a/source/reject.spec.ts b/source/reject.spec.ts new file mode 100644 index 00000000..39875230 --- /dev/null +++ b/source/reject.spec.ts @@ -0,0 +1,14 @@ +import { reject } from './reject' +import { pipe } from './pipe' + +test('happy', () => { + const isEven = (n: number) => n % 2 === 0 + expect(reject(isEven)([1, 2, 3, 4])).toEqual([1, 3]) +}) + +test('type test', () => { + const list = [1, 2, 3] + const result = pipe(list, reject(x => x > 1)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1]) +}) diff --git a/source/rejectObject.d.ts b/source/rejectObject.d.ts new file mode 100644 index 00000000..26a74d2e --- /dev/null +++ b/source/rejectObject.d.ts @@ -0,0 +1 @@ +export { rejectObject } from '../files/index' diff --git a/source/rejectObject.spec.ts b/source/rejectObject.spec.ts new file mode 100644 index 00000000..b2c61b1a --- /dev/null +++ b/source/rejectObject.spec.ts @@ -0,0 +1,17 @@ +import { rejectObject } from './rejectObject' +import { pipe } from './pipe' + +test('happy', () => { + const testInput = { a: 1, b: 2, c: 3 } + const result = pipe( + testInput, + rejectObject((x, prop) => x > 1), + ) + expect(result).toEqual({ a: 1 }) +}) + +test('type test', () => { + const result = pipe({ a: 1, b: 2 }, rejectObject(x => x > 1)) + expectTypeOf(result).toEqualTypeOf>() + expect(result).toEqual({ a: 1 }) +}) diff --git a/source/remeda-comparison-spec.ts b/source/remeda-comparison-spec.ts new file mode 100644 index 00000000..1c535c08 --- /dev/null +++ b/source/remeda-comparison-spec.ts @@ -0,0 +1,153 @@ +import { filter, groupBy, indexBy, map, pick, pipe, sortBy, find } from 'rambda' +import { describe, expectTypeOf, it } from 'vitest' +import { + drop as remedaDrop, + filter as remedaFilter, + find as remedaFind, + groupBy as remedaGroupBy, + indexBy as remedaIndexBy, + map as remedaMap, + sortBy as remedaSortBy, +} from 'remeda' + +describe('Remeda vs Rambda: type guard narrowing', () => { + it('find - Rambda lacks type guard narrowing', () => { + const items = ['hello', 'world', 42] as (string | number)[] + + const result = pipe( + items, + remedaFind((x): x is string => typeof x === 'string'), + ) + const resultRambda = pipe( + items, + find((x): x is string => typeof x === 'string'), + ) + // Remeda: find(predicate: value is S) => S | undefined + // -> narrows to string | undefined + // Rambda: find(predicate: (x: T) => boolean) => T | undefined + // -> would type as (string | number) | undefined + expectTypeOf(result).toEqualTypeOf() + }) +}) + +describe('Remeda vs Rambda: tuple preservation', () => { + it('drop - Remeda preserves tuple length', () => { + const tuple = [1, 2, 3, 4] as const + // Remeda: drop(array: T, n: N) => Drop + // -> Drop = readonly [3, 4] + const result = remedaDrop(tuple, 2) + expectTypeOf(result).toEqualTypeOf() + // Rambda: drop(howMany: number) => (list: T[]) => T[] + // -> would type as number[] + }) + + it('drop - works inside Rambda pipe', () => { + const result = pipe( + [1, 2, 3, 4] as const, + remedaDrop(2), + ) + expectTypeOf(result).toEqualTypeOf() + }) + + it('map - Remeda preserves tuple length', () => { + const tuple = [1, 2, 3] as const + // Remeda: map(data, fn) => Mapped + // preserves tuple: [number, number, number] + const remedaResult = remedaMap(tuple, x => x + 1) + expectTypeOf(remedaResult).toEqualTypeOf<[number, number, number]>() + + // Rambda: map(fn)(data) => Mapped + // also returns [number, number, number] for const tuples + const rambdaResult = map((x: number) => x + 1)(tuple) + // Rambda can preserve tuple too via Mapped type + expectTypeOf(rambdaResult).toEqualTypeOf<[number, number, number]>() + }) +}) + +describe('Remeda vs Rambda: sortBy multi-criteria', () => { + it('sortBy - Remeda supports multiple criteria and desc', () => { + const items = [ + { color: 'red', weight: 2 }, + { color: 'blue', weight: 1 }, + { color: 'green', weight: 1 }, + ] + + // Remeda: sortBy(data, fn1, [fn2, 'desc'], ...) => ReorderedArray + const sorted = remedaSortBy( + items, + x => x.weight, + // SUGGESTION: Rename 'asc'/'desc' to 'ascending'/'descending' for clarity + [x => x.color, 'desc' as const], + ) + expectTypeOf(sorted).toEqualTypeOf() + expectTypeOf(sorted[0].weight).toEqualTypeOf() + + // Rambda: only single criterion + const rambdaSorted = sortBy((x: { color: string; weight: number }) => x.weight)(items) + expectTypeOf(rambdaSorted).toEqualTypeOf() + }) +}) + +describe('Remeda vs Rambda: groupBy key inference', () => { + it('groupBy - Remeda uses NonEmptyArray for values', () => { + const items = [ + { category: 'a', val: 1 }, + { category: 'b', val: 2 }, + { category: 'a', val: 3 }, + ] + + // Remeda: groupBy returns Record> + // Key is string (widened), so no Partial (BoundedPartial = identity) + const remedaResult = remedaGroupBy(items, x => x.category) + expectTypeOf(remedaResult).toEqualTypeOf< + Record + >() + + // Rambda: groupBy => Partial> + const rambdaGrouped = pipe(items, groupBy(x => x.category)) + expectTypeOf(rambdaGrouped).toEqualTypeOf< + Partial> + >() + }) +}) + +describe('Remeda vs Rambda: filter nuances', () => { + it('filter(Boolean) - Remeda has no ExcludeFalsy', () => { + const list = [1, true, false] as const + + // Remeda: filter returns T[number][] for boolean predicates + const remedaResult = remedaFilter(list, Boolean) + // Remeda doesn't narrow — returns all element types including false + expectTypeOf(remedaResult).toEqualTypeOf<(1 | true | false)[]>() + + // Rambda: filter(Boolean) uses ExcludeFalsy which excludes 'true' literal + const rambdaResult = filter(Boolean)(list) + // @ts-expect-error - Rambda's ExcludeFalsy excludes true + expectTypeOf(rambdaResult).toEqualTypeOf<(1 | true)[]>() + // Actual type: 1[] -- bug: ExcludeFalsy<1 | true | false> = 1 + expectTypeOf(rambdaResult).toEqualTypeOf<1[]>() + }) +}) + +describe('Remeda vs Rambda: indexBy key inference', () => { + it('indexBy - Remeda infers literal keys', () => { + const list = [ + { id: 'a' as const, name: 'Alice' }, + { id: 'b' as const, name: 'Bob' }, + ] + + // Remeda: indexBy(data, fn) => BoundedPartial> + // infers literal keys 'a' | 'b', applies Partial via BoundedPartial + const remedaResult = remedaIndexBy(list, x => x.id) + expectTypeOf(remedaResult).toEqualTypeOf< + Partial> + >() + + // Rambda: indexBy(property)(list) => Record + // Takes a property key string, not a function + const rambdaResult = indexBy('id')(list) + expectTypeOf(rambdaResult).toEqualTypeOf< + Record + >() + }) +}) diff --git a/source/remove.d.ts b/source/remove.d.ts new file mode 100644 index 00000000..7f7bcc25 --- /dev/null +++ b/source/remove.d.ts @@ -0,0 +1 @@ +export { remove } from '../files/index' diff --git a/source/remove.spec.ts b/source/remove.spec.ts new file mode 100644 index 00000000..8aa62a25 --- /dev/null +++ b/source/remove.spec.ts @@ -0,0 +1,21 @@ +import { remove } from './remove' + +test('happy', () => { + const inputs = [/foo/, /not\shere/, /also/, 'bar'] + const text = 'foo bar baz foo' + const result = remove(inputs)(text) + expect(result).toEqual('baz foo') +}) + +test('with single rule', () => { + const inputs = /foo/g + const text = 'foo bar baz foo' + const result = remove(inputs)(text) + expect(result).toEqual(' bar baz ') +}) + +test('type test', () => { + const result = remove([/foo/])('foo bar') + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('bar') +}) diff --git a/source/replace.d.ts b/source/replace.d.ts new file mode 100644 index 00000000..b973e382 --- /dev/null +++ b/source/replace.d.ts @@ -0,0 +1 @@ +export { replace } from '../files/index' diff --git a/source/replace.spec.ts b/source/replace.spec.ts new file mode 100644 index 00000000..dcf2304e --- /dev/null +++ b/source/replace.spec.ts @@ -0,0 +1,13 @@ +import { replace } from './replace' + +test('happy', () => { + expect(replace(/\s/g, '|')('foo bar baz')).toBe('foo|bar|baz') + expect(replace('a', '|')('foo bar baz')).toBe('foo b|r baz') +}) + +test('type test', () => { + const str = 'foo bar foo' + const result = replace(/foo/g, 'bar')(str) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('bar bar bar') +}) diff --git a/source/replaceAll.d.ts b/source/replaceAll.d.ts new file mode 100644 index 00000000..b339ca9e --- /dev/null +++ b/source/replaceAll.d.ts @@ -0,0 +1 @@ +export { replaceAll } from '../files/index' diff --git a/source/replaceAll.spec.ts b/source/replaceAll.spec.ts new file mode 100644 index 00000000..9049c67e --- /dev/null +++ b/source/replaceAll.spec.ts @@ -0,0 +1,18 @@ +import { replaceAll } from './replaceAll' +import { pipe } from './pipe' + +const replacer = '|' +const patterns = [/foo/g, 'bar'] +const input = 'foo bar baz foo bar' + +test('happy', () => { + const result = replaceAll(patterns, replacer)(input) + expect(result).toEqual('| | baz | bar') +}) + +test('type test', () => { + const str = 'foo bar foo' + const result = pipe(str, replaceAll([/foo/g, 'bar'], 'bar')) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('bar bar bar') +}) diff --git a/source/shuffle.d.ts b/source/shuffle.d.ts new file mode 100644 index 00000000..af12eaff --- /dev/null +++ b/source/shuffle.d.ts @@ -0,0 +1 @@ +export { shuffle } from '../files/index' diff --git a/source/shuffle.spec.ts b/source/shuffle.spec.ts new file mode 100644 index 00000000..5f7ce86c --- /dev/null +++ b/source/shuffle.spec.ts @@ -0,0 +1,9 @@ +import { shuffle } from './shuffle' + +test('type test', () => { + const list = [1, 2, 3, 4, 5] + const result = shuffle(list) + expectTypeOf(result).toEqualTypeOf() + expect(result).toHaveLength(5) + expect(result.sort()).toEqual([1, 2, 3, 4, 5]) +}) diff --git a/source/sort.d.ts b/source/sort.d.ts new file mode 100644 index 00000000..06aa2cd2 --- /dev/null +++ b/source/sort.d.ts @@ -0,0 +1 @@ +export { sort } from '../files/index' diff --git a/source/sort.spec.ts b/source/sort.spec.ts new file mode 100644 index 00000000..73309407 --- /dev/null +++ b/source/sort.spec.ts @@ -0,0 +1,21 @@ +import { sort } from './sort' +import { pipe } from './pipe' + +const fn = (a: number, b: number) => (a > b ? 1 : -1) + +test('sort', () => { + expect(sort((a: number, b: number) => a - b)([2, 3, 1])).toEqual([1, 2, 3]) +}) + +test("it doesn't mutate", () => { + const list = ['foo', 'bar', 'baz'] + expect(sort(fn as any)(list)).toEqual(['bar', 'baz', 'foo']) + expect(list).toEqual(['foo', 'bar', 'baz']) +}) + +test('type test', () => { + const list = [3, 0, 5, 2, 1] + const result = sort((a, b) => (a > b ? 1 : -1))(list) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([0, 1, 2, 3, 5]) +}) diff --git a/source/sortBy.d.ts b/source/sortBy.d.ts new file mode 100644 index 00000000..6a147dda --- /dev/null +++ b/source/sortBy.d.ts @@ -0,0 +1 @@ +export { sortBy } from '../files/index' diff --git a/source/sortBy.spec.ts b/source/sortBy.spec.ts new file mode 100644 index 00000000..4fff5c9c --- /dev/null +++ b/source/sortBy.spec.ts @@ -0,0 +1,23 @@ +import { sortBy } from './sortBy' +import { pipe } from './pipe' + +const input = [{ a: 2 }, { a: 1 }, { a: 1 }, { a: 3 }] + +test('happy', () => { + const expected = [{ a: 1 }, { a: 1 }, { a: 2 }, { a: 3 }] + const result = sortBy(x => x.a)(input) + expect(result).toEqual(expected) +}) + +test('with non-existing path', () => { + expect(sortBy(x => x.b)(input)).toEqual(input) +}) + +test('type test', () => { + const result = pipe( + [{ a: 2 }, { a: 1 }, { a: 0 }], + sortBy(x => x.a), + ) + expectTypeOf(result[0].a).toEqualTypeOf() + expect(result[0].a).toBe(0) +}) diff --git a/source/sortByDescending.d.ts b/source/sortByDescending.d.ts new file mode 100644 index 00000000..f70c9144 --- /dev/null +++ b/source/sortByDescending.d.ts @@ -0,0 +1 @@ +export { sortByDescending } from '../files/index' diff --git a/source/sortByDescending.spec.ts b/source/sortByDescending.spec.ts new file mode 100644 index 00000000..3510137e --- /dev/null +++ b/source/sortByDescending.spec.ts @@ -0,0 +1,15 @@ +import { sortByDescending } from './sortByDescending' +import { path } from './path' + +const list = [{ a: { b: 3 } }, { a: { b: 1 } }, { a: { b: 2 } }] +const sorted = [{ a: { b: 3 } }, { a: { b: 2 } }, { a: { b: 1 } }] + +test('happy', () => { + expect(sortByDescending(path('a.b'))(list)).toEqual(sorted) +}) + +test('type test', () => { + const result = sortByDescending(path('a.b'))(list) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(sorted) +}) diff --git a/source/sortByPath.d.ts b/source/sortByPath.d.ts new file mode 100644 index 00000000..69b0f216 --- /dev/null +++ b/source/sortByPath.d.ts @@ -0,0 +1 @@ +export { sortByPath } from '../files/index' diff --git a/source/sortByPath.spec.ts b/source/sortByPath.spec.ts new file mode 100644 index 00000000..fb2dbc88 --- /dev/null +++ b/source/sortByPath.spec.ts @@ -0,0 +1,25 @@ +import { sortByPath } from './sortByPath' +import { pipe } from './pipe' + +const list = [{ a: { b: 3 } }, { a: { b: 1 } }, { a: { b: 2 } }] +const sorted = [{ a: { b: 1 } }, { a: { b: 2 } }, { a: { b: 3 } }] + +test('with string as path', () => { + expect(sortByPath('a.b')(list)).toEqual(sorted) +}) + +test('with list of strings as path', () => { + expect(sortByPath(['a', 'b'])(list)).toEqual(sorted) +}) + +test('when path is not found in any item', () => { + const list = [{ a: { b: 3 } }, { a: { b: 1 } }, { a: {} }] + expect(sortByPath('a.b.c.d')(list)).toEqual(list) +}) + +test('type test', () => { + const input = [{ a: { b: 2 } }, { a: { b: 1 } }] + const result = pipe(input, sortByPath('a.b')) + expectTypeOf(result[0].a.b).toEqualTypeOf() + expect(result[0].a.b).toBe(1) +}) diff --git a/source/sortByPathDescending.d.ts b/source/sortByPathDescending.d.ts new file mode 100644 index 00000000..8fd1e64a --- /dev/null +++ b/source/sortByPathDescending.d.ts @@ -0,0 +1 @@ +export { sortByPathDescending } from '../files/index' diff --git a/source/sortByPathDescending.spec.ts b/source/sortByPathDescending.spec.ts new file mode 100644 index 00000000..925b20b5 --- /dev/null +++ b/source/sortByPathDescending.spec.ts @@ -0,0 +1,18 @@ +import { sortByPathDescending } from './sortByPathDescending' + +const list = [{ a: { b: 3 } }, { a: { b: 1 } }, { a: { b: 2 } }] +const sorted = [{ a: { b: 3 } }, { a: { b: 2 } }, { a: { b: 1 } }] + +test('with string as path', () => { + expect(sortByPathDescending('a.b')(list)).toEqual(sorted) +}) + +test('with list of strings as path', () => { + expect(sortByPathDescending(['a', 'b'])(list)).toEqual(sorted) +}) + +test('type test', () => { + const result = sortByPathDescending('a.b')(list) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(sorted) +}) diff --git a/source/sortByProps.spec.ts b/source/sortByProps.spec.ts new file mode 100644 index 00000000..50aeba17 --- /dev/null +++ b/source/sortByProps.spec.ts @@ -0,0 +1,23 @@ +import { sortByProps } from 'rambdax' + +const list = [{ a: { b: 3 } }, { a: { b: 2 } }, { a: { b: 1 } }] + +test('happy', () => { + const result = sortByProps(['foo.bar', 'a.b'], list) + expectTypeOf(result).toEqualTypeOf<{ a: { b: number } }[]>() + expect(result).toEqual([ + { a: { b: 1 } }, + { a: { b: 2 } }, + { a: { b: 3 } }, + ]) +}) + +test('curried', () => { + const result = sortByProps(['foo.bar', 'a.b'])(list) + expectTypeOf(result).toEqualTypeOf<{ a: { b: number } }[]>() + expect(result).toEqual([ + { a: { b: 1 } }, + { a: { b: 2 } }, + { a: { b: 3 } }, + ]) +}) diff --git a/source/sortObject.d.ts b/source/sortObject.d.ts new file mode 100644 index 00000000..81122a22 --- /dev/null +++ b/source/sortObject.d.ts @@ -0,0 +1 @@ +export { sortObject } from '../files/index' diff --git a/source/sortObject.spec.ts b/source/sortObject.spec.ts new file mode 100644 index 00000000..3ed58b0e --- /dev/null +++ b/source/sortObject.spec.ts @@ -0,0 +1,18 @@ +import { sortObject } from './sortObject' +import { pipe } from './pipe' + +test('happy', () => { + const obj = { c: 7, a: 100, b: 1, d: 4 } + const predicate = (a: string, b: string, aValue: number, bValue: number) => { + if (a === 'a') return -1 + if (b === 'a') return 1 + return aValue > bValue ? -1 : 1 + } + const result = sortObject(predicate)(obj) + expect(result).toEqual({ a: 100, c: 7, d: 4, b: 1 }) +}) + +test('type test', () => { + const result = pipe({ c: 1, a: 2, b: 3 }, sortObject((propA, propB) => propA > propB ? -1 : 1)) + expectTypeOf(result).toEqualTypeOf<{ c: number; a: number; b: number }>() +}) diff --git a/source/sortWith.d.ts b/source/sortWith.d.ts new file mode 100644 index 00000000..08c7146d --- /dev/null +++ b/source/sortWith.d.ts @@ -0,0 +1 @@ +export { sortWith } from '../files/index' diff --git a/source/sortWith.spec.ts b/source/sortWith.spec.ts new file mode 100644 index 00000000..c7c3666c --- /dev/null +++ b/source/sortWith.spec.ts @@ -0,0 +1,47 @@ +import { ascend } from './ascend' +import { prop } from './prop' +import { sortWith } from './sortWith' + +const albums = [ + { artist: 'Rush', genre: 'Rock', score: 3, title: 'A Farewell to Kings' }, + { artist: 'Dave Brubeck Quartet', genre: 'Jazz', score: 3, title: 'Timeout' }, + { artist: 'Rush', genre: 'Rock', score: 5, title: 'Fly By Night' }, + { artist: 'Daniel Barenboim', genre: 'Baroque', score: 3, title: 'Goldberg Variations' }, + { artist: 'Glenn Gould', genre: 'Baroque', score: 3, title: 'Art of the Fugue' }, + { artist: 'Leonard Bernstein', genre: 'Romantic', score: 4, title: 'New World Symphony' }, + { artist: 'Don Byron', genre: 'Jazz', score: 5, title: 'Romance with the Unseen' }, + { artist: 'Iron Maiden', genre: 'Metal', score: 2, title: 'Somewhere In Time' }, + { artist: 'Danny Holt', genre: 'Modern', score: 1, title: 'In Times of Desparation' }, + { artist: 'Various', genre: 'Broadway', score: 3, title: 'Evita' }, + { artist: 'Nick Drake', genre: 'Folk', score: 1, title: 'Five Leaves Left' }, + { artist: 'John Eliot Gardiner', genre: 'Classical', score: 4, title: 'The Magic Flute' }, +] + +test('sorts by a simple property', () => { + const sortedAlbums = sortWith([ascend(prop('title'))])(albums) + expect(sortedAlbums).toHaveLength(albums.length) + expect(sortedAlbums[0].title).toBe('A Farewell to Kings') + expect(sortedAlbums[11].title).toBe('Timeout') +}) + +test('sorts by multiple properties', () => { + const sortedAlbums = sortWith([ascend(prop('score')), ascend(prop('title'))])(albums) + expect(sortedAlbums).toHaveLength(albums.length) + expect(sortedAlbums[0].title).toBe('Five Leaves Left') + expect(sortedAlbums[1].title).toBe('In Times of Desparation') + expect(sortedAlbums[11].title).toBe('Romance with the Unseen') +}) + +test('sorts by 3 properties', () => { + const sortedAlbums = sortWith([ascend(prop('genre')), ascend(prop('score')), ascend(prop('title'))])(albums) + expect(sortedAlbums).toHaveLength(albums.length) + expect(sortedAlbums[0].title).toBe('Art of the Fugue') + expect(sortedAlbums[1].title).toBe('Goldberg Variations') + expect(sortedAlbums[11].title).toBe('New World Symphony') +}) + +test('type test', () => { + const result = sortWith([ascend(prop('title'))])(albums) + expect(result).toHaveLength(albums.length) + expect(result[0].title).toBe('A Farewell to Kings') +}) diff --git a/source/split.d.ts b/source/split.d.ts new file mode 100644 index 00000000..bb4f18aa --- /dev/null +++ b/source/split.d.ts @@ -0,0 +1 @@ +export { split } from '../files/index' diff --git a/source/splitEvery-spec.ts b/source/splitEvery-spec.ts index 505ac333..a6b1ee80 100644 --- a/source/splitEvery-spec.ts +++ b/source/splitEvery-spec.ts @@ -1,4 +1,4 @@ -import { pipe, splitEvery } from 'rambda' +import { flatMap, pipe, shuffle, splitEvery } from 'rambda' import { describe, expectTypeOf, it } from 'vitest' const list = [1, 2, 3, 4, 5, 6, 7] @@ -8,4 +8,17 @@ describe('R.splitEvery', () => { const result = pipe(list, splitEvery(3)) expectTypeOf(result).toEqualTypeOf() }) + it('async', async () => { + const data = Array.from({ length: 100 }, (_, i) => i + 1) + const result = await pipe( + data, + shuffle, // NEEDS EXPLICIT TYPE ANNOTATION + // (list) => shuffle(list), // THIS ALSO WORKS + // shuffle, THIS IS NOT WORKING `TypeScript cannot infer types backward and forward at the exact same time` + splitEvery(10), + flatMap(String), + ) + + expectTypeOf(result).toEqualTypeOf() + }) }) diff --git a/source/splitEvery.d.ts b/source/splitEvery.d.ts new file mode 100644 index 00000000..fcd9e852 --- /dev/null +++ b/source/splitEvery.d.ts @@ -0,0 +1 @@ +export { splitEvery } from '../files/index' diff --git a/source/splitEvery.spec.ts b/source/splitEvery.spec.ts new file mode 100644 index 00000000..b97af9df --- /dev/null +++ b/source/splitEvery.spec.ts @@ -0,0 +1,12 @@ +import { splitEvery } from './splitEvery' +import { pipe } from './pipe' + +test('happy', () => { + expect(splitEvery(3)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2, 3], [4, 5, 6], [7]]) +}) + +test('type test', () => { + const result = pipe([1, 2, 3, 4, 5, 6, 7], splitEvery(3)) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7]]) +}) diff --git a/source/splitEveryStrict.d.ts b/source/splitEveryStrict.d.ts new file mode 100644 index 00000000..38c9ba06 --- /dev/null +++ b/source/splitEveryStrict.d.ts @@ -0,0 +1 @@ +export { splitEveryStrict } from '../files/index' diff --git a/source/splitEveryStrict.spec.ts b/source/splitEveryStrict.spec.ts new file mode 100644 index 00000000..b88bd12b --- /dev/null +++ b/source/splitEveryStrict.spec.ts @@ -0,0 +1,11 @@ +import { splitEveryStrict } from './splitEveryStrict' + +test('happy', () => { + expect(splitEveryStrict(3)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2, 3], [4, 5, 6]]) +}) + +test('type test', () => { + const result = splitEveryStrict(3)([1, 2, 3, 4, 5, 6, 7]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([[1, 2, 3], [4, 5, 6]]) +}) diff --git a/source/sum.d.ts b/source/sum.d.ts new file mode 100644 index 00000000..bbd69882 --- /dev/null +++ b/source/sum.d.ts @@ -0,0 +1 @@ +export { sum } from '../files/index' diff --git a/source/sum.spec.ts b/source/sum.spec.ts new file mode 100644 index 00000000..2d3622e8 --- /dev/null +++ b/source/sum.spec.ts @@ -0,0 +1,11 @@ +import { sum } from './sum' + +test('happy', () => { + expect(sum([1, 2, 3])).toEqual(6) +}) + +test('type test', () => { + const result = sum([1, 2, 3]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(6) +}) diff --git a/source/switcher.d.ts b/source/switcher.d.ts new file mode 100644 index 00000000..52308bdb --- /dev/null +++ b/source/switcher.d.ts @@ -0,0 +1 @@ +export { switcher } from '../files/index' diff --git a/source/switcher.spec.ts b/source/switcher.spec.ts new file mode 100644 index 00000000..196d503c --- /dev/null +++ b/source/switcher.spec.ts @@ -0,0 +1,79 @@ +import { switcher } from './switcher' +import { tap } from './tap' + +test('with undefined', () => { + const result = switcher(undefined) + .is(x => x === 0, '0') + .is(x => x === undefined, 'UNDEFINED') + .default('3') + expect(result).toBe('UNDEFINED') +}) + +test('happy', () => { + const a = true + const b = false + const result = switcher([a, b]) + .is([false, false], '0') + .is([false, true], '1') + .is([true, true], '2') + .default('3') + expect(result).toBe('3') +}) + +test('can compare objects', () => { + const result = switcher({ a: 1 }) + .is({ a: 1 }, 'it is object') + .is('baz', 'it is baz') + .default('it is default') + expect(result).toBe('it is object') +}) + +test('options are mixture of functions and values - input match function', () => { + const fn = switcher('foo').is('bar', 1) + .is('foo', x => x + 1) + .default(1000) + expect(fn(2)).toBe(3) +}) + +test('options are mixture of functions and values - input match value', () => { + const result = switcher('bar').is('bar', 1) + .is('foo', x => x + 1) + .default(1000) + expect(result).toBe(1) +}) + +test('return function if all options are functions', () => { + const fn = switcher('foo') + .is('bar', tap) + .is('foo', x => x + 1) + .default(9) + expect(fn(2)).toBe(3) +}) + +const switchFn = (input: unknown) => + switcher(input) + .is((x: any) => x.length && x.length === 7, 'has length of 7') + .is('baz', 'it is baz') + .default('it is default') + +test('works with function as condition', () => { + expect(switchFn([0, 1, 2, 3, 4, 5, 6])).toBe('has length of 7') +}) + +test('works with string as condition', () => { + expect(switchFn('baz')).toBe('it is baz') +}) + +test('fallback to default input when no matches', () => { + expect(switchFn(1)).toBe('it is default') +}) + +test('type test', () => { + const list = [1, 2, 3] + const result = switcher(list.length) + .is(x => x < 2, 4) + .is(x => x < 4, 6) + .default(7) + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(6) +}) diff --git a/source/symmetricDifference.d.ts b/source/symmetricDifference.d.ts new file mode 100644 index 00000000..9eaf4cf4 --- /dev/null +++ b/source/symmetricDifference.d.ts @@ -0,0 +1 @@ +export { symmetricDifference } from '../files/index' diff --git a/source/symmetricDifference.spec.ts b/source/symmetricDifference.spec.ts new file mode 100644 index 00000000..ed27b6fa --- /dev/null +++ b/source/symmetricDifference.spec.ts @@ -0,0 +1,20 @@ +import { symmetricDifference } from './symmetricDifference' + +test('symmetricDifference', () => { + const list1 = [1, 2, 3, 4] + const list2 = [3, 4, 5, 6] + expect(symmetricDifference(list1)(list2)).toEqual([1, 2, 5, 6]) + expect(symmetricDifference([])([])).toEqual([]) +}) + +test('symmetricDifference with objects', () => { + const list1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }] + const list2 = [{ id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }] + expect(symmetricDifference(list1)(list2)).toEqual([{ id: 1 }, { id: 2 }, { id: 5 }, { id: 6 }]) +}) + +test('type test', () => { + const result = symmetricDifference([{ id: 1 }])([{ id: 2 }]) + expectTypeOf(result).toEqualTypeOf<{ id: number }[]>() + expect(result).toEqual([{ id: 1 }, { id: 2 }]) +}) diff --git a/source/tail.d.ts b/source/tail.d.ts new file mode 100644 index 00000000..f05f8972 --- /dev/null +++ b/source/tail.d.ts @@ -0,0 +1 @@ +export { tail } from '../files/index' diff --git a/source/tail.spec.ts b/source/tail.spec.ts new file mode 100644 index 00000000..ed815088 --- /dev/null +++ b/source/tail.spec.ts @@ -0,0 +1,18 @@ +import { tail } from './tail' + +test('tail', () => { + expect(tail([1, 2, 3])).toEqual([2, 3]) + expect(tail([1, 2])).toEqual([2]) + expect(tail([1])).toEqual([]) + expect(tail([])).toEqual([]) + expect(tail('abc')).toBe('bc') + expect(tail('ab')).toBe('b') + expect(tail('a')).toBe('') + expect(tail('')).toBe('') +}) + +test('type test', () => { + expectTypeOf(tail('foo')).toEqualTypeOf() + expectTypeOf(tail(['foo', 'bar', 1, 2, 3])).toEqualTypeOf<(string | number)[]>() + expect(tail('abc')).toBe('bc') +}) diff --git a/source/take.d.ts b/source/take.d.ts new file mode 100644 index 00000000..ba326ae1 --- /dev/null +++ b/source/take.d.ts @@ -0,0 +1 @@ +export { take } from '../files/index' diff --git a/source/take.spec.ts b/source/take.spec.ts new file mode 100644 index 00000000..e94c441f --- /dev/null +++ b/source/take.spec.ts @@ -0,0 +1,26 @@ +import { take } from './take' + +test('happy', () => { + const arr = ['foo', 'bar', 'baz'] + expect(take(1)(arr)).toEqual(['foo']) + expect(arr).toEqual(['foo', 'bar', 'baz']) + expect(take(2)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar']) + expect(take(3)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) + expect(take(4)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) + expect(take(3)('rambda')).toBe('ram') +}) + +test('with negative index', () => { + expect(take(-1)([1, 2, 3])).toEqual([1, 2, 3]) + expect(take(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3]) +}) + +test('with zero index', () => { + expect(take(0)([1, 2, 3])).toEqual([]) +}) + +test('type test', () => { + const result = take(1)(['foo', 'bar', 'baz']) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['foo']) +}) diff --git a/source/takeLast.d.ts b/source/takeLast.d.ts new file mode 100644 index 00000000..2783a242 --- /dev/null +++ b/source/takeLast.d.ts @@ -0,0 +1 @@ +export { takeLast } from '../files/index' diff --git a/source/takeLast.spec.ts b/source/takeLast.spec.ts new file mode 100644 index 00000000..06580588 --- /dev/null +++ b/source/takeLast.spec.ts @@ -0,0 +1,25 @@ +import { takeLast } from './takeLast' + +test('with arrays', () => { + expect(takeLast(1)(['foo', 'bar', 'baz'])).toEqual(['baz']) + expect(takeLast(2)(['foo', 'bar', 'baz'])).toEqual(['bar', 'baz']) + expect(takeLast(3)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) + expect(takeLast(4)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) + expect(takeLast(10)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) +}) + +test('with strings', () => { + expect(takeLast(3)('rambda')).toBe('bda') + expect(takeLast(7)('rambda')).toBe('rambda') +}) + +test('with negative index', () => { + expect(takeLast(-1)([1, 2, 3])).toEqual([1, 2, 3]) + expect(takeLast(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3]) +}) + +test('type test', () => { + const result = takeLast(1)(['foo', 'bar', 'baz']) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['baz']) +}) diff --git a/source/takeLastWhile.d.ts b/source/takeLastWhile.d.ts new file mode 100644 index 00000000..88acc110 --- /dev/null +++ b/source/takeLastWhile.d.ts @@ -0,0 +1 @@ +export { takeLastWhile } from '../files/index' diff --git a/source/takeLastWhile.spec.ts b/source/takeLastWhile.spec.ts new file mode 100644 index 00000000..ecc0f6ed --- /dev/null +++ b/source/takeLastWhile.spec.ts @@ -0,0 +1,23 @@ +import { takeLastWhile } from './takeLastWhile' + +test('happy', () => { + const predicate = (x: number) => x > 2 + const result = takeLastWhile(predicate)([1, 2, 3, 4]) + expect(result).toEqual([3, 4]) +}) + +test('predicate is always true', () => { + const result = takeLastWhile(() => true)([1, 2, 3, 4]) + expect(result).toEqual([1, 2, 3, 4]) +}) + +test('predicate is always false', () => { + const result = takeLastWhile(() => false)([1, 2, 3, 4]) + expect(result).toEqual([]) +}) + +test('type test', () => { + const result = takeLastWhile(x => x > 2)([1, 2, 3, 4]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([3, 4]) +}) diff --git a/source/takeWhile.d.ts b/source/takeWhile.d.ts new file mode 100644 index 00000000..3e083969 --- /dev/null +++ b/source/takeWhile.d.ts @@ -0,0 +1 @@ +export { takeWhile } from '../files/index' diff --git a/source/takeWhile.spec.ts b/source/takeWhile.spec.ts new file mode 100644 index 00000000..b2306845 --- /dev/null +++ b/source/takeWhile.spec.ts @@ -0,0 +1,23 @@ +import { takeWhile } from './takeWhile' +import { pipe } from './pipe' + +test('happy', () => { + const result = takeWhile(x => x < 3)([1, 2, 3, 4, 5]) + expect(result).toEqual([1, 2]) +}) + +test('always true', () => { + const result = takeWhile(x => true)([1, 2, 3, 4, 5]) + expect(result).toEqual([1, 2, 3, 4, 5]) +}) + +test('always false', () => { + const result = takeWhile(x => 0)([1, 2, 3, 4, 5]) + expect(result).toEqual([]) +}) + +test('type test', () => { + const result = takeWhile(x => x > 1)([2, 3, 1]) + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([2, 3]) +}) diff --git a/source/tap.d.ts b/source/tap.d.ts new file mode 100644 index 00000000..702c7052 --- /dev/null +++ b/source/tap.d.ts @@ -0,0 +1 @@ +export { tap } from '../files/index' diff --git a/source/test.d.ts b/source/test.d.ts new file mode 100644 index 00000000..c95d1d83 --- /dev/null +++ b/source/test.d.ts @@ -0,0 +1 @@ +export { test } from '../files/index' diff --git a/source/test.spec.ts b/source/test.spec.ts new file mode 100644 index 00000000..7f1e7536 --- /dev/null +++ b/source/test.spec.ts @@ -0,0 +1,15 @@ +import { test as testMethod } from './test' + +test('happy', () => { + expect(testMethod(/^x/)('xyz')).toBeTruthy() + expect(testMethod(/^y/)('xyz')).toBeFalsy() +}) + +test('type test', () => { + const input = 'foo ' + const regex = /foo/ + const result = testMethod(regex)(input) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(true) +}) diff --git a/source/tryCatch.d.ts b/source/tryCatch.d.ts new file mode 100644 index 00000000..7337f566 --- /dev/null +++ b/source/tryCatch.d.ts @@ -0,0 +1 @@ +export { tryCatch } from '../files/index' diff --git a/source/tryCatch.spec.ts b/source/tryCatch.spec.ts new file mode 100644 index 00000000..b985626e --- /dev/null +++ b/source/tryCatch.spec.ts @@ -0,0 +1,44 @@ +import { prop } from './prop' +import { tryCatch } from './tryCatch' +import { pipe } from './pipe' +import { map } from './map' + +test('happy', () => { + const fn = () => { + throw new Error('foo') + } + const result = tryCatch(fn, () => true)() + expect(result).toBeTruthy() +}) + +test('when fallback is used', () => { + const fn = x => x.x + expect(tryCatch(fn, false)(null)).toBeFalsy() +}) + +test('with json parse', () => { + const good = () => JSON.parse(JSON.stringify({ a: 1 })) + const bad = () => JSON.parse('a{a') + expect(tryCatch(good, 1)()).toEqual({ a: 1 }) + expect(tryCatch(bad, 1)()).toBe(1) +}) + +test('when fn is used', () => { + const fn = prop('x') + expect(tryCatch(fn, false)({})).toBeUndefined() + expect(tryCatch(fn, false)({ x: 1 })).toBe(1) +}) + +test('type test', () => { + const result = pipe( + ['{a:1', '{"b": 2}'], + map( + tryCatch(x => { + return JSON.parse(x) as string + }, null), + ), + ) + + expectTypeOf(result).toEqualTypeOf<(string | null)[]>() + expect(result).toEqual([null, { b: 2 }]) +}) diff --git a/source/type.d.ts b/source/type.d.ts new file mode 100644 index 00000000..48471abd --- /dev/null +++ b/source/type.d.ts @@ -0,0 +1 @@ +export { type } from '../files/index' diff --git a/source/type.spec.ts b/source/type.spec.ts new file mode 100644 index 00000000..fc676067 --- /dev/null +++ b/source/type.spec.ts @@ -0,0 +1,172 @@ +import { type as typeRamda } from 'ramda' +import { type } from './type' + +test('with buffer', () => { + expect(type(new Buffer.from('foo'))).toBe('Uint8Array') +}) + +test('with array buffer', () => { + expect(type(new ArrayBuffer(8))).toBe('ArrayBuffer') +}) + +test('with big int', () => { + expect(type(BigInt(9007199254740991))).toBe('BigInt') +}) + +test('with generators', () => { + function* generator() { + yield 1 + yield 2 + yield 3 + } + const gen = generator() + expect(type(generator)).toBe('GeneratorFunction') + expect(type(gen)).toBe('Generator') +}) + +test('with Date', () => { + const date = new Date('December 17, 1995 03:24:00') + expect(type(date)).toBe('Date') +}) + +test('with infinity', () => { + expect(type(Number.POSITIVE_INFINITY)).toBe('Number') +}) + +test('with weak map', () => { + expect(type(new WeakMap())).toBe('WeakMap') +}) + +test('with map', () => { + expect(type(new Map())).toBe('Map') +}) + +test('with symbol', () => { + expect(type(Symbol())).toBe('Symbol') +}) + +test('with simple promise', () => { + expect(type(Promise.resolve(1))).toBe('Promise') +}) + +test('with new Boolean', () => { + expect(type(new Boolean(true))).toBe('Boolean') +}) + +test('with new String', () => { + expect(type(new String('I am a String object'))).toBe('String') +}) + +test('with new Number', () => { + expect(type(new Number(1))).toBe('Number') +}) + +test('with error', () => { + expect(type(Error('foo'))).toBe('Error') + expect(typeRamda(Error('foo'))).toBe('Error') +}) + +test('with error - wrong @types/ramda test', () => { + class ExtendedError extends Error {} + expect(type(ExtendedError)).toBe('Function') + expect(typeRamda(ExtendedError)).toBe('Function') +}) + +test('with new promise', () => { + const delay = ms => + new Promise(resolve => { + setTimeout(() => { + resolve(ms + 110) + }, ms) + }) + expect(type(delay(10))).toBe('Promise') +}) + +test('async function', () => { + expect(type(async () => {})).toBe('Promise') +}) + +test('async arrow', () => { + const asyncArrow = async () => {} + expect(type(asyncArrow)).toBe('Promise') +}) + +test('function', () => { + const fn1 = () => {} + const fn2 = () => {} + function fn3() {} + ;[() => {}, fn1, fn2, fn3].map(val => { + expect(type(val)).toBe('Function') + }) +}) + +test('object', () => { + expect(type({})).toBe('Object') +}) + +test('number', () => { + expect(type(1)).toBe('Number') +}) + +test('boolean', () => { + expect(type(false)).toBe('Boolean') +}) + +test('string', () => { + expect(type('foo')).toBe('String') +}) + +test('null', () => { + expect(type(null)).toBe('Null') +}) + +test('array', () => { + expect(type([])).toBe('Array') + expect(type([1, 2, 3])).toBe('Array') +}) + +test('regex', () => { + expect(type(/\s/g)).toBe('RegExp') +}) + +test('undefined', () => { + expect(type(undefined)).toBe('Undefined') +}) + +test('not a number', () => { + expect(type(Number('s'))).toBe('NaN') +}) + +test('set', () => { + const exampleSet = new Set([1, 2, 3]) + expect(type(exampleSet)).toBe('Set') + expect(typeRamda(exampleSet)).toBe('Set') +}) + +test('function inside object 1', () => { + const obj = { + f() { + return 4 + }, + } + expect(type(obj.f)).toBe('Function') + expect(typeRamda(obj.f)).toBe('Function') +}) + +test('function inside object 2', () => { + const name = 'f' + const obj = { + [name]() { + return 4 + }, + } + expect(type(obj.f)).toBe('Function') + expect(typeRamda(obj.f)).toBe('Function') +}) + +test('type test', () => { + const result = type(4) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('Number') +}) diff --git a/source/union.d.ts b/source/union.d.ts new file mode 100644 index 00000000..af2d25d1 --- /dev/null +++ b/source/union.d.ts @@ -0,0 +1 @@ +export { union } from '../files/index' diff --git a/source/union.spec.ts b/source/union.spec.ts new file mode 100644 index 00000000..9192a1f1 --- /dev/null +++ b/source/union.spec.ts @@ -0,0 +1,38 @@ +import { union } from './union' + +test('happy', () => { + expect(union([1, 2])([2, 3])).toEqual([1, 2, 3]) +}) + +test('with list of objects', () => { + const list1 = [{ a: 1 }, { a: 2 }] + const list2 = [{ a: 2 }, { a: 3 }] + const result = union(list1)(list2) + expect(result).toEqual([{ a: 1 }, { a: 2 }, { a: 3 }]) +}) + +test('type test', () => { + const result = union([1, 2])([2, 3]) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 2, 3]) +}) + +test('type test with array of objects - case 1', () => { + const list1 = [{ a: 1 }, { a: 2 }] + const list2 = [{ a: 2 }, { a: 3 }] + const result = union(list1)(list2) + + expectTypeOf(result).toEqualTypeOf<{ a: number }[]>() + expect(result).toEqual([{ a: 1 }, { a: 2 }, { a: 3 }]) +}) + +test('type test with array of objects - case 2', () => { + const list1 = [{ a: 1, b: 1 }, { a: 2 }] + const list2 = [{ a: 2 }, { a: 3, b: 3 }] + const result = union(list1)(list2) + + expectTypeOf(result[0].a).toEqualTypeOf() + expectTypeOf(result[0].b).toEqualTypeOf() + expect(result).toEqual([{ a: 1, b: 1 }, { a: 2 }, { a: 3, b: 3 }]) +}) diff --git a/source/unionWith.d.ts b/source/unionWith.d.ts new file mode 100644 index 00000000..cfd335b1 --- /dev/null +++ b/source/unionWith.d.ts @@ -0,0 +1 @@ +export { unionWith } from '../files/index' diff --git a/source/unionWith.spec.ts b/source/unionWith.spec.ts new file mode 100644 index 00000000..8f5fc43d --- /dev/null +++ b/source/unionWith.spec.ts @@ -0,0 +1,30 @@ +import { unionWith } from './unionWith' +import { pipe } from './pipe' + +test('happy', () => { + const list1 = [{ a: 1, b: 1 }, { a: 2, b: 1 }] + const list2 = [{ a: 2, b: 2 }, { a: 3, b: 2 }] + const result = pipe( + list2, + unionWith((x, y) => { + return x.a === y.a + }, list1), + ) + expect(result).toEqual([{ a: 1, b: 1 }, { a: 2, b: 1 }, { a: 3, b: 2 }]) +}) + +test('type test', () => { + const list = [{ a: 1, b: 1 }, { a: 2, b: 1 }] + const result = pipe( + list, + unionWith((x, y) => { + expectTypeOf(x.a).toEqualTypeOf() + expectTypeOf(y.b).toEqualTypeOf() + return x.a === y.a + }, [{ a: 2, b: 2 }, { a: 3, b: 2 }]), + ) + + expectTypeOf(result[0].a).toEqualTypeOf() + expectTypeOf(result[0].b).toEqualTypeOf() + expect(result).toEqual([{ a: 2, b: 2 }, { a: 3, b: 2 }, { a: 1, b: 1 }]) +}) diff --git a/source/uniq.d.ts b/source/uniq.d.ts new file mode 100644 index 00000000..455ea427 --- /dev/null +++ b/source/uniq.d.ts @@ -0,0 +1 @@ +export { uniq } from '../files/index' diff --git a/source/uniq.spec.ts b/source/uniq.spec.ts new file mode 100644 index 00000000..6a40d85e --- /dev/null +++ b/source/uniq.spec.ts @@ -0,0 +1,34 @@ +import { uniq } from './uniq' + +test('happy', () => { + const list = [1, 2, 3, 3, 3, 1, 2, 0] + expect(uniq(list)).toEqual([1, 2, 3, 0]) +}) + +test('with object', () => { + const list = [{ a: 1 }, { a: 2 }, { a: 1 }, { a: 2 }] + expect(uniq(list)).toEqual([{ a: 1 }, { a: 2 }]) +}) + +test('with nested array', () => { + expect(uniq([[42], [42]])).toEqual([[42]]) +}) + +test('with booleans', () => { + expect(uniq([[false], [false], [true]])).toEqual([[false], [true]]) +}) + +test('with falsy values', () => { + expect(uniq([undefined, null])).toEqual([undefined, null]) +}) + +test('can distinct between string and number', () => { + expect(uniq([1, '1'])).toEqual([1, '1']) +}) + +test('type test', () => { + const result = uniq([1, 2, 3, 3, 3, 1, 2, 0]) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([1, 2, 3, 0]) +}) diff --git a/source/uniqBy.d.ts b/source/uniqBy.d.ts new file mode 100644 index 00000000..ec278f80 --- /dev/null +++ b/source/uniqBy.d.ts @@ -0,0 +1 @@ +export { uniqBy } from '../files/index' diff --git a/source/uniqBy.spec.ts b/source/uniqBy.spec.ts new file mode 100644 index 00000000..63c47871 --- /dev/null +++ b/source/uniqBy.spec.ts @@ -0,0 +1,22 @@ +import { uniqBy } from './uniqBy' + +test('happy', () => { + expect(uniqBy(Math.abs)([-2, -1, 0, 1, 2])).toEqual([-2, -1, 0]) +}) + +test('returns an empty array for an empty array', () => { + expect(uniqBy(Math.abs)([])).toEqual([]) +}) + +test('uses R.uniq', () => { + const list = [{ a: 1 }, { a: 2 }, { a: 1 }] + const expected = [{ a: 1 }, { a: 2 }] + expect(uniqBy(x => x)(list)).toEqual(expected) +}) + +test('type test', () => { + const result = uniqBy(Math.abs)([-2, -1, 0]) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual([-2, -1, 0]) +}) diff --git a/source/uniqWith.d.ts b/source/uniqWith.d.ts new file mode 100644 index 00000000..c5898258 --- /dev/null +++ b/source/uniqWith.d.ts @@ -0,0 +1 @@ +export { uniqWith } from '../files/index' diff --git a/source/uniqWith.spec.ts b/source/uniqWith.spec.ts new file mode 100644 index 00000000..6bff11c4 --- /dev/null +++ b/source/uniqWith.spec.ts @@ -0,0 +1,49 @@ +import { uniqWith } from './uniqWith' +import { pipe } from './pipe' + +const list = [{ a: 1 }, { a: 1 }] + +test('happy', () => { + const fn = (x, y) => x.a === y.a + const result = uniqWith(fn)(list) + expect(result).toEqual([{ a: 1 }]) +}) + +test('with list of strings', () => { + const fn = (x, y) => x.length === y.length + const list = ['0', '11', '222', '33', '4', '55'] + const result = uniqWith(fn)(list) + expect(result).toEqual(['0', '11', '222']) +}) + +test('should return items that are not equal to themselves', () => { + const data = [ + { id: 1, reason: 'No name' }, + { id: 1, reason: 'No name' }, + { reason: 'No name' }, + { reason: 'No name' }, + ] + const expectedResult = [ + { id: 1, reason: 'No name' }, + { reason: 'No name' }, + { reason: 'No name' }, + ] + const result = uniqWith((errorA, errorB) => { + if (errorA.id === undefined || errorB.id === undefined) { + return false + } + return errorA.id === errorB.id + })(data) + + expect(result).toEqual(expectedResult) +}) + +test('type test', () => { + const result = pipe( + [{ a: 1 }, { a: 1 }], + uniqWith((x, y) => x.a === y.a), + ) + + expectTypeOf(result).toEqualTypeOf<{ a: number }[]>() + expect(result).toEqual([{ a: 1 }]) +}) diff --git a/source/unless.d.ts b/source/unless.d.ts new file mode 100644 index 00000000..2c37151d --- /dev/null +++ b/source/unless.d.ts @@ -0,0 +1 @@ +export { unless } from '../files/index' diff --git a/source/unless.spec.ts b/source/unless.spec.ts new file mode 100644 index 00000000..8da77cc2 --- /dev/null +++ b/source/unless.spec.ts @@ -0,0 +1,48 @@ +import { unless } from './unless' +import { pipe } from './pipe' + +test('happy', () => { + expect( + unless( + x => x > 10, + x => x + 1, + )(20), + ).toEqual(20) + expect( + unless( + x => x > 10, + x => x + 1, + )(5), + ).toEqual(6) +}) + +const inc = (x: number) => x + 1 + +test('type test', () => { + const result = pipe( + 1, + unless(x => x > 5, inc), + ) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) + +test('with two different types', () => { + const result = pipe( + 1, + unless( + x => { + expectTypeOf(x).toEqualTypeOf() + return x > 5 + }, + x => { + expectTypeOf(x).toEqualTypeOf() + return `${x}-foo` + }, + ), + ) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe('1-foo') +}) diff --git a/source/unwind.d.ts b/source/unwind.d.ts new file mode 100644 index 00000000..859ba953 --- /dev/null +++ b/source/unwind.d.ts @@ -0,0 +1 @@ +export { unwind } from '../files/index' diff --git a/source/unwind.spec.ts b/source/unwind.spec.ts new file mode 100644 index 00000000..81bd5c78 --- /dev/null +++ b/source/unwind.spec.ts @@ -0,0 +1,37 @@ +import { unwind } from './unwind' +import { pipe } from './pipe' + +const obj = { + a: 1, + b: [2, 3], +} + +test('happy', () => { + const obj = { + a: 1, + b: [2, 3], + c: [3, 4], + } + const expected = [ + { a: 1, b: 2, c: [3, 4] }, + { a: 1, b: 3, c: [3, 4] }, + ] + const result = unwind('b')(obj) + expect(result).toEqual(expected) +}) + +test('type test', () => { + const [result] = unwind('b')(obj) + + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expect(result).toEqual({ a: 1, b: 2 }) +}) + +test('inside pipe', () => { + const [result] = pipe(obj, unwind('b')) + + expectTypeOf(result.a).toEqualTypeOf() + expectTypeOf(result.b).toEqualTypeOf() + expect(result).toEqual({ a: 1, b: 2 }) +}) diff --git a/source/update.d.ts b/source/update.d.ts new file mode 100644 index 00000000..37b1eee6 --- /dev/null +++ b/source/update.d.ts @@ -0,0 +1 @@ +export { update } from '../files/index' diff --git a/source/update.spec.ts b/source/update.spec.ts new file mode 100644 index 00000000..eb1f31cf --- /dev/null +++ b/source/update.spec.ts @@ -0,0 +1,28 @@ +import { update } from './update' + +const list = [1, 2, 3] + +test('happy', () => { + const newValue = 8 + const index = 1 + const result = update(index, newValue)(list) + + const expected = [1, 8, 3] + expect(result).toEqual(expected) +}) + +test('list has no such index', () => { + const newValue = 8 + const index = 10 + const result = update(index, newValue)(list) + + expect(result).toEqual(list) +}) + +test('with negative index', () => { + expect(update(-1, 10)([1])).toEqual([10]) + expect(update(-1, 10)([])).toEqual([]) + expect(update(-1, 10)(list)).toEqual([1, 2, 10]) + expect(update(-2, 10)(list)).toEqual([1, 10, 3]) + expect(update(-3, 10)(list)).toEqual([10, 2, 3]) +}) diff --git a/source/vitest-globals.d.ts b/source/vitest-globals.d.ts new file mode 100644 index 00000000..9896c472 --- /dev/null +++ b/source/vitest-globals.d.ts @@ -0,0 +1 @@ +/// diff --git a/source/when.d.ts b/source/when.d.ts new file mode 100644 index 00000000..cabd51ed --- /dev/null +++ b/source/when.d.ts @@ -0,0 +1 @@ +export { when } from '../files/index' diff --git a/source/when.spec.ts b/source/when.spec.ts new file mode 100644 index 00000000..a1934de3 --- /dev/null +++ b/source/when.spec.ts @@ -0,0 +1,47 @@ +import { head } from './head' +import { pipe } from './pipe' +import { tap } from './tap' +import { when } from './when' + +const predicate = x => typeof x === 'number' + +test('happy', () => { + const fn = when(predicate, x => x + 1) + expect(fn(11)).toBe(12) + expect(fn('foo')).toBe('foo') +}) + +function notNull(a: T | null | undefined): a is T { + return a != null +} + +test('type test', () => { + const result = pipe( + 1, + when( + x => x > 2, + x => x, + ), + tap(x => { + expectTypeOf(x).toEqualTypeOf() + }), + when( + x => x > 2, + x => String(x), + ), + ) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(1) +}) + +test('with assertion of type', () => { + const result = pipe( + [1, null, 2, 3], + head, + when(notNull, x => x + 1), + ) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toBe(2) +}) diff --git a/source/zip.d.ts b/source/zip.d.ts new file mode 100644 index 00000000..b8908b77 --- /dev/null +++ b/source/zip.d.ts @@ -0,0 +1 @@ +export { zip } from '../files/index' diff --git a/source/zip.spec.ts b/source/zip.spec.ts new file mode 100644 index 00000000..f879f105 --- /dev/null +++ b/source/zip.spec.ts @@ -0,0 +1,43 @@ +import { zip } from './zip' + +const array1 = [1, 2, 3] +const array2 = ['A', 'B', 'C'] + +test('should return an array', () => { + const actual = zip(array1)(array2) + expect(actual).toBeInstanceOf(Array) +}) + +test('should return and array or tuples', () => { + const expected = [ + [1, 'A'], + [2, 'B'], + [3, 'C'], + ] + const actual = zip(array1)(array2) + expect(actual).toEqual(expected) +}) + +test('should truncate result to length of shorted input list', () => { + const expectedA = [ + [1, 'A'], + [2, 'B'], + ] + const actualA = zip([1, 2])(array2) + expect(actualA).toEqual(expectedA) + + const expectedB = [ + [1, 'A'], + [2, 'B'], + ] + const actualB = zip(array1)(['A', 'B']) + expect(actualB).toEqual(expectedB) +}) + +test('type test', () => { + const result = zip(array1)(array2) + + expectTypeOf(result[0][0]).toEqualTypeOf() + expectTypeOf(result[0][1]).toEqualTypeOf() + expect(result).toEqual([[1, 'A'], [2, 'B'], [3, 'C']]) +}) diff --git a/source/zipWith.d.ts b/source/zipWith.d.ts new file mode 100644 index 00000000..82502a18 --- /dev/null +++ b/source/zipWith.d.ts @@ -0,0 +1 @@ +export { zipWith } from '../files/index' diff --git a/source/zipWith.spec.ts b/source/zipWith.spec.ts new file mode 100644 index 00000000..d22caced --- /dev/null +++ b/source/zipWith.spec.ts @@ -0,0 +1,31 @@ +import { pipe } from './pipe' +import { zipWith } from './zipWith' + +const add = (x, y) => x + y +const list1 = [1, 2, 3] +const list2 = [10, 20, 30, 40] +const list3 = [100, 200] + +test('when second list is shorter', () => { + const result = zipWith(add, list1)(list3) + expect(result).toEqual([101, 202]) +}) + +test('when second list is longer', () => { + const result = zipWith(add, list1)(list2) + expect(result).toEqual([11, 22, 33]) +}) + +test('type test', () => { + const result = pipe( + list2, + zipWith((x, y) => { + expectTypeOf(x).toEqualTypeOf() + expectTypeOf(y).toEqualTypeOf() + return `${x}-${y}` + }, list1), + ) + + expectTypeOf(result).toEqualTypeOf() + expect(result).toEqual(['1-10', '2-20', '3-30']) +}) diff --git a/vitest.config.js b/vitest.config.js index 2ed8cab3..d5e1d0a2 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -1,9 +1,9 @@ import { defineConfig } from 'vitest/config' -export default defineConfig(env => ({ +export default defineConfig(() => ({ test: { globals: true, - include: ['source/**/*.spec.js', 'source/**/*-spec.ts'], + include: ['source/**/*.spec.js', 'source/**/*-spec.ts', 'source/**/*.spec.ts'], exclude: ['source/_internals/**'], coverage: { thresholds: { 100: true }, diff --git a/vitest.typings.config.js b/vitest.typings.config.js index bedd3406..931dcad9 100644 --- a/vitest.typings.config.js +++ b/vitest.typings.config.js @@ -4,7 +4,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { globals: true, - include: ['source/**/*-spec.ts'], + include: ['source/**/*-spec.ts', 'source/**/*.spec.ts'], exclude: ['source/_internals/**'], }, }) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 7518f0ba..44689d9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,24 +4,24 @@ "@babel/helper-string-parser@^7.27.1": version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz" integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== "@babel/helper-validator-identifier@^7.28.5": version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz" integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== "@babel/parser@^7.29.3": version "7.29.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.3.tgz#116f70a77958307fceac27747573032f8a62f88e" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz" integrity sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA== dependencies: "@babel/types" "^7.29.0" "@babel/types@^7.29.0": version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz" integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== dependencies: "@babel/helper-string-parser" "^7.27.1" @@ -29,328 +29,433 @@ "@bcoe/v8-coverage@^1.0.2": version "1.0.2" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz#bbe12dca5b4ef983a0d0af4b07b9bc90ea0ababa" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz" integrity sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA== -"@emnapi/core@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.10.0.tgz#380ccc8f2412ea22d1d972df7f8ee23a3b9c7467" - integrity sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw== +"@emnapi/core@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.11.1.tgz#b9e1064f3a6b1631e241e638eb48d736bfd372a6" + integrity sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ== dependencies: - "@emnapi/wasi-threads" "1.2.1" + "@emnapi/wasi-threads" "1.2.2" tslib "^2.4.0" -"@emnapi/runtime@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.10.0.tgz#4b260c0d3534204e98c6110b8db1a987d26ec87c" - integrity sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA== +"@emnapi/runtime@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.11.1.tgz#58f1f3d5d81a9b12f793ab688c96371901027c24" + integrity sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw== dependencies: tslib "^2.4.0" -"@emnapi/wasi-threads@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz#28fed21a1ba1ce797c44a070abc94d42f3ae8548" - integrity sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w== +"@emnapi/wasi-threads@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz#4c93becf5bfa3b13d1bbdcc06aee38321ad8139a" + integrity sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA== dependencies: tslib "^2.4.0" "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/sourcemap-codec@^1.4.14": version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== "@jridgewell/trace-mapping@^0.3.31": version "0.3.31" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz" integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@napi-rs/wasm-runtime@^1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz#a46bbfedc29751b7170c5d23bc1d8ee8c7e3c1e1" - integrity sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow== +"@napi-rs/wasm-runtime@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz#ed33806d0f9be98dc76d0c3d4fd872fda701b5d5" + integrity sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg== dependencies: - "@tybys/wasm-util" "^0.10.1" + "@tybys/wasm-util" "^0.10.3" -"@oxc-project/types@=0.130.0": - version "0.130.0" - resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.130.0.tgz#a7825148711dc28805c46cfc21d94b63a4d41e88" - integrity sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q== +"@oxc-project/types@=0.138.0": + version "0.138.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.138.0.tgz#ce9690ec80144b4c38dfed44e76a67b911df9aca" + integrity sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA== -"@rolldown/binding-android-arm64@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz#7b250c89f16d74affd581dbe38f702e8c2c644d3" - integrity sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg== +"@rolldown/binding-android-arm64@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.4.tgz#6c31f378f42d5ea75b37970d2add539682264792" + integrity sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw== -"@rolldown/binding-darwin-arm64@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz#cd4de96687e6522062984b0503fbffbbc9220023" - integrity sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg== +"@rolldown/binding-darwin-arm64@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.4.tgz#1dbbbbaf2b00d13b32127cbf3a379d6ef69fd647" + integrity sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ== -"@rolldown/binding-darwin-x64@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz#5b0a631e3784d5a7741dd93097dcf6dfca029960" - integrity sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg== +"@rolldown/binding-darwin-x64@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.4.tgz#3b8f76dfd462e28e8914e7ded63647194866329f" + integrity sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg== -"@rolldown/binding-freebsd-x64@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz#d82e561079db89f796438f56ec11bb3565ee1875" - integrity sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw== +"@rolldown/binding-freebsd-x64@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.4.tgz#7f3f82c6a7b9fcec4e24c29e89d8343c9c72d403" + integrity sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ== -"@rolldown/binding-linux-arm-gnueabihf@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz#f2645afff4253c7b46b80ba14af5fd3fc18d45dc" - integrity sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ== +"@rolldown/binding-linux-arm-gnueabihf@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.4.tgz#baee435c7addf84e58fee72c70e98acc603aba3e" + integrity sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA== -"@rolldown/binding-linux-arm64-gnu@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz#a16b97f175e7b115c5ece77c7b648d0c868f4486" - integrity sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A== +"@rolldown/binding-linux-arm64-gnu@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.4.tgz#cc8c63913bac68bf1f49a0d095634e09008741ce" + integrity sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w== -"@rolldown/binding-linux-arm64-musl@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz#e695aec4ef2c8713c9d959b42a208059891276da" - integrity sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg== +"@rolldown/binding-linux-arm64-musl@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.4.tgz#aaa1d02f5ee705bd6812ff84ab1f7752ba4e4497" + integrity sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng== -"@rolldown/binding-linux-ppc64-gnu@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz#4a9edf16112cbe99cdd396c60efac39cbd1758ac" - integrity sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg== +"@rolldown/binding-linux-ppc64-gnu@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.4.tgz#9e26bb9ba2a846039902270b778d1d3ba0b62033" + integrity sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg== -"@rolldown/binding-linux-s390x-gnu@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz#314aa3ec1ce8251501d865f98fb91e42a1e671e4" - integrity sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ== +"@rolldown/binding-linux-s390x-gnu@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.4.tgz#d9ec4d5b1bd6f8029072670da9f0d58e728e8c44" + integrity sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ== -"@rolldown/binding-linux-x64-gnu@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz#7c51f13cf1141c503ee162830b4fc692d91640be" - integrity sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw== +"@rolldown/binding-linux-x64-gnu@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.4.tgz#6cc9cad61ea020ac2191037755a36f8fcfa11434" + integrity sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw== -"@rolldown/binding-linux-x64-musl@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz#b7213936bbc9310b02a34f71cefd25f9e71f329b" - integrity sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ== +"@rolldown/binding-linux-x64-musl@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.4.tgz#d23df39a184be427877da934fc3c30e3f25cd686" + integrity sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ== -"@rolldown/binding-openharmony-arm64@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz#006e88acde4f12b41a4c72292685c9dc9e6a3627" - integrity sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ== +"@rolldown/binding-openharmony-arm64@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.4.tgz#189d1a062624f57f9b0a52f94163d51b6aa692ab" + integrity sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA== -"@rolldown/binding-wasm32-wasi@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz#033525c84da217418232f35be19f1ddc0af4f31e" - integrity sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ== +"@rolldown/binding-wasm32-wasi@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.4.tgz#98c634b91a9abf5de74b8402aa8063fb5044efd4" + integrity sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg== dependencies: - "@emnapi/core" "1.10.0" - "@emnapi/runtime" "1.10.0" - "@napi-rs/wasm-runtime" "^1.1.4" + "@emnapi/core" "1.11.1" + "@emnapi/runtime" "1.11.1" + "@napi-rs/wasm-runtime" "^1.1.6" -"@rolldown/binding-win32-arm64-msvc@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz#febbf109cf1b5837e21369f0e0d2fefca1519c39" - integrity sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw== +"@rolldown/binding-win32-arm64-msvc@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.4.tgz#1c8c8515c811ae28fc26355079b80f617fdddb0b" + integrity sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA== -"@rolldown/binding-win32-x64-msvc@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz#dfb32a67ccb0deaa3c9a57f6cb4890b5697dfa2c" - integrity sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ== +"@rolldown/binding-win32-x64-msvc@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.4.tgz#e14b1ef53473f51a4180d9b46c5f0cea9f1713cb" + integrity sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ== "@rolldown/pluginutils@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz#e3fcee093fbb5ce765e1ad088ff4de2889f6f9be" integrity sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw== -"@rollup/rollup-android-arm-eabi@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz#3a04f01e9f01392bbef5920b94aa3b88794be7ab" - integrity sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ== - -"@rollup/rollup-android-arm64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz#e371b653ceabc900790ae73f5548a0fd7cd63a70" - integrity sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw== - -"@rollup/rollup-darwin-arm64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz#2a5aa70432e39816d666d79287a7324cfc3b4e72" - integrity sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA== - -"@rollup/rollup-darwin-x64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz#c3b5b49629379cd9cdc5d841bf00ed44ebf393dd" - integrity sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg== - -"@rollup/rollup-freebsd-arm64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz#f929d8e0462fae6602fc960beeabd7287d859283" - integrity sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g== - -"@rollup/rollup-freebsd-x64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz#c01cb58031226f95d0900b1ec847f4fb32c6e809" - integrity sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw== - -"@rollup/rollup-linux-arm-gnueabihf@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz#f29d890c4858c8e0d3be01677eef4f6a359eed9d" - integrity sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA== - -"@rollup/rollup-linux-arm-musleabihf@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz#1ebfc8eb9f66136ed2faae5f44995add5ca3c964" - integrity sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w== - -"@rollup/rollup-linux-arm64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz#c1fa823c2c4ce46ba7f61de1a4c3fdadd4fb4e7b" - integrity sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg== - -"@rollup/rollup-linux-arm64-musl@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz#a7f18854d0471b78bda8ea38f0891a4e059b571d" - integrity sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A== - -"@rollup/rollup-linux-loong64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz#83658a9a4576bcce8cef85b2c78b9b649d2200c4" - integrity sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ== - -"@rollup/rollup-linux-loong64-musl@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz#fd2af677ae3417bb58d57ae37dd0d84686e40244" - integrity sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw== - -"@rollup/rollup-linux-ppc64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz#6481647181c4cf8f1ddbd99f62c84cfc56c1a94a" - integrity sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg== - -"@rollup/rollup-linux-ppc64-musl@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz#18610a1a1550e28a5042ca916f898419540f17f4" - integrity sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A== - -"@rollup/rollup-linux-riscv64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz#597bb80465a2621dbe0de0a41c66394a8a7e9a6e" - integrity sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA== - -"@rollup/rollup-linux-riscv64-musl@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz#a2a919a9f927ef7f24a60af77e3cb55f1ad59e4d" - integrity sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw== - -"@rollup/rollup-linux-s390x-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz#3166f6ceae7df9bbfddf9f36be1937231e13e3c6" - integrity sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ== - -"@rollup/rollup-linux-x64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz#23c9bf79771d804fb87415eb0767569f273261e5" - integrity sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ== - -"@rollup/rollup-linux-x64-musl@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz#97941c6b94d67fe25cde0f027c10a19f2d1fdd39" - integrity sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg== - -"@rollup/rollup-openbsd-x64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz#7aeb7d92e2cd1d399f56daf75c39040b777b6c77" - integrity sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA== - -"@rollup/rollup-openharmony-arm64@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz#925de61ae83bf99aa636e8acea87432e8c0ffaab" - integrity sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg== - -"@rollup/rollup-win32-arm64-msvc@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz#888ab83842721491044c46a7407e1f38f3235bb4" - integrity sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw== - -"@rollup/rollup-win32-ia32-msvc@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz#fa30ac24e3f0232139d2a47500560a28695764d4" - integrity sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA== - -"@rollup/rollup-win32-x64-gnu@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz#223e2bc93f86e0707568e1fadb5b537e50c976c7" - integrity sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw== - -"@rollup/rollup-win32-x64-msvc@4.60.4": - version "4.60.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz#da4f1676d87e2bdf744291b504b0ab79550c3e61" - integrity sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw== - -"@tybys/wasm-util@^0.10.1": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.2.tgz#12b3a1b33db1f9cad4ddff1f604ab7dd00bf464e" - integrity sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg== +"@rollup/rollup-android-arm-eabi@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz#5e9849b661c2229cf967a08dbe2dbbe9e8c991e5" + integrity sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg== + +"@rollup/rollup-android-arm64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz#5b0699ee5dd484b222c9ed74aff43c91ea8b17f8" + integrity sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw== + +"@rollup/rollup-darwin-arm64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz#8bc52c9d7a3ce8d0533c351a9c935de781daa06f" + integrity sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A== + +"@rollup/rollup-darwin-x64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz#ba2ef3e8fb310f0af35588f270cfa5aa96e48764" + integrity sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA== + +"@rollup/rollup-freebsd-arm64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz#93b10bdbfe8ada226b8bc0c02ef6b7f544474d96" + integrity sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw== + +"@rollup/rollup-freebsd-x64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz#3e8aa38ef3c9c300946871e3fdbb0c30e0a20f86" + integrity sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg== + +"@rollup/rollup-linux-arm-gnueabihf@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz#1d7994384bb0ad1bc41921b506e1642d4f9d7fc3" + integrity sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg== + +"@rollup/rollup-linux-arm-musleabihf@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz#a6540f47cf844a56b80ca9ff95d2acdfb2cef97b" + integrity sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA== + +"@rollup/rollup-linux-arm64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz#404f2045651840cbf48da91ba6d0f490f0bc2cbf" + integrity sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA== + +"@rollup/rollup-linux-arm64-musl@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz#a3404ffddf7b474b48c99b9c893b6247bb765ba5" + integrity sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ== + +"@rollup/rollup-linux-loong64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz#e8aac6d549b377945e349882f199b7c8eb75ca38" + integrity sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg== + +"@rollup/rollup-linux-loong64-musl@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz#6e2e44ea50310b3a582078a915e5feb879c820d4" + integrity sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ== + +"@rollup/rollup-linux-ppc64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz#6898302da6d77a0537cde64b2b4c6b60659bd110" + integrity sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A== + +"@rollup/rollup-linux-ppc64-musl@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz#333717c95dd5a66bef8f63e7ef8a9fd845fd18d0" + integrity sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w== + +"@rollup/rollup-linux-riscv64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz#81bc06ba380352004d01f4826eb7cdccefa05bad" + integrity sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg== + +"@rollup/rollup-linux-riscv64-musl@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz#95a7cd39de21389ad6788a5284eaaa738e29ca4c" + integrity sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q== + +"@rollup/rollup-linux-s390x-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz#06e6db2ec1bc48b5374c7923ef83c2eb024b2452" + integrity sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg== + +"@rollup/rollup-linux-x64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz#5dc818988285e09e88790c6462def72413df2da3" + integrity sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A== + +"@rollup/rollup-linux-x64-musl@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz#2080f4a93349e9afd34be6fc1a37e01fc8bfc80f" + integrity sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg== + +"@rollup/rollup-openbsd-x64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz#21d64a8acb66221724b923e51af5333df1af044b" + integrity sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg== + +"@rollup/rollup-openharmony-arm64@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz#8e0fcd9d02141e337b4c5b5cff576cb9a76b1ba0" + integrity sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA== + +"@rollup/rollup-win32-arm64-msvc@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz#bdb4cc4efd58efe808203347f0f5463f0ea16e52" + integrity sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg== + +"@rollup/rollup-win32-ia32-msvc@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz#dbaebde5afd24eae0eefe915d901632e7cb59860" + integrity sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q== + +"@rollup/rollup-win32-x64-gnu@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz#84109e85fea5f8f1353499f96578fdc2a0e8b138" + integrity sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg== + +"@rollup/rollup-win32-x64-msvc@4.62.2": + version "4.62.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz#3671ce3f9b928d5c01f879792d5c0b60ae14d4ad" + integrity sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA== + +"@standard-schema/spec@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" + integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== + +"@tybys/wasm-util@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz#015cba9e9dd47ce14d03d2a8c5d547bfb169665d" + integrity sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg== dependencies: tslib "^2.4.0" "@types/chai@^5.2.2": version "5.2.2" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.2.tgz#6f14cea18180ffc4416bc0fd12be05fdd73bdd6b" + resolved "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz" integrity sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg== dependencies: "@types/deep-eql" "*" "@types/deep-eql@*": version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz" integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== -"@types/estree@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" - integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== +"@types/estree@1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24" + integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg== "@types/estree@^1.0.0": version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== "@types/mocha@10.0.10": version "10.0.10" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz" integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== -"@types/node@25.8.0": - version "25.8.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.8.0.tgz#d13033397d1c186876bed4c9b9d7f3f962097eb3" - integrity sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ== +"@types/node@26.1.0": + version "26.1.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-26.1.0.tgz#aa85f0727fc5611347091c478341c63650903439" + integrity sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw== dependencies: - undici-types ">=7.24.0 <7.24.7" + undici-types "~8.3.0" "@types/tinycolor2@^1.4.0": version "1.4.6" - resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.6.tgz#670cbc0caf4e58dd61d1e3a6f26386e473087f06" + resolved "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz" integrity sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw== -"@vitest/coverage-v8@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-5.0.0-beta.2.tgz#24fac5f3cd5308aa2605735b9f24c60391a2f344" - integrity sha512-sRRGUEWDwapKSwWNPftXkajT4kNRiWYWsWoWrAjusQRet9yjXGrsdPEKBcvPL02zbQOaf8MkC7GG5vti6kw43A== +"@typescript/typescript-aix-ppc64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.1-rc.tgz#1a70f9027d000181e9695793383f3940061cbf04" + integrity sha512-oqq2ZfEJ7BQuufcC3QBQndZLPNyamYNHLao8lKRBeeSkZKypBqxPSgkzrcFZtbYcIaBvpiyUnQP9MT7DEYHWbw== + +"@typescript/typescript-darwin-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.1-rc.tgz#dee4a0eba61cc25425573b78537d1448c0a3dfd6" + integrity sha512-Slc0yTftT2F/uGDmtPst8ijydneL6uZaLEyr2UjahxZpbhTjHFBJ5agXtVz/TL4A+ldxzjzj+E8QtLZlh/5mXw== + +"@typescript/typescript-darwin-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.1-rc.tgz#c1bf844eb2b0231e93f92d24d0c9a928dbda11c8" + integrity sha512-h68iFW/LbA1/BsGgSRGFw981/3s1f/rY27YrmeZNuN+ly7dI+fiDduwT9ZT9866x2onoKNRq7PTyxSKyKDzfAQ== + +"@typescript/typescript-freebsd-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.1-rc.tgz#7bc9c6cb78d233d9676a92127a1531c1c8d378bd" + integrity sha512-DE+ppd8Ix2c6OMuRkKY4PJ4hngMGJ9M95OQUP17p9xL/1IKXof7npIeuusMN/bgL5o5JzMfSGh+N+5scTYRg0Q== + +"@typescript/typescript-freebsd-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.1-rc.tgz#3916d9d760aaf2a1a42ddb654ca1f34d4034bffe" + integrity sha512-ST1ozHMw0u+CLOnWkcTyWDMV4Qn9osZ6fd1V1lnKDM1t0hZIp81mdGpdHxyHJjd7jdGrb6Gb/QXcZ1uqZ0t5zw== + +"@typescript/typescript-linux-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.1-rc.tgz#b64e05934b319036b4dd7faf6991f4c568b4d660" + integrity sha512-N46pRihK3t5zD5MUtTQcdmQUqr1WI4U2nxno1gLwOtRSsB4krFkRjPHcQNG7h2DtRkX64rQiReX6WKwg2wprMA== + +"@typescript/typescript-linux-arm@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.1-rc.tgz#0f531bc7fdf8f8f30fdb982da240ed4bf9a28f35" + integrity sha512-gHmHwT5Naq5CKM8g9bbaGeEpnwQEvWCLn3fwP4K2m61VQdDKkPk0Dhab/OoZ4LV2SrMddmclYXTzpyg23YGt5g== + +"@typescript/typescript-linux-loong64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.1-rc.tgz#bc4275d26a63c5f1c2408ea50effc940945f6d9d" + integrity sha512-G17Sao312rgiPBTh2F4nOpLpa3CcnBSaNhqNghZk2LNhnsp1RaMO5HMq2me21gqu9xLpc6CIgHtOzU6JBgNlfg== + +"@typescript/typescript-linux-mips64el@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.1-rc.tgz#7600bcd9ddc5dfbea1effe75b4412e6e541439b9" + integrity sha512-0FQspOb5UsQ4tQKvWgUO3pS9OIWkP7/8dPRWq+CRazJUeQZ4LBjtYK52jg5iIOrvItrVl2CwvRtrU3/9OihwJg== + +"@typescript/typescript-linux-ppc64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.1-rc.tgz#ab2c6f38402731e540f297466ff7ce34ef06ea62" + integrity sha512-SUmwfVBEv6A2Ld0eWfcvW0FqrgemfQL8jFGOmV1qYxsDqumjE5DekHXqbstgmbE4SHr4rrjHjvmuGCY+kTH/vw== + +"@typescript/typescript-linux-riscv64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.1-rc.tgz#0fd9dc6b13db6da1c43ea927feaf8357d0444518" + integrity sha512-rxeqnNnGiYzv/LlPHi/3+4p0ooR1cNJLjRIHXKovtiVmxXGJq6gtw8VSpbHuWPekyFMXgIAoLCZN0SQ51rAALQ== + +"@typescript/typescript-linux-s390x@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.1-rc.tgz#e8cbed22cdfc251063eefb9e762138b037099218" + integrity sha512-RYWCHCiPypxajdRHM2CNK/eM22e4Ex5TTjV2pXf7PTtBowGr0xX8i8kIMknyZS0LX2QfleYHouaoMVsFDSle3g== + +"@typescript/typescript-linux-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.1-rc.tgz#e0a21851d783270d6638ea62186865499573e504" + integrity sha512-PfLJSu0JzroDkqw2m4nqflPEcn8yev0m/vHFQlY9EzHorzjR6QG0wL8AJHvnD1e6h1s76AZngJ5u+z1K/D/HKw== + +"@typescript/typescript-netbsd-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.1-rc.tgz#a3cf5068e1a3044e0b927fc77a5a446d39812e3a" + integrity sha512-FfbPxH3dTfp8yVIaNM7bdWTixXuyxpzoemluqcqMROSIz+ImpCG3Q9HO9Ptzp9/giv+P9YYEnCMSXh61migj2w== + +"@typescript/typescript-netbsd-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.1-rc.tgz#c207f70f2e3383c24e53b16dd0c9a67e55610b18" + integrity sha512-FzdTfSzhRYb6hlav6K3cI5RVgcvCTvNAu/vc+t7B6AmZkThQ+t/1ntnvT5fnHmY1Az2RIBw7/b+qtCEG61HJTQ== + +"@typescript/typescript-openbsd-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.1-rc.tgz#8a2d194c2badf1f70d43198ba9e1a0826717eb43" + integrity sha512-PQGhlxfNig+0YQ9Wwzd0USPBkt6w/ZqkBQWsU7G/0JkTzunJel+jSWwhKw4947pak/m7hGSeYiI04xReDLGZww== + +"@typescript/typescript-openbsd-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.1-rc.tgz#da3c1fc1c70bfcd6694b95a588d3ca741c56732d" + integrity sha512-WJ7NYgO2mHmLUkI/tZ+hl8lFd26QPJqO8ONOHNuYbdsybLvSB6B6sep222JIVrOfPRDGvFinbGGB+l3m1FWRWA== + +"@typescript/typescript-sunos-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.1-rc.tgz#4f7665b930ae91716142efe008d7f7c232fd5f88" + integrity sha512-UYjDeUxd765V9qcwlUPk4pEXyL0i3G76CJm9baK4i99u1pGO1psf3nXDw4MMmElVOPvGbZag99ZR/O59E2OX6w== + +"@typescript/typescript-win32-arm64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.1-rc.tgz#7f16d54f0bcd7c87f1b06b3f68ace67bec04eb52" + integrity sha512-KzXzFSXZOm7zvEt2Aw0MsB2LbTL88znAiVqTDNAOHdlEb7brgmUQh/X2wM/8Be+N0fjEqWKl65cBKNwpWEbJiw== + +"@typescript/typescript-win32-x64@7.0.1-rc": + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.1-rc.tgz#bb3c3a5e455123b49bdadd6367ed40abf390b95c" + integrity sha512-98R3+OqDr/r0/PLWEoXu88AE0lGVLNd335Ew8ONgzK1JWkNs4ou/5BGt3Or1ij4iXjH+c7PRL+jFjCbtWze+EA== + +"@vitest/coverage-v8@5.0.0-beta.5": + version "5.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-5.0.0-beta.5.tgz#f5899b8bca3c0d6cd59925b376c96aea48023849" + integrity sha512-trID5lraLV94hgKp9rK09EUF5PkUYBZZaMwii+zuZDZTmsh4QDlN2UjjLi9ZlabfP+pWR7DRiReLCmWRr/bmUg== dependencies: "@bcoe/v8-coverage" "^1.0.2" - "@vitest/utils" "5.0.0-beta.2" + "@vitest/utils" "5.0.0-beta.5" ast-v8-to-istanbul "^1.0.0" istanbul-lib-coverage "^3.2.2" istanbul-lib-report "^3.0.1" @@ -360,76 +465,114 @@ std-env "^4.0.0-rc.1" tinyrainbow "^3.1.0" -"@vitest/mocker@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-5.0.0-beta.2.tgz#6f55d5d668c5a28dbd6c927a6ad0cf74bd203099" - integrity sha512-MraW8T92TOcCd0MG+1gz5YeGgIGNsfiIcxuP9Azy7qcIxUwQ3zmngU1NbfvG0HRWVY++/FLsJ/xdKFsb7vZS0w== +"@vitest/expect@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.9.tgz#ba1af73ae53262e3dc9b518cb7b76fb614e0ef53" + integrity sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA== + dependencies: + "@standard-schema/spec" "^1.1.0" + "@types/chai" "^5.2.2" + "@vitest/spy" "4.1.9" + "@vitest/utils" "4.1.9" + chai "^6.2.2" + tinyrainbow "^3.1.0" + +"@vitest/mocker@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.9.tgz#a483de79b358aba3dd8f319a0d8ab17c89f5c75d" + integrity sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw== dependencies: - "@vitest/spy" "5.0.0-beta.2" + "@vitest/spy" "4.1.9" estree-walker "^3.0.3" magic-string "^0.30.21" -"@vitest/pretty-format@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-5.0.0-beta.2.tgz#1c2076c1b137b01fbfd9af25603e952086598e52" - integrity sha512-mMl+7McYN0g7ORBsufBB5CwpsV8e/kK/0ytiFwSWSK8181C5n0WjsxDysm9wxsNsAZ8T/EnEv0unWNa8CyOUVw== +"@vitest/pretty-format@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.9.tgz#885cfe9fcb6ff3df4409ea66192cc1fb23d62fae" + integrity sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A== dependencies: tinyrainbow "^3.1.0" -"@vitest/runner@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-5.0.0-beta.2.tgz#867679b1bfb64e1b3e4674a56774d820ed4b6737" - integrity sha512-9FjC3DzggveiRcXXh0zP2ko4+D9W6GfrmpAlLjuCp/vr2nJSb8rGLKkyz3g072ZHbpx8XxLoPg411eVRnrPmvg== +"@vitest/pretty-format@5.0.0-beta.5": + version "5.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-5.0.0-beta.5.tgz#84a9e9edc9c40e15dcc26a2d4ea7e2c0bb006d18" + integrity sha512-eFj80bS7sN1aOOV7Ibi/sDYhhzs1fj2S8+/Y2mjOw2POpSW/6Esjj7FIdj0cD2/cdsKFumEokh+ijVijisd9+w== + dependencies: + tinyrainbow "^3.1.0" + +"@vitest/runner@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.9.tgz#bb742947ce4841dfb2d8984a2f9014850be10f51" + integrity sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg== + dependencies: + "@vitest/utils" "4.1.9" + pathe "^2.0.3" + +"@vitest/snapshot@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.9.tgz#bdfb670ae5617613ea8776e93d0666a66defeeb7" + integrity sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA== dependencies: - "@vitest/utils" "5.0.0-beta.2" + "@vitest/pretty-format" "4.1.9" + "@vitest/utils" "4.1.9" + magic-string "^0.30.21" pathe "^2.0.3" -"@vitest/spy@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-5.0.0-beta.2.tgz#2b90c27e9aac075702aaee509b4801a352571aec" - integrity sha512-P5t/CesIZSAdZ5OA2AR34JEulKoLGgy4owaO5KorzzTmld8gLBgjdUAHc0oO+YTtLOgtxkc7J57xJCVZkC/6wA== +"@vitest/spy@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.9.tgz#bfc40d48fb9bd1a1228bfbfde7f5555e7f6b3867" + integrity sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA== -"@vitest/utils@5.0.0-beta.2": - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-5.0.0-beta.2.tgz#64efde8f9c1bb60f8029e2ff006f851a00121422" - integrity sha512-62fiZ9rgF8x8CpI10prslir65AvUIo3Fc9dI4hOVm05sjRV1Ss65U0N832kBWq4DhmuylAJFuoWqwyX+rylu5g== +"@vitest/utils@4.1.9": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.9.tgz#0184c7e6eb3234739b2b6b3b985f78d1ed823ee1" + integrity sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA== dependencies: - "@vitest/pretty-format" "5.0.0-beta.2" + "@vitest/pretty-format" "4.1.9" + convert-source-map "^2.0.0" + tinyrainbow "^3.1.0" + +"@vitest/utils@5.0.0-beta.5": + version "5.0.0-beta.5" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-5.0.0-beta.5.tgz#44eab57b9b0a16283f860d3205c735f4c1ab747f" + integrity sha512-M+DZy1Q7v6//AbTYjVy86ChuF4tgSdGySVpH49kSkES16IRL5QRSmtAPdZVQ19S6Eke+NzAqWn1PUZNKljftfg== + dependencies: + "@vitest/pretty-format" "5.0.0-beta.5" convert-source-map "^2.0.0" tinyrainbow "^3.1.0" ansi-align@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz" integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== dependencies: string-width "^4.1.0" ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.2.2: version "6.2.2" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz" integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== ansi-styles@^3.2.0: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^6.2.1: version "6.2.3" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz" integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== ast-v8-to-istanbul@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz#d1e8bfc79fa9c452972ff91897633bda4e5e7577" + resolved "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz" integrity sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg== dependencies: "@jridgewell/trace-mapping" "^0.3.31" @@ -438,7 +581,7 @@ ast-v8-to-istanbul@^1.0.0: boxen@8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-8.0.1.tgz#7e9fcbb45e11a2d7e6daa8fdcebfc3242fc19fe3" + resolved "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz" integrity sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw== dependencies: ansi-align "^3.0.1" @@ -452,12 +595,12 @@ boxen@8.0.1: camelcase@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-8.0.0.tgz#c0d36d418753fb6ad9c5e0437579745c1c14a534" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz" integrity sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA== cfonts@3.3.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/cfonts/-/cfonts-3.3.1.tgz#38c149f0c292bb0cebcec637f8e50983e4785814" + resolved "https://registry.npmjs.org/cfonts/-/cfonts-3.3.1.tgz" integrity sha512-ZGEmN3W9mViWEDjsuPo4nK4h39sfh6YtoneFYp9WLPI/rw8BaSSrfQC6jkrGW3JMvV3ZnExJB/AEqXc/nHYxkw== dependencies: supports-color "^8" @@ -465,44 +608,44 @@ cfonts@3.3.1: chai@^6.2.2: version "6.2.2" - resolved "https://registry.yarnpkg.com/chai/-/chai-6.2.2.tgz#ae41b52c9aca87734505362717f3255facda360e" + resolved "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz" integrity sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg== chalk@5.6.2: version "5.6.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz" integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== chalk@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== cli-boxes@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" + resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz" integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== dependencies: is-descriptor "^1.0.0" @@ -514,46 +657,46 @@ detect-libc@^2.0.3: emoji-regex@^10.3.0: version "10.6.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz" integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== env-fn@2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/env-fn/-/env-fn-2.2.0.tgz#30288cd0294bcc8ac76f2ec9c71ec6ddb2736c43" + resolved "https://registry.npmjs.org/env-fn/-/env-fn-2.2.0.tgz" integrity sha512-hdR0Dpguc2GTA/d1lu7nBgze6gXB/bXkmN1nW6zlaRmRsw8mK4vTNuE0o4bbR0NfXTzgI7mecdGiHsqZRAeO9w== dependencies: rambda "6.4.0" es-module-lexer@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.1.0.tgz#1dfcbb5ea3bbfb63f28e1fc3676c3676d1c9624c" + resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz" integrity sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ== estree-walker@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz" integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== dependencies: "@types/estree" "^1.0.0" expect-type@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + resolved "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz" integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== fdir@6.5.0, fdir@^6.5.0: version "6.5.0" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== fs-extra@11.3.2: version "11.3.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.2.tgz#c838aeddc6f4a8c74dd15f85e11fe5511bfe02a4" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz" integrity sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A== dependencies: graceful-fs "^4.2.0" @@ -567,27 +710,27 @@ fsevents@~2.3.2, fsevents@~2.3.3: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== get-east-asian-width@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz#216900f91df11a8b2c198c3e1d93d6c035a776b9" + resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz" integrity sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA== get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== gradient-string@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-3.0.0.tgz#716d6d6f35309513fa92d38f506c6df0ce1f5ebb" + resolved "https://registry.npmjs.org/gradient-string/-/gradient-string-3.0.0.tgz" integrity sha512-frdKI4Qi8Ihp4C6wZNB565de/THpIaw3DjP5ku87M+N9rNSGmPTjfkq61SdRXB7eCaL8O1hkKDvf6CDMtOzIAg== dependencies: chalk "^5.3.0" @@ -595,19 +738,19 @@ gradient-string@3.0.0: has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== hasown@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" helpers-fn@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/helpers-fn/-/helpers-fn-2.1.1.tgz#65cf1d2ba5f134ff975a2949238e1a5f81ee4a27" + resolved "https://registry.npmjs.org/helpers-fn/-/helpers-fn-2.1.1.tgz" integrity sha512-BWKP+xKHyWpzrahTuzv8jjezQTUTMmWS5jxp4M3L6yReENrJUFcNCqRQGc/x/wfYMM4GKfcIQXsppPKSyjNTUg== dependencies: boxen "8.0.1" @@ -625,31 +768,31 @@ helpers-fn@2.1.1: html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== is-accessor-descriptor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz" integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== dependencies: hasown "^2.0.0" is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-data-descriptor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz" integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== dependencies: hasown "^2.0.0" is-descriptor@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz" integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== dependencies: is-accessor-descriptor "^1.0.1" @@ -657,51 +800,51 @@ is-descriptor@^1.0.0: is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-number@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== dependencies: kind-of "^3.0.2" is-obj@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz" integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== is-plain-object@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz" integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== is-unicode-supported@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz" integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== isobject@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -710,7 +853,7 @@ istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: istanbul-reports@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz" integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== dependencies: html-escaper "^2.0.0" @@ -718,12 +861,12 @@ istanbul-reports@^3.2.0: js-tokens@^10.0.0: version "10.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-10.0.0.tgz#dffe7599b4a8bb7fe30aff8d0235234dffb79831" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz" integrity sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q== jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: universalify "^2.0.0" @@ -732,7 +875,7 @@ jsonfile@^6.0.1: kind-of@^3.0.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== dependencies: is-buffer "^1.1.5" @@ -813,12 +956,12 @@ lightningcss@^1.32.0: lodash@4.18.1: version "4.18.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz" integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q== log-symbols@7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-7.0.1.tgz#f52e68037d96f589fc572ff2193dc424d48c195b" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz" integrity sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg== dependencies: is-unicode-supported "^2.0.0" @@ -826,14 +969,14 @@ log-symbols@7.0.1: magic-string@^0.30.21: version "0.30.21" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz" integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== dependencies: "@jridgewell/sourcemap-codec" "^1.5.5" magicast@^0.5.2: version "0.5.3" - resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.3.tgz#1800f6e76dd8b0dbe7257438a2c336aefabbd905" + resolved "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz" integrity sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw== dependencies: "@babel/parser" "^7.29.3" @@ -842,29 +985,29 @@ magicast@^0.5.2: make-dir@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: semver "^7.5.3" -nanoid@^3.3.11: - version "3.3.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== +nanoid@^3.3.12: + version "3.3.15" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.15.tgz#36c490fad8c6e86c824c940dfdde999b69ed4316" + integrity sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA== node-os-utils@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/node-os-utils/-/node-os-utils-2.0.1.tgz#a0ea8b30861396c0dab4e2733fa92bdba5257a00" + resolved "https://registry.npmjs.org/node-os-utils/-/node-os-utils-2.0.1.tgz" integrity sha512-rH2N3qHZETLhdgTGhMMCE8zU3gsWO4we1MFtrSiAI7tYWrnJRc6dk2PseV4co3Lb0v/MbRONLQI2biHQYbpTpg== obug@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.1.tgz#2cba74ff241beb77d63055ddf4cd1e9f90b538be" + resolved "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz" integrity sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ== pathe@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz" integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== picocolors@^1.1.1: @@ -874,26 +1017,26 @@ picocolors@^1.1.1: picomatch@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== picomatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" - integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== + version "4.0.5" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.5.tgz#51ea57a17d86f605f81039595fbc40ed06a55fab" + integrity sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A== -postcss@^8.5.14: - version "8.5.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.14.tgz#a66c2d7808fadf69ebb5b84a03f8bafd76c4919c" - integrity sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg== +postcss@^8.5.16: + version "8.5.16" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.16.tgz#1230ce0b5df354c24c0ea45f99ce5f6a88279d28" + integrity sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg== dependencies: - nanoid "^3.3.11" + nanoid "^3.3.12" picocolors "^1.1.1" source-map-js "^1.2.1" q-i@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/q-i/-/q-i-2.0.1.tgz#fec7e3f0e713f3467358bb5ac80bcc4c115187d6" + resolved "https://registry.npmjs.org/q-i/-/q-i-2.0.1.tgz" integrity sha512-tr7CzPNxkBDBuPzqi/HDUS4uBOppb91akNTeh56TYio8TiIeXp2Yp8ea9NmDu2DmGH35ZjJDq6C3E4SepVZ4bQ== dependencies: ansi-styles "^3.2.0" @@ -902,127 +1045,127 @@ q-i@2.0.1: radashi@13.0.0-beta.ffa4778: version "13.0.0-beta.ffa4778" - resolved "https://registry.yarnpkg.com/radashi/-/radashi-13.0.0-beta.ffa4778.tgz#9208595544e77cad5add33dcd1fb4e45212a0788" + resolved "https://registry.npmjs.org/radashi/-/radashi-13.0.0-beta.ffa4778.tgz" integrity sha512-hjuQJ787SpfHU7CMY+Y5i6dagK6EecKaHrRZjQS9ct31eJNankhngArFQxCcVnj5CdiKn1MVsGGZIfUNUC38iw== rambda@6.4.0: version "6.4.0" - resolved "https://registry.yarnpkg.com/rambda/-/rambda-6.4.0.tgz#bf080047b03d8d2c72e3ce5c17c603517a65749a" + resolved "https://registry.npmjs.org/rambda/-/rambda-6.4.0.tgz" integrity sha512-aBoE7YrGQP1xnxjyg5fhupfS+FTrDVjZMtwpezl15RKLNnKLOYDfjx/0xDE+8GyWbbZfODRkAOZmnpvxrAONbQ== rambdax@11.3.0: version "11.3.0" - resolved "https://registry.yarnpkg.com/rambdax/-/rambdax-11.3.0.tgz#1439408c310d674efbb853262033927303584733" + resolved "https://registry.npmjs.org/rambdax/-/rambdax-11.3.0.tgz" integrity sha512-3zj6gv1qXMlr/p90pV2psu+bK68lG+2JS0WoH0mHbPU8RZnLrCq9rsRq/gezsTYpbvhM+A3pfX0/5eSr1C0pFQ== rambdax@11.3.1: version "11.3.1" - resolved "https://registry.yarnpkg.com/rambdax/-/rambdax-11.3.1.tgz#b8136ca8a0eb96d0ea2c7f7723593b16d6b0e36d" + resolved "https://registry.npmjs.org/rambdax/-/rambdax-11.3.1.tgz" integrity sha512-ecsDpTQZuzZD16hPGpkja3klaho4I0tRp5IkjmUUrR7tNnw5RP9K/eiPfHev4HrRNr4OoUetIL/OOWFmeYls7A== ramda@0.32.0: version "0.32.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.32.0.tgz#b2116807b59b6b177af7a2ad19b14a3653570e96" + resolved "https://registry.npmjs.org/ramda/-/ramda-0.32.0.tgz" integrity sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ== -remeda@2.34.1: - version "2.34.1" - resolved "https://registry.yarnpkg.com/remeda/-/remeda-2.34.1.tgz#4c2038ea90d31716ca735ac05210331238bf96ef" - integrity sha512-k5iIF3lHm2NQ+2bNGDvZTD5jZl/JZkCS6AQOfGjYBd7V4rbb3K5whHvab0/O7CqPI43vYzbnIVCQXQJqmOyI6w== +remeda@2.39.0: + version "2.39.0" + resolved "https://registry.yarnpkg.com/remeda/-/remeda-2.39.0.tgz#ff10ab8ee5a2a84955ec1c1d173621051be69bd4" + integrity sha512-3Ki8dU1o3OVu4dwIQ2Pj+yiuP7OnEbmWAGmJ3yDRqopily5jsj8NWzPvbS89H85d6UdONKEcUnrfuHY6jN9vyw== -rolldown@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.1.tgz#2e2e839106dc47951e42dbba414f0f0ecf97ac68" - integrity sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ== +rolldown@~1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.1.4.tgz#7e15fb26997353808330109ef6bffda274aaa027" + integrity sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA== dependencies: - "@oxc-project/types" "=0.130.0" + "@oxc-project/types" "=0.138.0" "@rolldown/pluginutils" "^1.0.0" optionalDependencies: - "@rolldown/binding-android-arm64" "1.0.1" - "@rolldown/binding-darwin-arm64" "1.0.1" - "@rolldown/binding-darwin-x64" "1.0.1" - "@rolldown/binding-freebsd-x64" "1.0.1" - "@rolldown/binding-linux-arm-gnueabihf" "1.0.1" - "@rolldown/binding-linux-arm64-gnu" "1.0.1" - "@rolldown/binding-linux-arm64-musl" "1.0.1" - "@rolldown/binding-linux-ppc64-gnu" "1.0.1" - "@rolldown/binding-linux-s390x-gnu" "1.0.1" - "@rolldown/binding-linux-x64-gnu" "1.0.1" - "@rolldown/binding-linux-x64-musl" "1.0.1" - "@rolldown/binding-openharmony-arm64" "1.0.1" - "@rolldown/binding-wasm32-wasi" "1.0.1" - "@rolldown/binding-win32-arm64-msvc" "1.0.1" - "@rolldown/binding-win32-x64-msvc" "1.0.1" - -rollup@4.60.4: - version "4.60.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.60.4.tgz#ca3814f5900da3ac3981d2e0c61944b7e6e0cb09" - integrity sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g== - dependencies: - "@types/estree" "1.0.8" + "@rolldown/binding-android-arm64" "1.1.4" + "@rolldown/binding-darwin-arm64" "1.1.4" + "@rolldown/binding-darwin-x64" "1.1.4" + "@rolldown/binding-freebsd-x64" "1.1.4" + "@rolldown/binding-linux-arm-gnueabihf" "1.1.4" + "@rolldown/binding-linux-arm64-gnu" "1.1.4" + "@rolldown/binding-linux-arm64-musl" "1.1.4" + "@rolldown/binding-linux-ppc64-gnu" "1.1.4" + "@rolldown/binding-linux-s390x-gnu" "1.1.4" + "@rolldown/binding-linux-x64-gnu" "1.1.4" + "@rolldown/binding-linux-x64-musl" "1.1.4" + "@rolldown/binding-openharmony-arm64" "1.1.4" + "@rolldown/binding-wasm32-wasi" "1.1.4" + "@rolldown/binding-win32-arm64-msvc" "1.1.4" + "@rolldown/binding-win32-x64-msvc" "1.1.4" + +rollup@4.62.2: + version "4.62.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.62.2.tgz#d90fc4cb811f071303c890b779595634f35f9541" + integrity sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA== + dependencies: + "@types/estree" "1.0.9" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.60.4" - "@rollup/rollup-android-arm64" "4.60.4" - "@rollup/rollup-darwin-arm64" "4.60.4" - "@rollup/rollup-darwin-x64" "4.60.4" - "@rollup/rollup-freebsd-arm64" "4.60.4" - "@rollup/rollup-freebsd-x64" "4.60.4" - "@rollup/rollup-linux-arm-gnueabihf" "4.60.4" - "@rollup/rollup-linux-arm-musleabihf" "4.60.4" - "@rollup/rollup-linux-arm64-gnu" "4.60.4" - "@rollup/rollup-linux-arm64-musl" "4.60.4" - "@rollup/rollup-linux-loong64-gnu" "4.60.4" - "@rollup/rollup-linux-loong64-musl" "4.60.4" - "@rollup/rollup-linux-ppc64-gnu" "4.60.4" - "@rollup/rollup-linux-ppc64-musl" "4.60.4" - "@rollup/rollup-linux-riscv64-gnu" "4.60.4" - "@rollup/rollup-linux-riscv64-musl" "4.60.4" - "@rollup/rollup-linux-s390x-gnu" "4.60.4" - "@rollup/rollup-linux-x64-gnu" "4.60.4" - "@rollup/rollup-linux-x64-musl" "4.60.4" - "@rollup/rollup-openbsd-x64" "4.60.4" - "@rollup/rollup-openharmony-arm64" "4.60.4" - "@rollup/rollup-win32-arm64-msvc" "4.60.4" - "@rollup/rollup-win32-ia32-msvc" "4.60.4" - "@rollup/rollup-win32-x64-gnu" "4.60.4" - "@rollup/rollup-win32-x64-msvc" "4.60.4" + "@rollup/rollup-android-arm-eabi" "4.62.2" + "@rollup/rollup-android-arm64" "4.62.2" + "@rollup/rollup-darwin-arm64" "4.62.2" + "@rollup/rollup-darwin-x64" "4.62.2" + "@rollup/rollup-freebsd-arm64" "4.62.2" + "@rollup/rollup-freebsd-x64" "4.62.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.62.2" + "@rollup/rollup-linux-arm-musleabihf" "4.62.2" + "@rollup/rollup-linux-arm64-gnu" "4.62.2" + "@rollup/rollup-linux-arm64-musl" "4.62.2" + "@rollup/rollup-linux-loong64-gnu" "4.62.2" + "@rollup/rollup-linux-loong64-musl" "4.62.2" + "@rollup/rollup-linux-ppc64-gnu" "4.62.2" + "@rollup/rollup-linux-ppc64-musl" "4.62.2" + "@rollup/rollup-linux-riscv64-gnu" "4.62.2" + "@rollup/rollup-linux-riscv64-musl" "4.62.2" + "@rollup/rollup-linux-s390x-gnu" "4.62.2" + "@rollup/rollup-linux-x64-gnu" "4.62.2" + "@rollup/rollup-linux-x64-musl" "4.62.2" + "@rollup/rollup-openbsd-x64" "4.62.2" + "@rollup/rollup-openharmony-arm64" "4.62.2" + "@rollup/rollup-win32-arm64-msvc" "4.62.2" + "@rollup/rollup-win32-ia32-msvc" "4.62.2" + "@rollup/rollup-win32-x64-gnu" "4.62.2" + "@rollup/rollup-win32-x64-msvc" "4.62.2" fsevents "~2.3.2" semver@^7.5.3: version "7.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== siginfo@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== source-map-js@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== stackback@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz" integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== std-env@^4.0.0-rc.1: version "4.1.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-4.1.0.tgz#45899abc590d86d682e87f0acd1033a75084cd3f" + resolved "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz" integrity sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ== string-fn@3.6.3: version "3.6.3" - resolved "https://registry.yarnpkg.com/string-fn/-/string-fn-3.6.3.tgz#952203a4c512f013fb419fe3bcf52e3715075068" + resolved "https://registry.npmjs.org/string-fn/-/string-fn-3.6.3.tgz" integrity sha512-TOuTWUnWZt3EYPIyRJ7DWByKpxgZv1CIP/hLjT+8c3kIAS/14MAypz2olew9XmVNSDE98X/QYiMt8PKGZ9mDXQ== dependencies: rambdax "11.3.0" string-width@^4.1.0: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -1031,7 +1174,7 @@ string-width@^4.1.0: string-width@^7.0.0, string-width@^7.2.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + resolved "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz" integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: emoji-regex "^10.3.0" @@ -1040,7 +1183,7 @@ string-width@^7.0.0, string-width@^7.2.0: stringify-object@^3.2.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz" integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== dependencies: get-own-enumerable-property-symbols "^3.0.0" @@ -1049,28 +1192,28 @@ stringify-object@^3.2.0: strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.2.0.tgz#d22a269522836a627af8d04b5c3fd2c7fa3e32e3" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz" integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w== dependencies: ansi-regex "^6.2.2" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8: version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" @@ -1082,33 +1225,33 @@ tinybench@^2.9.0: tinycolor2@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz" integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== tinyexec@^1.0.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.1.2.tgz#11feef204b706d4668ca4013db29f3bd64f5c4dc" + resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz" integrity sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA== tinyglobby@^0.2.15: version "0.2.15" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: fdir "^6.5.0" picomatch "^4.0.3" -tinyglobby@^0.2.16: - version "0.2.16" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.16.tgz#1c3b7eb953fce42b226bc5a1ee06428281aff3d6" - integrity sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg== +tinyglobby@^0.2.17: + version "0.2.17" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" + integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== dependencies: fdir "^6.5.0" picomatch "^4.0.4" tinygradient@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/tinygradient/-/tinygradient-1.1.5.tgz#0fb855ceb18d96b21ba780b51a8012033b2530ef" + resolved "https://registry.npmjs.org/tinygradient/-/tinygradient-1.1.5.tgz" integrity sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw== dependencies: "@types/tinycolor2" "^1.4.0" @@ -1116,12 +1259,12 @@ tinygradient@^1.1.5: tinyrainbow@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz#1d8a623893f95cf0a2ddb9e5d11150e191409421" + resolved "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz" integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw== ts-toolbelt@^9.6.0: version "9.6.0" - resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5" + resolved "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz" integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w== tslib@^2.4.0: @@ -1131,56 +1274,77 @@ tslib@^2.4.0: type-fest@^4.21.0: version "4.41.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz" integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== -types-ramda@0.31.0: - version "0.31.0" - resolved "https://registry.yarnpkg.com/types-ramda/-/types-ramda-0.31.0.tgz#7cb72d1133107679855aab1e57a0cbffff3ea8b1" - integrity sha512-vaoC35CRC3xvL8Z6HkshDbi6KWM1ezK0LHN0YyxXWUn9HKzBNg/T3xSGlJZjCYspnOD3jE7bcizsp0bUXZDxnQ== +types-ramda@0.32.0: + version "0.32.0" + resolved "https://registry.yarnpkg.com/types-ramda/-/types-ramda-0.32.0.tgz#ea4ca5f9e0753f1f0ee20f72cb294a4db2d3db0a" + integrity sha512-iZtriSUdsDqOlip/wUaDNcoiskbVf5RdcqLNpQdUcOM1JKFClochCvPZCDjn/cc9HzoBzi4DEB4iPr1PbrhN1w== dependencies: ts-toolbelt "^9.6.0" -typescript@6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" - integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== - -"undici-types@>=7.24.0 <7.24.7": - version "7.24.6" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.24.6.tgz#61275b485d7fd4e9d269c7cf04ec2873c9cc0f91" - integrity sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg== +typescript@7.0.1-rc: + version "7.0.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-7.0.1-rc.tgz#cf7c211803b742c1cace8183656acc57685eaaf7" + integrity sha512-drEP77wK7CCDlPfXZH4e008UUQOsw1DFmHmZOZjuNA+yoDLLnSNMZRXi90NbV/1LVo7SbNLq1bs3jjvk49TEqQ== + optionalDependencies: + "@typescript/typescript-aix-ppc64" "7.0.1-rc" + "@typescript/typescript-darwin-arm64" "7.0.1-rc" + "@typescript/typescript-darwin-x64" "7.0.1-rc" + "@typescript/typescript-freebsd-arm64" "7.0.1-rc" + "@typescript/typescript-freebsd-x64" "7.0.1-rc" + "@typescript/typescript-linux-arm" "7.0.1-rc" + "@typescript/typescript-linux-arm64" "7.0.1-rc" + "@typescript/typescript-linux-loong64" "7.0.1-rc" + "@typescript/typescript-linux-mips64el" "7.0.1-rc" + "@typescript/typescript-linux-ppc64" "7.0.1-rc" + "@typescript/typescript-linux-riscv64" "7.0.1-rc" + "@typescript/typescript-linux-s390x" "7.0.1-rc" + "@typescript/typescript-linux-x64" "7.0.1-rc" + "@typescript/typescript-netbsd-arm64" "7.0.1-rc" + "@typescript/typescript-netbsd-x64" "7.0.1-rc" + "@typescript/typescript-openbsd-arm64" "7.0.1-rc" + "@typescript/typescript-openbsd-x64" "7.0.1-rc" + "@typescript/typescript-sunos-x64" "7.0.1-rc" + "@typescript/typescript-win32-arm64" "7.0.1-rc" + "@typescript/typescript-win32-x64" "7.0.1-rc" + +undici-types@~8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-8.3.0.tgz#44e9fc9f3244648cdea35e4f9bb2d681e9410809" + integrity sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ== universalify@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== "vite@^6.0.0 || ^7.0.0 || ^8.0.0": - version "8.0.13" - resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.13.tgz#d75fb40aeee761051b0eb4620993da625c7719ab" - integrity sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw== + version "8.1.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-8.1.3.tgz#ce05b445b501014a10e5a8073811759c223e8ac2" + integrity sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA== dependencies: lightningcss "^1.32.0" picomatch "^4.0.4" - postcss "^8.5.14" - rolldown "1.0.1" - tinyglobby "^0.2.16" + postcss "^8.5.16" + rolldown "~1.1.3" + tinyglobby "^0.2.17" optionalDependencies: fsevents "~2.3.3" -vitest@5.0.0-beta.2: - version "5.0.0-beta.2" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-5.0.0-beta.2.tgz#812eaae0240e9027df6ec636cd8b570f1426ffeb" - integrity sha512-HnM/uQfbToilHYwWW2tdaPM0GYZCdDx5Moxzgfq4wjlpF3MTUP8T7XGgXIE/S90y4BX8pLoc4xD9jqDvHbY2qA== - dependencies: - "@types/chai" "^5.2.2" - "@vitest/mocker" "5.0.0-beta.2" - "@vitest/pretty-format" "5.0.0-beta.2" - "@vitest/runner" "5.0.0-beta.2" - "@vitest/spy" "5.0.0-beta.2" - "@vitest/utils" "5.0.0-beta.2" - chai "^6.2.2" +vitest@4.1.9: + version "4.1.9" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.9.tgz#98f22fbd70e2a18c4a92bb20624bc92e5dfac5f3" + integrity sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ== + dependencies: + "@vitest/expect" "4.1.9" + "@vitest/mocker" "4.1.9" + "@vitest/pretty-format" "4.1.9" + "@vitest/runner" "4.1.9" + "@vitest/snapshot" "4.1.9" + "@vitest/spy" "4.1.9" + "@vitest/utils" "4.1.9" es-module-lexer "^2.0.0" expect-type "^1.3.0" magic-string "^0.30.21" @@ -1197,7 +1361,7 @@ vitest@5.0.0-beta.2: why-is-node-running@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + resolved "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz" integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== dependencies: siginfo "^2.0.0" @@ -1205,14 +1369,14 @@ why-is-node-running@^2.3.0: widest-line@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-5.0.0.tgz#b74826a1e480783345f0cd9061b49753c9da70d0" + resolved "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz" integrity sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA== dependencies: string-width "^7.0.0" window-size@^1: version "1.1.1" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-1.1.1.tgz#9858586580ada78ab26ecd6978a6e03115c1af20" + resolved "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz" integrity sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA== dependencies: define-property "^1.0.0" @@ -1220,7 +1384,7 @@ window-size@^1: wrap-ansi@^9.0.0: version "9.0.2" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz" integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== dependencies: ansi-styles "^6.2.1" @@ -1229,5 +1393,5 @@ wrap-ansi@^9.0.0: yoctocolors@^2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.2.tgz#d795f54d173494e7d8db93150cec0ed7f678c83a" + resolved "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz" integrity sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==