Files

163 lines
5.9 KiB
JavaScript
Executable File

'use strict';
const XLSX = require('xlsx');
const extend = require('node.extend');
const excelToJson = (function() {
let _config = {};
const getCellRow = cell => Number(cell.replace(/[A-z]/gi, ''));
const getCellColumn = cell => cell.replace(/[0-9]/g, '').toUpperCase();
const getRangeBegin = cell => cell.match(/^[^:]*/)[0];
const getRangeEnd = cell => cell.match(/[^:]*$/)[0];
function getSheetCellValue(sheetCell) {
if (!sheetCell) {
return undefined;
}
if (sheetCell.t === 'z' && _config.sheetStubs) {
return null;
}
return (sheetCell.t === 'n' || sheetCell.t === 'd') ? sheetCell.v : (sheetCell.w && sheetCell.w.trim && sheetCell.w.trim()) || sheetCell.w;
};
const parseSheet = (sheetData, workbook) => {
const sheetName = (sheetData.constructor == String) ? sheetData : sheetData.name;
const sheet = workbook.Sheets[sheetName];
const columnToKey = sheetData.columnToKey || _config.columnToKey;
const range = sheetData.range || _config.range;
const headerRows = (sheetData.header && sheetData.header.rows) || (_config.header && _config.header.rows);
const headerRowToKeys = (sheetData.header && sheetData.header.rowToKeys) || (_config.header && _config.header.rowToKeys);
let strictRangeColumns;
let strictRangeRows;
if (range) {
strictRangeColumns = {
from: getCellColumn(getRangeBegin(range)),
to: getCellColumn(getRangeEnd(range))
};
strictRangeRows = {
from: getCellRow(getRangeBegin(range)),
to: getCellRow(getRangeEnd(range))
};
}
let rows = [];
for (let cell in sheet) {
// !ref is not a data to be retrieved || this cell doesn't have a value
if (cell == '!ref' || (sheet[cell].v === undefined && !(_config.sheetStubs && sheet[cell].t === 'z'))) {
continue;
}
const row = getCellRow(cell);
const column = getCellColumn(cell);
// Is a Header row
if (headerRows && row <= headerRows) {
continue;
}
// This column is not _configured to be retrieved
if (columnToKey && !(columnToKey[column] || columnToKey['*'])) {
continue;
}
// This cell is out of the _configured range
if ((strictRangeColumns && strictRangeRows) && (column < strictRangeColumns.from || column > strictRangeColumns.to || row < strictRangeRows.from || row > strictRangeRows.to)) {
continue;
}
const rowData = rows[row] = rows[row] || {};
let columnData = (columnToKey && (columnToKey[column] || columnToKey['*'])) ?
columnToKey[column] || columnToKey['*'] :
(headerRowToKeys) ?
`{{${column}${headerRowToKeys}}}` :
column;
let dataVariables = columnData.match(/{{([^}}]+)}}/g);
if (dataVariables) {
dataVariables.forEach(dataVariable => {
let dataVariableRef = dataVariable.replace(/[\{\}]*/gi, '');
let variableValue;
switch (dataVariableRef) {
case 'columnHeader':
dataVariableRef = (headerRows) ? `${column}${headerRows}` : `${column + 1}`;
default:
variableValue = getSheetCellValue(sheet[dataVariableRef]);
}
columnData = columnData.replace(dataVariable, variableValue);
});
}
if (columnData === '') {
continue;
}
rowData[columnData] = getSheetCellValue(sheet[cell]);
if (sheetData.appendData) {
extend(true, rowData, sheetData.appendData);
}
}
// removing first row i.e. 0th rows because first cell itself starts from A1
rows.shift();
// Cleaning empty if required
if (!_config.includeEmptyLines) {
rows = rows.filter(v => v !== null && v !== undefined);
}
return rows;
};
const convertExcelToJson = function(config = {}, sourceFile) {
_config = config.constructor === String ? JSON.parse(config) : config;
_config.sourceFile = _config.sourceFile || sourceFile;
// ignoring empty lines by default
_config.includeEmptyLines = _config.includeEmptyLines || false;
// at least sourceFile or source has to be defined and have a value
if (!(_config.sourceFile || _config.source)) {
throw new Error(':: \'sourceFile\' or \'source\' required for _config :: ');
}
let workbook = {};
if (_config.source) {
workbook = XLSX.read(_config.source, {
sheetStubs: true,
cellDates: true
});
} else {
workbook = XLSX.readFile(_config.sourceFile, {
sheetStubs: true,
cellDates: true
});
}
let sheetsToGet = (_config.sheets && _config.sheets.constructor === Array) ?
_config.sheets :
Object.keys(workbook.Sheets).slice(0, (_config && _config.sheets && _config.sheets.numberOfSheetsToGet) || undefined);
let parsedData = {};
sheetsToGet.forEach(sheet => {
sheet = (sheet.constructor == String) ? {
name: sheet
} : sheet;
parsedData[sheet.name] = parseSheet(sheet, workbook);
});
return parsedData;
};
return convertExcelToJson;
}());
module.exports = excelToJson;