From 9921a8f70b07e9df3f0573c6256e534311509804 Mon Sep 17 00:00:00 2001
From: Braden MacDonald <mail@bradenm.com>
Date: Sat, 30 Dec 2023 18:52:46 -0800
Subject: [PATCH 1/4] fix parsing bug where SGML has _some_ closing tags
 present

---
 ofx.js                 |   3 +-
 test/data/example2.ofx | 310 +++++++++++++++++++++++++++++++++++++++++
 test/parse.js          |  19 +++
 3 files changed, 331 insertions(+), 1 deletion(-)
 create mode 100644 test/data/example2.ofx

diff --git a/ofx.js b/ofx.js
index 705baf5..dfc2870 100644
--- a/ofx.js
+++ b/ofx.js
@@ -5,8 +5,9 @@ function sgml2Xml(sgml) {
         .replace(/>\s+</g, '><')    // remove whitespace inbetween tag close/open
         .replace(/\s+</g, '<')      // remove whitespace before a close tag
         .replace(/>\s+/g, '>')      // remove whitespace after a close tag
+        .replace(/<([A-Za-z0-9_]+)>([^<]+)<\/\1>/g, '<\$1>\$2') // remove closing tags if present. Example: <FOO>bar</FOO> becomes <FOO>bar for consistency, fixed in last step below.
         .replace(/<([A-Z0-9_]*)+\.+([A-Z0-9_]*)>([^<]+)/g, '<\$1\$2>\$3' )
-        .replace(/<(\w+?)>([^<]+)/g, '<\$1>\$2</\$1>');
+        .replace(/<(\w+?)>([^<]+)/g, '<\$1>\$2</\$1>'); // Add closing tag wherever they seem to be missing: <FOO>bar becomes <FOO>bar</FOO>
 }
 
 /**
diff --git a/test/data/example2.ofx b/test/data/example2.ofx
new file mode 100644
index 0000000..1fac492
--- /dev/null
+++ b/test/data/example2.ofx
@@ -0,0 +1,310 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:102
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+<OFX>
+<SIGNONMSGSRSV1>
+<SONRS>
+<STATUS>
+<CODE>0
+<SEVERITY>INFO
+</STATUS>
+<DTSERVER>*******
+<LANGUAGE>FRA
+<DTPROFUP>******
+<DTACCTUP>******
+</SONRS>
+</SIGNONMSGSRSV1>
+<BANKMSGSRSV1>
+<STMTTRNRS>
+<TRNUID>******
+<STATUS>
+<CODE>0
+<SEVERITY>INFO
+</STATUS>
+<STMTRS>
+<CURDEF>EUR
+<BANKACCTFROM>
+<BANKID>*****</BANKID>
+<BRANCHID>*****</BRANCHID>
+<ACCTID>*****</ACCTID>
+<ACCTTYPE>CHECKING</ACCTTYPE>
+</BANKACCTFROM>
+<BANKTRANLIST>
+<DTSTART>****
+<DTEND>****
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-45.54
+<FITID>******
+<CHECKNUM>*****
+<NAME>FRAIS DE TUTELLE
+<MEMO>*******
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>******
+<TRNAMT>-90.00
+<FITID>*****
+<CHECKNUM>****
+<NAME>ACHAT PRODUITS HYGIENE
+<MEMO>******
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-78.73
+<FITID>*****
+<CHECKNUM>*****
+<NAME>APIVIA COURTAGE
+<MEMO>********
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>*****
+<TRNAMT>+721.01
+<FITID>*****
+<CHECKNUM>*****
+<NAME>EURO VIR CARSAT LANGUEDOC ROUSSI
+<MEMO>******
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>****
+<TRNAMT>+130.83
+<FITID>******
+<CHECKNUM>*****
+<NAME>EURO VIR CARSAT TI LR PREST
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>*****
+<TRNAMT>+247.28
+<FITID>****
+<CHECKNUM>******
+<NAME>EURO VIR CAF GARD
+<MEMO>******
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-37.00
+<FITID>*****
+<CHECKNUM>*****
+<NAME>DIRECTION GENERALE DES
+<MEMO>******
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-122.00
+<FITID>****
+<CHECKNUM>*****
+<NAME>CHEQUE
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>***
+<TRNAMT>-448.00
+<FITID>****
+<CHECKNUM>***
+<NAME>DIRECTION GENERALE DES
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>***
+<TRNAMT>-2199.50
+<FITID>****
+<CHECKNUM>*****
+<NAME>EHPAD 092023
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-3.00
+<FITID>****
+<CHECKNUM>****
+<NAME>COTISATIONS BANCAIRES
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>*****
+<TRNAMT>-21.41
+<FITID>*****
+<CHECKNUM>***
+<NAME>DDFIP GARD
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>***
+<TRNAMT>-44.50
+<FITID>****
+<CHECKNUM>****
+<NAME>COTISATIONS BANCAIRES
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>****
+<TRNAMT>+23947.61
+<FITID>****
+<CHECKNUM>****
+<NAME>VIR
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-45.54
+<FITID>****
+<CHECKNUM>****
+<NAME>FRAIS DE TUTELLE
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-122.00
+<FITID>****
+<CHECKNUM>*****
+<NAME>CHEQUE
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>*****
+<TRNAMT>-78.73
+<FITID>*****
+<CHECKNUM>****
+<NAME>APIVIA COURTAGE
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>****
+<TRNAMT>+721.01
+<FITID>*****
+<CHECKNUM>****
+<NAME>EURO VIR CARSAT LANGUEDOC ROUSSI
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>*****
+<TRNAMT>+130.83
+<FITID>****
+<CHECKNUM>*****
+<NAME>EURO VIR CARSAT TI LR PREST
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>*****
+<TRNAMT>+242.28
+<FITID>*****
+<CHECKNUM>*****
+<NAME>EURO VIR CAF GARD
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-3.00
+<FITID>****
+<CHECKNUM>*****
+<NAME>COTISATIONS BANCAIRES
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-2267.65
+<FITID>****
+<CHECKNUM>****
+<NAME>****
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>*****
+<TRNAMT>-78.73
+<FITID>****
+<CHECKNUM>****
+<NAME>****
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>***
+<TRNAMT>+637.88
+<FITID>****
+<CHECKNUM>****
+<NAME>EURO VIR CARSAT LANGUEDOC ROUSSI
+<MEMO>EURO ****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>****
+<TRNAMT>+130.83
+<FITID>****
+<CHECKNUM>****
+<NAME>EURO VIR CARSAT TI LR PREST
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>CREDIT
+<DTPOSTED>***
+<TRNAMT>+242.28
+<FITID>****
+<CHECKNUM>*****
+<NAME>EURO VIR CAF GARD
+<MEMO>*****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>***
+<TRNAMT>-45.54
+<FITID>****
+<CHECKNUM>****
+<NAME>FRAIS DE TUTELLE
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>****
+<TRNAMT>-3.00
+<FITID>***
+<CHECKNUM>****
+<NAME>COTISATIONS BANCAIRES
+<MEMO>****
+</STMTTRN>
+<STMTTRN>
+<TRNTYPE>DEBIT
+<DTPOSTED>***
+<TRNAMT>-122.00
+<FITID>***
+<CHECKNUM>****
+<NAME>SNC L ESCALE 30ST PRIVAT DES
+<MEMO>*****
+</STMTTRN>
+</BANKTRANLIST>
+<LEDGERBAL>
+<BALAMT>+23757.44
+<DTASOF>****
+</LEDGERBAL>
+</STMTRS>
+</STMTTRNRS>
+</BANKMSGSRSV1>
+</OFX>
\ No newline at end of file
diff --git a/test/parse.js b/test/parse.js
index 5750b51..f4e928f 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -23,6 +23,25 @@ test('parse', t => {
     });
 });
 
+test('parse 2', t => {
+    const file = fs.readFileSync(__dirname + '/data/example2.ofx', 'utf8');
+    ofx.parse(file).then(data => {
+        // headers
+        t.equal(data.header.OFXHEADER, '100');
+        t.equal(data.header.ENCODING, 'USASCII');
+
+        var transactions = data.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST.STMTTRN;
+        t.equal(transactions.length, 29);
+        t.equal(transactions[0].TRNAMT, "-45.54");
+
+        var status = data.OFX.SIGNONMSGSRSV1.SONRS.STATUS;
+        t.equal(status.CODE, '0');
+        t.equal(status.SEVERITY, 'INFO');
+
+        t.end();
+    });
+});
+
 test('parse XML', t => {
     const file = fs.readFileSync(__dirname + '/data/example-xml.qfx', 'utf8');
     ofx.parse(file).then(data => {

From dbde009d6a1506b6c8b51726664c34d34e5b9523 Mon Sep 17 00:00:00 2001
From: Braden MacDonald <mail@bradenm.com>
Date: Sat, 30 Dec 2023 18:52:56 -0800
Subject: [PATCH 2/4] Version bump: xml2js

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index dd16e2b..6c9f2fc 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
     "tape": "^4.6.3"
   },
   "dependencies": {
-    "xml2js": "^0.4.19"
+    "xml2js": "^0.6.2"
   },
   "main": "./ofx.js",
   "directories": {},

From 17d53428dd01bbb0fd35f0d7f8f4a422fcb2de59 Mon Sep 17 00:00:00 2001
From: Braden MacDonald <mail@bradenm.com>
Date: Sat, 30 Dec 2023 18:59:55 -0800
Subject: [PATCH 3/4] Run tests using GitHub Actions, not CircleCI

---
 .circleci/config.yml          | 14 --------------
 .github/workflows/ci-test.yml | 20 ++++++++++++++++++++
 2 files changed, 20 insertions(+), 14 deletions(-)
 delete mode 100644 .circleci/config.yml
 create mode 100644 .github/workflows/ci-test.yml

diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index c2dd773..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-version: 2
-jobs:
-  build:
-    docker:
-      - image: node:7.4.0
-    working_directory: ~/ofx-js
-    steps:
-      - checkout
-      - run:
-          name: Install Dependencies
-          command: npm install
-      - run:
-          name: NPM Test
-          command: npm test
diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml
new file mode 100644
index 0000000..06c952c
--- /dev/null
+++ b/.github/workflows/ci-test.yml
@@ -0,0 +1,20 @@
+name: Run tests (Node.js)
+
+on: [push]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        node-version: ['14.x', '16.x', '18.x']
+
+    steps:
+      - uses: actions/checkout@v4
+      - name: Use Node.js ${{ matrix.node-version }}
+        uses: actions/setup-node@v3
+        with:
+          node-version: ${{ matrix.node-version }}
+      - run: npm install
+      - run: npm test

From 868468e64023141e141a45ada69e9aba0d953468 Mon Sep 17 00:00:00 2001
From: Braden MacDonald <mail@bradenm.com>
Date: Sat, 30 Dec 2023 19:05:29 -0800
Subject: [PATCH 4/4] Version bump

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 6c9f2fc..e5ecf91 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "ofx-js",
   "description": "Parse OFX files using pure JavaScript.",
-  "version": "0.1.1",
+  "version": "0.2.0",
   "homepage": "https://github.com/bradenmacdonald/ofx-js",
   "contributors": [
     {