@optique/git 0.10.7 → 1.0.0-dev.1116
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 +20 -10
- package/dist/index.cjs +113 -24
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +113 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,7 +30,8 @@ Quick start
|
|
|
30
30
|
|
|
31
31
|
~~~~ typescript
|
|
32
32
|
import { gitBranch, gitTag, gitCommit } from "@optique/git";
|
|
33
|
-
import {
|
|
33
|
+
import { object } from "@optique/core/constructs";
|
|
34
|
+
import { argument, option } from "@optique/core/primitives";
|
|
34
35
|
import { parseAsync } from "@optique/core/parser";
|
|
35
36
|
|
|
36
37
|
const parser = object({
|
|
@@ -53,7 +54,8 @@ Use `createGitParsers()` to create parsers for a different repository:
|
|
|
53
54
|
|
|
54
55
|
~~~~ typescript
|
|
55
56
|
import { createGitParsers } from "@optique/git";
|
|
56
|
-
import {
|
|
57
|
+
import { object } from "@optique/core/constructs";
|
|
58
|
+
import { argument, option } from "@optique/core/primitives";
|
|
57
59
|
import { parseAsync } from "@optique/core/parser";
|
|
58
60
|
|
|
59
61
|
const git = createGitParsers({ dir: "/path/to/repo" });
|
|
@@ -79,7 +81,8 @@ existing branch in the repository.
|
|
|
79
81
|
|
|
80
82
|
~~~~ typescript
|
|
81
83
|
import { gitBranch } from "@optique/git";
|
|
82
|
-
import {
|
|
84
|
+
import { object } from "@optique/core/constructs";
|
|
85
|
+
import { argument } from "@optique/core/primitives";
|
|
83
86
|
import { parseAsync } from "@optique/core/parser";
|
|
84
87
|
|
|
85
88
|
const parser = object({
|
|
@@ -102,7 +105,8 @@ existing branch on the specified remote.
|
|
|
102
105
|
|
|
103
106
|
~~~~ typescript
|
|
104
107
|
import { gitRemoteBranch } from "@optique/git";
|
|
105
|
-
import {
|
|
108
|
+
import { object } from "@optique/core/constructs";
|
|
109
|
+
import { option } from "@optique/core/primitives";
|
|
106
110
|
import { parseAsync } from "@optique/core/parser";
|
|
107
111
|
|
|
108
112
|
const parser = object({
|
|
@@ -120,7 +124,8 @@ in the repository.
|
|
|
120
124
|
|
|
121
125
|
~~~~ typescript
|
|
122
126
|
import { gitTag } from "@optique/git";
|
|
123
|
-
import {
|
|
127
|
+
import { object } from "@optique/core/constructs";
|
|
128
|
+
import { option } from "@optique/core/primitives";
|
|
124
129
|
import { parseAsync } from "@optique/core/parser";
|
|
125
130
|
|
|
126
131
|
const parser = object({
|
|
@@ -138,7 +143,8 @@ remote in the repository.
|
|
|
138
143
|
|
|
139
144
|
~~~~ typescript
|
|
140
145
|
import { gitRemote } from "@optique/git";
|
|
141
|
-
import {
|
|
146
|
+
import { object } from "@optique/core/constructs";
|
|
147
|
+
import { option } from "@optique/core/primitives";
|
|
142
148
|
import { parseAsync } from "@optique/core/parser";
|
|
143
149
|
|
|
144
150
|
const parser = object({
|
|
@@ -156,7 +162,8 @@ A value parser for commit SHAs. Validates that the input is a valid commit SHA
|
|
|
156
162
|
|
|
157
163
|
~~~~ typescript
|
|
158
164
|
import { gitCommit } from "@optique/git";
|
|
159
|
-
import {
|
|
165
|
+
import { object } from "@optique/core/constructs";
|
|
166
|
+
import { option } from "@optique/core/primitives";
|
|
160
167
|
import { parseAsync } from "@optique/core/parser";
|
|
161
168
|
|
|
162
169
|
const parser = object({
|
|
@@ -174,7 +181,8 @@ that the input resolves to a valid Git reference.
|
|
|
174
181
|
|
|
175
182
|
~~~~ typescript
|
|
176
183
|
import { gitRef } from "@optique/git";
|
|
177
|
-
import {
|
|
184
|
+
import { object } from "@optique/core/constructs";
|
|
185
|
+
import { option } from "@optique/core/primitives";
|
|
178
186
|
import { parseAsync } from "@optique/core/parser";
|
|
179
187
|
|
|
180
188
|
const parser = object({
|
|
@@ -192,7 +200,8 @@ created by the factory share the same filesystem and directory options.
|
|
|
192
200
|
|
|
193
201
|
~~~~ typescript
|
|
194
202
|
import { createGitParsers } from "@optique/git";
|
|
195
|
-
import {
|
|
203
|
+
import { object } from "@optique/core/constructs";
|
|
204
|
+
import { argument, option } from "@optique/core/primitives";
|
|
196
205
|
import { parseAsync } from "@optique/core/parser";
|
|
197
206
|
|
|
198
207
|
const git = createGitParsers({ dir: "/path/to/repo" });
|
|
@@ -224,7 +233,8 @@ the user's input prefix.
|
|
|
224
233
|
|
|
225
234
|
~~~~ typescript
|
|
226
235
|
import { gitBranch } from "@optique/git";
|
|
227
|
-
import {
|
|
236
|
+
import { object } from "@optique/core/constructs";
|
|
237
|
+
import { argument } from "@optique/core/primitives";
|
|
228
238
|
|
|
229
239
|
const parser = object({
|
|
230
240
|
branch: argument(gitBranch()),
|
package/dist/index.cjs
CHANGED
|
@@ -37,15 +37,16 @@ const logger = (0, __logtape_logtape.getLogger)(["optique", "git"]);
|
|
|
37
37
|
* Write methods are implemented as stubs that return rejected promises,
|
|
38
38
|
* enforcing the read-only contract and preventing accidental writes.
|
|
39
39
|
*/
|
|
40
|
+
const readOnlyFsMethod = () => Promise.reject(/* @__PURE__ */ new Error("gitFs is read-only for write operations."));
|
|
40
41
|
const gitFs = {
|
|
41
42
|
readFile: node_fs_promises.readFile,
|
|
42
|
-
writeFile:
|
|
43
|
-
mkdir:
|
|
44
|
-
rmdir:
|
|
45
|
-
unlink:
|
|
43
|
+
writeFile: readOnlyFsMethod,
|
|
44
|
+
mkdir: readOnlyFsMethod,
|
|
45
|
+
rmdir: readOnlyFsMethod,
|
|
46
|
+
unlink: readOnlyFsMethod,
|
|
46
47
|
readdir: node_fs_promises.readdir,
|
|
47
48
|
readlink: node_fs_promises.readlink,
|
|
48
|
-
symlink:
|
|
49
|
+
symlink: readOnlyFsMethod,
|
|
49
50
|
stat: node_fs_promises.stat,
|
|
50
51
|
lstat: node_fs_promises.lstat
|
|
51
52
|
};
|
|
@@ -75,8 +76,55 @@ function listFailureMessage(error, dir, errors, fallback) {
|
|
|
75
76
|
}
|
|
76
77
|
/** Default depth for commit suggestions. */
|
|
77
78
|
const DEFAULT_SUGGESTION_DEPTH = 15;
|
|
79
|
+
/**
|
|
80
|
+
* Computes the shortest unique short OID for each given full OID within the
|
|
81
|
+
* provided set, starting from a minimum length. When two or more OIDs share
|
|
82
|
+
* the same short prefix, their prefixes are lengthened until each is unique
|
|
83
|
+
* (up to the full 40-char OID).
|
|
84
|
+
*
|
|
85
|
+
* Note: this only disambiguates within the given set, not against the entire
|
|
86
|
+
* object database. In the rare case that a suggested short OID collides with
|
|
87
|
+
* an older commit outside the suggestion window, the parser will report a
|
|
88
|
+
* clear "ambiguous" error prompting the user to type more characters.
|
|
89
|
+
*/
|
|
90
|
+
function uniqueShortOids(oids, minLength) {
|
|
91
|
+
const result = /* @__PURE__ */ new Map();
|
|
92
|
+
const lengths = /* @__PURE__ */ new Map();
|
|
93
|
+
for (const oid of oids) lengths.set(oid, minLength);
|
|
94
|
+
let remaining = new Set(oids);
|
|
95
|
+
while (remaining.size > 0) {
|
|
96
|
+
const groups = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const oid of remaining) {
|
|
98
|
+
const len = lengths.get(oid);
|
|
99
|
+
const short = oid.slice(0, len);
|
|
100
|
+
const group = groups.get(short);
|
|
101
|
+
if (group != null) group.push(oid);
|
|
102
|
+
else groups.set(short, [oid]);
|
|
103
|
+
}
|
|
104
|
+
const nextRemaining = /* @__PURE__ */ new Set();
|
|
105
|
+
for (const [short, group] of groups) if (group.length === 1) result.set(group[0], short);
|
|
106
|
+
else for (const oid of group) {
|
|
107
|
+
const currentLen = lengths.get(oid);
|
|
108
|
+
if (currentLen >= oid.length) result.set(oid, oid);
|
|
109
|
+
else {
|
|
110
|
+
lengths.set(oid, currentLen + 1);
|
|
111
|
+
nextRemaining.add(oid);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
remaining = nextRemaining;
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
78
118
|
function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
79
119
|
(0, __optique_core_nonempty.ensureNonEmptyString)(metavar);
|
|
120
|
+
if (options?.suggestionDepth !== void 0) {
|
|
121
|
+
if (!Number.isInteger(options.suggestionDepth) || options.suggestionDepth < 1) {
|
|
122
|
+
const depth = options.suggestionDepth;
|
|
123
|
+
const repr = typeof depth === "number" ? String(depth) : typeof depth === "string" ? JSON.stringify(depth) : `${typeof depth} ${String(depth)}`;
|
|
124
|
+
throw new RangeError(`Invalid suggestionDepth (must be a positive integer): ${repr}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const validatedDepth = options?.suggestionDepth ?? DEFAULT_SUGGESTION_DEPTH;
|
|
80
128
|
return {
|
|
81
129
|
$mode: "async",
|
|
82
130
|
metavar,
|
|
@@ -89,10 +137,7 @@ function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
|
89
137
|
},
|
|
90
138
|
async *suggest(prefix) {
|
|
91
139
|
const dir = getRepoDir(options?.dir);
|
|
92
|
-
if (suggestFn)
|
|
93
|
-
const depth = options?.suggestionDepth ?? DEFAULT_SUGGESTION_DEPTH;
|
|
94
|
-
yield* suggestFn(dir, prefix, depth);
|
|
95
|
-
}
|
|
140
|
+
if (suggestFn) yield* suggestFn(dir, prefix, validatedDepth);
|
|
96
141
|
}
|
|
97
142
|
};
|
|
98
143
|
}
|
|
@@ -104,6 +149,7 @@ function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
|
104
149
|
*
|
|
105
150
|
* @param options Configuration options for the parser.
|
|
106
151
|
* @returns A value parser that accepts existing branch names.
|
|
152
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
107
153
|
* @since 0.9.0
|
|
108
154
|
*
|
|
109
155
|
* @example
|
|
@@ -169,6 +215,7 @@ function gitBranch(options) {
|
|
|
169
215
|
* @param remote The remote name to validate against.
|
|
170
216
|
* @param options Configuration options for the parser.
|
|
171
217
|
* @returns A value parser that accepts existing remote branch names.
|
|
218
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
172
219
|
* @since 0.9.0
|
|
173
220
|
*
|
|
174
221
|
* @example
|
|
@@ -192,6 +239,27 @@ function gitRemoteBranch(remote, options) {
|
|
|
192
239
|
success: true,
|
|
193
240
|
value: input
|
|
194
241
|
};
|
|
242
|
+
if (branches.length === 0) {
|
|
243
|
+
const remotes = await isomorphic_git.listRemotes({
|
|
244
|
+
fs: gitFs,
|
|
245
|
+
dir
|
|
246
|
+
});
|
|
247
|
+
const names = remotes.map((r) => r.remote);
|
|
248
|
+
if (!names.includes(remote)) {
|
|
249
|
+
if (errors?.remoteNotFound) return {
|
|
250
|
+
success: false,
|
|
251
|
+
error: errors.remoteNotFound(remote, names)
|
|
252
|
+
};
|
|
253
|
+
if (errors?.notFound) return {
|
|
254
|
+
success: false,
|
|
255
|
+
error: errors.notFound(input, branches)
|
|
256
|
+
};
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
error: __optique_core_message.message`Remote ${(0, __optique_core_message.value)(remote)} does not exist. Available remotes: ${(0, __optique_core_message.valueSet)(names)}`
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
195
263
|
if (errors?.notFound) return {
|
|
196
264
|
success: false,
|
|
197
265
|
error: errors.notFound(input, branches)
|
|
@@ -233,6 +301,7 @@ function gitRemoteBranch(remote, options) {
|
|
|
233
301
|
*
|
|
234
302
|
* @param options Configuration options for the parser.
|
|
235
303
|
* @returns A value parser that accepts existing tag names.
|
|
304
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
236
305
|
* @since 0.9.0
|
|
237
306
|
*/
|
|
238
307
|
function gitTag(options) {
|
|
@@ -286,6 +355,7 @@ function gitTag(options) {
|
|
|
286
355
|
*
|
|
287
356
|
* @param options Configuration options for the parser.
|
|
288
357
|
* @returns A value parser that accepts existing remote names.
|
|
358
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
289
359
|
* @since 0.9.0
|
|
290
360
|
*/
|
|
291
361
|
function gitRemote(options) {
|
|
@@ -343,6 +413,7 @@ function gitRemote(options) {
|
|
|
343
413
|
*
|
|
344
414
|
* @param options Configuration options for the parser.
|
|
345
415
|
* @returns A value parser that accepts existing commit SHAs.
|
|
416
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
346
417
|
* @since 0.9.0
|
|
347
418
|
*/
|
|
348
419
|
function gitCommit(options) {
|
|
@@ -369,7 +440,7 @@ function gitCommit(options) {
|
|
|
369
440
|
value: oid
|
|
370
441
|
};
|
|
371
442
|
} catch (e) {
|
|
372
|
-
if (hasErrorCode(e, "AmbiguousShortOidError")) return {
|
|
443
|
+
if (hasErrorCode(e, "AmbiguousShortOidError") || hasErrorCode(e, "AmbiguousError")) return {
|
|
373
444
|
success: false,
|
|
374
445
|
error: __optique_core_message.message`Commit SHA ${(0, __optique_core_message.value)(input)} is ambiguous. Provide more characters to disambiguate.`
|
|
375
446
|
};
|
|
@@ -389,8 +460,11 @@ function gitCommit(options) {
|
|
|
389
460
|
dir,
|
|
390
461
|
depth
|
|
391
462
|
});
|
|
392
|
-
|
|
393
|
-
|
|
463
|
+
const matching = commits.filter((c) => c.oid.startsWith(prefix));
|
|
464
|
+
const minLen = Math.max(7, prefix.length);
|
|
465
|
+
const shortOids = uniqueShortOids(matching.map((c) => c.oid), minLen);
|
|
466
|
+
for (const commit of matching) {
|
|
467
|
+
const shortOid = shortOids.get(commit.oid);
|
|
394
468
|
const firstLine = commit.commit.message.split("\n")[0];
|
|
395
469
|
yield {
|
|
396
470
|
kind: "literal",
|
|
@@ -415,6 +489,7 @@ function gitCommit(options) {
|
|
|
415
489
|
*
|
|
416
490
|
* @param options Configuration options for the parser.
|
|
417
491
|
* @returns A value parser that accepts any git reference.
|
|
492
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
418
493
|
* @since 0.9.0
|
|
419
494
|
*/
|
|
420
495
|
function gitRef(options) {
|
|
@@ -443,7 +518,7 @@ function gitRef(options) {
|
|
|
443
518
|
value: oid
|
|
444
519
|
};
|
|
445
520
|
} catch (e) {
|
|
446
|
-
if (hasErrorCode(e, "AmbiguousShortOidError")) return {
|
|
521
|
+
if (hasErrorCode(e, "AmbiguousShortOidError") || hasErrorCode(e, "AmbiguousError")) return {
|
|
447
522
|
success: false,
|
|
448
523
|
error: __optique_core_message.message`Reference ${(0, __optique_core_message.value)(input)} is ambiguous. Provide more characters to disambiguate.`
|
|
449
524
|
};
|
|
@@ -473,16 +548,28 @@ function gitRef(options) {
|
|
|
473
548
|
depth
|
|
474
549
|
})
|
|
475
550
|
]);
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
for (const
|
|
485
|
-
|
|
551
|
+
const seen = /* @__PURE__ */ new Set();
|
|
552
|
+
for (const branch of branches) if (branch.startsWith(prefix) && !seen.has(branch)) {
|
|
553
|
+
seen.add(branch);
|
|
554
|
+
yield {
|
|
555
|
+
kind: "literal",
|
|
556
|
+
text: branch
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
for (const tag of tags) if (tag.startsWith(prefix) && !seen.has(tag)) {
|
|
560
|
+
seen.add(tag);
|
|
561
|
+
yield {
|
|
562
|
+
kind: "literal",
|
|
563
|
+
text: tag
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const matching = commits.filter((c) => c.oid.startsWith(prefix));
|
|
567
|
+
const minLen = Math.max(7, prefix.length);
|
|
568
|
+
const shortOids = uniqueShortOids(matching.map((c) => c.oid), minLen);
|
|
569
|
+
for (const commit of matching) {
|
|
570
|
+
const shortOid = shortOids.get(commit.oid);
|
|
571
|
+
if (seen.has(shortOid)) continue;
|
|
572
|
+
seen.add(shortOid);
|
|
486
573
|
const firstLine = commit.commit.message.split("\n")[0];
|
|
487
574
|
yield {
|
|
488
575
|
kind: "literal",
|
|
@@ -503,7 +590,9 @@ function gitRef(options) {
|
|
|
503
590
|
* Creates a set of git parsers with shared configuration.
|
|
504
591
|
*
|
|
505
592
|
* @param options Shared configuration for the parsers.
|
|
506
|
-
* @returns An object containing git parsers.
|
|
593
|
+
* @returns An object containing git parsers. Each returned method may throw
|
|
594
|
+
* a {@link RangeError} if the merged `suggestionDepth` is not a positive
|
|
595
|
+
* integer.
|
|
507
596
|
* @since 0.9.0
|
|
508
597
|
*/
|
|
509
598
|
function createGitParsers(options) {
|
package/dist/index.d.cts
CHANGED
|
@@ -29,7 +29,9 @@ interface GitParserOptions {
|
|
|
29
29
|
errors?: GitParserErrors;
|
|
30
30
|
/**
|
|
31
31
|
* Maximum number of recent commits to include in shell completion suggestions.
|
|
32
|
-
* Only
|
|
32
|
+
* Only affects suggestions from `gitCommit()` and `gitRef()` parsers, but
|
|
33
|
+
* is validated by all git parser functions.
|
|
34
|
+
* Must be a positive integer.
|
|
33
35
|
* Defaults to 15.
|
|
34
36
|
*
|
|
35
37
|
* @since 0.9.0
|
|
@@ -66,6 +68,16 @@ interface GitParserErrors {
|
|
|
66
68
|
* @returns A custom error message.
|
|
67
69
|
*/
|
|
68
70
|
invalidFormat?: (input: string) => Message;
|
|
71
|
+
/**
|
|
72
|
+
* Error message when the remote does not exist.
|
|
73
|
+
* Only used by {@link gitRemoteBranch}.
|
|
74
|
+
*
|
|
75
|
+
* @param remote The remote name that was not found.
|
|
76
|
+
* @param availableRemotes List of available remote names.
|
|
77
|
+
* @returns A custom error message.
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
*/
|
|
80
|
+
remoteNotFound?: (remote: string, availableRemotes: readonly string[]) => Message;
|
|
69
81
|
}
|
|
70
82
|
/**
|
|
71
83
|
* Git parsers factory interface.
|
|
@@ -77,6 +89,7 @@ interface GitParsers {
|
|
|
77
89
|
* Creates a value parser that validates local branch names.
|
|
78
90
|
* @param options Configuration options for the parser.
|
|
79
91
|
* @returns A value parser that accepts existing branch names.
|
|
92
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
80
93
|
*/
|
|
81
94
|
branch(options?: GitParserOptions): ValueParser<"async", string>;
|
|
82
95
|
/**
|
|
@@ -84,24 +97,28 @@ interface GitParsers {
|
|
|
84
97
|
* @param remote The remote name to validate against.
|
|
85
98
|
* @param options Configuration options for the parser.
|
|
86
99
|
* @returns A value parser that accepts existing remote branch names.
|
|
100
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
87
101
|
*/
|
|
88
102
|
remoteBranch(remote: string, options?: GitParserOptions): ValueParser<"async", string>;
|
|
89
103
|
/**
|
|
90
104
|
* Creates a value parser that validates tag names.
|
|
91
105
|
* @param options Configuration options for the parser.
|
|
92
106
|
* @returns A value parser that accepts existing tag names.
|
|
107
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
93
108
|
*/
|
|
94
109
|
tag(options?: GitParserOptions): ValueParser<"async", string>;
|
|
95
110
|
/**
|
|
96
111
|
* Creates a value parser that validates remote names.
|
|
97
112
|
* @param options Configuration options for the parser.
|
|
98
113
|
* @returns A value parser that accepts existing remote names.
|
|
114
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
99
115
|
*/
|
|
100
116
|
remote(options?: GitParserOptions): ValueParser<"async", string>;
|
|
101
117
|
/**
|
|
102
118
|
* Creates a value parser that validates commit SHAs.
|
|
103
119
|
* @param options Configuration options for the parser.
|
|
104
120
|
* @returns A value parser that accepts existing commit SHAs.
|
|
121
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
105
122
|
*/
|
|
106
123
|
commit(options?: GitParserOptions): ValueParser<"async", string>;
|
|
107
124
|
/**
|
|
@@ -109,6 +126,7 @@ interface GitParsers {
|
|
|
109
126
|
* Accepts branch names, tag names, or commit SHAs.
|
|
110
127
|
* @param options Configuration options for the parser.
|
|
111
128
|
* @returns A value parser that accepts any git reference.
|
|
129
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
112
130
|
*/
|
|
113
131
|
ref(options?: GitParserOptions): ValueParser<"async", string>;
|
|
114
132
|
}
|
|
@@ -120,6 +138,7 @@ interface GitParsers {
|
|
|
120
138
|
*
|
|
121
139
|
* @param options Configuration options for the parser.
|
|
122
140
|
* @returns A value parser that accepts existing branch names.
|
|
141
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
123
142
|
* @since 0.9.0
|
|
124
143
|
*
|
|
125
144
|
* @example
|
|
@@ -140,6 +159,7 @@ declare function gitBranch(options?: GitParserOptions): ValueParser<"async", str
|
|
|
140
159
|
* @param remote The remote name to validate against.
|
|
141
160
|
* @param options Configuration options for the parser.
|
|
142
161
|
* @returns A value parser that accepts existing remote branch names.
|
|
162
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
143
163
|
* @since 0.9.0
|
|
144
164
|
*
|
|
145
165
|
* @example
|
|
@@ -156,6 +176,7 @@ declare function gitRemoteBranch(remote: string, options?: GitParserOptions): Va
|
|
|
156
176
|
*
|
|
157
177
|
* @param options Configuration options for the parser.
|
|
158
178
|
* @returns A value parser that accepts existing tag names.
|
|
179
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
159
180
|
* @since 0.9.0
|
|
160
181
|
*/
|
|
161
182
|
declare function gitTag(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -164,6 +185,7 @@ declare function gitTag(options?: GitParserOptions): ValueParser<"async", string
|
|
|
164
185
|
*
|
|
165
186
|
* @param options Configuration options for the parser.
|
|
166
187
|
* @returns A value parser that accepts existing remote names.
|
|
188
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
167
189
|
* @since 0.9.0
|
|
168
190
|
*/
|
|
169
191
|
declare function gitRemote(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -175,6 +197,7 @@ declare function gitRemote(options?: GitParserOptions): ValueParser<"async", str
|
|
|
175
197
|
*
|
|
176
198
|
* @param options Configuration options for the parser.
|
|
177
199
|
* @returns A value parser that accepts existing commit SHAs.
|
|
200
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
178
201
|
* @since 0.9.0
|
|
179
202
|
*/
|
|
180
203
|
declare function gitCommit(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -186,6 +209,7 @@ declare function gitCommit(options?: GitParserOptions): ValueParser<"async", str
|
|
|
186
209
|
*
|
|
187
210
|
* @param options Configuration options for the parser.
|
|
188
211
|
* @returns A value parser that accepts any git reference.
|
|
212
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
189
213
|
* @since 0.9.0
|
|
190
214
|
*/
|
|
191
215
|
declare function gitRef(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -193,7 +217,9 @@ declare function gitRef(options?: GitParserOptions): ValueParser<"async", string
|
|
|
193
217
|
* Creates a set of git parsers with shared configuration.
|
|
194
218
|
*
|
|
195
219
|
* @param options Shared configuration for the parsers.
|
|
196
|
-
* @returns An object containing git parsers.
|
|
220
|
+
* @returns An object containing git parsers. Each returned method may throw
|
|
221
|
+
* a {@link RangeError} if the merged `suggestionDepth` is not a positive
|
|
222
|
+
* integer.
|
|
197
223
|
* @since 0.9.0
|
|
198
224
|
*/
|
|
199
225
|
declare function createGitParsers(options?: GitParserOptions): GitParsers;
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,9 @@ interface GitParserOptions {
|
|
|
29
29
|
errors?: GitParserErrors;
|
|
30
30
|
/**
|
|
31
31
|
* Maximum number of recent commits to include in shell completion suggestions.
|
|
32
|
-
* Only
|
|
32
|
+
* Only affects suggestions from `gitCommit()` and `gitRef()` parsers, but
|
|
33
|
+
* is validated by all git parser functions.
|
|
34
|
+
* Must be a positive integer.
|
|
33
35
|
* Defaults to 15.
|
|
34
36
|
*
|
|
35
37
|
* @since 0.9.0
|
|
@@ -66,6 +68,16 @@ interface GitParserErrors {
|
|
|
66
68
|
* @returns A custom error message.
|
|
67
69
|
*/
|
|
68
70
|
invalidFormat?: (input: string) => Message;
|
|
71
|
+
/**
|
|
72
|
+
* Error message when the remote does not exist.
|
|
73
|
+
* Only used by {@link gitRemoteBranch}.
|
|
74
|
+
*
|
|
75
|
+
* @param remote The remote name that was not found.
|
|
76
|
+
* @param availableRemotes List of available remote names.
|
|
77
|
+
* @returns A custom error message.
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
*/
|
|
80
|
+
remoteNotFound?: (remote: string, availableRemotes: readonly string[]) => Message;
|
|
69
81
|
}
|
|
70
82
|
/**
|
|
71
83
|
* Git parsers factory interface.
|
|
@@ -77,6 +89,7 @@ interface GitParsers {
|
|
|
77
89
|
* Creates a value parser that validates local branch names.
|
|
78
90
|
* @param options Configuration options for the parser.
|
|
79
91
|
* @returns A value parser that accepts existing branch names.
|
|
92
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
80
93
|
*/
|
|
81
94
|
branch(options?: GitParserOptions): ValueParser<"async", string>;
|
|
82
95
|
/**
|
|
@@ -84,24 +97,28 @@ interface GitParsers {
|
|
|
84
97
|
* @param remote The remote name to validate against.
|
|
85
98
|
* @param options Configuration options for the parser.
|
|
86
99
|
* @returns A value parser that accepts existing remote branch names.
|
|
100
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
87
101
|
*/
|
|
88
102
|
remoteBranch(remote: string, options?: GitParserOptions): ValueParser<"async", string>;
|
|
89
103
|
/**
|
|
90
104
|
* Creates a value parser that validates tag names.
|
|
91
105
|
* @param options Configuration options for the parser.
|
|
92
106
|
* @returns A value parser that accepts existing tag names.
|
|
107
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
93
108
|
*/
|
|
94
109
|
tag(options?: GitParserOptions): ValueParser<"async", string>;
|
|
95
110
|
/**
|
|
96
111
|
* Creates a value parser that validates remote names.
|
|
97
112
|
* @param options Configuration options for the parser.
|
|
98
113
|
* @returns A value parser that accepts existing remote names.
|
|
114
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
99
115
|
*/
|
|
100
116
|
remote(options?: GitParserOptions): ValueParser<"async", string>;
|
|
101
117
|
/**
|
|
102
118
|
* Creates a value parser that validates commit SHAs.
|
|
103
119
|
* @param options Configuration options for the parser.
|
|
104
120
|
* @returns A value parser that accepts existing commit SHAs.
|
|
121
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
105
122
|
*/
|
|
106
123
|
commit(options?: GitParserOptions): ValueParser<"async", string>;
|
|
107
124
|
/**
|
|
@@ -109,6 +126,7 @@ interface GitParsers {
|
|
|
109
126
|
* Accepts branch names, tag names, or commit SHAs.
|
|
110
127
|
* @param options Configuration options for the parser.
|
|
111
128
|
* @returns A value parser that accepts any git reference.
|
|
129
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
112
130
|
*/
|
|
113
131
|
ref(options?: GitParserOptions): ValueParser<"async", string>;
|
|
114
132
|
}
|
|
@@ -120,6 +138,7 @@ interface GitParsers {
|
|
|
120
138
|
*
|
|
121
139
|
* @param options Configuration options for the parser.
|
|
122
140
|
* @returns A value parser that accepts existing branch names.
|
|
141
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
123
142
|
* @since 0.9.0
|
|
124
143
|
*
|
|
125
144
|
* @example
|
|
@@ -140,6 +159,7 @@ declare function gitBranch(options?: GitParserOptions): ValueParser<"async", str
|
|
|
140
159
|
* @param remote The remote name to validate against.
|
|
141
160
|
* @param options Configuration options for the parser.
|
|
142
161
|
* @returns A value parser that accepts existing remote branch names.
|
|
162
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
143
163
|
* @since 0.9.0
|
|
144
164
|
*
|
|
145
165
|
* @example
|
|
@@ -156,6 +176,7 @@ declare function gitRemoteBranch(remote: string, options?: GitParserOptions): Va
|
|
|
156
176
|
*
|
|
157
177
|
* @param options Configuration options for the parser.
|
|
158
178
|
* @returns A value parser that accepts existing tag names.
|
|
179
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
159
180
|
* @since 0.9.0
|
|
160
181
|
*/
|
|
161
182
|
declare function gitTag(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -164,6 +185,7 @@ declare function gitTag(options?: GitParserOptions): ValueParser<"async", string
|
|
|
164
185
|
*
|
|
165
186
|
* @param options Configuration options for the parser.
|
|
166
187
|
* @returns A value parser that accepts existing remote names.
|
|
188
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
167
189
|
* @since 0.9.0
|
|
168
190
|
*/
|
|
169
191
|
declare function gitRemote(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -175,6 +197,7 @@ declare function gitRemote(options?: GitParserOptions): ValueParser<"async", str
|
|
|
175
197
|
*
|
|
176
198
|
* @param options Configuration options for the parser.
|
|
177
199
|
* @returns A value parser that accepts existing commit SHAs.
|
|
200
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
178
201
|
* @since 0.9.0
|
|
179
202
|
*/
|
|
180
203
|
declare function gitCommit(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -186,6 +209,7 @@ declare function gitCommit(options?: GitParserOptions): ValueParser<"async", str
|
|
|
186
209
|
*
|
|
187
210
|
* @param options Configuration options for the parser.
|
|
188
211
|
* @returns A value parser that accepts any git reference.
|
|
212
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
189
213
|
* @since 0.9.0
|
|
190
214
|
*/
|
|
191
215
|
declare function gitRef(options?: GitParserOptions): ValueParser<"async", string>;
|
|
@@ -193,7 +217,9 @@ declare function gitRef(options?: GitParserOptions): ValueParser<"async", string
|
|
|
193
217
|
* Creates a set of git parsers with shared configuration.
|
|
194
218
|
*
|
|
195
219
|
* @param options Shared configuration for the parsers.
|
|
196
|
-
* @returns An object containing git parsers.
|
|
220
|
+
* @returns An object containing git parsers. Each returned method may throw
|
|
221
|
+
* a {@link RangeError} if the merged `suggestionDepth` is not a positive
|
|
222
|
+
* integer.
|
|
197
223
|
* @since 0.9.0
|
|
198
224
|
*/
|
|
199
225
|
declare function createGitParsers(options?: GitParserOptions): GitParsers;
|
package/dist/index.js
CHANGED
|
@@ -15,15 +15,16 @@ const logger = getLogger(["optique", "git"]);
|
|
|
15
15
|
* Write methods are implemented as stubs that return rejected promises,
|
|
16
16
|
* enforcing the read-only contract and preventing accidental writes.
|
|
17
17
|
*/
|
|
18
|
+
const readOnlyFsMethod = () => Promise.reject(/* @__PURE__ */ new Error("gitFs is read-only for write operations."));
|
|
18
19
|
const gitFs = {
|
|
19
20
|
readFile: fs.readFile,
|
|
20
|
-
writeFile:
|
|
21
|
-
mkdir:
|
|
22
|
-
rmdir:
|
|
23
|
-
unlink:
|
|
21
|
+
writeFile: readOnlyFsMethod,
|
|
22
|
+
mkdir: readOnlyFsMethod,
|
|
23
|
+
rmdir: readOnlyFsMethod,
|
|
24
|
+
unlink: readOnlyFsMethod,
|
|
24
25
|
readdir: fs.readdir,
|
|
25
26
|
readlink: fs.readlink,
|
|
26
|
-
symlink:
|
|
27
|
+
symlink: readOnlyFsMethod,
|
|
27
28
|
stat: fs.stat,
|
|
28
29
|
lstat: fs.lstat
|
|
29
30
|
};
|
|
@@ -53,8 +54,55 @@ function listFailureMessage(error, dir, errors, fallback) {
|
|
|
53
54
|
}
|
|
54
55
|
/** Default depth for commit suggestions. */
|
|
55
56
|
const DEFAULT_SUGGESTION_DEPTH = 15;
|
|
57
|
+
/**
|
|
58
|
+
* Computes the shortest unique short OID for each given full OID within the
|
|
59
|
+
* provided set, starting from a minimum length. When two or more OIDs share
|
|
60
|
+
* the same short prefix, their prefixes are lengthened until each is unique
|
|
61
|
+
* (up to the full 40-char OID).
|
|
62
|
+
*
|
|
63
|
+
* Note: this only disambiguates within the given set, not against the entire
|
|
64
|
+
* object database. In the rare case that a suggested short OID collides with
|
|
65
|
+
* an older commit outside the suggestion window, the parser will report a
|
|
66
|
+
* clear "ambiguous" error prompting the user to type more characters.
|
|
67
|
+
*/
|
|
68
|
+
function uniqueShortOids(oids, minLength) {
|
|
69
|
+
const result = /* @__PURE__ */ new Map();
|
|
70
|
+
const lengths = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const oid of oids) lengths.set(oid, minLength);
|
|
72
|
+
let remaining = new Set(oids);
|
|
73
|
+
while (remaining.size > 0) {
|
|
74
|
+
const groups = /* @__PURE__ */ new Map();
|
|
75
|
+
for (const oid of remaining) {
|
|
76
|
+
const len = lengths.get(oid);
|
|
77
|
+
const short = oid.slice(0, len);
|
|
78
|
+
const group = groups.get(short);
|
|
79
|
+
if (group != null) group.push(oid);
|
|
80
|
+
else groups.set(short, [oid]);
|
|
81
|
+
}
|
|
82
|
+
const nextRemaining = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const [short, group] of groups) if (group.length === 1) result.set(group[0], short);
|
|
84
|
+
else for (const oid of group) {
|
|
85
|
+
const currentLen = lengths.get(oid);
|
|
86
|
+
if (currentLen >= oid.length) result.set(oid, oid);
|
|
87
|
+
else {
|
|
88
|
+
lengths.set(oid, currentLen + 1);
|
|
89
|
+
nextRemaining.add(oid);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
remaining = nextRemaining;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
56
96
|
function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
57
97
|
ensureNonEmptyString(metavar);
|
|
98
|
+
if (options?.suggestionDepth !== void 0) {
|
|
99
|
+
if (!Number.isInteger(options.suggestionDepth) || options.suggestionDepth < 1) {
|
|
100
|
+
const depth = options.suggestionDepth;
|
|
101
|
+
const repr = typeof depth === "number" ? String(depth) : typeof depth === "string" ? JSON.stringify(depth) : `${typeof depth} ${String(depth)}`;
|
|
102
|
+
throw new RangeError(`Invalid suggestionDepth (must be a positive integer): ${repr}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const validatedDepth = options?.suggestionDepth ?? DEFAULT_SUGGESTION_DEPTH;
|
|
58
106
|
return {
|
|
59
107
|
$mode: "async",
|
|
60
108
|
metavar,
|
|
@@ -67,10 +115,7 @@ function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
|
67
115
|
},
|
|
68
116
|
async *suggest(prefix) {
|
|
69
117
|
const dir = getRepoDir(options?.dir);
|
|
70
|
-
if (suggestFn)
|
|
71
|
-
const depth = options?.suggestionDepth ?? DEFAULT_SUGGESTION_DEPTH;
|
|
72
|
-
yield* suggestFn(dir, prefix, depth);
|
|
73
|
-
}
|
|
118
|
+
if (suggestFn) yield* suggestFn(dir, prefix, validatedDepth);
|
|
74
119
|
}
|
|
75
120
|
};
|
|
76
121
|
}
|
|
@@ -82,6 +127,7 @@ function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
|
|
|
82
127
|
*
|
|
83
128
|
* @param options Configuration options for the parser.
|
|
84
129
|
* @returns A value parser that accepts existing branch names.
|
|
130
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
85
131
|
* @since 0.9.0
|
|
86
132
|
*
|
|
87
133
|
* @example
|
|
@@ -147,6 +193,7 @@ function gitBranch(options) {
|
|
|
147
193
|
* @param remote The remote name to validate against.
|
|
148
194
|
* @param options Configuration options for the parser.
|
|
149
195
|
* @returns A value parser that accepts existing remote branch names.
|
|
196
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
150
197
|
* @since 0.9.0
|
|
151
198
|
*
|
|
152
199
|
* @example
|
|
@@ -170,6 +217,27 @@ function gitRemoteBranch(remote, options) {
|
|
|
170
217
|
success: true,
|
|
171
218
|
value: input
|
|
172
219
|
};
|
|
220
|
+
if (branches.length === 0) {
|
|
221
|
+
const remotes = await git.listRemotes({
|
|
222
|
+
fs: gitFs,
|
|
223
|
+
dir
|
|
224
|
+
});
|
|
225
|
+
const names = remotes.map((r) => r.remote);
|
|
226
|
+
if (!names.includes(remote)) {
|
|
227
|
+
if (errors?.remoteNotFound) return {
|
|
228
|
+
success: false,
|
|
229
|
+
error: errors.remoteNotFound(remote, names)
|
|
230
|
+
};
|
|
231
|
+
if (errors?.notFound) return {
|
|
232
|
+
success: false,
|
|
233
|
+
error: errors.notFound(input, branches)
|
|
234
|
+
};
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error: message`Remote ${value(remote)} does not exist. Available remotes: ${valueSet(names)}`
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
173
241
|
if (errors?.notFound) return {
|
|
174
242
|
success: false,
|
|
175
243
|
error: errors.notFound(input, branches)
|
|
@@ -211,6 +279,7 @@ function gitRemoteBranch(remote, options) {
|
|
|
211
279
|
*
|
|
212
280
|
* @param options Configuration options for the parser.
|
|
213
281
|
* @returns A value parser that accepts existing tag names.
|
|
282
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
214
283
|
* @since 0.9.0
|
|
215
284
|
*/
|
|
216
285
|
function gitTag(options) {
|
|
@@ -264,6 +333,7 @@ function gitTag(options) {
|
|
|
264
333
|
*
|
|
265
334
|
* @param options Configuration options for the parser.
|
|
266
335
|
* @returns A value parser that accepts existing remote names.
|
|
336
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
267
337
|
* @since 0.9.0
|
|
268
338
|
*/
|
|
269
339
|
function gitRemote(options) {
|
|
@@ -321,6 +391,7 @@ function gitRemote(options) {
|
|
|
321
391
|
*
|
|
322
392
|
* @param options Configuration options for the parser.
|
|
323
393
|
* @returns A value parser that accepts existing commit SHAs.
|
|
394
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
324
395
|
* @since 0.9.0
|
|
325
396
|
*/
|
|
326
397
|
function gitCommit(options) {
|
|
@@ -347,7 +418,7 @@ function gitCommit(options) {
|
|
|
347
418
|
value: oid
|
|
348
419
|
};
|
|
349
420
|
} catch (e) {
|
|
350
|
-
if (hasErrorCode(e, "AmbiguousShortOidError")) return {
|
|
421
|
+
if (hasErrorCode(e, "AmbiguousShortOidError") || hasErrorCode(e, "AmbiguousError")) return {
|
|
351
422
|
success: false,
|
|
352
423
|
error: message`Commit SHA ${value(input)} is ambiguous. Provide more characters to disambiguate.`
|
|
353
424
|
};
|
|
@@ -367,8 +438,11 @@ function gitCommit(options) {
|
|
|
367
438
|
dir,
|
|
368
439
|
depth
|
|
369
440
|
});
|
|
370
|
-
|
|
371
|
-
|
|
441
|
+
const matching = commits.filter((c) => c.oid.startsWith(prefix));
|
|
442
|
+
const minLen = Math.max(7, prefix.length);
|
|
443
|
+
const shortOids = uniqueShortOids(matching.map((c) => c.oid), minLen);
|
|
444
|
+
for (const commit of matching) {
|
|
445
|
+
const shortOid = shortOids.get(commit.oid);
|
|
372
446
|
const firstLine = commit.commit.message.split("\n")[0];
|
|
373
447
|
yield {
|
|
374
448
|
kind: "literal",
|
|
@@ -393,6 +467,7 @@ function gitCommit(options) {
|
|
|
393
467
|
*
|
|
394
468
|
* @param options Configuration options for the parser.
|
|
395
469
|
* @returns A value parser that accepts any git reference.
|
|
470
|
+
* @throws {RangeError} If `suggestionDepth` is not a positive integer.
|
|
396
471
|
* @since 0.9.0
|
|
397
472
|
*/
|
|
398
473
|
function gitRef(options) {
|
|
@@ -421,7 +496,7 @@ function gitRef(options) {
|
|
|
421
496
|
value: oid
|
|
422
497
|
};
|
|
423
498
|
} catch (e) {
|
|
424
|
-
if (hasErrorCode(e, "AmbiguousShortOidError")) return {
|
|
499
|
+
if (hasErrorCode(e, "AmbiguousShortOidError") || hasErrorCode(e, "AmbiguousError")) return {
|
|
425
500
|
success: false,
|
|
426
501
|
error: message`Reference ${value(input)} is ambiguous. Provide more characters to disambiguate.`
|
|
427
502
|
};
|
|
@@ -451,16 +526,28 @@ function gitRef(options) {
|
|
|
451
526
|
depth
|
|
452
527
|
})
|
|
453
528
|
]);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
462
|
-
for (const
|
|
463
|
-
|
|
529
|
+
const seen = /* @__PURE__ */ new Set();
|
|
530
|
+
for (const branch of branches) if (branch.startsWith(prefix) && !seen.has(branch)) {
|
|
531
|
+
seen.add(branch);
|
|
532
|
+
yield {
|
|
533
|
+
kind: "literal",
|
|
534
|
+
text: branch
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
for (const tag of tags) if (tag.startsWith(prefix) && !seen.has(tag)) {
|
|
538
|
+
seen.add(tag);
|
|
539
|
+
yield {
|
|
540
|
+
kind: "literal",
|
|
541
|
+
text: tag
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
const matching = commits.filter((c) => c.oid.startsWith(prefix));
|
|
545
|
+
const minLen = Math.max(7, prefix.length);
|
|
546
|
+
const shortOids = uniqueShortOids(matching.map((c) => c.oid), minLen);
|
|
547
|
+
for (const commit of matching) {
|
|
548
|
+
const shortOid = shortOids.get(commit.oid);
|
|
549
|
+
if (seen.has(shortOid)) continue;
|
|
550
|
+
seen.add(shortOid);
|
|
464
551
|
const firstLine = commit.commit.message.split("\n")[0];
|
|
465
552
|
yield {
|
|
466
553
|
kind: "literal",
|
|
@@ -481,7 +568,9 @@ function gitRef(options) {
|
|
|
481
568
|
* Creates a set of git parsers with shared configuration.
|
|
482
569
|
*
|
|
483
570
|
* @param options Shared configuration for the parsers.
|
|
484
|
-
* @returns An object containing git parsers.
|
|
571
|
+
* @returns An object containing git parsers. Each returned method may throw
|
|
572
|
+
* a {@link RangeError} if the merged `suggestionDepth` is not a positive
|
|
573
|
+
* integer.
|
|
485
574
|
* @since 0.9.0
|
|
486
575
|
*/
|
|
487
576
|
function createGitParsers(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/git",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-dev.1116+6084dd3a",
|
|
4
4
|
"description": "Git value parsers for Optique",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@logtape/logtape": "^1.2.2",
|
|
61
61
|
"isomorphic-git": "^1.36.1",
|
|
62
|
-
"@optique/core": "0.
|
|
62
|
+
"@optique/core": "1.0.0-dev.1116+6084dd3a"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@types/node": "^20.19.9",
|