@rowsncolumns/fast-formula-parser 6.2.33 → 6.2.35

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/esm/index.js CHANGED
@@ -3219,12 +3219,15 @@ const IndexedColors = Object.freeze([
3219
3219
 
3220
3220
  const isSingleSectionElapsedTimePattern = (pattern) => !pattern.includes(";") &&
3221
3221
  /\[(?:h+|m+|s+)\]/i.test(pattern.replace(/\[\$[^\]]+\]/g, ""));
3222
+ const localeForPattern = (pattern, locale) => {
3223
+ return locale;
3224
+ };
3222
3225
  const ssfFormat = (pattern, value, locale) => {
3223
3226
  try {
3224
3227
  const isNegativeElapsedTime = typeof value === "number" &&
3225
3228
  value < 0 &&
3226
3229
  isSingleSectionElapsedTimePattern(pattern);
3227
- const formatted = format(pattern, isNegativeElapsedTime ? Math.abs(value) : value, { locale });
3230
+ const formatted = format(pattern, isNegativeElapsedTime ? Math.abs(value) : value, { locale: localeForPattern(pattern, locale) });
3228
3231
  return isNegativeElapsedTime ? `-${formatted}` : formatted;
3229
3232
  }
3230
3233
  catch (err) {
@@ -41820,7 +41823,19 @@ const allTokens = [
41820
41823
 
41821
41824
  const SelectLexer = new Lexer(allTokens, { ensureOptimizations: true });
41822
41825
 
41823
- allTokens.forEach((tokenType) => {
41826
+ // Catch-all for characters no other token matches. Spelled out as a code-unit
41827
+ // range because Chevrotain's first-char optimisation mis-analyses `[\s\S]`
41828
+ // (it never matches) and refuses to optimise the complement set `[^]`.
41829
+ const UnknownChar = createToken({
41830
+ name: "UnknownChar",
41831
+ pattern: /[\u0000-\uFFFF]/,
41832
+ });
41833
+
41834
+ const tolerantTokens = [...allTokens, UnknownChar];
41835
+
41836
+ const TolerantLexer = new Lexer(tolerantTokens, { ensureOptimizations: true });
41837
+
41838
+ tolerantTokens.forEach((tokenType) => {
41824
41839
  tokenVocabulary$1[tokenType.name] = tokenType;
41825
41840
  });
41826
41841
 
@@ -41848,11 +41863,29 @@ function lex(inputText) {
41848
41863
  /**
41849
41864
  * Tolerant lexer that returns partial tokens even when errors occur.
41850
41865
  * Useful for incomplete formulas (e.g., '=SUM(') without throwing.
41866
+ *
41867
+ * Every character the formula grammar has no token for (e.g. a bare `\`)
41868
+ * is lexed as an `UnknownChar` token instead of being dropped by Chevrotain's
41869
+ * error recovery, which never advances its column counter over the dropped
41870
+ * characters. Unknown characters stay in `tokens` as first-class tokens with
41871
+ * native positions and are additionally reported in `errors` (Chevrotain's
41872
+ * `ILexingError` shape) so callers can still detect them.
41851
41873
  */
41852
41874
  function tolerantLex(inputText) {
41853
- const lexingResult = SelectLexer.tokenize(inputText);
41854
- // Do not throw on errors; callers can inspect lexingResult.errors if needed.
41855
- return lexingResult;
41875
+ const lexingResult = TolerantLexer.tokenize(inputText);
41876
+ const errors = [];
41877
+ for (const token of lexingResult.tokens) {
41878
+ if (token.tokenType === UnknownChar) {
41879
+ errors.push({
41880
+ offset: token.startOffset,
41881
+ line: token.startLine,
41882
+ column: token.startColumn,
41883
+ length: 1,
41884
+ message: `unexpected character: ->${token.image}<- at offset: ${token.startOffset}, skipped 1 characters.`,
41885
+ });
41886
+ }
41887
+ }
41888
+ return { tokens: lexingResult.tokens, groups: lexingResult.groups, errors };
41856
41889
  }
41857
41890
 
41858
41891
  const tokenVocabulary = tokenVocabulary$1;
@@ -45495,6 +45528,17 @@ class DepParser {
45495
45528
  if (fnName === "OFFSET") {
45496
45529
  return this.handleOffset(args);
45497
45530
  }
45531
+ // ADDRESS is pure and is the idiomatic way to build INDIRECT's
45532
+ // target. Folding it here lets handleIndirect register the real
45533
+ // precedent edge (`INDIRECT(ADDRESS(1,3,1,1,"Source"))` →
45534
+ // Source!$C$1), so the calc engine orders the INDIRECT cell after
45535
+ // the chain it reads instead of evaluating it against stale values.
45536
+ if (fnName === "ADDRESS") {
45537
+ const folded = this.foldAddress(args);
45538
+ if (folded !== undefined) {
45539
+ return { value: folded };
45540
+ }
45541
+ }
45498
45542
  // Phase 7 LAMBDA: __RNC_LAMBDA__("params", "body") is the
45499
45543
  // preprocessor's runtime lambda constructor. The body is a string
45500
45544
  // literal that may contain cell refs — recurse the dep parser on
@@ -45561,6 +45605,31 @@ class DepParser {
45561
45605
  }
45562
45606
  }
45563
45607
 
45608
+ /**
45609
+ * Evaluate ADDRESS(...) when every argument is a literal scalar.
45610
+ * Returns undefined when an argument is a reference or another
45611
+ * function's placeholder result (the dep parser does not evaluate
45612
+ * those), or when ADDRESS itself would error.
45613
+ */
45614
+ foldAddress(args = []) {
45615
+ if (!args.length || args.length > 5) return undefined;
45616
+ const scalars = [];
45617
+ for (const arg of args) {
45618
+ if (arg == null) {
45619
+ scalars.push(undefined);
45620
+ continue;
45621
+ }
45622
+ if (typeof arg === "object") return undefined;
45623
+ scalars.push(arg);
45624
+ }
45625
+ try {
45626
+ const address = ReferenceFunctions.ADDRESS(...scalars);
45627
+ return typeof address === "string" ? address : undefined;
45628
+ } catch {
45629
+ return undefined;
45630
+ }
45631
+ }
45632
+
45564
45633
  handleIndirect(args = []) {
45565
45634
  const refText = this.extractScalar(args[0]);
45566
45635
  if (typeof refText !== "string") {
@@ -45743,5 +45812,5 @@ class DepParser {
45743
45812
  // Export a Set of implemented function names for O(1) lookup
45744
45813
  const implementedFunctionNames = FormulaParser.getImplementedFunctionNames();
45745
45814
 
45746
- export { Address, Criteria, DepParser, Factorials, FormulaError, FormulaHelpers, MAX_COLUMN, MAX_ROW, ReversedTypes, Types, WildCard, allTokens, FormulaParser as default, implementedFunctionNames, lex, noop, tokenVocabulary$1 as tokenVocabulary, tolerantLex };
45815
+ export { Address, Criteria, DepParser, Factorials, FormulaError, FormulaHelpers, MAX_COLUMN, MAX_ROW, ReversedTypes, Types, UnknownChar, WildCard, allTokens, FormulaParser as default, implementedFunctionNames, lex, noop, tokenVocabulary$1 as tokenVocabulary, tolerantLex };
45747
45816
  //# sourceMappingURL=index.js.map