2017-05-28 00:38:50 +02:00
"use strict" ;
/ * *
* @ license
* Copyright 2017 Palantir Technologies , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
var tslib _1 = require ( "tslib" ) ;
var tsutils _1 = require ( "tsutils" ) ;
var ts = require ( "typescript" ) ;
var Lint = require ( "../index" ) ;
var OPTION _ALLOW _PUBLIC = "allow-public" ;
var OPTION _ALLOW _PROTECTED = "allow-protected" ;
2017-10-14 18:40:54 +02:00
var Rule = /** @class */ ( function ( _super ) {
2017-05-28 00:38:50 +02:00
tslib _1 . _ _extends ( Rule , _super ) ;
function Rule ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
Rule . prototype . apply = function ( sourceFile ) {
return this . applyWithWalker ( new PreferFunctionOverMethodWalker ( sourceFile , this . ruleName , {
allowProtected : this . ruleArguments . indexOf ( OPTION _ALLOW _PROTECTED ) !== - 1 ,
allowPublic : this . ruleArguments . indexOf ( OPTION _ALLOW _PUBLIC ) !== - 1 ,
} ) ) ;
} ;
2017-08-14 05:01:11 +02:00
/* tslint:disable:object-literal-sort-keys */
Rule . metadata = {
ruleName : "prefer-function-over-method" ,
description : "Warns for class methods that do not use 'this'." ,
optionsDescription : ( _a = [ "\n \"" , "\" excludes checking of public methods.\n \"" , "\" excludes checking of protected methods." ] , _a . raw = [ "\n \"" , "\" excludes checking of public methods.\n \"" , "\" excludes checking of protected methods." ] , Lint . Utils . dedent ( _a , OPTION _ALLOW _PUBLIC , OPTION _ALLOW _PROTECTED ) ) ,
options : {
type : "string" ,
enum : [ OPTION _ALLOW _PUBLIC , OPTION _ALLOW _PROTECTED ] ,
} ,
optionExamples : [
true ,
[ true , OPTION _ALLOW _PUBLIC , OPTION _ALLOW _PROTECTED ] ,
] ,
type : "style" ,
typescriptOnly : false ,
} ;
/* tslint:enable:object-literal-sort-keys */
Rule . FAILURE _STRING = "Class method does not use 'this'. Use a function instead." ;
2017-05-28 00:38:50 +02:00
return Rule ;
} ( Lint . Rules . AbstractRule ) ) ;
exports . Rule = Rule ;
2017-10-14 18:40:54 +02:00
var PreferFunctionOverMethodWalker = /** @class */ ( function ( _super ) {
2017-05-28 00:38:50 +02:00
tslib _1 . _ _extends ( PreferFunctionOverMethodWalker , _super ) ;
function PreferFunctionOverMethodWalker ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
PreferFunctionOverMethodWalker . prototype . walk = function ( sourceFile ) {
var _this = this ;
var cb = function ( node ) {
if ( tsutils _1 . isMethodDeclaration ( node ) && ! _this . isExempt ( node ) ) {
// currentScope is always undefined here, so we don't need to save it and just set it to undefined afterwards
_this . currentScope = {
isThisUsed : false ,
name : tsutils _1 . getPropertyName ( node . name ) ,
} ;
ts . forEachChild ( node , cb ) ;
if ( ! _this . currentScope . isThisUsed ) {
_this . addFailureAtNode ( node . name , Rule . FAILURE _STRING ) ;
}
_this . currentScope = undefined ;
}
else if ( tsutils _1 . hasOwnThisReference ( node ) ) {
var scope = _this . currentScope ;
_this . currentScope = undefined ;
ts . forEachChild ( node , cb ) ;
_this . currentScope = scope ;
}
else if ( _this . currentScope !== undefined &&
( node . kind === ts . SyntaxKind . ThisKeyword && ! isRecursiveCall ( node , _this . currentScope . name ) ||
node . kind === ts . SyntaxKind . SuperKeyword ) ) {
_this . currentScope . isThisUsed = true ;
}
else {
return ts . forEachChild ( node , cb ) ;
}
} ;
return ts . forEachChild ( sourceFile , cb ) ;
} ;
PreferFunctionOverMethodWalker . prototype . isExempt = function ( node ) {
// TODO: handle the override keyword once it lands in the language
2017-10-14 18:40:54 +02:00
return node . body === undefined || // exclude abstract methods and overload signatures
2017-05-28 00:38:50 +02:00
// exclude object methods
node . parent . kind !== ts . SyntaxKind . ClassDeclaration && node . parent . kind !== ts . SyntaxKind . ClassExpression ||
tsutils _1 . hasModifier ( node . modifiers , ts . SyntaxKind . StaticKeyword ) ||
this . options . allowProtected && tsutils _1 . hasModifier ( node . modifiers , ts . SyntaxKind . ProtectedKeyword ) ||
this . options . allowPublic && ( tsutils _1 . hasModifier ( node . modifiers , ts . SyntaxKind . PublicKeyword ) ||
! tsutils _1 . hasModifier ( node . modifiers , ts . SyntaxKind . ProtectedKeyword , ts . SyntaxKind . PrivateKeyword ) ) ;
} ;
return PreferFunctionOverMethodWalker ;
} ( Lint . AbstractWalker ) ) ;
function isRecursiveCall ( node , name ) {
return name !== undefined &&
node . parent . kind === ts . SyntaxKind . PropertyAccessExpression &&
node . parent . name . text === name ;
}
var _a ;