dubstack 0.1.3 → 0.3.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/README.md +22 -1
- package/dist/index.js +1180 -105
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/dist/commands/create.d.ts +0 -18
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -35
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/init.d.ts +0 -18
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -41
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/log.d.ts +0 -12
- package/dist/commands/log.d.ts.map +0 -1
- package/dist/commands/log.js +0 -77
- package/dist/commands/log.js.map +0 -1
- package/dist/commands/restack.d.ts +0 -33
- package/dist/commands/restack.d.ts.map +0 -1
- package/dist/commands/restack.js +0 -190
- package/dist/commands/restack.js.map +0 -1
- package/dist/commands/undo.d.ts +0 -21
- package/dist/commands/undo.d.ts.map +0 -1
- package/dist/commands/undo.js +0 -63
- package/dist/commands/undo.js.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/errors.d.ts +0 -15
- package/dist/lib/errors.d.ts.map +0 -1
- package/dist/lib/errors.js +0 -18
- package/dist/lib/errors.js.map +0 -1
- package/dist/lib/git.d.ts +0 -69
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js +0 -184
- package/dist/lib/git.js.map +0 -1
- package/dist/lib/state.d.ts +0 -70
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js +0 -110
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/undo-log.d.ts +0 -33
- package/dist/lib/undo-log.d.ts.map +0 -1
- package/dist/lib/undo-log.js +0 -37
- package/dist/lib/undo-log.js.map +0 -1
package/dist/commands/restack.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { DubError } from "../lib/errors.js";
|
|
4
|
-
import { branchExists, checkoutBranch, getBranchTip, getCurrentBranch, getMergeBase, rebaseContinue as gitRebaseContinue, isWorkingTreeClean, rebaseOnto, } from "../lib/git.js";
|
|
5
|
-
import { getDubDir, readState } from "../lib/state.js";
|
|
6
|
-
import { saveUndoEntry } from "../lib/undo-log.js";
|
|
7
|
-
/**
|
|
8
|
-
* Rebases all branches in the current stack onto their updated parents.
|
|
9
|
-
*
|
|
10
|
-
* Uses a snapshot-before-rebase strategy: captures every branch's tip
|
|
11
|
-
* BEFORE starting any rebases, then uses `git rebase --onto <parent_new_tip>
|
|
12
|
-
* <parent_old_tip> <child>`. This prevents the duplication bug where a child
|
|
13
|
-
* replays its parent's already-rebased commits.
|
|
14
|
-
*
|
|
15
|
-
* On conflict, writes progress to `restack-progress.json` so
|
|
16
|
-
* `dub restack --continue` can resume.
|
|
17
|
-
*
|
|
18
|
-
* @param cwd - Working directory
|
|
19
|
-
* @returns Result with status, list of rebased branches, and optional conflict branch
|
|
20
|
-
* @throws {DubError} If not initialized, dirty tree, not in a stack, or branch missing
|
|
21
|
-
*/
|
|
22
|
-
export async function restack(cwd) {
|
|
23
|
-
const state = await readState(cwd);
|
|
24
|
-
if (!(await isWorkingTreeClean(cwd))) {
|
|
25
|
-
throw new DubError("Working tree has uncommitted changes. Commit or stash them before restacking.");
|
|
26
|
-
}
|
|
27
|
-
const originalBranch = await getCurrentBranch(cwd);
|
|
28
|
-
const targetStacks = getTargetStacks(state.stacks, originalBranch);
|
|
29
|
-
if (targetStacks.length === 0) {
|
|
30
|
-
throw new DubError(`Branch '${originalBranch}' is not part of any stack. Run 'dub create' first.`);
|
|
31
|
-
}
|
|
32
|
-
const allBranches = targetStacks.flatMap((s) => s.branches);
|
|
33
|
-
for (const branch of allBranches) {
|
|
34
|
-
if (!(await branchExists(branch.name, cwd))) {
|
|
35
|
-
throw new DubError(`Branch '${branch.name}' is tracked in state but no longer exists in git.\n` +
|
|
36
|
-
" Remove it from the stack or recreate it before restacking.");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
// Snapshot all branch tips BEFORE building steps or rebasing
|
|
40
|
-
const branchTips = {};
|
|
41
|
-
for (const branch of allBranches) {
|
|
42
|
-
branchTips[branch.name] = await getBranchTip(branch.name, cwd);
|
|
43
|
-
}
|
|
44
|
-
const steps = await buildRestackSteps(targetStacks, cwd);
|
|
45
|
-
if (steps.length === 0) {
|
|
46
|
-
return { status: "up-to-date", rebased: [] };
|
|
47
|
-
}
|
|
48
|
-
await saveUndoEntry({
|
|
49
|
-
operation: "restack",
|
|
50
|
-
timestamp: new Date().toISOString(),
|
|
51
|
-
previousBranch: originalBranch,
|
|
52
|
-
previousState: structuredClone(state),
|
|
53
|
-
branchTips,
|
|
54
|
-
createdBranches: [],
|
|
55
|
-
}, cwd);
|
|
56
|
-
const progress = { originalBranch, steps };
|
|
57
|
-
await writeProgress(progress, cwd);
|
|
58
|
-
return executeRestackSteps(progress, cwd);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Continues a restack after conflict resolution.
|
|
62
|
-
*
|
|
63
|
-
* Reads the saved progress file, finishes the in-progress rebase,
|
|
64
|
-
* then resumes with remaining branches.
|
|
65
|
-
*
|
|
66
|
-
* @param cwd - Working directory
|
|
67
|
-
* @throws {DubError} If no restack is in progress
|
|
68
|
-
*/
|
|
69
|
-
export async function restackContinue(cwd) {
|
|
70
|
-
const progress = await readProgress(cwd);
|
|
71
|
-
if (!progress) {
|
|
72
|
-
throw new DubError("No restack in progress. Run 'dub restack' to start.");
|
|
73
|
-
}
|
|
74
|
-
await gitRebaseContinue(cwd);
|
|
75
|
-
const conflictedStep = progress.steps.find((s) => s.status === "conflicted");
|
|
76
|
-
if (conflictedStep) {
|
|
77
|
-
conflictedStep.status = "done";
|
|
78
|
-
}
|
|
79
|
-
return executeRestackSteps(progress, cwd);
|
|
80
|
-
}
|
|
81
|
-
async function executeRestackSteps(progress, cwd) {
|
|
82
|
-
const rebased = [];
|
|
83
|
-
for (const step of progress.steps) {
|
|
84
|
-
if (step.status !== "pending") {
|
|
85
|
-
if (step.status === "done")
|
|
86
|
-
rebased.push(step.branch);
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
const parentNewTip = await getBranchTip(step.parent, cwd);
|
|
90
|
-
if (parentNewTip === step.parentOldTip) {
|
|
91
|
-
step.status = "skipped";
|
|
92
|
-
await writeProgress(progress, cwd);
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
await rebaseOnto(parentNewTip, step.parentOldTip, step.branch, cwd);
|
|
97
|
-
step.status = "done";
|
|
98
|
-
rebased.push(step.branch);
|
|
99
|
-
await writeProgress(progress, cwd);
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
if (error instanceof DubError && error.message.includes("Conflict")) {
|
|
103
|
-
step.status = "conflicted";
|
|
104
|
-
await writeProgress(progress, cwd);
|
|
105
|
-
return { status: "conflict", rebased, conflictBranch: step.branch };
|
|
106
|
-
}
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
await clearProgress(cwd);
|
|
111
|
-
await checkoutBranch(progress.originalBranch, cwd);
|
|
112
|
-
const allSkipped = progress.steps.every((s) => s.status === "skipped" || s.status === "done");
|
|
113
|
-
return {
|
|
114
|
-
status: rebased.length === 0 && allSkipped ? "up-to-date" : "success",
|
|
115
|
-
rebased,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function getTargetStacks(stacks, currentBranch) {
|
|
119
|
-
// If current branch is a root of any stacks, restack all of them
|
|
120
|
-
const rootStacks = stacks.filter((s) => s.branches.some((b) => b.name === currentBranch && b.type === "root"));
|
|
121
|
-
if (rootStacks.length > 0)
|
|
122
|
-
return rootStacks;
|
|
123
|
-
// Otherwise, find the stack containing the current branch
|
|
124
|
-
const stack = stacks.find((s) => s.branches.some((b) => b.name === currentBranch));
|
|
125
|
-
return stack ? [stack] : [];
|
|
126
|
-
}
|
|
127
|
-
async function buildRestackSteps(stacks, cwd) {
|
|
128
|
-
const steps = [];
|
|
129
|
-
for (const stack of stacks) {
|
|
130
|
-
const ordered = topologicalOrder(stack);
|
|
131
|
-
for (const branch of ordered) {
|
|
132
|
-
if (branch.type === "root" || !branch.parent)
|
|
133
|
-
continue;
|
|
134
|
-
const mergeBase = await getMergeBase(branch.parent, branch.name, cwd);
|
|
135
|
-
steps.push({
|
|
136
|
-
branch: branch.name,
|
|
137
|
-
parent: branch.parent,
|
|
138
|
-
parentOldTip: mergeBase,
|
|
139
|
-
status: "pending",
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return steps;
|
|
144
|
-
}
|
|
145
|
-
function topologicalOrder(stack) {
|
|
146
|
-
const result = [];
|
|
147
|
-
const root = stack.branches.find((b) => b.type === "root");
|
|
148
|
-
if (!root)
|
|
149
|
-
return result;
|
|
150
|
-
const childMap = new Map();
|
|
151
|
-
for (const branch of stack.branches) {
|
|
152
|
-
if (branch.parent) {
|
|
153
|
-
const children = childMap.get(branch.parent) ?? [];
|
|
154
|
-
children.push(branch);
|
|
155
|
-
childMap.set(branch.parent, children);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const queue = [root];
|
|
159
|
-
while (queue.length > 0) {
|
|
160
|
-
const current = queue.shift();
|
|
161
|
-
if (!current)
|
|
162
|
-
break;
|
|
163
|
-
result.push(current);
|
|
164
|
-
const children = childMap.get(current.name) ?? [];
|
|
165
|
-
queue.push(...children);
|
|
166
|
-
}
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
|
-
async function getProgressPath(cwd) {
|
|
170
|
-
const dubDir = await getDubDir(cwd);
|
|
171
|
-
return path.join(dubDir, "restack-progress.json");
|
|
172
|
-
}
|
|
173
|
-
async function writeProgress(progress, cwd) {
|
|
174
|
-
const progressPath = await getProgressPath(cwd);
|
|
175
|
-
fs.writeFileSync(progressPath, `${JSON.stringify(progress, null, 2)}\n`);
|
|
176
|
-
}
|
|
177
|
-
async function readProgress(cwd) {
|
|
178
|
-
const progressPath = await getProgressPath(cwd);
|
|
179
|
-
if (!fs.existsSync(progressPath))
|
|
180
|
-
return null;
|
|
181
|
-
const raw = fs.readFileSync(progressPath, "utf-8");
|
|
182
|
-
return JSON.parse(raw);
|
|
183
|
-
}
|
|
184
|
-
async function clearProgress(cwd) {
|
|
185
|
-
const progressPath = await getProgressPath(cwd);
|
|
186
|
-
if (fs.existsSync(progressPath)) {
|
|
187
|
-
fs.unlinkSync(progressPath);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
//# sourceMappingURL=restack.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"restack.js","sourceRoot":"","sources":["../../src/commands/restack.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/undo.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
interface UndoResult {
|
|
2
|
-
undone: "create" | "restack";
|
|
3
|
-
details: string;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Undoes the last `dub create` or `dub restack` operation.
|
|
7
|
-
*
|
|
8
|
-
* Reversal strategy:
|
|
9
|
-
* - **create**: Deletes the created branch, restores state, checks out the previous branch.
|
|
10
|
-
* - **restack**: Resets every rebased branch to its pre-rebase tip via `git branch -f`,
|
|
11
|
-
* restores state, checks out the previous branch.
|
|
12
|
-
*
|
|
13
|
-
* Only one level of undo is supported. After undo, the undo entry is cleared.
|
|
14
|
-
*
|
|
15
|
-
* @param cwd - Working directory
|
|
16
|
-
* @returns What was undone and a human-readable summary
|
|
17
|
-
* @throws {DubError} If nothing to undo or working tree is dirty
|
|
18
|
-
*/
|
|
19
|
-
export declare function undo(cwd: string): Promise<UndoResult>;
|
|
20
|
-
export {};
|
|
21
|
-
//# sourceMappingURL=undo.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/commands/undo.ts"],"names":[],"mappings":"AAWA,UAAU,UAAU;IACnB,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA4D3D"}
|
package/dist/commands/undo.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { DubError } from "../lib/errors.js";
|
|
2
|
-
import { checkoutBranch, deleteBranch, forceBranchTo, getCurrentBranch, isWorkingTreeClean, } from "../lib/git.js";
|
|
3
|
-
import { writeState } from "../lib/state.js";
|
|
4
|
-
import { clearUndoEntry, readUndoEntry } from "../lib/undo-log.js";
|
|
5
|
-
/**
|
|
6
|
-
* Undoes the last `dub create` or `dub restack` operation.
|
|
7
|
-
*
|
|
8
|
-
* Reversal strategy:
|
|
9
|
-
* - **create**: Deletes the created branch, restores state, checks out the previous branch.
|
|
10
|
-
* - **restack**: Resets every rebased branch to its pre-rebase tip via `git branch -f`,
|
|
11
|
-
* restores state, checks out the previous branch.
|
|
12
|
-
*
|
|
13
|
-
* Only one level of undo is supported. After undo, the undo entry is cleared.
|
|
14
|
-
*
|
|
15
|
-
* @param cwd - Working directory
|
|
16
|
-
* @returns What was undone and a human-readable summary
|
|
17
|
-
* @throws {DubError} If nothing to undo or working tree is dirty
|
|
18
|
-
*/
|
|
19
|
-
export async function undo(cwd) {
|
|
20
|
-
const entry = await readUndoEntry(cwd);
|
|
21
|
-
if (!(await isWorkingTreeClean(cwd))) {
|
|
22
|
-
throw new DubError("Working tree has uncommitted changes. Commit or stash them before undoing.");
|
|
23
|
-
}
|
|
24
|
-
const currentBranch = await getCurrentBranch(cwd);
|
|
25
|
-
if (entry.operation === "create") {
|
|
26
|
-
// If we're on a branch that's about to be deleted, switch away first
|
|
27
|
-
const needsCheckout = entry.createdBranches.includes(currentBranch);
|
|
28
|
-
if (needsCheckout) {
|
|
29
|
-
await checkoutBranch(entry.previousBranch, cwd);
|
|
30
|
-
}
|
|
31
|
-
for (const branch of entry.createdBranches) {
|
|
32
|
-
await deleteBranch(branch, cwd);
|
|
33
|
-
}
|
|
34
|
-
if (!needsCheckout && currentBranch !== entry.previousBranch) {
|
|
35
|
-
await checkoutBranch(entry.previousBranch, cwd);
|
|
36
|
-
}
|
|
37
|
-
await writeState(entry.previousState, cwd);
|
|
38
|
-
await clearUndoEntry(cwd);
|
|
39
|
-
return {
|
|
40
|
-
undone: "create",
|
|
41
|
-
details: `Deleted branch${entry.createdBranches.length > 1 ? "es" : ""} '${entry.createdBranches.join("', '")}'`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
// restack undo: reset all branches to their pre-rebase tips
|
|
45
|
-
// First checkout a safe branch so we don't conflict with force-moves
|
|
46
|
-
await checkoutBranch(entry.previousBranch, cwd);
|
|
47
|
-
for (const [name, sha] of Object.entries(entry.branchTips)) {
|
|
48
|
-
if (name === entry.previousBranch)
|
|
49
|
-
continue; // skip the branch we're on
|
|
50
|
-
await forceBranchTo(name, sha, cwd);
|
|
51
|
-
}
|
|
52
|
-
// Now force the branch we're on (if it was tracked)
|
|
53
|
-
if (entry.branchTips[entry.previousBranch]) {
|
|
54
|
-
await forceBranchTo(entry.previousBranch, entry.branchTips[entry.previousBranch], cwd);
|
|
55
|
-
}
|
|
56
|
-
await writeState(entry.previousState, cwd);
|
|
57
|
-
await clearUndoEntry(cwd);
|
|
58
|
-
return {
|
|
59
|
-
undone: "restack",
|
|
60
|
-
details: `Reset ${Object.keys(entry.branchTips).length} branches to pre-restack state`,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=undo.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/commands/undo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACN,cAAc,EACd,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAW;IACrC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IAEvC,IAAI,CAAC,CAAC,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CACjB,4EAA4E,CAC5E,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAElD,IAAI,KAAK,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,qEAAqE;QACrE,MAAM,aAAa,GAAG,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACpE,IAAI,aAAa,EAAE,CAAC;YACnB,MAAM,cAAc,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;YAC5C,MAAM,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC,aAAa,IAAI,aAAa,KAAK,KAAK,CAAC,cAAc,EAAE,CAAC;YAC9D,MAAM,cAAc,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,UAAU,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;QAE1B,OAAO;YACN,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,iBAAiB,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;SAChH,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,qEAAqE;IACrE,MAAM,cAAc,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAEhD,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5D,IAAI,IAAI,KAAK,KAAK,CAAC,cAAc;YAAE,SAAS,CAAC,2BAA2B;QACxE,MAAM,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,oDAAoD;IACpD,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QAC5C,MAAM,aAAa,CAClB,KAAK,CAAC,cAAc,EACpB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,EACtC,GAAG,CACH,CAAC;IACH,CAAC;IAED,MAAM,UAAU,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC3C,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;IAE1B,OAAO;QACN,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,gCAAgC;KACtF,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* DubStack CLI — manage stacked diffs with ease.
|
|
4
|
-
*
|
|
5
|
-
* A local-first tool for managing chains of dependent git branches
|
|
6
|
-
* (stacked diffs) without manually dealing with complex rebase chains.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```bash
|
|
10
|
-
* dub init # Initialize in current repo
|
|
11
|
-
* dub create feat/my-branch # Create stacked branch
|
|
12
|
-
* dub log # View stack tree
|
|
13
|
-
* dub restack # Rebase stack onto updated parent
|
|
14
|
-
* dub undo # Undo last dub operation
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* @packageDocumentation
|
|
18
|
-
*/
|
|
19
|
-
export {};
|
|
20
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;GAgBG"}
|
package/dist/lib/errors.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base error class for all user-facing DubStack errors.
|
|
3
|
-
*
|
|
4
|
-
* The CLI entry point catches instances of this class and prints
|
|
5
|
-
* a clean, colored error message. Unknown errors get a full stack trace.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* throw new DubError("Branch 'feat/x' already exists")
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export declare class DubError extends Error {
|
|
13
|
-
constructor(message: string);
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/lib/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,qBAAa,QAAS,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI3B"}
|
package/dist/lib/errors.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base error class for all user-facing DubStack errors.
|
|
3
|
-
*
|
|
4
|
-
* The CLI entry point catches instances of this class and prints
|
|
5
|
-
* a clean, colored error message. Unknown errors get a full stack trace.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* throw new DubError("Branch 'feat/x' already exists")
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export class DubError extends Error {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message);
|
|
15
|
-
this.name = "DubError";
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=errors.js.map
|
package/dist/lib/errors.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IAClC,YAAY,OAAe;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACxB,CAAC;CACD"}
|
package/dist/lib/git.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks whether the given directory is inside a git repository.
|
|
3
|
-
* @returns `true` if inside a git worktree, `false` otherwise. Never throws.
|
|
4
|
-
*/
|
|
5
|
-
export declare function isGitRepo(cwd: string): Promise<boolean>;
|
|
6
|
-
/**
|
|
7
|
-
* Returns the absolute path to the repository root.
|
|
8
|
-
* @throws {DubError} If not inside a git repository.
|
|
9
|
-
*/
|
|
10
|
-
export declare function getRepoRoot(cwd: string): Promise<string>;
|
|
11
|
-
/**
|
|
12
|
-
* Returns the name of the currently checked-out branch.
|
|
13
|
-
* @throws {DubError} If HEAD is detached or the repo has no commits.
|
|
14
|
-
*/
|
|
15
|
-
export declare function getCurrentBranch(cwd: string): Promise<string>;
|
|
16
|
-
/**
|
|
17
|
-
* Checks whether a branch with the given name exists locally.
|
|
18
|
-
* @returns `true` if the branch exists, `false` otherwise. Never throws.
|
|
19
|
-
*/
|
|
20
|
-
export declare function branchExists(name: string, cwd: string): Promise<boolean>;
|
|
21
|
-
/**
|
|
22
|
-
* Creates a new branch and switches to it.
|
|
23
|
-
* @throws {DubError} If a branch with that name already exists.
|
|
24
|
-
*/
|
|
25
|
-
export declare function createBranch(name: string, cwd: string): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Switches to an existing branch.
|
|
28
|
-
* @throws {DubError} If the branch does not exist.
|
|
29
|
-
*/
|
|
30
|
-
export declare function checkoutBranch(name: string, cwd: string): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* Deletes a local branch forcefully. Used by undo to remove created branches.
|
|
33
|
-
* @throws {DubError} If the branch does not exist.
|
|
34
|
-
*/
|
|
35
|
-
export declare function deleteBranch(name: string, cwd: string): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* Force-moves a branch pointer to a specific commit SHA.
|
|
38
|
-
* Used by undo to reset branches to their pre-operation tips.
|
|
39
|
-
*/
|
|
40
|
-
export declare function forceBranchTo(name: string, sha: string, cwd: string): Promise<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Checks whether the working tree is clean (no uncommitted changes).
|
|
43
|
-
* @returns `true` if clean (no output from `git status --porcelain`).
|
|
44
|
-
*/
|
|
45
|
-
export declare function isWorkingTreeClean(cwd: string): Promise<boolean>;
|
|
46
|
-
/**
|
|
47
|
-
* Performs `git rebase --onto` to move a branch from one base to another.
|
|
48
|
-
*
|
|
49
|
-
* @param newBase - The commit/branch to rebase onto
|
|
50
|
-
* @param oldBase - The old base commit to replay from
|
|
51
|
-
* @param branch - The branch being rebased
|
|
52
|
-
* @throws {DubError} If a merge conflict occurs during rebase
|
|
53
|
-
*/
|
|
54
|
-
export declare function rebaseOnto(newBase: string, oldBase: string, branch: string, cwd: string): Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* Continues an in-progress rebase after conflicts have been resolved.
|
|
57
|
-
* @throws {DubError} If the rebase continue fails.
|
|
58
|
-
*/
|
|
59
|
-
export declare function rebaseContinue(cwd: string): Promise<void>;
|
|
60
|
-
/**
|
|
61
|
-
* Returns the merge-base (common ancestor) commit SHA of two branches.
|
|
62
|
-
*/
|
|
63
|
-
export declare function getMergeBase(a: string, b: string, cwd: string): Promise<string>;
|
|
64
|
-
/**
|
|
65
|
-
* Returns the commit SHA at the tip of a branch.
|
|
66
|
-
* @throws {DubError} If the branch does not exist.
|
|
67
|
-
*/
|
|
68
|
-
export declare function getBranchTip(name: string, cwd: string): Promise<string>;
|
|
69
|
-
//# sourceMappingURL=git.d.ts.map
|
package/dist/lib/git.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW7D;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW9D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBnE;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3E;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM7E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGtE;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/D;AAED;;GAEG;AACH,wBAAsB,YAAY,CACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,CAAC,CASjB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7E"}
|
package/dist/lib/git.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { execa } from "execa";
|
|
2
|
-
import { DubError } from "./errors.js";
|
|
3
|
-
/**
|
|
4
|
-
* Checks whether the given directory is inside a git repository.
|
|
5
|
-
* @returns `true` if inside a git worktree, `false` otherwise. Never throws.
|
|
6
|
-
*/
|
|
7
|
-
export async function isGitRepo(cwd) {
|
|
8
|
-
try {
|
|
9
|
-
const { stdout } = await execa("git", ["rev-parse", "--is-inside-work-tree"], { cwd });
|
|
10
|
-
return stdout.trim() === "true";
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Returns the absolute path to the repository root.
|
|
18
|
-
* @throws {DubError} If not inside a git repository.
|
|
19
|
-
*/
|
|
20
|
-
export async function getRepoRoot(cwd) {
|
|
21
|
-
try {
|
|
22
|
-
const { stdout } = await execa("git", ["rev-parse", "--show-toplevel"], {
|
|
23
|
-
cwd,
|
|
24
|
-
});
|
|
25
|
-
return stdout.trim();
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
throw new DubError("Not a git repository. Run this command inside a git repo.");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Returns the name of the currently checked-out branch.
|
|
33
|
-
* @throws {DubError} If HEAD is detached or the repo has no commits.
|
|
34
|
-
*/
|
|
35
|
-
export async function getCurrentBranch(cwd) {
|
|
36
|
-
try {
|
|
37
|
-
const { stdout } = await execa("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
|
|
38
|
-
const branch = stdout.trim();
|
|
39
|
-
if (branch === "HEAD") {
|
|
40
|
-
throw new DubError("HEAD is detached. Checkout a branch before running this command.");
|
|
41
|
-
}
|
|
42
|
-
return branch;
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
if (error instanceof DubError)
|
|
46
|
-
throw error;
|
|
47
|
-
throw new DubError("Repository has no commits. Make at least one commit first.");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Checks whether a branch with the given name exists locally.
|
|
52
|
-
* @returns `true` if the branch exists, `false` otherwise. Never throws.
|
|
53
|
-
*/
|
|
54
|
-
export async function branchExists(name, cwd) {
|
|
55
|
-
try {
|
|
56
|
-
await execa("git", ["rev-parse", "--verify", `refs/heads/${name}`], {
|
|
57
|
-
cwd,
|
|
58
|
-
});
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Creates a new branch and switches to it.
|
|
67
|
-
* @throws {DubError} If a branch with that name already exists.
|
|
68
|
-
*/
|
|
69
|
-
export async function createBranch(name, cwd) {
|
|
70
|
-
if (await branchExists(name, cwd)) {
|
|
71
|
-
throw new DubError(`Branch '${name}' already exists.`);
|
|
72
|
-
}
|
|
73
|
-
await execa("git", ["checkout", "-b", name], { cwd });
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Switches to an existing branch.
|
|
77
|
-
* @throws {DubError} If the branch does not exist.
|
|
78
|
-
*/
|
|
79
|
-
export async function checkoutBranch(name, cwd) {
|
|
80
|
-
try {
|
|
81
|
-
await execa("git", ["checkout", name], { cwd });
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
throw new DubError(`Branch '${name}' not found.`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Deletes a local branch forcefully. Used by undo to remove created branches.
|
|
89
|
-
* @throws {DubError} If the branch does not exist.
|
|
90
|
-
*/
|
|
91
|
-
export async function deleteBranch(name, cwd) {
|
|
92
|
-
try {
|
|
93
|
-
await execa("git", ["branch", "-D", name], { cwd });
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
throw new DubError(`Failed to delete branch '${name}'. It may not exist.`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Force-moves a branch pointer to a specific commit SHA.
|
|
101
|
-
* Used by undo to reset branches to their pre-operation tips.
|
|
102
|
-
*/
|
|
103
|
-
export async function forceBranchTo(name, sha, cwd) {
|
|
104
|
-
try {
|
|
105
|
-
const current = await getCurrentBranch(cwd).catch(() => null);
|
|
106
|
-
if (current === name) {
|
|
107
|
-
await execa("git", ["reset", "--hard", sha], { cwd });
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
await execa("git", ["branch", "-f", name, sha], { cwd });
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
if (error instanceof DubError)
|
|
115
|
-
throw error;
|
|
116
|
-
throw new DubError(`Failed to reset branch '${name}' to ${sha}.`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Checks whether the working tree is clean (no uncommitted changes).
|
|
121
|
-
* @returns `true` if clean (no output from `git status --porcelain`).
|
|
122
|
-
*/
|
|
123
|
-
export async function isWorkingTreeClean(cwd) {
|
|
124
|
-
const { stdout } = await execa("git", ["status", "--porcelain"], { cwd });
|
|
125
|
-
return stdout.trim() === "";
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Performs `git rebase --onto` to move a branch from one base to another.
|
|
129
|
-
*
|
|
130
|
-
* @param newBase - The commit/branch to rebase onto
|
|
131
|
-
* @param oldBase - The old base commit to replay from
|
|
132
|
-
* @param branch - The branch being rebased
|
|
133
|
-
* @throws {DubError} If a merge conflict occurs during rebase
|
|
134
|
-
*/
|
|
135
|
-
export async function rebaseOnto(newBase, oldBase, branch, cwd) {
|
|
136
|
-
try {
|
|
137
|
-
await execa("git", ["rebase", "--onto", newBase, oldBase, branch], { cwd });
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
throw new DubError(`Conflict while restacking '${branch}'.\n` +
|
|
141
|
-
" Resolve conflicts, stage changes, then run: dub restack --continue");
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Continues an in-progress rebase after conflicts have been resolved.
|
|
146
|
-
* @throws {DubError} If the rebase continue fails.
|
|
147
|
-
*/
|
|
148
|
-
export async function rebaseContinue(cwd) {
|
|
149
|
-
try {
|
|
150
|
-
await execa("git", ["rebase", "--continue"], {
|
|
151
|
-
cwd,
|
|
152
|
-
env: { GIT_EDITOR: "true" },
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
throw new DubError("Failed to continue rebase. Ensure all conflicts are resolved and staged.");
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Returns the merge-base (common ancestor) commit SHA of two branches.
|
|
161
|
-
*/
|
|
162
|
-
export async function getMergeBase(a, b, cwd) {
|
|
163
|
-
try {
|
|
164
|
-
const { stdout } = await execa("git", ["merge-base", a, b], { cwd });
|
|
165
|
-
return stdout.trim();
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
throw new DubError(`Could not find common ancestor between '${a}' and '${b}'.`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Returns the commit SHA at the tip of a branch.
|
|
173
|
-
* @throws {DubError} If the branch does not exist.
|
|
174
|
-
*/
|
|
175
|
-
export async function getBranchTip(name, cwd) {
|
|
176
|
-
try {
|
|
177
|
-
const { stdout } = await execa("git", ["rev-parse", name], { cwd });
|
|
178
|
-
return stdout.trim();
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
throw new DubError(`Branch '${name}' not found.`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
//# sourceMappingURL=git.js.map
|
package/dist/lib/git.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IAC1C,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAC7B,KAAK,EACL,CAAC,WAAW,EAAE,uBAAuB,CAAC,EACtC,EAAE,GAAG,EAAE,CACP,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,MAAM,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC5C,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE;YACvE,GAAG;SACH,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CACjB,2DAA2D,CAC3D,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW;IACjD,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAC7B,KAAK,EACL,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,EACrC,EAAE,GAAG,EAAE,CACP,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,QAAQ,CACjB,kEAAkE,CAClE,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC3C,MAAM,IAAI,QAAQ,CACjB,4DAA4D,CAC5D,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,IAAY,EACZ,GAAW;IAEX,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,IAAI,EAAE,CAAC,EAAE;YACnE,GAAG;SACH,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,GAAW;IAC3D,IAAI,MAAM,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,mBAAmB,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,GAAW;IAC7D,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,cAAc,CAAC,CAAC;IACnD,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,GAAW;IAC3D,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CAAC,4BAA4B,IAAI,sBAAsB,CAAC,CAAC;IAC5E,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,IAAY,EACZ,GAAW,EACX,GAAW;IAEX,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACP,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1D,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC3C,MAAM,IAAI,QAAQ,CAAC,2BAA2B,IAAI,QAAQ,GAAG,GAAG,CAAC,CAAC;IACnE,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IACnD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1E,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,OAAe,EACf,OAAe,EACf,MAAc,EACd,GAAW;IAEX,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CACjB,8BAA8B,MAAM,MAAM;YACzC,sEAAsE,CACvE,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW;IAC/C,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE;YAC5C,GAAG;YACH,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;SAC3B,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CACjB,0EAA0E,CAC1E,CAAC;IACH,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,CAAS,EACT,CAAS,EACT,GAAW;IAEX,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CACjB,2CAA2C,CAAC,UAAU,CAAC,IAAI,CAC3D,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,GAAW;IAC3D,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,QAAQ,CAAC,WAAW,IAAI,cAAc,CAAC,CAAC;IACnD,CAAC;AACF,CAAC"}
|