@rowsncolumns/fast-formula-parser 6.2.42 → 6.2.45
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/cjs/index.js +89 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +89 -6
- package/dist/esm/index.js.map +1 -1
- package/index.d.ts +12 -0
- package/package.json +4 -3
package/dist/cjs/index.js
CHANGED
|
@@ -5649,6 +5649,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5649
5649
|
"ISNUMBER": "ESTNUM",
|
|
5650
5650
|
"ISO.CEILING": "ISO.PLAFOND",
|
|
5651
5651
|
"ISODD": "EST.IMPAIR",
|
|
5652
|
+
"ISOMITTED": "ISOMITTED",
|
|
5652
5653
|
"ISOWEEKNUM": "NO.SEMAINE.ISO",
|
|
5653
5654
|
"ISPMT": "ISPMT",
|
|
5654
5655
|
"ISREF": "ESTREF",
|
|
@@ -25694,6 +25695,55 @@ const lookupEquals = (a, b) =>
|
|
|
25694
25695
|
? a.toLowerCase() === b.toLowerCase()
|
|
25695
25696
|
: a === b;
|
|
25696
25697
|
|
|
25698
|
+
/**
|
|
25699
|
+
* The sheet range a lookup table argument was read from, or undefined when the table is an
|
|
25700
|
+
* array (an array constant, a spilled range or another function's result). The matrix the
|
|
25701
|
+
* host returned must fit inside that range — it is a window starting at `from` (a full-column
|
|
25702
|
+
* reference is trimmed to the data extent) — or no cell can be derived from a matrix index.
|
|
25703
|
+
*/
|
|
25704
|
+
const rangeOf = (arg, matrix) => {
|
|
25705
|
+
const ref = arg?.position;
|
|
25706
|
+
if (!ref || ref.isSpilledRange || ref.sheetEnd != null) return undefined;
|
|
25707
|
+
let range;
|
|
25708
|
+
if (ref.from && ref.to) {
|
|
25709
|
+
range = ref;
|
|
25710
|
+
} else if (ref.row != null && ref.col != null) {
|
|
25711
|
+
range = {
|
|
25712
|
+
sheet: ref.sheet,
|
|
25713
|
+
from: { row: ref.row, col: ref.col },
|
|
25714
|
+
to: { row: ref.row, col: ref.col },
|
|
25715
|
+
};
|
|
25716
|
+
} else {
|
|
25717
|
+
return undefined;
|
|
25718
|
+
}
|
|
25719
|
+
const fits =
|
|
25720
|
+
matrix.length <= range.to.row - range.from.row + 1 &&
|
|
25721
|
+
(matrix[0]?.length ?? 0) <= range.to.col - range.from.col + 1;
|
|
25722
|
+
return fits ? range : undefined;
|
|
25723
|
+
};
|
|
25724
|
+
|
|
25725
|
+
/**
|
|
25726
|
+
* The cell VLOOKUP/HLOOKUP found. Over a sheet range it is the cell's REFERENCE (as INDEX returns
|
|
25727
|
+
* one), so the result carries `=B2` semantics by construction: a blank cell displays 0, is 0 in
|
|
25728
|
+
* arithmetic and comparison, "" in text — `=VLOOKUP(…)+0` is 0, `=VLOOKUP(…)=""` is TRUE,
|
|
25729
|
+
* `=VLOOKUP(…)&"x"` is "x". The engine has no blank scalar to return instead: the dispatcher reads
|
|
25730
|
+
* a returned `undefined` as "function not implemented" (`#NAME?`) and `null` is the skipped-argument
|
|
25731
|
+
* marker. Over an array there is no cell to point at, so a blank slot coerces to 0 as blank does in
|
|
25732
|
+
* arithmetic. A cell holding `=""` is text, not blank, and comes back as "" either way.
|
|
25733
|
+
*/
|
|
25734
|
+
const matchedCell = (tableRange, tableArray, rowIdx, colIdx) => {
|
|
25735
|
+
if (tableRange) {
|
|
25736
|
+
return {
|
|
25737
|
+
ref: {
|
|
25738
|
+
sheet: tableRange.sheet,
|
|
25739
|
+
row: tableRange.from.row + rowIdx,
|
|
25740
|
+
col: tableRange.from.col + colIdx,
|
|
25741
|
+
},
|
|
25742
|
+
};
|
|
25743
|
+
}
|
|
25744
|
+
return tableArray[rowIdx][colIdx] ?? 0;
|
|
25745
|
+
};
|
|
25746
|
+
|
|
25697
25747
|
/**
|
|
25698
25748
|
* Exact-mode match for VLOOKUP/HLOOKUP/XLOOKUP/XMATCH: wildcards when the lookup text has
|
|
25699
25749
|
* them, otherwise case-insensitive equality.
|
|
@@ -25960,6 +26010,7 @@ const ReferenceFunctions = {
|
|
|
25960
26010
|
HLOOKUP: (lookupValue, tableArray, rowIndexNum, rangeLookup) => {
|
|
25961
26011
|
// preserve type of lookupValue
|
|
25962
26012
|
lookupValue = H$2.accept(lookupValue);
|
|
26013
|
+
const tableArg = tableArray;
|
|
25963
26014
|
try {
|
|
25964
26015
|
tableArray = H$2.accept(tableArray, Types.ARRAY, undefined, false);
|
|
25965
26016
|
} catch (e) {
|
|
@@ -25971,6 +26022,7 @@ const ReferenceFunctions = {
|
|
|
25971
26022
|
}
|
|
25972
26023
|
throw e;
|
|
25973
26024
|
}
|
|
26025
|
+
const tableRange = rangeOf(tableArg, tableArray);
|
|
25974
26026
|
rowIndexNum = H$2.accept(rowIndexNum, Types.NUMBER);
|
|
25975
26027
|
rangeLookup = H$2.accept(rangeLookup, Types.BOOLEAN, true);
|
|
25976
26028
|
|
|
@@ -25983,7 +26035,7 @@ const ReferenceFunctions = {
|
|
|
25983
26035
|
if (rangeLookup) {
|
|
25984
26036
|
const index = approximateMatchIndex(tableArray[0], lookupValue);
|
|
25985
26037
|
if (index === -1) throw FormulaError.NA;
|
|
25986
|
-
return tableArray
|
|
26038
|
+
return matchedCell(tableRange, tableArray, rowIndexNum - 1, index);
|
|
25987
26039
|
}
|
|
25988
26040
|
// exact lookup: case-insensitive, with wildcard support
|
|
25989
26041
|
else {
|
|
@@ -25992,7 +26044,7 @@ const ReferenceFunctions = {
|
|
|
25992
26044
|
);
|
|
25993
26045
|
// the exact match is not found
|
|
25994
26046
|
if (index === -1) throw FormulaError.NA;
|
|
25995
|
-
return tableArray
|
|
26047
|
+
return matchedCell(tableRange, tableArray, rowIndexNum - 1, index);
|
|
25996
26048
|
}
|
|
25997
26049
|
},
|
|
25998
26050
|
|
|
@@ -26496,6 +26548,7 @@ const ReferenceFunctions = {
|
|
|
26496
26548
|
VLOOKUP: (lookupValue, tableArray, colIndexNum, rangeLookup) => {
|
|
26497
26549
|
// preserve type of lookupValue
|
|
26498
26550
|
lookupValue = H$2.accept(lookupValue);
|
|
26551
|
+
const tableArg = tableArray;
|
|
26499
26552
|
try {
|
|
26500
26553
|
tableArray = H$2.accept(tableArray, Types.ARRAY, undefined, false);
|
|
26501
26554
|
} catch (e) {
|
|
@@ -26507,6 +26560,7 @@ const ReferenceFunctions = {
|
|
|
26507
26560
|
}
|
|
26508
26561
|
throw e;
|
|
26509
26562
|
}
|
|
26563
|
+
const tableRange = rangeOf(tableArg, tableArray);
|
|
26510
26564
|
colIndexNum = H$2.accept(colIndexNum, Types.NUMBER);
|
|
26511
26565
|
rangeLookup = H$2.accept(rangeLookup, Types.BOOLEAN, true);
|
|
26512
26566
|
|
|
@@ -26522,7 +26576,7 @@ const ReferenceFunctions = {
|
|
|
26522
26576
|
lookupValue,
|
|
26523
26577
|
);
|
|
26524
26578
|
if (index === -1) throw FormulaError.NA;
|
|
26525
|
-
return tableArray
|
|
26579
|
+
return matchedCell(tableRange, tableArray, index, colIndexNum - 1);
|
|
26526
26580
|
}
|
|
26527
26581
|
// exact lookup: case-insensitive, with wildcard support
|
|
26528
26582
|
else {
|
|
@@ -26531,7 +26585,7 @@ const ReferenceFunctions = {
|
|
|
26531
26585
|
);
|
|
26532
26586
|
// the exact match is not found
|
|
26533
26587
|
if (index === -1) throw FormulaError.NA;
|
|
26534
|
-
return tableArray
|
|
26588
|
+
return matchedCell(tableRange, tableArray, index, colIndexNum - 1);
|
|
26535
26589
|
}
|
|
26536
26590
|
},
|
|
26537
26591
|
|
|
@@ -53177,6 +53231,11 @@ class FormulaParser {
|
|
|
53177
53231
|
);
|
|
53178
53232
|
this.onRange = config.onRange;
|
|
53179
53233
|
this.onCell = config.onCell;
|
|
53234
|
+
// Observer of every cell / range the evaluation actually reads, with the
|
|
53235
|
+
// cell being evaluated. `INDIRECT` / `OFFSET` targets only exist at run
|
|
53236
|
+
// time, so this is how a host learns the dynamic precedents of a formula
|
|
53237
|
+
// (the dependency parser cannot see them).
|
|
53238
|
+
this.onReferenceResolved = config.onReferenceResolved;
|
|
53180
53239
|
// Optional host callback reporting row visibility for SUBTOTAL:
|
|
53181
53240
|
// ({sheet, row}) => {hiddenByFilter?: boolean, hiddenByUser?: boolean}
|
|
53182
53241
|
this.onRowHidden = config.onRowHidden;
|
|
@@ -53326,18 +53385,36 @@ class FormulaParser {
|
|
|
53326
53385
|
const bounds = this.onSpilledRange(ref);
|
|
53327
53386
|
if (bounds instanceof FormulaError) return bounds;
|
|
53328
53387
|
if (bounds && bounds.from && bounds.to) {
|
|
53329
|
-
|
|
53388
|
+
const spilled = {
|
|
53330
53389
|
from: bounds.from,
|
|
53331
53390
|
to: bounds.to,
|
|
53332
53391
|
sheet: bounds.sheet ?? ref.sheet,
|
|
53333
|
-
}
|
|
53392
|
+
};
|
|
53393
|
+
this.noteReferenceResolved("range", spilled, finalPosition);
|
|
53394
|
+
return this.onRange(spilled);
|
|
53334
53395
|
}
|
|
53335
53396
|
}
|
|
53336
53397
|
return FormulaError.REF;
|
|
53337
53398
|
}
|
|
53399
|
+
this.noteReferenceResolved("cell", ref, finalPosition);
|
|
53338
53400
|
return this.onCell(ref);
|
|
53339
53401
|
}
|
|
53340
53402
|
|
|
53403
|
+
/**
|
|
53404
|
+
* Tell the host which reference an evaluation is about to read.
|
|
53405
|
+
* @param {"cell"|"range"} kind
|
|
53406
|
+
* @param ref - the resolved reference (sheet already defaulted)
|
|
53407
|
+
* @param position - the cell being evaluated, when known
|
|
53408
|
+
*/
|
|
53409
|
+
noteReferenceResolved(kind, ref, position) {
|
|
53410
|
+
if (typeof this.onReferenceResolved !== "function") return;
|
|
53411
|
+
try {
|
|
53412
|
+
this.onReferenceResolved({ kind, ref, position });
|
|
53413
|
+
} catch {
|
|
53414
|
+
// An observer must never break the evaluation.
|
|
53415
|
+
}
|
|
53416
|
+
}
|
|
53417
|
+
|
|
53341
53418
|
/**
|
|
53342
53419
|
* Get values from the range reference.
|
|
53343
53420
|
* @param ref
|
|
@@ -53352,6 +53429,7 @@ class FormulaParser {
|
|
|
53352
53429
|
if (ref.sheetEnd != null) {
|
|
53353
53430
|
return this.get3DRange(ref, true);
|
|
53354
53431
|
}
|
|
53432
|
+
this.noteReferenceResolved("range", ref, finalPosition);
|
|
53355
53433
|
return this.onRange(ref);
|
|
53356
53434
|
}
|
|
53357
53435
|
|
|
@@ -53388,6 +53466,11 @@ class FormulaParser {
|
|
|
53388
53466
|
for (const sheet of sheets) {
|
|
53389
53467
|
const { sheetEnd: _ignored, ...perSheet } = ref;
|
|
53390
53468
|
perSheet.sheet = sheet;
|
|
53469
|
+
this.noteReferenceResolved(
|
|
53470
|
+
isRange ? "range" : "cell",
|
|
53471
|
+
perSheet,
|
|
53472
|
+
this.position,
|
|
53473
|
+
);
|
|
53391
53474
|
const value = isRange ? this.onRange(perSheet) : this.onCell(perSheet);
|
|
53392
53475
|
if (value instanceof FormulaError) return value;
|
|
53393
53476
|
if (Array.isArray(value)) {
|