@@ -449,25 +449,71 @@ TEST: addTests('isRepoHome', [
449449 'https://github.com/sindresorhus/refined-github?files=1' ,
450450] ) ;
451451
452+ export type RepoExplorerInfo = {
453+ nameWithOwner : string ;
454+ branch : string ;
455+ filePath : string ;
456+ } ;
457+
458+ // https://github.com/eslint/js/tree/2.x ->'eslint/js at 2.x'
459+ // https://github.com/eslint/js/tree/2.x ->'js/ at 2.x · eslint/js'
460+ // https://github.com/eslint/js/tree/2.x/tools -> 'js/tools at 2.x · eslint/js'
461+ const titleParseRegex = / ^ (?: (?< nameWithOwner > [ ^ ] + ) a t (?< branch > [ ^ ] + ) | [ ^ / ] + (?: \/ (?< filePath > [ ^ ] * ) ) ? a t (?< branch2 > [ ^ ] + ) (?: · (?< nameWithOwner2 > [ ^ ] + ) ) ? ) $ / ;
462+ // TODO: Reuse regex group names on the next MAJOR version https://github.com/tc39/proposal-duplicate-named-capturing-groups/issues/4
463+
464+ const parseRepoExplorerTitle = ( pathname : string , title : string ) : RepoExplorerInfo | undefined => {
465+ const match = titleParseRegex . exec ( title ) ;
466+ if ( ! match ?. groups ) {
467+ return ;
468+ }
469+
470+ let { nameWithOwner, branch, filePath, nameWithOwner2, branch2} = match . groups ;
471+
472+ nameWithOwner ??= nameWithOwner2 ;
473+ branch ??= branch2 ;
474+ filePath ??= '' ;
475+
476+ if ( ! nameWithOwner || ! branch || ! pathname . startsWith ( `/${ nameWithOwner } /tree/` ) ) {
477+ return ;
478+ }
479+
480+ return { nameWithOwner, branch, filePath} ;
481+ } ;
482+
452483const _isRepoRoot = ( url ?: URL | HTMLAnchorElement | Location ) : boolean => {
453484 const repository = getRepo ( url ?? location ) ;
454485
455486 if ( ! repository ) {
487+ // Not a repo
456488 return false ;
457489 }
458490
459- if ( ! repository . path ) {
460- // Absolute repo root: `isRepoHome`
461- return true ;
462- }
491+ const path = repository . path ? repository . path . split ( '/' ) : [ ] ;
463492
464- if ( url ) {
465- // Root of a branch/commit/tag
466- return / ^ t r e e \/ [ ^ / ] + $ / . test ( repository . path ) ;
467- }
493+ switch ( path . length ) {
494+ case 0 : {
495+ // Absolute repo root: `isRepoHome`
496+ return true ;
497+ }
498+
499+ case 2 : {
500+ // 100% certainty that it's a root if it's `tree`
501+ return path [ 0 ] === 'tree' ;
502+ }
468503
469- // If we're checking the current page, add support for branches with slashes // #15 #24
470- return repository . path . startsWith ( 'tree/' ) && document . title . startsWith ( repository . nameWithOwner ) && ! document . title . endsWith ( repository . nameWithOwner ) ;
504+ default : {
505+ if ( url ) {
506+ // From the URL we can safely only know it's a root if it's `user/repo/tree/something`
507+ // With `user/repo/tree/something/else` we can't be sure whether `else` is a folder or still the branch name ("something/else")
508+ return false ;
509+ }
510+
511+ // If we're checking the current page, add support for branches with slashes
512+ const titleInfo = parseRepoExplorerTitle ( location . pathname , document . title ) ;
513+
514+ return titleInfo ?. filePath === '' ;
515+ }
516+ }
471517} ;
472518
473519// `_isRepoRoot` logic depends on whether a URL was passed, so don't use a `url` default parameter
@@ -857,4 +903,5 @@ export const utils = {
857903 getCleanPathname,
858904 getCleanGistPathname,
859905 getRepositoryInfo : getRepo ,
906+ parseRepoExplorerTitle,
860907} ;
0 commit comments