Skip to content

feat: implement SORT dynamic array function (HF-69)#1707

Open
marcin-kordas-hoc wants to merge 1 commit into
developfrom
feature/HF-69-sort
Open

feat: implement SORT dynamic array function (HF-69)#1707
marcin-kordas-hoc wants to merge 1 commit into
developfrom
feature/HF-69-sort

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

What & why

Implements SORT (HF-69, child of HF-28 "Modern dynamic array functions", sibling of the shipped SEQUENCE and of VSTACK/HSTACK). Adds SORT(array, [sort_index], [sort_order], [by_col]) as a dynamic array function.

Tests: handsontable/hyperformula-tests#24 (paired).
Sibling PR: #1708 (UNIQUE / HF-68).
ADR: docs/adr/2026-07-13-sort-unique-array-functions.md.

Behavior

  • Returns an array the same shape as the input.
  • sort_index (default 1): 1-based index into the sort dimension.
  • sort_order: 1 ascending (default) or -1 descending.
  • by_col: FALSE (default) reorders rows; TRUE reorders columns.
  • Ordering reuses ArithmeticHelper (mixed types: numbers < text < logical; empties; locale collation via caseSensitive/accentSensitive) and is stable — ties keep input order.

Design

Mirrors the SEQUENCE/FILTER machinery: sizeOfResultArrayMethod + vectorizationForbidden: true, runtime via runFunction returning SimpleRangeValue/CellError, parse-time size method returning a fresh ArraySize (the input's isRef flag is dropped — a ref-flagged size is treated as scalar and would collapse the spill).

Notes — divergences from Excel (surfaced here + inline + in tests)

  • sort_order is strictly {1, -1}; any other value → #VALUE!. Excel documents only {1,-1}; the reported "sort_order=0 does not error" quirk is undocumented and could not be re-verified against live Excel in this environment, so the strict documented contract was chosen (see ADR dec_2, con_1). Flagged for live-Excel/Kuba confirmation.
  • Multi-key array-constant sort_index (e.g. {1,2}) is not supported in v1 (documented in known-limitations.md; ADR dec_6).
  • In-range errors propagate (first error found; ADR dec_7).

Error-type map

sort_order ∉ {1,-1}#VALUE! (BadMode) · sort_index < 1#VALUE! (LessThanOne) · sort_index > dimension → #VALUE! (ValueLarge) · in-range error → propagate · wrong arity → #N/A.

Definition of Done

  • Production code (SortPlugin.ts, registered via plugin/index.ts)
  • i18n — all 17 language packs (authoritative MS Functions Translator names; enUS inherits enGB)
  • Tests (paired tests PR) — across the standard array-function groups, dual-env safe
  • Docs — built-in-functions.md, known-limitations.md
  • JSDoc on all methods
  • CHANGELOG entry
  • ADR with audit-verified citations

Source: https://app.clickup.com/t/86c89q1tt

@netlify

netlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit 05389bf
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a5532fb2f108c000836c3f2
😎 Deploy Preview https://deploy-preview-1707--hyperformula-dev-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@qunabu

qunabu commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Add SORT(array, [sort_index], [sort_order], [by_col]) as a dynamic array
function, mirroring the SEQUENCE/FILTER machinery. Ordering reuses
ArithmeticHelper (mixed types, empties, collation) and is stable, so ties
keep input order. sort_order is validated strictly to {1,-1}; sort_index is
bounds-checked; errors in the input range propagate. Output shape equals the
input shape.

Includes i18n for all 17 language packs, docs (built-in-functions,
known-limitations), a changelog entry, and the shared ADR.

Source: https://app.clickup.com/t/86c89q1tt
ADR: docs/adr/2026-07-13-sort-unique-array-functions.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@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 1 potential issue.

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 05389bf. Configure here.

r1[keyIndex] as InternalNoErrorScalarValue,
r2[keyIndex] as InternalNoErrorScalarValue,
))
return SimpleRangeValue.onlyValues(rows)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty sort result crashes evaluation

High Severity

When the input range has zero height (for example inverted endpoints like B2:B1), the row-sort path builds an empty rows array and passes it to SimpleRangeValue.onlyValues. That constructor reads _data[0].length, so evaluation throws an uncaught TypeError instead of returning a sorted range or a cell error. Excel treats inverted ranges as normalized spans, so this is a plausible user input.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 05389bf. Configure here.

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

Performance comparison of head (05389bf) vs base (033f8ac)

                                     testName |   base |   head | change
------------------------------------------------------------------------
                                      Sheet A |  453.7 | 424.12 | -6.52%
                                      Sheet B |  138.1 | 128.84 | -6.71%
                                      Sheet T |  123.7 | 116.71 | -5.65%
                                Column ranges | 593.84 | 542.45 | -8.65%
Sheet A:  change value, add/remove row/column |  11.75 |  10.94 | -6.89%
 Sheet B: change value, add/remove row/column | 112.48 | 102.34 | -9.01%
                   Column ranges - add column | 145.04 | 132.98 | -8.31%
                Column ranges - without batch | 455.54 |  419.6 | -7.89%
                        Column ranges - batch |    112 | 106.58 | -4.84%

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.17%. Comparing base (033f8ac) to head (05389bf).

Files with missing lines Patch % Lines
src/interpreter/plugin/SortPlugin.ts 98.18% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1707      +/-   ##
===========================================
+ Coverage    97.15%   97.17%   +0.01%     
===========================================
  Files          176      177       +1     
  Lines        15404    15460      +56     
  Branches      3409     3421      +12     
===========================================
+ Hits         14966    15023      +57     
+ Misses         438      437       -1     
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 1 file 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