# `charsets` _(no submodules)_ ## Purpose Defines the canonical character-class constants used by every generator in the package — `LOWERCASE`, `UPPERCASE`, `DIGITS`, `SYMBOLS`, plus the curated `AMBIGUOUS` and `LOOKALIKES` sets that callers subtract to avoid characters confusable in fixed-width fonts. Exposing each class as a frozen `ReadonlySet` lets callers compose custom unions (`new Set([...LOWERCASE, ...DIGITS])`) without depending on any private representation. The `buildEffectiveCharset(opts)` helper merges the enabled classes and subtracts `opts.exclude` to produce the deduplicated string array a generator can index into via `randomInt`. The four built-in classes are pairwise disjoint by construction, so insertion-order union is enough to deduplicate — adding a `Set`-tracked check would be dead code. ## Features - Frozen `ReadonlySet` for each class — safe to share across modules. - `AMBIGUOUS` (`0Ol1I`) and `LOOKALIKES` curated by frequency of human misreads. - `SYMBOLS` drawn from the OWASP-recommended printable range; excludes shell-quoting hazards (backtick, backslash, whitespace). - `buildEffectiveCharset(opts)` accepts string / array / `Set` exclusions. ## Usage: Basic Example ```ts import { AMBIGUOUS, buildEffectiveCharset, } from "@suaveplan/password-generator"; const charset = buildEffectiveCharset({ exclude: AMBIGUOUS }); ``` ## Usage: Advanced Example ```ts import { DIGITS, LOWERCASE, UPPERCASE, buildEffectiveCharset, } from "@suaveplan/password-generator"; // Hex charset only (digits + a-f) via two passes const hexLower = [ ...buildEffectiveCharset({ uppercase: false, symbols: false }), ].filter((c) => DIGITS.has(c) || "abcdef".includes(c)); // "Vault-friendly" passwords: drop ambiguous + shell-hostile chars const safe = buildEffectiveCharset({ exclude: "0Ol1I`\\\"' " }); const charset = safe.filter((c) => !UPPERCASE.has(c) || LOWERCASE.has(c.toLowerCase())); ``` ## API Reference ### Constants - `LOWERCASE: ReadonlySet` — `a–z` (26 entries). - `UPPERCASE: ReadonlySet` — `A–Z` (26 entries). - `DIGITS: ReadonlySet` — `0–9` (10 entries). - `SYMBOLS: ReadonlySet` — `!@#$%^&*()-_=+[]{};:,.<>/?` (25 entries). - `AMBIGUOUS: ReadonlySet` — `0Ol1I`. - `LOOKALIKES: ReadonlySet` — `0OQ1lI5S2Z8B`. ### `buildEffectiveCharset(opts?: CharsetOptions): string[]` Builds the deduplicated union of enabled classes minus `opts.exclude`. Returns a fresh array on every call; insertion order is lowercase → uppercase → digits → symbols. - `lowercase` / `uppercase` / `digits` / `symbols` — each defaults to `true`. - `exclude` — `string` (per-character), `readonly string[]`, or `ReadonlySet`; defaults to none. ## Implementation Notes Every set is frozen at module load via `Object.freeze`, which only freezes the `Set` object itself (not the underlying internal storage). The intent is to surface accidental `.add` / `.delete` calls at call sites; consumers who need to add or remove characters must clone the set first. `SYMBOLS` intentionally omits whitespace, the backslash, double-quote, and backtick. Those characters routinely break shell interpolations and CSV exports; including them would force every caller to filter them out before interpolating the generated password into a deployment script. Callers who want them can compose `new Set([...SYMBOLS, "\\\""])` themselves — the omission is conservative-by-default but trivially reversible.