Skip to content

Commit e8f338c

Browse files
sequbabudnix
andauthored
Add IRR function for calculating internal rate of return (#1598)
* Add unit tests for IRR * Add IRR function for calculating internal rate of return * Add additional edge case tests for IRR function * Add tests to cover uncovered lines in irrCore * Fix linter warnings * Handle guess = -1 same as Excel * Return #VALUE for guess < -1 * Add instructions file for Claude Code * Fix typos --------- Co-authored-by: Krzysztof ‘Budzio’ Budnik <[email protected]>
1 parent 7f856be commit e8f338c

File tree

21 files changed

+675
-0
lines changed

21 files changed

+675
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Added a new function: IRR. [#1591](https://github.com/handsontable/hyperformula/issues/1591)
13+
1014
## [3.1.1] - 2025-12-18
1115

1216
### Fixed

CLAUDE.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
HyperFormula is a headless spreadsheet engine written in TypeScript. It parses and evaluates Excel-compatible formulas and can run in browser or Node.js environments. The library implements ~400 built-in functions with support for custom functions, undo/redo, CRUD operations, and i18n (17 languages).
8+
9+
## Build & Development Commands
10+
11+
```bash
12+
npm install # Install dependencies
13+
npm run compile # TypeScript compilation to lib/
14+
npm run bundle-all # Full build: compile + bundle all formats
15+
npm run lint # Run ESLint
16+
npm run lint:fix # Auto-fix lint issues
17+
```
18+
19+
## Testing
20+
21+
```bash
22+
npm test # Full suite: lint + unit + browser + compatibility
23+
npm run test:unit # Jest unit tests only
24+
npm run test:watch # Jest watch mode (run tests on file changes)
25+
npm run test:coverage # Unit tests with coverage report
26+
npm run test:browser # Karma browser tests (Chrome/Firefox)
27+
npm run test:performance # Run performance benchmarks
28+
npm run test:compatibility # Excel compatibility tests
29+
```
30+
31+
Test files are located in `test/unit/` and follow the pattern `*.spec.ts`.
32+
33+
## Architecture
34+
35+
### Core Components
36+
37+
- **`src/HyperFormula.ts`** - Main engine class, public API entry point
38+
- **`src/parser/`** - Formula parsing using Chevrotain parser generator
39+
- **`src/interpreter/`** - Formula evaluation engine
40+
- **`src/DependencyGraph/`** - Cell dependency tracking and recalculation order
41+
- **`src/CrudOperations.ts`** - Create/Read/Update/Delete operations on sheets and cells
42+
43+
### Function Plugins (`src/interpreter/plugin/`)
44+
45+
All spreadsheet functions are implemented as plugins extending `FunctionPlugin`. Each plugin:
46+
- Declares `implementedFunctions` static property mapping function names to metadata
47+
- Uses `runFunction()` helper for argument validation, coercion, and array handling
48+
- Registers function translations in `src/i18n/languages/`
49+
50+
To add a new function:
51+
1. Create or modify a plugin in `src/interpreter/plugin/`
52+
2. Add function metadata to `implementedFunctions`
53+
3. Implement the function method
54+
4. Add translations to all language files in `src/i18n/languages/`
55+
5. Add tests in `test/unit/interpreter/`
56+
57+
### i18n (`src/i18n/languages/`)
58+
59+
Function name translations for each supported language. When adding new functions, translations can be found at:
60+
- https://support.microsoft.com/en-us/office/excel-functions-translator-f262d0c0-991c-485b-89b6-32cc8d326889
61+
- http://dolf.trieschnigg.nl/excel/index.php
62+
63+
## Output Formats
64+
65+
The build produces multiple output formats:
66+
- `commonjs/` - CommonJS modules (main entry)
67+
- `es/` - ES modules (.mjs files)
68+
- `dist/` - UMD bundles for browsers
69+
- `typings/` - TypeScript declaration files
70+
71+
## Contributing Guidelines
72+
73+
- Create feature branches, never commit directly to master
74+
- Target the `develop` branch for pull requests
75+
- Add tests for all changes in `test/` folder
76+
- Run linter before submitting (`npm run lint`)
77+
- Maintain compatibility with Excel and Google Sheets behavior
78+
- In documentation, commit messages, pull request descriptions and code comments, do not mention Claude Code nor LLM models used for code generation
79+
80+
## Response Guidelines
81+
82+
- By default speak ultra-concisely, using as few words as you can, unless asked otherwise.
83+
- Focus solely on instructions and provide relevant responses.
84+
- Ask questions to remove ambiguity and make sure you're speaking about the right thing.
85+
- Ask questions if you need more information to provide an accurate answer.
86+
- If you don't know something, simply say, "I don't know," and ask for help.
87+
- Present your answer in a structured way, use bullet lists, numbered lists, tables, etc.
88+
- When asked for specific content, start the response with the requested info immediately.
89+
- When answering based on context, support your claims by quoting exact fragments of available documents.
90+
91+
## Code Style
92+
93+
- When generating code, prefer functional approach whenever possible (in JS/TS use filter, map and reduce functions).
94+
- Make the code self-documenting. Use meaningfull names for classes, functions, valiables etc. Add code comments only when necessary.
95+
- Add jsdocs to all classes and functions.

docs/guide/built-in-functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ Total number of functions: **{{ $page.functionsCount }}**
176176
| FV | Returns the future value of an investment. | FV(Rate, Nper, Pmt[, Pv,[ Type]]) |
177177
| FVSCHEDULE | Returns the future value of an investment based on a rate schedule. | FV(Pv, Schedule) |
178178
| IPMT | Returns the interest portion of a given loan payment in a given payment period. | IPMT(Rate, Per, Nper, Pv[, Fv[, Type]]) |
179+
| IRR | Returns the internal rate of return for a series of cash flows. | IRR(Values[, Guess]) |
179180
| ISPMT | Returns the interest paid for a given period of an investment with equal principal payments. | ISPMT(Rate, Per, Nper, Value) |
180181
| MIRR | Returns modified internal value for cashflows. | MIRR(Flows, FRate, RRate) |
181182
| NOMINAL | Returns the nominal interest rate. | NOMINAL(Effect_rate, Npery) |

src/i18n/languages/csCZ.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const dictionary: RawTranslationPackage = {
111111
INT: 'CELÁ.ČÁST',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'PLATBA.ÚROK',
114+
IRR: 'MÍRA.VÝNOSNOSTI',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'JE.PRÁZDNÉ',
116117
ISERR: 'JE.CHYBA',

src/i18n/languages/daDK.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const dictionary: RawTranslationPackage = {
111111
INT: 'HELTAL',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'R.YDELSE',
114+
IRR: 'IA',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'ER.TOM',
116117
ISERR: 'ER.FJL',

src/i18n/languages/deDE.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const dictionary: RawTranslationPackage = {
111111
INT: 'GANZZAHL',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'ZINSZ',
114+
IRR: 'IKV',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'ISTLEER',
116117
ISERR: 'ISTFEHL',

src/i18n/languages/enGB.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ const dictionary: RawTranslationPackage = {
112112
INT: 'INT',
113113
INTERVAL: 'INTERVAL',
114114
IPMT: 'IPMT',
115+
IRR: 'IRR',
115116
ISBINARY: 'ISBINARY',
116117
ISBLANK: 'ISBLANK',
117118
ISERR: 'ISERR',

src/i18n/languages/esES.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export const dictionary: RawTranslationPackage = {
111111
INT: 'ENTERO',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'PAGOINT',
114+
IRR: 'TIR',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'ESBLANCO',
116117
ISERR: 'ESERR',

src/i18n/languages/fiFI.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const dictionary: RawTranslationPackage = {
111111
INT: 'KOKONAISLUKU',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'IPMT',
114+
IRR: 'SISÄINEN.KORKO',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'ONTYHJÄ',
116117
ISERR: 'ONVIRH',

src/i18n/languages/frFR.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ const dictionary: RawTranslationPackage = {
111111
INT: 'ENT',
112112
INTERVAL: 'INTERVAL', //FIXME
113113
IPMT: 'INTPER',
114+
IRR: 'TRI',
114115
ISBINARY: 'ISBINARY',
115116
ISBLANK: 'ESTVIDE',
116117
ISERR: 'ESTERR',

0 commit comments

Comments
 (0)