@@ -96,14 +96,14 @@ export default createRule('no-navigation-without-base', {
9696 }
9797 const hrefValue = node . value [ 0 ] ;
9898 if ( hrefValue . type === 'SvelteLiteral' ) {
99- if ( ! urlIsAbsolute ( hrefValue ) ) {
99+ if ( ! expressionIsAbsolute ( hrefValue ) ) {
100100 context . report ( { loc : hrefValue . loc , messageId : 'linkNotPrefixed' } ) ;
101101 }
102102 return ;
103103 }
104104 if (
105- ! urlStartsWithBase ( hrefValue . expression , basePathNames ) &&
106- ! urlIsAbsolute ( hrefValue . expression )
105+ ! expressionStartsWithBase ( context , hrefValue . expression , basePathNames ) &&
106+ ! expressionIsAbsolute ( hrefValue . expression )
107107 ) {
108108 context . report ( { loc : hrefValue . loc , messageId : 'linkNotPrefixed' } ) ;
109109 }
@@ -183,7 +183,7 @@ function checkGotoCall(
183183 return ;
184184 }
185185 const url = call . arguments [ 0 ] ;
186- if ( ! urlStartsWithBase ( url , basePathNames ) ) {
186+ if ( url . type === 'SpreadElement' || ! expressionStartsWithBase ( context , url , basePathNames ) ) {
187187 context . report ( { loc : url . loc , messageId : 'gotoNotPrefixed' } ) ;
188188 }
189189}
@@ -198,45 +198,59 @@ function checkShallowNavigationCall(
198198 return ;
199199 }
200200 const url = call . arguments [ 0 ] ;
201- if ( ! urlIsEmpty ( url ) && ! urlStartsWithBase ( url , basePathNames ) ) {
201+ if (
202+ url . type === 'SpreadElement' ||
203+ ( ! expressionIsEmpty ( url ) && ! expressionStartsWithBase ( context , url , basePathNames ) )
204+ ) {
202205 context . report ( { loc : url . loc , messageId } ) ;
203206 }
204207}
205208
206209// Helper functions
207210
208- function urlStartsWithBase (
209- url : TSESTree . CallExpressionArgument ,
211+ function expressionStartsWithBase (
212+ context : RuleContext ,
213+ url : TSESTree . Expression ,
210214 basePathNames : Set < TSESTree . Identifier >
211215) : boolean {
212216 switch ( url . type ) {
213217 case 'BinaryExpression' :
214- return binaryExpressionStartsWithBase ( url , basePathNames ) ;
218+ return binaryExpressionStartsWithBase ( context , url , basePathNames ) ;
219+ case 'Identifier' :
220+ return variableStartsWithBase ( context , url , basePathNames ) ;
215221 case 'TemplateLiteral' :
216- return templateLiteralStartsWithBase ( url , basePathNames ) ;
222+ return templateLiteralStartsWithBase ( context , url , basePathNames ) ;
217223 default :
218224 return false ;
219225 }
220226}
221227
222228function binaryExpressionStartsWithBase (
229+ context : RuleContext ,
223230 url : TSESTree . BinaryExpression ,
224231 basePathNames : Set < TSESTree . Identifier >
225232) : boolean {
226- return url . left . type === 'Identifier' && basePathNames . has ( url . left ) ;
233+ return (
234+ url . left . type !== 'PrivateIdentifier' &&
235+ expressionStartsWithBase ( context , url . left , basePathNames )
236+ ) ;
227237}
228238
229239function templateLiteralStartsWithBase (
240+ context : RuleContext ,
230241 url : TSESTree . TemplateLiteral ,
231242 basePathNames : Set < TSESTree . Identifier >
232243) : boolean {
233- const startingIdentifier = extractLiteralStartingIdentifier ( url ) ;
234- return startingIdentifier !== undefined && basePathNames . has ( startingIdentifier ) ;
244+ const startingIdentifier = extractLiteralStartingExpression ( url ) ;
245+ return (
246+ startingIdentifier !== undefined &&
247+ expressionStartsWithBase ( context , startingIdentifier , basePathNames )
248+ ) ;
235249}
236250
237- function extractLiteralStartingIdentifier (
251+ function extractLiteralStartingExpression (
238252 templateLiteral : TSESTree . TemplateLiteral
239- ) : TSESTree . Identifier | undefined {
253+ ) : TSESTree . Expression | undefined {
240254 const literalParts = [ ...templateLiteral . expressions , ...templateLiteral . quasis ] . sort ( ( a , b ) =>
241255 a . range [ 0 ] < b . range [ 0 ] ? - 1 : 1
242256 ) ;
@@ -245,15 +259,35 @@ function extractLiteralStartingIdentifier(
245259 // Skip empty quasi in the begining
246260 continue ;
247261 }
248- if ( part . type === 'Identifier ') {
262+ if ( part . type !== 'TemplateElement ') {
249263 return part ;
250264 }
251265 return undefined ;
252266 }
253267 return undefined ;
254268}
255269
256- function urlIsEmpty ( url : TSESTree . CallExpressionArgument ) : boolean {
270+ function variableStartsWithBase (
271+ context : RuleContext ,
272+ url : TSESTree . Identifier ,
273+ basePathNames : Set < TSESTree . Identifier >
274+ ) : boolean {
275+ if ( basePathNames . has ( url ) ) {
276+ return true ;
277+ }
278+ const variable = findVariable ( context , url ) ;
279+ if (
280+ variable === null ||
281+ variable . identifiers . length !== 1 ||
282+ variable . identifiers [ 0 ] . parent . type !== 'VariableDeclarator' ||
283+ variable . identifiers [ 0 ] . parent . init === null
284+ ) {
285+ return false ;
286+ }
287+ return expressionStartsWithBase ( context , variable . identifiers [ 0 ] . parent . init , basePathNames ) ;
288+ }
289+
290+ function expressionIsEmpty ( url : TSESTree . Expression ) : boolean {
257291 return (
258292 ( url . type === 'Literal' && url . value === '' ) ||
259293 ( url . type === 'TemplateLiteral' &&
@@ -263,7 +297,7 @@ function urlIsEmpty(url: TSESTree.CallExpressionArgument): boolean {
263297 ) ;
264298}
265299
266- function urlIsAbsolute ( url : SvelteLiteral | TSESTree . Expression ) : boolean {
300+ function expressionIsAbsolute ( url : SvelteLiteral | TSESTree . Expression ) : boolean {
267301 switch ( url . type ) {
268302 case 'BinaryExpression' :
269303 return binaryExpressionIsAbsolute ( url ) ;
@@ -280,13 +314,14 @@ function urlIsAbsolute(url: SvelteLiteral | TSESTree.Expression): boolean {
280314
281315function binaryExpressionIsAbsolute ( url : TSESTree . BinaryExpression ) : boolean {
282316 return (
283- ( url . left . type !== 'PrivateIdentifier' && urlIsAbsolute ( url . left ) ) || urlIsAbsolute ( url . right )
317+ ( url . left . type !== 'PrivateIdentifier' && expressionIsAbsolute ( url . left ) ) ||
318+ expressionIsAbsolute ( url . right )
284319 ) ;
285320}
286321
287322function templateLiteralIsAbsolute ( url : TSESTree . TemplateLiteral ) : boolean {
288323 return (
289- url . expressions . some ( urlIsAbsolute ) ||
324+ url . expressions . some ( expressionIsAbsolute ) ||
290325 url . quasis . some ( ( quasi ) => urlValueIsAbsolute ( quasi . value . raw ) )
291326 ) ;
292327}
0 commit comments