@@ -5,12 +5,14 @@ import * as minimatch from 'minimatch';
5
5
6
6
/**
7
7
* Rule that enforces certain decorator properties to be defined and to match a pattern.
8
- * Supports whitelisting via the third argument. E.g.
8
+ * Properties can be forbidden by prefixing their name with a `!`.
9
+ * Supports whitelisting files via the third argument. E.g.
9
10
*
10
11
* ```
11
12
* "validate-decorators": [true, {
12
13
* "Component": {
13
- * "encapsulation": "\\.None$"
14
+ * "encapsulation": "\\.None$",
15
+ * "!styles": ".*"
14
16
* }
15
17
* }, "src/lib"]
16
18
* ```
@@ -21,8 +23,16 @@ export class Rule extends Lint.Rules.AbstractRule {
21
23
}
22
24
}
23
25
24
- /** Rules that can be used to validate the decorators in a file. */
25
- type DecoratorRules = { [ key : string ] : { [ key : string ] : RegExp } } ;
26
+ /** Represents a set of required and forbidden decorator properties. */
27
+ type DecoratorRuleSet = {
28
+ required : { [ key : string ] : RegExp } ,
29
+ forbidden : { [ key : string ] : RegExp } ,
30
+ } ;
31
+
32
+ /** Represents a map between decorator names and rule sets. */
33
+ type DecoratorRules = {
34
+ [ key : string ] : DecoratorRuleSet
35
+ } ;
26
36
27
37
class Walker extends Lint . RuleWalker {
28
38
// Whether the file should be checked at all.
@@ -76,20 +86,30 @@ class Walker extends Lint.RuleWalker {
76
86
node
77
87
} ) ) ;
78
88
79
- // Find all of the rule properties that are missing from the decorator.
80
- const missing = Object . keys ( rules ) . filter ( key => ! props . find ( ( prop : any ) => prop . name === key ) ) ;
89
+ // Find all of the required rule properties that are missing from the decorator.
90
+ const missing = Object . keys ( rules . required )
91
+ . filter ( key => ! props . find ( ( prop : any ) => prop . name === key ) ) ;
81
92
82
93
if ( missing . length ) {
83
94
// Exit early if any of the properties are missing.
84
95
this . addFailureAtNode ( decorator . parent , 'Missing required properties: ' + missing . join ( ', ' ) ) ;
85
96
} else {
86
- // If all the necessary properties are defined, ensure that they match the pattern.
97
+ // If all the necessary properties are defined, ensure that
98
+ // they match the pattern and aren't in the forbidden list.
87
99
props
88
- . filter ( ( prop : any ) => rules [ prop . name ] )
89
- . filter ( ( prop : any ) => ! rules [ prop . name ] . test ( prop . value ) )
100
+ . filter ( ( prop : any ) => rules . required [ prop . name ] || rules . forbidden [ prop . name ] )
90
101
. forEach ( ( prop : any ) => {
91
- this . addFailureAtNode ( prop . node ,
92
- `Invalid value for property. Expected value to match "${ rules [ prop . name ] } ".` ) ;
102
+ const { name, value, node} = prop ;
103
+ const requiredPattern = rules . required [ name ] ;
104
+ const forbiddenPattern = rules . forbidden [ name ] ;
105
+
106
+ if ( requiredPattern && ! requiredPattern . test ( value ) ) {
107
+ this . addFailureAtNode ( node , `Invalid value for property. ` +
108
+ `Expected value to match "${ requiredPattern } ".` ) ;
109
+ } else if ( forbiddenPattern && forbiddenPattern . test ( value ) ) {
110
+ this . addFailureAtNode ( node , `Property value not allowed. ` +
111
+ `Value should not match "${ forbiddenPattern } ".` ) ;
112
+ }
93
113
} ) ;
94
114
}
95
115
}
@@ -108,9 +128,18 @@ class Walker extends Lint.RuleWalker {
108
128
. filter ( decoratorName => Object . keys ( config [ decoratorName ] ) . length > 0 )
109
129
. forEach ( decoratorName => {
110
130
output [ decoratorName ] = Object . keys ( config [ decoratorName ] ) . reduce ( ( accumulator , prop ) => {
111
- accumulator [ prop ] = new RegExp ( config [ decoratorName ] [ prop ] ) ;
131
+ const isForbidden = prop . startsWith ( '!' ) ;
132
+ const cleanName = isForbidden ? prop . slice ( 1 ) : prop ;
133
+ const pattern = new RegExp ( config [ decoratorName ] [ prop ] ) ;
134
+
135
+ if ( isForbidden ) {
136
+ accumulator . forbidden [ cleanName ] = pattern ;
137
+ } else {
138
+ accumulator . required [ cleanName ] = pattern ;
139
+ }
140
+
112
141
return accumulator ;
113
- } , { } as { [ key : string ] : RegExp } ) ;
142
+ } , { required : { } , forbidden : { } } as DecoratorRuleSet ) ;
114
143
} ) ;
115
144
}
116
145
0 commit comments