first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user