diff options
author | 2020-05-19 22:52:08 +0200 | |
---|---|---|
committer | 2020-05-19 22:52:08 +0200 | |
commit | f9d8b7a5a402e19b0cb16fd937e0f19c43a6e699 (patch) | |
tree | 0b7a3d6cc31c8975921a7d7fcf6c4bc7e0e020e2 /source/libs/utils.ts | |
parent | 508c93a3f4cf219f343d19b927ae0d07ec3ad7f8 (diff) | |
download | refined-github-f9d8b7a5a402e19b0cb16fd937e0f19c43a6e699.tar.gz refined-github-f9d8b7a5a402e19b0cb16fd937e0f19c43a6e699.tar.zst refined-github-f9d8b7a5a402e19b0cb16fd937e0f19c43a6e699.zip |
Meta: Reorganize utility functions (#3110)
Diffstat (limited to 'source/libs/utils.ts')
-rw-r--r-- | source/libs/utils.ts | 192 |
1 files changed, 0 insertions, 192 deletions
diff --git a/source/libs/utils.ts b/source/libs/utils.ts deleted file mode 100644 index 6ba75dd6..00000000 --- a/source/libs/utils.ts +++ /dev/null @@ -1,192 +0,0 @@ -import select from 'select-dom'; -import onetime from 'onetime'; -import stripIndent from 'strip-indent'; -import compareVersions from 'tiny-version-compare'; -import {isRepo, isPR, isIssue} from 'github-url-detection'; - -export function logError(id: FeatureID, error: Error | string, ...extras: unknown[]): void { - if (error instanceof TypeError && error.message === 'Object(...)(...) is null') { - error.message = 'The element wasn’t found, the selector needs to be updated.'; - } - - const message = typeof error === 'string' ? error : error.message; - - if (message.includes('token')) { - console.log(`ℹ️ Refined GitHub → ${id} →`, message); - return; - } - - // Don't change this to `throw Error` because Firefox doesn't show extensions' errors in the console. - // Use `return` after calling this function. - console.error( - `❌ Refined GitHub → ${id} →`, - error, - ...extras, - stripIndent(` - Search issue: https://github.com/sindresorhus/refined-github/issues?q=is%3Aissue+${encodeURIComponent(message)} - - Open an issue: https://github.com/sindresorhus/refined-github/issues/new?labels=bug&template=bug_report.md&title=${encodeURIComponent(`\`${id}\`: ${message}`)} - `) - ); -} - -export const getUsername = onetime(() => select('meta[name="user-login"]')!.getAttribute('content')!); - -export const getDiscussionNumber = (): string | undefined => { - if (isPR() || isIssue()) { - return getCleanPathname().split('/')[3]; - } - - return undefined; -}; - -export const pluralize = (count: number, single: string, plural: string, zero?: string): string => { - if (count === 0 && zero) { - return zero.replace('$$', '0'); - } - - if (count === 1) { - return single.replace('$$', '1'); - } - - return plural.replace('$$', String(count)); -}; - -// Drops leading and trailing slash to avoid /\/?/ everywhere -export const getCleanPathname = (): string => location.pathname.replace(/^\/|\/$/g, ''); - -// Parses a repo's subpage, e.g. -// '/user/repo/issues/' -> 'issues' -// '/user/repo/' -> '' -// returns undefined if the path is not a repo -export const getRepoPath = (): string | undefined => { - if (isRepo()) { - return getCleanPathname().split('/').slice(2).join('/'); - } - - return undefined; -}; - -export const replaceBranch = (currentBranch: string, newBranch: string): string => { - // `pageType` will be either `blob' or 'tree' - const [pageType, ...branchAndPathParts] = getRepoPath()!.split('/'); - - const newBranchRepoPath = branchAndPathParts.join('/').replace(currentBranch, newBranch); - - return `/${getRepoURL()}/${pageType}/${newBranchRepoPath}`; -}; - -/* Should work on `isRepoTree` `isBlame` `isSingleFile` `isCommitList` `isCompare` `isPRCommit` */ -export const getCurrentBranch = (): string => { - return select.last<HTMLLinkElement>('link[rel="alternate"]')! - .href - .split('/') - .slice(6) - .join('/') - .replace(/\.atom.*/, ''); -}; - -export const isFirefox = navigator.userAgent.includes('Firefox/'); - -export const getRepoURL = (): string => location.pathname.slice(1).split('/', 2).join('/').toLowerCase(); -export const getRepoGQL = (): string => { - const {ownerName, repoName} = getOwnerAndRepo(); - return `owner: "${ownerName!}", name: "${repoName!}"`; -}; - -export const getOwnerAndRepo = (): { - ownerName: string | undefined; - repoName: string | undefined; -} => { - const [, ownerName, repoName] = location.pathname.split('/', 3); - return {ownerName, repoName}; -}; - -export function getForkedRepo(): string | undefined { - return select<HTMLAnchorElement>('.fork-flag a')?.pathname.slice(1); -} - -export const parseTag = (tag: string): {version: string; namespace: string} => { - const [, namespace = '', version = ''] = /(?:(.*)@)?([^@]+)/.exec(tag) ?? []; - return {namespace, version}; -}; - -export function compareNames(username: string, realname: string): boolean { - return username.replace(/-/g, '').toLowerCase() === realname.normalize('NFD').replace(/[\u0300-\u036F\W.]/g, '').toLowerCase(); -} - -export async function poll<T>(callback: () => T, frequency: number): Promise<T> { - return new Promise(resolve => { - (function loop() { - const result = callback(); - if (result !== null && typeof result !== undefined) { - resolve(result); - } else { - setTimeout(loop, frequency); - } - })(); - }); -} - -/** - * Prepend `:scope >` to a single or group of css selectors. - * @param {string} selector A css selector. - */ -export function getScopedSelector(selector: string): string { - return selector.split(',').map(sub => `:scope > ${sub.trim()}`).join(','); -} - -export function looseParseInt(text: string): number { - return Number(text.replace(/\D+/g, '')); -} - -const validVersion = /^[vr]?\d+(?:\.\d+)+/; -const isPrerelease = /^[vr]?\d+(?:\.\d+)+(-\d)/; -export function getLatestVersionTag(tags: string[]): string { - // Some tags aren't valid versions; comparison is meaningless. - // Just use the latest tag returned by the API (reverse chronologically-sorted list) - if (!tags.every(tag => validVersion.test(tag))) { - return tags[0]; - } - - // Exclude pre-releases - let releases = tags.filter(tag => !isPrerelease.test(tag)); - if (releases.length === 0) { // They were all pre-releases; undo. - releases = tags; - } - - let latestVersion = releases[0]; - for (const release of releases) { - if (compareVersions(latestVersion, release) < 0) { - latestVersion = release; - } - } - - return latestVersion; -} - -export function parseRoute(pathname: string): string[] { - const [user, repository, route, ...next] = pathname.replace(/^\/|\/$/g, '').split('/'); - const parts = next.join('/'); - const currentBranch = getCurrentBranch(); - if (parts !== currentBranch && !parts.startsWith(currentBranch + '/')) { - throw new Error('The branch of the current page must match the branch in the `pathname` parameter'); - } - - const filePath = parts.replace(currentBranch + '/', ''); - return [ - '', - user, - repository, - route, - currentBranch, - filePath - ]; -} - -const escapeRegex = (string: string) => string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); -export const prCommitRegex = new RegExp(`\\b${escapeRegex(location.origin)}[/][^/]+[/][^/]+[/]pull[/]\\d+[/]commits[/][0-9a-f]{7,40}\\b(?! \\]|\\))`, 'gi'); - -export function preventPrCommitLinkBreak(comment: string) { - return comment.replace(prCommitRegex, '[$& ]($&)'); -} |