first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
# Collator ergonomic helpers
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The three ergonomic helpers (`compareCaseInsensitive`,
`compareNumericAware`, `sortStrings`) pre-bind `compareStrings` and
`formatCollation` with the most common option configurations so
consumers don't have to remember which `sensitivity` value matches
case-insensitive comparison or which boolean flag enables natural
sort.
## Features
- `compareCaseInsensitive(a, b, locale)` — pre-binds `sensitivity: "accent"` (case-insensitive but accent-aware)
- `compareNumericAware(a, b, locale)` — pre-binds `numeric: true` (natural sort: `"file2" < "file10"`)
- `sortStrings(values, locale, options?)` — alias for `formatCollation` with a more familiar name
## Usage: Basic Example
```ts
import {
compareCaseInsensitive,
compareNumericAware,
sortStrings,
} from "@suaveplan/i18n-formatter-collator";
compareCaseInsensitive("apple", "Apple", "en-GB"); // 0
compareNumericAware("file2", "file10", "en-GB"); // -1
sortStrings(["c", "a", "b"], "en-GB"); // ["a", "b", "c"]
sortStrings(["file10", "file2"], "en-GB", { numeric: true });
// ["file2", "file10"]
```
## Usage: Advanced Example
```ts
import {
compareCaseInsensitive,
compareNumericAware,
sortStrings,
} from "@suaveplan/i18n-formatter-collator";
// Build a case-insensitive search filter.
function findItems(needle: string, items: string[], locale: string) {
return items.filter(
(item) => compareCaseInsensitive(needle, item, locale) === 0
);
}
// Sort a list of file names naturally.
const files = ["log10.txt", "log2.txt", "log1.txt"];
const sorted = sortStrings(files, "en-GB", { numeric: true });
// ["log1.txt", "log2.txt", "log10.txt"]
// Sort then group names case-insensitively.
function groupBy<T>(
items: readonly T[],
keyFn: (item: T) => string,
locale: string
): Record<string, T[]> {
const sortedItems = [...items].sort((x, y) =>
compareCaseInsensitive(keyFn(x), keyFn(y), locale)
);
const out: Record<string, T[]> = {};
for (const item of sortedItems) {
const key = keyFn(item);
const bucket = out[key] ?? [];
bucket.push(item);
out[key] = bucket;
}
return out;
}
```
## API Reference
### `compareCaseInsensitive(a, b, locale): -1 | 0 | 1`
Pre-binds `sensitivity: "accent"`. Treats `"a"` and `"A"` as equal
(case-insensitive) but distinguishes `"a"` from `"á"`
(accent-sensitive). For full base-letter comparison (treating `"a"`
and `"á"` equal as well), call `compareStrings` directly with
`sensitivity: "base"`.
### `compareNumericAware(a, b, locale): -1 | 0 | 1`
Pre-binds `numeric: true`. Embedded numbers sort by their numeric
value, not their lexicographic order: `"file2"` sorts before
`"file10"` (lexicographic would put `"file10"` first).
### `sortStrings(values, locale, options?): string[]`
Alias for `formatCollation` with a familiar name. Returns a NEW
sorted array; the input is never mutated. All options forwarded.
## Implementation Notes
- Each helper is a one-line wrapper around `compareStrings` /
`formatCollation`. The underlying per-(locale, options-hash) cache
applies — calling `compareCaseInsensitive` twice with the same
locale reuses one `Intl.Collator`.
- The helpers are pure functions with no shared state.