Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build:demo
- run: npm run test:demo
- run: grep -rq "/fregante/" ./demo/dist
# https://github.com/refined-github/github-url-detection/pull/161
name: Ensure that the demo is built correctly
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v3
with:
path: demo/dist/

Expand All @@ -42,4 +42,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v4
45 changes: 45 additions & 0 deletions index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,48 @@ test('getRepositoryInfo', () => {
});
}
});

test('parseRepoExplorerTitle', () => {
const parse = pageDetect.utils.parseRepoExplorerTitle;

assert.deepEqual(
parse('/eslint/js/tree/2.x', 'eslint/js at 2.x'),
{
nameWithOwner: 'eslint/js',
branch: '2.x',
filePath: '',
},
);
assert.deepEqual(
parse('/eslint/js/tree/2.x', 'js/ at 2.x · eslint/js'),
{
nameWithOwner: 'eslint/js',
branch: '2.x',
filePath: '',
},
);
assert.deepEqual(
parse('/eslint/js/tree/2.x/tools', 'js/tools at 2.x · eslint/js'),
{
nameWithOwner: 'eslint/js',
branch: '2.x',
filePath: 'tools',
},
);
assert.deepEqual(
parse('/eslint/js/tree/2.x/docs/ast', 'js/docs/ast at 2.x · eslint/js'),
{
nameWithOwner: 'eslint/js',
branch: '2.x',
filePath: 'docs/ast',
},
);
assert.deepEqual(
parse('https://github.com/eslint/js', 'only /tree/ URLs are supported'),
undefined,
);
assert.deepEqual(
parse('https://github.com/eslint/js/issues', 'irrelephant'),
undefined,
);
});
67 changes: 57 additions & 10 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,25 +449,71 @@ TEST: addTests('isRepoHome', [
'https://github.com/sindresorhus/refined-github?files=1',
]);

export type RepoExplorerInfo = {
nameWithOwner: string;
branch: string;
filePath: string;
};

// https://github.com/eslint/js/tree/2.x ->'eslint/js at 2.x'
// https://github.com/eslint/js/tree/2.x ->'js/ at 2.x · eslint/js'
// https://github.com/eslint/js/tree/2.x/tools -> 'js/tools at 2.x · eslint/js'
const titleParseRegex = /^(?:(?<nameWithOwner>[^ ]+) at (?<branch>[^ ]+)|[^/ ]+(?:\/(?<filePath>[^ ]*))? at (?<branch2>[^ ]+)(?: · (?<nameWithOwner2>[^ ]+))?)$/;
// TODO: Reuse regex group names on the next MAJOR version https://github.com/tc39/proposal-duplicate-named-capturing-groups/issues/4

const parseRepoExplorerTitle = (pathname: string, title: string): RepoExplorerInfo | undefined => {
const match = titleParseRegex.exec(title);
if (!match?.groups) {
return;
}

let {nameWithOwner, branch, filePath, nameWithOwner2, branch2} = match.groups;

nameWithOwner ??= nameWithOwner2;
branch ??= branch2;
filePath ??= '';

if (!nameWithOwner || !branch || !pathname.startsWith(`/${nameWithOwner}/tree/`)) {
return;
}

return {nameWithOwner, branch, filePath};
};

const _isRepoRoot = (url?: URL | HTMLAnchorElement | Location): boolean => {
const repository = getRepo(url ?? location);

if (!repository) {
// Not a repo
return false;
}

if (!repository.path) {
// Absolute repo root: `isRepoHome`
return true;
}
const path = repository.path ? repository.path.split('/') : [];

if (url) {
// Root of a branch/commit/tag
return /^tree\/[^/]+$/.test(repository.path);
}
switch (path.length) {
case 0: {
// Absolute repo root: `isRepoHome`
return true;
}

case 2: {
// 100% certainty that it's a root if it's `tree`
return path[0] === 'tree';
}

// If we're checking the current page, add support for branches with slashes // #15 #24
return repository.path.startsWith('tree/') && document.title.startsWith(repository.nameWithOwner) && !document.title.endsWith(repository.nameWithOwner);
default: {
if (url) {
// From the URL we can safely only know it's a root if it's `user/repo/tree/something`
// With `user/repo/tree/something/else` we can't be sure whether `else` is a folder or still the branch name ("something/else")
return false;
}

// If we're checking the current page, add support for branches with slashes
const titleInfo = parseRepoExplorerTitle(location.pathname, document.title);

return titleInfo?.filePath === '';
}
}
};

// `_isRepoRoot` logic depends on whether a URL was passed, so don't use a `url` default parameter
Expand Down Expand Up @@ -857,4 +903,5 @@ export const utils = {
getCleanPathname,
getCleanGistPathname,
getRepositoryInfo: getRepo,
parseRepoExplorerTitle,
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"build:esbuild": "esbuild index.ts --bundle --external:github-reserved-names --outdir=distribution --format=esm --drop-labels=TEST",
"build:typescript": "tsc --declaration --emitDeclarationOnly",
"build:demo": "vite build demo",
"try": "esbuild index.ts --bundle --global-name=x --format=iife | pbcopy && echo 'Copied to clipboard'",
"fix": "xo --fix",
"prepack": "npm run build",
"test": "run-p build test:* xo",
Expand Down