|
/* Adapted by Jason Schwarzenberger |
|
* for Typescript from |
|
* qif2json |
|
* https://github.com/spmason/qif2json |
|
* |
|
* Copyright (c) 2012 Steve Mason |
|
* Licensed under the MIT license. |
|
*/ |
|
|
|
function parseDate(str: string, format: string) { |
|
const [day, month, year]: any[] = str.replace(' ', '').split(/[^0-9]/); |
|
const output: { |
|
year: number; |
|
month: string; |
|
day: string; |
|
} = { year: 0, month: '00', day: '00' }; |
|
const yearNow = new Date().getFullYear(); |
|
const yearInt = parseInt(year, 10); |
|
const year1900 = 1900 + yearInt; |
|
const year2000 = 2000 + yearInt; |
|
|
|
output.day = day.length < 2 ? `0${day}` : day; |
|
output.month = month.length < 2 ? `0${month}` : day; |
|
output.year = year; |
|
|
|
if (year.length <= 2) { |
|
output.year = year2000 > yearNow ? year1900 : year2000; |
|
} |
|
|
|
if (format === 'us') { |
|
return `${output.year}-${output.day}-${output.month}`; |
|
} |
|
return `${output.year}-${output.month}-${output.day}`; |
|
} |
|
|
|
export interface QifOptions { |
|
dateFormat?: string; |
|
ignoreType?: boolean; |
|
} |
|
|
|
export interface Qif { |
|
transactions: Transaction[]; |
|
type: string; |
|
} |
|
|
|
export interface Division { |
|
amount: number; |
|
category: string; |
|
description: string; |
|
subcategory: string; |
|
} |
|
|
|
export interface Transaction { |
|
date: string; |
|
amount: number; |
|
number: string; |
|
memo: string; |
|
address: string[]; |
|
payee: string; |
|
category: string; |
|
subcategory: string; |
|
clearedStatus: string; |
|
division: Division[]; |
|
[key: string]: any; |
|
} |
|
|
|
export const parser = (qif: string, options: QifOptions = <QifOptions>{ ignoreType: false }): Qif => { |
|
const lines = qif.split('\n'); |
|
let line = lines.shift(); |
|
let transaction: Transaction = <Transaction>{}; |
|
let division: Division = <Division>{}; |
|
const typeArray = /!Type:([^$]*)$/.exec(line!.trim()) || []; |
|
|
|
if (!typeArray || !typeArray.length) { |
|
if (!options.ignoreType) { |
|
throw new Error('File does not appear to be a valid qif file: ' + line); |
|
} |
|
typeArray[1] = line!.trim(); |
|
} |
|
|
|
const type = typeArray[1]; |
|
const transactions: Transaction[] = []; |
|
|
|
// tslint:disable-next-line: no-conditional-assignment |
|
while ((line = lines.shift())) { |
|
line = line.trim(); |
|
if (line === '^') { |
|
transactions.push(transaction); |
|
transaction = <Transaction>{}; |
|
continue; |
|
} |
|
switch (line[0]) { |
|
case 'D': |
|
transaction.date = parseDate(line.substring(1), options.dateFormat || ''); |
|
break; |
|
case 'T': |
|
transaction.amount = parseFloat(line.substring(1).replace(',', '')); |
|
break; |
|
case 'N': |
|
transaction.number = line.substring(1); |
|
break; |
|
case 'M': |
|
transaction.memo = line.substring(1); |
|
break; |
|
case 'A': |
|
transaction.address = (transaction.address || []).concat(line.substring(1)); |
|
break; |
|
case 'P': |
|
transaction.payee = line.substring(1).replace(/&/g, '&'); |
|
break; |
|
case 'L': |
|
const lArray = line.substring(1).split(':'); |
|
transaction.category = lArray[0]; |
|
if (lArray[1] !== undefined) { |
|
transaction.subcategory = lArray[1]; |
|
} |
|
break; |
|
case 'C': |
|
transaction.clearedStatus = line.substring(1); |
|
break; |
|
case 'S': |
|
const sArray = line.substring(1).split(':'); |
|
division.category = sArray[0]; |
|
if (sArray[1] !== undefined) { |
|
division.subcategory = sArray[1]; |
|
} |
|
break; |
|
case 'E': |
|
division.description = line.substring(1); |
|
break; |
|
case '$': |
|
division.amount = parseFloat(line.substring(1)); |
|
if (!(transaction.division instanceof Array)) { |
|
transaction.division = []; |
|
} |
|
transaction.division.push(division); |
|
division = <Division>{}; |
|
|
|
break; |
|
|
|
default: |
|
throw new Error('Unknown Detail Code: ' + line[0]); |
|
} |
|
} |
|
|
|
if (Object.keys(transaction).length) { |
|
transactions.push(transaction); |
|
} |
|
|
|
return <Qif>{ |
|
transactions, |
|
type |
|
}; |
|
}; |