@marketto/codice-fiscale-utils
Version:
TS & JS utilities to handle Italian Codice Fiscale
70 lines (65 loc) • 2.42 kB
text/typescript
import { CRC_OFFSET, LASTNAME_OFFSET } from "../const/cf-offsets.const";
import { PARTIAL_CF } from "../const/matcher.const";
import CRC from "../enums/crc.enum";
import generatorWrapper from "../functions/generator-wrapper.function";
import type IGeneratorWrapper from "../interfaces/generator-wrapper.interface";
import type CodiceFiscaleCRC from "../types/codice-fiscale-crc.type";
class CheckDigitizer {
/**
* Evaluate given partial CF to produce last check digit character
* @param codiceFiscale Partial or complete Fiscal Code to evaluate to produce last character
* @returns 16th CF char
*/
public static checkDigit(codiceFiscale: string): CodiceFiscaleCRC | null {
if (
typeof codiceFiscale === "string" &&
new RegExp(PARTIAL_CF).test(codiceFiscale)
) {
const partialCF = codiceFiscale.substr(LASTNAME_OFFSET, CRC_OFFSET);
let partialCfValue = 0;
for (const charValue of this.evaluateChar(partialCF)) {
partialCfValue += charValue as number;
}
return String.fromCharCode(
(partialCfValue % this.CRC_MOD) + this.CHAR_OFFSET
) as CodiceFiscaleCRC;
}
return null;
}
public static evaluateChar(
partialCF: string = ""
): IGeneratorWrapper<number, 0, void> {
return generatorWrapper(this.evaluateCharGenerator(partialCF));
}
private static CHAR_OFFSET: number = 65;
private static CRC_MOD: number = 26;
/**
* Partial FiscalCode Evaluator
* @param Partial Fiscal Code to evaluate
* @yields character value odd/even
*/
private static *evaluateCharGenerator(partialCF: string = ""): Generator {
if (typeof partialCF === "string" && partialCF.length) {
for (let index = 0; index < partialCF.length; index++) {
let char: string = partialCF[index].toUpperCase();
const isNumber: boolean = /^\d$/u.test(char);
if (isNumber) {
// Numbers have always (odd/even) the same values of corresponding letters (0-9 => A-J)
char = String.fromCharCode(parseInt(char, 10) + this.CHAR_OFFSET);
}
// Odd/Even are shifted/swapped
// array starts from 0, "Agenzia delle Entrate" documentation counts the string from 1
const isOdd: boolean = !(index % 2); // Odd according to documentation
if (isOdd) {
// Odd positions
yield parseInt(CRC[char as any], 10);
} else {
// Even positions
yield char.charCodeAt(0) - this.CHAR_OFFSET;
}
}
}
return 0;
}
}
export default CheckDigitizer;