1+ import {
2+ inlineCodeFilePathCandidate ,
3+ isConventionalFilePosition ,
4+ } from "@t3tools/client-runtime/markdown-links" ;
5+ import { videoMimeType } from "@t3tools/shared/video" ;
6+
17import type { MARKDOWN_FILE_ICON_SOURCES } from "./markdownFileIcons.generated" ;
28
39const WINDOWS_DRIVE_PATH_PATTERN = / ^ [ A - Z a - z ] : [ \\ / ] / ;
@@ -253,15 +259,22 @@ function normalizeDestination(value: string): string {
253259 return trimmed . startsWith ( "<" ) && trimmed . endsWith ( ">" ) ? trimmed . slice ( 1 , - 1 ) : trimmed ;
254260}
255261
262+ /** Native link and media APIs have no document scheme to inherit from protocol-relative URLs. */
263+ export function normalizeNativeMarkdownUrl ( value : string ) : string {
264+ return value . startsWith ( "//" ) ? `https:${ value } ` : value ;
265+ }
266+
256267function fileUrlTarget ( href : string ) : { readonly path : string ; readonly hash : string } | null {
257268 try {
258269 const parsed = new URL ( href ) ;
259270 if ( parsed . protocol . toLowerCase ( ) !== "file:" ) {
260271 return null ;
261272 }
262- const path = / ^ \/ [ A - Z a - z ] : [ \\ / ] / . test ( parsed . pathname )
263- ? parsed . pathname . slice ( 1 )
273+ const uncHostname = parsed . hostname . toLowerCase ( ) === "localhost" ? "" : parsed . hostname ;
274+ const rawPath = uncHostname
275+ ? `\\\\${ uncHostname } ${ parsed . pathname . replaceAll ( "/" , "\\" ) } `
264276 : parsed . pathname ;
277+ const path = / ^ \/ [ A - Z a - z ] : [ \\ / ] / . test ( rawPath ) ? rawPath . slice ( 1 ) : rawPath ;
265278 return { path, hash : parsed . hash } ;
266279 } catch {
267280 return null ;
@@ -327,6 +340,7 @@ function looksLikeFilePath(value: string): boolean {
327340 if ( FILE_ICON_BY_NAME [ value . replace ( POSITION_SUFFIX_PATTERN , "" ) . toLowerCase ( ) ] ) {
328341 return true ;
329342 }
343+ if ( isConventionalFilePosition ( value ) ) return true ;
330344 return RELATIVE_FILE_PATH_PATTERN . test ( value ) || RELATIVE_FILE_NAME_PATTERN . test ( value ) ;
331345}
332346
@@ -338,6 +352,7 @@ function fileLabel(value: string): string {
338352
339353export function resolveMarkdownFileIcon ( value : string ) : MarkdownFileIcon {
340354 const basename = fileLabel ( value ) . replace ( POSITION_SUFFIX_PATTERN , "" ) . toLowerCase ( ) ;
355+ if ( videoMimeType ( { name : basename , mimeType : "" } ) !== null ) return "video" ;
341356 const exactIcon = FILE_ICON_BY_NAME [ basename ] ;
342357 if ( exactIcon ) return exactIcon ;
343358 if ( basename . startsWith ( "tsconfig." ) && basename . endsWith ( ".json" ) ) {
@@ -354,7 +369,7 @@ export function resolveMarkdownFileIcon(value: string): MarkdownFileIcon {
354369export function resolveMarkdownLinkPresentation ( href : string ) : MarkdownLinkPresentation {
355370 const normalized = normalizeDestination ( href ) ;
356371 try {
357- const parsed = new URL ( normalized ) ;
372+ const parsed = new URL ( normalizeNativeMarkdownUrl ( normalized ) ) ;
358373 if ( parsed . protocol === "http:" || parsed . protocol === "https:" ) {
359374 return {
360375 kind : "external" ,
@@ -399,3 +414,13 @@ export function resolveMarkdownLinkPresentation(href: string): MarkdownLinkPrese
399414 href : / ^ (?: m a i l t o | t e l ) : / i. test ( normalized ) ? normalized : null ,
400415 } ;
401416}
417+
418+ /** Backticks become file references only when the shared path heuristic recognizes the whole span. */
419+ export function resolveMarkdownInlineCodePresentation (
420+ content : string ,
421+ ) : Extract < MarkdownLinkPresentation , { readonly kind : "file" } > | null {
422+ const candidate = inlineCodeFilePathCandidate ( content ) ;
423+ if ( candidate === null ) return null ;
424+ const presentation = resolveMarkdownLinkPresentation ( candidate ) ;
425+ return presentation . kind === "file" ? presentation : null ;
426+ }
0 commit comments