@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/cjs/index.js CHANGED
@@ -3223,12 +3223,15 @@ const IndexedColors = Object.freeze([
3223
3223
 
3224
3224
  const isSingleSectionElapsedTimePattern = (pattern) => !pattern.includes(";") &&
3225
3225
  /\[(?:h+|m+|s+)\]/i.test(pattern.replace(/\[\$[^\]]+\]/g, ""));
3226
+ const localeForPattern = (pattern, locale) => {
3227
+ return locale;
3228
+ };
3226
3229
  const ssfFormat = (pattern, value, locale) => {
3227
3230
  try {
3228
3231
  const isNegativeElapsedTime = typeof value === "number" &&
3229
3232
  value < 0 &&
3230
3233
  isSingleSectionElapsedTimePattern(pattern);
3231
- const formatted = format(pattern, isNegativeElapsedTime ? Math.abs(value) : value, { locale });
3234
+ const formatted = format(pattern, isNegativeElapsedTime ? Math.abs(value) : value, { locale: localeForPattern(pattern, locale) });
3232
3235
  return isNegativeElapsedTime ? `-${formatted}` : formatted;
3233
3236
  }
3234
3237
  catch (err) {
@@ -41824,7 +41827,19 @@ const allTokens = [
41824
41827
 
41825
41828
  const SelectLexer = new Lexer(allTokens, { ensureOptimizations: true });
41826
41829
 
41827
- allTokens.forEach((tokenType) => {
41830
+ // Catch-all for characters no other token matches. Spelled out as a code-unit
41831
+ // range because Chevrotain's first-char optimisation mis-analyses `[\s\S]`
41832
+ // (it never matches) and refuses to optimise the complement set `[^]`.
41833
+ const UnknownChar = createToken({
41834
+ name: "UnknownChar",
41835
+ pattern: /[\u0000-\uFFFF]/,
41836
+ });
41837
+
41838
+ const tolerantTokens = [...allTokens, UnknownChar];
41839
+
41840
+ const TolerantLexer = new Lexer(tolerantTokens, { ensureOptimizations: true });
41841
+
41842
+ tolerantTokens.forEach((tokenType) => {
41828
41843
  tokenVocabulary$1[tokenType.name] = tokenType;
41829
41844
  });
41830
41845
 
@@ -41852,11 +41867,29 @@ function lex(inputText) {
41852
41867
  /**
41853
41868
  * Tolerant lexer that returns partial tokens even when errors occur.
41854
41869
  * Useful for incomplete formulas (e.g., '=SUM(') without throwing.
41870
+ *
41871
+ * Every character the formula grammar has no token for (e.g. a bare `\`)
41872
+ * is lexed as an `UnknownChar` token instead of being dropped by Chevrotain's
41873
+ * error recovery, which never advances its column counter over the dropped
41874
+ * characters. Unknown characters stay in `tokens` as first-class tokens with
41875
+ * native positions and are additionally reported in `errors` (Chevrotain's
41876
+ * `ILexingError` shape) so callers can still detect them.
41855
41877
  */
41856
41878
  function tolerantLex(inputText) {
41857
- const lexingResult = SelectLexer.tokenize(inputText);
41858
- // Do not throw on errors; callers can inspect lexingResult.errors if needed.
41859
- return lexingResult;
41879
+ const lexingResult = TolerantLexer.tokenize(inputText);
41880
+ const errors = [];
41881
+ for (const token of lexingResult.tokens) {
41882
+ if (token.tokenType === UnknownChar) {
41883
+ errors.push({
41884
+ offset: token.startOffset,
41885
+ line: token.startLine,
41886
+ column: token.startColumn,
41887
+ length: 1,
41888
+ message: `unexpected character: ->${token.image}<- at offset: ${token.startOffset}, skipped 1 characters.`,
41889
+ });
41890
+ }
41891
+ }
41892
+ return { tokens: lexingResult.tokens, groups: lexingResult.groups, errors };
41860
41893
  }
41861
41894
 
41862
41895
  const tokenVocabulary = tokenVocabulary$1;
@@ -45499,6 +45532,17 @@ class DepParser {
45499
45532
  if (fnName === "OFFSET") {
45500
45533
  return this.handleOffset(args);
45501
45534
  }
45535
+ // ADDRESS is pure and is the idiomatic way to build INDIRECT's
45536
+ // target. Folding it here lets handleIndirect register the real
45537
+ // precedent edge (`INDIRECT(ADDRESS(1,3,1,1,"Source"))` →
45538
+ // Source!$C$1), so the calc engine orders the INDIRECT cell after
45539
+ // the chain it reads instead of evaluating it against stale values.
45540
+ if (fnName === "ADDRESS") {
45541
+ const folded = this.foldAddress(args);
45542
+ if (folded !== undefined) {
45543
+ return { value: folded };
45544
+ }
45545
+ }
45502
45546
  // Phase 7 LAMBDA: __RNC_LAMBDA__("params", "body") is the
45503
45547
  // preprocessor's runtime lambda constructor. The body is a string
45504
45548
  // literal that may contain cell refs — recurse the dep parser on
@@ -45565,6 +45609,31 @@ class DepParser {
45565
45609
  }
45566
45610
  }
45567
45611
 
45612
+ /**
45613
+ * Evaluate ADDRESS(...) when every argument is a literal scalar.
45614
+ * Returns undefined when an argument is a reference or another
45615
+ * function's placeholder result (the dep parser does not evaluate
45616
+ * those), or when ADDRESS itself would error.
45617
+ */
45618
+ foldAddress(args = []) {
45619
+ if (!args.length || args.length > 5) return undefined;
45620
+ const scalars = [];
45621
+ for (const arg of args) {
45622
+ if (arg == null) {
45623
+ scalars.push(undefined);
45624
+ continue;
45625
+ }
45626
+ if (typeof arg === "object") return undefined;
45627
+ scalars.push(arg);
45628
+ }
45629
+ try {
45630
+ const address = ReferenceFunctions.ADDRESS(...scalars);
45631
+ return typeof address === "string" ? address : undefined;
45632
+ } catch {
45633
+ return undefined;
45634
+ }
45635
+ }
45636
+
45568
45637
  handleIndirect(args = []) {
45569
45638
  const refText = this.extractScalar(args[0]);
45570
45639
  if (typeof refText !== "string") {
@@ -45757,6 +45826,7 @@ exports.MAX_COLUMN = MAX_COLUMN;
45757
45826
  exports.MAX_ROW = MAX_ROW;
45758
45827
  exports.ReversedTypes = ReversedTypes;
45759
45828
  exports.Types = Types;
45829
+ exports.UnknownChar = UnknownChar;
45760
45830
  exports.WildCard = WildCard;
45761
45831
  exports.allTokens = allTokens;
45762
45832
  exports.default = FormulaParser;