new-branch 0.7.0 → 0.8.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 (44) hide show
  1. package/README.md +27 -211
  2. package/dist/cli.js +92 -2
  3. package/dist/config/loadConfig.js +17 -7
  4. package/dist/config/sources/git.loader.js +27 -0
  5. package/dist/config/sources/packageJson.loader.js +13 -0
  6. package/dist/config/sources/rc.loader.js +15 -0
  7. package/dist/config/types.js +6 -4
  8. package/dist/config/validate.js +61 -8
  9. package/dist/didactic/explain.js +29 -2
  10. package/dist/didactic/listTransforms.js +7 -3
  11. package/dist/didactic/printConfig.js +8 -3
  12. package/dist/git/createBranch.js +10 -3
  13. package/dist/git/gitBuiltins.js +73 -6
  14. package/dist/git/gitConfig.js +28 -4
  15. package/dist/git/sanitizeGitRef.js +23 -5
  16. package/dist/git/truncateEnd.js +31 -0
  17. package/dist/git/validateBranchName.js +12 -3
  18. package/dist/parseArgs.js +34 -0
  19. package/dist/pattern/parsePattern.js +14 -0
  20. package/dist/pattern/transforms/after.js +15 -0
  21. package/dist/pattern/transforms/before.js +15 -0
  22. package/dist/pattern/transforms/camel.js +13 -7
  23. package/dist/pattern/transforms/helpers/words.js +6 -0
  24. package/dist/pattern/transforms/ifEmpty.js +15 -0
  25. package/dist/pattern/transforms/index.js +10 -0
  26. package/dist/pattern/transforms/kebab.js +10 -4
  27. package/dist/pattern/transforms/lower.js +13 -0
  28. package/dist/pattern/transforms/max.js +15 -0
  29. package/dist/pattern/transforms/registry.js +13 -0
  30. package/dist/pattern/transforms/remove.js +13 -0
  31. package/dist/pattern/transforms/renderPattern.js +9 -0
  32. package/dist/pattern/transforms/replace.js +13 -0
  33. package/dist/pattern/transforms/replaceAll.js +13 -0
  34. package/dist/pattern/transforms/slugify.js +18 -0
  35. package/dist/pattern/transforms/snake.js +10 -4
  36. package/dist/pattern/transforms/stripAccents.js +15 -0
  37. package/dist/pattern/transforms/title.js +11 -4
  38. package/dist/pattern/transforms/types.js +5 -0
  39. package/dist/pattern/transforms/upper.js +13 -0
  40. package/dist/pattern/transforms/words.js +11 -7
  41. package/dist/pattern/types.js +5 -0
  42. package/dist/runtime/builtins.js +5 -0
  43. package/dist/runtime/enums.js +14 -0
  44. package/package.json +6 -2
package/README.md CHANGED
@@ -4,28 +4,19 @@
4
4
  <img src="./logo.svg" width="180" alt="new-branch logo" />
5
5
  </p>
6
6
 
7
- > “Explicit is better than implicit.”
8
- > — The Zen of Python (PEP 20)
9
-
10
- A composable CLI to generate and optionally create standardized Git branch names using a pattern + transform pipeline.
7
+ A composable CLI to generate and create standardized Git branch names using a pattern + transform pipeline.
11
8
 
12
9
  ![demo](./demo.gif)
13
10
 
14
11
  [![CI](https://github.com/teles/new-branch/actions/workflows/ci.yml/badge.svg)](https://github.com/teles/new-branch/actions/workflows/ci.yml)
15
12
  [![codecov](https://codecov.io/gh/teles/new-branch/branch/main/graph/badge.svg)](https://codecov.io/gh/teles/new-branch)
16
13
 
17
- ---
18
-
19
- ## Why
20
-
21
- Keep branch names consistent across your team using a declarative pattern language.
14
+ 📖 **[Full Documentation](https://teles.github.io/new-branch/)**
22
15
 
23
16
  ---
24
17
 
25
18
  ## Install
26
19
 
27
- Run without installing:
28
-
29
20
  ```bash
30
21
  npx new-branch
31
22
  ```
@@ -36,227 +27,54 @@ Or install globally:
36
27
  npm install -g new-branch
37
28
  ```
38
29
 
39
- ---
40
-
41
- ## Usage
42
-
43
- Generate a branch name:
30
+ ## Quick Start
44
31
 
45
32
  ```bash
46
33
  new-branch \
47
34
  --pattern "{type}/{title:slugify;max:25}-{id}" \
48
35
  --type feat \
49
- --title "My task" \
50
- --id STK-123
51
- ```
52
-
53
- Create the branch automatically:
54
-
55
- ```bash
56
- new-branch \
57
- --pattern "{type}/{title:slugify}-{id}" \
58
- --type feat \
59
- --title "My task" \
60
- --id STK-123 \
36
+ --title "Add login page" \
37
+ --id PROJ-123 \
61
38
  --create
62
39
  ```
63
40
 
64
- ---
65
-
66
- ## Pattern Language
67
-
68
- Patterns are composed of variables and ordered transforms.
69
-
70
- Example:
71
-
72
- ```
73
- {type}/{title:slugify;max:25}-{id}
74
- ```
75
-
76
- ### Syntax
77
-
78
41
  ```
79
- {variable:transform1;transform2:arg}
42
+ ✅ Branch created and switched to: feat/add-login-page-PROJ-123
80
43
  ```
81
44
 
82
- - Variables are wrapped in `{}`
83
- - Transforms run left-to-right
84
- - Multiple transforms are separated by `;`
85
- - Transform arguments use `:`
86
-
87
- ---
88
-
89
- ## Built-in Variables
90
-
91
- ### Core Variables
92
-
93
- - `type`
94
- - `title`
95
- - `id`
96
-
97
- ### Date Built-ins (derived from local system time)
98
-
99
- - `year` → YYYY
100
- - `month` → MM (zero padded)
101
- - `day` → DD (zero padded)
102
- - `date` → YYYY-MM-DD
103
- - `dateCompact` → YYYYMMDD
104
-
105
- ### Git Built-ins (derived from current Git repository)
106
-
107
- - `currentBranch` → Current Git branch name (e.g. `main`, `feature/PROJ-123`)
108
- - `shortSha` → Short SHA of `HEAD` (e.g. `a1b2c3d`)
109
- - `repoName` → Repository directory name
110
- - `userName` → Git user name (`git config user.name`)
111
- - `lastTag` → Most recent Git tag (`git describe --tags --abbrev=0`)
112
-
113
- > Note:
114
- >
115
- > - Git built-ins are resolved lazily and only when referenced in the pattern.
116
- > - They are never prompted interactively.
117
- > - When unavailable (e.g. outside a Git repository), they resolve to an empty string.
118
-
119
- #### Example with Git built-ins
120
-
121
- ```bash
122
- new-branch \
123
- --pattern "{currentBranch}-{shortSha}-{type}-{title:slugify}" \
124
- --type feat \
125
- --title "Improve logging"
126
- ```
127
-
128
- Example output:
129
-
130
- ```
131
- main-a1b2c3d-feat-improve-logging
132
- ```
133
-
134
- ---
135
-
136
- ## Built-in Transforms
137
-
138
- | Transform | Description |
139
- | --------- | -------------------------- |
140
- | `slugify` | Convert to URL-safe slug |
141
- | `lower` | Convert to lowercase |
142
- | `upper` | Convert to uppercase |
143
- | `camel` | Convert to camelCase |
144
- | `kebab` | Convert to kebab-case |
145
- | `snake` | Convert to snake_case |
146
- | `title` | Convert to Title Case |
147
- | `words:n` | Keep at most `n` words |
148
- | `max:n` | Truncate to `n` characters |
149
-
150
- All transforms are pure functions and composable.
151
-
152
- ---
153
-
154
- ## Interactive Mode
155
-
156
- If variables referenced by the pattern are missing, the CLI prompts for them by default.
157
-
158
- Disable prompts with:
159
-
160
- ```bash
161
- --no-prompt
162
- ```
163
-
164
- ---
165
-
166
- ## CLI Options
167
-
168
- | Option | Description |
169
- | ------------------------- | ----------------------------------- |
170
- | `-p, --pattern <pattern>` | Branch pattern |
171
- | `--type <type>` | Branch type |
172
- | `--title <title>` | Task title |
173
- | `--id <id>` | Task identifier |
174
- | `--create` | Create branch using `git switch -c` |
175
- | `--no-prompt` | Fail instead of prompting |
176
- | `--quiet` | Suppress output |
177
-
178
- ---
179
-
180
- ## Project Configuration and precedence
181
-
182
- Configuration for `new-branch` may come from several places. The CLI resolves the first _non-empty_ configuration it finds according to the following precedence (highest → lowest):
183
-
184
- 1. CLI flags (explicit `--pattern`, `--type`, etc.)
185
- 2. `.newbranchrc.json` (a repository-local JSON config file)
186
- 3. `package.json` under the `new-branch` key
187
- 4. Git config (`new-branch.pattern`) — local then global
188
- 5. Interactive prompt (only if enabled and a value is still missing)
189
-
190
- This means that if a higher-precedence source provides a non-empty value, lower-precedence sources are not consulted or merged.
191
-
192
- Examples
193
-
194
- 1. `.newbranchrc.json` (preferred when present and non-empty):
45
+ Save your pattern so you don't have to type it every time:
195
46
 
196
47
  ```json
197
48
  {
198
49
  "pattern": "{type}/{title:slugify}-{id}",
199
50
  "types": [
200
51
  { "value": "feat", "label": "Feature" },
201
- { "value": "fix", "label": "Fix" }
202
- ],
203
- "defaultType": "feat"
204
- }
205
- ```
206
-
207
- 2. `package.json` fallback:
208
-
209
- ```json
210
- {
211
- "new-branch": {
212
- "pattern": "{type}/{title:slugify}-{id}",
213
- "defaultType": "fix"
214
- }
52
+ { "value": "fix", "label": "Bug Fix" }
53
+ ]
215
54
  }
216
55
  ```
217
56
 
218
- 3. Git config fallback (local takes precedence over global):
219
-
220
- ```bash
221
- git config --local new-branch.pattern "{type}/{title:slugify}-{id}"
222
- git config --global new-branch.pattern "{type}/{title:slugify}-{id}"
223
- ```
224
-
225
- Notes about `type` and `defaultType`
226
-
227
- - Order for resolving the branch `type` follows the SPEC behavior we implemented:
228
- 1. CLI `--type` (explicit flag) overrides everything.
229
- 2. `defaultType` from the selected configuration source is used next (if present).
230
- 3. If the project config declares exactly one `type` in `types[]`, that single type is used as a convenience.
231
- 4. If the type is still not resolved and interactive prompting is allowed, the CLI will prompt for it.
232
- 5. If the type is still missing and `--no-prompt` (or `prompt: false`) is in effect, the CLI will fail with a helpful error.
57
+ ## Features
233
58
 
234
- - Validation: when a configuration source provides both `types[]` and `defaultType`, the `defaultType` must match one of the declared `types[].value`. If it does not, configuration validation will surface an error.
59
+ - **Pattern language** declarative syntax with variables, transforms, and arguments
60
+ - **16 built-in transforms** — `slugify`, `kebab`, `camel`, `max`, `replace`, `stripAccents`, and more
61
+ - **Flexible config** — `.newbranchrc.json`, `package.json`, or `git config`
62
+ - **Pattern aliases** — define named patterns and switch with `--use feature`
63
+ - **Interactive mode** — prompts for missing values, disable with `--no-prompt`
64
+ - **Git safety** — sanitized and validated via `git check-ref-format`
65
+ - **Didactic modes** — `--explain`, `--list-transforms`, `--print-config`
235
66
 
236
- - Interactive prompts: when `types[]` are present in the chosen project config, those entries are exposed as choices to the interactive `type` select prompt so users see and can pick project-defined types.
67
+ ## Documentation
237
68
 
238
- To remove the pattern from Git config:
239
-
240
- ```bash
241
- # Remove from local repository
242
- git config --unset --local new-branch.pattern
243
-
244
- # Remove from global config
245
- git config --unset --global new-branch.pattern
246
- ```
247
-
248
- ---
249
-
250
- ## Git Safety
251
-
252
- After rendering, branch names are:
253
-
254
- 1. Lightly sanitized
255
- 2. Validated via `git check-ref-format --branch`
256
-
257
- Invalid names cause the command to fail.
258
-
259
- ---
69
+ | Section | Description |
70
+ | --------------------------------------------------------------------------- | ------------------------------------ |
71
+ | [Getting Started](https://teles.github.io/new-branch/guide/getting-started) | Installation and first branch |
72
+ | [Patterns](https://teles.github.io/new-branch/guide/patterns) | Pattern language syntax and examples |
73
+ | [Transforms](https://teles.github.io/new-branch/guide/transforms) | All 16 transforms with I/O tables |
74
+ | [Configuration](https://teles.github.io/new-branch/guide/configuration) | Config sources and precedence |
75
+ | [Pattern Aliases](https://teles.github.io/new-branch/guide/pattern-aliases) | Named patterns with `--use` |
76
+ | [CLI Reference](https://teles.github.io/new-branch/reference/cli-options) | All flags and options |
77
+ | [Recipes](https://teles.github.io/new-branch/recipes/github-flow) | GitHub Flow, Gitflow, Monorepo |
260
78
 
261
79
  ## Development
262
80
 
@@ -266,8 +84,6 @@ pnpm test:run
266
84
  pnpm build
267
85
  ```
268
86
 
269
- ---
270
-
271
87
  ## License
272
88
 
273
89
  MIT
package/dist/cli.js CHANGED
@@ -1,4 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * @module cli
4
+ *
5
+ * Entry point for the `new-branch` CLI.
6
+ *
7
+ * @remarks
8
+ * This module orchestrates the full branch-name pipeline:
9
+ * pattern → AST → resolve values → render → sanitize →
10
+ * truncate → validate → (optional) git create → output.
11
+ */
2
12
  import { parseArgs } from "./parseArgs.js";
3
13
  import { parsePattern } from "./pattern/parsePattern.js";
4
14
  import { allTransforms, defaultTransforms } from "./pattern/transforms/index.js";
@@ -9,20 +19,50 @@ import { loadConfigWithSource } from "./config/loadConfig.js";
9
19
  import { getGitConfig } from "./git/gitConfig.js";
10
20
  import { extractGitBuiltinKeysFromPattern, getGitBuiltins, patternNeedsGitBuiltins, } from "./git/gitBuiltins.js";
11
21
  import { sanitizeGitRef } from "./git/sanitizeGitRef.js";
22
+ import { truncateEnd } from "./git/truncateEnd.js";
12
23
  import { validateBranchName } from "./git/validateBranchName.js";
13
24
  import { createBranch } from "./git/createBranch.js";
14
25
  import { listTransforms } from "./didactic/listTransforms.js";
15
26
  import { printConfig } from "./didactic/printConfig.js";
16
27
  import { explain } from "./didactic/explain.js";
28
+ /**
29
+ * Wraps a value in an {@link Ok} result.
30
+ *
31
+ * @typeParam T - Value type.
32
+ * @param value - The success value.
33
+ * @returns An `Ok<T>` result.
34
+ */
17
35
  const ok = (value) => ({ ok: true, value });
36
+ /**
37
+ * Wraps an error in an {@link Err} result.
38
+ *
39
+ * @param error - The failure reason.
40
+ * @returns An `Err` result.
41
+ */
18
42
  const err = (error) => ({ ok: false, error });
43
+ /**
44
+ * Type-narrowing guard that checks whether `r` is an {@link Ok} result.
45
+ */
19
46
  const isOk = (r) => r.ok;
47
+ /**
48
+ * Prints an error message and exits the process with code 1.
49
+ *
50
+ * @param msg - Human-readable error headline.
51
+ * @param e - Optional underlying error to print.
52
+ */
20
53
  function fail(msg, e) {
21
54
  console.error(`\n❌ ${msg}`);
22
55
  if (e)
23
56
  console.error(e);
24
57
  process.exit(1);
25
58
  }
59
+ /**
60
+ * Wraps a synchronous function in a {@link Result}.
61
+ *
62
+ * @typeParam T - Return type of `fn`.
63
+ * @param fn - The function to execute.
64
+ * @returns `Ok<T>` on success, `Err` on thrown exception.
65
+ */
26
66
  function safe(fn) {
27
67
  try {
28
68
  return ok(fn());
@@ -31,6 +71,13 @@ function safe(fn) {
31
71
  return err(e);
32
72
  }
33
73
  }
74
+ /**
75
+ * Wraps an asynchronous function in a {@link Result}.
76
+ *
77
+ * @typeParam T - Resolved type of the returned promise.
78
+ * @param fn - The async function to execute.
79
+ * @returns `Ok<T>` on success, `Err` on rejection.
80
+ */
34
81
  async function safeAsync(fn) {
35
82
  try {
36
83
  return ok(await fn());
@@ -39,12 +86,25 @@ async function safeAsync(fn) {
39
86
  return err(e);
40
87
  }
41
88
  }
89
+ /**
90
+ * Validates that a pattern string was provided.
91
+ *
92
+ * @param pattern - The resolved pattern string (may be `undefined`).
93
+ * @returns `Ok<string>` when valid, `Err` when missing or blank.
94
+ */
42
95
  function requirePattern(pattern) {
43
96
  if (!pattern || pattern.trim().length === 0) {
44
97
  return err(new Error("Pattern is required. Use --pattern to specify it."));
45
98
  }
46
99
  return ok(pattern);
47
100
  }
101
+ /**
102
+ * Extracts CLI-provided values (`id`, `title`, `type`) from parsed arguments
103
+ * into a {@link RenderValues} map.
104
+ *
105
+ * @param args - The parsed CLI arguments.
106
+ * @returns A partial {@link RenderValues} map.
107
+ */
48
108
  function toInitialValues(args) {
49
109
  return {
50
110
  id: args.options.id,
@@ -52,6 +112,25 @@ function toInitialValues(args) {
52
112
  type: args.options.type,
53
113
  };
54
114
  }
115
+ /**
116
+ * Main CLI entry point.
117
+ *
118
+ * @remarks
119
+ * Orchestrates the full branch-name pipeline:
120
+ *
121
+ * 1. Parse and normalise `process.argv`.
122
+ * 2. Load project configuration (RC / `package.json` / git config).
123
+ * 3. Resolve the pattern (CLI flag → `--use` alias → config → git config).
124
+ * 4. Parse the pattern into an AST.
125
+ * 5. Resolve built-in and git built-in values.
126
+ * 6. Prompt for any missing values (unless `--no-prompt`).
127
+ * 7. Render, sanitize, truncate (`--max-length`), and validate.
128
+ * 8. Optionally create the branch (`--create`).
129
+ * 9. Print the branch name (unless `--quiet`).
130
+ *
131
+ * Didactic modes (`--help`, `--list-transforms`, `--print-config`,
132
+ * `--explain`) short-circuit the pipeline and return early.
133
+ */
55
134
  export async function run() {
56
135
  // Normalize argv so it works consistently across:
57
136
  // - node dist/cli.js --id 123
@@ -173,6 +252,15 @@ export async function run() {
173
252
  if (!isOk(renderedRes))
174
253
  fail("Failed to render branch name.", renderedRes.error);
175
254
  const sanitized = sanitizeGitRef(renderedRes.value);
255
+ // Apply --max-length truncation (after sanitization, before validation)
256
+ const maxLength = args.options.maxLength;
257
+ let finalBranchName = sanitized;
258
+ if (maxLength !== undefined) {
259
+ const truncateRes = safe(() => truncateEnd(sanitized, maxLength));
260
+ if (!isOk(truncateRes))
261
+ fail("Invalid --max-length value.", truncateRes.error);
262
+ finalBranchName = truncateRes.value;
263
+ }
176
264
  // --- Didactic mode: --explain ---
177
265
  if (isExplain) {
178
266
  console.log(explain({
@@ -185,11 +273,13 @@ export async function run() {
185
273
  gitValues,
186
274
  rendered: renderedRes.value,
187
275
  sanitized,
276
+ maxLength,
277
+ truncated: finalBranchName,
188
278
  transforms: defaultTransforms,
189
279
  }));
190
280
  return;
191
281
  }
192
- const validateRes = await safeAsync(() => validateBranchName(sanitized));
282
+ const validateRes = await safeAsync(() => validateBranchName(finalBranchName));
193
283
  if (!isOk(validateRes))
194
284
  fail("Branch name is not valid for git.", validateRes.error);
195
285
  const ctx = {
@@ -199,7 +289,7 @@ export async function run() {
199
289
  pattern: patternRes.value,
200
290
  ast: astRes.value,
201
291
  values: valuesRes.value,
202
- branchName: sanitized,
292
+ branchName: finalBranchName,
203
293
  };
204
294
  const createRes = create ? await safeAsync(() => createBranch(ctx.branchName)) : ok(undefined);
205
295
  if (!isOk(createRes))
@@ -1,18 +1,25 @@
1
1
  /**
2
- * @fileoverview
2
+ * @module config/loadConfig
3
+ *
3
4
  * Aggregates configuration sources without merging.
4
5
  *
5
- * Precedence:
6
- * 1) .new-branchrc.json
7
- * 2) package.json
8
- * 3) git config
6
+ * @remarks
7
+ * Precedence (first-found wins):
8
+ * 1. `.new-branchrc.json`
9
+ * 2. `package.json`
10
+ * 3. `git config`
9
11
  */
10
12
  import { rcLoader } from "./sources/rc.loader.js";
11
13
  import { packageJsonLoader } from "./sources/packageJson.loader.js";
12
14
  import { gitLoader } from "./sources/git.loader.js";
13
15
  /**
14
- * Loads the first configuration found.
15
- * No merging is performed.
16
+ * Loads the first configuration found across all supported sources.
17
+ *
18
+ * @remarks
19
+ * No merging is performed — the first source that returns a
20
+ * non-empty config wins.
21
+ *
22
+ * @returns The resolved {@link ProjectConfig}.
16
23
  */
17
24
  export async function loadConfig() {
18
25
  const { config } = await loadConfigWithSource();
@@ -20,6 +27,9 @@ export async function loadConfig() {
20
27
  }
21
28
  /**
22
29
  * Loads the first configuration found and reports which source provided it.
30
+ *
31
+ * @returns An object with the resolved {@link ProjectConfig} and a
32
+ * human-readable `source` label (e.g. `".newbranchrc.json"`).
23
33
  */
24
34
  export async function loadConfigWithSource() {
25
35
  const rcRes = await rcLoader.load();
@@ -1,5 +1,15 @@
1
1
  import { getGitConfig, getGitConfigRegexp } from "../../git/gitConfig.js";
2
2
  import { validateProjectConfigSource, validateProjectConfigFinal } from "../validate.js";
3
+ /**
4
+ * Parses a comma-separated git config value into {@link BranchType} entries.
5
+ *
6
+ * @remarks
7
+ * Each entry may be either `"value"` (label defaults to value) or
8
+ * `"value:label"` (colon-separated).
9
+ *
10
+ * @param raw - The raw comma-separated string from git config.
11
+ * @returns An array of {@link BranchType} objects.
12
+ */
3
13
  function parseGitTypes(raw) {
4
14
  return raw
5
15
  .split(",")
@@ -16,7 +26,14 @@ function parseGitTypes(raw) {
16
26
  };
17
27
  });
18
28
  }
29
+ /** Prefix used for per-alias pattern keys in git config. */
19
30
  const PATTERNS_PREFIX = "new-branch.patterns.";
31
+ /**
32
+ * Converts raw `git config --get-regexp` entries into a patterns map.
33
+ *
34
+ * @param entries - Key/value tuples from `getGitConfigRegexp`.
35
+ * @returns A record of pattern aliases, or `undefined` when empty.
36
+ */
20
37
  function parseGitPatterns(entries) {
21
38
  if (entries.length === 0)
22
39
  return undefined;
@@ -29,6 +46,16 @@ function parseGitPatterns(entries) {
29
46
  }
30
47
  return Object.keys(result).length > 0 ? result : undefined;
31
48
  }
49
+ /**
50
+ * Config loader that reads `new-branch.*` keys from git config.
51
+ *
52
+ * @remarks
53
+ * Supported keys:
54
+ * - `new-branch.pattern`
55
+ * - `new-branch.defaultType`
56
+ * - `new-branch.types` (comma-separated)
57
+ * - `new-branch.patterns.<alias>` (named patterns)
58
+ */
32
59
  export const gitLoader = {
33
60
  source: "git",
34
61
  async load() {
@@ -1,9 +1,22 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { validateProjectConfigSource, validateProjectConfigFinal } from "../validate.js";
4
+ /**
5
+ * Type guard for Node.js filesystem errors with a `code` property.
6
+ *
7
+ * @param e - The caught error value.
8
+ * @returns `true` if `e` has a `code` property.
9
+ */
4
10
  function isNodeFsError(e) {
5
11
  return typeof e === "object" && e !== null && "code" in e;
6
12
  }
13
+ /**
14
+ * Config loader that reads the `"new-branch"` key from `package.json`.
15
+ *
16
+ * @remarks
17
+ * Returns `found: false` when `package.json` does not exist or
18
+ * does not contain a `"new-branch"` key.
19
+ */
7
20
  export const packageJsonLoader = {
8
21
  source: "package.json",
9
22
  async load() {
@@ -1,10 +1,25 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { validateProjectConfigSource, validateProjectConfigFinal } from "../validate.js";
4
+ /** Default filename for the RC configuration file. */
4
5
  export const RC_FILENAME = ".newbranchrc.json";
6
+ /**
7
+ * Type guard for Node.js filesystem errors with a `code` property.
8
+ *
9
+ * @param e - The caught error value.
10
+ * @returns `true` if `e` has a `code` property.
11
+ */
5
12
  function isNodeFsError(e) {
6
13
  return typeof e === "object" && e !== null && "code" in e;
7
14
  }
15
+ /**
16
+ * Config loader that reads from a `.newbranchrc.json` file in the
17
+ * current working directory.
18
+ *
19
+ * @remarks
20
+ * Returns `found: false` when the RC file does not exist.
21
+ * Throws for any other filesystem or JSON parse error.
22
+ */
8
23
  export const rcLoader = {
9
24
  source: "rc",
10
25
  async load() {
@@ -1,8 +1,10 @@
1
1
  /**
2
- * @fileoverview
3
- * Core types for `new-branch` configuration system.
2
+ * @module config/types
4
3
  *
5
- * Naming consistency:
6
- * Always use `new-branch` (never `newBranch` or `newbranch`).
4
+ * Core types for the `new-branch` configuration system.
5
+ *
6
+ * @remarks
7
+ * Naming consistency: always use `new-branch`
8
+ * (never `newBranch` or `newbranch`).
7
9
  */
8
10
  export {};