@builttocreate/engine-utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # engine-utils
2
+ Utility library for common logic shared across web and mobile
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.getDefaultLinePoint = exports.getDefaultLine = void 0;
9
+
10
+ var _shortid = _interopRequireDefault(require("shortid"));
11
+
12
+ var getDefaultLine = function getDefaultLine() {
13
+ /**
14
+ * Why do we add more than 1 points by default to the new line?
15
+ *
16
+ * There is bug with victory-native that will throw an error if
17
+ * there aren't two data points in the array.
18
+ */
19
+ return {
20
+ _id: _shortid["default"].generate(),
21
+ deleted: false,
22
+ title: '',
23
+ description: '',
24
+ points: [getDefaultLinePoint(), getDefaultLinePoint(), getDefaultLinePoint()]
25
+ };
26
+ };
27
+
28
+ exports.getDefaultLine = getDefaultLine;
29
+
30
+ var getDefaultLinePoint = function getDefaultLinePoint() {
31
+ return {
32
+ _id: _shortid["default"].generate(),
33
+ label: '',
34
+ y: 0,
35
+ x: 0
36
+ };
37
+ };
38
+
39
+ exports.getDefaultLinePoint = getDefaultLinePoint;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var text = 'text';
8
+ var dropdown = 'dropdown';
9
+ var _default = {
10
+ text: text,
11
+ dropdown: dropdown
12
+ };
13
+ exports["default"] = _default;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var rowMenu = 'rowMenu';
8
+ var rowNumber = 'rowNumber';
9
+ var _default = {
10
+ rowMenu: rowMenu,
11
+ rowNumber: rowNumber
12
+ };
13
+ exports["default"] = _default;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ // Display Fields
8
+ var uniqueId = 'uniqueId';
9
+ var image = 'image';
10
+ var richText = 'richText'; // Data Fields
11
+
12
+ var text = 'text';
13
+ var textarea = 'textarea';
14
+ var number = 'number';
15
+ var dropdown = 'dropdown';
16
+ var multiSelect = 'multiSelect';
17
+ var date = 'date';
18
+ var signature = 'signature';
19
+ var list = 'list';
20
+ var user = 'user';
21
+ var task = 'task';
22
+ var table = 'table';
23
+ var inputGroup = 'inputGroup';
24
+ var chart = 'chart';
25
+ var types = {
26
+ uniqueId: uniqueId,
27
+ image: image,
28
+ richText: richText,
29
+ text: text,
30
+ textarea: textarea,
31
+ number: number,
32
+ date: date,
33
+ signature: signature,
34
+ list: list,
35
+ user: user,
36
+ task: task,
37
+ table: table,
38
+ inputGroup: inputGroup,
39
+ chart: chart,
40
+ multiSelect: multiSelect,
41
+ dropdown: dropdown
42
+ };
43
+ types.all = Object.keys(types);
44
+ types.titles = {
45
+ uniqueId: 'Auto Number',
46
+ image: 'Image',
47
+ richText: 'Rich Text',
48
+ text: 'Short Text',
49
+ textarea: 'Long Text',
50
+ number: 'Number',
51
+ date: 'Date',
52
+ signature: 'Signature',
53
+ user: 'User',
54
+ table: 'Table Field',
55
+ inputGroup: 'Field Group',
56
+ chart: 'Performance Chart',
57
+ multiSelect: 'Checkbox',
58
+ dropdown: 'Dropdown'
59
+ };
60
+ var _default = types;
61
+ exports["default"] = _default;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = exports.inputGroupFieldTypes = exports.viewTypes = exports.operandLetters = void 0;
7
+ var operandLetters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'];
8
+ exports.operandLetters = operandLetters;
9
+ var viewTypes = {
10
+ list: 'list',
11
+ table: 'table'
12
+ };
13
+ exports.viewTypes = viewTypes;
14
+ var inputGroupFieldTypes = {
15
+ inputGroupRowHeader: 'inputGroupRowHeader',
16
+ inputGroupDropdownCell: 'inputGroupDropdownCell',
17
+ inputGroupTextCell: 'inputGroupTextCell',
18
+ inputGroupFooter: 'inputGroupFooter'
19
+ };
20
+ exports.inputGroupFieldTypes = inputGroupFieldTypes;
21
+ var _default = {
22
+ operandLetters: operandLetters,
23
+ viewTypes: viewTypes,
24
+ inputGroupFieldTypes: inputGroupFieldTypes
25
+ };
26
+ exports["default"] = _default;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.getMultiSelectFieldValue = exports.getChartFieldValue = void 0;
9
+
10
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
11
+
12
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
13
+
14
+ /**
15
+ * Get chart field line data
16
+ *
17
+ * @param (String|Object) value
18
+ */
19
+ var getChartFieldValue = function getChartFieldValue(value) {
20
+ var parsedData = value || [];
21
+
22
+ if (value && typeof value === 'string') {
23
+ parsedData = JSON.parse(value);
24
+ }
25
+
26
+ if (parsedData && parsedData.length > 0) {
27
+ parsedData = parsedData.filter(function (line) {
28
+ return !line.deleted;
29
+ });
30
+ }
31
+
32
+ return (0, _toConsumableArray2["default"])(parsedData);
33
+ };
34
+ /**
35
+ * Get multiselect field value
36
+ *
37
+ * @param (String|Array) value
38
+ * @return Array
39
+ */
40
+
41
+
42
+ exports.getChartFieldValue = getChartFieldValue;
43
+
44
+ var getMultiSelectFieldValue = function getMultiSelectFieldValue(value) {
45
+ if (value && typeof value === 'string') {
46
+ return value.split(',');
47
+ } else if (value && (0, _typeof2["default"])(value) === 'object') {
48
+ return (0, _toConsumableArray2["default"])(value);
49
+ } else {
50
+ return [];
51
+ }
52
+ };
53
+
54
+ exports.getMultiSelectFieldValue = getMultiSelectFieldValue;
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.fieldHelper = exports.chartHelper = exports.tableHelper = exports["default"] = void 0;
9
+
10
+ var tableHelper = _interopRequireWildcard(require("./tableHelper"));
11
+
12
+ exports.tableHelper = tableHelper;
13
+
14
+ var chartHelper = _interopRequireWildcard(require("./chartHelper"));
15
+
16
+ exports.chartHelper = chartHelper;
17
+
18
+ var fieldHelper = _interopRequireWildcard(require("./fieldHelper"));
19
+
20
+ exports.fieldHelper = fieldHelper;
21
+ var _default = {
22
+ tableHelper: tableHelper,
23
+ chartHelper: chartHelper,
24
+ fieldHelper: fieldHelper
25
+ };
26
+ exports["default"] = _default;
@@ -0,0 +1,584 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
+
5
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
+
7
+ Object.defineProperty(exports, "__esModule", {
8
+ value: true
9
+ });
10
+ exports["default"] = exports.generateInputGroupFields = exports.spreadOperandRange = exports.validFormulaString = exports.hasOperandRange = exports.hasCircularOperandReference = exports.resolveOperandValue = exports.getFormulaResult = exports.generateTableLookup = exports.generateTableFieldLookups = exports.generateRowTableLookup = exports.getCellOperand = exports.getTemplateColumnOperandLookup = exports.getColumnOperand = exports.getColumns = exports.getTableFieldRowOrder = exports.getRowMap = exports.sortRows = exports.getRows = exports.getDefaultRow = exports.getTableFieldLookupKey = void 0;
11
+
12
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
+
14
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
15
+
16
+ var _shortid = _interopRequireDefault(require("shortid"));
17
+
18
+ var _Table = _interopRequireWildcard(require("./constants/Table"));
19
+
20
+ var _FieldTypes = _interopRequireDefault(require("./constants/FieldTypes"));
21
+
22
+ var _FieldTableColumnTypes = _interopRequireDefault(require("./constants/FieldTableColumnTypes"));
23
+
24
+ var _FieldTableCustomColumnIds = _interopRequireDefault(require("./constants/FieldTableCustomColumnIds"));
25
+
26
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
27
+
28
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
29
+
30
+ var FormulaParser = require('hot-formula-parser').Parser;
31
+
32
+ var parser = new FormulaParser();
33
+
34
+ var getTableFieldLookupKey = function getTableFieldLookupKey(fieldId, rowIndex, columnId) {
35
+ return "".concat(fieldId, "-").concat(rowIndex, "-").concat(columnId);
36
+ };
37
+
38
+ exports.getTableFieldLookupKey = getTableFieldLookupKey;
39
+
40
+ var getDefaultRow = function getDefaultRow() {
41
+ return {
42
+ _id: _shortid["default"].generate(),
43
+ deleted: false,
44
+ cells: {}
45
+ };
46
+ };
47
+
48
+ exports.getDefaultRow = getDefaultRow;
49
+
50
+ var getRows = function getRows(rows) {
51
+ var parsedRows = rows;
52
+
53
+ if (typeof parsedRows === 'string') {
54
+ parsedRows = JSON.parse(parsedRows);
55
+ }
56
+
57
+ return parsedRows ? parsedRows.filter(function (row) {
58
+ return !row.deleted;
59
+ }) : [];
60
+ };
61
+ /**
62
+ * Sort rows based on rowOrder
63
+ */
64
+
65
+
66
+ exports.getRows = getRows;
67
+
68
+ var sortRows = function sortRows(rows, rowOrder) {
69
+ var rowLookup = {};
70
+ rows.forEach(function (row) {
71
+ return rowLookup[row._id] = row;
72
+ });
73
+ var validRows = [];
74
+ rowOrder.forEach(function (rowId) {
75
+ if (rowLookup[rowId]) validRows.push(rowLookup[rowId]);
76
+ });
77
+ return validRows;
78
+ };
79
+ /**
80
+ * Create a table row map for simple value lookup
81
+ *
82
+ * For instance:
83
+ * {
84
+ * rowId: {columnId: value, columnId: value, ...},
85
+ * rowId: {columnId: value, columnId: value, ...},
86
+ * rowId: {columnId: value, columnId: value, ...}
87
+ * }
88
+ *
89
+ * @param {Array} rows
90
+ * @return {Object}
91
+ */
92
+
93
+
94
+ exports.sortRows = sortRows;
95
+
96
+ var getRowMap = function getRowMap() {
97
+ var rows = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
98
+ var items = getRows(rows);
99
+ var rowMap = {};
100
+ items.forEach(function (row) {
101
+ return rowMap[row._id] = row.cells || {};
102
+ });
103
+ return rowMap;
104
+ };
105
+ /**
106
+ * Get row order for table field. If there isn't a row order set in the
107
+ * fieldSettings then it will default to the normal row array Ids.
108
+ *
109
+ * @param {String} fieldId
110
+ * @param {Object} fieldSettings
111
+ * @param {Array} rows
112
+ *
113
+ * @return {Array}
114
+ */
115
+
116
+
117
+ exports.getRowMap = getRowMap;
118
+
119
+ var getTableFieldRowOrder = function getTableFieldRowOrder(fieldId, fieldSettings, rows) {
120
+ var filteredRows = rows ? getRows(rows) : [];
121
+ return fieldSettings && fieldSettings[fieldId] && fieldSettings[fieldId].rowOrder ? (0, _toConsumableArray2["default"])(fieldSettings[fieldId].rowOrder) : filteredRows.map(function (row) {
122
+ return row._id;
123
+ });
124
+ };
125
+ /**
126
+ * Get table columns with added operands. Operands are the A, B, C, etc.
127
+ */
128
+
129
+
130
+ exports.getTableFieldRowOrder = getTableFieldRowOrder;
131
+
132
+ var getColumns = function getColumns(columns) {
133
+ var parsedColumns = columns;
134
+
135
+ if (typeof parsedColumns === 'string') {
136
+ parsedColumns = JSON.parse(parsedColumns);
137
+ }
138
+
139
+ return !parsedColumns ? [] : parsedColumns.filter(function (column) {
140
+ return !column.deleted;
141
+ }).map(function (column, i) {
142
+ var nextColumn = _objectSpread({}, column);
143
+
144
+ nextColumn.operand = getColumnOperand(i);
145
+ return nextColumn;
146
+ });
147
+ };
148
+ /**
149
+ * Return letter for a column index. For intance: A, B, C
150
+ *
151
+ * Used to create the table lookup operands: A1, B12, etc.
152
+ */
153
+
154
+
155
+ exports.getColumns = getColumns;
156
+
157
+ var getColumnOperand = function getColumnOperand(index) {
158
+ return String.fromCharCode(65 + index);
159
+ };
160
+ /**
161
+ * Get operand lookup for all table/inputGroup fields in a template.
162
+ *
163
+ * For instance: {
164
+ * fieldId: { colId: 'A', colId: 'B', ...},
165
+ * ....
166
+ * }
167
+ */
168
+
169
+
170
+ exports.getColumnOperand = getColumnOperand;
171
+
172
+ var getTemplateColumnOperandLookup = function getTemplateColumnOperandLookup(template) {
173
+ var operandLookup = {};
174
+ template.fields.forEach(function (field) {
175
+ if (field.type !== _FieldTypes["default"].table && field.type !== _FieldTypes["default"].inputGroup) return;
176
+ if (!operandLookup[field._id]) operandLookup[field._id] = {};
177
+ var columns = getColumns(field.tableColumns);
178
+ columns.forEach(function (col, colIndex) {
179
+ operandLookup[field._id][col._id] = getColumnOperand(colIndex);
180
+ });
181
+ });
182
+ return operandLookup;
183
+ };
184
+ /**
185
+ * Return operand for cell. For intance: A1, B2, C1
186
+ *
187
+ * @param {String} columnOperand //A, B, C, etc.
188
+ * @param {Number} rowIndex
189
+ */
190
+
191
+
192
+ exports.getTemplateColumnOperandLookup = getTemplateColumnOperandLookup;
193
+
194
+ var getCellOperand = function getCellOperand(columnOperand, rowIndex) {
195
+ return "".concat(columnOperand).concat(rowIndex);
196
+ };
197
+ /**
198
+ * Generate table lookup by rowIndex and column operand
199
+ *
200
+ * For instance:
201
+ * {
202
+ * rowIndex: {A1: value, B1: value, ...},
203
+ * rowIndex: {A2: value, B2: value, ...},
204
+ * rowIndex: {A3: value, B3: value, ...},
205
+ * ...
206
+ * }
207
+ *
208
+ * @param {Array} rows
209
+ * @param {Array} columns
210
+ * @param {Object} tableLookup
211
+ *
212
+ * @return {Object}
213
+
214
+ */
215
+
216
+
217
+ exports.getCellOperand = getCellOperand;
218
+
219
+ var generateRowTableLookup = function generateRowTableLookup(rows, columns, tableLookup) {
220
+ if (!rows || !columns || !tableLookup) return {};
221
+ var rowTableLookup = {};
222
+ rows.forEach(function (row, rowIndex) {
223
+ rowTableLookup[rowIndex] = {};
224
+ columns.forEach(function (column, columnIndex) {
225
+ var operand = getColumnOperand(columnIndex);
226
+ var cellOperand = getCellOperand(operand, rowIndex + 1);
227
+ rowTableLookup[rowIndex][cellOperand] = tableLookup[cellOperand];
228
+ });
229
+ });
230
+ return rowTableLookup;
231
+ };
232
+ /**
233
+ * Generate table lookups for each table field in template. It takes
234
+ * all table & inputGroup fields and generates a table lookup object for them.
235
+ *
236
+ * For instance if you have a template and doc like the ones below:
237
+ *
238
+ * template: {
239
+ * fields: [
240
+ * {_id: textFieldId, ...},
241
+ * {_id: tableFieldId1, ...},
242
+ * {_id: tableFieldId2, ...},
243
+ * {_id: numberFieldId, ...},
244
+ * ...
245
+ * ]
246
+ * }
247
+ *
248
+ * returned object would be: {
249
+ * tableFieldId1: { A1: value, B1: value, ...},
250
+ * tableFieldId2: { A2: value, B2: value, ...},
251
+ * ...
252
+ * }
253
+ */
254
+
255
+
256
+ exports.generateRowTableLookup = generateRowTableLookup;
257
+
258
+ var generateTableFieldLookups = function generateTableFieldLookups(doc, template) {
259
+ var tableFields = template.fields.filter(function (field) {
260
+ return (field.type === _FieldTypes["default"].table || field.type === _FieldTypes["default"].inputGroup) && !field.deleted;
261
+ });
262
+ var tableLookups = {};
263
+ tableFields.forEach(function (field) {
264
+ var docValue = doc.fields[field._id];
265
+ var rows = getRows(docValue);
266
+ var columns = getColumns(field.tableColumns);
267
+ var docFieldSettings = doc.fieldSettings || {};
268
+ var fieldSettings = docFieldSettings[field._id] || {};
269
+ var rowOrder = fieldSettings.rowOrder && fieldSettings.rowOrder.length !== 0 ? fieldSettings.rowOrder : rows.map(function (row) {
270
+ return row._id;
271
+ });
272
+ var validRows = sortRows(rows, rowOrder);
273
+ tableLookups[field._id] = generateTableLookup(validRows, columns);
274
+ });
275
+ return tableLookups;
276
+ };
277
+ /**
278
+ * Generate Lookup Operand Lookup Table for Table Data. Supports converting
279
+ * formula cells to the calculated value.
280
+ *
281
+ * Operand examples: A1, B12, C25, etc.
282
+ *
283
+ * @param {Array} rows
284
+ * @param {Array} columns
285
+ * @retuns {Object}
286
+ *
287
+ * Example return object:
288
+ * {
289
+ * A1: 12,
290
+ * B1: 1,
291
+ * A2: 2,
292
+ * B2: 4,
293
+ * }
294
+ *
295
+ */
296
+
297
+
298
+ exports.generateTableFieldLookups = generateTableFieldLookups;
299
+
300
+ var generateTableLookup = function generateTableLookup(rows, columns) {
301
+ var tableLookup = {};
302
+ var columnOptionsLookup = {};
303
+ var tableColumns = [];
304
+ var filteredColumns = columns.filter(function (column) {
305
+ return !column.deleted //Used by both web and mobile
306
+ && column._id !== _FieldTableCustomColumnIds["default"].rowMenu //Used on mobile
307
+ && column._id !== _FieldTableCustomColumnIds["default"].rowNumber; //Used on mobile
308
+ });
309
+ filteredColumns.forEach(function (column, i) {
310
+ var nextColumn = _objectSpread({}, column);
311
+
312
+ nextColumn.operand = String.fromCharCode(65 + i);
313
+ tableColumns.push(nextColumn);
314
+
315
+ if (column.type === _FieldTableColumnTypes["default"].dropdown) {
316
+ columnOptionsLookup[column._id] = {};
317
+ column.options.forEach(function (option) {
318
+ columnOptionsLookup[column._id][option._id] = option.value;
319
+ });
320
+ }
321
+ });
322
+ var parsedRows = typeof rows === 'string' ? JSON.parse(rows) : rows;
323
+ var tableRows = parsedRows.filter(function (row) {
324
+ return !row.deleted;
325
+ });
326
+ var formulaCells = [];
327
+ tableRows.forEach(function (row, rowIndex) {
328
+ tableColumns.forEach(function (column) {
329
+ if (!column.operand) return;
330
+ var cellKey = "".concat(column.operand).concat(rowIndex + 1);
331
+ var cellValue = row.cells[column._id] ? row.cells[column._id].trim() : undefined;
332
+ var formulaCell = cellValue !== undefined && cellValue.charAt(0) === '=';
333
+ var containsOperands = cellValue !== undefined && cellValue.match(/[A-Z]([0-9]{1,10})/gi);
334
+
335
+ if (cellValue && column.type === _FieldTableColumnTypes["default"].dropdown) {
336
+ tableLookup[cellKey] = columnOptionsLookup[column._id][cellValue];
337
+ } else if (cellValue && formulaCell && containsOperands) {
338
+ formulaCells.push(cellKey);
339
+ tableLookup[cellKey] = cellValue;
340
+ } else if (cellValue) {
341
+ tableLookup[cellKey] = cellValue;
342
+ }
343
+ });
344
+ });
345
+ formulaCells.forEach(function (sourceOperand) {
346
+ var formula = tableLookup[sourceOperand];
347
+ var invalidFormulaError = validFormulaString(sourceOperand, formula);
348
+ if (invalidFormulaError) return tableLookup[sourceOperand] = invalidFormulaError;
349
+ getFormulaResult(sourceOperand, formula, tableLookup);
350
+ });
351
+ return tableLookup;
352
+ };
353
+
354
+ exports.generateTableLookup = generateTableLookup;
355
+
356
+ var getFormulaResult = function getFormulaResult(sourceOperand, formula, tableLookup) {
357
+ formula = spreadOperandRange(formula);
358
+ var invalidFormulaError = validFormulaString(sourceOperand, formula);
359
+ if (invalidFormulaError) return tableLookup[sourceOperand] = invalidFormulaError;
360
+ var formulaOperands = formula.match(/[A-Z]([0-9]{1,10})/g);
361
+ if (!formulaOperands) return tableLookup[sourceOperand] = '*INVALID';
362
+ formulaOperands.forEach(function (operand) {
363
+ var operandValue = resolveOperandValue(sourceOperand, operand, tableLookup);
364
+ formula = formula.replace(operand, operandValue);
365
+ });
366
+ /**
367
+ * Add leading zeros to decimal numbers. hot-formula-parser throws an
368
+ * error if we try to parse non leading decimal numbers. For instace,
369
+ * a non leading decimal number is: .7 .001 etc. We convert these
370
+ * values to 0.7 & 0.001
371
+ */
372
+
373
+ var noLeadingZeroDecimalMatches = formula.match(/\D\./);
374
+
375
+ if (noLeadingZeroDecimalMatches && noLeadingZeroDecimalMatches.length > 0) {
376
+ noLeadingZeroDecimalMatches.forEach(function (val) {
377
+ var splitVals = val.split('');
378
+ var prefixCharacter = splitVals[0];
379
+ var newValue = "".concat(prefixCharacter, "0.");
380
+ formula = formula.replace(val, newValue);
381
+ });
382
+ }
383
+
384
+ formula = formula.replace('=', '');
385
+ var parsedValue = parser.parse(formula);
386
+ if (parsedValue.result) parsedValue.result = Math.round(100 * parsedValue.result) / 100;
387
+ tableLookup[sourceOperand] = parsedValue.result ? parsedValue.result.toString() : parsedValue.error;
388
+ return parsedValue;
389
+ };
390
+ /**
391
+ * Resolve operand value
392
+ * An operand is A1, B1, etc.
393
+ *
394
+ * @param sourceOperand //The cell that is requesting the value
395
+ * @param targetOperand //The cell you are trying to retrieve a value from
396
+ * @param tableLookup //The lookup of values contained in the table;
397
+ */
398
+
399
+
400
+ exports.getFormulaResult = getFormulaResult;
401
+
402
+ var resolveOperandValue = function resolveOperandValue(sourceOperand, targetOperand, tableLookup) {
403
+ var targetValue = tableLookup[targetOperand] && typeof tableLookup[targetOperand] === 'string' ? tableLookup[targetOperand].trim() : tableLookup[targetOperand]; // 1. If tableLookup doesn't have a value then return undefined
404
+
405
+ if (!targetValue) return 0; // 2. If tableLookup is already a number return the number value
406
+
407
+ if (typeof targetValue === 'number') return targetValue; // 3. If targetCell has circular reference return invalid.
408
+ //
409
+ // A circular reference can occur when C1 reference B1 and B1 references C1.
410
+ // It creates and infinite circular loop of trying to resovle a value
411
+ // because they both depend on eachother.
412
+
413
+ if (sourceOperand && hasCircularOperandReference(targetValue, sourceOperand)) return '* INVALID - Circular Reference'; // 4. If targetCell has a formula value
414
+
415
+ if (targetValue !== undefined && targetValue.charAt(0) === '=') {
416
+ var result = getFormulaResult(sourceOperand, targetValue, tableLookup);
417
+ return result.result || result.error;
418
+ } // 5. If targetCell has a normal value or an already resolved
419
+ // formula cell then just return the cell value
420
+
421
+
422
+ if (targetValue) return targetValue;
423
+ };
424
+
425
+ exports.resolveOperandValue = resolveOperandValue;
426
+
427
+ var hasCircularOperandReference = function hasCircularOperandReference(targetValue, lookupOperand) {
428
+ var regExp = new RegExp(lookupOperand, 'gi');
429
+ var foundOperandReferences = targetValue.match(regExp);
430
+ return !!(foundOperandReferences && foundOperandReferences.length > 0);
431
+ };
432
+
433
+ exports.hasCircularOperandReference = hasCircularOperandReference;
434
+
435
+ var hasOperandRange = function hasOperandRange(targetValue) {
436
+ return /[A-Z]([0-9]{1,10}):[A-Z]([0-9]{1,10})/gi.test(targetValue);
437
+ };
438
+ /**
439
+ * Check for any invalid patterns inside of the formula string
440
+ */
441
+
442
+
443
+ exports.hasOperandRange = hasOperandRange;
444
+
445
+ var validFormulaString = function validFormulaString(sourceOperand, formula) {
446
+ if (sourceOperand && hasCircularOperandReference(formula, sourceOperand)) {
447
+ return '*INVALID - Circular Reference';
448
+ }
449
+
450
+ var lowercaseOperands = formula.match(/[a-z]/g);
451
+
452
+ if (lowercaseOperands && lowercaseOperands.length > 0) {
453
+ return '*INVALID - Lowercase Letters Not Supported';
454
+ }
455
+ };
456
+ /**
457
+ * Spread the operand range into individual operands.
458
+ * For instance: SUM(A1:A4) turns into SUM(A1, A2, A3, A4);
459
+ */
460
+
461
+
462
+ exports.validFormulaString = validFormulaString;
463
+
464
+ var spreadOperandRange = function spreadOperandRange(targetValue) {
465
+ if (!hasOperandRange(targetValue)) return targetValue;
466
+ var operandRangeMatches = targetValue.match(/[A-Z]([0-9]{1,10}):[A-Z]([0-9]{1,10})/gi);
467
+ var operandRange = operandRangeMatches[0];
468
+ var operands = operandRange.split(':');
469
+ var operandA = operands[0];
470
+ var operandALetter = operandA.match(/[A-Z]+/gi) ? operandA.match(/[A-Z]+/gi)[0] : null;
471
+ var operandAIndex = operandA.match(/[0-9]+/gi) ? operandA.match(/[0-9]+/gi)[0] : null;
472
+ var operandB = operands[1];
473
+ var operandBLetter = operandB.match(/[A-Z]+/gi) ? operandB.match(/[A-Z]+/gi)[0] : null;
474
+ var operandBIndex = operandB.match(/[0-9]+/gi) ? operandB.match(/[0-9]+/gi)[0] : null; // If any values are missing return orignal targetValue
475
+
476
+ if (!operandALetter || !operandAIndex || !operandBLetter || !operandBIndex) return targetValue; // Handle row range.
477
+ // For instance: C1:C8
478
+
479
+ if (operandALetter === operandBLetter) {
480
+ var columnOperand = operandALetter;
481
+ var startIndex = parseInt(operandAIndex, 10);
482
+ var endIndex = parseInt(operandBIndex, 10);
483
+ var operandRangeValues = operandA;
484
+ var i = startIndex + 1;
485
+
486
+ while (i <= endIndex) {
487
+ operandRangeValues += ",".concat(columnOperand).concat(i);
488
+ i++;
489
+ }
490
+
491
+ targetValue = targetValue.replace(/[A-Z](\d{1,10}):[A-Z](\d{1,10})/gi, operandRangeValues);
492
+ } // Handle column range
493
+ // For instance, A1:D1
494
+ else {
495
+ var _startIndex = parseInt(_Table["default"].operandLetters.indexOf(operandALetter.toUpperCase()), 10);
496
+
497
+ var _endIndex = parseInt(_Table["default"].operandLetters.indexOf(operandBLetter.toUpperCase()), 10);
498
+
499
+ var _operandRangeValues = operandA;
500
+
501
+ var _i = _startIndex + 1;
502
+
503
+ while (_i <= _endIndex) {
504
+ var nextOperandLetter = _Table["default"].operandLetters[_i];
505
+ _operandRangeValues += ",".concat(nextOperandLetter).concat(operandAIndex);
506
+ _i++;
507
+ }
508
+
509
+ targetValue = targetValue.replace(/[A-Z](\d{1,10}):[A-Z](\d{1,10})/gi, _operandRangeValues);
510
+ }
511
+
512
+ return targetValue;
513
+ };
514
+ /**
515
+ * Primarily used for Mobile
516
+ *
517
+ * Get list of input group fields in an array formt.
518
+ * This breaks the rows and cells down to a single array.
519
+ *
520
+ * @param {Object} field
521
+ * @param {Array} columns
522
+ * @param {Array} rows
523
+ *
524
+ */
525
+
526
+
527
+ exports.spreadOperandRange = spreadOperandRange;
528
+
529
+ var generateInputGroupFields = function generateInputGroupFields(field, columns) {
530
+ var rows = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [getDefaultRow()];
531
+ var fieldSettings = arguments.length > 3 ? arguments[3] : undefined;
532
+ var tableReferences = [];
533
+ var tableColumns = getColumns(columns);
534
+ var tableRows = getRows(rows);
535
+ var rowOrder = getTableFieldRowOrder(field._id, fieldSettings, tableRows);
536
+ var sortedTableRows = sortRows(tableRows, rowOrder);
537
+ sortedTableRows.forEach(function (row, rowIndex) {
538
+ /**
539
+ * Step 1: Add InputGroup Row Header
540
+ */
541
+ tableReferences.push(_objectSpread(_objectSpread({}, field), {}, {
542
+ type: _Table.inputGroupFieldTypes.inputGroupRowHeader,
543
+ rowIndex: rowIndex,
544
+ row: row
545
+ }));
546
+ /**
547
+ * Step 2: Add Input Group Row Cells
548
+ */
549
+
550
+ tableColumns.forEach(function (column, columnIndex) {
551
+ tableReferences.push(_objectSpread(_objectSpread({}, field), {}, {
552
+ type: column.type === _FieldTableColumnTypes["default"].dropdown ? _Table.inputGroupFieldTypes.inputGroupDropdownCell : _Table.inputGroupFieldTypes.inputGroupTextCell,
553
+ rowIndex: rowIndex,
554
+ row: row,
555
+ columnIndex: columnIndex,
556
+ column: column,
557
+ docValue: row && row.cells ? row.cells[column._id] : ''
558
+ }));
559
+ });
560
+ });
561
+ return tableReferences;
562
+ };
563
+
564
+ exports.generateInputGroupFields = generateInputGroupFields;
565
+ var _default = {
566
+ generateTableLookup: generateTableLookup,
567
+ generateRowTableLookup: generateRowTableLookup,
568
+ generateInputGroupFields: generateInputGroupFields,
569
+ getColumnOperand: getColumnOperand,
570
+ getCellOperand: getCellOperand,
571
+ getRows: getRows,
572
+ getDefaultRow: getDefaultRow,
573
+ getRowMap: getRowMap,
574
+ getColumns: getColumns,
575
+ getFormulaResult: getFormulaResult,
576
+ resolveOperandValue: resolveOperandValue,
577
+ hasCircularOperandReference: hasCircularOperandReference,
578
+ validFormulaString: validFormulaString,
579
+ hasOperandRange: hasOperandRange,
580
+ spreadOperandRange: spreadOperandRange,
581
+ getTableFieldLookupKey: getTableFieldLookupKey,
582
+ getTableFieldRowOrder: getTableFieldRowOrder
583
+ };
584
+ exports["default"] = _default;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@builttocreate/engine-utils",
3
+ "version": "1.0.0",
4
+ "description": "Utility library for common logic shared across web and mobile",
5
+ "main": "dist/index.js",
6
+ "files": [
7
+ "dist/**/*",
8
+ "dist/*"
9
+ ],
10
+ "scripts": {
11
+ "clean": "rm -rf dist",
12
+ "build-src": "NODE_ENV=production babel src --out-dir dist --extensions '.js,.jsx' --ignore 'src/testUtils/*','src/**/*.stories.js','src/**/*.test.js','src/lib/**/*.test.js','src/**/__snapshots__','src/**/__mocks__'",
13
+ "build": "npm run clean && npm run build-src",
14
+ "prepublish": "npm run build",
15
+ "test": "jest",
16
+ "test-watch": "jest --watch",
17
+ "lint": "npx eslint ./src --fix",
18
+ "coverage": "jest --coverage"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/zionlabs/engine-utils.git"
23
+ },
24
+ "author": "Docspace Team",
25
+ "license": "ISC",
26
+ "bugs": {
27
+ "url": "https://github.com/zionlabs/engine-utils/issues"
28
+ },
29
+ "homepage": "https://github.com/zionlabs/engine-utils#readme",
30
+ "devDependencies": {
31
+ "@babel/cli": "^7.12.10",
32
+ "@babel/core": "^7.12.10",
33
+ "@babel/plugin-proposal-class-properties": "^7.12.1",
34
+ "@babel/plugin-transform-regenerator": "^7.12.1",
35
+ "@babel/plugin-transform-runtime": "^7.12.10",
36
+ "@babel/preset-env": "^7.12.11",
37
+ "babel-eslint": "^10.1.0",
38
+ "eslint": "^7.18.0",
39
+ "eslint-config-airbnb": "^18.2.1",
40
+ "eslint-plugin-import": "^2.22.1",
41
+ "eslint-plugin-jsx-a11y": "^6.4.1",
42
+ "eslint-plugin-react": "^7.22.0",
43
+ "jest": "^26.6.3"
44
+ },
45
+ "dependencies": {
46
+ "@babel/polyfill": "^7.12.1",
47
+ "hot-formula-parser": "^4.0.0",
48
+ "shortid": "^2.2.16"
49
+ },
50
+ "jest": {
51
+ "verbose": true,
52
+ "moduleNameMapper": {
53
+ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
54
+ "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
55
+ }
56
+ }
57
+ }