@xbzbing/dsh-git-panel 1.5.3 → 1.5.4

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.
File without changes
@@ -2,7 +2,7 @@
2
2
  * git output parsers: porcelain status, log, branch, numstat, name-status.
3
3
  * Pure functions over raw stdout, no I/O.
4
4
  */
5
- import type { GitBranch, GitChange, GitCommit, GitFileStat, GraphCommit, GitRef, StashEntry } from './types.ts';
5
+ import type { GitBranch, GitChange, GitCommit, GitFileStat, GraphCommit, GitRef, StashEntry } from './types.js';
6
6
  /**
7
7
  * Build a GitCommit from a `%H\x1f%h\x1f%s\x1f%an\x1f%aI`-ordered field array
8
8
  * (the body, when present, is the caller's `parts.slice(5)`). Null when the
@@ -0,0 +1,213 @@
1
+ function commitFromFields(parts) {
2
+ const hash = parts[0];
3
+ if (parts.length < 5 || hash === void 0 || hash === "") return null;
4
+ return {
5
+ hash,
6
+ shortHash: parts[1] ?? "",
7
+ subject: parts[2] ?? "",
8
+ author: parts[3] ?? "",
9
+ dateIso: parts[4] ?? ""
10
+ };
11
+ }
12
+ function statusOf(code) {
13
+ switch (code) {
14
+ case "A":
15
+ return "added";
16
+ case "M":
17
+ return "modified";
18
+ case "D":
19
+ return "deleted";
20
+ case "R":
21
+ return "renamed";
22
+ case "C":
23
+ return "added";
24
+ case "T":
25
+ return "typechange";
26
+ case "U":
27
+ return "conflicted";
28
+ case "?":
29
+ return "untracked";
30
+ default:
31
+ return "modified";
32
+ }
33
+ }
34
+ function parseStatus(stdout) {
35
+ const out = [];
36
+ const records = stdout.split("\0");
37
+ for (let i = 0; i < records.length; i++) {
38
+ const rec = records[i];
39
+ if (rec === void 0 || rec.length < 3) continue;
40
+ const x = rec[0];
41
+ const y = rec[1];
42
+ let path = rec.slice(3);
43
+ if (x === "R" || x === "C" || y === "R" || y === "C") {
44
+ i++;
45
+ }
46
+ const isDirectory = path.endsWith("/");
47
+ if (isDirectory) path = path.replace(/\/+$/, "");
48
+ if (x === "?" && y === "?") {
49
+ out.push({ path, status: "untracked", staged: false, isDirectory });
50
+ continue;
51
+ }
52
+ if (x === "U" || y === "U" || x === "A" && y === "A" || x === "D" && y === "D") {
53
+ out.push({ path, status: "conflicted", staged: false, isDirectory });
54
+ continue;
55
+ }
56
+ if (x !== " " && x !== "?") {
57
+ out.push({ path, status: statusOf(x), staged: true, isDirectory });
58
+ }
59
+ if (y !== " " && y !== "?") {
60
+ out.push({ path, status: statusOf(y), staged: false, isDirectory });
61
+ }
62
+ }
63
+ return out;
64
+ }
65
+ function parseGraphLog(stdout) {
66
+ const out = [];
67
+ for (const record of stdout.split("")) {
68
+ const rec = record.replace(/^\n+/, "");
69
+ if (rec.trim() === "") continue;
70
+ const parts = rec.split("");
71
+ if (parts.length < 7) continue;
72
+ const [hash, shortHash, parentsRaw, author, dateIso, decoration] = parts;
73
+ const subject = parts.slice(6).join("");
74
+ const parents = (parentsRaw ?? "").trim() === "" ? [] : parentsRaw.trim().split(/\s+/);
75
+ out.push({
76
+ hash: hash ?? "",
77
+ shortHash: shortHash ?? "",
78
+ subject,
79
+ author: author ?? "",
80
+ dateIso: dateIso ?? "",
81
+ parents,
82
+ refs: parseRefs(decoration ?? "")
83
+ });
84
+ }
85
+ return out;
86
+ }
87
+ function parseRefs(decoration) {
88
+ const refs = [];
89
+ for (const raw of decoration.split(",")) {
90
+ let token = raw.trim();
91
+ if (token === "") continue;
92
+ let head = false;
93
+ if (token.startsWith("HEAD -> ")) {
94
+ head = true;
95
+ token = token.slice("HEAD -> ".length).trim();
96
+ } else if (token === "HEAD") {
97
+ continue;
98
+ }
99
+ if (token.startsWith("tag: ")) {
100
+ refs.push({ kind: "tag", name: token.slice("tag: ".length).trim().replace(/^refs\/tags\//, ""), head: false });
101
+ } else if (token.startsWith("refs/tags/")) {
102
+ refs.push({ kind: "tag", name: token.slice("refs/tags/".length), head: false });
103
+ } else if (token.startsWith("refs/remotes/")) {
104
+ refs.push({ kind: "remote", name: token.slice("refs/remotes/".length), head });
105
+ } else if (token.startsWith("refs/heads/")) {
106
+ refs.push({ kind: "branch", name: token.slice("refs/heads/".length), head });
107
+ } else if (head) {
108
+ refs.push({ kind: "branch", name: token, head });
109
+ } else if (token.startsWith("origin/") || token.includes("/")) {
110
+ refs.push({ kind: "remote", name: token, head });
111
+ } else {
112
+ refs.push({ kind: "branch", name: token, head });
113
+ }
114
+ }
115
+ return refs;
116
+ }
117
+ function parseBranches(stdout) {
118
+ const out = [];
119
+ for (const line of stdout.split("\n")) {
120
+ if (line.trim() === "") continue;
121
+ const [name, shortHash = "", track = ""] = line.split("\0");
122
+ if (name === void 0 || name === "") continue;
123
+ const branch = {
124
+ name,
125
+ shortHash: shortHash === "" ? null : shortHash
126
+ };
127
+ const ahead = /ahead (\d+)/.exec(track);
128
+ const behind = /behind (\d+)/.exec(track);
129
+ if (ahead) branch.ahead = Number(ahead[1]);
130
+ if (behind) branch.behind = Number(behind[1]);
131
+ out.push(branch);
132
+ }
133
+ return out;
134
+ }
135
+ function parseTags(stdout) {
136
+ const out = [];
137
+ for (const line of stdout.split("\n")) {
138
+ if (line.trim() === "") continue;
139
+ const [name, shortHash = ""] = line.split("\0");
140
+ if (name) out.push({ name, shortHash: shortHash === "" ? null : shortHash });
141
+ }
142
+ return out;
143
+ }
144
+ function parseStashList(stdout) {
145
+ const out = [];
146
+ for (const record of stdout.split("\0")) {
147
+ if (record.trim() === "") continue;
148
+ const [selector = "", sha = "", subject = "", relTime = ""] = record.split("");
149
+ const idxMatch = /stash@\{(\d+)\}/.exec(selector);
150
+ if (idxMatch === null) continue;
151
+ const index = Number(idxMatch[1]);
152
+ let branch = null;
153
+ let message = subject;
154
+ const m = /^(?:WIP on|On) (.+?): (.*)$/s.exec(subject);
155
+ if (m !== null) {
156
+ branch = m[1] === "(no branch)" ? null : m[1] ?? null;
157
+ message = m[2] ?? "";
158
+ }
159
+ out.push({ index, sha: sha.trim(), message: message.trim(), branch, relTime: relTime.trim() });
160
+ }
161
+ return out;
162
+ }
163
+ function parseNameStatus(stdout) {
164
+ const out = [];
165
+ const tokens = stdout.split("\0");
166
+ let i = 0;
167
+ while (i < tokens.length) {
168
+ const tok = tokens[i];
169
+ if (tok === void 0 || tok === "") {
170
+ i += 1;
171
+ continue;
172
+ }
173
+ const code = tok[0];
174
+ if (code === void 0 || !/[AMDRCTU]/.test(code)) break;
175
+ if (code === "R" || code === "C") {
176
+ const newPath = tokens[i + 2];
177
+ if (newPath === void 0) break;
178
+ out.push({ path: newPath, status: statusOf(code) });
179
+ i += 3;
180
+ } else {
181
+ const path = tokens[i + 1];
182
+ if (path === void 0) break;
183
+ if (path !== "") out.push({ path, status: statusOf(code) });
184
+ i += 2;
185
+ }
186
+ }
187
+ return out;
188
+ }
189
+ function sumNumstat(stdout) {
190
+ let insertions = 0;
191
+ let deletions = 0;
192
+ for (const line of stdout.split("\n")) {
193
+ if (line.trim() === "") continue;
194
+ const parts = line.split(" ");
195
+ if (parts.length < 2) continue;
196
+ const add = Number(parts[0]);
197
+ const del = Number(parts[1]);
198
+ if (Number.isFinite(add)) insertions += add;
199
+ if (Number.isFinite(del)) deletions += del;
200
+ }
201
+ return { insertions, deletions };
202
+ }
203
+ export {
204
+ commitFromFields,
205
+ parseBranches,
206
+ parseGraphLog,
207
+ parseNameStatus,
208
+ parseRefs,
209
+ parseStashList,
210
+ parseStatus,
211
+ parseTags,
212
+ sumNumstat
213
+ };
@@ -1,3 +1,3 @@
1
- import type { SnapshotDeps, GitPanelConfig } from './core.ts';
2
- import type { GitQueryRequest, GitQueryResponse } from './types.ts';
1
+ import type { SnapshotDeps, GitPanelConfig } from './core.js';
2
+ import type { GitQueryRequest, GitQueryResponse } from './types.js';
3
3
  export declare function runQuery(deps: SnapshotDeps, config: GitPanelConfig, request: GitQueryRequest): Promise<GitQueryResponse>;