From 0705f8af0f78eb8513395b20f00f5b2917e10641 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sun, 6 Sep 2026 13:09:44 +0200 Subject: [PATCH 1/5] chore: run transform script (dirty) --- src/modules/finance/account-name.ts | 21 +++ src/modules/finance/account-number.ts | 118 ++++++++++++++++ src/modules/finance/amount.ts | 82 +++++++++++ src/modules/finance/bic.ts | 52 +++++++ src/modules/finance/bitcoin-address.ts | 61 ++++++++ src/modules/finance/credit-card-cvv.ts | 18 +++ src/modules/finance/credit-card-issuer.ts | 18 +++ src/modules/finance/credit-card-number.ts | 132 ++++++++++++++++++ src/modules/finance/currency-code.ts | 19 +++ src/modules/finance/currency-name.ts | 18 +++ src/modules/finance/currency-numeric-code.ts | 19 +++ src/modules/finance/currency-symbol.ts | 30 ++++ src/modules/finance/currency.ts | 23 +++ src/modules/finance/ethereum-address.ts | 24 ++++ src/modules/finance/iban.ts | 98 +++++++++++++ src/modules/finance/litecoin-address.ts | 29 ++++ src/modules/finance/pin.ts | 131 +++++++++++++++++ src/modules/finance/routing-number.ts | 40 ++++++ .../finance/transaction-description.ts | 21 +++ src/modules/finance/transaction-type.ts | 18 +++ src/modules/finance/vat-number.ts | 62 ++++++++ 21 files changed, 1034 insertions(+) create mode 100644 src/modules/finance/account-name.ts create mode 100644 src/modules/finance/account-number.ts create mode 100644 src/modules/finance/amount.ts create mode 100644 src/modules/finance/bic.ts create mode 100644 src/modules/finance/bitcoin-address.ts create mode 100644 src/modules/finance/credit-card-cvv.ts create mode 100644 src/modules/finance/credit-card-issuer.ts create mode 100644 src/modules/finance/credit-card-number.ts create mode 100644 src/modules/finance/currency-code.ts create mode 100644 src/modules/finance/currency-name.ts create mode 100644 src/modules/finance/currency-numeric-code.ts create mode 100644 src/modules/finance/currency-symbol.ts create mode 100644 src/modules/finance/currency.ts create mode 100644 src/modules/finance/ethereum-address.ts create mode 100644 src/modules/finance/iban.ts create mode 100644 src/modules/finance/litecoin-address.ts create mode 100644 src/modules/finance/pin.ts create mode 100644 src/modules/finance/routing-number.ts create mode 100644 src/modules/finance/transaction-description.ts create mode 100644 src/modules/finance/transaction-type.ts create mode 100644 src/modules/finance/vat-number.ts diff --git a/src/modules/finance/account-name.ts b/src/modules/finance/account-name.ts new file mode 100644 index 00000000000..10a97cffdde --- /dev/null +++ b/src/modules/finance/account-name.ts @@ -0,0 +1,21 @@ +import type { FakerCore } from '../../core'; +import { arrayElement } from '../helpers/array-element'; + +/** + * Generates a random account name. + * + * @param fakerCore The FakerCore to use. + * + * @example + * accountName(fakerCore) // 'Personal Loan Account' + * + * @since 11.0.0 + * + * @experimental + */ +export function accountName(fakerCore: FakerCore): string { + return [ + arrayElement(fakerCore, fakerCore.locale.finance.account_type), + 'Account', + ].join(' '); +} diff --git a/src/modules/finance/account-number.ts b/src/modules/finance/account-number.ts new file mode 100644 index 00000000000..e3704b98071 --- /dev/null +++ b/src/modules/finance/account-number.ts @@ -0,0 +1,118 @@ +import type { FakerCore } from '../../core'; +import { numeric } from '../string/numeric'; + +/** + * Generates a random account number. + * + * @param fakerCore The FakerCore to use. + * @param length The length of the account number. Defaults to `8`. + * + * @see stringNumeric(fakerCore): For generating the number with greater control. + * + * @example + * accountNumber(fakerCore) // '92842238' + * accountNumber(fakerCore, 5) // '32564' + * + * @since 11.0.0 + * + * @experimental + */ +export function accountNumber(fakerCore: FakerCore, length?: number): string; +/** + * Generates a random account number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object. + * @param options.length The length of the account number. Defaults to `8`. + * + * @see stringNumeric(fakerCore): For generating the number with greater control. + * + * @example + * accountNumber(fakerCore) // '92842238' + * accountNumber(fakerCore, { length: 5 }) // '32564' + * + * @since 11.0.0 + * + * @experimental + */ +export function accountNumber( + fakerCore: FakerCore, + options?: { + /** + * The length of the account number. + * + * @default 8 + */ + length?: number; + } +): string; +/** + * Generates a random account number. + * + * @param fakerCore The FakerCore to use. + * @param optionsOrLength An options object or the length of the account number. + * @param optionsOrLength.length The length of the account number. Defaults to `8`. + * + * @see stringNumeric(fakerCore): For generating the number with greater control. + * + * @example + * accountNumber(fakerCore) // '92842238' + * accountNumber(fakerCore, 5) // '28736' + * accountNumber(fakerCore, { length: 5 }) // '32564' + * + * @since 11.0.0 + * + * @experimental + */ +export function accountNumber( + fakerCore: FakerCore, + optionsOrLength?: + | number + | { + /** + * The length of the account number. + * + * @default 8 + */ + length?: number; + } +): string; +/** + * Generates a random account number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object or the length of the account number. + * @param options.length The length of the account number. Defaults to `8`. + * + * @see stringNumeric(fakerCore): For generating the number with greater control. + * + * @example + * accountNumber(fakerCore) // '92842238' + * accountNumber(fakerCore, 5) // '28736' + * accountNumber(fakerCore, { length: 5 }) // '32564' + * + * @since 11.0.0 + * + * @experimental + */ +export function accountNumber( + fakerCore: FakerCore, + options: + | number + | { + /** + * The length of the account number. + * + * @default 8 + */ + length?: number; + } = {} +): string { + if (typeof options === 'number') { + options = { length: options }; + } + + const { length = 8 } = options; + + return numeric(fakerCore, { length, allowLeadingZeros: true }); +} diff --git a/src/modules/finance/amount.ts b/src/modules/finance/amount.ts new file mode 100644 index 00000000000..226c73e044f --- /dev/null +++ b/src/modules/finance/amount.ts @@ -0,0 +1,82 @@ +import type { FakerCore } from '../../core'; +import { float } from '../number/float'; + +/** + * Generates a random amount between the given bounds (inclusive). + * + * @param fakerCore The FakerCore to use. + * @param options An options object. + * @param options.min The lower bound for the amount. Defaults to `0`. + * @param options.max The upper bound for the amount. Defaults to `1000`. + * @param options.dec The number of decimal places for the amount. Defaults to `2`. + * @param options.symbol The symbol used to prefix the amount. Defaults to `''`. + * @param options.autoFormat If true this method will use `Number.toLocaleString()`. Otherwise it will use `Number.toFixed()`. + * + * @see numberFloat(fakerCore): For generating the amount with greater control. + * + * @example + * amount(fakerCore) // '617.87' + * amount(fakerCore, { min: 5, max: 10 }) // '5.53' + * amount(fakerCore, { min: 5, max: 10, dec: 0 }) // '8' + * amount(fakerCore, { min: 5, max: 10, dec: 2, symbol: '$' }) // '$5.85' + * amount(fakerCore, { min: 5, max: 10, dec: 5, symbol: '', autoFormat: true }) // '9,75067' + * + * @since 11.0.0 + * + * @experimental + */ +export function amount( + fakerCore: FakerCore, + options: { + /** + * The lower bound for the amount. + * + * @default 0 + */ + min?: number; + /** + * The upper bound for the amount. + * + * @default 1000 + */ + max?: number; + /** + * The number of decimal places for the amount. + * + * @default 2 + */ + dec?: number; + /** + * The symbol used to prefix the amount. + * + * @default '' + */ + symbol?: string; + /** + * If true this method will use `Number.toLocaleString()`. Otherwise it will use `Number.toFixed()`. + * + * @default false + */ + autoFormat?: boolean; + } = {} +): string { + const { + autoFormat = false, + dec = 2, + max = 1000, + min = 0, + symbol = '', + } = options; + + const randValue = float(fakerCore, { + max, + min, + fractionDigits: dec, + }); + + const formattedString = autoFormat + ? randValue.toLocaleString(undefined, { minimumFractionDigits: dec }) + : randValue.toFixed(dec); + + return symbol + formattedString; +} diff --git a/src/modules/finance/bic.ts b/src/modules/finance/bic.ts new file mode 100644 index 00000000000..a6b4974da42 --- /dev/null +++ b/src/modules/finance/bic.ts @@ -0,0 +1,52 @@ +import type { FakerCore } from '../../core'; +import { boolean } from '../datatype/boolean'; +import { arrayElement } from '../helpers/array-element'; +import { alpha } from '../string/alpha'; +import { alphanumeric } from '../string/alphanumeric'; + +/** + * Generates a random SWIFT/BIC code based on the [ISO-9362](https://en.wikipedia.org/wiki/ISO_9362) format. + * + * @param fakerCore The FakerCore to use. + * @param options Options object. + * @param options.includeBranchCode Whether to include a three-digit branch code at the end of the generated code. Defaults to a random boolean value. + * + * @example + * bic(fakerCore) // 'WYAUPGX1' + * bic(fakerCore, { includeBranchCode: true }) // 'KCAUPGR1432' + * bic(fakerCore, { includeBranchCode: false }) // 'XDAFQGT7' + * + * @since 11.0.0 + * + * @experimental + */ +export function bic( + fakerCore: FakerCore, + options: { + /** + * Whether to include a three-digit branch code at the end of the generated code. + * + * @default datatypeBoolean(fakerCore) + */ + includeBranchCode?: boolean; + } = {} +): string { + const { includeBranchCode = boolean(fakerCore) } = options; + + const bankIdentifier = alpha(fakerCore, { + length: 4, + casing: 'upper', + }); + const countryCode = arrayElement(fakerCore, iban.iso3166); + const locationCode = alphanumeric(fakerCore, { + length: 2, + casing: 'upper', + }); + const branchCode = includeBranchCode + ? boolean(fakerCore) + ? alphanumeric(fakerCore, { length: 3, casing: 'upper' }) + : 'XXX' + : ''; + + return `${bankIdentifier}${countryCode}${locationCode}${branchCode}`; +} diff --git a/src/modules/finance/bitcoin-address.ts b/src/modules/finance/bitcoin-address.ts new file mode 100644 index 00000000000..6d68214660c --- /dev/null +++ b/src/modules/finance/bitcoin-address.ts @@ -0,0 +1,61 @@ +import type { FakerCore } from '../../core'; +import { enumValue } from '../helpers/enum-value'; +import { int } from '../number/int'; +import { alphanumeric } from '../string/alphanumeric'; +import type { BitcoinAddressFamilyType, BitcoinNetworkType } from './_bitcoin'; +import { + BitcoinAddressFamily, + BitcoinAddressSpecs, + BitcoinNetwork, +} from './_bitcoin'; + +/** + * Generates a random Bitcoin address. + * + * @param fakerCore The FakerCore to use. + * @param options An optional options object. + * @param options.type The bitcoin address type (`'legacy'`, `'segwit'`, `'bech32'` or `'taproot'`). Defaults to a random address type. + * @param options.network The bitcoin network (`'mainnet'` or `'testnet'`). Defaults to `'mainnet'`. + * + * @example + * bitcoinAddress(fakerCore) // '1TeZEFLmGPLEQrSRdAcnZLoWwYeiHwmRog' + * bitcoinAddress(fakerCore, { type: 'bech32' }) // 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4' + * bitcoinAddress(fakerCore, { type: 'bech32', network: 'testnet' }) // 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' + * + * @since 11.0.0 + * + * @experimental + */ +export function bitcoinAddress( + fakerCore: FakerCore, + options: { + /** + * The bitcoin address type (`'legacy'`, `'segwit'`, `'bech32'` or `'taproot'`). + * + * @default helpersEnumValue(fakerCore, BitcoinAddressFamily) + */ + type?: BitcoinAddressFamilyType; + /** + * The bitcoin network (`'mainnet'` or `'testnet'`). + * + * @default 'mainnet' + */ + network?: BitcoinNetworkType; + } = {} +): string { + const { + type = enumValue(fakerCore, BitcoinAddressFamily), + network = BitcoinNetwork.Mainnet, + } = options; + const addressSpec = BitcoinAddressSpecs[type]; + const addressPrefix = addressSpec.prefix[network]; + const addressLength = int(fakerCore, addressSpec.length); + + const address = alphanumeric(fakerCore, { + length: addressLength - addressPrefix.length, + casing: addressSpec.casing, + exclude: addressSpec.exclude, + }); + + return addressPrefix + address; +} diff --git a/src/modules/finance/credit-card-cvv.ts b/src/modules/finance/credit-card-cvv.ts new file mode 100644 index 00000000000..a11898b5150 --- /dev/null +++ b/src/modules/finance/credit-card-cvv.ts @@ -0,0 +1,18 @@ +import type { FakerCore } from '../../core'; +import { numeric } from '../string/numeric'; + +/** + * Generates a random credit card CVV. + * + * @param fakerCore The FakerCore to use. + * + * @example + * creditCardCVV(fakerCore) // '506' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardCVV(fakerCore: FakerCore): string { + return numeric(fakerCore, { length: 3, allowLeadingZeros: true }); +} diff --git a/src/modules/finance/credit-card-issuer.ts b/src/modules/finance/credit-card-issuer.ts new file mode 100644 index 00000000000..42bd34be544 --- /dev/null +++ b/src/modules/finance/credit-card-issuer.ts @@ -0,0 +1,18 @@ +import type { FakerCore } from '../../core'; +import { objectKey } from '../helpers/object-key'; + +/** + * Returns a random credit card issuer. + * + * @param fakerCore The FakerCore to use. + * + * @example + * creditCardIssuer(fakerCore) // 'discover' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardIssuer(fakerCore: FakerCore): string { + return objectKey(fakerCore, fakerCore.locale.finance.credit_card) as string; +} diff --git a/src/modules/finance/credit-card-number.ts b/src/modules/finance/credit-card-number.ts new file mode 100644 index 00000000000..1e470b51f7b --- /dev/null +++ b/src/modules/finance/credit-card-number.ts @@ -0,0 +1,132 @@ +import type { FakerCore } from '../../core'; +import { arrayElement } from '../helpers/array-element'; +import { objectValue } from '../helpers/object-value'; +import { replaceCreditCardSymbols } from '../helpers/replace-credit-card-symbols'; + +/** + * Generates a random credit card number. + * + * @param fakerCore The FakerCore to use. + * @param issuer The name of the issuer (case-insensitive) or the format used to generate one. + * + * @example + * creditCardNumber(fakerCore) // '4427163488662' + * creditCardNumber(fakerCore, 'visa') // '4882664999007' + * creditCardNumber(fakerCore, '63[7-9]#-####-####-###L') // '6375-3265-4676-6646' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardNumber(fakerCore: FakerCore, issuer?: string): string; +/** + * Generates a random credit card number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object. + * @param options.issuer The name of the issuer (case-insensitive) or the format used to generate one. Defaults to `''`. + * + * @example + * creditCardNumber(fakerCore) // '4427163488662' + * creditCardNumber(fakerCore, { issuer: 'visa' }) // '4882664999007' + * creditCardNumber(fakerCore, { issuer: '63[7-9]#-####-####-###L' }) // '6375-3265-4676-6646' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardNumber( + fakerCore: FakerCore, + options?: { + /** + * The name of the issuer (case-insensitive) or the format used to generate one. + * + * @default '' + */ + issuer?: string; + } +): string; +/** + * Generates a random credit card number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object, the issuer or a custom format. + * @param options.issuer The name of the issuer (case-insensitive) or the format used to generate one. Defaults to `''`. + * + * @example + * creditCardNumber(fakerCore) // '4427163488662' + * creditCardNumber(fakerCore, { issuer: 'visa' }) // '4882664999007' + * creditCardNumber(fakerCore, { issuer: '63[7-9]#-####-####-###L' }) // '6375-3265-4676-6646' + * creditCardNumber(fakerCore, 'visa') // '1226423499765' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardNumber( + fakerCore: FakerCore, + options?: + | string + | { + /** + * The name of the issuer (case-insensitive) or the format used to generate one. + * + * @default '' + */ + issuer?: string; + } +): string; +/** + * Generates a random credit card number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object, the issuer or a custom format. + * @param options.issuer The name of the issuer (case-insensitive) or the format used to generate one. + * + * @example + * creditCardNumber(fakerCore) // '4427163488662' + * creditCardNumber(fakerCore, { issuer: 'visa' }) // '4882664999007' + * creditCardNumber(fakerCore, { issuer: '63[7-9]#-####-####-###L' }) // '6375-3265-4676-6646' + * creditCardNumber(fakerCore, 'visa') // '1226423499765' + * + * @since 11.0.0 + * + * @experimental + */ +export function creditCardNumber( + fakerCore: FakerCore, + options: + | string + | { + /** + * The name of the issuer (case-insensitive) or the format used to generate one. + * + * @default '' + */ + issuer?: string; + } = {} +): string { + if (typeof options === 'string') { + options = { issuer: options }; + } + + const { issuer = '' } = options; + + let format: string; + const localeFormat = fakerCore.locale.finance.credit_card; + const normalizedIssuer = issuer.toLowerCase(); + if (normalizedIssuer in localeFormat) { + format = arrayElement(fakerCore, localeFormat[normalizedIssuer]); + } else if (issuer.includes('#')) { + // The user chose an optional scheme + format = issuer; + } else { + // Choose a random issuer + // Credit cards are in an object structure + const formats = objectValue(fakerCore, localeFormat); // There could be multiple formats + format = arrayElement(fakerCore, formats); + } + + format = format.replaceAll('/', ''); + return replaceCreditCardSymbols(fakerCore, format); +} diff --git a/src/modules/finance/currency-code.ts b/src/modules/finance/currency-code.ts new file mode 100644 index 00000000000..1b6ecd49e9b --- /dev/null +++ b/src/modules/finance/currency-code.ts @@ -0,0 +1,19 @@ +import type { FakerCore } from '../../core'; +import { currency } from './currency'; + +/** + * Returns a random currency code. + * (The short text/abbreviation for the currency (e.g. `US Dollar` -> `USD`)) + * + * @param fakerCore The FakerCore to use. + * + * @example + * currencyCode(fakerCore) // 'USD' + * + * @since 11.0.0 + * + * @experimental + */ +export function currencyCode(fakerCore: FakerCore): string { + return currency(fakerCore).code; +} diff --git a/src/modules/finance/currency-name.ts b/src/modules/finance/currency-name.ts new file mode 100644 index 00000000000..1eed24382d5 --- /dev/null +++ b/src/modules/finance/currency-name.ts @@ -0,0 +1,18 @@ +import type { FakerCore } from '../../core'; +import { currency } from './currency'; + +/** + * Returns a random currency name. + * + * @param fakerCore The FakerCore to use. + * + * @example + * currencyName(fakerCore) // 'US Dollar' + * + * @since 11.0.0 + * + * @experimental + */ +export function currencyName(fakerCore: FakerCore): string { + return currency(fakerCore).name; +} diff --git a/src/modules/finance/currency-numeric-code.ts b/src/modules/finance/currency-numeric-code.ts new file mode 100644 index 00000000000..0b2af2cd8b9 --- /dev/null +++ b/src/modules/finance/currency-numeric-code.ts @@ -0,0 +1,19 @@ +import type { FakerCore } from '../../core'; +import { currency } from './currency'; + +/** + * Returns a random currency numeric code. + * (The ISO 4217 numerical code for a currency (e.g. `US Dollar` -> `840` )) + * + * @param fakerCore The FakerCore to use. + * + * @example + * currencyNumericCode(fakerCore) // '840' + * + * @since 11.0.0 + * + * @experimental + */ +export function currencyNumericCode(fakerCore: FakerCore): string { + return currency(fakerCore).numericCode; +} diff --git a/src/modules/finance/currency-symbol.ts b/src/modules/finance/currency-symbol.ts new file mode 100644 index 00000000000..a34d28451a1 --- /dev/null +++ b/src/modules/finance/currency-symbol.ts @@ -0,0 +1,30 @@ +import type { FakerCore } from '../../core'; +import { FakerError } from '../../errors/faker-error'; +import { arrayElement } from '../helpers/array-element'; + +/** + * Returns a random currency symbol. + * + * @param fakerCore The FakerCore to use. + * @throws {FakerError} If no currency in the locale data has a symbol. + * + * @example + * currencySymbol(fakerCore) // '$' + * + * @since 11.0.0 + * + * @experimental + */ +export function currencySymbol(fakerCore: FakerCore): string { + const currenciesWithSymbols = fakerCore.locale.finance.currency.filter( + (currency) => currency.symbol.length > 0 + ); + + if (currenciesWithSymbols.length === 0) { + throw new FakerError( + 'Cannot get currency symbol from dataset with no currency symbols.' + ); + } + + return arrayElement(fakerCore, currenciesWithSymbols).symbol; +} diff --git a/src/modules/finance/currency.ts b/src/modules/finance/currency.ts new file mode 100644 index 00000000000..ef10fa68e20 --- /dev/null +++ b/src/modules/finance/currency.ts @@ -0,0 +1,23 @@ +import type { FakerCore } from '../../core'; +import { arrayElement } from '../helpers/array-element'; + +/** + * Returns a random currency object, containing `code`, `name`, `symbol`, and `numericCode` properties. + * + * @param fakerCore The FakerCore to use. + * + * @see currencyCode(fakerCore): For generating specifically the currency code. + * @see currencyName(fakerCore): For generating specifically the currency name. + * @see currencySymbol(fakerCore): For generating specifically the currency symbol. + * @see currencyNumericCode(fakerCore): For generating specifically the currency numeric code. + * + * @example + * currency(fakerCore) // { code: 'USD', name: 'US Dollar', symbol: '$', numericCode: '840' } + * + * @since 11.0.0 + * + * @experimental + */ +export function currency(fakerCore: FakerCore): Currency { + return arrayElement(fakerCore, fakerCore.locale.finance.currency); +} diff --git a/src/modules/finance/ethereum-address.ts b/src/modules/finance/ethereum-address.ts new file mode 100644 index 00000000000..64c93ce1dc5 --- /dev/null +++ b/src/modules/finance/ethereum-address.ts @@ -0,0 +1,24 @@ +import type { FakerCore } from '../../core'; +import { hexadecimal } from '../string/hexadecimal'; + +/** + * Creates a random, non-checksum Ethereum address. + * + * To generate a checksummed Ethereum address (with specific per character casing), wrap this method in a custom method and use third-party libraries to transform the result. + * + * @param fakerCore The FakerCore to use. + * + * @example + * ethereumAddress(fakerCore) // '0xf03dfeecbafc5147241cc4c4ca20b3c9dfd04c4a' + * + * @since 11.0.0 + * + * @experimental + */ +export function ethereumAddress(fakerCore: FakerCore): string { + const address = hexadecimal(fakerCore, { + length: 40, + casing: 'lower', + }); + return address; +} diff --git a/src/modules/finance/iban.ts b/src/modules/finance/iban.ts new file mode 100644 index 00000000000..80f63eda427 --- /dev/null +++ b/src/modules/finance/iban.ts @@ -0,0 +1,98 @@ +import type { FakerCore } from '../../core'; +import { FakerError } from '../../errors/faker-error'; +import { boolean } from '../datatype/boolean'; +import { arrayElement } from '../helpers/array-element'; +import { int } from '../number/int'; + +/** + * Generates a random IBAN. + * + * Please note that the generated IBAN might be invalid due to randomly generated bank codes/other country specific validation rules. + * + * @param fakerCore The FakerCore to use. + * @param options An options object. + * @param options.formatted Return a formatted version of the generated IBAN. Defaults to `false`. + * @param options.countryCode The country code from which you want to generate an IBAN, if none is provided a random country will be used. + * + * @throws {FakerError} Will throw an error if the passed country code is not supported. + * + * @example + * iban(fakerCore) // 'TR736918640040966092800056' + * iban(fakerCore, { formatted: true }) // 'FR20 8008 2330 8984 74S3 Z620 224' + * iban(fakerCore, { formatted: true, countryCode: 'DE' }) // 'DE84 1022 7075 0900 1170 01' + * + * @since 11.0.0 + * + * @experimental + */ +export function iban( + fakerCore: FakerCore, + options: { + /** + * Return a formatted version of the generated IBAN. + * + * @default false + */ + formatted?: boolean; + /** + * The country code from which you want to generate an IBAN, + * if none is provided a random country will be used. + */ + countryCode?: string; + } = {} +): string { + const { countryCode, formatted = false } = options; + + const ibanFormat = countryCode + ? iban.formats.find((f) => f.country === countryCode) + : arrayElement(fakerCore, iban.formats); + + if (!ibanFormat) { + throw new FakerError(`Country code ${countryCode} not supported.`); + } + + let s = ''; + let count = 0; + for (const bban of ibanFormat.bban) { + let c = bban.count; + count += bban.count; + while (c > 0) { + if (bban.type === 'a') { + s += arrayElement(fakerCore, iban.alpha); + } else if (bban.type === 'c') { + if (boolean(fakerCore, 0.8)) { + s += int(fakerCore, 9); + } else { + s += arrayElement(fakerCore, iban.alpha); + } + } else { + if (c >= 3 && boolean(fakerCore, 0.3)) { + if (boolean(fakerCore)) { + s += arrayElement(fakerCore, iban.pattern100); + c -= 2; + } else { + s += arrayElement(fakerCore, iban.pattern10); + c--; + } + } else { + s += int(fakerCore, 9); + } + } + + c--; + } + + s = s.substring(0, count); + } + + let checksum: string | number = + 98 - iban.mod97(iban.toDigitString(`${s}${ibanFormat.country}00`)); + + if (checksum < 10) { + checksum = `0${checksum}`; + } + + const result = `${ibanFormat.country}${checksum}${s}`; + + return formatted ? prettyPrintIban(result) : result; +} diff --git a/src/modules/finance/litecoin-address.ts b/src/modules/finance/litecoin-address.ts new file mode 100644 index 00000000000..6121de362e1 --- /dev/null +++ b/src/modules/finance/litecoin-address.ts @@ -0,0 +1,29 @@ +import type { FakerCore } from '../../core'; +import { int } from '../number/int'; +import { fromCharacters } from '../string/from-characters'; + +/** + * Generates a random Litecoin address. + * + * @param fakerCore The FakerCore to use. + * + * @example + * litecoinAddress(fakerCore) // 'MoQaSTGWBRXkWfyxKbNKuPrAWGELzcW' + * + * @since 11.0.0 + * + * @experimental + */ +export function litecoinAddress(fakerCore: FakerCore): string { + const addressLength = int(fakerCore, { min: 26, max: 33 }); + + const address = + fromCharacters(fakerCore, 'LM3') + + fromCharacters( + fakerCore, + '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', + addressLength - 1 + ); + + return address; +} diff --git a/src/modules/finance/pin.ts b/src/modules/finance/pin.ts new file mode 100644 index 00000000000..d01b2450090 --- /dev/null +++ b/src/modules/finance/pin.ts @@ -0,0 +1,131 @@ +import type { FakerCore } from '../../core'; +import { FakerError } from '../../errors/faker-error'; +import { numeric } from '../string/numeric'; + +/** + * Generates a random PIN number. + * + * @param fakerCore The FakerCore to use. + * @param length The length of the PIN to generate. Defaults to `4`. + * + * @throws {FakerError} Will throw an error if length is less than 1. + * + * @see stringNumeric(fakerCore): For generating the pin with greater control. + * + * @example + * pin(fakerCore) // '5067' + * pin(fakerCore, 6) // '213789' + * + * @since 11.0.0 + * + * @experimental + */ +export function pin(fakerCore: FakerCore, length?: number): string; +/** + * Generates a random PIN number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object. + * @param options.length The length of the PIN to generate. Defaults to `4`. + * + * @throws {FakerError} Will throw an error if length is less than 1. + * + * @see stringNumeric(fakerCore): For generating the pin with greater control. + * + * @example + * pin(fakerCore) // '5067' + * pin(fakerCore, { length: 6 }) // '213789' + * + * @since 11.0.0 + * + * @experimental + */ +export function pin( + fakerCore: FakerCore, + options?: { + /** + * The length of the PIN to generate. + * + * @default 4 + */ + length?: number; + } +): string; +/** + * Generates a random PIN number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object or the length of the PIN. + * @param options.length The length of the PIN to generate. Defaults to `4`. + * + * @throws {FakerError} Will throw an error if length is less than 1. + * + * @see stringNumeric(fakerCore): For generating the pin with greater control. + * + * @example + * pin(fakerCore) // '5067' + * pin(fakerCore, { length: 6 }) // '213789' + * pin(fakerCore, 6) // '213789' + * + * @since 11.0.0 + * + * @experimental + */ +export function pin( + fakerCore: FakerCore, + options?: + | number + | { + /** + * The length of the PIN to generate. + * + * @default 4 + */ + length?: number; + } +): string; +/** + * Generates a random PIN number. + * + * @param fakerCore The FakerCore to use. + * @param options An options object or the length of the PIN. + * @param options.length The length of the PIN to generate. Defaults to `4`. + * + * @throws {FakerError} Will throw an error if length is less than 1. + * + * @see stringNumeric(fakerCore): For generating the pin with greater control. + * + * @example + * pin(fakerCore) // '5067' + * pin(fakerCore, { length: 6 }) // '213789' + * pin(fakerCore, 6) // '213789' + * + * @since 11.0.0 + * + * @experimental + */ +export function pin( + fakerCore: FakerCore, + options: + | number + | { + /** + * The length of the PIN to generate. + * + * @default 4 + */ + length?: number; + } = {} +): string { + if (typeof options === 'number') { + options = { length: options }; + } + + const { length = 4 } = options; + + if (length < 1) { + throw new FakerError('minimum length is 1'); + } + + return numeric(fakerCore, { length, allowLeadingZeros: true }); +} diff --git a/src/modules/finance/routing-number.ts b/src/modules/finance/routing-number.ts new file mode 100644 index 00000000000..7928af0c88a --- /dev/null +++ b/src/modules/finance/routing-number.ts @@ -0,0 +1,40 @@ +import type { FakerCore } from '../../core'; +import { arrayElement } from '../helpers/array-element'; +import { numeric } from '../string/numeric'; + +/** + * Generates a random [ABA routing number](https://en.wikipedia.org/wiki/ABA_routing_transit_number). + * + * @param fakerCore The FakerCore to use. + * + * @example + * routingNumber(fakerCore) // '062197511' + * + * @since 11.0.0 + * + * @experimental + */ +export function routingNumber(fakerCore: FakerCore): string { + const federalReserveRoutingSymbol = arrayElement( + fakerCore, + fakerCore.locale.finance.federal_reserve_routing_symbol + ); + + const institutionIdentifier = numeric(fakerCore, { + length: 4, + allowLeadingZeros: true, + }); + + const routingNumber = federalReserveRoutingSymbol + institutionIdentifier; + + // Modules 10 straight summation. + let sum = 0; + + for (let i = 0; i < routingNumber.length; i += 3) { + sum += Number(routingNumber[i]) * 3; + sum += Number(routingNumber[i + 1]) * 7; + sum += Number(routingNumber[i + 2]) || 0; + } + + return `${routingNumber}${Math.ceil(sum / 10) * 10 - sum}`; +} diff --git a/src/modules/finance/transaction-description.ts b/src/modules/finance/transaction-description.ts new file mode 100644 index 00000000000..330641d4bbf --- /dev/null +++ b/src/modules/finance/transaction-description.ts @@ -0,0 +1,21 @@ +import type { FakerCore } from '../../core'; +import { Faker } from '../../faker'; + +/** + * Generates a random transaction description. + * + * @param fakerCore The FakerCore to use. + * + * @example + * transactionDescription(fakerCore) + * // 'payment transaction at Emard LLC using card ending with ****9187 for HNL 506.57 in account ***2584.' + * + * @since 11.0.0 + * + * @experimental + */ +export function transactionDescription(fakerCore: FakerCore): string { + return new Faker(fakerCore).helpers.fake( + fakerCore.locale.finance.transaction_description_pattern + ); +} diff --git a/src/modules/finance/transaction-type.ts b/src/modules/finance/transaction-type.ts new file mode 100644 index 00000000000..a3540f9b9a1 --- /dev/null +++ b/src/modules/finance/transaction-type.ts @@ -0,0 +1,18 @@ +import type { FakerCore } from '../../core'; +import { arrayElement } from '../helpers/array-element'; + +/** + * Returns a random transaction type. + * + * @param fakerCore The FakerCore to use. + * + * @example + * transactionType(fakerCore) // 'payment' + * + * @since 11.0.0 + * + * @experimental + */ +export function transactionType(fakerCore: FakerCore): string { + return arrayElement(fakerCore, fakerCore.locale.finance.transaction_type); +} diff --git a/src/modules/finance/vat-number.ts b/src/modules/finance/vat-number.ts new file mode 100644 index 00000000000..9d3a4415182 --- /dev/null +++ b/src/modules/finance/vat-number.ts @@ -0,0 +1,62 @@ +import type { FakerCore } from '../../core'; +import { FakerError } from '../../errors/faker-error'; +import { arrayElement } from '../helpers/array-element'; +import { fromRegExp } from '../helpers/from-reg-exp'; +import type { VatNumberCountryCode } from './_vat-number'; +import { vatNumberCountryCodes, vatNumberFormats } from './_vat-number'; + +/** + * Generates a random VAT identification number for one of the EU member states. + * + * The supported country codes are the EU member states, using the two-letter code each + * country's numbers carry: + * `AT`, `BE`, `BG`, `CY`, `CZ`, `DE`, `DK`, `EE`, `EL` (or `GR`), `ES`, `FI`, `FR`, `HR`, `HU`, + * `IE`, `IT`, `LT`, `LU`, `LV`, `MT`, `NL`, `PL`, `PT`, `RO`, `SE`, `SI` and `SK`. + * + * @param fakerCore The FakerCore to use. + * @remark Please note that this currently only generates the structure of the respective country's VAT identification. + * But it will return random values for digits with intent such as check digits, so the result is likely to be invalid. + * + * @param options An options object. + * @param options.countryCode The two-letter code of the country you want a VAT number for. + * Greece may be given as either `GR` or `EL`. + * Defaults to a random supported country. + * + * @throws {FakerError} Will throw an error if the passed country code is not supported. + * + * @example + * vatNumber(fakerCore) // 'SK4318759382' + * vatNumber(fakerCore, { countryCode: 'DE' }) // 'DE644073457' + * vatNumber(fakerCore, { countryCode: 'NL' }) // 'NL840351580B96' + * vatNumber(fakerCore, { countryCode: 'GR' }) // 'EL892156043' + * + * @since 11.0.0 + * + * @experimental + */ +export function vatNumber( + fakerCore: FakerCore, + options: { + /** + * The two-letter code of the country you want a VAT number for. + * Greece may be given as either `GR` or `EL`. + * + * @default helpersArrayElement(fakerCore, vatNumberCountryCodes) + */ + countryCode?: VatNumberCountryCode; + } = {} +): string { + const { countryCode = arrayElement(fakerCore, vatNumberCountryCodes) } = + options; + + const pattern = vatNumberFormats[countryCode]; + + if (pattern == null) { + throw new FakerError(`Country code ${countryCode} not supported.`); + } + + return fromRegExp( + fakerCore, + typeof pattern === 'string' ? pattern : arrayElement(fakerCore, pattern) + ); +} From 7791c344af3476a9c2997d13462be5950db9ba9c Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Thu, 5 Mar 2026 00:23:45 +0100 Subject: [PATCH 2/5] refactor: transform finance module --- src/definitions/finance.ts | 2 +- src/index.ts | 12 +- src/modules/finance/_bitcoin.ts | 72 ---------- .../finance/{_iban.ts => _iban-lib.ts} | 9 +- src/modules/finance/_vat-number.ts | 115 ---------------- src/modules/finance/bic.ts | 3 +- src/modules/finance/bitcoin-address.ts | 78 ++++++++++- src/modules/finance/currency-symbol.ts | 1 + src/modules/finance/currency.ts | 25 ++++ src/modules/finance/iban.ts | 31 ++++- src/modules/finance/index.ts | 8 +- src/modules/finance/module.ts | 72 +++------- src/modules/finance/vat-number.ts | 126 +++++++++++++++++- test/modules/finance-iban.spec.ts | 4 +- test/modules/finance.spec-d.ts | 2 +- test/modules/finance.spec.ts | 8 +- 16 files changed, 289 insertions(+), 279 deletions(-) delete mode 100644 src/modules/finance/_bitcoin.ts rename src/modules/finance/{_iban.ts => _iban-lib.ts} (99%) delete mode 100644 src/modules/finance/_vat-number.ts diff --git a/src/definitions/finance.ts b/src/definitions/finance.ts index 8353cbfb126..1372b6b5dc4 100644 --- a/src/definitions/finance.ts +++ b/src/definitions/finance.ts @@ -1,4 +1,4 @@ -import type { Currency } from '../modules/finance'; +import type { Currency } from '../modules/finance/currency'; import type { LocaleEntry } from './definitions'; /** * The possible definitions related to finance. diff --git a/src/index.ts b/src/index.ts index 9712425a08d..049df148b67 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,25 +59,19 @@ export type { DatabaseModule } from './modules/database'; export type { DatatypeModule } from './modules/datatype'; export type { DateModule, SimpleDateModule } from './modules/date'; export type { + BitcoinAddressFamily, + BitcoinNetwork, Currency, FinanceModule, VatNumberCountryCode, } from './modules/finance'; -export { - BitcoinAddressFamily, - BitcoinNetwork, -} from './modules/finance/_bitcoin'; -export type { - BitcoinAddressFamilyType, - BitcoinNetworkType, -} from './modules/finance/_bitcoin'; export type { FoodModule } from './modules/food'; export type { GitModule } from './modules/git'; export type { HackerModule } from './modules/hacker'; export type { HelpersModule, SimpleHelpersModule } from './modules/helpers'; export type { ImageModule } from './modules/image'; export { IPv4Network } from './modules/internet'; -export type { IPv4NetworkType, InternetModule } from './modules/internet'; +export type { InternetModule, IPv4NetworkType } from './modules/internet'; export type { LocationModule, SimpleLocationModule } from './modules/location'; export type { LoremModule } from './modules/lorem'; export type { MedicalModule } from './modules/medical'; diff --git a/src/modules/finance/_bitcoin.ts b/src/modules/finance/_bitcoin.ts deleted file mode 100644 index ab8af2e812e..00000000000 --- a/src/modules/finance/_bitcoin.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { Casing, NumberRange } from '../../utils/types'; - -/** - * The bitcoin address families. - */ -export enum BitcoinAddressFamily { - Legacy = 'legacy', - Segwit = 'segwit', - Bech32 = 'bech32', - Taproot = 'taproot', -} - -/** - * The bitcoin address families. - */ -export type BitcoinAddressFamilyType = `${BitcoinAddressFamily}`; - -/** - * The different bitcoin networks. - */ -export enum BitcoinNetwork { - Mainnet = 'mainnet', - Testnet = 'testnet', -} - -/** - * The different bitcoin networks. - */ -export type BitcoinNetworkType = `${BitcoinNetwork}`; - -type BitcoinAddressOptions = { - prefix: Record; - length: NumberRange; - casing: Casing; - exclude: string; -}; - -export const BitcoinAddressSpecs: Record< - BitcoinAddressFamilyType, - BitcoinAddressOptions -> = { - [BitcoinAddressFamily.Legacy]: { - prefix: { [BitcoinNetwork.Mainnet]: '1', [BitcoinNetwork.Testnet]: 'm' }, - length: { min: 26, max: 34 }, - casing: 'mixed', - exclude: '0OIl', - }, - [BitcoinAddressFamily.Segwit]: { - prefix: { [BitcoinNetwork.Mainnet]: '3', [BitcoinNetwork.Testnet]: '2' }, - length: { min: 26, max: 34 }, - casing: 'mixed', - exclude: '0OIl', - }, - [BitcoinAddressFamily.Bech32]: { - prefix: { - [BitcoinNetwork.Mainnet]: 'bc1', - [BitcoinNetwork.Testnet]: 'tb1', - }, - length: { min: 42, max: 42 }, - casing: 'lower', - exclude: '1bBiIoO', - }, - [BitcoinAddressFamily.Taproot]: { - prefix: { - [BitcoinNetwork.Mainnet]: 'bc1p', - [BitcoinNetwork.Testnet]: 'tb1p', - }, - length: { min: 62, max: 62 }, - casing: 'lower', - exclude: '1bBiIoO', - }, -}; diff --git a/src/modules/finance/_iban.ts b/src/modules/finance/_iban-lib.ts similarity index 99% rename from src/modules/finance/_iban.ts rename to src/modules/finance/_iban-lib.ts index c4ca0e7f1fc..b897f80bf42 100644 --- a/src/modules/finance/_iban.ts +++ b/src/modules/finance/_iban-lib.ts @@ -13,7 +13,12 @@ interface Iban { toDigitString: (str: string) => string; } -const iban: Iban = { +/** + * The internal data required to generate IBANs. + * + * @internal + */ +export const ibanLib: Iban = { alpha: [ 'A', 'B', @@ -1422,5 +1427,3 @@ const iban: Iban = { String((match.toUpperCase().codePointAt(0) ?? Number.NaN) - 55) ), }; - -export default iban; diff --git a/src/modules/finance/_vat-number.ts b/src/modules/finance/_vat-number.ts deleted file mode 100644 index c1c026986e3..00000000000 --- a/src/modules/finance/_vat-number.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * The VAT identification number patterns of the EU member states, keyed by - * ISO 3166-1 alpha-2 code, plus `EL`: the prefix Greek numbers carry in place - * of `GR`. - * - * Each pattern is written for `faker.helpers.fromRegExp()`. - * Currently, all values are generated randomly, so parts with intent such as check digits will likely produce invalid values. - */ -export const vatNumberFormats = { - /** UID-Nummer. */ - AT: 'ATU[0-9]{8}', - /** - * BTW-nummer. Begins with 0 or 1: the 2005 ten-digit form zero-padded the - * older nine-digit numbers, and the 1 series was opened later, once the 0 - * series neared exhaustion. - */ - BE: 'BE[01][0-9]{9}', - /** DDS nomer. Nine digits for legal entities, ten for individuals. */ - BG: 'BG[0-9]{9,10}', - /** - * FPA. Numbers begin 0, 1, 3, 4, 5 or 9 under the legacy categories, or 6 - * under the format introduced in March 2023; 2, 7 and 8 are not issued. - */ - CY: 'CY[0134569][0-9]{7}[A-Z]', - /** DIC. */ - CZ: 'CZ[0-9]{8,10}', - /** Umsatzsteuer-Identifikationsnummer. */ - DE: 'DE[0-9]{9}', - /** CVR-nummer. */ - DK: 'DK[0-9]{8}', - /** KMKR number. */ - EE: 'EE[0-9]{9}', - /** AFM. */ - EL: 'EL[0-9]{9}', - /** - * NIF/CIF for entities. The leading character encodes the legal form, which - * constrains the control character: A, B, E and H always take a digit, - * C, D, F, G, J, U and V may take either, and foreign entities, public - * bodies, local corporations and religious congregations (N, P, Q, R, S, W) - * always take a letter. The two branches are separate patterns because one - * character class would pair the positions freely and emit combinations that - * are never issued; the may-take-either letters are generated with a digit, - * which under-generates rather than over-generates. The natural-person forms - * are out of scope. - */ - ES: ['ES[ABCDEFGHJUV][0-9]{7}[0-9]', 'ES[NPQRSW][0-9]{7}[A-J]'], - /** ALV-numero. */ - FI: 'FI[0-9]{8}', - /** - * Numero de TVA intracommunautaire: a two-character key followed by the - * nine-digit SIREN. The letters I and O are not used in the key. - */ - FR: 'FR[0-9ABCDEFGHJKLMNPQRSTUVWXYZ]{2}[0-9]{9}', - /** AFM. Same as `EL`. */ - GR: 'EL[0-9]{9}', - /** PDV ID. */ - HR: 'HR[0-9]{11}', - /** Kozossegi adoszam. */ - HU: 'HU[0-9]{8}', - /** - * VAT number: seven digits and a check letter, optionally followed by a - * `W` — the legacy marker for a married woman registered on her husband's - * number. The 2013 form, whose second letter runs A to I rather than being - * `W`, is not modelled, nor is the older form that carries a symbol. - */ - IE: 'IE[0-9]{7}[A-W]W{0,1}', - /** Partita IVA. */ - IT: 'IT[0-9]{11}', - /** - * PVM kodas. Nine digits for legal entities, where the eighth is always 1 - * and the ninth is a check digit. The twelve-digit form for temporarily - * registered taxpayers is rare and not modelled — note it could not simply - * widen this pattern to `[0-9]{9,12}`, since the lengths in between are - * never issued. - */ - LT: 'LT[0-9]{7}1[0-9]', - /** Numero de TVA. */ - LU: 'LU[0-9]{8}', - /** PVN numurs. */ - LV: 'LV[0-9]{11}', - /** VAT number. */ - MT: 'MT[0-9]{8}', - /** - * Btw-identificatienummer. The two digits after the `B` are a company index - * running from 01 to 99, so `B00` is never issued — which takes two patterns - * to express, since a plain digit pair would include it. - */ - NL: ['NL[0-9]{9}B0[1-9]', 'NL[0-9]{9}B[1-9][0-9]'], - /** NIP. */ - PL: 'PL[0-9]{10}', - /** Numero de identificacao fiscal. No taxpayer range begins with zero. */ - PT: 'PT[1-9][0-9]{8}', - /** Cod de identificare fiscala. Between 2 and 10 digits, never leading zero. */ - RO: 'RO[1-9][0-9]{1,9}', - /** - * Momsnummer: the ten-digit organisationsnummer followed by a two-digit - * establishment number. Only `01` is generated — it is the value for all but - * a handful of multi-establishment registrations. - */ - SE: 'SE[0-9]{10}01', - /** ID za DDV. Eight digits, never a leading zero. */ - SI: 'SI[1-9][0-9]{7}', - /** IC DPH. */ - SK: 'SK[0-9]{10}', -} as const satisfies Record>; - -/** The codes to draw from, minus `GR`, which would give Greece double weight. */ -export const vatNumberCountryCodes = Object.keys(vatNumberFormats).filter( - (code) => code !== 'GR' -) as VatNumberCountryCode[]; - -/** - * The country codes for which a VAT identification number can be generated. - */ -export type VatNumberCountryCode = keyof typeof vatNumberFormats; diff --git a/src/modules/finance/bic.ts b/src/modules/finance/bic.ts index a6b4974da42..2f865339b7f 100644 --- a/src/modules/finance/bic.ts +++ b/src/modules/finance/bic.ts @@ -3,6 +3,7 @@ import { boolean } from '../datatype/boolean'; import { arrayElement } from '../helpers/array-element'; import { alpha } from '../string/alpha'; import { alphanumeric } from '../string/alphanumeric'; +import { ibanLib } from './_iban-lib'; /** * Generates a random SWIFT/BIC code based on the [ISO-9362](https://en.wikipedia.org/wiki/ISO_9362) format. @@ -37,7 +38,7 @@ export function bic( length: 4, casing: 'upper', }); - const countryCode = arrayElement(fakerCore, iban.iso3166); + const countryCode = arrayElement(fakerCore, ibanLib.iso3166); const locationCode = alphanumeric(fakerCore, { length: 2, casing: 'upper', diff --git a/src/modules/finance/bitcoin-address.ts b/src/modules/finance/bitcoin-address.ts index 6d68214660c..0cf754b91ae 100644 --- a/src/modules/finance/bitcoin-address.ts +++ b/src/modules/finance/bitcoin-address.ts @@ -1,13 +1,79 @@ import type { FakerCore } from '../../core'; +import type { Casing, NumberRange } from '../../utils/types'; import { enumValue } from '../helpers/enum-value'; import { int } from '../number/int'; import { alphanumeric } from '../string/alphanumeric'; -import type { BitcoinAddressFamilyType, BitcoinNetworkType } from './_bitcoin'; -import { - BitcoinAddressFamily, - BitcoinAddressSpecs, - BitcoinNetwork, -} from './_bitcoin'; + +/** + * The bitcoin address families. + */ +export enum BitcoinAddressFamily { + Legacy = 'legacy', + Segwit = 'segwit', + Bech32 = 'bech32', + Taproot = 'taproot', +} + +/** + * The bitcoin address families. + */ +export type BitcoinAddressFamilyType = `${BitcoinAddressFamily}`; + +/** + * The different bitcoin networks. + */ +export enum BitcoinNetwork { + Mainnet = 'mainnet', + Testnet = 'testnet', +} + +/** + * The different bitcoin networks. + */ +export type BitcoinNetworkType = `${BitcoinNetwork}`; + +type BitcoinAddressOptions = { + prefix: Record; + length: NumberRange; + casing: Casing; + exclude: string; +}; + +export const BitcoinAddressSpecs: Record< + BitcoinAddressFamilyType, + BitcoinAddressOptions +> = { + [BitcoinAddressFamily.Legacy]: { + prefix: { [BitcoinNetwork.Mainnet]: '1', [BitcoinNetwork.Testnet]: 'm' }, + length: { min: 26, max: 34 }, + casing: 'mixed', + exclude: '0OIl', + }, + [BitcoinAddressFamily.Segwit]: { + prefix: { [BitcoinNetwork.Mainnet]: '3', [BitcoinNetwork.Testnet]: '2' }, + length: { min: 26, max: 34 }, + casing: 'mixed', + exclude: '0OIl', + }, + [BitcoinAddressFamily.Bech32]: { + prefix: { + [BitcoinNetwork.Mainnet]: 'bc1', + [BitcoinNetwork.Testnet]: 'tb1', + }, + length: { min: 42, max: 42 }, + casing: 'lower', + exclude: '1bBiIoO', + }, + [BitcoinAddressFamily.Taproot]: { + prefix: { + [BitcoinNetwork.Mainnet]: 'bc1p', + [BitcoinNetwork.Testnet]: 'tb1p', + }, + length: { min: 62, max: 62 }, + casing: 'lower', + exclude: '1bBiIoO', + }, +}; /** * Generates a random Bitcoin address. diff --git a/src/modules/finance/currency-symbol.ts b/src/modules/finance/currency-symbol.ts index a34d28451a1..5fdb88891c6 100644 --- a/src/modules/finance/currency-symbol.ts +++ b/src/modules/finance/currency-symbol.ts @@ -6,6 +6,7 @@ import { arrayElement } from '../helpers/array-element'; * Returns a random currency symbol. * * @param fakerCore The FakerCore to use. + * * @throws {FakerError} If no currency in the locale data has a symbol. * * @example diff --git a/src/modules/finance/currency.ts b/src/modules/finance/currency.ts index ef10fa68e20..84d7524bfda 100644 --- a/src/modules/finance/currency.ts +++ b/src/modules/finance/currency.ts @@ -1,6 +1,31 @@ import type { FakerCore } from '../../core'; import { arrayElement } from '../helpers/array-element'; +/** + * The possible definitions related to currency entries. + */ +export interface Currency { + /** + * The full name for the currency (e.g. `US Dollar`). + */ + name: string; + + /** + * The code/short text/abbreviation for the currency (e.g. `USD`). + */ + code: string; + + /** + * The symbol for the currency (e.g. `$`). + */ + symbol: string; + + /** + * The ISO 4217 numeric code for the currency (e.g. `840`). + */ + numericCode: string; +} + /** * Returns a random currency object, containing `code`, `name`, `symbol`, and `numericCode` properties. * diff --git a/src/modules/finance/iban.ts b/src/modules/finance/iban.ts index 80f63eda427..ba960c55dd4 100644 --- a/src/modules/finance/iban.ts +++ b/src/modules/finance/iban.ts @@ -3,6 +3,23 @@ import { FakerError } from '../../errors/faker-error'; import { boolean } from '../datatype/boolean'; import { arrayElement } from '../helpers/array-element'; import { int } from '../number/int'; +import { ibanLib } from './_iban-lib'; + +/** + * Puts a space after every 4 characters. + * + * @internal + * + * @param iban The iban to pretty print. + */ +export function prettyPrintIban(iban: string): string { + let pretty = ''; + for (let i = 0; i < iban.length; i += 4) { + pretty += `${iban.substring(i, i + 4)} `; + } + + return pretty.trimEnd(); +} /** * Generates a random IBAN. @@ -44,8 +61,8 @@ export function iban( const { countryCode, formatted = false } = options; const ibanFormat = countryCode - ? iban.formats.find((f) => f.country === countryCode) - : arrayElement(fakerCore, iban.formats); + ? ibanLib.formats.find((f) => f.country === countryCode) + : arrayElement(fakerCore, ibanLib.formats); if (!ibanFormat) { throw new FakerError(`Country code ${countryCode} not supported.`); @@ -58,20 +75,20 @@ export function iban( count += bban.count; while (c > 0) { if (bban.type === 'a') { - s += arrayElement(fakerCore, iban.alpha); + s += arrayElement(fakerCore, ibanLib.alpha); } else if (bban.type === 'c') { if (boolean(fakerCore, 0.8)) { s += int(fakerCore, 9); } else { - s += arrayElement(fakerCore, iban.alpha); + s += arrayElement(fakerCore, ibanLib.alpha); } } else { if (c >= 3 && boolean(fakerCore, 0.3)) { if (boolean(fakerCore)) { - s += arrayElement(fakerCore, iban.pattern100); + s += arrayElement(fakerCore, ibanLib.pattern100); c -= 2; } else { - s += arrayElement(fakerCore, iban.pattern10); + s += arrayElement(fakerCore, ibanLib.pattern10); c--; } } else { @@ -86,7 +103,7 @@ export function iban( } let checksum: string | number = - 98 - iban.mod97(iban.toDigitString(`${s}${ibanFormat.country}00`)); + 98 - ibanLib.mod97(ibanLib.toDigitString(`${s}${ibanFormat.country}00`)); if (checksum < 10) { checksum = `0${checksum}`; diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts index 30d9c039790..51d8261b841 100644 --- a/src/modules/finance/index.ts +++ b/src/modules/finance/index.ts @@ -1,2 +1,8 @@ +export { BitcoinAddressFamily, BitcoinNetwork } from './bitcoin-address'; +export type { + BitcoinAddressFamilyType, + BitcoinNetworkType, +} from './bitcoin-address'; +export type { Currency } from './currency'; export * from './module'; -export type { VatNumberCountryCode } from './_vat-number'; +export type { VatNumberCountryCode } from './vat-number'; diff --git a/src/modules/finance/module.ts b/src/modules/finance/module.ts index 2e2cb4bc5a7..06b5238312b 100644 --- a/src/modules/finance/module.ts +++ b/src/modules/finance/module.ts @@ -1,55 +1,19 @@ import { FakerError } from '../../errors/faker-error'; import { ModuleBase } from '../../internal/module-base'; -import type { BitcoinAddressFamilyType, BitcoinNetworkType } from './_bitcoin'; +import { ibanLib } from './_iban-lib'; +import type { + BitcoinAddressFamilyType, + BitcoinNetworkType, +} from './bitcoin-address'; import { BitcoinAddressFamily, BitcoinAddressSpecs, BitcoinNetwork, -} from './_bitcoin'; -import iban from './_iban'; -import type { VatNumberCountryCode } from './_vat-number'; -import { vatNumberCountryCodes, vatNumberFormats } from './_vat-number'; - -/** - * The possible definitions related to currency entries. - */ -export interface Currency { - /** - * The full name for the currency (e.g. `US Dollar`). - */ - name: string; - - /** - * The code/short text/abbreviation for the currency (e.g. `USD`). - */ - code: string; - - /** - * The symbol for the currency (e.g. `$`). - */ - symbol: string; - - /** - * The ISO 4217 numeric code for the currency (e.g. `840`). - */ - numericCode: string; -} - -/** - * Puts a space after every 4 characters. - * - * @internal - * - * @param iban The iban to pretty print. - */ -export function prettyPrintIban(iban: string): string { - let pretty = ''; - for (let i = 0; i < iban.length; i += 4) { - pretty += `${iban.substring(i, i + 4)} `; - } - - return pretty.trimEnd(); -} +} from './bitcoin-address'; +import type { Currency } from './currency'; +import { prettyPrintIban } from './iban'; +import { vatNumberCountryCodes, vatNumberFormats } from './vat-number'; +import type { VatNumberCountryCode } from './vat-number'; /** * Module to generate finance and money related entries. @@ -757,8 +721,8 @@ export class FinanceModule extends ModuleBase { const { countryCode, formatted = false } = options; const ibanFormat = countryCode - ? iban.formats.find((f) => f.country === countryCode) - : this.faker.helpers.arrayElement(iban.formats); + ? ibanLib.formats.find((f) => f.country === countryCode) + : this.faker.helpers.arrayElement(ibanLib.formats); if (!ibanFormat) { throw new FakerError(`Country code ${countryCode} not supported.`); @@ -771,20 +735,20 @@ export class FinanceModule extends ModuleBase { count += bban.count; while (c > 0) { if (bban.type === 'a') { - s += this.faker.helpers.arrayElement(iban.alpha); + s += this.faker.helpers.arrayElement(ibanLib.alpha); } else if (bban.type === 'c') { if (this.faker.datatype.boolean(0.8)) { s += this.faker.number.int(9); } else { - s += this.faker.helpers.arrayElement(iban.alpha); + s += this.faker.helpers.arrayElement(ibanLib.alpha); } } else { if (c >= 3 && this.faker.datatype.boolean(0.3)) { if (this.faker.datatype.boolean()) { - s += this.faker.helpers.arrayElement(iban.pattern100); + s += this.faker.helpers.arrayElement(ibanLib.pattern100); c -= 2; } else { - s += this.faker.helpers.arrayElement(iban.pattern10); + s += this.faker.helpers.arrayElement(ibanLib.pattern10); c--; } } else { @@ -799,7 +763,7 @@ export class FinanceModule extends ModuleBase { } let checksum: string | number = - 98 - iban.mod97(iban.toDigitString(`${s}${ibanFormat.country}00`)); + 98 - ibanLib.mod97(ibanLib.toDigitString(`${s}${ibanFormat.country}00`)); if (checksum < 10) { checksum = `0${checksum}`; @@ -839,7 +803,7 @@ export class FinanceModule extends ModuleBase { length: 4, casing: 'upper', }); - const countryCode = this.faker.helpers.arrayElement(iban.iso3166); + const countryCode = this.faker.helpers.arrayElement(ibanLib.iso3166); const locationCode = this.faker.string.alphanumeric({ length: 2, casing: 'upper', diff --git a/src/modules/finance/vat-number.ts b/src/modules/finance/vat-number.ts index 9d3a4415182..be0164679da 100644 --- a/src/modules/finance/vat-number.ts +++ b/src/modules/finance/vat-number.ts @@ -2,8 +2,128 @@ import type { FakerCore } from '../../core'; import { FakerError } from '../../errors/faker-error'; import { arrayElement } from '../helpers/array-element'; import { fromRegExp } from '../helpers/from-reg-exp'; -import type { VatNumberCountryCode } from './_vat-number'; -import { vatNumberCountryCodes, vatNumberFormats } from './_vat-number'; + +/** + * The VAT identification number patterns of the EU member states, keyed by + * ISO 3166-1 alpha-2 code, plus `EL`: the prefix Greek numbers carry in place + * of `GR`. + * + * Each pattern is written for `faker.helpers.fromRegExp()`. + * Currently, all values are generated randomly, so parts with intent such as check digits will likely produce invalid values. + * + * @internal + */ +export const vatNumberFormats = { + /** UID-Nummer. */ + AT: 'ATU[0-9]{8}', + /** + * BTW-nummer. Begins with 0 or 1: the 2005 ten-digit form zero-padded the + * older nine-digit numbers, and the 1 series was opened later, once the 0 + * series neared exhaustion. + */ + BE: 'BE[01][0-9]{9}', + /** DDS nomer. Nine digits for legal entities, ten for individuals. */ + BG: 'BG[0-9]{9,10}', + /** + * FPA. Numbers begin 0, 1, 3, 4, 5 or 9 under the legacy categories, or 6 + * under the format introduced in March 2023; 2, 7 and 8 are not issued. + */ + CY: 'CY[0134569][0-9]{7}[A-Z]', + /** DIC. */ + CZ: 'CZ[0-9]{8,10}', + /** Umsatzsteuer-Identifikationsnummer. */ + DE: 'DE[0-9]{9}', + /** CVR-nummer. */ + DK: 'DK[0-9]{8}', + /** KMKR number. */ + EE: 'EE[0-9]{9}', + /** AFM. */ + EL: 'EL[0-9]{9}', + /** + * NIF/CIF for entities. The leading character encodes the legal form, which + * constrains the control character: A, B, E and H always take a digit, + * C, D, F, G, J, U and V may take either, and foreign entities, public + * bodies, local corporations and religious congregations (N, P, Q, R, S, W) + * always take a letter. The two branches are separate patterns because one + * character class would pair the positions freely and emit combinations that + * are never issued; the may-take-either letters are generated with a digit, + * which under-generates rather than over-generates. The natural-person forms + * are out of scope. + */ + ES: ['ES[ABCDEFGHJUV][0-9]{7}[0-9]', 'ES[NPQRSW][0-9]{7}[A-J]'], + /** ALV-numero. */ + FI: 'FI[0-9]{8}', + /** + * Numero de TVA intracommunautaire: a two-character key followed by the + * nine-digit SIREN. The letters I and O are not used in the key. + */ + FR: 'FR[0-9ABCDEFGHJKLMNPQRSTUVWXYZ]{2}[0-9]{9}', + /** AFM. Same as `EL`. */ + GR: 'EL[0-9]{9}', + /** PDV ID. */ + HR: 'HR[0-9]{11}', + /** Kozossegi adoszam. */ + HU: 'HU[0-9]{8}', + /** + * VAT number: seven digits and a check letter, optionally followed by a + * `W` — the legacy marker for a married woman registered on her husband's + * number. The 2013 form, whose second letter runs A to I rather than being + * `W`, is not modelled, nor is the older form that carries a symbol. + */ + IE: 'IE[0-9]{7}[A-W]W{0,1}', + /** Partita IVA. */ + IT: 'IT[0-9]{11}', + /** + * PVM kodas. Nine digits for legal entities, where the eighth is always 1 + * and the ninth is a check digit. The twelve-digit form for temporarily + * registered taxpayers is rare and not modelled — note it could not simply + * widen this pattern to `[0-9]{9,12}`, since the lengths in between are + * never issued. + */ + LT: 'LT[0-9]{7}1[0-9]', + /** Numero de TVA. */ + LU: 'LU[0-9]{8}', + /** PVN numurs. */ + LV: 'LV[0-9]{11}', + /** VAT number. */ + MT: 'MT[0-9]{8}', + /** + * Btw-identificatienummer. The two digits after the `B` are a company index + * running from 01 to 99, so `B00` is never issued — which takes two patterns + * to express, since a plain digit pair would include it. + */ + NL: ['NL[0-9]{9}B0[1-9]', 'NL[0-9]{9}B[1-9][0-9]'], + /** NIP. */ + PL: 'PL[0-9]{10}', + /** Numero de identificacao fiscal. No taxpayer range begins with zero. */ + PT: 'PT[1-9][0-9]{8}', + /** Cod de identificare fiscala. Between 2 and 10 digits, never leading zero. */ + RO: 'RO[1-9][0-9]{1,9}', + /** + * Momsnummer: the ten-digit organisationsnummer followed by a two-digit + * establishment number. Only `01` is generated — it is the value for all but + * a handful of multi-establishment registrations. + */ + SE: 'SE[0-9]{10}01', + /** ID za DDV. Eight digits, never a leading zero. */ + SI: 'SI[1-9][0-9]{7}', + /** IC DPH. */ + SK: 'SK[0-9]{10}', +} as const satisfies Record>; + +/** + * The codes to draw from, minus `GR`, which would give Greece double weight. + * + * @internal + */ +export const vatNumberCountryCodes = Object.keys(vatNumberFormats).filter( + (code) => code !== 'GR' +) as VatNumberCountryCode[]; + +/** + * The country codes for which a VAT identification number can be generated. + */ +export type VatNumberCountryCode = keyof typeof vatNumberFormats; /** * Generates a random VAT identification number for one of the EU member states. @@ -13,10 +133,10 @@ import { vatNumberCountryCodes, vatNumberFormats } from './_vat-number'; * `AT`, `BE`, `BG`, `CY`, `CZ`, `DE`, `DK`, `EE`, `EL` (or `GR`), `ES`, `FI`, `FR`, `HR`, `HU`, * `IE`, `IT`, `LT`, `LU`, `LV`, `MT`, `NL`, `PL`, `PT`, `RO`, `SE`, `SI` and `SK`. * - * @param fakerCore The FakerCore to use. * @remark Please note that this currently only generates the structure of the respective country's VAT identification. * But it will return random values for digits with intent such as check digits, so the result is likely to be invalid. * + * @param fakerCore The FakerCore to use. * @param options An options object. * @param options.countryCode The two-letter code of the country you want a VAT number for. * Greece may be given as either `GR` or `EL`. diff --git a/test/modules/finance-iban.spec.ts b/test/modules/finance-iban.spec.ts index 58375d61ea5..4a830af9525 100644 --- a/test/modules/finance-iban.spec.ts +++ b/test/modules/finance-iban.spec.ts @@ -1,8 +1,8 @@ import { isIBAN } from 'validator'; import { describe, expect, it } from 'vitest'; import { faker } from '../../src'; -import { prettyPrintIban } from '../../src/modules/finance'; -import ibanLib from '../../src/modules/finance/_iban'; +import { ibanLib } from '../../src/modules/finance/_iban-lib'; +import { prettyPrintIban } from '../../src/modules/finance/iban'; import { times } from '../support/times'; const NON_SEEDED_BASED_RUN = 25; diff --git a/test/modules/finance.spec-d.ts b/test/modules/finance.spec-d.ts index b18f5da06ea..5a8c6777eb7 100644 --- a/test/modules/finance.spec-d.ts +++ b/test/modules/finance.spec-d.ts @@ -1,6 +1,6 @@ import type { VATCountryCode } from 'validator'; import { describe, expectTypeOf, it } from 'vitest'; -import type { VatNumberCountryCode } from '../../src/modules/finance/_vat-number'; +import type { VatNumberCountryCode } from '../../src/modules/finance/vat-number'; describe('finance', () => { describe('vatNumber', () => { diff --git a/test/modules/finance.spec.ts b/test/modules/finance.spec.ts index ba983209068..b28cc06ae50 100644 --- a/test/modules/finance.spec.ts +++ b/test/modules/finance.spec.ts @@ -8,13 +8,13 @@ import { FakerError } from '../../src/errors/faker-error'; import { BitcoinAddressFamily, BitcoinNetwork, -} from '../../src/modules/finance/_bitcoin'; -import ibanLib from '../../src/modules/finance/_iban'; -import type { VatNumberCountryCode } from '../../src/modules/finance/_vat-number'; +} from '../../src/modules/finance'; +import { ibanLib } from '../../src/modules/finance/_iban-lib'; import { vatNumberCountryCodes, vatNumberFormats, -} from '../../src/modules/finance/_vat-number'; +} from '../../src/modules/finance/vat-number'; +import type { VatNumberCountryCode } from '../../src/modules/finance/vat-number'; import { luhnCheck } from '../../src/modules/helpers/_luhn-check'; import { seededTests } from '../support/seeded-runs'; import { times } from '../support/times'; From 7a25199ff1eac58f73f78768c5e8a3175defb0d7 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Thu, 3 Sep 2026 23:29:20 +0200 Subject: [PATCH 3/5] chore: allow module --- scripts/temp-module-filter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/temp-module-filter.ts b/scripts/temp-module-filter.ts index 8acc3cefd3c..66123f9d932 100644 --- a/scripts/temp-module-filter.ts +++ b/scripts/temp-module-filter.ts @@ -8,6 +8,7 @@ export const ALLOWED_MODULES = new Set([ 'DatabaseModule', 'DatatypeModule', 'DateModule', + 'FinanceModule', 'FoodModule', 'GitModule', 'HackerModule', From dc0183a325c56a25016a13b76a2601bab9b7082a Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sun, 6 Sep 2026 13:10:51 +0200 Subject: [PATCH 4/5] chore: apply generate-module-tree script (clean) --- src/modules/finance/module.ts | 288 ++++++---------------------------- 1 file changed, 47 insertions(+), 241 deletions(-) diff --git a/src/modules/finance/module.ts b/src/modules/finance/module.ts index 06b5238312b..3218bc21470 100644 --- a/src/modules/finance/module.ts +++ b/src/modules/finance/module.ts @@ -1,19 +1,31 @@ -import { FakerError } from '../../errors/faker-error'; import { ModuleBase } from '../../internal/module-base'; -import { ibanLib } from './_iban-lib'; +import { accountName as financeAccountName } from './account-name'; +import { accountNumber as financeAccountNumber } from './account-number'; +import { amount as financeAmount } from './amount'; +import { bic as financeBic } from './bic'; import type { BitcoinAddressFamilyType, BitcoinNetworkType, } from './bitcoin-address'; -import { - BitcoinAddressFamily, - BitcoinAddressSpecs, - BitcoinNetwork, -} from './bitcoin-address'; +import { bitcoinAddress as financeBitcoinAddress } from './bitcoin-address'; +import { creditCardCVV as financeCreditCardCVV } from './credit-card-cvv'; +import { creditCardIssuer as financeCreditCardIssuer } from './credit-card-issuer'; +import { creditCardNumber as financeCreditCardNumber } from './credit-card-number'; import type { Currency } from './currency'; -import { prettyPrintIban } from './iban'; -import { vatNumberCountryCodes, vatNumberFormats } from './vat-number'; +import { currency as financeCurrency } from './currency'; +import { currencyCode as financeCurrencyCode } from './currency-code'; +import { currencyName as financeCurrencyName } from './currency-name'; +import { currencyNumericCode as financeCurrencyNumericCode } from './currency-numeric-code'; +import { currencySymbol as financeCurrencySymbol } from './currency-symbol'; +import { ethereumAddress as financeEthereumAddress } from './ethereum-address'; +import { iban as financeIban } from './iban'; +import { litecoinAddress as financeLitecoinAddress } from './litecoin-address'; +import { pin as financePin } from './pin'; +import { routingNumber as financeRoutingNumber } from './routing-number'; +import { transactionDescription as financeTransactionDescription } from './transaction-description'; +import { transactionType as financeTransactionType } from './transaction-type'; import type { VatNumberCountryCode } from './vat-number'; +import { vatNumber as financeVatNumber } from './vat-number'; /** * Module to generate finance and money related entries. @@ -31,6 +43,11 @@ import type { VatNumberCountryCode } from './vat-number'; * For blockchain related methods, use: [`bitcoinAddress()`](https://fakerjs.dev/api/finance.html#bitcoinaddress), [`ethereumAddress()`](https://fakerjs.dev/api/finance.html#ethereumaddress) and [`litecoinAddress()`](https://fakerjs.dev/api/finance.html#litecoinaddress). */ export class FinanceModule extends ModuleBase { + /* + * The class body is automatically generated. + * Run 'pnpm run generate:module-tree finance' to update the methods from their respective files. + */ + /** * Generates a random account number. * @@ -121,13 +138,7 @@ export class FinanceModule extends ModuleBase { length?: number; } = {} ): string { - if (typeof options === 'number') { - options = { length: options }; - } - - const { length = 8 } = options; - - return this.faker.string.numeric({ length, allowLeadingZeros: true }); + return financeAccountNumber(this.faker.fakerCore, options); } /** @@ -139,12 +150,7 @@ export class FinanceModule extends ModuleBase { * @since 2.0.1 */ accountName(): string { - return [ - this.faker.helpers.arrayElement( - this.faker.definitions.finance.account_type - ), - 'Account', - ].join(' '); + return financeAccountName(this.faker.fakerCore); } /** @@ -156,27 +162,7 @@ export class FinanceModule extends ModuleBase { * @since 5.0.0 */ routingNumber(): string { - const federalReserveRoutingSymbol = this.faker.helpers.arrayElement( - this.faker.definitions.finance.federal_reserve_routing_symbol - ); - - const institutionIdentifier = this.faker.string.numeric({ - length: 4, - allowLeadingZeros: true, - }); - - const routingNumber = federalReserveRoutingSymbol + institutionIdentifier; - - // Modules 10 straight summation. - let sum = 0; - - for (let i = 0; i < routingNumber.length; i += 3) { - sum += Number(routingNumber[i]) * 3; - sum += Number(routingNumber[i + 1]) * 7; - sum += Number(routingNumber[i + 2]) || 0; - } - - return `${routingNumber}${Math.ceil(sum / 10) * 10 - sum}`; + return financeRoutingNumber(this.faker.fakerCore); } /** @@ -234,25 +220,7 @@ export class FinanceModule extends ModuleBase { autoFormat?: boolean; } = {} ): string { - const { - autoFormat = false, - dec = 2, - max = 1000, - min = 0, - symbol = '', - } = options; - - const randValue = this.faker.number.float({ - max, - min, - fractionDigits: dec, - }); - - const formattedString = autoFormat - ? randValue.toLocaleString(undefined, { minimumFractionDigits: dec }) - : randValue.toFixed(dec); - - return symbol + formattedString; + return financeAmount(this.faker.fakerCore, options); } /** @@ -264,9 +232,7 @@ export class FinanceModule extends ModuleBase { * @since 2.0.1 */ transactionType(): string { - return this.faker.helpers.arrayElement( - this.faker.definitions.finance.transaction_type - ); + return financeTransactionType(this.faker.fakerCore); } /** @@ -283,9 +249,7 @@ export class FinanceModule extends ModuleBase { * @since 8.0.0 */ currency(): Currency { - return this.faker.helpers.arrayElement( - this.faker.definitions.finance.currency - ); + return financeCurrency(this.faker.fakerCore); } /** @@ -298,7 +262,7 @@ export class FinanceModule extends ModuleBase { * @since 2.0.1 */ currencyCode(): string { - return this.currency().code; + return financeCurrencyCode(this.faker.fakerCore); } /** @@ -310,7 +274,7 @@ export class FinanceModule extends ModuleBase { * @since 2.0.1 */ currencyName(): string { - return this.currency().name; + return financeCurrencyName(this.faker.fakerCore); } /** @@ -324,18 +288,7 @@ export class FinanceModule extends ModuleBase { * @since 2.0.1 */ currencySymbol(): string { - const currenciesWithSymbols = - this.faker.definitions.finance.currency.filter( - (currency) => currency.symbol.length > 0 - ); - - if (currenciesWithSymbols.length === 0) { - throw new FakerError( - 'Cannot get currency symbol from dataset with no currency symbols.' - ); - } - - return this.faker.helpers.arrayElement(currenciesWithSymbols).symbol; + return financeCurrencySymbol(this.faker.fakerCore); } /** @@ -348,7 +301,7 @@ export class FinanceModule extends ModuleBase { * @since 9.6.0 */ currencyNumericCode(): string { - return this.currency().numericCode; + return financeCurrencyNumericCode(this.faker.fakerCore); } /** @@ -381,21 +334,7 @@ export class FinanceModule extends ModuleBase { network?: BitcoinNetworkType; } = {} ): string { - const { - type = this.faker.helpers.enumValue(BitcoinAddressFamily), - network = BitcoinNetwork.Mainnet, - } = options; - const addressSpec = BitcoinAddressSpecs[type]; - const addressPrefix = addressSpec.prefix[network]; - const addressLength = this.faker.number.int(addressSpec.length); - - const address = this.faker.string.alphanumeric({ - length: addressLength - addressPrefix.length, - casing: addressSpec.casing, - exclude: addressSpec.exclude, - }); - - return addressPrefix + address; + return financeBitcoinAddress(this.faker.fakerCore, options); } /** @@ -407,16 +346,7 @@ export class FinanceModule extends ModuleBase { * @since 5.0.0 */ litecoinAddress(): string { - const addressLength = this.faker.number.int({ min: 26, max: 33 }); - - const address = - this.faker.string.fromCharacters('LM3') + - this.faker.string.fromCharacters( - '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', - addressLength - 1 - ); - - return address; + return financeLitecoinAddress(this.faker.fakerCore); } /** @@ -505,29 +435,7 @@ export class FinanceModule extends ModuleBase { issuer?: string; } = {} ): string { - if (typeof options === 'string') { - options = { issuer: options }; - } - - const { issuer = '' } = options; - - let format: string; - const localeFormat = this.faker.definitions.finance.credit_card; - const normalizedIssuer = issuer.toLowerCase(); - if (normalizedIssuer in localeFormat) { - format = this.faker.helpers.arrayElement(localeFormat[normalizedIssuer]); - } else if (issuer.includes('#')) { - // The user chose an optional scheme - format = issuer; - } else { - // Choose a random issuer - // Credit cards are in an object structure - const formats = this.faker.helpers.objectValue(localeFormat); // There could be multiple formats - format = this.faker.helpers.arrayElement(formats); - } - - format = format.replaceAll('/', ''); - return this.faker.helpers.replaceCreditCardSymbols(format); + return financeCreditCardNumber(this.faker.fakerCore, options); } /** @@ -539,7 +447,7 @@ export class FinanceModule extends ModuleBase { * @since 5.0.0 */ creditCardCVV(): string { - return this.faker.string.numeric({ length: 3, allowLeadingZeros: true }); + return financeCreditCardCVV(this.faker.fakerCore); } /** @@ -551,9 +459,7 @@ export class FinanceModule extends ModuleBase { * @since 6.3.0 */ creditCardIssuer(): string { - return this.faker.helpers.objectKey( - this.faker.definitions.finance.credit_card - ) as string; + return financeCreditCardIssuer(this.faker.fakerCore); } /** @@ -654,17 +560,7 @@ export class FinanceModule extends ModuleBase { length?: number; } = {} ): string { - if (typeof options === 'number') { - options = { length: options }; - } - - const { length = 4 } = options; - - if (length < 1) { - throw new FakerError('minimum length is 1'); - } - - return this.faker.string.numeric({ length, allowLeadingZeros: true }); + return financePin(this.faker.fakerCore, options); } /** @@ -678,11 +574,7 @@ export class FinanceModule extends ModuleBase { * @since 5.0.0 */ ethereumAddress(): string { - const address = this.faker.string.hexadecimal({ - length: 40, - casing: 'lower', - }); - return address; + return financeEthereumAddress(this.faker.fakerCore); } /** @@ -718,60 +610,7 @@ export class FinanceModule extends ModuleBase { countryCode?: string; } = {} ): string { - const { countryCode, formatted = false } = options; - - const ibanFormat = countryCode - ? ibanLib.formats.find((f) => f.country === countryCode) - : this.faker.helpers.arrayElement(ibanLib.formats); - - if (!ibanFormat) { - throw new FakerError(`Country code ${countryCode} not supported.`); - } - - let s = ''; - let count = 0; - for (const bban of ibanFormat.bban) { - let c = bban.count; - count += bban.count; - while (c > 0) { - if (bban.type === 'a') { - s += this.faker.helpers.arrayElement(ibanLib.alpha); - } else if (bban.type === 'c') { - if (this.faker.datatype.boolean(0.8)) { - s += this.faker.number.int(9); - } else { - s += this.faker.helpers.arrayElement(ibanLib.alpha); - } - } else { - if (c >= 3 && this.faker.datatype.boolean(0.3)) { - if (this.faker.datatype.boolean()) { - s += this.faker.helpers.arrayElement(ibanLib.pattern100); - c -= 2; - } else { - s += this.faker.helpers.arrayElement(ibanLib.pattern10); - c--; - } - } else { - s += this.faker.number.int(9); - } - } - - c--; - } - - s = s.substring(0, count); - } - - let checksum: string | number = - 98 - ibanLib.mod97(ibanLib.toDigitString(`${s}${ibanFormat.country}00`)); - - if (checksum < 10) { - checksum = `0${checksum}`; - } - - const result = `${ibanFormat.country}${checksum}${s}`; - - return formatted ? prettyPrintIban(result) : result; + return financeIban(this.faker.fakerCore, options); } /** @@ -797,24 +636,7 @@ export class FinanceModule extends ModuleBase { includeBranchCode?: boolean; } = {} ): string { - const { includeBranchCode = this.faker.datatype.boolean() } = options; - - const bankIdentifier = this.faker.string.alpha({ - length: 4, - casing: 'upper', - }); - const countryCode = this.faker.helpers.arrayElement(ibanLib.iso3166); - const locationCode = this.faker.string.alphanumeric({ - length: 2, - casing: 'upper', - }); - const branchCode = includeBranchCode - ? this.faker.datatype.boolean() - ? this.faker.string.alphanumeric({ length: 3, casing: 'upper' }) - : 'XXX' - : ''; - - return `${bankIdentifier}${countryCode}${locationCode}${branchCode}`; + return financeBic(this.faker.fakerCore, options); } /** @@ -854,21 +676,7 @@ export class FinanceModule extends ModuleBase { countryCode?: VatNumberCountryCode; } = {} ): string { - const { - countryCode = this.faker.helpers.arrayElement(vatNumberCountryCodes), - } = options; - - const pattern = vatNumberFormats[countryCode]; - - if (pattern == null) { - throw new FakerError(`Country code ${countryCode} not supported.`); - } - - return this.faker.helpers.fromRegExp( - typeof pattern === 'string' - ? pattern - : this.faker.helpers.arrayElement(pattern) - ); + return financeVatNumber(this.faker.fakerCore, options); } /** @@ -881,8 +689,6 @@ export class FinanceModule extends ModuleBase { * @since 5.1.0 */ transactionDescription(): string { - return this.faker.helpers.fake( - this.faker.definitions.finance.transaction_description_pattern - ); + return financeTransactionDescription(this.faker.fakerCore); } } From 854794ae6992e8f957bd3df33983231258d749f6 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sat, 19 Sep 2026 23:22:54 +0200 Subject: [PATCH 5/5] postfix --- src/index.ts | 5 +++-- src/modules/finance/ethereum-address.ts | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 049df148b67..9db2bc7a461 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,12 +59,13 @@ export type { DatabaseModule } from './modules/database'; export type { DatatypeModule } from './modules/datatype'; export type { DateModule, SimpleDateModule } from './modules/date'; export type { - BitcoinAddressFamily, - BitcoinNetwork, + BitcoinAddressFamilyType, + BitcoinNetworkType, Currency, FinanceModule, VatNumberCountryCode, } from './modules/finance'; +export { BitcoinAddressFamily, BitcoinNetwork } from './modules/finance'; export type { FoodModule } from './modules/food'; export type { GitModule } from './modules/git'; export type { HackerModule } from './modules/hacker'; diff --git a/src/modules/finance/ethereum-address.ts b/src/modules/finance/ethereum-address.ts index 64c93ce1dc5..1eca42258c6 100644 --- a/src/modules/finance/ethereum-address.ts +++ b/src/modules/finance/ethereum-address.ts @@ -16,9 +16,8 @@ import { hexadecimal } from '../string/hexadecimal'; * @experimental */ export function ethereumAddress(fakerCore: FakerCore): string { - const address = hexadecimal(fakerCore, { + return hexadecimal(fakerCore, { length: 40, casing: 'lower', }); - return address; }