spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
name: dist/Sheet.js
-rw-r--r--
9044
  1"use strict";
  2exports.__esModule = true;
  3var Cell_1 = require("./Cell");
  4var Errors_1 = require("./Errors");
  5var DataStore_1 = require("./Parser/DataStore");
  6var Parser_1 = require("./Parser/Parser");
  7var Formulas_1 = require("./Formulas");
  8var MoreUtils_1 = require("./Utilities/MoreUtils");
  9/**
 10 * Represents a spreadsheet parser and data-store that act together as a functional spreadsheet.
 11 */
 12var Sheet = /** @class */ (function () {
 13    function Sheet() {
 14        this.parser = Parser_1.FormulaParser(this);
 15        this.dataStore = new DataStore_1.DataStore();
 16    }
 17    /**
 18     * Iterate through cells in the data-store, returning the collected cells in the range.
 19     * @param origin
 20     * @param startCell
 21     * @param endCell
 22     * @returns {{index: Array; value: Array}}
 23     */
 24    Sheet.prototype.iterateCells = function (origin, startCell, endCell) {
 25        var result = {
 26            index: [],
 27            value: [] // list of cell value
 28        };
 29        var cols = {
 30            start: 0,
 31            end: 0
 32        };
 33        if (endCell.col >= startCell.col) {
 34            cols = {
 35                start: startCell.col,
 36                end: endCell.col
 37            };
 38        }
 39        else {
 40            cols = {
 41                start: endCell.col,
 42                end: startCell.col
 43            };
 44        }
 45        var rows = {
 46            start: 0,
 47            end: 0
 48        };
 49        if (endCell.row >= startCell.row) {
 50            rows = {
 51                start: startCell.row,
 52                end: endCell.row
 53            };
 54        }
 55        else {
 56            rows = {
 57                start: endCell.row,
 58                end: startCell.row
 59            };
 60        }
 61        for (var column = cols.start; column <= cols.end; column++) {
 62            for (var row = rows.start; row <= rows.end; row++) {
 63                var cellIndex = MoreUtils_1.numberToCharacter(column) + (row + 1), cellValue = this.cellValue(origin, cellIndex);
 64                result.index.push(cellIndex);
 65                result.value.push(cellValue);
 66            }
 67        }
 68        return result;
 69    };
 70    /**
 71     * Call function with given arguments. Used for calling formulas.
 72     * @param fn
 73     * @param args
 74     * @returns {any}
 75     */
 76    Sheet.prototype.callFunction = function (fn, args) {
 77        fn = fn.toUpperCase();
 78        args = args || [];
 79        if (Formulas_1.Formulas.exists(fn)) {
 80            return Formulas_1.Formulas.get(fn).apply(this, args);
 81        }
 82        throw new Errors_1.NameError("Unknown function: '" + fn + "'.");
 83    };
 84    /**
 85     * Call variable, which could include calling a function.
 86     * @param args
 87     * @returns {any}
 88     */
 89    Sheet.prototype.callVariable = function (args) {
 90        args = args || [];
 91        var str = args.shift(); // the first in args is the name of the function to call.
 92        if (str) {
 93            str = str.toUpperCase();
 94            if (Formulas_1.Formulas.exists(str)) {
 95                return Formulas_1.Formulas.get(str).apply(this, args);
 96            }
 97        }
 98        throw new Errors_1.NameError("Unknown variable: '" + str + "'.");
 99    };
100    ;
101    /**
102     * Fetch cell, updating dependencies in process.
103     * @param origin
104     * @param cellId
105     * @returns {Cell}
106     */
107    Sheet.prototype.cellValue = function (origin, cellId) {
108        var cell = this.dataStore.getCell(cellId);
109        //update dependencies
110        this.dataStore.getCell(origin).updateDependencies([cellId]);
111        // check references error
112        if (cell && cell.getDependencies()) {
113            if (cell.getDependencies().indexOf(cellId) !== -1) {
114                throw new Errors_1.RefError("Reference does not exist.");
115            }
116        }
117        return cell;
118    };
119    /**
120     * Get a range of cells.
121     * @param origin - the cell id in A1 notation from which this range is being referenced.
122     * @param {string} start - first cell coordinate (in A1 notation) in iteration
123     * @param {string} end - final cell coordinate (in A1 notation) in iteration
124     * @returns {Array}
125     */
126    Sheet.prototype.cellRangeValue = function (origin, start, end) {
127        var coordsStart = MoreUtils_1.A1toRowColCoordinates(start), coordsEnd = MoreUtils_1.A1toRowColCoordinates(end);
128        // iterate cells to get values and indexes
129        var cells = this.iterateCells(origin, coordsStart, coordsEnd), result = [];
130        //update dependencies
131        this.dataStore.getCell(origin).updateDependencies(cells.index);
132        result.push(cells.value);
133        return result;
134    };
135    /**
136     * Get a fixed cell value.
137     * @param origin
138     * @param id
139     * @returns {Cell}
140     */
141    Sheet.prototype.fixedCellValue = function (origin, id) {
142        id = id.replace(/\$/g, '');
143        return this.cellValue(origin, id);
144    };
145    ;
146    /**
147     * Get a fixed cell value range.
148     * @param origin
149     * @param start
150     * @param end
151     * @returns {Array}
152     */
153    Sheet.prototype.fixedCellRangeValue = function (origin, start, end) {
154        start = start.replace(/\$/g, '');
155        end = end.replace(/\$/g, '');
156        return this.cellRangeValue(origin, start, end);
157    };
158    ;
159    /**
160     * Recalculate dependencies for a cell.
161     * @param {Cell} cell
162     */
163    Sheet.prototype.recalculateCellDependencies = function (cell) {
164        var allDependencies = this.dataStore.getDependencies(cell.getId());
165        for (var _i = 0, allDependencies_1 = allDependencies; _i < allDependencies_1.length; _i++) {
166            var refId = allDependencies_1[_i];
167            var currentCell = this.dataStore.getCell(refId);
168            if (currentCell && currentCell.hasFormula()) {
169                this.calculateCellFormula(currentCell);
170            }
171        }
172    };
173    /**
174     * Executes the formula in a cell.
175     * @param {Cell} cell
176     * @returns {{error: Error; result: any} | {error: any; result: any}}
177     */
178    Sheet.prototype.calculateCellFormula = function (cell) {
179        // to avoid double translate formulas, update cell data in parser
180        var parsed = this.parse(cell.getFormula(), cell.getId());
181        this.dataStore.getCell(cell.getId()).setValue(parsed.result);
182        this.dataStore.getCell(cell.getId()).setError(parsed.error);
183        return parsed;
184    };
185    /**
186     * Add a cell to the data-store, recording and updating dependencies if necessary.
187     * @param {Cell} cell
188     */
189    Sheet.prototype.registerCellInDataStore = function (cell) {
190        this.dataStore.addCell(cell);
191        if (cell.hasFormula()) {
192            this.calculateCellFormula(cell);
193        }
194    };
195    /**
196     * Parse a formula for a given cellId. This involves all calculations and look-ups.
197     * @param formula
198     * @param cellId
199     * @returns {any}
200     */
201    Sheet.prototype.parse = function (formula, cellId) {
202        var result = null;
203        var error = null;
204        try {
205            this.parser.yy.originCellId = cellId;
206            result = this.parser.parse(formula);
207            var deps = this.dataStore.getDependencies(cellId);
208            if (deps.indexOf(cellId) !== -1) {
209                result = null;
210                for (var _i = 0, deps_1 = deps; _i < deps_1.length; _i++) {
211                    var id = deps_1[_i];
212                    this.dataStore.getCell(id).setError(new Errors_1.RefError("Reference does not exist"));
213                    this.dataStore.getCell(id).clearValue();
214                }
215                error = new Errors_1.RefError("Reference does not exist.");
216            }
217        }
218        catch (e) {
219            error = e;
220        }
221        if (result instanceof Error) {
222            return {
223                error: result,
224                result: null
225            };
226        }
227        return {
228            error: error,
229            result: result
230        };
231    };
232    /**
233     * Set a cell's value, by id.
234     * @param {string} id
235     * @param {string} value
236     */
237    Sheet.prototype.setCell = function (id, value) {
238        var cell = new Cell_1.Cell(id);
239        cell.setValue(value.toString());
240        this.registerCellInDataStore(cell);
241        this.recalculateCellDependencies(cell);
242    };
243    /**
244     * Get a cell from the data-store, returning null if a cell is undefined.
245     * @param {string} id
246     * @returns {Cell}
247     */
248    Sheet.prototype.getCell = function (id) {
249        var cell = this.dataStore.getCell(id);
250        if (cell === undefined) {
251            return null;
252        }
253        return cell;
254    };
255    /**
256     * Load an a matrix of cells into the data-store.
257     * @param {Array<Array<any>>} input
258     */
259    Sheet.prototype.load = function (input) {
260        for (var y = 0; y < input.length; y++) {
261            for (var x = 0; x < input[0].length; x++) {
262                // set the cell here
263                var id = MoreUtils_1.convertXYtoA1Coordinates(x, y);
264                this.setCell(id, input[y][x].toString());
265            }
266        }
267    };
268    ;
269    return Sheet;
270}());
271exports.Sheet = Sheet;