-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation, tests, readme
- Loading branch information
Showing
13 changed files
with
354 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"root": true, | ||
|
||
"extends": "@ljharb", | ||
|
||
"rules": { | ||
"id-length": "off", | ||
"max-lines-per-function": "off", | ||
"new-cap": ["error", { | ||
"capIsNewExceptions": [ | ||
"GetIntrinsic", | ||
], | ||
}], | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# These are supported funding model platforms | ||
|
||
github: [ljharb] | ||
patreon: # Replace with a single Patreon username | ||
open_collective: # Replace with a single Open Collective username | ||
ko_fi: # Replace with a single Ko-fi username | ||
tidelift: npm/safe-array-concat | ||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry | ||
liberapay: # Replace with a single Liberapay username | ||
issuehunt: # Replace with a single IssueHunt username | ||
otechie: # Replace with a single Otechie username | ||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: 'Tests: node.js < 10' | ||
|
||
on: [pull_request, push] | ||
|
||
jobs: | ||
tests: | ||
uses: ljharb/actions/.github/workflows/node.yml@main | ||
with: | ||
range: '< 10' | ||
type: minors | ||
command: npm run tests-only | ||
|
||
node: | ||
name: 'node < 10' | ||
needs: [tests] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- run: 'echo tests completed' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name: 'Tests: pretest/posttest' | ||
|
||
on: [pull_request, push] | ||
|
||
jobs: | ||
tests: | ||
uses: ljharb/actions/.github/workflows/pretest.yml@main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: 'Tests: node.js >= 10' | ||
|
||
on: [pull_request, push] | ||
|
||
jobs: | ||
tests: | ||
uses: ljharb/actions/.github/workflows/node.yml@main | ||
with: | ||
range: '>= 10' | ||
type: minors | ||
command: npm run tests-only | ||
|
||
node: | ||
name: 'node >= 10' | ||
needs: [tests] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- run: 'echo tests completed' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Automatic Rebase | ||
|
||
on: [pull_request_target] | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
_: | ||
permissions: | ||
contents: write # for ljharb/rebase to push code to rebase | ||
pull-requests: read # for ljharb/rebase to get info about PR | ||
|
||
name: "Automatic Rebase" | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ljharb/rebase@master | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name: Require “Allow Edits” | ||
|
||
on: [pull_request_target] | ||
|
||
jobs: | ||
_: | ||
name: "Require “Allow Edits”" | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: ljharb/require-allow-edits@main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,3 +107,5 @@ dist | |
npm-shrinkwrap.json | ||
package-lock.json | ||
yarn.lock | ||
|
||
.npmignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"all": true, | ||
"check-coverage": false, | ||
"reporter": ["text-summary", "text", "html", "json"], | ||
"lines": 86, | ||
"statements": 85.93, | ||
"functions": 82.43, | ||
"branches": 76.06, | ||
"exclude": [ | ||
"coverage", | ||
"test" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,53 @@ | ||
# safe-array-concat | ||
Array.prototype.concat, but is safe by ignoring Symbol.isConcatSpreadable | ||
# safe-array-concat <sup>[![Version Badge][npm-version-svg]][package-url]</sup> | ||
|
||
[![github actions][actions-image]][actions-url] | ||
[![coverage][codecov-image]][codecov-url] | ||
[![License][license-image]][license-url] | ||
[![Downloads][downloads-image]][downloads-url] | ||
|
||
[![npm badge][npm-badge-png]][package-url] | ||
|
||
`Array.prototype.concat`, but made safe by ignoring Symbol.isConcatSpreadable | ||
|
||
## Getting started | ||
|
||
```sh | ||
npm install --save safe-array-concat | ||
``` | ||
|
||
## Usage/Examples | ||
|
||
```js | ||
var safeConcat = require('safe-array-concat'); | ||
var assert = require('assert'); | ||
|
||
assert.deepEqual([].concat([1, 2], 3, [[4]]), [1, 2, 3, [4]], 'arrays spread as expected with normal concat'); | ||
assert.deepEqual(safeConcat([1, 2], 3, [[4]]), [1, 2, 3, [4]], 'arrays spread as expected with safe concat'); | ||
|
||
String.prototype[Symbol.isConcatSpreadable] = true; | ||
assert.deepEqual([].concat('foo', Object('bar')), ['foo', 'b', 'a', 'r'], 'spreadable String objects are spread with normal concat!!!'); | ||
assert.deepEqual(safeConcat('foo', Object('bar')), ['foo', Object('bar')], 'spreadable String objects are not spread with safe concat'); | ||
|
||
Array.prototype[Symbol.isConcatSpreadable] = false; | ||
assert.deepEqual([].concat([1, 2], 3, [[4]]), [[], [1, 2], 3, [[4]]], 'non-concat-spreadable arrays do not spread with normal concat!!!'); | ||
assert.deepEqual(safeConcat([1, 2], 3, [[4]]), [1, 2, 3, [4]], 'non-concat-spreadable arrays still spread with safe concat'); | ||
``` | ||
|
||
## Tests | ||
Simply clone the repo, `npm install`, and run `npm test` | ||
|
||
[package-url]: https://npmjs.org/package/safe-array-concat | ||
[npm-version-svg]: https://versionbadg.es/ljharb/safe-array-concat.svg | ||
[deps-svg]: https://david-dm.org/ljharb/safe-array-concat.svg | ||
[deps-url]: https://david-dm.org/ljharb/safe-array-concat | ||
[dev-deps-svg]: https://david-dm.org/ljharb/safe-array-concat/dev-status.svg | ||
[dev-deps-url]: https://david-dm.org/ljharb/safe-array-concat#info=devDependencies | ||
[npm-badge-png]: https://nodei.co/npm/safe-array-concat.png?downloads=true&stars=true | ||
[license-image]: https://img.shields.io/npm/l/safe-array-concat.svg | ||
[license-url]: LICENSE | ||
[downloads-image]: https://img.shields.io/npm/dm/safe-array-concat.svg | ||
[downloads-url]: https://npm-stat.com/charts.html?package=safe-array-concat | ||
[codecov-image]: https://codecov.io/gh/ljharb/safe-array-concat/branch/main/graphs/badge.svg | ||
[codecov-url]: https://app.codecov.io/gh/ljharb/safe-array-concat/ | ||
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/safe-array-concat | ||
[actions-url]: https://github.com/ljharb/safe-array-concat/actions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
'use strict'; | ||
|
||
var GetIntrinsic = require('get-intrinsic'); | ||
var $concat = GetIntrinsic('%Array.prototype.concat%'); | ||
|
||
var callBind = require('call-bind'); | ||
|
||
var callBound = require('call-bind/callBound'); | ||
var $slice = callBound('Array.prototype.slice'); | ||
|
||
var hasSymbols = require('has-symbols/shams')(); | ||
var isConcatSpreadable = hasSymbols && Symbol.isConcatSpreadable; | ||
|
||
var empty = []; | ||
if (isConcatSpreadable) { | ||
empty[isConcatSpreadable] = true; | ||
} | ||
var $concatApply = isConcatSpreadable ? callBind.apply($concat, empty) : null; | ||
var $concatCall = isConcatSpreadable ? null : callBind($concat, empty); | ||
|
||
var isArray = isConcatSpreadable ? require('isarray') : null; | ||
|
||
module.exports = isConcatSpreadable | ||
// eslint-disable-next-line no-unused-vars | ||
? function safeArrayConcat(item) { | ||
for (var i = 0; i < arguments.length; i += 1) { | ||
var arg = arguments[i]; | ||
if (arg && typeof arg === 'object' && typeof arg[isConcatSpreadable] === 'boolean') { | ||
var arr = isArray(arg) ? $slice(arg) : [arg]; | ||
arr[isConcatSpreadable] = true; // shadow the property. TODO: use [[Define]] | ||
arguments[i] = arr; | ||
} | ||
} | ||
return $concatApply(arguments); | ||
} | ||
: $concatCall; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
'use strict'; | ||
|
||
var test = require('tape'); | ||
var mockProperty = require('mock-property'); | ||
var hasSymbols = require('has-symbols/shams')(); | ||
var isConcatSpreadable = hasSymbols && Symbol.isConcatSpreadable; | ||
var species = hasSymbols && Symbol.species; | ||
|
||
var boundFnsHaveConfigurableLengths = Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(function () {}.bind(), 'length').configurable; | ||
|
||
var safeConcat = require('../'); | ||
|
||
test('safe-array-concat', function (t) { | ||
t.equal(typeof safeConcat, 'function', 'is a function'); | ||
t.equal( | ||
safeConcat.length, | ||
boundFnsHaveConfigurableLengths ? 1 : 0, | ||
'has a length of ' + (boundFnsHaveConfigurableLengths ? 1 : '0 (function lengths are not configurable)'), | ||
'length is as expected' | ||
); | ||
|
||
t.deepEqual( | ||
safeConcat([1, 2], [3, 4], 'foo', 5, 6, [[7]]), | ||
[1, 2, 3, 4, 'foo', 5, 6, [7]], | ||
'works with flat and nested arrays' | ||
); | ||
|
||
t.deepEqual( | ||
safeConcat(undefined, 1, 2), | ||
[undefined, 1, 2], | ||
'first item as undefined is not the concat receiver, which would throw via ToObject' | ||
); | ||
t.deepEqual( | ||
safeConcat(null, 1, 2), | ||
[null, 1, 2], | ||
'first item as null is not the concat receiver, which would throw via ToObject' | ||
); | ||
|
||
var arr = [1, 2]; | ||
arr.constructor = function C() { | ||
return { args: arguments }; | ||
}; | ||
t.deepEqual( | ||
safeConcat(arr, 3, 4), | ||
[1, 2, 3, 4], | ||
'first item as an array with a nonArray .constructor; ignores constructor' | ||
); | ||
|
||
t.test('has Symbol.species', { skip: !species }, function (st) { | ||
var speciesArr = [1, 2]; | ||
speciesArr.constructor = {}; | ||
speciesArr.constructor[species] = function Species() { | ||
return { args: arguments }; | ||
}; | ||
|
||
st.deepEqual( | ||
safeConcat(speciesArr, 3, 4), | ||
[1, 2, 3, 4], | ||
'first item as an array with a .constructor object with a Symbol.species; ignores constructor and species' | ||
); | ||
|
||
st.end(); | ||
}); | ||
|
||
t.test('has isConcatSpreadable', { skip: !isConcatSpreadable }, function (st) { | ||
st.teardown(mockProperty(String.prototype, isConcatSpreadable, { value: true })); | ||
|
||
var nonSpreadable = [1, 2]; | ||
nonSpreadable[isConcatSpreadable] = false; | ||
|
||
st.deepEqual( | ||
safeConcat(nonSpreadable, 3, 4, 'foo', Object('bar')), | ||
[1, 2, 3, 4, 'foo', Object('bar')], | ||
'a non-concat-spreadable array is spreaded, and a concat-spreadable String is not spreaded' | ||
); | ||
|
||
st.teardown(mockProperty(Array.prototype, isConcatSpreadable, { value: false })); | ||
|
||
st.deepEqual( | ||
safeConcat([1, 2], 3, 4, 'foo', Object('bar')), | ||
[1, 2, 3, 4, 'foo', Object('bar')], | ||
'all arrays marked non-concat-spreadable are still spreaded, and a concat-spreadable String is not spreaded' | ||
); | ||
|
||
st.end(); | ||
}); | ||
|
||
t.end(); | ||
}); |