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" ) ;
// tslint:disable object-literal-sort-keys
var ts = require ( "typescript" ) ;
var Lint = require ( "../index" ) ;
var utils _1 = require ( "../utils" ) ;
var BANNED _KEYWORDS = [ "any" , "Number" , "number" , "String" , "string" , "Boolean" , "boolean" , "Undefined" , "undefined" ] ;
var bannedKeywordsSet = new Set ( BANNED _KEYWORDS ) ;
var bannedKeywordsStr = BANNED _KEYWORDS . map ( function ( kw ) { return "`" + kw + "`" ; } ) . join ( ", " ) ;
var OPTION _LEADING _UNDERSCORE = "allow-leading-underscore" ;
var OPTION _TRAILING _UNDERSCORE = "allow-trailing-underscore" ;
var OPTION _BAN _KEYWORDS = "ban-keywords" ;
var OPTION _CHECK _FORMAT = "check-format" ;
var OPTION _ALLOW _PASCAL _CASE = "allow-pascal-case" ;
var OPTION _ALLOW _SNAKE _CASE = "allow-snake-case" ;
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
Rule . metadata = {
ruleName : "variable-name" ,
description : "Checks variable names for various errors." ,
optionsDescription : ( _a = [ "\n Five arguments may be optionally provided:\n\n * `\"" , "\"`: allows only lowerCamelCased or UPPER_CASED variable names\n * `\"" , "\"` allows underscores at the beginning (only has an effect if \"check-format\" specified)\n * `\"" , "\"` allows underscores at the end. (only has an effect if \"check-format\" specified)\n * `\"" , "\"` allows PascalCase in addition to lowerCamelCase.\n * `\"" , "\"` allows snake_case in addition to lowerCamelCase.\n * `\"" , "\"`: disallows the use of certain TypeScript keywords as variable or parameter names.\n * These are: " , "" ] , _a . raw = [ "\n Five arguments may be optionally provided:\n\n * \\`\"" , "\"\\`: allows only lowerCamelCased or UPPER_CASED variable names\n * \\`\"" , "\"\\` allows underscores at the beginning (only has an effect if \"check-format\" specified)\n * \\`\"" , "\"\\` allows underscores at the end. (only has an effect if \"check-format\" specified)\n * \\`\"" , "\"\\` allows PascalCase in addition to lowerCamelCase.\n * \\`\"" , "\"\\` allows snake_case in addition to lowerCamelCase.\n * \\`\"" , "\"\\`: disallows the use of certain TypeScript keywords as variable or parameter names.\n * These are: " , "" ] , Lint . Utils . dedent ( _a , OPTION _CHECK _FORMAT , OPTION _LEADING _UNDERSCORE , OPTION _TRAILING _UNDERSCORE , OPTION _ALLOW _PASCAL _CASE , OPTION _ALLOW _SNAKE _CASE , OPTION _BAN _KEYWORDS , bannedKeywordsStr ) ) ,
options : {
type : "array" ,
items : {
type : "string" ,
enum : [
OPTION _CHECK _FORMAT ,
OPTION _LEADING _UNDERSCORE ,
OPTION _TRAILING _UNDERSCORE ,
OPTION _ALLOW _PASCAL _CASE ,
OPTION _ALLOW _SNAKE _CASE ,
OPTION _BAN _KEYWORDS ,
] ,
} ,
minLength : 0 ,
maxLength : 5 ,
} ,
optionExamples : [ [ true , "ban-keywords" , "check-format" , "allow-leading-underscore" ] ] ,
type : "style" ,
typescriptOnly : false ,
} ;
Rule . KEYWORD _FAILURE = "variable name clashes with keyword/type" ;
2017-05-28 00:38:50 +02:00
return Rule ;
} ( Lint . Rules . AbstractRule ) ) ;
exports . Rule = Rule ;
function parseOptions ( ruleArguments ) {
var banKeywords = hasOption ( OPTION _BAN _KEYWORDS ) ;
return {
banKeywords : banKeywords ,
// check variable name formatting by default if no options are specified
checkFormat : ! banKeywords || hasOption ( OPTION _CHECK _FORMAT ) ,
leadingUnderscore : hasOption ( OPTION _LEADING _UNDERSCORE ) ,
trailingUnderscore : hasOption ( OPTION _TRAILING _UNDERSCORE ) ,
allowPascalCase : hasOption ( OPTION _ALLOW _PASCAL _CASE ) ,
allowSnakeCase : hasOption ( OPTION _ALLOW _SNAKE _CASE ) ,
} ;
function hasOption ( name ) {
return ruleArguments . indexOf ( name ) !== - 1 ;
}
}
function walk ( ctx ) {
var options = ctx . options , sourceFile = ctx . sourceFile ;
return ts . forEachChild ( sourceFile , function cb ( node ) {
switch ( node . kind ) {
case ts . SyntaxKind . BindingElement : {
var _a = node , initializer = _a . initializer , name = _a . name , propertyName = _a . propertyName ;
if ( name . kind === ts . SyntaxKind . Identifier ) {
handleVariableNameKeyword ( name ) ;
// A destructuring pattern that does not rebind an expression is always an alias, e.g. `var {Foo} = ...;`.
// Only check if the name is rebound (`var {Foo: bar} = ...;`).
if ( node . parent . kind !== ts . SyntaxKind . ObjectBindingPattern || propertyName !== undefined ) {
handleVariableNameFormat ( name , initializer ) ;
}
}
break ;
}
case ts . SyntaxKind . VariableStatement :
// skip 'declare' keywords
if ( Lint . hasModifier ( node . modifiers , ts . SyntaxKind . DeclareKeyword ) ) {
return ;
}
break ;
case ts . SyntaxKind . Parameter :
case ts . SyntaxKind . PropertyDeclaration :
case ts . SyntaxKind . VariableDeclaration : {
var _b = node , name = _b . name , initializer = _b . initializer ;
if ( name . kind === ts . SyntaxKind . Identifier ) {
handleVariableNameFormat ( name , initializer ) ;
// do not check property declarations for keywords, they are allowed to be keywords
if ( node . kind !== ts . SyntaxKind . PropertyDeclaration ) {
handleVariableNameKeyword ( name ) ;
}
}
}
}
return ts . forEachChild ( node , cb ) ;
} ) ;
function handleVariableNameFormat ( name , initializer ) {
if ( ! options . checkFormat ) {
return ;
}
var text = name . text ;
if ( initializer !== undefined && isAlias ( text , initializer ) ) {
return ;
}
if ( ! isCamelCase ( text , options ) && ! utils _1 . isUpperCase ( text ) ) {
ctx . addFailureAtNode ( name , formatFailure ( ) ) ;
}
}
function handleVariableNameKeyword ( name ) {
if ( options . banKeywords && bannedKeywordsSet . has ( name . text ) ) {
ctx . addFailureAtNode ( name , Rule . KEYWORD _FAILURE ) ;
}
}
function formatFailure ( ) {
var failureMessage = "variable name must be in lowerCamelCase" ;
if ( options . allowPascalCase ) {
failureMessage += ", PascalCase" ;
}
if ( options . allowSnakeCase ) {
failureMessage += ", snake_case" ;
}
return failureMessage + " or UPPER_CASE" ;
}
}
function isAlias ( name , initializer ) {
switch ( initializer . kind ) {
case ts . SyntaxKind . PropertyAccessExpression :
return initializer . name . text === name ;
case ts . SyntaxKind . Identifier :
return initializer . text === name ;
default :
return false ;
}
}
function isCamelCase ( name , options ) {
var firstCharacter = name [ 0 ] ;
var lastCharacter = name [ name . length - 1 ] ;
var middle = name . slice ( 1 , - 1 ) ;
if ( ! options . leadingUnderscore && firstCharacter === "_" ) {
return false ;
}
if ( ! options . trailingUnderscore && lastCharacter === "_" ) {
return false ;
}
if ( ! options . allowPascalCase && ! utils _1 . isLowerCase ( firstCharacter ) ) {
return false ;
}
if ( ! options . allowSnakeCase && middle . indexOf ( "_" ) !== - 1 ) {
return false ;
}
return true ;
}
var _a ;