UNPKG

exceljs-wrpper-to-excel-export

Version:

A simple Excel export utility using ExcelJS

331 lines (330 loc) 20.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.excelJsWrapperToExcelExport = void 0; var exceljs_1 = __importDefault(require("exceljs")); var constants_1 = require("./constants"); var validateConfig = function (config) { if (!config || !config.columns || config.columns.length === 0) { throw new Error("Invalid configuration: Columns are missing."); } return true; }; var sanitizeSheetName = function (name) { return name.replace(/[:\/\\\?\*\[\]]/g, "").slice(0, 31); }; var AdjustColumnWidth = function (worksheet, columnConfigs, maxColumnWidth) { worksheet.columns.forEach(function (column) { //const lengths = column.values.map((v: any) => v.toString().length); var lengths = column.values.map(function (v) { return v != null ? v.toString().length : 0; // Use 0 for null/undefined values }); var columnKey = column.key; var columnConfig = columnConfigs && columnConfigs.find(function (config) { return config.key === columnKey; }); var maxLength = Math.max.apply(Math, lengths.filter(function (v) { return typeof v === "number"; })) + 3; // Set column width based on columnConfig or defaultMaxColumnWidth var maxWidth = (columnConfig === null || columnConfig === void 0 ? void 0 : columnConfig.maxWidth) || maxColumnWidth; if (maxWidth) { column.width = maxLength > maxWidth ? maxWidth : maxLength + 3; } else { column.width = maxLength; } }); }; // Function to calculate row height based on the content length (text wrapping) var calculateRowHeight = function (rowValues, columns) { var maxLines = 1; // Default height for 1 line of text columns.forEach(function (col) { var _a, _b, _c; var cellValue = rowValues[col.key]; if (typeof cellValue === "string" && ((_b = (_a = col.style) === null || _a === void 0 ? void 0 : _a.alignment) === null || _b === void 0 ? void 0 : _b.wrapText)) { var wrappedLines = Math.ceil(cellValue.length / ((_c = col.width) !== null && _c !== void 0 ? _c : 10)); // Estimate the number of lines after wrapping maxLines = Math.max(maxLines, wrappedLines); // Adjust maxLines for the row } }); var lineHeight = 15; // Approximate height per line of text (in points) return maxLines * lineHeight; }; var convertToDate = function (dateString) { // Extract the timestamp from the string var timestamp; timestamp = dateString && dateString.includes("Date") ? parseInt(dateString.replace(/\/Date\((\d+)\)\//, "$1")) : dateString; // Create a new Date object from the timestamp return timestamp ? new Date(timestamp) : ""; }; // Function to group data by a specified key var groupBy = function (data, key) { return data.reduce(function (result, item) { (result[item[key]] = result[item[key]] || []).push(item); return result; }, {}); }; var excelJsWrapperToExcelExport = function (fileName, sheetConfigs) { return __awaiter(void 0, void 0, void 0, function () { var workbook_1, sheetIndex_1, defSheetName_1, buffer, blob, url, a, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); workbook_1 = new exceljs_1.default.Workbook(); sheetIndex_1 = 0; defSheetName_1 = ""; sheetConfigs.forEach(function (_a) { var name = _a.name, config = _a.config, data = _a.data, extraHeaders = _a.extraHeaders; sheetIndex_1++; defSheetName_1 = constants_1.constants.defaultSheetPrefix + sheetIndex_1; var currentRowIndex = 1; var sheetName = sanitizeSheetName(name ? name : defSheetName_1); // Validate configuration validateConfig(config); var worksheet = workbook_1.addWorksheet(sheetName); // *** Extra Headers Region *** // Add Extra Headers (if any) if (extraHeaders) { extraHeaders.forEach(function (extraHeader, rowIndex) { // Add the extra header row with empty values var row = worksheet.addRow([]); // Merge cells based on mergeAcross array if provided if (extraHeader.mergeAcross) { var currentCol_1 = 1; // Start from the first column //length of extraHeader.values should equals to extraHeader.mergeAcross.lenght extraHeader.mergeAcross.forEach(function (mergeCount, valueIndex) { var startCol = currentCol_1; var endCol = startCol + mergeCount - 1; // Set value in the starting column only var cell = worksheet.getCell(rowIndex + 1, startCol); cell.value = extraHeader.values[valueIndex]; // Merge the cells for the current value worksheet.mergeCells(rowIndex + 1, startCol, rowIndex + 1, endCol); // Move to the next column currentCol_1 = endCol + 1; }); } // Apply styles to the row if provided if (extraHeader.style) { row.eachCell(function (cell) { if (extraHeader.style) cell.style = extraHeader.style; }); } // Move to the next row for column headers currentRowIndex++; }); } // *** END Extra Headers Region *** // *** Set Column configurations Region *** // Add Column Headers worksheet.columns = config.columns.map(function (col) { return ({ // header: col.header, key: col.key, width: col.width || 15, style: col.style, }); }); // Add Column Headers explicitly (in case styles/extra formatting are needed) var headerRow = worksheet.getRow(currentRowIndex); config.columns.forEach(function (col, colIndex) { var cell = headerRow.getCell(colIndex + 1); cell.value = col.header; if (col.headerStyle) { cell.style = col.headerStyle; // Apply individual column header styles } }); // Move to the next row for data after headers currentRowIndex++; // *** END Set Column configurations Region *** // *** groupBy Region *** if (config.groupBy) { // Group the data by the specified key var groupedData_1 = groupBy(data, config.groupBy); // Add rows for each group and calculate group sums Object.keys(groupedData_1).forEach(function (groupKey) { var _a; // Insert group header row if (config.groupHeaderRow) { var groupHeaderRow = worksheet.addRow([ "".concat(config.groupBy, ": ").concat(groupKey), ]); groupHeaderRow.font = { bold: true }; } // Insert rows for the group data groupedData_1[groupKey].forEach(function (item) { var row = config.columns.reduce(function (acc, col) { acc[col.key] = item[col.key]; return acc; }, {}); worksheet.addRow(row); }); // Calculate and add the group total row var lastGroupRowNumber = ((_a = worksheet.lastRow) === null || _a === void 0 ? void 0 : _a.number) || 1; var groupSumRow = {}; config.columns.forEach(function (col, index) { if (col.sum) { var columnLetter = worksheet.getColumn(index + 1).letter; // Get Excel column letter (A, B, C) groupSumRow[col.key] = { formula: "SUM(".concat(columnLetter).concat(lastGroupRowNumber - groupedData_1[groupKey].length + 1, ":").concat(columnLetter).concat(lastGroupRowNumber, ")"), }; } else { groupSumRow[col.key] = ""; // No sum for this column } }); // Add the group sum row var newGroupSumRow = worksheet.addRow(groupSumRow); newGroupSumRow.font = { bold: true }; // Make the sum row bold for distinction // Apply style to group sum row if (config.groupSumRowStyle) { newGroupSumRow.eachCell(function (cell) { if (config.groupSumRowStyle) cell.style = config.groupSumRowStyle; }); } // Add a label "Total" in the first column of the sum row var groupTotalLableCell = config.groupTotalLableCell ? config.groupTotalLableCell : constants_1.constants.groupTotalLableCell; worksheet.getCell("".concat(groupTotalLableCell).concat(newGroupSumRow.number)).value = config.groupTotalLable ? config.groupTotalLable : constants_1.constants.groupTotalLable; }); // *** END groupBy Region *** } else { // *** Append Simple/Normal Data Region *** data.forEach(function (item, rowIndex) { var row = {}; config.columns.forEach(function (col, colIndex) { try { if (col.formula) { // Replace any placeholders in formula (e.g., {row}, {column}, etc.) var columnLetter = worksheet.getColumn(colIndex + 1).letter; // Get Excel column letter (A, B, C) var formula = col.formula .replace(/\{row\}/g, (rowIndex + currentRowIndex).toString()) // Replace {row} with actual row number .replace(/\{column\}/g, columnLetter); // Replace {column} with column letter // Assign the complex formula to the cell row[col.key] = { formula: formula }; } else if (col.type && col.type.toLowerCase() == "date") { var datevalue = convertToDate(item[col.key]); // Create a new Date object from the timestamp and set it to cell value row[col.key] = datevalue; worksheet.getColumn(colIndex + 1).numFmt = col.dateFormat ? col.dateFormat : constants_1.constants.defaultDateFormat; } else { row[col.key] = item[col.key]; } } catch (error) { console.error("".concat(constants_1.constants.messges.formulaErrorMessage, " ").concat(col.key, ":"), error); row[col.key] = null; } }); worksheet.addRow(row); }); // *** END Append Simple/Normal Data Region *** // *** Merge vertically consecutive duplicate values for columns with mergeDuplicateRows: true *** config.columns.forEach(function (col, colIndex) { if (col.mergeDuplicateRows) { // Find the first data row and last data row var firstDataRow = currentRowIndex; var lastDataRow = worksheet.lastRow ? worksheet.lastRow.number : firstDataRow - 1; var startRow = firstDataRow; var prevValue = worksheet .getRow(startRow) .getCell(colIndex + 1).value; for (var rowNum = firstDataRow + 1; rowNum <= lastDataRow + 1; rowNum++) { var cellValue = rowNum <= lastDataRow ? worksheet.getRow(rowNum).getCell(colIndex + 1).value : null; if (cellValue !== prevValue) { if (rowNum - startRow > 1 && prevValue !== null && prevValue !== undefined && prevValue !== "") { worksheet.mergeCells(startRow, colIndex + 1, rowNum - 1, colIndex + 1); // Set vertical alignment to top for the merged cell var mergedCell = worksheet.getCell(startRow, colIndex + 1); mergedCell.alignment = Object.assign({}, mergedCell.alignment, { vertical: "top" }); } startRow = rowNum; prevValue = cellValue; } } } }); // *** END Merge vertically consecutive duplicate values *** } // *** Auto Adjust Columns Width Region *** if (config.autoAdjustColumnsWidth) AdjustColumnWidth(worksheet, config.columns, config.maxColumnWidth); }); return [4 /*yield*/, workbook_1.xlsx.writeBuffer()]; case 1: buffer = _a.sent(); if (!buffer) { throw new Error(constants_1.constants.messges.bufferErrorMessage); } blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); url = window.URL.createObjectURL(blob); a = document.createElement("a"); a.href = url; a.download = fileName ? fileName : constants_1.constants.defaultFileName; a.click(); window.URL.revokeObjectURL(url); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); console.error(constants_1.constants.messges.consolErrorMessage, error_1); alert(constants_1.constants.messges.defaultErrorMessage); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; exports.excelJsWrapperToExcelExport = excelJsWrapperToExcelExport;