diff --git a/.eslintrc b/.eslintrc index 4192b7c..304752b 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,15 +3,8 @@ "extends": "@ljharb", - "globals": { - "Promise": false - }, - "rules": { - "dot-notation": [2, { "allowKeywords": false }], "new-cap": [2, { "capIsNewExceptions": ["GetIntrinsic", "PromiseResolve", "Type"] }], - "no-magic-numbers": 0, - "sort-keys": 0, }, "overrides": [ diff --git a/.github/workflows/node-aught.yml b/.github/workflows/node-aught.yml new file mode 100644 index 0000000..4b48655 --- /dev/null +++ b/.github/workflows/node-aught.yml @@ -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: '> 0.10 < 10' + type: minors + command: npm run tests-only + + node: + name: 'node < 10' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: 'echo tests completed' diff --git a/.github/workflows/node-native.yml b/.github/workflows/node-native.yml new file mode 100644 index 0000000..7862306 --- /dev/null +++ b/.github/workflows/node-native.yml @@ -0,0 +1,18 @@ +name: 'Tests: node.js: native' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '>= 15' + type: minors + command: npm run test:native + + node: + name: 'node, native tests' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: 'echo tests completed' diff --git a/.github/workflows/node-pretest.yml b/.github/workflows/node-pretest.yml new file mode 100644 index 0000000..765edf7 --- /dev/null +++ b/.github/workflows/node-pretest.yml @@ -0,0 +1,7 @@ +name: 'Tests: pretest/posttest' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/pretest.yml@main diff --git a/.github/workflows/node-promise-shimmed.yml b/.github/workflows/node-promise-shimmed.yml new file mode 100644 index 0000000..36cc773 --- /dev/null +++ b/.github/workflows/node-promise-shimmed.yml @@ -0,0 +1,18 @@ +name: 'Tests: node.js: shimmed Promise' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '0.8 - 0.12' + type: minors + command: npm run test:promise-shimmed + + node: + name: 'node, promise-shimmed tests' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: 'echo tests completed' diff --git a/.github/workflows/node-tens.yml b/.github/workflows/node-tens.yml new file mode 100644 index 0000000..b49ceb1 --- /dev/null +++ b/.github/workflows/node-tens.yml @@ -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' diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index 027aed0..5b6d04b 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: ljharb/rebase@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v2 + - uses: ljharb/rebase@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/require-allow-edits.yml b/.github/workflows/require-allow-edits.yml index 549d7b4..7b842f8 100644 --- a/.github/workflows/require-allow-edits.yml +++ b/.github/workflows/require-allow-edits.yml @@ -9,4 +9,4 @@ jobs: runs-on: ubuntu-latest steps: - - uses: ljharb/require-allow-edits@main + - uses: ljharb/require-allow-edits@main diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000..1826526 --- /dev/null +++ b/.nycrc @@ -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" + ] +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 949264e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: ~> 1.0 -language: node_js -os: - - linux -import: - - ljharb/travis-ci:node/minors/gte_4.yml - - ljharb/travis-ci:node/minors/iojs.yml - - ljharb/travis-ci:node/pretest.yml - - ljharb/travis-ci:node/posttest.yml -node_js: - - "0.12" - - "0.11" -script: - - 'if [ -n "${ES5-}" ]; then npm run tests:es5 ; fi' - - 'if [ -n "${NATIVE-}" ]; then npm run test:native ; fi' -matrix: - include: - - node_js: "0.10" - env: ES5=true - - node_js: "node" - env: NATIVE=true ALLOW_FAILURE=true - allow_failures: - - env: NATIVE=true ALLOW_FAILURE=true diff --git a/implementation.js b/implementation.js index e929d4c..83a774f 100644 --- a/implementation.js +++ b/implementation.js @@ -14,10 +14,7 @@ var map = require('array.prototype.map'); var all = callBind(GetIntrinsic('%Promise.all%')); var reject = callBind(GetIntrinsic('%Promise.reject%')); - -var identity = function (x) { - return x; -}; +var $then = callBind(GetIntrinsic('%Promise.prototype.then%')); module.exports = function any(iterable) { var C = this; @@ -27,17 +24,20 @@ module.exports = function any(iterable) { var thrower = function (value) { return reject(C, value); }; - return all(C, map(iterate(iterable), function (item) { - var itemPromise = PromiseResolve(C, item); - try { - return itemPromise.then(thrower, identity); - } catch (e) { - return e; - } - })).then( - function (errors) { - throw new AggregateError(errors, 'Every promise rejected'); - }, - identity - ); + try { + return $then( + all(C, map(iterate(iterable), function (item) { + var itemPromise = PromiseResolve(C, item); + return itemPromise.then(thrower, function identity(x) { + return x; + }); + })), + function (errors) { + throw new AggregateError(errors, 'Every promise rejected'); + }, + function (x) { return x; } + ); + } catch (e) { + return reject(C, e); + } }; diff --git a/package.json b/package.json index 7679ec7..e9f68f1 100644 --- a/package.json +++ b/package.json @@ -11,19 +11,17 @@ "description": "ES Proposal spec-compliant shim for Promise.any", "main": "index.js", "scripts": { - "prepublish": "safe-publish-latest", - "lint": "eslint .", - "postlint": "evalmd README.md", - "pretest": "npm run lint && es-shim-api --bound", - "test": "npm run --silent tests-only", + "prepublishOnly": "safe-publish-latest", + "prepublish": "not-in-publish || npm run prepublishOnly", + "prelint": "evalmd README.md", + "lint": "eslint --ext=js,mjs .", + "postlint": "es-shim-api --bound", + "pretest": "npm run lint", + "test": "npm run tests-only && npm run test:promise-shimmed", "posttest": "npx aud --production", - "tests-only": "npm run --silent test:shimmed && npm run --silent test:module && npm run --silent tests:es5", - "tests:es5": "npm run --silent test:promise-shimmed", - "test:shimmed": "node test/shimmed", - "test:module": "node test", - "test:promise-shimmed": "node test/promise-shimmed", - "test:native": "node test/native", - "coverage": "covert test/*.js" + "tests-only": "nyc tape test/{implementation,index,shimmed}.js", + "test:promise-shimmed": "nyc node test/promise-shimmed", + "test:native": "node test/native" }, "repository": { "type": "git", @@ -56,24 +54,28 @@ }, "homepage": "https://github.com/es-shims/Promise.any#readme", "dependencies": { - "array.prototype.map": "^1.0.2", + "array.prototype.map": "^1.0.4", "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0", - "es-aggregate-error": "^1.0.3", + "es-abstract": "^1.19.1", + "es-aggregate-error": "^1.0.7", "get-intrinsic": "^1.1.1", "iterate-value": "^1.0.2" }, "devDependencies": { - "@es-shims/api": "^2.1.2", - "@ljharb/eslint-config": "^17.1.0", - "aud": "^1.1.2", - "es6-shim": "^0.35.5", - "eslint": "^7.2.0", + "@es-shims/api": "^2.2.3", + "@ljharb/eslint-config": "^20.1.0", + "aud": "^1.1.5", + "es6-shim": "^0.35.6", + "eslint": "^8.5.0", "evalmd": "^0.0.19", - "functions-have-names": "^1.2.1", - "safe-publish-latest": "^1.1.4", - "tape": "^5.0.1" + "functions-have-names": "^1.2.2", + "nyc": "^10.3.2", + "safe-publish-latest": "^2.0.0", + "tape": "^5.4.0" + }, + "testling": { + "files": "test/native.js" }, "engines": { "node": ">= 0.4" diff --git a/test/implementation.js b/test/implementation.js new file mode 100644 index 0000000..d1f5fdc --- /dev/null +++ b/test/implementation.js @@ -0,0 +1,30 @@ +'use strict'; + +var test = require('tape'); +var callBind = require('call-bind'); + +var any = require('../implementation'); +var runTests = require('./tests'); + +var bound = callBind(any); + +// eslint-disable-next-line no-shadow +var rebindable = function any(iterable) { + // eslint-disable-next-line no-invalid-this + return bound(typeof this === 'undefined' ? Promise : this, iterable); +}; + +test('as a function', function (t) { + t.test('bad Promise/this value', function (st) { + // eslint-disable-next-line no-useless-call + st['throws'](function () { any.call(undefined, []); }, TypeError, 'undefined is not an object'); + + // eslint-disable-next-line no-useless-call + st['throws'](function () { any.call(null, []); }, TypeError, 'null is not an object'); + st.end(); + }); + + runTests(rebindable, t); + + t.end(); +}); diff --git a/test/shimmed.js b/test/shimmed.js index f733a40..0b174ca 100644 --- a/test/shimmed.js +++ b/test/shimmed.js @@ -1,7 +1,6 @@ 'use strict'; -var any = require('../'); -any.shim(); +require('../auto'); var test = require('tape'); diff --git a/test/tests.js b/test/tests.js index a459c59..3bb4b83 100644 --- a/test/tests.js +++ b/test/tests.js @@ -85,15 +85,14 @@ module.exports = function (any, t) { }); t.test('poisoned .then', function (st) { - st.plan(2); + st.plan(1); var poison = new EvalError(); var promise = new Promise(function () {}); - promise.then = function () { throw poison; }; + promise.then = function poisionedThen() { throw poison; }; any([promise]).then(function () { st.fail('should not reach here'); }, function (error) { - st.equal(error instanceof AggregateError, true, 'error is an AggregateError'); - st.deepEqual(error.errors, [poison], 'rejection showed up as expected'); + st.equal(error, poison, 'error is whatever the poisoned then throws'); }); }); @@ -124,7 +123,18 @@ module.exports = function (any, t) { any.call(Subclass, [original]); assertArray(s2t, original.thenArgs, 1); - assertArray(s2t, Subclass.thenArgs, 3); + assertArray(s2t, original.thenArgs[0], 2); + + s2t.test('proper subclass then invocation count', { todo: true }, function (s3t) { + // native implementations report 1, this implementation reports 2 + assertArray(s3t, Subclass.thenArgs, 1); + + s3t.end(); + }); + s2t.ok(Array.isArray(Subclass.thenArgs), 'value is an array'); + s2t.match(String(Subclass.thenArgs.length), /^[12]$/, 'length is 1 or 2'); + + assertArray(s2t, Subclass.thenArgs[0], 2); s2t.end(); });