2017-05-28 00:38:50 +02:00
"use strict" ;
/ * *
* @ license
* Copyright 2013 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 utils = require ( "tsutils" ) ;
var ts = require ( "typescript" ) ;
var Lint = require ( "../index" ) ;
var OPTION _ALLOW _DECLARATIONS = "allow-declarations" ;
var OPTION _ALLOW _NAMED _FUNCTIONS = "allow-named-functions" ;
var Rule = ( function ( _super ) {
tslib _1 . _ _extends ( Rule , _super ) ;
function Rule ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
Rule . prototype . apply = function ( sourceFile ) {
return this . applyWithFunction ( sourceFile , walk , parseOptions ( this . ruleArguments ) ) ;
} ;
2017-08-14 05:01:11 +02:00
/* tslint:disable:object-literal-sort-keys */
Rule . metadata = {
ruleName : "only-arrow-functions" ,
description : "Disallows traditional (non-arrow) function expressions." ,
rationale : "Traditional functions don't bind lexical scope, which can lead to unexpected behavior when accessing 'this'." ,
optionsDescription : ( _a = [ "\n Two arguments may be optionally provided:\n\n * `\"" , "\"` allows standalone function declarations.\n * `\"" , "\"` allows the expression `function foo() {}` but not `function() {}`.\n " ] , _a . raw = [ "\n Two arguments may be optionally provided:\n\n * \\`\"" , "\"\\` allows standalone function declarations.\n * \\`\"" , "\"\\` allows the expression \\`function foo() {}\\` but not \\`function() {}\\`.\n " ] , Lint . Utils . dedent ( _a , OPTION _ALLOW _DECLARATIONS , OPTION _ALLOW _NAMED _FUNCTIONS ) ) ,
options : {
type : "array" ,
items : {
type : "string" ,
enum : [ OPTION _ALLOW _DECLARATIONS , OPTION _ALLOW _NAMED _FUNCTIONS ] ,
} ,
minLength : 0 ,
maxLength : 1 ,
} ,
optionExamples : [ true , [ true , OPTION _ALLOW _DECLARATIONS , OPTION _ALLOW _NAMED _FUNCTIONS ] ] ,
type : "typescript" ,
typescriptOnly : false ,
} ;
/* tslint:enable:object-literal-sort-keys */
Rule . FAILURE _STRING = "non-arrow functions are forbidden" ;
2017-05-28 00:38:50 +02:00
return Rule ;
} ( Lint . Rules . AbstractRule ) ) ;
exports . Rule = Rule ;
function parseOptions ( ruleArguments ) {
return {
allowDeclarations : hasOption ( OPTION _ALLOW _DECLARATIONS ) ,
allowNamedFunctions : hasOption ( OPTION _ALLOW _NAMED _FUNCTIONS ) ,
} ;
function hasOption ( name ) {
return ruleArguments . indexOf ( name ) !== - 1 ;
}
}
function walk ( ctx ) {
var sourceFile = ctx . sourceFile , _a = ctx . options , allowDeclarations = _a . allowDeclarations , allowNamedFunctions = _a . allowNamedFunctions ;
return ts . forEachChild ( sourceFile , function cb ( node ) {
switch ( node . kind ) {
case ts . SyntaxKind . FunctionDeclaration :
if ( allowDeclarations ) {
break ;
}
// falls through
case ts . SyntaxKind . FunctionExpression : {
var f = node ;
if ( ! ( allowNamedFunctions && f . name !== undefined ) && ! functionIsExempt ( f ) ) {
ctx . addFailureAtNode ( Lint . childOfKind ( node , ts . SyntaxKind . FunctionKeyword ) , Rule . FAILURE _STRING ) ;
}
}
}
return ts . forEachChild ( node , cb ) ;
} ) ;
}
/** Generator functions and functions using `this` are allowed. */
function functionIsExempt ( node ) {
2017-08-14 05:01:11 +02:00
return node . asteriskToken !== undefined || hasThisParameter ( node ) || node . body !== undefined && usesThisInBody ( node . body ) === true ;
2017-05-28 00:38:50 +02:00
}
function hasThisParameter ( node ) {
var first = node . parameters [ 0 ] ;
return first !== undefined && first . name . kind === ts . SyntaxKind . Identifier &&
first . name . originalKeywordKind === ts . SyntaxKind . ThisKeyword ;
}
function usesThisInBody ( node ) {
return node . kind === ts . SyntaxKind . ThisKeyword || ! utils . hasOwnThisReference ( node ) && ts . forEachChild ( node , usesThisInBody ) ;
}
var _a ;