xlsx-datafill
Version:
Scalable, template based data population for Excel XLSX spreadsheets.
951 lines (809 loc) • 113 kB
JavaScript
(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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