Ahead of the release
npm install @evanion/luhn gives you 3.0.0. These pages document main, which has changes that release does not.
API reference
createLuhn(options?)
function createLuhn(options?: LuhnOptions): Luhn;Validates the dictionary and returns a frozen Luhn.
| Option | Type | Default |
|---|---|---|
dictionary | string | DEFAULT_DICTIONARY |
caseInsensitive | boolean | true when dictionary is omitted, false when it is given |
Throws InvalidDictionaryError when the dictionary fails one of
the five constraints.
The returned object
interface Luhn {
readonly dictionary: string;
readonly n: number;
readonly caseInsensitive: boolean;
readonly uniformOverBytes: boolean;
generate(input: string): GenerateResult;
validate(input: string): ValidateResult;
}| Member | Meaning |
|---|---|
dictionary | the alphabet, as supplied |
n | the modulus: code points in the dictionary |
caseInsensitive | whether input is folded to lowercase before lookup |
uniformOverBytes | whether n divides 256, so byte % n draws uniformly |
generate | computes the check character |
validate | checks a string whose last dictionary character is the check |
Object.freezed, so luhn.dictionary = x throws a TypeError in a module
rather than being accepted and ignored.
generate(input)
interface GenerateResult {
phrase: string; // input with non-dictionary code points removed
checksum: string; // the check character
filtered: number; // how many code points were dropped
}Throws EmptyInputError when no code point of input is in the dictionary.
phrase does not include checksum — the check character did not exist when
the phrase was read.
validate(input)
interface ValidateResult {
phrase: string; // input with non-dictionary code points removed
isValid: boolean;
filtered: number;
}Never throws. isValid is false for fewer than two surviving code points.
phrase here does include the check character, because that is what was
validated.
Constants
| Export | Value |
|---|---|
Luhn | createLuhn(), frozen — the default instance |
DEFAULT_DICTIONARY | '0123456789abcdefghijklmnopqrstuvwxyz' — 36 characters |
ALTERNATING_CASE_DICTIONARY | 62 characters: 0-9 then Aa Bb … Zz, case-sensitive |
Luhn names the interface in type space and the default instance in value
space, so const luhn: Luhn = Luhn resolves both.
Types
LuhnOptions, GenerateResult, ValidateResult, InvalidDictionaryReason,
and the Luhn interface above.
type InvalidDictionaryReason =
'not-a-string' | 'too-short' | 'odd-length' | 'duplicate' | 'case-pairs';Errors
LuhnError
Base class for everything the library throws. Catch it to handle any failure without naming the subclasses.
The name is package-specific rather than a generic ValidationError, so it
cannot collide with the one @evanion/urn exports in a consumer’s import list.
The two hierarchies are unrelated and share no base.
InvalidDictionaryError extends LuhnError
Raised by createLuhn. One class carrying a reason rather than one class per
constraint, so a caller that only wants to know whether a dictionary is
acceptable writes one catch arm.
| Property | Meaning |
|---|---|
reason | which constraint failed |
dictionary | the dictionary as supplied |
offending | the code points the constraint named; empty for the whole-dictionary ones |
try {
createLuhn({ dictionary: 'aabbccdd' });
} catch (error) {
if (error instanceof InvalidDictionaryError) {
error.reason; // 'duplicate'
error.offending; // ['a', 'b', 'c', 'd']
}
}For case-pairs, offending holds each pair joined into one string — 'Aa',
'Bb'. For not-a-string, too-short and odd-length it is empty, because
those are properties of the dictionary as a whole.
EmptyInputError extends LuhnError
Raised by generate when nothing survived the filter. It is the only error
either operation can raise — every other constraint was settled at construction.