better-commits 1.20.0-cli-flags → 1.20.1-temp.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.
Files changed (71) hide show
  1. package/dist/branch.js +1 -1
  2. package/dist/{chunk-SIF4LZUS.js → chunk-LPU7O52G.js} +1 -1
  3. package/dist/chunk-QPUTIRGU.js +245 -0
  4. package/dist/index.js +2 -2
  5. package/dist/init.js +1 -1
  6. package/package.json +7 -1
  7. package/readme.md +141 -173
  8. package/.better-commits.json +0 -52
  9. package/.github/workflows/publish.yml +0 -34
  10. package/.github/workflows/test.yml +0 -27
  11. package/.opencode/package-lock.json +0 -115
  12. package/.opencode/plans/cli-args.md +0 -182
  13. package/.prettierignore +0 -5
  14. package/.prettierrc +0 -1
  15. package/.svelte-kit/ambient.d.ts +0 -289
  16. package/.svelte-kit/generated/client/app.js +0 -28
  17. package/.svelte-kit/generated/client/matchers.js +0 -1
  18. package/.svelte-kit/generated/client/nodes/0.js +0 -1
  19. package/.svelte-kit/generated/client/nodes/1.js +0 -1
  20. package/.svelte-kit/tsconfig.json +0 -49
  21. package/0001-feat-branch-124-update-worktrees-feature.patch +0 -316
  22. package/dist/chunk-OFJCRS3N.js +0 -4
  23. package/docs/ai-skills.yaml +0 -48
  24. package/docs/clack.md +0 -143
  25. package/docs/valibot.md +0 -228
  26. package/src/args.test.ts +0 -102
  27. package/src/args.ts +0 -106
  28. package/src/branch-args.test.ts +0 -72
  29. package/src/branch-args.ts +0 -106
  30. package/src/branch-help.ts +0 -114
  31. package/src/branch.ts +0 -95
  32. package/src/git.ts +0 -60
  33. package/src/help.ts +0 -131
  34. package/src/index.test.ts +0 -7
  35. package/src/index.ts +0 -100
  36. package/src/init.ts +0 -25
  37. package/src/prompts/branch-checkout.prompt.ts +0 -36
  38. package/src/prompts/branch-confirm.prompt.ts +0 -134
  39. package/src/prompts/branch-description.prompt.ts +0 -37
  40. package/src/prompts/branch-runnable.ts +0 -13
  41. package/src/prompts/branch-ticket.prompt.ts +0 -41
  42. package/src/prompts/branch-type.prompt.ts +0 -43
  43. package/src/prompts/branch-user.prompt.ts +0 -50
  44. package/src/prompts/branch-version.prompt.ts +0 -41
  45. package/src/prompts/commit-body.prompt.ts +0 -57
  46. package/src/prompts/commit-confirm.prompt.ts +0 -119
  47. package/src/prompts/commit-footer.prompt.ts +0 -195
  48. package/src/prompts/commit-scope.prompt.ts +0 -73
  49. package/src/prompts/commit-status.prompt.ts +0 -75
  50. package/src/prompts/commit-ticket.prompt.ts +0 -82
  51. package/src/prompts/commit-title.prompt.ts +0 -98
  52. package/src/prompts/commit-type.prompt.ts +0 -93
  53. package/src/prompts/runnable.ts +0 -13
  54. package/src/utils/build-branch.test.ts +0 -141
  55. package/src/utils/build-branch.ts +0 -46
  56. package/src/utils/build-commit-string.test.ts +0 -253
  57. package/src/utils/build-commit-string.ts +0 -158
  58. package/src/utils/commit-title-size.ts +0 -24
  59. package/src/utils/infer.test.ts +0 -83
  60. package/src/utils/infer.ts +0 -114
  61. package/src/utils/messages.ts +0 -25
  62. package/src/utils/no-interactive-branch-validation.test.ts +0 -170
  63. package/src/utils/no-interactive-validation.test.ts +0 -174
  64. package/src/utils/no-interactive-validation.ts +0 -190
  65. package/src/utils.ts +0 -219
  66. package/src/valibot-consts.ts +0 -114
  67. package/src/valibot-state.test.ts +0 -48
  68. package/src/valibot-state.ts +0 -265
  69. package/tsconfig.json +0 -15
  70. package/tsup.config.ts +0 -12
  71. package/vitest.config.ts +0 -8
package/docs/valibot.md DELETED
@@ -1,228 +0,0 @@
1
- # Valibot Usage
2
-
3
- `better-commits` uses [`valibot`](https://valibot.dev) (`^0.30.0`) for all runtime schema validation, type inference, and config parsing. Valibot defines the shape of every configuration object, commit state, and branch state in the application.
4
-
5
- ## Files
6
-
7
- | File | Role |
8
- | ----------------------- | ------------------------------------------------------------------ |
9
- | `src/valibot-consts.ts` | Shared picklist schemas and constant arrays |
10
- | `src/valibot-state.ts` | Core schema definitions for `Config`, `CommitState`, `BranchState` |
11
- | `src/utils.ts` | Config loading, `parse`, and `ValiError` handling |
12
- | `src/index.ts` | Parses `CommitState`; uses `Output<>` types |
13
- | `src/branch.ts` | Parses `BranchState`; uses `Output<>` types |
14
- | `src/init.ts` | Calls `parse(Config, {})` to generate a default config file |
15
-
16
- ## Schema Overview
17
-
18
- ### `src/valibot-consts.ts` — Picklist Constants
19
-
20
- Defines shared enum-like schemas used across the codebase:
21
-
22
- ```ts
23
- export const V_BRANCH_ACTIONS = v.picklist(["branch", "worktree"]);
24
- export const V_FOOTER_OPTIONS = v.picklist([
25
- "closes",
26
- "trailer",
27
- "breaking-change",
28
- "deprecated",
29
- "custom",
30
- ]);
31
- export const V_BRANCH_FIELDS = v.picklist([
32
- "user",
33
- "version",
34
- "type",
35
- "ticket",
36
- "description",
37
- ]);
38
- export const V_BRANCH_CONFIG_FIELDS = v.picklist([
39
- "branch_user",
40
- "branch_version",
41
- "branch_type",
42
- "branch_ticket",
43
- "branch_description",
44
- ]);
45
- ```
46
-
47
- Constant arrays are typed using `v.Output<>` to derive element types directly from the schemas:
48
-
49
- ```ts
50
- export const FOOTER_OPTION_VALUES: v.Output<typeof V_FOOTER_OPTIONS>[] = [...];
51
- export const BRANCH_ORDER_DEFAULTS: v.Output<typeof V_BRANCH_FIELDS>[] = [...];
52
- ```
53
-
54
- ---
55
-
56
- ### `src/valibot-state.ts` — Core Schemas
57
-
58
- #### `Config`
59
-
60
- The main application config schema. Validates `.better-commits.json`. Parsing an empty object `{}` produces a fully-defaulted config.
61
-
62
- Key fields and their validators:
63
-
64
- | Field | Schema | Default |
65
- | ------------------------ | ------------------------------------------------------------- | ---------- |
66
- | `check_status` | `v.optional(v.boolean(), true)` | `true` |
67
- | `cache_last_value` | `v.optional(v.boolean(), true)` | `true` |
68
- | `confirm_with_editor` | `v.optional(v.boolean(), false)` | `false` |
69
- | `confirm_commit` | `v.optional(v.boolean(), true)` | `true` |
70
- | `print_commit_output` | `v.optional(v.boolean(), true)` | `true` |
71
- | `enable_worktrees` | `v.optional(v.boolean(), true)` | `true` |
72
- | `branch_pre_commands` | `v.optional(v.array(v.string()), [])` | `[]` |
73
- | `branch_post_commands` | `v.optional(v.array(v.string()), [])` | `[]` |
74
- | `worktree_pre_commands` | `v.optional(v.array(v.string()), [])` | `[]` |
75
- | `worktree_post_commands` | `v.optional(v.array(v.string()), [])` | `[]` |
76
- | `branch_action_default` | `v.optional(V_BRANCH_ACTIONS, "branch")` | `"branch"` |
77
- | `branch_order` | `v.optional(v.array(V_BRANCH_FIELDS), BRANCH_ORDER_DEFAULTS)` | all fields |
78
-
79
- **Notable nested validators:**
80
-
81
- - `commit_type.options[].emoji` — `v.string([v.emoji()])` validates the value is a real emoji character
82
- - `commit_type.max_items` / `commit_scope.max_items` — `v.number([v.minValue(1)])` enforces minimum of 1
83
- - `check_ticket.prepend_hashtag` — `v.picklist(["Never", "Always", "Prompt"])`
84
- - `check_ticket.surround` — `v.picklist(["", "()", "[]", "{}"])`
85
- - `check_ticket.title_position` — `v.picklist(["start", "end", "before-colon", "beginning"])`
86
- - `branch_*.separator` — `v.picklist(["/", "-", "_"])` (branch_description also allows `""`)
87
-
88
- **Cross-field validation with `v.custom`:**
89
-
90
- Both `commit_type` and `commit_scope` use `v.custom` to ensure `initial_value` exists within their `options` array:
91
-
92
- ```ts
93
- v.custom(
94
- (val) =>
95
- !val.initial_value ||
96
- val.options.some((o) => o.value === val.initial_value),
97
- (val) =>
98
- `Type: initial_value "${val.input.initial_value}" must exist in options`,
99
- );
100
- ```
101
-
102
- **Post-parse transformation with `v.transform`:**
103
-
104
- - `commit_type` — when `append_emoji_to_label` is `true`, prepends emoji to each option's label
105
- - `commit_scope` — when `custom_scope` is `true`, injects `{ label: "custom", value: "custom", hint: "..." }` into options if not already present
106
-
107
- ---
108
-
109
- #### `CommitState`
110
-
111
- Models the mutable in-memory state of an in-progress commit. All fields are `v.optional(v.string(), "")`.
112
-
113
- | Field | Purpose |
114
- | ------------------ | --------------------------- |
115
- | `type` | Commit type (e.g. `"feat"`) |
116
- | `scope` | Commit scope (e.g. `"app"`) |
117
- | `title` | Short commit title |
118
- | `body` | Long commit body |
119
- | `closes` | "Closes: " footer token |
120
- | `ticket` | Issue/ticket number |
121
- | `breaking_title` | Breaking change summary |
122
- | `breaking_body` | Breaking change description |
123
- | `deprecates` | Deprecation marker |
124
- | `deprecates_title` | Deprecation summary |
125
- | `deprecates_body` | Deprecation description |
126
- | `custom_footer` | Custom footer text |
127
- | `trailer` | Git trailer string |
128
-
129
- ---
130
-
131
- #### `BranchState`
132
-
133
- Models the mutable in-memory state for the `better-branch` CLI flow. All fields are `v.optional(v.string(), "")`.
134
-
135
- | Field | Purpose |
136
- | ------------- | ----------------------------------- |
137
- | `user` | Git username portion of branch name |
138
- | `type` | Branch type (mirrors commit type) |
139
- | `ticket` | Ticket/issue number |
140
- | `description` | Short branch description |
141
- | `version` | Version number |
142
-
143
- ---
144
-
145
- ## Runtime Usage
146
-
147
- ### Parsing with defaults
148
-
149
- All three state objects are initialized by parsing an empty object, which triggers all `v.optional` defaults:
150
-
151
- ```ts
152
- // src/index.ts
153
- const commit_state = parse(CommitState, {});
154
-
155
- // src/branch.ts
156
- const branch_state = parse(BranchState, {});
157
-
158
- // src/init.ts
159
- const default_config = parse(Config, {});
160
- ```
161
-
162
- ### Config validation in `src/utils.ts`
163
-
164
- `validate_config` wraps `parse(Config, config)` to produce human-friendly errors:
165
-
166
- ```ts
167
- function validate_config(config: unknown) {
168
- try {
169
- return parse(Config, config);
170
- } catch (err) {
171
- if (err instanceof ValiError) {
172
- const path = err.issues[0].path?.map((p) => p.key).join(".");
173
- p.log.error(`Invalid config at: ${path}`);
174
- process.exit(1);
175
- }
176
- }
177
- }
178
- ```
179
-
180
- ### TypeScript types via `Output<>`
181
-
182
- `Output<typeof Schema>` is used throughout as the TypeScript type for parsed objects, avoiding manual interface duplication:
183
-
184
- ```ts
185
- // Function signatures
186
- function build_commit_string(
187
- state: Output<typeof CommitState>,
188
- config: Output<typeof Config>
189
- ): string { ... }
190
-
191
- // Variable types
192
- const checkout_type: Output<typeof V_BRANCH_ACTIONS> = ...;
193
- ```
194
-
195
- ---
196
-
197
- ## Valibot API Summary
198
-
199
- | API | Purpose |
200
- | ----------------------------- | ---------------------------------------------------------------------- |
201
- | `v.object({...})` | Defines all three top-level schemas and all nested sub-objects |
202
- | `v.optional(schema, default)` | Makes fields optional with a fallback default |
203
- | `v.boolean()` | Validates boolean config flags |
204
- | `v.string()` | Validates string fields |
205
- | `v.number([...])` | Validates number fields with optional pipe validators |
206
- | `v.array(schema)` | Validates array fields |
207
- | `v.picklist([...])` | Validates enum-like string fields |
208
- | `v.minValue(1)` | Pipe validator: enforces a minimum numeric value |
209
- | `v.emoji()` | Pipe validator: ensures a string is a valid emoji character |
210
- | `v.custom(fn, msgFn)` | Cross-field validation with a custom predicate |
211
- | `v.transform(schema, fn)` | Post-parse transformation of validated data |
212
- | `parse(schema, data)` | Parses and validates data, applying all defaults and transforms |
213
- | `Output<typeof Schema>` | TypeScript utility to extract the inferred output type |
214
- | `ValiError` | Error class caught to produce human-readable validation error messages |
215
-
216
- ---
217
-
218
- ## Known Quirk
219
-
220
- `src/branch.ts` contains a bare no-op reference to `CommitState` at the bottom of the file:
221
-
222
- ```ts
223
- // TODO: No idea what's happening here
224
- // If you don't use CommitState, (even in unreachable code), parse fails on Config
225
- CommitState;
226
- ```
227
-
228
- This is a workaround for a bundler/tree-shaking issue: without this reference, `parse(Config, ...)` fails at runtime. The root cause is likely that `CommitState` imports something from `valibot-state.ts` that is needed for `Config` to work correctly at runtime, but the bundler eliminates it as dead code without this reference.
package/src/args.test.ts DELETED
@@ -1,102 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parse_runtime_flags } from "./args";
3
-
4
- describe("parse_runtime_flags", () => {
5
- it("uses interactive mode by default", () => {
6
- const parsed = parse_runtime_flags([]);
7
-
8
- expect(parsed.no_interactive).toBe(false);
9
- expect(parsed.dry_run).toBe(false);
10
- expect(parsed.git_args).toBe("");
11
- expect(parsed.commit_state).toEqual({});
12
- });
13
-
14
- it("parses --no-interactive and --dry-run", () => {
15
- const parsed = parse_runtime_flags(["--no-interactive", "--dry-run"]);
16
-
17
- expect(parsed.no_interactive).toBe(true);
18
- expect(parsed.dry_run).toBe(true);
19
- });
20
-
21
- it("parses --version and -v", () => {
22
- const long_flag = parse_runtime_flags(["--version"]);
23
- const short_flag = parse_runtime_flags(["-v"]);
24
-
25
- expect(long_flag.version).toBe(true);
26
- expect(short_flag.version).toBe(true);
27
- });
28
-
29
- it("maps commit flags into commit_state keys", () => {
30
- const parsed = parse_runtime_flags([
31
- "--type",
32
- "feat",
33
- "--title",
34
- "ship feature",
35
- "--breaking-title",
36
- "api changed",
37
- "--custom-footer",
38
- "Reviewed-by: Jane",
39
- ]);
40
-
41
- expect(parsed.commit_state).toEqual({
42
- type: "feat",
43
- title: "ship feature",
44
- breaking_title: "api changed",
45
- custom_footer: "Reviewed-by: Jane",
46
- });
47
- });
48
-
49
- it("builds git args from --git-dir and --work-tree", () => {
50
- const parsed = parse_runtime_flags([
51
- "--git-dir",
52
- "/tmp/repo/.git",
53
- "--work-tree",
54
- "/tmp/repo",
55
- ]);
56
-
57
- expect(parsed.git_args).toBe(
58
- "--git-dir=/tmp/repo/.git --work-tree=/tmp/repo",
59
- );
60
- });
61
-
62
- it("builds git args when only one git location flag is provided", () => {
63
- const with_git_dir = parse_runtime_flags(["--git-dir", "/tmp/repo/.git"]);
64
- const with_work_tree = parse_runtime_flags(["--work-tree", "/tmp/repo"]);
65
-
66
- expect(with_git_dir.git_args).toBe("--git-dir=/tmp/repo/.git");
67
- expect(with_work_tree.git_args).toBe("--work-tree=/tmp/repo");
68
- });
69
-
70
- it("maps dashed commit flags to snake_case commit_state keys", () => {
71
- const parsed = parse_runtime_flags([
72
- "--breaking-body",
73
- "major impact",
74
- "--deprecates-title",
75
- "legacy endpoint",
76
- "--deprecates-body",
77
- "use v2 endpoint",
78
- "--custom-footer",
79
- "Reviewed-by: Alex",
80
- "--breaking-title",
81
- "v1 removed",
82
- ]);
83
-
84
- expect(parsed.commit_state).toEqual({
85
- breaking_body: "major impact",
86
- deprecates_title: "legacy endpoint",
87
- deprecates_body: "use v2 endpoint",
88
- custom_footer: "Reviewed-by: Alex",
89
- breaking_title: "v1 removed",
90
- });
91
- });
92
-
93
- it("honors interactive flag semantics", () => {
94
- const default_flags = parse_runtime_flags([]);
95
- const explicit_interactive = parse_runtime_flags(["--interactive"]);
96
- const no_interactive = parse_runtime_flags(["--no-interactive"]);
97
-
98
- expect(default_flags.no_interactive).toBe(false);
99
- expect(explicit_interactive.no_interactive).toBe(false);
100
- expect(no_interactive.no_interactive).toBe(true);
101
- });
102
- });
package/src/args.ts DELETED
@@ -1,106 +0,0 @@
1
- import { parse } from "@bomb.sh/args";
2
- import { InferOutput } from "valibot";
3
- import { CommitState } from "./valibot-state";
4
-
5
- type CommitStateRuntime = InferOutput<typeof CommitState>;
6
-
7
- type ParsedRuntimeFlags = {
8
- help: boolean;
9
- version: boolean;
10
- git_args: string;
11
- no_interactive: boolean;
12
- dry_run: boolean;
13
- commit_state: Partial<CommitStateRuntime>;
14
- };
15
-
16
- export const COMMIT_OPTIONS = [
17
- "type",
18
- "scope",
19
- "title",
20
- "body",
21
- "closes",
22
- "ticket",
23
- "trailer",
24
- "deprecates",
25
- "breaking-title",
26
- "breaking-body",
27
- "deprecates-title",
28
- "deprecates-body",
29
- "custom-footer",
30
- ] as const;
31
-
32
- export const GIT_OPTIONS = ["git-dir", "work-tree"] as const;
33
-
34
- export const BOOLEAN_FLAGS = [
35
- "interactive",
36
- "dry-run",
37
- "help",
38
- "version",
39
- ] as const;
40
-
41
- class Flags {
42
- #runtime: ParsedRuntimeFlags;
43
-
44
- constructor(runtime: ParsedRuntimeFlags) {
45
- this.#runtime = runtime;
46
- }
47
-
48
- get git_args(): string {
49
- return this.#runtime.git_args;
50
- }
51
-
52
- get interactive(): boolean {
53
- return !this.#runtime.no_interactive;
54
- }
55
-
56
- get dry_run(): boolean {
57
- return this.#runtime.dry_run;
58
- }
59
-
60
- get help(): boolean {
61
- return this.#runtime.help;
62
- }
63
-
64
- get version(): boolean {
65
- return this.#runtime.version;
66
- }
67
-
68
- get commit_state(): Partial<CommitStateRuntime> {
69
- return this.#runtime.commit_state;
70
- }
71
- }
72
-
73
- export const flags = new Flags(parse_runtime_flags(process.argv.slice(2)));
74
-
75
- export function parse_runtime_flags(argv: string[]): ParsedRuntimeFlags {
76
- const parsed = parse(argv, {
77
- alias: { h: "help", v: "version" },
78
- boolean: BOOLEAN_FLAGS,
79
- string: [...COMMIT_OPTIONS, ...GIT_OPTIONS],
80
- });
81
-
82
- const commit_state: Partial<CommitStateRuntime> = {};
83
- COMMIT_OPTIONS.forEach((value) => {
84
- const cli_value = parsed[value];
85
- if (cli_value) {
86
- const str = value.replace("-", "_") as keyof CommitStateRuntime;
87
- commit_state[str] = cli_value;
88
- }
89
- });
90
-
91
- return {
92
- help: parsed["help"] === true,
93
- version: parsed["version"] === true,
94
- git_args: get_git_args(parsed["git-dir"], parsed["work-tree"]),
95
- no_interactive: parsed.interactive === false,
96
- dry_run: parsed["dry-run"] === true,
97
- commit_state,
98
- };
99
- }
100
-
101
- function get_git_args(
102
- git_dir: string | undefined,
103
- work_tree: string | undefined,
104
- ): string {
105
- return `${git_dir ? `--git-dir=${git_dir}` : ""} ${work_tree ? `--work-tree=${work_tree}` : ""}`.trim();
106
- }
@@ -1,72 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parse_branch_runtime_flags } from "./branch-args";
3
-
4
- describe("parse_branch_runtime_flags", () => {
5
- it("maps branch flags into branch_state keys", () => {
6
- const parsed = parse_branch_runtime_flags([
7
- "--user",
8
- "erik",
9
- "--type",
10
- "feat",
11
- "--ticket",
12
- "ABC-123",
13
- "--description",
14
- "add-parser",
15
- "--branch-version",
16
- "1.2.0",
17
- ]);
18
-
19
- expect(parsed.branch_state).toEqual({
20
- user: "erik",
21
- type: "feat",
22
- ticket: "ABC-123",
23
- description: "add-parser",
24
- version: "1.2.0",
25
- });
26
- });
27
-
28
- it("maps --checkout into checkout", () => {
29
- const parsed = parse_branch_runtime_flags(["--checkout", "worktree"]);
30
-
31
- expect(parsed.branch_state).toEqual({
32
- checkout: "worktree",
33
- });
34
- });
35
-
36
- it("does not set checkout when --checkout is omitted", () => {
37
- const parsed = parse_branch_runtime_flags([
38
- "--type",
39
- "feat",
40
- "--description",
41
- "add-parser",
42
- ]);
43
-
44
- expect(parsed.branch_state).toEqual({
45
- type: "feat",
46
- description: "add-parser",
47
- });
48
- });
49
-
50
- it("honors interactive flag semantics", () => {
51
- const default_flags = parse_branch_runtime_flags([]);
52
- const explicit_interactive = parse_branch_runtime_flags(["--interactive"]);
53
- const no_interactive = parse_branch_runtime_flags(["--no-interactive"]);
54
-
55
- expect(default_flags.no_interactive).toBe(false);
56
- expect(explicit_interactive.no_interactive).toBe(false);
57
- expect(no_interactive.no_interactive).toBe(true);
58
- });
59
-
60
- it("parses git-dir and work-tree into git_args", () => {
61
- const parsed = parse_branch_runtime_flags([
62
- "--git-dir",
63
- "/tmp/repo/.git",
64
- "--work-tree",
65
- "/tmp/repo",
66
- ]);
67
-
68
- expect(parsed.git_args).toBe(
69
- "--git-dir=/tmp/repo/.git --work-tree=/tmp/repo",
70
- );
71
- });
72
- });
@@ -1,106 +0,0 @@
1
- import { parse } from "@bomb.sh/args";
2
- import { InferOutput } from "valibot";
3
- import { BranchState } from "./valibot-state";
4
-
5
- type BranchStateRuntime = InferOutput<typeof BranchState>;
6
-
7
- type ParsedRuntimeFlags = {
8
- help: boolean;
9
- version: boolean;
10
- git_args: string;
11
- no_interactive: boolean;
12
- dry_run: boolean;
13
- branch_state: Partial<BranchStateRuntime>;
14
- };
15
-
16
- const BRANCH_OPTIONS = [
17
- "user",
18
- "type",
19
- "description",
20
- "ticket",
21
- "branch-version",
22
- "checkout",
23
- ] as const;
24
-
25
- export const GIT_OPTIONS = ["git-dir", "work-tree"] as const;
26
-
27
- export const BOOLEAN_FLAGS = [
28
- "interactive",
29
- "dry-run",
30
- "help",
31
- "version",
32
- ] as const;
33
-
34
- class BranchFlags {
35
- #runtime: ParsedRuntimeFlags;
36
-
37
- constructor(runtime: ParsedRuntimeFlags) {
38
- this.#runtime = runtime;
39
- }
40
-
41
- get interactive(): boolean {
42
- return !this.#runtime.no_interactive;
43
- }
44
-
45
- get dry_run(): boolean {
46
- return this.#runtime.dry_run;
47
- }
48
-
49
- get help(): boolean {
50
- return this.#runtime.help;
51
- }
52
-
53
- get version(): boolean {
54
- return this.#runtime.version;
55
- }
56
-
57
- get git_args(): string {
58
- return this.#runtime.git_args;
59
- }
60
-
61
- get branch_state(): Partial<BranchStateRuntime> {
62
- return this.#runtime.branch_state;
63
- }
64
- }
65
-
66
- export const branch_flags = new BranchFlags(
67
- parse_branch_runtime_flags(process.argv.slice(2)),
68
- );
69
-
70
- export function parse_branch_runtime_flags(argv: string[]): ParsedRuntimeFlags {
71
- const parsed = parse(argv, {
72
- alias: { h: "help", v: "version" },
73
- boolean: BOOLEAN_FLAGS,
74
- string: [...BRANCH_OPTIONS, ...GIT_OPTIONS],
75
- });
76
-
77
- const branch_state: Partial<BranchStateRuntime> = {};
78
- BRANCH_OPTIONS.forEach((value) => {
79
- const cli_value = parsed[value];
80
- if (cli_value) {
81
- const str = (value === "branch-version"
82
- ? "version"
83
- : value.replace("-", "_")) as keyof BranchStateRuntime;
84
- if (str === "checkout")
85
- branch_state[str] =
86
- (cli_value as "worktree" | "branch" | undefined) ?? "branch";
87
- else branch_state[str] = cli_value;
88
- }
89
- });
90
-
91
- return {
92
- help: parsed["help"] === true,
93
- version: parsed["version"] === true,
94
- git_args: get_git_args(parsed["git-dir"], parsed["work-tree"]),
95
- no_interactive: parsed["interactive"] === false,
96
- dry_run: parsed["dry-run"] === true,
97
- branch_state: branch_state,
98
- };
99
- }
100
-
101
- function get_git_args(
102
- git_dir: string | undefined,
103
- work_tree: string | undefined,
104
- ): string {
105
- return `${git_dir ? `--git-dir=${git_dir}` : ""} ${work_tree ? `--work-tree=${work_tree}` : ""}`.trim();
106
- }