1- import * as Lint from 'tslint' ;
2- import * as ts from 'typescript' ;
3- import { ComponentMetadata } from './angular/metadata' ;
1+ import { sprintf } from 'sprintf-js' ;
2+ import { IOptions , IRuleMetadata , RuleFailure , Rules , Utils } from 'tslint/lib' ;
3+ import { SourceFile } from 'typescript/lib/typescript' ;
4+ import { CodeWithSourceMap , ComponentMetadata } from './angular/metadata' ;
45import { NgWalker } from './angular/ngWalker' ;
56
6- export class Rule extends Lint . Rules . AbstractRule {
7- public static metadata : Lint . IRuleMetadata = {
8- ruleName : 'max-inline-declarations' ,
9- type : 'maintainability' ,
10- description : 'Disallows having too many lines in inline template or styles. Forces separate template or styles file creation.' ,
11- descriptionDetails : 'See more at https://angular.io/guide/styleguide#style-05-04' ,
7+ const DEFAULT_STYLES_LIMIT : number = 3 ;
8+ const DEFAULT_TEMPLATE_LIMIT : number = 3 ;
9+ const OPTION_STYLES = 'styles' ;
10+ const OPTION_TEMPLATE = 'template' ;
11+
12+ export class Rule extends Rules . AbstractRule {
13+ static readonly metadata : IRuleMetadata = {
14+ description : 'Disallows having too many lines in inline template and styles. Forces separate template or styles file creation.' ,
15+ descriptionDetails : 'See more at https://angular.io/guide/styleguide#style-05-04.' ,
16+ optionExamples : [ true , [ true , { [ OPTION_STYLES ] : 8 , [ OPTION_TEMPLATE ] : 5 } ] ] ,
1217 options : {
13- type : 'array' ,
1418 items : {
19+ properties : {
20+ [ OPTION_STYLES ] : {
21+ type : 'number'
22+ } ,
23+ [ OPTION_TEMPLATE ] : {
24+ type : 'number'
25+ }
26+ } ,
1527 type : 'object'
16- }
28+ } ,
29+ maxLength : 1 ,
30+ minLength : 0 ,
31+ type : 'array'
1732 } ,
18- optionsDescription : 'Define inline template and styles lines limit.' ,
19- optionExamples : [ '[{template: 5, styles: 8}]' ] ,
33+ optionsDescription : Utils . dedent `
34+ It can take an optional object with the properties '${ OPTION_STYLES } ' and '${ OPTION_TEMPLATE } ':
35+ * \`${ OPTION_STYLES } \` - number > 0 defining the maximum allowed inline lines for styles. Defaults to ${ DEFAULT_STYLES_LIMIT } .
36+ * \`${ OPTION_TEMPLATE } \` - number > 0 defining the maximum allowed inline lines for template. Defaults to ${ DEFAULT_TEMPLATE_LIMIT } .
37+ ` ,
38+ rationale :
39+ "Large, inline templates and styles obscure the component's purpose and implementation, reducing readability and maintainability." ,
40+ ruleName : 'max-inline-declarations' ,
41+ type : 'maintainability' ,
2042 typescriptOnly : true
2143 } ;
2244
23- private readonly templateLinesLimit : number = 3 ;
24- private readonly stylesLinesLimit : number = 3 ;
45+ static readonly FAILURE_STRING = 'Exceeds the maximum allowed inline lines for %s. Defined limit: %s / total lines: %s' ;
2546
26- constructor ( options : Lint . IOptions ) {
27- super ( options ) ;
28- if ( options . ruleArguments . length > 1 ) {
29- const args = options . ruleArguments [ 1 ] ;
30- if ( args . template > - 1 ) {
31- this . templateLinesLimit = args . template ;
32- }
33- if ( args . styles > - 1 ) {
34- this . stylesLinesLimit = args . styles ;
35- }
36- }
37- }
38-
39- public apply ( sourceFile : ts . SourceFile ) : Lint . RuleFailure [ ] {
40- return this . applyWithWalker (
41- new MaxInlineDeclarationsValidator ( sourceFile , this . getOptions ( ) , this . templateLinesLimit , this . stylesLinesLimit )
42- ) ;
47+ apply ( sourceFile : SourceFile ) : RuleFailure [ ] {
48+ return this . applyWithWalker ( new MaxInlineDeclarationsValidator ( sourceFile , this . getOptions ( ) ) ) ;
4349 }
4450}
4551
52+ type PropertyType = 'styles' | 'template' ;
53+
54+ export type PropertyPair = { [ key in PropertyType ] ?: number } ;
55+
56+ const generateFailure = ( type : PropertyType , limit : number , value : number ) : string => {
57+ return sprintf ( Rule . FAILURE_STRING , type , limit , value ) ;
58+ } ;
59+
60+ export const getStylesFailure = ( value : number , limit = DEFAULT_STYLES_LIMIT ) : string => {
61+ return generateFailure ( OPTION_STYLES , limit , value ) ;
62+ } ;
63+
64+ export const getTemplateFailure = ( value : number , limit = DEFAULT_TEMPLATE_LIMIT ) : string => {
65+ return generateFailure ( OPTION_TEMPLATE , limit , value ) ;
66+ } ;
67+
4668export class MaxInlineDeclarationsValidator extends NgWalker {
47- private newLineRegExp = / \r \n | \r | \n / ;
69+ private readonly stylesLinesLimit = DEFAULT_STYLES_LIMIT ;
70+ private readonly templateLinesLimit = DEFAULT_TEMPLATE_LIMIT ;
71+ private readonly newLineRegExp = / \r \n | \r | \n / ;
4872
49- constructor ( sourceFile : ts . SourceFile , options : Lint . IOptions , private templateLinesLimit : number , private stylesLinesLimit : number ) {
73+ constructor ( sourceFile : SourceFile , options : IOptions ) {
5074 super ( sourceFile , options ) ;
75+
76+ const { styles, template } = ( options . ruleArguments [ 0 ] || [ ] ) as PropertyPair ;
77+
78+ this . stylesLinesLimit = styles > - 1 ? styles : this . stylesLinesLimit ;
79+ this . templateLinesLimit = template > - 1 ? template : this . templateLinesLimit ;
5180 }
5281
5382 protected visitNgComponent ( metadata : ComponentMetadata ) : void {
@@ -56,30 +85,44 @@ export class MaxInlineDeclarationsValidator extends NgWalker {
5685 super . visitNgComponent ( metadata ) ;
5786 }
5887
59- private validateInlineTemplate ( metadata : ComponentMetadata ) : void {
60- if ( this . hasInlineTemplate ( metadata ) && this . getTemplateLinesCount ( metadata ) > this . templateLinesLimit ) {
61- const templateLinesCount = this . getTemplateLinesCount ( metadata ) ;
62- const msg = `Inline template lines limit exceeded. Defined limit: ${ this . templateLinesLimit } / template lines: ${ templateLinesCount } ` ;
63- this . addFailureAtNode ( metadata . template . node , msg ) ;
64- }
88+ private getTotalLines ( source : CodeWithSourceMap [ 'source' ] ) : number {
89+ return source . trim ( ) . split ( this . newLineRegExp ) . length ;
90+ }
91+
92+ private getTemplateLinesCount ( metadata : ComponentMetadata ) : number {
93+ return this . hasInlineTemplate ( metadata ) ? this . getTotalLines ( metadata . template . template . source ) : 0 ;
6594 }
6695
6796 private hasInlineTemplate ( metadata : ComponentMetadata ) : boolean {
68- return ! ! metadata . template && ! metadata . template . url && ! ! metadata . template . template && ! ! metadata . template . template . source ;
97+ return ! ! ( metadata . template && ! metadata . template . url && metadata . template . template && metadata . template . template . source ) ;
6998 }
7099
71- private getTemplateLinesCount ( metadata : ComponentMetadata ) : number {
72- return metadata . template . template . source . split ( this . newLineRegExp ) . length ;
100+ private validateInlineTemplate ( metadata : ComponentMetadata ) : void {
101+ const templateLinesCount = this . getTemplateLinesCount ( metadata ) ;
102+
103+ if ( templateLinesCount <= this . templateLinesLimit ) {
104+ return ;
105+ }
106+
107+ const failureMessage = getTemplateFailure ( templateLinesCount , this . templateLinesLimit ) ;
108+
109+ this . addFailureAtNode ( metadata . template . node , failureMessage ) ;
73110 }
74111
75- private validateInlineStyles ( metadata : ComponentMetadata ) : void {
76- if ( this . hasInlineStyles ( metadata ) && this . getInlineStylesLinesCount ( metadata ) > this . stylesLinesLimit ) {
77- const stylesLinesCount = this . getInlineStylesLinesCount ( metadata ) ;
78- const msg = `Inline styles lines limit exceeded. Defined limit: ${ this . stylesLinesLimit } / styles lines: ${ stylesLinesCount } ` ;
79- for ( let i = 0 ; i < metadata . styles . length ; i ++ ) {
80- this . addFailureAtNode ( metadata . styles [ i ] . node , msg ) ;
112+ private getInlineStylesLinesCount ( metadata : ComponentMetadata ) : number {
113+ let result = 0 ;
114+
115+ if ( ! this . hasInlineStyles ( metadata ) ) {
116+ return result ;
117+ }
118+
119+ for ( let i = 0 ; i < metadata . styles . length ; i ++ ) {
120+ if ( ! metadata . styles [ i ] . url ) {
121+ result += this . getTotalLines ( metadata . styles [ i ] . style . source ) ;
81122 }
82123 }
124+
125+ return result ;
83126 }
84127
85128 private hasInlineStyles ( metadata : ComponentMetadata ) : boolean {
@@ -89,6 +132,7 @@ export class MaxInlineDeclarationsValidator extends NgWalker {
89132
90133 for ( let i = 0 ; i < metadata . styles . length ; i ++ ) {
91134 const style = metadata . styles [ i ] ;
135+
92136 if ( ! style . url && style . style && style . style . source ) {
93137 return true ;
94138 }
@@ -97,14 +141,17 @@ export class MaxInlineDeclarationsValidator extends NgWalker {
97141 return false ;
98142 }
99143
100- private getInlineStylesLinesCount ( metadata : ComponentMetadata ) {
101- let result = 0 ;
102- for ( let i = 0 ; i < metadata . styles . length ; i ++ ) {
103- if ( ! metadata . styles [ i ] . url ) {
104- result += metadata . styles [ i ] . style . source . split ( this . newLineRegExp ) . length ;
105- }
144+ private validateInlineStyles ( metadata : ComponentMetadata ) : void {
145+ const stylesLinesCount = this . getInlineStylesLinesCount ( metadata ) ;
146+
147+ if ( stylesLinesCount <= this . stylesLinesLimit ) {
148+ return ;
106149 }
107150
108- return result ;
151+ const failureMessage = getStylesFailure ( stylesLinesCount , this . stylesLinesLimit ) ;
152+
153+ for ( let i = 0 ; i < metadata . styles . length ; i ++ ) {
154+ this . addFailureAtNode ( metadata . styles [ i ] . node , failureMessage ) ;
155+ }
109156 }
110157}
0 commit comments