@@ -98,7 +98,8 @@ export default createRule('no-navigation-without-resolve', {
9898 node . parent . parent . name . type !== 'SvelteName' ||
9999 node . parent . parent . name . name !== 'a' ||
100100 node . key . name !== 'href' ||
101- node . value . type !== 'Identifier'
101+ node . value . type !== 'Identifier' ||
102+ hasRelExternal ( new FindVariableContext ( context ) , node . parent )
102103 ) {
103104 return ;
104105 }
@@ -117,7 +118,8 @@ export default createRule('no-navigation-without-resolve', {
117118 node . parent . parent . kind !== 'html' ||
118119 node . parent . parent . name . type !== 'SvelteName' ||
119120 node . parent . parent . name . name !== 'a' ||
120- node . key . name !== 'href'
121+ node . key . name !== 'href' ||
122+ hasRelExternal ( new FindVariableContext ( context ) , node . parent )
121123 ) {
122124 return ;
123125 }
@@ -431,3 +433,38 @@ function templateLiteralIsFragment(
431433function urlValueIsFragment ( url : string ) : boolean {
432434 return url . startsWith ( '#' ) ;
433435}
436+
437+ function hasRelExternal ( ctx : FindVariableContext , element : AST . SvelteStartTag ) : boolean {
438+ function identifierIsExternal ( identifier : TSESTree . Identifier ) : boolean {
439+ const variable = ctx . findVariable ( identifier ) ;
440+ return (
441+ variable !== null &&
442+ variable . identifiers . length > 0 &&
443+ variable . identifiers [ 0 ] . parent . type === 'VariableDeclarator' &&
444+ variable . identifiers [ 0 ] . parent . init !== null &&
445+ variable . identifiers [ 0 ] . parent . init . type === 'Literal' &&
446+ variable . identifiers [ 0 ] . parent . init . value === 'external'
447+ ) ;
448+ }
449+
450+ for ( const attr of element . attributes ) {
451+ if (
452+ ( attr . type === 'SvelteAttribute' &&
453+ attr . key . name === 'rel' &&
454+ ( ( attr . value [ 0 ] . type === 'SvelteLiteral' &&
455+ attr . value [ 0 ] . value . split ( / \s + / ) . includes ( 'external' ) ) ||
456+ ( attr . value [ 0 ] . type === 'SvelteMustacheTag' &&
457+ ( ( attr . value [ 0 ] . expression . type === 'Literal' &&
458+ attr . value [ 0 ] . expression . value ?. toString ( ) . split ( / \s + / ) . includes ( 'external' ) ) ||
459+ ( attr . value [ 0 ] . expression . type === 'Identifier' &&
460+ identifierIsExternal ( attr . value [ 0 ] . expression ) ) ) ) ) ) ||
461+ ( attr . type === 'SvelteShorthandAttribute' &&
462+ attr . key . name === 'rel' &&
463+ attr . value . type === 'Identifier' &&
464+ identifierIsExternal ( attr . value ) )
465+ ) {
466+ return true ;
467+ }
468+ }
469+ return false ;
470+ }
0 commit comments