github-url-detection 11.1.2 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/distribution/index.d.ts +53 -2
- package/distribution/index.js +36 -5
- package/package.json +2 -2
- package/readme.md +24 -0
package/distribution/index.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
/* Examples added by add-examples-to-dts.ts */
|
|
2
|
+
/**
|
|
3
|
+
* Waits for a detection to return true by repeatedly checking it on each animation frame.
|
|
4
|
+
* Useful for DOM-based detections that need to wait for elements to appear.
|
|
5
|
+
* @param detection - A detection function to check repeatedly
|
|
6
|
+
* @returns A promise that resolves to the final result of the detection
|
|
7
|
+
* @example
|
|
8
|
+
* ```
|
|
9
|
+
* import {utils} from 'github-url-detection';
|
|
10
|
+
*
|
|
11
|
+
* async function init() {
|
|
12
|
+
* if (!await utils.waitFor(isOrganizationProfile)) {
|
|
13
|
+
* return;
|
|
14
|
+
* }
|
|
15
|
+
* // Do something when on organization profile
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
declare function waitFor(detection: () => boolean): Promise<boolean>;
|
|
2
20
|
export declare const is404: () => boolean;
|
|
3
21
|
export declare const is500: () => boolean;
|
|
4
22
|
export declare const isPasswordConfirmation: () => boolean;
|
|
@@ -42,15 +60,16 @@ export declare const isCompare: (url?: URL | HTMLAnchorElement | Location) => bo
|
|
|
42
60
|
*/
|
|
43
61
|
export declare const isCompareWikiPage: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
44
62
|
/**
|
|
63
|
+
* @deprecated Use `isHome` and/or `isFeed` instead
|
|
64
|
+
*
|
|
45
65
|
* @example https://github.com///
|
|
46
66
|
* @example https://github.com//
|
|
47
67
|
* @example https://github.com/
|
|
48
68
|
* @example https://github.com
|
|
49
|
-
* @example https://github.com/orgs/
|
|
69
|
+
* @example https://github.com/orgs/refined-github/dashboard
|
|
50
70
|
* @example https://github.com/dashboard/index/2
|
|
51
71
|
* @example https://github.com//dashboard
|
|
52
72
|
* @example https://github.com/dashboard
|
|
53
|
-
* @example https://github.com/orgs/edit/dashboard
|
|
54
73
|
* @example https://github.big-corp.com/
|
|
55
74
|
* @example https://not-github.com/
|
|
56
75
|
* @example https://my-little-hub.com/
|
|
@@ -63,6 +82,29 @@ export declare const isCompareWikiPage: (url?: URL | HTMLAnchorElement | Locatio
|
|
|
63
82
|
* @example https://github.com/dashboard-feed
|
|
64
83
|
*/
|
|
65
84
|
export declare const isDashboard: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
85
|
+
/**
|
|
86
|
+
* @example https://github.com
|
|
87
|
+
* @example https://github.com//dashboard
|
|
88
|
+
* @example https://github.com///
|
|
89
|
+
* @example https://github.com//
|
|
90
|
+
* @example https://github.com/
|
|
91
|
+
* @example https://github.com/dashboard
|
|
92
|
+
* @example https://github.big-corp.com/
|
|
93
|
+
* @example https://not-github.com/
|
|
94
|
+
* @example https://my-little-hub.com/
|
|
95
|
+
* @example https://github.com/?tab=repositories
|
|
96
|
+
* @example https://github.com/?tab=stars
|
|
97
|
+
* @example https://github.com/?tab=followers
|
|
98
|
+
* @example https://github.com/?tab=following
|
|
99
|
+
* @example https://github.com/?tab=overview
|
|
100
|
+
* @example https://github.com?search=1
|
|
101
|
+
*/
|
|
102
|
+
export declare const isHome: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
103
|
+
/**
|
|
104
|
+
* @example https://github.com/feed
|
|
105
|
+
* @example https://github.com/orgs/refined-github/dashboard
|
|
106
|
+
*/
|
|
107
|
+
export declare const isFeed: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
66
108
|
/**
|
|
67
109
|
* @example https://github.big-corp.com/
|
|
68
110
|
* @example https://not-github.com/
|
|
@@ -274,6 +316,9 @@ export declare const hasWikiPageEditor: (url?: URL | HTMLAnchorElement | Locatio
|
|
|
274
316
|
export declare const isRepo: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
275
317
|
export declare const hasRepoHeader: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
276
318
|
export declare const isEmptyRepoRoot: () => boolean;
|
|
319
|
+
/**
|
|
320
|
+
* @deprecated Doesn't work anymore. Use `isEmptyRepoRoot` or API instead.
|
|
321
|
+
*/
|
|
277
322
|
export declare const isEmptyRepo: () => boolean;
|
|
278
323
|
export declare const isPublicRepo: () => boolean;
|
|
279
324
|
export declare const isArchivedRepo: () => boolean;
|
|
@@ -599,7 +644,11 @@ export declare const isNewAction: (url?: URL | HTMLAnchorElement | Location) =>
|
|
|
599
644
|
*/
|
|
600
645
|
export declare const isRepositoryActions: (url?: URL | HTMLAnchorElement | Location) => boolean;
|
|
601
646
|
export declare const isUserTheOrganizationOwner: () => boolean;
|
|
647
|
+
/**
|
|
648
|
+
* @deprecated Use canUserAccessRepoSettings or API instead.
|
|
649
|
+
*/
|
|
602
650
|
export declare const canUserAdminRepo: () => boolean;
|
|
651
|
+
export declare const canUserAccessRepoSettings: () => boolean;
|
|
603
652
|
/**
|
|
604
653
|
* @example https://github.com/new
|
|
605
654
|
* @example https://github.com/organizations/npmhub/repositories/new
|
|
@@ -636,4 +685,6 @@ export declare const utils: {
|
|
|
636
685
|
getCleanGistPathname: (url?: URL | HTMLAnchorElement | Location) => string | undefined;
|
|
637
686
|
getRepositoryInfo: (url?: URL | HTMLAnchorElement | Location | string) => RepositoryInfo | undefined;
|
|
638
687
|
parseRepoExplorerTitle: (pathname: string, title: string) => RepoExplorerInfo | undefined;
|
|
688
|
+
waitFor: typeof waitFor;
|
|
639
689
|
};
|
|
690
|
+
export {};
|
package/distribution/index.js
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
import reservedNames from "github-reserved-names/reserved-names.json" with { type: "json" };
|
|
3
3
|
var $ = (selector) => document.querySelector(selector);
|
|
4
4
|
var exists = (selector) => Boolean($(selector));
|
|
5
|
+
async function waitFor(detection) {
|
|
6
|
+
while (!detection() && document.readyState !== "complete") {
|
|
7
|
+
await new Promise((resolve) => {
|
|
8
|
+
requestAnimationFrame(resolve);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
return detection();
|
|
12
|
+
}
|
|
5
13
|
var is404 = () => /^(Page|File) not found · GitHub/.test(document.title);
|
|
6
14
|
var is500 = () => document.title === "Server Error \xB7 GitHub" || document.title === "Unicorn! \xB7 GitHub" || document.title === "504 Gateway Time-out";
|
|
7
15
|
var isPasswordConfirmation = () => document.title === "Confirm password" || document.title === "Confirm access";
|
|
@@ -13,6 +21,8 @@ var isRepoCommitList = (url = location) => Boolean(getRepo(url)?.path.startsWith
|
|
|
13
21
|
var isCompare = (url = location) => Boolean(getRepo(url)?.path.startsWith("compare"));
|
|
14
22
|
var isCompareWikiPage = (url = location) => isRepoWiki(url) && getCleanPathname(url).split("/").slice(3, 5).includes("_compare");
|
|
15
23
|
var isDashboard = (url = location) => !isGist(url) && /^$|^(orgs\/[^/]+\/)?dashboard(-feed)?(\/|$)/.test(getCleanPathname(url));
|
|
24
|
+
var isHome = (url = location) => !isGist(url) && /^$|^dashboard\/?$/.test(getCleanPathname(url));
|
|
25
|
+
var isFeed = (url = location) => !isGist(url) && /^(feed|orgs\/[^/]+\/dashboard)\/?$/.test(getCleanPathname(url));
|
|
16
26
|
var isEnterprise = (url = location) => url.hostname !== "github.com" && url.hostname !== "gist.github.com";
|
|
17
27
|
var isGist = (url = location) => typeof getCleanGistPathname(url) === "string";
|
|
18
28
|
var isGlobalIssueOrPRList = (url = location) => ["issues", "pulls"].includes(url.pathname.split("/", 2)[1]);
|
|
@@ -29,7 +39,11 @@ var isNewRelease = (url = location) => getRepo(url)?.path === "releases/new";
|
|
|
29
39
|
var isNewWikiPage = (url = location) => isRepoWiki(url) && getCleanPathname(url).endsWith("/_new");
|
|
30
40
|
var isNotifications = (url = location) => getCleanPathname(url) === "notifications";
|
|
31
41
|
var isOrganizationProfile = () => exists('meta[name="hovercard-subject-tag"][content^="organization"]');
|
|
32
|
-
var isOrganizationRepo = () => exists(
|
|
42
|
+
var isOrganizationRepo = () => exists([
|
|
43
|
+
'qbsearch-input[data-current-repository][data-current-org]:not([data-current-repository=""], [data-current-org=""])',
|
|
44
|
+
// TODO: Remove after June 2026
|
|
45
|
+
'.AppHeader-context-full [data-hovercard-type="organization"]'
|
|
46
|
+
].join(","));
|
|
33
47
|
var isTeamDiscussion = (url = location) => Boolean(getOrg(url)?.path.startsWith("teams"));
|
|
34
48
|
var isOwnUserProfile = () => getCleanPathname() === getLoggedInUser();
|
|
35
49
|
var isOwnOrganizationProfile = () => isOrganizationProfile() && !exists('[href*="contact/report-abuse?report="]');
|
|
@@ -82,7 +96,12 @@ var isRepo = (url = location) => {
|
|
|
82
96
|
return Boolean(user && repo && !reservedNames.includes(user) && !url.hostname.startsWith("gist.") && extra !== "generate");
|
|
83
97
|
};
|
|
84
98
|
var hasRepoHeader = (url = location) => isRepo(url) && !isRepoSearch(url);
|
|
85
|
-
var isEmptyRepoRoot = () => isRepoHome() &&
|
|
99
|
+
var isEmptyRepoRoot = () => isRepoHome() && exists([
|
|
100
|
+
// If you don't have write access
|
|
101
|
+
".blankslate-icon",
|
|
102
|
+
// If you have write access
|
|
103
|
+
"#empty-setup-clone-url"
|
|
104
|
+
].join(","));
|
|
86
105
|
var isEmptyRepo = () => exists('[aria-label="Cannot fork because repository is empty."]');
|
|
87
106
|
var isPublicRepo = () => exists('meta[name="octolytics-dimension-repository_public"][content="true"]');
|
|
88
107
|
var isArchivedRepo = () => Boolean(isRepo() && $("main > .flash-warn")?.textContent.includes("archived"));
|
|
@@ -163,7 +182,7 @@ var doesLookLikeAProfile = (string) => typeof string === "string" && string.leng
|
|
|
163
182
|
var isProfile = (url = location) => !isGist(url) && doesLookLikeAProfile(getCleanPathname(url));
|
|
164
183
|
var isGistProfile = (url = location) => doesLookLikeAProfile(getCleanGistPathname(url));
|
|
165
184
|
var isUserProfile = () => isProfile() && !isOrganizationProfile();
|
|
166
|
-
var isPrivateUserProfile = () => isUserProfile() &&
|
|
185
|
+
var isPrivateUserProfile = () => isUserProfile() && exists("#user-private-profile-frame");
|
|
167
186
|
var isUserProfileMainTab = () => isUserProfile() && !new URLSearchParams(location.search).has("tab");
|
|
168
187
|
var isUserProfileRepoTab = (url = location) => isProfile(url) && new URLSearchParams(url.search).get("tab") === "repositories";
|
|
169
188
|
var isUserProfileStarsTab = (url = location) => isProfile(url) && new URLSearchParams(url.search).get("tab") === "stars";
|
|
@@ -181,7 +200,15 @@ var isActionRun = (url = location) => /^(actions\/)?runs/.test(getRepo(url)?.pat
|
|
|
181
200
|
var isNewAction = (url = location) => getRepo(url)?.path === "actions/new";
|
|
182
201
|
var isRepositoryActions = (url = location) => /^actions(\/workflows\/.+\.ya?ml)?$/.test(getRepo(url)?.path);
|
|
183
202
|
var isUserTheOrganizationOwner = () => isOrganizationProfile() && exists('[aria-label="Organization"] [data-tab-item="org-header-settings-tab"]');
|
|
184
|
-
var canUserAdminRepo = () =>
|
|
203
|
+
var canUserAdminRepo = () => {
|
|
204
|
+
const repo = getRepo();
|
|
205
|
+
return Boolean(repo && exists(`:is(${[
|
|
206
|
+
".GlobalNav",
|
|
207
|
+
// Remove after June 2026
|
|
208
|
+
".js-repo-nav"
|
|
209
|
+
].join(",")}) a[href="/${repo.nameWithOwner}/settings"]`));
|
|
210
|
+
};
|
|
211
|
+
var canUserAccessRepoSettings = canUserAdminRepo;
|
|
185
212
|
var isNewRepo = (url = location) => !isGist(url) && (url.pathname === "/new" || /^organizations\/[^/]+\/repositories\/new$/.test(getCleanPathname(url)));
|
|
186
213
|
var isNewRepoTemplate = (url = location) => Boolean(url.pathname.split("/")[3] === "generate");
|
|
187
214
|
var getLoggedInUser = () => $('meta[name="user-login"]')?.getAttribute("content") ?? void 0;
|
|
@@ -232,9 +259,11 @@ var utils = {
|
|
|
232
259
|
getCleanPathname,
|
|
233
260
|
getCleanGistPathname,
|
|
234
261
|
getRepositoryInfo: getRepo,
|
|
235
|
-
parseRepoExplorerTitle
|
|
262
|
+
parseRepoExplorerTitle,
|
|
263
|
+
waitFor
|
|
236
264
|
};
|
|
237
265
|
export {
|
|
266
|
+
canUserAccessRepoSettings,
|
|
238
267
|
canUserAdminRepo,
|
|
239
268
|
hasCode,
|
|
240
269
|
hasComments,
|
|
@@ -270,6 +299,7 @@ export {
|
|
|
270
299
|
isEmptyRepo,
|
|
271
300
|
isEmptyRepoRoot,
|
|
272
301
|
isEnterprise,
|
|
302
|
+
isFeed,
|
|
273
303
|
isFileFinder,
|
|
274
304
|
isForkedRepo,
|
|
275
305
|
isForkingRepo,
|
|
@@ -279,6 +309,7 @@ export {
|
|
|
279
309
|
isGistRevision,
|
|
280
310
|
isGlobalIssueOrPRList,
|
|
281
311
|
isGlobalSearchResults,
|
|
312
|
+
isHome,
|
|
282
313
|
isIssue,
|
|
283
314
|
isIssueOrPRList,
|
|
284
315
|
isLabelList,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-url-detection",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.2.0",
|
|
4
4
|
"description": "Which GitHub page are you on? Is it an issue? Is it a list? Perfect for your WebExtension or userscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"xo": "xo"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"github-reserved-names": "^2.1.
|
|
45
|
+
"github-reserved-names": "^2.1.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@sindresorhus/tsconfig": "^8.1.0",
|
package/readme.md
CHANGED
|
@@ -67,6 +67,30 @@ if (pageDetect.isOrganizationProfile()) {
|
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
### Async detections with `waitFor`
|
|
71
|
+
|
|
72
|
+
The `waitFor` helper function allows you to wait for a detection to become true by repeatedly checking it on each animation frame. This is useful for DOM-based detections that need to wait for elements to appear before the document is fully loaded.
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
import {utils, isOrganizationProfile} from 'github-url-detection';
|
|
76
|
+
|
|
77
|
+
async function init() {
|
|
78
|
+
// Wait for the detection to return true or for the document to be complete
|
|
79
|
+
if (!await utils.waitFor(isOrganizationProfile)) {
|
|
80
|
+
return; // Not an organization profile
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// The page is now confirmed to be an organization profile
|
|
84
|
+
console.log('On organization profile!');
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The `waitFor` function:
|
|
89
|
+
- Repeatedly calls the detection function on each animation frame
|
|
90
|
+
- Stops when the detection returns `true` or when `document.readyState` is `'complete'`
|
|
91
|
+
- Returns the final result of the detection
|
|
92
|
+
- Works with any detection function that returns a boolean
|
|
93
|
+
|
|
70
94
|
## Related
|
|
71
95
|
|
|
72
96
|
- [github-reserved-names](https://github.com/Mottie/github-reserved-names) - Get a list, or check if a user or organization name is reserved by GitHub.
|