@shell-shock/plugin-console 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { For, Show, code } from "@alloy-js/core";
3
3
  import { ElseClause, ElseIfClause, FunctionDeclaration, IfStatement, InterfaceDeclaration, InterfaceMember, TypeDeclaration, VarDeclaration } from "@alloy-js/typescript";
4
4
  import { ReflectionKind } from "@powerlines/deepkit/vendor/type";
5
5
  import { Spacing } from "@powerlines/plugin-alloy/core/components/spacing";
6
+ import { ClassDeclaration, ClassField, ClassMethod, ClassPropertyGet, ClassPropertySet } from "@powerlines/plugin-alloy/typescript";
6
7
  import { BuiltinFile } from "@powerlines/plugin-alloy/typescript/components/builtin-file";
7
8
  import { TSDoc, TSDocDefaultValue, TSDocExample, TSDocParam, TSDocRemarks, TSDocReturns } from "@powerlines/plugin-alloy/typescript/components/tsdoc";
8
9
  import { IsNotDebug, IsNotVerbose } from "@shell-shock/core/components/helpers";
@@ -1208,6 +1209,144 @@ function ColorsDeclaration() {
1208
1209
  }
1209
1210
  })}
1210
1211
  }
1212
+ },
1213
+ spinner: {
1214
+ icon: {
1215
+ active: ${createComponent(ColorFunction, {
1216
+ get ansi16() {
1217
+ return colors.ansi16.theme.text.spinner.icon.active;
1218
+ },
1219
+ get ansi256() {
1220
+ return colors.ansi256.theme.text.spinner.icon.active;
1221
+ },
1222
+ get ansi16m() {
1223
+ return colors.ansi16m.theme.text.spinner.icon.active;
1224
+ }
1225
+ })},
1226
+ warning: ${createComponent(ColorFunction, {
1227
+ get ansi16() {
1228
+ return colors.ansi16.theme.text.spinner.icon.warning;
1229
+ },
1230
+ get ansi256() {
1231
+ return colors.ansi256.theme.text.spinner.icon.warning;
1232
+ },
1233
+ get ansi16m() {
1234
+ return colors.ansi16m.theme.text.spinner.icon.warning;
1235
+ }
1236
+ })},
1237
+ error: ${createComponent(ColorFunction, {
1238
+ get ansi16() {
1239
+ return colors.ansi16.theme.text.spinner.icon.error;
1240
+ },
1241
+ get ansi256() {
1242
+ return colors.ansi256.theme.text.spinner.icon.error;
1243
+ },
1244
+ get ansi16m() {
1245
+ return colors.ansi16m.theme.text.spinner.icon.error;
1246
+ }
1247
+ })},
1248
+ success: ${createComponent(ColorFunction, {
1249
+ get ansi16() {
1250
+ return colors.ansi16.theme.text.spinner.icon.success;
1251
+ },
1252
+ get ansi256() {
1253
+ return colors.ansi256.theme.text.spinner.icon.success;
1254
+ },
1255
+ get ansi16m() {
1256
+ return colors.ansi16m.theme.text.spinner.icon.success;
1257
+ }
1258
+ })},
1259
+ info: ${createComponent(ColorFunction, {
1260
+ get ansi16() {
1261
+ return colors.ansi16.theme.text.spinner.icon.info;
1262
+ },
1263
+ get ansi256() {
1264
+ return colors.ansi256.theme.text.spinner.icon.info;
1265
+ },
1266
+ get ansi16m() {
1267
+ return colors.ansi16m.theme.text.spinner.icon.info;
1268
+ }
1269
+ })},
1270
+ help: ${createComponent(ColorFunction, {
1271
+ get ansi16() {
1272
+ return colors.ansi16.theme.text.spinner.icon.help;
1273
+ },
1274
+ get ansi256() {
1275
+ return colors.ansi256.theme.text.spinner.icon.help;
1276
+ },
1277
+ get ansi16m() {
1278
+ return colors.ansi16m.theme.text.spinner.icon.help;
1279
+ }
1280
+ })}
1281
+ },
1282
+ message: {
1283
+ active: ${createComponent(ColorFunction, {
1284
+ get ansi16() {
1285
+ return colors.ansi16.theme.text.spinner.message.active;
1286
+ },
1287
+ get ansi256() {
1288
+ return colors.ansi256.theme.text.spinner.message.active;
1289
+ },
1290
+ get ansi16m() {
1291
+ return colors.ansi16m.theme.text.spinner.message.active;
1292
+ }
1293
+ })},
1294
+ warning: ${createComponent(ColorFunction, {
1295
+ get ansi16() {
1296
+ return colors.ansi16.theme.text.spinner.message.warning;
1297
+ },
1298
+ get ansi256() {
1299
+ return colors.ansi256.theme.text.spinner.message.warning;
1300
+ },
1301
+ get ansi16m() {
1302
+ return colors.ansi16m.theme.text.spinner.message.warning;
1303
+ }
1304
+ })},
1305
+ error: ${createComponent(ColorFunction, {
1306
+ get ansi16() {
1307
+ return colors.ansi16.theme.text.spinner.message.error;
1308
+ },
1309
+ get ansi256() {
1310
+ return colors.ansi256.theme.text.spinner.message.error;
1311
+ },
1312
+ get ansi16m() {
1313
+ return colors.ansi16m.theme.text.spinner.message.error;
1314
+ }
1315
+ })},
1316
+ success: ${createComponent(ColorFunction, {
1317
+ get ansi16() {
1318
+ return colors.ansi16.theme.text.spinner.message.success;
1319
+ },
1320
+ get ansi256() {
1321
+ return colors.ansi256.theme.text.spinner.message.success;
1322
+ },
1323
+ get ansi16m() {
1324
+ return colors.ansi16m.theme.text.spinner.message.success;
1325
+ }
1326
+ })},
1327
+ info: ${createComponent(ColorFunction, {
1328
+ get ansi16() {
1329
+ return colors.ansi16.theme.text.spinner.message.info;
1330
+ },
1331
+ get ansi256() {
1332
+ return colors.ansi256.theme.text.spinner.message.info;
1333
+ },
1334
+ get ansi16m() {
1335
+ return colors.ansi16m.theme.text.spinner.message.info;
1336
+ }
1337
+ })},
1338
+ help: ${createComponent(ColorFunction, {
1339
+ get ansi16() {
1340
+ return colors.ansi16.theme.text.spinner.message.help;
1341
+ },
1342
+ get ansi256() {
1343
+ return colors.ansi256.theme.text.spinner.message.help;
1344
+ },
1345
+ get ansi16m() {
1346
+ return colors.ansi16m.theme.text.spinner.message.help;
1347
+ }
1348
+ })}
1349
+ }
1211
1350
  }
1212
1351
  },
1213
1352
  border: {
@@ -2095,6 +2234,558 @@ function LinkFunctionDeclaration() {
2095
2234
  }
2096
2235
  })];
2097
2236
  }
2237
+ /**
2238
+ * A component to generate the `spinner` function in the `shell-shock:console` builtin module.
2239
+ */
2240
+ function SpinnerFunctionDeclaration() {
2241
+ const theme = useTheme();
2242
+ return [
2243
+ createComponent(TypeDeclaration, {
2244
+ name: "WriteStream",
2245
+ children: `NodeJS.WriteStream;`
2246
+ }),
2247
+ createComponent(Spacing, {}),
2248
+ createComponent(VarDeclaration, {
2249
+ "const": true,
2250
+ name: "activeHooksPerStream",
2251
+ initializer: "new Set();"
2252
+ }),
2253
+ createComponent(Spacing, {}),
2254
+ createComponent(InterfaceDeclaration, {
2255
+ "export": true,
2256
+ name: "SpinnerOptions",
2257
+ doc: "Options for configuring the spinner.",
2258
+ get children() {
2259
+ return [
2260
+ createComponent(InterfaceMember, {
2261
+ name: "message",
2262
+ optional: true,
2263
+ type: "string",
2264
+ doc: "The message text to display next to the spinner. Defaults to an empty string."
2265
+ }),
2266
+ createIntrinsic("hbr", {}),
2267
+ createComponent(InterfaceMember, {
2268
+ name: "stream",
2269
+ optional: true,
2270
+ type: "WriteStream",
2271
+ doc: "The output stream to write the spinner to. Defaults to process.stderr."
2272
+ }),
2273
+ createIntrinsic("hbr", {}),
2274
+ createComponent(InterfaceMember, {
2275
+ name: "spinner",
2276
+ optional: true,
2277
+ type: "ThemeSpinnerResolvedConfig | SpinnerPreset",
2278
+ doc: "The spinner animation to use. Should be an object with a 'frames' property (an array of strings representing each frame of the animation) and an 'interval' property (the time in milliseconds between each frame). If not specified, a default spinner animation will be used."
2279
+ })
2280
+ ];
2281
+ }
2282
+ }),
2283
+ createComponent(Spacing, {}),
2284
+ createComponent(ClassDeclaration, {
2285
+ name: "Spinner",
2286
+ get children() {
2287
+ return [
2288
+ createComponent(ClassField, {
2289
+ name: "frames",
2290
+ isPrivateMember: true,
2291
+ type: "string[]"
2292
+ }),
2293
+ createIntrinsic("hbr", {}),
2294
+ createComponent(ClassField, {
2295
+ name: "interval",
2296
+ isPrivateMember: true,
2297
+ type: "number"
2298
+ }),
2299
+ createIntrinsic("hbr", {}),
2300
+ createComponent(ClassField, {
2301
+ name: "currentFrame",
2302
+ isPrivateMember: true,
2303
+ type: "number",
2304
+ children: code`-1`
2305
+ }),
2306
+ createIntrinsic("hbr", {}),
2307
+ createComponent(ClassField, {
2308
+ name: "timer",
2309
+ isPrivateMember: true,
2310
+ optional: true,
2311
+ type: "NodeJS.Timeout"
2312
+ }),
2313
+ createIntrinsic("hbr", {}),
2314
+ createComponent(ClassField, {
2315
+ name: "message",
2316
+ isPrivateMember: true,
2317
+ type: "string",
2318
+ children: code`""`
2319
+ }),
2320
+ createIntrinsic("hbr", {}),
2321
+ createComponent(ClassField, {
2322
+ name: "stream",
2323
+ isPrivateMember: true,
2324
+ type: "WriteStream",
2325
+ children: code`process.stderr`
2326
+ }),
2327
+ createIntrinsic("hbr", {}),
2328
+ createComponent(ClassField, {
2329
+ name: "lines",
2330
+ isPrivateMember: true,
2331
+ type: "number",
2332
+ children: code`0`
2333
+ }),
2334
+ createIntrinsic("hbr", {}),
2335
+ createComponent(ClassField, {
2336
+ name: "exitHandlerBound",
2337
+ isPrivateMember: true,
2338
+ type: "(signal: any) => void",
2339
+ children: code`() => {}`
2340
+ }),
2341
+ createIntrinsic("hbr", {}),
2342
+ createComponent(ClassField, {
2343
+ name: "lastSpinnerFrameTime",
2344
+ isPrivateMember: true,
2345
+ type: "number",
2346
+ children: code`0`
2347
+ }),
2348
+ createIntrinsic("hbr", {}),
2349
+ createComponent(ClassField, {
2350
+ name: "isSpinning",
2351
+ isPrivateMember: true,
2352
+ type: "boolean",
2353
+ children: code`false`
2354
+ }),
2355
+ createIntrinsic("hbr", {}),
2356
+ createComponent(ClassField, {
2357
+ name: "hookedStreams",
2358
+ isPrivateMember: true,
2359
+ type: "Map<WriteStream, { write?: WriteStream[\"write\"]; originalWrite: WriteStream[\"write\"]; hookedWrite: WriteStream[\"write\"] }>",
2360
+ children: code`new Map()`
2361
+ }),
2362
+ createIntrinsic("hbr", {}),
2363
+ createComponent(ClassField, {
2364
+ name: "isInternalWrite",
2365
+ isPrivateMember: true,
2366
+ type: "boolean",
2367
+ children: code`false`
2368
+ }),
2369
+ createIntrinsic("hbr", {}),
2370
+ createComponent(ClassField, {
2371
+ name: "isDeferringRender",
2372
+ isPrivateMember: true,
2373
+ type: "boolean",
2374
+ children: code`false`
2375
+ }),
2376
+ createComponent(Spacing, {}),
2377
+ memo(() => code`constructor(options: SpinnerOptions = {}) {
2378
+ const spinner = (typeof options.spinner === "string" ? resolveSpinner(options.spinner as SpinnerPreset) : options.spinner) ?? ${JSON.stringify(theme.spinner)};
2379
+ this.#frames = spinner.frames;
2380
+ this.#interval = spinner.interval;
2381
+
2382
+ if (options.message) {
2383
+ this.#message = options.message;
2384
+ }
2385
+ if (options.stream) {
2386
+ this.#stream = options.stream;
2387
+ }
2388
+
2389
+ this.#exitHandlerBound = this.#exitHandler.bind(this);
2390
+ }
2391
+
2392
+ #internalWrite(action: () => unknown) {
2393
+ this.#isInternalWrite = true;
2394
+ try {
2395
+ return action();
2396
+ } finally {
2397
+ this.#isInternalWrite = false;
2398
+ }
2399
+ }
2400
+
2401
+ #stringifyChunk(chunk: string | Uint8Array<ArrayBufferLike> | ArrayBufferLike) {
2402
+ if (chunk === undefined || chunk === null) {
2403
+ return "";
2404
+ }
2405
+
2406
+ if (typeof chunk === "string") {
2407
+ return chunk;
2408
+ }
2409
+
2410
+ if (Buffer.isBuffer(chunk) || ArrayBuffer.isView(chunk)) {
2411
+ return Buffer.from(chunk).toString("utf8");
2412
+ }
2413
+
2414
+ return String(chunk);
2415
+ }
2416
+
2417
+ #withSynchronizedOutput(action: () => unknown) {
2418
+ if (!isInteractive) {
2419
+ return action();
2420
+ }
2421
+
2422
+ try {
2423
+ this.#write("\\u001B[?2026h");
2424
+ return action();
2425
+ } finally {
2426
+ this.#write("\\u001B[?2026l");
2427
+ }
2428
+ }
2429
+
2430
+ #hookStream(stream: WriteStream) {
2431
+ if (!stream || this.#hookedStreams.has(stream) || typeof stream.write !== "function") {
2432
+ return;
2433
+ }
2434
+
2435
+ if (activeHooksPerStream.has(stream)) {
2436
+ return;
2437
+ }
2438
+
2439
+ const originalWrite = stream.write;
2440
+ const hookedWrite = ((...writeArguments: Parameters<WriteStream["write"]>) => this.#hookedWrite(stream, originalWrite, writeArguments)) as WriteStream["write"];
2441
+
2442
+ this.#hookedStreams.set(stream, {originalWrite, hookedWrite});
2443
+ activeHooksPerStream.add(stream);
2444
+ stream.write = hookedWrite;
2445
+ }
2446
+
2447
+ #installHook() {
2448
+ if (!isInteractive || this.#hookedStreams.size > 0) {
2449
+ return;
2450
+ }
2451
+
2452
+ const streamsToHook = new Set([this.#stream]);
2453
+ if (isInteractive && (this.#stream === process.stdout || this.#stream === process.stderr)) {
2454
+ streamsToHook.add(process.stdout);
2455
+ streamsToHook.add(process.stderr);
2456
+ }
2457
+
2458
+ for (const stream of streamsToHook) {
2459
+ this.#hookStream(stream);
2460
+ }
2461
+ }
2462
+
2463
+ #uninstallHook() {
2464
+ for (const [stream, hookInfo] of this.#hookedStreams) {
2465
+ if (stream.write === hookInfo.hookedWrite) {
2466
+ stream.write = hookInfo.originalWrite;
2467
+ }
2468
+
2469
+ activeHooksPerStream.delete(stream);
2470
+ }
2471
+
2472
+ this.#hookedStreams.clear();
2473
+ }
2474
+
2475
+ #hookedWrite(stream: WriteStream, originalWrite: typeof stream.write, writeArguments: Parameters<typeof stream.write>) {
2476
+ const [chunk, callback] = writeArguments;
2477
+
2478
+ if (this.#isInternalWrite || !this.isSpinning) {
2479
+ return originalWrite.call(stream, chunk);
2480
+ }
2481
+
2482
+ if (this.#lines > 0) {
2483
+ this.clear();
2484
+ }
2485
+
2486
+ const chunkString = this.#stringifyChunk(chunk);
2487
+ const chunkTerminatesLine = chunkString.at(-1) === "\\n";
2488
+ const writeResult = originalWrite.call(stream, chunk);
2489
+
2490
+ if (chunkTerminatesLine) {
2491
+ this.#isDeferringRender = false;
2492
+ } else if (chunkString !== "") {
2493
+ this.#isDeferringRender = true;
2494
+ }
2495
+
2496
+ if (this.isSpinning && !this.#isDeferringRender) {
2497
+ this.#render();
2498
+ }
2499
+
2500
+ return writeResult;
2501
+ }
2502
+
2503
+ #stopWithIcon(icon: string, message: string) {
2504
+ return this.stop(\` \${icon} \${message ?? this.#message}\`);
2505
+ }
2506
+
2507
+ #render() {
2508
+ if (this.#isDeferringRender) {
2509
+ return;
2510
+ }
2511
+
2512
+ if (this.#currentFrame === -1 || Date.now() - this.#lastSpinnerFrameTime >= this.#interval) {
2513
+ this.#currentFrame = ++this.#currentFrame % this.#frames.length;
2514
+ this.#lastSpinnerFrameTime = Date.now();
2515
+ }
2516
+
2517
+ let display = \`\${colors.text.spinner.icon.active(this.#frames[this.#currentFrame])} \${colors.text.spinner.message.active(this.#message)}\`;
2518
+ if (!isInteractive) {
2519
+ display += "\\n";
2520
+ }
2521
+
2522
+ if (isInteractive) {
2523
+ this.#withSynchronizedOutput(() => {
2524
+ this.clear();
2525
+ this.#write(display);
2526
+ });
2527
+ } else {
2528
+ this.#write(display);
2529
+ }
2530
+
2531
+ if (isInteractive) {
2532
+ this.#lines = this.#lineCount(display);
2533
+ }
2534
+ }
2535
+
2536
+ #write(message: string) {
2537
+ this.#internalWrite(() => {
2538
+ this.#stream.write(message);
2539
+ });
2540
+ }
2541
+
2542
+ #lineCount(message: string) {
2543
+ const width = this.#stream.columns ?? 80;
2544
+ const lines = stripVTControlCharacters(message).split("\\n");
2545
+
2546
+ let lineCount = 0;
2547
+ for (const line of lines) {
2548
+ lineCount += Math.max(1, Math.ceil(line.length / width));
2549
+ }
2550
+
2551
+ return lineCount;
2552
+ }
2553
+
2554
+ #hideCursor() {
2555
+ if (isInteractive) {
2556
+ this.#write("\\u001B[?25l");
2557
+ }
2558
+ }
2559
+
2560
+ #showCursor() {
2561
+ if (isInteractive) {
2562
+ this.#write("\\u001B[?25h");
2563
+ }
2564
+ }
2565
+
2566
+ #subscribeToProcessEvents() {
2567
+ process.once("SIGINT", this.#exitHandlerBound);
2568
+ process.once("SIGTERM", this.#exitHandlerBound);
2569
+ }
2570
+
2571
+ #unsubscribeFromProcessEvents() {
2572
+ process.off("SIGINT", this.#exitHandlerBound);
2573
+ process.off("SIGTERM", this.#exitHandlerBound);
2574
+ }
2575
+
2576
+ #exitHandler(signal: any) {
2577
+ if (this.isSpinning) {
2578
+ this.stop();
2579
+ }
2580
+
2581
+ process.exit(signal === "SIGINT" ? 130 : (signal === "SIGTERM" ? 143 : 1));
2582
+ } `),
2583
+ createComponent(ClassPropertyGet, {
2584
+ "public": true,
2585
+ name: "isSpinning",
2586
+ type: "boolean",
2587
+ doc: "Whether the spinner is currently active and spinning.",
2588
+ children: code`return this.#isSpinning;`
2589
+ }),
2590
+ createComponent(Spacing, {}),
2591
+ createComponent(ClassPropertySet, {
2592
+ "public": true,
2593
+ name: "message",
2594
+ type: "string",
2595
+ doc: "Set the message displayed by the spinner.",
2596
+ children: code`this.#message = value;`
2597
+ }),
2598
+ createComponent(Spacing, {}),
2599
+ createComponent(ClassPropertyGet, {
2600
+ "public": true,
2601
+ name: "message",
2602
+ type: "string",
2603
+ doc: "Get the message displayed by the spinner.",
2604
+ children: code`return this.#message;`
2605
+ }),
2606
+ createComponent(Spacing, {}),
2607
+ createComponent(ClassMethod, {
2608
+ name: "start",
2609
+ doc: "Start the spinner animation.",
2610
+ parameters: [{
2611
+ name: "message",
2612
+ type: "string"
2613
+ }],
2614
+ get children() {
2615
+ return [
2616
+ createComponent(IfStatement, {
2617
+ condition: code`message !== undefined`,
2618
+ children: code`this.#message = message;`
2619
+ }),
2620
+ createComponent(IfStatement, {
2621
+ condition: code`this.isSpinning`,
2622
+ children: code`return this;`
2623
+ }),
2624
+ code`this.#isSpinning = true;
2625
+ this.#hideCursor();
2626
+ this.#installHook();
2627
+ this.#render();
2628
+ this.#subscribeToProcessEvents();
2629
+
2630
+ if (isInteractive) {
2631
+ this.#timer = setInterval(() => {
2632
+ this.#render();
2633
+ }, this.#interval);
2634
+ }
2635
+
2636
+ return this;
2637
+ `
2638
+ ];
2639
+ }
2640
+ }),
2641
+ createComponent(Spacing, {}),
2642
+ createComponent(ClassMethod, {
2643
+ name: "stop",
2644
+ doc: "Stop the spinner animation.",
2645
+ parameters: [{
2646
+ name: "finalMessage",
2647
+ optional: true,
2648
+ type: "string"
2649
+ }],
2650
+ children: code`if (!this.isSpinning) {
2651
+ return this;
2652
+ }
2653
+
2654
+ const shouldWriteNewline = this.#isDeferringRender;
2655
+ this.#isSpinning = false;
2656
+ if (this.#timer) {
2657
+ clearInterval(this.#timer);
2658
+ this.#timer = undefined;
2659
+ }
2660
+
2661
+ this.#isDeferringRender = false;
2662
+ this.#uninstallHook();
2663
+ this.#showCursor();
2664
+ this.clear();
2665
+ this.#unsubscribeFromProcessEvents();
2666
+
2667
+ if (finalMessage) {
2668
+ const prefix = shouldWriteNewline ? "\\n" : "";
2669
+ this.#stream.write(\`\${prefix}\${finalMessage}\\n\`);
2670
+ }
2671
+
2672
+ return this;
2673
+
2674
+ `
2675
+ }),
2676
+ createComponent(Spacing, {}),
2677
+ createComponent(ClassMethod, {
2678
+ name: "clear",
2679
+ doc: "Clear the spinner animation.",
2680
+ children: code`if (!isInteractive) {
2681
+ return this;
2682
+ }
2683
+
2684
+ if (this.#lines === 0) {
2685
+ return this;
2686
+ }
2687
+
2688
+ this.#internalWrite(() => {
2689
+ this.#stream.cursorTo(0);
2690
+
2691
+ for (let index = 0; index < this.#lines; index++) {
2692
+ if (index > 0) {
2693
+ this.#stream.moveCursor(0, -1);
2694
+ }
2695
+
2696
+ this.#stream.clearLine(1);
2697
+ }
2698
+ });
2699
+
2700
+ this.#lines = 0;
2701
+ return this; `
2702
+ }),
2703
+ createComponent(Spacing, {}),
2704
+ createComponent(ClassMethod, {
2705
+ name: "success",
2706
+ doc: "Mark the spinner as successful.",
2707
+ parameters: [{
2708
+ name: "message",
2709
+ type: "string"
2710
+ }],
2711
+ get children() {
2712
+ return code`return this.#stopWithIcon(colors.text.spinner.icon.success("${theme.icons.spinner.success}"), colors.text.spinner.message.success(message)); `;
2713
+ }
2714
+ }),
2715
+ createComponent(Spacing, {}),
2716
+ createComponent(ClassMethod, {
2717
+ name: "error",
2718
+ doc: "Mark the spinner as failed.",
2719
+ parameters: [{
2720
+ name: "message",
2721
+ type: "string"
2722
+ }],
2723
+ get children() {
2724
+ return code`return this.#stopWithIcon(colors.text.spinner.icon.error("${theme.icons.spinner.error}"), colors.text.spinner.message.error(message)); `;
2725
+ }
2726
+ }),
2727
+ createComponent(Spacing, {}),
2728
+ createComponent(ClassMethod, {
2729
+ name: "warning",
2730
+ doc: "Mark the spinner as warning.",
2731
+ parameters: [{
2732
+ name: "message",
2733
+ type: "string"
2734
+ }],
2735
+ get children() {
2736
+ return code`return this.#stopWithIcon(colors.text.spinner.icon.warning("${theme.icons.spinner.warning}"), colors.text.spinner.message.warning(message)); `;
2737
+ }
2738
+ }),
2739
+ createComponent(Spacing, {}),
2740
+ createComponent(ClassMethod, {
2741
+ name: "info",
2742
+ doc: "Mark the spinner as informational.",
2743
+ parameters: [{
2744
+ name: "message",
2745
+ type: "string"
2746
+ }],
2747
+ get children() {
2748
+ return code`return this.#stopWithIcon(colors.text.spinner.icon.info("${theme.icons.spinner.info}"), colors.text.spinner.message.info(message)); `;
2749
+ }
2750
+ }),
2751
+ createComponent(Spacing, {}),
2752
+ createComponent(ClassMethod, {
2753
+ name: "help",
2754
+ doc: "Mark the spinner as help.",
2755
+ parameters: [{
2756
+ name: "message",
2757
+ type: "string"
2758
+ }],
2759
+ get children() {
2760
+ return code`return this.#stopWithIcon(colors.text.spinner.icon.help("${theme.icons.spinner.help}"), colors.text.spinner.message.help(message)); `;
2761
+ }
2762
+ }),
2763
+ createComponent(Spacing, {})
2764
+ ];
2765
+ }
2766
+ }),
2767
+ createComponent(Spacing, {}),
2768
+ createComponent(TSDoc, {
2769
+ heading: "Render a spinner in the console.",
2770
+ get children() {
2771
+ return [createComponent(TSDocParam, {
2772
+ name: "options",
2773
+ children: `Options for configuring the spinner, including the message to display, the output stream to write to, and the spinner animation to use.`
2774
+ }), createComponent(TSDocReturns, { children: `An instance of the Spinner class, which can be used to control the spinner animation (e.g., start, stop, mark as success/error, etc.).` })];
2775
+ }
2776
+ }),
2777
+ createComponent(FunctionDeclaration, {
2778
+ "export": true,
2779
+ name: "createSpinner",
2780
+ parameters: [{
2781
+ name: "options",
2782
+ type: "SpinnerOptions",
2783
+ optional: true
2784
+ }],
2785
+ children: code`return new Spinner(options);`
2786
+ })
2787
+ ];
2788
+ }
2098
2789
  function extractBorderOptionsObject(direction, theme) {
2099
2790
  return `borderOptions.${direction} === "primary" ? colors.border.app.table.primary("${theme.borderStyles.app.table.primary[direction]}") : borderOptions.${direction} === "secondary" ? colors.border.app.table.secondary("${theme.borderStyles.app.table.secondary[direction]}") : borderOptions.${direction} === "tertiary" ? colors.border.app.table.tertiary("${theme.borderStyles.app.table.tertiary[direction]}") : !borderOptions.${direction} || borderOptions.${direction} === "none" ? "" : borderOptions.${direction}`;
2100
2791
  }
@@ -2796,16 +3487,28 @@ function ConsoleBuiltin(props) {
2796
3487
  id: "console",
2797
3488
  description: "A collection of helper utilities to assist in generating content meant for display in the console.",
2798
3489
  get imports() {
2799
- return defu(imports, { "@shell-shock/plugin-theme/types/theme": [{
2800
- name: "ThemeColorsResolvedConfig",
2801
- type: true
2802
- }] });
3490
+ return defu(imports, {
3491
+ "@shell-shock/plugin-theme/types/theme": [{
3492
+ name: "ThemeColorsResolvedConfig",
3493
+ type: true
3494
+ }, {
3495
+ name: "ThemeSpinnerResolvedConfig",
3496
+ type: true
3497
+ }],
3498
+ "@shell-shock/plugin-theme/helpers/spinners": [{
3499
+ name: "SpinnerPreset",
3500
+ type: true
3501
+ }, { name: "resolveSpinner" }],
3502
+ "node:buffer": ["WithImplicitCoercion"],
3503
+ "node:util": ["stripVTControlCharacters"]
3504
+ });
2803
3505
  },
2804
3506
  get builtinImports() {
2805
3507
  return defu(builtinImports, {
2806
3508
  utils: [
2807
3509
  "hasFlag",
2808
3510
  "isMinimal",
3511
+ "isInteractive",
2809
3512
  "isColorSupported",
2810
3513
  "colorSupportLevels",
2811
3514
  "isHyperlinkSupported"
@@ -2833,6 +3536,8 @@ function ConsoleBuiltin(props) {
2833
3536
  createComponent(Spacing, {}),
2834
3537
  createComponent(DividerFunctionDeclaration, {}),
2835
3538
  createComponent(Spacing, {}),
3539
+ createComponent(SpinnerFunctionDeclaration, {}),
3540
+ createComponent(Spacing, {}),
2836
3541
  createComponent(MessageFunctionDeclaration, {
2837
3542
  type: "help",
2838
3543
  variant: "help",
@@ -2931,8 +3636,8 @@ function ConsoleBuiltin(props) {
2931
3636
  get children() {
2932
3637
  return [createComponent(IfStatement, {
2933
3638
  condition: code`(err as Error)?.stack`,
2934
- children: code`message += " \\n\\n" + (err as Error).stack;`
2935
- }), createComponent(ElseClause, { children: code`message += " \\n\\n" + (new Error(" ")).stack.split("\\n").slice(2).map(line => line.trim()).join("\\n");` })];
3639
+ children: code`message += " \\n\\n" + ((err as Error).stack || "");`
3640
+ }), createComponent(ElseClause, { children: code`message += " \\n\\n" + ((new Error(" ")).stack || "").split("\\n").slice(2).map(line => line.trim()).join("\\n");` })];
2936
3641
  }
2937
3642
  })
2938
3643
  ];
@@ -2949,5 +3654,5 @@ function ConsoleBuiltin(props) {
2949
3654
  }
2950
3655
 
2951
3656
  //#endregion
2952
- export { AnsiHelpersDeclarations, ColorsDeclaration, ConsoleBuiltin, DividerFunctionDeclaration, LinkFunctionDeclaration, MessageFunctionDeclaration, StripAnsiFunctionDeclaration, TableFunctionDeclaration, WrapAnsiFunction, WriteLineFunctionDeclaration };
3657
+ export { AnsiHelpersDeclarations, ColorsDeclaration, ConsoleBuiltin, DividerFunctionDeclaration, LinkFunctionDeclaration, MessageFunctionDeclaration, SpinnerFunctionDeclaration, StripAnsiFunctionDeclaration, TableFunctionDeclaration, WrapAnsiFunction, WriteLineFunctionDeclaration };
2953
3658
  //# sourceMappingURL=console-builtin.mjs.map