@solaqua/gji 0.13.0 → 0.15.0
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/dist/application/worktree/go-resolution.js +5 -3
- package/dist/application/worktree/sources.d.ts +13 -4
- package/dist/application/worktree/sources.js +34 -13
- package/dist/cli/commands/clean.d.ts +4 -2
- package/dist/cli/commands/clean.js +338 -65
- package/dist/cli/commands/go.d.ts +2 -1
- package/dist/cli/commands/go.js +17 -13
- package/dist/cli/commands/hub.js +4 -1
- package/dist/cli/commands/warp.js +6 -4
- package/dist/cli/program.js +5 -0
- package/dist/domain/shared/concurrency.d.ts +1 -1
- package/dist/domain/shared/concurrency.js +6 -1
- package/dist/domain/worktree/path-filter.d.ts +13 -0
- package/dist/domain/worktree/path-filter.js +72 -0
- package/dist/domain/worktree/policy.d.ts +1 -0
- package/dist/domain/worktree/policy.js +1 -1
- package/dist/gji-bundle.mjs +746 -368
- package/dist/infrastructure/git/refs.js +3 -11
- package/dist/presentation/shell/completion.js +7 -2
- package/dist/presentation/worktree/picker.d.ts +9 -6
- package/dist/presentation/worktree/picker.js +19 -2
- package/man/man1/gji-back.1 +1 -1
- package/man/man1/gji-clean.1 +4 -1
- package/man/man1/gji-completion.1 +1 -1
- package/man/man1/gji-config.1 +1 -1
- package/man/man1/gji-doctor.1 +1 -1
- package/man/man1/gji-done.1 +1 -1
- package/man/man1/gji-go.1 +1 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +1 -1
- package/man/man1/gji-ls.1 +1 -1
- package/man/man1/gji-new.1 +1 -1
- package/man/man1/gji-open.1 +1 -1
- package/man/man1/gji-pr.1 +1 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-run-hook.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync-files.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-task.1 +1 -1
- package/man/man1/gji-undo.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +1 -1
- package/package.json +1 -1
package/dist/cli/program.js
CHANGED
|
@@ -295,6 +295,7 @@ function registerCommands(program) {
|
|
|
295
295
|
.description("interactively prune linked worktrees")
|
|
296
296
|
.option("-f, --force", "bypass prompts, force-remove dirty worktrees, and force-delete unmerged branches")
|
|
297
297
|
.option("--stale", "only target clean worktrees whose upstream is gone and branch is merged into the default branch")
|
|
298
|
+
.option("--path <pattern>", "only target worktrees under a directory or matching a path glob (repeatable)", collectOption)
|
|
298
299
|
.option("--dry-run", "show what would be deleted without removing anything")
|
|
299
300
|
.option("--json", "emit JSON on success or error instead of human-readable output")
|
|
300
301
|
.action(notImplemented("clean"));
|
|
@@ -638,6 +639,7 @@ function attachCommandActions(program, options) {
|
|
|
638
639
|
dryRun: commandOptions.dryRun,
|
|
639
640
|
force: commandOptions.force,
|
|
640
641
|
json: commandOptions.json,
|
|
642
|
+
paths: commandOptions.path,
|
|
641
643
|
stale: commandOptions.stale,
|
|
642
644
|
runtime: options.dependencies,
|
|
643
645
|
stderr: options.stderr,
|
|
@@ -752,6 +754,9 @@ function requireCommand(parent, name) {
|
|
|
752
754
|
}
|
|
753
755
|
return command;
|
|
754
756
|
}
|
|
757
|
+
function collectOption(value, previous = []) {
|
|
758
|
+
return [...previous, value];
|
|
759
|
+
}
|
|
755
760
|
function notImplemented(commandName) {
|
|
756
761
|
return () => {
|
|
757
762
|
throw new Error(`'${commandName}' is not implemented yet.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function mapWithConcurrency<Input, Output>(items: readonly Input[], limit: number, mapper: (item: Input) => Promise<Output
|
|
1
|
+
export declare function mapWithConcurrency<Input, Output>(items: readonly Input[], limit: number, mapper: (item: Input) => Promise<Output>, signal?: AbortSignal): Promise<Output[]>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export async function mapWithConcurrency(items, limit, mapper) {
|
|
1
|
+
export async function mapWithConcurrency(items, limit, mapper, signal) {
|
|
2
2
|
const results = new Array(items.length);
|
|
3
3
|
let nextIndex = 0;
|
|
4
4
|
async function readNext() {
|
|
5
5
|
for (;;) {
|
|
6
|
+
throwIfAborted(signal);
|
|
6
7
|
const index = nextIndex;
|
|
7
8
|
nextIndex += 1;
|
|
8
9
|
if (index >= items.length)
|
|
@@ -13,3 +14,7 @@ export async function mapWithConcurrency(items, limit, mapper) {
|
|
|
13
14
|
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => readNext()));
|
|
14
15
|
return results;
|
|
15
16
|
}
|
|
17
|
+
function throwIfAborted(signal) {
|
|
18
|
+
if (signal?.aborted)
|
|
19
|
+
throw new Error("Operation cancelled");
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a predicate that matches worktree paths against any of the absolute
|
|
3
|
+
* patterns. A pattern without glob characters matches that directory and
|
|
4
|
+
* anything inside it. A pattern with `*` (within one segment), `**` (across
|
|
5
|
+
* segments), or `?` (one character) must match the whole path. A backslash
|
|
6
|
+
* makes the next character literal, so `\*` and `\?` match themselves. No
|
|
7
|
+
* patterns match every path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createWorktreePathFilter(patterns: readonly string[]): (worktreePath: string) => boolean;
|
|
10
|
+
/** Returns the index of the first unescaped glob character, or -1. */
|
|
11
|
+
export declare function findGlobIndex(pattern: string): number;
|
|
12
|
+
export declare function escapePathPattern(path: string): string;
|
|
13
|
+
export declare function unescapePathPattern(pattern: string): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a predicate that matches worktree paths against any of the absolute
|
|
3
|
+
* patterns. A pattern without glob characters matches that directory and
|
|
4
|
+
* anything inside it. A pattern with `*` (within one segment), `**` (across
|
|
5
|
+
* segments), or `?` (one character) must match the whole path. A backslash
|
|
6
|
+
* makes the next character literal, so `\*` and `\?` match themselves. No
|
|
7
|
+
* patterns match every path.
|
|
8
|
+
*/
|
|
9
|
+
export function createWorktreePathFilter(patterns) {
|
|
10
|
+
const matchers = patterns.map(createPathMatcher);
|
|
11
|
+
if (matchers.length === 0)
|
|
12
|
+
return () => true;
|
|
13
|
+
return (worktreePath) => matchers.some((matches) => matches(worktreePath));
|
|
14
|
+
}
|
|
15
|
+
/** Returns the index of the first unescaped glob character, or -1. */
|
|
16
|
+
export function findGlobIndex(pattern) {
|
|
17
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
18
|
+
const character = pattern[index];
|
|
19
|
+
if (character === "\\")
|
|
20
|
+
index += 1;
|
|
21
|
+
else if (character === "*" || character === "?")
|
|
22
|
+
return index;
|
|
23
|
+
}
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
26
|
+
export function escapePathPattern(path) {
|
|
27
|
+
return path.replace(/[\\*?]/g, "\\$&");
|
|
28
|
+
}
|
|
29
|
+
export function unescapePathPattern(pattern) {
|
|
30
|
+
return pattern.replace(/\\(.)/g, "$1");
|
|
31
|
+
}
|
|
32
|
+
function createPathMatcher(pattern) {
|
|
33
|
+
if (findGlobIndex(pattern) !== -1) {
|
|
34
|
+
const regExp = globToRegExp(pattern);
|
|
35
|
+
return (path) => regExp.test(path);
|
|
36
|
+
}
|
|
37
|
+
const literal = unescapePathPattern(pattern);
|
|
38
|
+
const prefix = literal === "/" ? "/" : `${literal}/`;
|
|
39
|
+
return (path) => path === literal || path.startsWith(prefix);
|
|
40
|
+
}
|
|
41
|
+
function globToRegExp(pattern) {
|
|
42
|
+
let source = "";
|
|
43
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
44
|
+
let character = pattern[index];
|
|
45
|
+
if (character === "*") {
|
|
46
|
+
if (pattern[index + 1] === "*") {
|
|
47
|
+
index += 1;
|
|
48
|
+
if (pattern[index + 1] === "/") {
|
|
49
|
+
index += 1;
|
|
50
|
+
source += "(?:.*/)?";
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
source += ".*";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
source += "[^/]*";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (character === "?") {
|
|
61
|
+
source += "[^/]";
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (character === "\\" && index + 1 < pattern.length) {
|
|
65
|
+
index += 1;
|
|
66
|
+
character = pattern[index];
|
|
67
|
+
}
|
|
68
|
+
source += character.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return new RegExp(`^${source}$`);
|
|
72
|
+
}
|