Witan Calc
Witan Calc recalculates formulas in an Excel workbook. Use the calculation engine from exec when recalculation is part of a workbook script, or use the standalone command when you need a file-level pass, a non-mutating verification check, or CLI reporting of changed cells and formula errors.
From Exec
Inside witan xlsx exec, write operations recalculate affected formulas as part of the operation:
witan xlsx exec model.xlsx --stdin <<'WITAN'
const result = await xlsx.setCells(wb, [
{ address: "Inputs!B5", value: 1.1 }
])
return {
value: result.touched["Summary!F25"],
changed: result.changed,
errors: result.errors
}
WITAN
The returned touched map contains recalculated display values keyed by address. Check errors before saving. If an expected output address is not in touched, that output was not in the recalculated dependency chain for the edit; trace the model or check that you changed the intended input.
Standalone Command
Use witan xlsx calc for a whole-file recalculation pass. By default it writes updated cached values back to the workbook file so Excel, previewers, and import tools see current results immediately.
witan xlsx calc report.xlsx
Clean output is intentionally short:
247 cells recalculated, 0 errors, 0 changed
If formula errors are found, calc prints only those errors by default and exits with code 2:
1 error:
Summary!B5 =B2/B10 #DIV/0! <- B10 is empty
Automatic Recalculation
This is the usual workflow:
- Read or trace the workbook to identify the input and output cells.
- Call
xlsx.setCellsor another mutating API. - Read recalculated values from the operation result.
- Check
errorsbefore saving.
Do not run witan xlsx calc after every exec --save edit by default. It is useful as a separate verification or reporting step, not as a required commit step.
Explicit Calc In Exec
The witan xlsx exec scripting API does not require a separate calculation call after normal writes. Methods that change cell values, formulas, or workbook structure perform the needed recalculation and return the affected results.
If you are running Office Script-style code in exec, explicit calculation methods are available:
witan xlsx exec model.xlsx --stdin <<'WITAN'
function main(workbook: ExcelScript.Workbook) {
workbook.getApplication().calculate(ExcelScript.CalculationType.full)
return workbook.getApplication().getCalculationState()
}
WITAN
Office Script application.calculate, worksheet.calculate, and range.calculate use the same workbook calculation engine as witan xlsx calc. Prefer the result returned by the write method unless you are running Office Script-style code or deliberately forcing a workbook/range calculation pass inside one script.
Behavior
- By default, the workbook at
<file>is overwritten with updated cached formula values. - With
--verify, the workbook is not modified. - By default, human-readable output shows errors only.
- Use
--show-touchedto print recalculated cells and their computed values. - One or more
--rangevalues seed recalculation from those ranges; downstream dependent formulas are still recalculated. - Use
--jsonfor the full machine-readable result.
Verify Mode
--verify checks whether recalculation would change the workbook without writing the updated file back to disk:
witan xlsx calc report.xlsx --verify
It exits with code 2 when either condition is true:
- Recalculation produces formula errors.
- Any computed cached value would change.
When --verify is used with human-readable output, calc also prints the changed addresses:
247 cells recalculated, 0 errors, 3 changed
Changed (3):
Summary!B5
Summary!B6
Summary!B7
Showing Recalculated Cells
Use --show-touched when you need the recalculated values in the terminal:
witan xlsx calc budget.xlsx -r "Sheet1!B2:B6" --show-touched
Example output:
Sheet1!B2 =SUM(Inputs!B2:B13) 1,284,500
Sheet1!B3 =B2*0.3 385,350
Sheet1!B4 =VLOOKUP("Q4",Data!A:C,3,FALSE) 342,100
Sheet1!B5 =B2/B10 #DIV/0! <- B10 is empty
Sheet1!B6 =IFERROR(B5,"N/A") N/A
5 cells recalculated, 1 changed, 1 error
Each line contains the address, formula if present, and either the computed display value or an error code with detail.
Range Seeding
--range is repeatable:
witan xlsx calc report.xlsx \
-r "Inputs!B1:B20" \
-r "Summary!A1:H10"
Ranges are not just output filters. They tell the engine where to start recalculation. Any downstream formulas that depend on those ranges are still recalculated.
If you need to inspect the touched cells, combine --range with --show-touched.
Formula Dependencies
Witan Calc is built on the same formula dependency graph exposed through exec. Use dependency queries before changing a model, or when a recalculation result is surprising.
Use getCellPrecedents to see what feeds a formula:
witan xlsx exec model.xlsx --stdin <<'WITAN'
return await xlsx.getCellPrecedents(wb, "Summary!F25", 3)
WITAN
Use getCellDependents to see what will be affected by an input edit:
witan xlsx exec model.xlsx --stdin <<'WITAN'
return await xlsx.getCellDependents(wb, "Inputs!B5", 3)
WITAN
The depth argument limits how many dependency hops to follow. Use 1 for the immediate formulas on either side of a cell, a larger number for a bounded trace, or Infinity when the script needs the complete reachable graph.
For a model-level view, traceToInputs walks upstream until it reaches leaf input cells, and traceToOutputs walks downstream until it reaches final output cells:
witan xlsx exec model.xlsx --stdin <<'WITAN'
const inputs = await xlsx.traceToInputs(wb, "Summary!F25")
const outputs = await xlsx.traceToOutputs(wb, "Inputs!B5")
return { inputs, outputs }
WITAN
This is useful before an edit because it tells the script which assumptions support an output and which visible results should be checked after changing an input. After an edit, compare the expected downstream outputs with the touched addresses returned by setCells or printed by calc --show-touched.
Dependency Index Coverage
The dependency index tracks static workbook references at cell, range, sheet, and workbook scope. Supported references include:
| Reference form | Dependency behavior |
|---|---|
| Direct cells and ranges | Tracks same-sheet and sheet-qualified A1 references, R1C1 formulas, ranges, unions, intersections, whole rows, and whole columns |
| Multi-sheet references | Expands in-workbook 3D sheet references such as Jan:Mar!A1 into the cells on each resolved sheet |
| Defined names | Resolves workbook-scoped and sheet-scoped names, including names that refer to ranges or static formula expressions |
| Tables | Resolves Excel structured references such as Table1[Amount] to the corresponding table range |
| Dynamic arrays | Tracks spill-producing formulas, spill children, spill-range references such as A1#, and dependents of resized spills during recalculation |
| What-if data tables | Tracks data-table source formulas, substitution cells, and cell-specific dependencies for one-variable and two-variable data tables |
| LET and LAMBDA | Tracks LET bindings, named lambdas, sheet-scoped lambdas, captured cells, supplied lambda arguments, and helper functions such as MAP, REDUCE, SCAN, BYROW, BYCOL, and MAKEARRAY |
| Circular models | Detects circular references and uses workbook iterative-calculation settings when iterative calculation is enabled |
Some Excel formulas are intentionally dynamic: the cells they reference are determined only when the formula is evaluated. In those cases, the dependency index reports warnings instead of silently pretending the static graph is complete. Common warning cases are:
| Warning | Meaning |
|---|---|
UNTRACKED_FUNCTION |
A formula uses a runtime reference function such as INDIRECT or OFFSET, so its exact referenced cells are determined during calculation rather than from syntax alone |
UNTRACKED_NAME |
A defined name resolves through a dynamic or otherwise untrackable expression |
RECURSIVE_DEFINED_NAME |
A defined-name cycle prevents static expansion |
UNRESOLVED_NAME, UNRESOLVED_TABLE, UNRESOLVED_SHEET |
The referenced workbook object was not found |
EXTERNAL_REF |
The formula references another workbook; cached values may be usable for calculation, but the dependency graph does not open or index that external workbook |
PARSE_ERROR |
The formula could not be parsed into a dependency graph |
These warnings affect static dependency tracing, not calculation correctness. Untracked functions are fully supported for recalculation: Witan evaluates them, runs bounded extra passes for dynamic-reference formulas, and then recalculates their static dependents. For example, INDIRECT("A1") can update correctly when A1 changes even though getCellPrecedents cannot report A1 as a static edge before the formula runs.
Dependency Behavior
The calculation engine uses a workbook dependency graph rather than blindly evaluating every formula after every edit. For incremental writes, the engine:
- Starts from the cells modified by the operation.
- Finds the downstream formula dependency closure.
- Evaluates the affected formulas in dependency order.
- Includes volatile formulas such as
NOW,TODAY,RAND,RANDBETWEEN, andRANDARRAYon recalculation passes, along with their dependents. - Handles dynamic-array spills by cascading recalculation to formulas that depend on newly spilled cells.
- Respects workbook iterative-calculation settings for circular models and reports convergence errors when they do not settle within the workbook limits.
When a formula edit changes the dependency graph, Witan rebuilds the dependency state before later recalculation. Format-only changes do not trigger formula recalculation.
Some Excel formulas use dynamic references that cannot be fully known statically, such as INDIRECT and some OFFSET patterns. Witan tracks those as untracked formulas and runs bounded extra passes so their dependents can settle after ordinary dependency-graph recalculation.
See xlsx API for the exact dependency tracing and formula evaluation return shapes.
Formula Evaluation
Formula evaluation helpers use the same calculation engine without requiring a cell write:
witan xlsx exec model.xlsx --stdin <<'WITAN'
return await xlsx.evaluateFormulas(wb, "Summary", [
"=SUM(Inputs!B2:B13)",
"=XLOOKUP(\"Q4\", Inputs!A:A, Inputs!B:B)"
])
WITAN
Use these helpers to test formulas against the workbook context before assigning them to cells, especially when formulas depend on defined names, table structured references, spill ranges, or sheet-qualified references.
Formula Features
Witan evaluates normal formulas, shared formulas, legacy CSE array formulas, dynamic-array formulas, and Excel data tables.
Supported calculation features include:
- Arithmetic, comparison, text concatenation, range, union, and intersection operators.
- A1 references, R1C1 references, sheet-qualified references, 3D references, table structured references, defined names, and spill references.
- External workbook references when the referenced values are available in the workbook's cached external-link data. External 3D references and external structured references are not evaluated.
- Scalar values, ranges, arrays, array constants, implicit intersection, array broadcasting, and functions that return arrays.
- Dynamic-array spill resize, spill blocker detection, cleanup of former spill cells, and recalculation of formulas that depend on spill children.
- Legacy CSE array formulas with fixed output ranges.
- One-variable and two-variable data table formulas.
- Future-function storage normalization, so user-facing formulas can use names such as
XLOOKUP,LET, andSEQUENCEwithout the internal_xlfn.prefix. - Volatile functions. Registered volatile functions are
AREAS,CELL,INDIRECT,INFO,NOW,OFFSET,RAND,RANDARRAY,RANDBETWEEN, andTODAY. - Circular-reference handling. When iterative calculation is enabled in the workbook, Witan uses the workbook's iteration count and max-change settings. When iterative calculation is disabled, circular references in the affected calculation scope are reported as formula errors.
Supported Functions
The calculation engine registers 497 worksheet functions. Functions in this list are evaluated by Witan; functions not listed here, including custom add-in functions and unsupported Excel feature families such as cube functions, are not evaluated.
Future functions are shown by their normal Excel names. The workbook file may store them with an internal _xlfn. prefix, but that prefix is not part of the public formula syntax you should write.
Database
DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP
Date And Time
DATE, DATEDIF, DATEVALUE, DAY, DAYS, DAYS360, EDATE, EOMONTH, HOUR, ISOWEEKNUM, MINUTE, MONTH, NETWORKDAYS, NETWORKDAYS.INTL, NOW, SECOND, TIME, TIMEVALUE, TODAY, WEEKDAY, WEEKNUM, WORKDAY, WORKDAY.INTL, YEAR, YEARFRAC
Engineering
BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, BITAND, BITLSHIFT, BITOR, BITRSHIFT, BITXOR, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERF.PRECISE, ERFC, ERFC.PRECISE, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMCOT, IMCSC, IMCSCH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSEC, IMSECH, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, OCT2BIN, OCT2DEC, OCT2HEX
Financial
ACCRINT, ACCRINTM, AMORDEGRC, AMORLINC, COUPDAYBS, COUPDAYS, COUPDAYSNC, COUPNCD, COUPNUM, COUPPCD, CUMIPMT, CUMPRINC, DB, DDB, DISC, DOLLARDE, DOLLARFR, DURATION, EFFECT, FV, FVSCHEDULE, INTRATE, IPMT, IRR, ISPMT, MDURATION, MIRR, NOMINAL, NPER, NPV, ODDFPRICE, ODDFYIELD, ODDLPRICE, ODDLYIELD, PDURATION, PMT, PPMT, PRICE, PRICEDISC, PRICEMAT, PV, RATE, RECEIVED, RRI, SLN, SYD, TBILLEQ, TBILLPRICE, TBILLYIELD, VDB, XIRR, XNPV, YIELD, YIELDDISC, YIELDMAT
Information
CELL, ERROR.TYPE, INFO, ISBLANK, ISERR, ISERROR, ISEVEN, ISFORMULA, ISLOGICAL, ISNA, ISNONTEXT, ISNUMBER, ISODD, ISREF, ISTEXT, N, NA, SHEET, SHEETS, TYPE
Lambda
BYCOL, BYROW, ISOMITTED, LAMBDA, LET, MAKEARRAY, MAP, REDUCE, SCAN
Logical
AND, FALSE, IF, IFERROR, IFNA, IFS, NOT, OR, SWITCH, TRUE, XOR
Lookup
ADDRESS, AREAS, CHOOSE, CHOOSECOLS, CHOOSEROWS, COLUMN, COLUMNS, DROP, EXPAND, FILTER, FORMULATEXT, GETPIVOTDATA, HLOOKUP, HSTACK, HYPERLINK, INDEX, INDIRECT, LOOKUP, MATCH, OFFSET, ROW, ROWS, RTD, SORT, SORTBY, TAKE, TOCOL, TOROW, TRANSPOSE, TRIMRANGE, UNIQUE, VLOOKUP, VSTACK, WRAPCOLS, WRAPROWS, XLOOKUP, XMATCH
Math And Trigonometry
ABS, ACOS, ACOSH, ACOT, ACOTH, AGGREGATE, ARABIC, ASIN, ASINH, ATAN, ATAN2, ATANH, BASE, CEILING, CEILING.MATH, CEILING.PRECISE, COMBIN, COMBINA, COS, COSH, COT, COTH, CSC, CSCH, DECIMAL, DEGREES, EVEN, EXP, FACT, FACTDOUBLE, FLOOR, FLOOR.MATH, FLOOR.PRECISE, GCD, INT, ISO.CEILING, LCM, LN, LOG, LOG10, MDETERM, MINVERSE, MMULT, MOD, MROUND, MULTINOMIAL, MUNIT, ODD, PERCENTOF, PI, POWER, PRODUCT, QUOTIENT, RADIANS, RAND, RANDARRAY, RANDBETWEEN, ROMAN, ROUND, ROUNDDOWN, ROUNDUP, SEC, SECH, SEQUENCE, SERIESSUM, SIGN, SIN, SINH, SQRT, SQRTPI, SUBTOTAL, SUM, SUMIF, SUMIFS, SUMPRODUCT, SUMSQ, SUMX2MY2, SUMX2PY2, SUMXMY2, TAN, TANH, TRUNC
Statistical
AVEDEV, AVERAGE, AVERAGEA, AVERAGEIF, AVERAGEIFS, BETA.DIST, BETA.INV, BETADIST, BETAINV, BINOM.DIST, BINOM.DIST.RANGE, BINOM.INV, BINOMDIST, CHIDIST, CHIINV, CHISQ.DIST, CHISQ.DIST.RT, CHISQ.INV, CHISQ.INV.RT, CHISQ.TEST, CHITEST, CONFIDENCE, CONFIDENCE.NORM, CONFIDENCE.T, CORREL, COUNT, COUNTA, COUNTBLANK, COUNTIF, COUNTIFS, COVAR, COVARIANCE.P, COVARIANCE.S, CRITBINOM, DEVSQ, EXPON.DIST, EXPONDIST, F.DIST, F.DIST.RT, F.INV, F.INV.RT, F.TEST, FDIST, FINV, FISHER, FISHERINV, FORECAST, FORECAST.LINEAR, FREQUENCY, FTEST, GAMMA, GAMMA.DIST, GAMMA.INV, GAMMADIST, GAMMAINV, GAMMALN, GAMMALN.PRECISE, GAUSS, GEOMEAN, GROWTH, HARMEAN, HYPGEOM.DIST, HYPGEOMDIST, INTERCEPT, KURT, LARGE, LINEST, LOGEST, LOGINV, LOGNORM.DIST, LOGNORM.INV, LOGNORMDIST, MAX, MAXA, MAXIFS, MEDIAN, MIN, MINA, MINIFS, MODE, MODE.MULT, MODE.SNGL, NEGBINOM.DIST, NEGBINOMDIST, NORM.DIST, NORM.INV, NORM.S.DIST, NORM.S.INV, NORMDIST, NORMINV, NORMSDIST, NORMSINV, PEARSON, PERCENTILE, PERCENTILE.EXC, PERCENTILE.INC, PERCENTRANK, PERCENTRANK.EXC, PERCENTRANK.INC, PERMUT, PERMUTATIONA, PHI, POISSON, POISSON.DIST, PROB, QUARTILE, QUARTILE.EXC, QUARTILE.INC, RANK, RANK.AVG, RANK.EQ, RSQ, SKEW, SKEW.P, SLOPE, SMALL, STANDARDIZE, STDEV, STDEV.P, STDEV.S, STDEVA, STDEVP, STDEVPA, STEYX, T.DIST, T.DIST.2T, T.DIST.RT, T.INV, T.INV.2T, T.TEST, TDIST, TINV, TREND, TRIMMEAN, TTEST, VAR, VAR.P, VAR.S, VARA, VARP, VARPA, WEIBULL, WEIBULL.DIST, Z.TEST, ZTEST
Text
ARRAYTOTEXT, ASC, CHAR, CLEAN, CODE, CONCAT, CONCATENATE, DOLLAR, EXACT, FIND, FINDB, FIXED, LEFT, LEFTB, LEN, LENB, LOWER, MID, MIDB, NUMBERVALUE, PROPER, REGEXEXTRACT, REGEXREPLACE, REGEXTEST, REPLACE, REPLACEB, REPT, RIGHT, RIGHTB, SEARCH, SEARCHB, SUBSTITUTE, T, TEXT, TEXTAFTER, TEXTBEFORE, TEXTJOIN, TEXTSPLIT, TRIM, UNICHAR, UNICODE, UPPER, VALUE, VALUETOTEXT
Web
ENCODEURL, EUROCONVERT, FILTERXML
JSON Output
--json prints the calculation response object:
witan xlsx calc report.xlsx --json
{
"touched": {
"Summary!B5": {
"value": "$1,250,000",
"formula": "=SUM(Revenue!B2:B13)"
}
},
"changed": ["Summary!B5"],
"errors": []
}
Fields:
| Field | Meaning |
|---|---|
touched |
Map of recalculated addresses to display values and formulas. |
changed |
Addresses whose cached computed value changed. |
errors |
Formula errors found during recalculation. |
The CLI removes returned workbook bytes from JSON output before printing, because the file payload is not useful in terminal automation.
CLI Reference
witan xlsx calc <file> [flags]
| Flag | Description |
|---|---|
<file> |
Path to the .xlsx, .xls, or .xlsm workbook. |
--range, -r |
Sheet-qualified range to seed recalculation from. Repeatable. |
--show-touched |
Print recalculated cells with formulas and computed values. |
--verify |
Do not overwrite the workbook; exit 2 if errors exist or values changed. |
--json |
Print the machine-readable calculation result as JSON. |
Exit Codes
| Code | Meaning |
|---|---|
0 |
Recalculation completed and no reported formula errors were found. |
1 |
Transport, API, file, or request error. |
2 |
Formula errors were found. In --verify mode, also returned when cached values would change. |
Limits
calc does not execute VBA macros. Macro-enabled workbooks can be opened and recalculated, but macro code is not run.
Custom add-in functions are not evaluated unless the engine has native support for that function. External workbook references are resolved from available cached workbook data; calc does not open arbitrary referenced workbooks from disk.