diff --git a/__tests__/spec-only.js b/__tests__/spec-only.js index ea93a378..e54f1860 100644 --- a/__tests__/spec-only.js +++ b/__tests__/spec-only.js @@ -9,7 +9,13 @@ ruleTester.run('spec-only', rule, { 'Promise.resolve()', 'Promise.reject()', 'Promise.all()', + 'Promise["all"]', + 'Promise[method];', + 'Promise.prototype;', + 'Promise.prototype[method];', + 'Promise.prototype["then"];', 'Promise.race()', + 'var ctch = Promise.prototype.catch', 'Promise.withResolvers()', 'new Promise(function (resolve, reject) {})', 'SomeClass.resolve()', @@ -22,6 +28,14 @@ ruleTester.run('spec-only', rule, { }, ], }, + { + code: 'Promise.prototype.permittedInstanceMethod', + options: [ + { + allowedMethods: ['permittedInstanceMethod'], + }, + ], + }, ], invalid: [ { @@ -53,5 +67,13 @@ ruleTester.run('spec-only', rule, { `, errors: [{ message: "Avoid using non-standard 'Promise.done'" }], }, + { + code: `var done = Promise.prototype.done`, + errors: [{ message: "Avoid using non-standard 'Promise.prototype'" }], + }, + { + code: `Promise["done"];`, + errors: [{ message: "Avoid using non-standard 'Promise.done'" }], + }, ], }) diff --git a/rules/lib/is-promise.js b/rules/lib/is-promise.js index 840dfb2f..a13f2bb7 100644 --- a/rules/lib/is-promise.js +++ b/rules/lib/is-promise.js @@ -29,7 +29,7 @@ function isPromise(expression) { expression.callee.type === 'MemberExpression' && expression.callee.object.type === 'Identifier' && expression.callee.object.name === 'Promise' && - PROMISE_STATICS[expression.callee.property.name] && + PROMISE_STATICS.has(expression.callee.property.name) && expression.callee.property.name !== 'withResolvers') ) } diff --git a/rules/lib/promise-statics.js b/rules/lib/promise-statics.js index e42205a0..3cf7415f 100644 --- a/rules/lib/promise-statics.js +++ b/rules/lib/promise-statics.js @@ -1,11 +1,11 @@ 'use strict' -module.exports = { - all: true, - allSettled: true, - any: true, - race: true, - reject: true, - resolve: true, - withResolvers: true, -} +module.exports = new Set([ + 'all', + 'allSettled', + 'any', + 'race', + 'reject', + 'resolve', + 'withResolvers', +]) diff --git a/rules/no-new-statics.js b/rules/no-new-statics.js index c2483ce4..5274fe2e 100644 --- a/rules/no-new-statics.js +++ b/rules/no-new-statics.js @@ -22,7 +22,7 @@ module.exports = { if ( node.callee.type === 'MemberExpression' && node.callee.object.name === 'Promise' && - PROMISE_STATICS[node.callee.property.name] + PROMISE_STATICS.has(node.callee.property.name) ) { context.report({ node, diff --git a/rules/spec-only.js b/rules/spec-only.js index e5ab90a9..4554e3cc 100644 --- a/rules/spec-only.js +++ b/rules/spec-only.js @@ -3,6 +3,30 @@ const PROMISE_STATICS = require('./lib/promise-statics') const getDocsUrl = require('./lib/get-docs-url') +const PROMISE_INSTANCE_METHODS = new Set(['then', 'catch', 'finally']) + +function isPermittedProperty(expression, standardSet, allowedMethods) { + // istanbul ignore if + if (expression.type !== 'MemberExpression') return false + + if (expression.property.type === 'Literal') + return ( + standardSet.has(expression.property.value) || + allowedMethods.includes(expression.property.value) + ) + + // istanbul ignore else + if (expression.property.type === 'Identifier') + return ( + expression.computed || + standardSet.has(expression.property.name) || + allowedMethods.includes(expression.property.name) + ) + + // istanbul ignore next + return false +} + module.exports = { meta: { type: 'problem', @@ -36,13 +60,20 @@ module.exports = { if ( node.object.type === 'Identifier' && node.object.name === 'Promise' && - !(node.property.name in PROMISE_STATICS) && - !allowedMethods.includes(node.property.name) + ((node.property.name !== 'prototype' && + !isPermittedProperty(node, PROMISE_STATICS, allowedMethods)) || + (node.property.name === 'prototype' && + node.parent.type === 'MemberExpression' && + !isPermittedProperty( + node.parent, + PROMISE_INSTANCE_METHODS, + allowedMethods, + ))) ) { context.report({ node, messageId: 'avoidNonStandard', - data: { name: node.property.name }, + data: { name: node.property.name ?? node.property.value }, }) } },