Skip to content

Feature/choosecols function - #1734

Open
Tobiadefami wants to merge 8 commits into
developfrom
feature/choosecols-function
Open

Feature/choosecols function#1734
Tobiadefami wants to merge 8 commits into
developfrom
feature/choosecols-function

Conversation

@Tobiadefami

@Tobiadefami Tobiadefami commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Context

HyperFormula does not currently support CHOOSECOLS.

This change adds CHOOSECOLS, allowing columns to be selected from an array using positive or negative
indexes. It preserves the requested order and duplicate indexes and includes function metadata,
translations, documentation, and tests.

The implementation remains local to ArrayPlugin. CHOOSEROWS is outside the scope of this change.

How did you test your changes?

Added tests covering:

  • Required and repeated arguments.
  • Positive, negative, mixed, and duplicate indexes.
  • Fractional indexes and numeric coercion.
  • Cell-reference and calculated index arguments.
  • Scalar, range, whole-row, and calculated-array inputs.
  • Spill dimensions and blocked spill ranges.
  • Bounds validation and error propagation.
  • Reading only selected worksheet columns.
  • Public function metadata and localized function names.

All 35 focused tests passed.

The full Jest and browser test suites, TypeScript compilation, linting, and documentation generation also
completed successfully.

Types of changes

  • Breaking change (a fix or a feature because of which an existing functionality doesn't work as
    expected anymore)
  • New feature or improvement (a non-breaking change that adds functionality)
  • Bug fix (a non-breaking change that fixes an issue)
  • Additional language file, or a change to an existing language file (translations)
  • Change to the documentation

Related issues:

None.

Checklist:

  • I have reviewed the guidelines about [Contributing to HyperFormula](https://
    hyperformula.handsontable.com/guide/contributing.html) and I confirm that my code follows the code style of
    this project.
  • I have signed the Contributor License Agreement.
  • My change is compliant with the [OpenDocument](https://docs.oasis-open.org/office/OpenDocument/v1.3/
    os/part4-formula/OpenDocument-v1.3-os-part4-formula.html) standard.
  • My change is compatible with Microsoft Excel.
  • My change is compatible with Google Sheets.
  • I described my changes in the [CHANGELOG.md](https://github.com/handsontable/hyperformula/blob/master/
    CHANGELOG.md) file.
  • My changes require a documentation update.
  • My changes require a migration guide.

Note

Low Risk
New lookup/array function in ArrayPlugin following existing dynamic-array patterns; no changes to core calculation or auth paths.

Overview
Adds the CHOOSECOLS dynamic-array function so formulas can return selected columns from a range in a given order, including positive/negative indexing and duplicate column picks.

Implementation lives in ArrayPlugin: choosecols evaluates the selection (with worksheet-range reads when the source is a bound range), and choosecolsArraySize plus parseChooseColsLiteralIndex predict spill size and reject invalid literal column indexes before spill allocation. Whole-column sources spill only from row 1; below that, #SPILL! is returned. Empty sources yield #N/A.

Documentation and metadata: changelog entry, known limitations (scalar index args only, spill vs error ordering), Excel/Sheets comparison row for whole-column refs, lookup metadata, and localized function names across language packs.

Reviewed by Cursor Bugbot for commit f9d182e. Bugbot is set up for automated code reviews on this repo. Configure here.

@cla-external-contractor-signup

Copy link
Copy Markdown

@Tobiadefami thanks for the pull request. No CLA step needed here — our records show you signed the Contributor License Agreement on 2026-07-31. That signature came from our previous signing form and has been carried over, so there is nothing for you to re-sign.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
hyperformula-docs f9d182e Commit Preview URL

Branch Preview URL
Aug 19 2026, 02:57 PM

Comment thread src/interpreter/plugin/ArrayPlugin.ts
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

Performance comparison of head (f9d182e) vs base (61ead73)

                                     testName |    base |    head | change
--------------------------------------------------------------------------
                                      Sheet A |  495.52 |   492.2 | -0.67%
                                      Sheet B |  159.79 |  156.74 | -1.91%
                                      Sheet T |  138.87 |  137.48 | -1.00%
                                Column ranges |  526.09 |  524.41 | -0.32%
                                Sorted lookup | 16244.5 | 15544.5 | -4.31%
Sheet A:  change value, add/remove row/column |    17.6 |   17.67 | +0.40%
 Sheet B: change value, add/remove row/column |  143.31 |  150.49 | +5.01%
                   Column ranges - add column |   164.3 |  163.33 | -0.59%
                Column ranges - without batch |  506.93 |  485.28 | -4.27%
                        Column ranges - batch |  130.56 |  122.58 | -6.11%

Comment thread src/interpreter/plugin/ArrayPlugin.ts
* @param {ProcedureAst} ast - The parsed function-call AST node.
* @param {InterpreterState} state - The current interpreter evaluation state.
*/
public choosecolsArraySize(ast: ProcedureAst, state: InterpreterState): ArraySize {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same finding as on #1722's TAKE: CHOOSECOLS(A:A,1) returns #VALUE! even on the same sheet, where real Excel spills correctly (confirmed live via MS Graph). SORT/UNIQUE/FILTER already support this in the same codebase — worth reusing whatever they do differently in array-size prediction rather than the current blanket rejection of non-finite dimensions.

known-limitations.md's new CHOOSECOLS entry is otherwise excellent, by the way — exactly the house style (HF's own behavior + consequence, no Excel-comparison framing). Once the same-sheet case is fixed, the "Spills the whole column when space is available" line in list-of-differences.md will need to become case-specific: same-sheet works, cross-sheet genuinely does not (confirmed #SPILL! in real Excel).

@marcin-kordas-hoc

Copy link
Copy Markdown
Collaborator

This PR also touches script/release/release.sh (adds a release-checklist line: "Review the deployed docs and test the demos"), which is unrelated to CHOOSECOLS and not mentioned in the description — it says the change is "local to ArrayPlugin." Either split it out into its own PR, or explain why it is bundled here.

@Tobiadefami
Tobiadefami changed the base branch from master to develop August 17, 2026 10:27
}
}

return new ArraySize(ast.args.length - 1, effectiveHeight)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finite height breaks column spills

High Severity

choosecolsArraySize now materializes whole-column results with a finite effectiveHeight snapshot instead of keeping an unbounded height. Array size is fixed when the formula is set, so when the source sheet later grows, evaluation returns more rows than predicted and ArrayValue.resize throws. SORT/UNIQUE/FILTER keep POSITIVE_INFINITY here so spill stays an AbsoluteColumnRange and can expand.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0df4d1f. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reran this against the current PR commit (0df4d1f28c) using both cross-sheet and same-sheet whole-column formulas.

One clarification: updating a source cell does reevaluate the formula, but it does not rerun the array-size predictor or rebuild the formula vertex.

Test setup

I started with three values in column A and then extended the sheet’s used height by adding a fourth value:

  hf.setCellContents(
    { sheet: dataSheet, col: 0, row: 3 },
    40,
  )

I tested the following cross-sheet formulas:

=CHOOSECOLS(Data!A:A, 1)
=SORT(Data!A:A)
=UNIQUE(Data!A:A)

I repeated the test using same-sheet references:

=CHOOSECOLS(A:A, 1)
=SORT(A:A)
=UNIQUE(A:A)

Result

All three functions throw the same error when the new value extends the used height of the source range:

Error: Resizing to smaller array
    at ArrayValue.resize (.../src/ArrayValue.ts:141:13)
    at ArrayFormulaVertex.setCellValue (.../src/DependencyGraph/FormulaVertex.ts:132:11)
    at Evaluator.recomputeFormulaVertexValue (.../src/Evaluator.ts:141:21)

For the same-sheet tests, SORT and UNIQUE initially spill all three rows correctly. However, they still throw after adding the fourth source value.

The following control cases succeed:

  • Updating a value within the source’s existing used height.
  • Using a finite source such as Data!A1:A4 and then populating A4.

Could you rerun the source-growth check against SORT and UNIQUE?

Based on these results, they do not currently expand successfully after the used height of a whole-column source increases.

It also appears that preserving Infinity during the initial array-size prediction is insufficient on its own. After the first evaluation, the array formula vertex holds the finite size of the materialized result. The subsequent, larger result then fails in ArrayValue.resize.

This may therefore require an engine-level change to spill allocation or predicted-size retention -- or another mechanism that allows an existing array formula vertex to grow during recalculation.

@Tobiadefami

Copy link
Copy Markdown
Collaborator Author

cursor review verbose=true

@cursor

cursor Bot commented Aug 19, 2026

Copy link
Copy Markdown

Bugbot request id: serverGenReqId_13ccdf6c-fbd0-4e9c-ada9-f067011978d8

@cursor

cursor Bot commented Aug 19, 2026

Copy link
Copy Markdown

Bugbot rules debug

Bugbot rules included in this run
Rule Type Size Status
BugBot must only comment on code that is part of the current PR diff (team-eabd5813-f182-4953-8f13-f36d29df4505) team 372 chars included

https://cursor.com/docs/bugbot#team-rules

Bugbot request id: serverGenReqId_13ccdf6c-fbd0-4e9c-ada9-f067011978d8

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0df4d1f. Configure here.

Comment thread src/interpreter/plugin/ArrayPlugin.ts
Comment thread src/interpreter/plugin/ArrayPlugin.ts
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.35%. Comparing base (61ead73) to head (f9d182e).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1734      +/-   ##
===========================================
+ Coverage    97.31%   97.35%   +0.03%     
===========================================
  Files          195      195              
  Lines        15719    15797      +78     
  Branches      3455     3416      -39     
===========================================
+ Hits         15297    15379      +82     
- Misses         414      418       +4     
+ Partials         8        0       -8     
Files with missing lines Coverage Δ
src/i18n/languages/csCZ.ts 100.00% <ø> (ø)
src/i18n/languages/daDK.ts 100.00% <ø> (ø)
src/i18n/languages/deDE.ts 100.00% <ø> (ø)
src/i18n/languages/enGB.ts 100.00% <ø> (ø)
src/i18n/languages/esES.ts 100.00% <ø> (ø)
src/i18n/languages/fiFI.ts 100.00% <ø> (ø)
src/i18n/languages/frFR.ts 100.00% <ø> (ø)
src/i18n/languages/huHU.ts 100.00% <ø> (ø)
src/i18n/languages/idID.ts 100.00% <ø> (ø)
src/i18n/languages/itIT.ts 100.00% <ø> (ø)
... and 9 more

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants