import { takeRightWhile } from 'lodash'; export function getSymbol(type) { if (type === 'new') return '+'; if (type === 'old') return '-'; return ''; } function getLineNumber(lineRange, key) { if (!lineRange || !key || !lineRange[key]) return ''; const { new_line: newLine, old_line: oldLine, type } = lineRange[key]; const otherKey = key === 'start' ? 'end' : 'start'; // By default we want to see the "old" or "left side" line number // The exception is if the "end" line is on the "right" side // `otherLineType` is only used if `type` is null to make sure the line // number relfects the "right" side number, if that is the side // the comment form is located on const otherLineType = !type ? lineRange[otherKey]?.type : null; const lineType = type || ''; let lineNumber = oldLine; if (lineType === 'new' || otherLineType === 'new') lineNumber = newLine; return (lineNumber && getSymbol(lineType) + lineNumber) || ''; } export function getStartLineNumber(lineRange) { return getLineNumber(lineRange, 'start'); } export function getEndLineNumber(lineRange) { return getLineNumber(lineRange, 'end'); } export function getLineClasses(line) { const symbol = typeof line === 'string' ? line.charAt(0) : getSymbol(line?.type); if (symbol !== '+' && symbol !== '-') return ''; return [ 'gl-px-1 gl-rounded-small gl-border-solid gl-border-1 gl-border-white', { 'gl-bg-green-100 gl-text-green-800': symbol === '+', 'gl-bg-red-100 gl-text-red-800': symbol === '-', }, ]; } export function commentLineOptions(diffLines, startingLine, lineCode, side = 'left') { const preferredSide = side === 'left' ? 'old_line' : 'new_line'; const fallbackSide = preferredSide === 'new_line' ? 'old_line' : 'new_line'; const notMatchType = l => l.type !== 'match'; const linesCopy = [...diffLines]; // don't mutate the argument const startingLineCode = startingLine.line_code; const currentIndex = linesCopy.findIndex(line => line.line_code === lineCode); // We're limiting adding comments to only lines above the current line // to make rendering simpler. Future interations will use a more // intuitive dragging interface that will make this unnecessary const upToSelected = linesCopy.slice(0, currentIndex + 1); // Only include the lines up to the first "Show unchanged lines" block // i.e. not a "match" type const lines = takeRightWhile(upToSelected, notMatchType); // If the selected line is "hidden" in an unchanged line block // or "above" the current group of lines add it to the array so // that the drop down is not defaulted to empty const selectedIndex = lines.findIndex(line => line.line_code === startingLineCode); if (selectedIndex < 0) lines.unshift(startingLine); return lines.map(l => { const { line_code, type, old_line, new_line } = l; return { value: { line_code, type, old_line, new_line }, text: `${getSymbol(type)}${l[preferredSide] || l[fallbackSide]}`, }; }); } export function formatLineRange(start, end) { const extractProps = ({ line_code, type, old_line, new_line }) => ({ line_code, type, old_line, new_line, }); return { start: extractProps(start), end: extractProps(end), }; } export function getCommentedLines(selectedCommentPosition, diffLines) { if (!selectedCommentPosition) { // This structure simplifies the logic that consumes this result // by keeping the returned shape the same and adjusting the bounds // to something unreachable. This way our component logic stays: // "if index between start and end" return { startLine: diffLines.length + 1, endLine: diffLines.length + 1, }; } const findLineCodeIndex = line => position => { return [position.line_code, position.left?.line_code, position.right?.line_code].includes( line.line_code, ); }; const { start, end } = selectedCommentPosition; const startLine = diffLines.findIndex(findLineCodeIndex(start)); const endLine = diffLines.findIndex(findLineCodeIndex(end)); return { startLine, endLine }; }