@young1lin/dsh-ui-gitworkbench 0.1.3 → 0.1.5
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/AGENTS.md +1 -1
- package/CHANGELOG.md +48 -0
- package/CHANGELOG_EN.md +48 -0
- package/README.md +36 -6
- package/README_EN.md +3 -2
- package/lib/client.js +2126 -304
- package/lib/discard-ops.js +158 -0
- package/lib/fs-remove.js +73 -0
- package/lib/git-log.js +10 -6
- package/lib/git-ops.js +30 -9
- package/lib/index.js +191 -5
- package/lib/log-filter.js +71 -0
- package/lib/shortlog.js +40 -0
- package/package.json +1 -1
- package/src/client/GitWorkbenchPanel.module.css +523 -6
- package/src/client/GitWorkbenchPanel.tsx +1030 -26
- package/src/client/active-file.ts +83 -0
- package/src/client/calendar.ts +99 -0
- package/src/client/commit-filter.ts +49 -0
- package/src/client/dir-tree.ts +112 -0
- package/src/client/discard-flow.ts +82 -0
- package/src/client/file-filter.ts +66 -0
- package/src/client/index.ts +52 -5
- package/src/client/locales.ts +94 -0
- package/src/client/log-filter-query.ts +189 -0
- package/src/client/path-select.ts +131 -0
- package/src/discard-ops.ts +197 -0
- package/src/fs-remove.ts +76 -0
- package/src/git-log.ts +24 -6
- package/src/git-ops.ts +39 -7
- package/src/index.ts +191 -4
- package/src/log-filter.ts +87 -0
- package/src/shortlog.ts +46 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The history filter, compiled into `git log` arguments.
|
|
3
|
+
*
|
|
4
|
+
* This is the pushdown half of the IDEA-style filter: matching runs inside
|
|
5
|
+
* `git log` over ALL history, not client-side over the loaded pages — the
|
|
6
|
+
* loaded-pages blind spot is the reason this module exists. Everything here is
|
|
7
|
+
* pure so the argument matrix is testable without spawning git.
|
|
8
|
+
*
|
|
9
|
+
* DIALECT RULE: whenever any pattern is emitted, the flags are `-i -E` and
|
|
10
|
+
* every literal input is escaped for POSIX ERE. Mixing `--fixed-strings` with
|
|
11
|
+
* `-E` is not possible (one overrides the other for EVERY pattern on the
|
|
12
|
+
* command line), so a single dialect keeps users literal no matter what the
|
|
13
|
+
* text criterion's regex toggle says; regex text alone is passed raw.
|
|
14
|
+
*
|
|
15
|
+
* Dates pass through verbatim: approxidate ("2 weeks ago") is git's language,
|
|
16
|
+
* and reimplementing even a slice of it client-side is how the dual-semantics
|
|
17
|
+
* bug farm starts. An invalid date is git's error to raise, surfaced by the
|
|
18
|
+
* host's usual exit-code + stderr format.
|
|
19
|
+
*
|
|
20
|
+
* @module @young1lin/dsh-ui-gitworkbench/log-filter
|
|
21
|
+
*/
|
|
22
|
+
/** The filter that filters nothing — also the default when a client sends none. */
|
|
23
|
+
export function emptyLogFilter() {
|
|
24
|
+
return { users: [], text: '', textRegex: false, paths: [], after: '', before: '' };
|
|
25
|
+
}
|
|
26
|
+
/** POSIX ERE metacharacters, escaped so each matches itself. */
|
|
27
|
+
function escapeEre(literal) {
|
|
28
|
+
return literal.replace(/[\\.[\]*+?(){}|^$-]/g, '\\$&');
|
|
29
|
+
}
|
|
30
|
+
const DAY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
31
|
+
/**
|
|
32
|
+
* Expand a bare calendar day into an explicit moment. Git's approxidate
|
|
33
|
+
* parses `--since=2026-08-18` against an implementation-defined timezone,
|
|
34
|
+
* which on Windows silently excludes that very day's commits; `T00:00:00`
|
|
35
|
+
* pins it to local midnight (a picker day means the whole day, so `before`
|
|
36
|
+
* gets the day's last second instead).
|
|
37
|
+
*/
|
|
38
|
+
function expandDay(bound, endOfDay) {
|
|
39
|
+
if (!DAY_RE.test(bound))
|
|
40
|
+
return bound;
|
|
41
|
+
return endOfDay ? `${bound}T23:59:59` : `${bound}T00:00:00`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compile a filter into the argument segment inserted after the log command's
|
|
45
|
+
* own flags. Pathspecs come last behind a bare `--`, so the CALLER must place
|
|
46
|
+
* this segment at the end of the argument list.
|
|
47
|
+
* @param filter - the query; blank entries are dropped, not turned into empty
|
|
48
|
+
* patterns (an empty `--author=` would match nothing).
|
|
49
|
+
*/
|
|
50
|
+
export function logFilterArgs(filter) {
|
|
51
|
+
const users = filter.users.map(user => user.trim()).filter(user => user.length > 0);
|
|
52
|
+
const paths = filter.paths.map(path => path.trim()).filter(path => path.length > 0);
|
|
53
|
+
const text = filter.text.trim();
|
|
54
|
+
const after = filter.after.trim();
|
|
55
|
+
const before = filter.before.trim();
|
|
56
|
+
const args = [];
|
|
57
|
+
if (users.length > 0 || text.length > 0) {
|
|
58
|
+
args.push('-i', '-E');
|
|
59
|
+
for (const user of users)
|
|
60
|
+
args.push(`--author=${escapeEre(user)}`);
|
|
61
|
+
if (text.length > 0)
|
|
62
|
+
args.push(`--grep=${filter.textRegex ? text : escapeEre(text)}`);
|
|
63
|
+
}
|
|
64
|
+
if (after.length > 0)
|
|
65
|
+
args.push(`--since=${expandDay(after, false)}`);
|
|
66
|
+
if (before.length > 0)
|
|
67
|
+
args.push(`--until=${expandDay(before, true)}`);
|
|
68
|
+
if (paths.length > 0)
|
|
69
|
+
args.push('--', ...paths);
|
|
70
|
+
return args;
|
|
71
|
+
}
|
package/lib/shortlog.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author roster from `git shortlog -sne`, for the filter popup's user picker.
|
|
3
|
+
*
|
|
4
|
+
* The REF the roster walks is the caller's choice (the host passes the same
|
|
5
|
+
* ref the history list walks, or `--all` in All-branches mode); shortlog
|
|
6
|
+
* already did the aggregation, and this module only parses its fixed shape
|
|
7
|
+
* (`<count> <name> <<email>>`), sorts by activity and applies the cap — with
|
|
8
|
+
* the cap VISIBLE, because a filter popup that silently lost the long tail of
|
|
9
|
+
* occasional committers would be quietly wrong about who exists.
|
|
10
|
+
*
|
|
11
|
+
* @module @young1lin/dsh-ui-gitworkbench/shortlog
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Parse shortlog output into busiest-first authors, capped.
|
|
15
|
+
* @param stdout - `git shortlog -sne <ref>` output (the ref is the caller's choice).
|
|
16
|
+
* @param limit - how many authors to keep; the busier half survives.
|
|
17
|
+
* @returns the roster and whether it was cut short.
|
|
18
|
+
*/
|
|
19
|
+
export function parseShortlog(stdout, limit) {
|
|
20
|
+
const authors = [];
|
|
21
|
+
for (const line of stdout.split('\n')) {
|
|
22
|
+
const match = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
23
|
+
if (match === null)
|
|
24
|
+
continue;
|
|
25
|
+
const count = Number(match[1]);
|
|
26
|
+
const who = match[2];
|
|
27
|
+
// The email is the LAST <...> on the line; a name may legally contain
|
|
28
|
+
// anything else.
|
|
29
|
+
const emailMatch = /<([^>]*)>\s*$/.exec(who);
|
|
30
|
+
if (emailMatch === null)
|
|
31
|
+
continue;
|
|
32
|
+
const name = who.slice(0, emailMatch.index).trim();
|
|
33
|
+
if (name.length === 0)
|
|
34
|
+
continue;
|
|
35
|
+
authors.push({ name, email: emailMatch[1], count });
|
|
36
|
+
}
|
|
37
|
+
authors.sort((a, b) => b.count - a.count);
|
|
38
|
+
const truncated = authors.length > limit;
|
|
39
|
+
return { authors: truncated ? authors.slice(0, limit) : authors, truncated };
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@young1lin/dsh-ui-gitworkbench",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Out-of-tree dsh web UI plugin: a session-header git workbench chip opening a drawer with the file tree, per-file diff, history, compare, staging, commit, and sync (fetch/pull/push).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|