@@ -96,14 +96,14 @@ export default createRule('no-navigation-without-base', {
96
96
}
97
97
const hrefValue = node . value [ 0 ] ;
98
98
if ( hrefValue . type === 'SvelteLiteral' ) {
99
- if ( ! urlIsAbsolute ( hrefValue ) ) {
99
+ if ( ! expressionIsAbsolute ( hrefValue ) ) {
100
100
context . report ( { loc : hrefValue . loc , messageId : 'linkNotPrefixed' } ) ;
101
101
}
102
102
return ;
103
103
}
104
104
if (
105
- ! urlStartsWithBase ( hrefValue . expression , basePathNames ) &&
106
- ! urlIsAbsolute ( hrefValue . expression )
105
+ ! expressionStartsWithBase ( context , hrefValue . expression , basePathNames ) &&
106
+ ! expressionIsAbsolute ( hrefValue . expression )
107
107
) {
108
108
context . report ( { loc : hrefValue . loc , messageId : 'linkNotPrefixed' } ) ;
109
109
}
@@ -183,7 +183,7 @@ function checkGotoCall(
183
183
return ;
184
184
}
185
185
const url = call . arguments [ 0 ] ;
186
- if ( ! urlStartsWithBase ( url , basePathNames ) ) {
186
+ if ( url . type === 'SpreadElement' || ! expressionStartsWithBase ( context , url , basePathNames ) ) {
187
187
context . report ( { loc : url . loc , messageId : 'gotoNotPrefixed' } ) ;
188
188
}
189
189
}
@@ -198,45 +198,79 @@ function checkShallowNavigationCall(
198
198
return ;
199
199
}
200
200
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
+ ) {
202
205
context . report ( { loc : url . loc , messageId } ) ;
203
206
}
204
207
}
205
208
206
209
// Helper functions
207
210
208
- function urlStartsWithBase (
209
- url : TSESTree . CallExpressionArgument ,
211
+ function expressionStartsWithBase (
212
+ context : RuleContext ,
213
+ url : TSESTree . Expression ,
210
214
basePathNames : Set < TSESTree . Identifier >
211
215
) : boolean {
212
216
switch ( url . type ) {
213
217
case 'BinaryExpression' :
214
- return binaryExpressionStartsWithBase ( url , basePathNames ) ;
218
+ return binaryExpressionStartsWithBase ( context , url , basePathNames ) ;
219
+ case 'Identifier' :
220
+ return variableStartsWithBase ( context , url , basePathNames ) ;
215
221
case 'TemplateLiteral' :
216
- return templateLiteralStartsWithBase ( url , basePathNames ) ;
222
+ return templateLiteralStartsWithBase ( context , url , basePathNames ) ;
217
223
default :
218
224
return false ;
219
225
}
220
226
}
221
227
222
228
function binaryExpressionStartsWithBase (
229
+ context : RuleContext ,
223
230
url : TSESTree . BinaryExpression ,
224
231
basePathNames : Set < TSESTree . Identifier >
225
232
) : 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
+ ) ;
237
+ }
238
+
239
+ function variableStartsWithBase (
240
+ context : RuleContext ,
241
+ url : TSESTree . Identifier ,
242
+ basePathNames : Set < TSESTree . Identifier >
243
+ ) : boolean {
244
+ if ( basePathNames . has ( url ) ) {
245
+ return true ;
246
+ }
247
+ const variable = findVariable ( context , url ) ;
248
+ if (
249
+ variable === null ||
250
+ variable . identifiers . length !== 1 ||
251
+ variable . identifiers [ 0 ] . parent . type !== 'VariableDeclarator' ||
252
+ variable . identifiers [ 0 ] . parent . init === null
253
+ ) {
254
+ return false ;
255
+ }
256
+ return expressionStartsWithBase ( context , variable . identifiers [ 0 ] . parent . init , basePathNames ) ;
227
257
}
228
258
229
259
function templateLiteralStartsWithBase (
260
+ context : RuleContext ,
230
261
url : TSESTree . TemplateLiteral ,
231
262
basePathNames : Set < TSESTree . Identifier >
232
263
) : boolean {
233
- const startingIdentifier = extractLiteralStartingIdentifier ( url ) ;
234
- return startingIdentifier !== undefined && basePathNames . has ( startingIdentifier ) ;
264
+ const startingIdentifier = extractLiteralStartingExpression ( url ) ;
265
+ return (
266
+ startingIdentifier !== undefined &&
267
+ expressionStartsWithBase ( context , startingIdentifier , basePathNames )
268
+ ) ;
235
269
}
236
270
237
- function extractLiteralStartingIdentifier (
271
+ function extractLiteralStartingExpression (
238
272
templateLiteral : TSESTree . TemplateLiteral
239
- ) : TSESTree . Identifier | undefined {
273
+ ) : TSESTree . Expression | undefined {
240
274
const literalParts = [ ...templateLiteral . expressions , ...templateLiteral . quasis ] . sort ( ( a , b ) =>
241
275
a . range [ 0 ] < b . range [ 0 ] ? - 1 : 1
242
276
) ;
@@ -245,15 +279,15 @@ function extractLiteralStartingIdentifier(
245
279
// Skip empty quasi in the begining
246
280
continue ;
247
281
}
248
- if ( part . type === 'Identifier ') {
282
+ if ( part . type !== 'TemplateElement ') {
249
283
return part ;
250
284
}
251
285
return undefined ;
252
286
}
253
287
return undefined ;
254
288
}
255
289
256
- function urlIsEmpty ( url : TSESTree . CallExpressionArgument ) : boolean {
290
+ function expressionIsEmpty ( url : TSESTree . Expression ) : boolean {
257
291
return (
258
292
( url . type === 'Literal' && url . value === '' ) ||
259
293
( url . type === 'TemplateLiteral' &&
@@ -263,7 +297,7 @@ function urlIsEmpty(url: TSESTree.CallExpressionArgument): boolean {
263
297
) ;
264
298
}
265
299
266
- function urlIsAbsolute ( url : SvelteLiteral | TSESTree . Expression ) : boolean {
300
+ function expressionIsAbsolute ( url : SvelteLiteral | TSESTree . Expression ) : boolean {
267
301
switch ( url . type ) {
268
302
case 'BinaryExpression' :
269
303
return binaryExpressionIsAbsolute ( url ) ;
@@ -280,13 +314,14 @@ function urlIsAbsolute(url: SvelteLiteral | TSESTree.Expression): boolean {
280
314
281
315
function binaryExpressionIsAbsolute ( url : TSESTree . BinaryExpression ) : boolean {
282
316
return (
283
- ( url . left . type !== 'PrivateIdentifier' && urlIsAbsolute ( url . left ) ) || urlIsAbsolute ( url . right )
317
+ ( url . left . type !== 'PrivateIdentifier' && expressionIsAbsolute ( url . left ) ) ||
318
+ expressionIsAbsolute ( url . right )
284
319
) ;
285
320
}
286
321
287
322
function templateLiteralIsAbsolute ( url : TSESTree . TemplateLiteral ) : boolean {
288
323
return (
289
- url . expressions . some ( urlIsAbsolute ) ||
324
+ url . expressions . some ( expressionIsAbsolute ) ||
290
325
url . quasis . some ( ( quasi ) => urlValueIsAbsolute ( quasi . value . raw ) )
291
326
) ;
292
327
}
0 commit comments