@@ -449,25 +449,71 @@ TEST: addTests('isRepoHome', [
449
449
'https://github.com/sindresorhus/refined-github?files=1' ,
450
450
] ) ;
451
451
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
+
452
483
const _isRepoRoot = ( url ?: URL | HTMLAnchorElement | Location ) : boolean => {
453
484
const repository = getRepo ( url ?? location ) ;
454
485
455
486
if ( ! repository ) {
487
+ // Not a repo
456
488
return false ;
457
489
}
458
490
459
- if ( ! repository . path ) {
460
- // Absolute repo root: `isRepoHome`
461
- return true ;
462
- }
491
+ const path = repository . path ? repository . path . split ( '/' ) : [ ] ;
463
492
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
+ }
468
503
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
+ }
471
517
} ;
472
518
473
519
// `_isRepoRoot` logic depends on whether a URL was passed, so don't use a `url` default parameter
@@ -857,4 +903,5 @@ export const utils = {
857
903
getCleanPathname,
858
904
getCleanGistPathname,
859
905
getRepositoryInfo : getRepo ,
906
+ parseRepoExplorerTitle,
860
907
} ;
0 commit comments