@fw-components/formula-editor 2.3.4-linting.1 → 2.3.4-notion-update.1
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/dist/{formula-editor.js → formula-editor/src/formula-editor.js} +16 -26
- package/dist/{suggestion-menu.js → formula-editor/src/suggestion-menu.js} +5 -6
- package/dist/{utils → formula-editor/src/utils}/parser.js +36 -33
- package/package.json +14 -8
- package/tsconfig.json +19 -8
- /package/dist/{styles → formula-editor/src/styles}/editor.js +0 -0
- /package/dist/{styles → formula-editor/src/styles}/suggestion-menu.js +0 -0
- /package/dist/{types → formula-editor/src/types}/index.js +0 -0
- /package/dist/{utils → formula-editor/src/utils}/constants.js +0 -0
- /package/dist/{utils → formula-editor/src/utils}/get-formula-tokens.js +0 -0
- /package/dist/{utils → formula-editor/src/utils}/queue.js +0 -0
- /package/dist/{utils → formula-editor/src/utils}/recommendor.js +0 -0
- /package/dist/{utils → formula-editor/src/utils}/stack.js +0 -0
|
@@ -5,20 +5,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, LitElement } from "lit";
|
|
8
|
-
import { customElement, property,
|
|
9
|
-
import
|
|
8
|
+
import { customElement, property, state, query } from "lit/decorators.js";
|
|
9
|
+
import "./suggestion-menu.js";
|
|
10
10
|
import { Parser } from "./utils/parser.js";
|
|
11
11
|
import { FormulaEditorStyles } from "./styles/editor.js";
|
|
12
|
+
import { getFormulaTokens } from "./utils/get-formula-tokens.js";
|
|
12
13
|
let FormulaEditor = class FormulaEditor extends LitElement {
|
|
13
14
|
constructor() {
|
|
14
15
|
super(...arguments);
|
|
15
16
|
this.recommendations = [];
|
|
16
17
|
this.currentCursorPosition = 0;
|
|
17
|
-
/**
|
|
18
|
-
* user input event type
|
|
19
|
-
*/
|
|
20
|
-
this.lastInputType = "";
|
|
21
|
-
this._selectedRecommendation = "";
|
|
22
18
|
this.isFocused = false;
|
|
23
19
|
/**
|
|
24
20
|
* Text area input value
|
|
@@ -26,14 +22,10 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
26
22
|
this.formulaString = "";
|
|
27
23
|
this.placeholder = "Type your formula...";
|
|
28
24
|
this.recommendationLabels = new Map();
|
|
29
|
-
this.label = "";
|
|
30
25
|
this.variables = new Map();
|
|
31
|
-
this.variableType = "";
|
|
32
26
|
this.minSuggestionLen = 2;
|
|
33
27
|
this.errorString = "";
|
|
34
|
-
this.formulaRegex = /.*/;
|
|
35
28
|
this.allowedNumbers = true;
|
|
36
|
-
this.allowedOperators = new Set();
|
|
37
29
|
}
|
|
38
30
|
updated(_changedProperties) {
|
|
39
31
|
if (_changedProperties.has("formulaString")) {
|
|
@@ -74,7 +66,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
74
66
|
this.currentCursorPosition = this.editor.selectionStart;
|
|
75
67
|
const { recommendations, errorString, formattedString, newCursorPosition } = this._parser.parseInput(this.formulaString, this.currentCursorPosition, recommendation);
|
|
76
68
|
this.recommendations = recommendations;
|
|
77
|
-
this.errorString = errorString
|
|
69
|
+
this.errorString = errorString;
|
|
78
70
|
/**
|
|
79
71
|
* Don't modify the text stream manually if the text is being composed,
|
|
80
72
|
* unless the user manually chooses to do so by selecting a recommendation.
|
|
@@ -100,7 +92,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
100
92
|
recommendations: this.recommendations,
|
|
101
93
|
formulaTokens: getFormulaTokens(this.formulaString || "", this.formulaRegex)
|
|
102
94
|
},
|
|
103
|
-
bubbles: true
|
|
95
|
+
bubbles: true,
|
|
104
96
|
}));
|
|
105
97
|
}
|
|
106
98
|
formatFormula() {
|
|
@@ -139,9 +131,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
139
131
|
}
|
|
140
132
|
render() {
|
|
141
133
|
return html `
|
|
142
|
-
<style>
|
|
143
|
-
${FormulaEditorStyles}
|
|
144
|
-
</style>
|
|
134
|
+
<style>${FormulaEditorStyles}</style>
|
|
145
135
|
|
|
146
136
|
${this.label ? html `<label for="fw-formula-editor" class="editor-label">${this.label}</label>` : ""}
|
|
147
137
|
|
|
@@ -165,7 +155,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
165
155
|
.onRecommendationClick=${this.onRecommendationClick.bind(this)}
|
|
166
156
|
.recommendationLabels=${this.recommendationLabels}
|
|
167
157
|
></suggestion-menu>`
|
|
168
|
-
:
|
|
158
|
+
: ''}
|
|
169
159
|
`;
|
|
170
160
|
}
|
|
171
161
|
};
|
|
@@ -191,31 +181,31 @@ __decorate([
|
|
|
191
181
|
property()
|
|
192
182
|
], FormulaEditor.prototype, "placeholder", void 0);
|
|
193
183
|
__decorate([
|
|
194
|
-
property(
|
|
184
|
+
property()
|
|
195
185
|
], FormulaEditor.prototype, "recommendationLabels", void 0);
|
|
196
186
|
__decorate([
|
|
197
|
-
property(
|
|
187
|
+
property()
|
|
198
188
|
], FormulaEditor.prototype, "label", void 0);
|
|
199
189
|
__decorate([
|
|
200
|
-
property(
|
|
190
|
+
property()
|
|
201
191
|
], FormulaEditor.prototype, "variables", void 0);
|
|
202
192
|
__decorate([
|
|
203
|
-
property(
|
|
193
|
+
property()
|
|
204
194
|
], FormulaEditor.prototype, "variableType", void 0);
|
|
205
195
|
__decorate([
|
|
206
|
-
property(
|
|
196
|
+
property()
|
|
207
197
|
], FormulaEditor.prototype, "minSuggestionLen", void 0);
|
|
208
198
|
__decorate([
|
|
209
|
-
property(
|
|
199
|
+
property()
|
|
210
200
|
], FormulaEditor.prototype, "errorString", void 0);
|
|
211
201
|
__decorate([
|
|
212
|
-
property(
|
|
202
|
+
property()
|
|
213
203
|
], FormulaEditor.prototype, "formulaRegex", void 0);
|
|
214
204
|
__decorate([
|
|
215
|
-
property(
|
|
205
|
+
property()
|
|
216
206
|
], FormulaEditor.prototype, "allowedNumbers", void 0);
|
|
217
207
|
__decorate([
|
|
218
|
-
property(
|
|
208
|
+
property()
|
|
219
209
|
], FormulaEditor.prototype, "allowedOperators", void 0);
|
|
220
210
|
__decorate([
|
|
221
211
|
query("#fw-formula-editor")
|
|
@@ -45,13 +45,12 @@ let SuggestionMenu = class SuggestionMenu extends LitElement {
|
|
|
45
45
|
}
|
|
46
46
|
render() {
|
|
47
47
|
return html `
|
|
48
|
-
<style>
|
|
49
|
-
${SuggestionMenuStyles}
|
|
50
|
-
</style>
|
|
48
|
+
<style>${SuggestionMenuStyles}</style>
|
|
51
49
|
<ul class="fw-formula-suggestion-menu" @mousedown=${(e) => e.preventDefault()}>
|
|
52
|
-
${this.recommendations.map((recommendation, index) => html `<li
|
|
53
|
-
${this.
|
|
54
|
-
|
|
50
|
+
${this.recommendations.map((recommendation, index) => html `<li
|
|
51
|
+
class="${this._currentFocusedIndex === index ? "selected" : ""}"
|
|
52
|
+
@click=${(e) => this.handleRecommendationSelect(index)}
|
|
53
|
+
>${this.recommendationLabels.get(recommendation) ?? recommendation}</li>`)}
|
|
55
54
|
</ul>
|
|
56
55
|
`;
|
|
57
56
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { getFormulaTokens } from "./get-formula-tokens.js";
|
|
3
|
-
import { Queue } from "./queue.js";
|
|
1
|
+
import Big from "big.js";
|
|
4
2
|
import { Recommender } from "./recommendor.js";
|
|
5
3
|
import { Stack } from "./stack.js";
|
|
6
|
-
import
|
|
4
|
+
import { Queue } from "./queue.js";
|
|
7
5
|
import { Expectation } from "../types";
|
|
6
|
+
import { operatorPrecedence, unaryOperators, mathematicalOperators } from "./constants.js";
|
|
7
|
+
import { getFormulaTokens } from "./get-formula-tokens.js";
|
|
8
8
|
export class Parser {
|
|
9
9
|
constructor(variables, minSuggestionLen, formulaRegex = /[A-Za-z0-9_#@.]+|[-+(),*^/\s]/g, allowedNumbers = true, allowedOperators = mathematicalOperators, variableType = "") {
|
|
10
10
|
this.variables = variables;
|
|
@@ -20,7 +20,7 @@ export class Parser {
|
|
|
20
20
|
return !Number.isNaN(Number(value));
|
|
21
21
|
}
|
|
22
22
|
formatFormulaToken(token) {
|
|
23
|
-
for (
|
|
23
|
+
for (let existingKey of this.variables.keys()) {
|
|
24
24
|
if (existingKey.toLowerCase() === token.toLowerCase()) {
|
|
25
25
|
return existingKey;
|
|
26
26
|
}
|
|
@@ -38,7 +38,7 @@ export class Parser {
|
|
|
38
38
|
recommendations: [],
|
|
39
39
|
formattedString: "",
|
|
40
40
|
newCursorPosition: prevCurPos ?? -1,
|
|
41
|
-
errorString: null
|
|
41
|
+
errorString: null,
|
|
42
42
|
};
|
|
43
43
|
if (!formula.trim() && recommendation) {
|
|
44
44
|
parseOutput.formattedString = recommendation;
|
|
@@ -73,6 +73,7 @@ export class Parser {
|
|
|
73
73
|
recommendation = null;
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
|
+
;
|
|
76
77
|
const updatedTokenLength = recommendation.length - token.length;
|
|
77
78
|
parseOutput.newCursorPosition = Math.min(parseOutput.newCursorPosition, formula.length) + updatedTokenLength;
|
|
78
79
|
token = recommendation;
|
|
@@ -83,7 +84,7 @@ export class Parser {
|
|
|
83
84
|
/**
|
|
84
85
|
* Error checks
|
|
85
86
|
* skip error check if there is one already
|
|
86
|
-
|
|
87
|
+
*/
|
|
87
88
|
if (expectation != Expectation.UNDEFINED) {
|
|
88
89
|
/**
|
|
89
90
|
* Unknown symbol/variable/word
|
|
@@ -100,37 +101,33 @@ export class Parser {
|
|
|
100
101
|
parseOutput.errorString = "Unexpected closing bracket. Make sure all opening brackets '(' have matching closing brackets ')'.";
|
|
101
102
|
expectation = Expectation.UNDEFINED;
|
|
102
103
|
}
|
|
103
|
-
else if (
|
|
104
104
|
/**
|
|
105
105
|
* Operator or ')' after an operator (Eg: '23 / *' or '23 / )')
|
|
106
106
|
* No error for Unary `+` and `-` as they might represent a positive or negative number respectively
|
|
107
107
|
*/
|
|
108
|
-
expectation === Expectation.VARIABLE &&
|
|
109
|
-
!
|
|
110
|
-
|
|
111
|
-
token != "(" &&
|
|
112
|
-
!(unaryOperators.includes(token) && (!parsedString.trim() || previousToken === "(" || this.allowedOperators.has(previousToken)))) {
|
|
113
|
-
parseOutput.errorString = `Please use ${this.variableType} ${this.variableType && this.allowedNumbers ? " or " : ""} ${this.allowedNumbers ? "numbers" : ""} after '${previousToken}'.`;
|
|
108
|
+
else if (expectation === Expectation.VARIABLE && !isNumber && !isSpace && token != "("
|
|
109
|
+
&& !((unaryOperators.includes(token)) && (!parsedString.trim() || previousToken === "(" || this.allowedOperators.has(previousToken)))) {
|
|
110
|
+
parseOutput.errorString = `Please use ${this.variableType} ${this.variableType && this.allowedNumbers ? " or " : ''} ${this.allowedNumbers ? "numbers" : ""} after '${previousToken}'.`;
|
|
114
111
|
expectation = Expectation.UNDEFINED;
|
|
115
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Multiple number/variable together without operator
|
|
115
|
+
*/
|
|
116
116
|
else if (expectation === Expectation.OPERATOR && !isOperator && !isSpace && token != ")") {
|
|
117
|
-
/**
|
|
118
|
-
* Multiple number/variable together without operator
|
|
119
|
-
*/
|
|
120
117
|
parseOutput.errorString = `Please use mathematical operators (${Array.from(this.allowedOperators).join(" ")}) after '${previousToken}'.`;
|
|
121
118
|
expectation = Expectation.UNDEFINED;
|
|
122
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* division by zero
|
|
122
|
+
*/
|
|
123
123
|
else if (isNumber && previousToken === "/" && (this.variables.get(token) === 0 || Number(token) === 0)) {
|
|
124
|
-
/**
|
|
125
|
-
* division by zero
|
|
126
|
-
*/
|
|
127
124
|
parseOutput.errorString = `Division by zero is not possible.`;
|
|
128
125
|
expectation = Expectation.UNDEFINED;
|
|
129
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Empty brackets
|
|
129
|
+
*/
|
|
130
130
|
else if (previousToken === "(" && token === ")") {
|
|
131
|
-
/**
|
|
132
|
-
* Empty brackets
|
|
133
|
-
*/
|
|
134
131
|
parseOutput.errorString = `Please don't use empty brackets ().`;
|
|
135
132
|
expectation = Expectation.UNDEFINED;
|
|
136
133
|
}
|
|
@@ -181,7 +178,7 @@ export class Parser {
|
|
|
181
178
|
let currentTokens = "";
|
|
182
179
|
// Check if variables include unary operators `-` and `+`.
|
|
183
180
|
for (const token of tokens) {
|
|
184
|
-
if (unaryOperators.includes(token) && (!currentTokens.trim() || previousToken === "(" || this.allowedOperators.has(previousToken))) {
|
|
181
|
+
if ((unaryOperators.includes(token)) && (!currentTokens.trim() || previousToken === "(" || this.allowedOperators.has(previousToken))) {
|
|
185
182
|
carriedToken = token;
|
|
186
183
|
}
|
|
187
184
|
else if (carriedToken) {
|
|
@@ -238,7 +235,7 @@ export class Parser {
|
|
|
238
235
|
let parsedLeftExpression;
|
|
239
236
|
let parsedRightExpression;
|
|
240
237
|
// check if the symbol is a number or variable or unaryOperatorPreceded Variable
|
|
241
|
-
if ((unaryOperators.includes(symbol[0]) && this.variables.has(symbol.substring(1))) ||
|
|
238
|
+
if (((unaryOperators.includes(symbol[0])) && this.variables.has(symbol.substring(1))) ||
|
|
242
239
|
this.variables.has(symbol) ||
|
|
243
240
|
(!Number.isNaN(parseFloat(symbol)) && Number.isFinite(parseFloat(symbol)))) {
|
|
244
241
|
resultStack.push(symbol);
|
|
@@ -246,14 +243,21 @@ export class Parser {
|
|
|
246
243
|
}
|
|
247
244
|
// If symbol is an operator, check operatorStack, adds brackets accordingly to the result and add it to operatorStack
|
|
248
245
|
else if (Object.keys(operatorPrecedence).includes(symbol)) {
|
|
249
|
-
const [rightExpression, leftExpression, operatorA, operatorB] = [
|
|
250
|
-
|
|
246
|
+
const [rightExpression, leftExpression, operatorA, operatorB] = [
|
|
247
|
+
resultStack.pop(),
|
|
248
|
+
resultStack.pop(),
|
|
249
|
+
operatorStack.pop(),
|
|
250
|
+
operatorStack.pop(),
|
|
251
|
+
];
|
|
252
|
+
if ((operatorPrecedence[operatorB] <= operatorPrecedence[symbol]) ||
|
|
253
|
+
(operatorPrecedence[operatorB] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
|
|
251
254
|
parsedLeftExpression = `(${leftExpression})`;
|
|
252
255
|
}
|
|
253
256
|
else {
|
|
254
257
|
parsedLeftExpression = leftExpression;
|
|
255
258
|
}
|
|
256
|
-
if (operatorPrecedence[operatorA] <= operatorPrecedence[symbol] ||
|
|
259
|
+
if (operatorPrecedence[operatorA] <= operatorPrecedence[symbol] ||
|
|
260
|
+
(operatorPrecedence[operatorA] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
|
|
257
261
|
parsedRightExpression = `(${rightExpression})`;
|
|
258
262
|
}
|
|
259
263
|
else {
|
|
@@ -273,7 +277,7 @@ export class Parser {
|
|
|
273
277
|
const formulaRPN = this.buildRPN(formula);
|
|
274
278
|
const calculationResult = {
|
|
275
279
|
result: undefined,
|
|
276
|
-
errorString: null
|
|
280
|
+
errorString: null,
|
|
277
281
|
};
|
|
278
282
|
if (!formulaRPN)
|
|
279
283
|
return calculationResult;
|
|
@@ -283,7 +287,7 @@ export class Parser {
|
|
|
283
287
|
if (!this.allowedOperators.has(frontItem)) {
|
|
284
288
|
const [sign, variableKey] = /^[+-]/.test(frontItem) ? [frontItem[0], frontItem.slice(1)] : ["", frontItem];
|
|
285
289
|
const operandValue = Number.parseFloat(this.variables.get(variableKey)?.toString() ?? variableKey);
|
|
286
|
-
const number = Number.parseFloat(
|
|
290
|
+
const number = Number.parseFloat(sign + "1") * operandValue;
|
|
287
291
|
calcStack.push(Big(number));
|
|
288
292
|
}
|
|
289
293
|
else {
|
|
@@ -317,7 +321,7 @@ export class Parser {
|
|
|
317
321
|
}
|
|
318
322
|
}
|
|
319
323
|
catch (error) {
|
|
320
|
-
calculationResult.errorString = error
|
|
324
|
+
calculationResult.errorString = error;
|
|
321
325
|
return calculationResult;
|
|
322
326
|
}
|
|
323
327
|
}
|
|
@@ -326,8 +330,7 @@ export class Parser {
|
|
|
326
330
|
calculationResult.errorString = "Calculation error: Empty result stack";
|
|
327
331
|
return calculationResult;
|
|
328
332
|
}
|
|
329
|
-
|
|
330
|
-
calculationResult.result = topValue !== undefined ? parseFloat(topValue.toString()) : undefined;
|
|
333
|
+
calculationResult.result = parseFloat(calcStack.top().toString());
|
|
331
334
|
return calculationResult;
|
|
332
335
|
}
|
|
333
336
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fw-components/formula-editor",
|
|
3
|
-
"version": "2.3.4-
|
|
3
|
+
"version": "2.3.4-notion-update.1",
|
|
4
4
|
"description": "A WYSIWYG type formula editor",
|
|
5
5
|
"main": "dist/formula-editor/src/formula-editor.js",
|
|
6
6
|
"exports": {
|
|
@@ -13,21 +13,27 @@
|
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
+
"start": "es-dev-server --app-index ../../index.html --node-resolve --watch --open",
|
|
16
17
|
"build": "tsc --composite false",
|
|
17
18
|
"dev": "tsc -w --composite false",
|
|
18
19
|
"prepublishOnly": "npm run build"
|
|
19
20
|
},
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"@fw-components/styles": "^2.3.4-
|
|
22
|
-
"big.js": "
|
|
23
|
-
"lit": "
|
|
24
|
-
"match-sorter": "
|
|
22
|
+
"@fw-components/styles": "^2.3.4-notion-update.1",
|
|
23
|
+
"big.js": "6.2.2",
|
|
24
|
+
"lit": "3.3.3",
|
|
25
|
+
"match-sorter": "8.3.0"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/fundwave/fw-components"
|
|
25
30
|
},
|
|
26
31
|
"author": "The Fundwave Authors",
|
|
27
32
|
"license": "ISC",
|
|
28
33
|
"devDependencies": {
|
|
29
|
-
"@types/big.js": "
|
|
30
|
-
"
|
|
34
|
+
"@types/big.js": "6.2.2",
|
|
35
|
+
"es-dev-server": "2.1.0",
|
|
36
|
+
"typescript": "5.9.3"
|
|
31
37
|
},
|
|
32
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "565e9ea66da929fc7b20287e99e04acc4ac0c385"
|
|
33
39
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"experimentalDecorators": true,
|
|
4
|
+
"useDefineForClassFields":false,
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "../",
|
|
7
|
+
"target": "esnext",
|
|
8
|
+
"module": "esnext",
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"declarationDir": "./dist/types",
|
|
12
|
+
"composite": false,
|
|
13
|
+
"lib": ["esnext", "dom"],
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"noEmitOnError": false
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|