license import { TSESLint as eslint , TSESTree as es , } from "@typescript-eslint/experimental-utils" ; import { getParent , getTypeServices , isBlockStatement , isCallExpression , isIdentifier , isMemberExpression , isProgram , } from "eslint-etc" ; import { ruleCreator } from "../utils" ; const rule = ruleCreator ( { defaultOptions : [ ] , meta : { docs : { description : "Forbids redundant notifications from completed or errored observables." , recommended : "error" , } , fixable : undefined , hasSuggestions : false , messages : { forbidden : "Redundant notifications are forbidden." , } , schema : [ ] , type : "problem" , } , name : "no-redundant-notify" , create : ( context ) => { const sourceCode = context . getSourceCode ( ) ; const { couldBeType } = getTypeServices ( context ) ; return { "ExpressionStatement[expression.callee.property.name=/^(complete|error)$/] + ExpressionStatement[expression.callee.property.name=/^(next|complete|error)$/]" : ( node ) => { const parent = getParent ( node ) ; if ( ! parent ) { return ; } if ( ! isBlockStatement ( parent ) && ! isProgram ( parent ) ) { return ; } const { body } = parent ; const index = body . indexOf ( node ) ; const sibling = body [ index - 1 ] as es . ExpressionStatement ; if ( getExpressionText ( sibling , sourceCode ) !== getExpressionText ( node , sourceCode ) ) { return ; } if ( ! isExpressionObserver ( sibling , couldBeType ) || ! isExpressionObserver ( node , couldBeType ) ) { return ; } const { expression } = node ; if ( isCallExpression ( expression ) ) { const { callee } = expression ; if ( isMemberExpression ( callee ) ) { const { property } = callee ; if ( isIdentifier ( property ) ) { context . report ( { messageId : "forbidden" , node : property , } ) ; } } } } , } ; } , } ) ; function getExpressionText ( expressionStatement , sourceCode ) { if ( ! isCallExpression ( expressionStatement . expression ) ) { return undefined ; } const callExpression = expressionStatement . expression ; if ( ! isMemberExpression ( callExpression . callee ) ) { return undefined ; } const { object } = callExpression . callee ; return sourceCode . getText ( object ) ; } function isExpressionObserver ( expressionStatement , couldBeType ) { if ( ! isCallExpression ( expressionStatement . expression ) ) { return false ; } const callExpression = expressionStatement . expression ; if ( ! isMemberExpression ( callExpression . callee ) ) { return false ; } const { object } = callExpression . callee ; return couldBeType ( object , /^(Subject|Subscriber)$/ ) ; } export = rule ;