ofx-data-extractor 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Fábio Pereira França
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # ofx-data-extractor
2
+ ## Ofx Data Extractor and Formatter
3
+ This is a `Node.js` module written in `TypeScript` that provides a utility for extracting data from an `OFX` file. The module can also format some of the data and retrieve specific parts of the file if requested.
4
+
5
+ ### Installation
6
+ You can install this module using the Node Package Manager (`NPM`) with the following command:
7
+
8
+ ```bash
9
+ npm install ofx-ts
10
+ ```
11
+ Usage
12
+ The module provides a class called Ofx that can be used to extract and format data from an `OFX` file. Here's an example of how to use it:
13
+
14
+ ```typescript
15
+ import { Ofx } from 'ofx-data-extractor';
16
+
17
+ const data = 'OFXHEADER:100\nDATA:OFXSGML\nVERSION:102\n...';
18
+ const ofx = new Ofx(data);
19
+
20
+ const headers = ofx.getHeaders();
21
+ console.log(headers);
22
+
23
+ const transactionsSummary = ofx.getTransactionsSummary();
24
+ console.log(transactionsSummary);
25
+
26
+ const bankTransferList = ofx.getBankTransferList();
27
+ console.log(bankTransferList);
28
+
29
+ const ofxResponse = ofx.toJson();
30
+ console.log(ofxResponse);
31
+ ```
32
+ ### Constructor
33
+ The `Ofx` class constructor takes in two arguments:
34
+
35
+ `data`: The `OFX` file content as a string or a Buffer.
36
+ `config`: Optional configuration options for formatting the OFX data.
37
+ ### Methods
38
+ The `Ofx` class provides the following methods:
39
+
40
+ - `getHeaders(): OFXMetaData`: Returns the metadata section of the OFX file as an object.
41
+ - `getBankTransferList(): Pick<BankTransferList, 'STRTTRN'>`: Returns a list of bank transfer transactions as an object.
42
+ - `getTransactionsSummary()`: Object: Returns a summary of transactions for a bank statement as an object.
43
+ - `getContent(): OfxStructure`: Returns the OFX file content as an object.
44
+ - `toJson(): OfxResponse`: Returns the entire OFX file content as a JSON object.
45
+
46
+ ### Configuration
47
+ The `Ofx` class can be configured with the following options:
48
+
49
+ - `formatDate`: A function that takes in a date string and returns a formatted date string.
50
+ - `fitId`: A string that determines how the financial institution transaction ID is handled. Possible values are "separated" (the default) or "included".
51
+ - `nativeTypes`: A boolean value that determines whether numeric fields should be represented as numbers or strings in the resulting JSON object.
@@ -0,0 +1,4 @@
1
+ export declare const ELEMENT_CLOSURE_REGEX: RegExp;
2
+ export declare const ELEMENT_OPENING_REGEX: RegExp;
3
+ export declare const START_TEXT_BANK_TRANSFER = "<STMTTRN>";
4
+ export declare const END_TEXT_BANK_TRANSFER = "</STMTTRN>";
@@ -0,0 +1,22 @@
1
+ import { STRTTRN as STRTTRNType } from './types';
2
+ export declare function formatDate(date: string, format: string): string;
3
+ export declare function fixJsonProblems(content: string): string;
4
+ export declare function extractFinancialInstitutionTransactionId(fitid: string): string;
5
+ export declare function isDateField(field: string): boolean;
6
+ export declare function trim(str: string): string;
7
+ export declare function objectStartReplacer(param: string): string;
8
+ export declare function objectEndReplacer(param: string): "</STMTTRN>" | "},";
9
+ export declare function isValidNumberToConvert(field: string, value: string): boolean;
10
+ export declare function getBankTransferListText(ofxContent: string): {
11
+ oldListText: string;
12
+ newListText: string;
13
+ };
14
+ export declare function convertMetaDataToObject(stringList: string[], nativeTypes: boolean): {
15
+ [key: string]: any;
16
+ };
17
+ export declare function getTransactionsSummary(STRTTRN: STRTTRNType[]): {
18
+ credit: number;
19
+ debit: number;
20
+ amountOfCredits: number;
21
+ amountOfDebits: number;
22
+ };
@@ -0,0 +1,3 @@
1
+ export { Ofx } from './main';
2
+ export { formatDate, fixJsonProblems } from './helpers';
3
+ export type { OfxResponse, OFXMetaData, OfxStructure, BankTransferList, } from './types';
@@ -0,0 +1,9 @@
1
+ const p=/<\/\w+>/g,h=/<\w+>/g,l="<STMTTRN>",o="</STMTTRN>";function m(n){const t=n.slice(0,4),e=n.slice(4,6),s=n.slice(6,8),r=n.slice(8,10),i=n.slice(10,12),c=n.slice(12,14),[a,g]=n.slice(14).replace("[","").replace("]","").split(":");return{yyyy:t,yy:t.slice(2),y:t,MM:e,M:e,dd:s,d:s,hh:r,h:r,mm:i,m:i,ss:c,s:c,O:a,TZ:g}}function u(n,t){const e=m(n);let s=t;for(const[r,i]of Object.entries(e))s=s.replace(r,i);return s}function f(n){const t=n.replace(/(},})/g,"}}").replace(/(}")/g,'},"').replace(/(},])/g,"}]").replace(/(,})/g,"}").replace(/({")/g,`{
2
+ "`).replace(/(})/g,`
3
+ }`).replace(/(",")/g,`",
4
+ "`).replace(/,\s*}/g,`
5
+ }`);return t.at(-1)===","?t.slice(0,-1):t}function N(n){const t=n.slice(0,12),e=n.slice(12,19),s=n.slice(19),r={date:t,transactionCode:e,protocol:s};return JSON.stringify(r)}function R(n){return n.startsWith("DT")}function x(n){return n.trim()}function D(n){return n===l?n:n.replace("<","").replace(">",":{")}function S(n){return n===o?n:"},"}function d(n,t){return n.endsWith("ID")||n.endsWith("NUM")?!1:!isNaN(Number(t))}function T(n){const t=n.indexOf(l),e=n.lastIndexOf(o)+o.length,s=n.substring(t,e),r=new RegExp(l,"g"),i=new RegExp(o,"g"),c=`"STRTTRN":[${s.replace(r,"{").replace(i,"},")}]`;return{oldListText:s,newListText:c}}function E(n,t){const e={};for(const s of n){const[r,i]=s.split(":"),c=r.replace(`
6
+ `,"");e[c]=t&&d(r,i)?Number(i):i}return e}function O(n){return n.reduce((t,e)=>e.TRNTYPE.toLocaleLowerCase().startsWith("deb")?(t.amountOfDebits++,t.debit+=Number(e.TRNAMT.replace("-","")),t):(t.amountOfCredits++,t.debit+=Number(e.TRNAMT),t),{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0})}class y{data;config={};constructor(t,e){e&&(this.config=e),t instanceof Buffer?this.data=t.toString():this.data=t}getHeaders(){const[t]=this.data.split("<OFX>"),e=t.split(`
7
+ `),s=i=>!!i.trim().length,r=e.filter(s);return E(r,!!this.config.nativeTypes)}getBankTransferList(){const{newListText:t}=T(this.getPartialJsonData()),e=t.slice(10),s=f(e);return JSON.parse(s)}getPartialJsonData(){const[t,e]=this.data.split("<OFX>"),s="<OFX>"+e,{sanitize:r}=this;return s.replace(p,S).replace(h,D).split(`
8
+ `).map(x).filter(Boolean).map(r,this).join("")}sanitizeValue(t,e){let s=e.replace(/[{},]/g,"");if(R(t))s=this.configDate(s);else{if(t==="FITID")return this.configFinancialInstitutionTransactionId(s);if(this.config.nativeTypes&&d(t,s))return`${s},`}return`"${s}",`}sanitize(t){let e=t;const s=e.slice(0,e.indexOf(":")),r=this.sanitizeValue,i=a=>r.call(this,s,a);return t.match(/{(\w|\W)+/)&&(e=e.replace(/({(\w|\W)+)$/,i)),e.search(/(^\w+:)/)<0?e:e.replace(s,`"${s}"`)}configFinancialInstitutionTransactionId(t){const{fitId:e}=this.config;return e==="separated"?N(t):`"${t}",`}configDate(t){const{formatDate:e}=this.config;return e?u(t,e):u(t,"y-M-d")}getTransactionsSummary(){const t=this.getContent(),{DTEND:e,DTSTART:s,STRTTRN:r}=t.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST,i=O(r);return{dateStart:s,dateEnd:e,...i}}getContent(){const t=this.getPartialJsonData(),{newListText:e,oldListText:s}=T(t),r=t.replace(s,e);return JSON.parse(`{${f(r)}}`)}toJson(){const t=this.getHeaders(),e=this.getContent();return{...t,...e}}}export{y as Ofx,f as fixJsonProblems,u as formatDate};
9
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/helpers.ts","../src/main.ts"],"sourcesContent":["export const ELEMENT_CLOSURE_REGEX = /<\\/\\w+>/g\nexport const ELEMENT_OPENING_REGEX = /<\\w+>/g\nexport const START_TEXT_BANK_TRANSFER = '<STMTTRN>'\nexport const END_TEXT_BANK_TRANSFER = '</STMTTRN>'\n","import { END_TEXT_BANK_TRANSFER, START_TEXT_BANK_TRANSFER } from './config'\nimport { STRTTRN as STRTTRNType } from './types'\n\nfunction separatePartsOfDate(date: string) {\n const year = date.slice(0, 4)\n const month = date.slice(4, 6)\n const day = date.slice(6, 8)\n const hour = date.slice(8, 10)\n const minutes = date.slice(10, 12)\n const seconds = date.slice(12, 14)\n const [offset, timezone] = date\n .slice(14)\n .replace('[', '')\n .replace(']', '')\n .split(':')\n return {\n yyyy: year,\n yy: year.slice(2),\n y: year,\n MM: month,\n M: month,\n dd: day,\n d: day,\n hh: hour,\n h: hour,\n mm: minutes,\n m: minutes,\n ss: seconds,\n s: seconds,\n O: offset,\n TZ: timezone,\n }\n}\n\nexport function formatDate(date: string, format: string) {\n const parts = separatePartsOfDate(date)\n let result = format\n for (const [key, value] of Object.entries(parts)) {\n result = result.replace(key, value)\n }\n return result\n}\n\nexport function fixJsonProblems(content: string) {\n const result = content\n .replace(/(},})/g, '}}')\n .replace(/(}\")/g, '},\"')\n .replace(/(},])/g, '}]')\n .replace(/(,})/g, '}')\n .replace(/({\")/g, '{\\n\"')\n .replace(/(})/g, '\\n}')\n .replace(/(\",\")/g, '\",\\n\"')\n .replace(/,\\s*}/g, '\\n}')\n return result.at(-1) === ',' ? result.slice(0, -1) : result\n}\n\nexport function extractFinancialInstitutionTransactionId(fitid: string) {\n const dateText = fitid.slice(0, 12)\n const transactionCode = fitid.slice(12, 19)\n const protocol = fitid.slice(19)\n const resultObject = {\n date: dateText,\n transactionCode,\n protocol,\n }\n return JSON.stringify(resultObject)\n}\n\nexport function isDateField(field: string) {\n return field.startsWith('DT')\n}\n\nexport function trim(str: string) {\n return str.trim()\n}\n\nexport function objectStartReplacer(param: string) {\n if (param === START_TEXT_BANK_TRANSFER) return param\n return param.replace('<', '').replace('>', ':{')\n}\n\nexport function objectEndReplacer(param: string) {\n if (param === END_TEXT_BANK_TRANSFER) return param\n return '},'\n}\n\nexport function isValidNumberToConvert(field: string, value: string) {\n if (field.endsWith('ID') || field.endsWith('NUM')) return false\n return !isNaN(Number(value))\n}\n\nexport function getBankTransferListText(ofxContent: string) {\n const startIndex = ofxContent.indexOf(START_TEXT_BANK_TRANSFER)\n const endIndex =\n ofxContent.lastIndexOf(END_TEXT_BANK_TRANSFER) +\n END_TEXT_BANK_TRANSFER.length\n const oldListText = ofxContent.substring(startIndex, endIndex)\n const startRgx = new RegExp(START_TEXT_BANK_TRANSFER, 'g')\n const endRgx = new RegExp(END_TEXT_BANK_TRANSFER, 'g')\n const newListText = `\"STRTTRN\":[${oldListText\n .replace(startRgx, '{')\n .replace(endRgx, '},')}]`\n return { oldListText, newListText }\n}\n\nexport function convertMetaDataToObject(\n stringList: string[],\n nativeTypes: boolean,\n) {\n const result: { [key: string]: any } = {}\n for (const line of stringList) {\n const [key, value] = line.split(':')\n const sanitizedKey = key.replace('\\n', '')\n result[sanitizedKey] =\n nativeTypes && isValidNumberToConvert(key, value) ? Number(value) : value\n }\n return result\n}\n\nexport function getTransactionsSummary(STRTTRN: STRTTRNType[]) {\n return STRTTRN.reduce(\n (prevValue, currValue) => {\n if (currValue.TRNTYPE.toLocaleLowerCase().startsWith('deb')) {\n prevValue.amountOfDebits++\n prevValue.debit += Number(currValue.TRNAMT.replace('-', ''))\n return prevValue\n }\n prevValue.amountOfCredits++\n prevValue.debit += Number(currValue.TRNAMT)\n return prevValue\n },\n { credit: 0, debit: 0, amountOfCredits: 0, amountOfDebits: 0 },\n )\n}\n","import { ELEMENT_CLOSURE_REGEX, ELEMENT_OPENING_REGEX } from './config'\r\nimport {\r\n convertMetaDataToObject,\r\n extractFinancialInstitutionTransactionId,\r\n fixJsonProblems,\r\n formatDate,\r\n getBankTransferListText,\r\n getTransactionsSummary,\r\n isDateField,\r\n isValidNumberToConvert,\r\n objectEndReplacer,\r\n objectStartReplacer,\r\n trim,\r\n} from './helpers'\r\nimport {\r\n BankTransferList,\r\n OfxConfig,\r\n OFXMetaData,\r\n OfxResponse,\r\n OfxStructure,\r\n} from './types'\r\n\r\nexport class Ofx {\r\n private data: string\r\n private config: OfxConfig = {}\r\n\r\n constructor(data: string | Buffer, config?: OfxConfig) {\r\n if (config) this.config = config\r\n if (data instanceof Buffer) this.data = data.toString()\r\n else this.data = data\r\n }\r\n\r\n getHeaders(): OFXMetaData {\r\n const [metaDataString] = this.data.split('<OFX>')\r\n const metaDataList = metaDataString.split('\\n')\r\n const validate = (line: string) => !!line.trim().length\r\n const validatedMetaDataList = metaDataList.filter(validate)\r\n return convertMetaDataToObject(\r\n validatedMetaDataList,\r\n !!this.config.nativeTypes,\r\n ) as OFXMetaData\r\n }\r\n\r\n getBankTransferList(): Pick<BankTransferList, 'STRTTRN'> {\r\n const { newListText } = getBankTransferListText(this.getPartialJsonData())\r\n\r\n const list = newListText.slice(10)\r\n const fixedList = fixJsonProblems(list)\r\n return JSON.parse(fixedList)\r\n }\r\n\r\n private getPartialJsonData() {\r\n const [_, ofxContentText] = this.data.split('<OFX>')\r\n const ofxContent = '<OFX>' + ofxContentText\r\n const { sanitize } = this\r\n /**\r\n * Use replace first for closing tag so there is no conflict in `objectStartReplacer`\r\n */\r\n return ofxContent\r\n .replace(ELEMENT_CLOSURE_REGEX, objectEndReplacer)\r\n .replace(ELEMENT_OPENING_REGEX, objectStartReplacer)\r\n .split('\\n')\r\n .map(trim)\r\n .filter(Boolean)\r\n .map(sanitize, this)\r\n .join('')\r\n }\r\n\r\n private sanitizeValue(field: string, value: string) {\r\n let fieldValue = value.replace(/[{},]/g, '')\r\n if (isDateField(field)) {\r\n fieldValue = this.configDate(fieldValue)\r\n } else if (field === 'FITID') {\r\n return this.configFinancialInstitutionTransactionId(fieldValue)\r\n } else if (\r\n this.config.nativeTypes &&\r\n isValidNumberToConvert(field, fieldValue)\r\n ) {\r\n return `${fieldValue},`\r\n }\r\n return `\"${fieldValue}\",`\r\n }\r\n\r\n private sanitize(line: string) {\r\n let sanitizedLine = line\r\n const field = sanitizedLine.slice(0, sanitizedLine.indexOf(':'))\r\n const sanitizeValue = this.sanitizeValue\r\n const replacer = (matched: string) =>\r\n sanitizeValue.call(this, field, matched)\r\n if (line.match(/{(\\w|\\W)+/)) {\r\n sanitizedLine = sanitizedLine.replace(/({(\\w|\\W)+)$/, replacer)\r\n }\r\n const matchedProperty = sanitizedLine.search(/(^\\w+:)/)\r\n if (matchedProperty < 0) return sanitizedLine\r\n\r\n return sanitizedLine.replace(field, `\"${field}\"`)\r\n }\r\n\r\n private configFinancialInstitutionTransactionId(fitString: string) {\r\n const { fitId } = this.config\r\n if (fitId === 'separated')\r\n return extractFinancialInstitutionTransactionId(fitString)\r\n return `\"${fitString}\",`\r\n }\r\n\r\n private configDate(dateString: string) {\r\n const { formatDate: format } = this.config\r\n if (format) return formatDate(dateString, format)\r\n return formatDate(dateString, 'y-M-d')\r\n }\r\n\r\n getTransactionsSummary() {\r\n const jsonData = this.getContent()\r\n const { DTEND, DTSTART, STRTTRN } =\r\n jsonData.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST\r\n const summary = getTransactionsSummary(STRTTRN)\r\n return {\r\n dateStart: DTSTART,\r\n dateEnd: DTEND,\r\n ...summary,\r\n }\r\n }\r\n\r\n getContent(): OfxStructure {\r\n const ofxText = this.getPartialJsonData()\r\n const { newListText, oldListText } = getBankTransferListText(ofxText)\r\n const result = ofxText.replace(oldListText, newListText)\r\n return JSON.parse(`{${fixJsonProblems(result)}}`)\r\n }\r\n\r\n toJson(): OfxResponse {\r\n const ofxMetaDataResult = this.getHeaders()\r\n const ofxContentResult = this.getContent()\r\n const result = { ...ofxMetaDataResult, ...ofxContentResult }\r\n return result\r\n }\r\n}\r\n"],"names":["ELEMENT_CLOSURE_REGEX","ELEMENT_OPENING_REGEX","START_TEXT_BANK_TRANSFER","END_TEXT_BANK_TRANSFER","separatePartsOfDate","date","year","month","day","hour","minutes","seconds","offset","timezone","formatDate","format","parts","result","key","value","fixJsonProblems","content","extractFinancialInstitutionTransactionId","fitid","dateText","transactionCode","protocol","resultObject","isDateField","field","trim","str","objectStartReplacer","param","objectEndReplacer","isValidNumberToConvert","getBankTransferListText","ofxContent","startIndex","endIndex","oldListText","startRgx","endRgx","newListText","convertMetaDataToObject","stringList","nativeTypes","line","sanitizedKey","getTransactionsSummary","STRTTRN","prevValue","currValue","Ofx","data","config","metaDataString","metaDataList","validate","validatedMetaDataList","list","fixedList","_","ofxContentText","sanitize","fieldValue","sanitizedLine","sanitizeValue","replacer","matched","fitString","fitId","dateString","jsonData","DTEND","DTSTART","summary","ofxText","ofxMetaDataResult","ofxContentResult"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";const p=/<\/\w+>/g,h=/<\w+>/g,l="<STMTTRN>",o="</STMTTRN>";function m(n){const t=n.slice(0,4),e=n.slice(4,6),s=n.slice(6,8),r=n.slice(8,10),i=n.slice(10,12),c=n.slice(12,14),[a,g]=n.slice(14).replace("[","").replace("]","").split(":");return{yyyy:t,yy:t.slice(2),y:t,MM:e,M:e,dd:s,d:s,hh:r,h:r,mm:i,m:i,ss:c,s:c,O:a,TZ:g}}function u(n,t){const e=m(n);let s=t;for(const[r,i]of Object.entries(e))s=s.replace(r,i);return s}function f(n){const t=n.replace(/(},})/g,"}}").replace(/(}")/g,'},"').replace(/(},])/g,"}]").replace(/(,})/g,"}").replace(/({")/g,`{
2
+ "`).replace(/(})/g,`
3
+ }`).replace(/(",")/g,`",
4
+ "`).replace(/,\s*}/g,`
5
+ }`);return t.at(-1)===","?t.slice(0,-1):t}function N(n){const t=n.slice(0,12),e=n.slice(12,19),s=n.slice(19),r={date:t,transactionCode:e,protocol:s};return JSON.stringify(r)}function R(n){return n.startsWith("DT")}function x(n){return n.trim()}function D(n){return n===l?n:n.replace("<","").replace(">",":{")}function S(n){return n===o?n:"},"}function d(n,t){return n.endsWith("ID")||n.endsWith("NUM")?!1:!isNaN(Number(t))}function T(n){const t=n.indexOf(l),e=n.lastIndexOf(o)+o.length,s=n.substring(t,e),r=new RegExp(l,"g"),i=new RegExp(o,"g"),c=`"STRTTRN":[${s.replace(r,"{").replace(i,"},")}]`;return{oldListText:s,newListText:c}}function E(n,t){const e={};for(const s of n){const[r,i]=s.split(":"),c=r.replace(`
6
+ `,"");e[c]=t&&d(r,i)?Number(i):i}return e}function O(n){return n.reduce((t,e)=>e.TRNTYPE.toLocaleLowerCase().startsWith("deb")?(t.amountOfDebits++,t.debit+=Number(e.TRNAMT.replace("-","")),t):(t.amountOfCredits++,t.debit+=Number(e.TRNAMT),t),{credit:0,debit:0,amountOfCredits:0,amountOfDebits:0})}class y{data;config={};constructor(t,e){e&&(this.config=e),t instanceof Buffer?this.data=t.toString():this.data=t}getHeaders(){const[t]=this.data.split("<OFX>"),e=t.split(`
7
+ `),s=i=>!!i.trim().length,r=e.filter(s);return E(r,!!this.config.nativeTypes)}getBankTransferList(){const{newListText:t}=T(this.getPartialJsonData()),e=t.slice(10),s=f(e);return JSON.parse(s)}getPartialJsonData(){const[t,e]=this.data.split("<OFX>"),s="<OFX>"+e,{sanitize:r}=this;return s.replace(p,S).replace(h,D).split(`
8
+ `).map(x).filter(Boolean).map(r,this).join("")}sanitizeValue(t,e){let s=e.replace(/[{},]/g,"");if(R(t))s=this.configDate(s);else{if(t==="FITID")return this.configFinancialInstitutionTransactionId(s);if(this.config.nativeTypes&&d(t,s))return`${s},`}return`"${s}",`}sanitize(t){let e=t;const s=e.slice(0,e.indexOf(":")),r=this.sanitizeValue,i=a=>r.call(this,s,a);return t.match(/{(\w|\W)+/)&&(e=e.replace(/({(\w|\W)+)$/,i)),e.search(/(^\w+:)/)<0?e:e.replace(s,`"${s}"`)}configFinancialInstitutionTransactionId(t){const{fitId:e}=this.config;return e==="separated"?N(t):`"${t}",`}configDate(t){const{formatDate:e}=this.config;return e?u(t,e):u(t,"y-M-d")}getTransactionsSummary(){const t=this.getContent(),{DTEND:e,DTSTART:s,STRTTRN:r}=t.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST,i=O(r);return{dateStart:s,dateEnd:e,...i}}getContent(){const t=this.getPartialJsonData(),{newListText:e,oldListText:s}=T(t),r=t.replace(s,e);return JSON.parse(`{${f(r)}}`)}toJson(){const t=this.getHeaders(),e=this.getContent();return{...t,...e}}}exports.Ofx=y;exports.fixJsonProblems=f;exports.formatDate=u;
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/config.ts","../src/helpers.ts","../src/main.ts"],"sourcesContent":["export const ELEMENT_CLOSURE_REGEX = /<\\/\\w+>/g\nexport const ELEMENT_OPENING_REGEX = /<\\w+>/g\nexport const START_TEXT_BANK_TRANSFER = '<STMTTRN>'\nexport const END_TEXT_BANK_TRANSFER = '</STMTTRN>'\n","import { END_TEXT_BANK_TRANSFER, START_TEXT_BANK_TRANSFER } from './config'\nimport { STRTTRN as STRTTRNType } from './types'\n\nfunction separatePartsOfDate(date: string) {\n const year = date.slice(0, 4)\n const month = date.slice(4, 6)\n const day = date.slice(6, 8)\n const hour = date.slice(8, 10)\n const minutes = date.slice(10, 12)\n const seconds = date.slice(12, 14)\n const [offset, timezone] = date\n .slice(14)\n .replace('[', '')\n .replace(']', '')\n .split(':')\n return {\n yyyy: year,\n yy: year.slice(2),\n y: year,\n MM: month,\n M: month,\n dd: day,\n d: day,\n hh: hour,\n h: hour,\n mm: minutes,\n m: minutes,\n ss: seconds,\n s: seconds,\n O: offset,\n TZ: timezone,\n }\n}\n\nexport function formatDate(date: string, format: string) {\n const parts = separatePartsOfDate(date)\n let result = format\n for (const [key, value] of Object.entries(parts)) {\n result = result.replace(key, value)\n }\n return result\n}\n\nexport function fixJsonProblems(content: string) {\n const result = content\n .replace(/(},})/g, '}}')\n .replace(/(}\")/g, '},\"')\n .replace(/(},])/g, '}]')\n .replace(/(,})/g, '}')\n .replace(/({\")/g, '{\\n\"')\n .replace(/(})/g, '\\n}')\n .replace(/(\",\")/g, '\",\\n\"')\n .replace(/,\\s*}/g, '\\n}')\n return result.at(-1) === ',' ? result.slice(0, -1) : result\n}\n\nexport function extractFinancialInstitutionTransactionId(fitid: string) {\n const dateText = fitid.slice(0, 12)\n const transactionCode = fitid.slice(12, 19)\n const protocol = fitid.slice(19)\n const resultObject = {\n date: dateText,\n transactionCode,\n protocol,\n }\n return JSON.stringify(resultObject)\n}\n\nexport function isDateField(field: string) {\n return field.startsWith('DT')\n}\n\nexport function trim(str: string) {\n return str.trim()\n}\n\nexport function objectStartReplacer(param: string) {\n if (param === START_TEXT_BANK_TRANSFER) return param\n return param.replace('<', '').replace('>', ':{')\n}\n\nexport function objectEndReplacer(param: string) {\n if (param === END_TEXT_BANK_TRANSFER) return param\n return '},'\n}\n\nexport function isValidNumberToConvert(field: string, value: string) {\n if (field.endsWith('ID') || field.endsWith('NUM')) return false\n return !isNaN(Number(value))\n}\n\nexport function getBankTransferListText(ofxContent: string) {\n const startIndex = ofxContent.indexOf(START_TEXT_BANK_TRANSFER)\n const endIndex =\n ofxContent.lastIndexOf(END_TEXT_BANK_TRANSFER) +\n END_TEXT_BANK_TRANSFER.length\n const oldListText = ofxContent.substring(startIndex, endIndex)\n const startRgx = new RegExp(START_TEXT_BANK_TRANSFER, 'g')\n const endRgx = new RegExp(END_TEXT_BANK_TRANSFER, 'g')\n const newListText = `\"STRTTRN\":[${oldListText\n .replace(startRgx, '{')\n .replace(endRgx, '},')}]`\n return { oldListText, newListText }\n}\n\nexport function convertMetaDataToObject(\n stringList: string[],\n nativeTypes: boolean,\n) {\n const result: { [key: string]: any } = {}\n for (const line of stringList) {\n const [key, value] = line.split(':')\n const sanitizedKey = key.replace('\\n', '')\n result[sanitizedKey] =\n nativeTypes && isValidNumberToConvert(key, value) ? Number(value) : value\n }\n return result\n}\n\nexport function getTransactionsSummary(STRTTRN: STRTTRNType[]) {\n return STRTTRN.reduce(\n (prevValue, currValue) => {\n if (currValue.TRNTYPE.toLocaleLowerCase().startsWith('deb')) {\n prevValue.amountOfDebits++\n prevValue.debit += Number(currValue.TRNAMT.replace('-', ''))\n return prevValue\n }\n prevValue.amountOfCredits++\n prevValue.debit += Number(currValue.TRNAMT)\n return prevValue\n },\n { credit: 0, debit: 0, amountOfCredits: 0, amountOfDebits: 0 },\n )\n}\n","import { ELEMENT_CLOSURE_REGEX, ELEMENT_OPENING_REGEX } from './config'\r\nimport {\r\n convertMetaDataToObject,\r\n extractFinancialInstitutionTransactionId,\r\n fixJsonProblems,\r\n formatDate,\r\n getBankTransferListText,\r\n getTransactionsSummary,\r\n isDateField,\r\n isValidNumberToConvert,\r\n objectEndReplacer,\r\n objectStartReplacer,\r\n trim,\r\n} from './helpers'\r\nimport {\r\n BankTransferList,\r\n OfxConfig,\r\n OFXMetaData,\r\n OfxResponse,\r\n OfxStructure,\r\n} from './types'\r\n\r\nexport class Ofx {\r\n private data: string\r\n private config: OfxConfig = {}\r\n\r\n constructor(data: string | Buffer, config?: OfxConfig) {\r\n if (config) this.config = config\r\n if (data instanceof Buffer) this.data = data.toString()\r\n else this.data = data\r\n }\r\n\r\n getHeaders(): OFXMetaData {\r\n const [metaDataString] = this.data.split('<OFX>')\r\n const metaDataList = metaDataString.split('\\n')\r\n const validate = (line: string) => !!line.trim().length\r\n const validatedMetaDataList = metaDataList.filter(validate)\r\n return convertMetaDataToObject(\r\n validatedMetaDataList,\r\n !!this.config.nativeTypes,\r\n ) as OFXMetaData\r\n }\r\n\r\n getBankTransferList(): Pick<BankTransferList, 'STRTTRN'> {\r\n const { newListText } = getBankTransferListText(this.getPartialJsonData())\r\n\r\n const list = newListText.slice(10)\r\n const fixedList = fixJsonProblems(list)\r\n return JSON.parse(fixedList)\r\n }\r\n\r\n private getPartialJsonData() {\r\n const [_, ofxContentText] = this.data.split('<OFX>')\r\n const ofxContent = '<OFX>' + ofxContentText\r\n const { sanitize } = this\r\n /**\r\n * Use replace first for closing tag so there is no conflict in `objectStartReplacer`\r\n */\r\n return ofxContent\r\n .replace(ELEMENT_CLOSURE_REGEX, objectEndReplacer)\r\n .replace(ELEMENT_OPENING_REGEX, objectStartReplacer)\r\n .split('\\n')\r\n .map(trim)\r\n .filter(Boolean)\r\n .map(sanitize, this)\r\n .join('')\r\n }\r\n\r\n private sanitizeValue(field: string, value: string) {\r\n let fieldValue = value.replace(/[{},]/g, '')\r\n if (isDateField(field)) {\r\n fieldValue = this.configDate(fieldValue)\r\n } else if (field === 'FITID') {\r\n return this.configFinancialInstitutionTransactionId(fieldValue)\r\n } else if (\r\n this.config.nativeTypes &&\r\n isValidNumberToConvert(field, fieldValue)\r\n ) {\r\n return `${fieldValue},`\r\n }\r\n return `\"${fieldValue}\",`\r\n }\r\n\r\n private sanitize(line: string) {\r\n let sanitizedLine = line\r\n const field = sanitizedLine.slice(0, sanitizedLine.indexOf(':'))\r\n const sanitizeValue = this.sanitizeValue\r\n const replacer = (matched: string) =>\r\n sanitizeValue.call(this, field, matched)\r\n if (line.match(/{(\\w|\\W)+/)) {\r\n sanitizedLine = sanitizedLine.replace(/({(\\w|\\W)+)$/, replacer)\r\n }\r\n const matchedProperty = sanitizedLine.search(/(^\\w+:)/)\r\n if (matchedProperty < 0) return sanitizedLine\r\n\r\n return sanitizedLine.replace(field, `\"${field}\"`)\r\n }\r\n\r\n private configFinancialInstitutionTransactionId(fitString: string) {\r\n const { fitId } = this.config\r\n if (fitId === 'separated')\r\n return extractFinancialInstitutionTransactionId(fitString)\r\n return `\"${fitString}\",`\r\n }\r\n\r\n private configDate(dateString: string) {\r\n const { formatDate: format } = this.config\r\n if (format) return formatDate(dateString, format)\r\n return formatDate(dateString, 'y-M-d')\r\n }\r\n\r\n getTransactionsSummary() {\r\n const jsonData = this.getContent()\r\n const { DTEND, DTSTART, STRTTRN } =\r\n jsonData.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST\r\n const summary = getTransactionsSummary(STRTTRN)\r\n return {\r\n dateStart: DTSTART,\r\n dateEnd: DTEND,\r\n ...summary,\r\n }\r\n }\r\n\r\n getContent(): OfxStructure {\r\n const ofxText = this.getPartialJsonData()\r\n const { newListText, oldListText } = getBankTransferListText(ofxText)\r\n const result = ofxText.replace(oldListText, newListText)\r\n return JSON.parse(`{${fixJsonProblems(result)}}`)\r\n }\r\n\r\n toJson(): OfxResponse {\r\n const ofxMetaDataResult = this.getHeaders()\r\n const ofxContentResult = this.getContent()\r\n const result = { ...ofxMetaDataResult, ...ofxContentResult }\r\n return result\r\n }\r\n}\r\n"],"names":["ELEMENT_CLOSURE_REGEX","ELEMENT_OPENING_REGEX","START_TEXT_BANK_TRANSFER","END_TEXT_BANK_TRANSFER","separatePartsOfDate","date","year","month","day","hour","minutes","seconds","offset","timezone","formatDate","format","parts","result","key","value","fixJsonProblems","content","extractFinancialInstitutionTransactionId","fitid","dateText","transactionCode","protocol","resultObject","isDateField","field","trim","str","objectStartReplacer","param","objectEndReplacer","isValidNumberToConvert","getBankTransferListText","ofxContent","startIndex","endIndex","oldListText","startRgx","endRgx","newListText","convertMetaDataToObject","stringList","nativeTypes","line","sanitizedKey","getTransactionsSummary","STRTTRN","prevValue","currValue","Ofx","data","config","metaDataString","metaDataList","validate","validatedMetaDataList","list","fixedList","_","ofxContentText","sanitize","fieldValue","sanitizedLine","sanitizeValue","replacer","matched","fitString","fitId","dateString","jsonData","DTEND","DTSTART","summary","ofxText","ofxMetaDataResult","ofxContentResult"],"mappings":"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"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /// <reference types="node" />
2
+ import { BankTransferList, OfxConfig, OFXMetaData, OfxResponse, OfxStructure } from './types';
3
+ export declare class Ofx {
4
+ private data;
5
+ private config;
6
+ constructor(data: string | Buffer, config?: OfxConfig);
7
+ getHeaders(): OFXMetaData;
8
+ getBankTransferList(): Pick<BankTransferList, 'STRTTRN'>;
9
+ private getPartialJsonData;
10
+ private sanitizeValue;
11
+ private sanitize;
12
+ private configFinancialInstitutionTransactionId;
13
+ private configDate;
14
+ getTransactionsSummary(): {
15
+ credit: number;
16
+ debit: number;
17
+ amountOfCredits: number;
18
+ amountOfDebits: number;
19
+ dateStart: import("./types").DateResponse;
20
+ dateEnd: import("./types").DateResponse;
21
+ };
22
+ getContent(): OfxStructure;
23
+ toJson(): OfxResponse;
24
+ }
@@ -0,0 +1,110 @@
1
+ export type OFXMetaData = {
2
+ OFXHEADER: string;
3
+ DATA: string;
4
+ VERSION: string;
5
+ SECURITY: string;
6
+ ENCODING: string;
7
+ CHARSET: string;
8
+ COMPRESSION: string;
9
+ OLDFILEUID: string;
10
+ NEWFILEUID: string;
11
+ };
12
+ export type DateResponse = {
13
+ datetime: string | null;
14
+ date: string | null;
15
+ time: string | null;
16
+ offset: string | null;
17
+ timezone: string | null;
18
+ };
19
+ /**
20
+ * separated - returns the separate transaction id:
21
+ * "date": string,
22
+ * "transactionCode": string,
23
+ * "protocol": string
24
+ */
25
+ type ConfigFitId = 'normal' | 'separated';
26
+ export type ConfigDate = {
27
+ /**
28
+ * @description supported keys:
29
+ * yy => year -> 2 digits,
30
+ * yyyy or y => year,
31
+ * MM or M => month,
32
+ * dd or d => day,
33
+ * hh or h => hour,
34
+ * mm or m => minute,
35
+ * ss or s => second,
36
+ * O => offset,
37
+ * TZ => timezone
38
+ * @example format: 'y-M-d h:m:s'
39
+ * @returns '2022-02-21 09:00:00'
40
+ */
41
+ formatDate?: string;
42
+ };
43
+ type MapKeys<T> = {
44
+ [Property in keyof T]?: string;
45
+ };
46
+ type KeysJson = MapKeys<Status | BankAccountFrom | STRTTRN | BankTransferList | LedGerBal | FINANCIAL_INSTITUTION | OfxStructure>;
47
+ export type OfxConfig = ConfigDate & {
48
+ fitId?: ConfigFitId;
49
+ nativeTypes?: boolean;
50
+ formatJson?: MapKeys<KeysJson>;
51
+ };
52
+ export type Status = {
53
+ CODE: string;
54
+ SEVERITY: string;
55
+ };
56
+ export type BankAccountFrom = {
57
+ BANKID: string;
58
+ ACCTID: string;
59
+ ACCTT: string;
60
+ };
61
+ type TransferType = string;
62
+ export type STRTTRN = {
63
+ TRNTYPE: TransferType;
64
+ DTPOSTED: DateResponse;
65
+ TRNAMT: string;
66
+ FITID: string;
67
+ CHECKNUM: string;
68
+ MEMO: string;
69
+ };
70
+ export type BankTransferList = {
71
+ DTSTART: DateResponse;
72
+ DTEND: DateResponse;
73
+ STRTTRN: STRTTRN[];
74
+ };
75
+ export type LedGerBal = {
76
+ BALAMT: string;
77
+ DTASOF: DateResponse;
78
+ };
79
+ export type FINANCIAL_INSTITUTION = {
80
+ ORG: string;
81
+ FID: string;
82
+ };
83
+ export type OfxStructure = {
84
+ OFX: {
85
+ SIGNONMSGSRSV1: {
86
+ SONRS: {
87
+ STATUS: Status;
88
+ DTSERVER: DateResponse;
89
+ LANGUAGE: string;
90
+ DTACCTUP: DateResponse;
91
+ FI: FINANCIAL_INSTITUTION;
92
+ };
93
+ };
94
+ BANKMSGSRSV1: {
95
+ STMTTRNRS: {
96
+ TRNUID: number;
97
+ STATUS: Status;
98
+ STMTRS: {
99
+ CURDEF: string;
100
+ BANKACCTFROM: BankAccountFrom;
101
+ BANKTRANLIST: BankTransferList;
102
+ LEDGERBAL: LedGerBal;
103
+ MKTGINFO: string;
104
+ };
105
+ };
106
+ };
107
+ };
108
+ };
109
+ export type OfxResponse = OFXMetaData & OfxStructure;
110
+ export {};
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "ofx-data-extractor",
3
+ "version": "1.0.8",
4
+ "keywords": [
5
+ "ofx",
6
+ "financial",
7
+ "ofx-js",
8
+ "ofx-ts",
9
+ "banking",
10
+ "parser",
11
+ "data-extraction",
12
+ "typescript",
13
+ "utility",
14
+ "ofx-file",
15
+ "data-formatting"
16
+ ],
17
+ "author": "Fábio Pereira França",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/Fabiopf02/ofx-ts.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/Fabiopf02/ofx-ts/issues"
24
+ },
25
+ "license": "ISC",
26
+ "description": "",
27
+ "main": "dist/index.js",
28
+ "module": "dist/index.mjs",
29
+ "typings": "dist/index.d.ts",
30
+ "files": [
31
+ "dist/**/*"
32
+ ],
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js",
37
+ "require": "./dist/index.esm.js"
38
+ }
39
+ },
40
+ "scripts": {
41
+ "test": "node tests/index.js",
42
+ "build": "rollup --config",
43
+ "start": "node dist/index.js",
44
+ "format": "prettier --write \"src/**/*.ts\"",
45
+ "lint": "tslint -p tsconfig.json"
46
+ },
47
+ "devDependencies": {
48
+ "@rollup/plugin-typescript": "^10.0.1",
49
+ "@types/jest": "^29.2.3",
50
+ "@types/node": "^18.11.10",
51
+ "esbuild": "^0.15.16",
52
+ "jest": "^29.3.1",
53
+ "prettier": "^2.8.0",
54
+ "rollup": "^3.5.1",
55
+ "rollup-plugin-esbuild": "^5.0.0",
56
+ "ts-jest": "^29.0.3",
57
+ "tslint": "^6.1.3",
58
+ "tslint-config-prettier": "^1.18.0",
59
+ "typescript": "^4.9.3"
60
+ }
61
+ }