"use strict"; require("core-js/modules/es.symbol"); require("core-js/modules/es.symbol.description"); require("core-js/modules/es.symbol.iterator"); require("core-js/modules/es.array.index-of"); require("core-js/modules/es.array.iterator"); require("core-js/modules/es.object.to-string"); require("core-js/modules/es.regexp.exec"); require("core-js/modules/es.regexp.to-string"); require("core-js/modules/es.string.iterator"); require("core-js/modules/es.string.match"); require("core-js/modules/es.string.replace"); require("core-js/modules/es.string.split"); require("core-js/modules/es.string.starts-with"); require("core-js/modules/web.dom-collections.iterator"); exports.__esModule = true; exports.default = void 0; var _hotFormulaParser = require("hot-formula-parser"); var _array = require("../../helpers/array"); var _object = require("../../helpers/object"); var _localHooks = _interopRequireDefault(require("../../mixins/localHooks")); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } 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 BARE_CELL_STRICT_REGEX = /^\$?[A-Z]+\$?\d+$/; var BARE_CELL_REGEX = /\$?[A-Z]+\$?\d+/; var CELL_REGEX = /(?:[^0-9A-Z$: ]|^)\s*(\$?[A-Z]+\$?\d+)\s*(?![0-9A-Z_: ])/g; var RANGE_REGEX = /\$?[A-Z]+\$?\d+\s*:\s*\$?[A-Z]+\$?\d+/g; var CELL_AND_RANGE_REGEX = /((?:[^0-9A-Z$: ]|^)\s*(\$?[A-Z]+\$?\d+)\s*(?![0-9A-Z_: ]))|(\$?[A-Z]+\$?\d+\s*:\s*\$?[A-Z]+\$?\d+)/g; /** * Component adds an ability to parse and modify formula expressions. It is designed for translating cell * coordinates and cell ranges in any direction. By default, component translates only relative coordinates but this * behavior can be overwritten by passing custom modifier which controls translating process. * * @class ExpressionModifier * @util */ var ExpressionModifier = /*#__PURE__*/ function () { function ExpressionModifier(expression) { _classCallCheck(this, ExpressionModifier); /** * Formula expression to modify. * * @type {String} */ this.expression = ''; /** * Extracted cells and cells ranges. * * @type {Array} */ this.cells = []; /** * Function which can modify default behaviour of how cells and cell ranges will be translated. * * @type {null|Function} */ this.customModifier = null; if (typeof expression === 'string') { this.setExpression(expression); } } /** * Set formula expression to modify. * * @param {String} expression Formula expression to process. * @returns {ExpressionModifier} */ _createClass(ExpressionModifier, [{ key: "setExpression", value: function setExpression(expression) { this.cells.length = 0; this.expression = (0, _utils.toUpperCaseFormula)(expression); this._extractCells(); this._extractCellsRange(); return this; } /** * Set function which can modify default behavior of how cells and cell ranges will be translated. * The passed function will be called with 4 arguments: * - cell, A cell object with structure * like this: {start: {row, column}, end: {row, column}, origLabel, type: 'cell|range', refError, toLabel: () => {}} * - axis, Type of currently processing axis ('row' or 'column') * - delta, Number as distance to translate. Can be positive or negative. * - startFromIndex, Base index which translation will be applied from. * * the function must return an array with 3 items, where: * [ * deltaStart, Number as a delta to translate first part of coordinates. * deltaEnd, Number as a delta to translate second part of coordinates (if cell range is modified). * refError, Defines an error which refers to the situation when translated cell overcrossed the data boundary. * ] * * * @param {Function} customModifier Function with custom logic. */ }, { key: "useCustomModifier", value: function useCustomModifier(customModifier) { this.customModifier = customModifier; } /** * Translate formula expression cells. * * @param {Object} delta Distance to move in proper direction. * @param {Object} [startFrom] Coordinates which translation will be applied from. * @returns {ExpressionModifier} */ }, { key: "translate", value: function translate(_ref) { var _this = this; var deltaRow = _ref.row, deltaColumn = _ref.column; var startFrom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; (0, _array.arrayEach)(this.cells, function (cell) { if (deltaRow !== null && deltaRow !== void 0) { _this._translateCell(cell, 'row', deltaRow, startFrom.row); } if (deltaColumn !== null && deltaColumn !== void 0) { _this._translateCell(cell, 'column', deltaColumn, startFrom.column); } }); return this; } /** * Translate object into string representation. * * @returns {String} */ }, { key: "toString", value: function toString() { var _this2 = this; var expression = this.expression.replace(CELL_AND_RANGE_REGEX, function (match, p1, p2) { var isSingleCell = match.indexOf(':') === -1; var result = match; var cellLabel = match; var translatedCellLabel = null; if (isSingleCell) { cellLabel = BARE_CELL_STRICT_REGEX.test(p1) ? p1 : p2; } var cell = _this2._searchCell(cellLabel); if (cell) { translatedCellLabel = cell.refError ? (0, _hotFormulaParser.error)(_hotFormulaParser.ERROR_REF) : cell.toLabel(); if (isSingleCell) { result = match.replace(cellLabel, translatedCellLabel); } else { result = translatedCellLabel; } } return result; }); if (!expression.startsWith('=')) { expression = "=".concat(expression); } return expression; } /** * Translate single cell. * * @param {Object} cell Cell object. * @param {String} axis Axis to modify. * @param {Number} delta Distance to move. * @param {Number} [startFromIndex] Base index which translation will be applied from. * @private */ }, { key: "_translateCell", value: function _translateCell(cell, axis, delta, startFromIndex) { var start = cell.start, end = cell.end; var startIndex = start[axis].index; var endIndex = end[axis].index; var deltaStart = delta; var deltaEnd = delta; var refError = false; if (this.customModifier) { var _this$customModifier = this.customModifier(cell, axis, delta, startFromIndex); var _this$customModifier2 = _slicedToArray(_this$customModifier, 3); deltaStart = _this$customModifier2[0]; deltaEnd = _this$customModifier2[1]; refError = _this$customModifier2[2]; } else { // By default only relative cells are translated, if meets absolute reset deltas to 0 if (start[axis].isAbsolute) { deltaStart = 0; } if (end[axis].isAbsolute) { deltaEnd = 0; } } if (deltaStart && !refError) { if (startIndex + deltaStart < 0) { refError = true; } start[axis].index = Math.max(startIndex + deltaStart, 0); } if (deltaEnd && !refError) { if (endIndex + deltaEnd < 0) { refError = true; } end[axis].index = Math.max(endIndex + deltaEnd, 0); } if (refError) { cell.refError = true; } } /** * Extract all cells from the formula expression. * * @private */ }, { key: "_extractCells", value: function _extractCells() { var _this3 = this; var matches = this.expression.match(CELL_REGEX); if (!matches) { return; } (0, _array.arrayEach)(matches, function (coord) { var cellCoords = coord.match(BARE_CELL_REGEX); if (!cellCoords) { return; } var _extractLabel = (0, _hotFormulaParser.extractLabel)(cellCoords[0]), _extractLabel2 = _slicedToArray(_extractLabel, 2), row = _extractLabel2[0], column = _extractLabel2[1]; _this3.cells.push(_this3._createCell({ row: row, column: column }, { row: row, column: column }, cellCoords[0])); }); } /** * Extract all cells range from the formula expression. * * @private */ }, { key: "_extractCellsRange", value: function _extractCellsRange() { var _this4 = this; var matches = this.expression.match(RANGE_REGEX); if (!matches) { return; } (0, _array.arrayEach)(matches, function (match) { var _match$split = match.split(':'), _match$split2 = _slicedToArray(_match$split, 2), start = _match$split2[0], end = _match$split2[1]; var _extractLabel3 = (0, _hotFormulaParser.extractLabel)(start), _extractLabel4 = _slicedToArray(_extractLabel3, 2), startRow = _extractLabel4[0], startColumn = _extractLabel4[1]; var _extractLabel5 = (0, _hotFormulaParser.extractLabel)(end), _extractLabel6 = _slicedToArray(_extractLabel5, 2), endRow = _extractLabel6[0], endColumn = _extractLabel6[1]; var startCell = { row: startRow, column: startColumn }; var endCell = { row: endRow, column: endColumn }; _this4.cells.push(_this4._createCell(startCell, endCell, match)); }); } /** * Search cell by its label. * * @param {String} label Cell label eq. `B4` or `$B$6`. * @returns {Object|null} * @private */ }, { key: "_searchCell", value: function _searchCell(label) { var _arrayFilter = (0, _array.arrayFilter)(this.cells, function (cellMeta) { return cellMeta.origLabel === label; }), _arrayFilter2 = _slicedToArray(_arrayFilter, 1), cell = _arrayFilter2[0]; return cell || null; } /** * Create object cell. * * @param {Object} start Start coordinates (top-left). * @param {Object} end End coordinates (bottom-right). * @param {String} label Original label name. * @returns {Object} * @private */ }, { key: "_createCell", value: function _createCell(start, end, label) { return { start: start, end: end, origLabel: label, type: label.indexOf(':') === -1 ? 'cell' : 'range', refError: false, toLabel: function toLabel() { var newLabel = (0, _hotFormulaParser.toLabel)(this.start.row, this.start.column); if (this.type === 'range') { newLabel += ":".concat((0, _hotFormulaParser.toLabel)(this.end.row, this.end.column)); } return newLabel; } }; } }]); return ExpressionModifier; }(); (0, _object.mixin)(ExpressionModifier, _localHooks.default); var _default = ExpressionModifier; exports.default = _default;