@git-diff-view/core
Advanced tools
+5
-3
@@ -18,2 +18,3 @@ // Generated by dts-bundle-generator v9.5.1 | ||
| ast?: DiffAST; | ||
| theme?: "light" | "dark"; | ||
| rawFile: Record<number, string>; | ||
@@ -129,3 +130,3 @@ hasDoRaw: boolean; | ||
| getSplitHunkLine: (index: number) => DiffHunkItem; | ||
| onSplitHunkExpand: (dir: "up" | "down" | "all", index: number, needTrigger?: boolean) => void; | ||
| onSplitHunkExpand: (dir: "up" | "down" | "all" | "up-all" | "down-all", index: number, needTrigger?: boolean) => void; | ||
| getUnifiedLine: (index: number) => UnifiedLineItem; | ||
@@ -135,3 +136,3 @@ getUnifiedLineByLineNumber: (lienNumber: number, side: SplitSide) => UnifiedLineItem; | ||
| getUnifiedHunkLine: (index: number) => DiffHunkItem; | ||
| onUnifiedHunkExpand: (dir: "up" | "down" | "all", index: number, needTrigger?: boolean) => void; | ||
| onUnifiedHunkExpand: (dir: "up" | "down" | "all" | "up-all" | "down-all", index: number, needTrigger?: boolean) => void; | ||
| onAllExpand: (mode: "split" | "unified") => void; | ||
@@ -320,2 +321,3 @@ get hasExpandSplitAll(): boolean; | ||
| diffChanges?: DiffRange; | ||
| _diffChanges?: DiffRange; | ||
| plainTemplate?: string; | ||
@@ -325,3 +327,3 @@ plainTemplateMode?: "fast-diff" | "relative"; | ||
| syntaxTemplateMode?: "fast-diff" | "relative"; | ||
| constructor(text: string, type: DiffLineType, originalLineNumber: number | null, oldLineNumber: number | null, newLineNumber: number | null, noTrailingNewLine?: boolean, changes?: IRange, diffChanges?: DiffRange, plainTemplate?: string, plainTemplateMode?: "fast-diff" | "relative", syntaxTemplate?: string, syntaxTemplateMode?: "fast-diff" | "relative"); | ||
| constructor(text: string, type: DiffLineType, originalLineNumber: number | null, oldLineNumber: number | null, newLineNumber: number | null, noTrailingNewLine?: boolean, changes?: IRange, diffChanges?: DiffRange, _diffChanges?: DiffRange, plainTemplate?: string, plainTemplateMode?: "fast-diff" | "relative", syntaxTemplate?: string, syntaxTemplateMode?: "fast-diff" | "relative"); | ||
| withNoTrailingNewLine(noTrailingNewLine: boolean): DiffLine; | ||
@@ -328,0 +330,0 @@ isIncludeableLine(): boolean; |
+2
-2
@@ -6,3 +6,3 @@ { | ||
| "license": "MIT", | ||
| "version": "0.0.35", | ||
| "version": "0.0.36", | ||
| "main": "index.js", | ||
@@ -54,3 +54,3 @@ "types": "index.d.ts", | ||
| "dependencies": { | ||
| "@git-diff-view/lowlight": "^0.0.35", | ||
| "@git-diff-view/lowlight": "^0.0.36", | ||
| "highlight.js": "^11.11.0", | ||
@@ -57,0 +57,0 @@ "lowlight": "^3.3.0", |
+124
-33
@@ -1,52 +0,143 @@ | ||
| ## `git diff` for @git-diff-view Component | ||
| # @git-diff-view/core | ||
| > Core diff engine for git diff processing with syntax highlighting | ||
| [](https://www.npmjs.com/package/@git-diff-view/core) | ||
| [](https://www.npmjs.com/package/@git-diff-view/core) | ||
| ## Features | ||
| - ✅ Git diff parsing and processing | ||
| - ✅ Syntax highlighting with HAST AST | ||
| - ✅ Split & Unified view data generation | ||
| - ✅ Web Worker / Node.js compatible | ||
| - ✅ Bundle-based data transfer | ||
| - ✅ Theme support (light/dark) | ||
| ## Installation | ||
| ```bash | ||
| npm install @git-diff-view/core | ||
| # or | ||
| pnpm add @git-diff-view/core | ||
| # or | ||
| yarn add @git-diff-view/core | ||
| ``` | ||
| ## Usage | ||
| ```tsx | ||
| // ==== step1: generate diff view data, this part can be used in the worker/server environment for better performance ==== // | ||
| ### Basic Usage | ||
| ```typescript | ||
| import { DiffFile } from "@git-diff-view/core"; | ||
| // Create diff file instance | ||
| const file = new DiffFile( | ||
| data?.oldFile?.fileName || "", | ||
| data?.oldFile?.content || "", | ||
| data?.newFile?.fileName || "", | ||
| data?.newFile?.content || "", | ||
| data?.hunks || [], | ||
| data?.oldFile?.fileLang || "", | ||
| data?.newFile?.fileLang || "" | ||
| ); | ||
| // light / dark theme, base on current highlight engine | ||
| // default is light | ||
| file.initTheme(xxx); | ||
| // init | ||
| oldFileName, | ||
| oldContent, | ||
| newFileName, | ||
| newContent, | ||
| hunks, // git diff hunks | ||
| oldFileLang, // e.g., "typescript" | ||
| newFileLang | ||
| ); | ||
| // Initialize theme (optional, default: light) | ||
| file.initTheme('dark'); | ||
| // Initialize diff data | ||
| file.init(); | ||
| // or you can use below method to init | ||
| file.initRaw(); | ||
| file.initSyntax(); // if you do not want syntax highlight, you can skip this step | ||
| // build the `Split View` data; | ||
| // Build view data | ||
| file.buildSplitDiffLines(); // For split view | ||
| file.buildUnifiedDiffLines(); // For unified view | ||
| ``` | ||
| ### Advanced: Separate Initialization | ||
| ```typescript | ||
| // For more control over initialization | ||
| file.initRaw(); // Parse git diff | ||
| file.initSyntax(); // Apply syntax highlighting (optional) | ||
| file.buildSplitDiffLines(); | ||
| file.buildUnifiedDiffLines(); | ||
| ``` | ||
| // build the `Unified View` data; | ||
| ### Worker/Server Pattern | ||
| Process diff data in a separate thread or server for better performance: | ||
| ```typescript | ||
| // Worker/Server side - generate bundle | ||
| const file = new DiffFile(/* ... */); | ||
| file.initTheme('dark'); | ||
| file.init(); | ||
| file.buildSplitDiffLines(); | ||
| file.buildUnifiedDiffLines(); | ||
| // get All the diff data bundle, you can safely to send this data to the client side | ||
| const bundle = file.getBundle(); | ||
| // Send bundle to main thread/client | ||
| // ==== step2: render the @git-diff-view component ==== // | ||
| // Main thread/Client side - reconstruct | ||
| import { DiffFile } from "@git-diff-view/core"; | ||
| // merge bundle | ||
| const mergeFile = DiffFile.createInstance(data || {}, bundle); | ||
| const mergedFile = DiffFile.createInstance(data, bundle); | ||
| // used for @git-diff-view/react and @git-diff-view/vue | ||
| <DiffView diffFile={mergeFile} /> | ||
| // Use with UI components | ||
| <DiffView diffFile={mergedFile} /> | ||
| ``` | ||
| <DiffView :diffFile="mergeFile" /> | ||
| ## API Reference | ||
| ### DiffFile Class | ||
| #### Constructor | ||
| ```typescript | ||
| new DiffFile( | ||
| oldFileName: string, | ||
| oldContent: string, | ||
| newFileName: string, | ||
| newContent: string, | ||
| hunks: string[], | ||
| oldFileLang?: string, | ||
| newFileLang?: string | ||
| ) | ||
| ``` | ||
| ## Screen Shot | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
| #### Methods | ||
| | Method | Description | | ||
| |--------|-------------| | ||
| | `initTheme(theme)` | Set theme ('light' or 'dark') | | ||
| | `init()` | Initialize diff data (calls initRaw + initSyntax) | | ||
| | `initRaw()` | Parse git diff without syntax highlighting | | ||
| | `initSyntax()` | Apply syntax highlighting | | ||
| | `buildSplitDiffLines()` | Generate split view data | | ||
| | `buildUnifiedDiffLines()` | Generate unified view data | | ||
| | `getBundle()` | Export data for transfer | | ||
| #### Static Methods | ||
| | Method | Description | | ||
| |--------|-------------| | ||
| | `createInstance(data, bundle)` | Reconstruct DiffFile from bundle | | ||
| ## Use Cases | ||
| - **Client-side**: Direct rendering with UI frameworks | ||
| - **Worker pattern**: Offload processing to Web Worker | ||
| - **Server-side**: Pre-process diffs in Node.js, send to client | ||
| - **Hybrid**: Mix of client and server processing | ||
| ## Related Packages | ||
| - [@git-diff-view/react](https://www.npmjs.com/package/@git-diff-view/react) - React components | ||
| - [@git-diff-view/vue](https://www.npmjs.com/package/@git-diff-view/vue) - Vue components | ||
| - [@git-diff-view/file](https://www.npmjs.com/package/@git-diff-view/file) - File comparison mode | ||
| - [@git-diff-view/lowlight](https://www.npmjs.com/package/@git-diff-view/lowlight) - Syntax highlighter | ||
| ## License | ||
| MIT © [MrWangJustToDo](https://github.com/MrWangJustToDo) |
+78
-7
@@ -364,3 +364,10 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
| } | ||
| if (!hasSymbolChanged && oldFileContent === newFileContent) return; | ||
| if (!hasSymbolChanged && oldFileContent === newFileContent) { | ||
| if (__DEV__) { | ||
| console.warn( | ||
| 'the composed "oldFileContent" and "newFileContent" are the same, maybe the "diff" string is not valid' | ||
| ); | ||
| } | ||
| return; | ||
| } | ||
| this._oldFileContent = oldFileContent; | ||
@@ -773,3 +780,3 @@ this._newFileContent = newFileContent; | ||
| if (__DEV__ && !this.#oldFileResult && !this.#newFileResult && this.#composeByMerge) { | ||
| if (__DEV__ && !this.#oldFileResult && !this.#newFileResult && this.#composeByMerge && !this.#composeByFullMerge) { | ||
| console.error( | ||
@@ -960,3 +967,3 @@ "this instance can not `buildSplitDiffLines` because of the data missing, try to use '_getFullBundle' & '_mergeFullBundle' instead of 'getBundle' & 'mergeBundle'" | ||
| if (__DEV__ && !this.#oldFileResult && !this.#newFileResult && this.#composeByMerge) { | ||
| if (__DEV__ && !this.#oldFileResult && !this.#newFileResult && this.#composeByMerge && !this.#composeByFullMerge) { | ||
| console.error( | ||
@@ -1158,3 +1165,3 @@ "this instance can not `buildUnifiedDiffLines` because of the data missing, try to use '_getFullBundle' & '_mergeFullBundle' instead of 'getBundle' & 'mergeBundle'" | ||
| onSplitHunkExpand = (dir: "up" | "down" | "all", index: number, needTrigger = true) => { | ||
| onSplitHunkExpand = (dir: "up" | "down" | "all" | "up-all" | "down-all", index: number, needTrigger = true) => { | ||
| const current = this.#splitHunksLines?.[index]; | ||
@@ -1197,3 +1204,15 @@ if (!current || !current.splitInfo) return; | ||
| } | ||
| } else { | ||
| } else if (dir === "down-all") { | ||
| for (let i = current.splitInfo.startHiddenIndex; i < current.splitInfo.endHiddenIndex; i++) { | ||
| const leftLine = this.#splitLeftLines[i]; | ||
| const rightLine = this.#splitRightLines[i]; | ||
| if (leftLine?.isHidden) leftLine.isHidden = false; | ||
| if (rightLine?.isHidden) rightLine.isHidden = false; | ||
| } | ||
| current.splitInfo = { | ||
| ...current.splitInfo, | ||
| plainText: "", | ||
| startHiddenIndex: current.splitInfo.endHiddenIndex, | ||
| }; | ||
| } else if (dir === "up") { | ||
| if (current.isLast) { | ||
@@ -1228,2 +1247,24 @@ if (__DEV__) { | ||
| this.#splitHunksLines![current.splitInfo.endHiddenIndex] = current; | ||
| } else if (dir === "up-all") { | ||
| if (current.isLast) { | ||
| if (__DEV__) { | ||
| console.error("the last hunk can not expand up!"); | ||
| } | ||
| return; | ||
| } | ||
| for (let i = current.splitInfo.startHiddenIndex; i < current.splitInfo.endHiddenIndex; i++) { | ||
| const leftLine = this.#splitLeftLines[i]; | ||
| const rightLine = this.#splitRightLines[i]; | ||
| if (leftLine?.isHidden) leftLine.isHidden = false; | ||
| if (rightLine?.isHidden) rightLine.isHidden = false; | ||
| } | ||
| current.splitInfo = { | ||
| ...current.splitInfo, | ||
| plainText: "", | ||
| endHiddenIndex: current.splitInfo.startHiddenIndex, | ||
| }; | ||
| delete this.#splitHunksLines?.[index]; | ||
| this.#splitHunksLines![current.splitInfo.endHiddenIndex] = current; | ||
| } | ||
@@ -1261,3 +1302,3 @@ | ||
| // TODO! support rollback? | ||
| onUnifiedHunkExpand = (dir: "up" | "down" | "all", index: number, needTrigger = true) => { | ||
| onUnifiedHunkExpand = (dir: "up" | "down" | "all" | "up-all" | "down-all", index: number, needTrigger = true) => { | ||
| if (this.#composeByDiff) return; | ||
@@ -1299,3 +1340,13 @@ | ||
| } | ||
| } else { | ||
| } else if (dir === "down-all") { | ||
| for (let i = current.unifiedInfo.startHiddenIndex; i < current.unifiedInfo.endHiddenIndex; i++) { | ||
| const unifiedLine = this.#unifiedLines[i]; | ||
| if (unifiedLine?.isHidden) unifiedLine.isHidden = false; | ||
| } | ||
| current.unifiedInfo = { | ||
| ...current.unifiedInfo, | ||
| plainText: "", | ||
| startHiddenIndex: current.unifiedInfo.endHiddenIndex, | ||
| }; | ||
| } else if (dir === "up") { | ||
| if (current.isLast) { | ||
@@ -1328,2 +1379,22 @@ if (__DEV__) { | ||
| this.#unifiedHunksLines![current.unifiedInfo.endHiddenIndex] = current; | ||
| } else if (dir === "up-all") { | ||
| if (current.isLast) { | ||
| if (__DEV__) { | ||
| console.error("the last hunk can not expand up!"); | ||
| } | ||
| return; | ||
| } | ||
| for (let i = current.unifiedInfo.startHiddenIndex; i < current.unifiedInfo.endHiddenIndex; i++) { | ||
| const unifiedLine = this.#unifiedLines[i]; | ||
| if (unifiedLine?.isHidden) unifiedLine.isHidden = false; | ||
| } | ||
| current.unifiedInfo = { | ||
| ...current.unifiedInfo, | ||
| plainText: "", | ||
| endHiddenIndex: current.unifiedInfo.startHiddenIndex, | ||
| }; | ||
| delete this.#unifiedHunksLines?.[index]; | ||
| this.#unifiedHunksLines![current.unifiedInfo.endHiddenIndex] = current; | ||
| } | ||
@@ -1330,0 +1401,0 @@ |
+7
-1
@@ -37,2 +37,4 @@ import { highlighter } from "@git-diff-view/lowlight"; | ||
| theme?: "light" | "dark"; | ||
| rawFile: Record<number, string> = {}; | ||
@@ -65,2 +67,4 @@ | ||
| file.theme = data?.theme; | ||
| file.rawFile = data?.rawFile || {}; | ||
@@ -110,3 +114,3 @@ | ||
| }) { | ||
| if (!this.raw || this.hasDoSyntax) return; | ||
| if (!this.raw || (this.hasDoSyntax && this.theme === theme)) return; | ||
@@ -143,2 +147,4 @@ const finalHighlighter = registerHighlighter || highlighter; | ||
| this.theme = theme; | ||
| if (!this.ast) return; | ||
@@ -145,0 +151,0 @@ |
@@ -24,2 +24,3 @@ import type { DiffRange, IRange } from "./change-range"; | ||
| public diffChanges?: DiffRange, | ||
| public _diffChanges?: DiffRange, | ||
| public plainTemplate?: string, | ||
@@ -26,0 +27,0 @@ public plainTemplateMode?: "fast-diff" | "relative", |
@@ -339,3 +339,3 @@ /* eslint-disable max-lines */ | ||
| if (!line) { | ||
| if (line === null) { | ||
| throw new Error("Expected unified diff line but reached end of diff"); | ||
@@ -446,3 +446,3 @@ } | ||
| do { | ||
| while (this.peek()) { | ||
| const hunk = this.parseHunk(linesConsumed, hunks.length, previousHunk); | ||
@@ -452,3 +452,3 @@ hunks.push(hunk); | ||
| linesConsumed += hunk.lines.length; | ||
| } while (this.peek()); | ||
| } | ||
@@ -455,0 +455,0 @@ const contents = this.text |
@@ -185,2 +185,4 @@ import { diffChanges, relativeChanges } from "./change-range"; | ||
| deletion.diffChanges = delRange; | ||
| addition._diffChanges = delRange; | ||
| deletion._diffChanges = addRange; | ||
| getPlainDiffTemplateByFastDiff({ | ||
@@ -187,0 +189,0 @@ diffLine: addition, |
+11
-13
@@ -195,2 +195,4 @@ import { addContentHighlightBGName, delContentHighlightBGName, getSymbol } from "@git-diff-view/utils"; | ||
| const _changes = diffLine._diffChanges; | ||
| if (!changes || !changes.hasLineChange) return; | ||
@@ -202,4 +204,6 @@ | ||
| const allRange = changes.range.filter((item) => item.type !== 0); | ||
| const allRange = changes?.range?.filter((item) => item.type !== 0) || []; | ||
| const _allRange = _changes?.range?.filter((item) => item.type !== 0) || []; | ||
| let rangeIndex = 0; | ||
@@ -214,2 +218,4 @@ | ||
| const noDiff = allRange.length === 0 && _allRange.length === 0; | ||
| const isLastNode = index === array.length - 1; | ||
@@ -226,5 +232,2 @@ | ||
| template += transform(value); | ||
| if (isEndStr && changes.newLineSymbol) { | ||
| template += `<span data-newline-symbol data-diff-highlight style="background-color: var(${operator === "add" ? addContentHighlightBGName : delContentHighlightBGName});border-radius: 0.2em;">${getSymbol(changes.newLineSymbol)}</span>`; | ||
| } | ||
| // start of range | ||
@@ -240,5 +243,2 @@ } else if (index === range.startIndex) { | ||
| template += transform(value); | ||
| if (isEndStr && changes.newLineSymbol) { | ||
| template += `<span data-newline-symbol>${getSymbol(changes.newLineSymbol)}</span>`; | ||
| } | ||
| if (isLastStr) { | ||
@@ -268,5 +268,2 @@ template += `</span>`; | ||
| template += transform(value); | ||
| if (isEndStr && changes.newLineSymbol) { | ||
| template += `<span data-newline-symbol>${getSymbol(changes.newLineSymbol)}</span>`; | ||
| } | ||
| if (isLastStr) { | ||
@@ -287,5 +284,2 @@ template += `</span>`; | ||
| } | ||
| if (isEndStr && changes.newLineSymbol) { | ||
| template += `<span data-newline-symbol>${getSymbol(changes.newLineSymbol)}</span>`; | ||
| } | ||
| template += `</span>`; | ||
@@ -298,2 +292,6 @@ rangeIndex++; | ||
| template += transform(value); | ||
| if (noDiff && isEndStr && changes.newLineSymbol) { | ||
| template += `<span data-diff-highlight style="background-color: var(${operator === "add" ? addContentHighlightBGName : delContentHighlightBGName});border-radius: 0.2em;">`; | ||
| template += `<span data-newline-symbol>${getSymbol(changes.newLineSymbol)}</span></span>`; | ||
| } | ||
| } | ||
@@ -300,0 +298,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1162846
2.5%12618
1.91%144
171.7%49
6.52%+ Added
- Removed