├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github
├── CONTRIBUTING.md
└── workflows
│ ├── node-aught.yml
│ ├── node-pretest.yml
│ ├── node-tens.yml
│ ├── publish-on-tag.yml
│ ├── rebase.yml
│ └── require-allow-edits.yml
├── .gitignore
├── .npmrc
├── .nycrc
├── CHANGELOG.md
├── LICENSE-MIT.txt
├── README.md
├── auto.js
├── implementation.js
├── index.js
├── package.json
├── polyfill.js
├── shim.js
└── test
├── index.js
├── shimmed.js
└── tests.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | insert_final_newline = true
7 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 |
4 | "extends": "@ljharb",
5 |
6 | "rules": {
7 | "id-length": "off",
8 | "new-cap": ["error", {
9 | "capIsNewExceptions": [
10 | "IsRegExp",
11 | "RequireObjectCoercible",
12 | "StringCharCodeAt",
13 | "ToIntegerOrInfinity",
14 | "ToString",
15 | ],
16 | }],
17 | },
18 |
19 | "overrides": [
20 | {
21 | "files": "test/**/*",
22 | "rules": {
23 | "max-lines-per-function": "off",
24 | },
25 | },
26 | ],
27 | }
28 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Automatically normalize line endings for all text-based files
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## For maintainers
4 |
5 | ### How to publish a new release
6 |
7 | 1. On the `main` branch, bump the version number in `package.json`:
8 |
9 | ```sh
10 | npm version patch
11 | ```
12 |
13 | Instead of `patch`, use `minor` or `major` [as needed](https://semver.org/).
14 |
15 | Note that this produces a Git commit + tag.
16 |
17 | 1. Push the release commit and tag:
18 |
19 | ```sh
20 | git push && git push --tags
21 | ```
22 |
23 | Our CI then automatically publishes the new release to npm.
24 |
--------------------------------------------------------------------------------
/.github/workflows/node-aught.yml:
--------------------------------------------------------------------------------
1 | name: 'Tests: node.js < 10'
2 |
3 | on: [pull_request, push]
4 |
5 | jobs:
6 | tests:
7 | uses: ljharb/actions/.github/workflows/node.yml@main
8 | with:
9 | range: '< 10'
10 | type: minors
11 | command: npm run tests-only
12 |
13 | node:
14 | name: 'node < 10'
15 | needs: [tests]
16 | runs-on: ubuntu-latest
17 | steps:
18 | - run: 'echo tests completed'
19 |
--------------------------------------------------------------------------------
/.github/workflows/node-pretest.yml:
--------------------------------------------------------------------------------
1 | name: 'Tests: pretest/posttest'
2 |
3 | on: [pull_request, push]
4 |
5 | jobs:
6 | tests:
7 | uses: ljharb/actions/.github/workflows/pretest.yml@main
8 |
--------------------------------------------------------------------------------
/.github/workflows/node-tens.yml:
--------------------------------------------------------------------------------
1 | name: 'Tests: node.js >= 10'
2 |
3 | on: [pull_request, push]
4 |
5 | jobs:
6 | tests:
7 | uses: ljharb/actions/.github/workflows/node.yml@main
8 | with:
9 | range: '>= 10'
10 | type: minors
11 | command: npm run tests-only
12 |
13 | node:
14 | name: 'node >= 10'
15 | needs: [tests]
16 | runs-on: ubuntu-latest
17 | steps:
18 | - run: 'echo tests completed'
19 |
--------------------------------------------------------------------------------
/.github/workflows/publish-on-tag.yml:
--------------------------------------------------------------------------------
1 | name: publish-on-tag
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | publish:
10 | if: ${{ !github.event.repository.fork }}
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | - uses: ljharb/actions/node/install@main
16 | - name: Test
17 | run: npm test
18 | - name: Publish
19 | env:
20 | NPM_TOKEN: ${{secrets.NPM_TOKEN}}
21 | run: |
22 | npm config set registry 'https://wombat-dressing-room.appspot.com/'
23 | npm config set '//wombat-dressing-room.appspot.com/:_authToken' '${NPM_TOKEN}'
24 | npm publish
25 |
--------------------------------------------------------------------------------
/.github/workflows/rebase.yml:
--------------------------------------------------------------------------------
1 | name: Automatic Rebase
2 |
3 | on: [pull_request_target]
4 |
5 | permissions:
6 | contents: read
7 |
8 | jobs:
9 | tests:
10 | uses: ljharb/actions/.github/workflows/pretest.yml@main
11 |
--------------------------------------------------------------------------------
/.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 | # Coverage report
2 | coverage
3 | .nyc_output/
4 |
5 | # Installed npm modules
6 | node_modules
7 | package-lock.json
8 |
9 | # Folder view configuration files
10 | .DS_Store
11 | Desktop.ini
12 |
13 | # Thumbnail cache files
14 | ._*
15 | Thumbs.db
16 |
17 | # Files that might appear on external disks
18 | .Spotlight-V100
19 | .Trashes
20 |
--------------------------------------------------------------------------------
/.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 | "lines": 86,
6 | "statements": 85.93,
7 | "functions": 82.43,
8 | "branches": 76.06,
9 | "exclude": [
10 | "coverage",
11 | "test"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/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 | ## [v1.0.2](https://github.com/mathiasbynens/String.prototype.endsWith/compare/v1.0.1...v1.0.2) - 2024-03-18
9 |
10 | ### Commits
11 |
12 | - [Deps] update `call-bind`, `define-properties`, `es-abstract` [`38e22e6`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/38e22e69450af8a3f4ffa4f50a836b78a6204ffc)
13 | - [eslint] fix linting errors [`44cfb77`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/44cfb77f14f5ad2e8be69d6eb41d90c510d07c09)
14 | - [Dev Deps] update `aud`, `function-bind`, `tape` [`6f50b14`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/6f50b145b90c2a7faee01a924c26e8b9b487fc7d)
15 | - [Refactor] use `es-object-atoms` instead of `es-abstract` when possible [`42aa444`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/42aa4443737685d4fd2229cef1ecd03f83e8018d)
16 | - [meta] add missing `engines.node` [`bccb5bb`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/bccb5bb26e7e5c1a874f5c2558af8d8f7b7ede7f)
17 |
18 | ## [v1.0.1](https://github.com/mathiasbynens/String.prototype.endsWith/compare/v1.0.0...v1.0.1) - 2023-09-11
19 |
20 | ### Commits
21 |
22 | - [eslint] add eslint [`fb8cc46`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/fb8cc4665fd53eb2c91bb9da9cb4571c5a61f949)
23 | - [Tests] Switch from travis to GH actions [`b35ea44`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/b35ea44919003637de2bc13ee9a44b0e1247ba81)
24 | - [meta] add `auto-changelog` [`b6da653`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/b6da653669763483e3653fe3c62f7f699c3df535)
25 | - Set up automated `npm publish` [`b9be2b4`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/b9be2b462ad6c125dbe0de55d8f1d53891bcd4d4)
26 | - [readme] move maintainer instructions to CONTRIBUTING.md [`46da5f5`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/46da5f56fc6cb50915cd90f5f50cabb22b2c4ade)
27 | - [readme] update badges [`64e2a03`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/64e2a035f9fc8b086e3f1320771fe2f8996a287d)
28 | - [Deps] update `define-properties`, `es-abstract`; add `call-bind` [`185ac54`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/185ac546e6cc4840b185f30fda48c9fd12fac313)
29 | - [Tests] switch from istanbul to nyc [`8d33676`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/8d336769e74e1083c9caa353b55a6610a01ef33c)
30 | - [actions] use reusable rebase action [`a53f174`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/a53f17412eacf0d6161efe3a2f87938c474c62df)
31 | - [actions] fix publish workflow [`84d19c3`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/84d19c3c019ed8b727ec8a337144a6e24cc9cec6)
32 | - [Dev Deps] update `@es-shims/api`, `functions-have-names`, `tape` [`9543e15`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/9543e15819960a7823ee8117ef13cd76bd652f29)
33 | - [meta] remove broken `getPolyfill` entry point; add correct `polyfill` entry point [`0d5242c`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/0d5242c56c72c0f28961eb859be107eca0ea2d80)
34 | - [Tests] rename `tests` to `test` [`5e344d8`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/5e344d8a15c9ca4c6bf5097bb0c3f0598390ea43)
35 | - [Tests] add `aud` via `npm run posttest` [`699cf8c`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/699cf8ce416bb8b3904a476e485129d1d7d242a5)
36 |
37 | ## [v1.0.0](https://github.com/mathiasbynens/String.prototype.endsWith/compare/v0.2.0...v1.0.0) - 2020-05-21
38 |
39 | ### Commits
40 |
41 | - Merge pull request #9 from mathiasbynens/nr/es-shim-api [`272752d`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/272752d0bd32884fb6acb9bcf5e05f2e46c8310b)
42 | - Use `tape` in tests and run them on every Node.js version [`8030508`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/8030508ea2fcebf20ec3c1b7f30cf525a3d26185)
43 | - [breaking] Implement the es-shim-api interface [`c6eb152`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/c6eb1525f9a405c72c3f63d7fb3453c7b10f2ad6)
44 | - Use HTTPS URLs where possible [`a0eea7f`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/a0eea7f368c6f3f00a1f7a53f01f8c05db325e12)
45 | - Update readme [`15ba134`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/15ba134cabae6af361afc60865abce6bbe6c2482)
46 | - Test that it respects the es-shim-api interface [`1baf690`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/1baf69037e3b852fcc238a4bda85884a0a99b136)
47 | - Update repo config files [`e5b7310`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/e5b73100fe51f680f0207fc77f7d22682e46cd8d)
48 | - Improve error messages [`6853d40`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/6853d40f69ed13350deb2cd3007eb508407f7665)
49 |
50 | ## [v0.2.0](https://github.com/mathiasbynens/String.prototype.endsWith/compare/v0.1.0...v0.2.0) - 2014-04-10
51 |
52 | ### Fixed
53 |
54 | - Follow spec order [`#5`](https://github.com/mathiasbynens/String.prototype.endsWith/issues/5)
55 |
56 | ### Commits
57 |
58 | - Avoid IE8’s broken `Object.defineProperty` [`e27c8f2`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/e27c8f24a761e88792e5a850834e103cc01b5c3e)
59 | - Add more tests [`cc63a25`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/cc63a259d2d2814d28745ec6e543c8596879dbcd)
60 | - Make the `endsWith` property non-enumerable [`bffbff9`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/bffbff90911cabf88ff0541ad44205018b5e9ab8)
61 | - Avoid `lastIndexOf` [`bb6501c`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/bb6501c9fab6c2f380dc1a45a8efd024a0719bca)
62 | - Tag the v0.2.0 release [`ca2dddb`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/ca2dddb7e3a6f7fe8d996b02eec6ee908c958663)
63 | - README: Explicitly request SVG badges [`c20c83a`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/c20c83a5efadc594431de9ba4dcfb58786409007)
64 | - Perform RegExp check after `ToString(this)` [`f375ac0`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/f375ac092cc7f5e52b2f6216c9808c8f8e09de50)
65 | - README: Mention polyfills for similar functions [`960fccb`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/960fccb4d7139bd2361e8d91c74e7688074c5bb9)
66 | - Use `charCodeAt` instead of `charAt` [`bb1901f`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/bb1901f9173c5df8ca7444919cfbe18457ebfa3f)
67 | - Avoid `isNaN` [`dd38046`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/dd3804682838a24c10cb25371fc2b4a95f693d37)
68 | - README: Update Traceur link [`c34bff5`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/c34bff5eaecf484658ced6e291c08bf074975f23)
69 | - README: Update es6-shim link [`f51af73`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/f51af73a18afaef7b51264cb8cf81525d457c449)
70 | - Fix typo in test [`e10ff32`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/e10ff323b6a1b3489cfcd8776c3248a4db617ac4)
71 | - README: Update link [`c28d87c`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/c28d87cf41d32c27d52e1dc97cd02c3bf34199b4)
72 | - README: Note that Traceur now uses this polyfill [`2e2d880`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/2e2d880a24c42754937e5039ada1a9b938f2f16f)
73 |
74 | ## v0.1.0 - 2013-12-17
75 |
76 | ### Commits
77 |
78 | - Initial commit [`4bf8ebd`](https://github.com/mathiasbynens/String.prototype.endsWith/commit/4bf8ebdbc0e77cb7be77ca69dc5b29c734ed7e12)
79 |
--------------------------------------------------------------------------------
/LICENSE-MIT.txt:
--------------------------------------------------------------------------------
1 | Copyright Mathias Bynens
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # string.prototype.endswith [![Version Badge][npm-version-svg]][package-url]
2 |
3 | [![dependency status][deps-svg]][deps-url]
4 | [![dev dependency status][dev-deps-svg]][dev-deps-url]
5 | [![License][license-image]][license-url]
6 | [![Downloads][downloads-image]][downloads-url]
7 |
8 | [![npm badge][npm-badge-png]][package-url]
9 |
10 | An ESnext spec-compliant `String.prototype.endsWith` shim/polyfill/replacement that works as far down as ES3.
11 |
12 | This package implements the [es-shim API](https://github.com/es-shims/api) interface. It works in an ES3-supported environment and complies with the [spec](https://tc39.es/ecma262/#sec-string.prototype.endswith).
13 |
14 | Because `String.prototype.endsWith` depends on a receiver (the `this` value), the main export takes the string to operate on as the first argument.
15 |
16 | Other polyfills for `String.prototype.endsWith` are available:
17 |
18 | * by [Paul Miller](http://paulmillr.com/) (~~fails some tests: [1](https://github.com/paulmillr/es6-shim/issues/168), [2](https://github.com/paulmillr/es6-shim/issues/175)~~ passes all tests)
19 | * by Google (~~[fails a lot of tests](https://github.com/google/traceur-compiler/pull/555)~~ now uses this polyfill and passes all tests)
20 |
21 | ## Installation
22 |
23 | Via [npm](http://npmjs.org/):
24 |
25 | ```bash
26 | npm install string.prototype.endswith
27 | ```
28 |
29 | Then, in [Node.js](http://nodejs.org/):
30 |
31 | ```js
32 | var endsWith = require('string.prototype.endswith');
33 | ```
34 |
35 | ```html
36 |
37 | ```
38 |
39 | > **NOTE**: It's recommended that you install this module using a package manager
40 | > such as `npm`, because loading multiple polyfills from a CDN (such as `bundle.run`)
41 | > will lead to duplicated code.
42 |
43 | ## Notes
44 |
45 | Polyfills + test suites for [`String.prototype.startsWith`](https://mths.be/startswith) and [`String.prototype.contains`](https://mths.be/contains) are available, too.
46 |
47 | ## Author
48 |
49 | | [](https://twitter.com/mathias "Follow @mathias on Twitter") |
50 | |---|
51 | | [Mathias Bynens](https://mathiasbynens.be/) |
52 |
53 | ## License
54 |
55 | This polyfill is available under the [MIT](https://mths.be/mit) license.
56 |
57 | ## Tests
58 | Simply clone the repo, `npm install`, and run `npm test`
59 |
60 | [package-url]: https://npmjs.org/package/string.prototype.endswith
61 | [npm-version-svg]: https://versionbadg.es/es-shims/String.prototype.endsWith.svg
62 | [deps-svg]: https://david-dm.org/es-shims/String.prototype.endsWith.svg
63 | [deps-url]: https://david-dm.org/es-shims/String.prototype.endsWith
64 | [dev-deps-svg]: https://david-dm.org/es-shims/String.prototype.endsWith/dev-status.svg
65 | [dev-deps-url]: https://david-dm.org/es-shims/String.prototype.endsWith#info=devDependencies
66 | [npm-badge-png]: https://nodei.co/npm/string.prototype.endswith.png?downloads=true&stars=true
67 | [license-image]: https://img.shields.io/npm/l/string.prototype.endswith.svg
68 | [license-url]: LICENSE
69 | [downloads-image]: https://img.shields.io/npm/dm/string.prototype.endswith.svg
70 | [downloads-url]: https://npm-stat.com/charts.html?package=string.prototype.endswith
71 |
--------------------------------------------------------------------------------
/auto.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./shim')();
4 |
--------------------------------------------------------------------------------
/implementation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var RequireObjectCoercible = require('es-object-atoms/RequireObjectCoercible');
4 | var ToString = require('es-abstract/2024/ToString');
5 | var IsRegExp = require('es-abstract/2024/IsRegExp');
6 | var ToIntegerOrInfinity = require('es-abstract/2024/ToIntegerOrInfinity');
7 |
8 | var callBound = require('call-bind/callBound');
9 |
10 | var StringCharCodeAt = callBound('String.prototype.charCodeAt');
11 | var max = Math.max;
12 | var min = Math.min;
13 |
14 | module.exports = function endsWith(searchString) {
15 | var O = RequireObjectCoercible(this);
16 | var S = ToString(O);
17 | if (IsRegExp(searchString)) {
18 | throw new TypeError('Argument to String.prototype.endsWith cannot be a RegExp');
19 | }
20 | var searchStr = ToString(searchString);
21 |
22 | var len = S.length;
23 | var searchLength = searchStr.length;
24 | var endPosition = arguments.length > 1 ? arguments[1] : undefined;
25 | var pos = endPosition === undefined ? len : ToIntegerOrInfinity(endPosition);
26 |
27 | var end = min(max(pos, 0), len);
28 | var start = end - searchLength;
29 | if (start < 0) {
30 | return false;
31 | }
32 | var index = -1;
33 | while (++index < searchLength) { // eslint-disable-line no-plusplus
34 | if (StringCharCodeAt(S, start + index) !== StringCharCodeAt(searchStr, index)) {
35 | return false;
36 | }
37 | }
38 | return true;
39 | };
40 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*! https://mths.be/endswith v1.0.0 by @mathias */
2 |
3 | 'use strict';
4 |
5 | var callBind = require('call-bind');
6 | var define = require('define-properties');
7 |
8 | var implementation = require('./implementation');
9 | var getPolyfill = require('./polyfill');
10 | var shim = require('./shim');
11 |
12 | var boundEndsWith = callBind(getPolyfill());
13 |
14 | define(boundEndsWith, {
15 | getPolyfill: getPolyfill,
16 | implementation: implementation,
17 | shim: shim
18 | });
19 |
20 | module.exports = boundEndsWith;
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "string.prototype.endswith",
3 | "version": "1.0.2",
4 | "description": "A robust & optimized `String.prototype.endsWith` polyfill, based on the ECMAScript 6 specification.",
5 | "homepage": "https://mths.be/endswith",
6 | "main": "index.js",
7 | "exports": {
8 | ".": "./index.js",
9 | "./auto": "./auto.js",
10 | "./polyfill": "./polyfill.js",
11 | "./implementation": "./implementation.js",
12 | "./shim": "./shim.js",
13 | "./package.json": "./package.json"
14 | },
15 | "keywords": [
16 | "string",
17 | "endswith",
18 | "es6",
19 | "ecmascript",
20 | "polyfill"
21 | ],
22 | "license": "MIT",
23 | "author": {
24 | "name": "Mathias Bynens",
25 | "url": "https://mathiasbynens.be/"
26 | },
27 | "repository": {
28 | "type": "git",
29 | "url": "https://github.com/mathiasbynens/String.prototype.endsWith.git"
30 | },
31 | "bugs": "https://github.com/mathiasbynens/String.prototype.endsWith/issues",
32 | "scripts": {
33 | "lint": "eslint --ext=js,mjs .",
34 | "postlint": "es-shim-api --bound",
35 | "pretest": "npm run lint",
36 | "test": "npm run tests-only",
37 | "tests-only": "nyc tape 'test/*.js'",
38 | "posttest": "aud --production",
39 | "version": "auto-changelog && git add CHANGELOG.md",
40 | "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
41 | },
42 | "dependencies": {
43 | "call-bind": "^1.0.7",
44 | "define-properties": "^1.2.1",
45 | "es-abstract": "^1.23.2",
46 | "es-object-atoms": "^1.0.0"
47 | },
48 | "devDependencies": {
49 | "@es-shims/api": "^2.4.2",
50 | "@ljharb/eslint-config": "^21.1.0",
51 | "aud": "^2.0.4",
52 | "auto-changelog": "^2.4.0",
53 | "eslint": "=8.8.0",
54 | "function-bind": "^1.1.2",
55 | "functions-have-names": "^1.2.3",
56 | "nyc": "^10.3.2",
57 | "tape": "^5.7.5"
58 | },
59 | "auto-changelog": {
60 | "output": "CHANGELOG.md",
61 | "template": "keepachangelog",
62 | "unreleased": false,
63 | "commitLimit": false,
64 | "backfillLimit": false,
65 | "hideCredit": true
66 | },
67 | "engines": {
68 | "node": ">= 0.4"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/polyfill.js:
--------------------------------------------------------------------------------
1 | /*! https://mths.be/endswith v1.0.0 by @mathias */
2 |
3 | 'use strict';
4 |
5 | var implementation = require('./implementation');
6 |
7 | module.exports = function getPolyfill() {
8 | return String.prototype.endsWith || implementation;
9 | };
10 |
--------------------------------------------------------------------------------
/shim.js:
--------------------------------------------------------------------------------
1 | /*! https://mths.be/endswith v1.0.0 by @mathias */
2 |
3 | 'use strict';
4 |
5 | var define = require('define-properties');
6 |
7 | var getPolyfill = require('./polyfill');
8 |
9 | module.exports = function shimEndsWith() {
10 | var polyfill = getPolyfill();
11 |
12 | if (String.prototype.endsWith !== polyfill) {
13 | define(String.prototype, { endsWith: polyfill });
14 | }
15 |
16 | return polyfill;
17 | };
18 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var endsWith = require('../');
4 | var test = require('tape');
5 |
6 | var runTests = require('./tests');
7 |
8 | test('as a function', function (t) {
9 | runTests(endsWith, t);
10 |
11 | t.end();
12 | });
13 |
--------------------------------------------------------------------------------
/test/shimmed.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var endsWith = require('../');
4 | endsWith.shim();
5 |
6 | var test = require('tape');
7 | var defineProperties = require('define-properties');
8 | var bind = require('function-bind');
9 | var isEnumerable = Object.prototype.propertyIsEnumerable;
10 | var functionsHaveNames = require('functions-have-names')();
11 |
12 | var runTests = require('./tests');
13 |
14 | test('shimmed', function (t) {
15 | t.equal(String.prototype.endsWith.length, 1, 'String#endsWith has a length of 1');
16 |
17 | t.test('Function name', { skip: !functionsHaveNames }, function (st) {
18 | st.equal(String.prototype.endsWith.name, 'endsWith', 'String#endsWith has name "endsWith"');
19 | st.end();
20 | });
21 |
22 | t.test('enumerability', { skip: !defineProperties.supportsDescriptors }, function (st) {
23 | st.equal(false, isEnumerable.call(String.prototype, 'endsWith'), 'String#endsWith is not enumerable');
24 | st.end();
25 | });
26 |
27 | runTests(bind.call(Function.call, String.prototype.endsWith), t);
28 |
29 | t.end();
30 | });
31 |
--------------------------------------------------------------------------------
/test/tests.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (endsWith, t) {
4 | t.test('nullish search string', function (st) {
5 | st.equal(endsWith('undefined'), true);
6 | st.equal(endsWith('undefined', undefined), true);
7 | st.equal(endsWith('undefined', null), false);
8 | st.equal(endsWith('null'), false);
9 | st.equal(endsWith('null', undefined), false);
10 | st.equal(endsWith('null', null), true);
11 | st.end();
12 | });
13 |
14 | t.test('basic support', function (st) {
15 | st.equal(endsWith('abc'), false);
16 | st.equal(endsWith('abc', ''), true);
17 | st.equal(endsWith('abc', '\0'), false);
18 | st.equal(endsWith('abc', 'c'), true);
19 | st.equal(endsWith('abc', 'b'), false);
20 | st.equal(endsWith('abc', 'ab'), false);
21 | st.equal(endsWith('abc', 'bc'), true);
22 | st.equal(endsWith('abc', 'abc'), true);
23 | st.equal(endsWith('abc', 'bcd'), false);
24 | st.equal(endsWith('abc', 'abcd'), false);
25 | st.equal(endsWith('abc', 'bcde'), false);
26 | st.end();
27 | });
28 |
29 | t.test('position argument - NaN', function (st) {
30 | st.equal(endsWith('abc', '', NaN), true);
31 | st.equal(endsWith('abc', '\0', NaN), false);
32 | st.equal(endsWith('abc', 'c', NaN), false);
33 | st.equal(endsWith('abc', 'b', NaN), false);
34 | st.equal(endsWith('abc', 'a', NaN), false);
35 | st.equal(endsWith('abc', 'ab', NaN), false);
36 | st.equal(endsWith('abc', 'bc', NaN), false);
37 | st.equal(endsWith('abc', 'abc', NaN), false);
38 | st.equal(endsWith('abc', 'bcd', NaN), false);
39 | st.equal(endsWith('abc', 'abcd', NaN), false);
40 | st.equal(endsWith('abc', 'bcde', NaN), false);
41 | st.end();
42 | });
43 |
44 | t.test('position argument - false', function (st) {
45 | st.equal(endsWith('abc', '', false), true);
46 | st.equal(endsWith('abc', '\0', false), false);
47 | st.equal(endsWith('abc', 'c', false), false);
48 | st.equal(endsWith('abc', 'b', false), false);
49 | st.equal(endsWith('abc', 'a', false), false);
50 | st.equal(endsWith('abc', 'ab', false), false);
51 | st.equal(endsWith('abc', 'bc', false), false);
52 | st.equal(endsWith('abc', 'abc', false), false);
53 | st.equal(endsWith('abc', 'bcd', false), false);
54 | st.equal(endsWith('abc', 'abcd', false), false);
55 | st.equal(endsWith('abc', 'bcde', false), false);
56 | st.end();
57 | });
58 |
59 | t.test('position argument - undefined', function (st) {
60 | st.equal(endsWith('abc', '', undefined), true);
61 | st.equal(endsWith('abc', '\0', undefined), false);
62 | st.equal(endsWith('abc', 'c', undefined), true);
63 | st.equal(endsWith('abc', 'b', undefined), false);
64 | st.equal(endsWith('abc', 'a', undefined), false);
65 | st.equal(endsWith('abc', 'ab', undefined), false);
66 | st.equal(endsWith('abc', 'bc', undefined), true);
67 | st.equal(endsWith('abc', 'abc', undefined), true);
68 | st.equal(endsWith('abc', 'bcd', undefined), false);
69 | st.equal(endsWith('abc', 'abcd', undefined), false);
70 | st.equal(endsWith('abc', 'bcde', undefined), false);
71 | st.end();
72 | });
73 |
74 | t.test('position argument - null', function (st) {
75 | st.equal(endsWith('abc', '', null), true);
76 | st.equal(endsWith('abc', '\0', null), false);
77 | st.equal(endsWith('abc', 'c', null), false);
78 | st.equal(endsWith('abc', 'b', null), false);
79 | st.equal(endsWith('abc', 'a', null), false);
80 | st.equal(endsWith('abc', 'ab', null), false);
81 | st.equal(endsWith('abc', 'bc', null), false);
82 | st.equal(endsWith('abc', 'abc', null), false);
83 | st.equal(endsWith('abc', 'bcd', null), false);
84 | st.equal(endsWith('abc', 'abcd', null), false);
85 | st.equal(endsWith('abc', 'bcde', null), false);
86 | st.end();
87 | });
88 |
89 | t.test('position argument - -Infinity', function (st) {
90 | st.equal(endsWith('abc', '', -Infinity), true);
91 | st.equal(endsWith('abc', '\0', -Infinity), false);
92 | st.equal(endsWith('abc', 'c', -Infinity), false);
93 | st.equal(endsWith('abc', 'b', -Infinity), false);
94 | st.equal(endsWith('abc', 'a', -Infinity), false);
95 | st.equal(endsWith('abc', 'ab', -Infinity), false);
96 | st.equal(endsWith('abc', 'bc', -Infinity), false);
97 | st.equal(endsWith('abc', 'abc', -Infinity), false);
98 | st.equal(endsWith('abc', 'bcd', -Infinity), false);
99 | st.equal(endsWith('abc', 'abcd', -Infinity), false);
100 | st.equal(endsWith('abc', 'bcde', -Infinity), false);
101 | st.end();
102 | });
103 |
104 | t.test('position argument - -1', function (st) {
105 | st.equal(endsWith('abc', '', -1), true);
106 | st.equal(endsWith('abc', '\0', -1), false);
107 | st.equal(endsWith('abc', 'c', -1), false);
108 | st.equal(endsWith('abc', 'b', -1), false);
109 | st.equal(endsWith('abc', 'a', -1), false);
110 | st.equal(endsWith('abc', 'ab', -1), false);
111 | st.equal(endsWith('abc', 'bc', -1), false);
112 | st.equal(endsWith('abc', 'abc', -1), false);
113 | st.equal(endsWith('abc', 'bcd', -1), false);
114 | st.equal(endsWith('abc', 'abcd', -1), false);
115 | st.equal(endsWith('abc', 'bcde', -1), false);
116 | st.end();
117 | });
118 |
119 | t.test('position argument - -0', function (st) {
120 | st.equal(endsWith('abc', '', -0), true);
121 | st.equal(endsWith('abc', '\0', -0), false);
122 | st.equal(endsWith('abc', 'c', -0), false);
123 | st.equal(endsWith('abc', 'b', -0), false);
124 | st.equal(endsWith('abc', 'a', -0), false);
125 | st.equal(endsWith('abc', 'ab', -0), false);
126 | st.equal(endsWith('abc', 'bc', -0), false);
127 | st.equal(endsWith('abc', 'abc', -0), false);
128 | st.equal(endsWith('abc', 'bcd', -0), false);
129 | st.equal(endsWith('abc', 'abcd', -0), false);
130 | st.equal(endsWith('abc', 'bcde', -0), false);
131 | st.end();
132 | });
133 |
134 | t.test('position argument - +0', function (st) {
135 | st.equal(endsWith('abc', '', +0), true);
136 | st.equal(endsWith('abc', '\0', +0), false);
137 | st.equal(endsWith('abc', 'c', +0), false);
138 | st.equal(endsWith('abc', 'b', +0), false);
139 | st.equal(endsWith('abc', 'a', +0), false);
140 | st.equal(endsWith('abc', 'ab', +0), false);
141 | st.equal(endsWith('abc', 'bc', +0), false);
142 | st.equal(endsWith('abc', 'abc', +0), false);
143 | st.equal(endsWith('abc', 'bcd', +0), false);
144 | st.equal(endsWith('abc', 'abcd', +0), false);
145 | st.equal(endsWith('abc', 'bcde', +0), false);
146 | st.end();
147 | });
148 |
149 | t.test('position argument - 1', function (st) {
150 | st.equal(endsWith('abc', '', 1), true);
151 | st.equal(endsWith('abc', '\0', 1), false);
152 | st.equal(endsWith('abc', 'c', 1), false);
153 | st.equal(endsWith('abc', 'b', 1), false);
154 | st.equal(endsWith('abc', 'a', 1), true);
155 | st.equal(endsWith('abc', 'ab', 1), false);
156 | st.equal(endsWith('abc', 'bc', 1), false);
157 | st.equal(endsWith('abc', 'abc', 1), false);
158 | st.equal(endsWith('abc', 'bcd', 1), false);
159 | st.equal(endsWith('abc', 'abcd', 1), false);
160 | st.equal(endsWith('abc', 'bcde', 1), false);
161 | st.end();
162 | });
163 |
164 | t.test('position argument - common integer', function (st) {
165 | st.equal(endsWith('abc', '', 2), true);
166 | st.equal(endsWith('abc', '\0', 2), false);
167 | st.equal(endsWith('abc', 'c', 2), false);
168 | st.equal(endsWith('abc', 'b', 2), true);
169 | st.equal(endsWith('abc', 'a', 2), false);
170 | st.equal(endsWith('abc', 'ab', 2), true);
171 | st.equal(endsWith('abc', 'bc', 2), false);
172 | st.equal(endsWith('abc', 'abc', 2), false);
173 | st.equal(endsWith('abc', 'bcd', 2), false);
174 | st.equal(endsWith('abc', 'abcd', 2), false);
175 | st.equal(endsWith('abc', 'bcde', 2), false);
176 | st.end();
177 | });
178 |
179 | t.test('position argument - +Infinity', function (st) {
180 | st.equal(endsWith('abc', '', Number(Infinity)), true);
181 | st.equal(endsWith('abc', '\0', Number(Infinity)), false);
182 | st.equal(endsWith('abc', 'c', Number(Infinity)), true);
183 | st.equal(endsWith('abc', 'b', Number(Infinity)), false);
184 | st.equal(endsWith('abc', 'a', Number(Infinity)), false);
185 | st.equal(endsWith('abc', 'ab', Number(Infinity)), false);
186 | st.equal(endsWith('abc', 'bc', Number(Infinity)), true);
187 | st.equal(endsWith('abc', 'abc', Number(Infinity)), true);
188 | st.equal(endsWith('abc', 'bcd', Number(Infinity)), false);
189 | st.equal(endsWith('abc', 'abcd', Number(Infinity)), false);
190 | st.equal(endsWith('abc', 'bcde', Number(Infinity)), false);
191 | st.end();
192 | });
193 |
194 | t.test('position argument - true', function (st) {
195 | st.equal(endsWith('abc', '', true), true);
196 | st.equal(endsWith('abc', '\0', true), false);
197 | st.equal(endsWith('abc', 'c', true), false);
198 | st.equal(endsWith('abc', 'b', true), false);
199 | st.equal(endsWith('abc', 'a', true), true);
200 | st.equal(endsWith('abc', 'ab', true), false);
201 | st.equal(endsWith('abc', 'bc', true), false);
202 | st.equal(endsWith('abc', 'abc', true), false);
203 | st.equal(endsWith('abc', 'bcd', true), false);
204 | st.equal(endsWith('abc', 'abcd', true), false);
205 | st.equal(endsWith('abc', 'bcde', true), false);
206 | st.end();
207 | });
208 |
209 | t.test('position argument - string', function (st) {
210 | st.equal(endsWith('abc', '', 'x'), true);
211 | st.equal(endsWith('abc', '\0', 'x'), false);
212 | st.equal(endsWith('abc', 'c', 'x'), false);
213 | st.equal(endsWith('abc', 'b', 'x'), false);
214 | st.equal(endsWith('abc', 'a', 'x'), false);
215 | st.equal(endsWith('abc', 'ab', 'x'), false);
216 | st.equal(endsWith('abc', 'bc', 'x'), false);
217 | st.equal(endsWith('abc', 'abc', 'x'), false);
218 | st.equal(endsWith('abc', 'bcd', 'x'), false);
219 | st.equal(endsWith('abc', 'abcd', 'x'), false);
220 | st.equal(endsWith('abc', 'bcde', 'x'), false);
221 | st.end();
222 | });
223 |
224 | t.test('search regexp', function (st) {
225 | st.equal(endsWith('[a-z]+(bar)?', '(bar)?'), true);
226 | st['throws'](function () { endsWith('[a-z]+(bar)?', /(bar)?/); }, TypeError);
227 | st.equal(endsWith('[a-z]+(bar)?', '[a-z]+', 6), true);
228 | st['throws'](function () { endsWith('[a-z]+(bar)?', /(bar)?/); }, TypeError);
229 | st['throws'](function () { endsWith('[a-z]+/(bar)?/', /(bar)?/); }, TypeError);
230 | st.end();
231 | });
232 |
233 | t.test('astral code points', function (st) {
234 | // https://mathiasbynens.be/notes/javascript-unicode#poo-test
235 | var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
236 | st.equal(string.endsWith(''), true);
237 | st.equal(string.endsWith('\xF1t\xEBr'), false);
238 | st.equal(string.endsWith('\xF1t\xEBr', 5), true);
239 | st.equal(string.endsWith('\xE0liz\xE6'), false);
240 | st.equal(string.endsWith('\xE0liz\xE6', 16), true);
241 | st.equal(string.endsWith('\xF8n\u2603\uD83D\uDCA9'), true);
242 | st.equal(string.endsWith('\xF8n\u2603\uD83D\uDCA9', 23), true);
243 | st.equal(string.endsWith('\u2603'), false);
244 | st.equal(string.endsWith('\u2603', 21), true);
245 | st.equal(string.endsWith('\uD83D\uDCA9'), true);
246 | st.equal(string.endsWith('\uD83D\uDCA9', 23), true);
247 | st.end();
248 | });
249 |
250 | t.test('nullish this object', function (st) {
251 | st['throws'](function () { endsWith(undefined); }, TypeError);
252 | st['throws'](function () { endsWith(undefined, 'b'); }, TypeError);
253 | st['throws'](function () { endsWith(undefined, 'b', 4); }, TypeError);
254 | st['throws'](function () { endsWith(null); }, TypeError);
255 | st['throws'](function () { endsWith(null, 'b'); }, TypeError);
256 | st['throws'](function () { endsWith(null, 'b', 4); }, TypeError);
257 | st.end();
258 | });
259 |
260 | t.test('cast this object', function (st) {
261 | st.equal(endsWith(42, '2'), true);
262 | st.equal(endsWith(42, '4'), false);
263 | st.equal(endsWith(42, 'b', 4), false);
264 | st.equal(endsWith(42, '2', 1), false);
265 | st.equal(endsWith(42, '2', 4), true);
266 | st.equal(endsWith({ toString: function () { return 'abc'; } }, 'b', 0), false);
267 | st.equal(endsWith({ toString: function () { return 'abc'; } }, 'b', 1), false);
268 | st.equal(endsWith({ toString: function () { return 'abc'; } }, 'b', 2), true);
269 | st['throws'](function () { endsWith({ toString: function () { throw new RangeError(); } }, /./); }, RangeError);
270 | st['throws'](function () { endsWith({ toString: function () { return 'abc'; } }, /./); }, TypeError);
271 | st.end();
272 | });
273 | };
274 |
--------------------------------------------------------------------------------