jsrepo 1.13.2 → 1.13.3

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 (2) hide show
  1. package/dist/index.js +51 -3473
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,3475 +1,53 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/index.ts
4
- import fs13 from "node:fs";
5
- import { fileURLToPath } from "node:url";
6
- import { program as program8 } from "commander";
7
- import path13 from "pathe";
8
-
9
- // src/commands/add.ts
10
- import fs7 from "node:fs";
11
- import { cancel, confirm, isCancel, multiselect, outro, spinner as spinner2, text } from "@clack/prompts";
12
- import color8 from "chalk";
13
- import { Command, program as program2 } from "commander";
14
- import { resolveCommand as resolveCommand2 } from "package-manager-detector/commands";
15
- import { detect } from "package-manager-detector/detect";
16
- import path7 from "pathe";
17
- import * as v5 from "valibot";
18
-
19
- // src/utils/ascii.ts
20
- import color from "chalk";
21
- var VERTICAL_LINE = color.gray("\u2502");
22
- var HORIZONTAL_LINE = color.gray("\u2500");
23
- var TOP_RIGHT_CORNER = color.gray("\u2510");
24
- var BOTTOM_RIGHT_CORNER = color.gray("\u2518");
25
- var JUNCTION_RIGHT = color.gray("\u251C");
26
- var TOP_LEFT_CORNER = color.gray("\u250C");
27
- var BOTTOM_LEFT_CORNER = color.gray("\u2514");
28
- var WARN = color.bgRgb(245, 149, 66).white("WARN");
29
- var INFO = color.bgBlueBright.white("INFO");
30
- var JSREPO = color.hex("#f7df1e")("jsrepo");
31
-
32
- // src/utils/blocks.ts
33
- import fs4 from "node:fs";
34
- import color5 from "chalk";
35
- import path4 from "pathe";
36
-
37
- // src/utils/blocks/types/result.ts
38
- var Result = class {
39
- _result;
40
- constructor(result) {
41
- this._result = result;
42
- }
43
- /** Allows you to run callbacks based on the result.
44
- *
45
- * @param success callback to be run when result is success
46
- * @param failure callback to be run when result is failure
47
- * @returns
48
- *
49
- * ## Usage
50
- *
51
- * ```ts
52
- * result.match(
53
- * (val) => val,
54
- * () => {
55
- * throw new Error('oops!')
56
- * }
57
- * );
58
- * ```
59
- *
60
- * ## Examples
61
- *
62
- * ```ts
63
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello, World!");
64
- *
65
- * const result = functionThatMightFail();
66
- *
67
- * const val = result.match(
68
- * (val) => val,
69
- * () => {
70
- * throw new Error('oops!')
71
- * }
72
- * );
73
- *
74
- * console.log(val); // "Hello, World!"
75
- * ```
76
- */
77
- match(success, failure) {
78
- if (!this._result.ok) {
79
- return failure(this._result.err);
80
- }
81
- return success(this._result.val);
82
- }
83
- /** Maps `Result<T, E>` to `Result<A, E>` using the passed mapping function
84
- *
85
- * @param fn Mapping function
86
- * @returns
87
- *
88
- * ## Usage
89
- *
90
- * ```ts
91
- * result.map((val) => val.length);
92
- * ```
93
- *
94
- * ## Examples
95
- *
96
- * ```ts
97
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello, World!");
98
- *
99
- * const result = functionThatMightFail();
100
- *
101
- * const hello = result.map((val) => val.slice(0, 5));
102
- *
103
- * console.log(hello.unwrap()); // "Hello"
104
- * ```
105
- */
106
- map(fn) {
107
- return this.match(
108
- (val) => Ok(fn(val)),
109
- (err) => Err(err)
110
- );
111
- }
112
- /** In the `Ok` case returns the mapped value using the function else returns `defaultVal`
113
- *
114
- * @param defaultVal Value to be returned when `Err`
115
- * @param fn Mapping function to map in case of `Ok`
116
- * @returns
117
- *
118
- * ## Usage
119
- *
120
- * ```ts
121
- * result.mapOr(1, (val) => val.length);
122
- * ```
123
- *
124
- * ## Examples
125
- *
126
- * ### When `Ok`
127
- *
128
- * ```ts
129
- * const functionThatMightFail = (): Result<string, string> => Ok("foo");
130
- *
131
- * const result = functionThatMightFail();
132
- *
133
- * const length = result.mapOr(1, (val) => val.length);
134
- *
135
- * console.log(length); // 3
136
- * ```
137
- *
138
- * ### When `Err`
139
- *
140
- * ```ts
141
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
142
- *
143
- * const result = functionThatMightFail();
144
- *
145
- * const length = result.mapOr(1, (val) => val.length);
146
- *
147
- * console.log(length); // 1
148
- * ```
149
- */
150
- mapOr(defaultVal, fn) {
151
- return this.match(
152
- (val) => fn(val),
153
- (_) => defaultVal
154
- );
155
- }
156
- /** In the `Ok` case returns the mapped value using `fn` else returns value of `def`
157
- *
158
- * @param def Mapping function called when `Err`
159
- * @param fn Mapping function called when `Ok`
160
- * @returns
161
- *
162
- * ## Usage
163
- *
164
- * ```ts
165
- * result.mapOrElse(() => 1, (val) => val.length);
166
- * ```
167
- *
168
- * ## Examples
169
- *
170
- * ### When `Ok`
171
- *
172
- * ```ts
173
- * const functionThatMightFail = (): Result<string, string> => Ok("foo");
174
- *
175
- * const result = functionThatMightFail();
176
- *
177
- * const length = result.mapOrElse(() => 1, (val) => val.length);
178
- *
179
- * console.log(length); // 3
180
- * ```
181
- *
182
- * ### When `Err`
183
- *
184
- * ```ts
185
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
186
- *
187
- * const result = functionThatMightFail();
188
- *
189
- * const length = result.mapOr(() => 1, (val) => val.length);
190
- *
191
- * console.log(length); // 1
192
- * ```
193
- */
194
- mapOrElse(def, fn) {
195
- return this.match(
196
- (val) => fn(val),
197
- (err) => def(err)
198
- );
199
- }
200
- /** Maps `Result<T, E>` to `Result<T, A>` using the passed mapping function
201
- *
202
- * @param fn Mapping function
203
- * @returns
204
- *
205
- * ## Usage
206
- *
207
- * ```ts
208
- * result.mapErr((err) => getCodeMsg(err));
209
- * ```
210
- *
211
- * ## Examples
212
- *
213
- * ```ts
214
- * const functionThatMightFail = (): Result<string, string> => Err(10);
215
- *
216
- * const result = functionThatMightFail();
217
- *
218
- * const message = result.mapErr(() => "Error");
219
- *
220
- * console.log(message); // "Error"
221
- * ```
222
- */
223
- mapErr(fn) {
224
- return this.match(
225
- (val) => Ok(val),
226
- (err) => Err(fn(err))
227
- );
228
- }
229
- /** In the `Err` case returns the mapped value using the function else returns `defaultVal`
230
- *
231
- * @param defaultVal Value to be returned when `Ok`
232
- * @param fn Mapping function to map in case of `Err`
233
- * @returns
234
- *
235
- * ## Usage
236
- *
237
- * ```ts
238
- * result.mapErrOr("Should've been error", (err) => getCodeMsg(err));
239
- * ```
240
- *
241
- * ## Examples
242
- *
243
- * ### When `Ok`
244
- *
245
- * ```ts
246
- * const functionThatMightFail = (): Result<string, string> => Ok("foo");
247
- *
248
- * const result = functionThatMightFail();
249
- *
250
- * const message = result.mapErrOr("Should've been error", () => "Error");
251
- *
252
- * console.log(message); // "Should've been error"
253
- * ```
254
- *
255
- * ### When `Err`
256
- *
257
- * ```ts
258
- * const functionThatMightFail = (): Result<string, string> => Err(10);
259
- *
260
- * const result = functionThatMightFail();
261
- *
262
- * const message = result.mapErrOr("Should've been error", () => "Error");
263
- *
264
- * console.log(message); // "Error"
265
- * ```
266
- */
267
- mapErrOr(defaultVal, fn) {
268
- return this.match(
269
- (_) => defaultVal,
270
- (err) => fn(err)
271
- );
272
- }
273
- /** In the `Err` case returns the mapped value using the function else returns value of `def`
274
- *
275
- * @param def Mapping function called when `Ok`
276
- * @param fn Mapping function called when `Err`
277
- * @returns
278
- *
279
- * ## Usage
280
- *
281
- * ```ts
282
- * result.mapErrOrElse(() => "Value", (_) => "Error!");
283
- * ```
284
- *
285
- * ## Examples
286
- *
287
- * ### When `Ok`
288
- *
289
- * ```ts
290
- * const functionThatMightFail = (): Result<string, string> => Ok("foo");
291
- *
292
- * const result = functionThatMightFail();
293
- *
294
- * const length = result.mapErrOrElse(() => 1, (val) => val.length);
295
- *
296
- * console.log(length); // 1
297
- * ```
298
- *
299
- * ### When `Err`
300
- *
301
- * ```ts
302
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
303
- *
304
- * const result = functionThatMightFail();
305
- *
306
- * const length = result.mapOr(() => 1, (val) => val.length);
307
- *
308
- * console.log(length); // 4
309
- * ```
310
- */
311
- mapErrOrElse(def, fn) {
312
- return this.match(
313
- (val) => def(val),
314
- (err) => fn(err)
315
- );
316
- }
317
- /** Returns true if result is `Ok`
318
- *
319
- * @returns
320
- *
321
- * ## Usage
322
- *
323
- * ```ts
324
- * result.isOk();
325
- * ```
326
- */
327
- isOk() {
328
- return this.match(
329
- () => true,
330
- () => false
331
- );
332
- }
333
- /** Returns true if result is `Err`
334
- *
335
- * @returns
336
- *
337
- * ## Usage
338
- *
339
- * ```ts
340
- * result.isErr();
341
- * ```
342
- */
343
- isErr() {
344
- return this.match(
345
- () => false,
346
- () => true
347
- );
348
- }
349
- /** Tries to return value if value is `Err` throws generic error message.
350
- *
351
- * @returns
352
- *
353
- * ## Usage
354
- *
355
- * ```ts
356
- * result.unwrap();
357
- * ```
358
- *
359
- * ## Examples
360
- *
361
- * ### When `Ok`
362
- *
363
- * ```ts
364
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
365
- *
366
- * const result = functionThatMightFail();
367
- *
368
- * console.log(result.unwrap()); // "Hello!"
369
- * ```
370
- *
371
- * ### When `Err`
372
- *
373
- * ```ts
374
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
375
- *
376
- * const result = functionThatMightFail();
377
- *
378
- * result.unwrap(); // Error: Attempted to call `.unwrap()` on a non `Ok` value.
379
- * ```
380
- */
381
- unwrap() {
382
- return this.match(
383
- (val) => val,
384
- () => {
385
- throw new Error("Attempted to call `.unwrap()` on a non `Ok` value.");
386
- }
387
- );
388
- }
389
- /** Tries to return err if value is `Ok` throws generic error message.
390
- *
391
- * @returns
392
- *
393
- * ## Usage
394
- *
395
- * ```ts
396
- * result.unwrapErr();
397
- * ```
398
- *
399
- * ## Examples
400
- *
401
- * ### When `Ok`
402
- *
403
- * ```ts
404
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
405
- *
406
- * const result = functionThatMightFail();
407
- *
408
- * result.unwrapErr(); // Error: Attempted to call `.unwrapErr()` on a non `Err` value.
409
- * ```
410
- *
411
- * ### When `Err`
412
- *
413
- * ```ts
414
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
415
- *
416
- * const result = functionThatMightFail();
417
- *
418
- * console.log(result.unwrapErr()); // "oops!"
419
- * ```
420
- */
421
- unwrapErr() {
422
- return this.match(
423
- () => {
424
- throw new Error("Attempted to call `.unwrapErr()` on a non `Err` value.");
425
- },
426
- (err) => err
427
- );
428
- }
429
- /** Tries to unwrap the value if value is `Err` returns `defaultVal`
430
- *
431
- * @param defaultVal Value to be returned if `Err`
432
- * @returns
433
- *
434
- * ## Usage
435
- *
436
- * ```ts
437
- * result.unwrapOr(7);
438
- * ```
439
- *
440
- * ## Examples
441
- *
442
- * ### When `Ok`
443
- *
444
- * ```ts
445
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
446
- *
447
- * const result = functionThatMightFail();
448
- *
449
- * console.log(result.unwrapOr("Yellow!")); // "Hello!"
450
- * ```
451
- *
452
- * ### When `Err`
453
- *
454
- * ```ts
455
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
456
- *
457
- * const result = functionThatMightFail();
458
- *
459
- * console.log(result.unwrapOr("Yellow!")); // "Yellow!"
460
- * ```
461
- */
462
- unwrapOr(defaultVal) {
463
- return this.match(
464
- (val) => val,
465
- (_) => defaultVal
466
- );
467
- }
468
- /** Tries to unwrap the error if vale is `Ok` returns `defaultVal`
469
- *
470
- * @param defaultVal
471
- * @returns
472
- *
473
- * ## Usage
474
- *
475
- * ```ts
476
- * result.unwrapErrOr("Error");
477
- * ```
478
- *
479
- * ## Examples
480
- *
481
- * ### When `Ok`
482
- *
483
- * ```ts
484
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
485
- *
486
- * const result = functionThatMightFail();
487
- *
488
- * console.log(result.unwrapErrOr("Yellow!")); // "Yellow!"
489
- * ```
490
- *
491
- * ### When `Err`
492
- *
493
- * ```ts
494
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
495
- *
496
- * const result = functionThatMightFail();
497
- *
498
- * console.log(result.unwrapErrOr("Yellow!")); // "oops!"
499
- * ```
500
- */
501
- unwrapErrOr(defaultVal) {
502
- return this.match(
503
- () => defaultVal,
504
- (err) => err
505
- );
506
- }
507
- /** Tries to return the value if value is `Err` calls `fn`
508
- *
509
- * @param fn Function called if `Err`
510
- *
511
- * ## Usage
512
- *
513
- * ```ts
514
- * result.unwrapOrElse(() => "Hello!");
515
- * ```
516
- *
517
- * ## Examples
518
- *
519
- * ### When `Ok`
520
- *
521
- * ```ts
522
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
523
- *
524
- * const result = functionThatMightFail();
525
- *
526
- * console.log(result.unwrapOrElse(() => "oops!")); // "Hello!"
527
- * ```
528
- *
529
- * ### When `Err`
530
- *
531
- * ```ts
532
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
533
- *
534
- * const result = functionThatMightFail();
535
- *
536
- * console.log(result.unwrapOrElse(() => "Hello!")); // "Hello!"
537
- * ```
538
- *
539
- */
540
- unwrapOrElse(fn) {
541
- return this.match(
542
- (val) => val,
543
- (err) => fn(err)
544
- );
545
- }
546
- /** Tries to return the error if value is `Ok` calls `fn`
547
- *
548
- * @param fn Function called if `Ok`
549
- *
550
- * ## Usage
551
- *
552
- * ```ts
553
- * result.unwrapErrOrElse(() => "Error!");
554
- * ```
555
- *
556
- * ## Examples
557
- *
558
- * ### When `Ok`
559
- *
560
- * ```ts
561
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
562
- *
563
- * const result = functionThatMightFail();
564
- *
565
- * console.log(result.unwrapErrOrElse(() => "oops!")); // "oops!"
566
- * ```
567
- *
568
- * ### When `Err`
569
- *
570
- * ```ts
571
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
572
- *
573
- * const result = functionThatMightFail();
574
- *
575
- * console.log(result.unwrapErrOrElse(() => "Hello!")); // "oops!"
576
- * ```
577
- *
578
- */
579
- unwrapErrOrElse(fn) {
580
- return this.match(
581
- (val) => fn(val),
582
- (err) => err
583
- );
584
- }
585
- /** Tries to return value if value is `Err` throws custom error message.
586
- *
587
- * @param message Message to show when value is `Err`
588
- * @returns
589
- *
590
- * ## Usage
591
- *
592
- * ```ts
593
- * result.expect("Custom message");
594
- * ```
595
- *
596
- * ## Examples
597
- *
598
- * ### When `Ok`
599
- *
600
- * ```ts
601
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
602
- *
603
- * const result = functionThatMightFail();
604
- *
605
- * console.log(result.expect("I failed!")); // "Hello!"
606
- * ```
607
- *
608
- * ### When `Err`
609
- *
610
- * ```ts
611
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
612
- *
613
- * const result = functionThatMightFail();
614
- *
615
- * result.expect("I failed!"); // Error: I failed!
616
- * ```
617
- */
618
- expect(message) {
619
- return this.match(
620
- (val) => val,
621
- () => {
622
- throw new Error(message);
623
- }
624
- );
625
- }
626
- /** Tries to return error value if value is `Ok` throws custom error message
627
- *
628
- * @param message
629
- * @returns
630
- *
631
- * ## Usage
632
- *
633
- * ```ts
634
- * result.expectErr("Custom message");
635
- * ```
636
- *
637
- * ## Examples
638
- *
639
- * ### When `Ok`
640
- *
641
- * ```ts
642
- * const functionThatMightFail = (): Result<string, string> => Ok("Hello!");
643
- *
644
- * const result = functionThatMightFail();
645
- *
646
- * console.log(result.expectErr("I failed!")); // Error: I failed!
647
- * ```
648
- *
649
- * ### When `Err`
650
- *
651
- * ```ts
652
- * const functionThatMightFail = (): Result<string, string> => Err("oops!");
653
- *
654
- * const result = functionThatMightFail();
655
- *
656
- * console.log(result.expectErr("I failed!")); // "oops!"
657
- * ```
658
- */
659
- expectErr(message) {
660
- return this.match(
661
- () => {
662
- throw new Error(message);
663
- },
664
- (err) => err
665
- );
666
- }
667
- };
668
- var Ok = (val) => {
669
- return new Result({ ok: true, val });
670
- };
671
- var Err = (err) => {
672
- return new Result({ ok: false, err });
673
- };
674
-
675
- // src/utils/blocks/utils/map-to-array.ts
676
- var mapToArray = (map, fn) => {
677
- const items = [];
678
- for (const [key, value] of map) {
679
- items.push(fn(key, value));
680
- }
681
- return items;
682
- };
683
-
684
- // src/utils/git-providers.ts
685
- import color4 from "chalk";
686
- import fetch from "node-fetch";
687
- import { Octokit } from "octokit";
688
- import * as v3 from "valibot";
689
-
690
- // src/utils/build.ts
691
- import fs3 from "node:fs";
692
- import color3 from "chalk";
693
- import { program } from "commander";
694
- import path3 from "pathe";
695
- import * as v2 from "valibot";
696
-
697
- // src/utils/language-support.ts
698
- import fs2 from "node:fs";
699
- import { builtinModules } from "node:module";
700
- import { Biome, Distribution } from "@biomejs/js-api";
701
- import * as v from "@vue/compiler-sfc";
702
- import color2 from "chalk";
703
- import { walk } from "estree-walker";
704
- import path2 from "pathe";
705
- import * as prettier from "prettier";
706
- import * as sv from "svelte/compiler";
707
- import { Project } from "ts-morph";
708
- import validatePackageName from "validate-npm-package-name";
709
-
710
- // src/utils/blocks/utils/lines.ts
711
- import os from "node:os";
712
-
713
- // src/utils/blocks/utils/strip-ansi.ts
714
- import ansiRegex from "ansi-regex";
715
- var stripAsni = (str) => str.replace(ansiRegex(), "");
716
-
717
- // src/utils/blocks/utils/pad.ts
718
- var leftPadMin = (str, length, padWith = " ") => {
719
- if (stripAsni(str).length > length)
720
- throw new Error("String length is greater than the length provided.");
721
- return padWith.repeat(length - stripAsni(str).length) + str;
722
- };
723
- var rightPad = (str, space, padWith = " ") => {
724
- return str + padWith.repeat(space);
725
- };
726
- var rightPadMin = (str, length, padWith = " ") => {
727
- if (stripAsni(str).length > length)
728
- throw new Error("String length is greater than the length provided.");
729
- return str + padWith.repeat(length - stripAsni(str).length);
730
- };
731
-
732
- // src/utils/blocks/utils/lines.ts
733
- var NEW_LINE_REGEX = /\n|\r\n/g;
734
- var get = (str) => str.split(NEW_LINE_REGEX);
735
- var join = (lines, { lineNumbers = false, prefix } = {}) => {
736
- let transformed = lines;
737
- if (lineNumbers) {
738
- const length = lines.length.toString().length + 1;
739
- transformed = transformed.map((line, i) => `${leftPadMin(`${i + 1}`, length)} ${line}`);
740
- }
741
- if (prefix !== void 0) {
742
- transformed = transformed.map((line, i) => `${prefix(i, lines.length)}${line}`);
743
- }
744
- return transformed.join(os.EOL);
745
- };
746
-
747
- // src/utils/package.ts
748
- import fs from "node:fs";
749
- import path from "pathe";
750
- var findNearestPackageJson = (startDir, until) => {
751
- const packagePath = path.join(startDir, "package.json");
752
- if (fs.existsSync(packagePath)) return packagePath;
753
- if (startDir === until) return void 0;
754
- const segments = startDir.split(/[\/\\]/);
755
- return findNearestPackageJson(segments.slice(0, segments.length - 1).join("/"), until);
756
- };
757
- var getPackage = (path14) => {
758
- if (!fs.existsSync(path14)) return Err(`${path14} doesn't exist`);
759
- const contents = fs.readFileSync(path14).toString();
760
- return Ok(JSON.parse(contents));
761
- };
762
- var returnShouldInstall = (dependencies, devDependencies, { cwd }) => {
763
- const tempDeps = dependencies;
764
- const tempDevDeps = devDependencies;
765
- const packageResult = getPackage(path.join(cwd, "package.json"));
766
- if (!packageResult.isErr()) {
767
- const pkg = packageResult.unwrap();
768
- if (pkg.dependencies) {
769
- for (const dep of tempDeps) {
770
- const [name2, version2] = dep.split("@");
771
- const foundDep = pkg.dependencies[name2];
772
- if (version2 === void 0 && foundDep) continue;
773
- if (foundDep && foundDep === version2) {
774
- tempDeps.delete(dep);
775
- }
776
- }
777
- }
778
- if (pkg.devDependencies) {
779
- for (const dep of tempDevDeps) {
780
- const [name2, version2] = dep.split("@");
781
- const foundDep = pkg.devDependencies[name2];
782
- if (version2 === void 0 && foundDep) continue;
783
- if (foundDep && foundDep === version2) {
784
- tempDevDeps.delete(dep);
785
- }
786
- }
787
- }
788
- }
789
- return { dependencies: tempDeps, devDependencies: tempDevDeps };
790
- };
791
-
792
- // src/utils/parse-package-name.ts
793
- var RE_SCOPED = /^(@[^\/]+\/[^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
794
- var RE_NON_SCOPED = /^([^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
795
- var parsePackageName = (input) => {
796
- const m = RE_SCOPED.exec(input) || RE_NON_SCOPED.exec(input);
797
- if (!m) return Err(`invalid package name: ${input}`);
798
- return Ok({
799
- name: m[1] || "",
800
- version: m[2] || "latest",
801
- path: m[3] || ""
802
- });
803
- };
804
-
805
- // src/utils/language-support.ts
806
- var typescript = {
807
- matches: (fileName) => fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".tsx") || fileName.endsWith(".jsx"),
808
- resolveDependencies: ({ filePath, isSubDir, excludeDeps }) => {
809
- const project = new Project();
810
- const blockFile = project.addSourceFileAtPath(filePath);
811
- const imports = blockFile.getImportDeclarations();
812
- const relativeImports = imports.filter(
813
- (declaration) => declaration.getModuleSpecifierValue().startsWith(".")
814
- );
815
- const localDeps = /* @__PURE__ */ new Set();
816
- for (const relativeImport of relativeImports) {
817
- const mod = relativeImport.getModuleSpecifierValue();
818
- const localDep = resolveLocalImport(mod, isSubDir, { filePath });
819
- if (localDep.isErr()) return Err(localDep.unwrapErr());
820
- if (localDep.unwrap()) localDeps.add(localDep.unwrap());
821
- }
822
- const deps = imports.filter((declaration) => !declaration.getModuleSpecifierValue().startsWith(".")).map((declaration) => declaration.getModuleSpecifierValue());
823
- const { devDependencies, dependencies } = resolveRemoteDeps(
824
- Array.from(deps),
825
- filePath,
826
- excludeDeps
827
- );
828
- return Ok({
829
- local: Array.from(localDeps),
830
- dependencies,
831
- devDependencies
832
- });
833
- },
834
- comment: (content) => `/*
835
- ${join(get(content), { prefix: () => " " })}
836
- */`,
837
- format: async (code, { formatter, filePath, prettierOptions, biomeOptions }) => {
838
- if (!formatter) return code;
839
- if (formatter === "prettier") {
840
- return await prettier.format(code, { filepath: filePath, ...prettierOptions });
841
- }
842
- const biome = await Biome.create({
843
- distribution: Distribution.NODE
844
- });
845
- if (biomeOptions) {
846
- biome.applyConfiguration(biomeOptions);
847
- }
848
- return biome.formatContent(code, { filePath }).content;
849
- }
850
- };
851
- var svelte = {
852
- matches: (fileName) => fileName.endsWith(".svelte"),
853
- resolveDependencies: ({ filePath, isSubDir, excludeDeps }) => {
854
- const sourceCode = fs2.readFileSync(filePath).toString();
855
- const root = sv.parse(sourceCode, { modern: true, filename: filePath });
856
- if (!root.instance) return Ok({ dependencies: [], devDependencies: [], local: [] });
857
- const localDeps = /* @__PURE__ */ new Set();
858
- const deps = /* @__PURE__ */ new Set();
859
- walk(root.instance, {
860
- enter: (node) => {
861
- if (node.type === "ImportDeclaration") {
862
- if (typeof node.source.value === "string") {
863
- if (node.source.value.startsWith(".")) {
864
- const localDep = resolveLocalImport(node.source.value, isSubDir, {
865
- filePath
866
- });
867
- if (localDep.isErr()) return Err(localDep.unwrapErr());
868
- if (localDep.unwrap()) localDeps.add(localDep.unwrap());
869
- } else {
870
- deps.add(node.source.value);
871
- }
872
- }
873
- }
874
- }
875
- });
876
- const { devDependencies, dependencies } = resolveRemoteDeps(Array.from(deps), filePath, [
877
- "svelte",
878
- ...excludeDeps
879
- ]);
880
- return Ok({
881
- dependencies,
882
- devDependencies,
883
- local: Array.from(localDeps)
884
- });
885
- },
886
- comment: (content) => `<!--
887
- ${join(get(content), { prefix: () => " " })}
888
- -->`,
889
- format: async (code, { formatter, filePath, prettierOptions }) => {
890
- if (!formatter) return code;
891
- if (formatter === "prettier" && prettierOptions && prettierOptions.plugins?.find((plugin) => plugin === "prettier-plugin-svelte")) {
892
- return await prettier.format(code, { filepath: filePath, ...prettierOptions });
893
- }
894
- return code;
895
- }
896
- };
897
- var vue = {
898
- matches: (fileName) => fileName.endsWith(".vue"),
899
- resolveDependencies: ({ filePath, isSubDir, excludeDeps }) => {
900
- const sourceCode = fs2.readFileSync(filePath).toString();
901
- const parsed = v.parse(sourceCode, { filename: filePath });
902
- if (!parsed.descriptor.script?.content && !parsed.descriptor.scriptSetup?.content)
903
- return Ok({ dependencies: [], devDependencies: [], local: [] });
904
- const localDeps = /* @__PURE__ */ new Set();
905
- const deps = /* @__PURE__ */ new Set();
906
- let compiled;
907
- try {
908
- compiled = v.compileScript(parsed.descriptor, { id: "shut-it" });
909
- } catch (err) {
910
- return Err(`Compile error: ${err}`);
911
- }
912
- if (!compiled.imports) return Ok({ dependencies: [], devDependencies: [], local: [] });
913
- const imports = Object.values(compiled.imports);
914
- for (const imp of imports) {
915
- if (imp.source.startsWith(".")) {
916
- const localDep = resolveLocalImport(imp.source, isSubDir, {
917
- filePath
918
- });
919
- if (localDep.isErr()) return Err(localDep.unwrapErr());
920
- if (localDep.unwrap()) localDeps.add(localDep.unwrap());
921
- } else {
922
- deps.add(imp.source);
923
- }
924
- }
925
- const { devDependencies, dependencies } = resolveRemoteDeps(Array.from(deps), filePath, [
926
- "vue",
927
- ...excludeDeps
928
- ]);
929
- return Ok({
930
- dependencies,
931
- devDependencies,
932
- local: Array.from(localDeps)
933
- });
934
- },
935
- comment: (content) => `<!--
936
- ${join(get(content), { prefix: () => " " })}
937
- -->`,
938
- format: async (code, { formatter, prettierOptions }) => {
939
- if (!formatter) return code;
940
- if (formatter === "prettier") {
941
- return await prettier.format(code, { parser: "vue", ...prettierOptions });
942
- }
943
- return code;
944
- }
945
- };
946
- var yaml = {
947
- matches: (fileName) => fileName.endsWith(".yml") || fileName.endsWith(".yaml"),
948
- resolveDependencies: () => Ok({ dependencies: [], local: [], devDependencies: [] }),
949
- comment: (content) => join(get(content), { prefix: () => "# " }),
950
- format: async (code, { formatter, prettierOptions }) => {
951
- if (!formatter) return code;
952
- if (formatter === "prettier") {
953
- return await prettier.format(code, { parser: "yaml", ...prettierOptions });
954
- }
955
- return code;
956
- }
957
- };
958
- var resolveLocalImport = (mod, isSubDir, { filePath }) => {
959
- if (isSubDir && (mod.startsWith("./") || mod === ".")) return Ok(void 0);
960
- const categoryDir = isSubDir ? path2.join(filePath, "../../") : path2.join(filePath, "../");
961
- const modPath = path2.join(path2.join(filePath, "../"), mod);
962
- const fullDir = path2.join(categoryDir, "../");
963
- if (modPath.startsWith(fullDir)) {
964
- let [category, block] = modPath.slice(fullDir.length).split("/");
965
- if (block.includes(".")) {
966
- block = block.slice(0, block.length - path2.parse(block).ext.length);
967
- }
968
- return Ok(`${category}/${block}`);
969
- }
970
- return Err(
971
- `${filePath}:
972
- ${mod} references code not contained in ${categoryDir} and cannot be resolved.`
973
- );
974
- };
975
- var resolveRemoteDeps = (deps, filePath, doNotInstall = []) => {
976
- const exemptDeps = new Set(doNotInstall);
977
- const filteredDeps = deps.filter(
978
- (dep) => !builtinModules.includes(dep) && !dep.startsWith("node:")
979
- );
980
- const pkgPath = findNearestPackageJson(path2.dirname(filePath), "");
981
- const dependencies = /* @__PURE__ */ new Set();
982
- const devDependencies = /* @__PURE__ */ new Set();
983
- if (pkgPath) {
984
- const { devDependencies: packageDevDependencies, dependencies: packageDependencies } = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
985
- for (const dep of filteredDeps) {
986
- const parsed = parsePackageName(dep);
987
- if (parsed.isErr()) {
988
- console.warn(
989
- `${WARN} Skipped adding import \`${color2.cyan(dep)}\`. Reason: Couldn't parse package name`
990
- );
991
- continue;
992
- }
993
- const depInfo = parsed.unwrap();
994
- if (!validatePackageName(depInfo.name).validForNewPackages) {
995
- console.warn(
996
- `${WARN} Skipped adding import \`${color2.cyan(dep)}\`. Reason: Not a valid package name`
997
- );
998
- continue;
999
- }
1000
- if (exemptDeps.has(depInfo.name)) continue;
1001
- let version2 = void 0;
1002
- if (packageDependencies !== void 0) {
1003
- version2 = packageDependencies[depInfo.name];
1004
- }
1005
- if (version2 !== void 0) {
1006
- dependencies.add(`${depInfo.name}@${version2}`);
1007
- continue;
1008
- }
1009
- if (packageDevDependencies !== void 0) {
1010
- version2 = packageDevDependencies[depInfo.name];
1011
- }
1012
- if (version2 !== void 0) {
1013
- devDependencies.add(`${depInfo.name}@${version2}`);
1014
- continue;
1015
- }
1016
- dependencies.add(depInfo.name);
1017
- }
1018
- }
1019
- return {
1020
- dependencies: Array.from(dependencies),
1021
- devDependencies: Array.from(devDependencies)
1022
- };
1023
- };
1024
- var languages = [typescript, svelte, vue, yaml];
1025
-
1026
- // src/utils/build.ts
1027
- var blockSchema = v2.object({
1028
- name: v2.string(),
1029
- category: v2.string(),
1030
- localDependencies: v2.array(v2.string()),
1031
- dependencies: v2.array(v2.string()),
1032
- devDependencies: v2.array(v2.string()),
1033
- tests: v2.boolean(),
1034
- /** Where to find the block relative to root */
1035
- directory: v2.string(),
1036
- subdirectory: v2.boolean(),
1037
- files: v2.array(v2.string())
1038
- });
1039
- var categorySchema = v2.object({
1040
- name: v2.string(),
1041
- blocks: v2.array(blockSchema)
1042
- });
1043
- var TEST_SUFFIXES = [".test.ts", "_test.ts", ".test.js", "_test.js"];
1044
- var isTestFile = (file) => TEST_SUFFIXES.find((suffix) => file.endsWith(suffix)) !== void 0;
1045
- var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps, includeBlocks, includeCategories, errorOnWarn }) => {
1046
- let paths;
1047
- try {
1048
- paths = fs3.readdirSync(blocksPath);
1049
- } catch {
1050
- program.error(color3.red(`Couldn't read the ${color3.bold(blocksPath)} directory.`));
1051
- }
1052
- const categories = [];
1053
- for (const categoryPath of paths) {
1054
- const categoryDir = path3.join(blocksPath, categoryPath);
1055
- if (fs3.statSync(categoryDir).isFile()) continue;
1056
- const categoryName = path3.basename(categoryPath);
1057
- if (includeCategories.length > 0 && includeCategories.find((val) => val.trim() === categoryName.trim()) === void 0)
1058
- continue;
1059
- const category = {
1060
- name: categoryName,
1061
- blocks: []
1062
- };
1063
- const files = fs3.readdirSync(categoryDir);
1064
- for (const file of files) {
1065
- const blockDir = path3.join(categoryDir, file);
1066
- if (fs3.statSync(blockDir).isFile()) {
1067
- if (isTestFile(file)) continue;
1068
- const name2 = path3.parse(path3.basename(file)).name;
1069
- if (includeBlocks.length > 0 && includeBlocks.find((val) => val.trim() === name2.trim()) === void 0)
1070
- continue;
1071
- const lang = languages.find((resolver) => resolver.matches(file));
1072
- if (!lang) {
1073
- const error = "files are not currently supported!";
1074
- if (errorOnWarn) {
1075
- program.error(
1076
- color3.red(
1077
- `Couldn't add \`${color3.bold(blockDir)}\` \`*${color3.bold(
1078
- path3.parse(file).ext
1079
- )}\` ${error}`
1080
- )
1081
- );
1082
- } else {
1083
- console.warn(
1084
- `${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(blockDir)}\` \`*${color3.bold(
1085
- path3.parse(file).ext
1086
- )}\` ${error}`
1087
- );
1088
- }
1089
- continue;
1090
- }
1091
- const testsPath = files.find(
1092
- (f) => TEST_SUFFIXES.find((suffix) => f === `${name2}${suffix}`)
1093
- );
1094
- const { dependencies, devDependencies, local } = lang.resolveDependencies({
1095
- filePath: blockDir,
1096
- isSubDir: false,
1097
- excludeDeps,
1098
- cwd
1099
- }).match(
1100
- (val) => val,
1101
- (err) => {
1102
- program.error(color3.red(err));
1103
- }
1104
- );
1105
- const block = {
1106
- name: name2,
1107
- directory: path3.relative(cwd, categoryDir),
1108
- category: categoryName,
1109
- tests: testsPath !== void 0,
1110
- subdirectory: false,
1111
- files: [file],
1112
- localDependencies: local,
1113
- dependencies,
1114
- devDependencies
1115
- };
1116
- if (testsPath !== void 0) {
1117
- block.files.push(testsPath);
1118
- }
1119
- category.blocks.push(block);
1120
- } else {
1121
- const blockName = file;
1122
- if (includeBlocks.length > 0 && includeBlocks.find((val) => val.trim() === blockName.trim()) === void 0)
1123
- continue;
1124
- const blockFiles = fs3.readdirSync(blockDir);
1125
- const hasTests = blockFiles.findIndex((f) => isTestFile(f)) !== -1;
1126
- const localDepsSet = /* @__PURE__ */ new Set();
1127
- const depsSet = /* @__PURE__ */ new Set();
1128
- const devDepsSet = /* @__PURE__ */ new Set();
1129
- for (const f of blockFiles) {
1130
- if (isTestFile(f)) continue;
1131
- if (fs3.statSync(path3.join(blockDir, f)).isDirectory()) {
1132
- const error = "subdirectories are not currently supported!";
1133
- if (errorOnWarn) {
1134
- program.error(
1135
- color3.red(
1136
- `Couldn't add \`${color3.bold(path3.join(blockDir, f))}\` ${error}`
1137
- )
1138
- );
1139
- } else {
1140
- console.warn(
1141
- `${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` ${error}`
1142
- );
1143
- }
1144
- continue;
1145
- }
1146
- const lang = languages.find((resolver) => resolver.matches(f));
1147
- if (!lang) {
1148
- const error = "files are not currently supported!";
1149
- if (errorOnWarn) {
1150
- program.error(
1151
- color3.red(
1152
- `Couldn't add \`${color3.bold(path3.join(blockDir, f))}\` \`*${color3.bold(
1153
- path3.parse(f).ext
1154
- )}\` ${error}`
1155
- )
1156
- );
1157
- } else {
1158
- console.warn(
1159
- `${VERTICAL_LINE} ${WARN} Skipped \`${path3.join(blockDir, f)}\` \`*${color3.bold(
1160
- path3.parse(f).ext
1161
- )}\` ${error}`
1162
- );
1163
- }
1164
- continue;
1165
- }
1166
- const { local, dependencies, devDependencies } = lang.resolveDependencies({
1167
- filePath: path3.join(blockDir, f),
1168
- isSubDir: true,
1169
- excludeDeps,
1170
- cwd
1171
- }).match(
1172
- (val) => val,
1173
- (err) => {
1174
- program.error(color3.red(err));
1175
- }
1176
- );
1177
- for (const dep of local) {
1178
- localDepsSet.add(dep);
1179
- }
1180
- for (const dep of dependencies) {
1181
- depsSet.add(dep);
1182
- }
1183
- for (const dep of devDependencies) {
1184
- devDepsSet.add(dep);
1185
- }
1186
- }
1187
- const block = {
1188
- name: blockName,
1189
- directory: path3.relative(cwd, blockDir),
1190
- category: categoryName,
1191
- tests: hasTests,
1192
- subdirectory: true,
1193
- files: [...blockFiles],
1194
- localDependencies: Array.from(localDepsSet.keys()),
1195
- dependencies: Array.from(depsSet.keys()),
1196
- devDependencies: Array.from(devDepsSet.keys())
1197
- };
1198
- category.blocks.push(block);
1199
- }
1200
- }
1201
- categories.push(category);
1202
- }
1203
- return categories;
1204
- };
1205
-
1206
- // src/utils/context.ts
1207
- var OUTPUT_FILE = "jsrepo-manifest.json";
1208
-
1209
- // src/utils/persisted.ts
1210
- import Conf from "conf";
1211
- var get2 = () => {
1212
- return new Conf({ projectName: "jsrepo" });
1213
- };
1214
-
1215
- // src/utils/git-providers.ts
1216
- var rawErrorMessage = (info, filePath, defaultBranch) => {
1217
- return Err(
1218
- `There was an error fetching the \`${color4.bold(filePath)}\` from ${color4.bold(info.url)}.
1219
-
1220
- ${color4.bold("This may be for one of the following reasons:")}
1221
- 1. The \`${color4.bold(filePath)}\` or containing repository doesn't exist
1222
- 2. Your repository path is incorrect (wrong branch, wrong tag) default branches other than \`${color4.bold(defaultBranch)}\` must be specified \`${color4.bold("github/<owner>/<name>/tree/<branch>")}\`
2
+ import Ne from'node:fs';import {fileURLToPath}from'node:url';import {Command,program,Option,Argument}from'commander';import J from'pathe';import {outro,spinner,confirm,isCancel,cancel,multiselect,text,select,password,intro}from'@clack/prompts';import I from'chalk';import {resolveCommand}from'package-manager-detector/commands';import {detect}from'package-manager-detector/detect';import*as B from'valibot';import xt from'node-fetch';import {Octokit}from'octokit';import {builtinModules}from'node:module';import {Biome,Distribution}from'@biomejs/js-api';import*as st from'@vue/compiler-sfc';import {walk}from'estree-walker';import*as Xe from'prettier';import*as Qt from'svelte/compiler';import {Project}from'ts-morph';import Fr from'validate-npm-package-name';import Ir from'node:os';import xr from'ansi-regex';import Mr from'conf';import {execa}from'execa';import {detect as detect$1,resolveCommand as resolveCommand$1}from'package-manager-detector';import {diffLines,diffChars}from'diff';var N=I.gray("\u2502"),yt=I.gray("\u2500"),Ut=I.gray("\u2510"),zt=I.gray("\u2518"),vt=I.gray("\u251C");I.gray("\u250C");I.gray("\u2514");var ie=I.bgRgb(245,149,66).white("WARN"),Le=I.bgBlueBright.white("INFO"),fe=I.hex("#f7df1e")("jsrepo");var nt=class{_result;constructor(e){this._result=e;}match(e,r){return this._result.ok?e(this._result.val):r(this._result.err)}map(e){return this.match(r=>O(e(r)),r=>P(r))}mapOr(e,r){return this.match(o=>r(o),o=>e)}mapOrElse(e,r){return this.match(o=>r(o),o=>e(o))}mapErr(e){return this.match(r=>O(r),r=>P(e(r)))}mapErrOr(e,r){return this.match(o=>e,o=>r(o))}mapErrOrElse(e,r){return this.match(o=>e(o),o=>r(o))}isOk(){return this.match(()=>!0,()=>!1)}isErr(){return this.match(()=>!1,()=>!0)}unwrap(){return this.match(e=>e,()=>{throw new Error("Attempted to call `.unwrap()` on a non `Ok` value.")})}unwrapErr(){return this.match(()=>{throw new Error("Attempted to call `.unwrapErr()` on a non `Err` value.")},e=>e)}unwrapOr(e){return this.match(r=>r,r=>e)}unwrapErrOr(e){return this.match(()=>e,r=>r)}unwrapOrElse(e){return this.match(r=>r,r=>e(r))}unwrapErrOrElse(e){return this.match(r=>e(r),r=>r)}expect(e){return this.match(r=>r,()=>{throw new Error(e)})}expectErr(e){return this.match(()=>{throw new Error(e)},r=>r)}},O=t=>new nt({ok:!0,val:t}),P=t=>new nt({ok:!1,err:t});var Gt=(t,e)=>{let r=[];for(let[o,n]of t)r.push(e(o,n));return r};var xe=t=>t.replace(xr(),"");var qe=(t,e,r=" ")=>{if(xe(t).length>e)throw new Error("String length is greater than the length provided.");return r.repeat(e-xe(t).length)+t},Ht=(t,e,r=" ")=>t+r.repeat(e),Kt=(t,e,r=" ")=>{if(xe(t).length>e)throw new Error("String length is greater than the length provided.");return t+r.repeat(e-xe(t).length)};var Er=/\n|\r\n/g,se=t=>t.split(Er),Q=(t,{lineNumbers:e=!1,prefix:r}={})=>{let o=t;if(e){let n=t.length.toString().length+1;o=o.map((i,s)=>`${qe(`${s+1}`,n)} ${i}`);}return r!==void 0&&(o=o.map((n,i)=>`${r(i,t.length)}${n}`)),o.join(Ir.EOL)};var $t=(t,e)=>{let r=J.join(t,"package.json");if(Ne.existsSync(r))return r;if(t===e)return;let o=t.split(/[\/\\]/);return $t(o.slice(0,o.length-1).join("/"),e)},Sr=t=>{if(!Ne.existsSync(t))return P(`${t} doesn't exist`);let e=Ne.readFileSync(t).toString();return O(JSON.parse(e))},it=(t,e,{cwd:r})=>{let o=t,n=e,i=Sr(J.join(r,"package.json"));if(!i.isErr()){let s=i.unwrap();if(s.dependencies)for(let a of o){let[d,h]=a.split("@"),f=s.dependencies[d];h===void 0&&f||f&&f===h&&o.delete(a);}if(s.devDependencies)for(let a of n){let[d,h]=a.split("@"),f=s.devDependencies[d];h===void 0&&f||f&&f===h&&n.delete(a);}}return {dependencies:o,devDependencies:n}};var jr=/^(@[^\/]+\/[^@\/]+)(?:@([^\/]+))?(\/.*)?$/,Tr=/^([^@\/]+)(?:@([^\/]+))?(\/.*)?$/,Xt=t=>{let e=jr.exec(t)||Tr.exec(t);return e?O({name:e[1]||"",version:e[2]||"latest",path:e[3]||""}):P(`invalid package name: ${t}`)};var Br={matches:t=>t.endsWith(".ts")||t.endsWith(".js")||t.endsWith(".tsx")||t.endsWith(".jsx"),resolveDependencies:({filePath:t,isSubDir:e,excludeDeps:r})=>{let i=new Project().addSourceFileAtPath(t).getImportDeclarations(),s=i.filter($=>$.getModuleSpecifierValue().startsWith(".")),a=new Set;for(let $ of s){let v=$.getModuleSpecifierValue(),m=kt(v,e,{filePath:t});if(m.isErr())return P(m.unwrapErr());m.unwrap()&&a.add(m.unwrap());}let d=i.filter($=>!$.getModuleSpecifierValue().startsWith(".")).map($=>$.getModuleSpecifierValue()),{devDependencies:h,dependencies:f}=Rt(Array.from(d),t,r);return O({local:Array.from(a),dependencies:f,devDependencies:h})},comment:t=>`/*
3
+ ${Q(se(t),{prefix:()=>" "})}
4
+ */`,format:async(t,{formatter:e,filePath:r,prettierOptions:o,biomeOptions:n})=>{if(!e)return t;if(e==="prettier")return await Xe.format(t,{filepath:r,...o});let i=await Biome.create({distribution:Distribution.NODE});return n&&i.applyConfiguration(n),i.formatContent(t,{filePath:r}).content}},Lr={matches:t=>t.endsWith(".svelte"),resolveDependencies:({filePath:t,isSubDir:e,excludeDeps:r})=>{let o=Ne.readFileSync(t).toString(),n=Qt.parse(o,{modern:!0,filename:t});if(!n.instance)return O({dependencies:[],devDependencies:[],local:[]});let i=new Set,s=new Set;walk(n.instance,{enter:h=>{if(h.type==="ImportDeclaration"&&typeof h.source.value=="string")if(h.source.value.startsWith(".")){let f=kt(h.source.value,e,{filePath:t});if(f.isErr())return P(f.unwrapErr());f.unwrap()&&i.add(f.unwrap());}else s.add(h.source.value);}});let{devDependencies:a,dependencies:d}=Rt(Array.from(s),t,["svelte",...r]);return O({dependencies:d,devDependencies:a,local:Array.from(i)})},comment:t=>`<!--
5
+ ${Q(se(t),{prefix:()=>" "})}
6
+ -->`,format:async(t,{formatter:e,filePath:r,prettierOptions:o})=>e&&e==="prettier"&&o&&o.plugins?.find(n=>n==="prettier-plugin-svelte")?await Xe.format(t,{filepath:r,...o}):t},_r={matches:t=>t.endsWith(".vue"),resolveDependencies:({filePath:t,isSubDir:e,excludeDeps:r})=>{let o=Ne.readFileSync(t).toString(),n=st.parse(o,{filename:t});if(!n.descriptor.script?.content&&!n.descriptor.scriptSetup?.content)return O({dependencies:[],devDependencies:[],local:[]});let i=new Set,s=new Set,a;try{a=st.compileScript(n.descriptor,{id:"shut-it"});}catch($){return P(`Compile error: ${$}`)}if(!a.imports)return O({dependencies:[],devDependencies:[],local:[]});let d=Object.values(a.imports);for(let $ of d)if($.source.startsWith(".")){let v=kt($.source,e,{filePath:t});if(v.isErr())return P(v.unwrapErr());v.unwrap()&&i.add(v.unwrap());}else s.add($.source);let{devDependencies:h,dependencies:f}=Rt(Array.from(s),t,["vue",...r]);return O({dependencies:f,devDependencies:h,local:Array.from(i)})},comment:t=>`<!--
7
+ ${Q(se(t),{prefix:()=>" "})}
8
+ -->`,format:async(t,{formatter:e,prettierOptions:r})=>e&&e==="prettier"?await Xe.format(t,{parser:"vue",...r}):t},Wr={matches:t=>t.endsWith(".yml")||t.endsWith(".yaml"),resolveDependencies:()=>O({dependencies:[],local:[],devDependencies:[]}),comment:t=>Q(se(t),{prefix:()=>"# "}),format:async(t,{formatter:e,prettierOptions:r})=>e&&e==="prettier"?await Xe.format(t,{parser:"yaml",...r}):t},kt=(t,e,{filePath:r})=>{if(e&&(t.startsWith("./")||t==="."))return O(void 0);let o=e?J.join(r,"../../"):J.join(r,"../"),n=J.join(J.join(r,"../"),t),i=J.join(o,"../");if(n.startsWith(i)){let[s,a]=n.slice(i.length).split("/");return a.includes(".")&&(a=a.slice(0,a.length-J.parse(a).ext.length)),O(`${s}/${a}`)}return P(`${r}:
9
+ ${t} references code not contained in ${o} and cannot be resolved.`)},Rt=(t,e,r=[])=>{let o=new Set(r),n=t.filter(d=>!builtinModules.includes(d)&&!d.startsWith("node:")),i=$t(J.dirname(e),""),s=new Set,a=new Set;if(i){let{devDependencies:d,dependencies:h}=JSON.parse(Ne.readFileSync(i,"utf-8"));for(let f of n){let $=Xt(f);if($.isErr()){console.warn(`${ie} Skipped adding import \`${I.cyan(f)}\`. Reason: Couldn't parse package name`);continue}let v=$.unwrap();if(!Fr(v.name).validForNewPackages){console.warn(`${ie} Skipped adding import \`${I.cyan(f)}\`. Reason: Not a valid package name`);continue}if(o.has(v.name))continue;let m;if(h!==void 0&&(m=h[v.name]),m!==void 0){s.add(`${v.name}@${m}`);continue}if(d!==void 0&&(m=d[v.name]),m!==void 0){a.add(`${v.name}@${m}`);continue}s.add(v.name);}}return {dependencies:Array.from(s),devDependencies:Array.from(a)}},he=[Br,Lr,_r,Wr];var Vr=B.object({name:B.string(),category:B.string(),localDependencies:B.array(B.string()),dependencies:B.array(B.string()),devDependencies:B.array(B.string()),tests:B.boolean(),directory:B.string(),subdirectory:B.boolean(),files:B.array(B.string())}),at=B.object({name:B.string(),blocks:B.array(Vr)}),er=[".test.ts","_test.ts",".test.js","_test.js"],ae=t=>er.find(e=>t.endsWith(e))!==void 0,tr=(t,{cwd:e,excludeDeps:r,includeBlocks:o,includeCategories:n,errorOnWarn:i})=>{let s;try{s=Ne.readdirSync(t);}catch{program.error(I.red(`Couldn't read the ${I.bold(t)} directory.`));}let a=[];for(let d of s){let h=J.join(t,d);if(Ne.statSync(h).isFile())continue;let f=J.basename(d);if(n.length>0&&n.find(m=>m.trim()===f.trim())===void 0)continue;let $={name:f,blocks:[]},v=Ne.readdirSync(h);for(let m of v){let b=J.join(h,m);if(Ne.statSync(b).isFile()){if(ae(m))continue;let S=J.parse(J.basename(m)).name;if(o.length>0&&o.find(c=>c.trim()===S.trim())===void 0)continue;let j=he.find(c=>c.matches(m));if(!j){let c="files are not currently supported!";i?program.error(I.red(`Couldn't add \`${I.bold(b)}\` \`*${I.bold(J.parse(m).ext)}\` ${c}`)):console.warn(`${N} ${ie} Skipped \`${I.bold(b)}\` \`*${I.bold(J.parse(m).ext)}\` ${c}`);continue}let T=v.find(c=>er.find(y=>c===`${S}${y}`)),{dependencies:w,devDependencies:g,local:l}=j.resolveDependencies({filePath:b,isSubDir:!1,excludeDeps:r,cwd:e}).match(c=>c,c=>{program.error(I.red(c));}),p={name:S,directory:J.relative(e,h),category:f,tests:T!==void 0,subdirectory:!1,files:[m],localDependencies:l,dependencies:w,devDependencies:g};T!==void 0&&p.files.push(T),$.blocks.push(p);}else {let S=m;if(o.length>0&&o.find(c=>c.trim()===S.trim())===void 0)continue;let j=Ne.readdirSync(b),T=j.findIndex(c=>ae(c))!==-1,w=new Set,g=new Set,l=new Set;for(let c of j){if(ae(c))continue;if(Ne.statSync(J.join(b,c)).isDirectory()){let k="subdirectories are not currently supported!";i?program.error(I.red(`Couldn't add \`${I.bold(J.join(b,c))}\` ${k}`)):console.warn(`${N} ${ie} Skipped \`${I.bold(J.join(b,c))}\` ${k}`);continue}let y=he.find(k=>k.matches(c));if(!y){let k="files are not currently supported!";i?program.error(I.red(`Couldn't add \`${I.bold(J.join(b,c))}\` \`*${I.bold(J.parse(c).ext)}\` ${k}`)):console.warn(`${N} ${ie} Skipped \`${J.join(b,c)}\` \`*${I.bold(J.parse(c).ext)}\` ${k}`);continue}let{local:R,dependencies:u,devDependencies:C}=y.resolveDependencies({filePath:J.join(b,c),isSubDir:!0,excludeDeps:r,cwd:e}).match(k=>k,k=>{program.error(I.red(k));});for(let k of R)w.add(k);for(let k of u)g.add(k);for(let k of C)l.add(k);}let p={name:S,directory:J.relative(e,b),category:f,tests:T,subdirectory:!0,files:[...j],localDependencies:Array.from(w.keys()),dependencies:Array.from(g.keys()),devDependencies:Array.from(l.keys())};$.blocks.push(p);}}a.push($);}return a};var ce="jsrepo-manifest.json";var ye=()=>new Mr({projectName:"jsrepo"});var Ve=(t,e,r)=>P(`There was an error fetching the \`${I.bold(e)}\` from ${I.bold(t.url)}.
10
+
11
+ ${I.bold("This may be for one of the following reasons:")}
12
+ 1. The \`${I.bold(e)}\` or containing repository doesn't exist
13
+ 2. Your repository path is incorrect (wrong branch, wrong tag) default branches other than \`${I.bold(r)}\` must be specified \`${I.bold("github/<owner>/<name>/tree/<branch>")}\`
1223
14
  3. You are using an expired access token or a token that doesn't have access to this repository
1224
- `
1225
- );
1226
- };
1227
- var github = {
1228
- name: () => "github",
1229
- defaultBranch: () => "main",
1230
- resolveRaw: async (repoPath, resourcePath) => {
1231
- const info = await github.info(repoPath);
1232
- return new URL(
1233
- resourcePath,
1234
- `https://raw.githubusercontent.com/${info.owner}/${info.repoName}/refs/${info.refs}/${info.ref}/`
1235
- );
1236
- },
1237
- fetchRaw: async (repoPath, resourcePath, { verbose } = {}) => {
1238
- const info = await github.info(repoPath);
1239
- const url = await github.resolveRaw(info, resourcePath);
1240
- verbose?.(`Trying to fetch from ${url}`);
1241
- try {
1242
- const token = get2().get(`${github.name()}-token`);
1243
- const headers = new Headers();
1244
- if (token !== void 0) {
1245
- headers.append("Authorization", `token ${token}`);
1246
- }
1247
- const response = await fetch(url, { headers });
1248
- verbose?.(`Got a response from ${url} ${response.status} ${response.statusText}`);
1249
- if (!response.ok) {
1250
- return rawErrorMessage(info, resourcePath, github.defaultBranch());
1251
- }
1252
- return Ok(await response.text());
1253
- } catch (err) {
1254
- verbose?.(`erroring in response ${err} `);
1255
- return rawErrorMessage(info, resourcePath, github.defaultBranch());
1256
- }
1257
- },
1258
- fetchManifest: async (repoPath) => {
1259
- const manifest = await github.fetchRaw(repoPath, OUTPUT_FILE);
1260
- if (manifest.isErr()) return Err(manifest.unwrapErr());
1261
- const categories = v3.parse(v3.array(categorySchema), JSON.parse(manifest.unwrap()));
1262
- return Ok(categories);
1263
- },
1264
- info: async (repoPath) => {
1265
- if (typeof repoPath !== "string") return repoPath;
1266
- const repo = repoPath.replaceAll(/(https:\/\/github.com\/)|(github\/)/g, "");
1267
- const [owner, repoName, ...rest] = repo.split("/");
1268
- let ref = github.defaultBranch();
1269
- const token = get2().get(`${github.name()}-token`);
1270
- const octokit = new Octokit({ auth: token });
1271
- if (rest[0] === "tree") {
1272
- ref = rest[1];
1273
- } else {
1274
- try {
1275
- const { data: repo2 } = await octokit.rest.repos.get({ owner, repo: repoName });
1276
- ref = repo2.default_branch;
1277
- } catch {
1278
- }
1279
- }
1280
- let refs = "heads";
1281
- if (ref !== github.defaultBranch()) {
1282
- try {
1283
- const { data: tags } = await octokit.rest.git.listMatchingRefs({
1284
- owner,
1285
- repo: repoName,
1286
- ref: "tags"
1287
- });
1288
- if (tags.some((tag) => tag.ref === `refs/tags/${ref}`)) {
1289
- refs = "tags";
1290
- }
1291
- } catch {
1292
- refs = "heads";
1293
- }
1294
- }
1295
- return {
1296
- refs,
1297
- url: repoPath,
1298
- name: github.name(),
1299
- repoName,
1300
- owner,
1301
- ref,
1302
- provider: github
1303
- };
1304
- },
1305
- matches: (repoPath) => repoPath.toLowerCase().startsWith("https://github.com") || repoPath.toLowerCase().startsWith("github")
1306
- };
1307
- var gitlab = {
1308
- name: () => "gitlab",
1309
- defaultBranch: () => "main",
1310
- resolveRaw: async (repoPath, resourcePath) => {
1311
- const info = await gitlab.info(repoPath);
1312
- return new URL(
1313
- `${encodeURIComponent(resourcePath)}/raw?ref=${info.ref}`,
1314
- `https://gitlab.com/api/v4/projects/${encodeURIComponent(`${info.owner}/${info.repoName}`)}/repository/files/`
1315
- );
1316
- },
1317
- fetchRaw: async (repoPath, resourcePath, { verbose } = {}) => {
1318
- const info = await github.info(repoPath);
1319
- const url = await gitlab.resolveRaw(info, resourcePath);
1320
- verbose?.(`Trying to fetch from ${url}`);
1321
- try {
1322
- const token = get2().get(`${gitlab.name()}-token`);
1323
- const headers = new Headers();
1324
- if (token !== void 0) {
1325
- headers.append("PRIVATE-TOKEN", `${token}`);
1326
- }
1327
- const response = await fetch(url, { headers });
1328
- verbose?.(`Got a response from ${url} ${response.status} ${response.statusText}`);
1329
- if (!response.ok) {
1330
- return rawErrorMessage(info, resourcePath, gitlab.defaultBranch());
1331
- }
1332
- return Ok(await response.text());
1333
- } catch {
1334
- return rawErrorMessage(info, resourcePath, gitlab.defaultBranch());
1335
- }
1336
- },
1337
- fetchManifest: async (repoPath) => {
1338
- const manifest = await gitlab.fetchRaw(repoPath, OUTPUT_FILE);
1339
- if (manifest.isErr()) return Err(manifest.unwrapErr());
1340
- const categories = v3.parse(v3.array(categorySchema), JSON.parse(manifest.unwrap()));
1341
- return Ok(categories);
1342
- },
1343
- info: async (repoPath) => {
1344
- if (typeof repoPath !== "string") return repoPath;
1345
- const repo = repoPath.replaceAll(/(https:\/\/gitlab.com\/)|(gitlab\/)/g, "");
1346
- const [owner, repoName, ...rest] = repo.split("/");
1347
- let ref = gitlab.defaultBranch();
1348
- let refs = "heads";
1349
- if (rest[0] === "-" && rest[1] === "tree") {
1350
- if (rest[2].includes("?")) {
1351
- const [tempRef, last] = rest[2].split("?");
1352
- ref = tempRef;
1353
- if (last.startsWith("ref_type=")) {
1354
- if (last.slice(10) === "tags") {
1355
- refs = "tags";
1356
- }
1357
- }
1358
- } else {
1359
- ref = rest[2];
1360
- }
1361
- }
1362
- return {
1363
- refs,
1364
- url: repoPath,
1365
- name: gitlab.name(),
1366
- repoName,
1367
- owner,
1368
- ref,
1369
- provider: gitlab
1370
- };
1371
- },
1372
- matches: (repoPath) => repoPath.toLowerCase().startsWith("https://gitlab.com") || repoPath.toLowerCase().startsWith("gitlab")
1373
- };
1374
- var bitbucket = {
1375
- name: () => "bitbucket",
1376
- defaultBranch: () => "master",
1377
- resolveRaw: async (repoPath, resourcePath) => {
1378
- const info = await bitbucket.info(repoPath);
1379
- return new URL(
1380
- resourcePath,
1381
- `https://api.bitbucket.org/2.0/repositories/${info.owner}/${info.repoName}/src/${info.ref}/`
1382
- );
1383
- },
1384
- fetchRaw: async (repoPath, resourcePath, { verbose } = {}) => {
1385
- const info = await bitbucket.info(repoPath);
1386
- const url = await bitbucket.resolveRaw(info, resourcePath);
1387
- verbose?.(`Trying to fetch from ${url}`);
1388
- try {
1389
- const token = get2().get(`${bitbucket.name()}-token`);
1390
- const headers = new Headers();
1391
- if (token !== void 0) {
1392
- headers.append("Authorization", `Bearer ${token}`);
1393
- }
1394
- const response = await fetch(url, { headers });
1395
- verbose?.(`Got a response from ${url} ${response.status} ${response.statusText}`);
1396
- if (!response.ok) {
1397
- return rawErrorMessage(info, resourcePath, bitbucket.defaultBranch());
1398
- }
1399
- return Ok(await response.text());
1400
- } catch {
1401
- return rawErrorMessage(info, resourcePath, bitbucket.defaultBranch());
1402
- }
1403
- },
1404
- fetchManifest: async (repoPath) => {
1405
- const manifest = await bitbucket.fetchRaw(repoPath, OUTPUT_FILE);
1406
- if (manifest.isErr()) return Err(manifest.unwrapErr());
1407
- const categories = v3.parse(v3.array(categorySchema), JSON.parse(manifest.unwrap()));
1408
- return Ok(categories);
1409
- },
1410
- info: async (repoPath) => {
1411
- if (typeof repoPath !== "string") return repoPath;
1412
- const repo = repoPath.replaceAll(/(https:\/\/bitbucket.org\/)|(bitbucket\/)/g, "");
1413
- const [owner, repoName, ...rest] = repo.split("/");
1414
- const refs = "heads";
1415
- let ref = bitbucket.defaultBranch();
1416
- if (rest[0] === "src") {
1417
- ref = rest[1];
1418
- }
1419
- return {
1420
- refs,
1421
- url: repoPath,
1422
- name: bitbucket.name(),
1423
- repoName,
1424
- owner,
1425
- ref,
1426
- provider: bitbucket
1427
- };
1428
- },
1429
- matches: (repoPath) => repoPath.toLowerCase().startsWith("https://bitbucket.org") || repoPath.toLowerCase().startsWith("bitbucket")
1430
- };
1431
- var providers = [github, gitlab, bitbucket];
1432
- var getProviderInfo = async (repo) => {
1433
- const provider = providers.find((provider2) => provider2.matches(repo));
1434
- if (provider) {
1435
- return Ok(await provider.info(repo));
1436
- }
1437
- return Err(
1438
- `Only ${providers.map((p, i) => `${i === providers.length - 1 ? "and" : ""}${color4.cyan(p.name())}`).join(", ")} repositories are supported at this time!`
1439
- );
1440
- };
1441
- var fetchBlocks = async (...repos) => {
1442
- const blocksMap = /* @__PURE__ */ new Map();
1443
- for (const repo of repos) {
1444
- const getProviderResult = await getProviderInfo(repo);
1445
- if (getProviderResult.isErr()) return Err({ message: getProviderResult.unwrapErr(), repo });
1446
- const providerInfo = getProviderResult.unwrap();
1447
- const getManifestResult = await providerInfo.provider.fetchManifest(providerInfo);
1448
- if (getManifestResult.isErr()) return Err({ message: getManifestResult.unwrapErr(), repo });
1449
- const categories = getManifestResult.unwrap();
1450
- for (const category of categories) {
1451
- for (const block of category.blocks) {
1452
- blocksMap.set(
1453
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
1454
- {
1455
- ...block,
1456
- sourceRepo: providerInfo
1457
- }
1458
- );
1459
- }
1460
- }
1461
- }
1462
- return Ok(blocksMap);
1463
- };
1464
-
1465
- // src/utils/blocks.ts
1466
- var resolveTree = async (blockSpecifiers, blocksMap, repoPaths) => {
1467
- const blocks = /* @__PURE__ */ new Map();
1468
- for (const blockSpecifier of blockSpecifiers) {
1469
- let block = void 0;
1470
- if (!providers.find((p) => blockSpecifier.startsWith(p.name()))) {
1471
- if (repoPaths.length === 0) {
1472
- return Err(
1473
- color5.red(
1474
- `If your config doesn't repos then you must provide the repo in the block specifier ex: \`${color5.bold(
1475
- `github/<owner>/<name>/${blockSpecifier}`
1476
- )}\`!`
1477
- )
1478
- );
1479
- }
1480
- for (const repo of repoPaths) {
1481
- const providerInfo = (await getProviderInfo(repo)).unwrap();
1482
- const tempBlock = blocksMap.get(
1483
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier}`
1484
- );
1485
- if (tempBlock === void 0) continue;
1486
- block = tempBlock;
1487
- break;
1488
- }
1489
- } else {
1490
- const [providerName, owner, repoName, ...rest] = blockSpecifier.split("/");
1491
- block = blocksMap.get(
1492
- `${providerName}/${owner}/${repoName}/${rest.slice(rest.length - 2).join("/")}`
1493
- );
1494
- }
1495
- if (!block) {
1496
- return Err(`Invalid block! ${color5.bold(blockSpecifier)} does not exist!`);
1497
- }
1498
- const specifier = `${block.category}/${block.name}`;
1499
- blocks.set(specifier, { name: block.name, subDependency: false, block });
1500
- if (block.localDependencies && block.localDependencies.length > 0) {
1501
- const subDeps = await resolveTree(
1502
- block.localDependencies.filter((dep) => !blocks.has(dep)),
1503
- blocksMap,
1504
- repoPaths
1505
- );
1506
- if (subDeps.isErr()) return Err(subDeps.unwrapErr());
1507
- for (const dep of subDeps.unwrap()) {
1508
- blocks.set(dep.name, dep);
1509
- }
1510
- }
1511
- }
1512
- return Ok(mapToArray(blocks, (_, val) => val));
1513
- };
1514
- var getInstalled = (blocks, config, cwd) => {
1515
- const installedBlocks = [];
1516
- for (const [_, block] of blocks) {
1517
- const baseDir = path4.join(cwd, config.path, block.category);
1518
- let blockPath = path4.join(baseDir, block.files[0]);
1519
- if (block.subdirectory) {
1520
- blockPath = path4.join(baseDir, block.name);
1521
- }
1522
- if (fs4.existsSync(blockPath))
1523
- installedBlocks.push({
1524
- specifier: `${block.category}/${block.name}`,
1525
- path: blockPath,
1526
- block
1527
- });
1528
- }
1529
- return installedBlocks;
1530
- };
1531
-
1532
- // src/utils/config.ts
1533
- import fs5 from "node:fs";
1534
- import path5 from "pathe";
1535
- import * as v4 from "valibot";
1536
- var CONFIG_NAME = "jsrepo.json";
1537
- var formatterSchema = v4.union([v4.literal("prettier"), v4.literal("biome")]);
1538
- var schema = v4.object({
1539
- $schema: v4.string(),
1540
- repos: v4.optional(v4.array(v4.string()), []),
1541
- includeTests: v4.boolean(),
1542
- path: v4.pipe(v4.string(), v4.minLength(1)),
1543
- watermark: v4.optional(v4.boolean(), true),
1544
- formatter: v4.optional(formatterSchema)
1545
- });
1546
- var getConfig = (cwd) => {
1547
- if (!fs5.existsSync(path5.join(cwd, CONFIG_NAME))) {
1548
- return Err("Could not find your configuration file! Please run `init`.");
1549
- }
1550
- const config = v4.safeParse(
1551
- schema,
1552
- JSON.parse(fs5.readFileSync(path5.join(cwd, CONFIG_NAME)).toString())
1553
- );
1554
- if (!config.success) {
1555
- return Err(`There was an error reading your \`${CONFIG_NAME}\` file!`);
1556
- }
1557
- return Ok(config.output);
1558
- };
1559
-
1560
- // src/utils/dependencies.ts
1561
- import color6 from "chalk";
1562
- import { execa } from "execa";
1563
- import { resolveCommand } from "package-manager-detector";
1564
- var installDependencies = async ({
1565
- pm,
1566
- deps,
1567
- dev,
1568
- cwd
1569
- }) => {
1570
- let add2;
1571
- if (dev) {
1572
- add2 = resolveCommand(pm, "install", [...deps, "-D"]);
1573
- } else {
1574
- add2 = resolveCommand(pm, "install", [...deps]);
1575
- }
1576
- if (add2 == null) return Err(color6.red(`Could not resolve add command for '${pm}'.`));
1577
- try {
1578
- await execa(add2.command, [...add2.args], { cwd });
1579
- return Ok(deps);
1580
- } catch {
1581
- return Err(
1582
- color6.red(
1583
- `Failed to install ${color6.bold(deps.join(", "))}! Failed while running '${color6.bold(
1584
- `${add2.command} ${add2.args.join(" ")}`
1585
- )}'`
1586
- )
1587
- );
1588
- }
1589
- };
1590
-
1591
- // src/utils/format.ts
1592
- import fs6 from "node:fs";
1593
- import path6 from "pathe";
1594
- import * as prettier2 from "prettier";
1595
- var loadFormatterConfig = async ({
1596
- formatter,
1597
- cwd
1598
- }) => {
1599
- let prettierOptions = null;
1600
- if (formatter === "prettier") {
1601
- prettierOptions = await prettier2.resolveConfig(path6.join(cwd, ".prettierrc"));
1602
- }
1603
- let biomeOptions = null;
1604
- if (formatter === "biome") {
1605
- const configPath = path6.join(cwd, "biome.json");
1606
- if (fs6.existsSync(configPath)) {
1607
- biomeOptions = JSON.parse(fs6.readFileSync(configPath).toString());
1608
- }
1609
- }
1610
- return {
1611
- biomeOptions,
1612
- prettierOptions
1613
- };
1614
- };
1615
-
1616
- // src/utils/get-watermark.ts
1617
- var getWatermark = (version2, repoUrl) => {
1618
- return `jsrepo ${version2}
1619
- Installed from ${repoUrl}
1620
- ${(/* @__PURE__ */ new Date()).toLocaleDateString().replaceAll("/", "-")}`;
1621
- };
1622
-
1623
- // src/utils/prompts.ts
1624
- import { intro, spinner } from "@clack/prompts";
1625
- import color7 from "chalk";
1626
- var runTasks = async (tasks, { verbose = void 0 }) => {
1627
- const loading = spinner();
1628
- for (const task of tasks) {
1629
- if (verbose) {
1630
- verbose(task.loadingMessage);
1631
- } else {
1632
- loading.start(task.loadingMessage);
1633
- }
1634
- try {
1635
- await task.run();
1636
- } catch (err) {
1637
- loading.stop(`Error while ${task.loadingMessage}`);
1638
- console.error(err);
1639
- }
1640
- if (verbose) {
1641
- verbose(task.completedMessage);
1642
- } else {
1643
- loading.stop(task.completedMessage);
1644
- }
1645
- }
1646
- };
1647
- var nextSteps = (steps) => {
1648
- let max = 20;
1649
- steps.map((val) => {
1650
- const reset = rightPad(stripAsni(val), 4);
1651
- if (reset.length > max) max = reset.length;
1652
- });
1653
- const NEXT_STEPS = "Next Steps";
1654
- let result = `${VERTICAL_LINE}
1655
- `;
1656
- result += `${JUNCTION_RIGHT} ${NEXT_STEPS} ${HORIZONTAL_LINE.repeat(
1657
- max - NEXT_STEPS.length - 1
1658
- )}${TOP_RIGHT_CORNER}
1659
- `;
1660
- result += `${VERTICAL_LINE} ${" ".repeat(max)} ${VERTICAL_LINE}
1661
- `;
1662
- steps.map((step) => {
1663
- result += `${VERTICAL_LINE} ${rightPadMin(step, max - 1)} ${VERTICAL_LINE}
1664
- `;
1665
- });
1666
- result += `${VERTICAL_LINE} ${" ".repeat(max)} ${VERTICAL_LINE}
1667
- `;
1668
- result += `${JUNCTION_RIGHT}${HORIZONTAL_LINE.repeat(max + 2)}${BOTTOM_RIGHT_CORNER}
1669
- `;
1670
- return result;
1671
- };
1672
- var _intro = (version2) => intro(`${color7.bgHex("#f7df1e").black(" jsrepo ")}${color7.gray(` v${version2} `)}`);
1673
-
1674
- // src/commands/add.ts
1675
- var schema2 = v5.object({
1676
- repo: v5.optional(v5.string()),
1677
- allow: v5.boolean(),
1678
- yes: v5.boolean(),
1679
- verbose: v5.boolean(),
1680
- cwd: v5.string()
1681
- });
1682
- var add = new Command("add").argument(
1683
- "[blocks...]",
1684
- "Names of the blocks you want to add to your project. ex: (utils/math, github/ieedan/std/utils/math)"
1685
- ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("-y, --yes", "Skip confirmation prompt.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
1686
- const options = v5.parse(schema2, opts);
1687
- _intro(context.package.version);
1688
- await _add(blockNames, options);
1689
- outro(color8.green("All done!"));
1690
- });
1691
- var _add = async (blockNames, options) => {
1692
- const verbose = (msg) => {
1693
- if (options.verbose) {
1694
- console.info(`${INFO} ${msg}`);
1695
- }
1696
- };
1697
- verbose(`Attempting to add ${JSON.stringify(blockNames)}`);
1698
- const loading = spinner2();
1699
- const configResult = getConfig(options.cwd);
1700
- const noConfig = configResult.isErr();
1701
- let config;
1702
- if (configResult.isErr()) {
1703
- const response = await confirm({
1704
- message: `You don't have ${JSREPO} initialized in your project. Do you want to continue?`,
1705
- initialValue: false
1706
- });
1707
- if (isCancel(response) || !response) {
1708
- cancel("Canceled!");
1709
- process.exit(0);
1710
- }
1711
- config = {
1712
- $schema: "",
1713
- includeTests: false,
1714
- watermark: true,
1715
- path: "./src/blocks",
1716
- repos: []
1717
- };
1718
- } else {
1719
- config = configResult.unwrap();
1720
- }
1721
- let repoPaths = config.repos;
1722
- if (options.repo) repoPaths = [options.repo];
1723
- for (const blockSpecifier of blockNames) {
1724
- if (!providers.find((p) => blockSpecifier.startsWith(p.name()))) continue;
1725
- const [providerName, owner, repoName, ...rest] = blockSpecifier.split("/");
1726
- let repo;
1727
- if (rest.length > 2) {
1728
- repo = `${providerName}/${owner}/${repoName}/${rest.slice(0, rest.length - 2).join("/")}`;
1729
- } else {
1730
- repo = `${providerName}/${owner}/${repoName}`;
1731
- }
1732
- if (!repoPaths.find((repoPath) => repoPath === repo)) {
1733
- if (!options.allow) {
1734
- const result = await confirm({
1735
- message: `Allow ${JSREPO} to download and run code from ${color8.cyan(repo)}?`,
1736
- initialValue: true
1737
- });
1738
- if (isCancel(result) || !result) {
1739
- cancel("Canceled!");
1740
- process.exit(0);
1741
- }
1742
- }
1743
- repoPaths.push(repo);
1744
- }
1745
- }
1746
- if (!options.allow && options.repo) {
1747
- const result = await confirm({
1748
- message: `Allow ${JSREPO} to download and run code from ${color8.cyan(options.repo)}?`,
1749
- initialValue: true
1750
- });
1751
- if (isCancel(result) || !result) {
1752
- cancel("Canceled!");
1753
- process.exit(0);
1754
- }
1755
- }
1756
- if (repoPaths.length === 0) {
1757
- if (noConfig) {
1758
- program2.error(
1759
- color8.red(
1760
- `Fully quality blocks ex: (github/ieedan/std/utils/math) or provide the \`${color8.bold(
1761
- "--repo"
1762
- )}\` flag to specify a registry.`
1763
- )
1764
- );
1765
- }
1766
- program2.error(
1767
- color8.red(
1768
- `There were no repos present in your config and you didn't provide the \`${color8.bold(
1769
- "--repo"
1770
- )}\` flag with a repo.`
1771
- )
1772
- );
1773
- }
1774
- verbose(`Fetching blocks from ${color8.cyan(repoPaths.join(", "))}`);
1775
- if (!options.verbose) loading.start(`Fetching blocks from ${color8.cyan(repoPaths.join(", "))}`);
1776
- const blocksMap = (await fetchBlocks(...repoPaths)).match(
1777
- (val) => val,
1778
- ({ repo, message }) => {
1779
- loading.stop(`Failed fetching blocks from ${color8.cyan(repo)}`);
1780
- program2.error(color8.red(message));
1781
- }
1782
- );
1783
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color8.cyan(repoPaths.join(", "))}`);
1784
- verbose(`Retrieved blocks from ${color8.cyan(repoPaths.join(", "))}`);
1785
- const installedBlocks = getInstalled(blocksMap, config, options.cwd).map(
1786
- (val) => val.specifier
1787
- );
1788
- let installingBlockNames = blockNames;
1789
- if (installingBlockNames.length === 0) {
1790
- const promptResult = await multiselect({
1791
- message: "Select which blocks to add.",
1792
- options: Array.from(blocksMap.entries()).map(([key, value]) => {
1793
- const shortName = `${value.category}/${value.name}`;
1794
- const blockExists = installedBlocks.findIndex((block) => block === shortName) !== -1;
1795
- let label;
1796
- if (repoPaths.length > 1) {
1797
- label = `${color8.cyan(
1798
- `${value.sourceRepo.name}/${value.sourceRepo.owner}/${value.sourceRepo.repoName}/${value.category}`
1799
- )}/${value.name}`;
1800
- } else {
1801
- label = `${color8.cyan(value.category)}/${value.name}`;
1802
- }
1803
- return {
1804
- label: blockExists ? color8.gray(label) : label,
1805
- value: key,
1806
- // show hint for `Installed` if block is already installed
1807
- hint: blockExists ? "Installed" : void 0
1808
- };
1809
- }),
1810
- required: true
1811
- });
1812
- if (isCancel(promptResult)) {
1813
- cancel("Canceled!");
1814
- process.exit(0);
1815
- }
1816
- installingBlockNames = promptResult;
1817
- }
1818
- verbose(`Installing blocks ${color8.cyan(installingBlockNames.join(", "))}`);
1819
- if (options.verbose) console.log("Blocks map: ", blocksMap);
1820
- const installingBlocks = (await resolveTree(installingBlockNames, blocksMap, repoPaths)).match(
1821
- (val) => val,
1822
- (err) => program2.error(err)
1823
- );
1824
- const pm = (await detect({ cwd: options.cwd }))?.agent ?? "npm";
1825
- const tasks = [];
1826
- let devDeps = /* @__PURE__ */ new Set();
1827
- let deps = /* @__PURE__ */ new Set();
1828
- if (noConfig) {
1829
- const blocksPath = await text({
1830
- message: "Where would you like to add the blocks?",
1831
- initialValue: config.path,
1832
- defaultValue: config.path,
1833
- placeholder: config.path,
1834
- validate(value) {
1835
- if (value.trim() === "") return "Please provide a value";
1836
- }
1837
- });
1838
- if (isCancel(blocksPath)) {
1839
- cancel("Canceled!");
1840
- process.exit(0);
1841
- }
1842
- config.path = blocksPath;
1843
- if (!options.yes) {
1844
- const includeTests = await confirm({
1845
- message: "Include tests?",
1846
- initialValue: config.includeTests
1847
- });
1848
- if (isCancel(includeTests)) {
1849
- cancel("Canceled!");
1850
- process.exit(0);
1851
- }
1852
- config.includeTests = includeTests;
1853
- const addWatermark = await confirm({
1854
- message: "Add watermark?",
1855
- initialValue: config.watermark
1856
- });
1857
- if (isCancel(addWatermark)) {
1858
- cancel("Canceled!");
1859
- process.exit(0);
1860
- }
1861
- config.watermark = addWatermark;
1862
- }
1863
- }
1864
- const { prettierOptions, biomeOptions } = await loadFormatterConfig({
1865
- formatter: config.formatter,
1866
- cwd: options.cwd
1867
- });
1868
- for (const { block } of installingBlocks) {
1869
- const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
1870
- const shortSpecifier = `${block.category}/${block.name}`;
1871
- const watermark = getWatermark(context.package.version, block.sourceRepo.url);
1872
- const providerInfo = block.sourceRepo;
1873
- verbose(`Setting up ${fullSpecifier}`);
1874
- const directory = path7.join(options.cwd, config.path, block.category);
1875
- const blockExists = !block.subdirectory && fs7.existsSync(path7.join(directory, block.files[0])) || block.subdirectory && fs7.existsSync(path7.join(directory, block.name));
1876
- if (blockExists && !options.yes) {
1877
- const result = await confirm({
1878
- message: `${color8.cyan(shortSpecifier)} already exists in your project would you like to overwrite it?`,
1879
- initialValue: false
1880
- });
1881
- if (isCancel(result) || !result) {
1882
- cancel("Canceled!");
1883
- process.exit(0);
1884
- }
1885
- }
1886
- tasks.push({
1887
- loadingMessage: `Adding ${fullSpecifier}`,
1888
- completedMessage: `Added ${fullSpecifier}`,
1889
- run: async () => {
1890
- verbose(`Creating directory ${color8.bold(directory)}`);
1891
- fs7.mkdirSync(directory, { recursive: true });
1892
- verbose(`Created directory ${color8.bold(directory)}`);
1893
- const files = [];
1894
- const getSourceFile = async (filePath) => {
1895
- const content = await providerInfo.provider.fetchRaw(providerInfo, filePath, {
1896
- verbose
1897
- });
1898
- if (content.isErr()) {
1899
- loading.stop(color8.red(`Error fetching ${color8.bold(filePath)}`));
1900
- program2.error(
1901
- color8.red(`There was an error trying to get ${fullSpecifier}`)
1902
- );
1903
- }
1904
- return content.unwrap();
1905
- };
1906
- for (const sourceFile of block.files) {
1907
- if (!config.includeTests && isTestFile(sourceFile)) continue;
1908
- const sourcePath = path7.join(block.directory, sourceFile);
1909
- let destPath;
1910
- if (block.subdirectory) {
1911
- destPath = path7.join(directory, block.name, sourceFile);
1912
- } else {
1913
- destPath = path7.join(directory, sourceFile);
1914
- }
1915
- verbose(`Adding ${color8.bold(sourcePath)}`);
1916
- const content = await getSourceFile(sourcePath);
1917
- const pathFolder = destPath.slice(0, destPath.length - sourceFile.length);
1918
- verbose(`Creating directory ${color8.bold(pathFolder)}`);
1919
- fs7.mkdirSync(pathFolder, {
1920
- recursive: true
1921
- });
1922
- verbose(`Created directory ${color8.bold(pathFolder)}`);
1923
- files.push({ content, destPath });
1924
- verbose(`Got ${color8.bold(sourcePath)}`);
1925
- }
1926
- for (const file of files) {
1927
- const lang = languages.find((lang2) => lang2.matches(file.destPath));
1928
- let content = file.content;
1929
- if (lang) {
1930
- if (config.watermark) {
1931
- const comment = lang.comment(watermark);
1932
- content = `${comment}
1933
-
1934
- ${content}`;
1935
- }
1936
- verbose(`Formatting ${color8.bold(file.destPath)}`);
1937
- content = await lang.format(content, {
1938
- filePath: file.destPath,
1939
- formatter: config.formatter,
1940
- prettierOptions,
1941
- biomeOptions
1942
- });
1943
- }
1944
- verbose(`Writing to ${color8.bold(file.destPath)}`);
1945
- fs7.writeFileSync(file.destPath, content);
1946
- }
1947
- if (config.includeTests && block.tests) {
1948
- verbose("Trying to include tests");
1949
- const { devDependencies } = JSON.parse(
1950
- fs7.readFileSync(path7.join(options.cwd, "package.json")).toString()
1951
- );
1952
- if (devDependencies === void 0 || devDependencies.vitest === void 0) {
1953
- devDeps.add("vitest");
1954
- }
1955
- }
1956
- for (const dep of block.devDependencies) {
1957
- devDeps.add(dep);
1958
- }
1959
- for (const dep of block.dependencies) {
1960
- deps.add(dep);
1961
- }
1962
- }
1963
- });
1964
- }
1965
- await runTasks(tasks, { verbose: options.verbose ? verbose : void 0 });
1966
- const requiredDependencies = returnShouldInstall(deps, devDeps, { cwd: options.cwd });
1967
- deps = requiredDependencies.dependencies;
1968
- devDeps = requiredDependencies.devDependencies;
1969
- const hasDependencies = deps.size > 0 || devDeps.size > 0;
1970
- if (hasDependencies) {
1971
- let install = options.yes;
1972
- if (!options.yes) {
1973
- const result = await confirm({
1974
- message: "Would you like to install dependencies?",
1975
- initialValue: true
1976
- });
1977
- if (isCancel(result)) {
1978
- cancel("Canceled!");
1979
- process.exit(0);
1980
- }
1981
- install = result;
1982
- }
1983
- if (install) {
1984
- if (deps.size > 0) {
1985
- if (!options.verbose)
1986
- loading.start(`Installing dependencies with ${color8.cyan(pm)}`);
1987
- (await installDependencies({
1988
- pm,
1989
- deps: Array.from(deps),
1990
- dev: false,
1991
- cwd: options.cwd
1992
- })).match(
1993
- (installed) => {
1994
- if (!options.verbose)
1995
- loading.stop(`Installed ${color8.cyan(installed.join(", "))}`);
1996
- },
1997
- (err) => {
1998
- if (!options.verbose) loading.stop("Failed to install dependencies");
1999
- program2.error(err);
2000
- }
2001
- );
2002
- }
2003
- if (devDeps.size > 0) {
2004
- if (!options.verbose)
2005
- loading.start(`Installing dependencies with ${color8.cyan(pm)}`);
2006
- (await installDependencies({
2007
- pm,
2008
- deps: Array.from(devDeps),
2009
- dev: true,
2010
- cwd: options.cwd
2011
- })).match(
2012
- (installed) => {
2013
- if (!options.verbose)
2014
- loading.stop(`Installed ${color8.cyan(installed.join(", "))}`);
2015
- },
2016
- (err) => {
2017
- if (!options.verbose) loading.stop("Failed to install dev dependencies");
2018
- program2.error(err);
2019
- }
2020
- );
2021
- }
2022
- }
2023
- let steps = [];
2024
- if (!install) {
2025
- if (deps.size > 0) {
2026
- const cmd = resolveCommand2(pm, "install", [...deps]);
2027
- steps.push(
2028
- `Install dependencies \`${color8.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2029
- );
2030
- }
2031
- if (devDeps.size > 0) {
2032
- const cmd = resolveCommand2(pm, "install", [...devDeps, "-D"]);
2033
- steps.push(
2034
- `Install dev dependencies \`${color8.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2035
- );
2036
- }
2037
- }
2038
- steps = steps.map((step, i) => `${i + 1}. ${step}`);
2039
- if (!install) {
2040
- steps.push("");
2041
- }
2042
- steps.push(`Import the blocks from \`${color8.cyan(config.path)}\``);
2043
- const next = nextSteps(steps);
2044
- process.stdout.write(next);
2045
- }
2046
- };
2047
-
2048
- // src/commands/auth.ts
2049
- import { cancel as cancel2, confirm as confirm2, isCancel as isCancel2, outro as outro2, password, select } from "@clack/prompts";
2050
- import color9 from "chalk";
2051
- import { Command as Command2, Option } from "commander";
2052
- import * as v6 from "valibot";
2053
- var schema3 = v6.object({
2054
- token: v6.optional(v6.string()),
2055
- provider: v6.optional(v6.string()),
2056
- logout: v6.boolean(),
2057
- cwd: v6.string()
2058
- });
2059
- var auth = new Command2("auth").description("Provide a token for access to private repositories.").option("--token <token>", "The token to use for authenticating to your provider.").addOption(
2060
- new Option("--provider <name>", "The provider this token belongs to.").choices(
2061
- providers.map((provider) => provider.name())
2062
- )
2063
- ).option("--logout", "Erase tokens from each provider from storage.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2064
- const options = v6.parse(schema3, opts);
2065
- _intro(context.package.version);
2066
- await _auth(options);
2067
- outro2(color9.green("All done!"));
2068
- });
2069
- var _auth = async (options) => {
2070
- const storage = get2();
2071
- if (options.logout) {
2072
- for (const provider of providers) {
2073
- const tokenKey = `${provider.name()}-token`;
2074
- if (storage.get(tokenKey) === void 0) {
2075
- process.stdout.write(`${VERTICAL_LINE}
2076
- `);
2077
- process.stdout.write(
2078
- color9.gray(
2079
- `${VERTICAL_LINE} Already logged out of ${provider.name()}.
2080
- `
2081
- )
2082
- );
2083
- continue;
2084
- }
2085
- const response = await confirm2({
2086
- message: `Remove ${provider.name()} token?`,
2087
- initialValue: true
2088
- });
2089
- if (isCancel2(response)) {
2090
- cancel2("Canceled!");
2091
- process.exit(0);
2092
- }
2093
- if (!response) continue;
2094
- storage.delete(tokenKey);
2095
- }
2096
- return;
2097
- }
2098
- if (providers.length > 1) {
2099
- const response = await select({
2100
- message: "Which provider is this token for?",
2101
- options: providers.map((provider) => ({
2102
- label: provider.name(),
2103
- value: provider.name()
2104
- })),
2105
- initialValue: providers[0].name()
2106
- });
2107
- if (isCancel2(response)) {
2108
- cancel2("Canceled!");
2109
- process.exit(0);
2110
- }
2111
- options.provider = response;
2112
- } else {
2113
- options.provider = providers[0].name();
2114
- }
2115
- if (options.token === void 0) {
2116
- const response = await password({
2117
- message: "Paste your token",
2118
- validate(value) {
2119
- if (value.trim() === "") return "Please provide a value";
2120
- }
2121
- });
2122
- if (isCancel2(response) || !response) {
2123
- cancel2("Canceled!");
2124
- process.exit(0);
2125
- }
2126
- options.token = response;
2127
- }
2128
- storage.set(`${options.provider}-token`, options.token);
2129
- };
2130
-
2131
- // src/commands/build.ts
2132
- import fs8 from "node:fs";
2133
- import { outro as outro3, spinner as spinner3 } from "@clack/prompts";
2134
- import color10 from "chalk";
2135
- import { Command as Command3, program as program3 } from "commander";
2136
- import path8 from "pathe";
2137
- import * as v7 from "valibot";
2138
- var schema4 = v7.object({
2139
- dirs: v7.array(v7.string()),
2140
- includeBlocks: v7.array(v7.string()),
2141
- includeCategories: v7.array(v7.string()),
2142
- excludeDeps: v7.array(v7.string()),
2143
- output: v7.boolean(),
2144
- errorOnWarn: v7.boolean(),
2145
- verbose: v7.boolean(),
2146
- cwd: v7.string()
2147
- });
2148
- var build = new Command3("build").description(`Builds the provided --dirs in the project root into a \`${OUTPUT_FILE}\` file.`).option("--dirs [dirs...]", "The directories containing the blocks.", ["./blocks"]).option("--include-blocks [blockNames...]", "Include only the blocks with these names.", []).option(
2149
- "--include-categories [categoryNames...]",
2150
- "Include only the categories with these names.",
2151
- []
2152
- ).option("--exclude-deps [deps...]", "Dependencies that should not be added.", []).option("--no-output", `Do not output a \`${OUTPUT_FILE}\` file.`).option(
2153
- "--error-on-warn",
2154
- "If there is a warning throw an error and do not allow build to complete.",
2155
- false
2156
- ).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2157
- const options = v7.parse(schema4, opts);
2158
- _intro(context.package.version);
2159
- await _build(options);
2160
- outro3(color10.green("All done!"));
2161
- });
2162
- var _build = async (options) => {
2163
- const loading = spinner3();
2164
- const categories = [];
2165
- const outFile = path8.join(options.cwd, OUTPUT_FILE);
2166
- for (const dir of options.dirs) {
2167
- const dirPath = path8.join(options.cwd, dir);
2168
- loading.start(`Building ${color10.cyan(dirPath)}`);
2169
- if (options.output && fs8.existsSync(outFile)) fs8.rmSync(outFile);
2170
- const builtCategories = buildBlocksDirectory(dirPath, { ...options });
2171
- for (const category of builtCategories) {
2172
- if (categories.find((cat) => cat.name === category.name) !== void 0) {
2173
- const error = "a category with the same name already exists!";
2174
- if (options.errorOnWarn) {
2175
- program3.error(
2176
- color10.red(
2177
- `\`${color10.bold(`${dir}/${category.name}`)}\` could not be added because ${error}`
2178
- )
2179
- );
2180
- } else {
2181
- console.warn(
2182
- `${VERTICAL_LINE} ${WARN} Skipped adding \`${color10.cyan(`${dir}/${category.name}`)}\` because ${error}`
2183
- );
2184
- }
2185
- continue;
2186
- }
2187
- categories.push(category);
2188
- }
2189
- loading.stop(`Built ${color10.cyan(dirPath)}`);
2190
- }
2191
- loading.start("Checking manifest");
2192
- const warnings = [];
2193
- for (const category of categories) {
2194
- for (const block of category.blocks) {
2195
- for (const dep of block.localDependencies) {
2196
- const [depCategoryName, depBlockName] = dep.split("/");
2197
- const depCategory = categories.find(
2198
- (cat) => cat.name.trim() === depCategoryName.trim()
2199
- );
2200
- const invalidDependencyError = () => {
2201
- const error = `depends on ${color10.bold(dep)} which doesn't exist!`;
2202
- if (options.errorOnWarn) {
2203
- warnings.push(
2204
- color10.red(`${color10.bold(`${category.name}/${block.name}`)} ${error}`)
2205
- );
2206
- } else {
2207
- warnings.push(
2208
- `${VERTICAL_LINE} ${WARN} ${color10.bold(`${category.name}/${block.name}`)} ${error}`
2209
- );
2210
- }
2211
- };
2212
- if (!depCategory) {
2213
- invalidDependencyError();
2214
- continue;
2215
- }
2216
- if (depCategory.blocks.find((b) => b.name === depBlockName) === void 0) {
2217
- invalidDependencyError();
2218
- }
2219
- }
2220
- for (const dep of [...block.dependencies, ...block.devDependencies]) {
2221
- if (!dep.includes("@")) {
2222
- const error = `You haven't installed ${color10.bold(dep)} as a dependency so your users could get any version of it when they install your block!`;
2223
- if (options.errorOnWarn) {
2224
- warnings.push(color10.red(error));
2225
- } else {
2226
- warnings.push(`${VERTICAL_LINE} ${WARN} ${error}`);
2227
- }
2228
- }
2229
- }
2230
- }
2231
- }
2232
- loading.stop("Completed checking manifest.");
2233
- if (warnings.length > 0) {
2234
- for (const warning of warnings) {
2235
- console.log(warning);
2236
- }
2237
- if (options.errorOnWarn) {
2238
- program3.error("Had warnings while checking manifest.");
2239
- }
2240
- }
2241
- if (options.output) {
2242
- loading.start(`Writing output to \`${color10.cyan(outFile)}\``);
2243
- fs8.writeFileSync(outFile, JSON.stringify(categories, null, " "));
2244
- loading.stop(`Wrote output to \`${color10.cyan(outFile)}\``);
2245
- }
2246
- };
2247
-
2248
- // src/commands/diff.ts
2249
- import fs9 from "node:fs";
2250
- import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, spinner as spinner4 } from "@clack/prompts";
2251
- import color12 from "chalk";
2252
- import { Command as Command4, program as program4 } from "commander";
2253
- import { diffLines } from "diff";
2254
- import path9 from "pathe";
2255
- import * as v8 from "valibot";
2256
-
2257
- // src/utils/diff.ts
2258
- import color11 from "chalk";
2259
- import { diffChars } from "diff";
2260
-
2261
- // src/utils/blocks/utils/array-sum.ts
2262
- var arraySum = (arr, fn) => {
2263
- let total = 0;
2264
- for (const item of arr) {
2265
- total = total + fn(item);
2266
- }
2267
- return total;
2268
- };
2269
-
2270
- // src/utils/diff.ts
2271
- var isWhitespace = (str) => /^\s+$/g.test(str);
2272
- var trimSingleNewLine = (str) => {
2273
- let i = str.length - 1;
2274
- while (isWhitespace(str[i]) && i >= 0) {
2275
- if (str[i] === "\n") {
2276
- if (str[i - 1] === "\r") {
2277
- return str.slice(0, i - 1);
2278
- }
2279
- return str.slice(0, i);
2280
- }
2281
- i--;
2282
- }
2283
- return str;
2284
- };
2285
- var formatDiff = ({
2286
- from,
2287
- to,
2288
- changes,
2289
- expand = false,
2290
- maxUnchanged = 5,
2291
- colorRemoved = color11.red,
2292
- colorAdded = color11.green,
2293
- colorCharsRemoved = color11.bgRed,
2294
- colorCharsAdded = color11.bgGreen,
2295
- prefix,
2296
- onUnchanged,
2297
- intro: intro2
2298
- }) => {
2299
- let result = "";
2300
- const length = arraySum(changes, (change) => change.count ?? 0).toString().length + 1;
2301
- let lineOffset = 0;
2302
- if (changes.length === 1 && !changes[0].added && !changes[0].removed) {
2303
- return onUnchanged({
2304
- from,
2305
- to,
2306
- changes,
2307
- expand,
2308
- maxUnchanged,
2309
- colorAdded,
2310
- colorRemoved,
2311
- prefix,
2312
- onUnchanged,
2313
- intro: intro2
2314
- });
2315
- }
2316
- result += intro2({
2317
- from,
2318
- to,
2319
- changes,
2320
- expand,
2321
- maxUnchanged,
2322
- colorAdded,
2323
- colorRemoved,
2324
- prefix,
2325
- onUnchanged,
2326
- intro: intro2
2327
- });
2328
- const linePrefix = (line) => color11.gray(`${prefix?.() ?? ""}${leftPadMin(`${line + 1 + lineOffset} `, length)} `);
2329
- for (let i = 0; i < changes.length; i++) {
2330
- const change = changes[i];
2331
- const hasPreviousChange = changes[i - 1]?.added || changes[i - 1]?.removed;
2332
- const hasNextChange = changes[i + 1]?.added || changes[i + 1]?.removed;
2333
- if (!change.added && !change.removed) {
2334
- if (!expand && change.count !== void 0 && change.count > maxUnchanged) {
2335
- const prevLineOffset = lineOffset;
2336
- const ls = get(trimSingleNewLine(change.value));
2337
- let shownLines = 0;
2338
- if (hasNextChange) shownLines += maxUnchanged;
2339
- if (hasPreviousChange) shownLines += maxUnchanged;
2340
- if (shownLines >= ls.length) {
2341
- result += `${join(ls, {
2342
- prefix: linePrefix
2343
- })}
2344
- `;
2345
- lineOffset += ls.length;
2346
- continue;
2347
- }
2348
- if (hasPreviousChange) {
2349
- result += `${join(ls.slice(0, maxUnchanged), {
2350
- prefix: linePrefix
2351
- })}
2352
- `;
2353
- }
2354
- if (ls.length > shownLines) {
2355
- const count = ls.length - shownLines;
2356
- result += `${join(
2357
- get(
2358
- color11.gray(
2359
- `+ ${count} more unchanged (${color11.italic("-E to expand")})`
2360
- )
2361
- ),
2362
- {
2363
- prefix: () => `${prefix?.() ?? ""}${leftPadMin(" ", length)} `
2364
- }
2365
- )}
2366
- `;
2367
- }
2368
- if (hasNextChange) {
2369
- lineOffset = lineOffset + ls.length - maxUnchanged;
2370
- result += `${join(ls.slice(ls.length - maxUnchanged), {
2371
- prefix: linePrefix
2372
- })}
2373
- `;
2374
- }
2375
- lineOffset = prevLineOffset + change.count;
2376
- continue;
2377
- }
2378
- result += `${join(get(trimSingleNewLine(change.value)), {
2379
- prefix: linePrefix
2380
- })}
2381
- `;
2382
- lineOffset += change.count ?? 0;
2383
- continue;
2384
- }
2385
- const colorLineChange = (change2) => {
2386
- if (change2.added) {
2387
- return colorAdded(trimSingleNewLine(change2.value));
2388
- }
2389
- if (change2.removed) {
2390
- return colorRemoved(trimSingleNewLine(change2.value));
2391
- }
2392
- return change2.value;
2393
- };
2394
- const colorCharChange = (change2) => {
2395
- if (change2.added) {
2396
- return colorCharsAdded(trimSingleNewLine(change2.value));
2397
- }
2398
- if (change2.removed) {
2399
- return colorCharsRemoved(trimSingleNewLine(change2.value));
2400
- }
2401
- return change2.value;
2402
- };
2403
- if (change.removed && change.count === 1 && changes[i + 1]?.added && changes[i + 1]?.count === 1) {
2404
- const diffedChars = diffChars(change.value, changes[i + 1].value);
2405
- const sentence = diffedChars.map((chg) => colorCharChange(chg)).join("");
2406
- result += `${linePrefix(0)}${sentence}`;
2407
- lineOffset += 1;
2408
- i++;
2409
- } else {
2410
- if (isWhitespace(change.value)) {
2411
- result += `${join(get(colorCharChange(change)), {
2412
- prefix: (line) => `${linePrefix(line)}${colorCharChange({ removed: true, value: " ", added: false })}`
2413
- })}
2414
- `;
2415
- if (!change.removed) {
2416
- lineOffset += change.count ?? 0;
2417
- }
2418
- } else {
2419
- result += `${join(get(colorLineChange(change)), {
2420
- prefix: linePrefix
2421
- })}
2422
- `;
2423
- if (!change.removed) {
2424
- lineOffset += change.count ?? 0;
2425
- }
2426
- }
2427
- }
2428
- }
2429
- return result;
2430
- };
2431
-
2432
- // src/commands/diff.ts
2433
- var schema5 = v8.object({
2434
- expand: v8.boolean(),
2435
- maxUnchanged: v8.number(),
2436
- repo: v8.optional(v8.string()),
2437
- allow: v8.boolean(),
2438
- cwd: v8.string()
2439
- });
2440
- var diff = new Command4("diff").description("Compares local blocks to the blocks in the provided repository.").option("-E, --expand", "Expands the diff so you see everything.", false).option(
2441
- "--max-unchanged <number>",
2442
- "Maximum unchanged lines that will show without being collapsed.",
2443
- (val) => Number.parseInt(val),
2444
- // this is such a dumb api thing
2445
- 3
2446
- ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2447
- const options = v8.parse(schema5, opts);
2448
- _intro(context.package.version);
2449
- await _diff(options);
2450
- outro4(color12.green("All done!"));
2451
- });
2452
- var _diff = async (options) => {
2453
- const loading = spinner4();
2454
- const config = getConfig(options.cwd).match(
2455
- (val) => val,
2456
- (err) => program4.error(color12.red(err))
2457
- );
2458
- let repoPaths = config.repos;
2459
- if (options.repo) repoPaths = [options.repo];
2460
- if (!options.allow && options.repo) {
2461
- const result = await confirm3({
2462
- message: `Allow ${color12.cyan("jsrepo")} to download and run code from ${color12.cyan(options.repo)}?`,
2463
- initialValue: true
2464
- });
2465
- if (isCancel3(result) || !result) {
2466
- cancel3("Canceled!");
2467
- process.exit(0);
2468
- }
2469
- }
2470
- loading.start(`Fetching blocks from ${color12.cyan(repoPaths.join(", "))}`);
2471
- const blocksMap = (await fetchBlocks(...repoPaths)).match(
2472
- (val) => val,
2473
- ({ repo, message }) => {
2474
- loading.stop(`Failed fetching blocks from ${color12.cyan(repo)}`);
2475
- program4.error(color12.red(message));
2476
- }
2477
- );
2478
- loading.stop(`Retrieved blocks from ${color12.cyan(repoPaths.join(", "))}`);
2479
- const installedBlocks = getInstalled(blocksMap, config, options.cwd);
2480
- for (const blockSpecifier of installedBlocks) {
2481
- let found = false;
2482
- for (const repo of repoPaths) {
2483
- const providerInfo = (await getProviderInfo(repo)).unwrap();
2484
- const fullSpecifier = `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier.specifier}`;
2485
- const block = blocksMap.get(fullSpecifier);
2486
- if (block === void 0) continue;
2487
- const watermark = getWatermark(context.package.version, repo);
2488
- found = true;
2489
- process.stdout.write(`${VERTICAL_LINE}
2490
- `);
2491
- process.stdout.write(`${VERTICAL_LINE} ${fullSpecifier}
2492
- `);
2493
- for (const file of block.files) {
2494
- if (!config.includeTests && isTestFile(file)) continue;
2495
- process.stdout.write(`${VERTICAL_LINE}
2496
- `);
2497
- const sourcePath = path9.join(block.directory, file);
2498
- const response = await providerInfo.provider.fetchRaw(providerInfo, sourcePath);
2499
- if (response.isErr()) {
2500
- program4.error(color12.red(`There was an error trying to get ${fullSpecifier}`));
2501
- }
2502
- let remoteContent = response.unwrap();
2503
- const directory = path9.join(options.cwd, config.path, block.category);
2504
- let localPath = path9.join(directory, file);
2505
- let prettyLocalPath = path9.join(config.path, block.category, file);
2506
- if (block.subdirectory) {
2507
- localPath = path9.join(directory, block.name, file);
2508
- prettyLocalPath = path9.join(config.path, block.category, block.name, file);
2509
- }
2510
- let fileContent = "";
2511
- if (fs9.existsSync(localPath)) {
2512
- fileContent = fs9.readFileSync(localPath).toString();
2513
- }
2514
- if (config.watermark) {
2515
- const lang = languages.find((lang2) => lang2.matches(sourcePath));
2516
- if (lang) {
2517
- const comment = lang.comment(watermark);
2518
- remoteContent = `${comment}
2519
-
2520
- ${remoteContent}`;
2521
- }
2522
- }
2523
- const changes = diffLines(fileContent, remoteContent);
2524
- const from = path9.join(
2525
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}`,
2526
- sourcePath
2527
- );
2528
- const formattedDiff = formatDiff({
2529
- from,
2530
- to: prettyLocalPath,
2531
- changes,
2532
- expand: options.expand,
2533
- maxUnchanged: options.maxUnchanged,
2534
- colorAdded: color12.greenBright,
2535
- colorRemoved: color12.redBright,
2536
- colorCharsAdded: color12.bgGreenBright,
2537
- colorCharsRemoved: color12.bgRedBright,
2538
- prefix: () => `${VERTICAL_LINE} `,
2539
- onUnchanged: ({ from: from2, to, prefix }) => `${prefix?.() ?? ""}${color12.cyan(from2)} \u2192 ${color12.gray(to)} ${color12.gray("(unchanged)")}
2540
- `,
2541
- intro: ({ from: from2, to, changes: changes2, prefix }) => {
2542
- const totalChanges = changes2.filter((a) => a.added).length;
2543
- return `${prefix?.() ?? ""}${color12.cyan(from2)} \u2192 ${color12.gray(to)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
2544
- ${prefix?.() ?? ""}
2545
- `;
2546
- }
2547
- });
2548
- process.stdout.write(formattedDiff);
2549
- }
2550
- break;
2551
- }
2552
- if (!found) {
2553
- program4.error(
2554
- color12.red(`Invalid block! ${color12.bold(blockSpecifier)} does not exist!`)
2555
- );
2556
- }
2557
- }
2558
- };
2559
-
2560
- // src/commands/init.ts
2561
- import fs10 from "node:fs";
2562
- import { cancel as cancel4, confirm as confirm4, isCancel as isCancel4, outro as outro5, password as password2, select as select2, spinner as spinner5, text as text2 } from "@clack/prompts";
2563
- import color13 from "chalk";
2564
- import { Command as Command5, Option as Option2, program as program5 } from "commander";
2565
- import { detect as detect2, resolveCommand as resolveCommand3 } from "package-manager-detector";
2566
- import path10 from "pathe";
2567
- import * as v9 from "valibot";
2568
- var schema6 = v9.object({
2569
- path: v9.optional(v9.string()),
2570
- repos: v9.optional(v9.array(v9.string())),
2571
- watermark: v9.boolean(),
2572
- tests: v9.optional(v9.boolean()),
2573
- formatter: v9.optional(formatterSchema),
2574
- project: v9.optional(v9.boolean()),
2575
- registry: v9.optional(v9.boolean()),
2576
- script: v9.string(),
2577
- yes: v9.boolean(),
2578
- cwd: v9.string()
2579
- });
2580
- var init = new Command5("init").description("Initializes your project with a configuration file.").option("--path <path>", "Path to install the blocks / Path to build the blocks from.").option("--repos [repos...]", "Repository to install the blocks from.").option(
2581
- "--no-watermark",
2582
- "Will not add a watermark to each file upon adding it to your project."
2583
- ).option("--tests", "Will include tests with the blocks.").addOption(
2584
- new Option2(
2585
- "--formatter <formatter>",
2586
- "What formatter to use when adding or updating blocks."
2587
- ).choices(["prettier", "biome"])
2588
- ).option("-P, --project", "Takes you through the steps to initialize a project.").option("-R, --registry", "Takes you through the steps to initialize a registry.").option("--script <name>", "The name of the build script. (For Registry setup)", "build").option("-y, --yes", "Skip confirmation prompt.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2589
- const options = v9.parse(schema6, opts);
2590
- _intro(context.package.version);
2591
- if (options.registry !== void 0 && options.project !== void 0) {
2592
- program5.error(
2593
- color13.red(
2594
- `You cannot provide both ${color13.bold("--project")} and ${color13.bold("--registry")} at the same time.`
2595
- )
2596
- );
2597
- }
2598
- if (options.registry === void 0 && options.project === void 0) {
2599
- const response = await select2({
2600
- message: "Initialize a project or registry?",
2601
- options: [
2602
- { value: "project", label: "project" },
2603
- { value: "registry", label: "registry" }
2604
- ],
2605
- initialValue: "project"
2606
- });
2607
- if (isCancel4(response)) {
2608
- cancel4("Canceled!");
2609
- process.exit(0);
2610
- }
2611
- options.registry = response === "registry";
2612
- }
2613
- if (options.registry) {
2614
- await _initRegistry(options);
2615
- } else {
2616
- await _initProject(options);
2617
- }
2618
- outro5(color13.green("All done!"));
2619
- });
2620
- var _initProject = async (options) => {
2621
- const storage = get2();
2622
- const initialConfig = getConfig(options.cwd);
2623
- const loading = spinner5();
2624
- if (!options.path) {
2625
- const result = await text2({
2626
- message: "Where should we add the blocks?",
2627
- validate(value) {
2628
- if (value.trim() === "") return "Please provide a value";
2629
- },
2630
- initialValue: initialConfig.isOk() ? initialConfig.unwrap().path : "src/blocks"
2631
- });
2632
- if (isCancel4(result)) {
2633
- cancel4("Canceled!");
2634
- process.exit(0);
2635
- }
2636
- options.path = result;
2637
- }
2638
- if (!options.repos) {
2639
- options.repos = initialConfig.isOk() ? initialConfig.unwrap().repos : [];
2640
- while (true) {
2641
- const confirmResult = await confirm4({
2642
- message: `Add ${options.repos.length > 0 ? "another" : "a"} repo?`,
2643
- initialValue: options.repos.length === 0
2644
- // default to yes for first repo
2645
- });
2646
- if (isCancel4(confirmResult)) {
2647
- cancel4("Canceled!");
2648
- process.exit(0);
2649
- }
2650
- if (!confirmResult) break;
2651
- const result = await text2({
2652
- message: "Where should we download the blocks from?",
2653
- placeholder: "github/ieedan/std",
2654
- validate: (val) => {
2655
- if (val.trim().length === 0) return "Please provide a value";
2656
- if (!providers.find((provider2) => provider2.matches(val))) {
2657
- return `Invalid provider! Valid providers (${providers.map((provider2) => provider2.name()).join(", ")})`;
2658
- }
2659
- }
2660
- });
2661
- if (isCancel4(result)) {
2662
- cancel4("Canceled!");
2663
- process.exit(0);
2664
- }
2665
- const provider = providers.find((p) => p.matches(result));
2666
- if (!provider) {
2667
- program5.error(color13.red("Invalid provider!"));
2668
- }
2669
- const tokenKey = `${provider.name()}-token`;
2670
- const token = storage.get(tokenKey);
2671
- if (!token) {
2672
- const result2 = await confirm4({
2673
- message: "Would you like to add an auth token?",
2674
- initialValue: false
2675
- });
2676
- if (isCancel4(result2)) {
2677
- cancel4("Canceled!");
2678
- process.exit(0);
2679
- }
2680
- if (result2) {
2681
- const response = await password2({
2682
- message: "Paste your token",
2683
- validate(value) {
2684
- if (value.trim() === "") return "Please provide a value";
2685
- }
2686
- });
2687
- if (isCancel4(response)) {
2688
- cancel4("Canceled!");
2689
- process.exit(0);
2690
- }
2691
- storage.set(tokenKey, response);
2692
- }
2693
- }
2694
- options.repos.push(result);
2695
- }
2696
- }
2697
- if (!options.formatter) {
2698
- let defaultFormatter = initialConfig.isErr() ? "none" : initialConfig.unwrap().formatter ?? "none";
2699
- if (fs10.existsSync(path10.join(options.cwd, ".prettierrc"))) {
2700
- defaultFormatter = "prettier";
2701
- }
2702
- if (fs10.existsSync(path10.join(options.cwd, "biome.json"))) {
2703
- defaultFormatter = "biome";
2704
- }
2705
- const response = await select2({
2706
- message: "What formatter would you like to use?",
2707
- options: ["Prettier", "Biome", "None"].map((val) => ({
2708
- value: val.toLowerCase(),
2709
- label: val
2710
- })),
2711
- initialValue: defaultFormatter
2712
- });
2713
- if (isCancel4(response)) {
2714
- cancel4("Canceled!");
2715
- process.exit(0);
2716
- }
2717
- if (response !== "none") {
2718
- options.formatter = response;
2719
- }
2720
- }
2721
- const config = {
2722
- $schema: `https://unpkg.com/jsrepo@${context.package.version}/schema.json`,
2723
- repos: options.repos,
2724
- path: options.path,
2725
- includeTests: initialConfig.isOk() && options.tests === void 0 ? initialConfig.unwrap().includeTests : options.tests ?? false,
2726
- watermark: options.watermark,
2727
- formatter: options.formatter
2728
- };
2729
- loading.start(`Writing config to \`${CONFIG_NAME}\``);
2730
- fs10.writeFileSync(
2731
- path10.join(options.cwd, CONFIG_NAME),
2732
- `${JSON.stringify(config, null, " ")}
2733
- `
2734
- );
2735
- fs10.mkdirSync(path10.join(options.cwd, config.path), { recursive: true });
2736
- loading.stop(`Wrote config to \`${CONFIG_NAME}\`.`);
2737
- };
2738
- var _initRegistry = async (options) => {
2739
- const loading = spinner5();
2740
- const packagePath = path10.join(options.cwd, "package.json");
2741
- if (!fs10.existsSync(packagePath)) {
2742
- program5.error(color13.red(`Couldn't find your ${color13.bold("package.json")}!`));
2743
- }
2744
- if (!options.path) {
2745
- const response = await text2({
2746
- message: "Where are your blocks located?",
2747
- defaultValue: "./blocks",
2748
- initialValue: "./blocks",
2749
- placeholder: "./blocks"
2750
- });
2751
- if (isCancel4(response)) {
2752
- cancel4("Canceled!");
2753
- process.exit(0);
2754
- }
2755
- options.path = response;
2756
- }
2757
- const pkg = JSON.parse(fs10.readFileSync(packagePath).toString());
2758
- const scriptAlreadyExists = pkg.scripts !== void 0 && pkg.scripts[options.script] !== void 0;
2759
- if (!options.yes && scriptAlreadyExists) {
2760
- const response = await confirm4({
2761
- message: `The \`${color13.cyan(options.script)}\` already exists overwrite?`,
2762
- initialValue: false
2763
- });
2764
- if (isCancel4(response)) {
2765
- cancel4("Canceled!");
2766
- process.exit(0);
2767
- }
2768
- if (!response) {
2769
- const response2 = await text2({
2770
- message: "What would you like to call the script?",
2771
- defaultValue: "build:registry",
2772
- placeholder: "build:registry",
2773
- initialValue: "build:registry",
2774
- validate: (val) => {
2775
- if (val.trim().length === 0) return "Please provide a value!";
2776
- }
2777
- });
2778
- if (isCancel4(response2)) {
2779
- cancel4("Canceled!");
2780
- process.exit(0);
2781
- }
2782
- options.script = response2;
2783
- }
2784
- }
2785
- const alreadyInstalled = pkg.devDependencies && pkg.devDependencies.jsrepo !== void 0;
2786
- let installAsDevDependency = options.yes || alreadyInstalled;
2787
- if (!options.yes && !alreadyInstalled) {
2788
- const response = await confirm4({
2789
- message: `Add ${JSREPO} as a dev dependency?`,
2790
- initialValue: true
2791
- });
2792
- if (isCancel4(response)) {
2793
- cancel4("Canceled!");
2794
- process.exit(0);
2795
- }
2796
- installAsDevDependency = response;
2797
- }
2798
- const pm = (await detect2({ cwd: "cwd" }))?.agent ?? "npm";
2799
- let buildScript = "";
2800
- if (installAsDevDependency) {
2801
- buildScript += "jsrepo build ";
2802
- } else {
2803
- const command = resolveCommand3(pm, "execute", ["jsrepo", "build"]);
2804
- if (!command) program5.error(color13.red(`Error resolving execute command for ${pm}`));
2805
- buildScript += `${command.command} ${command.args.join(" ")} `;
2806
- }
2807
- if (options.path !== "./build") {
2808
- buildScript += `--dirs ${options.path}`;
2809
- }
2810
- if (pkg.scripts === void 0) {
2811
- pkg.scripts = {};
2812
- }
2813
- pkg.scripts[options.script] = buildScript;
2814
- loading.start(`Adding \`${color13.cyan(options.script)}\` to scripts in package.json`);
2815
- try {
2816
- fs10.writeFileSync(packagePath, JSON.stringify(pkg, null, " "));
2817
- } catch (err) {
2818
- program5.error(color13.red(`Error writing to \`${color13.bold(packagePath)}\`. Error: ${err}`));
2819
- }
2820
- loading.stop(`Added \`${color13.cyan(options.script)}\` to scripts in package.json`);
2821
- let installed = alreadyInstalled;
2822
- if (installAsDevDependency && !alreadyInstalled) {
2823
- let shouldInstall = options.yes;
2824
- if (!options.yes) {
2825
- const response = await confirm4({
2826
- message: "Install dependencies?",
2827
- initialValue: true
2828
- });
2829
- if (isCancel4(response)) {
2830
- cancel4("Canceled!");
2831
- process.exit(0);
2832
- }
2833
- shouldInstall = response;
2834
- }
2835
- if (shouldInstall) {
2836
- loading.start(`Installing ${JSREPO}`);
2837
- const installedResult = await installDependencies({
2838
- pm,
2839
- deps: ["jsrepo"],
2840
- dev: true,
2841
- cwd: options.cwd
2842
- });
2843
- installedResult.match(
2844
- () => loading.stop(`Installed ${JSREPO}.`),
2845
- (err) => {
2846
- loading.stop(`Failed to install ${JSREPO}.`);
2847
- program5.error(err);
2848
- }
2849
- );
2850
- installed = true;
2851
- }
2852
- }
2853
- let steps = [];
2854
- if (!installed && installAsDevDependency) {
2855
- const cmd = resolveCommand3(pm, "install", ["jsrepo", "-D"]);
2856
- steps.push(
2857
- `Install ${JSREPO} as a dev dependency \`${color13.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2858
- );
2859
- }
2860
- steps.push(`Add blocks to \`${color13.cyan(options.path)}\`.`);
2861
- const runScript = resolveCommand3(pm, "run", [options.script]);
2862
- steps.push(
2863
- `Run \`${color13.cyan(`${runScript?.command} ${runScript?.args.join(" ")}`)}\` to build the registry.`
2864
- );
2865
- steps = steps.map((step, i) => `${i + 1}. ${step}`);
2866
- const next = nextSteps(steps);
2867
- process.stdout.write(next);
2868
- };
2869
-
2870
- // src/commands/test.ts
2871
- import fs11 from "node:fs";
2872
- import { cancel as cancel5, confirm as confirm5, isCancel as isCancel5, outro as outro6, spinner as spinner6 } from "@clack/prompts";
2873
- import color14 from "chalk";
2874
- import { Argument, Command as Command6, program as program6 } from "commander";
2875
- import { execa as execa2 } from "execa";
2876
- import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2877
- import { detect as detect3 } from "package-manager-detector/detect";
2878
- import path11 from "pathe";
2879
- import { Project as Project2 } from "ts-morph";
2880
- import * as v10 from "valibot";
2881
- var schema7 = v10.object({
2882
- repo: v10.optional(v10.string()),
2883
- allow: v10.boolean(),
2884
- debug: v10.boolean(),
2885
- verbose: v10.boolean(),
2886
- cwd: v10.string()
2887
- });
2888
- var test = new Command6("test").description("Tests local blocks against most recent remote tests.").addArgument(new Argument("[blocks...]", "The blocks you want to test.").default([])).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--debug", "Leaves the temp test file around for debugging upon failure.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
2889
- const options = v10.parse(schema7, opts);
2890
- _intro(context.package.version);
2891
- await _test(blockNames, options);
2892
- outro6(color14.green("All done!"));
2893
- });
2894
- var _test = async (blockNames, options) => {
2895
- const verbose = (msg) => {
2896
- if (options.verbose) {
2897
- console.info(`${INFO} ${msg}`);
2898
- }
2899
- };
2900
- verbose(`Attempting to test ${JSON.stringify(blockNames)}`);
2901
- const config = getConfig(options.cwd).match(
2902
- (val) => val,
2903
- (err) => program6.error(color14.red(err))
2904
- );
2905
- const loading = spinner6();
2906
- const blocksMap = /* @__PURE__ */ new Map();
2907
- let repoPaths = config.repos;
2908
- if (options.repo) repoPaths = [options.repo];
2909
- if (!options.allow && options.repo) {
2910
- const result = await confirm5({
2911
- message: `Allow ${color14.cyan("jsrepo")} to download and run code from ${color14.cyan(options.repo)}?`,
2912
- initialValue: true
2913
- });
2914
- if (isCancel5(result) || !result) {
2915
- cancel5("Canceled!");
2916
- process.exit(0);
2917
- }
2918
- }
2919
- verbose(`Fetching blocks from ${color14.cyan(repoPaths.join(", "))}`);
2920
- if (!options.verbose) loading.start(`Fetching blocks from ${color14.cyan(repoPaths.join(", "))}`);
2921
- for (const repo of repoPaths) {
2922
- const providerInfo = (await getProviderInfo(repo)).match(
2923
- (info) => info,
2924
- (err) => program6.error(color14.red(err))
2925
- );
2926
- const manifest = await providerInfo.provider.fetchManifest(providerInfo);
2927
- verbose(`Got info for provider ${color14.cyan(providerInfo.name)}`);
2928
- if (manifest.isErr()) {
2929
- if (!options.verbose) loading.stop(`Error fetching ${color14.cyan(repo)}`);
2930
- program6.error(
2931
- color14.red(
2932
- `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color14.cyan(
2933
- repo
2934
- )} make sure the target repository has a \`${OUTPUT_FILE}\` in its root?`
2935
- )
2936
- );
2937
- }
2938
- const categories = manifest.unwrap();
2939
- for (const category of categories) {
2940
- for (const block of category.blocks) {
2941
- blocksMap.set(
2942
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
2943
- {
2944
- ...block,
2945
- sourceRepo: providerInfo
2946
- }
2947
- );
2948
- }
2949
- }
2950
- }
2951
- verbose(`Retrieved blocks from ${color14.cyan(repoPaths.join(", "))}`);
2952
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color14.cyan(repoPaths.join(", "))}`);
2953
- const tempTestDirectory = path11.resolve(
2954
- path11.join(options.cwd, `blocks-tests-temp-${Date.now()}`)
2955
- );
2956
- verbose(`Trying to create the temp directory ${color14.bold(tempTestDirectory)}.`);
2957
- fs11.mkdirSync(tempTestDirectory, { recursive: true });
2958
- const cleanUp = () => {
2959
- fs11.rmSync(tempTestDirectory, { recursive: true, force: true });
2960
- };
2961
- const installedBlocks = getInstalled(blocksMap, config, options.cwd).map(
2962
- (val) => val.specifier
2963
- );
2964
- let testingBlocks = blockNames;
2965
- if (blockNames.length === 0) {
2966
- testingBlocks = installedBlocks;
2967
- }
2968
- if (testingBlocks.length === 0) {
2969
- cleanUp();
2970
- program6.error(color14.red("There were no blocks found in your project!"));
2971
- }
2972
- const testingBlocksMapped = [];
2973
- for (const blockSpecifier of testingBlocks) {
2974
- let block = void 0;
2975
- if (!providers.find((p) => blockSpecifier.startsWith(p.name()))) {
2976
- for (const repo of repoPaths) {
2977
- const providerInfo = (await getProviderInfo(repo)).unwrap();
2978
- const tempBlock = blocksMap.get(
2979
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier}`
2980
- );
2981
- if (tempBlock === void 0) continue;
2982
- block = tempBlock;
2983
- break;
2984
- }
2985
- } else {
2986
- if (repoPaths.length === 0) {
2987
- const [providerName, owner, repoName, ...rest] = blockSpecifier.split("/");
2988
- let repo;
2989
- if (rest.length > 2) {
2990
- repo = `${providerName}/${owner}/${repoName}/${rest.slice(0, rest.length - 2).join("/")}`;
2991
- } else {
2992
- repo = `${providerName}/${owner}/${repoName}`;
2993
- }
2994
- const providerInfo = (await getProviderInfo(repo)).match(
2995
- (val) => val,
2996
- (err) => program6.error(color14.red(err))
2997
- );
2998
- const categories = (await providerInfo.provider.fetchManifest(providerInfo)).match(
2999
- (val) => val,
3000
- (err) => program6.error(color14.red(err))
3001
- );
3002
- for (const category of categories) {
3003
- for (const block2 of category.blocks) {
3004
- blocksMap.set(
3005
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block2.name}`,
3006
- {
3007
- ...block2,
3008
- sourceRepo: providerInfo
3009
- }
3010
- );
3011
- }
3012
- }
3013
- }
3014
- block = blocksMap.get(blockSpecifier);
3015
- }
3016
- if (!block) {
3017
- program6.error(
3018
- color14.red(`Invalid block! ${color14.bold(blockSpecifier)} does not exist!`)
3019
- );
3020
- }
3021
- testingBlocksMapped.push({ name: blockSpecifier, block });
3022
- }
3023
- for (const { block } of testingBlocksMapped) {
3024
- const providerInfo = block.sourceRepo;
3025
- const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
3026
- if (!options.verbose) {
3027
- loading.start(`Setting up test file for ${color14.cyan(fullSpecifier)}`);
3028
- }
3029
- if (!block.tests) {
3030
- loading.stop(`No tests found for ${color14.cyan(fullSpecifier)}`);
3031
- continue;
3032
- }
3033
- const getSourceFile = async (filePath) => {
3034
- const content = await providerInfo.provider.fetchRaw(providerInfo, filePath);
3035
- if (content.isErr()) {
3036
- loading.stop(color14.red(`Error fetching ${color14.bold(filePath)}`));
3037
- program6.error(color14.red(`There was an error trying to get ${fullSpecifier}`));
3038
- }
3039
- return content.unwrap();
3040
- };
3041
- verbose(`Downloading and copying test files for ${fullSpecifier}`);
3042
- const testFiles = [];
3043
- for (const testFile of block.files.filter((file) => isTestFile(file))) {
3044
- const content = await getSourceFile(path11.join(block.directory, testFile));
3045
- const destPath = path11.join(tempTestDirectory, testFile);
3046
- fs11.writeFileSync(destPath, content);
3047
- testFiles.push(destPath);
3048
- }
3049
- const project = new Project2();
3050
- for (const file of testFiles) {
3051
- verbose(`Opening test file ${file}`);
3052
- const tempFile = project.addSourceFileAtPath(file);
3053
- for (const importDeclaration of tempFile.getImportDeclarations()) {
3054
- const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
3055
- let newModuleSpecifier = void 0;
3056
- if (moduleSpecifier.startsWith(".")) {
3057
- if (block.subdirectory) {
3058
- newModuleSpecifier = path11.join(
3059
- "../",
3060
- config.path,
3061
- block.category,
3062
- block.name,
3063
- moduleSpecifier
3064
- );
3065
- } else {
3066
- newModuleSpecifier = path11.join(
3067
- "../",
3068
- config.path,
3069
- block.category,
3070
- moduleSpecifier
3071
- );
3072
- }
3073
- }
3074
- if (newModuleSpecifier) {
3075
- importDeclaration.setModuleSpecifier(newModuleSpecifier.replaceAll(/\\/g, "/"));
3076
- }
3077
- }
3078
- }
3079
- project.saveSync();
3080
- verbose(`Completed ${color14.cyan.bold(fullSpecifier)} test file`);
3081
- if (!options.verbose) {
3082
- loading.stop(`Completed setup for ${color14.bold(fullSpecifier)}`);
3083
- }
3084
- }
3085
- verbose("Beginning testing");
3086
- const pm = await detect3({ cwd: options.cwd });
3087
- if (pm == null) {
3088
- program6.error(color14.red("Could not detect package manager"));
3089
- }
3090
- const resolved = resolveCommand4(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
3091
- if (resolved == null) {
3092
- program6.error(color14.red(`Could not resolve add command for '${pm.agent}'.`));
3093
- }
3094
- const { command, args } = resolved;
3095
- const testCommand = `${command} ${args.join(" ")}`;
3096
- const testingProcess = execa2({
3097
- cwd: options.cwd,
3098
- stdio: ["ignore", "pipe", "pipe"]
3099
- })`${testCommand}`;
3100
- const handler = (data) => console.info(data.toString());
3101
- testingProcess.stdout.on("data", handler);
3102
- testingProcess.stderr.on("data", handler);
3103
- try {
3104
- await testingProcess;
3105
- cleanUp();
3106
- } catch (err) {
3107
- if (options.debug) {
3108
- console.info(
3109
- `${color14.bold("--debug")} flag provided. Skipping cleanup. Run '${color14.bold(
3110
- testCommand
3111
- )}' to retry tests.
3112
- `
3113
- );
3114
- } else {
3115
- cleanUp();
3116
- }
3117
- program6.error(color14.red(`Tests failed! Error ${err}`));
3118
- }
3119
- };
3120
-
3121
- // src/commands/update.ts
3122
- import fs12 from "node:fs";
3123
- import { cancel as cancel6, confirm as confirm6, isCancel as isCancel6, multiselect as multiselect2, outro as outro7, spinner as spinner7 } from "@clack/prompts";
3124
- import color15 from "chalk";
3125
- import { Command as Command7, program as program7 } from "commander";
3126
- import { diffLines as diffLines2 } from "diff";
3127
- import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
3128
- import { detect as detect4 } from "package-manager-detector/detect";
3129
- import path12 from "pathe";
3130
- import * as v11 from "valibot";
3131
- var schema8 = v11.object({
3132
- all: v11.boolean(),
3133
- expand: v11.boolean(),
3134
- maxUnchanged: v11.number(),
3135
- repo: v11.optional(v11.string()),
3136
- allow: v11.boolean(),
3137
- yes: v11.boolean(),
3138
- verbose: v11.boolean(),
3139
- cwd: v11.string()
3140
- });
3141
- var update = new Command7("update").argument("[blocks...]", "Names of the blocks you want to update. ex: (utils/math)").option("--all", "Update all installed components.", false).option("-E, --expand", "Expands the diff so you see everything.", false).option(
3142
- "--max-unchanged <number>",
3143
- "Maximum unchanged lines that will show without being collapsed.",
3144
- (val) => Number.parseInt(val),
3145
- // this is such a dumb api thing
3146
- 3
3147
- ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("-y, --yes", "Skip confirmation prompt.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
3148
- const options = v11.parse(schema8, opts);
3149
- _intro(context.package.version);
3150
- await _update(blockNames, options);
3151
- outro7(color15.green("All done!"));
3152
- });
3153
- var _update = async (blockNames, options) => {
3154
- const verbose = (msg) => {
3155
- if (options.verbose) {
3156
- console.info(`${INFO} ${msg}`);
3157
- }
3158
- };
3159
- verbose(`Attempting to update ${JSON.stringify(blockNames)}`);
3160
- const loading = spinner7();
3161
- const config = getConfig(options.cwd).match(
3162
- (val) => val,
3163
- (err) => program7.error(color15.red(err))
3164
- );
3165
- let repoPaths = config.repos;
3166
- if (options.repo) repoPaths = [options.repo];
3167
- for (const blockSpecifier of blockNames) {
3168
- if (providers.find((p) => blockSpecifier.startsWith(p.name()))) {
3169
- program7.error(
3170
- color15.red(
3171
- `Invalid value provided for block names \`${color15.bold(blockSpecifier)}\`. Block names are expected to be provided in the format of \`${color15.bold("<category>/<name>")}\``
3172
- )
3173
- );
3174
- }
3175
- }
3176
- if (!options.allow && options.repo) {
3177
- const result = await confirm6({
3178
- message: `Allow ${color15.cyan("jsrepo")} to download and run code from ${color15.cyan(options.repo)}?`,
3179
- initialValue: true
3180
- });
3181
- if (isCancel6(result) || !result) {
3182
- cancel6("Canceled!");
3183
- process.exit(0);
3184
- }
3185
- }
3186
- verbose(`Fetching blocks from ${color15.cyan(repoPaths.join(", "))}`);
3187
- if (!options.verbose) loading.start(`Fetching blocks from ${color15.cyan(repoPaths.join(", "))}`);
3188
- const blocksMap = (await fetchBlocks(...repoPaths)).match(
3189
- (val) => val,
3190
- ({ repo, message }) => {
3191
- loading.stop(`Failed fetching blocks from ${color15.cyan(repo)}`);
3192
- program7.error(color15.red(message));
3193
- }
3194
- );
3195
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color15.cyan(repoPaths.join(", "))}`);
3196
- verbose(`Retrieved blocks from ${color15.cyan(repoPaths.join(", "))}`);
3197
- const installedBlocks = getInstalled(blocksMap, config, options.cwd);
3198
- if (installedBlocks.length === 0) {
3199
- program7.error(
3200
- color15.red(
3201
- `You haven't installed any blocks yet. Did you mean to \`${color15.bold("add")}\`?`
3202
- )
3203
- );
3204
- }
3205
- let updatingBlockNames = blockNames;
3206
- if (options.all) {
3207
- updatingBlockNames = installedBlocks.map((block) => block.specifier);
3208
- }
3209
- if (updatingBlockNames.length === 0) {
3210
- const promptResult = await multiselect2({
3211
- message: "Which blocks would you like to update?",
3212
- options: installedBlocks.map((block) => {
3213
- return {
3214
- label: `${color15.cyan(block.block.category)}/${block.block.name}`,
3215
- value: block.specifier
3216
- };
3217
- }),
3218
- required: true
3219
- });
3220
- if (isCancel6(promptResult)) {
3221
- cancel6("Canceled!");
3222
- process.exit(0);
3223
- }
3224
- updatingBlockNames = promptResult;
3225
- }
3226
- verbose(`Preparing to update ${color15.cyan(updatingBlockNames.join(", "))}`);
3227
- const updatingBlocks = (await resolveTree(updatingBlockNames, blocksMap, repoPaths)).match(
3228
- (val) => val,
3229
- program7.error
3230
- );
3231
- const pm = (await detect4({ cwd: options.cwd }))?.agent ?? "npm";
3232
- const tasks = [];
3233
- let devDeps = /* @__PURE__ */ new Set();
3234
- let deps = /* @__PURE__ */ new Set();
3235
- const { prettierOptions, biomeOptions } = await loadFormatterConfig({
3236
- formatter: config.formatter,
3237
- cwd: options.cwd
3238
- });
3239
- for (const { block } of updatingBlocks) {
3240
- const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
3241
- const watermark = getWatermark(context.package.version, block.sourceRepo.url);
3242
- const providerInfo = block.sourceRepo;
3243
- verbose(`Attempting to add ${fullSpecifier}`);
3244
- const directory = path12.join(options.cwd, config.path, block.category);
3245
- const files = [];
3246
- const getSourceFile = async (filePath) => {
3247
- const content = await providerInfo.provider.fetchRaw(providerInfo, filePath, {
3248
- verbose
3249
- });
3250
- if (content.isErr()) {
3251
- loading.stop(color15.red(`Error fetching ${color15.bold(filePath)}`));
3252
- program7.error(color15.red(`There was an error trying to get ${fullSpecifier}`));
3253
- }
3254
- return content.unwrap();
3255
- };
3256
- for (const sourceFile of block.files) {
3257
- if (!config.includeTests && isTestFile(sourceFile)) continue;
3258
- const sourcePath = path12.join(block.directory, sourceFile);
3259
- let destPath;
3260
- if (block.subdirectory) {
3261
- destPath = path12.join(directory, block.name, sourceFile);
3262
- } else {
3263
- destPath = path12.join(directory, sourceFile);
3264
- }
3265
- const content = await getSourceFile(sourcePath);
3266
- fs12.mkdirSync(destPath.slice(0, destPath.length - sourceFile.length), {
3267
- recursive: true
3268
- });
3269
- files.push({ content, destPath, fileName: sourceFile });
3270
- }
3271
- process.stdout.write(`${VERTICAL_LINE}
3272
- `);
3273
- process.stdout.write(`${VERTICAL_LINE} ${fullSpecifier}
3274
- `);
3275
- for (const file of files) {
3276
- const lang = languages.find((lang2) => lang2.matches(file.destPath));
3277
- let remoteContent = file.content;
3278
- if (lang) {
3279
- if (config.watermark) {
3280
- const comment = lang.comment(watermark);
3281
- remoteContent = `${comment}
3282
-
3283
- ${remoteContent}`;
3284
- }
3285
- remoteContent = await lang.format(remoteContent, {
3286
- filePath: file.destPath,
3287
- formatter: config.formatter,
3288
- prettierOptions,
3289
- biomeOptions
3290
- });
3291
- }
3292
- let acceptedChanges = options.yes;
3293
- if (!options.yes) {
3294
- process.stdout.write(`${VERTICAL_LINE}
3295
- `);
3296
- let localContent = "";
3297
- if (fs12.existsSync(file.destPath)) {
3298
- localContent = fs12.readFileSync(file.destPath).toString();
3299
- }
3300
- const changes = diffLines2(localContent, remoteContent);
3301
- const from = path12.join(
3302
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}`,
3303
- file.fileName
3304
- );
3305
- const to = path12.relative(options.cwd, file.destPath);
3306
- const formattedDiff = formatDiff({
3307
- from,
3308
- to,
3309
- changes,
3310
- expand: options.expand,
3311
- maxUnchanged: options.maxUnchanged,
3312
- colorAdded: color15.greenBright,
3313
- colorRemoved: color15.redBright,
3314
- colorCharsAdded: color15.bgGreenBright,
3315
- colorCharsRemoved: color15.bgRedBright,
3316
- prefix: () => `${VERTICAL_LINE} `,
3317
- onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color15.cyan(from2)} \u2192 ${color15.gray(to2)} ${color15.gray("(unchanged)")}
3318
- `,
3319
- intro: ({ from: from2, to: to2, changes: changes2, prefix }) => {
3320
- const totalChanges = changes2.filter((a) => a.added).length;
3321
- return `${prefix?.() ?? ""}${color15.cyan(from2)} \u2192 ${color15.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
3322
- ${prefix?.() ?? ""}
3323
- `;
3324
- }
3325
- });
3326
- process.stdout.write(formattedDiff);
3327
- if (changes.length > 1 || localContent === "") {
3328
- const confirmResult = await confirm6({
3329
- message: "Accept changes?",
3330
- initialValue: true
3331
- });
3332
- if (isCancel6(confirmResult)) {
3333
- cancel6("Canceled!");
3334
- process.exit(0);
3335
- }
3336
- acceptedChanges = confirmResult;
3337
- }
3338
- }
3339
- if (acceptedChanges) {
3340
- await runTasks(
3341
- [
3342
- {
3343
- loadingMessage: `Writing changes to ${color15.cyan(file.destPath)}`,
3344
- completedMessage: `Wrote changes to ${color15.cyan(file.destPath)}.`,
3345
- run: async () => fs12.writeFileSync(file.destPath, remoteContent)
3346
- }
3347
- ],
3348
- {
3349
- verbose: options.verbose ? verbose : void 0
3350
- }
3351
- );
3352
- }
3353
- }
3354
- if (config.includeTests && block.tests) {
3355
- verbose("Trying to include tests");
3356
- const { devDependencies } = JSON.parse(
3357
- fs12.readFileSync(path12.join(options.cwd, "package.json")).toString()
3358
- );
3359
- if (devDependencies === void 0 || devDependencies.vitest === void 0) {
3360
- devDeps.add("vitest");
3361
- }
3362
- }
3363
- for (const dep of block.devDependencies) {
3364
- devDeps.add(dep);
3365
- }
3366
- for (const dep of block.dependencies) {
3367
- deps.add(dep);
3368
- }
3369
- }
3370
- await runTasks(tasks, { verbose: options.verbose ? verbose : void 0 });
3371
- const requiredDependencies = returnShouldInstall(deps, devDeps, { cwd: options.cwd });
3372
- deps = requiredDependencies.dependencies;
3373
- devDeps = requiredDependencies.devDependencies;
3374
- const hasDependencies = deps.size > 0 || devDeps.size > 0;
3375
- if (hasDependencies) {
3376
- let install = options.yes;
3377
- if (!options.yes) {
3378
- const result = await confirm6({
3379
- message: "Would you like to install dependencies?",
3380
- initialValue: true
3381
- });
3382
- if (isCancel6(result)) {
3383
- cancel6("Canceled!");
3384
- process.exit(0);
3385
- }
3386
- install = result;
3387
- }
3388
- if (install) {
3389
- if (deps.size > 0) {
3390
- if (!options.verbose)
3391
- loading.start(`Installing dependencies with ${color15.cyan(pm)}`);
3392
- (await installDependencies({
3393
- pm,
3394
- deps: Array.from(deps),
3395
- dev: false,
3396
- cwd: options.cwd
3397
- })).match(
3398
- (installed) => {
3399
- if (!options.verbose)
3400
- loading.stop(`Installed ${color15.cyan(installed.join(", "))}`);
3401
- },
3402
- (err) => {
3403
- if (!options.verbose) loading.stop("Failed to install dependencies");
3404
- program7.error(err);
3405
- }
3406
- );
3407
- }
3408
- if (devDeps.size > 0) {
3409
- if (!options.verbose)
3410
- loading.start(`Installing dependencies with ${color15.cyan(pm)}`);
3411
- (await installDependencies({
3412
- pm,
3413
- deps: Array.from(devDeps),
3414
- dev: true,
3415
- cwd: options.cwd
3416
- })).match(
3417
- (installed) => {
3418
- if (!options.verbose)
3419
- loading.stop(`Installed ${color15.cyan(installed.join(", "))}`);
3420
- },
3421
- (err) => {
3422
- if (!options.verbose) loading.stop("Failed to install dev dependencies");
3423
- program7.error(err);
3424
- }
3425
- );
3426
- }
3427
- }
3428
- let steps = [];
3429
- if (!install) {
3430
- if (deps.size > 0) {
3431
- const cmd = resolveCommand5(pm, "install", [...deps]);
3432
- steps.push(
3433
- `Install dependencies \`${color15.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
3434
- );
3435
- }
3436
- if (devDeps.size > 0) {
3437
- const cmd = resolveCommand5(pm, "install", [...devDeps, "-D"]);
3438
- steps.push(
3439
- `Install dev dependencies \`${color15.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
3440
- );
3441
- }
3442
- }
3443
- steps = steps.map((step, i) => `${i + 1}. ${step}`);
3444
- if (!install) {
3445
- steps.push("");
3446
- }
3447
- steps.push(`Import the blocks from \`${color15.cyan(config.path)}\``);
3448
- const next = nextSteps(steps);
3449
- process.stdout.write(next);
3450
- }
3451
- };
3452
-
3453
- // src/index.ts
3454
- var resolveRelativeToRoot = (p) => {
3455
- const dirname = fileURLToPath(import.meta.url);
3456
- return path13.join(dirname, "../..", p);
3457
- };
3458
- var { version, name, description, repository } = JSON.parse(
3459
- fs13.readFileSync(resolveRelativeToRoot("package.json"), "utf-8")
3460
- );
3461
- var context = {
3462
- package: {
3463
- name,
3464
- description,
3465
- version,
3466
- repository
3467
- },
3468
- resolveRelativeToRoot
3469
- };
3470
- console.clear();
3471
- program8.name(name).description(description).version(version).addCommand(add).addCommand(auth).addCommand(init).addCommand(test).addCommand(build).addCommand(update).addCommand(diff);
3472
- program8.parse();
3473
- export {
3474
- context
3475
- };
15
+ `),H={name:()=>"github",defaultBranch:()=>"main",resolveRaw:async(t,e)=>{let r=await H.info(t);return new URL(e,`https://raw.githubusercontent.com/${r.owner}/${r.repoName}/refs/${r.refs}/${r.ref}/`)},fetchRaw:async(t,e,{verbose:r}={})=>{let o=await H.info(t),n=await H.resolveRaw(o,e);r?.(`Trying to fetch from ${n}`);try{let i=ye().get(`${H.name()}-token`),s=new Headers;i!==void 0&&s.append("Authorization",`token ${i}`);let a=await xt(n,{headers:s});return r?.(`Got a response from ${n} ${a.status} ${a.statusText}`),a.ok?O(await a.text()):Ve(o,e,H.defaultBranch())}catch(i){return r?.(`erroring in response ${i} `),Ve(o,e,H.defaultBranch())}},fetchManifest:async t=>{let e=await H.fetchRaw(t,ce);if(e.isErr())return P(e.unwrapErr());let r=B.parse(B.array(at),JSON.parse(e.unwrap()));return O(r)},info:async t=>{if(typeof t!="string")return t;let e=t.replaceAll(/(https:\/\/github.com\/)|(github\/)/g,""),[r,o,...n]=e.split("/"),i=H.defaultBranch(),s=ye().get(`${H.name()}-token`),a=new Octokit({auth:s});if(n[0]==="tree")i=n[1];else try{let{data:h}=await a.rest.repos.get({owner:r,repo:o});i=h.default_branch;}catch{}let d="heads";if(i!==H.defaultBranch())try{let{data:h}=await a.rest.git.listMatchingRefs({owner:r,repo:o,ref:"tags"});h.some(f=>f.ref===`refs/tags/${i}`)&&(d="tags");}catch{d="heads";}return {refs:d,url:t,name:H.name(),repoName:o,owner:r,ref:i,provider:H}},matches:t=>t.toLowerCase().startsWith("https://github.com")||t.toLowerCase().startsWith("github")},ue={name:()=>"gitlab",defaultBranch:()=>"main",resolveRaw:async(t,e)=>{let r=await ue.info(t);return new URL(`${encodeURIComponent(e)}/raw?ref=${r.ref}`,`https://gitlab.com/api/v4/projects/${encodeURIComponent(`${r.owner}/${r.repoName}`)}/repository/files/`)},fetchRaw:async(t,e,{verbose:r}={})=>{let o=await H.info(t),n=await ue.resolveRaw(o,e);r?.(`Trying to fetch from ${n}`);try{let i=ye().get(`${ue.name()}-token`),s=new Headers;i!==void 0&&s.append("PRIVATE-TOKEN",`${i}`);let a=await xt(n,{headers:s});return r?.(`Got a response from ${n} ${a.status} ${a.statusText}`),a.ok?O(await a.text()):Ve(o,e,ue.defaultBranch())}catch{return Ve(o,e,ue.defaultBranch())}},fetchManifest:async t=>{let e=await ue.fetchRaw(t,ce);if(e.isErr())return P(e.unwrapErr());let r=B.parse(B.array(at),JSON.parse(e.unwrap()));return O(r)},info:async t=>{if(typeof t!="string")return t;let e=t.replaceAll(/(https:\/\/gitlab.com\/)|(gitlab\/)/g,""),[r,o,...n]=e.split("/"),i=ue.defaultBranch(),s="heads";if(n[0]==="-"&&n[1]==="tree")if(n[2].includes("?")){let[a,d]=n[2].split("?");i=a,d.startsWith("ref_type=")&&d.slice(10)==="tags"&&(s="tags");}else i=n[2];return {refs:s,url:t,name:ue.name(),repoName:o,owner:r,ref:i,provider:ue}},matches:t=>t.toLowerCase().startsWith("https://gitlab.com")||t.toLowerCase().startsWith("gitlab")},le={name:()=>"bitbucket",defaultBranch:()=>"master",resolveRaw:async(t,e)=>{let r=await le.info(t);return new URL(e,`https://api.bitbucket.org/2.0/repositories/${r.owner}/${r.repoName}/src/${r.ref}/`)},fetchRaw:async(t,e,{verbose:r}={})=>{let o=await le.info(t),n=await le.resolveRaw(o,e);r?.(`Trying to fetch from ${n}`);try{let i=ye().get(`${le.name()}-token`),s=new Headers;i!==void 0&&s.append("Authorization",`Bearer ${i}`);let a=await xt(n,{headers:s});return r?.(`Got a response from ${n} ${a.status} ${a.statusText}`),a.ok?O(await a.text()):Ve(o,e,le.defaultBranch())}catch{return Ve(o,e,le.defaultBranch())}},fetchManifest:async t=>{let e=await le.fetchRaw(t,ce);if(e.isErr())return P(e.unwrapErr());let r=B.parse(B.array(at),JSON.parse(e.unwrap()));return O(r)},info:async t=>{if(typeof t!="string")return t;let e=t.replaceAll(/(https:\/\/bitbucket.org\/)|(bitbucket\/)/g,""),[r,o,...n]=e.split("/"),i="heads",s=le.defaultBranch();return n[0]==="src"&&(s=n[1]),{refs:i,url:t,name:le.name(),repoName:o,owner:r,ref:s,provider:le}},matches:t=>t.toLowerCase().startsWith("https://bitbucket.org")||t.toLowerCase().startsWith("bitbucket")},_=[H,ue,le],ve=async t=>{let e=_.find(r=>r.matches(t));return e?O(await e.info(t)):P(`Only ${_.map((r,o)=>`${o===_.length-1?"and":""}${I.cyan(r.name())}`).join(", ")} repositories are supported at this time!`)},Me=async(...t)=>{let e=new Map;for(let r of t){let o=await ve(r);if(o.isErr())return P({message:o.unwrapErr(),repo:r});let n=o.unwrap(),i=await n.provider.fetchManifest(n);if(i.isErr())return P({message:i.unwrapErr(),repo:r});let s=i.unwrap();for(let a of s)for(let d of a.blocks)e.set(`${n.name}/${n.owner}/${n.repoName}/${a.name}/${d.name}`,{...d,sourceRepo:n});}return O(e)};var Qe=async(t,e,r)=>{let o=new Map;for(let n of t){let i;if(_.find(a=>n.startsWith(a.name()))){let[a,d,h,...f]=n.split("/");i=e.get(`${a}/${d}/${h}/${f.slice(f.length-2).join("/")}`);}else {if(r.length===0)return P(I.red(`If your config doesn't repos then you must provide the repo in the block specifier ex: \`${I.bold(`github/<owner>/<name>/${n}`)}\`!`));for(let a of r){let d=(await ve(a)).unwrap(),h=e.get(`${d.name}/${d.owner}/${d.repoName}/${n}`);if(h!==void 0){i=h;break}}}if(!i)return P(`Invalid block! ${I.bold(n)} does not exist!`);let s=`${i.category}/${i.name}`;if(o.set(s,{name:i.name,subDependency:!1,block:i}),i.localDependencies&&i.localDependencies.length>0){let a=await Qe(i.localDependencies.filter(d=>!o.has(d)),e,r);if(a.isErr())return P(a.unwrapErr());for(let d of a.unwrap())o.set(d.name,d);}}return O(Gt(o,(n,i)=>i))},ke=(t,e,r)=>{let o=[];for(let[n,i]of t){let s=J.join(r,e.path,i.category),a=J.join(s,i.files[0]);i.subdirectory&&(a=J.join(s,i.name)),Ne.existsSync(a)&&o.push({specifier:`${i.category}/${i.name}`,path:a,block:i});}return o};var Se="jsrepo.json",St=B.union([B.literal("prettier"),B.literal("biome")]),zr=B.object({$schema:B.string(),repos:B.optional(B.array(B.string()),[]),includeTests:B.boolean(),path:B.pipe(B.string(),B.minLength(1)),watermark:B.optional(B.boolean(),!0),formatter:B.optional(St)}),ge=t=>{if(!Ne.existsSync(J.join(t,Se)))return P("Could not find your configuration file! Please run `init`.");let e=B.safeParse(zr,JSON.parse(Ne.readFileSync(J.join(t,Se)).toString()));return e.success?O(e.output):P(`There was an error reading your \`${Se}\` file!`)};var Re=async({pm:t,deps:e,dev:r,cwd:o})=>{let n;if(r?n=resolveCommand$1(t,"install",[...e,"-D"]):n=resolveCommand$1(t,"install",[...e]),n==null)return P(I.red(`Could not resolve add command for '${t}'.`));try{return await execa(n.command,[...n.args],{cwd:o}),O(e)}catch{return P(I.red(`Failed to install ${I.bold(e.join(", "))}! Failed while running '${I.bold(`${n.command} ${n.args.join(" ")}`)}'`))}};var lt=async({formatter:t,cwd:e})=>{let r=null;t==="prettier"&&(r=await Xe.resolveConfig(J.join(e,".prettierrc")));let o=null;if(t==="biome"){let n=J.join(e,"biome.json");Ne.existsSync(n)&&(o=JSON.parse(Ne.readFileSync(n).toString()));}return {biomeOptions:o,prettierOptions:r}};var Je=(t,e)=>`jsrepo ${t}
16
+ Installed from ${e}
17
+ ${new Date().toLocaleDateString().replaceAll("/","-")}`;var et=async(t,{verbose:e=void 0})=>{let r=spinner();for(let o of t){e?e(o.loadingMessage):r.start(o.loadingMessage);try{await o.run();}catch(n){r.stop(`Error while ${o.loadingMessage}`),console.error(n);}e?e(o.completedMessage):r.stop(o.completedMessage);}},Ue=t=>{let e=20;t.map(n=>{let i=Ht(xe(n),4);i.length>e&&(e=i.length);});let r="Next Steps",o=`${N}
18
+ `;return o+=`${vt} ${r} ${yt.repeat(e-r.length-1)}${Ut}
19
+ `,o+=`${N} ${" ".repeat(e)} ${N}
20
+ `,t.map(n=>{o+=`${N} ${Kt(n,e-1)} ${N}
21
+ `;}),o+=`${N} ${" ".repeat(e)} ${N}
22
+ `,o+=`${vt}${yt.repeat(e+2)}${zt}
23
+ `,o},K=t=>intro(`${I.bgHex("#f7df1e").black(" jsrepo ")}${I.gray(` v${t} `)}`);var to=B.object({repo:B.optional(B.string()),allow:B.boolean(),yes:B.boolean(),verbose:B.boolean(),cwd:B.string()}),jt=new Command("add").argument("[blocks...]","Names of the blocks you want to add to your project. ex: (utils/math, github/ieedan/std/utils/math)").option("--repo <repo>","Repository to download the blocks from.").option("-A, --allow","Allow jsrepo to download code from the provided repo.",!1).option("-y, --yes","Skip confirmation prompt.",!1).option("--verbose","Include debug logs.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async(t,e)=>{let r=B.parse(to,e);K(M.package.version),await ro(t,r),outro(I.green("All done!"));}),ro=async(t,e)=>{let r=l=>{e.verbose&&console.info(`${Le} ${l}`);};r(`Attempting to add ${JSON.stringify(t)}`);let o=spinner(),n=ge(e.cwd),i=n.isErr(),s;if(n.isErr()){let l=await confirm({message:`You don't have ${fe} initialized in your project. Do you want to continue?`,initialValue:!1});(isCancel(l)||!l)&&(cancel("Canceled!"),process.exit(0)),s={$schema:"",includeTests:!1,watermark:!0,path:"./src/blocks",repos:[]};}else s=n.unwrap();let a=s.repos;e.repo&&(a=[e.repo]);for(let l of t){if(!_.find(C=>l.startsWith(C.name())))continue;let[p,c,y,...R]=l.split("/"),u;if(R.length>2?u=`${p}/${c}/${y}/${R.slice(0,R.length-2).join("/")}`:u=`${p}/${c}/${y}`,!a.find(C=>C===u)){if(!e.allow){let C=await confirm({message:`Allow ${fe} to download and run code from ${I.cyan(u)}?`,initialValue:!0});(isCancel(C)||!C)&&(cancel("Canceled!"),process.exit(0));}a.push(u);}}if(!e.allow&&e.repo){let l=await confirm({message:`Allow ${fe} to download and run code from ${I.cyan(e.repo)}?`,initialValue:!0});(isCancel(l)||!l)&&(cancel("Canceled!"),process.exit(0));}a.length===0&&(i&&program.error(I.red(`Fully quality blocks ex: (github/ieedan/std/utils/math) or provide the \`${I.bold("--repo")}\` flag to specify a registry.`)),program.error(I.red(`There were no repos present in your config and you didn't provide the \`${I.bold("--repo")}\` flag with a repo.`))),r(`Fetching blocks from ${I.cyan(a.join(", "))}`),e.verbose||o.start(`Fetching blocks from ${I.cyan(a.join(", "))}`);let d=(await Me(...a)).match(l=>l,({repo:l,message:p})=>{o.stop(`Failed fetching blocks from ${I.cyan(l)}`),program.error(I.red(p));});e.verbose||o.stop(`Retrieved blocks from ${I.cyan(a.join(", "))}`),r(`Retrieved blocks from ${I.cyan(a.join(", "))}`);let h=ke(d,s,e.cwd).map(l=>l.specifier),f=t;if(f.length===0){let l=await multiselect({message:"Select which blocks to add.",options:Array.from(d.entries()).map(([p,c])=>{let y=`${c.category}/${c.name}`,R=h.findIndex(C=>C===y)!==-1,u;return a.length>1?u=`${I.cyan(`${c.sourceRepo.name}/${c.sourceRepo.owner}/${c.sourceRepo.repoName}/${c.category}`)}/${c.name}`:u=`${I.cyan(c.category)}/${c.name}`,{label:R?I.gray(u):u,value:p,hint:R?"Installed":void 0}}),required:!0});isCancel(l)&&(cancel("Canceled!"),process.exit(0)),f=l;}r(`Installing blocks ${I.cyan(f.join(", "))}`),e.verbose&&console.log("Blocks map: ",d);let $=(await Qe(f,d,a)).match(l=>l,l=>program.error(l)),v=(await detect({cwd:e.cwd}))?.agent??"npm",m=[],b=new Set,S=new Set;if(i){let l=await text({message:"Where would you like to add the blocks?",initialValue:s.path,defaultValue:s.path,placeholder:s.path,validate(p){if(p.trim()==="")return "Please provide a value"}});if(isCancel(l)&&(cancel("Canceled!"),process.exit(0)),s.path=l,!e.yes){let p=await confirm({message:"Include tests?",initialValue:s.includeTests});isCancel(p)&&(cancel("Canceled!"),process.exit(0)),s.includeTests=p;let c=await confirm({message:"Add watermark?",initialValue:s.watermark});isCancel(c)&&(cancel("Canceled!"),process.exit(0)),s.watermark=c;}}let{prettierOptions:j,biomeOptions:T}=await lt({formatter:s.formatter,cwd:e.cwd});for(let{block:l}of $){let p=`${l.sourceRepo.url}/${l.category}/${l.name}`,c=`${l.category}/${l.name}`,y=Je(M.package.version,l.sourceRepo.url),R=l.sourceRepo;r(`Setting up ${p}`);let u=J.join(e.cwd,s.path,l.category);if((!l.subdirectory&&Ne.existsSync(J.join(u,l.files[0]))||l.subdirectory&&Ne.existsSync(J.join(u,l.name)))&&!e.yes){let k=await confirm({message:`${I.cyan(c)} already exists in your project would you like to overwrite it?`,initialValue:!1});(isCancel(k)||!k)&&(cancel("Canceled!"),process.exit(0));}m.push({loadingMessage:`Adding ${p}`,completedMessage:`Added ${p}`,run:async()=>{r(`Creating directory ${I.bold(u)}`),Ne.mkdirSync(u,{recursive:!0}),r(`Created directory ${I.bold(u)}`);let k=[],F=async x=>{let X=await R.provider.fetchRaw(R,x,{verbose:r});return X.isErr()&&(o.stop(I.red(`Error fetching ${I.bold(x)}`)),program.error(I.red(`There was an error trying to get ${p}`))),X.unwrap()};for(let x of l.files){if(!s.includeTests&&ae(x))continue;let X=J.join(l.directory,x),Z;l.subdirectory?Z=J.join(u,l.name,x):Z=J.join(u,x),r(`Adding ${I.bold(X)}`);let Fe=await F(X),Ye=Z.slice(0,Z.length-x.length);r(`Creating directory ${I.bold(Ye)}`),Ne.mkdirSync(Ye,{recursive:!0}),r(`Created directory ${I.bold(Ye)}`),k.push({content:Fe,destPath:Z}),r(`Got ${I.bold(X)}`);}for(let x of k){let X=he.find(Fe=>Fe.matches(x.destPath)),Z=x.content;X&&(s.watermark&&(Z=`${X.comment(y)}
24
+
25
+ ${Z}`),r(`Formatting ${I.bold(x.destPath)}`),Z=await X.format(Z,{filePath:x.destPath,formatter:s.formatter,prettierOptions:j,biomeOptions:T})),r(`Writing to ${I.bold(x.destPath)}`),Ne.writeFileSync(x.destPath,Z);}if(s.includeTests&&l.tests){r("Trying to include tests");let{devDependencies:x}=JSON.parse(Ne.readFileSync(J.join(e.cwd,"package.json")).toString());(x===void 0||x.vitest===void 0)&&b.add("vitest");}for(let x of l.devDependencies)b.add(x);for(let x of l.dependencies)S.add(x);}});}await et(m,{verbose:e.verbose?r:void 0});let w=it(S,b,{cwd:e.cwd});if(S=w.dependencies,b=w.devDependencies,S.size>0||b.size>0){let l=e.yes;if(!e.yes){let y=await confirm({message:"Would you like to install dependencies?",initialValue:!0});isCancel(y)&&(cancel("Canceled!"),process.exit(0)),l=y;}l&&(S.size>0&&(e.verbose||o.start(`Installing dependencies with ${I.cyan(v)}`),(await Re({pm:v,deps:Array.from(S),dev:!1,cwd:e.cwd})).match(y=>{e.verbose||o.stop(`Installed ${I.cyan(y.join(", "))}`);},y=>{e.verbose||o.stop("Failed to install dependencies"),program.error(y);})),b.size>0&&(e.verbose||o.start(`Installing dependencies with ${I.cyan(v)}`),(await Re({pm:v,deps:Array.from(b),dev:!0,cwd:e.cwd})).match(y=>{e.verbose||o.stop(`Installed ${I.cyan(y.join(", "))}`);},y=>{e.verbose||o.stop("Failed to install dev dependencies"),program.error(y);})));let p=[];if(!l){if(S.size>0){let y=resolveCommand(v,"install",[...S]);p.push(`Install dependencies \`${I.cyan(`${y?.command} ${y?.args.join(" ")}`)}\``);}if(b.size>0){let y=resolveCommand(v,"install",[...b,"-D"]);p.push(`Install dev dependencies \`${I.cyan(`${y?.command} ${y?.args.join(" ")}`)}\``);}}p=p.map((y,R)=>`${R+1}. ${y}`),l||p.push(""),p.push(`Import the blocks from \`${I.cyan(s.path)}\``);let c=Ue(p);process.stdout.write(c);}};var lo=B.object({token:B.optional(B.string()),provider:B.optional(B.string()),logout:B.boolean(),cwd:B.string()}),At=new Command("auth").description("Provide a token for access to private repositories.").option("--token <token>","The token to use for authenticating to your provider.").addOption(new Option("--provider <name>","The provider this token belongs to.").choices(_.map(t=>t.name()))).option("--logout","Erase tokens from each provider from storage.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async t=>{let e=B.parse(lo,t);K(M.package.version),await po(e),outro(I.green("All done!"));}),po=async t=>{let e=ye();if(t.logout){for(let r of _){let o=`${r.name()}-token`;if(e.get(o)===void 0){process.stdout.write(`${N}
26
+ `),process.stdout.write(I.gray(`${N} Already logged out of ${r.name()}.
27
+ `));continue}let n=await confirm({message:`Remove ${r.name()} token?`,initialValue:!0});isCancel(n)&&(cancel("Canceled!"),process.exit(0)),n&&e.delete(o);}return}if(_.length>1){let r=await select({message:"Which provider is this token for?",options:_.map(o=>({label:o.name(),value:o.name()})),initialValue:_[0].name()});isCancel(r)&&(cancel("Canceled!"),process.exit(0)),t.provider=r;}else t.provider=_[0].name();if(t.token===void 0){let r=await password({message:"Paste your token",validate(o){if(o.trim()==="")return "Please provide a value"}});(isCancel(r)||!r)&&(cancel("Canceled!"),process.exit(0)),t.token=r;}e.set(`${t.provider}-token`,t.token);};var go=B.object({dirs:B.array(B.string()),includeBlocks:B.array(B.string()),includeCategories:B.array(B.string()),excludeDeps:B.array(B.string()),output:B.boolean(),errorOnWarn:B.boolean(),verbose:B.boolean(),cwd:B.string()}),Nt=new Command("build").description(`Builds the provided --dirs in the project root into a \`${ce}\` file.`).option("--dirs [dirs...]","The directories containing the blocks.",["./blocks"]).option("--include-blocks [blockNames...]","Include only the blocks with these names.",[]).option("--include-categories [categoryNames...]","Include only the categories with these names.",[]).option("--exclude-deps [deps...]","Dependencies that should not be added.",[]).option("--no-output",`Do not output a \`${ce}\` file.`).option("--error-on-warn","If there is a warning throw an error and do not allow build to complete.",!1).option("--verbose","Include debug logs.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async t=>{let e=B.parse(go,t);K(M.package.version),await ho(e),outro(I.green("All done!"));}),ho=async t=>{let e=spinner(),r=[],o=J.join(t.cwd,ce);for(let i of t.dirs){let s=J.join(t.cwd,i);e.start(`Building ${I.cyan(s)}`),t.output&&Ne.existsSync(o)&&Ne.rmSync(o);let a=tr(s,{...t});for(let d of a){if(r.find(h=>h.name===d.name)!==void 0){let h="a category with the same name already exists!";t.errorOnWarn?program.error(I.red(`\`${I.bold(`${i}/${d.name}`)}\` could not be added because ${h}`)):console.warn(`${N} ${ie} Skipped adding \`${I.cyan(`${i}/${d.name}`)}\` because ${h}`);continue}r.push(d);}e.stop(`Built ${I.cyan(s)}`);}e.start("Checking manifest");let n=[];for(let i of r)for(let s of i.blocks){for(let a of s.localDependencies){let[d,h]=a.split("/"),f=r.find(v=>v.name.trim()===d.trim()),$=()=>{let v=`depends on ${I.bold(a)} which doesn't exist!`;t.errorOnWarn?n.push(I.red(`${I.bold(`${i.name}/${s.name}`)} ${v}`)):n.push(`${N} ${ie} ${I.bold(`${i.name}/${s.name}`)} ${v}`);};if(!f){$();continue}f.blocks.find(v=>v.name===h)===void 0&&$();}for(let a of [...s.dependencies,...s.devDependencies])if(!a.includes("@")){let d=`You haven't installed ${I.bold(a)} as a dependency so your users could get any version of it when they install your block!`;t.errorOnWarn?n.push(I.red(d)):n.push(`${N} ${ie} ${d}`);}}if(e.stop("Completed checking manifest."),n.length>0){for(let i of n)console.log(i);t.errorOnWarn&&program.error("Had warnings while checking manifest.");}t.output&&(e.start(`Writing output to \`${I.cyan(o)}\``),Ne.writeFileSync(o,JSON.stringify(r,null," ")),e.stop(`Wrote output to \`${I.cyan(o)}\``));};var mr=(t,e)=>{let r=0;for(let o of t)r=r+e(o);return r};var ur=t=>/^\s+$/g.test(t),Ge=t=>{let e=t.length-1;for(;ur(t[e])&&e>=0;){if(t[e]===`
28
+ `)return t[e-1]==="\r"?t.slice(0,e-1):t.slice(0,e);e--;}return t},dt=({from:t,to:e,changes:r,expand:o=!1,maxUnchanged:n=5,colorRemoved:i=I.red,colorAdded:s=I.green,colorCharsRemoved:a=I.bgRed,colorCharsAdded:d=I.bgGreen,prefix:h,onUnchanged:f,intro:$})=>{let v="",m=mr(r,j=>j.count??0).toString().length+1,b=0;if(r.length===1&&!r[0].added&&!r[0].removed)return f({from:t,to:e,changes:r,expand:o,maxUnchanged:n,colorAdded:s,colorRemoved:i,prefix:h,onUnchanged:f,intro:$});v+=$({from:t,to:e,changes:r,expand:o,maxUnchanged:n,colorAdded:s,colorRemoved:i,prefix:h,onUnchanged:f,intro:$});let S=j=>I.gray(`${h?.()??""}${qe(`${j+1+b} `,m)} `);for(let j=0;j<r.length;j++){let T=r[j],w=r[j-1]?.added||r[j-1]?.removed,g=r[j+1]?.added||r[j+1]?.removed;if(!T.added&&!T.removed){if(!o&&T.count!==void 0&&T.count>n){let c=b,y=se(Ge(T.value)),R=0;if(g&&(R+=n),w&&(R+=n),R>=y.length){v+=`${Q(y,{prefix:S})}
29
+ `,b+=y.length;continue}if(w&&(v+=`${Q(y.slice(0,n),{prefix:S})}
30
+ `),y.length>R){let u=y.length-R;v+=`${Q(se(I.gray(`+ ${u} more unchanged (${I.italic("-E to expand")})`)),{prefix:()=>`${h?.()??""}${qe(" ",m)} `})}
31
+ `;}g&&(b=b+y.length-n,v+=`${Q(y.slice(y.length-n),{prefix:S})}
32
+ `),b=c+T.count;continue}v+=`${Q(se(Ge(T.value)),{prefix:S})}
33
+ `,b+=T.count??0;continue}let l=c=>c.added?s(Ge(c.value)):c.removed?i(Ge(c.value)):c.value,p=c=>c.added?d(Ge(c.value)):c.removed?a(Ge(c.value)):c.value;if(T.removed&&T.count===1&&r[j+1]?.added&&r[j+1]?.count===1){let y=diffChars(T.value,r[j+1].value).map(R=>p(R)).join("");v+=`${S(0)}${y}`,b+=1,j++;}else ur(T.value)?(v+=`${Q(se(p(T)),{prefix:c=>`${S(c)}${p({removed:!0,value:" ",added:!1})}`})}
34
+ `,T.removed||(b+=T.count??0)):(v+=`${Q(se(l(T)),{prefix:S})}
35
+ `,T.removed||(b+=T.count??0));}return v};var xo=B.object({expand:B.boolean(),maxUnchanged:B.number(),repo:B.optional(B.string()),allow:B.boolean(),cwd:B.string()}),Dt=new Command("diff").description("Compares local blocks to the blocks in the provided repository.").option("-E, --expand","Expands the diff so you see everything.",!1).option("--max-unchanged <number>","Maximum unchanged lines that will show without being collapsed.",t=>Number.parseInt(t),3).option("--repo <repo>","Repository to download the blocks from.").option("-A, --allow","Allow jsrepo to download code from the provided repo.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async t=>{let e=B.parse(xo,t);K(M.package.version),await Io(e),outro(I.green("All done!"));}),Io=async t=>{let e=spinner(),r=ge(t.cwd).match(s=>s,s=>program.error(I.red(s))),o=r.repos;if(t.repo&&(o=[t.repo]),!t.allow&&t.repo){let s=await confirm({message:`Allow ${I.cyan("jsrepo")} to download and run code from ${I.cyan(t.repo)}?`,initialValue:!0});(isCancel(s)||!s)&&(cancel("Canceled!"),process.exit(0));}e.start(`Fetching blocks from ${I.cyan(o.join(", "))}`);let n=(await Me(...o)).match(s=>s,({repo:s,message:a})=>{e.stop(`Failed fetching blocks from ${I.cyan(s)}`),program.error(I.red(a));});e.stop(`Retrieved blocks from ${I.cyan(o.join(", "))}`);let i=ke(n,r,t.cwd);for(let s of i){let a=!1;for(let d of o){let h=(await ve(d)).unwrap(),f=`${h.name}/${h.owner}/${h.repoName}/${s.specifier}`,$=n.get(f);if($===void 0)continue;let v=Je(M.package.version,d);a=!0,process.stdout.write(`${N}
36
+ `),process.stdout.write(`${N} ${f}
37
+ `);for(let m of $.files){if(!r.includeTests&&ae(m))continue;process.stdout.write(`${N}
38
+ `);let b=J.join($.directory,m),S=await h.provider.fetchRaw(h,b);S.isErr()&&program.error(I.red(`There was an error trying to get ${f}`));let j=S.unwrap(),T=J.join(t.cwd,r.path,$.category),w=J.join(T,m),g=J.join(r.path,$.category,m);$.subdirectory&&(w=J.join(T,$.name,m),g=J.join(r.path,$.category,$.name,m));let l="";if(Ne.existsSync(w)&&(l=Ne.readFileSync(w).toString()),r.watermark){let R=he.find(u=>u.matches(b));R&&(j=`${R.comment(v)}
39
+
40
+ ${j}`);}let p=diffLines(l,j),c=J.join(`${h.name}/${h.owner}/${h.repoName}`,b),y=dt({from:c,to:g,changes:p,expand:t.expand,maxUnchanged:t.maxUnchanged,colorAdded:I.greenBright,colorRemoved:I.redBright,colorCharsAdded:I.bgGreenBright,colorCharsRemoved:I.bgRedBright,prefix:()=>`${N} `,onUnchanged:({from:R,to:u,prefix:C})=>`${C?.()??""}${I.cyan(R)} \u2192 ${I.gray(u)} ${I.gray("(unchanged)")}
41
+ `,intro:({from:R,to:u,changes:C,prefix:k})=>{let F=C.filter(x=>x.added).length;return `${k?.()??""}${I.cyan(R)} \u2192 ${I.gray(u)} (${F} change${F===1?"":"s"})
42
+ ${k?.()??""}
43
+ `}});process.stdout.write(y);}break}a||program.error(I.red(`Invalid block! ${I.bold(s)} does not exist!`));}};var Ao=B.object({path:B.optional(B.string()),repos:B.optional(B.array(B.string())),watermark:B.boolean(),tests:B.optional(B.boolean()),formatter:B.optional(St),project:B.optional(B.boolean()),registry:B.optional(B.boolean()),script:B.string(),yes:B.boolean(),cwd:B.string()}),Bt=new Command("init").description("Initializes your project with a configuration file.").option("--path <path>","Path to install the blocks / Path to build the blocks from.").option("--repos [repos...]","Repository to install the blocks from.").option("--no-watermark","Will not add a watermark to each file upon adding it to your project.").option("--tests","Will include tests with the blocks.").addOption(new Option("--formatter <formatter>","What formatter to use when adding or updating blocks.").choices(["prettier","biome"])).option("-P, --project","Takes you through the steps to initialize a project.").option("-R, --registry","Takes you through the steps to initialize a registry.").option("--script <name>","The name of the build script. (For Registry setup)","build").option("-y, --yes","Skip confirmation prompt.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async t=>{let e=B.parse(Ao,t);if(K(M.package.version),e.registry!==void 0&&e.project!==void 0&&program.error(I.red(`You cannot provide both ${I.bold("--project")} and ${I.bold("--registry")} at the same time.`)),e.registry===void 0&&e.project===void 0){let r=await select({message:"Initialize a project or registry?",options:[{value:"project",label:"project"},{value:"registry",label:"registry"}],initialValue:"project"});isCancel(r)&&(cancel("Canceled!"),process.exit(0)),e.registry=r==="registry";}e.registry?await No(e):await Po(e),outro(I.green("All done!"));}),Po=async t=>{let e=ye(),r=ge(t.cwd),o=spinner();if(!t.path){let i=await text({message:"Where should we add the blocks?",validate(s){if(s.trim()==="")return "Please provide a value"},initialValue:r.isOk()?r.unwrap().path:"src/blocks"});isCancel(i)&&(cancel("Canceled!"),process.exit(0)),t.path=i;}if(!t.repos)for(t.repos=r.isOk()?r.unwrap().repos:[];;){let i=await confirm({message:`Add ${t.repos.length>0?"another":"a"} repo?`,initialValue:t.repos.length===0});if(isCancel(i)&&(cancel("Canceled!"),process.exit(0)),!i)break;let s=await text({message:"Where should we download the blocks from?",placeholder:"github/ieedan/std",validate:f=>{if(f.trim().length===0)return "Please provide a value";if(!_.find($=>$.matches(f)))return `Invalid provider! Valid providers (${_.map($=>$.name()).join(", ")})`}});isCancel(s)&&(cancel("Canceled!"),process.exit(0));let a=_.find(f=>f.matches(s));a||program.error(I.red("Invalid provider!"));let d=`${a.name()}-token`;if(!e.get(d)){let f=await confirm({message:"Would you like to add an auth token?",initialValue:!1});if(isCancel(f)&&(cancel("Canceled!"),process.exit(0)),f){let $=await password({message:"Paste your token",validate(v){if(v.trim()==="")return "Please provide a value"}});isCancel($)&&(cancel("Canceled!"),process.exit(0)),e.set(d,$);}}t.repos.push(s);}if(!t.formatter){let i=r.isErr()?"none":r.unwrap().formatter??"none";Ne.existsSync(J.join(t.cwd,".prettierrc"))&&(i="prettier"),Ne.existsSync(J.join(t.cwd,"biome.json"))&&(i="biome");let s=await select({message:"What formatter would you like to use?",options:["Prettier","Biome","None"].map(a=>({value:a.toLowerCase(),label:a})),initialValue:i});isCancel(s)&&(cancel("Canceled!"),process.exit(0)),s!=="none"&&(t.formatter=s);}let n={$schema:`https://unpkg.com/jsrepo@${M.package.version}/schema.json`,repos:t.repos,path:t.path,includeTests:r.isOk()&&t.tests===void 0?r.unwrap().includeTests:t.tests??!1,watermark:t.watermark,formatter:t.formatter};o.start(`Writing config to \`${Se}\``),Ne.writeFileSync(J.join(t.cwd,Se),`${JSON.stringify(n,null," ")}
44
+ `),Ne.mkdirSync(J.join(t.cwd,n.path),{recursive:!0}),o.stop(`Wrote config to \`${Se}\`.`);},No=async t=>{let e=spinner(),r=J.join(t.cwd,"package.json");if(Ne.existsSync(r)||program.error(I.red(`Couldn't find your ${I.bold("package.json")}!`)),!t.path){let m=await text({message:"Where are your blocks located?",defaultValue:"./blocks",initialValue:"./blocks",placeholder:"./blocks"});isCancel(m)&&(cancel("Canceled!"),process.exit(0)),t.path=m;}let o=JSON.parse(Ne.readFileSync(r).toString()),n=o.scripts!==void 0&&o.scripts[t.script]!==void 0;if(!t.yes&&n){let m=await confirm({message:`The \`${I.cyan(t.script)}\` already exists overwrite?`,initialValue:!1});if(isCancel(m)&&(cancel("Canceled!"),process.exit(0)),!m){let b=await text({message:"What would you like to call the script?",defaultValue:"build:registry",placeholder:"build:registry",initialValue:"build:registry",validate:S=>{if(S.trim().length===0)return "Please provide a value!"}});isCancel(b)&&(cancel("Canceled!"),process.exit(0)),t.script=b;}}let i=o.devDependencies&&o.devDependencies.jsrepo!==void 0,s=t.yes||i;if(!t.yes&&!i){let m=await confirm({message:`Add ${fe} as a dev dependency?`,initialValue:!0});isCancel(m)&&(cancel("Canceled!"),process.exit(0)),s=m;}let a=(await detect$1({cwd:"cwd"}))?.agent??"npm",d="";if(s)d+="jsrepo build ";else {let m=resolveCommand$1(a,"execute",["jsrepo","build"]);m||program.error(I.red(`Error resolving execute command for ${a}`)),d+=`${m.command} ${m.args.join(" ")} `;}t.path!=="./build"&&(d+=`--dirs ${t.path}`),o.scripts===void 0&&(o.scripts={}),o.scripts[t.script]=d,e.start(`Adding \`${I.cyan(t.script)}\` to scripts in package.json`);try{Ne.writeFileSync(r,JSON.stringify(o,null," "));}catch(m){program.error(I.red(`Error writing to \`${I.bold(r)}\`. Error: ${m}`));}e.stop(`Added \`${I.cyan(t.script)}\` to scripts in package.json`);let h=i;if(s&&!i){let m=t.yes;if(!t.yes){let b=await confirm({message:"Install dependencies?",initialValue:!0});isCancel(b)&&(cancel("Canceled!"),process.exit(0)),m=b;}m&&(e.start(`Installing ${fe}`),(await Re({pm:a,deps:["jsrepo"],dev:!0,cwd:t.cwd})).match(()=>e.stop(`Installed ${fe}.`),S=>{e.stop(`Failed to install ${fe}.`),program.error(S);}),h=!0);}let f=[];if(!h&&s){let m=resolveCommand$1(a,"install",["jsrepo","-D"]);f.push(`Install ${fe} as a dev dependency \`${I.cyan(`${m?.command} ${m?.args.join(" ")}`)}\``);}f.push(`Add blocks to \`${I.cyan(t.path)}\`.`);let $=resolveCommand$1(a,"run",[t.script]);f.push(`Run \`${I.cyan(`${$?.command} ${$?.args.join(" ")}`)}\` to build the registry.`),f=f.map((m,b)=>`${b+1}. ${m}`);let v=Ue(f);process.stdout.write(v);};var Go=B.object({repo:B.optional(B.string()),allow:B.boolean(),debug:B.boolean(),verbose:B.boolean(),cwd:B.string()}),_t=new Command("test").description("Tests local blocks against most recent remote tests.").addArgument(new Argument("[blocks...]","The blocks you want to test.").default([])).option("--repo <repo>","Repository to download the blocks from.").option("-A, --allow","Allow jsrepo to download code from the provided repo.",!1).option("--debug","Leaves the temp test file around for debugging upon failure.",!1).option("--verbose","Include debug logs.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async(t,e)=>{let r=B.parse(Go,e);K(M.package.version),await Ho(t,r),outro(I.green("All done!"));}),Ho=async(t,e)=>{let r=g=>{e.verbose&&console.info(`${Le} ${g}`);};r(`Attempting to test ${JSON.stringify(t)}`);let o=ge(e.cwd).match(g=>g,g=>program.error(I.red(g))),n=spinner(),i=new Map,s=o.repos;if(e.repo&&(s=[e.repo]),!e.allow&&e.repo){let g=await confirm({message:`Allow ${I.cyan("jsrepo")} to download and run code from ${I.cyan(e.repo)}?`,initialValue:!0});(isCancel(g)||!g)&&(cancel("Canceled!"),process.exit(0));}r(`Fetching blocks from ${I.cyan(s.join(", "))}`),e.verbose||n.start(`Fetching blocks from ${I.cyan(s.join(", "))}`);for(let g of s){let l=(await ve(g)).match(y=>y,y=>program.error(I.red(y))),p=await l.provider.fetchManifest(l);r(`Got info for provider ${I.cyan(l.name)}`),p.isErr()&&(e.verbose||n.stop(`Error fetching ${I.cyan(g)}`),program.error(I.red(`There was an error fetching the \`${ce}\` from the repository ${I.cyan(g)} make sure the target repository has a \`${ce}\` in its root?`)));let c=p.unwrap();for(let y of c)for(let R of y.blocks)i.set(`${l.name}/${l.owner}/${l.repoName}/${y.name}/${R.name}`,{...R,sourceRepo:l});}r(`Retrieved blocks from ${I.cyan(s.join(", "))}`),e.verbose||n.stop(`Retrieved blocks from ${I.cyan(s.join(", "))}`);let a=J.resolve(J.join(e.cwd,`blocks-tests-temp-${Date.now()}`));r(`Trying to create the temp directory ${I.bold(a)}.`),Ne.mkdirSync(a,{recursive:!0});let d=()=>{Ne.rmSync(a,{recursive:!0,force:!0});},h=ke(i,o,e.cwd).map(g=>g.specifier),f=t;t.length===0&&(f=h),f.length===0&&(d(),program.error(I.red("There were no blocks found in your project!")));let $=[];for(let g of f){let l;if(_.find(p=>g.startsWith(p.name()))){if(s.length===0){let[p,c,y,...R]=g.split("/"),u;R.length>2?u=`${p}/${c}/${y}/${R.slice(0,R.length-2).join("/")}`:u=`${p}/${c}/${y}`;let C=(await ve(u)).match(F=>F,F=>program.error(I.red(F))),k=(await C.provider.fetchManifest(C)).match(F=>F,F=>program.error(I.red(F)));for(let F of k)for(let x of F.blocks)i.set(`${C.name}/${C.owner}/${C.repoName}/${F.name}/${x.name}`,{...x,sourceRepo:C});}l=i.get(g);}else for(let p of s){let c=(await ve(p)).unwrap(),y=i.get(`${c.name}/${c.owner}/${c.repoName}/${g}`);if(y!==void 0){l=y;break}}l||program.error(I.red(`Invalid block! ${I.bold(g)} does not exist!`)),$.push({name:g,block:l});}for(let{block:g}of $){let l=g.sourceRepo,p=`${g.sourceRepo.url}/${g.category}/${g.name}`;if(e.verbose||n.start(`Setting up test file for ${I.cyan(p)}`),!g.tests){n.stop(`No tests found for ${I.cyan(p)}`);continue}let c=async u=>{let C=await l.provider.fetchRaw(l,u);return C.isErr()&&(n.stop(I.red(`Error fetching ${I.bold(u)}`)),program.error(I.red(`There was an error trying to get ${p}`))),C.unwrap()};r(`Downloading and copying test files for ${p}`);let y=[];for(let u of g.files.filter(C=>ae(C))){let C=await c(J.join(g.directory,u)),k=J.join(a,u);Ne.writeFileSync(k,C),y.push(k);}let R=new Project;for(let u of y){r(`Opening test file ${u}`);let C=R.addSourceFileAtPath(u);for(let k of C.getImportDeclarations()){let F=k.getModuleSpecifierValue(),x;F.startsWith(".")&&(g.subdirectory?x=J.join("../",o.path,g.category,g.name,F):x=J.join("../",o.path,g.category,F)),x&&k.setModuleSpecifier(x.replaceAll(/\\/g,"/"));}}R.saveSync(),r(`Completed ${I.cyan.bold(p)} test file`),e.verbose||n.stop(`Completed setup for ${I.bold(p)}`);}r("Beginning testing");let v=await detect({cwd:e.cwd});v==null&&program.error(I.red("Could not detect package manager"));let m=resolveCommand(v.agent,"execute",["vitest","run",a]);m==null&&program.error(I.red(`Could not resolve add command for '${v.agent}'.`));let{command:b,args:S}=m,j=`${b} ${S.join(" ")}`,T=execa({cwd:e.cwd,stdio:["ignore","pipe","pipe"]})`${j}`,w=g=>console.info(g.toString());T.stdout.on("data",w),T.stderr.on("data",w);try{await T,d();}catch(g){e.debug?console.info(`${I.bold("--debug")} flag provided. Skipping cleanup. Run '${I.bold(j)}' to retry tests.
45
+ `):d(),program.error(I.red(`Tests failed! Error ${g}`));}};var en=B.object({all:B.boolean(),expand:B.boolean(),maxUnchanged:B.number(),repo:B.optional(B.string()),allow:B.boolean(),yes:B.boolean(),verbose:B.boolean(),cwd:B.string()}),Vt=new Command("update").argument("[blocks...]","Names of the blocks you want to update. ex: (utils/math)").option("--all","Update all installed components.",!1).option("-E, --expand","Expands the diff so you see everything.",!1).option("--max-unchanged <number>","Maximum unchanged lines that will show without being collapsed.",t=>Number.parseInt(t),3).option("--repo <repo>","Repository to download the blocks from.").option("-A, --allow","Allow jsrepo to download code from the provided repo.",!1).option("-y, --yes","Skip confirmation prompt.",!1).option("--verbose","Include debug logs.",!1).option("--cwd <path>","The current working directory.",process.cwd()).action(async(t,e)=>{let r=B.parse(en,e);K(M.package.version),await tn(t,r),outro(I.green("All done!"));}),tn=async(t,e)=>{let r=w=>{e.verbose&&console.info(`${Le} ${w}`);};r(`Attempting to update ${JSON.stringify(t)}`);let o=spinner(),n=ge(e.cwd).match(w=>w,w=>program.error(I.red(w))),i=n.repos;e.repo&&(i=[e.repo]);for(let w of t)_.find(g=>w.startsWith(g.name()))&&program.error(I.red(`Invalid value provided for block names \`${I.bold(w)}\`. Block names are expected to be provided in the format of \`${I.bold("<category>/<name>")}\``));if(!e.allow&&e.repo){let w=await confirm({message:`Allow ${I.cyan("jsrepo")} to download and run code from ${I.cyan(e.repo)}?`,initialValue:!0});(isCancel(w)||!w)&&(cancel("Canceled!"),process.exit(0));}r(`Fetching blocks from ${I.cyan(i.join(", "))}`),e.verbose||o.start(`Fetching blocks from ${I.cyan(i.join(", "))}`);let s=(await Me(...i)).match(w=>w,({repo:w,message:g})=>{o.stop(`Failed fetching blocks from ${I.cyan(w)}`),program.error(I.red(g));});e.verbose||o.stop(`Retrieved blocks from ${I.cyan(i.join(", "))}`),r(`Retrieved blocks from ${I.cyan(i.join(", "))}`);let a=ke(s,n,e.cwd);a.length===0&&program.error(I.red(`You haven't installed any blocks yet. Did you mean to \`${I.bold("add")}\`?`));let d=t;if(e.all&&(d=a.map(w=>w.specifier)),d.length===0){let w=await multiselect({message:"Which blocks would you like to update?",options:a.map(g=>({label:`${I.cyan(g.block.category)}/${g.block.name}`,value:g.specifier})),required:!0});isCancel(w)&&(cancel("Canceled!"),process.exit(0)),d=w;}r(`Preparing to update ${I.cyan(d.join(", "))}`);let h=(await Qe(d,s,i)).match(w=>w,program.error),f=(await detect({cwd:e.cwd}))?.agent??"npm",$=[],v=new Set,m=new Set,{prettierOptions:b,biomeOptions:S}=await lt({formatter:n.formatter,cwd:e.cwd});for(let{block:w}of h){let g=`${w.sourceRepo.url}/${w.category}/${w.name}`,l=Je(M.package.version,w.sourceRepo.url),p=w.sourceRepo;r(`Attempting to add ${g}`);let c=J.join(e.cwd,n.path,w.category),y=[],R=async u=>{let C=await p.provider.fetchRaw(p,u,{verbose:r});return C.isErr()&&(o.stop(I.red(`Error fetching ${I.bold(u)}`)),program.error(I.red(`There was an error trying to get ${g}`))),C.unwrap()};for(let u of w.files){if(!n.includeTests&&ae(u))continue;let C=J.join(w.directory,u),k;w.subdirectory?k=J.join(c,w.name,u):k=J.join(c,u);let F=await R(C);Ne.mkdirSync(k.slice(0,k.length-u.length),{recursive:!0}),y.push({content:F,destPath:k,fileName:u});}process.stdout.write(`${N}
46
+ `),process.stdout.write(`${N} ${g}
47
+ `);for(let u of y){let C=he.find(x=>x.matches(u.destPath)),k=u.content;C&&(n.watermark&&(k=`${C.comment(l)}
48
+
49
+ ${k}`),k=await C.format(k,{filePath:u.destPath,formatter:n.formatter,prettierOptions:b,biomeOptions:S}));let F=e.yes;if(!e.yes){process.stdout.write(`${N}
50
+ `);let x="";Ne.existsSync(u.destPath)&&(x=Ne.readFileSync(u.destPath).toString());let X=diffLines(x,k),Z=J.join(`${p.name}/${p.owner}/${p.repoName}`,u.fileName),Fe=J.relative(e.cwd,u.destPath),Ye=dt({from:Z,to:Fe,changes:X,expand:e.expand,maxUnchanged:e.maxUnchanged,colorAdded:I.greenBright,colorRemoved:I.redBright,colorCharsAdded:I.bgGreenBright,colorCharsRemoved:I.bgRedBright,prefix:()=>`${N} `,onUnchanged:({from:Be,to:gt,prefix:ht})=>`${ht?.()??""}${I.cyan(Be)} \u2192 ${I.gray(gt)} ${I.gray("(unchanged)")}
51
+ `,intro:({from:Be,to:gt,changes:ht,prefix:Mt})=>{let Jt=ht.filter(Cr=>Cr.added).length;return `${Mt?.()??""}${I.cyan(Be)} \u2192 ${I.gray(gt)} (${Jt} change${Jt===1?"":"s"})
52
+ ${Mt?.()??""}
53
+ `}});if(process.stdout.write(Ye),X.length>1||x===""){let Be=await confirm({message:"Accept changes?",initialValue:!0});isCancel(Be)&&(cancel("Canceled!"),process.exit(0)),F=Be;}}F&&await et([{loadingMessage:`Writing changes to ${I.cyan(u.destPath)}`,completedMessage:`Wrote changes to ${I.cyan(u.destPath)}.`,run:async()=>Ne.writeFileSync(u.destPath,k)}],{verbose:e.verbose?r:void 0});}if(n.includeTests&&w.tests){r("Trying to include tests");let{devDependencies:u}=JSON.parse(Ne.readFileSync(J.join(e.cwd,"package.json")).toString());(u===void 0||u.vitest===void 0)&&v.add("vitest");}for(let u of w.devDependencies)v.add(u);for(let u of w.dependencies)m.add(u);}await et($,{verbose:e.verbose?r:void 0});let j=it(m,v,{cwd:e.cwd});if(m=j.dependencies,v=j.devDependencies,m.size>0||v.size>0){let w=e.yes;if(!e.yes){let p=await confirm({message:"Would you like to install dependencies?",initialValue:!0});isCancel(p)&&(cancel("Canceled!"),process.exit(0)),w=p;}w&&(m.size>0&&(e.verbose||o.start(`Installing dependencies with ${I.cyan(f)}`),(await Re({pm:f,deps:Array.from(m),dev:!1,cwd:e.cwd})).match(p=>{e.verbose||o.stop(`Installed ${I.cyan(p.join(", "))}`);},p=>{e.verbose||o.stop("Failed to install dependencies"),program.error(p);})),v.size>0&&(e.verbose||o.start(`Installing dependencies with ${I.cyan(f)}`),(await Re({pm:f,deps:Array.from(v),dev:!0,cwd:e.cwd})).match(p=>{e.verbose||o.stop(`Installed ${I.cyan(p.join(", "))}`);},p=>{e.verbose||o.stop("Failed to install dev dependencies"),program.error(p);})));let g=[];if(!w){if(m.size>0){let p=resolveCommand(f,"install",[...m]);g.push(`Install dependencies \`${I.cyan(`${p?.command} ${p?.args.join(" ")}`)}\``);}if(v.size>0){let p=resolveCommand(f,"install",[...v,"-D"]);g.push(`Install dev dependencies \`${I.cyan(`${p?.command} ${p?.args.join(" ")}`)}\``);}}g=g.map((p,c)=>`${c+1}. ${p}`),w||g.push(""),g.push(`Import the blocks from \`${I.cyan(n.path)}\``);let l=Ue(g);process.stdout.write(l);}};var $r=t=>{let e=fileURLToPath(import.meta.url);return J.join(e,"../..",t)},{version:br,name:kr,description:Rr,repository:an}=JSON.parse(Ne.readFileSync($r("package.json"),"utf-8")),M={package:{name:kr,description:Rr,version:br,repository:an},resolveRelativeToRoot:$r};console.clear();program.name(kr).description(Rr).version(br).addCommand(jt).addCommand(At).addCommand(Bt).addCommand(_t).addCommand(Nt).addCommand(Vt).addCommand(Dt);program.parse();export{M as context};