@@ -239,6 +239,11 @@ describe('assets/index', () => {
239239 } ) ;
240240
241241 describe ( 'getAssetByPath' , ( ) => {
242+ /**
243+ * @type {import('vitest').MockedFunction<typeof
244+ * import('$lib/services/utils/file').decodeFilePath
245+ * >}
246+ */
242247 let decodeFilePathMock ;
243248
244249 beforeEach ( async ( ) => {
@@ -343,6 +348,126 @@ describe('assets/index', () => {
343348 expect ( result ) . toBeUndefined ( ) ;
344349 } ) ;
345350
351+ it ( 'should remove URL fragments before processing path' , async ( ) => {
352+ const { stripSlashes } = await import ( '@sveltia/utils/string' ) ;
353+ const stripSlashesMock = vi . mocked ( stripSlashes ) ;
354+
355+ stripSlashesMock . mockReturnValue ( '/assets/image.jpg' ) ;
356+
357+ const mockAsset = {
358+ path : '/assets/image.jpg' ,
359+ name : 'image.jpg' ,
360+ kind : /** @type {import('$lib/types/private').AssetKind } */ ( 'image' ) ,
361+ sha : 'abc123' ,
362+ size : 1024 ,
363+ folder : {
364+ internalPath : 'assets' ,
365+ publicPath : '/assets' ,
366+ collectionName : undefined ,
367+ entryRelative : false ,
368+ hasTemplateTags : false ,
369+ } ,
370+ } ;
371+
372+ allAssets . set ( [ mockAsset ] ) ;
373+
374+ const result = getAssetByPath ( {
375+ value : '/assets/image.jpg#fragment' ,
376+ collectionName : 'posts' ,
377+ } ) ;
378+
379+ expect ( result ) . toEqual ( mockAsset ) ;
380+ expect ( decodeFilePathMock ) . toHaveBeenCalledWith ( '/assets/image.jpg' ) ;
381+ expect ( stripSlashesMock ) . toHaveBeenCalledWith ( '/assets/image.jpg' ) ;
382+ } ) ;
383+
384+ it ( 'should remove URL fragments with complex hashes' , async ( ) => {
385+ const { stripSlashes } = await import ( '@sveltia/utils/string' ) ;
386+ const stripSlashesMock = vi . mocked ( stripSlashes ) ;
387+
388+ stripSlashesMock . mockReturnValue ( '/assets/image.jpg' ) ;
389+
390+ const mockAsset = {
391+ path : '/assets/image.jpg' ,
392+ name : 'image.jpg' ,
393+ kind : /** @type {import('$lib/types/private').AssetKind } */ ( 'image' ) ,
394+ sha : 'abc123' ,
395+ size : 1024 ,
396+ folder : {
397+ internalPath : 'assets' ,
398+ publicPath : '/assets' ,
399+ collectionName : undefined ,
400+ entryRelative : false ,
401+ hasTemplateTags : false ,
402+ } ,
403+ } ;
404+
405+ allAssets . set ( [ mockAsset ] ) ;
406+
407+ const result = getAssetByPath ( {
408+ value : '/assets/image.jpg#section:subsection' ,
409+ collectionName : 'posts' ,
410+ } ) ;
411+
412+ expect ( result ) . toEqual ( mockAsset ) ;
413+ expect ( decodeFilePathMock ) . toHaveBeenCalledWith ( '/assets/image.jpg' ) ;
414+ } ) ;
415+
416+ it ( 'should handle relative paths with fragments' , async ( ) => {
417+ const { resolvePath } = await import ( '$lib/services/utils/file' ) ;
418+ const { getAssociatedCollections } = await import ( '$lib/services/contents/entry' ) ;
419+ const { getCollectionFilesByEntry } = await import ( '$lib/services/contents/collection/files' ) ;
420+ const resolvePathMock = vi . mocked ( resolvePath ) ;
421+ const getAssociatedCollectionsMock = vi . mocked ( getAssociatedCollections ) ;
422+ const getCollectionFilesByEntryMock = vi . mocked ( getCollectionFilesByEntry ) ;
423+
424+ const mockEntry = /** @type {any } */ ( {
425+ slug : 'test-post' ,
426+ id : 'test-post' ,
427+ subPath : 'test-post.md' ,
428+ locales : {
429+ en : {
430+ path : 'content/posts/test-post.md' ,
431+ content : { title : 'Test Post' } ,
432+ } ,
433+ } ,
434+ } ) ;
435+
436+ const mockCollection = /** @type {any } */ ( {
437+ name : 'posts' ,
438+ _i18n : { defaultLocale : 'en' } ,
439+ } ) ;
440+
441+ const mockAsset = {
442+ path : 'content/posts/image.jpg' ,
443+ name : 'image.jpg' ,
444+ kind : /** @type {import('$lib/types/private').AssetKind } */ ( 'image' ) ,
445+ sha : 'abc123' ,
446+ size : 1024 ,
447+ folder : {
448+ internalPath : 'content/posts' ,
449+ publicPath : '/posts' ,
450+ collectionName : 'posts' ,
451+ entryRelative : false ,
452+ hasTemplateTags : false ,
453+ } ,
454+ } ;
455+
456+ allAssets . set ( [ mockAsset ] ) ;
457+ resolvePathMock . mockReturnValue ( 'content/posts/image.jpg' ) ;
458+ getAssociatedCollectionsMock . mockReturnValue ( [ mockCollection ] ) ;
459+ getCollectionFilesByEntryMock . mockReturnValue ( [ ] ) ;
460+
461+ const result = getAssetByPath ( {
462+ value : 'image.jpg#anchor' ,
463+ entry : mockEntry ,
464+ collectionName : 'posts' ,
465+ } ) ;
466+
467+ expect ( result ) . toEqual ( mockAsset ) ;
468+ expect ( decodeFilePathMock ) . toHaveBeenCalledWith ( 'image.jpg' ) ;
469+ } ) ;
470+
346471 it ( 'should handle @ prefixed paths as absolute' , async ( ) => {
347472 const { stripSlashes } = await import ( '@sveltia/utils/string' ) ;
348473 const stripSlashesMock = vi . mocked ( stripSlashes ) ;
0 commit comments