├── .gitignore ├── index.d.ts ├── test-import ├── tsconfig.json ├── package.json ├── index.ts ├── test.mjs └── test.js ├── index.mjs ├── index.js ├── component.json ├── .github ├── dependabot.yml └── FUNDING.yml ├── package.json ├── readme.md ├── LICENSE ├── test.js └── .circleci └── config.yml /.gitignore: -------------------------------------------------------------------------------- 1 | components 2 | build 3 | node_modules 4 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare function isPromise(obj: PromiseLike | S): obj is PromiseLike; 2 | export default isPromise; 3 | -------------------------------------------------------------------------------- /test-import/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": true, 4 | "skipLibCheck": false, 5 | "strict": true 6 | } 7 | } -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | export default function isPromise(obj) { 2 | return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; 3 | } 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = isPromise; 2 | module.exports.default = isPromise; 3 | 4 | function isPromise(obj) { 5 | return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; 6 | } 7 | -------------------------------------------------------------------------------- /test-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-promise-test-import", 3 | "private": true, 4 | "@rollingversions/ignore": true, 5 | "scripts": { 6 | "test": "node test" 7 | }, 8 | "dependencies": { 9 | "type-assertions": "^1.1.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-import/index.ts: -------------------------------------------------------------------------------- 1 | import * as ta from 'type-assertions'; 2 | import isPromise from 'is-promise'; 3 | 4 | declare const x: number | Promise; 5 | if (isPromise(x)) { 6 | ta.assert>>(); 7 | } else { 8 | ta.assert>(); 9 | } -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-promise", 3 | "repo": "then/is-promise", 4 | "description": "Test whether an object looks like a promises-a+ promise", 5 | "version": "2.2.2", 6 | "keywords": [], 7 | "dependencies": {}, 8 | "development": {}, 9 | "license": "MIT", 10 | "scripts": [ 11 | "index.js" 12 | ], 13 | "twitter": "@ForbesLindesay" 14 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-promise", 3 | "version": "2.2.2", 4 | "description": "Test whether an object looks like a promises-a+ promise", 5 | "main": "./index.js", 6 | "scripts": { 7 | "test": "node test" 8 | }, 9 | "files": [ 10 | "index.js", 11 | "index.mjs", 12 | "index.d.ts" 13 | ], 14 | "exports": { 15 | ".": [ 16 | { 17 | "import": "./index.mjs", 18 | "require": "./index.js", 19 | "default": "./index.js" 20 | }, 21 | "./index.js" 22 | ] 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/then/is-promise.git" 27 | }, 28 | "author": "ForbesLindesay", 29 | "license": "MIT" 30 | } 31 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ForbesLindesay] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 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/is-promise # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 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 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # is-promise 4 | 5 | Test whether an object looks like a promises-a+ promise 6 | 7 | [![Build Status](https://img.shields.io/circleci/build/github/then/is-promise/master?style=for-the-badge)](https://app.circleci.com/pipelines/github/then/is-promise) 8 | [![NPM version](https://img.shields.io/npm/v/is-promise.svg?style=for-the-badge)](https://www.npmjs.org/package/is-promise) 9 | 10 | 11 | 12 | ## Installation 13 | 14 | $ npm install is-promise 15 | 16 | You can also use it client side via npm. 17 | 18 | ## API 19 | 20 | ```typescript 21 | import isPromise from 'is-promise'; 22 | 23 | isPromise(Promise.resolve());//=>true 24 | isPromise({then:function () {...}});//=>true 25 | isPromise(null);//=>false 26 | isPromise({});//=>false 27 | isPromise({then: true})//=>false 28 | ``` 29 | 30 | ## License 31 | 32 | MIT 33 | -------------------------------------------------------------------------------- /test-import/test.mjs: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import isPromise from 'is-promise'; 3 | 4 | 5 | assert(isPromise(null) === false); 6 | assert(isPromise(undefined) === false); 7 | assert(isPromise(0) === false); 8 | assert(isPromise(-42) === false); 9 | assert(isPromise(42) === false); 10 | assert(isPromise('') === false); 11 | assert(isPromise('then') === false); 12 | assert(isPromise(false) === false); 13 | assert(isPromise(true) === false); 14 | assert(isPromise({}) === false); 15 | assert(isPromise({then: true}) === false); 16 | assert(isPromise([]) === false); 17 | assert(isPromise([true]) === false); 18 | assert(isPromise(() => {}) === false); 19 | 20 | // This looks similar enough to a promise 21 | // that promises/A+ says we should treat 22 | // it as a promise. 23 | var promise = {then: function () {}}; 24 | 25 | assert(isPromise(promise) === true); 26 | const fn = () => {}; 27 | fn.then = () => {}; 28 | assert(isPromise(fn) === true); 29 | 30 | console.log('ES Modules tests passed') 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Forbes Lindesay 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var isPromise = require('./'); 3 | 4 | // `.then` methods on primitive types should 5 | // not make them count as promises 6 | String.prototype.then = () => {}; 7 | Number.prototype.then = () => {}; 8 | Boolean.prototype.then = () => {}; 9 | 10 | assert(isPromise(null) === false); 11 | assert(isPromise(undefined) === false); 12 | assert(isPromise(0) === false); 13 | assert(isPromise(-42) === false); 14 | assert(isPromise(42) === false); 15 | assert(isPromise('') === false); 16 | assert(isPromise('then') === false); 17 | assert(isPromise(false) === false); 18 | assert(isPromise(true) === false); 19 | assert(isPromise({}) === false); 20 | assert(isPromise({then: true}) === false); 21 | assert(isPromise([]) === false); 22 | assert(isPromise([true]) === false); 23 | assert(isPromise(() => {}) === false); 24 | 25 | // This looks similar enough to a promise 26 | // that promises/A+ says we should treat 27 | // it as a promise. 28 | var promise = {then: function () {}}; 29 | 30 | assert(isPromise(promise) === true); 31 | const fn = () => {}; 32 | fn.then = () => {}; 33 | assert(isPromise(fn) === true); 34 | 35 | console.log('tests passed') 36 | -------------------------------------------------------------------------------- /test-import/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var isPromise = require('is-promise'); 3 | 4 | 5 | assert(isPromise(null) === false); 6 | assert(isPromise(undefined) === false); 7 | assert(isPromise(0) === false); 8 | assert(isPromise(-42) === false); 9 | assert(isPromise(42) === false); 10 | assert(isPromise('') === false); 11 | assert(isPromise('then') === false); 12 | assert(isPromise(false) === false); 13 | assert(isPromise(true) === false); 14 | assert(isPromise({}) === false); 15 | assert(isPromise({then: true}) === false); 16 | assert(isPromise([]) === false); 17 | assert(isPromise([true]) === false); 18 | assert(isPromise(() => {}) === false); 19 | 20 | // This looks similar enough to a promise 21 | // that promises/A+ says we should treat 22 | // it as a promise. 23 | var promise = {then: function () {}}; 24 | 25 | assert(isPromise(promise) === true); 26 | const fn = () => {}; 27 | fn.then = () => {}; 28 | assert(isPromise(fn) === true); 29 | 30 | console.log('CommonJS tests passed') 31 | 32 | if(parseInt(process.version.split('.')[0].substr(1), 10) >= 14) { 33 | const result = require('child_process').spawnSync('node', ['test.mjs'], {cwd: __dirname, stdio: 'inherit'}); 34 | if (result.status) process.exit(result.status); 35 | } 36 | 37 | if(parseInt(process.version.split('.')[0].substr(1), 10) >= 12) { 38 | const result = require('child_process').spawnSync('npx', ['typescript', 'index.ts'], {cwd: __dirname, stdio: 'inherit'}); 39 | if (result.status) process.exit(result.status); 40 | console.log('TypeScript tests passed'); 41 | } -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | refs: 4 | - &only_master 5 | filters: 6 | branches: 7 | only: master 8 | 9 | - ¬_master 10 | filters: 11 | branches: 12 | ignore: master 13 | 14 | workflows: 15 | test: 16 | jobs: 17 | - unit-tests: 18 | <<: *not_master 19 | name: node-6 20 | version: '6' 21 | - unit-tests: 22 | <<: *not_master 23 | name: node-8 24 | version: '8' 25 | - unit-tests: 26 | <<: *not_master 27 | name: node-10 28 | version: '10' 29 | - unit-tests: 30 | <<: *not_master 31 | name: node-12 32 | version: '12' 33 | - unit-tests: 34 | <<: *not_master 35 | name: node-14 36 | version: '14' 37 | 38 | release: 39 | jobs: 40 | - unit-tests: 41 | <<: *only_master 42 | name: node-6 43 | version: '6' 44 | - unit-tests: 45 | <<: *only_master 46 | name: node-8 47 | version: '8' 48 | - unit-tests: 49 | <<: *only_master 50 | name: node-10 51 | version: '10' 52 | - unit-tests: 53 | <<: *only_master 54 | name: node-12 55 | version: '12' 56 | - unit-tests: 57 | <<: *only_master 58 | name: node-14 59 | version: '14' 60 | 61 | - publish-dry-run: 62 | <<: *only_master 63 | 64 | - publish-approval: 65 | type: approval 66 | requires: 67 | - publish-dry-run 68 | 69 | - publish: 70 | <<: *only_master 71 | requires: 72 | - node-6 73 | - node-8 74 | - node-10 75 | - node-12 76 | - node-14 77 | - publish-approval 78 | 79 | jobs: 80 | unit-tests: 81 | parameters: 82 | version: 83 | type: string 84 | docker: 85 | - image: circleci/node:<< parameters.version >> 86 | steps: 87 | - setup 88 | - test 89 | 90 | publish-dry-run: 91 | docker: 92 | - image: circleci/node:12 93 | steps: 94 | - setup 95 | - publish-dry-run 96 | 97 | publish: 98 | docker: 99 | - image: circleci/node:12 100 | steps: 101 | - setup 102 | - publish 103 | 104 | commands: 105 | setup: 106 | description: 'Checkout and install dependencies' 107 | steps: 108 | - checkout 109 | - run: 110 | name: Versions 111 | command: node -v && npm -v 112 | - run: 113 | name: Install Dependencies 114 | command: npm i 115 | 116 | test: 117 | steps: 118 | - run: 119 | name: Test 120 | command: npm test 121 | - run: 122 | name: Pack 123 | command: npm pack 124 | - run: 125 | name: Setup Import Test 126 | command: echo $PWD && cd .. && cp -a project/test-import/ test-import/ && cd test-import && npm i && npm i ../project/is-promise-2.2.2.tgz 127 | - run: 128 | name: Test Import 129 | command: cd ../test-import && npm test 130 | 131 | publish-dry-run: 132 | steps: 133 | - run: 134 | name: NPM Auth 135 | command: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc 136 | - run: 137 | name: Release (Dry Run) 138 | command: npx rollingversions publish --dry-run 139 | 140 | publish: 141 | steps: 142 | - run: 143 | name: NPM Auth 144 | command: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc 145 | - run: 146 | name: Release 147 | command: npx rollingversions publish --------------------------------------------------------------------------------