UNPKG

@pierre/diffs

Version:

872 lines (870 loc) 36.1 kB
import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, DEFAULT_EXPANDED_REGION, DEFAULT_RENDER_RANGE, DEFAULT_THEMES, DEFAULT_TOKENIZE_MAX_LENGTH } from "../constants.js"; import { FILE_ANNOTATION_HUNK_INDEX, FILE_ANNOTATION_LINE_INDEX, getFileAnnotations, shouldRenderFileAnnotations } from "../utils/includesFileAnnotations.js"; import { createGutterGap, createGutterItem, createGutterWrapper, createHastElement } from "../utils/hast_utils.js"; import { areLanguagesAttached } from "../highlighter/languages/areLanguagesAttached.js"; import { getHighlighterIfLoaded, getSharedHighlighter } from "../highlighter/shared_highlighter.js"; import { areThemesAttached } from "../highlighter/themes/areThemesAttached.js"; import { areRenderRangesEqual } from "../utils/areRenderRangesEqual.js"; import { createAnnotationElement } from "../utils/createAnnotationElement.js"; import { createContentColumn } from "../utils/createContentColumn.js"; import { createFileHeaderElement } from "../utils/createFileHeaderElement.js"; import { createPreElement } from "../utils/createPreElement.js"; import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js"; import { getHighlighterOptions } from "../utils/getHighlighterOptions.js"; import { getLineAnnotationName } from "../utils/getLineAnnotationName.js"; import { shouldUseTokenTransformer } from "../utils/shouldUseTokenTransformer.js"; import { areDiffTargetsEqual } from "../utils/areDiffTargetsEqual.js"; import { getTrailingContextRangeSize } from "../utils/virtualDiffLayout.js"; import { iterateOverDiff } from "../utils/iterateOverDiff.js"; import { areDiffRenderOptionsEqual } from "../utils/areDiffRenderOptionsEqual.js"; import { createEmptyRowBuffer } from "../utils/createEmptyRowBuffer.js"; import { createNoNewlineElement } from "../utils/createNoNewlineElement.js"; import { createSeparator } from "../utils/createSeparator.js"; import { getHunkSeparatorSlotName } from "../utils/getHunkSeparatorSlotName.js"; import { getTotalLineCountFromHunks } from "../utils/getTotalLineCountFromHunks.js"; import { isDefaultRenderRange } from "../utils/isDefaultRenderRange.js"; import { isDiffPlainText } from "../utils/isDiffPlainText.js"; import { renderDiffWithHighlighter } from "../utils/renderDiffWithHighlighter.js"; import { toHtml } from "hast-util-to-html"; //#region src/renderers/DiffHunksRenderer.ts let instanceId = -1; var DiffHunksRenderer = class { __id = `diff-hunks-renderer:${++instanceId}`; highlighter; diff; expandedHunks = /* @__PURE__ */ new Map(); deletionAnnotations = {}; additionAnnotations = {}; computedLang = "text"; renderCache; constructor(options = { theme: DEFAULT_THEMES }, onRenderUpdate, workerManager) { this.options = options; this.onRenderUpdate = onRenderUpdate; this.workerManager = workerManager; if (workerManager?.isWorkingPool() !== true) this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES) ? getHighlighterIfLoaded() : void 0; } cleanUp() { this.recycle(); this.expandedHunks.clear(); this.workerManager = void 0; this.onRenderUpdate = void 0; } recycle() { this.highlighter = void 0; this.diff = void 0; this.clearRenderCache(); this.additionAnnotations = {}; this.deletionAnnotations = {}; this.workerManager?.cleanUpTasks(this); } clearRenderCache() { this.renderCache = void 0; } setOptions(options) { this.options = options; } mergeOptions(options) { this.options = { ...this.options, ...options }; } expandHunk(index, direction, expansionLineCount = this.getOptionsWithDefaults().expansionLineCount) { const region = { ...this.expandedHunks.get(index) ?? { fromStart: 0, fromEnd: 0 } }; if (direction === "up" || direction === "both") region.fromStart += expansionLineCount; if (direction === "down" || direction === "both") region.fromEnd += expansionLineCount; if (this.renderCache?.highlighted !== true) this.clearRenderCache(); this.expandedHunks.set(index, region); } getExpandedHunk(hunkIndex) { return this.expandedHunks.get(hunkIndex) ?? DEFAULT_EXPANDED_REGION; } getExpandedHunksMap() { return this.expandedHunks; } setLineAnnotations(lineAnnotations) { this.additionAnnotations = {}; this.deletionAnnotations = {}; for (const annotation of lineAnnotations) { const map = (() => { switch (annotation.side) { case "deletions": return this.deletionAnnotations; case "additions": return this.additionAnnotations; } })(); const arr = map[annotation.lineNumber] ?? []; map[annotation.lineNumber] = arr; arr.push(annotation); } } getUnifiedLineDecoration({ lineType }) { return { gutterLineType: lineType }; } getSplitLineDecoration({ side, type }) { if (type !== "change") return { gutterLineType: type }; return { gutterLineType: side === "deletions" ? "change-deletion" : "change-addition" }; } createAnnotationElement = (span) => { return createAnnotationElement(span); }; getOptionsWithDefaults() { const { diffIndicators = "bars", diffStyle = "split", disableBackground = false, disableFileHeader = false, disableLineNumbers = false, disableVirtualizationBuffers = false, collapsed = false, expandUnchanged = false, collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, expansionLineCount = 100, hunkSeparators = "line-info", lineDiffType = "word-alt", maxLineDiffLength = 1e3, overflow = "scroll", stickyHeader = false, theme = DEFAULT_THEMES, headerRenderMode = "default", tokenizeMaxLineLength = 1e3, tokenizeMaxLength = DEFAULT_TOKENIZE_MAX_LENGTH, useTokenTransformer = false, useCSSClasses = false } = this.options; return { diffIndicators, diffStyle, disableBackground, disableFileHeader, disableLineNumbers, disableVirtualizationBuffers, collapsed, expandUnchanged, collapsedContextThreshold, expansionLineCount, hunkSeparators, lineDiffType, maxLineDiffLength, overflow, stickyHeader, theme: this.workerManager?.getDiffRenderOptions().theme ?? theme, headerRenderMode, tokenizeMaxLineLength, tokenizeMaxLength, useTokenTransformer, useCSSClasses }; } async initializeHighlighter() { this.highlighter = await getSharedHighlighter(getHighlighterOptions(this.computedLang, this.options)); return this.highlighter; } hydrate(diff) { if (diff == null) return; this.diff = diff; const { options } = this.getRenderOptions(diff); const massiveDiff = isDiffMassive(diff, this.getTokenizeMaxLength()); let cache = this.workerManager?.getDiffResultCache(diff); if (cache != null && !areDiffRenderOptionsEqual(options, cache.options)) cache = void 0; this.renderCache ??= { diff, highlighted: !massiveDiff && !isDiffPlainText(diff), options, result: massiveDiff ? void 0 : cache?.result, renderRange: void 0 }; if (this.workerManager?.isWorkingPool() === true) { if (this.renderCache.result == null && !massiveDiff) this.workerManager.highlightDiffAST(this, this.diff); } else if (this.highlighter == null) { this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name); this.initializeHighlighter(); } } getRenderOptions(diff) { const options = (() => { if (this.workerManager?.isWorkingPool() === true) return this.workerManager.getDiffRenderOptions(); const { theme, tokenizeMaxLineLength, lineDiffType, maxLineDiffLength } = this.getOptionsWithDefaults(); return { theme, useTokenTransformer: shouldUseTokenTransformer(this.options), tokenizeMaxLineLength, lineDiffType, maxLineDiffLength }; })(); this.getOptionsWithDefaults(); const { renderCache } = this; if (renderCache?.result == null) return { options, forceHighlight: true }; if (!areDiffTargetsEqual(diff, renderCache.diff) || !areDiffRenderOptionsEqual(options, renderCache.options)) return { options, forceHighlight: true }; return { options, forceHighlight: false }; } renderDiff(diff = this.renderCache?.diff, renderRange = DEFAULT_RENDER_RANGE) { if (diff == null) return; const { expandUnchanged = false, collapsedContextThreshold } = this.getOptionsWithDefaults(); let { options, forceHighlight } = this.getRenderOptions(diff); const cache = this.getMatchingWorkerResultCache(diff, options); if (cache != null && !this.hasHighlightedRenderCache(diff, options)) { this.renderCache = { diff, highlighted: true, renderRange: void 0, ...cache }; forceHighlight = false; } this.renderCache ??= { diff, highlighted: false, options, result: void 0, renderRange: void 0 }; const hasContent = diff.additionLines.length > 0 || diff.deletionLines.length > 0; const forcePlainText = !hasContent || isDiffPlainText(diff) || isDiffMassive(diff, this.getTokenizeMaxLength()); const newContent = !areDiffTargetsEqual(diff, this.renderCache.diff); const newRenderRange = !areRenderRangesEqual(this.renderCache.renderRange, renderRange); if (this.workerManager?.isWorkingPool() === true) { if (forcePlainText || this.renderCache.result == null || !this.renderCache.highlighted && (newContent || newRenderRange)) { this.renderCache.diff = diff; this.renderCache.options = options; this.renderCache.highlighted = false; if (this.renderCache.result == null || newContent || newRenderRange || forceHighlight) this.renderCache.result = this.workerManager.getPlainDiffAST(diff, renderRange.startingLine, renderRange.totalLines, isDefaultRenderRange(renderRange) ? true : expandUnchanged ? true : this.expandedHunks, collapsedContextThreshold); this.renderCache.renderRange = renderRange; } if (!forcePlainText && hasContent && (!this.renderCache.highlighted || forceHighlight)) this.workerManager.highlightDiffAST(this, diff); } else { this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name); const hasThemes = this.highlighter != null && areThemesAttached(options.theme); const hasLangs = this.highlighter != null && areLanguagesAttached(this.computedLang); const canHighlight = !forcePlainText && hasLangs; if (this.highlighter != null && hasThemes && (forceHighlight || forcePlainText || !this.renderCache.highlighted && canHighlight || this.renderCache.result == null)) { const { result, options: options$1 } = this.renderDiffWithHighlighter(diff, this.highlighter, forcePlainText || !hasLangs); this.renderCache = { diff, options: options$1, highlighted: canHighlight, result, renderRange: void 0 }; } if (!hasThemes || !forcePlainText && !hasLangs) this.asyncHighlight(diff).then(({ result, options: options$1 }) => { if (this.renderCache != null) this.renderCache.highlighted = false; this.onHighlightSuccess(diff, result, options$1, !forcePlainText); }); } return this.renderCache.result != null ? this.processDiffResult(this.renderCache.diff, renderRange, this.renderCache.result) : void 0; } async asyncRender(diff, renderRange = DEFAULT_RENDER_RANGE) { const { result } = await this.asyncHighlight(diff); return this.processDiffResult(diff, renderRange, result); } createPreElement(split, totalLines, customProperties) { const { diffIndicators, disableBackground, disableLineNumbers, overflow } = this.getOptionsWithDefaults(); return createPreElement({ type: "diff", diffIndicators, disableBackground, disableLineNumbers, overflow, split, totalLines, customProperties }); } async asyncHighlight(diff) { const forcePlainText = isDiffMassive(diff, this.getTokenizeMaxLength()); this.computedLang = forcePlainText ? "text" : diff.lang ?? getFiletypeFromFileName(diff.name); const hasThemes = this.highlighter != null && areThemesAttached(this.options.theme ?? DEFAULT_THEMES); const hasLangs = forcePlainText || this.highlighter != null && areLanguagesAttached(this.computedLang); if (this.highlighter == null || !hasThemes || !hasLangs) this.highlighter = await this.initializeHighlighter(); return this.renderDiffWithHighlighter(diff, this.highlighter, forcePlainText); } renderDiffWithHighlighter(diff, highlighter, forcePlainText = false) { const { options } = this.getRenderOptions(diff); const { collapsedContextThreshold } = this.getOptionsWithDefaults(); return { result: renderDiffWithHighlighter(diff, highlighter, options, { forcePlainText, expandedHunks: forcePlainText ? true : void 0, collapsedContextThreshold }), options }; } onHighlightSuccess(diff, result, options, highlighted = true) { if (this.renderCache == null) return; const triggerRenderUpdate = !this.renderCache.highlighted || !areDiffRenderOptionsEqual(this.renderCache.options, options) || !areDiffTargetsEqual(this.renderCache.diff, diff); this.renderCache = { diff, options, highlighted, result, renderRange: void 0 }; if (triggerRenderUpdate) this.onRenderUpdate?.(); } getMatchingWorkerResultCache(diff, options) { const cache = this.workerManager?.getDiffResultCache(diff); if (cache == null || !areDiffRenderOptionsEqual(options, cache.options)) return; return cache; } hasHighlightedRenderCache(diff, options) { const { renderCache } = this; return renderCache?.result != null && renderCache.highlighted && areDiffTargetsEqual(diff, renderCache.diff) && areDiffRenderOptionsEqual(options, renderCache.options); } onHighlightError(error) { console.error(error); } getTokenizeMaxLength() { return this.options.tokenizeMaxLength ?? DEFAULT_TOKENIZE_MAX_LENGTH; } processDiffResult(fileDiff, renderRange, { code, themeStyles, baseThemeType }) { const { diffStyle, disableFileHeader, expandUnchanged, expansionLineCount, collapsedContextThreshold, hunkSeparators } = this.getOptionsWithDefaults(); this.diff = fileDiff; const unified = diffStyle === "unified"; let additionsContentAST = []; let deletionsContentAST = []; let unifiedContentAST = []; const hunkData = []; const { additionLines, deletionLines } = code; const context = { rowCount: 0, hunkSeparators, additionsContentAST, deletionsContentAST, unifiedContentAST, unifiedGutterAST: createGutterWrapper(), deletionsGutterAST: createGutterWrapper(), additionsGutterAST: createGutterWrapper(), expansionLineCount, hunkData, incrementRowCount(count = 1) { context.rowCount += count; }, pushToGutter(type, element) { switch (type) { case "unified": context.unifiedGutterAST.children.push(element); break; case "deletions": context.deletionsGutterAST.children.push(element); break; case "additions": context.additionsGutterAST.children.push(element); break; } } }; const trailingRangeSize = getTrailingContextRangeSize({ fileDiff, errorPrefix: "DiffHunksRenderer.processDiffResult" }); const pendingSplitContext = { size: 0, side: void 0, increment() { this.size += 1; }, flush() { if (diffStyle === "unified") return; if (this.size <= 0 || this.side == null) { this.side = void 0; this.size = 0; return; } if (this.side === "additions") { context.pushToGutter("additions", createGutterGap(void 0, "buffer", this.size)); additionsContentAST?.push(createEmptyRowBuffer(this.size)); } else { context.pushToGutter("deletions", createGutterGap(void 0, "buffer", this.size)); deletionsContentAST?.push(createEmptyRowBuffer(this.size)); } this.size = 0; this.side = void 0; } }; const pushGutterLineNumber = (type, lineType, lineNumber, lineIndex, gutterProperties) => { context.pushToGutter(type, createGutterItem(lineType, lineNumber, lineIndex, gutterProperties)); }; function pushSeparators(props) { pendingSplitContext.flush(); if (diffStyle === "unified") pushSeparator("unified", props, context); else { pushSeparator("deletions", props, context); pushSeparator("additions", props, context); } } this.pushFileLevelAnnotations(fileDiff, diffStyle, renderRange, context); iterateOverDiff({ diff: fileDiff, diffStyle, startingLine: renderRange.startingLine, totalLines: renderRange.totalLines, expandedHunks: expandUnchanged ? true : this.expandedHunks, collapsedContextThreshold, callback: ({ hunkIndex, hunk, collapsedBefore, collapsedAfter, additionLine, deletionLine, type }) => { const splitLineIndex = deletionLine != null ? deletionLine.splitLineIndex : additionLine.splitLineIndex; const unifiedLineIndex = additionLine != null ? additionLine.unifiedLineIndex : deletionLine.unifiedLineIndex; if (diffStyle === "split" && type !== "change") pendingSplitContext.flush(); if (collapsedBefore > 0) pushSeparators({ hunkIndex, collapsedLines: collapsedBefore, rangeSize: Math.max(hunk?.collapsedBefore ?? 0, 0), hunkSpecs: hunk?.hunkSpecs, isFirstHunk: hunkIndex === 0, isLastHunk: false, isExpandable: !fileDiff.isPartial }); const lineIndex = diffStyle === "unified" ? unifiedLineIndex : splitLineIndex; const renderedLineContext = { type, hunkIndex, lineIndex, unifiedLineIndex, splitLineIndex, deletionLine, additionLine }; if (diffStyle === "unified") { const injectedRows = this.getUnifiedInjectedRowsForLine?.(renderedLineContext); if (injectedRows?.before != null) pushUnifiedInjectedRows(injectedRows.before, context); let deletionLineContent = deletionLine != null ? deletionLines[deletionLine.lineIndex] : void 0; let additionLineContent = additionLine != null ? additionLines[additionLine.lineIndex] : void 0; if (deletionLineContent == null && additionLineContent == null) { const errorMessage = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong"; console.error(errorMessage, { file: fileDiff.name }); throw new Error(errorMessage); } const lineType = type === "change" ? additionLine != null ? "change-addition" : "change-deletion" : type; const lineDecoration = this.getUnifiedLineDecoration({ type, lineType, additionLineIndex: additionLine?.lineIndex, deletionLineIndex: deletionLine?.lineIndex }); pushGutterLineNumber("unified", lineDecoration.gutterLineType, additionLine != null ? additionLine.lineNumber : deletionLine.lineNumber, `${unifiedLineIndex},${splitLineIndex}`, lineDecoration.gutterProperties); if (additionLineContent != null) additionLineContent = withContentProperties(additionLineContent, lineDecoration.contentProperties); else if (deletionLineContent != null) deletionLineContent = withContentProperties(deletionLineContent, lineDecoration.contentProperties); pushLineWithAnnotation({ diffStyle: "unified", type, deletionLine: deletionLineContent, additionLine: additionLineContent, unifiedSpan: this.getAnnotations("unified", deletionLine?.lineNumber, additionLine?.lineNumber, hunkIndex, lineIndex), createAnnotationElement: (span) => this.createAnnotationElement(span), context }); if (injectedRows?.after != null) pushUnifiedInjectedRows(injectedRows.after, context); } else { const injectedRows = this.getSplitInjectedRowsForLine?.(renderedLineContext); if (injectedRows?.before != null) pushSplitInjectedRows(injectedRows.before, context, pendingSplitContext); let deletionLineContent = deletionLine != null ? deletionLines[deletionLine.lineIndex] : void 0; let additionLineContent = additionLine != null ? additionLines[additionLine.lineIndex] : void 0; const deletionLineDecoration = this.getSplitLineDecoration({ side: "deletions", type, lineIndex: deletionLine?.lineIndex }); const additionLineDecoration = this.getSplitLineDecoration({ side: "additions", type, lineIndex: additionLine?.lineIndex }); if (deletionLineContent == null && additionLineContent == null) { const errorMessage = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong"; console.error(errorMessage, { file: fileDiff.name }); throw new Error(errorMessage); } const missingSide = (() => { if (type === "change") { if (additionLineContent == null) return "additions"; else if (deletionLineContent == null) return "deletions"; } })(); if (missingSide != null) { if (pendingSplitContext.side != null && pendingSplitContext.side !== missingSide) throw new Error("DiffHunksRenderer.processDiffResult: iterateOverDiff, invalid pending splits"); pendingSplitContext.side = missingSide; pendingSplitContext.increment(); } const annotationSpans = this.getAnnotations("split", deletionLine?.lineNumber, additionLine?.lineNumber, hunkIndex, lineIndex); if (annotationSpans != null && pendingSplitContext.size > 0) pendingSplitContext.flush(); if (deletionLine != null) { const deletionLineDecorated = withContentProperties(deletionLineContent, deletionLineDecoration.contentProperties); pushGutterLineNumber("deletions", deletionLineDecoration.gutterLineType, deletionLine.lineNumber, `${deletionLine.unifiedLineIndex},${splitLineIndex}`, deletionLineDecoration.gutterProperties); if (deletionLineDecorated != null) deletionLineContent = deletionLineDecorated; } if (additionLine != null) { const additionLineDecorated = withContentProperties(additionLineContent, additionLineDecoration.contentProperties); pushGutterLineNumber("additions", additionLineDecoration.gutterLineType, additionLine.lineNumber, `${additionLine.unifiedLineIndex},${splitLineIndex}`, additionLineDecoration.gutterProperties); if (additionLineDecorated != null) additionLineContent = additionLineDecorated; } pushLineWithAnnotation({ diffStyle: "split", type, additionLine: additionLineContent, deletionLine: deletionLineContent, ...annotationSpans, createAnnotationElement: (span) => this.createAnnotationElement(span), context }); if (injectedRows?.after != null) pushSplitInjectedRows(injectedRows.after, context, pendingSplitContext); } const isFinalSplitHunkRow = diffStyle === "split" && hunk != null && splitLineIndex === hunk.splitLineStart + hunk.splitLineCount - 1; const splitNoEOFCRDeletion = isFinalSplitHunkRow ? hunk.noEOFCRDeletions : false; const splitNoEOFCRAddition = isFinalSplitHunkRow ? hunk.noEOFCRAdditions : false; const noEOFCRDeletion = (deletionLine?.noEOFCR ?? false) || splitNoEOFCRDeletion; const noEOFCRAddition = (additionLine?.noEOFCR ?? false) || splitNoEOFCRAddition; if (noEOFCRAddition || noEOFCRDeletion) { if (diffStyle === "split") pendingSplitContext.flush(); if (noEOFCRDeletion) { const noEOFType = type === "context" || type === "context-expanded" ? type : "change-deletion"; if (diffStyle === "unified") { context.unifiedContentAST.push(createNoNewlineElement(noEOFType)); context.pushToGutter("unified", createGutterGap(noEOFType, "metadata", 1)); } else { context.deletionsContentAST.push(createNoNewlineElement(noEOFType)); context.pushToGutter("deletions", createGutterGap(noEOFType, "metadata", 1)); if (!noEOFCRAddition) { context.pushToGutter("additions", createGutterGap(void 0, "buffer", 1)); context.additionsContentAST.push(createEmptyRowBuffer(1)); } } } if (noEOFCRAddition) { const noEOFType = type === "context" || type === "context-expanded" ? type : "change-addition"; if (diffStyle === "unified") { context.unifiedContentAST.push(createNoNewlineElement(noEOFType)); context.pushToGutter("unified", createGutterGap(noEOFType, "metadata", 1)); } else { context.additionsContentAST.push(createNoNewlineElement(noEOFType)); context.pushToGutter("additions", createGutterGap(noEOFType, "metadata", 1)); if (!noEOFCRDeletion) { context.pushToGutter("deletions", createGutterGap(void 0, "buffer", 1)); context.deletionsContentAST.push(createEmptyRowBuffer(1)); } } } context.incrementRowCount(1); } if (collapsedAfter > 0 && hunkSeparators !== "simple") pushSeparators({ hunkIndex: type === "context-expanded" ? hunkIndex : hunkIndex + 1, collapsedLines: collapsedAfter, rangeSize: trailingRangeSize, hunkSpecs: void 0, isFirstHunk: false, isLastHunk: true, isExpandable: !fileDiff.isPartial }); context.incrementRowCount(1); } }); if (diffStyle === "split") pendingSplitContext.flush(); const totalLines = Math.max(getTotalLineCountFromHunks(fileDiff.hunks), fileDiff.additionLines.length ?? 0, fileDiff.deletionLines.length ?? 0); const hasBuffer = renderRange.bufferBefore > 0 || renderRange.bufferAfter > 0; const shouldIncludeAdditions = !unified && fileDiff.type !== "deleted"; const shouldIncludeDeletions = !unified && fileDiff.type !== "new"; const hasContent = context.rowCount > 0 || hasBuffer; additionsContentAST = shouldIncludeAdditions && hasContent ? additionsContentAST : void 0; deletionsContentAST = shouldIncludeDeletions && hasContent ? deletionsContentAST : void 0; unifiedContentAST = unified && hasContent ? unifiedContentAST : void 0; const preNode = this.createPreElement(deletionsContentAST != null && additionsContentAST != null, totalLines); return { unifiedGutterAST: unified && hasContent ? context.unifiedGutterAST.children : void 0, unifiedContentAST, deletionsGutterAST: shouldIncludeDeletions && hasContent ? context.deletionsGutterAST.children : void 0, deletionsContentAST, additionsGutterAST: shouldIncludeAdditions && hasContent ? context.additionsGutterAST.children : void 0, additionsContentAST, hunkData, preNode, themeStyles, baseThemeType, headerElement: !disableFileHeader ? this.renderHeader(this.diff) : void 0, totalLines, rowCount: context.rowCount, bufferBefore: renderRange.bufferBefore, bufferAfter: renderRange.bufferAfter, css: "" }; } renderCodeAST(type, result) { const gutterAST = type === "unified" ? result.unifiedGutterAST : type === "deletions" ? result.deletionsGutterAST : result.additionsGutterAST; const contentAST = type === "unified" ? result.unifiedContentAST : type === "deletions" ? result.deletionsContentAST : result.additionsContentAST; if (gutterAST == null || contentAST == null) return; const gutter = createGutterWrapper(gutterAST); gutter.properties.style = `grid-row: span ${result.rowCount}`; return [gutter, createContentColumn(contentAST, result.rowCount)]; } renderFullAST(result, children = []) { const containerSize = this.getOptionsWithDefaults().hunkSeparators === "line-info"; const unifiedAST = this.renderCodeAST("unified", result); if (unifiedAST != null) { children.push(createHastElement({ tagName: "code", children: unifiedAST, properties: { "data-code": "", "data-container-size": containerSize ? "" : void 0, "data-unified": "" } })); return { ...result.preNode, children }; } const deletionsAST = this.renderCodeAST("deletions", result); if (deletionsAST != null) children.push(createHastElement({ tagName: "code", children: deletionsAST, properties: { "data-code": "", "data-container-size": containerSize ? "" : void 0, "data-deletions": "" } })); const additionsAST = this.renderCodeAST("additions", result); if (additionsAST != null) children.push(createHastElement({ tagName: "code", children: additionsAST, properties: { "data-code": "", "data-container-size": containerSize ? "" : void 0, "data-additions": "" } })); return { ...result.preNode, children }; } renderFullHTML(result, tempChildren = []) { return toHtml(this.renderFullAST(result, tempChildren)); } renderPartialHTML(children, columnType) { if (columnType == null) return toHtml(children); return toHtml(createHastElement({ tagName: "code", children, properties: { "data-code": "", "data-container-size": this.getOptionsWithDefaults().hunkSeparators === "line-info" ? "" : void 0, [`data-${columnType}`]: "" } })); } pushFileLevelAnnotations(fileDiff, diffStyle, renderRange, context) { if (!shouldRenderFileAnnotations(renderRange)) return; const deletionAnnotationNames = fileDiff.type !== "new" ? getAnnotationNames(getFileAnnotations(this.deletionAnnotations)) : []; const additionAnnotationNames = fileDiff.type !== "deleted" ? getAnnotationNames(getFileAnnotations(this.additionAnnotations)) : []; if (deletionAnnotationNames.length === 0 && additionAnnotationNames.length === 0) return; const hunkIndex = FILE_ANNOTATION_HUNK_INDEX; const lineIndex = FILE_ANNOTATION_LINE_INDEX; const { createAnnotationElement: createAnnotationElement$1 } = this; if (diffStyle === "unified") { pushLineWithAnnotation({ diffStyle, type: "context", unifiedSpan: { type: "annotation", hunkIndex, lineIndex, annotations: deletionAnnotationNames.concat(additionAnnotationNames) }, createAnnotationElement: createAnnotationElement$1, context }); return; } pushLineWithAnnotation({ diffStyle, type: "context", deletionSpan: { type: "annotation", hunkIndex, lineIndex, annotations: deletionAnnotationNames }, additionSpan: { type: "annotation", hunkIndex, lineIndex, annotations: additionAnnotationNames }, createAnnotationElement: createAnnotationElement$1, context }); } getAnnotations(type, deletionLineNumber, additionLineNumber, hunkIndex, lineIndex) { const deletionSpan = { type: "annotation", hunkIndex, lineIndex, annotations: [] }; if (deletionLineNumber != null) for (const anno of this.deletionAnnotations[deletionLineNumber] ?? []) deletionSpan.annotations.push(getLineAnnotationName(anno)); const additionSpan = { type: "annotation", hunkIndex, lineIndex, annotations: [] }; if (additionLineNumber != null) for (const anno of this.additionAnnotations[additionLineNumber] ?? []) (type === "unified" ? deletionSpan : additionSpan).annotations.push(getLineAnnotationName(anno)); if (type === "unified") { if (deletionSpan.annotations.length > 0) return deletionSpan; return; } if (additionSpan.annotations.length === 0 && deletionSpan.annotations.length === 0) return; return { deletionSpan, additionSpan }; } renderHeader(diff) { const { headerRenderMode, stickyHeader } = this.getOptionsWithDefaults(); return createFileHeaderElement({ fileOrDiff: diff, mode: headerRenderMode, stickyHeader }); } }; function getAnnotationNames(annotations) { return annotations?.map((annotation) => getLineAnnotationName(annotation)) ?? []; } function getModifiedLinesString(lines) { return `${lines} unmodified line${lines > 1 ? "s" : ""}`; } function pushUnifiedInjectedRows(rows, context) { for (const row of rows) { context.unifiedContentAST.push(row.content); context.pushToGutter("unified", row.gutter); context.incrementRowCount(1); } } function pushSplitInjectedRows(rows, context, pendingSplitContext) { for (const { deletion, addition } of rows) { if (deletion == null && addition == null) continue; const missingSide = deletion != null && addition != null ? void 0 : deletion == null ? "deletions" : "additions"; if (missingSide == null || pendingSplitContext.side !== missingSide) pendingSplitContext.flush(); if (deletion != null) { context.deletionsContentAST.push(deletion.content); context.pushToGutter("deletions", deletion.gutter); } if (addition != null) { context.additionsContentAST.push(addition.content); context.pushToGutter("additions", addition.gutter); } if (missingSide != null) { pendingSplitContext.side = missingSide; pendingSplitContext.increment(); } context.incrementRowCount(1); } } function pushLineWithAnnotation({ diffStyle, type, deletionLine, additionLine, unifiedSpan, deletionSpan, additionSpan, createAnnotationElement: createAnnotationElement$1, context }) { let hasAnnotationRow = false; if (diffStyle === "unified") { if (additionLine != null) context.unifiedContentAST.push(additionLine); else if (deletionLine != null) context.unifiedContentAST.push(deletionLine); if (unifiedSpan != null) { const lineType = type === "change" ? deletionLine != null ? "change-deletion" : "change-addition" : type; context.unifiedContentAST.push(createAnnotationElement$1(unifiedSpan)); context.pushToGutter("unified", createGutterGap(lineType, "annotation", 1)); hasAnnotationRow = true; } } else if (diffStyle === "split") { if (deletionLine != null) context.deletionsContentAST.push(deletionLine); if (additionLine != null) context.additionsContentAST.push(additionLine); if (deletionSpan != null) { const lineType = type === "change" ? deletionLine != null ? "change-deletion" : "context" : type; context.deletionsContentAST.push(createAnnotationElement$1(deletionSpan)); context.pushToGutter("deletions", createGutterGap(lineType, "annotation", 1)); hasAnnotationRow = true; } if (additionSpan != null) { const lineType = type === "change" ? additionLine != null ? "change-addition" : "context" : type; context.additionsContentAST.push(createAnnotationElement$1(additionSpan)); context.pushToGutter("additions", createGutterGap(lineType, "annotation", 1)); hasAnnotationRow = true; } } if (hasAnnotationRow) context.incrementRowCount(1); } function pushSeparator(type, { hunkIndex, collapsedLines, rangeSize, hunkSpecs, isFirstHunk, isLastHunk, isExpandable }, context) { if (collapsedLines <= 0) return; const linesAST = type === "unified" ? context.unifiedContentAST : type === "deletions" ? context.deletionsContentAST : context.additionsContentAST; if (context.hunkSeparators === "metadata") { if (hunkSpecs != null) { context.pushToGutter(type, createSeparator({ type: "metadata", content: hunkSpecs, isFirstHunk, isLastHunk })); linesAST.push(createSeparator({ type: "metadata", content: hunkSpecs, isFirstHunk, isLastHunk })); if (type !== "additions") context.incrementRowCount(1); } return; } if (context.hunkSeparators === "simple") { if (hunkIndex > 0) { context.pushToGutter(type, createSeparator({ type: "simple", isFirstHunk, isLastHunk: false })); linesAST.push(createSeparator({ type: "simple", isFirstHunk, isLastHunk: false })); if (type !== "additions") context.incrementRowCount(1); } return; } const slotName = getHunkSeparatorSlotName(type, hunkIndex); const chunked = rangeSize > context.expansionLineCount; const expandIndex = isExpandable ? hunkIndex : void 0; context.pushToGutter(type, createSeparator({ type: context.hunkSeparators, content: getModifiedLinesString(collapsedLines), expandIndex, chunked, slotName, isFirstHunk, isLastHunk })); linesAST.push(createSeparator({ type: context.hunkSeparators, content: getModifiedLinesString(collapsedLines), expandIndex, chunked, slotName, isFirstHunk, isLastHunk })); if (type !== "additions") context.incrementRowCount(1); context.hunkData.push({ slotName, hunkIndex, lines: collapsedLines, type, expandable: isExpandable ? { up: !isFirstHunk, down: !isLastHunk, chunked } : void 0 }); } function withContentProperties(lineNode, contentProperties) { if (lineNode == null || lineNode.type !== "element" || contentProperties == null) return lineNode; return { ...lineNode, properties: { ...lineNode.properties, ...contentProperties } }; } function isDiffMassive(diff, tokenizeMaxLength) { return Math.max(diff.additionLines.length, diff.deletionLines.length) > tokenizeMaxLength; } //#endregion export { DiffHunksRenderer }; //# sourceMappingURL=DiffHunksRenderer.js.map