UNPKG

bai2-parser

Version:

Parse the bai2 statement file as CSV or JSON file

1,339 lines (1,306 loc) 47.1 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var bai2_parser_exports = {}; __export(bai2_parser_exports, { BAI2: () => BAI2 }); module.exports = __toCommonJS(bai2_parser_exports); var import_fs = __toESM(require("fs")); var import_json_2_csv = require("json-2-csv"); // enums/index.ts var enums_exports = {}; __export(enums_exports, { AIErrorMsgEnum: () => AIErrorMsgEnum, ATErrorMsgEnum: () => ATErrorMsgEnum, AsOfDateModifierEnum: () => AsOfDateModifierEnum, CNErrorMsgEnum: () => CNErrorMsgEnum, FHErrorMsgEnum: () => FHErrorMsgEnum, FTErrorMsgEnum: () => FTErrorMsgEnum, FUTYErrorMsgEnum: () => FUTYErrorMsgEnum, FundsTypeEnum: () => FundsTypeEnum, GHErrorMsgEnum: () => GHErrorMsgEnum, GTErrorMsgEnum: () => GTErrorMsgEnum, GroupStatusEnum: () => GroupStatusEnum, RecordCodesEnum: () => RecordCodesEnum, TDErrorMsgEnum: () => TDErrorMsgEnum }); // enums/as-of-date-modifier.enum.ts var AsOfDateModifierEnum = /* @__PURE__ */ ((AsOfDateModifierEnum3) => { AsOfDateModifierEnum3[AsOfDateModifierEnum3["INTERIM_PREVIOUS_DAY"] = 1] = "INTERIM_PREVIOUS_DAY"; AsOfDateModifierEnum3[AsOfDateModifierEnum3["FINAL_PREVIOUS_DAY"] = 2] = "FINAL_PREVIOUS_DAY"; AsOfDateModifierEnum3[AsOfDateModifierEnum3["INTERIM_SAME_DAY"] = 3] = "INTERIM_SAME_DAY"; AsOfDateModifierEnum3[AsOfDateModifierEnum3["FINAL_SAME_DAY"] = 4] = "FINAL_SAME_DAY"; return AsOfDateModifierEnum3; })(AsOfDateModifierEnum || {}); // enums/funds-type.enum.ts var FundsTypeEnum = /* @__PURE__ */ ((FundsTypeEnum3) => { FundsTypeEnum3["IMMEDIATE_AVAILABILITY"] = "0"; FundsTypeEnum3["ONE_DAY_AVAILABILITY"] = "1"; FundsTypeEnum3["TWO_OR_MORE_DAYS_AVAILABILITY"] = "2"; FundsTypeEnum3["DISTRIBUTED_AVAILABILITY_THREE"] = "S"; FundsTypeEnum3["VALUE_DATED"] = "V"; FundsTypeEnum3["DISTRIBUTED_AVAILABILITY"] = "D"; FundsTypeEnum3["UNKNOWN"] = "Z"; return FundsTypeEnum3; })(FundsTypeEnum || {}); var FUTYErrorMsgEnum = /* @__PURE__ */ ((FUTYErrorMsgEnum2) => { FUTYErrorMsgEnum2["PARSE"] = "FundsType :: Unable to parse"; FUTYErrorMsgEnum2["VALIDATE"] = "FundsType :: Invalid"; return FUTYErrorMsgEnum2; })(FUTYErrorMsgEnum || {}); // enums/group-status.enum.ts var GroupStatusEnum = /* @__PURE__ */ ((GroupStatusEnum3) => { GroupStatusEnum3[GroupStatusEnum3["UPDATE"] = 1] = "UPDATE"; GroupStatusEnum3[GroupStatusEnum3["DELETION"] = 2] = "DELETION"; GroupStatusEnum3[GroupStatusEnum3["CORRECTION"] = 3] = "CORRECTION"; GroupStatusEnum3[GroupStatusEnum3["TEST_ONLY"] = 4] = "TEST_ONLY"; return GroupStatusEnum3; })(GroupStatusEnum || {}); // enums/record-account-identifier.enum.ts var AIErrorMsgEnum = /* @__PURE__ */ ((AIErrorMsgEnum2) => { AIErrorMsgEnum2["PARSE"] = "AccountIdentifier :: Unable to parse"; AIErrorMsgEnum2["VALIDATE"] = "AccountIdentifier :: Invalid"; return AIErrorMsgEnum2; })(AIErrorMsgEnum || {}); // enums/record-account-trailer.enum.ts var ATErrorMsgEnum = /* @__PURE__ */ ((ATErrorMsgEnum2) => { ATErrorMsgEnum2["PARSE"] = "AccountTrailer :: Unable to parse"; ATErrorMsgEnum2["VALIDATE"] = "AccountTrailer :: Invalid"; return ATErrorMsgEnum2; })(ATErrorMsgEnum || {}); // enums/record-codes.enum.ts var RecordCodesEnum = /* @__PURE__ */ ((RecordCodesEnum2) => { RecordCodesEnum2["FileHeaderCode"] = "01"; RecordCodesEnum2["GroupHeaderCode"] = "02"; RecordCodesEnum2["AccountIdentifierCode"] = "03"; RecordCodesEnum2["TransactionDetailCode"] = "16"; RecordCodesEnum2["ContinuationCode"] = "88"; RecordCodesEnum2["AccountTrailerCode"] = "49"; RecordCodesEnum2["GroupTrailerCode"] = "98"; RecordCodesEnum2["FileTrailerCode"] = "99"; return RecordCodesEnum2; })(RecordCodesEnum || {}); // enums/record-continuation.enum.ts var CNErrorMsgEnum = /* @__PURE__ */ ((CNErrorMsgEnum2) => { CNErrorMsgEnum2["PARSE"] = "Continuation :: Unable to parse"; return CNErrorMsgEnum2; })(CNErrorMsgEnum || {}); // enums/record-file-header.enum.ts var FHErrorMsgEnum = /* @__PURE__ */ ((FHErrorMsgEnum2) => { FHErrorMsgEnum2["PARSE"] = "FileHeader :: Unable to parse"; FHErrorMsgEnum2["VALIDATE"] = "FileHeader :: Invalid"; return FHErrorMsgEnum2; })(FHErrorMsgEnum || {}); // enums/record-file-trailer.enum.ts var FTErrorMsgEnum = /* @__PURE__ */ ((FTErrorMsgEnum2) => { FTErrorMsgEnum2["PARSE"] = "FileTrailer :: Unable to parse"; FTErrorMsgEnum2["VALIDATE"] = "FileTrailer :: Invalid"; return FTErrorMsgEnum2; })(FTErrorMsgEnum || {}); // enums/record-group-header.enum.ts var GHErrorMsgEnum = /* @__PURE__ */ ((GHErrorMsgEnum2) => { GHErrorMsgEnum2["PARSE"] = "GroupHeader :: Unable to parse"; GHErrorMsgEnum2["VALIDATE"] = "GroupHeader :: Invalid"; return GHErrorMsgEnum2; })(GHErrorMsgEnum || {}); // enums/record-group-trailer.enum.ts var GTErrorMsgEnum = /* @__PURE__ */ ((GTErrorMsgEnum2) => { GTErrorMsgEnum2["PARSE"] = "GroupTrailer :: Unable to parse"; GTErrorMsgEnum2["VALIDATE"] = "GroupTrailer :: Invalid"; return GTErrorMsgEnum2; })(GTErrorMsgEnum || {}); // enums/record-transaction-detail.enum.ts var TDErrorMsgEnum = /* @__PURE__ */ ((TDErrorMsgEnum2) => { TDErrorMsgEnum2["PARSE"] = "TransactionDetail :: Unable to parse"; TDErrorMsgEnum2["VALIDATE"] = "TransactionDetail :: Invalid"; return TDErrorMsgEnum2; })(TDErrorMsgEnum || {}); // models/index.ts var models_exports = {}; // helpers/reader.ts var Reader = class _Reader { static field(input, start, uptoLast = false) { let data = ""; if (start < input.length) { data = input.slice(start); } if (data === "") { return { value: "", newStart: 0, error: new Error("Insufficient input string") }; } let lineIdx = 0; if (uptoLast) { lineIdx = _Reader.getUptoLastIndex(data); } else { lineIdx = _Reader.getIndex(data); } if (lineIdx === -1) { return { value: "", newStart: 0, error: new Error("Invalid delimiter") }; } return { value: data.slice(0, lineIdx), newStart: lineIdx + 1, error: null }; } static fieldAsInt(input, start) { let data = ""; if (start < input.length) { data = input.slice(start); } if (data === "") { return { value: 0, newStart: 0, error: new Error("Insufficient input string") }; } const lineIdx = _Reader.getIndex(data); if (lineIdx === -1) { return { value: 0, newStart: 0, error: new Error("Invalid delimiter") }; } if (data.slice(0, lineIdx) === "") { return { value: 0, newStart: lineIdx + 1, error: null }; } const parsedValue = parseInt(data.slice(0, lineIdx), 10); if (isNaN(parsedValue)) { return { value: 0, newStart: 0, error: new Error("Invalid value") }; } return { value: parsedValue, newStart: lineIdx + 1, error: null }; } static getIndex(input) { const idx1 = input.indexOf(","); const idx2 = input.indexOf("/"); if (idx1 === -1) { return idx2; } if (idx2 > -1 && idx2 < idx1) { return idx2; } return idx1; } static getSize(line) { const size = line.indexOf("/"); if (size >= 0) { return size + 1; } return size; } static getUptoLastIndex(input) { const lastIdx = input.length - 1; return lastIdx; } }; // helpers/validator.ts var Validator = class _Validator { static CURRENCY_CODE_REGEX = /^[a-zA-Z]{3}$/; static DATE_TYPE_REGEX = /[0-9][0-9][0-9][0-9]-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[01])/; static SIGNED_NUMBER_REGEX = /^(-|\+|)?[0-9]\d*$/; static TIME_TYPE_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)\.\d{3}$/; static TYPE_CODE_REGEX = /^[0-9]{3}$/; static Date(input) { return _Validator.DATE_TYPE_REGEX.test(input); } static Time(input) { return _Validator.TIME_TYPE_REGEX.test(input); } static FundsType(input) { if (Object.values(RecordCodesEnum).includes(input)) { return true; } return false; } static Amount(input) { return _Validator.SIGNED_NUMBER_REGEX.test(input); } static CurrencyCode(input) { return _Validator.CURRENCY_CODE_REGEX.test(input); } static TypeCode(input) { return _Validator.TYPE_CODE_REGEX.test(input); } }; // helpers/util.ts var Util = class _Util { static returnValue(value) { return { value, error: null }; } static returnFieldError(message, field) { return { value: null, error: new Error(`${message} :: ${field}`), newStart: 0 }; } static returnReaderError(message) { return { value: null, error: new Error(`ERROR :: ${message}`), newStart: 0 }; } static returnParserError(message) { return { value: null, error: new Error(message), newStart: 0 }; } static getFlattenTransactions = (parsedData) => { let output = []; parsedData?.groups?.forEach((group) => { group?.accounts?.forEach((acc) => { if (acc?.details?.length) { let txns = acc.details.map((detail) => { const txnAmount = detail?.amount; return { BankIdentifier: parsedData.sender, FileIdNumber: parsedData.fileIdNumber, TransactionDate: parsedData.fileCreatedDate, BankAcctNumber: acc.accountNumber, Currency: acc.currencyCode ?? "USD", TxnTypeCode: detail.typeCode ?? "", TxnAmount: txnAmount && txnAmount > 0 ? txnAmount / 100 : 0, BankReference: detail.bankReferenceNumber ?? "", CustomerReference: detail.customerReferenceNumber ?? "", Comment: detail.text ?? "", Sender: detail?.Sender ?? "", Receiver: detail?.Receiver ?? "", Tracer: detail?.Tracer ?? "", IMAD: detail?.IMAD ?? "", VirtualAccount: detail?.VirtualAccount ?? "" }; }); output = [...output, ...txns]; } }); }); return _Util.returnValue(output); }; }; // parser/funds-type.ts var FundsType = class _FundsType { static validate(funds) { const fundsTypeCodeErr = _FundsType.typeCodeValidate(funds.typeCode); if (fundsTypeCodeErr) { return fundsTypeCodeErr; } if (funds.typeCode.toUpperCase() === "D" /* DISTRIBUTED_AVAILABILITY */ && funds.distributionNumber !== funds.distributions?.length) { return Util.returnFieldError("FundsType :: Invalid" /* VALIDATE */, `number of distributions is not match`); } if (funds.typeCode.toUpperCase() === "V" /* VALUE_DATED */) { if (funds.date && !Validator.Date(funds.date)) { return Util.returnFieldError( "FundsType :: Invalid" /* VALIDATE */, `date of fund type V ( ${funds.date} )` ); } if (funds.time && !Validator.Time(funds.time)) { return Util.returnFieldError( "FundsType :: Invalid" /* VALIDATE */, `time of fund type V ( ${funds.time} )` ); } } return null; } static parse(data) { let read = 0; let fundsTypeData = {}; const typeCode = Reader.field(data, read); if (typeCode.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "type code"); } else { read += typeCode.newStart; fundsTypeData = { ...fundsTypeData, typeCode: typeCode.value }; } if (typeCode.value === "S" /* DISTRIBUTED_AVAILABILITY_THREE */) { const immediateAmount = Reader.fieldAsInt(data, read); if (immediateAmount.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "ImmediateAmount"); } else { read += immediateAmount.newStart; fundsTypeData = { ...fundsTypeData, immediateAmount: immediateAmount.value }; } const oneDayAmount = Reader.fieldAsInt(data, read); if (oneDayAmount.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "OneDayAmount"); } else { read += oneDayAmount.newStart; fundsTypeData = { ...fundsTypeData, oneDayAmount: oneDayAmount.value }; } const twoDayAmount = Reader.fieldAsInt(data, read); if (twoDayAmount.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "TwoDayAmount"); } else { read += twoDayAmount.newStart; fundsTypeData = { ...fundsTypeData, twoDayAmount: twoDayAmount.value }; } } else if (typeCode.value === "V" /* VALUE_DATED */) { const date = Reader.field(data, read); if (date.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "Date"); } else { read += date.newStart; fundsTypeData = { ...fundsTypeData, date: date.value }; } const time = Reader.field(data, read); if (time.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "Time"); } else { read += time.newStart; fundsTypeData = { ...fundsTypeData, time: time.value }; } } else if (typeCode.value === "D" /* DISTRIBUTED_AVAILABILITY */) { const distributionNumber = Reader.fieldAsInt(data, read); if (distributionNumber.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "DistributionNumber"); } else { read += distributionNumber.newStart; fundsTypeData = { ...fundsTypeData, distributionNumber: distributionNumber.value }; } for (let distIdx = 0; distIdx < distributionNumber.value; distIdx++) { let distribution = {}; const day = Reader.fieldAsInt(data, read); if (day.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "day"); } else { read += day.newStart; distribution = { ...distribution, day: day.value }; } const amount = Reader.fieldAsInt(data, read); if (amount.error) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "amount"); } else { read += amount.newStart; distribution = { ...distribution, amount: amount.value }; } fundsTypeData = { ...fundsTypeData, distributions: [...fundsTypeData.distributions || [], distribution] }; } } if (data.slice(0, read - 1).includes("/")) { return Util.returnFieldError("FundsType :: Unable to parse" /* PARSE */, "sub elements"); } const fundsTypeErr = _FundsType.validate(fundsTypeData); if (fundsTypeErr) { return { error: fundsTypeErr.error, value: null, newStart: read }; } return { error: null, value: fundsTypeData, newStart: read }; } static typeCodeValidate(typeCode) { const availableTypes = Object.values(FundsTypeEnum); if (typeCode.length === 0 || availableTypes.includes( typeCode.toUpperCase() )) { return null; } return Util.returnFieldError("FundsType :: Invalid" /* VALIDATE */, "Fund Typecode"); } }; // parser/record-account-identifier.ts var RecordAccountIdentifier = class _RecordAccountIdentifier { static parse(data) { let line = ""; let read = 0; let identifierData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("03" /* AccountIdentifierCode */ !== data.slice(0, 2)) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const accountNumber = Reader.field(line, read); if (accountNumber.error) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "AccountNumber"); } else { read += accountNumber.newStart; identifierData = { ...identifierData, accountNumber: accountNumber.value }; } const currencyCode = Reader.field(line, read); if (currencyCode.error) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "CurrencyCode"); } else { read += currencyCode.newStart; identifierData = { ...identifierData, currencyCode: currencyCode.value }; } while (read < data.length) { let summary = {}; const typeCode = Reader.field(line, read); if (typeCode.error) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "TypeCode"); } else { read += typeCode.newStart; summary = { ...summary, typeCode: typeCode.value }; } const amount = Reader.field(line, read); if (amount.error) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "Amount"); } else { read += amount.newStart; summary = { ...summary, amount: amount.value }; } const itemCount = Reader.fieldAsInt(line, read); if (itemCount.error) { return Util.returnFieldError("AccountIdentifier :: Unable to parse" /* PARSE */, "ItemCount"); } else { read += itemCount.newStart; summary = { ...summary, itemCount: itemCount.value }; } const fundsType = FundsType.parse(line.slice(read)); if (fundsType.error) { return Util.returnFieldError( "AccountIdentifier :: Unable to parse" /* PARSE */, `FundsType :: ${fundsType.error.message}` ); } else { read += fundsType.newStart; summary = { ...summary, fundsType: fundsType.value }; } identifierData = { ...identifierData, summaries: [...identifierData.summaries || [], summary] }; } const identifierErr = _RecordAccountIdentifier.validate(identifierData); if (identifierErr) { return Util.returnParserError(identifierErr.error.message); } return Util.returnValue(identifierData); } static validate(data) { if (data.accountNumber === "") { return Util.returnFieldError( "AccountIdentifier :: Invalid" /* VALIDATE */, "AccountNumber" ); } if (data.currencyCode && !Validator.CurrencyCode(data.currencyCode)) { return Util.returnFieldError( "AccountIdentifier :: Invalid" /* VALIDATE */, "CurrencyCode" ); } for (const summary of data.summaries) { if (summary.amount && !Validator.Amount(summary.amount)) { return Util.returnFieldError("AccountIdentifier :: Invalid" /* VALIDATE */, "Amount"); } if (summary.typeCode && !Validator.TypeCode(summary.typeCode)) { return Util.returnFieldError("AccountIdentifier :: Invalid" /* VALIDATE */, "TypeCode"); } } return null; } }; // parser/record-account-trailer.ts var RecordAccountTrailer = class _RecordAccountTrailer { static parse(data) { let line = ""; let read = 0; let trailerData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("AccountTrailer :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("49" /* AccountTrailerCode */ !== data.slice(0, 2)) { return Util.returnFieldError("AccountTrailer :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const accountControlTotal = Reader.field(line, read); if (accountControlTotal.error) { return Util.returnFieldError("AccountTrailer :: Unable to parse" /* PARSE */, "AccountControlTotal"); } else { read += accountControlTotal.newStart; trailerData = { ...trailerData, accountControlTotal: accountControlTotal.value }; } const numberRecords = Reader.fieldAsInt(line, read); if (numberRecords.error) { return Util.returnFieldError("AccountTrailer :: Unable to parse" /* PARSE */, "NumberRecords"); } else { read += numberRecords.newStart; trailerData = { ...trailerData, numberRecords: numberRecords.value }; } const trailerErr = _RecordAccountTrailer.validate(trailerData); if (trailerErr) { return Util.returnParserError(trailerErr.error.message); } return Util.returnValue(trailerData); } static validate(trailerData) { if (trailerData.accountControlTotal !== "" && !Validator.Amount(trailerData.accountControlTotal)) { return Util.returnFieldError("AccountTrailer :: Invalid" /* VALIDATE */, "Amount"); } return null; } }; // parser/record-continuation.ts var Continuation = class { static parse(data) { let line = ""; let read = 0; let continuedData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("Continuation :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("88" /* ContinuationCode */ !== data.slice(0, 2)) { return Util.returnFieldError("Continuation :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const key = Reader.field(line, read); if (key.error) { return Util.returnFieldError("Continuation :: Unable to parse" /* PARSE */, "Key"); } else { read += key.newStart; continuedData = { ...continuedData, [key.value]: "" }; } const value = Reader.field(line, read); if (value.error) { return Util.returnFieldError("Continuation :: Unable to parse" /* PARSE */, "Value"); } else { read += value.newStart; continuedData = { ...continuedData, [key.value]: value.value }; } return Util.returnValue(continuedData); } }; // parser/record-file-header.ts var FileHeader = class _FileHeader { static parse(data) { let line = ""; let read = 0; let headerData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); ; } if ("01" /* FileHeaderCode */ !== data.slice(0, 2)) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const sender = Reader.field(line, read); if (sender.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "Sender"); } else { read += sender.newStart; headerData = { ...headerData, sender: sender.value }; } const receiver = Reader.field(line, read); if (receiver.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "Receiver"); } else { read += receiver.newStart; headerData = { ...headerData, receiver: receiver.value }; } const fileCreatedDate = Reader.field(line, read); if (fileCreatedDate.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "FileCreatedDate"); } else { read += fileCreatedDate.newStart; headerData = { ...headerData, fileCreatedDate: fileCreatedDate.value }; } const fileCreatedTime = Reader.field(line, read); if (fileCreatedTime.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "FileCreatedTime"); } else { read += fileCreatedTime.newStart; headerData = { ...headerData, fileCreatedTime: fileCreatedTime.value }; } const fileIdNumber = Reader.field(line, read); if (fileIdNumber.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "FileIdNumber"); } else { read += fileIdNumber.newStart; headerData = { ...headerData, fileIdNumber: fileIdNumber.value }; } const physicalRecordLength = Reader.fieldAsInt(line, read); if (physicalRecordLength.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "PhysicalRecordLength"); } else { read += physicalRecordLength.newStart; headerData = { ...headerData, physicalRecordLength: physicalRecordLength.value }; } const blockSize = Reader.fieldAsInt(line, read); if (blockSize.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "BlockSize"); } else { read += blockSize.newStart; headerData = { ...headerData, blockSize: blockSize.value }; } const versionNumber = Reader.fieldAsInt(line, read); if (versionNumber.error) { return Util.returnFieldError("FileHeader :: Unable to parse" /* PARSE */, "VersionNumber"); } else { read += versionNumber.newStart; headerData = { ...headerData, versionNumber: versionNumber.value }; } const headerErr = _FileHeader.validate(headerData); if (headerErr) { return Util.returnParserError(headerErr.error.message); } return Util.returnValue(headerData); } static validate(headerData) { if (headerData.sender === "") { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "Sender"); } if (headerData.receiver === "") { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "Receiver"); } if (headerData.fileCreatedDate === "" || !Validator.Date(headerData.fileCreatedDate)) { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "FileCreatedDate"); } if (headerData.fileCreatedTime === "" || !Validator.Time(headerData.fileCreatedTime)) { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "FileCreatedDate"); } if (headerData.fileIdNumber === "") { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "FileIdNumber"); } if (headerData.versionNumber !== 2) { return Util.returnFieldError("FileHeader :: Invalid" /* VALIDATE */, "VersionNumber"); } return null; } }; // parser/record-file-trailer.ts var FileTrailer = class _FileTrailer { static parse(data) { let line = ""; let read = 0; let trailerData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("FileTrailer :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("99" /* FileTrailerCode */ !== data.slice(0, 2)) { return Util.returnFieldError("FileTrailer :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const fileControlTotal = Reader.field(line, read); if (fileControlTotal.error) { return Util.returnFieldError("FileTrailer :: Unable to parse" /* PARSE */, "GroupControlTotal"); } else { read += fileControlTotal.newStart; trailerData = { ...trailerData, fileControlTotal: fileControlTotal.value }; } const numberOfGroups = Reader.fieldAsInt(line, read); if (numberOfGroups.error) { return Util.returnFieldError("FileTrailer :: Unable to parse" /* PARSE */, "NumberOfGroups"); } else { read += numberOfGroups.newStart; trailerData = { ...trailerData, numberOfGroups: numberOfGroups.value }; } const numberOfRecords = Reader.fieldAsInt(line, read); if (numberOfRecords.error) { return Util.returnFieldError("FileTrailer :: Unable to parse" /* PARSE */, "NumberOfRecords"); } else { read += numberOfRecords.newStart; trailerData = { ...trailerData, numberOfRecords: numberOfRecords.value }; } const trailerErr = _FileTrailer.validate(trailerData); if (trailerErr) { return Util.returnParserError(trailerErr.error.message); } return Util.returnValue(trailerData); } static validate(trailerData) { if (trailerData.fileControlTotal !== "" && !Validator.Amount(trailerData.fileControlTotal)) { return Util.returnFieldError("FileTrailer :: Invalid" /* VALIDATE */, "FileControlTotal"); } return null; } }; // parser/record-group-header.ts var GroupHeader = class _GroupHeader { static parse(data) { let line = ""; let read = 0; let headerData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("02" /* GroupHeaderCode */ !== data.slice(0, 2)) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const receiver = Reader.field(line, read); if (receiver.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "Receiver"); } else { read += receiver.newStart; headerData = { ...headerData, receiver: receiver.value }; } const originator = Reader.field(line, read); if (originator.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "Originator"); } else { read += originator.newStart; headerData = { ...headerData, originator: originator.value }; } const groupStatus = Reader.fieldAsInt(line, read); if (groupStatus.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "GroupStatus"); } else { read += groupStatus.newStart; headerData = { ...headerData, groupStatus: groupStatus.value }; } const asOfDate = Reader.field(line, read); if (asOfDate.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "AsOfDate"); } else { read += asOfDate.newStart; headerData = { ...headerData, asOfDate: asOfDate.value }; } const asOfTime = Reader.field(line, read); if (asOfTime.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "AsOfTime"); } else { read += asOfTime.newStart; headerData = { ...headerData, asOfTime: asOfTime.value }; } const currencyCode = Reader.field(line, read); if (currencyCode.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "CurrencyCode"); } else { read += currencyCode.newStart; headerData = { ...headerData, currencyCode: currencyCode.value }; } const asOfDateModifier = Reader.fieldAsInt(line, read); if (asOfDateModifier.error) { return Util.returnFieldError("GroupHeader :: Unable to parse" /* PARSE */, "AsOfDateModifier"); } else { read += asOfDateModifier.newStart; headerData = { ...headerData, asOfDateModifier: asOfDateModifier.value }; } const headerErr = _GroupHeader.validate(headerData); if (headerErr) { return Util.returnParserError(headerErr.error.message); } return Util.returnValue(headerData); } static validate(headerData) { if (headerData.originator === "") { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "Originator"); } if (headerData.groupStatus < 0 || headerData.groupStatus > 4) { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "GroupStatus"); } if (headerData.asOfDate === "" || !Validator.Date(headerData.asOfDate)) { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "AsOfDate"); } if (headerData.asOfTime && !Validator.Time(headerData.asOfTime)) { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "AsOfTime"); } if (headerData.currencyCode && !Validator.CurrencyCode(headerData.currencyCode)) { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "CurrencyCode"); } if (!headerData.asOfDateModifier || headerData.asOfDateModifier < 0 || headerData.asOfDateModifier > 4) { return Util.returnFieldError("GroupHeader :: Invalid" /* VALIDATE */, "AsOfDateModifier"); } return null; } }; // parser/record-group-trailer.ts var GroupTrailer = class _GroupTrailer { static parse(data) { let line = ""; let read = 0; let trailerData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("GroupTrailer :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("98" /* GroupTrailerCode */ !== data.slice(0, 2)) { return Util.returnFieldError("GroupTrailer :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const groupControlTotal = Reader.field(line, read); if (groupControlTotal.error) { return Util.returnFieldError("GroupTrailer :: Unable to parse" /* PARSE */, "GroupControlTotal"); } else { read += groupControlTotal.newStart; trailerData = { ...trailerData, groupControlTotal: groupControlTotal.value }; } const numberOfAccounts = Reader.fieldAsInt(line, read); if (numberOfAccounts.error) { return Util.returnFieldError("GroupTrailer :: Unable to parse" /* PARSE */, "NumberOfAccounts"); } else { read += numberOfAccounts.newStart; trailerData = { ...trailerData, numberOfAccounts: numberOfAccounts.value }; } const numberRecords = Reader.fieldAsInt(line, read); if (numberRecords.error) { return Util.returnFieldError("GroupTrailer :: Unable to parse" /* PARSE */, "NumberRecords"); } else { read += numberRecords.newStart; trailerData = { ...trailerData, numberRecords: numberRecords.value }; } const trailerErr = _GroupTrailer.validate(trailerData); if (trailerErr) { return Util.returnParserError(trailerErr.error.message); } return Util.returnValue(trailerData); } static validate(trailerData) { if (trailerData.groupControlTotal !== "" && !Validator.Amount(trailerData.groupControlTotal)) { return Util.returnFieldError("GroupTrailer :: Invalid" /* VALIDATE */, "GroupControlTotal"); } return null; } }; // parser/record-transaction-detail.ts var TransactionDetail = class _TransactionDetail { static validate(data) { if (data.typeCode !== "" && !Validator.TypeCode(data.typeCode)) { return Util.returnFieldError("TransactionDetail :: Invalid" /* VALIDATE */, "TypeCode"); } if (data.amount && !Validator.Amount(data.amount)) { return Util.returnFieldError("TransactionDetail :: Invalid" /* VALIDATE */, "Amount"); } return null; } static parse(data) { let line = ""; let read = 0; let txnData = {}; const length = data.length; if (length < 3) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "record"); } else { line = data.slice(0, length); } if ("16" /* TransactionDetailCode */ !== data.slice(0, 2)) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "RecordCode"); } read += 3; const typeCode = Reader.field(line, read); if (typeCode.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "TypeCode"); } else { read += typeCode.newStart; txnData = { ...txnData, typeCode: typeCode.value }; } const amount = Reader.field(line, read); if (amount.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, `Amount`); } else { read += amount.newStart; txnData = { ...txnData, amount: amount.value }; } const fundsTypeSize = FundsType.parse(line.slice(read)); if (fundsTypeSize.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, `FundsType :: ${fundsTypeSize.error.message}`); } else { read += fundsTypeSize.newStart; txnData = { ...txnData, fundsTypeSize: fundsTypeSize.value }; } const bankReferenceNumber = Reader.field(line, read); if (bankReferenceNumber.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "BankReferenceNumber"); } else { read += bankReferenceNumber.newStart; txnData = { ...txnData, bankReferenceNumber: bankReferenceNumber.value }; } const customerReferenceNumber = Reader.field(line, read); if (customerReferenceNumber.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "CustomerReferenceNumber"); } else { read += customerReferenceNumber.newStart; txnData = { ...txnData, customerReferenceNumber: customerReferenceNumber.value }; } const text = Reader.field(line, read, true); if (text.error) { return Util.returnFieldError("TransactionDetail :: Unable to parse" /* PARSE */, "Text"); } else { read += text.newStart; txnData = { ...txnData, text: text.value }; } const txnErr = _TransactionDetail.validate(txnData); if (txnErr) { return Util.returnParserError(txnErr.error.message); } return Util.returnValue(txnData); } }; // reader/detail.ts var Detail = class { static read(lines, lineIndex) { var rawData = ""; var find = false; var isBreak = false; let output = {}; for (let lineIdx = lineIndex; lineIdx < lines.length; lineIdx++) { const line = lines[lineIdx]; if (!line) continue; if (line.length < 3) continue; const recordCode = line.slice(0, 2); switch (recordCode) { case "16" /* TransactionDetailCode */: if (find) { isBreak = true; break; } rawData = line; find = true; const transactionDetail = TransactionDetail.parse(rawData); if (transactionDetail.error) { return Util.returnReaderError( `Reading DETAIL :: Transaction(${"16" /* TransactionDetailCode */}) on line ${lineIdx + 1} :: (${transactionDetail.error.message})` ); } output = { ...output, ...transactionDetail.value }; break; case "88" /* ContinuationCode */: const continuedData = Continuation.parse(line); if (continuedData.error) { return Util.returnReaderError( `Reading DETAIL :: Continuation(${"88" /* ContinuationCode */}) on line ${lineIdx + 1} :: (${continuedData.error.message})` ); } output = { ...output, ...continuedData.value }; break; default: break; } if (isBreak) { break; } } return Util.returnValue(output); } }; // reader/account.ts var Account = class { static read(lines, lineIndex) { let output = {}; let find = false; let isBreak = false; for (let lineIdx = lineIndex; lineIdx < lines.length; lineIdx++) { const line = lines[lineIdx]; if (!line) continue; if (line.length < 3) continue; const recordCode = line.slice(0, 2); switch (recordCode) { case "03" /* AccountIdentifierCode */: { if (find) { isBreak = true; break; } find = true; const accountIdentifier = RecordAccountIdentifier.parse(line); if (accountIdentifier.error) { return Util.returnReaderError( `Reading ACCOUNT :: AccountIdentifier(${"03" /* AccountIdentifierCode */}) on line ${lineIdx + 1} :: (${accountIdentifier.error.message})` ); } output = { ...output, ...accountIdentifier.value }; break; } case "88" /* ContinuationCode */: { break; } case "49" /* AccountTrailerCode */: { const accountTrailer = RecordAccountTrailer.parse(line); if (accountTrailer.error) { return Util.returnReaderError( `Reading ACCOUNT :: AccountTrailer(${"49" /* AccountTrailerCode */}) on line ${lineIdx + 1} :: (${accountTrailer.error.message})` ); } output = { ...output, ...accountTrailer.value }; break; } case "16" /* TransactionDetailCode */: { const detail = Detail.read(lines, lineIdx); if (detail.error) { return Util.returnReaderError(detail.error.message); } output = { ...output, details: [...output.details || [], detail.value] }; break; } default: break; } if (isBreak) { break; } } return Util.returnValue(output); } }; // reader/group.ts var Group = class { static read(lines, lineIndex) { let output = {}; for (let lineIdx = lineIndex; lineIdx < lines.length; lineIdx++) { const line = lines[lineIdx]; if (!line) continue; if (line.length < 3) continue; const recordCode = line.slice(0, 2); switch (recordCode) { case "02" /* GroupHeaderCode */: { const groupHeader = GroupHeader.parse(line); if (groupHeader.error) { return Util.returnReaderError( `Reading GROUP :: GroupHeader(${"02" /* GroupHeaderCode */}) on line ${lineIdx + 1} :: (${groupHeader.error.message})` ); } output = { ...output, ...groupHeader.value }; break; } case "03" /* AccountIdentifierCode */: { const accountData = Account.read(lines, lineIdx); if (accountData.error) { return Util.returnReaderError( `Reading GROUP :: AccountIdentifier(${"03" /* AccountIdentifierCode */}) on line ${lineIdx + 1} :: (${accountData.error.message})` ); } output = { ...output, accounts: [...output.accounts || [], accountData.value] }; break; } case "98" /* GroupTrailerCode */: { const groupTrailer = GroupTrailer.parse(line); if (groupTrailer.error) { return Util.returnReaderError( `Reading GROUP :: GroupTrailer(${"98" /* GroupTrailerCode */}) on line ${lineIdx + 1} :: (${groupTrailer.error.message})` ); } output = { ...output, ...groupTrailer.value }; break; } default: break; } } return Util.returnValue(output); } }; // reader/file.ts var File = class { static read(bai2Data) { let output = {}; const lines = bai2Data.split("\n"); for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) { const line = lines[lineIdx]; if (!line) continue; if (line.length < 3) continue; const recordCode = line.slice(0, 2); switch (recordCode) { case "01" /* FileHeaderCode */: { const fileHeader = FileHeader.parse(line); if (fileHeader.error) { return Util.returnReaderError( `Reading FILE :: FileHeader(${"01" /* FileHeaderCode */}) on line ${lineIdx + 1} :: (${fileHeader.error.message})` ); } output = { ...output, ...fileHeader.value }; break; } case "02" /* GroupHeaderCode */: { const groupData = Group.read(lines, lineIdx); if (groupData.error) { return Util.returnReaderError( `Reading FILE :: GroupHeader(${"02" /* GroupHeaderCode */}) on line ${lineIdx + 1} :: (${groupData.error.message})` ); } output = { ...output, groups: [...output.groups || [], groupData.value] }; break; } case "99" /* FileTrailerCode */: { const fileTrailer = FileTrailer.parse(line); if (fileTrailer.error) { return Util.returnReaderError( `Reading FILE :: FileTrailer(${"99" /* FileTrailerCode */}) on line ${lineIdx + 1} :: (${fileTrailer.error.message})` ); } output = { ...output, ...fileTrailer.value }; break; } default: continue; } } const flatTxns = Util.getFlattenTransactions(output); if (flatTxns.error) { return Util.returnReaderError(flatTxns.error.message); } return Util.returnValue(flatTxns.value); } }; // index.ts var BAI_FILE; ((BAI_FILE2) => { BAI_FILE2.Enums = enums_exports; BAI_FILE2.Models = models_exports; let Reader2; ((Reader3) => { Reader3.File = File; })(Reader2 = BAI_FILE2.Reader || (BAI_FILE2.Reader = {})); })(BAI_FILE || (BAI_FILE = {})); function getParsedValue(fileString, options) { try { const parser = BAI_FILE.Reader.File.read(fileString); const data = parser.value; if (options.output === "CSV") { const csv = (0, import_json_2_csv.json2csv)(data); return csv; } else { return data; } } catch (error) { throw error.message; } } var BAI2; ((BAI22) => { function fromString(fileString, options = {}) { try { const res = getParsedValue(fileString, options); return res; } catch (error) { throw error.message; } } BAI22.fromString = fromString; })(BAI2 || (BAI2 = {})); ((BAI22) => { function fromFile(filePath, options = {}) { try { const fileString = import_fs.default.readFileSync(filePath).toString(); const res = getParsedValue(fileString, options); return res; } catch (error) { throw error.message; } } BAI22.fromFile = fromFile; })(BAI2 || (BAI2 = {})); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BAI2 });