Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 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
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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
arrFlatMaphelper andpolyArrFlatMappolyfill implementation. - Introduced
ArrFlatMapCallbackFntype 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
left a comment
There was a problem hiding this comment.
Approved by nevware21-bot
- 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.
nevware21-bot
left a comment
There was a problem hiding this comment.
Approved by nevware21-bot
| 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; |
There was a problem hiding this comment.
_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.
| 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); |
| 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"]); |
There was a problem hiding this comment.
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.
| 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); |
| 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"]); | ||
| }); |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
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.
| 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"]); |
arrFlatMapandpolyArrFlatMapimplementations with one-level flatten behavior for mapped values.ArrFlatMapCallbackFntype for array and array-like callback signatures.arrFlatMapand the callback type from public index and polyfills entry points.