From c05e64435d53a8a2e0084a5d3140f8959b95a12d Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 19:48:11 +0800 Subject: [PATCH 01/89] feat(gui-v2): include SmartsheetColumnFormulaOptions --- packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue b/packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue index c1aa52e34d..d6e698339a 100644 --- a/packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue +++ b/packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue @@ -87,6 +87,7 @@ watchEffect(() => { + From bf88b78ba61b13ef7ddbb29e4e5f77600f9ff6df Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 19:48:29 +0800 Subject: [PATCH 02/89] feat(gui-v2): add formula utils --- packages/nc-gui-v2/utils/formulaUtils.ts | 494 +++++++++++++++++++++++ packages/nc-gui-v2/utils/index.ts | 1 + 2 files changed, 495 insertions(+) create mode 100644 packages/nc-gui-v2/utils/formulaUtils.ts diff --git a/packages/nc-gui-v2/utils/formulaUtils.ts b/packages/nc-gui-v2/utils/formulaUtils.ts new file mode 100644 index 0000000000..80306d8394 --- /dev/null +++ b/packages/nc-gui-v2/utils/formulaUtils.ts @@ -0,0 +1,494 @@ +const formulaTypes = { + NUMERIC: "numeric", + STRING: "string", + DATE: "date", + LOGICAL: "logical", + COND_EXP: "conditional_expression" +} + +const formulas = { + AVG: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1 + } + }, + description: 'Average of input parameters', + syntax: 'AVG(value1, [value2, ...])', + examples: [ + 'AVG(10, 5) => 7.5', + 'AVG({column1}, {column2})', + 'AVG({column1}, {column2}, {column3})' + ] + }, + ADD: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1 + } + }, + description: 'Sum of input parameters', + syntax: 'ADD(value1, [value2, ...])', + examples: [ + 'ADD(5, 5) => 10', + 'ADD({column1}, {column2})', + 'ADD({column1}, {column2}, {column3})' + ] + }, + DATEADD: { + type: formulaTypes.DATE, + validation: { + args: { + rqd: 3 + } + }, + description: 'Adds a "count" units to Datetime.', + syntax: 'DATEADD(date | datetime, value, ["day" | "week" | "month" | "year"])', + examples: [ + 'DATEADD({column1}, 2, "day")', + 'DATEADD({column1}, -2, "day")', + 'DATEADD({column1}, 2, "week")', + 'DATEADD({column1}, -2, "week")', + 'DATEADD({column1}, 2, "month")', + 'DATEADD({column1}, -2, "month")', + 'DATEADD({column1}, 2, "year")', + 'DATEADD({column1}, -2, "year")' + ] + }, + AND: { + type: formulaTypes.COND_EXP, + validation: { + args: { + min: 1 + } + }, + description: 'TRUE if all expr evaluate to TRUE', + syntax: 'AND(expr1, [expr2, ...])', + examples: [ + 'AND(5 > 2, 5 < 10) => 1', + 'AND({column1} > 2, {column2} < 10)' + ] + }, + OR: { + type: formulaTypes.COND_EXP, + validation: { + args: { + min: 1 + } + }, + description: 'TRUE if at least one expr evaluates to TRUE', + syntax: 'OR(expr1, [expr2, ...])', + examples: [ + 'OR(5 > 2, 5 < 10) => 1', + 'OR({column1} > 2, {column2} < 10)' + ] + }, + CONCAT: { + type: formulaTypes.STRING, + validation: { + args: { + min: 1 + } + }, + description: 'Concatenated string of input parameters', + syntax: 'CONCAT(str1, [str2, ...])', + examples: [ + 'CONCAT("AA", "BB", "CC") => "AABBCC"', + 'CONCAT({column1}, {column2}, {column3})' + ] + }, + TRIM: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 1 + } + }, + description: 'Remove trailing and leading whitespaces from input parameter', + syntax: 'TRIM(str)', + examples: [ + 'TRIM(" HELLO WORLD ") => "HELLO WORLD"', + 'TRIM({column1})' + ] + }, + UPPER: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 1 + } + }, + description: 'Upper case converted string of input parameter', + syntax: 'UPPER(str)', + examples: [ + 'UPPER("nocodb") => "NOCODB"', + 'UPPER({column1})' + ] + }, + LOWER: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 1 + } + }, + description: 'Lower case converted string of input parameter', + syntax: 'LOWER(str)', + examples: [ + 'LOWER("NOCODB") => "nocodb"', + 'LOWER({column1})' + ] + }, + LEN: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 1 + } + }, + description: 'Input parameter character length', + syntax: 'LEN(value)', + examples: [ + 'LEN("NocoDB") => 6', + 'LEN({column1})' + ] + }, + MIN: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1 + } + }, + description: 'Minimum value amongst input parameters', + syntax: 'MIN(value1, [value2, ...])', + examples: [ + 'MIN(1000, 2000) => 1000', + 'MIN({column1}, {column2})' + ] + }, + MAX: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1 + } + }, + description: 'Maximum value amongst input parameters', + syntax: 'MAX(value1, [value2, ...])', + examples: [ + 'MAX(1000, 2000) => 2000', + 'MAX({column1}, {column2})' + ] + }, + CEILING: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Rounded next largest integer value of input parameter', + syntax: 'CEILING(value)', + examples: [ + 'CEILING(1.01) => 2', + 'CEILING({column1})' + ] + }, + FLOOR: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Rounded largest integer less than or equal to input parameter', + syntax: 'FLOOR(value)', + examples: [ + 'FLOOR(3.1415) => 3', + 'FLOOR({column1})' + ] + }, + ROUND: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Nearest integer to the input parameter', + syntax: 'ROUND(value)', + examples: [ + 'ROUND(3.1415) => 3', + 'ROUND({column1})' + ] + }, + MOD: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 2 + } + }, + description: 'Remainder after integer division of input parameters', + syntax: 'MOD(value1, value2)', + examples: [ + 'MOD(1024, 1000) => 24', + 'MOD({column}, 2)' + ] + }, + REPEAT: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 2 + } + }, + description: 'Specified copies of the input parameter string concatenated together', + syntax: 'REPEAT(str, count)', + examples: [ + 'REPEAT("A", 5) => "AAAAA"', + 'REPEAT({column}, 5)' + ] + }, + LOG: { + type: formulaTypes.NUMERIC, + validation: {}, + description: 'Logarithm of input parameter to the base (default = e) specified', + syntax: 'LOG([base], value)', + examples: [ + 'LOG(2, 1024) => 10', + 'LOG(2, {column1})' + ] + }, + EXP: { + type: formulaTypes.NUMERIC, + validation: {}, + description: 'Exponential value of input parameter (e ^ power)', + syntax: 'EXP(power)', + examples: [ + 'EXP(1) => 2.718281828459045', + 'EXP({column1})' + ] + }, + POWER: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 2 + } + }, + description: 'base to the exponent power, as in base ^ exponent', + syntax: 'POWER(base, exponent)', + examples: [ + 'POWER(2, 10) => 1024', + 'POWER({column1}, 10)' + ] + }, + SQRT: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Square root of the input parameter', + syntax: 'SQRT(value)', + examples: [ + 'SQRT(100) => 10', + 'SQRT({column1})' + ] + }, + ABS: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Absolute value of the input parameter', + syntax: 'ABS(value)', + examples: [ + 'ABS({column1})' + ] + }, + NOW: { + type: formulaTypes.DATE, + validation: { + args: { + rqd: 0 + } + }, + description: 'Returns the current time and day', + syntax: 'NOW()', + examples: [ + 'NOW() => 2022-05-19 17:20:43' + ] + }, + REPLACE: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 3 + } + }, + description: 'String, after replacing all occurrences of srchStr with rplcStr', + syntax: 'REPLACE(str, srchStr, rplcStr)', + examples: [ + 'REPLACE("AABBCC", "AA", "BB") => "BBBBCC"', + 'REPLACE({column1}, {column2}, {column3})' + ] + }, + SEARCH: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 2 + } + }, + description: 'Index of srchStr specified if found, 0 otherwise', + syntax: 'SEARCH(str, srchStr)', + examples: [ + 'SEARCH("HELLO WORLD", "WORLD") => 7', + 'SEARCH({column1}, "abc")' + ] + }, + INT: { + type: formulaTypes.NUMERIC, + validation: { + args: { + rqd: 1 + } + }, + description: 'Integer value of input parameter', + syntax: 'INT(value)', + examples: [ + 'INT(3.1415) => 3', + 'INT({column1})' + ] + }, + RIGHT: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 2 + } + }, + description: 'n characters from the end of input parameter', + syntax: 'RIGHT(str, n)', + examples: [ + 'RIGHT("HELLO WORLD", 5) => WORLD', + 'RIGHT({column1}, 3)' + ] + }, + LEFT: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 2 + } + }, + description: 'n characters from the beginning of input parameter', + syntax: 'LEFT(str, n)', + examples: [ + 'LEFT({column1}, 2)', + 'LEFT("ABCD", 2) => "AB"' + ] + }, + SUBSTR: { + type: formulaTypes.STRING, + validation: { + args: { + min: 2, + max: 3 + } + }, + description: 'Substring of length n of input string from the postition specified', + syntax: ' SUBTR(str, position, [n])', + examples: [ + 'SUBSTR("HELLO WORLD", 7) => WORLD', + 'SUBSTR("HELLO WORLD", 7, 3) => WOR', + 'SUBSTR({column1}, 7, 5)' + ] + }, + MID: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 3 + } + }, + description: 'Alias for SUBSTR', + syntax: 'MID(str, position, [count])', + examples: [ + 'MID("NocoDB", 3, 2) => "co"', + 'MID({column1}, 3, 2)' + ] + }, + IF: { + type: formulaTypes.COND_EXP, + validation: { + args: { + min: 2, + max: 3 + } + }, + description: 'SuccessCase if expr evaluates to TRUE, elseCase otherwise', + syntax: 'IF(expr, successCase, elseCase)', + examples: [ + 'IF(5 > 1, "YES", "NO") => "YES"', + 'IF({column} > 1, "YES", "NO")' + ] + }, + SWITCH: { + type: formulaTypes.COND_EXP, + validation: { + args: { + min: 3 + } + }, + description: 'Switch case value based on expr output', + syntax: 'SWITCH(expr, [pattern, value, ..., default])', + examples: [ + 'SWITCH(1, 1, "One", 2, "Two", "N/A") => "One""', + 'SWITCH(2, 1, "One", 2, "Two", "N/A") => "Two"', + 'SWITCH(3, 1, "One", 2, "Two", "N/A") => "N/A"', + 'SWITCH({column1}, 1, "One", 2, "Two", "N/A")' + ] + }, + URL: { + type: formulaTypes.STRING, + validation: { + args: { + rqd: 1 + } + }, + description: 'Convert to a hyperlink if it is a valid URL', + syntax: 'URL(str)', + examples: [ + 'URL("https://github.com/nocodb/nocodb")', + 'URL({column1})' + ] + }, + WEEKDAY: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1, + max: 2, + } + }, + description: 'Returns the day of the week as an integer between 0 and 6 inclusive starting from Monday by default', + syntax: 'WEEKDAY(date, [startDayOfWeek])', + examples: [ + 'WEEKDAY("2021-06-09")', + 'WEEKDAY(NOW(), "sunday")' + ] + } +} + +const formulaList = Object.keys(formulas) + +export { formulaList, formulas, formulaTypes } diff --git a/packages/nc-gui-v2/utils/index.ts b/packages/nc-gui-v2/utils/index.ts index fb53c2b25d..51b714866d 100644 --- a/packages/nc-gui-v2/utils/index.ts +++ b/packages/nc-gui-v2/utils/index.ts @@ -1,6 +1,7 @@ export * from './colorsUtils' export * from './dateTimeUtils' export * from './deepCompare' +export * from './formulaUtils' export * from './durationUtils' export * from './errorUtils' export * from './fileUtils' From 6150d4785a893a05ab593488b943f63f2b069c98 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 19:48:41 +0800 Subject: [PATCH 03/89] wip(gui-v2): formula options --- .../smartsheet-column/FormulaOptions.vue | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue diff --git a/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue b/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue new file mode 100644 index 0000000000..680a763c1a --- /dev/null +++ b/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue @@ -0,0 +1,123 @@ + + + From 34bee526cf1d2a862a4a730af61b849eb878cfa5 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 20:19:28 +0800 Subject: [PATCH 04/89] feat(gui-v2): add jsep --- packages/nc-gui-v2/package-lock.json | 14 ++++++++++++++ packages/nc-gui-v2/package.json | 1 + 2 files changed, 15 insertions(+) diff --git a/packages/nc-gui-v2/package-lock.json b/packages/nc-gui-v2/package-lock.json index 082fb125b8..eab7b55eac 100644 --- a/packages/nc-gui-v2/package-lock.json +++ b/packages/nc-gui-v2/package-lock.json @@ -11,6 +11,7 @@ "ant-design-vue": "^3.2.10", "dayjs": "^1.11.3", "file-saver": "^2.0.5", + "jsep": "^1.3.6", "jwt-decode": "^3.1.2", "locale-codes": "^1.3.1", "monaco-editor": "^0.33.0", @@ -8785,6 +8786,14 @@ "node": ">=12" } }, + "node_modules/jsep": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.6.tgz", + "integrity": "sha512-o7fP1eZVROIChADx7HKiwGRVI0tUqgUUGhaok6DP7cMxpDeparuooREDBDeNk2G5KIB49MBSkRYsCOu4PmZ+1w==", + "engines": { + "node": ">= 10.16.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -21278,6 +21287,11 @@ } } }, + "jsep": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.6.tgz", + "integrity": "sha512-o7fP1eZVROIChADx7HKiwGRVI0tUqgUUGhaok6DP7cMxpDeparuooREDBDeNk2G5KIB49MBSkRYsCOu4PmZ+1w==" + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", diff --git a/packages/nc-gui-v2/package.json b/packages/nc-gui-v2/package.json index 30894765ad..a03599eec8 100644 --- a/packages/nc-gui-v2/package.json +++ b/packages/nc-gui-v2/package.json @@ -17,6 +17,7 @@ "ant-design-vue": "^3.2.10", "dayjs": "^1.11.3", "file-saver": "^2.0.5", + "jsep": "^1.3.6", "jwt-decode": "^3.1.2", "locale-codes": "^1.3.1", "monaco-editor": "^0.33.0", From 721a8c8dfe2dfddacb622a19b064ad1129f8bde5 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 20:26:03 +0800 Subject: [PATCH 05/89] feat(gui-v2): export column in useColumnCreateStore --- packages/nc-gui-v2/composables/useColumnCreateStore.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nc-gui-v2/composables/useColumnCreateStore.ts b/packages/nc-gui-v2/composables/useColumnCreateStore.ts index 50328a7b0e..535f6c522f 100644 --- a/packages/nc-gui-v2/composables/useColumnCreateStore.ts +++ b/packages/nc-gui-v2/composables/useColumnCreateStore.ts @@ -211,6 +211,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState addOrUpdate, generateNewColumnMeta, isEdit: !!column?.id, + column } }) From 9e57d8fcd90c368b6ef9013f7ac5dac6036efcbe Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Wed, 3 Aug 2022 20:26:37 +0800 Subject: [PATCH 06/89] feat(gui-v2): add useProvideColumnCreateStore --- .../components/smartsheet-header/VirtualCell.vue | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue b/packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue index 187b30cb6d..3d89d148f0 100644 --- a/packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue +++ b/packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue @@ -1,10 +1,17 @@ \ No newline at end of file + From a8d89309b62ded986efbc51a26e4728a077aac3b Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Thu, 4 Aug 2022 20:07:21 +0800 Subject: [PATCH 30/89] fix(gui-v2): type-related issues in formula option --- .../smartsheet-column/FormulaOptions.vue | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue b/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue index 23729d802e..081d2dae61 100644 --- a/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue +++ b/packages/nc-gui-v2/components/smartsheet-column/FormulaOptions.vue @@ -20,6 +20,18 @@ import MdiFunctionIcon from '~icons/mdi/function' import MdiColumnIcon from '~icons/mdi/view-column-outline' import MdiOperatorIcon from '~icons/mdi/calculator' +enum JSEPNode { + COMPOUND = 'Compound', + IDENTIFIER = 'Identifier', + MEMBER_EXP = 'MemberExpression', + LITERAL = 'Literal', + THIS_EXP = 'ThisExpression', + CALL_EXP = 'CallExpression', + UNARY_EXP = 'UnaryExpression', + BINARY_EXP = 'BinaryExpression', + ARRAY_EXP = 'ArrayExpression', +} + const { formState, validateInfos, setAdditionalValidations, sqlUi, onDataTypeChange, onAlter, column } = useColumnCreateStoreOrThrow() @@ -76,8 +88,8 @@ const suggestionsList = computed(() => { const unsupportedFnList = sqlUi.value.getUnsupportedFnList() return [ ...availableFunctions - .filter((fn) => !unsupportedFnList.includes(fn)) - .map((fn) => ({ + .filter((fn: string) => !unsupportedFnList.includes(fn)) + .map((fn: string) => ({ text: `${fn}()`, type: 'function', description: formulas[fn].description, @@ -127,7 +139,7 @@ function parseAndValidateFormula(formula: string) { } function validateAgainstMeta(parsedTree: any, errors = new Set(), typeErrors = new Set()) { - if (parsedTree.type === jsep.CALL_EXP) { + if (parsedTree.type === JSEPNode.CALL_EXP) { // validate function name if (!availableFunctions.includes(parsedTree.callee.name)) { errors.add(`'${parsedTree.callee.name}' function is not available`) @@ -146,7 +158,7 @@ function validateAgainstMeta(parsedTree: any, errors = new Set(), typeErrors = n parsedTree.arguments.map((arg: Record) => validateAgainstMeta(arg, errors)) // validate data type - if (parsedTree.callee.type === jsep.IDENTIFIER) { + if (parsedTree.callee.type === JSEPNode.IDENTIFIER) { const expectedType = formulas[parsedTree.callee.name].type if (expectedType === formulaTypes.NUMERIC) { if (parsedTree.callee.name === 'WEEKDAY') { @@ -220,7 +232,7 @@ function validateAgainstMeta(parsedTree: any, errors = new Set(), typeErrors = n } errors = new Set([...errors, ...typeErrors]) - } else if (parsedTree.type === jsep.IDENTIFIER) { + } else if (parsedTree.type === JSEPNode.IDENTIFIER) { if ( columns.value .filter((c: Record) => !column || column.id !== c.id) @@ -304,15 +316,15 @@ function validateAgainstMeta(parsedTree: any, errors = new Set(), typeErrors = n errors.add('Can’t save field because it causes a circular reference') } } - } else if (parsedTree.type === jsep.BINARY_EXP) { + } else if (parsedTree.type === JSEPNode.BINARY_EXP) { if (!availableBinOps.includes(parsedTree.operator)) { errors.add(`'${parsedTree.operator}' operation is not available`) } validateAgainstMeta(parsedTree.left, errors) validateAgainstMeta(parsedTree.right, errors) - } else if (parsedTree.type === jsep.LITERAL || parsedTree.type === jsep.UNARY_EXP) { + } else if (parsedTree.type === JSEPNode.LITERAL || parsedTree.type === JSEPNode.UNARY_EXP) { // do nothing - } else if (parsedTree.type === jsep.COMPOUND) { + } else if (parsedTree.type === JSEPNode.COMPOUND) { if (parsedTree.body.length) { errors.add('Can’t save field because the formula is invalid') } @@ -326,7 +338,7 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t if (parsedTree === false || typeof parsedTree === 'undefined') { return typeErrors } - if (parsedTree.type === jsep.LITERAL) { + if (parsedTree.type === JSEPNode.LITERAL) { if (typeof func === 'function') { func(parsedTree.value) } else if (expectedType === formulaTypes.NUMERIC) { @@ -338,7 +350,7 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t typeErrors.add('string type is expected') } } - } else if (parsedTree.type === jsep.IDENTIFIER) { + } else if (parsedTree.type === JSEPNode.IDENTIFIER) { const col = columns.value.find((c) => c.title === parsedTree.name) as Record if (col === undefined) { return @@ -412,12 +424,12 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t break } } - } else if (parsedTree.type === jsep.UNARY_EXP || parsedTree.type === jsep.BINARY_EXP) { + } else if (parsedTree.type === JSEPNode.UNARY_EXP || parsedTree.type === JSEPNode.BINARY_EXP) { if (expectedType !== formulaTypes.NUMERIC) { // parsedTree.name won't be available here typeErrors.add(`${formulaTypes.NUMERIC} type is found but ${expectedType} type is expected`) } - } else if (parsedTree.type === jsep.CALL_EXP) { + } else if (parsedTree.type === JSEPNode.CALL_EXP) { if (formulas[parsedTree.callee.name]?.type && expectedType !== formulas[parsedTree.callee.name].type) { typeErrors.add(`${expectedType} not matched with ${formulas[parsedTree.callee.name].type}`) } @@ -427,9 +439,9 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t function getRootDataType(parsedTree: any): any { // given a parse tree, return the data type of it - if (parsedTree.type === jsep.CALL_EXP) { + if (parsedTree.type === JSEPNode.CALL_EXP) { return formulas[parsedTree.callee.name].type - } else if (parsedTree.type === jsep.IDENTIFIER) { + } else if (parsedTree.type === JSEPNode.IDENTIFIER) { const col = columns.value.find((c) => c.title === parsedTree.name) as Record if (col?.uidt === UITypes.Formula) { return getRootDataType(jsep(col?.colOptions?.formula_raw)) @@ -479,9 +491,9 @@ function getRootDataType(parsedTree: any): any { return 'N/A' } } - } else if (parsedTree.type === jsep.BINARY_EXP || parsedTree.type === jsep.UNARY_EXP) { + } else if (parsedTree.type === JSEPNode.BINARY_EXP || parsedTree.type === JSEPNode.UNARY_EXP) { return formulaTypes.NUMERIC - } else if (parsedTree.type === jsep.LITERAL) { + } else if (parsedTree.type === JSEPNode.LITERAL) { return typeof parsedTree.value } else { return 'N/A' @@ -525,7 +537,9 @@ function handleInput() { const query = getWordUntilCaret(formulaRef.value.$el) const parts = query.split(/\W+/) wordToComplete.value = parts.pop() || '' - suggestion.value = acTree.value.complete(wordToComplete.value)?.sort((x, y) => sortOrder[x.type] - sortOrder[y.type]) // TODO: check .type + suggestion.value = acTree.value + .complete(wordToComplete.value) + ?.sort((x: Record, y: Record) => sortOrder[x.type] - sortOrder[y.type]) if (!isCurlyBracketBalanced()) { suggestion.value = suggestion.value.filter((v: Record) => v.type === 'column') } @@ -597,7 +611,6 @@ onMounted(() => {