@optique/git 0.9.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,553 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ const __optique_core_message = __toESM(require("@optique/core/message"));
25
+ const __optique_core_nonempty = __toESM(require("@optique/core/nonempty"));
26
+ const isomorphic_git = __toESM(require("isomorphic-git"));
27
+ const node_process = __toESM(require("node:process"));
28
+
29
+ //#region src/index.ts
30
+ const METAVAR_BRANCH = "BRANCH";
31
+ const METAVAR_TAG = "TAG";
32
+ const METAVAR_REMOTE = "REMOTE";
33
+ let defaultFs = null;
34
+ let fsLoading = null;
35
+ async function getDefaultFs() {
36
+ if (defaultFs) return await defaultFs;
37
+ if (fsLoading) return await fsLoading;
38
+ fsLoading = (async () => {
39
+ const nodeFs = await import("node:fs/promises");
40
+ const { TextDecoder } = await import("node:util");
41
+ const decoder = new TextDecoder();
42
+ defaultFs = {
43
+ async readFile(path) {
44
+ const data = await nodeFs.readFile(path);
45
+ if (path.endsWith("/index") || path.endsWith(".idx")) return data;
46
+ return decoder.decode(data);
47
+ },
48
+ async writeFile(path, data) {
49
+ await nodeFs.writeFile(path, data);
50
+ },
51
+ async mkdir(path, options) {
52
+ await nodeFs.mkdir(path, options);
53
+ },
54
+ async rmdir(path, options) {
55
+ await nodeFs.rmdir(path, options);
56
+ },
57
+ async unlink(path) {
58
+ await nodeFs.unlink(path);
59
+ },
60
+ async readdir(path) {
61
+ const entries = await nodeFs.readdir(path, { withFileTypes: false });
62
+ return entries.filter((e) => typeof e === "string");
63
+ },
64
+ async lstat(path) {
65
+ return await nodeFs.lstat(path);
66
+ },
67
+ async stat(path) {
68
+ return await nodeFs.stat(path);
69
+ },
70
+ async readlink(path) {
71
+ return await nodeFs.readlink(path);
72
+ },
73
+ async symlink(target, path) {
74
+ await nodeFs.symlink(target, path, "file");
75
+ },
76
+ async chmod(path, mode) {
77
+ await nodeFs.chmod(path, mode);
78
+ },
79
+ async chown(path, uid, gid) {
80
+ await nodeFs.chown(path, uid, gid);
81
+ },
82
+ async rename(oldPath, newPath) {
83
+ await nodeFs.rename(oldPath, newPath);
84
+ },
85
+ async copyFile(srcPath, destPath) {
86
+ await nodeFs.copyFile(srcPath, destPath);
87
+ },
88
+ async exists(path) {
89
+ try {
90
+ await nodeFs.stat(path);
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+ };
97
+ return defaultFs;
98
+ })();
99
+ return fsLoading;
100
+ }
101
+ function createAsyncValueParser(options, metavar, parseFn, suggestFn) {
102
+ return {
103
+ $mode: "async",
104
+ metavar,
105
+ async parse(input) {
106
+ const fs = options?.fs ?? await getDefaultFs();
107
+ const dir = options?.dir ?? (typeof node_process.default !== "undefined" ? node_process.default.cwd() : ".");
108
+ (0, __optique_core_nonempty.ensureNonEmptyString)(metavar);
109
+ return parseFn(fs, dir, input);
110
+ },
111
+ format(value) {
112
+ return value;
113
+ },
114
+ async *suggest(prefix) {
115
+ const fs = options?.fs ?? await getDefaultFs();
116
+ const dir = options?.dir ?? (typeof node_process.default !== "undefined" ? node_process.default.cwd() : ".");
117
+ if (suggestFn) yield* suggestFn(fs, dir, prefix);
118
+ }
119
+ };
120
+ }
121
+ /**
122
+ * Creates a value parser that validates local branch names.
123
+ *
124
+ * This parser uses isomorphic-git to verify that the provided input
125
+ * matches an existing branch in the repository.
126
+ *
127
+ * @param options Configuration options for the parser.
128
+ * @returns A value parser that accepts existing branch names.
129
+ * @since 0.9.0
130
+ *
131
+ * @example
132
+ * ~~~~ typescript
133
+ * import { gitBranch } from "@optique/git";
134
+ * import { argument } from "@optique/core/primitives";
135
+ *
136
+ * const parser = argument(gitBranch());
137
+ * ~~~~
138
+ */
139
+ function gitBranch(options) {
140
+ const metavar = options?.metavar ?? METAVAR_BRANCH;
141
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
142
+ try {
143
+ const branches = await isomorphic_git.listBranches({
144
+ fs,
145
+ dir
146
+ });
147
+ if (branches.includes(input)) return {
148
+ success: true,
149
+ value: input
150
+ };
151
+ return {
152
+ success: false,
153
+ error: __optique_core_message.message`Branch ${(0, __optique_core_message.text)(input)} does not exist. Available branches: ${branches.join(", ")}`
154
+ };
155
+ } catch {
156
+ return {
157
+ success: false,
158
+ error: __optique_core_message.message`Failed to list branches. Ensure ${(0, __optique_core_message.text)(dir)} is a valid git repository.`
159
+ };
160
+ }
161
+ }, async function* suggestBranch(fs, dir, prefix) {
162
+ try {
163
+ const branches = await isomorphic_git.listBranches({
164
+ fs,
165
+ dir
166
+ });
167
+ for (const branch of branches) if (branch.startsWith(prefix)) yield {
168
+ kind: "literal",
169
+ text: branch
170
+ };
171
+ } catch {}
172
+ });
173
+ }
174
+ /**
175
+ * Creates a value parser that validates remote branch names.
176
+ *
177
+ * This parser uses isomorphic-git to verify that the provided input
178
+ * matches an existing branch on the specified remote.
179
+ *
180
+ * @param remote The remote name to validate against.
181
+ * @param options Configuration options for the parser.
182
+ * @returns A value parser that accepts existing remote branch names.
183
+ * @since 0.9.0
184
+ *
185
+ * @example
186
+ * ~~~~ typescript
187
+ * import { gitRemoteBranch } from "@optique/git";
188
+ * import { option } from "@optique/core/primitives";
189
+ *
190
+ * const parser = option("-b", "--branch", gitRemoteBranch("origin"));
191
+ * ~~~~
192
+ */
193
+ function gitRemoteBranch(remote, options) {
194
+ const metavar = options?.metavar ?? METAVAR_BRANCH;
195
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
196
+ try {
197
+ const branches = await isomorphic_git.listBranches({
198
+ fs,
199
+ dir,
200
+ remote
201
+ });
202
+ if (branches.includes(input)) return {
203
+ success: true,
204
+ value: input
205
+ };
206
+ return {
207
+ success: false,
208
+ error: __optique_core_message.message`Remote branch ${(0, __optique_core_message.text)(input)} does not exist on remote ${(0, __optique_core_message.text)(remote)}. Available branches: ${branches.join(", ")}`
209
+ };
210
+ } catch {
211
+ return {
212
+ success: false,
213
+ error: __optique_core_message.message`Failed to list remote branches. Ensure remote ${(0, __optique_core_message.text)(remote)} exists.`
214
+ };
215
+ }
216
+ }, async function* suggestRemoteBranch(fs, dir, prefix) {
217
+ try {
218
+ const branches = await isomorphic_git.listBranches({
219
+ fs,
220
+ dir,
221
+ remote
222
+ });
223
+ for (const branch of branches) if (branch.startsWith(prefix)) yield {
224
+ kind: "literal",
225
+ text: branch
226
+ };
227
+ } catch {}
228
+ });
229
+ }
230
+ /**
231
+ * Creates a value parser that validates tag names.
232
+ *
233
+ * This parser uses isomorphic-git to verify that the provided input
234
+ * matches an existing tag in the repository.
235
+ *
236
+ * @param options Configuration options for the parser.
237
+ * @returns A value parser that accepts existing tag names.
238
+ * @since 0.9.0
239
+ *
240
+ * @example
241
+ * ~~~~ typescript
242
+ * import { gitTag } from "@optique/git";
243
+ * import { option } from "@optique/core/primitives";
244
+ *
245
+ * const parser = option("-t", "--tag", gitTag());
246
+ * ~~~~
247
+ */
248
+ function gitTag(options) {
249
+ const metavar = options?.metavar ?? METAVAR_TAG;
250
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
251
+ try {
252
+ const tags = await isomorphic_git.listTags({
253
+ fs,
254
+ dir
255
+ });
256
+ if (tags.includes(input)) return {
257
+ success: true,
258
+ value: input
259
+ };
260
+ return {
261
+ success: false,
262
+ error: __optique_core_message.message`Tag ${(0, __optique_core_message.text)(input)} does not exist. Available tags: ${tags.join(", ")}`
263
+ };
264
+ } catch {
265
+ return {
266
+ success: false,
267
+ error: __optique_core_message.message`Failed to list tags. Ensure ${(0, __optique_core_message.text)(dir)} is a valid git repository.`
268
+ };
269
+ }
270
+ }, async function* suggestTag(fs, dir, prefix) {
271
+ try {
272
+ const tags = await isomorphic_git.listTags({
273
+ fs,
274
+ dir
275
+ });
276
+ for (const tag of tags) if (tag.startsWith(prefix)) yield {
277
+ kind: "literal",
278
+ text: tag
279
+ };
280
+ } catch {}
281
+ });
282
+ }
283
+ /**
284
+ * Creates a value parser that validates remote names.
285
+ *
286
+ * This parser uses isomorphic-git to verify that the provided input
287
+ * matches an existing remote in the repository.
288
+ *
289
+ * @param options Configuration options for the parser.
290
+ * @returns A value parser that accepts existing remote names.
291
+ * @since 0.9.0
292
+ *
293
+ * @example
294
+ * ~~~~ typescript
295
+ * import { gitRemote } from "@optique/git";
296
+ * import { option } from "@optique/core/primitives";
297
+ *
298
+ * const parser = option("-r", "--remote", gitRemote());
299
+ * ~~~~
300
+ */
301
+ function gitRemote(options) {
302
+ const metavar = options?.metavar ?? METAVAR_REMOTE;
303
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
304
+ try {
305
+ const remotes = await isomorphic_git.listRemotes({
306
+ fs,
307
+ dir
308
+ });
309
+ const remoteNames = [];
310
+ for (const r of remotes) if ("remote" in r && typeof r.remote === "string") remoteNames.push(r.remote);
311
+ if (remoteNames.includes(input)) return {
312
+ success: true,
313
+ value: input
314
+ };
315
+ return {
316
+ success: false,
317
+ error: __optique_core_message.message`Remote ${(0, __optique_core_message.text)(input)} does not exist. Available remotes: ${remoteNames.join(", ")}`
318
+ };
319
+ } catch {
320
+ return {
321
+ success: false,
322
+ error: __optique_core_message.message`Failed to list remotes. Ensure ${(0, __optique_core_message.text)(dir)} is a valid git repository.`
323
+ };
324
+ }
325
+ }, async function* suggestRemote(fs, dir, prefix) {
326
+ try {
327
+ const remotes = await isomorphic_git.listRemotes({
328
+ fs,
329
+ dir
330
+ });
331
+ for (const r of remotes) if ("remote" in r && typeof r.remote === "string" && r.remote.startsWith(prefix)) yield {
332
+ kind: "literal",
333
+ text: r.remote
334
+ };
335
+ } catch {}
336
+ });
337
+ }
338
+ /**
339
+ * Creates a value parser that validates commit SHAs.
340
+ *
341
+ * This parser uses isomorphic-git to verify that the provided input
342
+ * is a valid commit SHA (full or shortened) that exists in the repository.
343
+ *
344
+ * @param options Configuration options for the parser.
345
+ * @returns A value parser that accepts valid commit SHAs.
346
+ * @since 0.9.0
347
+ *
348
+ * @example
349
+ * ~~~~ typescript
350
+ * import { gitCommit } from "@optique/git";
351
+ * import { option } from "@optique/core/primitives";
352
+ *
353
+ * const parser = option("-c", "--commit", gitCommit());
354
+ * ~~~~
355
+ */
356
+ function gitCommit(options) {
357
+ const metavar = options?.metavar ?? "COMMIT";
358
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
359
+ try {
360
+ const oid = await isomorphic_git.expandOid({
361
+ fs,
362
+ dir,
363
+ oid: input
364
+ });
365
+ await isomorphic_git.readObject({
366
+ fs,
367
+ dir,
368
+ oid
369
+ });
370
+ return {
371
+ success: true,
372
+ value: oid
373
+ };
374
+ } catch {
375
+ return {
376
+ success: false,
377
+ error: __optique_core_message.message`Commit ${(0, __optique_core_message.text)(input)} does not exist. Provide a valid commit SHA.`
378
+ };
379
+ }
380
+ }, async function* suggestCommit(fs, dir, prefix) {
381
+ try {
382
+ const branches = await isomorphic_git.listBranches({
383
+ fs,
384
+ dir
385
+ });
386
+ const commits = [];
387
+ for (const branch of branches.slice(0, 10)) try {
388
+ const oid = await isomorphic_git.resolveRef({
389
+ fs,
390
+ dir,
391
+ ref: branch
392
+ });
393
+ if (oid.startsWith(prefix)) commits.push(oid);
394
+ } catch {}
395
+ for (const commit of [...new Set(commits)].slice(0, 10)) yield {
396
+ kind: "literal",
397
+ text: commit
398
+ };
399
+ } catch {}
400
+ });
401
+ }
402
+ /**
403
+ * Creates a value parser that validates any git reference
404
+ * (branches, tags, or commits).
405
+ *
406
+ * This parser uses isomorphic-git to verify that the provided input
407
+ * resolves to a valid git reference (branch, tag, or commit SHA).
408
+ *
409
+ * @param options Configuration options for the parser.
410
+ * @returns A value parser that accepts branches, tags, or commit SHAs.
411
+ * @since 0.9.0
412
+ *
413
+ * @example
414
+ * ~~~~ typescript
415
+ * import { gitRef } from "@optique/git";
416
+ * import { option } from "@optique/core/primitives";
417
+ *
418
+ * const parser = option("--ref", gitRef());
419
+ * ~~~~
420
+ */
421
+ function gitRef(options) {
422
+ const metavar = options?.metavar ?? "REF";
423
+ return createAsyncValueParser(options, metavar, async (fs, dir, input) => {
424
+ try {
425
+ const oid = await isomorphic_git.resolveRef({
426
+ fs,
427
+ dir,
428
+ ref: input
429
+ });
430
+ return {
431
+ success: true,
432
+ value: oid
433
+ };
434
+ } catch {
435
+ return {
436
+ success: false,
437
+ error: __optique_core_message.message`Reference ${(0, __optique_core_message.text)(input)} does not exist. Provide a valid branch, tag, or commit SHA.`
438
+ };
439
+ }
440
+ }, async function* suggestRef(fs, dir, prefix) {
441
+ try {
442
+ const branches = await isomorphic_git.listBranches({
443
+ fs,
444
+ dir
445
+ });
446
+ for (const branch of branches) if (branch.startsWith(prefix)) yield {
447
+ kind: "literal",
448
+ text: branch
449
+ };
450
+ const tags = await isomorphic_git.listTags({
451
+ fs,
452
+ dir
453
+ });
454
+ for (const tag of tags) if (tag.startsWith(prefix)) yield {
455
+ kind: "literal",
456
+ text: tag
457
+ };
458
+ } catch {}
459
+ });
460
+ }
461
+ /**
462
+ * Creates a factory for git parsers with shared configuration.
463
+ *
464
+ * This function returns an object with methods for creating individual git
465
+ * parsers that share the same configuration (filesystem and directory).
466
+ *
467
+ * @param options Shared configuration options for all parsers.
468
+ * @returns An object with methods for creating individual git parsers.
469
+ * @since 0.9.0
470
+ *
471
+ * @example
472
+ * ~~~~ typescript
473
+ * import { createGitParsers } from "@optique/git";
474
+ *
475
+ * const git = createGitParsers({ dir: "/path/to/repo" });
476
+ *
477
+ * const branchParser = git.branch();
478
+ * const tagParser = git.tag();
479
+ * ~~~~
480
+ */
481
+ function createGitParsers(options) {
482
+ return {
483
+ branch: (parserOptions) => gitBranch({
484
+ ...options,
485
+ ...parserOptions
486
+ }),
487
+ remoteBranch: (remote, parserOptions) => gitRemoteBranch(remote, {
488
+ ...options,
489
+ ...parserOptions
490
+ }),
491
+ tag: (parserOptions) => gitTag({
492
+ ...options,
493
+ ...parserOptions
494
+ }),
495
+ remote: (parserOptions) => gitRemote({
496
+ ...options,
497
+ ...parserOptions
498
+ }),
499
+ commit: (parserOptions) => gitCommit({
500
+ ...options,
501
+ ...parserOptions
502
+ }),
503
+ ref: (parserOptions) => gitRef({
504
+ ...options,
505
+ ...parserOptions
506
+ })
507
+ };
508
+ }
509
+
510
+ //#endregion
511
+ exports.createGitParsers = createGitParsers;
512
+ Object.defineProperty(exports, 'expandOid', {
513
+ enumerable: true,
514
+ get: function () {
515
+ return isomorphic_git.expandOid;
516
+ }
517
+ });
518
+ exports.gitBranch = gitBranch;
519
+ exports.gitCommit = gitCommit;
520
+ exports.gitRef = gitRef;
521
+ exports.gitRemote = gitRemote;
522
+ exports.gitRemoteBranch = gitRemoteBranch;
523
+ exports.gitTag = gitTag;
524
+ Object.defineProperty(exports, 'listBranches', {
525
+ enumerable: true,
526
+ get: function () {
527
+ return isomorphic_git.listBranches;
528
+ }
529
+ });
530
+ Object.defineProperty(exports, 'listRemotes', {
531
+ enumerable: true,
532
+ get: function () {
533
+ return isomorphic_git.listRemotes;
534
+ }
535
+ });
536
+ Object.defineProperty(exports, 'listTags', {
537
+ enumerable: true,
538
+ get: function () {
539
+ return isomorphic_git.listTags;
540
+ }
541
+ });
542
+ Object.defineProperty(exports, 'readObject', {
543
+ enumerable: true,
544
+ get: function () {
545
+ return isomorphic_git.readObject;
546
+ }
547
+ });
548
+ Object.defineProperty(exports, 'resolveRef', {
549
+ enumerable: true,
550
+ get: function () {
551
+ return isomorphic_git.resolveRef;
552
+ }
553
+ });