@pierre/diffs 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,19 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Diffs, from Pierre
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@pierre/diffs` is an open source diff and file rendering library built on
|
|
4
|
+
[Shiki](https://shiki.style/). It's super customizable and packed with the
|
|
5
|
+
features you need. Made with love by
|
|
6
|
+
[The Pierre Computer Company](https://pierre.computer). Available as vanilla
|
|
7
|
+
JavaScript and React components.
|
|
8
|
+
|
|
9
|
+
**View examples and read documentation on [Diffs.com](https://diffs.com).**
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Diff file versions, patches, and arbitrary files
|
|
14
|
+
- Split or stacked layout
|
|
15
|
+
- Automatically adapts to Shiki themes
|
|
16
|
+
- Supports light and dark mode
|
|
17
|
+
- Options for diff highlight styles, in-line highlighting, wrapping, line
|
|
18
|
+
numbers, and more
|
|
19
|
+
- Supports custom fonts and `font-feature-settings`
|
|
20
|
+
- Flexible annotation framework for injecting comments, annotations, and more
|
|
21
|
+
- Add your own accept/reject changes UI
|
|
22
|
+
- Select and highlight lines
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun i @pierre/diffs
|
|
28
|
+
```
|
|
4
29
|
|
|
5
30
|
## Development
|
|
6
31
|
|
|
7
|
-
|
|
32
|
+
Technically you can use the package manager of your choice, but we use
|
|
33
|
+
[bun](https://bun.sh/).
|
|
8
34
|
|
|
9
35
|
```bash
|
|
10
|
-
|
|
36
|
+
# From the root of the mono repo: setup dependencies
|
|
37
|
+
bun install
|
|
38
|
+
|
|
39
|
+
# Start the demo vite test server from root
|
|
40
|
+
bun run demo:dev
|
|
41
|
+
|
|
42
|
+
# To run the docs from root
|
|
43
|
+
bun run docs:dev
|
|
11
44
|
```
|
|
12
45
|
|
|
13
46
|
### Testing
|
|
14
47
|
|
|
15
48
|
```bash
|
|
16
|
-
# Run tests
|
|
49
|
+
# Run tests and related command from within the package directory
|
|
17
50
|
bun test
|
|
18
51
|
|
|
19
52
|
# Update snapshots
|
|
@@ -25,3 +58,40 @@ bun run tsc
|
|
|
25
58
|
|
|
26
59
|
Tests are located in the `test/` folder and use Bun's native testing framework
|
|
27
60
|
with snapshot support.
|
|
61
|
+
|
|
62
|
+
## Publishing
|
|
63
|
+
|
|
64
|
+
**Applicable to the Pierre team only.**
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# You may need to login with npm first:
|
|
68
|
+
npm login
|
|
69
|
+
|
|
70
|
+
# Always run publish from within the package directory
|
|
71
|
+
cd packages/diffs
|
|
72
|
+
bun publish
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Building Icons
|
|
76
|
+
|
|
77
|
+
**For Pierre team only.**
|
|
78
|
+
|
|
79
|
+
To build all our SVG icons from Figma there's a couple preparation steps that
|
|
80
|
+
you need to run first.
|
|
81
|
+
|
|
82
|
+
Perform a full export of all `Published Icons` the `Pierre Design` Figma file
|
|
83
|
+
|
|
84
|
+
Do this by selecting all the icons but not the art board and in the bottom right
|
|
85
|
+
click `Export XXX Layers` and make sure to point it to a `./svg` folder at the
|
|
86
|
+
root level of this project
|
|
87
|
+
|
|
88
|
+
Once that's done, simply run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bun run icons:build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This will run a full build of all the icons into
|
|
95
|
+
`./apps/docs/components/icons/icons`
|
|
96
|
+
|
|
97
|
+
Then make sure to check in any changes needed
|
|
@@ -150,14 +150,18 @@ var DiffHunksRenderer = class {
|
|
|
150
150
|
}
|
|
151
151
|
renderDiff(diff = this.renderCache?.diff) {
|
|
152
152
|
if (diff == null) return;
|
|
153
|
+
const cache = this.workerManager?.getDiffResultCache(diff);
|
|
154
|
+
if (cache != null && this.renderCache == null) this.renderCache = {
|
|
155
|
+
diff,
|
|
156
|
+
highlighted: true,
|
|
157
|
+
...cache
|
|
158
|
+
};
|
|
153
159
|
const { options, forceRender } = this.getRenderOptions(diff);
|
|
154
|
-
let cache = this.workerManager?.getDiffResultCache(diff);
|
|
155
|
-
if (cache != null && !areRenderOptionsEqual(options, cache.options)) cache = void 0;
|
|
156
160
|
this.renderCache ??= {
|
|
157
161
|
diff,
|
|
158
|
-
highlighted:
|
|
159
|
-
options
|
|
160
|
-
result:
|
|
162
|
+
highlighted: false,
|
|
163
|
+
options,
|
|
164
|
+
result: void 0
|
|
161
165
|
};
|
|
162
166
|
if (this.workerManager?.isWorkingPool() === true) {
|
|
163
167
|
this.renderCache.result ??= this.workerManager.getPlainDiffAST(diff);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffHunksRenderer.js","names":["EXPANDED_REGION: ExpansionRegion","options: BaseDiffOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options","options: RenderDiffOptions","additionsAST: ElementContent[] | undefined","deletionsAST: ElementContent[] | undefined","unifiedAST: ElementContent[] | undefined","hunkData: HunkData[]","prevHunk: Hunk | undefined","oldLine: ElementContent | undefined","newLine: ElementContent | undefined","oldLine","newLine","deletionSpan: AnnotationSpan","additionSpan: AnnotationSpan"],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport type {\n AnnotationLineMap,\n AnnotationSpan,\n BaseDiffOptions,\n DiffLineAnnotation,\n DiffsHighlighter,\n ExpansionDirections,\n FileDiffMetadata,\n Hunk,\n HunkData,\n RenderDiffFilesResult,\n RenderDiffHunksResult,\n RenderDiffOptions,\n RenderDiffResult,\n RenderedDiffASTCache,\n SupportedLanguages,\n ThemeTypes,\n ThemedDiffResult,\n} from '../types';\nimport { areThemesEqual } from '../utils/areThemesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createEmptyRowBuffer } from '../utils/createEmptyRowBuffer';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createNoNewlineElement } from '../utils/createNoNewlineElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { createSeparator } from '../utils/createSeparator';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getHunkSeparatorSlotName } from '../utils/getHunkSeparatorSlotName';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getTotalLineCountFromHunks } from '../utils/getTotalLineCountFromHunks';\nimport { createHastElement } from '../utils/hast_utils';\nimport { renderDiffWithHighlighter } from '../utils/renderDiffWithHighlighter';\nimport type { WorkerPoolManager } from '../worker';\n\nconst EXPANDED_REGION: ExpansionRegion = {\n fromStart: 0,\n fromEnd: 0,\n};\n\ninterface PushHunkSeparatorProps {\n type: 'additions' | 'deletions' | 'unified';\n linesAST: ElementContent[];\n}\n\ninterface RenderRangeProps {\n rangeLen: number;\n fromStart: boolean;\n}\n\ninterface PushLineWithAnnotation {\n newLine?: ElementContent;\n oldLine?: ElementContent;\n\n unifiedAST?: ElementContent[];\n deletionsAST?: ElementContent[];\n additionsAST?: ElementContent[];\n\n unifiedSpan?: AnnotationSpan;\n deletionSpan?: AnnotationSpan;\n additionSpan?: AnnotationSpan;\n}\n\ninterface RenderCollapsedHunksProps {\n ast: RenderDiffFilesResult | RenderDiffHunksResult;\n hunkData: HunkData[];\n hunkIndex: number;\n hunkSpecs: string | undefined;\n isFirstHunk: boolean;\n isLastHunk: boolean;\n rangeSize: number;\n\n lineIndex: number;\n additionLineNumber: number;\n deletionLineNumber: number;\n\n additionsAST: ElementContent[];\n deletionsAST: ElementContent[];\n unifiedAST: ElementContent[];\n}\n\ninterface RenderHunkProps {\n hunk: Hunk;\n hunkData: HunkData[];\n hunkIndex: number;\n lineIndex: number;\n isLastHunk: boolean;\n prevHunk: Hunk | undefined;\n\n ast: RenderDiffFilesResult | RenderDiffHunksResult;\n unifiedAST: ElementContent[];\n deletionsAST: ElementContent[];\n additionsAST: ElementContent[];\n}\n\ninterface GetRenderOptionsReturn {\n options: RenderDiffOptions;\n forceRender: boolean;\n}\n\ntype OptionsWithDefaults = Required<\n Omit<BaseDiffOptions, 'lang' | 'unsafeCSS'>\n>;\n\ninterface ExpansionRegion {\n fromStart: number;\n fromEnd: number;\n}\n\nexport interface HunksRenderResult {\n additionsAST: ElementContent[] | undefined;\n deletionsAST: ElementContent[] | undefined;\n unifiedAST: ElementContent[] | undefined;\n hunkData: HunkData[];\n css: string;\n preNode: HASTElement;\n headerElement: HASTElement | undefined;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n}\n\nexport class DiffHunksRenderer<LAnnotation = undefined> {\n private highlighter: DiffsHighlighter | undefined;\n private diff: FileDiffMetadata | undefined;\n\n private expandedHunks = new Map<number, ExpansionRegion>();\n\n private deletionAnnotations: AnnotationLineMap<LAnnotation> = {};\n private additionAnnotations: AnnotationLineMap<LAnnotation> = {};\n\n private computedLang: SupportedLanguages = 'text';\n private renderCache: RenderedDiffASTCache | undefined;\n\n constructor(\n public options: BaseDiffOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n cleanUp(): void {\n this.highlighter = undefined;\n this.diff = undefined;\n this.renderCache = undefined;\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n setOptions(options: BaseDiffOptions): void {\n this.options = options;\n }\n\n private mergeOptions(options: Partial<BaseDiffOptions>) {\n this.options = { ...this.options, ...options };\n }\n\n setThemeType(themeType: ThemeTypes): void {\n if (this.getOptionsWithDefaults().themeType === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n }\n\n expandHunk(index: number, direction: ExpansionDirections): void {\n const { expansionLineCount } = this.getOptionsWithDefaults();\n const region = this.expandedHunks.get(index) ?? {\n fromStart: 0,\n fromEnd: 0,\n };\n if (direction === 'up' || direction === 'both') {\n region.fromStart += expansionLineCount;\n }\n if (direction === 'down' || direction === 'both') {\n region.fromEnd += expansionLineCount;\n }\n this.expandedHunks.set(index, region);\n }\n\n setLineAnnotations(lineAnnotations: DiffLineAnnotation<LAnnotation>[]): void {\n this.additionAnnotations = {};\n this.deletionAnnotations = {};\n for (const annotation of lineAnnotations) {\n const map = ((): AnnotationLineMap<LAnnotation> => {\n switch (annotation.side) {\n case 'deletions':\n return this.deletionAnnotations;\n case 'additions':\n return this.additionAnnotations;\n }\n })();\n const arr = map[annotation.lineNumber] ?? [];\n map[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n getOptionsWithDefaults(): OptionsWithDefaults {\n const {\n diffIndicators = 'bars',\n diffStyle = 'split',\n disableBackground = false,\n disableFileHeader = false,\n disableLineNumbers = false,\n expandUnchanged = false,\n expansionLineCount = 100,\n hunkSeparators = 'line-info',\n lineDiffType = 'word-alt',\n maxLineDiffLength = 1000,\n overflow = 'scroll',\n theme = DEFAULT_THEMES,\n themeType = 'system',\n tokenizeMaxLineLength = 1000,\n useCSSClasses = false,\n } = this.options;\n return {\n diffIndicators,\n diffStyle,\n disableBackground,\n disableFileHeader,\n disableLineNumbers,\n expandUnchanged,\n expansionLineCount,\n hunkSeparators,\n lineDiffType,\n maxLineDiffLength,\n overflow,\n theme: this.workerManager?.getDiffRenderOptions().theme ?? theme,\n themeType,\n tokenizeMaxLineLength,\n useCSSClasses,\n };\n }\n\n async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n hydrate(diff: FileDiffMetadata | undefined): void {\n if (diff == null) {\n return;\n }\n this.diff = diff;\n const { options } = this.getRenderOptions(diff);\n let cache = this.workerManager?.getDiffResultCache(diff);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n diff,\n // NOTE(amadeus): If we're hydrating, we can assume there was\n // pre-rendered HTML, otherwise one should not be hydrating\n highlighted: true,\n options,\n result: cache?.result,\n };\n if (\n this.workerManager?.isWorkingPool() === true &&\n this.renderCache.result == null\n ) {\n this.workerManager.highlightDiffAST(this, this.diff);\n } else {\n void this.asyncHighlight(diff).then(({ result, options }) => {\n this.onHighlightSuccess(diff, result, options);\n });\n }\n }\n\n private getRenderOptions(diff: FileDiffMetadata): GetRenderOptionsReturn {\n const options: RenderDiffOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getDiffRenderOptions();\n }\n const { theme, tokenizeMaxLineLength, lineDiffType } =\n this.getOptionsWithDefaults();\n return { theme, tokenizeMaxLineLength, lineDiffType };\n })();\n this.getOptionsWithDefaults();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceRender: true };\n }\n if (\n diff !== renderCache.diff ||\n !areRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceRender: true };\n }\n return { options, forceRender: false };\n }\n\n renderDiff(\n diff: FileDiffMetadata | undefined = this.renderCache?.diff\n ): HunksRenderResult | undefined {\n if (diff == null) {\n return undefined;\n }\n const { options, forceRender } = this.getRenderOptions(diff);\n let cache = this.workerManager?.getDiffResultCache(diff);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n diff,\n highlighted: cache != null ? true : false,\n options: cache?.options ?? options,\n result: cache?.result,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n this.renderCache.result ??= this.workerManager.getPlainDiffAST(diff);\n if (!this.renderCache.highlighted || forceRender) {\n this.workerManager.highlightDiffAST(this, diff);\n }\n } else {\n this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceRender ||\n (!this.renderCache.highlighted && hasLangs) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderDiffWithHighlighter(\n diff,\n this.highlighter,\n !hasLangs\n );\n this.renderCache = {\n diff,\n options,\n highlighted: hasLangs,\n result,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || !hasLangs) {\n void this.asyncHighlight(diff).then(({ result, options }) => {\n this.onHighlightSuccess(diff, result, options);\n });\n }\n }\n return this.renderCache.result != null\n ? this.processDiffResult(this.renderCache.diff, this.renderCache.result)\n : undefined;\n }\n\n async asyncRender(diff: FileDiffMetadata): Promise<HunksRenderResult> {\n const { result } = await this.asyncHighlight(diff);\n return this.processDiffResult(diff, result);\n }\n\n private createPreElement(\n split: boolean,\n totalLines: number,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const {\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n themeType,\n } = this.getOptionsWithDefaults();\n return createPreElement({\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n themeStyles,\n split,\n themeType: baseThemeType ?? themeType,\n totalLines,\n });\n }\n\n private async asyncHighlight(\n diff: FileDiffMetadata\n ): Promise<RenderDiffResult> {\n this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name);\n const hasThemes =\n this.highlighter != null &&\n areThemesAttached(this.options.theme ?? DEFAULT_THEMES);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderDiffWithHighlighter(diff, this.highlighter);\n }\n\n private renderDiffWithHighlighter(\n diff: FileDiffMetadata,\n highlighter: DiffsHighlighter,\n plainText = false\n ): RenderDiffResult {\n const { options } = this.getRenderOptions(diff);\n const result = renderDiffWithHighlighter(\n diff,\n highlighter,\n options,\n plainText\n );\n return { result, options };\n }\n\n onHighlightSuccess(\n diff: FileDiffMetadata,\n result: ThemedDiffResult,\n options: RenderDiffOptions\n ): void {\n // If renderCache was blown away, we can assume we've run cleanUp()\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n this.renderCache.diff !== diff ||\n !this.renderCache.highlighted ||\n !areRenderOptionsEqual(this.renderCache.options, options);\n\n this.renderCache = {\n diff,\n options,\n highlighted: true,\n result,\n };\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private processDiffResult(\n fileDiff: FileDiffMetadata,\n { code, themeStyles, baseThemeType }: ThemedDiffResult\n ): HunksRenderResult {\n const { diffStyle, disableFileHeader } = this.getOptionsWithDefaults();\n\n this.diff = fileDiff;\n const unified = diffStyle === 'unified';\n\n let additionsAST: ElementContent[] | undefined = [];\n let deletionsAST: ElementContent[] | undefined = [];\n let unifiedAST: ElementContent[] | undefined = [];\n\n let hunkIndex = 0;\n const hunkData: HunkData[] = [];\n\n let prevHunk: Hunk | undefined;\n let lineIndex = 0;\n for (const hunk of fileDiff.hunks) {\n lineIndex += hunk.collapsedBefore;\n lineIndex = this.renderHunks({\n ast: code,\n hunk,\n prevHunk,\n hunkIndex,\n isLastHunk: hunkIndex === fileDiff.hunks.length - 1,\n additionsAST,\n deletionsAST,\n unifiedAST,\n hunkData,\n lineIndex,\n });\n hunkIndex++;\n prevHunk = hunk;\n }\n\n const totalLines = Math.max(\n getTotalLineCountFromHunks(fileDiff.hunks),\n fileDiff.newLines?.length ?? 0,\n fileDiff.oldLines?.length ?? 0\n );\n\n additionsAST =\n !unified && (code.hunks != null || code.newLines.length > 0)\n ? additionsAST\n : undefined;\n deletionsAST =\n !unified && (code.hunks != null || code.oldLines.length > 0)\n ? deletionsAST\n : undefined;\n unifiedAST = unifiedAST.length > 0 ? unifiedAST : undefined;\n\n const preNode = this.createPreElement(\n deletionsAST != null && additionsAST != null,\n totalLines,\n themeStyles,\n baseThemeType\n );\n\n return {\n additionsAST,\n deletionsAST,\n unifiedAST,\n hunkData,\n preNode,\n themeStyles,\n baseThemeType,\n headerElement: !disableFileHeader\n ? this.renderHeader(this.diff, themeStyles, baseThemeType)\n : undefined,\n totalLines,\n // FIXME\n css: '',\n };\n }\n\n renderFullAST(\n result: HunksRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n if (result.unifiedAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.unifiedAST,\n properties: {\n 'data-code': '',\n 'data-unified': '',\n },\n })\n );\n }\n if (result.deletionsAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.deletionsAST,\n properties: {\n 'data-code': '',\n 'data-deletions': '',\n },\n })\n );\n }\n if (result.additionsAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.additionsAST,\n properties: {\n 'data-code': '',\n 'data-additions': '',\n },\n })\n );\n }\n return { ...result.preNode, children };\n }\n\n renderFullHTML(\n result: HunksRenderResult,\n tempChildren: ElementContent[] = []\n ): string {\n return toHtml(this.renderFullAST(result, tempChildren));\n }\n\n renderPartialHTML(\n children: ElementContent[],\n columnType?: 'unified' | 'deletions' | 'additions'\n ): string {\n if (columnType == null) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: {\n 'data-code': '',\n [`data-${columnType}`]: '',\n },\n })\n );\n }\n\n private renderCollapsedHunks({\n ast,\n hunkData,\n hunkIndex,\n hunkSpecs,\n isFirstHunk,\n isLastHunk,\n rangeSize,\n lineIndex,\n additionLineNumber,\n deletionLineNumber,\n unifiedAST,\n deletionsAST,\n additionsAST,\n }: RenderCollapsedHunksProps) {\n if (rangeSize <= 0) {\n return;\n }\n const { hunkSeparators, expandUnchanged, diffStyle, expansionLineCount } =\n this.getOptionsWithDefaults();\n const expandable =\n ast.hunks == null && ast.newLines.length > 0 && ast.oldLines.length > 0;\n const expandedRegion = this.expandedHunks.get(hunkIndex) ?? EXPANDED_REGION;\n const chunked = rangeSize > expansionLineCount;\n const collapsedLines = Math.max(\n !expandUnchanged\n ? rangeSize - (expandedRegion.fromEnd + expandedRegion.fromStart)\n : 0,\n 0\n );\n\n const pushHunkSeparator = ({ type, linesAST }: PushHunkSeparatorProps) => {\n if (hunkSeparators === 'line-info' || hunkSeparators === 'custom') {\n const slotName = getHunkSeparatorSlotName(type, hunkIndex);\n linesAST.push(\n createSeparator({\n type: hunkSeparators,\n content: getModifiedLinesString(collapsedLines),\n expandIndex: expandable ? hunkIndex : undefined,\n chunked,\n slotName,\n isFirstHunk,\n isLastHunk,\n })\n );\n hunkData.push({\n slotName,\n hunkIndex,\n lines: collapsedLines,\n type,\n expandable: expandable\n ? {\n up: expandable && !isFirstHunk,\n down: expandable,\n chunked,\n }\n : undefined,\n });\n } else if (hunkSeparators === 'metadata' && hunkSpecs != null) {\n linesAST.push(\n createSeparator({\n type: 'metadata',\n content: hunkSpecs,\n isFirstHunk,\n isLastHunk,\n })\n );\n } else if (hunkSeparators === 'simple' && hunkIndex > 0) {\n linesAST.push(\n createSeparator({ type: 'simple', isFirstHunk, isLastHunk: false })\n );\n }\n };\n\n const renderRange = ({ rangeLen, fromStart }: RenderRangeProps) => {\n if (ast.newLines == null || ast.oldLines == null) {\n return;\n }\n\n const offset = isLastHunk ? 0 : fromStart ? rangeSize : rangeLen;\n let dLineNumber = deletionLineNumber - offset;\n let aLineNumber = additionLineNumber - offset;\n let lIndex = lineIndex - offset;\n\n for (let i = 0; i < rangeLen; i++) {\n const oldLine = ast.oldLines[dLineNumber];\n const newLine = ast.newLines[aLineNumber];\n if (oldLine == null || newLine == null) {\n console.error({ aLineNumber, dLineNumber, ast });\n throw new Error(\n 'DiffHunksRenderer.renderHunks prefill context invalid. Must include data for old and new lines'\n );\n }\n dLineNumber++;\n aLineNumber++;\n\n if (diffStyle === 'unified') {\n this.pushLineWithAnnotation({\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n dLineNumber,\n aLineNumber,\n hunkIndex,\n lIndex\n ),\n });\n } else {\n this.pushLineWithAnnotation({\n newLine,\n oldLine,\n additionsAST,\n deletionsAST,\n ...this.getAnnotations(\n 'split',\n dLineNumber,\n aLineNumber,\n hunkIndex,\n lIndex\n ),\n });\n }\n lIndex++;\n }\n };\n\n if (expandable) {\n renderRange({\n rangeLen: Math.min(\n collapsedLines === 0 || expandUnchanged\n ? rangeSize\n : expandedRegion.fromStart,\n rangeSize\n ),\n fromStart: true,\n });\n }\n\n if (collapsedLines > 0) {\n if (diffStyle === 'unified') {\n pushHunkSeparator({ type: 'unified', linesAST: unifiedAST });\n } else {\n pushHunkSeparator({ type: 'deletions', linesAST: deletionsAST });\n pushHunkSeparator({ type: 'additions', linesAST: additionsAST });\n }\n }\n\n if (collapsedLines > 0 && expandedRegion.fromEnd > 0 && !isLastHunk) {\n renderRange({\n rangeLen: Math.min(expandedRegion.fromEnd, rangeSize),\n fromStart: false,\n });\n }\n }\n\n private renderHunks({\n hunk,\n hunkData,\n hunkIndex,\n lineIndex,\n isLastHunk,\n prevHunk,\n ast,\n deletionsAST,\n additionsAST,\n unifiedAST,\n }: RenderHunkProps): number {\n const { diffStyle } = this.getOptionsWithDefaults();\n const unified = diffStyle === 'unified';\n let additionLineNumber = hunk.additionStart - 1;\n let deletionLineNumber = hunk.deletionStart - 1;\n\n this.renderCollapsedHunks({\n additionLineNumber,\n additionsAST,\n ast,\n deletionLineNumber,\n deletionsAST,\n hunkData,\n hunkIndex,\n hunkSpecs: hunk.hunkSpecs,\n isFirstHunk: prevHunk == null,\n isLastHunk: false,\n lineIndex,\n rangeSize: Math.max(hunk.collapsedBefore, 0),\n unifiedAST,\n });\n\n let { oldLines, newLines, oldIndex, newIndex } = (() => {\n if (ast.hunks != null) {\n const lineHunk = ast.hunks[hunkIndex];\n if (lineHunk == null) {\n console.error({ ast, hunkIndex });\n throw new Error(\n `DiffHunksRenderer.renderHunks: lineHunk doesn't exist`\n );\n }\n return {\n oldLines: lineHunk.oldLines,\n newLines: lineHunk.newLines,\n oldIndex: 0,\n newIndex: 0,\n };\n }\n return {\n oldLines: ast.oldLines,\n newLines: ast.newLines,\n oldIndex: deletionLineNumber,\n newIndex: additionLineNumber,\n };\n })();\n\n // Render hunk/diff content\n for (const hunkContent of hunk.hunkContent) {\n if (hunkContent.type === 'context') {\n const { length: len } = hunkContent.lines;\n for (let i = 0; i < len; i++) {\n const oldLine = oldLines[oldIndex];\n const newLine = newLines[newIndex];\n oldIndex++;\n newIndex++;\n additionLineNumber++;\n deletionLineNumber++;\n if (unified) {\n if (newLine == null) {\n throw new Error(\n 'DiffHunksRenderer.renderHunks: newLine doesnt exist for context...'\n );\n }\n this.pushLineWithAnnotation({\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n deletionLineNumber,\n additionLineNumber,\n hunkIndex,\n lineIndex\n ),\n });\n } else {\n if (newLine == null || oldLine == null) {\n throw new Error(\n 'DiffHunksRenderer.renderHunks: newLine or oldLine doesnt exist for context...'\n );\n }\n this.pushLineWithAnnotation({\n oldLine,\n newLine,\n deletionsAST,\n additionsAST,\n ...this.getAnnotations(\n 'split',\n deletionLineNumber,\n additionLineNumber,\n hunkIndex,\n lineIndex\n ),\n });\n }\n lineIndex++;\n }\n if (hunkContent.noEOFCR) {\n const node = createNoNewlineElement('context');\n if (unified) {\n unifiedAST.push(node);\n } else {\n deletionsAST.push(node);\n additionsAST.push(node);\n }\n }\n } else {\n const { length: dLen } = hunkContent.deletions;\n const { length: aLen } = hunkContent.additions;\n const len = unified ? dLen + aLen : Math.max(dLen, aLen);\n let spanSize = 0;\n for (let i = 0; i < len; i++) {\n const { oldLine, newLine } = (() => {\n let oldLine: ElementContent | undefined = oldLines[oldIndex];\n let newLine: ElementContent | undefined = newLines[newIndex];\n if (unified) {\n if (i < dLen) {\n newLine = undefined;\n } else {\n oldLine = undefined;\n }\n } else {\n if (i >= dLen) {\n oldLine = undefined;\n }\n if (i >= aLen) {\n newLine = undefined;\n }\n }\n if (oldLine == null && newLine == null) {\n console.error({ i, len, ast, hunkContent });\n throw new Error(\n 'renderHunks: oldLine and newLine are null, something is wrong'\n );\n }\n return { oldLine, newLine };\n })();\n\n if (oldLine != null) {\n oldIndex++;\n deletionLineNumber++;\n }\n if (newLine != null) {\n newIndex++;\n additionLineNumber++;\n }\n\n if (unified) {\n this.pushLineWithAnnotation({\n oldLine,\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n oldLine != null ? deletionLineNumber : undefined,\n newLine != null ? additionLineNumber : undefined,\n hunkIndex,\n lineIndex\n ),\n });\n lineIndex++;\n } else {\n if (oldLine == null || newLine == null) {\n spanSize++;\n }\n const annotationSpans = this.getAnnotations(\n 'split',\n oldLine != null ? deletionLineNumber : undefined,\n newLine != null ? additionLineNumber : undefined,\n hunkIndex,\n lineIndex\n );\n if (annotationSpans != null) {\n if (spanSize > 0) {\n if (aLen > dLen) {\n deletionsAST.push(createEmptyRowBuffer(spanSize));\n } else {\n additionsAST.push(createEmptyRowBuffer(spanSize));\n }\n spanSize = 0;\n }\n }\n this.pushLineWithAnnotation({\n newLine,\n oldLine,\n deletionsAST,\n additionsAST,\n ...annotationSpans,\n });\n lineIndex++;\n }\n }\n if (!unified) {\n if (spanSize > 0) {\n if (aLen > dLen) {\n deletionsAST.push(createEmptyRowBuffer(spanSize));\n } else {\n additionsAST.push(createEmptyRowBuffer(spanSize));\n }\n spanSize = 0;\n }\n if (hunkContent.noEOFCRDeletions) {\n deletionsAST.push(createNoNewlineElement('change-deletion'));\n if (!hunkContent.noEOFCRAdditions) {\n additionsAST.push(createEmptyRowBuffer(1));\n }\n }\n if (hunkContent.noEOFCRAdditions) {\n additionsAST.push(createNoNewlineElement('change-addition'));\n if (!hunkContent.noEOFCRDeletions) {\n deletionsAST.push(createEmptyRowBuffer(1));\n }\n }\n }\n }\n }\n\n if (isLastHunk && ast.newLines != null && ast.newLines.length > 0) {\n this.renderCollapsedHunks({\n additionLineNumber,\n additionsAST,\n ast,\n deletionLineNumber,\n deletionsAST,\n hunkData,\n hunkIndex: hunkIndex + 1,\n hunkSpecs: undefined,\n isFirstHunk: false,\n isLastHunk: true,\n lineIndex,\n rangeSize: Math.max(\n ast.newLines.length -\n Math.max(hunk.additionStart + hunk.additionCount - 1, 0),\n 0\n ),\n unifiedAST,\n });\n }\n return lineIndex;\n }\n\n private pushLineWithAnnotation({\n newLine,\n oldLine,\n unifiedAST,\n additionsAST,\n deletionsAST,\n unifiedSpan,\n deletionSpan,\n additionSpan,\n }: PushLineWithAnnotation) {\n if (unifiedAST != null) {\n if (oldLine != null) {\n unifiedAST.push(oldLine);\n } else if (newLine != null) {\n unifiedAST.push(newLine);\n }\n if (unifiedSpan != null) {\n unifiedAST.push(createAnnotationElement(unifiedSpan));\n }\n } else if (deletionsAST != null && additionsAST != null) {\n if (oldLine != null) {\n deletionsAST.push(oldLine);\n }\n if (newLine != null) {\n additionsAST.push(newLine);\n }\n if (deletionSpan != null) {\n deletionsAST.push(createAnnotationElement(deletionSpan));\n }\n if (additionSpan != null) {\n additionsAST.push(createAnnotationElement(additionSpan));\n }\n }\n }\n\n private getAnnotations(\n type: 'unified',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ): AnnotationSpan | undefined;\n private getAnnotations(\n type: 'split',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ): { deletionSpan: AnnotationSpan; additionSpan: AnnotationSpan } | undefined;\n private getAnnotations(\n type: 'unified' | 'split',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ):\n | AnnotationSpan\n | { deletionSpan: AnnotationSpan; additionSpan: AnnotationSpan }\n | undefined {\n const deletionSpan: AnnotationSpan = {\n type: 'annotation',\n hunkIndex,\n lineIndex,\n annotations: [],\n };\n if (oldLineNumber != null) {\n for (const anno of this.deletionAnnotations[oldLineNumber] ?? []) {\n deletionSpan.annotations.push(getLineAnnotationName(anno));\n }\n }\n const additionSpan: AnnotationSpan = {\n type: 'annotation',\n hunkIndex,\n lineIndex,\n annotations: [],\n };\n if (newLineNumber != null) {\n for (const anno of this.additionAnnotations[newLineNumber] ?? []) {\n (type === 'unified' ? deletionSpan : additionSpan).annotations.push(\n getLineAnnotationName(anno)\n );\n }\n }\n if (type === 'unified') {\n if (deletionSpan.annotations.length > 0) {\n return deletionSpan;\n }\n return undefined;\n }\n if (\n additionSpan.annotations.length === 0 &&\n deletionSpan.annotations.length === 0\n ) {\n return undefined;\n }\n return { deletionSpan, additionSpan };\n }\n\n private renderHeader(\n diff: FileDiffMetadata,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const { themeType } = this.getOptionsWithDefaults();\n return createFileHeaderElement({\n fileOrDiff: diff,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n });\n }\n}\n\nfunction areRenderOptionsEqual(\n optionsA: RenderDiffOptions,\n optionsB: RenderDiffOptions\n): boolean {\n return (\n areThemesEqual(optionsA.theme, optionsB.theme) &&\n optionsA.tokenizeMaxLineLength === optionsB.tokenizeMaxLineLength &&\n optionsA.lineDiffType === optionsB.lineDiffType\n );\n}\n\nfunction getModifiedLinesString(lines: number) {\n return `${lines} unmodified line${lines > 1 ? 's' : ''}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6CA,MAAMA,kBAAmC;CACvC,WAAW;CACX,SAAS;CACV;AAoFD,IAAa,oBAAb,MAAwD;CACtD,AAAQ;CACR,AAAQ;CAER,AAAQ,gCAAgB,IAAI,KAA8B;CAE1D,AAAQ,sBAAsD,EAAE;CAChE,AAAQ,sBAAsD,EAAE;CAEhE,AAAQ,eAAmC;CAC3C,AAAQ;CAER,YACE,AAAOC,UAA2B,EAAE,OAAO,gBAAgB,EAC3D,AAAQC,gBACR,AAAQC,eACR;EAHO;EACC;EACA;AAER,MAAI,eAAe,eAAe,KAAK,KACrC,MAAK,cAAc,kBAAkB,QAAQ,SAAS,eAAe,GACjE,wBAAwB,GACxB;;CAIR,UAAgB;AACd,OAAK,cAAc;AACnB,OAAK,OAAO;AACZ,OAAK,cAAc;AACnB,OAAK,gBAAgB;AACrB,OAAK,iBAAiB;;CAGxB,WAAW,SAAgC;AACzC,OAAK,UAAU;;CAGjB,AAAQ,aAAa,SAAmC;AACtD,OAAK,UAAU;GAAE,GAAG,KAAK;GAAS,GAAG;GAAS;;CAGhD,aAAa,WAA6B;AACxC,MAAI,KAAK,wBAAwB,CAAC,cAAc,UAC9C;AAEF,OAAK,aAAa,EAAE,WAAW,CAAC;;CAGlC,WAAW,OAAe,WAAsC;EAC9D,MAAM,EAAE,uBAAuB,KAAK,wBAAwB;EAC5D,MAAM,SAAS,KAAK,cAAc,IAAI,MAAM,IAAI;GAC9C,WAAW;GACX,SAAS;GACV;AACD,MAAI,cAAc,QAAQ,cAAc,OACtC,QAAO,aAAa;AAEtB,MAAI,cAAc,UAAU,cAAc,OACxC,QAAO,WAAW;AAEpB,OAAK,cAAc,IAAI,OAAO,OAAO;;CAGvC,mBAAmB,iBAA0D;AAC3E,OAAK,sBAAsB,EAAE;AAC7B,OAAK,sBAAsB,EAAE;AAC7B,OAAK,MAAM,cAAc,iBAAiB;GACxC,MAAM,aAA6C;AACjD,YAAQ,WAAW,MAAnB;KACE,KAAK,YACH,QAAO,KAAK;KACd,KAAK,YACH,QAAO,KAAK;;OAEd;GACJ,MAAM,MAAM,IAAI,WAAW,eAAe,EAAE;AAC5C,OAAI,WAAW,cAAc;AAC7B,OAAI,KAAK,WAAW;;;CAIxB,yBAA8C;EAC5C,MAAM,EACJ,iBAAiB,QACjB,YAAY,SACZ,oBAAoB,OACpB,oBAAoB,OACpB,qBAAqB,OACrB,kBAAkB,OAClB,qBAAqB,KACrB,iBAAiB,aACjB,eAAe,YACf,oBAAoB,KACpB,WAAW,UACX,QAAQ,gBACR,YAAY,UACZ,wBAAwB,KACxB,gBAAgB,UACd,KAAK;AACT,SAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,OAAO,KAAK,eAAe,sBAAsB,CAAC,SAAS;GAC3D;GACA;GACA;GACD;;CAGH,MAAM,wBAAmD;AACvD,OAAK,cAAc,MAAM,qBACvB,sBAAsB,KAAK,cAAc,KAAK,QAAQ,CACvD;AACD,SAAO,KAAK;;CAGd,QAAQ,MAA0C;AAChD,MAAI,QAAQ,KACV;AAEF,OAAK,OAAO;EACZ,MAAM,EAAE,YAAY,KAAK,iBAAiB,KAAK;EAC/C,IAAI,QAAQ,KAAK,eAAe,mBAAmB,KAAK;AACxD,MAAI,SAAS,QAAQ,CAAC,sBAAsB,SAAS,MAAM,QAAQ,CACjE,SAAQ;AAEV,OAAK,gBAAgB;GACnB;GAGA,aAAa;GACb;GACA,QAAQ,OAAO;GAChB;AACD,MACE,KAAK,eAAe,eAAe,KAAK,QACxC,KAAK,YAAY,UAAU,KAE3B,MAAK,cAAc,iBAAiB,MAAM,KAAK,KAAK;MAEpD,CAAK,KAAK,eAAe,KAAK,CAAC,MAAM,EAAE,QAAQ,yBAAc;AAC3D,QAAK,mBAAmB,MAAM,QAAQC,UAAQ;IAC9C;;CAIN,AAAQ,iBAAiB,MAAgD;EACvE,MAAMC,iBAAoC;AACxC,OAAI,KAAK,eAAe,eAAe,KAAK,KAC1C,QAAO,KAAK,cAAc,sBAAsB;GAElD,MAAM,EAAE,OAAO,uBAAuB,iBACpC,KAAK,wBAAwB;AAC/B,UAAO;IAAE;IAAO;IAAuB;IAAc;MACnD;AACJ,OAAK,wBAAwB;EAC7B,MAAM,EAAE,gBAAgB;AACxB,MAAI,aAAa,UAAU,KACzB,QAAO;GAAE;GAAS,aAAa;GAAM;AAEvC,MACE,SAAS,YAAY,QACrB,CAAC,sBAAsB,SAAS,YAAY,QAAQ,CAEpD,QAAO;GAAE;GAAS,aAAa;GAAM;AAEvC,SAAO;GAAE;GAAS,aAAa;GAAO;;CAGxC,WACE,OAAqC,KAAK,aAAa,MACxB;AAC/B,MAAI,QAAQ,KACV;EAEF,MAAM,EAAE,SAAS,gBAAgB,KAAK,iBAAiB,KAAK;EAC5D,IAAI,QAAQ,KAAK,eAAe,mBAAmB,KAAK;AACxD,MAAI,SAAS,QAAQ,CAAC,sBAAsB,SAAS,MAAM,QAAQ,CACjE,SAAQ;AAEV,OAAK,gBAAgB;GACnB;GACA,aAAa,SAAS,OAAO,OAAO;GACpC,SAAS,OAAO,WAAW;GAC3B,QAAQ,OAAO;GAChB;AACD,MAAI,KAAK,eAAe,eAAe,KAAK,MAAM;AAChD,QAAK,YAAY,WAAW,KAAK,cAAc,gBAAgB,KAAK;AACpE,OAAI,CAAC,KAAK,YAAY,eAAe,YACnC,MAAK,cAAc,iBAAiB,MAAM,KAAK;SAE5C;AACL,QAAK,eAAe,KAAK,QAAQ,wBAAwB,KAAK,KAAK;GACnE,MAAM,YACJ,KAAK,eAAe,QAAQ,kBAAkB,QAAQ,MAAM;GAC9D,MAAM,WACJ,KAAK,eAAe,QAAQ,qBAAqB,KAAK,aAAa;AAMrE,OACE,KAAK,eAAe,QACpB,cACC,eACE,CAAC,KAAK,YAAY,eAAe,YAClC,KAAK,YAAY,UAAU,OAC7B;IACA,MAAM,EAAE,QAAQ,uBAAY,KAAK,0BAC/B,MACA,KAAK,aACL,CAAC,SACF;AACD,SAAK,cAAc;KACjB;KACA;KACA,aAAa;KACb;KACD;;AAMH,OAAI,CAAC,aAAa,CAAC,SACjB,CAAK,KAAK,eAAe,KAAK,CAAC,MAAM,EAAE,QAAQ,yBAAc;AAC3D,SAAK,mBAAmB,MAAM,QAAQD,UAAQ;KAC9C;;AAGN,SAAO,KAAK,YAAY,UAAU,OAC9B,KAAK,kBAAkB,KAAK,YAAY,MAAM,KAAK,YAAY,OAAO,GACtE;;CAGN,MAAM,YAAY,MAAoD;EACpE,MAAM,EAAE,WAAW,MAAM,KAAK,eAAe,KAAK;AAClD,SAAO,KAAK,kBAAkB,MAAM,OAAO;;CAG7C,AAAQ,iBACN,OACA,YACA,aACA,eACa;EACb,MAAM,EACJ,gBACA,mBACA,oBACA,UACA,cACE,KAAK,wBAAwB;AACjC,SAAO,iBAAiB;GACtB;GACA;GACA;GACA;GACA;GACA;GACA,WAAW,iBAAiB;GAC5B;GACD,CAAC;;CAGJ,MAAc,eACZ,MAC2B;AAC3B,OAAK,eAAe,KAAK,QAAQ,wBAAwB,KAAK,KAAK;EACnE,MAAM,YACJ,KAAK,eAAe,QACpB,kBAAkB,KAAK,QAAQ,SAAS,eAAe;EACzD,MAAM,WACJ,KAAK,eAAe,QAAQ,qBAAqB,KAAK,aAAa;AAGrE,MAAI,KAAK,eAAe,QAAQ,CAAC,aAAa,CAAC,SAC7C,MAAK,cAAc,MAAM,KAAK,uBAAuB;AAEvD,SAAO,KAAK,0BAA0B,MAAM,KAAK,YAAY;;CAG/D,AAAQ,0BACN,MACA,aACA,YAAY,OACM;EAClB,MAAM,EAAE,YAAY,KAAK,iBAAiB,KAAK;AAO/C,SAAO;GAAE,QANM,0BACb,MACA,aACA,SACA,UACD;GACgB;GAAS;;CAG5B,mBACE,MACA,QACA,SACM;AAEN,MAAI,KAAK,eAAe,KACtB;EAEF,MAAM,sBACJ,KAAK,YAAY,SAAS,QAC1B,CAAC,KAAK,YAAY,eAClB,CAAC,sBAAsB,KAAK,YAAY,SAAS,QAAQ;AAE3D,OAAK,cAAc;GACjB;GACA;GACA,aAAa;GACb;GACD;AACD,MAAI,oBACF,MAAK,kBAAkB;;CAI3B,iBAAiB,OAAsB;AACrC,UAAQ,MAAM,MAAM;;CAGtB,AAAQ,kBACN,UACA,EAAE,MAAM,aAAa,iBACF;EACnB,MAAM,EAAE,WAAW,sBAAsB,KAAK,wBAAwB;AAEtE,OAAK,OAAO;EACZ,MAAM,UAAU,cAAc;EAE9B,IAAIE,eAA6C,EAAE;EACnD,IAAIC,eAA6C,EAAE;EACnD,IAAIC,aAA2C,EAAE;EAEjD,IAAI,YAAY;EAChB,MAAMC,WAAuB,EAAE;EAE/B,IAAIC;EACJ,IAAI,YAAY;AAChB,OAAK,MAAM,QAAQ,SAAS,OAAO;AACjC,gBAAa,KAAK;AAClB,eAAY,KAAK,YAAY;IAC3B,KAAK;IACL;IACA;IACA;IACA,YAAY,cAAc,SAAS,MAAM,SAAS;IAClD;IACA;IACA;IACA;IACA;IACD,CAAC;AACF;AACA,cAAW;;EAGb,MAAM,aAAa,KAAK,IACtB,2BAA2B,SAAS,MAAM,EAC1C,SAAS,UAAU,UAAU,GAC7B,SAAS,UAAU,UAAU,EAC9B;AAED,iBACE,CAAC,YAAY,KAAK,SAAS,QAAQ,KAAK,SAAS,SAAS,KACtD,eACA;AACN,iBACE,CAAC,YAAY,KAAK,SAAS,QAAQ,KAAK,SAAS,SAAS,KACtD,eACA;AACN,eAAa,WAAW,SAAS,IAAI,aAAa;EAElD,MAAM,UAAU,KAAK,iBACnB,gBAAgB,QAAQ,gBAAgB,MACxC,YACA,aACA,cACD;AAED,SAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;GACA,eAAe,CAAC,oBACZ,KAAK,aAAa,KAAK,MAAM,aAAa,cAAc,GACxD;GACJ;GAEA,KAAK;GACN;;CAGH,cACE,QACA,WAA6B,EAAE,EAClB;AACb,MAAI,OAAO,cAAc,KACvB,UAAS,KACP,kBAAkB;GAChB,SAAS;GACT,UAAU,OAAO;GACjB,YAAY;IACV,aAAa;IACb,gBAAgB;IACjB;GACF,CAAC,CACH;AAEH,MAAI,OAAO,gBAAgB,KACzB,UAAS,KACP,kBAAkB;GAChB,SAAS;GACT,UAAU,OAAO;GACjB,YAAY;IACV,aAAa;IACb,kBAAkB;IACnB;GACF,CAAC,CACH;AAEH,MAAI,OAAO,gBAAgB,KACzB,UAAS,KACP,kBAAkB;GAChB,SAAS;GACT,UAAU,OAAO;GACjB,YAAY;IACV,aAAa;IACb,kBAAkB;IACnB;GACF,CAAC,CACH;AAEH,SAAO;GAAE,GAAG,OAAO;GAAS;GAAU;;CAGxC,eACE,QACA,eAAiC,EAAE,EAC3B;AACR,SAAO,OAAO,KAAK,cAAc,QAAQ,aAAa,CAAC;;CAGzD,kBACE,UACA,YACQ;AACR,MAAI,cAAc,KAChB,QAAO,OAAO,SAAS;AAEzB,SAAO,OACL,kBAAkB;GAChB,SAAS;GACT;GACA,YAAY;IACV,aAAa;KACZ,QAAQ,eAAe;IACzB;GACF,CAAC,CACH;;CAGH,AAAQ,qBAAqB,EAC3B,KACA,UACA,WACA,WACA,aACA,YACA,WACA,WACA,oBACA,oBACA,YACA,cACA,gBAC4B;AAC5B,MAAI,aAAa,EACf;EAEF,MAAM,EAAE,gBAAgB,iBAAiB,WAAW,uBAClD,KAAK,wBAAwB;EAC/B,MAAM,aACJ,IAAI,SAAS,QAAQ,IAAI,SAAS,SAAS,KAAK,IAAI,SAAS,SAAS;EACxE,MAAM,iBAAiB,KAAK,cAAc,IAAI,UAAU,IAAI;EAC5D,MAAM,UAAU,YAAY;EAC5B,MAAM,iBAAiB,KAAK,IAC1B,CAAC,kBACG,aAAa,eAAe,UAAU,eAAe,aACrD,GACJ,EACD;EAED,MAAM,qBAAqB,EAAE,MAAM,eAAuC;AACxE,OAAI,mBAAmB,eAAe,mBAAmB,UAAU;IACjE,MAAM,WAAW,yBAAyB,MAAM,UAAU;AAC1D,aAAS,KACP,gBAAgB;KACd,MAAM;KACN,SAAS,uBAAuB,eAAe;KAC/C,aAAa,aAAa,YAAY;KACtC;KACA;KACA;KACA;KACD,CAAC,CACH;AACD,aAAS,KAAK;KACZ;KACA;KACA,OAAO;KACP;KACA,YAAY,aACR;MACE,IAAI,cAAc,CAAC;MACnB,MAAM;MACN;MACD,GACD;KACL,CAAC;cACO,mBAAmB,cAAc,aAAa,KACvD,UAAS,KACP,gBAAgB;IACd,MAAM;IACN,SAAS;IACT;IACA;IACD,CAAC,CACH;YACQ,mBAAmB,YAAY,YAAY,EACpD,UAAS,KACP,gBAAgB;IAAE,MAAM;IAAU;IAAa,YAAY;IAAO,CAAC,CACpE;;EAIL,MAAM,eAAe,EAAE,UAAU,gBAAkC;AACjE,OAAI,IAAI,YAAY,QAAQ,IAAI,YAAY,KAC1C;GAGF,MAAM,SAAS,aAAa,IAAI,YAAY,YAAY;GACxD,IAAI,cAAc,qBAAqB;GACvC,IAAI,cAAc,qBAAqB;GACvC,IAAI,SAAS,YAAY;AAEzB,QAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;IACjC,MAAM,UAAU,IAAI,SAAS;IAC7B,MAAM,UAAU,IAAI,SAAS;AAC7B,QAAI,WAAW,QAAQ,WAAW,MAAM;AACtC,aAAQ,MAAM;MAAE;MAAa;MAAa;MAAK,CAAC;AAChD,WAAM,IAAI,MACR,iGACD;;AAEH;AACA;AAEA,QAAI,cAAc,UAChB,MAAK,uBAAuB;KAC1B;KACA;KACA,aAAa,KAAK,eAChB,WACA,aACA,aACA,WACA,OACD;KACF,CAAC;QAEF,MAAK,uBAAuB;KAC1B;KACA;KACA;KACA;KACA,GAAG,KAAK,eACN,SACA,aACA,aACA,WACA,OACD;KACF,CAAC;AAEJ;;;AAIJ,MAAI,WACF,aAAY;GACV,UAAU,KAAK,IACb,mBAAmB,KAAK,kBACpB,YACA,eAAe,WACnB,UACD;GACD,WAAW;GACZ,CAAC;AAGJ,MAAI,iBAAiB,EACnB,KAAI,cAAc,UAChB,mBAAkB;GAAE,MAAM;GAAW,UAAU;GAAY,CAAC;OACvD;AACL,qBAAkB;IAAE,MAAM;IAAa,UAAU;IAAc,CAAC;AAChE,qBAAkB;IAAE,MAAM;IAAa,UAAU;IAAc,CAAC;;AAIpE,MAAI,iBAAiB,KAAK,eAAe,UAAU,KAAK,CAAC,WACvD,aAAY;GACV,UAAU,KAAK,IAAI,eAAe,SAAS,UAAU;GACrD,WAAW;GACZ,CAAC;;CAIN,AAAQ,YAAY,EAClB,MACA,UACA,WACA,WACA,YACA,UACA,KACA,cACA,cACA,cAC0B;EAC1B,MAAM,EAAE,cAAc,KAAK,wBAAwB;EACnD,MAAM,UAAU,cAAc;EAC9B,IAAI,qBAAqB,KAAK,gBAAgB;EAC9C,IAAI,qBAAqB,KAAK,gBAAgB;AAE9C,OAAK,qBAAqB;GACxB;GACA;GACA;GACA;GACA;GACA;GACA;GACA,WAAW,KAAK;GAChB,aAAa,YAAY;GACzB,YAAY;GACZ;GACA,WAAW,KAAK,IAAI,KAAK,iBAAiB,EAAE;GAC5C;GACD,CAAC;EAEF,IAAI,EAAE,UAAU,UAAU,UAAU,oBAAoB;AACtD,OAAI,IAAI,SAAS,MAAM;IACrB,MAAM,WAAW,IAAI,MAAM;AAC3B,QAAI,YAAY,MAAM;AACpB,aAAQ,MAAM;MAAE;MAAK;MAAW,CAAC;AACjC,WAAM,IAAI,MACR,wDACD;;AAEH,WAAO;KACL,UAAU,SAAS;KACnB,UAAU,SAAS;KACnB,UAAU;KACV,UAAU;KACX;;AAEH,UAAO;IACL,UAAU,IAAI;IACd,UAAU,IAAI;IACd,UAAU;IACV,UAAU;IACX;MACC;AAGJ,OAAK,MAAM,eAAe,KAAK,YAC7B,KAAI,YAAY,SAAS,WAAW;GAClC,MAAM,EAAE,QAAQ,QAAQ,YAAY;AACpC,QAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;IAC5B,MAAM,UAAU,SAAS;IACzB,MAAM,UAAU,SAAS;AACzB;AACA;AACA;AACA;AACA,QAAI,SAAS;AACX,SAAI,WAAW,KACb,OAAM,IAAI,MACR,qEACD;AAEH,UAAK,uBAAuB;MAC1B;MACA;MACA,aAAa,KAAK,eAChB,WACA,oBACA,oBACA,WACA,UACD;MACF,CAAC;WACG;AACL,SAAI,WAAW,QAAQ,WAAW,KAChC,OAAM,IAAI,MACR,gFACD;AAEH,UAAK,uBAAuB;MAC1B;MACA;MACA;MACA;MACA,GAAG,KAAK,eACN,SACA,oBACA,oBACA,WACA,UACD;MACF,CAAC;;AAEJ;;AAEF,OAAI,YAAY,SAAS;IACvB,MAAM,OAAO,uBAAuB,UAAU;AAC9C,QAAI,QACF,YAAW,KAAK,KAAK;SAChB;AACL,kBAAa,KAAK,KAAK;AACvB,kBAAa,KAAK,KAAK;;;SAGtB;GACL,MAAM,EAAE,QAAQ,SAAS,YAAY;GACrC,MAAM,EAAE,QAAQ,SAAS,YAAY;GACrC,MAAM,MAAM,UAAU,OAAO,OAAO,KAAK,IAAI,MAAM,KAAK;GACxD,IAAI,WAAW;AACf,QAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;IAC5B,MAAM,EAAE,SAAS,mBAAmB;KAClC,IAAIC,YAAsC,SAAS;KACnD,IAAIC,YAAsC,SAAS;AACnD,SAAI,QACF,KAAI,IAAI,KACN,aAAU;SAEV,aAAU;UAEP;AACL,UAAI,KAAK,KACP,aAAU;AAEZ,UAAI,KAAK,KACP,aAAU;;AAGd,SAAIC,aAAW,QAAQC,aAAW,MAAM;AACtC,cAAQ,MAAM;OAAE;OAAG;OAAK;OAAK;OAAa,CAAC;AAC3C,YAAM,IAAI,MACR,gEACD;;AAEH,YAAO;MAAE;MAAS;MAAS;QACzB;AAEJ,QAAI,WAAW,MAAM;AACnB;AACA;;AAEF,QAAI,WAAW,MAAM;AACnB;AACA;;AAGF,QAAI,SAAS;AACX,UAAK,uBAAuB;MAC1B;MACA;MACA;MACA,aAAa,KAAK,eAChB,WACA,WAAW,OAAO,qBAAqB,QACvC,WAAW,OAAO,qBAAqB,QACvC,WACA,UACD;MACF,CAAC;AACF;WACK;AACL,SAAI,WAAW,QAAQ,WAAW,KAChC;KAEF,MAAM,kBAAkB,KAAK,eAC3B,SACA,WAAW,OAAO,qBAAqB,QACvC,WAAW,OAAO,qBAAqB,QACvC,WACA,UACD;AACD,SAAI,mBAAmB,MACrB;UAAI,WAAW,GAAG;AAChB,WAAI,OAAO,KACT,cAAa,KAAK,qBAAqB,SAAS,CAAC;WAEjD,cAAa,KAAK,qBAAqB,SAAS,CAAC;AAEnD,kBAAW;;;AAGf,UAAK,uBAAuB;MAC1B;MACA;MACA;MACA;MACA,GAAG;MACJ,CAAC;AACF;;;AAGJ,OAAI,CAAC,SAAS;AACZ,QAAI,WAAW,GAAG;AAChB,SAAI,OAAO,KACT,cAAa,KAAK,qBAAqB,SAAS,CAAC;SAEjD,cAAa,KAAK,qBAAqB,SAAS,CAAC;AAEnD,gBAAW;;AAEb,QAAI,YAAY,kBAAkB;AAChC,kBAAa,KAAK,uBAAuB,kBAAkB,CAAC;AAC5D,SAAI,CAAC,YAAY,iBACf,cAAa,KAAK,qBAAqB,EAAE,CAAC;;AAG9C,QAAI,YAAY,kBAAkB;AAChC,kBAAa,KAAK,uBAAuB,kBAAkB,CAAC;AAC5D,SAAI,CAAC,YAAY,iBACf,cAAa,KAAK,qBAAqB,EAAE,CAAC;;;;AAOpD,MAAI,cAAc,IAAI,YAAY,QAAQ,IAAI,SAAS,SAAS,EAC9D,MAAK,qBAAqB;GACxB;GACA;GACA;GACA;GACA;GACA;GACA,WAAW,YAAY;GACvB,WAAW;GACX,aAAa;GACb,YAAY;GACZ;GACA,WAAW,KAAK,IACd,IAAI,SAAS,SACX,KAAK,IAAI,KAAK,gBAAgB,KAAK,gBAAgB,GAAG,EAAE,EAC1D,EACD;GACD;GACD,CAAC;AAEJ,SAAO;;CAGT,AAAQ,uBAAuB,EAC7B,SACA,SACA,YACA,cACA,cACA,aACA,cACA,gBACyB;AACzB,MAAI,cAAc,MAAM;AACtB,OAAI,WAAW,KACb,YAAW,KAAK,QAAQ;YACf,WAAW,KACpB,YAAW,KAAK,QAAQ;AAE1B,OAAI,eAAe,KACjB,YAAW,KAAK,wBAAwB,YAAY,CAAC;aAE9C,gBAAgB,QAAQ,gBAAgB,MAAM;AACvD,OAAI,WAAW,KACb,cAAa,KAAK,QAAQ;AAE5B,OAAI,WAAW,KACb,cAAa,KAAK,QAAQ;AAE5B,OAAI,gBAAgB,KAClB,cAAa,KAAK,wBAAwB,aAAa,CAAC;AAE1D,OAAI,gBAAgB,KAClB,cAAa,KAAK,wBAAwB,aAAa,CAAC;;;CAmB9D,AAAQ,eACN,MACA,eACA,eACA,WACA,WAIY;EACZ,MAAMC,eAA+B;GACnC,MAAM;GACN;GACA;GACA,aAAa,EAAE;GAChB;AACD,MAAI,iBAAiB,KACnB,MAAK,MAAM,QAAQ,KAAK,oBAAoB,kBAAkB,EAAE,CAC9D,cAAa,YAAY,KAAK,sBAAsB,KAAK,CAAC;EAG9D,MAAMC,eAA+B;GACnC,MAAM;GACN;GACA;GACA,aAAa,EAAE;GAChB;AACD,MAAI,iBAAiB,KACnB,MAAK,MAAM,QAAQ,KAAK,oBAAoB,kBAAkB,EAAE,CAC9D,EAAC,SAAS,YAAY,eAAe,cAAc,YAAY,KAC7D,sBAAsB,KAAK,CAC5B;AAGL,MAAI,SAAS,WAAW;AACtB,OAAI,aAAa,YAAY,SAAS,EACpC,QAAO;AAET;;AAEF,MACE,aAAa,YAAY,WAAW,KACpC,aAAa,YAAY,WAAW,EAEpC;AAEF,SAAO;GAAE;GAAc;GAAc;;CAGvC,AAAQ,aACN,MACA,aACA,eACa;EACb,MAAM,EAAE,cAAc,KAAK,wBAAwB;AACnD,SAAO,wBAAwB;GAC7B,YAAY;GACZ;GACA,WAAW,iBAAiB;GAC7B,CAAC;;;AAIN,SAAS,sBACP,UACA,UACS;AACT,QACE,eAAe,SAAS,OAAO,SAAS,MAAM,IAC9C,SAAS,0BAA0B,SAAS,yBAC5C,SAAS,iBAAiB,SAAS;;AAIvC,SAAS,uBAAuB,OAAe;AAC7C,QAAO,GAAG,MAAM,kBAAkB,QAAQ,IAAI,MAAM"}
|
|
1
|
+
{"version":3,"file":"DiffHunksRenderer.js","names":["EXPANDED_REGION: ExpansionRegion","options: BaseDiffOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options","options: RenderDiffOptions","additionsAST: ElementContent[] | undefined","deletionsAST: ElementContent[] | undefined","unifiedAST: ElementContent[] | undefined","hunkData: HunkData[]","prevHunk: Hunk | undefined","oldLine: ElementContent | undefined","newLine: ElementContent | undefined","oldLine","newLine","deletionSpan: AnnotationSpan","additionSpan: AnnotationSpan"],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport type {\n AnnotationLineMap,\n AnnotationSpan,\n BaseDiffOptions,\n DiffLineAnnotation,\n DiffsHighlighter,\n ExpansionDirections,\n FileDiffMetadata,\n Hunk,\n HunkData,\n RenderDiffFilesResult,\n RenderDiffHunksResult,\n RenderDiffOptions,\n RenderDiffResult,\n RenderedDiffASTCache,\n SupportedLanguages,\n ThemeTypes,\n ThemedDiffResult,\n} from '../types';\nimport { areThemesEqual } from '../utils/areThemesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createEmptyRowBuffer } from '../utils/createEmptyRowBuffer';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createNoNewlineElement } from '../utils/createNoNewlineElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { createSeparator } from '../utils/createSeparator';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getHunkSeparatorSlotName } from '../utils/getHunkSeparatorSlotName';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getTotalLineCountFromHunks } from '../utils/getTotalLineCountFromHunks';\nimport { createHastElement } from '../utils/hast_utils';\nimport { renderDiffWithHighlighter } from '../utils/renderDiffWithHighlighter';\nimport type { WorkerPoolManager } from '../worker';\n\nconst EXPANDED_REGION: ExpansionRegion = {\n fromStart: 0,\n fromEnd: 0,\n};\n\ninterface PushHunkSeparatorProps {\n type: 'additions' | 'deletions' | 'unified';\n linesAST: ElementContent[];\n}\n\ninterface RenderRangeProps {\n rangeLen: number;\n fromStart: boolean;\n}\n\ninterface PushLineWithAnnotation {\n newLine?: ElementContent;\n oldLine?: ElementContent;\n\n unifiedAST?: ElementContent[];\n deletionsAST?: ElementContent[];\n additionsAST?: ElementContent[];\n\n unifiedSpan?: AnnotationSpan;\n deletionSpan?: AnnotationSpan;\n additionSpan?: AnnotationSpan;\n}\n\ninterface RenderCollapsedHunksProps {\n ast: RenderDiffFilesResult | RenderDiffHunksResult;\n hunkData: HunkData[];\n hunkIndex: number;\n hunkSpecs: string | undefined;\n isFirstHunk: boolean;\n isLastHunk: boolean;\n rangeSize: number;\n\n lineIndex: number;\n additionLineNumber: number;\n deletionLineNumber: number;\n\n additionsAST: ElementContent[];\n deletionsAST: ElementContent[];\n unifiedAST: ElementContent[];\n}\n\ninterface RenderHunkProps {\n hunk: Hunk;\n hunkData: HunkData[];\n hunkIndex: number;\n lineIndex: number;\n isLastHunk: boolean;\n prevHunk: Hunk | undefined;\n\n ast: RenderDiffFilesResult | RenderDiffHunksResult;\n unifiedAST: ElementContent[];\n deletionsAST: ElementContent[];\n additionsAST: ElementContent[];\n}\n\ninterface GetRenderOptionsReturn {\n options: RenderDiffOptions;\n forceRender: boolean;\n}\n\ntype OptionsWithDefaults = Required<\n Omit<BaseDiffOptions, 'lang' | 'unsafeCSS'>\n>;\n\ninterface ExpansionRegion {\n fromStart: number;\n fromEnd: number;\n}\n\nexport interface HunksRenderResult {\n additionsAST: ElementContent[] | undefined;\n deletionsAST: ElementContent[] | undefined;\n unifiedAST: ElementContent[] | undefined;\n hunkData: HunkData[];\n css: string;\n preNode: HASTElement;\n headerElement: HASTElement | undefined;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n}\n\nexport class DiffHunksRenderer<LAnnotation = undefined> {\n private highlighter: DiffsHighlighter | undefined;\n private diff: FileDiffMetadata | undefined;\n\n private expandedHunks = new Map<number, ExpansionRegion>();\n\n private deletionAnnotations: AnnotationLineMap<LAnnotation> = {};\n private additionAnnotations: AnnotationLineMap<LAnnotation> = {};\n\n private computedLang: SupportedLanguages = 'text';\n private renderCache: RenderedDiffASTCache | undefined;\n\n constructor(\n public options: BaseDiffOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n cleanUp(): void {\n this.highlighter = undefined;\n this.diff = undefined;\n this.renderCache = undefined;\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n setOptions(options: BaseDiffOptions): void {\n this.options = options;\n }\n\n private mergeOptions(options: Partial<BaseDiffOptions>) {\n this.options = { ...this.options, ...options };\n }\n\n setThemeType(themeType: ThemeTypes): void {\n if (this.getOptionsWithDefaults().themeType === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n }\n\n expandHunk(index: number, direction: ExpansionDirections): void {\n const { expansionLineCount } = this.getOptionsWithDefaults();\n const region = this.expandedHunks.get(index) ?? {\n fromStart: 0,\n fromEnd: 0,\n };\n if (direction === 'up' || direction === 'both') {\n region.fromStart += expansionLineCount;\n }\n if (direction === 'down' || direction === 'both') {\n region.fromEnd += expansionLineCount;\n }\n this.expandedHunks.set(index, region);\n }\n\n setLineAnnotations(lineAnnotations: DiffLineAnnotation<LAnnotation>[]): void {\n this.additionAnnotations = {};\n this.deletionAnnotations = {};\n for (const annotation of lineAnnotations) {\n const map = ((): AnnotationLineMap<LAnnotation> => {\n switch (annotation.side) {\n case 'deletions':\n return this.deletionAnnotations;\n case 'additions':\n return this.additionAnnotations;\n }\n })();\n const arr = map[annotation.lineNumber] ?? [];\n map[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n getOptionsWithDefaults(): OptionsWithDefaults {\n const {\n diffIndicators = 'bars',\n diffStyle = 'split',\n disableBackground = false,\n disableFileHeader = false,\n disableLineNumbers = false,\n expandUnchanged = false,\n expansionLineCount = 100,\n hunkSeparators = 'line-info',\n lineDiffType = 'word-alt',\n maxLineDiffLength = 1000,\n overflow = 'scroll',\n theme = DEFAULT_THEMES,\n themeType = 'system',\n tokenizeMaxLineLength = 1000,\n useCSSClasses = false,\n } = this.options;\n return {\n diffIndicators,\n diffStyle,\n disableBackground,\n disableFileHeader,\n disableLineNumbers,\n expandUnchanged,\n expansionLineCount,\n hunkSeparators,\n lineDiffType,\n maxLineDiffLength,\n overflow,\n theme: this.workerManager?.getDiffRenderOptions().theme ?? theme,\n themeType,\n tokenizeMaxLineLength,\n useCSSClasses,\n };\n }\n\n async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n hydrate(diff: FileDiffMetadata | undefined): void {\n if (diff == null) {\n return;\n }\n this.diff = diff;\n const { options } = this.getRenderOptions(diff);\n let cache = this.workerManager?.getDiffResultCache(diff);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n diff,\n // NOTE(amadeus): If we're hydrating, we can assume there was\n // pre-rendered HTML, otherwise one should not be hydrating\n highlighted: true,\n options,\n result: cache?.result,\n };\n if (\n this.workerManager?.isWorkingPool() === true &&\n this.renderCache.result == null\n ) {\n this.workerManager.highlightDiffAST(this, this.diff);\n } else {\n void this.asyncHighlight(diff).then(({ result, options }) => {\n this.onHighlightSuccess(diff, result, options);\n });\n }\n }\n\n private getRenderOptions(diff: FileDiffMetadata): GetRenderOptionsReturn {\n const options: RenderDiffOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getDiffRenderOptions();\n }\n const { theme, tokenizeMaxLineLength, lineDiffType } =\n this.getOptionsWithDefaults();\n return { theme, tokenizeMaxLineLength, lineDiffType };\n })();\n this.getOptionsWithDefaults();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceRender: true };\n }\n if (\n diff !== renderCache.diff ||\n !areRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceRender: true };\n }\n return { options, forceRender: false };\n }\n\n renderDiff(\n diff: FileDiffMetadata | undefined = this.renderCache?.diff\n ): HunksRenderResult | undefined {\n if (diff == null) {\n return undefined;\n }\n const cache = this.workerManager?.getDiffResultCache(diff);\n if (cache != null && this.renderCache == null) {\n this.renderCache = { diff, highlighted: true, ...cache };\n }\n const { options, forceRender } = this.getRenderOptions(diff);\n this.renderCache ??= {\n diff,\n highlighted: false,\n options,\n result: undefined,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n this.renderCache.result ??= this.workerManager.getPlainDiffAST(diff);\n if (!this.renderCache.highlighted || forceRender) {\n this.workerManager.highlightDiffAST(this, diff);\n }\n } else {\n this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceRender ||\n (!this.renderCache.highlighted && hasLangs) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderDiffWithHighlighter(\n diff,\n this.highlighter,\n !hasLangs\n );\n this.renderCache = {\n diff,\n options,\n highlighted: hasLangs,\n result,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || !hasLangs) {\n void this.asyncHighlight(diff).then(({ result, options }) => {\n this.onHighlightSuccess(diff, result, options);\n });\n }\n }\n return this.renderCache.result != null\n ? this.processDiffResult(this.renderCache.diff, this.renderCache.result)\n : undefined;\n }\n\n async asyncRender(diff: FileDiffMetadata): Promise<HunksRenderResult> {\n const { result } = await this.asyncHighlight(diff);\n return this.processDiffResult(diff, result);\n }\n\n private createPreElement(\n split: boolean,\n totalLines: number,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const {\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n themeType,\n } = this.getOptionsWithDefaults();\n return createPreElement({\n diffIndicators,\n disableBackground,\n disableLineNumbers,\n overflow,\n themeStyles,\n split,\n themeType: baseThemeType ?? themeType,\n totalLines,\n });\n }\n\n private async asyncHighlight(\n diff: FileDiffMetadata\n ): Promise<RenderDiffResult> {\n this.computedLang = diff.lang ?? getFiletypeFromFileName(diff.name);\n const hasThemes =\n this.highlighter != null &&\n areThemesAttached(this.options.theme ?? DEFAULT_THEMES);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderDiffWithHighlighter(diff, this.highlighter);\n }\n\n private renderDiffWithHighlighter(\n diff: FileDiffMetadata,\n highlighter: DiffsHighlighter,\n plainText = false\n ): RenderDiffResult {\n const { options } = this.getRenderOptions(diff);\n const result = renderDiffWithHighlighter(\n diff,\n highlighter,\n options,\n plainText\n );\n return { result, options };\n }\n\n onHighlightSuccess(\n diff: FileDiffMetadata,\n result: ThemedDiffResult,\n options: RenderDiffOptions\n ): void {\n // If renderCache was blown away, we can assume we've run cleanUp()\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n this.renderCache.diff !== diff ||\n !this.renderCache.highlighted ||\n !areRenderOptionsEqual(this.renderCache.options, options);\n\n this.renderCache = {\n diff,\n options,\n highlighted: true,\n result,\n };\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private processDiffResult(\n fileDiff: FileDiffMetadata,\n { code, themeStyles, baseThemeType }: ThemedDiffResult\n ): HunksRenderResult {\n const { diffStyle, disableFileHeader } = this.getOptionsWithDefaults();\n\n this.diff = fileDiff;\n const unified = diffStyle === 'unified';\n\n let additionsAST: ElementContent[] | undefined = [];\n let deletionsAST: ElementContent[] | undefined = [];\n let unifiedAST: ElementContent[] | undefined = [];\n\n let hunkIndex = 0;\n const hunkData: HunkData[] = [];\n\n let prevHunk: Hunk | undefined;\n let lineIndex = 0;\n for (const hunk of fileDiff.hunks) {\n lineIndex += hunk.collapsedBefore;\n lineIndex = this.renderHunks({\n ast: code,\n hunk,\n prevHunk,\n hunkIndex,\n isLastHunk: hunkIndex === fileDiff.hunks.length - 1,\n additionsAST,\n deletionsAST,\n unifiedAST,\n hunkData,\n lineIndex,\n });\n hunkIndex++;\n prevHunk = hunk;\n }\n\n const totalLines = Math.max(\n getTotalLineCountFromHunks(fileDiff.hunks),\n fileDiff.newLines?.length ?? 0,\n fileDiff.oldLines?.length ?? 0\n );\n\n additionsAST =\n !unified && (code.hunks != null || code.newLines.length > 0)\n ? additionsAST\n : undefined;\n deletionsAST =\n !unified && (code.hunks != null || code.oldLines.length > 0)\n ? deletionsAST\n : undefined;\n unifiedAST = unifiedAST.length > 0 ? unifiedAST : undefined;\n\n const preNode = this.createPreElement(\n deletionsAST != null && additionsAST != null,\n totalLines,\n themeStyles,\n baseThemeType\n );\n\n return {\n additionsAST,\n deletionsAST,\n unifiedAST,\n hunkData,\n preNode,\n themeStyles,\n baseThemeType,\n headerElement: !disableFileHeader\n ? this.renderHeader(this.diff, themeStyles, baseThemeType)\n : undefined,\n totalLines,\n // FIXME\n css: '',\n };\n }\n\n renderFullAST(\n result: HunksRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n if (result.unifiedAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.unifiedAST,\n properties: {\n 'data-code': '',\n 'data-unified': '',\n },\n })\n );\n }\n if (result.deletionsAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.deletionsAST,\n properties: {\n 'data-code': '',\n 'data-deletions': '',\n },\n })\n );\n }\n if (result.additionsAST != null) {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.additionsAST,\n properties: {\n 'data-code': '',\n 'data-additions': '',\n },\n })\n );\n }\n return { ...result.preNode, children };\n }\n\n renderFullHTML(\n result: HunksRenderResult,\n tempChildren: ElementContent[] = []\n ): string {\n return toHtml(this.renderFullAST(result, tempChildren));\n }\n\n renderPartialHTML(\n children: ElementContent[],\n columnType?: 'unified' | 'deletions' | 'additions'\n ): string {\n if (columnType == null) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: {\n 'data-code': '',\n [`data-${columnType}`]: '',\n },\n })\n );\n }\n\n private renderCollapsedHunks({\n ast,\n hunkData,\n hunkIndex,\n hunkSpecs,\n isFirstHunk,\n isLastHunk,\n rangeSize,\n lineIndex,\n additionLineNumber,\n deletionLineNumber,\n unifiedAST,\n deletionsAST,\n additionsAST,\n }: RenderCollapsedHunksProps) {\n if (rangeSize <= 0) {\n return;\n }\n const { hunkSeparators, expandUnchanged, diffStyle, expansionLineCount } =\n this.getOptionsWithDefaults();\n const expandable =\n ast.hunks == null && ast.newLines.length > 0 && ast.oldLines.length > 0;\n const expandedRegion = this.expandedHunks.get(hunkIndex) ?? EXPANDED_REGION;\n const chunked = rangeSize > expansionLineCount;\n const collapsedLines = Math.max(\n !expandUnchanged\n ? rangeSize - (expandedRegion.fromEnd + expandedRegion.fromStart)\n : 0,\n 0\n );\n\n const pushHunkSeparator = ({ type, linesAST }: PushHunkSeparatorProps) => {\n if (hunkSeparators === 'line-info' || hunkSeparators === 'custom') {\n const slotName = getHunkSeparatorSlotName(type, hunkIndex);\n linesAST.push(\n createSeparator({\n type: hunkSeparators,\n content: getModifiedLinesString(collapsedLines),\n expandIndex: expandable ? hunkIndex : undefined,\n chunked,\n slotName,\n isFirstHunk,\n isLastHunk,\n })\n );\n hunkData.push({\n slotName,\n hunkIndex,\n lines: collapsedLines,\n type,\n expandable: expandable\n ? {\n up: expandable && !isFirstHunk,\n down: expandable,\n chunked,\n }\n : undefined,\n });\n } else if (hunkSeparators === 'metadata' && hunkSpecs != null) {\n linesAST.push(\n createSeparator({\n type: 'metadata',\n content: hunkSpecs,\n isFirstHunk,\n isLastHunk,\n })\n );\n } else if (hunkSeparators === 'simple' && hunkIndex > 0) {\n linesAST.push(\n createSeparator({ type: 'simple', isFirstHunk, isLastHunk: false })\n );\n }\n };\n\n const renderRange = ({ rangeLen, fromStart }: RenderRangeProps) => {\n if (ast.newLines == null || ast.oldLines == null) {\n return;\n }\n\n const offset = isLastHunk ? 0 : fromStart ? rangeSize : rangeLen;\n let dLineNumber = deletionLineNumber - offset;\n let aLineNumber = additionLineNumber - offset;\n let lIndex = lineIndex - offset;\n\n for (let i = 0; i < rangeLen; i++) {\n const oldLine = ast.oldLines[dLineNumber];\n const newLine = ast.newLines[aLineNumber];\n if (oldLine == null || newLine == null) {\n console.error({ aLineNumber, dLineNumber, ast });\n throw new Error(\n 'DiffHunksRenderer.renderHunks prefill context invalid. Must include data for old and new lines'\n );\n }\n dLineNumber++;\n aLineNumber++;\n\n if (diffStyle === 'unified') {\n this.pushLineWithAnnotation({\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n dLineNumber,\n aLineNumber,\n hunkIndex,\n lIndex\n ),\n });\n } else {\n this.pushLineWithAnnotation({\n newLine,\n oldLine,\n additionsAST,\n deletionsAST,\n ...this.getAnnotations(\n 'split',\n dLineNumber,\n aLineNumber,\n hunkIndex,\n lIndex\n ),\n });\n }\n lIndex++;\n }\n };\n\n if (expandable) {\n renderRange({\n rangeLen: Math.min(\n collapsedLines === 0 || expandUnchanged\n ? rangeSize\n : expandedRegion.fromStart,\n rangeSize\n ),\n fromStart: true,\n });\n }\n\n if (collapsedLines > 0) {\n if (diffStyle === 'unified') {\n pushHunkSeparator({ type: 'unified', linesAST: unifiedAST });\n } else {\n pushHunkSeparator({ type: 'deletions', linesAST: deletionsAST });\n pushHunkSeparator({ type: 'additions', linesAST: additionsAST });\n }\n }\n\n if (collapsedLines > 0 && expandedRegion.fromEnd > 0 && !isLastHunk) {\n renderRange({\n rangeLen: Math.min(expandedRegion.fromEnd, rangeSize),\n fromStart: false,\n });\n }\n }\n\n private renderHunks({\n hunk,\n hunkData,\n hunkIndex,\n lineIndex,\n isLastHunk,\n prevHunk,\n ast,\n deletionsAST,\n additionsAST,\n unifiedAST,\n }: RenderHunkProps): number {\n const { diffStyle } = this.getOptionsWithDefaults();\n const unified = diffStyle === 'unified';\n let additionLineNumber = hunk.additionStart - 1;\n let deletionLineNumber = hunk.deletionStart - 1;\n\n this.renderCollapsedHunks({\n additionLineNumber,\n additionsAST,\n ast,\n deletionLineNumber,\n deletionsAST,\n hunkData,\n hunkIndex,\n hunkSpecs: hunk.hunkSpecs,\n isFirstHunk: prevHunk == null,\n isLastHunk: false,\n lineIndex,\n rangeSize: Math.max(hunk.collapsedBefore, 0),\n unifiedAST,\n });\n\n let { oldLines, newLines, oldIndex, newIndex } = (() => {\n if (ast.hunks != null) {\n const lineHunk = ast.hunks[hunkIndex];\n if (lineHunk == null) {\n console.error({ ast, hunkIndex });\n throw new Error(\n `DiffHunksRenderer.renderHunks: lineHunk doesn't exist`\n );\n }\n return {\n oldLines: lineHunk.oldLines,\n newLines: lineHunk.newLines,\n oldIndex: 0,\n newIndex: 0,\n };\n }\n return {\n oldLines: ast.oldLines,\n newLines: ast.newLines,\n oldIndex: deletionLineNumber,\n newIndex: additionLineNumber,\n };\n })();\n\n // Render hunk/diff content\n for (const hunkContent of hunk.hunkContent) {\n if (hunkContent.type === 'context') {\n const { length: len } = hunkContent.lines;\n for (let i = 0; i < len; i++) {\n const oldLine = oldLines[oldIndex];\n const newLine = newLines[newIndex];\n oldIndex++;\n newIndex++;\n additionLineNumber++;\n deletionLineNumber++;\n if (unified) {\n if (newLine == null) {\n throw new Error(\n 'DiffHunksRenderer.renderHunks: newLine doesnt exist for context...'\n );\n }\n this.pushLineWithAnnotation({\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n deletionLineNumber,\n additionLineNumber,\n hunkIndex,\n lineIndex\n ),\n });\n } else {\n if (newLine == null || oldLine == null) {\n throw new Error(\n 'DiffHunksRenderer.renderHunks: newLine or oldLine doesnt exist for context...'\n );\n }\n this.pushLineWithAnnotation({\n oldLine,\n newLine,\n deletionsAST,\n additionsAST,\n ...this.getAnnotations(\n 'split',\n deletionLineNumber,\n additionLineNumber,\n hunkIndex,\n lineIndex\n ),\n });\n }\n lineIndex++;\n }\n if (hunkContent.noEOFCR) {\n const node = createNoNewlineElement('context');\n if (unified) {\n unifiedAST.push(node);\n } else {\n deletionsAST.push(node);\n additionsAST.push(node);\n }\n }\n } else {\n const { length: dLen } = hunkContent.deletions;\n const { length: aLen } = hunkContent.additions;\n const len = unified ? dLen + aLen : Math.max(dLen, aLen);\n let spanSize = 0;\n for (let i = 0; i < len; i++) {\n const { oldLine, newLine } = (() => {\n let oldLine: ElementContent | undefined = oldLines[oldIndex];\n let newLine: ElementContent | undefined = newLines[newIndex];\n if (unified) {\n if (i < dLen) {\n newLine = undefined;\n } else {\n oldLine = undefined;\n }\n } else {\n if (i >= dLen) {\n oldLine = undefined;\n }\n if (i >= aLen) {\n newLine = undefined;\n }\n }\n if (oldLine == null && newLine == null) {\n console.error({ i, len, ast, hunkContent });\n throw new Error(\n 'renderHunks: oldLine and newLine are null, something is wrong'\n );\n }\n return { oldLine, newLine };\n })();\n\n if (oldLine != null) {\n oldIndex++;\n deletionLineNumber++;\n }\n if (newLine != null) {\n newIndex++;\n additionLineNumber++;\n }\n\n if (unified) {\n this.pushLineWithAnnotation({\n oldLine,\n newLine,\n unifiedAST,\n unifiedSpan: this.getAnnotations(\n 'unified',\n oldLine != null ? deletionLineNumber : undefined,\n newLine != null ? additionLineNumber : undefined,\n hunkIndex,\n lineIndex\n ),\n });\n lineIndex++;\n } else {\n if (oldLine == null || newLine == null) {\n spanSize++;\n }\n const annotationSpans = this.getAnnotations(\n 'split',\n oldLine != null ? deletionLineNumber : undefined,\n newLine != null ? additionLineNumber : undefined,\n hunkIndex,\n lineIndex\n );\n if (annotationSpans != null) {\n if (spanSize > 0) {\n if (aLen > dLen) {\n deletionsAST.push(createEmptyRowBuffer(spanSize));\n } else {\n additionsAST.push(createEmptyRowBuffer(spanSize));\n }\n spanSize = 0;\n }\n }\n this.pushLineWithAnnotation({\n newLine,\n oldLine,\n deletionsAST,\n additionsAST,\n ...annotationSpans,\n });\n lineIndex++;\n }\n }\n if (!unified) {\n if (spanSize > 0) {\n if (aLen > dLen) {\n deletionsAST.push(createEmptyRowBuffer(spanSize));\n } else {\n additionsAST.push(createEmptyRowBuffer(spanSize));\n }\n spanSize = 0;\n }\n if (hunkContent.noEOFCRDeletions) {\n deletionsAST.push(createNoNewlineElement('change-deletion'));\n if (!hunkContent.noEOFCRAdditions) {\n additionsAST.push(createEmptyRowBuffer(1));\n }\n }\n if (hunkContent.noEOFCRAdditions) {\n additionsAST.push(createNoNewlineElement('change-addition'));\n if (!hunkContent.noEOFCRDeletions) {\n deletionsAST.push(createEmptyRowBuffer(1));\n }\n }\n }\n }\n }\n\n if (isLastHunk && ast.newLines != null && ast.newLines.length > 0) {\n this.renderCollapsedHunks({\n additionLineNumber,\n additionsAST,\n ast,\n deletionLineNumber,\n deletionsAST,\n hunkData,\n hunkIndex: hunkIndex + 1,\n hunkSpecs: undefined,\n isFirstHunk: false,\n isLastHunk: true,\n lineIndex,\n rangeSize: Math.max(\n ast.newLines.length -\n Math.max(hunk.additionStart + hunk.additionCount - 1, 0),\n 0\n ),\n unifiedAST,\n });\n }\n return lineIndex;\n }\n\n private pushLineWithAnnotation({\n newLine,\n oldLine,\n unifiedAST,\n additionsAST,\n deletionsAST,\n unifiedSpan,\n deletionSpan,\n additionSpan,\n }: PushLineWithAnnotation) {\n if (unifiedAST != null) {\n if (oldLine != null) {\n unifiedAST.push(oldLine);\n } else if (newLine != null) {\n unifiedAST.push(newLine);\n }\n if (unifiedSpan != null) {\n unifiedAST.push(createAnnotationElement(unifiedSpan));\n }\n } else if (deletionsAST != null && additionsAST != null) {\n if (oldLine != null) {\n deletionsAST.push(oldLine);\n }\n if (newLine != null) {\n additionsAST.push(newLine);\n }\n if (deletionSpan != null) {\n deletionsAST.push(createAnnotationElement(deletionSpan));\n }\n if (additionSpan != null) {\n additionsAST.push(createAnnotationElement(additionSpan));\n }\n }\n }\n\n private getAnnotations(\n type: 'unified',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ): AnnotationSpan | undefined;\n private getAnnotations(\n type: 'split',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ): { deletionSpan: AnnotationSpan; additionSpan: AnnotationSpan } | undefined;\n private getAnnotations(\n type: 'unified' | 'split',\n oldLineNumber: number | undefined,\n newLineNumber: number | undefined,\n hunkIndex: number,\n lineIndex: number\n ):\n | AnnotationSpan\n | { deletionSpan: AnnotationSpan; additionSpan: AnnotationSpan }\n | undefined {\n const deletionSpan: AnnotationSpan = {\n type: 'annotation',\n hunkIndex,\n lineIndex,\n annotations: [],\n };\n if (oldLineNumber != null) {\n for (const anno of this.deletionAnnotations[oldLineNumber] ?? []) {\n deletionSpan.annotations.push(getLineAnnotationName(anno));\n }\n }\n const additionSpan: AnnotationSpan = {\n type: 'annotation',\n hunkIndex,\n lineIndex,\n annotations: [],\n };\n if (newLineNumber != null) {\n for (const anno of this.additionAnnotations[newLineNumber] ?? []) {\n (type === 'unified' ? deletionSpan : additionSpan).annotations.push(\n getLineAnnotationName(anno)\n );\n }\n }\n if (type === 'unified') {\n if (deletionSpan.annotations.length > 0) {\n return deletionSpan;\n }\n return undefined;\n }\n if (\n additionSpan.annotations.length === 0 &&\n deletionSpan.annotations.length === 0\n ) {\n return undefined;\n }\n return { deletionSpan, additionSpan };\n }\n\n private renderHeader(\n diff: FileDiffMetadata,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const { themeType } = this.getOptionsWithDefaults();\n return createFileHeaderElement({\n fileOrDiff: diff,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n });\n }\n}\n\nfunction areRenderOptionsEqual(\n optionsA: RenderDiffOptions,\n optionsB: RenderDiffOptions\n): boolean {\n return (\n areThemesEqual(optionsA.theme, optionsB.theme) &&\n optionsA.tokenizeMaxLineLength === optionsB.tokenizeMaxLineLength &&\n optionsA.lineDiffType === optionsB.lineDiffType\n );\n}\n\nfunction getModifiedLinesString(lines: number) {\n return `${lines} unmodified line${lines > 1 ? 's' : ''}`;\n}\n"],"mappings":"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"}
|
|
@@ -94,14 +94,18 @@ var FileRenderer = class {
|
|
|
94
94
|
}
|
|
95
95
|
renderFile(file = this.renderCache?.file) {
|
|
96
96
|
if (file == null) return;
|
|
97
|
+
const cache = this.workerManager?.getFileResultCache(file);
|
|
98
|
+
if (cache != null && this.renderCache == null) this.renderCache = {
|
|
99
|
+
file,
|
|
100
|
+
highlighted: true,
|
|
101
|
+
...cache
|
|
102
|
+
};
|
|
97
103
|
const { options, forceRender } = this.getRenderOptions(file);
|
|
98
|
-
let cache = this.workerManager?.getFileResultCache(file);
|
|
99
|
-
if (cache != null && !areRenderOptionsEqual(options, cache.options)) cache = void 0;
|
|
100
104
|
this.renderCache ??= {
|
|
101
105
|
file,
|
|
102
|
-
highlighted:
|
|
103
|
-
options
|
|
104
|
-
result:
|
|
106
|
+
highlighted: false,
|
|
107
|
+
options,
|
|
108
|
+
result: void 0
|
|
105
109
|
};
|
|
106
110
|
if (this.workerManager?.isWorkingPool() === true) {
|
|
107
111
|
this.renderCache.result ??= this.workerManager.getPlainFileAST(file);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileRenderer.js","names":["options: FileRendererOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options","options: RenderFileOptions","codeAST: ElementContent[]"],"sources":["../../src/renderers/FileRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport { hasResolvedThemes } from '../highlighter/themes/hasResolvedThemes';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n FileContents,\n LineAnnotation,\n RenderFileOptions,\n RenderFileResult,\n RenderedFileASTCache,\n SupportedLanguages,\n ThemeTypes,\n ThemedFileResult,\n} from '../types';\nimport { areThemesEqual } from '../utils/areThemesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getThemes } from '../utils/getThemes';\nimport { createHastElement } from '../utils/hast_utils';\nimport { renderFileWithHighlighter } from '../utils/renderFileWithHighlighter';\nimport type { WorkerPoolManager } from '../worker';\n\ntype AnnotationLineMap<LAnnotation> = Record<\n number,\n LineAnnotation<LAnnotation>[] | undefined\n>;\n\ninterface GetRenderOptionsReturn {\n options: RenderFileOptions;\n forceRender: boolean;\n}\n\nexport interface FileRenderResult {\n codeAST: ElementContent[];\n preAST: HASTElement;\n headerAST: HASTElement | undefined;\n css: string;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface FileRendererOptions extends BaseCodeOptions {}\n\nexport class FileRenderer<LAnnotation = undefined> {\n private highlighter: DiffsHighlighter | undefined;\n private renderCache: RenderedFileASTCache | undefined;\n private computedLang: SupportedLanguages = 'text';\n private lineAnnotations: AnnotationLineMap<LAnnotation> = {};\n\n constructor(\n public options: FileRendererOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n setOptions(options: FileRendererOptions): void {\n this.options = options;\n }\n\n private mergeOptions(options: Partial<FileRendererOptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n setThemeType(themeType: ThemeTypes): void {\n const currentThemeType = this.options.themeType ?? 'system';\n if (currentThemeType === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n }\n\n setLineAnnotations(lineAnnotations: LineAnnotation<LAnnotation>[]): void {\n this.lineAnnotations = {};\n for (const annotation of lineAnnotations) {\n const arr = this.lineAnnotations[annotation.lineNumber] ?? [];\n this.lineAnnotations[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n cleanUp(): void {\n this.renderCache = undefined;\n this.highlighter = undefined;\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n hydrate(file: FileContents): void {\n const { options } = this.getRenderOptions(file);\n let cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n file,\n options,\n // NOTE(amadeus): If we're hydrating, we can assume there was\n // pre-rendered HTML, otherwise one should not be hydrating\n highlighted: true,\n result: cache?.result,\n };\n if (\n this.workerManager?.isWorkingPool() === true &&\n this.renderCache.result == null\n ) {\n this.workerManager.highlightFileAST(this, file);\n } else {\n void this.asyncHighlight(file).then(({ result, options }) => {\n this.onHighlightSuccess(file, result, options);\n });\n }\n }\n\n private getRenderOptions(file: FileContents): GetRenderOptionsReturn {\n const options: RenderFileOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getFileRenderOptions();\n }\n const { theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1000 } =\n this.options;\n return { theme, tokenizeMaxLineLength };\n })();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceRender: true };\n }\n if (\n file !== renderCache.file ||\n !areRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceRender: true };\n }\n return { options, forceRender: false };\n }\n\n renderFile(\n file: FileContents | undefined = this.renderCache?.file\n ): FileRenderResult | undefined {\n if (file == null) {\n return undefined;\n }\n const { options, forceRender } = this.getRenderOptions(file);\n let cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n file,\n highlighted: cache != null ? true : false,\n options: cache?.options ?? options,\n result: cache?.result,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n this.renderCache.result ??= this.workerManager.getPlainFileAST(file);\n // TODO(amadeus): Figure out how to only fire this on a per file\n // basis... (maybe the poolManager can figure it out based on file name\n // and file contents probably?)\n if (!this.renderCache.highlighted || forceRender) {\n this.workerManager.highlightFileAST(this, file);\n }\n } else {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceRender ||\n (!this.renderCache.highlighted && hasLangs) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderFileWithHighlighter(\n file,\n this.highlighter,\n !hasLangs\n );\n this.renderCache = {\n file,\n options,\n highlighted: hasLangs,\n result,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || !hasLangs) {\n void this.asyncHighlight(file).then(({ result, options }) => {\n this.onHighlightSuccess(file, result, options);\n });\n }\n }\n\n return this.renderCache.result != null\n ? this.processFileResult(this.renderCache.file, this.renderCache.result)\n : undefined;\n }\n\n async asyncRender(file: FileContents): Promise<FileRenderResult> {\n const { result } = await this.asyncHighlight(file);\n return this.processFileResult(file, result);\n }\n\n private async asyncHighlight(file: FileContents): Promise<RenderFileResult> {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null &&\n hasResolvedThemes(getThemes(this.options.theme));\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderFileWithHighlighter(file, this.highlighter);\n }\n\n private renderFileWithHighlighter(\n file: FileContents,\n highlighter: DiffsHighlighter,\n plainText = false\n ): RenderFileResult {\n const { options } = this.getRenderOptions(file);\n const result = renderFileWithHighlighter(\n file,\n highlighter,\n options,\n plainText\n );\n return { result, options };\n }\n\n private processFileResult(\n file: FileContents,\n result: ThemedFileResult\n ): FileRenderResult {\n const { disableFileHeader = false } = this.options;\n const codeAST: ElementContent[] = [];\n let lineIndex = 1;\n for (const line of result.code) {\n codeAST.push(line);\n const annotations = this.lineAnnotations[lineIndex];\n if (annotations != null) {\n codeAST.push(\n createAnnotationElement({\n type: 'annotation',\n hunkIndex: 0,\n lineIndex,\n annotations: annotations.map((annotation) =>\n getLineAnnotationName(annotation)\n ),\n })\n );\n }\n lineIndex++;\n }\n\n return {\n codeAST,\n preAST: this.createPreElement(\n result.code.length,\n result.themeStyles,\n result.baseThemeType\n ),\n headerAST: !disableFileHeader\n ? this.renderHeader(file, result.themeStyles, result.baseThemeType)\n : undefined,\n totalLines: result.code.length,\n themeStyles: result.themeStyles,\n baseThemeType: result.baseThemeType,\n // FIXME(amadeus): Fix this\n css: '',\n };\n }\n\n private renderHeader(\n file: FileContents,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ) {\n const { themeType = 'system' } = this.options;\n return createFileHeaderElement({\n fileOrDiff: file,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n });\n }\n\n renderFullHTML(result: FileRenderResult): string {\n return toHtml(this.renderFullAST(result));\n }\n\n renderFullAST(\n result: FileRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.codeAST,\n properties: { 'data-code': '' },\n })\n );\n return { ...result.preAST, children };\n }\n\n renderPartialHTML(\n children: ElementContent[],\n includeCodeNode: boolean = false\n ): string {\n if (!includeCodeNode) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: { 'data-code': '' },\n })\n );\n }\n\n async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n onHighlightSuccess(\n file: FileContents,\n result: ThemedFileResult,\n options: RenderFileOptions\n ): void {\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n this.renderCache.file !== file ||\n !this.renderCache.highlighted ||\n !areRenderOptionsEqual(options, this.renderCache.options);\n\n this.renderCache = {\n file,\n options,\n highlighted: true,\n result,\n };\n\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private createPreElement(\n totalLines: number,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const {\n disableLineNumbers = false,\n overflow = 'scroll',\n themeType = 'system',\n } = this.options;\n return createPreElement({\n diffIndicators: 'none',\n disableBackground: true,\n disableLineNumbers,\n overflow,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n split: false,\n totalLines,\n });\n }\n}\n\nfunction areRenderOptionsEqual(\n optionsA: RenderFileOptions,\n optionsB: RenderFileOptions\n): boolean {\n return (\n areThemesEqual(optionsA.theme, optionsB.theme) &&\n optionsA.tokenizeMaxLineLength === optionsB.tokenizeMaxLineLength\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileRenderer.js","names":["options: FileRendererOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options","options: RenderFileOptions","codeAST: ElementContent[]"],"sources":["../../src/renderers/FileRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport { hasResolvedThemes } from '../highlighter/themes/hasResolvedThemes';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n FileContents,\n LineAnnotation,\n RenderFileOptions,\n RenderFileResult,\n RenderedFileASTCache,\n SupportedLanguages,\n ThemeTypes,\n ThemedFileResult,\n} from '../types';\nimport { areThemesEqual } from '../utils/areThemesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getThemes } from '../utils/getThemes';\nimport { createHastElement } from '../utils/hast_utils';\nimport { renderFileWithHighlighter } from '../utils/renderFileWithHighlighter';\nimport type { WorkerPoolManager } from '../worker';\n\ntype AnnotationLineMap<LAnnotation> = Record<\n number,\n LineAnnotation<LAnnotation>[] | undefined\n>;\n\ninterface GetRenderOptionsReturn {\n options: RenderFileOptions;\n forceRender: boolean;\n}\n\nexport interface FileRenderResult {\n codeAST: ElementContent[];\n preAST: HASTElement;\n headerAST: HASTElement | undefined;\n css: string;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface FileRendererOptions extends BaseCodeOptions {}\n\nexport class FileRenderer<LAnnotation = undefined> {\n private highlighter: DiffsHighlighter | undefined;\n private renderCache: RenderedFileASTCache | undefined;\n private computedLang: SupportedLanguages = 'text';\n private lineAnnotations: AnnotationLineMap<LAnnotation> = {};\n\n constructor(\n public options: FileRendererOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n setOptions(options: FileRendererOptions): void {\n this.options = options;\n }\n\n private mergeOptions(options: Partial<FileRendererOptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n setThemeType(themeType: ThemeTypes): void {\n const currentThemeType = this.options.themeType ?? 'system';\n if (currentThemeType === themeType) {\n return;\n }\n this.mergeOptions({ themeType });\n }\n\n setLineAnnotations(lineAnnotations: LineAnnotation<LAnnotation>[]): void {\n this.lineAnnotations = {};\n for (const annotation of lineAnnotations) {\n const arr = this.lineAnnotations[annotation.lineNumber] ?? [];\n this.lineAnnotations[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n cleanUp(): void {\n this.renderCache = undefined;\n this.highlighter = undefined;\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n hydrate(file: FileContents): void {\n const { options } = this.getRenderOptions(file);\n let cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && !areRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n file,\n options,\n // NOTE(amadeus): If we're hydrating, we can assume there was\n // pre-rendered HTML, otherwise one should not be hydrating\n highlighted: true,\n result: cache?.result,\n };\n if (\n this.workerManager?.isWorkingPool() === true &&\n this.renderCache.result == null\n ) {\n this.workerManager.highlightFileAST(this, file);\n } else {\n void this.asyncHighlight(file).then(({ result, options }) => {\n this.onHighlightSuccess(file, result, options);\n });\n }\n }\n\n private getRenderOptions(file: FileContents): GetRenderOptionsReturn {\n const options: RenderFileOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getFileRenderOptions();\n }\n const { theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1000 } =\n this.options;\n return { theme, tokenizeMaxLineLength };\n })();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceRender: true };\n }\n if (\n file !== renderCache.file ||\n !areRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceRender: true };\n }\n return { options, forceRender: false };\n }\n\n renderFile(\n file: FileContents | undefined = this.renderCache?.file\n ): FileRenderResult | undefined {\n if (file == null) {\n return undefined;\n }\n const cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && this.renderCache == null) {\n this.renderCache = { file, highlighted: true, ...cache };\n }\n const { options, forceRender } = this.getRenderOptions(file);\n this.renderCache ??= {\n file,\n highlighted: false,\n options,\n result: undefined,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n this.renderCache.result ??= this.workerManager.getPlainFileAST(file);\n // TODO(amadeus): Figure out how to only fire this on a per file\n // basis... (maybe the poolManager can figure it out based on file name\n // and file contents probably?)\n if (!this.renderCache.highlighted || forceRender) {\n this.workerManager.highlightFileAST(this, file);\n }\n } else {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceRender ||\n (!this.renderCache.highlighted && hasLangs) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderFileWithHighlighter(\n file,\n this.highlighter,\n !hasLangs\n );\n this.renderCache = {\n file,\n options,\n highlighted: hasLangs,\n result,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || !hasLangs) {\n void this.asyncHighlight(file).then(({ result, options }) => {\n this.onHighlightSuccess(file, result, options);\n });\n }\n }\n\n return this.renderCache.result != null\n ? this.processFileResult(this.renderCache.file, this.renderCache.result)\n : undefined;\n }\n\n async asyncRender(file: FileContents): Promise<FileRenderResult> {\n const { result } = await this.asyncHighlight(file);\n return this.processFileResult(file, result);\n }\n\n private async asyncHighlight(file: FileContents): Promise<RenderFileResult> {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null &&\n hasResolvedThemes(getThemes(this.options.theme));\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderFileWithHighlighter(file, this.highlighter);\n }\n\n private renderFileWithHighlighter(\n file: FileContents,\n highlighter: DiffsHighlighter,\n plainText = false\n ): RenderFileResult {\n const { options } = this.getRenderOptions(file);\n const result = renderFileWithHighlighter(\n file,\n highlighter,\n options,\n plainText\n );\n return { result, options };\n }\n\n private processFileResult(\n file: FileContents,\n result: ThemedFileResult\n ): FileRenderResult {\n const { disableFileHeader = false } = this.options;\n const codeAST: ElementContent[] = [];\n let lineIndex = 1;\n for (const line of result.code) {\n codeAST.push(line);\n const annotations = this.lineAnnotations[lineIndex];\n if (annotations != null) {\n codeAST.push(\n createAnnotationElement({\n type: 'annotation',\n hunkIndex: 0,\n lineIndex,\n annotations: annotations.map((annotation) =>\n getLineAnnotationName(annotation)\n ),\n })\n );\n }\n lineIndex++;\n }\n\n return {\n codeAST,\n preAST: this.createPreElement(\n result.code.length,\n result.themeStyles,\n result.baseThemeType\n ),\n headerAST: !disableFileHeader\n ? this.renderHeader(file, result.themeStyles, result.baseThemeType)\n : undefined,\n totalLines: result.code.length,\n themeStyles: result.themeStyles,\n baseThemeType: result.baseThemeType,\n // FIXME(amadeus): Fix this\n css: '',\n };\n }\n\n private renderHeader(\n file: FileContents,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ) {\n const { themeType = 'system' } = this.options;\n return createFileHeaderElement({\n fileOrDiff: file,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n });\n }\n\n renderFullHTML(result: FileRenderResult): string {\n return toHtml(this.renderFullAST(result));\n }\n\n renderFullAST(\n result: FileRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n children.push(\n createHastElement({\n tagName: 'code',\n children: result.codeAST,\n properties: { 'data-code': '' },\n })\n );\n return { ...result.preAST, children };\n }\n\n renderPartialHTML(\n children: ElementContent[],\n includeCodeNode: boolean = false\n ): string {\n if (!includeCodeNode) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: { 'data-code': '' },\n })\n );\n }\n\n async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n onHighlightSuccess(\n file: FileContents,\n result: ThemedFileResult,\n options: RenderFileOptions\n ): void {\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n this.renderCache.file !== file ||\n !this.renderCache.highlighted ||\n !areRenderOptionsEqual(options, this.renderCache.options);\n\n this.renderCache = {\n file,\n options,\n highlighted: true,\n result,\n };\n\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private createPreElement(\n totalLines: number,\n themeStyles: string,\n baseThemeType: 'light' | 'dark' | undefined\n ): HASTElement {\n const {\n disableLineNumbers = false,\n overflow = 'scroll',\n themeType = 'system',\n } = this.options;\n return createPreElement({\n diffIndicators: 'none',\n disableBackground: true,\n disableLineNumbers,\n overflow,\n themeStyles,\n themeType: baseThemeType ?? themeType,\n split: false,\n totalLines,\n });\n }\n}\n\nfunction areRenderOptionsEqual(\n optionsA: RenderFileOptions,\n optionsB: RenderFileOptions\n): boolean {\n return (\n areThemesEqual(optionsA.theme, optionsB.theme) &&\n optionsA.tokenizeMaxLineLength === optionsB.tokenizeMaxLineLength\n );\n}\n"],"mappings":"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"}
|