aboutsummaryrefslogtreecommitdiff
path: root/packages/server/src/git/patch.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src/git/patch.ts')
-rw-r--r--packages/server/src/git/patch.ts113
1 files changed, 113 insertions, 0 deletions
diff --git a/packages/server/src/git/patch.ts b/packages/server/src/git/patch.ts
new file mode 100644
index 0000000..71d9193
--- /dev/null
+++ b/packages/server/src/git/patch.ts
@@ -0,0 +1,113 @@
+import { Diff } from "./diff";
+import { ConvenientPatch as NodeGitPatch } from "nodegit";
+
+type Hunk = {
+ new_start: number,
+ new_lines_cnt: number,
+ old_start: number,
+ old_lines_cnt: number,
+ new_lines: number[],
+ deleted_lines: number[],
+ hunk: string
+}
+
+type Hunks = {
+ prev: null | number,
+ hunks: Hunk[]
+}
+
+function getHunkContent(hunk: string[]) {
+ interface Lines {
+ new_lines: number[],
+ deleted_lines: number[]
+ }
+
+ const lines = hunk.reduce((result: Lines, line, index) => {
+ if(line.charAt(0) === "+") {
+ hunk[index] = line.slice(1);
+ result.new_lines.push(index);
+ }
+ else if(line.charAt(0) === "-") {
+ hunk[index] = line.slice(1);
+ result.deleted_lines.push(index);
+ }
+ return result;
+ }, { new_lines: [], deleted_lines: [] });
+
+ return { ...lines, hunk: hunk.join("\n") };
+}
+
+export class Patch {
+ private _ng_patch: NodeGitPatch;
+
+ public from: string;
+ public to: string;
+ public additions: number;
+ public deletions: number;
+ public too_large = false;
+ public content: string | null = null;
+
+ constructor(diff: Diff, patch: NodeGitPatch, index: number) {
+ this._ng_patch = patch;
+
+ this.from = patch.oldFile().path();
+ this.to = patch.newFile().path();
+ this.additions = patch.lineStats()["total_additions"];
+ this.deletions = patch.lineStats()["total_deletions"];
+
+ const raw_patches_arr = diff.raw_patches.split("\n");
+ const start = diff.patch_header_indexes[index] + diff.patch_header_lengths[index];
+ const end = (typeof diff.patch_header_indexes[index + 1] === "undefined") ? raw_patches_arr.length - 1 : diff.patch_header_indexes[index + 1];
+
+ const patch_content = raw_patches_arr.slice(start, end);
+
+ if(patch_content.length !== 0) {
+ this.content = patch_content.join("\n");
+
+ const line_lengths = patch_content.map(line => line.length).reduce((result, length) => result + length);
+
+ if(patch_content.length > 5000 || line_lengths > 5000) {
+ this.too_large = true;
+ }
+ }
+ }
+
+ async getHunks(): Promise<Hunk[] | null> {
+ if(!this.content) {
+ return null;
+ }
+
+ const content = this.content.split("\n");
+ const hunks = await this._ng_patch.hunks();
+
+ const hunks_data = hunks.reduce((result: Hunks, hunk, hunk_index) => {
+ const hunk_header = hunk.header();
+ const hunk_header_index = content.indexOf(hunk_header.replace(/\n/gu, ""));
+
+ if(result.prev !== null) {
+ const prev_hunk = hunks[hunk_index - 1];
+ result.hunks.push({
+ new_start: prev_hunk.newStart(),
+ new_lines_cnt: prev_hunk.newLines(),
+ old_start: prev_hunk.oldStart(),
+ old_lines_cnt: prev_hunk.oldLines(),
+ ...getHunkContent(content.slice(result.prev, hunk_header_index))
+ });
+ }
+
+ result.prev = hunk_header_index;
+ return result;
+ }, { prev: null, hunks: [] });
+
+ const prev_hunk = hunks[hunks.length - 1];
+ hunks_data.hunks.push({
+ new_start: prev_hunk.newStart(),
+ new_lines_cnt: prev_hunk.newLines(),
+ old_start: prev_hunk.oldStart(),
+ old_lines_cnt: prev_hunk.oldLines(),
+ ...getHunkContent(content.slice(<number>hunks_data.prev))
+ });
+
+ return hunks_data.hunks;
+ }
+} \ No newline at end of file