RSS Git Download  Clone
Raw Blame History
const nodeExcel = require('excel-export')
const objectPath = require('object-path')

const transform = function (json, config) {
    const conf = transform.prepareJson(json, config)
    const result = nodeExcel.execute(conf)
    return result
}

// get a xls type based on js type
function getType (obj, type) {
    if (type) {
        return type
    }
    const t = typeof obj
    switch (t) {
        case 'string':
        case 'number':
            return t
        case 'boolean':
            return 'bool'
        default:
            return 'string'
    }
}

// get a nested property from a JSON object given its key, i.e 'a.b.c'
function getByString (object, path) {
    path = path.replace(/\[(\w+)\]/g, '.$1') // convert indexes to properties
    path = path.replace(/^\./, '') // strip a leading dot
    const defaultValue = object[path] || null
    return objectPath.get(object, path, defaultValue)
}

// prepare json to be in the correct format for excel-export
transform.prepareJson = function (json, config) {
    const res = {}
    const conf = config || {}
    const jsonArr = [].concat(json)
    let fields = conf.fields || Object.keys(jsonArr[0] || {})
    let types = []
    if (!(fields instanceof Array)) {
        types = Object.keys(fields).map(function (key) {
            return fields[key]
        })
        fields = Object.keys(fields)
    }
    // cols
    res.cols = fields.map(function (key, i) {
        return {
            caption: key,
            type: getType(jsonArr[0][key], types[i]),
            beforeCellWrite: function (row, cellData, eOpt) {
                eOpt.cellType = getType(cellData, types[i])
                return cellData
            }
        }
    })
    // rows
    res.rows = jsonArr.map(function (row) {
        return fields.map(function (key) {
            let value = getByString(row, key)
            // stringify objects
            if (value && value.constructor === Object) value = JSON.stringify(value)
            // replace illegal xml characters with a square
            // see http://www.w3.org/TR/xml/#charsets
            // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
            if (typeof value === 'string') {
                // eslint-disable-next-line no-control-regex
                value = value.replace(/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/g, '')
            }
            return value
        })
    })
    // add style xml if given
    if (conf.style) {
        res.stylesXmlFile = conf.style
    }
    return res
}

/*
transform.middleware = function (req, res, next) {
    res.xls = function (fn, data, config) {
        const xls = transform(data, config)
        res.setHeader('Content-Type', 'application/vnd.openxmlformats')
        res.setHeader('Content-Disposition', 'attachment filename=' + fn)
        res.end(xls, 'binary')
    }
    next()
}
 */

module.exports = transform