@italia-tools/faker
Version:
Italian-specific fake data generator based on Faker.js
82 lines (79 loc) • 3.84 kB
JavaScript
import { Gender } from '../types/types.mjs';
// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
class FiscalCodeGenerator {
static generate(person) {
const surname = FiscalCodeGenerator.processSurname(person.lastName);
const name = FiscalCodeGenerator.processName(person.firstName);
const dateCode = FiscalCodeGenerator.processDate(person.birthDate, person.gender);
const belfioreCode = person.birthPlace.type === 'italian' ? person.birthPlace.city.belfioreCode : person.birthPlace.country.code;
const baseCode = surname + name + dateCode + belfioreCode;
const controlChar = FiscalCodeGenerator.calculateControlChar(baseCode);
return baseCode + controlChar;
}
static processSurname(surname) {
const consonants = surname.toUpperCase().replace(/[^BCDFGHJKLMNPQRSTVWXYZ]/g, '');
const vowels = surname.toUpperCase().replace(/[^AEIOU]/g, '');
const combined = consonants + vowels + 'XXX';
return combined.slice(0, 3);
}
static processName(name) {
const consonants = name.toUpperCase().replace(/[^BCDFGHJKLMNPQRSTVWXYZ]/g, '');
if (consonants.length > 3) {
return consonants[0] + consonants[2] + consonants[3];
}
const vowels = name.toUpperCase().replace(/[^AEIOU]/g, '');
const combined = consonants + vowels + 'XXX';
return combined.slice(0, 3);
}
static processDate(date, gender) {
const year = date.getFullYear().toString().slice(-2);
const month = FiscalCodeGenerator.MONTH_CODES[date.getMonth()];
let day = date.getDate().toString().padStart(2, '0');
if (gender === Gender.Female) {
day = (parseInt(day) + 40).toString();
}
return year + month + day;
}
static calculateControlChar(code) {
if (code.length !== 15) {
throw new Error('Base code must be exactly 15 characters long');
}
let sum = 0;
// Process characters in odd positions (1-based index)
for (let i = 0; i < code.length; i += 2) {
const char = code[i];
const value = FiscalCodeGenerator.ODD_CHARS[char];
if (value === undefined) {
throw new Error(`Invalid character in odd position: ${char}`);
}
sum += value;
}
// Process characters in even positions (1-based index)
for (let i = 1; i < code.length; i += 2) {
const char = code[i];
const value = FiscalCodeGenerator.EVEN_CHARS[char];
if (value === undefined) {
throw new Error(`Invalid character in even position: ${char}`);
}
sum += value;
}
// Calculate remainder and get corresponding letter
const remainder = sum % 26;
return FiscalCodeGenerator.REMAINDER_CHARS.charAt(remainder);
}
}
FiscalCodeGenerator.MONTH_CODES = ['A', 'B', 'C', 'D', 'E', 'H', 'L', 'M', 'P', 'R', 'S', 'T'];
FiscalCodeGenerator.ODD_CHARS = {
'0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19,
'9': 21, 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17,
'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6,
'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23
};
FiscalCodeGenerator.EVEN_CHARS = {
'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
'9': 9, 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7,
'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16,
'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25
};
FiscalCodeGenerator.REMAINDER_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
export { FiscalCodeGenerator };