summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
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.ts25
-rw-r--r--source/github-helpers/prevent-link-loss.ts40
-rw-r--r--source/helpers/rgh-issue-link.tsx10
-rw-r--r--source/options-storage.ts3
-rw-r--r--source/refined-github.ts2
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';