Fast Excel Formula Parser and Evaluator

1.0.19 · active · verified Tue Apr 21

fast-formula-parser is a high-performance JavaScript library designed for parsing and evaluating Microsoft Excel formulas. It uses an LL(1) parser to offer fast and reliable formula processing, supporting over 280 standard Excel functions. The library is currently at version 1.0.19 and maintains an active release cadence, frequently adding new functions, fixing bugs, and improving existing features. It differentiates itself through its speed, extensive function coverage, and a grammar engineered to eliminate ambiguities, making it an robust choice for integrating Excel-like formula capabilities into web or Node.js applications. It also provides hooks for custom functions, including asynchronous ones, and supports formula dependency parsing for building complex calculation graphs.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart initializes the formula parser with sample data and custom handlers for cell references, ranges, variables, and a custom function. It then demonstrates parsing and evaluating formulas, including one that uses a custom variable and another that uses a custom function, and shows how to get formula dependencies.

import FormulaParser, { FormulaError } from 'fast-formula-parser';

const data = [
  ['', 'A', 'B', 'C'],
  ['1', 10, 20, 30],
  ['2', 5, 15, '=A1+B1'],
  ['3', '=B2*2', '=SUM(A1:C1)', '=IF(C2>50, "High", "Low")']
];

const parser = new FormulaParser({
  onVariable: (name, sheetName, position) => {
    // Implement custom variable handling if needed
    // 'position' is available since v1.0.19
    console.log(`Accessing variable '${name}' at sheet '${sheetName}', position: ${JSON.stringify(position)}`);
    if (name === 'MY_CONSTANT') return 100;
    return FormulaError.NAME;
  },
  onCell: (ref, sheetName) => {
    // ref: { sheet, row, col }
    const row = ref.row - 1; // 0-indexed
    const col = ref.col - 1; // 0-indexed
    if (data[row] && data[row][col] !== undefined) {
      return data[row][col];
    }
    return FormulaError.REF;
  },
  onRange: (ref, sheetName) => {
    // ref: { sheet, from: { row, col }, to: { row, col } }
    const startRow = ref.from.row - 1;
    const startCol = ref.from.col - 1;
    const endRow = ref.to.row - 1;
    const endCol = ref.to.col - 1;
    const rangeData = [];
    for (let r = startRow; r <= endRow; r++) {
      const rowData = [];
      for (let c = startCol; c <= endCol; c++) {
        if (data[r] && data[r][c] !== undefined) {
          rowData.push(data[r][c]);
        }
      }
      rangeData.push(rowData);
    }
    return rangeData;
  },
  functions: {
    // Custom function example
    MYCUSTOMADD: (arg1, arg2) => arg1 + arg2
  }
});

// Example usage
const position = { row: 3, col: 2, sheet: 'Sheet1' }; // Position of the formula '=SUM(A1:C1)'
const formulaResult = parser.parse(data[position.row - 1][position.col - 1], position);
console.log(`Result of '=SUM(A1:C1)' at B3: ${formulaResult}`);

const directResult = parser.parse('=MYCUSTOMADD(10, MY_CONSTANT)');
console.log(`Result of '=MYCUSTOMADD(10, MY_CONSTANT)': ${directResult}`);

const ifFormulaResult = parser.parse(data[position.row][position.col], { row: 4, col: 3, sheet: 'Sheet1' });
console.log(`Result of '=IF(C2>50, "High", "Low")' at C4: ${ifFormulaResult}`);

const depParser = new FormulaParser.DepParser({ onCell: parser.options.onCell, onRange: parser.options.onRange });
const dependencies = depParser.parse('=A1+B1', { row: 2, col: 3, sheet: 'Sheet1' });
console.log(`Dependencies for '=A1+B1': ${JSON.stringify(dependencies)}`);

view raw JSON →