11import type { TSESTree } from '@typescript-eslint/experimental-utils' ;
22import { createESLintRule } from '../utils/create-eslint-rule' ;
33import { COMPONENT_CLASS_DECORATOR } from '../utils/selectors' ;
4- import {
5- getDecoratorProperty ,
6- isArrayExpression ,
7- isLiteralWithStringValue ,
8- } from '../utils/utils' ;
4+ import { isArrayExpression , isLiteralWithStringValue } from '../utils/utils' ;
95
106type Options = [ ] ;
117export type MessageIds = 'relativeUrlPrefix' ;
128export const RULE_NAME = 'relative-url-prefix' ;
139
1410const STYLE_GUIDE_LINK = 'https://angular.io/styleguide#style-05-04' ;
15- const RELATIVE_URL_PREFIX_MATCHER = / ^ \. { 1 , 2 } \/ [ ^ . / ] / ;
11+ const RELATIVE_URL_PREFIX_MATCHER = / ^ \. \. ? \/ . + / ;
1612
1713export default createESLintRule < Options , MessageIds > ( {
1814 name : RULE_NAME ,
1915 meta : {
2016 type : 'suggestion' ,
2117 docs : {
22- description : `The ./ and ../ prefix is standard syntax for relative URLs; don't depend on Angular's current ability to do without that prefix. See more at ${ STYLE_GUIDE_LINK } . ` ,
18+ description : `The ./ and ../ prefix is standard syntax for relative URLs; don't depend on Angular's current ability to do without that prefix. See more at ${ STYLE_GUIDE_LINK } ` ,
2319 category : 'Best Practices' ,
2420 recommended : false ,
2521 } ,
@@ -31,43 +27,35 @@ export default createESLintRule<Options, MessageIds>({
3127 defaultOptions : [ ] ,
3228 create ( context ) {
3329 return {
34- [ COMPONENT_CLASS_DECORATOR ] ( node : TSESTree . Decorator ) {
35- const templateUrlProperty = getDecoratorProperty ( node , 'templateUrl' ) ;
36- if (
37- templateUrlProperty &&
38- isLiteralWithStringValue ( templateUrlProperty . value )
39- ) {
40- if (
41- ! RELATIVE_URL_PREFIX_MATCHER . test ( templateUrlProperty . value . value )
42- ) {
43- context . report ( {
44- node : templateUrlProperty . value ,
45- messageId : 'relativeUrlPrefix' ,
46- } ) ;
47- }
48- }
30+ [ `${ COMPONENT_CLASS_DECORATOR } Property[key.name='templateUrl']` ] ( {
31+ value,
32+ } : TSESTree . Property ) {
33+ if ( ! isUrlInvalid ( value ) ) return ;
4934
50- const styleUrlsProperty = getDecoratorProperty ( node , 'styleUrls' ) ;
51- if ( styleUrlsProperty ) {
52- if (
53- styleUrlsProperty . value &&
54- isArrayExpression ( styleUrlsProperty . value ) &&
55- styleUrlsProperty . value . elements . length > 0
56- ) {
57- styleUrlsProperty . value . elements . forEach ( ( e ) => {
58- if (
59- isLiteralWithStringValue ( e ) &&
60- ! RELATIVE_URL_PREFIX_MATCHER . test ( e . value )
61- ) {
62- context . report ( {
63- node : e ,
64- messageId : 'relativeUrlPrefix' ,
65- } ) ;
66- }
67- } ) ;
68- }
69- }
35+ context . report ( {
36+ node : value ,
37+ messageId : 'relativeUrlPrefix' ,
38+ } ) ;
39+ } ,
40+ [ `${ COMPONENT_CLASS_DECORATOR } Property[key.name='styleUrls']` ] ( {
41+ value,
42+ } : TSESTree . Property ) {
43+ if ( ! isArrayExpression ( value ) ) return ;
44+
45+ value . elements . filter ( isUrlInvalid ) . forEach ( ( element ) => {
46+ context . report ( {
47+ node : element ,
48+ messageId : 'relativeUrlPrefix' ,
49+ } ) ;
50+ } ) ;
7051 } ,
7152 } ;
7253 } ,
7354} ) ;
55+
56+ function isUrlInvalid ( node : TSESTree . Property | TSESTree . Property [ 'value' ] ) {
57+ return (
58+ ! isLiteralWithStringValue ( node ) ||
59+ ! RELATIVE_URL_PREFIX_MATCHER . test ( node . value )
60+ ) ;
61+ }
0 commit comments