Skip to content

Conversation

@ss-vibe-bot
Copy link
Contributor

@ss-vibe-bot ss-vibe-bot bot commented Jan 28, 2026

Summary

Fixes false positives in rule S7739 (no-thenable) that were incorrectly flagging legitimate Promise and thenable implementations. The rule now recognizes intentional thenable patterns used in Promise polyfills, Deferred patterns, and objects made awaitable for Promise interoperability.

Key Changes

  • RHS delegation patterns: Recognize obj.then = promise.then and obj.then = promise.then.bind(promise) patterns used in ant-design, vuetify, and jQuery
  • Arrow function delegation: Handle result.then = (args) => promise.then(args) patterns used in ant-design's message components
  • Promise/Deferred class context: Allow then methods defined in functions/classes named "Promise" or "Deferred" (polyfill and jQuery patterns)
  • Prototype extension: Allow X.prototype.then assignments (React Promise pattern)
  • Sibling thenable methods: Recognize objects with both then and catch/finally methods as complete thenable implementations
  • Code quality: Applied optional chaining to fix S6582 code smell

Testing

  • Added failing tests covering all the false positive patterns
  • Updated expected ruling files (ruling tests pass)

Relates to JS-1108

Vibe Bot and others added 5 commits January 28, 2026 09:03
Tests cover intentional thenable implementations that should not raise issues:
- Prototype extension with then method (ReactPromise pattern)
- RHS delegation with bind (ant-design, vuetify pattern)
- RHS delegation directly to another object's then (jQuery readyList)
- Deferred class with then method (jQuery.Deferred pattern)
- Class/function named "Promise" with then method (polyfill pattern)
- Object with both then AND catch methods (complete thenable implementation)

Also includes true positive test cases that should continue to raise issues.

Relates to JS-1108
Enhance the interceptReport decorator to recognize intentional Promise/thenable
implementations that should not trigger the no-thenable rule.

The fix adds checks for:
- RHS delegation pattern: obj.then = promise.then or obj.then = promise.then.bind(promise)
- Promise/Deferred class context: then defined in function/class named Promise or Deferred
- Prototype extension: X.prototype.then assignments
- Sibling thenable methods: objects with both then and catch/finally

These patterns represent legitimate thenable implementations used in Promise polyfills
(angular.js), Deferred patterns (jQuery), and objects made awaitable for Promise
interoperability (ant-design, vuetify, React).

The implementation follows the proposed approach from the Jira ticket, including the
feedback to check for the 'then' property in isPrototypeThenAssignment.

Relates to JS-1108
Extend the isDelegatingToPromiseThen() check to handle arrow function
patterns like `result.then = (args) => promise.then(args)`. This pattern
is used in ant-design's message components to make objects awaitable by
delegating to an underlying Promise.

The fix adds two new helper functions:
- isArrowFunctionDelegatingToThen(): detects arrow functions whose body
  calls X.then()
- isCallToThenMethod(): checks if a CallExpression calls .then()

Also added a test case covering the arrow function delegation pattern.
Synced expected ruling files from actual results and removed orphaned
expected files that no longer have corresponding actual ruling files.

Ruling Status: PASS (rule-specific projects refined successfully)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Replace `!objectExpr || objectExpr.type !== 'ObjectExpression'` with the
more concise optional chain expression `objectExpr?.type !== 'ObjectExpression'`
in hasSiblingThenableMethods() to address S6582 (prefer-optional-chain).
@github-actions
Copy link
Contributor

Ruling Report

Code no longer flagged (8 issues)

S7739

ag-grid/src/ts/misc/simpleHttpRequest.ts:26

    24 |     private thenFunc: (result: any)=>void;
    25 | 
>   26 |     public then(func: (result: any)=>void) {
    27 |         this.thenFunc = func;
    28 |     }

angular.js/src/ng/animateRunner.js:128

   126 |       },
   127 | 
>  128 |       then: function(resolveHandler, rejectHandler) {
   129 |         return this.getPromise().then(resolveHandler, rejectHandler);
   130 |       },

angular.js/src/ng/q.js:320

   318 | 
   319 |   extend(Promise.prototype, {
>  320 |     then: function(onFulfilled, onRejected, progressBack) {
   321 |       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
   322 |         return this;

ant-design/components/message/hooks/useMessage.tsx:65

    63 |         }
    64 |       };
>   65 |       result.then = (filled: ThenableArgument, rejected: ThenableArgument) =>
    66 |         closePromise.then(filled, rejected);
    67 |       result.promise = closePromise;

ant-design/components/message/index.tsx:199

   197 |     }
   198 |   };
>  199 |   result.then = (filled: ThenableArgument, rejected: ThenableArgument) =>
   200 |     closePromise.then(filled, rejected);
   201 |   result.promise = closePromise;

jquery/src/core/ready.js:55

    53 | } );
    54 | 
>   55 | jQuery.ready.then = readyList.then;
    56 | 
    57 | // The ready event handler and self cleanup method

jquery/src/deferred.js:102

   100 | 					} ).promise();
   101 | 				},
>  102 | 				then: function( onFulfilled, onRejected, onProgress ) {
   103 | 					var maxDepth = 0;
   104 | 					function resolve( depth, deferred, handler, special ) {

vuetify/packages/vuetify/src/components/VForm/VForm.tsx:37

    35 | 
    36 |       const ready = form.validate()
>   37 |       e.then = ready.then.bind(ready)
    38 |       e.catch = ready.catch.bind(ready)
    39 |       e.finally = ready.finally.bind(ready)

@sonarqube-next
Copy link

@ss-vibe-bot
Copy link
Contributor Author

ss-vibe-bot bot commented Jan 28, 2026

github-actions[bot] 2026-01-28T12:12:59Z addressed
These 8 issues are expected to no longer be flagged. All of them are intentional thenable implementations that were labeled as false positives:

File Pattern Reason
ag-grid simpleHttpRequest.ts:26 Custom Promise class Class named Promise with then() method
angular.js animateRunner.js:128 Thenable delegating to Promise then() delegates to getPromise().then()
angular.js q.js:320 Promise polyfill Promise.prototype.then in $q implementation
ant-design useMessage.tsx:65 Arrow function delegation result.then = (...) => closePromise.then(...)
ant-design index.tsx:199 Arrow function delegation result.then = (...) => closePromise.then(...)
jquery ready.js:55 RHS delegation jQuery.ready.then = readyList.then
jquery deferred.js:102 Sibling thenable methods Has then, catch, and finally
vuetify VForm.tsx:37 Bind delegation e.then = ready.then.bind(ready)

The fix correctly identifies these as legitimate Promise/thenable implementations per the approved approach.

@ss-vibe-bot ss-vibe-bot bot marked this pull request as ready for review January 28, 2026 13:05
@francois-mora-sonarsource francois-mora-sonarsource requested a review from a team January 29, 2026 11:24
Copy link
Contributor

@francois-mora-sonarsource francois-mora-sonarsource left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ss-vibe-bot ss-vibe-bot bot merged commit 44b910e into master Jan 30, 2026
76 of 77 checks passed
@ss-vibe-bot ss-vibe-bot bot deleted the fix/JS-1108-fix-fp-on-s7739-custom-promisethenable-implementations-with-required-then-method-opus branch January 30, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant