diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/features/prevent-link-loss.tsx (renamed from source/features/prevent-pr-commit-link-loss.tsx) | 31 | ||||
| -rw-r--r-- | source/github-helpers/index.ts | 25 | ||||
| -rw-r--r-- | source/github-helpers/prevent-link-loss.ts | 40 | ||||
| -rw-r--r-- | source/helpers/rgh-issue-link.tsx | 10 | ||||
| -rw-r--r-- | source/options-storage.ts | 3 | ||||
| -rw-r--r-- | source/refined-github.ts | 2 |
6 files changed, 76 insertions, 35 deletions
diff --git a/source/features/prevent-pr-commit-link-loss.tsx b/source/features/prevent-link-loss.tsx index 88191cd8..27445852 100644 --- a/source/features/prevent-pr-commit-link-loss.tsx +++ b/source/features/prevent-link-loss.tsx @@ -7,27 +7,42 @@ import * as pageDetect from 'github-url-detection'; import * as textFieldEdit from 'text-field-edit'; import features from '.'; -import {prCommitUrlRegex, preventPrCommitLinkLoss, prCompareUrlRegex, preventPrCompareLinkLoss} from '../github-helpers'; +import { + prCommitUrlRegex, + preventPrCommitLinkLoss, + prCompareUrlRegex, + preventPrCompareLinkLoss, + discussionUrlRegex, + preventDiscussionLinkLoss +} from '../github-helpers/prevent-link-loss'; +import createRghIssueLink from '../helpers/rgh-issue-link'; function handleButtonClick({delegateTarget: fixButton}: delegate.Event<MouseEvent, HTMLButtonElement>): void { const field = fixButton.form!.querySelector('textarea')!; textFieldEdit.replace(field, prCommitUrlRegex, preventPrCommitLinkLoss); textFieldEdit.replace(field, prCompareUrlRegex, preventPrCompareLinkLoss); + textFieldEdit.replace(field, discussionUrlRegex, preventDiscussionLinkLoss); fixButton.parentElement!.remove(); } function getUI(field: HTMLTextAreaElement): HTMLElement { - return select('.rgh-fix-pr-commit-links-container', field.form!) ?? ( - <div className="flash flash-warn mb-2 rgh-fix-pr-commit-links-container"> - <AlertIcon/> Your PR Commit link may be <a target="_blank" rel="noopener noreferrer" href="https://github.com/sindresorhus/refined-github/issues/2327">misinterpreted by GitHub.</a> - <button type="button" className="btn btn-sm primary flash-action rgh-fix-pr-commit-links">Fix link</button> + return select('.rgh-prevent-link-loss-container', field.form!) ?? ( + <div className="flash flash-warn mb-2 rgh-prevent-link-loss-container"> + <AlertIcon/> Your link may be misinterpreted by GitHub (see {createRghIssueLink(2327)}. + <button type="button" className="btn btn-sm primary flash-action rgh-prevent-link-loss">Fix link</button> </div> ); } -const updateUI = debounceFn(({delegateTarget: field}: delegate.Event<Event, HTMLTextAreaElement>): void => { +function isVulnerableToLinkLoss(value: string): boolean { // The replacement logic is not just in the regex, so it alone can't be used to detect the need for the replacement - if (field.value === field.value.replace(prCommitUrlRegex, preventPrCommitLinkLoss) && field.value === field.value.replace(prCompareUrlRegex, preventPrCompareLinkLoss)) { + return value !== value.replace(prCommitUrlRegex, preventPrCommitLinkLoss) || + value !== value.replace(prCompareUrlRegex, preventPrCompareLinkLoss) || + value !== value.replace(discussionUrlRegex, preventDiscussionLinkLoss); +} + +const updateUI = debounceFn(({delegateTarget: field}: delegate.Event<Event, HTMLTextAreaElement>): void => { + if (!isVulnerableToLinkLoss(field.value)) { getUI(field).remove(); } else if (pageDetect.isNewIssue() || pageDetect.isCompare()) { select('file-attachment', field.form!)!.append( @@ -42,7 +57,7 @@ const updateUI = debounceFn(({delegateTarget: field}: delegate.Event<Event, HTML function init(): void { delegate(document, 'form#new_issue textarea, form.js-new-comment-form textarea, textarea.comment-form-textarea', 'input', updateUI); - delegate(document, '.rgh-fix-pr-commit-links', 'click', handleButtonClick); + delegate(document, '.rgh-prevent-link-loss', 'click', handleButtonClick); } void features.add(__filebasename, { diff --git a/source/github-helpers/index.ts b/source/github-helpers/index.ts index 0dd648d8..eb63bdf7 100644 --- a/source/github-helpers/index.ts +++ b/source/github-helpers/index.ts @@ -89,31 +89,6 @@ export function getLatestVersionTag(tags: string[]): string { return latestVersion; } -const escapeRegex = (string: string): string => string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); -const prCommitPathnameRegex = /[/][^/]+[/][^/]+[/]pull[/](\d+)[/]commits[/]([\da-f]{7})[\da-f]{33}(?:#[\w-]+)?\b/; // eslint-disable-line unicorn/better-regex -export const prCommitUrlRegex = new RegExp('\\b' + escapeRegex(location.origin) + prCommitPathnameRegex.source, 'gi'); - -const prComparePathnameRegex = /[/][^/]+[/][^/]+[/]compare[/](.+)(#diff-[\da-fR-]+)/; // eslint-disable-line unicorn/better-regex -export const prCompareUrlRegex = new RegExp('\\b' + escapeRegex(location.origin) + prComparePathnameRegex.source, 'gi'); - -// To be used as replacer callback in string.replace() -export function preventPrCommitLinkLoss(url: string, pr: string, commit: string, index: number, fullText: string): string { - if (fullText[index + url.length] === ')') { - return url; - } - - return `[\`${commit}\` (#${pr})](${url})`; -} - -// To be used as replacer callback in string.replace() for compare links -export function preventPrCompareLinkLoss(url: string, compare: string, hash: string, index: number, fullText: string): string { - if (fullText[index + url.length] === ')') { - return url; - } - - return `[\`${compare}\`${hash.slice(0, 16)}](${url})`; -} - // https://github.com/idimetrix/text-case/blob/master/packages/upper-case-first/src/index.ts export function upperCaseFirst(input: string): string { return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase(); diff --git a/source/github-helpers/prevent-link-loss.ts b/source/github-helpers/prevent-link-loss.ts new file mode 100644 index 00000000..de7b570f --- /dev/null +++ b/source/github-helpers/prevent-link-loss.ts @@ -0,0 +1,40 @@ +const escapeRegex = (string: string): string => string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); +const prCommitPathnameRegex = /[/][^/]+[/][^/]+[/]pull[/](\d+)[/]commits[/]([\da-f]{7})[\da-f]{33}(?:#[\w-]+)?\b/; // eslint-disable-line unicorn/better-regex +export const prCommitUrlRegex = new RegExp('\\b' + escapeRegex(location.origin) + prCommitPathnameRegex.source, 'gi'); + +const prComparePathnameRegex = /[/][^/]+[/][^/]+[/]compare[/](.+)(#diff-[\da-fR-]+)/; // eslint-disable-line unicorn/better-regex +export const prCompareUrlRegex = new RegExp('\\b' + escapeRegex(location.origin) + prComparePathnameRegex.source, 'gi'); + +const discussionPathnameRegex = /[/][^/]+[/][^/]+[/]discussions[/](\d+)[?][^#\s]+(#discussioncomment-\w+)?\b/; // eslint-disable-line unicorn/better-regex +export const discussionUrlRegex = new RegExp('\\b' + escapeRegex(location.origin) + discussionPathnameRegex.source, 'gi'); + +// To be used as replacer callback in string.replace() for PR commit links +export function preventPrCommitLinkLoss(url: string, pr: string, commit: string, index: number, fullText: string): string { + if (fullText[index + url.length] === ')') { + return url; + } + + return `[\`${commit}\` (#${pr})](${url})`; +} + +// To be used as replacer callback in string.replace() for compare links +export function preventPrCompareLinkLoss(url: string, compare: string, hash: string, index: number, fullText: string): string { + if (fullText[index + url.length] === ')') { + return url; + } + + return `[\`${compare}\`${hash.slice(0, 16)}](${url})`; +} + +// To be used as replacer callback in string.replace() for discussion links +export function preventDiscussionLinkLoss(url: string, discussion: string, comment: string, index: number, fullText: string): string { + if (fullText[index + url.length] === ')') { + return url; + } + + if (comment) { + return `[#${discussion} (comment)](${url})`; + } + + return `[#${discussion}](${url})`; +} diff --git a/source/helpers/rgh-issue-link.tsx b/source/helpers/rgh-issue-link.tsx new file mode 100644 index 00000000..2bc0b869 --- /dev/null +++ b/source/helpers/rgh-issue-link.tsx @@ -0,0 +1,10 @@ +import React from 'dom-chef'; + +export default function createRghIssueLink(issueNumber: number | number): Element { + const issueLink = `https://github.com/sindresorhus/refined-github/issues/${issueNumber}`; + return ( + <a target="_blank" rel="noopener noreferrer" data-hovercard-type="issue" data-hovercard-url={issueLink + '/hovercard'} href={issueLink}> + #{issueNumber} + </a> + ); +} diff --git a/source/options-storage.ts b/source/options-storage.ts index 47d79300..b32e9ecb 100644 --- a/source/options-storage.ts +++ b/source/options-storage.ts @@ -20,7 +20,8 @@ const defaults = Object.assign({ // TODO[2021-10-01]: Drop classes `muted-link`, `link-gray`, `link-gray-dark`, `text-gray`, `text-gray-light`, `text-gray-dark`, `text-green`, `text-red` `text-blue` #4021 const migrations = [ featureWasRenamed('collapse-markdown-sections', 'collapse-wiki-sections'), // Merged in May - featureWasRenamed('separate-draft-pr-button', 'one-click-pr-or-gist'), + featureWasRenamed('separate-draft-pr-button', 'one-click-pr-or-gist'), // Merged in May + featureWasRenamed('prevent-pr-commit-link-loss', 'prevent-link-loss'), // Merged in May // Removed features will be automatically removed from the options as well OptionsSyncPerDomain.migrations.removeUnused diff --git a/source/refined-github.ts b/source/refined-github.ts index 97275fee..34dd99ec 100644 --- a/source/refined-github.ts +++ b/source/refined-github.ts @@ -174,7 +174,7 @@ import './features/batch-mark-files-as-viewed'; import './features/unwrap-useless-dropdowns'; import './features/linkify-notification-repository-header'; import './features/stop-redirecting-in-notification-bar'; -import './features/prevent-pr-commit-link-loss'; +import './features/prevent-link-loss'; import './features/first-published-tag-for-merged-pr'; import './features/show-associated-branch-prs-on-fork'; import './features/faster-reviews'; |
