UNPKG

xlsx-datafill

Version:

Scalable, template based data population for Excel XLSX spreadsheets.

951 lines (809 loc) 113 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.XlsxDataFill = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ (function (global){ "use strict"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _2 = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null); var defaultOpts = { templateRegExp: /\{\{([^}]*)\}\}/, fieldSplitter: "|", joinText: ",", mergeCells: true, duplicateCells: false, followFormulae: false, copyStyle: true, callbacksMap: { '': function _(data) { return _2.keys(data); }, $: function $(data) { return _2.values(data); } } }; var refRegExp = /('?([^!]*)?'?!)?([A-Z]+\d+)(:([A-Z]+\d+))?/; /** * Data fill engine, taking an instance of Excel sheet accessor and a JSON object as data, and filling the values from the latter into the former. */ var XlsxDataFill = /*#__PURE__*/function () { /** * Constructs a new instance of XlsxDataFill with given options. * @param {object} accessor An instance of XLSX spreadsheet accessing class. * @param {{}} opts Options to be used during processing. * @param {RegExp} opts.templateRegExp The regular expression to be used for template recognizing. Default is `/\{\{([^}]*)\}\}/`, i.e. Mustache. * @param {string|RegExo} opts.fieldSplitter The string or regular expression to be used as template fields splitter. Default is `|`. * @param {string} opts.joinText The string to be used when the extracted value for a single cell is an array, and it needs to be joined. Default is `,`. * @param {string|boolean} opts.mergeCells Whether to merge the higher dimension cells in the output. Default is true, but valid values are also `"both"`, `"vertical"` and `"horizontal"`. * @param {string|boolean} opts.duplicateCells Whether to duplicate the content of higher dimension cells, when not merged. Default is false. Same valud values as `mergeCells`. * @param {boolean} opts.followFormulae If a template is located as a result of a formula, whether to still process it. Default is false. * @param {boolean} opts.copyStyle Copy the style of the template cell when populating. Even when `false`, the template styling _is_ applied. Default is true. * @param {object.<string, function>} opts.callbacksMap A map of handlers to be used for data and value extraction. */ function XlsxDataFill(accessor, opts) { _classCallCheck(this, XlsxDataFill); this._opts = _2.defaultsDeep({}, opts, defaultOpts); this._rowSizes = {}; this._colSizes = {}; this._access = accessor; } /** * Setter/getter for XlsxDataFill's options as set during construction. * @param {{}|null} newOpts If set - the new options to be used. Check [up here]{@link #new-xlsxdatafillaccessor-opts}. * @returns {XlsxDataFill|{}} The required options (in getter mode) or XlsxDataFill (in setter mode) for chaining. */ _createClass(XlsxDataFill, [{ key: "options", value: function options(newOpts) { if (newOpts !== null) { _2.merge(this._opts, newOpts); return this; } else return this._opts; } /** * The main entry point for whole data population mechanism. * @param {{}} data The data to be applied. * @returns {XlsxDataFill} For invocation chaining. */ }, { key: "fillData", value: function fillData(data) { var _this = this; var dataFills = {}; // Build the dependency connections between templates. this.collectTemplates(function (template) { var aFill = { template: template, dependents: [], formulas: [], processed: false }; if (template.reference) { var refFill = dataFills[template.reference]; if (!refFill) throw new Error("Unable to find a reference '".concat(template.reference, "'!")); if (template.formula) refFill.formulas.push(aFill);else refFill.dependents.push(aFill); aFill.offset = _this._access.cellDistance(refFill.template.cell, template.cell); } dataFills[template.id] = aFill; }); // Apply each fill onto the sheet. _2.each(dataFills, function (fill) { if (fill.processed) return;else if (fill.template.formula) throw new Error("Non-referencing formula found '".concat(fill.extractor, "'. Use a non-templated one!"));else _this.applyFill(fill, data, fill.template.cell); }); return this; } /** * Retrieves the provided handler from the map. * @param {string} handlerName The name of the handler. * @returns {function} The handler function itself. * @ignore */ }, { key: "getHandler", value: function getHandler(handlerName) { var handlerFn = this._opts.callbacksMap[handlerName]; if (!handlerFn) throw new Error("Handler '".concat(handlerName, "' cannot be found!"));else if (typeof handlerFn !== 'function') throw new Error("Handler '".concat(handlerName, "' is not a function!"));else return handlerFn; } /** * Parses the provided extractor (ot iterator) string to find a callback id inside, if present. * @param {string} extractor The iterator/extractor string to be investigated. * @returns {object.<string, function>} A { `path`, `handler` } object representing the JSON path * ready for use and the provided `handler` _function_ - ready for invoking, if such is provided. * If not - the `path` property contains the provided `extractor`, and the `handler` is `null`. * @ignore */ }, { key: "parseExtractor", value: function parseExtractor(extractor) { // A specific extractor can be specified after semilon - find and remember it. var extractParts = extractor.split(":"), handlerName = _2.trim(extractParts[1]); return extractParts.length == 1 ? { path: extractor, handler: null } : { path: _2.trim(extractParts[0]), handler: this.getHandler(handlerName) }; } /** * Applies the style part of the template onto a given cell. * @param {Cell} cell The destination cell to apply styling to. * @param {{}} data The data chunk for that cell. * @param {{}} template The template to be used for that cell. * @returns {DataFiller} For invocation chaining. * @ignore */ }, { key: "applyDataStyle", value: function applyDataStyle(cell, data, template) { var _this2 = this; var styles = template.styles; if (this._opts.copyStyle) this._access.copyStyle(cell, template.cell); if (styles && data) { _2.each(styles, function (pair) { if (_2.startsWith(pair.name, ":")) { _this2.getHandler(pair.name.substr(1)).call(_this2._opts, data, cell); } else if (!_2.startsWith(pair.name, "!")) { var val = _this2.extractValues(data, pair.extractor, cell); if (val) _this2._access.setCellStyle(cell, pair.name, JSON.parse(val)); } }); } return this; } /** * Extract the options-specific parameters from the styles field and merge them with the global ones. * @param {{}} template The template to extract options properties from. * @returns {{}} The full options, * @ignore */ }, { key: "getTemplateOpts", value: function getTemplateOpts(template) { if (!template.styles) return this._opts; var opts = _2.clone(this._opts); _2.each(template.styles, function (pair) { if (_2.startsWith(pair.name, "!")) opts[pair.name.substr(1)] = JSON.parse(pair.extractor); }); return opts; } /** * Parses the contents of the cell into a valid template info. * @param {Cell} cell The cell containing the template to be parsed. * @returns {{}} The parsed template. * @description This method builds template info, taking into account the supplied options. * @ignore */ }, { key: "parseTemplate", value: function parseTemplate(cell) { var value = this._access.cellValue(cell); if (value == null || typeof value !== 'string') return null; var reMatch = value.match(this._opts.templateRegExp); if (!reMatch || !this._opts.followFormulae && this._access.cellType(cell) === 'formula') return null; var parts = reMatch[1].split(this._opts.fieldSplitter).map(_2.trim), styles = !parts[4] ? null : parts[4].split(","), extractor = parts[2] || "", cellRef = this._access.buildRef(cell, parts[0]); if (parts.length < 2) throw new Error("Not enough components of the template '".concat(reMatch[0], "'")); if (!!parts[0] && !cellRef) throw new Error("Invalid reference passed: '".concat(parts[0], "'")); return { id: this._access.cellRef(cell), reference: cellRef, iterators: parts[1].split(/x|\*/).map(_2.trim), extractor: extractor, formula: extractor.startsWith("="), cell: cell, cellSize: this._access.cellSize(cell), padding: (parts[3] || "").split(/:|,|x|\*/).map(function (v) { return parseInt(v) || 0; }), styles: !styles ? null : _2.map(styles, function (s) { var pair = _2.trim(s).split("="); return { name: _2.trim(pair[0]), extractor: _2.trim(pair[1]) }; }) }; } }, { key: "sortTemplates", value: function sortTemplates(list) { var sorted = [], related = {}, map = {}, freeList = []; // First, make the dependency map and add the list of non-referencing templates for (var i = 0; i < list.length; ++i) { var t = list[i]; map[t.id] = i; if (!t.reference) freeList.push(t.id);else (related[t.reference] = related[t.reference] || []).push(t.id); } // Now, make the actual sorting. while (freeList.length > 0) { var id = freeList.shift(), _t = list[map[id]]; sorted.push(_t); // We use the fact that there is a single predecessor in our setup. if (related[_t.id]) freeList.push.apply(freeList, _toConsumableArray(related[_t.id])); } if (sorted.length < list.length) throw new Error("A reference cycle found, involving \"".concat(_2.map(_2.xor(list, sorted), 'id').join(','), "\"!")); return sorted; } /** * Searches the whole workbook for template pattern and constructs the templates for processing. * @param {Function} cb The callback to be invoked on each templated, after they are sorted. * @returns {undefined} * @description The templates collected are sorted, based on the intra-template reference - if one template * is referring another one, it'll appear _later_ in the returned array, than the referred template. * This is the order the callback is being invoked on. * @ignore */ }, { key: "collectTemplates", value: function collectTemplates(cb) { var _this3 = this; var allTemplates = []; this._access.forAllCells(function (cell) { var template = _this3.parseTemplate(cell); if (template) allTemplates.push(template); }); return this.sortTemplates(allTemplates).forEach(cb); } /** * Extracts the value(s) from the provided data `root` to be set in the provided `cell`. * @param {{}} root The data root to be extracted values from. * @param {string} extractor The extraction string provided by the template. Usually a JSON path within the data `root`. * @param {Cell} cell A reference cell, if such exists. * @returns {string|number|Date|Array|Array.<Array.<*>>} The value to be used. * @description This method is used even when a whole - possibly rectangular - range is about to be set, so it can * return an array of arrays. * @ignore */ }, { key: "extractValues", value: function extractValues(root, extractor, cell) { var _this4 = this; var _this$parseExtractor = this.parseExtractor(extractor), path = _this$parseExtractor.path, handler = _this$parseExtractor.handler; if (!Array.isArray(root)) root = _2.get(root, path, root);else if (root.sizes !== undefined) root = !extractor ? root : _2.map(root, function (entry) { return _this4.extractValues(entry, extractor, cell); });else if (!handler) return root.join(this._opts.joinText || ","); return !handler ? root : handler.call(this._opts, root, cell); } /** * Extracts an array (possibly of arrays) with data for the given fill, based on the given * root object. * @param {{}} root The main reference object to apply iterators to. * @param {Array} iterators List of iterators - string JSON paths inside the root object. * @param {Number} idx The index in the iterators array to work on. * @returns {Array|Array.<Array>} An array (possibly of arrays) with extracted data. * @ignore */ }, { key: "extractData", value: function extractData(root, iterators, idx) { var _this5 = this; var iter = iterators[idx], sizes = [], transposed = false, data = null; if (iter == '1') { transposed = true; iter = iterators[++idx]; } if (!iter) return root; // A specific extractor can be specified after semilon - find and remember it. var parsedIter = this.parseExtractor(iter); data = _2.get(root, parsedIter.path, root); if (typeof parsedIter.handler === 'function') data = parsedIter.handler.call(this._opts, data); if (!Array.isArray(data) && _typeof(data) === 'object') return data;else if (idx < iterators.length - 1) { data = _2.map(data, function (inRoot) { return _this5.extractData(inRoot, iterators, idx + 1); }); sizes = data[0].sizes || []; } // data = _.values(data); // Some data sanity checks. if (!data) throw new Error("The iterator '".concat(iter, "' extracted no data!"));else if (_typeof(data) !== 'object') throw new Error("The data extracted from iterator '".concat(iter, "' is neither an array, nor object!")); sizes.unshift(transposed ? -data.length : data.length); data.sizes = sizes; return data; } /** * Put the data values into the proper cells, with correct extracted values. * @param {{}} cell The starting cell for the data to be put. * @param {Array} data The actual data to be put. The values will be _extracted_ from here first. * @param {{}} template The template that is being implemented with that data fill. * @returns {Array} Matrix size that this data has occupied on the sheet [rows, cols]. * @ignore */ }, { key: "putValues", value: function putValues(cell, data, template) { var _this6 = this; if (!cell) throw new Error("Crash! Null reference cell in 'putValues()'!"); var entrySize = data.sizes, value = this.extractValues(data, template.extractor, cell); // if we've come up with a raw data if (!Array.isArray(value) || !entrySize || !entrySize.length) { this._access.setCellValue(cell, value); this.applyDataStyle(cell, data, template); entrySize = template.cellSize; } else if (entrySize.length <= 2) { // Normalize the size and data. if (entrySize[0] < 0) { entrySize = [1, -entrySize[0]]; value = [value]; data = [data]; } else if (entrySize.length == 1) { entrySize = entrySize.concat([1]); value = _2.chunk(value, 1); data = _2.chunk(data, 1); } this._access.getCellRange(cell, entrySize[0] - 1, entrySize[1] - 1).forEach(function (cell, ri, ci) { _this6._access.setCellValue(cell, value[ri][ci]); _this6.applyDataStyle(cell, data[ri][ci], template); }); } else throw new Error("Values extracted with '".concat(template.extractor, "' are more than 2 dimension!'")); return entrySize; } /** * Apply the given filter onto the sheet - extracting the proper data, following dependent fills, etc. * @param {{}} aFill The fill to be applied, as constructed in the {@link fillData} method. * @param {{}} root The data root to be used for data extraction. * @param {Cell} mainCell The starting cell for data placement procedure. * @returns {Array} The size of the data put in [row, col] format. * @ignore */ }, { key: "applyFill", value: function applyFill(aFill, root, mainCell) { var _this7 = this; var template = aFill.template, theData = this.extractData(root, template.iterators, 0); var entrySize = [1, 1]; if (!aFill.dependents || !aFill.dependents.length) entrySize = this.putValues(mainCell, theData, template);else { var nextCell = mainCell; var sizeMaxxer = function sizeMaxxer(val, idx) { return entrySize[idx] = Math.max(entrySize[idx], val); }; var _loop = function _loop(d) { var inRoot = theData[d]; for (var f = 0; f < aFill.dependents.length; ++f) { var inFill = aFill.dependents[f], inCell = _this7._access.offsetCell(nextCell, inFill.offset[0], inFill.offset[1]); _2.forEach(_this7.applyFill(inFill, inRoot, inCell), sizeMaxxer); } // Now we have the inner data put and the size calculated. _2.forEach(_this7.putValues(nextCell, inRoot, template), sizeMaxxer); var rowOffset = entrySize[0], colOffset = entrySize[1], rowPadding = template.padding[0] || 0, colPadding = template.padding[1] || 0; // Make sure we grow only on one dimension. if (theData.sizes[0] < 0) { if (template.padding.length < 2) colPadding = rowPadding; rowOffset = rowPadding = 0; entrySize[1] = 1; } else if (theData.sizes.length < 2) { colOffset = colPadding = 0; entrySize[0] = 1; } if (rowOffset > 1 || colOffset > 1) { var rng = _this7._access.getCellRange(nextCell, Math.max(rowOffset - 1, 0), Math.max(colOffset - 1, 0)), _opts = _this7.getTemplateOpts(template); if (_opts.mergeCells === true || _opts.mergeCell === 'both' || rowOffset > 1 && _opts.mergeCells === 'vertical' || colOffset > 1 && _opts.mergeCells === 'horizontal') _this7._access.rangeMerged(rng, true);else if (_opts.duplicateCells === true || _opts.duplicateCells === 'both' || rowOffset > 1 && _opts.duplicateCells === 'vertical' || colOffset > 1 && _opts.duplicateCells === 'horizontal') _this7._access.duplicateCell(nextCell, rng); rng.forEach(function (cell) { return _this7.applyDataStyle(cell, inRoot, template); }); } // Finally, calculate the next cell. nextCell = _this7._access.offsetCell(nextCell, rowOffset + rowPadding, colOffset + colPadding); }; for (var d = 0; d < theData.length; ++d) { _loop(d); } // Now recalc combined entry size. _2.forEach(this._access.cellDistance(mainCell, nextCell), sizeMaxxer); } _2.forEach(aFill.formulas, function (f) { return _this7.applyFormula(f, entrySize, mainCell); }); aFill.processed = true; return entrySize; } /** * Process a formula be shifting all the fixed offset. * @param {String} formula The formula to be shifted. * @param {Array<Number,Number>} offset The offset of the referenced template to the formula one. * @param {Array<Number,Number>} size The size of the ranges as they should be. * @returns {String} The processed text. * @ignore */ }, { key: "shiftFormula", value: function shiftFormula(formula, offset, size) { var newFormula = ''; for (;;) { var match = formula.match(refRegExp); if (!match) break; var from = this._access.getCell(match[3], match[2]), newRef = null; if (offset[0] > 0 || offset[1] > 0) from = this._access.offsetCell(from, offset[0], offset[1]); newRef = !match[5] ? this._access.cellRef(from, !!match[2]) : this._access.rangeRef(this._access.getCellRange(from, size[0], size[1]), !!match[2]); newFormula += formula.substr(0, match.index) + newRef; formula = formula.substr(match.index + match[0].length); } newFormula += formula; return newFormula; } /** * Apply the given formula in the sheet, i.e. changing it to match the * sizes of the references templates. * @param {{}} aFill The fill to be applied, as constructed in the {@link fillData} method. * @param {Array<Number>} entrySize The fill-to-size map, as constructed so far * @param {Cell} cell The cell to put/start this formula into * @returns {undefined} * @ignore */ }, { key: "applyFormula", value: function applyFormula(aFill, entrySize, cell) { cell = this._access.offsetCell(cell, aFill.offset[0], aFill.offset[1]); var template = aFill.template, iter = _2.trim(template.iterators[0]), offset = this._access.cellDistance(template.cell, cell); var formula = template.extractor, rng; aFill.processed = true; this._access.setCellValue(cell, null); if (entrySize[0] < 2 && entrySize[1] < 2 || iter === 'both') { formula = this.shiftFormula(formula, offset, [0, 0]); rng = this._access.getCellRange(cell, entrySize[0] - 1, entrySize[1] - 1); } else if (iter === 'cols') { formula = this.shiftFormula(formula, offset, [entrySize[0] - 1, 0]); rng = this._access.getCellRange(cell, 0, entrySize[1] - 1); } else if (iter === 'rows') { formula = this.shiftFormula(formula, offset, [0, entrySize[1] - 1]); rng = this._access.getCellRange(cell, entrySize[0] - 1, 0); } else { // i.e. 'none' this._access.setCellFormula(cell, this.shiftFormula(formula, offset, [entrySize[0] - 1, entrySize[1] - 1])); return; } this._access.setRangeFormula(rng, formula); } }]); return XlsxDataFill; }(); /** * The built-in accessor based on xlsx-populate npm module * @type {XlsxPopulateAccess} */ XlsxDataFill.XlsxPopulateAccess = require('./XlsxPopulateAccess'); XlsxDataFill.version = "1.0.3"; module.exports = XlsxDataFill; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./XlsxPopulateAccess":2}],2:[function(require,module,exports){ (function (global){ "use strict"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null); // const allStyles = [ // "bold", // "italic", // "underline", // "strikethrough", // "subscript", // "superscript", // "fontSize", // "fontFamily", // "fontGenericFamily", // "fontScheme", // "fontColor", // "horizontalAlignment", // "justifyLastLine", // "indent", // "verticalAlignment", // "wrapText", // "shrinkToFit", // "textDirection", // "textRotation", // "angleTextCounterclockwise", // "angleTextClockwise", // "rotateTextUp", // "rotateTextDown", // "verticalText", // "fill", // "border", // "borderColor", // "borderStyle", // "leftBorder", "rightBorder", "topBorder", "bottomBorder", "diagonalBorder", // "leftBorderColor", "rightBorderColor", "topBorderColor", "bottomBorderColor", "diagonalBorderColor", // "leftBorderStyle", "rightBorderStyle", "topBorderStyle", "bottomBorderStyle", "diagonalBorderStyle", // "diagonalBorderDirection", // "numberFormat" // ]; var _RichText = null; /** * `xslx-populate` library based accessor to a given Excel workbook. All these methods are internally used by {@link XlsxDataFill}, * but can be used as a reference for implementing custom spreadsheet accessors. */ var XlsxPopulateAccess = /*#__PURE__*/function () { /** * Constructs a new instance of XlsxSmartTemplate with given options. * @param {Workbook} workbook - The workbook to be accessed. * @param {XlsxPopulate} XlsxPopulate - The actual xlsx-populate library object. * @description The `XlsxPopulate` object need to be passed in order to extract * certain information from it, _without_ referring the whole library, thus * avoiding making the `xlsx-datafill` package a dependency. */ function XlsxPopulateAccess(workbook, XlsxPopulate) { _classCallCheck(this, XlsxPopulateAccess); this._workbook = workbook; this._rowSizes = {}; this._colSizes = {}; _RichText = XlsxPopulate.RichText; } /** * Returns the configured workbook for direct XlsxPopulate manipulation. * @returns {Workbook} The workbook involved. */ _createClass(XlsxPopulateAccess, [{ key: "workbook", value: function workbook() { return this._workbook; } /** * Gets the textual representation of the cell value. * @param {Cell} cell - The cell to retrieve the value from. * @returns {string} The textual representation of cell's contents. */ }, { key: "cellValue", value: function cellValue(cell) { var theValue = cell.value(); return theValue instanceof _RichText ? theValue.text() : theValue; } /** * Sets the cell value. * @param {Cell} cell - The cell to retrieve the value from. * @param {*} value - The requested value for setting. * @returns {XlsxPopulateAccess} Either the requested value or chainable this. */ }, { key: "setCellValue", value: function setCellValue(cell, value) { cell.value(value); return this; } /** * Gets the textual representation of the cell value. * @param {Cell} cell - The cell to retrieve the value from. * @returns {string} The type of the cell - 'formula', 'richtext', * 'text', 'number', 'date', 'hyperlink', or 'unknown'; */ }, { key: "cellType", value: function cellType(cell) { if (cell.formula()) return 'formula';else if (cell.hyperlink()) return 'hyperlink'; var theValue = cell.value(); if (theValue instanceof _RichText) return 'richtext';else if (theValue instanceof Date) return 'date';else return _typeof(theValue); } /** * Sets the formula in the cell * @param {Cell} cell - The cell to retrieve the value from. * @param {string} formula - the text of the formula to be set. * @returns {XlsxPopulateAccess} For chaining. */ }, { key: "setCellFormula", value: function setCellFormula(cell, formula) { cell.formula(_.trimStart(formula, ' =')); return this; } /** * Measures the distance, as a vector between two given cells. * @param {Cell} from The first cell. * @param {Cell} to The second cell. * @returns {Array.<Number>} An array with two values [<rows>, <cols>], representing the distance between the two cells. */ }, { key: "cellDistance", value: function cellDistance(from, to) { return [to.rowNumber() - from.rowNumber(), to.columnNumber() - from.columnNumber()]; } /** * Determines the size of cell, taking into account if it is part of a merged range. * @param {Cell} cell The cell to be investigated. * @returns {Array.<Number>} An array with two values [<rows>, <cols>], representing the occupied size. */ }, { key: "cellSize", value: function cellSize(cell) { var _this = this; var cellAddr = cell.address(); var theSize = [1, 1]; _.forEach(cell.sheet()._mergeCells, function (range) { var rangeAddr = range.attributes.ref.split(":"); if (rangeAddr[0] == cellAddr) { theSize = _this.cellDistance(cell, cell.sheet().cell(rangeAddr[1])); ++theSize[0]; ++theSize[1]; return false; } }); return theSize; } /** * Sets a named style of a given cell. * @param {Cell} cell The cell to be operated. * @param {string} name The name of the style property to be set. * @param {string|object} value The value for this property to be set. * @returns {XlsxPopulateAccess} For invocation chaining. */ }, { key: "setCellStyle", value: function setCellStyle(cell, name, value) { cell.style(name, value); return this; } /** * Creates a reference Id for a given cell, based on its sheet and address. * @param {Cell} cell The cell to create a reference Id to. * @param {boolean} withSheet Whether to include the sheet name in the reference. Defaults to true. * @returns {string} The id to be used as a reference for this cell. */ }, { key: "cellRef", value: function cellRef(cell, withSheet) { if (withSheet == null) withSheet = true; return cell.address({ includeSheetName: withSheet }); } /** * Build a reference string for a cell identified by @param adr, from the @param cell. * @param {Cell} cell A cell that is a base of the reference. * @param {string} adr The address of the target cell, as mentioned in @param cell. * @param {boolean} withSheet Whether to include the sheet name in the reference. Defaults to true. * @returns {string} A reference string identifying the target cell uniquely. */ }, { key: "buildRef", value: function buildRef(cell, adr, withSheet) { if (withSheet == null) withSheet = true; return adr ? cell.sheet().cell(adr).address({ includeSheetName: withSheet }) : null; } /** * Retrieves a given cell from a given sheet (or an active one). * @param {string|object|array} address The cell adress to be used * @param {string|idx} sheetId The id/name of the sheet to retrieve the cell from. Defaults to an active one. * @returns {Cell} A reference to the required cell. */ }, { key: "getCell", value: function getCell(address, sheetId) { var theSheet = sheetId == null ? this._workbook.activeSheet() : this._workbook.sheet(sheetId); return theSheet.cell(address); } /** * Duplicates a cell across a given range. * @param {Cell} cell Cell, which needs duplicating. * @param {Range} range The range, as returned from {@link getCellRange} * @returns {XlsxPopulateAccess} For chain invokes. */ }, { key: "duplicateCell", value: function duplicateCell(cell, range) { range.value(cell.value()); return this; } /** * Constructs and returns the range starting from the given cell and spawning given rows and cells. * @param {Cell} cell The starting cell of the range. * @param {Number} rowOffset Number of rows away from the starting cell. 0 means same row. * @param {Number} colOffset Number of columns away from the starting cell. 0 means same column. * @returns {Range} The constructed range. */ }, { key: "getCellRange", value: function getCellRange(cell, rowOffset, colOffset) { return cell.rangeTo(cell.relativeCell(rowOffset, colOffset)); } /** * Gets the cell at a certain offset from a given one. * @param {Cell} cell The reference cell to make the offset from. * @param {int} rows Number of rows to offset. * @param {int} cols Number of columns to offset. * @returns {Cell} The resulting cell. */ }, { key: "offsetCell", value: function offsetCell(cell, rows, cols) { return cell.relativeCell(rows, cols); } /** * Merge or split range of cells. * @param {Range} range The range, as returned from {@link getCellRange} * @param {boolean} status The merged status to be set. * @returns {XlsxPopulateAccess} For chain invokes. */ }, { key: "rangeMerged", value: function rangeMerged(range, status) { if (status === undefined) return range.merged();else { range.merged(status); return this; } } /** * Sets a formula for the whole range. If it contains only one - it is set directly. * @param {Range} range The range, as returned from {@link getCellRange} * @param {String} formula The formula to be set. * @returns {XlsxPopulateAccess} For chain invokes. */ }, { key: "setRangeFormula", value: function setRangeFormula(range, formula) { range.formula(_.trimStart(formula, ' =')); return this; } /** * Return the string representation of a given range. * @param {Range} range The range which address we're interested in. * @param {boolean} withSheet Whether to include sheet name in the address. * @return {String} The string, representing the given range. */ }, { key: "rangeRef", value: function rangeRef(range, withSheet) { if (withSheet == null) withSheet = true; return range.address({ includeSheetName: withSheet }); } /** * Iterate over all used cells of the given workbook. * @param {function} cb The callback to be invoked with `cell` argument for each used cell. * @returns {XlsxPopulateAccess} For chain invokes. */ }, { key: "forAllCells", value: function forAllCells(cb) { this._workbook.sheets().forEach(function (sheet) { var theRange = sheet.usedRange(); if (theRange) theRange.forEach(cb); }); return this; } /** * Copies the styles from `src` cell to the `dest`-ination one. * @param {Cell} dest Destination cell. * @param {Cell} src Source cell. * @returns {XlsxPopulateAccess} For invocation chaining. */ }, { key: "copyStyle", value: function copyStyle(dest, src) { if (!src || !dest) throw new Error("Crash! Null 'src' or 'dest' for copyStyle()!"); if (src == dest) return this; if (src._style !== undefined) dest.style(src._style);else if (src._styleId > 0) dest._styleId = src._styleId; var destSheetId = dest.sheet().name(), rowId = "'".concat(destSheetId, "':").concat(dest.rowNumber()), colId = "'".concat(destSheetId, "':").concat(dest.columnNumber()); if (this._rowSizes[rowId] === undefined) dest.row().height(this._rowSizes[rowId] = src.row().height()); if (this._colSizes[colId] === undefined) dest.column().width(this._colSizes[colId] = src.column().width()); return this; } }]); return XlsxPopulateAccess; }(); module.exports = XlsxPopulateAccess; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}]},{},[1])(1) }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvWGxzeERhdGFGaWxsLmpzIiwic3JjL1hsc3hQb3B1bGF0ZUFjY2Vzcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLElBQU0sRUFBQyxHQUFHLE9BQU8sQ0FBQyxRQUFELENBQWpCOztBQUVBLElBQU0sV0FBVyxHQUFHO0FBQ2hCLEVBQUEsY0FBYyxFQUFFLGlCQURBO0FBRWhCLEVBQUEsYUFBYSxFQUFFLEdBRkM7QUFHaEIsRUFBQSxRQUFRLEVBQUUsR0FITTtBQUloQixFQUFBLFVBQVUsRUFBRSxJQUpJO0FBS2hCLEVBQUEsY0FBYyxFQUFFLEtBTEE7QUFNaEIsRUFBQSxjQUFjLEVBQUUsS0FOQTtBQU9oQixFQUFBLFNBQVMsRUFBRSxJQVBLO0FBUWhCLEVBQUEsWUFBWSxFQUFFO0FBQ1YsUUFBSSxXQUFBLElBQUk7QUFBQSxhQUFJLEVBQUMsQ0FBQyxJQUFGLENBQU8sSUFBUCxDQUFKO0FBQUEsS0FERTtBQUVWLElBQUEsQ0FBQyxFQUFFLFdBQUEsSUFBSTtBQUFBLGFBQUksRUFBQyxDQUFDLE1BQUYsQ0FBUyxJQUFULENBQUo7QUFBQTtBQUZHO0FBUkUsQ0FBcEI7QUFjQSxJQUFNLFNBQVMsR0FBRyw0Q0FBbEI7QUFFQTs7OztJQUdNLFk7QUFDRjs7Ozs7Ozs7Ozs7OztBQWFBLHdCQUFZLFFBQVosRUFBc0IsSUFBdEIsRUFBNEI7QUFBQTs7QUFDeEIsU0FBSyxLQUFMLEdBQWEsRUFBQyxDQUFDLFlBQUYsQ0FBZSxFQUFmLEVBQW1CLElBQW5CLEVBQXlCLFdBQXpCLENBQWI7QUFDQSxTQUFLLFNBQUwsR0FBaUIsRUFBakI7QUFDQSxTQUFLLFNBQUwsR0FBaUIsRUFBakI7QUFDQSxTQUFLLE9BQUwsR0FBZSxRQUFmO0FBQ0g7QUFFRDs7Ozs7Ozs7OzRCQUtRLE8sRUFBUztBQUNiLFVBQUksT0FBTyxLQUFL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