@@ -279,7 +279,7 @@ private static void ProcessLinkText(InlineProcessor processor, LinkInline link,
279
279
_ = link . AppendChild ( new LiteralInline ( title ) ) ;
280
280
}
281
281
282
- private static IFileInfo ResolveFile ( ParserContext context , string url ) =>
282
+ public static IFileInfo ResolveFile ( ParserContext context , string url ) =>
283
283
string . IsNullOrWhiteSpace ( url )
284
284
? context . MarkdownSourcePath
285
285
: url . StartsWith ( '/' )
@@ -302,49 +302,8 @@ private static void UpdateLinkUrl(LinkInline link, MarkdownFile? linkMarkdown, s
302
302
newUrl = linkMarkdown . Url ;
303
303
}
304
304
else
305
- {
306
- // TODO revisit when we refactor our documentation set graph
307
- // This method grew too complex, we need to revisit our documentation set graph generation so we can ask these questions
308
- // on `DocumentationFile` that are mostly precomputed
309
- var urlPathPrefix = context . Build . UrlPathPrefix ?? string . Empty ;
310
-
311
- if ( ! newUrl . StartsWith ( '/' ) && ! string . IsNullOrEmpty ( newUrl ) )
312
- {
313
- // eat overall path prefix since its gets appended later
314
- var subPrefix = context . CurrentUrlPath . Length >= urlPathPrefix . Length
315
- ? context . CurrentUrlPath [ urlPathPrefix . Length ..]
316
- : urlPathPrefix ;
317
-
318
- // if we are trying to resolve a relative url from a _snippet folder ensure we eat the _snippet folder
319
- // as it's not part of url by chopping of the extra parent navigation
320
- if ( newUrl . StartsWith ( "../" ) && context . DocumentationFileLookup ( context . MarkdownSourcePath ) is SnippetFile snippetFile )
321
- newUrl = url . Substring ( 3 ) ;
322
-
323
- // TODO check through context.DocumentationFileLookup if file is index vs "index.md" check
324
- var markdownPath = context . MarkdownSourcePath ;
325
- // if the current path is an index e.g /reference/cloud-k8s/
326
- // './' current path lookups should be relative to sub-path.
327
- // If it's not e.g /reference/cloud-k8s/api-docs/ these links should resolve on folder up.
328
- var lastIndexPath = subPrefix . LastIndexOf ( '/' ) ;
329
- if ( lastIndexPath >= 0 && markdownPath . Name != "index.md" )
330
- subPrefix = subPrefix [ ..lastIndexPath ] ;
331
- var combined = '/' + Path . Combine ( subPrefix , newUrl ) . TrimStart ( '/' ) ;
332
- newUrl = Path . GetFullPath ( combined ) ;
333
- }
334
-
335
- // When running on Windows, path traversal results must be normalized prior to being used in a URL
336
- // Path.GetFullPath() will result in the drive letter being appended to the path, which needs to be pruned back.
337
- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
338
- {
339
- newUrl = newUrl . Replace ( '\\ ' , '/' ) ;
340
- if ( newUrl . Length > 2 && newUrl [ 1 ] == ':' )
341
- newUrl = newUrl [ 2 ..] ;
342
- }
305
+ newUrl = UpdateRelativeUrl ( context , url ) ;
343
306
344
- if ( ! string . IsNullOrWhiteSpace ( newUrl ) && ! string . IsNullOrWhiteSpace ( urlPathPrefix ) )
345
- newUrl = $ "{ urlPathPrefix . TrimEnd ( '/' ) } { newUrl } ";
346
-
347
- }
348
307
349
308
if ( newUrl . EndsWith ( ".md" ) )
350
309
{
@@ -364,6 +323,52 @@ private static void UpdateLinkUrl(LinkInline link, MarkdownFile? linkMarkdown, s
364
323
: newUrl ;
365
324
}
366
325
326
+ // TODO revisit when we refactor our documentation set graph
327
+ // This method grew too complex, we need to revisit our documentation set graph generation so we can ask these questions
328
+ // on `DocumentationFile` that are mostly precomputed
329
+ public static string UpdateRelativeUrl ( ParserContext context , string url )
330
+ {
331
+ var urlPathPrefix = context . Build . UrlPathPrefix ?? string . Empty ;
332
+ var newUrl = url ;
333
+ if ( ! newUrl . StartsWith ( '/' ) && ! string . IsNullOrEmpty ( newUrl ) )
334
+ {
335
+ var subPrefix = context . CurrentUrlPath . Length >= urlPathPrefix . Length
336
+ ? context . CurrentUrlPath [ urlPathPrefix . Length ..]
337
+ : urlPathPrefix ;
338
+
339
+ // if we are trying to resolve a relative url from a _snippet folder ensure we eat the _snippet folder
340
+ // as it's not part of url by chopping of the extra parent navigation
341
+ if ( newUrl . StartsWith ( "../" ) && context . DocumentationFileLookup ( context . MarkdownSourcePath ) is SnippetFile )
342
+ newUrl = url [ 3 ..] ;
343
+
344
+ // TODO check through context.DocumentationFileLookup if file is index vs "index.md" check
345
+ var markdownPath = context . MarkdownSourcePath ;
346
+ // if the current path is an index e.g /reference/cloud-k8s/
347
+ // './' current path lookups should be relative to sub-path.
348
+ // If it's not e.g /reference/cloud-k8s/api-docs/ these links should resolve on folder up.
349
+ var lastIndexPath = subPrefix . LastIndexOf ( '/' ) ;
350
+ if ( lastIndexPath >= 0 && markdownPath . Name != "index.md" )
351
+ subPrefix = subPrefix [ ..lastIndexPath ] ;
352
+ var combined = '/' + Path . Combine ( subPrefix , newUrl ) . TrimStart ( '/' ) ;
353
+ newUrl = Path . GetFullPath ( combined ) ;
354
+
355
+ }
356
+ // When running on Windows, path traversal results must be normalized prior to being used in a URL
357
+ // Path.GetFullPath() will result in the drive letter being appended to the path, which needs to be pruned back.
358
+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
359
+ {
360
+ newUrl = newUrl . Replace ( '\\ ' , '/' ) ;
361
+ if ( newUrl . Length > 2 && newUrl [ 1 ] == ':' )
362
+ newUrl = newUrl [ 2 ..] ;
363
+ }
364
+
365
+ if ( ! string . IsNullOrWhiteSpace ( newUrl ) && ! string . IsNullOrWhiteSpace ( urlPathPrefix ) )
366
+ newUrl = $ "{ urlPathPrefix . TrimEnd ( '/' ) } { newUrl } ";
367
+
368
+ // eat overall path prefix since its gets appended later
369
+ return newUrl ;
370
+ }
371
+
367
372
private static bool IsCrossLink ( [ NotNullWhen ( true ) ] Uri ? uri ) =>
368
373
uri != null // This means it's not a local
369
374
&& ! ExcludedSchemes . Contains ( uri . Scheme )
0 commit comments