app.ts 4.28 KB
Newer Older
gustawdaniel's avatar
gustawdaniel committed
1 2 3
import fs from 'fs'
import chai from 'chai'

gustawdaniel's avatar
gustawdaniel committed
4 5 6 7 8 9 10 11 12 13 14 15
const dict: { [key: string]: string } = {
    'Szwajcaria': 'CHF'
}

interface YearData {
    [key: string]: {
        col: number,
        div: number,
        values: { [key: string]: number }[]
    }
}

16 17 18 19
const getDateFromArr = (arr: string[]) => {
    return getDate(arr[0]) || getDate(arr[1])
}

gustawdaniel's avatar
gustawdaniel committed
20
const getDate = (input: string) => {
gustawdaniel's avatar
gustawdaniel committed
21
    if (/^\d{2}\.\d{2}\.\d{4}/.test(input)) {
gustawdaniel's avatar
gustawdaniel committed
22 23
        return input.split('.').reverse().join('-')
    }
gustawdaniel's avatar
gustawdaniel committed
24 25 26 27
    if (/^\d{2}\/\d{2}\/\d{4}/.test(input)) {
        const [m, d, y] = input.split('/')
        return [y, m, d].join('-')
    }
gustawdaniel's avatar
gustawdaniel committed
28 29 30 31
    return false
}


gustawdaniel's avatar
gustawdaniel committed
32 33
const decomposeBaseSettingsFromNames = (localArr: string[]) => localArr.reduce((p: YearData, n: string, i: number): YearData => {
    if (Object.keys(dict).includes(n)) {
gustawdaniel's avatar
gustawdaniel committed
34
        p[dict[n]] = { col: i, div: NaN, values: [] }
gustawdaniel's avatar
gustawdaniel committed
35 36 37 38
    }
    return p
}, {})

39
const decomposeBaseSettingsFromCodes = (localArr: string[]) => localArr.reduce((p: YearData, n: string, i: number): YearData => {
gustawdaniel's avatar
gustawdaniel committed
40 41
    const [, div, curr] = n.match(/^(\d*)(\w+)$/) || []
    if (curr && Object.values(dict).includes(curr)) {
42 43 44 45 46
        p[curr] = { col: i, div: parseInt(div), values: [] }
    }
    return p
}, {})

gustawdaniel's avatar
gustawdaniel committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
const extendSettingsByDivCoefficient = (arr: string[][], settings: YearData) => {
    const subHead = arr.shift()
    if (!subHead) throw Error('File do not have sub-header line.')
    Object.keys(settings).forEach(key => {
        settings[key].div = parseInt(subHead[settings[key].col])
    })
}

const recognizeSettingsFromHead = (arr: string[][]):YearData => {
    const head = arr.shift()
    if (!head) throw Error('File do not have header line.')
    let settings: YearData = decomposeBaseSettingsFromNames(head)
    if (Object.keys(settings).length) {
        extendSettingsByDivCoefficient(arr, settings);
    } else {
        settings = decomposeBaseSettingsFromCodes(head);
        while (Object.keys(settings).some(key => Number.isNaN(settings[key].div))) {
            extendSettingsByDivCoefficient(arr, settings);
        }
    }

    return settings;
}

gustawdaniel's avatar
gustawdaniel committed
71 72 73 74
const FILES_FILTER = (e: string, i: number) => i < Infinity
const ROWS_FILTER = (e: string, i: number) => i <= Infinity

const DROP_SPACES = (l: string): string => l.replace(/\s+/g, '')
gustawdaniel's avatar
gustawdaniel committed
75
const DROP_JUNK_LINES = (l: string): string => l.replace(/(Nr)|(data)|(WALUTA\/CURRENCY)|(\.tab)/ig, '')
gustawdaniel's avatar
gustawdaniel committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
const DROP_EMPTY_LINES = (e:string) => !/^,*$/.test(e)

const testYearData = (r:YearData):void => {
    chai.expect(r).to.haveOwnProperty('CHF');
    chai.expect(r.CHF).to.haveOwnProperty('col');
    chai.expect(r.CHF).to.haveOwnProperty('div');
    chai.expect(r.CHF).to.haveOwnProperty('values');
    chai.expect(r.CHF.col).to.be.a('number');
    chai.expect(r.CHF.div).to.be.a('number');
    chai.expect(r.CHF.values).to.be.a('array');
    chai.expect(r.CHF.values.length).to.be.greaterThan(0);
    r.CHF.values.forEach(v => {
        chai.expect(Object.keys(v)[0]).to.be.a('string');
        chai.expect(/\d{4}-\d{2}-\d{2}/.test(Object.keys(v)[0])).to.be.true;
        chai.expect(Object.values(v)[0]).to.be.a('number');
        chai.expect(Object.values(v)[0]).to.be.greaterThan(0);
    })
};
gustawdaniel's avatar
gustawdaniel committed
94

gustawdaniel's avatar
gustawdaniel committed
95 96 97
const main = () => {
    const rawDir = process.cwd() + `/raw`

gustawdaniel's avatar
gustawdaniel committed
98
    return fs.readdirSync(rawDir).filter(f => f.endsWith('csv'))
gustawdaniel's avatar
gustawdaniel committed
99 100 101 102 103 104
        .filter(FILES_FILTER)
        .map((name, i) => {
            const arr = fs
                .readFileSync(`${rawDir}/${name}`)
                .toString()
                .split(`\n`)
gustawdaniel's avatar
gustawdaniel committed
105
                .map(DROP_SPACES)
gustawdaniel's avatar
gustawdaniel committed
106
                .map(DROP_JUNK_LINES)
gustawdaniel's avatar
gustawdaniel committed
107 108
                .filter(DROP_EMPTY_LINES)
                .filter(ROWS_FILTER)
gustawdaniel's avatar
gustawdaniel committed
109 110
                .map(l => l.split(','));

gustawdaniel's avatar
gustawdaniel committed
111
            console.table(arr.map(l => l));
gustawdaniel's avatar
gustawdaniel committed
112

gustawdaniel's avatar
gustawdaniel committed
113
            let settings: YearData = recognizeSettingsFromHead(arr);
gustawdaniel's avatar
gustawdaniel committed
114

gustawdaniel's avatar
gustawdaniel committed
115
            arr.forEach(localArr => {
116
                const date = getDateFromArr(localArr)
gustawdaniel's avatar
gustawdaniel committed
117 118 119 120 121 122
                if (typeof date === 'string') {
                    Object.keys(settings).forEach(key => {
                        settings[key].values.push({ [date]: parseFloat(localArr[settings[key].col]) / settings[key].div })
                    })
                }
            })
gustawdaniel's avatar
gustawdaniel committed
123 124 125
            console.dir(settings, {depth: Infinity});

            testYearData(settings);
gustawdaniel's avatar
gustawdaniel committed
126

gustawdaniel's avatar
gustawdaniel committed
127
            return settings;
gustawdaniel's avatar
gustawdaniel committed
128

gustawdaniel's avatar
gustawdaniel committed
129
        })
gustawdaniel's avatar
gustawdaniel committed
130 131
}

gustawdaniel's avatar
gustawdaniel committed
132
console.dir(main(), {depth: Infinity, maxArrayLength: Infinity})