forked from LucasBremm/node-ofx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathofx.js
110 lines (92 loc) · 2.55 KB
/
ofx.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
const { XMLParser } = require("fast-xml-parser");
const options = {
ignoreAttributes: true,
allowBooleanAttributes: false,
parseAttributeValue: false,
trimValues: true,
numberParseOptions: {
skipLike: /.*/, // Parsee all numbers as strings
},
};
const parser = new XMLParser(options);
function sgml2Xml(sgml) {
return 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-Z0-9_]*)+\.+([A-Z0-9_]*)>([^<]+)/g, "<$1$2>$3")
.replace(/<(\w+?)>([^<]+)/g, "<$1>$2</$1>");
}
// Preparing data fixing issues with special characters
function prepareData(content) {
return content.replace(/&/g, "&amp;");
}
function parse(data) {
// firstly, split into the header attributes and the footer sgml
const ofx = data.split("<OFX>", 2);
// firstly, parse the headers
const headerString = ofx[0].split(/\r?\n/);
const header = {};
headerString.forEach((attrs) => {
const headAttr = attrs.split(/:/, 2);
header[headAttr[0]] = headAttr[1];
});
// make the SGML and the XML
const content = `<OFX>${ofx[1]}`;
// Parse the XML/SGML portion of the file into an object
// Try as SGML->XML mangling first since fast-xml-parser doesn't error on missing closing tags,
// If that fails try normal XML
let dataParsed = null;
try {
dataParsed = parser.parse(prepareData(sgml2Xml(content)));
} catch (e) {
dataParsed = parser.parse(prepareData(content));
}
// put the headers into the returned data
dataParsed.header = header;
return dataParsed;
}
function serialize(header, body) {
let out = "";
// header order could matter
const headers = [
"OFXHEADER",
"DATA",
"VERSION",
"SECURITY",
"ENCODING",
"CHARSET",
"COMPRESSION",
"OLDFILEUID",
"NEWFILEUID",
];
headers.forEach((name) => {
out += `${name}:${header[name]}\n`;
});
out += "\n";
out += objToOfx({ OFX: body });
return out;
}
const objToOfx = (obj) => {
let out = "";
Object.keys(obj).forEach((name) => {
const item = obj[name];
const start = `<${name}>`;
const end = `</${name}>`;
if (item instanceof Object) {
if (item instanceof Array) {
item.forEach((it) => {
out += `${start}\n${objToOfx(it)}${end}\n`;
});
return;
}
return (out += `${start}\n${objToOfx(item)}${end}\n`);
}
out += start + item + "\n";
});
return out;
};
module.exports = {
parse,
serialize,
};