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" ) ;
2018-09-20 02:56:13 +02:00
var tsutils _1 = require ( "tsutils" ) ;
2017-05-28 00:38:50 +02:00
var ts = require ( "typescript" ) ;
2017-08-14 05:01:11 +02:00
var error _1 = require ( "../error" ) ;
2017-05-28 00:38:50 +02:00
var Lint = require ( "../index" ) ;
var utils _1 = require ( "../utils" ) ;
var OPTION _ORDER = "order" ;
var OPTION _ALPHABETIZE = "alphabetize" ;
var MemberKind ;
( function ( MemberKind ) {
MemberKind [ MemberKind [ "publicStaticField" ] = 0 ] = "publicStaticField" ;
MemberKind [ MemberKind [ "publicStaticMethod" ] = 1 ] = "publicStaticMethod" ;
MemberKind [ MemberKind [ "protectedStaticField" ] = 2 ] = "protectedStaticField" ;
MemberKind [ MemberKind [ "protectedStaticMethod" ] = 3 ] = "protectedStaticMethod" ;
MemberKind [ MemberKind [ "privateStaticField" ] = 4 ] = "privateStaticField" ;
MemberKind [ MemberKind [ "privateStaticMethod" ] = 5 ] = "privateStaticMethod" ;
MemberKind [ MemberKind [ "publicInstanceField" ] = 6 ] = "publicInstanceField" ;
MemberKind [ MemberKind [ "protectedInstanceField" ] = 7 ] = "protectedInstanceField" ;
MemberKind [ MemberKind [ "privateInstanceField" ] = 8 ] = "privateInstanceField" ;
MemberKind [ MemberKind [ "publicConstructor" ] = 9 ] = "publicConstructor" ;
MemberKind [ MemberKind [ "protectedConstructor" ] = 10 ] = "protectedConstructor" ;
MemberKind [ MemberKind [ "privateConstructor" ] = 11 ] = "privateConstructor" ;
MemberKind [ MemberKind [ "publicInstanceMethod" ] = 12 ] = "publicInstanceMethod" ;
MemberKind [ MemberKind [ "protectedInstanceMethod" ] = 13 ] = "protectedInstanceMethod" ;
MemberKind [ MemberKind [ "privateInstanceMethod" ] = 14 ] = "privateInstanceMethod" ;
} ) ( MemberKind || ( MemberKind = { } ) ) ;
var PRESETS = new Map ( [
[ "fields-first" , [
"public-static-field" ,
"protected-static-field" ,
"private-static-field" ,
"public-instance-field" ,
"protected-instance-field" ,
"private-instance-field" ,
"constructor" ,
"public-static-method" ,
"protected-static-method" ,
"private-static-method" ,
"public-instance-method" ,
"protected-instance-method" ,
"private-instance-method" ,
] ] ,
[ "instance-sandwich" , [
"public-static-field" ,
"protected-static-field" ,
"private-static-field" ,
"public-instance-field" ,
"protected-instance-field" ,
"private-instance-field" ,
"constructor" ,
"public-instance-method" ,
"protected-instance-method" ,
"private-instance-method" ,
"public-static-method" ,
"protected-static-method" ,
"private-static-method" ,
] ] ,
[ "statics-first" , [
"public-static-field" ,
"public-static-method" ,
"protected-static-field" ,
"protected-static-method" ,
"private-static-field" ,
"private-static-method" ,
"public-instance-field" ,
"protected-instance-field" ,
"private-instance-field" ,
"constructor" ,
"public-instance-method" ,
"protected-instance-method" ,
"private-instance-method" ,
] ] ,
] ) ;
var PRESET _NAMES = Array . from ( PRESETS . keys ( ) ) ;
var allMemberKindNames = utils _1 . mapDefined ( Object . keys ( MemberKind ) , function ( key ) {
var mk = MemberKind [ key ] ;
return typeof mk === "number" ? MemberKind [ mk ] . replace ( /[A-Z]/g , function ( cap ) { return "-" + cap . toLowerCase ( ) ; } ) : undefined ;
} ) ;
function namesMarkdown ( names ) {
return names . map ( function ( name ) { return "* `" + name + "`" ; } ) . join ( "\n " ) ;
}
2018-09-20 02:56:13 +02:00
var optionsDescription = Lint . Utils . dedent ( templateObject _1 || ( templateObject _1 = tslib _1 . _ _makeTemplateObject ( [ "\n One argument, which is an object, must be provided. It should contain an `order` property.\n The `order` property should have a value of one of the following strings:\n\n " , "\n\n Alternatively, the value for `order` maybe be an array consisting of the following strings:\n\n " , "\n\n You can also omit the access modifier to refer to \"public-\", \"protected-\", and \"private-\" all at once; for example, \"static-field\".\n\n You can also make your own categories by using an object instead of a string:\n\n {\n \"name\": \"static non-private\",\n \"kinds\": [\n \"public-static-field\",\n \"protected-static-field\",\n \"public-static-method\",\n \"protected-static-method\"\n ]\n }\n\n The '" , "' option will enforce that members within the same category should be alphabetically sorted by name." ] , [ "\n One argument, which is an object, must be provided. It should contain an \\`order\\` property.\n The \\`order\\` property should have a value of one of the following strings:\n\n " , "\n\n Alternatively, the value for \\`order\\` maybe be an array consisting of the following strings:\n\n " , "\n\n You can also omit the access modifier to refer to \"public-\", \"protected-\", and \"private-\" all at once; for example, \"static-field\".\n\n You can also make your own categories by using an object instead of a string:\n\n {\n \"name\": \"static non-private\",\n \"kinds\": [\n \"public-static-field\",\n \"protected-static-field\",\n \"public-static-method\",\n \"protected-static-method\"\n ]\n }\n\n The '" , "' option will enforce that members within the same category should be alphabetically sorted by name." ] ) ) , namesMarkdown ( PRESET _NAMES ) , namesMarkdown ( allMemberKindNames ) , OPTION _ALPHABETIZE ) ;
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 . FAILURE _STRING _ALPHABETIZE = function ( prevName , curName ) {
return show ( curName ) + " should come alphabetically before " + show ( prevName ) ;
function show ( s ) {
return s === "" ? "Computed property" : "'" + s + "'" ;
}
} ;
/* tslint:enable:object-literal-sort-keys */
Rule . prototype . apply = function ( sourceFile ) {
2017-08-14 05:01:11 +02:00
var options ;
try {
options = parseOptions ( this . ruleArguments ) ;
}
catch ( e ) {
error _1 . showWarningOnce ( "Warning: " + this . ruleName + " - " + e . message ) ;
return [ ] ;
}
return this . applyWithWalker ( new MemberOrderingWalker ( sourceFile , this . ruleName , options ) ) ;
2017-05-28 00:38:50 +02:00
} ;
2017-08-14 05:01:11 +02:00
/* tslint:disable:object-literal-sort-keys */
Rule . metadata = {
ruleName : "member-ordering" ,
description : "Enforces member ordering." ,
2018-09-20 02:56:13 +02:00
hasFix : true ,
rationale : Lint . Utils . dedent ( templateObject _2 || ( templateObject _2 = tslib _1 . _ _makeTemplateObject ( [ "\n A consistent ordering for class members can make classes easier to read, navigate, and edit.\n\n A common opposite practice to `member-ordering` is to keep related groups of classes together.\n Instead of creating classes with multiple separate groups, consider splitting class responsibilities\n apart across multiple single-responsibility classes.\n " ] , [ "\n A consistent ordering for class members can make classes easier to read, navigate, and edit.\n\n A common opposite practice to \\`member-ordering\\` is to keep related groups of classes together.\n Instead of creating classes with multiple separate groups, consider splitting class responsibilities\n apart across multiple single-responsibility classes.\n " ] ) ) ) ,
2017-08-14 05:01:11 +02:00
optionsDescription : optionsDescription ,
options : {
type : "object" ,
properties : {
order : {
oneOf : [
{
2017-05-28 00:38:50 +02:00
type : "string" ,
2017-08-14 05:01:11 +02:00
enum : PRESET _NAMES ,
} ,
{
type : "array" ,
items : {
type : "string" ,
enum : allMemberKindNames ,
} ,
maxLength : 13 ,
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
additionalProperties : false ,
2017-05-28 00:38:50 +02:00
} ,
2017-08-14 05:01:11 +02:00
optionExamples : [
[ true , { order : "fields-first" } ] ,
[ true , {
order : [
2017-12-10 21:51:33 +01:00
"public-static-field" ,
"public-instance-field" ,
"public-constructor" ,
"private-static-field" ,
"private-instance-field" ,
"private-constructor" ,
2017-08-14 05:01:11 +02:00
"public-instance-method" ,
"protected-instance-method" ,
"private-instance-method" ,
] ,
} ] ,
[ true , {
order : [
{
name : "static non-private" ,
kinds : [
"public-static-field" ,
"protected-static-field" ,
"public-static-method" ,
"protected-static-method" ,
] ,
} ,
"constructor" ,
] ,
} ] ,
] ,
type : "typescript" ,
typescriptOnly : false ,
} ;
return Rule ;
} ( Lint . Rules . AbstractRule ) ) ;
2017-05-28 00:38:50 +02:00
exports . Rule = Rule ;
2017-10-14 18:40:54 +02:00
var MemberOrderingWalker = /** @class */ ( function ( _super ) {
2017-05-28 00:38:50 +02:00
tslib _1 . _ _extends ( MemberOrderingWalker , _super ) ;
function MemberOrderingWalker ( ) {
2018-09-20 02:56:13 +02:00
var _this = _super !== null && _super . apply ( this , arguments ) || this ;
_this . fixes = [ ] ;
return _this ;
2017-05-28 00:38:50 +02:00
}
MemberOrderingWalker . prototype . walk = function ( sourceFile ) {
var _this = this ;
var cb = function ( node ) {
2018-09-20 02:56:13 +02:00
// NB: iterate through children first!
ts . forEachChild ( node , cb ) ;
2017-05-28 00:38:50 +02:00
switch ( node . kind ) {
case ts . SyntaxKind . ClassDeclaration :
case ts . SyntaxKind . ClassExpression :
case ts . SyntaxKind . InterfaceDeclaration :
case ts . SyntaxKind . TypeLiteral :
_this . checkMembers ( node . members ) ;
}
} ;
2018-09-20 02:56:13 +02:00
ts . forEachChild ( sourceFile , cb ) ;
// assign Replacements which have not been merged into surrounding ones to their RuleFailures.
this . fixes . forEach ( function ( _a ) {
var failure = _a [ 0 ] , replacement = _a [ 1 ] ;
failure . getFix ( ) . push ( replacement ) ;
} ) ;
2017-05-28 00:38:50 +02:00
} ;
2018-09-20 02:56:13 +02:00
/ * *
* Check wether the passed members adhere to the configured order . If not , RuleFailures are generated and a single
* Lint . Replacement is generated , which replaces the entire NodeArray with a correctly sorted one . The Replacement
* is not immediately added to a RuleFailure , as incorrectly sorted nodes can be nested ( e . g . a class declaration
* in a method implementation ) , but instead temporarily stored in ` this.fixes ` . Nested Replacements are manually
* merged , as TSLint doesn ' t handle overlapping ones . For this reason it is important that the recursion happens
* before the checkMembers call in this . walk ( ) .
* /
2017-05-28 00:38:50 +02:00
MemberOrderingWalker . prototype . checkMembers = function ( members ) {
2018-09-20 02:56:13 +02:00
var _this = this ;
2017-05-28 00:38:50 +02:00
var prevRank = - 1 ;
var prevName ;
2018-09-20 02:56:13 +02:00
var failureExists = false ;
2017-05-28 00:38:50 +02:00
for ( var _i = 0 , members _1 = members ; _i < members _1 . length ; _i ++ ) {
var member = members _1 [ _i ] ;
var rank = this . memberRank ( member ) ;
if ( rank === - 1 ) {
// no explicit ordering for this kind of node specified, so continue
continue ;
}
if ( rank < prevRank ) {
var nodeType = this . rankName ( rank ) ;
var prevNodeType = this . rankName ( prevRank ) ;
var lowerRank = this . findLowerRank ( members , rank ) ;
var locationHint = lowerRank !== - 1
? "after " + this . rankName ( lowerRank ) + "s"
: "at the beginning of the class/interface" ;
var errorLine1 = "Declaration of " + nodeType + " not allowed after declaration of " + prevNodeType + ". " +
( "Instead, this should come " + locationHint + "." ) ;
2018-09-20 02:56:13 +02:00
// add empty array as fix so we can add a replacement later. (fix itself is readonly)
this . addFailureAtNode ( member , errorLine1 , [ ] ) ;
failureExists = true ;
2017-05-28 00:38:50 +02:00
}
else {
if ( this . options . alphabetize && member . name !== undefined ) {
if ( rank !== prevRank ) {
// No alphabetical ordering between different ranks
prevName = undefined ;
}
var curName = nameString ( member . name ) ;
if ( prevName !== undefined && caseInsensitiveLess ( curName , prevName ) ) {
2018-09-20 02:56:13 +02:00
this . addFailureAtNode ( member . name , Rule . FAILURE _STRING _ALPHABETIZE ( this . findLowerName ( members , rank , curName ) , curName ) , [ ] ) ;
failureExists = true ;
2017-05-28 00:38:50 +02:00
}
else {
prevName = curName ;
}
}
// keep track of last good node
prevRank = rank ;
}
}
2018-09-20 02:56:13 +02:00
if ( failureExists ) {
var sortedMemberIndexes = members . map ( function ( _ , i ) { return i ; } ) . sort ( function ( ai , bi ) {
var a = members [ ai ] ;
var b = members [ bi ] ;
// first, sort by member rank
var rankDiff = _this . memberRank ( a ) - _this . memberRank ( b ) ;
if ( rankDiff !== 0 ) {
return rankDiff ;
}
// then lexicographically if alphabetize == true
if ( _this . options . alphabetize && a . name !== undefined && b . name !== undefined ) {
var aName = nameString ( a . name ) ;
var bName = nameString ( b . name ) ;
var nameDiff = aName . localeCompare ( bName ) ;
if ( nameDiff !== 0 ) {
return nameDiff ;
}
}
// finally, sort by position in original NodeArray so the sort remains stable.
return ai - bi ;
} ) ;
var splits _1 = getSplitIndexes ( members , this . sourceFile . text ) ;
var sortedMembersText = sortedMemberIndexes . map ( function ( i ) {
var start = splits _1 [ i ] ;
var end = splits _1 [ i + 1 ] ;
var nodeText = _this . sourceFile . text . substring ( start , end ) ;
while ( true ) {
// check if there are previous fixes which we need to merge into this one
// if yes, remove it from the list so that we do not return overlapping Replacements
var fixIndex = arrayFindLastIndex ( _this . fixes , function ( _a ) {
var r = _a [ 1 ] ;
return r . start >= start && r . start + r . length <= end ;
} ) ;
if ( fixIndex === - 1 ) {
break ;
}
var fix = _this . fixes . splice ( fixIndex , 1 ) [ 0 ] ;
var replacement = fix [ 1 ] ;
nodeText = applyReplacementOffset ( nodeText , replacement , start ) ;
}
return nodeText ;
} ) ;
// instead of assigning the fix immediately to the last failure, we temporarily store it in `this.fixes`,
// in case a containing node needs to be fixed too. We only "add" the fix to the last failure, although
// it fixes all failures in this NodeArray, as TSLint doesn't handle duplicate Replacements.
this . fixes . push ( [
arrayLast ( this . failures ) ,
Lint . Replacement . replaceFromTo ( splits _1 [ 0 ] , arrayLast ( splits _1 ) , sortedMembersText . join ( "" ) ) ,
] ) ;
}
2017-05-28 00:38:50 +02:00
} ;
/** Finds the lowest name higher than 'targetName'. */
MemberOrderingWalker . prototype . findLowerName = function ( members , targetRank , targetName ) {
for ( var _i = 0 , members _2 = members ; _i < members _2 . length ; _i ++ ) {
var member = members _2 [ _i ] ;
if ( member . name === undefined || this . memberRank ( member ) !== targetRank ) {
continue ;
}
var name = nameString ( member . name ) ;
if ( caseInsensitiveLess ( targetName , name ) ) {
return name ;
}
}
throw new Error ( "Expected to find a name" ) ;
} ;
/** Finds the highest existing rank lower than `targetRank`. */
MemberOrderingWalker . prototype . findLowerRank = function ( members , targetRank ) {
var max = - 1 ;
for ( var _i = 0 , members _3 = members ; _i < members _3 . length ; _i ++ ) {
var member = members _3 [ _i ] ;
var rank = this . memberRank ( member ) ;
if ( rank !== - 1 && rank < targetRank ) {
max = Math . max ( max , rank ) ;
}
}
return max ;
} ;
MemberOrderingWalker . prototype . memberRank = function ( member ) {
var optionName = getMemberKind ( member ) ;
if ( optionName === undefined ) {
return - 1 ;
}
return this . options . order . findIndex ( function ( category ) { return category . has ( optionName ) ; } ) ;
} ;
MemberOrderingWalker . prototype . rankName = function ( rank ) {
return this . options . order [ rank ] . name ;
} ;
return MemberOrderingWalker ;
} ( Lint . AbstractWalker ) ) ;
function caseInsensitiveLess ( a , b ) {
return a . toLowerCase ( ) < b . toLowerCase ( ) ;
}
function memberKindForConstructor ( access ) {
return MemberKind [ access + "Constructor" ] ;
}
function memberKindForMethodOrField ( access , membership , kind ) {
return MemberKind [ access + membership + kind ] ;
}
var allAccess = [ "public" , "protected" , "private" ] ;
function memberKindFromName ( name ) {
var kind = MemberKind [ Lint . Utils . camelize ( name ) ] ;
return typeof kind === "number" ? [ kind ] : allAccess . map ( addModifier ) ;
function addModifier ( modifier ) {
var modifiedKind = MemberKind [ Lint . Utils . camelize ( modifier + "-" + name ) ] ;
if ( typeof modifiedKind !== "number" ) {
throw new Error ( "Bad member kind: " + name ) ;
}
return modifiedKind ;
}
}
function getMemberKind ( member ) {
2018-09-20 02:56:13 +02:00
var accessLevel = tsutils _1 . hasModifier ( member . modifiers , ts . SyntaxKind . PrivateKeyword ) ? "private"
: tsutils _1 . hasModifier ( member . modifiers , ts . SyntaxKind . ProtectedKeyword ) ? "protected"
2017-05-28 00:38:50 +02:00
: "public" ;
switch ( member . kind ) {
case ts . SyntaxKind . Constructor :
case ts . SyntaxKind . ConstructSignature :
return memberKindForConstructor ( accessLevel ) ;
case ts . SyntaxKind . PropertyDeclaration :
case ts . SyntaxKind . PropertySignature :
return methodOrField ( isFunctionLiteral ( member . initializer ) ) ;
case ts . SyntaxKind . MethodDeclaration :
case ts . SyntaxKind . MethodSignature :
return methodOrField ( true ) ;
default :
return undefined ;
}
function methodOrField ( isMethod ) {
2018-09-20 02:56:13 +02:00
var membership = tsutils _1 . hasModifier ( member . modifiers , ts . SyntaxKind . StaticKeyword ) ? "Static" : "Instance" ;
2017-05-28 00:38:50 +02:00
return memberKindForMethodOrField ( accessLevel , membership , isMethod ? "Method" : "Field" ) ;
}
}
2017-10-14 18:40:54 +02:00
var MemberCategory = /** @class */ ( function ( ) {
2017-05-28 00:38:50 +02:00
function MemberCategory ( name , kinds ) {
this . name = name ;
this . kinds = kinds ;
}
MemberCategory . prototype . has = function ( kind ) { return this . kinds . has ( kind ) ; } ;
return MemberCategory ;
} ( ) ) ;
function parseOptions ( options ) {
var _a = getOptionsJson ( options ) , orderJson = _a . order , alphabetize = _a . alphabetize ;
var order = orderJson . map ( function ( cat ) { return typeof cat === "string"
? new MemberCategory ( cat . replace ( /-/g , " " ) , new Set ( memberKindFromName ( cat ) ) )
: new MemberCategory ( cat . name , new Set ( utils _1 . flatMap ( cat . kinds , memberKindFromName ) ) ) ; } ) ;
return { order : order , alphabetize : alphabetize } ;
}
function getOptionsJson ( allOptions ) {
2017-12-10 21:51:33 +01:00
if ( allOptions == undefined || allOptions . length === 0 || allOptions [ 0 ] == undefined ) {
2017-05-28 00:38:50 +02:00
throw new Error ( "Got empty options" ) ;
}
var firstOption = allOptions [ 0 ] ;
if ( typeof firstOption !== "object" ) {
// Undocumented direct string option. Deprecate eventually.
return { order : convertFromOldStyleOptions ( allOptions ) , alphabetize : false } ; // presume allOptions to be string[]
}
return { order : categoryFromOption ( firstOption [ OPTION _ORDER ] ) , alphabetize : firstOption [ OPTION _ALPHABETIZE ] === true } ;
}
function categoryFromOption ( orderOption ) {
if ( Array . isArray ( orderOption ) ) {
return orderOption ;
}
var preset = PRESETS . get ( orderOption ) ;
if ( preset === undefined ) {
throw new Error ( "Bad order: " + JSON . stringify ( orderOption ) ) ;
}
return preset ;
}
/ * *
* Convert from undocumented old - style options .
* This is designed to mimic the old behavior and should be removed eventually .
* /
function convertFromOldStyleOptions ( options ) {
var categories = [ { name : "member" , kinds : allMemberKindNames } ] ;
if ( hasOption ( "variables-before-functions" ) ) {
categories = splitOldStyleOptions ( categories , function ( kind ) { return kind . includes ( "field" ) ; } , "field" , "method" ) ;
}
if ( hasOption ( "static-before-instance" ) ) {
categories = splitOldStyleOptions ( categories , function ( kind ) { return kind . includes ( "static" ) ; } , "static" , "instance" ) ;
}
if ( hasOption ( "public-before-private" ) ) {
// 'protected' is considered public
categories = splitOldStyleOptions ( categories , function ( kind ) { return ! kind . includes ( "private" ) ; } , "public" , "private" ) ;
}
return categories ;
function hasOption ( x ) {
return options . indexOf ( x ) !== - 1 ;
}
}
function splitOldStyleOptions ( categories , filter , a , b ) {
var newCategories = [ ] ;
var _loop _1 = function ( cat ) {
var yes = [ ] ;
var no = [ ] ;
for ( var _i = 0 , _a = cat . kinds ; _i < _a . length ; _i ++ ) {
var kind = _a [ _i ] ;
if ( filter ( kind ) ) {
yes . push ( kind ) ;
}
else {
no . push ( kind ) ;
}
}
var augmentName = function ( s ) {
if ( a === "field" ) {
// Replace "member" with "field"/"method" instead of augmenting.
return s ;
}
return s + " " + cat . name ;
} ;
newCategories . push ( { name : augmentName ( a ) , kinds : yes } ) ;
newCategories . push ( { name : augmentName ( b ) , kinds : no } ) ;
} ;
for ( var _i = 0 , categories _1 = categories ; _i < categories _1 . length ; _i ++ ) {
var cat = categories _1 [ _i ] ;
_loop _1 ( cat ) ;
}
return newCategories ;
}
function isFunctionLiteral ( node ) {
if ( node === undefined ) {
return false ;
}
switch ( node . kind ) {
case ts . SyntaxKind . ArrowFunction :
case ts . SyntaxKind . FunctionExpression :
return true ;
default :
return false ;
}
}
function nameString ( name ) {
switch ( name . kind ) {
case ts . SyntaxKind . Identifier :
case ts . SyntaxKind . StringLiteral :
case ts . SyntaxKind . NumericLiteral :
return name . text ;
default :
return "" ;
}
}
2018-09-20 02:56:13 +02:00
/ * *
* Returns the last element of an array . ( Or undefined ) .
* /
function arrayLast ( array ) {
return array [ array . length - 1 ] ;
}
/ * *
* Array . prototype . findIndex , but the last index .
* /
function arrayFindLastIndex ( array , predicate ) {
for ( var i = array . length ; i -- > 0 ; ) {
if ( predicate ( array [ i ] , i , array ) ) {
return i ;
}
}
return - 1 ;
}
/ * *
* Applies a Replacement to a part of the text which starts at offset .
* See also Replacement . apply
* /
function applyReplacementOffset ( content , replacement , offset ) {
return content . substring ( 0 , replacement . start - offset )
+ replacement . text
+ content . substring ( replacement . start - offset + replacement . length ) ;
}
/ * *
* Get the indexes of the boundaries between nodes in the node array . The following points must be taken into account :
* - Trivia should stay with its corresponding node ( comments on the same line following the token belong to the
* previous token , the rest to the next ) .
* - Reordering the subtexts should not result in code being commented out due to being moved between a "//" and
* the following newline .
* - The end of one node must be the start of the next , otherwise the intravening whitespace will be lost when
* reordering .
*
* Hence , the boundaries are chosen to be _after _ the newline following the node , or the beginning of the next token ,
* if that comes first .
* /
function getSplitIndexes ( members , text ) {
var result = members . map ( function ( member ) { return getNextSplitIndex ( text , member . getFullStart ( ) ) ; } ) ;
result . push ( getNextSplitIndex ( text , arrayLast ( members ) . getEnd ( ) ) ) ;
return result ;
}
/ * *
* Calculates the index after the newline following pos , or the beginning of the next token , whichever comes first .
* See also getSplitIndexes .
* This method is a modified version of TypeScript ' s internal iterateCommentRanges function .
* /
function getNextSplitIndex ( text , pos ) {
scan : while ( pos >= 0 && pos < text . length ) {
var ch = text . charCodeAt ( pos ) ;
switch ( ch ) {
case 13 /* carriageReturn */ :
if ( text . charCodeAt ( pos + 1 ) === 10 /* lineFeed */ ) {
pos ++ ;
}
// falls through
case 10 /* lineFeed */ :
pos ++ ;
// split is after new line
return pos ;
case 9 /* tab */ :
case 11 /* verticalTab */ :
case 12 /* formFeed */ :
case 32 /* space */ :
// skip whitespace
pos ++ ;
continue ;
case 47 /* slash */ :
var nextChar = text . charCodeAt ( pos + 1 ) ;
if ( nextChar === 47 /* slash */ || nextChar === 42 /* asterisk */ ) {
var isSingleLineComment = nextChar === 47 /* slash */ ;
pos += 2 ;
if ( isSingleLineComment ) {
while ( pos < text . length ) {
if ( ts . isLineBreak ( text . charCodeAt ( pos ) ) ) {
// the comment ends here, go back to default logic to handle parsing new line and result
continue scan ;
}
pos ++ ;
}
}
else {
while ( pos < text . length ) {
if ( text . charCodeAt ( pos ) === 42 /* asterisk */ && text . charCodeAt ( pos + 1 ) === 47 /* slash */ ) {
pos += 2 ;
continue scan ;
}
pos ++ ;
}
}
// if we arrive here, it's because pos == text.length
return pos ;
}
break scan ;
default :
// skip whitespace:
if ( ch > 127 /* maxAsciiCharacter */ && ( ts . isWhiteSpaceLike ( ch ) ) ) {
pos ++ ;
continue ;
}
break scan ;
}
}
return pos ;
}
var templateObject _1 , templateObject _2 ;