Skip to content

feat(array): add arrFlatMap with ES5 polyfill#533

Open
nev21 wants to merge 1 commit intomainfrom
nev21/array
Open

feat(array): add arrFlatMap with ES5 polyfill#533
nev21 wants to merge 1 commit intomainfrom
nev21/array

Conversation

@nev21
Copy link
Copy Markdown
Contributor

@nev21 nev21 commented Mar 26, 2026

  • Add arrFlatMap and polyArrFlatMap implementations with one-level flatten behavior for mapped values.
  • Introduce ArrFlatMapCallbackFn type for array and array-like callback signatures.
  • Export arrFlatMap and the callback type from public index and polyfills entry points.

@nev21 nev21 added this to the 0.14.0 milestone Mar 26, 2026
@nev21 nev21 requested a review from a team as a code owner March 26, 2026 04:59
Copilot AI review requested due to automatic review settings March 26, 2026 04:59
@nev21 nev21 requested a review from a team as a code owner March 26, 2026 04:59
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.45%. Comparing base (53d481f) to head (f8dc20c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #533      +/-   ##
==========================================
+ Coverage   98.86%   99.45%   +0.58%     
==========================================
  Files         140      141       +1     
  Lines        4147     4202      +55     
  Branches      892      908      +16     
==========================================
+ Hits         4100     4179      +79     
+ Misses         47       23      -24     
Files with missing lines Coverage Δ
lib/src/array/callbacks.ts 100.00% <ø> (+50.00%) ⬆️
lib/src/array/flatMap.ts 100.00% <100.00%> (ø)
lib/src/array/flatten.ts 100.00% <ø> (ø)
lib/src/polyfills.ts 94.11% <100.00%> (+41.05%) ⬆️

... and 3 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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds arrFlatMap (with polyArrFlatMap) to @nevware21/ts-utils, extending the Array helper surface with an ES5-compatible flatMap implementation and public exports.

Changes:

  • Added arrFlatMap helper and polyArrFlatMap polyfill implementation.
  • Introduced ArrFlatMapCallbackFn type and exported it from the main index.
  • Added common tests, updated polyfills entry/export wiring, and adjusted bundle size thresholds/docs.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/src/array/flatMap.ts New arrFlatMap wrapper + polyArrFlatMap implementation.
lib/src/array/callbacks.ts Adds ArrFlatMapCallbackFn type for flatMap callbacks.
lib/src/index.ts Exports arrFlatMap and ArrFlatMapCallbackFn publicly.
lib/src/polyfills.ts Registers flatMap in prototype polyfill installation and exports polyArrFlatMap.
lib/src/array/flatten.ts Updates docs to reference arrFlatMap for map-then-flatten workflows.
lib/test/src/common/array/flatMap.test.ts Adds coverage for arrFlatMap, polyArrFlatMap, and export wiring.
lib/test/bundle-size-check.js Increases bundle size thresholds for ES5 minified artifacts.
.size-limit.json Updates size-limit thresholds for built ES5/ES6 modules.
docs/feature-backlog.md Updates backlog entry related to arrFlatMap (currently with a content issue).

nevware21-bot
nevware21-bot previously approved these changes Mar 26, 2026
Copy link
Copy Markdown
Contributor

@nevware21-bot nevware21-bot left a comment

Choose a reason for hiding this comment

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

Approved by nevware21-bot

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

- Add `arrFlatMap` and `polyArrFlatMap` implementations with one-level flatten behavior for mapped values.
- Introduce `ArrFlatMapCallbackFn` type for array and array-like callback signatures.
- Export `arrFlatMap` and the callback type from public index and polyfills entry points.
Copy link
Copy Markdown
Contributor

@nevware21-bot nevware21-bot left a comment

Choose a reason for hiding this comment

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

Approved by nevware21-bot

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Comment on lines +17 to +42
import { getKnownSymbol } from "../symbol/symbol";
import { isArrayLike } from "../helpers/base";
import { createCachedValue, ICachedValue } from "../helpers/cache";

let _isConcatSpreadable: ICachedValue<symbol>;

/*#__NO_SIDE_EFFECTS__*/
function _isFlatMapSpreadable(value: any): boolean {
let result = false;
if (isArray(value) || isArrayLike(value)) {
result = true;

if (!_isConcatSpreadable) {
_isConcatSpreadable = createCachedValue(getKnownSymbol("isConcatSpreadable", true) || null);
}

let sym = _isConcatSpreadable.v;
if (sym) {
let symVal = value[sym as any];
if (symVal !== undefined) {
result = !!symVal;
}
}
}

return result;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

_isFlatMapSpreadable() currently treats any isArrayLike() value (including strings) as spreadable and also uses Symbol.isConcatSpreadable to decide flattening. Native Array.prototype.flatMap flattens only Arrays (and does not honor isConcatSpreadable), so arrFlatMap will behave differently depending on whether the runtime has native flatMap or uses polyArrFlatMap. Consider changing the spreadability check to align with the native spec (flatten Arrays only) to keep behavior consistent across environments.

Suggested change
import { getKnownSymbol } from "../symbol/symbol";
import { isArrayLike } from "../helpers/base";
import { createCachedValue, ICachedValue } from "../helpers/cache";
let _isConcatSpreadable: ICachedValue<symbol>;
/*#__NO_SIDE_EFFECTS__*/
function _isFlatMapSpreadable(value: any): boolean {
let result = false;
if (isArray(value) || isArrayLike(value)) {
result = true;
if (!_isConcatSpreadable) {
_isConcatSpreadable = createCachedValue(getKnownSymbol("isConcatSpreadable", true) || null);
}
let sym = _isConcatSpreadable.v;
if (sym) {
let symVal = value[sym as any];
if (symVal !== undefined) {
result = !!symVal;
}
}
}
return result;
/*#__NO_SIDE_EFFECTS__*/
function _isFlatMapSpreadable(value: any): boolean {
// Align with native Array.prototype.flatMap: only Array instances are flattened,
// and Symbol.isConcatSpreadable is not considered.
return isArray(value);

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +90
it("should flatten array-like callback results", () => {
const mappedValue = { length: 2, 0: "x", 1: "y" };
const result = polyArrFlatMap([1], () => mappedValue as any);

assert.deepEqual(result, ["x", "y"]);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

This test expects polyArrFlatMap to flatten an array-like object returned from the callback. Native Array.prototype.flatMap only flattens Arrays, so this expectation will make the polyfill diverge from native behavior (and from arrFlatMap when the native implementation is used). Consider updating the test (and polyfill behavior) to only flatten when the callback returns an actual Array.

Suggested change
it("should flatten array-like callback results", () => {
const mappedValue = { length: 2, 0: "x", 1: "y" };
const result = polyArrFlatMap([1], () => mappedValue as any);
assert.deepEqual(result, ["x", "y"]);
it("should not flatten plain array-like callback results", () => {
const mappedValue = { length: 2, 0: "x", 1: "y" };
const result = polyArrFlatMap([1], () => mappedValue as any);
assert.equal(result.length, 1);
assert.strictEqual(result[0], mappedValue);

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +104
it("should flatten concat-spreadable mapped objects when symbol is available", () => {
const spreadSym = typeof Symbol !== "undefined" && Symbol.isConcatSpreadable;
if (!spreadSym) {
return;
}

const mappedValue: any = { length: 2, 0: "x", 1: "y" };
mappedValue[spreadSym] = true;

const result = polyArrFlatMap([1], () => mappedValue);
assert.deepEqual(result, ["x", "y"]);
});
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

These assertions assume polyArrFlatMap honors Symbol.isConcatSpreadable on non-Array objects. Native Array.prototype.flatMap does not use concat-spreadability when flattening (it only flattens Arrays), so this test enforces non-standard behavior and will cause cross-environment differences. Consider removing this behavior and updating the test accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +117
it("should not flatten mapped objects with concat-spreadable set to false", () => {
const spreadSym = typeof Symbol !== "undefined" && Symbol.isConcatSpreadable;
if (!spreadSym) {
return;
}

const mappedValue: any = { length: 2, 0: "x", 1: "y" };
mappedValue[spreadSym] = false;

const result = polyArrFlatMap([1], () => mappedValue);
assert.equal(result.length, 1);
assert.strictEqual(result[0], mappedValue);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

This test case for Symbol.isConcatSpreadable = false continues the concat-spreadable semantics which don't exist for native flatMap (it ignores Symbol.isConcatSpreadable). If the polyfill is updated to match native behavior (flatten Arrays only), this test should be removed or rewritten to cover Array-only flattening edge cases.

Suggested change
it("should not flatten mapped objects with concat-spreadable set to false", () => {
const spreadSym = typeof Symbol !== "undefined" && Symbol.isConcatSpreadable;
if (!spreadSym) {
return;
}
const mappedValue: any = { length: 2, 0: "x", 1: "y" };
mappedValue[spreadSym] = false;
const result = polyArrFlatMap([1], () => mappedValue);
assert.equal(result.length, 1);
assert.strictEqual(result[0], mappedValue);
it("should flatten arrays even when concat-spreadable is set to false", () => {
const spreadSym = typeof Symbol !== "undefined" && Symbol.isConcatSpreadable;
if (!spreadSym) {
return;
}
const mappedValue: any = ["x", "y"];
mappedValue[spreadSym] = false;
const result = polyArrFlatMap([1], () => mappedValue);
assert.deepEqual(result, ["x", "y"]);

Copilot uses AI. Check for mistakes.
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.

3 participants