qif-ts
Version:
Typescript library to map QIF formatted data
167 lines (166 loc) • 5.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.deserializeQif = void 0;
const types_1 = require("./types");
/**
* Deserializes a valid QIF formatted string.
*
* @param data - The string to be deserialized
* @returns A QifData object describing the data in the input
*
* @public
*/
function deserializeQif(data) {
const dataLines = data.split('\n').map((l) => l.trim()).filter(l => l !== '');
if (dataLines.length === 0) {
throw new types_1.QifParserError('No valid QIF content found.');
}
const type = types_1.QIF_TYPE_STRINGS_MAP[dataLines[0]];
dataLines.shift();
switch (type) {
case types_1.QifType.Investment:
return parseInvestmentFile(dataLines);
case types_1.QifType.Bank:
case types_1.QifType.Cash:
case types_1.QifType.Card:
case types_1.QifType.Liability:
case types_1.QifType.Asset:
return parseNonInvestmentFile(dataLines, type);
default:
throw new types_1.QifParserError('Qif File Type not supported: ' + type);
}
}
exports.deserializeQif = deserializeQif;
function parseNonInvestmentFile(dataLines, type) {
const qifData = {
type,
transactions: []
};
let transaction = {};
let parsingSplit = false;
let currentSplit = {};
for (const line of dataLines) {
const lineText = line.substring(1);
// handle Splits
if (parsingSplit === true) {
switch (line[0]) {
case 'E':
currentSplit.memo = lineText;
continue;
case '$':
currentSplit.amount = parseFloat(lineText);
continue;
case '%':
currentSplit.percent = parseFloat(lineText);
continue;
case 'S':
transaction.splits = transaction.splits || [];
transaction.splits.push(currentSplit);
currentSplit = {};
currentSplit.category = lineText;
continue;
}
if (Object.keys(currentSplit).length > 0) {
transaction.splits = transaction.splits || [];
transaction.splits.push(currentSplit);
currentSplit = {};
}
parsingSplit = false;
}
switch (line[0]) {
case 'D':
transaction.date = lineText;
break;
case 'T':
transaction.amount = parseFloat(lineText);
break;
case 'C':
transaction.clearedStatus = lineText;
break;
case 'N':
transaction.reference = lineText;
break;
case 'P':
transaction.payee = lineText;
break;
case 'M':
transaction.memo = lineText;
break;
case 'A':
transaction.address = transaction.address || [];
transaction.address.push(lineText);
break;
case 'L':
transaction.category = lineText;
case 'S': // Split
parsingSplit = true;
currentSplit.category = lineText;
break;
case '^':
if (Object.keys(transaction).length > 0) {
qifData.transactions.push(transaction);
transaction = {};
}
break;
default:
throw new types_1.QifParserError('Did not recognise detail item for line: ' + line);
}
}
return qifData;
}
function parseInvestmentFile(dataLines) {
const qifData = {
type: types_1.QifType.Investment,
transactions: []
};
let transaction = {};
for (const line of dataLines) {
const lineText = line.substring(1);
switch (line[0]) {
case 'D':
transaction.date = lineText;
break;
case 'N':
transaction.investmentAction = lineText;
break;
case 'Y':
transaction.investmentSecurity = lineText;
break;
case 'I':
transaction.investmentPrice = parseFloat(lineText);
break;
case 'Q':
transaction.investmentQuantity = parseFloat(lineText);
break;
case 'T':
transaction.amount = parseFloat(lineText);
break;
case 'C':
transaction.clearedStatus = lineText;
break;
case 'P':
transaction.investmentReminder = lineText;
break;
case 'M':
transaction.memo = lineText;
break;
case 'O':
transaction.investmentComission = parseFloat(lineText);
break;
case 'L':
transaction.investmentAccount = lineText;
break;
case '$':
transaction.investmentAmountTransferred = parseFloat(lineText);
case '^':
if (Object.keys(transaction).length > 0) {
qifData.transactions.push(transaction);
transaction = {};
}
break;
default:
throw new types_1.QifParserError('Did not recognise detail item for line: ' + line);
}
}
return qifData;
}