@ricsam/formula-engine 0.2.9 → 0.2.10
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 +40 -0
- package/dist/cjs/core/engine.cjs +37 -1
- package/dist/cjs/core/engine.cjs.map +3 -3
- package/dist/cjs/core/managers/dependency-manager.cjs +151 -67
- package/dist/cjs/core/managers/dependency-manager.cjs.map +3 -3
- package/dist/cjs/core/managers/workbook-manager.cjs +197 -1
- package/dist/cjs/core/managers/workbook-manager.cjs.map +3 -3
- package/dist/cjs/core/types.cjs.map +2 -2
- package/dist/cjs/core/workbook-renamer.cjs.map +1 -1
- package/dist/cjs/evaluator/formula-evaluator.cjs +22 -48
- package/dist/cjs/evaluator/formula-evaluator.cjs.map +3 -3
- package/dist/cjs/functions/math/sum/summation-utils.cjs +2 -2
- package/dist/cjs/functions/math/sum/summation-utils.cjs.map +2 -2
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/parser/formatter.cjs +3 -4
- package/dist/cjs/parser/formatter.cjs.map +3 -3
- package/dist/cjs/parser/parser.cjs +24 -216
- package/dist/cjs/parser/parser.cjs.map +3 -3
- package/dist/mjs/core/engine.mjs +37 -1
- package/dist/mjs/core/engine.mjs.map +3 -3
- package/dist/mjs/core/managers/dependency-manager.mjs +151 -67
- package/dist/mjs/core/managers/dependency-manager.mjs.map +3 -3
- package/dist/mjs/core/managers/workbook-manager.mjs +197 -1
- package/dist/mjs/core/managers/workbook-manager.mjs.map +3 -3
- package/dist/mjs/core/types.mjs.map +2 -2
- package/dist/mjs/core/workbook-renamer.mjs.map +1 -1
- package/dist/mjs/evaluator/formula-evaluator.mjs +22 -48
- package/dist/mjs/evaluator/formula-evaluator.mjs.map +3 -3
- package/dist/mjs/functions/math/sum/summation-utils.mjs +2 -2
- package/dist/mjs/functions/math/sum/summation-utils.mjs.map +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/parser/formatter.mjs +3 -4
- package/dist/mjs/parser/formatter.mjs.map +3 -3
- package/dist/mjs/parser/parser.mjs +24 -216
- package/dist/mjs/parser/parser.mjs.map +3 -3
- package/dist/types/core/engine.d.ts +15 -1
- package/dist/types/core/managers/dependency-manager.d.ts +4 -0
- package/dist/types/core/managers/workbook-manager.d.ts +23 -1
- package/dist/types/core/types.d.ts +35 -0
- package/dist/types/parser/parser.d.ts +4 -6
- package/package.json +1 -1
|
@@ -75,6 +75,9 @@ class Parser {
|
|
|
75
75
|
}
|
|
76
76
|
if (token.type === "RBRACKET") {
|
|
77
77
|
const nextToken = this.tokens.peekAhead(pos + 1);
|
|
78
|
+
if (nextToken?.type === "EXCLAMATION") {
|
|
79
|
+
return { isWorkbookReference: true };
|
|
80
|
+
}
|
|
78
81
|
if (nextToken && nextToken.type === "IDENTIFIER") {
|
|
79
82
|
let lookPos = pos + 2;
|
|
80
83
|
while (lookPos < pos + 10) {
|
|
@@ -117,6 +120,10 @@ class Parser {
|
|
|
117
120
|
}
|
|
118
121
|
const workbookName = this.input.substring(workbookStartPos, workbookEndPos);
|
|
119
122
|
this.tokens.consume();
|
|
123
|
+
if (this.tokens.match("EXCLAMATION")) {
|
|
124
|
+
this.tokens.consume();
|
|
125
|
+
return this.parseWorkbookQualifiedTableReference(workbookName, start);
|
|
126
|
+
}
|
|
120
127
|
if (!this.tokens.match("IDENTIFIER")) {
|
|
121
128
|
throw new ParseError("Expected sheet name after workbook reference", this.tokens.peek().position);
|
|
122
129
|
}
|
|
@@ -179,6 +186,16 @@ class Parser {
|
|
|
179
186
|
});
|
|
180
187
|
}
|
|
181
188
|
}
|
|
189
|
+
parseWorkbookQualifiedTableReference(workbookName, startPos) {
|
|
190
|
+
if (!this.tokens.match("IDENTIFIER")) {
|
|
191
|
+
throw new ParseError(`Expected table name after [${workbookName}]!`, this.tokens.peek().position);
|
|
192
|
+
}
|
|
193
|
+
const tableName = this.tokens.consume().value;
|
|
194
|
+
if (!this.tokens.match("LBRACKET")) {
|
|
195
|
+
throw new ParseError(`Workbook-qualified references without a sheet only support tables. Use [${workbookName}]!${tableName}[...] for tables or [${workbookName}]Sheet!A1 for sheet references`, this.tokens.peek().position);
|
|
196
|
+
}
|
|
197
|
+
return this.parseTableReference(tableName, startPos, { workbookName });
|
|
198
|
+
}
|
|
182
199
|
parseBareColumnReference() {
|
|
183
200
|
const startPos = this.tokens.peek().position.start;
|
|
184
201
|
this.tokens.consume();
|
|
@@ -693,7 +710,8 @@ class Parser {
|
|
|
693
710
|
sheetName: parsed.sheet
|
|
694
711
|
});
|
|
695
712
|
}
|
|
696
|
-
parseTableReference(tableName, startPos) {
|
|
713
|
+
parseTableReference(tableName, startPos, qualifiers) {
|
|
714
|
+
const { sheetName, workbookName } = qualifiers ?? {};
|
|
697
715
|
this.tokens.consume();
|
|
698
716
|
let selector;
|
|
699
717
|
let cols;
|
|
@@ -891,6 +909,8 @@ class Parser {
|
|
|
891
909
|
}
|
|
892
910
|
return import_ast.createStructuredReferenceNode({
|
|
893
911
|
tableName,
|
|
912
|
+
sheetName,
|
|
913
|
+
workbookName,
|
|
894
914
|
cols,
|
|
895
915
|
selector,
|
|
896
916
|
isCurrentRow,
|
|
@@ -901,212 +921,7 @@ class Parser {
|
|
|
901
921
|
});
|
|
902
922
|
}
|
|
903
923
|
parseTableReferenceWithSheet(tableName, sheetName, startPos) {
|
|
904
|
-
this.
|
|
905
|
-
let selector;
|
|
906
|
-
let cols;
|
|
907
|
-
let isCurrentRow = false;
|
|
908
|
-
if (this.tokens.match("LBRACKET")) {
|
|
909
|
-
this.tokens.consume();
|
|
910
|
-
if (this.tokens.match("HASH")) {
|
|
911
|
-
this.tokens.consume();
|
|
912
|
-
if (!this.tokens.match("IDENTIFIER")) {
|
|
913
|
-
throw new ParseError("Expected selector name after #", this.tokens.peek().position);
|
|
914
|
-
}
|
|
915
|
-
const selectorName = this.tokens.consume().value;
|
|
916
|
-
selector = `#${selectorName}`;
|
|
917
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
918
|
-
throw new ParseError("Expected ] after selector", this.tokens.peek().position);
|
|
919
|
-
}
|
|
920
|
-
this.tokens.consume();
|
|
921
|
-
if (this.tokens.match("COMMA")) {
|
|
922
|
-
this.tokens.consume();
|
|
923
|
-
if (!this.tokens.match("LBRACKET")) {
|
|
924
|
-
throw new ParseError("Expected [ after comma", this.tokens.peek().position);
|
|
925
|
-
}
|
|
926
|
-
this.tokens.consume();
|
|
927
|
-
if (!this.tokens.match("IDENTIFIER") && !this.tokens.match("FUNCTION") && !this.tokens.match("NUMBER") && !this.tokens.match("OPERATOR")) {
|
|
928
|
-
throw new ParseError("Expected column name", this.tokens.peek().position);
|
|
929
|
-
}
|
|
930
|
-
const colStart = this.parseColumnName();
|
|
931
|
-
if (this.tokens.match("COLON") && !this.tokens.peekAhead(1)?.type.match(/RBRACKET/)) {
|
|
932
|
-
this.tokens.consume();
|
|
933
|
-
if (!this.tokens.match("IDENTIFIER") && !this.tokens.match("FUNCTION") && !this.tokens.match("NUMBER") && !this.tokens.match("OPERATOR")) {
|
|
934
|
-
throw new ParseError("Expected end column name after :", this.tokens.peek().position);
|
|
935
|
-
}
|
|
936
|
-
const colEnd = this.parseColumnName();
|
|
937
|
-
cols = {
|
|
938
|
-
startCol: colStart,
|
|
939
|
-
endCol: colEnd
|
|
940
|
-
};
|
|
941
|
-
} else {
|
|
942
|
-
cols = {
|
|
943
|
-
startCol: colStart,
|
|
944
|
-
endCol: colStart
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
948
|
-
throw new ParseError("Expected ] after column specification", this.tokens.peek().position);
|
|
949
|
-
}
|
|
950
|
-
this.tokens.consume();
|
|
951
|
-
if (this.tokens.match("COLON")) {
|
|
952
|
-
this.tokens.consume();
|
|
953
|
-
if (!this.tokens.match("LBRACKET")) {
|
|
954
|
-
throw new ParseError("Expected [ after : in column range", this.tokens.peek().position);
|
|
955
|
-
}
|
|
956
|
-
this.tokens.consume();
|
|
957
|
-
if (!this.tokens.match("IDENTIFIER") && !this.tokens.match("FUNCTION") && !this.tokens.match("NUMBER") && !this.tokens.match("OPERATOR")) {
|
|
958
|
-
throw new ParseError("Expected end column name", this.tokens.peek().position);
|
|
959
|
-
}
|
|
960
|
-
const colEnd = this.parseColumnName();
|
|
961
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
962
|
-
throw new ParseError("Expected ] after end column name", this.tokens.peek().position);
|
|
963
|
-
}
|
|
964
|
-
this.tokens.consume();
|
|
965
|
-
cols = {
|
|
966
|
-
startCol: colStart,
|
|
967
|
-
endCol: colEnd
|
|
968
|
-
};
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
972
|
-
throw new ParseError("Expected ] to close table reference", this.tokens.peek().position);
|
|
973
|
-
}
|
|
974
|
-
this.tokens.consume();
|
|
975
|
-
} else if (this.tokens.match("IDENTIFIER") || this.tokens.match("FUNCTION") || this.tokens.match("NUMBER") || this.tokens.match("OPERATOR")) {
|
|
976
|
-
const colStart = this.parseColumnName();
|
|
977
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
978
|
-
throw new ParseError("Expected ] after column name", this.tokens.peek().position);
|
|
979
|
-
}
|
|
980
|
-
this.tokens.consume();
|
|
981
|
-
if (this.tokens.match("COLON")) {
|
|
982
|
-
this.tokens.consume();
|
|
983
|
-
if (!this.tokens.match("LBRACKET")) {
|
|
984
|
-
throw new ParseError("Expected [ before second column name", this.tokens.peek().position);
|
|
985
|
-
}
|
|
986
|
-
this.tokens.consume();
|
|
987
|
-
const colEnd = this.parseColumnName();
|
|
988
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
989
|
-
throw new ParseError("Expected ] after second column name", this.tokens.peek().position);
|
|
990
|
-
}
|
|
991
|
-
this.tokens.consume();
|
|
992
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
993
|
-
throw new ParseError("Expected ] to close table reference", this.tokens.peek().position);
|
|
994
|
-
}
|
|
995
|
-
this.tokens.consume();
|
|
996
|
-
cols = {
|
|
997
|
-
startCol: colStart,
|
|
998
|
-
endCol: colEnd
|
|
999
|
-
};
|
|
1000
|
-
} else {
|
|
1001
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1002
|
-
throw new ParseError("Expected ] to close table reference", this.tokens.peek().position);
|
|
1003
|
-
}
|
|
1004
|
-
this.tokens.consume();
|
|
1005
|
-
cols = {
|
|
1006
|
-
startCol: colStart,
|
|
1007
|
-
endCol: colStart
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
} else if (this.tokens.match("AT")) {
|
|
1012
|
-
this.tokens.consume();
|
|
1013
|
-
isCurrentRow = true;
|
|
1014
|
-
if (this.tokens.match("LBRACKET")) {
|
|
1015
|
-
this.tokens.consume();
|
|
1016
|
-
const colStart = this.parseColumnName();
|
|
1017
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1018
|
-
throw new ParseError("Expected ] after column name", this.tokens.peek().position);
|
|
1019
|
-
}
|
|
1020
|
-
this.tokens.consume();
|
|
1021
|
-
if (this.tokens.match("COLON")) {
|
|
1022
|
-
this.tokens.consume();
|
|
1023
|
-
if (!this.tokens.match("LBRACKET")) {
|
|
1024
|
-
throw new ParseError("Expected [ before second column name", this.tokens.peek().position);
|
|
1025
|
-
}
|
|
1026
|
-
this.tokens.consume();
|
|
1027
|
-
const colEnd = this.parseColumnName();
|
|
1028
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1029
|
-
throw new ParseError("Expected ] after second column name", this.tokens.peek().position);
|
|
1030
|
-
}
|
|
1031
|
-
this.tokens.consume();
|
|
1032
|
-
cols = {
|
|
1033
|
-
startCol: colStart,
|
|
1034
|
-
endCol: colEnd
|
|
1035
|
-
};
|
|
1036
|
-
} else {
|
|
1037
|
-
cols = {
|
|
1038
|
-
startCol: colStart,
|
|
1039
|
-
endCol: colStart
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1043
|
-
throw new ParseError("Expected ] to close table reference", this.tokens.peek().position);
|
|
1044
|
-
}
|
|
1045
|
-
this.tokens.consume();
|
|
1046
|
-
} else {
|
|
1047
|
-
const colStart = this.parseColumnName();
|
|
1048
|
-
if (this.tokens.match("COLON")) {
|
|
1049
|
-
this.tokens.consume();
|
|
1050
|
-
const colEnd = this.parseColumnName();
|
|
1051
|
-
cols = {
|
|
1052
|
-
startCol: colStart,
|
|
1053
|
-
endCol: colEnd
|
|
1054
|
-
};
|
|
1055
|
-
} else {
|
|
1056
|
-
cols = {
|
|
1057
|
-
startCol: colStart,
|
|
1058
|
-
endCol: colStart
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1062
|
-
throw new ParseError("Expected ] after column reference", this.tokens.peek().position);
|
|
1063
|
-
}
|
|
1064
|
-
this.tokens.consume();
|
|
1065
|
-
}
|
|
1066
|
-
} else if (this.tokens.match("IDENTIFIER") || this.tokens.match("FUNCTION") || this.tokens.match("NUMBER") || this.tokens.match("OPERATOR")) {
|
|
1067
|
-
const colStart = this.parseColumnName();
|
|
1068
|
-
if (this.tokens.match("COLON")) {
|
|
1069
|
-
this.tokens.consume();
|
|
1070
|
-
const colEnd = this.parseColumnName();
|
|
1071
|
-
cols = {
|
|
1072
|
-
startCol: colStart,
|
|
1073
|
-
endCol: colEnd
|
|
1074
|
-
};
|
|
1075
|
-
} else {
|
|
1076
|
-
cols = {
|
|
1077
|
-
startCol: colStart,
|
|
1078
|
-
endCol: colStart
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1082
|
-
throw new ParseError("Expected ] after column name", this.tokens.peek().position);
|
|
1083
|
-
}
|
|
1084
|
-
this.tokens.consume();
|
|
1085
|
-
} else if (this.tokens.match("HASH")) {
|
|
1086
|
-
this.tokens.consume();
|
|
1087
|
-
if (!this.tokens.match("IDENTIFIER")) {
|
|
1088
|
-
throw new ParseError("Expected selector name after #", this.tokens.peek().position);
|
|
1089
|
-
}
|
|
1090
|
-
const selectorName = this.tokens.consume().value;
|
|
1091
|
-
selector = `#${selectorName}`;
|
|
1092
|
-
if (!this.tokens.match("RBRACKET")) {
|
|
1093
|
-
throw new ParseError("Expected ] after selector", this.tokens.peek().position);
|
|
1094
|
-
}
|
|
1095
|
-
this.tokens.consume();
|
|
1096
|
-
} else {
|
|
1097
|
-
throw new ParseError("Expected column name or selector in table reference", this.tokens.peek().position);
|
|
1098
|
-
}
|
|
1099
|
-
return import_ast.createStructuredReferenceNode({
|
|
1100
|
-
tableName,
|
|
1101
|
-
sheetName,
|
|
1102
|
-
cols,
|
|
1103
|
-
selector,
|
|
1104
|
-
isCurrentRow,
|
|
1105
|
-
position: {
|
|
1106
|
-
start: startPos,
|
|
1107
|
-
end: this.tokens.peek().position?.end ?? 0
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
924
|
+
return this.parseTableReference(tableName, startPos, { sheetName });
|
|
1110
925
|
}
|
|
1111
926
|
parseCellOrRangeAfterSheets() {
|
|
1112
927
|
const start = this.tokens.peek().position?.start ?? 0;
|
|
@@ -1280,13 +1095,6 @@ class Parser {
|
|
|
1280
1095
|
rangeNode.workbookName = workbookName;
|
|
1281
1096
|
return rangeNode;
|
|
1282
1097
|
}
|
|
1283
|
-
parseTableReferenceWithWorkbookAndSheet(tableName, workbookName, sheetName, startPos) {
|
|
1284
|
-
const tableRef = this.parseTableReferenceWithSheet(tableName, sheetName, startPos);
|
|
1285
|
-
if (tableRef.type === "structured-reference") {
|
|
1286
|
-
tableRef.workbookName = workbookName;
|
|
1287
|
-
}
|
|
1288
|
-
return tableRef;
|
|
1289
|
-
}
|
|
1290
1098
|
parseRange(startRef, endRef, startPos, endPos) {
|
|
1291
1099
|
let fullRange = `${startRef}:${endRef}`;
|
|
1292
1100
|
let sheetName;
|
|
@@ -1598,7 +1406,7 @@ class Parser {
|
|
|
1598
1406
|
const identifier2 = this.tokens.consume();
|
|
1599
1407
|
ref += identifier2.value;
|
|
1600
1408
|
if (this.tokens.match("LBRACKET")) {
|
|
1601
|
-
|
|
1409
|
+
throw new ParseError(`Cross-workbook table references use [${workbookName}]!${identifier2.value}[...] instead of [${workbookName}]${sheetName}!${identifier2.value}[...]`, this.tokens.peek().position);
|
|
1602
1410
|
}
|
|
1603
1411
|
if (this.tokens.match("COLON")) {
|
|
1604
1412
|
this.tokens.consume();
|
|
@@ -1707,4 +1515,4 @@ function parseFormula(formula) {
|
|
|
1707
1515
|
return Parser.parse(formula);
|
|
1708
1516
|
}
|
|
1709
1517
|
|
|
1710
|
-
//# debugId=
|
|
1518
|
+
//# debugId=B6F0346D15B1EFC164756E2164756E21
|