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;