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 tsutils _1 = require ( "tsutils" ) ;
var ts = require ( "typescript" ) ;
var Lint = require ( "../index" ) ;
2017-08-14 05:01:11 +02:00
var defaultOptions = fillOptions ( "ignore" ) ; // tslint:disable-line no-unnecessary-type-assertion
2017-05-28 00:38:50 +02:00
function fillOptions ( value ) {
return {
arrays : value ,
exports : value ,
functions : value ,
imports : value ,
objects : value ,
typeLiterals : value ,
} ;
}
function normalizeOptions ( options ) {
return { multiline : normalize ( options . multiline ) , singleline : normalize ( options . singleline ) } ;
function normalize ( value ) {
return typeof value === "string" ? fillOptions ( value ) : tslib _1 . _ _assign ( { } , defaultOptions , value ) ;
}
}
/* tslint:disable:object-literal-sort-keys */
var metadataOptionShape = {
anyOf : [
{
type : "string" ,
enum : [ "always" , "never" ] ,
} ,
{
type : "object" ,
properties : fillOptions ( {
type : "string" ,
enum : [ "always" , "never" , "ignore" ] ,
} ) ,
} ,
] ,
} ;
/* tslint:enable:object-literal-sort-keys */
var Rule = ( function ( _super ) {
tslib _1 . _ _extends ( Rule , _super ) ;
function Rule ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
Rule . prototype . apply = function ( sourceFile ) {
var options = normalizeOptions ( this . ruleArguments [ 0 ] ) ;
return this . applyWithWalker ( new TrailingCommaWalker ( sourceFile , this . ruleName , options ) ) ;
} ;
Rule . prototype . isEnabled = function ( ) {
return _super . prototype . isEnabled . call ( this ) && this . ruleArguments . length !== 0 ;
} ;
2017-08-14 05:01:11 +02:00
/* tslint:disable:object-literal-sort-keys */
Rule . metadata = {
ruleName : "trailing-comma" ,
description : ( _a = [ "\n Requires or disallows trailing commas in array and object literals, destructuring assignments, function typings,\n named imports and exports and function parameters." ] , _a . raw = [ "\n Requires or disallows trailing commas in array and object literals, destructuring assignments, function typings,\n named imports and exports and function parameters." ] , Lint . Utils . dedent ( _a ) ) ,
hasFix : true ,
optionsDescription : ( _b = [ "\n One argument which is an object with the keys `multiline` and `singleline`.\n Both can be set to a string (`\"always\"` or `\"never\"`) or an object.\n\n The object can contain any of the following keys: `\"arrays\"`, `\"objects\"`, `\"functions\"`,\n `\"imports\"`, `\"exports\"`, and `\"typeLiterals\"`; each key can have one of the following\n values: `\"always\"`, `\"never\"`, and `\"ignore\"`. Any missing keys will default to `\"ignore\"`.\n\n * `\"multiline\"` checks multi-line object literals.\n * `\"singleline\"` checks single-line object literals.\n\n An array is considered \"multiline\" if its closing bracket is on a line\n after the last array element. The same general logic is followed for\n object literals, function typings, named import statements\n and function parameters." ] , _b . raw = [ "\n One argument which is an object with the keys \\`multiline\\` and \\`singleline\\`.\n Both can be set to a string (\\`\"always\"\\` or \\`\"never\"\\`) or an object.\n\n The object can contain any of the following keys: \\`\"arrays\"\\`, \\`\"objects\"\\`, \\`\"functions\"\\`,\n \\`\"imports\"\\`, \\`\"exports\"\\`, and \\`\"typeLiterals\"\\`; each key can have one of the following\n values: \\`\"always\"\\`, \\`\"never\"\\`, and \\`\"ignore\"\\`. Any missing keys will default to \\`\"ignore\"\\`.\n\n * \\`\"multiline\"\\` checks multi-line object literals.\n * \\`\"singleline\"\\` checks single-line object literals.\n\n An array is considered \"multiline\" if its closing bracket is on a line\n after the last array element. The same general logic is followed for\n object literals, function typings, named import statements\n and function parameters." ] , Lint . Utils . dedent ( _b ) ) ,
options : {
type : "object" ,
properties : {
multiline : metadataOptionShape ,
singleline : metadataOptionShape ,
} ,
additionalProperties : false ,
2017-05-28 00:38:50 +02:00
} ,
2017-08-14 05:01:11 +02:00
optionExamples : [
[ true , { multiline : "always" , singleline : "never" } ] ,
[
true ,
{
multiline : {
objects : "always" ,
arrays : "always" ,
functions : "never" ,
typeLiterals : "ignore" ,
} ,
2017-05-28 00:38:50 +02:00
} ,
2017-08-14 05:01:11 +02:00
] ,
2017-05-28 00:38:50 +02:00
] ,
2017-08-14 05:01:11 +02:00
type : "maintainability" ,
typescriptOnly : false ,
} ;
/* tslint:enable:object-literal-sort-keys */
Rule . FAILURE _STRING _NEVER = "Unnecessary trailing comma" ;
Rule . FAILURE _STRING _ALWAYS = "Missing trailing comma" ;
return Rule ;
} ( Lint . Rules . AbstractRule ) ) ;
2017-05-28 00:38:50 +02:00
exports . Rule = Rule ;
var TrailingCommaWalker = ( function ( _super ) {
tslib _1 . _ _extends ( TrailingCommaWalker , _super ) ;
function TrailingCommaWalker ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
TrailingCommaWalker . prototype . walk = function ( sourceFile ) {
var _this = this ;
var cb = function ( node ) {
switch ( node . kind ) {
case ts . SyntaxKind . ArrayLiteralExpression :
case ts . SyntaxKind . ArrayBindingPattern :
_this . checkList ( node . elements , node . end , "arrays" ) ;
break ;
case ts . SyntaxKind . ObjectBindingPattern :
_this . checkList ( node . elements , node . end , "objects" ) ;
break ;
case ts . SyntaxKind . NamedImports :
_this . checkList ( node . elements , node . end , "imports" ) ;
break ;
case ts . SyntaxKind . NamedExports :
_this . checkList ( node . elements , node . end , "exports" ) ;
break ;
case ts . SyntaxKind . ObjectLiteralExpression :
_this . checkList ( node . properties , node . end , "objects" ) ;
break ;
case ts . SyntaxKind . EnumDeclaration :
_this . checkList ( node . members , node . end , "objects" ) ;
break ;
case ts . SyntaxKind . NewExpression :
if ( node . arguments === undefined ) {
break ;
}
// falls through
case ts . SyntaxKind . CallExpression :
_this . checkList ( node . arguments , node . end , "functions" ) ;
break ;
case ts . SyntaxKind . ArrowFunction :
case ts . SyntaxKind . Constructor :
case ts . SyntaxKind . FunctionDeclaration :
case ts . SyntaxKind . FunctionExpression :
case ts . SyntaxKind . MethodDeclaration :
case ts . SyntaxKind . SetAccessor :
case ts . SyntaxKind . MethodSignature :
case ts . SyntaxKind . ConstructSignature :
case ts . SyntaxKind . ConstructorType :
case ts . SyntaxKind . FunctionType :
case ts . SyntaxKind . CallSignature :
_this . checkListWithEndToken ( node , node . parameters , ts . SyntaxKind . CloseParenToken , "functions" ) ;
break ;
case ts . SyntaxKind . TypeLiteral :
_this . checkTypeLiteral ( node ) ;
break ;
default :
}
return ts . forEachChild ( node , cb ) ;
} ;
return ts . forEachChild ( sourceFile , cb ) ;
} ;
TrailingCommaWalker . prototype . checkTypeLiteral = function ( node ) {
var members = node . members ;
if ( members . length === 0 ) {
return ;
}
var sourceText = this . sourceFile . text ;
for ( var _i = 0 , members _1 = members ; _i < members _1 . length ; _i ++ ) {
var member = members _1 [ _i ] ;
// PropertySignature in TypeLiteral can end with semicolon or comma. If one ends with a semicolon don't check for trailing comma
if ( sourceText [ member . end - 1 ] === ";" ) {
return ;
}
}
// The trailing comma is part of the last member and therefore not present as hasTrailingComma on the NodeArray
var hasTrailingComma = sourceText [ members . end - 1 ] === "," ;
return this . checkComma ( hasTrailingComma , members , node . end , "typeLiterals" ) ;
} ;
TrailingCommaWalker . prototype . checkListWithEndToken = function ( node , list , closeTokenKind , optionKey ) {
if ( list . length === 0 ) {
return ;
}
var token = tsutils _1 . getChildOfKind ( node , closeTokenKind , this . sourceFile ) ;
if ( token !== undefined ) {
2017-08-14 05:01:11 +02:00
return this . checkComma ( list . hasTrailingComma , list , token . end , optionKey ) ;
2017-05-28 00:38:50 +02:00
}
} ;
TrailingCommaWalker . prototype . checkList = function ( list , closeElementPos , optionKey ) {
if ( list . length === 0 ) {
return ;
}
2017-08-14 05:01:11 +02:00
return this . checkComma ( list . hasTrailingComma , list , closeElementPos , optionKey ) ;
2017-05-28 00:38:50 +02:00
} ;
/* Expects `list.length !== 0` */
TrailingCommaWalker . prototype . checkComma = function ( hasTrailingComma , list , closeTokenPos , optionKey ) {
var options = tsutils _1 . isSameLine ( this . sourceFile , list [ list . length - 1 ] . end , closeTokenPos )
? this . options . singleline
: this . options . multiline ;
var option = options [ optionKey ] ;
if ( option === "always" && ! hasTrailingComma ) {
this . addFailureAt ( list . end , 0 , Rule . FAILURE _STRING _ALWAYS , Lint . Replacement . appendText ( list . end , "," ) ) ;
}
else if ( option === "never" && hasTrailingComma ) {
this . addFailureAt ( list . end - 1 , 1 , Rule . FAILURE _STRING _NEVER , Lint . Replacement . deleteText ( list . end - 1 , 1 ) ) ;
}
} ;
return TrailingCommaWalker ;
} ( Lint . AbstractWalker ) ) ;
var _a , _b ;