bai2-parser
Version:
Parse the bai2 statement file as CSV or JSON file
1,339 lines (1,306 loc) • 47.1 kB
JavaScript
"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
});