couponjs
Version:
Generate coupons.
1 lines • 53.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/helpers/index.ts","../src/constants/index.ts","../src/constants/error-constants.ts","../src/error/validation-error.ts","../src/validators/index.ts","../src/validators/generate-coupon-config-validator.ts","../src/validators/formatter-validator.ts","../src/formatter.ts","../src/character-set.ts","../src/helpers/character-list.ts","../src/engine.ts","../src/configs/option.ts","../src/helpers/performance.ts","../src/validators/coupon-config-validator.ts","../src/index.ts"],"sourcesContent":["/**\n * This will return an integer value between min and max both inclusive.\n * @param {number} min The starting integer value.\n * @param {number} max The ending integer value.\n * @returns {number} Random integer value between min and max, both inclusive.\n */\nexport function randomInteger(min: number, max: number): number {\n return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + Math.ceil(min);\n}\n\n/**\n * This will sum up the values.\n * @param {number[]} values\n * @returns {number}\n */\nexport function sumOf(values: number[]): number {\n return values.reduce((sum, size) => sum + size);\n}\n\n/**\n * This will attach prefix to the coupon.\n * @param {string} prefix\n * @returns {function(string): string}\n */\nexport function attachPrefix(prefix = '') {\n return function attachPrefixFn(coupon: string): string {\n return `${prefix}${coupon}`;\n };\n}\n\n/**\n * This will attach suffix to the coupon.\n * @param {string} suffix\n * @returns {function(string): string}\n */\nexport function attachSuffix(suffix = '') {\n return function attachSuffixFn(coupon: string): string {\n return `${coupon}${suffix}`;\n };\n}\n\n/**\n * This will take in an array of operators to operate on a value.\n * @param {*} operators\n * @returns {function(*=): *}\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function pipe(operators: any[]) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function (value: any) {\n return operators.reduce((enrichedValue, operator) => operator(enrichedValue), value);\n };\n}\n\n/**\n * This will return the first argument it receives.\n * @param {*} value\n * @returns {*}\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function identity(value: any): any {\n return value;\n}\n\n/**\n * This will omit the specified values.\n * @param {string[]} values\n * @param {string[]} valuesToOmit\n * @returns {string[]}\n */\nexport function omit(values: string[], valuesToOmit: string[]): string[] {\n return values.filter(value => !valuesToOmit.includes(value));\n}\n\n/**\n * This will return unique characters array.\n * @param {string[]} characters\n * @returns {string[]}\n */\nexport function uniqueCharacters(characters: string[]): string[] {\n return [...new Set(characters.join(''))];\n}\n\n/**\n * Copies all enumerable own properties from one or more objects to an empty target object.\n * @param {...object} sourceObjects\n * @returns {object}\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function shallowMerge(...sourceObjects: any[]): any {\n return Object.assign({}, ...sourceObjects);\n}\n","export const COUPONJS = 'COUPONJS';\nexport const MIN_NUMBER_OF_COUPONS_TO_GENERATE = 1;\nexport const MAX_NUMBER_OF_COUPONS_TO_GENERATE = 100000;\nexport const DEFAULT_NUMBER_OF_COUPONS_TO_GENERATE = MIN_NUMBER_OF_COUPONS_TO_GENERATE;\nexport const MAX_LENGTH = 128;\nexport const MIN_LENGTH = 1;\nexport const DEFAULT_LENGTH = 6;\nexport const DEFAULT_PREFIX = '';\nexport const DEFAULT_SUFFIX = '';\nexport const ALPHABET_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nexport const ALPHABET_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';\nexport const DIGIT = '0123456789';\nexport const BINARY = '01';\nexport const OCTAL = '01234567';\nexport const HEX = '0123456789ABCDEF';\nexport const HEX_LOWER = '0123456789abcdef';\nexport const ALNUM = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\nexport const CHARSET_ALPHA = 'CHARSET_ALPHA';\nexport const CHARSET_ALPHA_LOWER = 'CHARSET_ALPHA_LOWER';\nexport const CHARSET_DIGIT = 'CHARSET_DIGIT';\nexport const CHARSET_ALNUM = 'CHARSET_ALNUM';\nexport const CHARSET_BINARY = 'CHARSET_BINARY';\nexport const CHARSET_OCTAL = 'CHARSET_OCTAL';\nexport const CHARSET_HEX = 'CHARSET_HEX';\nexport const CHARSET_HEX_LOWER = 'CHARSET_HEX_LOWER';\nexport const DEFAULT_OMIT_CHARACTERS = [];\nexport const UNDEFINED = 'UNDEFINED';\nexport const DEFAULT_COUPON_FORMAT = UNDEFINED;\nexport const DEFAULT_CUSTOM_CHARACTER_SET = [];\nexport const DEFAULT_BUILTIN_CHARACTER_SET = [CHARSET_ALPHA];\nexport const DEFAULT_CHARACTER_SET_OPTION = {\n builtIn: DEFAULT_BUILTIN_CHARACTER_SET,\n custom: DEFAULT_CUSTOM_CHARACTER_SET\n};\n","export const ERROR_TYPE_VALIDATION_ERROR = 'COUPONJS_VALIDATION_ERROR';\nexport const ERROR_TYPE_CHARACTER_SET_ERROR = 'COUPONJS_CHARACTER_SET_ERROR';\nexport const ERROR_TYPE_FORMAT_ERROR = 'COUPONJS_FORMAT_ERROR';\nexport const ERROR_TYPE_GENERATE_COUPON_CONFIGURATION_ERROR = 'COUPONJS_GENERATE_COUPON_CONFIGURATION_ERROR';\nexport const ERROR_TYPE_COUPON_ENGINE_CONFIGURATION_ERROR = 'COUPONJS_COUPON_ENGINE_CONFIGURATION_ERROR';\nexport const ERROR_CONSTANTS = {\n [ERROR_TYPE_VALIDATION_ERROR]: {\n type: ERROR_TYPE_VALIDATION_ERROR,\n message: 'Validation error'\n },\n [ERROR_TYPE_CHARACTER_SET_ERROR]: {\n type: ERROR_TYPE_CHARACTER_SET_ERROR,\n message: 'Character set error'\n },\n [ERROR_TYPE_FORMAT_ERROR]: {\n type: ERROR_TYPE_FORMAT_ERROR,\n message: 'Format error'\n },\n [ERROR_TYPE_GENERATE_COUPON_CONFIGURATION_ERROR]: {\n type: ERROR_TYPE_GENERATE_COUPON_CONFIGURATION_ERROR,\n message: 'Generate coupon configuration error'\n },\n [ERROR_TYPE_COUPON_ENGINE_CONFIGURATION_ERROR]: {\n type: ERROR_TYPE_COUPON_ENGINE_CONFIGURATION_ERROR,\n message: 'Coupon engine configuration error'\n }\n};\n","import { ERROR_CONSTANTS } from '../constants/error-constants';\nimport { ErrorsType } from '../ts-def/errors-type';\n\nexport type ValidationErrorConstructorArgsType = {\n message: string;\n errors?: ErrorsType[];\n};\n\nexport default class ValidationError extends Error {\n public type: string;\n public errors: ErrorsType[];\n\n constructor({ message, errors = [] }: ValidationErrorConstructorArgsType) {\n super(message);\n this.type = ERROR_CONSTANTS.COUPONJS_VALIDATION_ERROR.type;\n this.errors = errors;\n }\n}","export function isOfType(operand: unknown, type: string): boolean {\n return typeof operand === type;\n}\n\nexport function isBoolean(value: unknown): boolean {\n return typeof value === 'boolean';\n}\n\nexport function isObject(value: unknown): boolean {\n return typeof value === 'object' && value !== null && value.constructor === Object;\n}\n\nexport function isString(value: unknown): boolean {\n return typeof value === 'string';\n}\n\nexport function isUndefined(value: unknown): boolean {\n return typeof value === 'undefined';\n}\n\nexport function isInteger(value: unknown): boolean {\n return Number.isInteger(value) && Number.isFinite(value);\n}\n\nexport function isArray(value: unknown): boolean {\n return Array.isArray(value);\n}\n\nexport function isEmptyArray(value: unknown): boolean {\n return isArray(value) && (value as Array<unknown>).length === 0;\n}\n","import {\n MAX_LENGTH,\n MIN_LENGTH,\n MIN_NUMBER_OF_COUPONS_TO_GENERATE\n} from '../constants';\nimport { ERROR_CONSTANTS } from '../constants/error-constants';\nimport ValidationError from '../error/validation-error';\nimport {\n isArray,\n isUndefined,\n isInteger,\n isString,\n isObject,\n isEmptyArray\n} from './index';\nimport { CharacterSetOptionsType } from '../ts-def/option-type';\nimport { ErrorType } from '../ts-def/format-rule-type';\n\nconst throwValidationError = ({ message, field }: { message: string, field: string }) => {\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n field,\n type: ERROR_CONSTANTS.COUPONJS_GENERATE_COUPON_CONFIGURATION_ERROR.type\n }\n ]\n });\n};\n\n/**\n * This will validate length of the coupon.\n * @param {number} length\n * @returns {number | undefined}\n */\nexport function validateLength(length: number): number | undefined {\n if (!isUndefined(length)) {\n if (!isInteger(length)) {\n throwValidationError({\n message: `The field 'length' must be of type integer.`,\n field: 'length'\n });\n }\n if (length < MIN_LENGTH) {\n throwValidationError({\n message: `Minimum value for 'length' is ${MIN_LENGTH}.`,\n field: 'length'\n });\n }\n if (length > MAX_LENGTH) {\n throwValidationError({\n message: `Maximum value for length is ${MAX_LENGTH}.`,\n field: 'length'\n });\n }\n return length;\n }\n\n throwValidationError({\n message: `The field 'length' must be defined.`,\n field: 'length'\n });\n}\n\n/**\n * This will validate the number of coupons.\n * @param {number} numberOfCoupons\n * @param {number} maxNumberOfCouponsToGenerate\n * @param {number} totalNumberOfPossibleCoupons\n * @returns {number | undefined}\n */\nexport function validateNumberOfCoupons(\n numberOfCoupons: number,\n maxNumberOfCouponsToGenerate: number,\n totalNumberOfPossibleCoupons: number\n): number | undefined {\n if (!isUndefined(numberOfCoupons)) {\n if (!isInteger(numberOfCoupons)) {\n throwValidationError({\n message: `The field 'numberOfCoupons' must be of type integer.`,\n field: 'numberOfCoupons'\n });\n }\n if (numberOfCoupons < MIN_NUMBER_OF_COUPONS_TO_GENERATE) {\n throwValidationError({\n message: `Minimum value for numberOfCoupons is ${MIN_NUMBER_OF_COUPONS_TO_GENERATE}.`,\n field: 'numberOfCoupons'\n });\n }\n if (numberOfCoupons > maxNumberOfCouponsToGenerate) {\n throwValidationError({\n message: `Maximum value for numberOfCoupons is ${maxNumberOfCouponsToGenerate}.`,\n field: 'numberOfCoupons'\n });\n }\n if (numberOfCoupons > totalNumberOfPossibleCoupons) {\n throwValidationError({\n message: `Total number of possible coupons that can be generated is ${totalNumberOfPossibleCoupons} for the given length and characterSet.`,\n field: 'numberOfCoupons'\n });\n }\n return numberOfCoupons;\n }\n\n throwValidationError({\n message: `The field 'numberOfCoupons' must be defined.`,\n field: 'numberOfCoupons'\n });\n}\n\n/**\n * This will validate the characters to omit.\n * @param {string[]} omitCharacters\n * @returns {string[] | undefined}\n */\nexport function validateOmitCharacters(omitCharacters: string[]): string[] | undefined {\n if (!isUndefined(omitCharacters)) {\n if (!isArray(omitCharacters)) {\n throwValidationError({\n message: `The field 'omitCharacters' must be of type array.`,\n field: 'omitCharacters'\n });\n }\n\n const errors = omitCharacters.reduce((error: ErrorType[], omitCharacter, index) => {\n if (isString(omitCharacter)) {\n return error;\n }\n return [\n ...error,\n {\n field: 'omitCharacters',\n message: `The field 'omitCharacters' must be an array of string. Non-string value found at index ${index}.`,\n type: ERROR_CONSTANTS.COUPONJS_GENERATE_COUPON_CONFIGURATION_ERROR.type\n }\n ];\n }, []);\n if (!isEmptyArray(errors)) {\n throw new ValidationError({\n errors,\n message: `The field 'omitCharacters' must be an array of strings.`\n });\n }\n return omitCharacters;\n }\n\n throwValidationError({\n message: `The field 'omitCharacters' must be defined.`,\n field: 'omitCharacters'\n });\n}\n\n/**\n * This will validate the prefix.\n * @param {string} prefix\n * @returns {string}\n */\nexport function validatePrefix(prefix: string): string {\n if (isUndefined(prefix)) {\n throwValidationError({\n message: `The field 'prefix' must be defined.`,\n field: 'prefix'\n });\n }\n\n if (!isString(prefix)) {\n throwValidationError({\n message: `The field 'prefix' must be of type string.`,\n field: 'prefix'\n });\n }\n\n return prefix;\n}\n\n/**\n * This will validate the suffix.\n * @param {string} suffix\n * @returns {string}\n */\nexport function validateSuffix(suffix: string): string {\n if (isUndefined(suffix)) {\n throwValidationError({\n message: `The field 'suffix' must be defined.`,\n field: 'suffix'\n });\n }\n\n if (!isString(suffix)) {\n throwValidationError({\n message: `The field 'suffix' must be of type string.`,\n field: 'suffix'\n });\n }\n\n return suffix;\n}\n\n/**\n * This will validate the character set option.\n * @param {CharacterSetOptionsType} characterSetOption\n * @returns {CharacterSetOptionsType}\n */\nexport function validateCharacterSetOption(\n characterSetOption: CharacterSetOptionsType\n): CharacterSetOptionsType {\n if (isUndefined(characterSetOption)) {\n throwValidationError({\n message: `The field 'characterSet' must be defined.`,\n field: 'characterSet'\n });\n }\n\n if (!isObject(characterSetOption)) {\n throwValidationError({\n message: `The field 'characterSet' must be of type object.`,\n field: 'characterSet'\n });\n }\n\n const { builtIn, custom } = characterSetOption;\n\n if (!isUndefined(builtIn)) {\n if (!isArray(builtIn)) {\n throwValidationError({\n message: `The field 'characterSet.builtIn' must be an array.`,\n field: 'characterSet.builtIn'\n });\n }\n const builtInErrors = (builtIn as string[]).reduce((error: ErrorType[], charSet, index) => {\n if (isString(charSet)) {\n return error;\n }\n return [\n ...error,\n {\n field: 'characterSet.builtIn',\n message: `The field 'characterSet.builtIn' must be an array of string. Non-string value found at index ${index}.`,\n type: ERROR_CONSTANTS.COUPONJS_GENERATE_COUPON_CONFIGURATION_ERROR.type\n }\n ];\n }, []);\n if (!isEmptyArray(builtInErrors)) {\n throw new ValidationError({\n errors: builtInErrors,\n message: `The field 'characterSet.builtIn' must be an array of strings.`\n });\n }\n }\n\n if (!isUndefined(custom)) {\n if (!isArray(custom)) {\n throwValidationError({\n message: `The field 'characterSet.custom' must be an array.`,\n field: 'characterSet.custom'\n });\n }\n const customErrors = (custom as string[]).reduce((error: ErrorType[], charSet, index) => {\n if (isString(charSet)) {\n return error;\n }\n return [\n ...error,\n {\n field: 'characterSet.custom',\n message: `The field 'characterSet.custom' must be an array of string. Non-string value found at index ${index}.`,\n type: ERROR_CONSTANTS.COUPONJS_GENERATE_COUPON_CONFIGURATION_ERROR.type\n }\n ];\n }, []);\n if (!isEmptyArray(customErrors)) {\n throw new ValidationError({\n errors: customErrors,\n message: `The field 'characterSet.custom' must be an array of strings.`\n });\n }\n }\n\n return characterSetOption;\n}\n","import { ERROR_CONSTANTS } from '../constants/error-constants';\nimport ValidationError from '../error/validation-error';\nimport { isArray, isString, isEmptyArray, isInteger } from './index';\nimport { sumOf } from '../helpers';\nimport {\n ErrorType,\n FormatRuleObjectReturnType,\n FormatRuleObjectType,\n GroupErrorType,\n SeparatorErrorType\n} from '../ts-def/format-rule-type';\n\nexport const getErrorsInGroups = (groups: number[]): ErrorType[] | [] => {\n return groups.reduce((error: GroupErrorType, group, index) => {\n if (isInteger(group)) {\n return error;\n }\n return [\n ...error,\n {\n field: 'groups',\n message: `Format object must only have integer elements in 'groups' array. Found error at index ${index}.`,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type\n }\n ];\n }, []);\n};\n\nconst getErrorsInSeparators = (separators: string[]): ErrorType[] | [] => {\n return separators.reduce((error: SeparatorErrorType, separator, index) => {\n if (isString(separator)) {\n return error;\n }\n return [\n ...error,\n {\n field: 'separators',\n message: `Format object must only have string elements in 'separators' array. Found error at index ${index}.`,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type\n }\n ];\n }, []);\n};\n\n/**\n * This will validate the format rule string and will return the required properties needed to format coupon.\n * @param {string} ruleString This is the format rule string.\n * @returns {FormatRuleObjectReturnType}\n */\nexport function validateFormatRuleString(ruleString: string): FormatRuleObjectReturnType {\n const isValidFormatRuleString = /^([x]+-?[x]*)*?x$/g.test(ruleString);\n if (isValidFormatRuleString) {\n const groups = ruleString.split('-').map(group => group.length);\n const totalCharactersInGroup = sumOf(groups);\n const separators = '-'.repeat(groups.length - 1).split('');\n return {\n groups,\n separators,\n totalCharactersInGroup\n };\n }\n throw new ValidationError({\n message: 'Invalid characters used in the format rule.',\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'format',\n message:\n 'Invalid characters used in the format rule. Only x and - are allowed. And only one - inbetween like xxx-xxx.'\n }\n ]\n });\n}\n\n/**\n * This will validate the format rule object and will return the required properties needed to format coupon.\n * @param {FormatRuleObjectType} ruleObject This is the format rule object.\n * @returns {FormatRuleObjectReturnType}\n */\nexport function validateFormatRuleObject(\n ruleObject: FormatRuleObjectType\n): FormatRuleObjectReturnType {\n const { separators, groups } = ruleObject;\n\n if (!isArray(separators)) {\n const message = `Format object must have field 'separators' of type array.`;\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'separators'\n }\n ]\n });\n }\n\n if (!isArray(groups)) {\n const message = `Format object must have field 'groups' of type array.`;\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'groups'\n }\n ]\n });\n }\n\n if (isEmptyArray(groups)) {\n const message = `Format object must have at least one element in the array field 'groups'.`;\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'groups'\n }\n ]\n });\n }\n\n if (separators.length >= groups.length) {\n const message = `Format object must not have 'separators' array with more elements than 'groups' array.`;\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'separators'\n }\n ]\n });\n }\n\n if (separators.length !== groups.length - 1) {\n const message = `Format object has ${\n groups.length\n } elements in 'groups' array so, it must have ${\n groups.length - 1\n } elements in 'separators' array.`;\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'separators'\n }\n ]\n });\n }\n\n const separatorElementTypeErrors = getErrorsInSeparators(separators);\n if (separatorElementTypeErrors.length > 0) {\n const message = `Format object has errors in 'separators' field.`;\n throw new ValidationError({\n message,\n errors: separatorElementTypeErrors\n });\n }\n\n const groupsElementTypeErrors = getErrorsInGroups(groups);\n if (groupsElementTypeErrors.length > 0) {\n const message = `Format object has errors in 'groups' field.`;\n throw new ValidationError({\n message,\n errors: groupsElementTypeErrors\n });\n }\n\n return {\n separators,\n groups,\n totalCharactersInGroup: sumOf(groups)\n };\n}\n\n/**\n * This will return true if total number of characters in the coupon is equal to the total number of characters present in the groups.\n * @param {string} coupon This is the coupon string.\n * @param {number} totalCharactersInGroup This is na integer value representing the total number of characters present in the groups.\n * @returns {boolean}\n */\nexport function hasEqualSumOfGroupsAndCouponLength(\n coupon: string,\n totalCharactersInGroup: number\n): boolean {\n return coupon.length === totalCharactersInGroup;\n}\n","import { ERROR_CONSTANTS } from './constants/error-constants';\nimport ValidationError from './error/validation-error';\nimport { isObject, isString, isUndefined } from './validators';\nimport {\n validateFormatRuleString,\n validateFormatRuleObject,\n hasEqualSumOfGroupsAndCouponLength\n} from './validators/formatter-validator';\nimport { FormatRuleObjectReturnType, FormatRuleObjectType } from './ts-def/format-rule-type';\n\ntype FormatRuleType = string | FormatRuleObjectType;\ntype CouponInGroupsType = { chunks: string[], lengthCovered: number };\n\nexport default class Formatter {\n private formatRule: FormatRuleType;\n private formatRuleResult: FormatRuleObjectReturnType;\n\n constructor(formatRule: FormatRuleType) {\n this.formatRule = formatRule;\n this.formatRuleResult = this.validate(formatRule);\n }\n\n public getConfig(): FormatRuleObjectReturnType {\n return this.formatRuleResult;\n }\n\n public format(coupon: string) {\n const { separators, groups, totalCharactersInGroup } = this.formatRuleResult;\n if (!hasEqualSumOfGroupsAndCouponLength(coupon, totalCharactersInGroup)) {\n const message = 'Coupon length is not equal to the sum of groups in the format.';\n throw new ValidationError({\n message,\n errors: [\n {\n message: `Coupon length: ${coupon.length} and sum of groups: ${groups.join(\n '+'\n )} = ${totalCharactersInGroup}`,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'format'\n }\n ]\n });\n }\n const { chunks } = this.getCouponInGroups(coupon, groups);\n return this.getFormattedCoupon(chunks, separators);\n }\n\n private getFormattedCoupon(couponChunks: string[], separators: string[]): string {\n const separatorLength = separators.length;\n return couponChunks.reduce((formattedCoupon, currentChunk, index) => {\n return index < separatorLength\n ? `${formattedCoupon}${currentChunk}${separators[index]}`\n : `${formattedCoupon}${currentChunk}`;\n }, '');\n }\n\n private getCouponInGroups(coupon: string, groups: number[]): CouponInGroupsType {\n return groups.reduce(\n (result: CouponInGroupsType, currentGroupSize) => {\n const { chunks, lengthCovered } = result;\n const chunk = coupon.substring(lengthCovered, lengthCovered + currentGroupSize);\n return {\n chunks: [...chunks, chunk],\n lengthCovered: lengthCovered + currentGroupSize\n };\n },\n { chunks: [], lengthCovered: 0 }\n );\n }\n\n private validate(format: FormatRuleType): FormatRuleObjectReturnType {\n if (isUndefined(format)) {\n const message = 'Format rule is not specified.';\n throw new ValidationError({\n message,\n errors: [\n {\n message,\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'format'\n }\n ]\n });\n } else if (isString(format)) {\n const result = validateFormatRuleString((format as string));\n const { groups, totalCharactersInGroup, separators } = result;\n return {\n groups,\n totalCharactersInGroup,\n separators\n };\n } else if (isObject(format)) {\n const result = validateFormatRuleObject((format as FormatRuleObjectType));\n const { groups, totalCharactersInGroup, separators } = result;\n return {\n groups,\n totalCharactersInGroup,\n separators\n };\n }\n\n throw new ValidationError({\n message: 'Invalid format rule.',\n errors: [\n {\n message: 'Invalid format rule.',\n type: ERROR_CONSTANTS.COUPONJS_FORMAT_ERROR.type,\n field: 'format'\n }\n ]\n });\n }\n}","import { ERROR_CONSTANTS } from './constants/error-constants';\nimport ValidationError from './error/validation-error';\nimport {\n ALPHABET_UPPERCASE,\n ALPHABET_LOWERCASE,\n ALNUM,\n DIGIT,\n BINARY,\n OCTAL,\n HEX,\n HEX_LOWER,\n CHARSET_ALPHA,\n CHARSET_ALPHA_LOWER,\n CHARSET_DIGIT,\n CHARSET_ALNUM,\n CHARSET_BINARY,\n CHARSET_OCTAL,\n CHARSET_HEX,\n CHARSET_HEX_LOWER\n} from './constants';\nimport { PossibleCharacterSetType } from './ts-def/possible-character-set-type';\n\n/**\n * This will return the characters based on the character set name.\n * @param {string} charSetName This is the name of the character set.\n * @returns {string} String of characters.\n */\nexport default function characterSet(charSetName: string): string {\n const possibleCharacterSets: PossibleCharacterSetType = {\n [CHARSET_ALPHA]: ALPHABET_UPPERCASE,\n [CHARSET_ALPHA_LOWER]: ALPHABET_LOWERCASE,\n [CHARSET_DIGIT]: DIGIT,\n [CHARSET_ALNUM]: ALNUM,\n [CHARSET_BINARY]: BINARY,\n [CHARSET_OCTAL]: OCTAL,\n [CHARSET_HEX]: HEX,\n [CHARSET_HEX_LOWER]: HEX_LOWER\n };\n const validCharSets: string[] = Object.keys(possibleCharacterSets);\n type possibleCharacterSetsObjectKey = keyof typeof possibleCharacterSets;\n const matchingCharacterSet = possibleCharacterSets[charSetName as possibleCharacterSetsObjectKey];\n if (!matchingCharacterSet) {\n const message = `Invalid builtIn characterSet specified. Allowed values: ${validCharSets.join(', ')}`;\n throw new ValidationError({\n message,\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_CHARACTER_SET_ERROR.type,\n field: 'builtIn',\n message: `Invalid character set ${charSetName}`\n }\n ]\n });\n }\n return matchingCharacterSet;\n}","import { CharacterSetOptionsType, OmitCharactersType } from '../ts-def/option-type';\nimport { DEFAULT_OMIT_CHARACTERS } from '../constants';\nimport { omit, uniqueCharacters } from './index';\nimport characterSet from '../character-set';\n\n/**\n * This will generate a string of unique characters based on the options provided.\n * @param {CharacterSetOptionsType} characterSetOptions The options to build the character set.\n * @param {OmitCharactersType} omitCharacters The array of characters that will be omitted.\n * @returns {string[]} The set of characters based on the options provided.\n */\nexport default function characterList(\n characterSetOptions: CharacterSetOptionsType,\n omitCharacters: OmitCharactersType = DEFAULT_OMIT_CHARACTERS\n): string[] {\n const { builtIn = [], custom = [] } = characterSetOptions;\n const charactersToOmit = uniqueCharacters(omitCharacters);\n const charactersFromCharacterSetOptions = uniqueCharacters([\n ...builtIn.map(characterSetName => characterSet(characterSetName)),\n ...custom\n ]);\n return omit(charactersFromCharacterSetOptions, charactersToOmit);\n}","import { attachSuffix, attachPrefix, pipe, identity } from './helpers';\nimport {\n validateLength,\n validateOmitCharacters,\n validateNumberOfCoupons,\n validatePrefix,\n validateSuffix,\n validateCharacterSetOption\n} from './validators/generate-coupon-config-validator';\nimport {\n DEFAULT_LENGTH,\n DEFAULT_PREFIX,\n DEFAULT_SUFFIX,\n MAX_NUMBER_OF_COUPONS_TO_GENERATE,\n DEFAULT_NUMBER_OF_COUPONS_TO_GENERATE,\n DEFAULT_OMIT_CHARACTERS,\n DEFAULT_CHARACTER_SET_OPTION,\n UNDEFINED\n} from './constants';\nimport Formatter from './formatter';\nimport characterList from './helpers/character-list';\nimport { EngineConstructorType, RandomIntegerFunctionType } from './ts-def/engine-type';\nimport { CharacterSetOptionsType } from './ts-def/option-type';\nimport { CouponResponseType } from './ts-def/coupon-response-type';\n\nexport default class Engine {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private formatter: any;\n private characterSetOption: CharacterSetOptionsType;\n private length: number;\n private prefix: string;\n private suffix: string;\n private numberOfCoupons: number;\n private maxNumberOfCouponsToGenerate: number;\n private charactersLength: number;\n private characters: string[];\n private randomInteger: RandomIntegerFunctionType;\n\n constructor({\n randomInteger,\n characterSetOption = DEFAULT_CHARACTER_SET_OPTION,\n length = DEFAULT_LENGTH,\n prefix = DEFAULT_PREFIX,\n suffix = DEFAULT_SUFFIX,\n numberOfCoupons = DEFAULT_NUMBER_OF_COUPONS_TO_GENERATE,\n omitCharacters = DEFAULT_OMIT_CHARACTERS,\n format = UNDEFINED,\n maxNumberOfCouponsToGenerate = MAX_NUMBER_OF_COUPONS_TO_GENERATE\n }: EngineConstructorType) {\n validatePrefix(prefix);\n validateSuffix(suffix);\n validateLength(length);\n validateOmitCharacters(omitCharacters);\n validateCharacterSetOption(characterSetOption);\n\n this.characters = characterList(characterSetOption, omitCharacters);\n this.charactersLength = this.characters.length;\n const totalNumberOfPossibleCoupons = Math.pow(this.charactersLength, length);\n\n validateNumberOfCoupons(\n numberOfCoupons,\n maxNumberOfCouponsToGenerate,\n totalNumberOfPossibleCoupons\n );\n\n this.randomInteger = randomInteger;\n this.length = length;\n this.prefix = prefix;\n this.suffix = suffix;\n this.numberOfCoupons = numberOfCoupons;\n this.characterSetOption = characterSetOption;\n this.maxNumberOfCouponsToGenerate = maxNumberOfCouponsToGenerate;\n this.formatter = format !== UNDEFINED ? new Formatter(format) : { format: identity };\n }\n\n private generateCoupon() {\n const generatedCouponCharacters = [];\n for (let i = 0; i < this.length; i++) {\n generatedCouponCharacters.push(\n (this.characters)[this.randomInteger(0, this.charactersLength - 1)]\n );\n }\n const coupon = generatedCouponCharacters.join('');\n return this.formatter.format(\n pipe([\n attachPrefix(this.prefix),\n attachSuffix(this.suffix)\n ])(coupon)\n );\n }\n\n private generateSingleCoupon(): string {\n return this.generateCoupon();\n }\n\n private generateMultipleCoupons(): string[] {\n const couponSet = new Set();\n while (couponSet.size < this.numberOfCoupons) {\n couponSet.add(this.generateCoupon());\n }\n return Array.from(couponSet) as string[];\n }\n\n public run(): CouponResponseType {\n if (this.numberOfCoupons === 1) {\n return this.generateSingleCoupon();\n }\n return this.generateMultipleCoupons();\n }\n}","import {\n DEFAULT_LENGTH,\n DEFAULT_PREFIX,\n DEFAULT_SUFFIX,\n DEFAULT_NUMBER_OF_COUPONS_TO_GENERATE,\n DEFAULT_OMIT_CHARACTERS,\n DEFAULT_COUPON_FORMAT,\n MAX_NUMBER_OF_COUPONS_TO_GENERATE,\n DEFAULT_CHARACTER_SET_OPTION\n} from '../constants';\nimport { OptionType } from '../ts-def/option-type';\n\nconst options: OptionType = {\n defaultCouponEngineOption: {\n verbose: false,\n logPerformance: false,\n maxNumberOfCouponsToGenerate: MAX_NUMBER_OF_COUPONS_TO_GENERATE\n },\n defaultCouponGenerationOption: {\n length: DEFAULT_LENGTH,\n prefix: DEFAULT_PREFIX,\n suffix: DEFAULT_SUFFIX,\n characterSet: DEFAULT_CHARACTER_SET_OPTION,\n numberOfCoupons: DEFAULT_NUMBER_OF_COUPONS_TO_GENERATE,\n omitCharacters: DEFAULT_OMIT_CHARACTERS,\n format: DEFAULT_COUPON_FORMAT\n }\n};\n\nexport default options;","import { PerformanceType } from '../ts-def/performance-type';\n\nexport default class Performance {\n private startedAt = 0;\n private endedAt = 0;\n\n public startTimer() {\n this.startedAt = new Date().getTime();\n }\n\n public stopTimer() {\n this.endedAt = new Date().getTime();\n }\n\n public stats(): PerformanceType {\n const milli = this.endedAt - this.startedAt;\n return {\n duration: {\n nano: milli * 1e6,\n micro: milli * 1e3,\n milli,\n second: milli / 1e3\n }\n };\n }\n}","import { ERROR_CONSTANTS } from '../constants/error-constants';\nimport ValidationError from '../error/validation-error';\nimport { isUndefined, isInteger, isBoolean } from './index';\n\ntype configType = {\n verbose?: boolean,\n logPerformance?: boolean,\n maxNumberOfCouponsToGenerate?: number\n};\n\nexport default function couponConfigValidator(config: configType) {\n const { verbose, logPerformance, maxNumberOfCouponsToGenerate } = config;\n\n if (!isUndefined(verbose) && !isBoolean(verbose)) {\n throw new ValidationError({\n message: `Coupon engine configuration field 'verbose' must be of type boolean.`,\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_COUPON_ENGINE_CONFIGURATION_ERROR.type,\n field: 'verbose',\n message: `Coupon engine configuration field 'verbose' must be of type boolean.`\n }\n ]\n });\n }\n\n if (!isUndefined(logPerformance) && !isBoolean(logPerformance)) {\n throw new ValidationError({\n message: `Coupon engine configuration field 'logPerformance' must be of type boolean.`,\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_COUPON_ENGINE_CONFIGURATION_ERROR.type,\n field: 'logPerformance',\n message: `Coupon engine configuration field 'logPerformance' must be of type boolean.`\n }\n ]\n });\n }\n\n if (!isUndefined(maxNumberOfCouponsToGenerate) && !isInteger(maxNumberOfCouponsToGenerate)) {\n throw new ValidationError({\n message: `Coupon engine configuration field 'maxNumberOfCouponsToGenerate' must be of type integer.`,\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_COUPON_ENGINE_CONFIGURATION_ERROR.type,\n field: 'maxNumberOfCouponsToGenerate',\n message: `Coupon engine configuration field 'maxNumberOfCouponsToGenerate' must be of type integer.`\n }\n ]\n });\n }\n\n if ((maxNumberOfCouponsToGenerate as number) < 1) {\n throw new ValidationError({\n message: `Coupon engine configuration field 'maxNumberOfCouponsToGenerate' must be greater than 0.`,\n errors: [\n {\n type: ERROR_CONSTANTS.COUPONJS_COUPON_ENGINE_CONFIGURATION_ERROR.type,\n field: 'maxNumberOfCouponsToGenerate',\n message: `Coupon engine configuration field 'maxNumberOfCouponsToGenerate' must be greater than 0.`\n }\n ]\n });\n }\n}\n","import Engine from './engine';\nimport options from './configs/option';\nimport { randomInteger, shallowMerge } from './helpers';\nimport Performance from './helpers/performance';\nimport couponConfigValidator from './validators/coupon-config-validator';\nimport { CouponEngineOptionType, CouponGenerationOptionType } from './ts-def/option-type';\nimport {\n CouponResponseType,\n ErrorResponseType,\n VerboseResponseType\n} from './ts-def/coupon-response-type';\nimport { ErrorType } from './ts-def/error-type';\n\nconst { defaultCouponGenerationOption, defaultCouponEngineOption } = options;\n\nexport class CouponJS {\n private config: CouponEngineOptionType;\n private performance: Performance;\n private maxNumberOfCouponsToGenerate: number;\n private logPerformance: boolean;\n private verbose: boolean;\n\n constructor(config?: CouponEngineOptionType) {\n this.config = config ?? {};\n this.performance = new Performance();\n\n const { verbose, logPerformance, maxNumberOfCouponsToGenerate } = shallowMerge(\n defaultCouponEngineOption,\n config\n );\n couponConfigValidator({ verbose, logPerformance, maxNumberOfCouponsToGenerate });\n\n this.maxNumberOfCouponsToGenerate = maxNumberOfCouponsToGenerate;\n this.logPerformance = logPerformance;\n this.verbose = verbose;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public generate(option?: CouponGenerationOptionType): any {\n this.performance.startTimer();\n const {\n numberOfCoupons,\n length,\n prefix,\n suffix,\n omitCharacters,\n format,\n characterSet: characterSetOption\n } = shallowMerge(defaultCouponGenerationOption, option);\n try {\n const engine = new Engine({\n randomInteger,\n characterSetOption,\n length,\n prefix,\n suffix,\n numberOfCoupons,\n omitCharacters,\n format,\n maxNumberOfCouponsToGenerate: this.maxNumberOfCouponsToGenerate\n });\n const generatedCoupons: CouponResponseType = engine.run();\n this.performance.stopTimer();\n const performanceStats = this.logPerformance ? { performance: this.performance.stats() } : {};\n const verboseResult: VerboseResponseType = {\n ...performanceStats,\n numberOfCoupons,\n status: 'success',\n coupons: numberOfCoupons === 1 ?\n [generatedCoupons] as string[] :\n generatedCoupons as string[]\n };\n return this.verbose ? verboseResult : generatedCoupons;\n } catch (e: unknown) {\n this.performance.stopTimer();\n const performanceStats = this.logPerformance ? { performance: this.performance.stats() } : {};\n if (this.verbose) {\n return ({\n status: 'error',\n error: {\n message: (e as ErrorType).message,\n type: (e as ErrorType).type,\n errors: (e as ErrorType).errors\n },\n ...performanceStats\n } as ErrorResponseType);\n } else {\n throw e;\n }\n }\n }\n}\n\nexport default CouponJS;"],"mappings":"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