├── .editorconfig ├── .eslintrc ├── .github ├── FUNDING.yml ├── SECURITY.md └── workflows │ ├── node-aught.yml │ ├── node-pretest.yml │ ├── node-tens.yml │ ├── node-twenties.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .npmrc ├── .nycrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── auto.js ├── implementation.js ├── index.js ├── package.json ├── polyfill.js ├── shim.js └── test ├── implementation.js ├── index.js ├── index.mjs ├── shimmed.js └── tests.js /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | trim_trailing_whitespace = true 5 | charset = utf-8 6 | 7 | [*.{js,json}] 8 | indent_style = tab 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "@ljharb", 5 | 6 | "rules": { 7 | "array-bracket-newline": 0, 8 | "id-length": [2, { "min": 1, "max": 25, "properties": "never" }], 9 | "max-statements": [2, 14], 10 | "max-statements-per-line": [2, { "max": 2 }], 11 | "max-params": 0, 12 | "multiline-comment-style": 0, 13 | "new-cap": [2, { 14 | "capIsNewExceptions": [ 15 | "Call", 16 | "Get", 17 | "IsCallable", 18 | "LengthOfArrayLike", 19 | "RequireObjectCoercible", 20 | "ToBoolean", 21 | "ToObject", 22 | "ToString", 23 | ], 24 | }], 25 | "no-magic-numbers": 0, 26 | "object-curly-newline": 0, 27 | }, 28 | 29 | "overrides": [ 30 | { 31 | "files": "test/**", 32 | "rules": { 33 | "id-length": 0, 34 | "max-lines-per-function": 0, 35 | "no-invalid-this": 0, 36 | }, 37 | }, 38 | ], 39 | } 40 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ljharb] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: npm/array.prototype.findindex 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report. 4 | -------------------------------------------------------------------------------- /.github/workflows/node-aught.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js < 10' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '< 10' 13 | type: minors 14 | command: npm run tests-only 15 | 16 | node: 17 | name: 'node < 10' 18 | needs: [tests] 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: 'echo tests completed' 22 | -------------------------------------------------------------------------------- /.github/workflows/node-pretest.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: pretest/posttest' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/pretest.yml@main 11 | -------------------------------------------------------------------------------- /.github/workflows/node-tens.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js 10 - 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 10 < 20' 13 | type: minors 14 | command: npm run tests-only 15 | 16 | node: 17 | name: 'node 10 - 20' 18 | needs: [tests] 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: true 22 | -------------------------------------------------------------------------------- /.github/workflows/node-twenties.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js >= 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 20' 13 | type: minors 14 | command: npm run tests-only 15 | 16 | node: 17 | name: 'node >= 20' 18 | needs: [tests] 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: true 22 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | uses: ljharb/actions/.github/workflows/rebase.yml@main 8 | secrets: 9 | token: ${{ secrets.GITHUB_TOKEN }} 10 | -------------------------------------------------------------------------------- /.github/workflows/require-allow-edits.yml: -------------------------------------------------------------------------------- 1 | name: Require “Allow Edits” 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | name: "Require “Allow Edits”" 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: ljharb/require-allow-edits@main 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *~ 7 | 8 | # OS or Editor folders 9 | .DS_Store 10 | .cache 11 | Icon? 12 | 13 | # Folders to ignore 14 | .hg 15 | .svn 16 | 17 | # Node.js package manager 18 | node_modules 19 | npm-debug.log 20 | 21 | # Other stuff 22 | *.pyc 23 | /tmp 24 | 25 | # Project stuff 26 | 27 | # Only apps should have lockfiles 28 | npm-shrinkwrap.json 29 | package-lock.json 30 | yarn.lock 31 | 32 | coverage/ 33 | .nyc_output/ 34 | 35 | .npmignore 36 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | allow-same-version=true 3 | message=v%s 4 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "check-coverage": false, 4 | "reporter": ["text-summary", "text", "html", "json"], 5 | "exclude": [ 6 | "coverage", 7 | "test" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [v2.2.4](https://github.com/ljharb/Array.prototype.findIndex/compare/v2.2.3...v2.2.4) - 2024-12-17 9 | 10 | ### Commits 11 | 12 | - [actions] split out node 10-20, and 20+ [`22ec19f`](https://github.com/ljharb/Array.prototype.findIndex/commit/22ec19ff06322731bffebc82f74cd1c5c7bdd28e) 13 | - [Dev Deps] update `@es-shims/api`, `auto-changelog`, `tape` [`60c8f4a`](https://github.com/ljharb/Array.prototype.findIndex/commit/60c8f4a80830034800977081a153b1c1e858345d) 14 | - [Deps] update `call-bind`, `es-abstract` [`31f714f`](https://github.com/ljharb/Array.prototype.findIndex/commit/31f714fd1d73f24369313138fa3a9c6dc4d30d8f) 15 | - [Dev Deps] update `@es-shims/api`, `@ljharb/eslint-config` [`763157c`](https://github.com/ljharb/Array.prototype.findIndex/commit/763157c9ab768fc8e474357a448174d838348e71) 16 | - [meta] add missing `engines.node` [`1f5d651`](https://github.com/ljharb/Array.prototype.findIndex/commit/1f5d6510f43e8e33b96c2575ccad6b6719bbbc72) 17 | - [Refactor] use `call-bound` directly [`ebc05aa`](https://github.com/ljharb/Array.prototype.findIndex/commit/ebc05aa2a2b60b576105a988e89bbbb8272d4c4d) 18 | - [Tests] replace `aud` with `npm audit` [`1f6d4de`](https://github.com/ljharb/Array.prototype.findIndex/commit/1f6d4de6868be6e22097fb3f656b7acb6fc38ba5) 19 | - [meta] add `SECURITY.md` [`2cf450e`](https://github.com/ljharb/Array.prototype.findIndex/commit/2cf450eae9393815ebe6f59177d101666bb8c06c) 20 | - [Deps] update `es-abstract` [`33ede20`](https://github.com/ljharb/Array.prototype.findIndex/commit/33ede205919316a2709123fee24b849e5dea3a88) 21 | - [Dev Deps] add missing peer dep [`906ece2`](https://github.com/ljharb/Array.prototype.findIndex/commit/906ece22b58b4cfaef2543bf6ba05de241182a44) 22 | 23 | ## [v2.2.3](https://github.com/ljharb/Array.prototype.findIndex/compare/v2.2.2...v2.2.3) - 2024-03-16 24 | 25 | ### Commits 26 | 27 | - [Refactor] use `es-object-atoms`, update `es-abstract` [`7747551`](https://github.com/ljharb/Array.prototype.findIndex/commit/7747551fe933fc7355dd69f855d48626ee083d6a) 28 | - [Deps] update `call-bind`, `define-properties`, `es-shim-unscopables` [`d0f9882`](https://github.com/ljharb/Array.prototype.findIndex/commit/d0f98829e8d853c46c453ff8801576684e96b1ed) 29 | - [Dev Deps] update `aud`, `npmignore`, `tape` [`f6a1abf`](https://github.com/ljharb/Array.prototype.findIndex/commit/f6a1abfc96ac033179455d466ba7c28cde107fdb) 30 | 31 | ## [v2.2.2](https://github.com/ljharb/Array.prototype.findIndex/compare/v2.2.1...v2.2.2) - 2023-08-27 32 | 33 | ### Commits 34 | 35 | - [meta] add `auto-changelog` [`d653e4c`](https://github.com/ljharb/Array.prototype.findIndex/commit/d653e4c1d09ffb154e7452530ec9072157505130) 36 | - [Deps] update `define-properties`, `es-abstract` [`6afe819`](https://github.com/ljharb/Array.prototype.findIndex/commit/6afe819c42ff3e207432613db0aa035d3cd7ccc7) 37 | - [Dev Deps] update `@es-shims/api`, `@ljharb/eslint-config`, `aud`, `tape` [`c65fb5f`](https://github.com/ljharb/Array.prototype.findIndex/commit/c65fb5f37731f37a6674c1fec274edd5e63e61e8) 38 | 39 | 40 | 41 | # 2.2.1 42 | - [Deps] update `define-properties`, `es-abstract` 43 | - [meta] use `npmignore` to autogenerate an npmignore file 44 | - [actions] update rebase action to use reusable workflow 45 | - [Dev Deps] update `aud`, `functions-have-names`, `tape` 46 | 47 | # 2.2.0 48 | - [New] `shim`/`auto`: add `findIndex` to `Symbol.unscopables` 49 | - [Tests] migrate to tape 50 | - [Deps] update `es-abstract` 51 | - [Dev Deps] update `@ljharb/eslint-config` 52 | 53 | # 2.1.1 54 | - [Refactor] update implementation to match spec text 55 | - [meta] add `safe-publish-latest` 56 | - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `@es-shims/api` 57 | - [Tests] migrate tests to Github Actions 58 | 59 | # 2.1.0 60 | - [New] add `auto` entry point 61 | - [Fix] remove `detect` file, broken/unused in v2 62 | - [Refactor] use split-up `es-abstract` (77% bundle size decrease) 63 | - [Performance] avoid checking `arguments` indexes beyond `arguments.length` 64 | - [Performance] inline `ES.Call` since `IsCallable` is already checked prior to the loop. 65 | - [Deps] update `define-properties` 66 | - [meta] Only apps should have lockfiles 67 | - [meta] add missing LICENSE file 68 | - [Tests] add `npm run lint` 69 | - [Tests] use shared travis-ci configs 70 | - [Tests] use `aud` in posttest 71 | 72 | # 2.0.2 73 | - [Performance] the entry point should use the native function when compliant 74 | 75 | # 2.0.1 76 | - [Fix] use call instead of apply in bound entry point function (#17) 77 | - [Refactor] Remove unnecessary double ToLength call (#16) 78 | - [Tests] run tests on travis-ci 79 | 80 | # 2.0.0 81 | - [Breaking] use es-shim API (#13) 82 | - [Docs] fix example in README (#9) 83 | - [Docs] Fix npm install command in README (#7) 84 | 85 | # 1.0.0 86 | - [Fix] do not skip holes, per ES6 change (#4) 87 | - [Fix] Older browsers report the typeof some host objects and regexes as "function" (#5) 88 | 89 | # 0.1.1 90 | - [Fix] Support IE8 by wrapping Object.defineProperty with a try catch (#3) 91 | - [Refactor] remove redundant enumerable: false (#1) 92 | 93 | # 0.1.0 94 | - Initial release. 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Paul Miller, Jordan Harband, and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ES6 `Array.prototype.findIndex` polyfill 2 | 3 | Simple ES6 [Array.prototype.findIndex](http://people.mozilla.org/%7Ejorendorff/es6-draft.html#sec-array.prototype.findindex) polyfill for older environments taken from [es6-shim](https://github.com/paulmillr/es6-shim). 4 | 5 | For browsers and node.js. 6 | 7 | ## Installation 8 | * Just include repo before your scripts. 9 | * `npm install array.prototype.findindex` if you’re using node.js. 10 | * `component install paulmillr/Array.prototype.findIndex` if you’re using [component(1)](https://github.com/component/component). 11 | * `bower install Array.prototype.findIndex` if you’re using [Twitter Bower](http://bower.io). 12 | 13 | 14 | ## Usage 15 | 16 | * `Array.prototype.findIndex(predicate[, thisArg])` returns first item index that matches `predicate` function. 17 | * `predicate(value, index, collection)`: takes three arguments 18 | * `value`: current collection element 19 | * `index`: current collection element index 20 | * `collection`: the collection 21 | 22 | ```javascript 23 | var findIndex = require('array.prototype.findindex'); 24 | 25 | findIndex.shim(); // if you want to install it on the global environment 26 | ``` 27 | 28 | Code example: 29 | 30 | ```javascript 31 | // Default: 32 | [1, 5, 10, 15].findIndex(function(a) {return a > 9;}) // 2 33 | ``` 34 | 35 | ## License 36 | 37 | The MIT License (MIT) 38 | 39 | Copyright (c) 2013 Paul Miller 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy 42 | of this software and associated documentation files (the “Software”), to deal 43 | in the Software without restriction, including without limitation the rights 44 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | copies of the Software, and to permit persons to whom the Software is 46 | furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in 49 | all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 55 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 56 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 57 | THE SOFTWARE. 58 | -------------------------------------------------------------------------------- /auto.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./shim')(); 4 | -------------------------------------------------------------------------------- /implementation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Call = require('es-abstract/2024/Call'); 4 | var Get = require('es-abstract/2024/Get'); 5 | var IsCallable = require('es-abstract/2024/IsCallable'); 6 | var LengthOfArrayLike = require('es-abstract/2024/LengthOfArrayLike'); 7 | var ToBoolean = require('es-abstract/2024/ToBoolean'); 8 | var ToObject = require('es-object-atoms/ToObject'); 9 | var ToString = require('es-abstract/2024/ToString'); 10 | 11 | module.exports = function findIndex(predicate) { 12 | var O = ToObject(this); 13 | var len = LengthOfArrayLike(O); 14 | if (!IsCallable(predicate)) { 15 | throw new TypeError('Array#findIndex: predicate must be a function'); 16 | } 17 | 18 | var thisArg = arguments.length > 1 ? arguments[1] : void undefined; 19 | 20 | var k = 0; 21 | while (k < len) { 22 | var Pk = ToString(k); 23 | var kValue = Get(O, Pk); 24 | var testResult = ToBoolean(Call(predicate, thisArg, [kValue, k, O])); 25 | if (testResult) { 26 | return k; 27 | } 28 | k += 1; 29 | } 30 | 31 | return -1; 32 | }; 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var define = require('define-properties'); 4 | var RequireObjectCoercible = require('es-object-atoms/RequireObjectCoercible'); 5 | var callBind = require('call-bind'); 6 | var callBound = require('call-bound'); 7 | 8 | var implementation = require('./implementation'); 9 | var getPolyfill = require('./polyfill'); 10 | var shim = require('./shim'); 11 | 12 | var $slice = callBound('Array.prototype.slice'); 13 | 14 | var polyfill = callBind.apply(getPolyfill()); 15 | 16 | var boundShim = function findIndex(array, predicate) { // eslint-disable-line no-unused-vars 17 | RequireObjectCoercible(array); 18 | var args = $slice(arguments, 1); 19 | return polyfill(array, args); 20 | }; 21 | 22 | define(boundShim, { 23 | getPolyfill: getPolyfill, 24 | implementation: implementation, 25 | shim: shim 26 | }); 27 | 28 | module.exports = boundShim; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "array.prototype.findindex", 3 | "version": "2.2.4", 4 | "description": "Array.prototype.findIndex ES2015 polyfill.", 5 | "keywords": [ 6 | "Array.prototype.findIndex", 7 | "findIndex", 8 | "es6", 9 | "es2015" 10 | ], 11 | "main": "index.js", 12 | "scripts": { 13 | "prepack": "npmignore --auto --commentLines=autogenerated", 14 | "prepublishOnly": "safe-publish-latest", 15 | "prepublish": "not-in-publish || npm run prepublishOnly", 16 | "prelint": "es-shim-api --bound", 17 | "lint": "eslint --ext=js,mjs .", 18 | "pretest": "npm run lint", 19 | "tests-only": "nyc tape 'test/**/*.js'", 20 | "test": "npm run tests-only", 21 | "posttest": "npx npm@'>= 10.2' audit --production", 22 | "version": "auto-changelog && git add CHANGELOG.md", 23 | "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git://github.com/paulmillr/Array.prototype.findIndex.git" 28 | }, 29 | "author": "Paul Miller ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/paulmillr/Array.prototype.findIndex/issues" 33 | }, 34 | "devDependencies": { 35 | "@es-shims/api": "^2.5.1", 36 | "@ljharb/eslint-config": "^21.1.1", 37 | "auto-changelog": "^2.5.0", 38 | "encoding": "^0.1.13", 39 | "eslint": "=8.8.0", 40 | "functions-have-names": "^1.2.3", 41 | "has-strict-mode": "^1.0.1", 42 | "in-publish": "^2.0.1", 43 | "npmignore": "^0.3.1", 44 | "nyc": "^10.3.2", 45 | "safe-publish-latest": "^2.0.0", 46 | "tape": "^5.9.0" 47 | }, 48 | "dependencies": { 49 | "call-bind": "^1.0.8", 50 | "call-bound": "^1.0.3", 51 | "define-properties": "^1.2.1", 52 | "es-abstract": "^1.23.6", 53 | "es-object-atoms": "^1.0.0", 54 | "es-shim-unscopables": "^1.0.2" 55 | }, 56 | "auto-changelog": { 57 | "output": "CHANGELOG.md", 58 | "template": "keepachangelog", 59 | "unreleased": false, 60 | "commitLimit": false, 61 | "backfillLimit": false, 62 | "hideCredit": true, 63 | "startingVersion": "2.2.2" 64 | }, 65 | "publishConfig": { 66 | "ignore": [ 67 | ".github/workflows" 68 | ] 69 | }, 70 | "engines": { 71 | "node": ">= 0.4" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /polyfill.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var implementation = require('./implementation'); 4 | 5 | module.exports = function getPolyfill() { 6 | // Detect if an implementation exists 7 | // Detect early implementations which skipped holes in sparse arrays 8 | // eslint-disable-next-line no-sparse-arrays 9 | var implemented = Array.prototype.findIndex && ([, 1].findIndex(function (item, idx) { 10 | return idx === 0; 11 | }) === 0); 12 | 13 | return implemented ? Array.prototype.findIndex : implementation; 14 | }; 15 | -------------------------------------------------------------------------------- /shim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var define = require('define-properties'); 4 | var shimUnscopables = require('es-shim-unscopables'); 5 | 6 | var getPolyfill = require('./polyfill'); 7 | 8 | module.exports = function shimFindIndex() { 9 | var polyfill = getPolyfill(); 10 | 11 | define( 12 | Array.prototype, 13 | { findIndex: polyfill }, 14 | { 15 | findIndex: function () { 16 | return Array.prototype.findIndex !== polyfill; 17 | } 18 | } 19 | ); 20 | 21 | shimUnscopables('findIndex'); 22 | 23 | return polyfill; 24 | }; 25 | -------------------------------------------------------------------------------- /test/implementation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var keys = require('../implementation'); 4 | var callBind = require('call-bind'); 5 | var test = require('tape'); 6 | var hasStrictMode = require('has-strict-mode')(); 7 | var runTests = require('./tests'); 8 | 9 | test('as a function', function (t) { 10 | t.test('bad array/this value', { skip: !hasStrictMode }, function (st) { 11 | /* eslint no-useless-call: 0 */ 12 | st['throws'](function () { keys.call(undefined); }, TypeError, 'undefined is not an object'); 13 | st['throws'](function () { keys.call(null); }, TypeError, 'null is not an object'); 14 | st.end(); 15 | }); 16 | 17 | runTests(callBind(keys), t); 18 | 19 | t.end(); 20 | }); 21 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var keys = require('../'); 4 | var test = require('tape'); 5 | var runTests = require('./tests'); 6 | 7 | test('as a function', function (t) { 8 | t.test('bad array/this value', function (st) { 9 | st['throws'](function () { keys(undefined); }, TypeError, 'undefined is not an object'); 10 | st['throws'](function () { keys(null); }, TypeError, 'null is not an object'); 11 | st.end(); 12 | }); 13 | 14 | runTests(keys, t); 15 | 16 | t.end(); 17 | }); 18 | -------------------------------------------------------------------------------- /test/index.mjs: -------------------------------------------------------------------------------- 1 | import keys from 'array.prototype.keys'; 2 | import * as keysModule from 'array.prototype.keys'; 3 | import test from 'tape'; 4 | import runTests from './tests.js'; 5 | 6 | test('as a function', (t) => { 7 | t.test('bad array/this value', (st) => { 8 | st.throws(() => keys(undefined), TypeError, 'undefined is not an object'); 9 | st.throws(() => keys(null), TypeError, 'null is not an object'); 10 | st.end(); 11 | }); 12 | 13 | runTests(keys, t); 14 | 15 | t.end(); 16 | }); 17 | 18 | test('named exports', async (t) => { 19 | t.deepEqual( 20 | Object.keys(keysModule).sort(), 21 | ['default', 'shim', 'getPolyfill', 'implementation'].sort(), 22 | 'has expected named exports', 23 | ); 24 | 25 | const { shim, getPolyfill, implementation } = keysModule; 26 | t.equal((await import('array.prototype.keys/shim')).default, shim, 'shim named export matches deep export'); 27 | t.equal((await import('array.prototype.keys/implementation')).default, implementation, 'implementation named export matches deep export'); 28 | t.equal((await import('array.prototype.keys/polyfill')).default, getPolyfill, 'getPolyfill named export matches deep export'); 29 | 30 | t.end(); 31 | }); 32 | -------------------------------------------------------------------------------- /test/shimmed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('../auto'); 4 | 5 | var test = require('tape'); 6 | var defineProperties = require('define-properties'); 7 | var callBind = require('call-bind'); 8 | 9 | var isEnumerable = Object.prototype.propertyIsEnumerable; 10 | var functionsHaveNames = require('functions-have-names')(); 11 | var hasStrictMode = require('has-strict-mode')(); 12 | 13 | var runTests = require('./tests'); 14 | 15 | test('shimmed', function (t) { 16 | t.equal(Array.prototype.findIndex.length, 1, 'Array#findIndex has a length of 1'); 17 | t.test('Function name', { skip: !functionsHaveNames }, function (st) { 18 | st.equal(Array.prototype.findIndex.name, 'findIndex', 'Array#findIndex has name "findIndex"'); 19 | st.end(); 20 | }); 21 | 22 | t.test('enumerability', { skip: !defineProperties.supportsDescriptors }, function (et) { 23 | et.equal(false, isEnumerable.call(Array.prototype, 'findIndex'), 'Array#findIndex is not enumerable'); 24 | et.end(); 25 | }); 26 | 27 | t.test('bad array/this value', { skip: !hasStrictMode }, function (st) { 28 | st['throws'](function () { return Array.prototype.findIndex.call(undefined); }, TypeError, 'undefined is not an object'); 29 | st['throws'](function () { return Array.prototype.findIndex.call(null); }, TypeError, 'null is not an object'); 30 | st.end(); 31 | }); 32 | 33 | runTests(callBind(Array.prototype.findIndex), t); 34 | 35 | t.end(); 36 | }); 37 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var canDistinguishSparseFromUndefined = 0 in [undefined]; // IE 6 - 8 have a bug where this returns false. 4 | 5 | var thrower = function () { 6 | throw new Error('should not reach here'); 7 | }; 8 | 9 | module.exports = function (findIndex, t) { 10 | var list = [5, 10, 15, 20]; 11 | 12 | t.equal( 13 | findIndex(list, function (item) { return item === 15; }), 14 | 2, 15 | 'find index by predicate' 16 | ); 17 | t.equal( 18 | findIndex(list, function (item) { return item === 'a'; }), 19 | -1, 20 | 'returns -1 when nothing matches' 21 | ); 22 | t['throws']( 23 | function () { findIndex(list); }, 24 | TypeError, 25 | 'throws without callback' 26 | ); 27 | 28 | var context = {}; 29 | var foundIndex = findIndex(list, function (value, index, arr) { 30 | t.equal(list[index], value); 31 | t.deepEqual(list, arr); 32 | t.equal(this, context, 'receiver is as expected'); 33 | return false; 34 | }, context); 35 | t.equal(foundIndex, -1, 'receives all three arguments'); 36 | 37 | var arraylike = { 0: 1, 1: 2, 2: 3, length: 3 }; 38 | t.equal( 39 | findIndex(arraylike, function (item) { 40 | return item === 2; 41 | }), 42 | 1, 43 | 'works with an array-like object' 44 | ); 45 | 46 | t.equal( 47 | findIndex({ 0: 1, 1: 2, 2: 3, length: -3 }, thrower), 48 | -1, 49 | 'works with an array-like object with negative length' 50 | ); 51 | 52 | t.test('sparse arrays', { skip: !canDistinguishSparseFromUndefined }, function (st) { 53 | st.test('works with a sparse array', function (s2t) { 54 | var obj = [1, , undefined]; // eslint-disable-line no-sparse-arrays 55 | s2t.notOk(1 in obj); 56 | var seen = []; 57 | var foundSparse = findIndex(obj, function (item, idx) { 58 | seen.push([idx, item]); 59 | return false; 60 | }); 61 | s2t.equal(foundSparse, -1); 62 | s2t.deepEqual(seen, [[0, 1], [1, undefined], [2, undefined]]); 63 | 64 | s2t.end(); 65 | }); 66 | 67 | st.test('works with a sparse array-like object', function (s2t) { 68 | var obj = { 0: 1, 2: undefined, length: 3.2 }; 69 | var seen = []; 70 | var foundSparse = findIndex(obj, function (item, idx) { 71 | seen.push([idx, item]); 72 | return false; 73 | }); 74 | s2t.equal(foundSparse, -1); 75 | s2t.deepEqual(seen, [[0, 1], [1, undefined], [2, undefined]]); 76 | 77 | s2t.end(); 78 | }); 79 | 80 | st.end(); 81 | }); 82 | }; 83 | --------------------------------------------------------------------------------