3.7 KB142 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {ExclusiveOr} from 'shared/typeUtils';
9import type {OneIndexedLineNumber} from './types';
10
11type Props = {
12 beforeLineNumber: number | null;
13 before: React.ReactFragment | null;
14 afterLineNumber: number | null;
15 after: React.ReactFragment | null;
16 rowType: SplitDiffRowType;
17 path: string;
18 unified: boolean;
19 openFileToLine?: (lineNumber: OneIndexedLineNumber) => unknown;
20};
21
22type SplitDiffRowType = 'add' | 'common' | 'modify' | 'remove' | 'expanded';
23
24export default function SplitDiffRow({
25 beforeLineNumber,
26 before,
27 afterLineNumber,
28 after,
29 rowType,
30 path,
31 unified,
32 openFileToLine,
33}: Props): [JSX.Element, JSX.Element, JSX.Element, JSX.Element] {
34 let beforeClass;
35 let afterClass;
36 switch (rowType) {
37 case 'remove':
38 beforeClass = 'patch-remove-line';
39 afterClass = undefined;
40 break;
41 case 'modify':
42 beforeClass = 'patch-remove-line';
43 afterClass = 'patch-add-line';
44 break;
45 case 'add':
46 beforeClass = undefined;
47 afterClass = 'patch-add-line';
48 break;
49 case 'common':
50 beforeClass = undefined;
51 afterClass = undefined;
52 break;
53 case 'expanded':
54 beforeClass = 'patch-expanded';
55 afterClass = 'patch-expanded';
56 break;
57 }
58
59 // Note that 'expanded' is a special case of 'common' where it is code that is
60 // common to both sides of the diff, but was previously displayed as
61 // collapsed. For whatever reason, GitHub does not make it possible to comment
62 // on lines outside of the patch contents in PRs:
63 //
64 // https://github.com/isaacs/github/issues/1655
65 //
66 // Even if you try to do so programmatically via the GraphQL API, it *still*
67 // doesn't work, so this seems to be some quirk in the underlying data model.
68 const canComment = rowType !== 'expanded';
69
70 return [
71 LineNumber({
72 className: beforeClass,
73 lineNumber: beforeLineNumber,
74 path,
75 side: 'LEFT',
76 column: 0,
77 canComment,
78 }),
79 <td data-column={unified ? 2 : 1} className={beforeClass}>
80 {before}
81 </td>,
82 LineNumber({
83 className: afterClass,
84 lineNumber: afterLineNumber,
85 path,
86 side: 'RIGHT',
87 column: unified ? 1 : 2,
88 canComment,
89 openFileToLine, // opening to a line number only makes sense on the "right" comparison side
90 }),
91 <td data-column={unified ? 2 : 3} className={afterClass}>
92 {after}
93 </td>,
94 ];
95}
96
97type LineNumberProps = {
98 className?: string;
99 lineNumber: number | null;
100 path: string;
101 side: 'LEFT' | 'RIGHT';
102 column: number;
103 canComment: boolean;
104 openFileToLine?: (lineNumber: OneIndexedLineNumber) => unknown;
105};
106
107function LineNumber({
108 className,
109 lineNumber,
110 path,
111 side,
112 column,
113 openFileToLine,
114}: LineNumberProps): JSX.Element {
115 const clickableLineNumber = openFileToLine != null && lineNumber != null;
116 const extraClassName =
117 (className != null ? ` ${className}-number` : '') + (clickableLineNumber ? ' clickable' : '');
118 return (
119 <td
120 className={`lineNumber${extraClassName} lineNumber-${side}`}
121 data-line-number={lineNumber}
122 data-path={path}
123 data-side={side}
124 data-column={column}
125 onClick={clickableLineNumber ? () => openFileToLine(lineNumber) : undefined}>
126 {lineNumber}
127 </td>
128 );
129}
130
131export function BlankLineNumber({before}: ExclusiveOr<{before: true}, {after: true}>) {
132 return (
133 <td
134 className={
135 before
136 ? 'patch-remove-line-number lineNumber lineNumber-LEFT'
137 : 'patch-add-line-number lineNumber lineNumber-RIGHT'
138 }
139 />
140 );
141}
142