@reliverse/dler 1.7.53 → 1.7.55

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.
@@ -1,20 +1,63 @@
1
+ import path from "@reliverse/pathkit";
2
+ import fs from "@reliverse/relifso";
1
3
  import { selectPrompt, runCmd, confirmPrompt, inputPrompt } from "@reliverse/rempts";
2
4
  import { getAggCmd } from "../cmds.js";
3
5
  import { getConfigDler } from "../../libs/sdk/sdk-impl/config/load.js";
6
+ async function fileExists(filePath) {
7
+ return await fs.pathExists(filePath);
8
+ }
9
+ async function findMainEntryFile(config) {
10
+ const { coreEntryFile, coreEntrySrcDir } = config;
11
+ if (coreEntryFile && coreEntrySrcDir) {
12
+ const configuredPath = path.join(coreEntrySrcDir, coreEntryFile);
13
+ if (await fileExists(configuredPath)) {
14
+ return configuredPath;
15
+ }
16
+ }
17
+ const fallbackPatterns = [
18
+ path.join(coreEntrySrcDir || "src", "mod.ts"),
19
+ path.join(coreEntrySrcDir || "src", "index.ts"),
20
+ path.join(coreEntrySrcDir || "src", "mod.js"),
21
+ path.join(coreEntrySrcDir || "src", "index.js")
22
+ ];
23
+ for (const pattern of fallbackPatterns) {
24
+ if (await fileExists(pattern)) {
25
+ return pattern;
26
+ }
27
+ }
28
+ return null;
29
+ }
4
30
  export async function promptAggCommand() {
5
31
  const config = await getConfigDler();
6
32
  let selectedLibName = null;
33
+ const mainEntryFile = await findMainEntryFile(config);
7
34
  if (config?.libsList && Object.keys(config.libsList).length > 0) {
8
35
  const libs = Object.entries(config.libsList).map(([name, lib]) => ({
9
36
  value: name,
10
37
  label: name,
11
38
  hint: `${config.libsDirSrc}/${lib.libDirName}/${lib.libDirName}-impl`
12
39
  }));
13
- libs.push({ value: "", label: "Skip library selection", hint: "" });
40
+ if (mainEntryFile) {
41
+ libs.unshift({
42
+ value: "main",
43
+ label: "Main package",
44
+ hint: mainEntryFile
45
+ });
46
+ }
47
+ libs.push({ value: "", label: "Skip selection", hint: "" });
14
48
  selectedLibName = await selectPrompt({
15
- title: "Select a library to aggregate or skip",
49
+ title: "Select a package to aggregate or skip",
16
50
  options: libs
17
51
  });
52
+ } else if (mainEntryFile) {
53
+ const shouldUseMain = await confirmPrompt({
54
+ title: "Use main package for aggregation?",
55
+ content: `Found: ${mainEntryFile}`,
56
+ defaultValue: true
57
+ });
58
+ if (shouldUseMain) {
59
+ selectedLibName = "main";
60
+ }
18
61
  }
19
62
  let imports = false;
20
63
  let input = "";
@@ -25,11 +68,18 @@ export async function promptAggCommand() {
25
68
  let separateTypesFile = false;
26
69
  let typesOut = "";
27
70
  if (selectedLibName && selectedLibName !== "") {
28
- const libConfig = config?.libsList?.[selectedLibName];
29
- if (config && libConfig) {
30
- input = `${config.libsDirSrc}/${libConfig.libDirName}/${libConfig.libDirName}-impl`;
31
- out = `${config.libsDirSrc}/${libConfig.libMainFile}`;
32
- strip = `${config.libsDirSrc}/${libConfig.libDirName}`;
71
+ if (selectedLibName === "main" && mainEntryFile) {
72
+ const entryDir = path.dirname(mainEntryFile);
73
+ input = entryDir;
74
+ out = mainEntryFile;
75
+ strip = entryDir;
76
+ } else {
77
+ const libConfig = config?.libsList?.[selectedLibName];
78
+ if (config && libConfig) {
79
+ input = `${config.libsDirSrc}/${libConfig.libDirName}/${libConfig.libDirName}-impl`;
80
+ out = `${config.libsDirSrc}/${libConfig.libMainFile}`;
81
+ strip = `${config.libsDirSrc}/${libConfig.libDirName}`;
82
+ }
33
83
  }
34
84
  }
35
85
  if (!selectedLibName || !input) {
@@ -128,8 +128,14 @@ async function compareFileStructures(srcDir, distDir) {
128
128
  onlyFiles: true,
129
129
  dot: true
130
130
  });
131
- const srcSet = new Set(srcFiles);
132
- const distSet = new Set(distFiles);
131
+ const filteredSrcFiles = srcFiles.filter(
132
+ (file) => !file.endsWith(".test.ts") && !file.endsWith(".test.js")
133
+ );
134
+ const filteredDistFiles = distFiles.filter(
135
+ (file) => !file.endsWith(".test.ts") && !file.endsWith(".test.js")
136
+ );
137
+ const srcSet = new Set(filteredSrcFiles);
138
+ const distSet = new Set(filteredDistFiles);
133
139
  const onlyInSrc = [...srcSet].filter((x) => !distSet.has(x));
134
140
  const onlyInDist = [...distSet].filter((x) => !srcSet.has(x));
135
141
  if (onlyInSrc.length > 0 || onlyInDist.length > 0) {
@@ -12,9 +12,9 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
12
12
  projectDeployService?: "none" | "vercel" | "netlify" | "railway" | "deno" | undefined;
13
13
  projectPackageManager?: "npm" | "bun" | "yarn" | "pnpm" | undefined;
14
14
  projectState?: "created" | "creating" | undefined;
15
- projectCategory?: "browser" | "cli" | "unknown" | "website" | "vscode" | "library" | "mobile" | undefined;
15
+ projectCategory?: "cli" | "unknown" | "website" | "vscode" | "browser" | "library" | "mobile" | undefined;
16
16
  projectSubcategory?: "unknown" | "e-commerce" | "tool" | undefined;
17
- projectFramework?: "npm-jsr" | "rempts" | "unknown" | "vue" | "svelte" | "vscode" | "nextjs" | "vite" | "remix" | "astro" | "nuxt" | "solid" | "qwik" | "wxt" | "lynx" | "react-native" | "expo" | "capacitor" | "ionic" | "electron" | "tauri" | "neutralino" | "citty" | "commander" | "cac" | "meow" | "yargs" | "webextension" | "browser-extension" | undefined;
17
+ projectFramework?: "rempts" | "unknown" | "vscode" | "nextjs" | "vite" | "svelte" | "remix" | "astro" | "nuxt" | "solid" | "qwik" | "vue" | "wxt" | "lynx" | "react-native" | "expo" | "capacitor" | "ionic" | "electron" | "tauri" | "neutralino" | "citty" | "commander" | "cac" | "meow" | "yargs" | "webextension" | "browser-extension" | "npm-jsr" | undefined;
18
18
  projectTemplate?: "unknown" | "blefnk/relivator-nextjs-template" | "blefnk/relivator-docker-template" | "blefnk/next-react-ts-src-minimal" | "blefnk/all-in-one-nextjs-template" | "blefnk/create-t3-app" | "blefnk/create-next-app" | "blefnk/astro-starlight-template" | "blefnk/versator-nextjs-template" | "blefnk/relivator-lynxjs-template" | "blefnk/relivator-react-native-template" | "reliverse/template-browser-extension" | "microsoft/vscode-extension-samples" | "microsoft/vscode-extension-template" | "rsetarter-template" | "blefnk/deno-cli-tutorial" | undefined;
19
19
  projectTemplateDate?: string | undefined;
20
20
  features?: {
@@ -34,17 +34,18 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
34
34
  } | undefined;
35
35
  preferredLibraries?: {
36
36
  search?: "unknown" | "algolia" | undefined;
37
+ cdn?: "unknown" | "cloudflare" | undefined;
37
38
  i18n?: "unknown" | "next-intl" | undefined;
38
39
  analytics?: "unknown" | "vercel" | undefined;
39
40
  authentication?: "unknown" | "better-auth" | "clerk" | "next-auth" | "supabase-auth" | "auth0" | undefined;
40
- api?: "unknown" | "rest" | "hono" | "trpc" | "graphql" | undefined;
41
- testing?: "bun" | "unknown" | "jest" | "vitest" | "playwright" | "cypress" | undefined;
41
+ api?: "rest" | "unknown" | "hono" | "trpc" | "graphql" | undefined;
42
+ testing?: "bun" | "unknown" | "vitest" | "jest" | "playwright" | "cypress" | undefined;
42
43
  stateManagement?: "unknown" | "zustand" | "jotai" | "redux-toolkit" | undefined;
43
44
  formManagement?: "unknown" | "react-hook-form" | "formik" | undefined;
44
- styling?: "unknown" | "sass" | "tailwind" | "styled-components" | "css-modules" | undefined;
45
+ styling?: "unknown" | "tailwind" | "styled-components" | "css-modules" | "sass" | undefined;
45
46
  uiComponents?: "unknown" | "shadcn-ui" | "chakra-ui" | "material-ui" | undefined;
46
47
  databaseLibrary?: "unknown" | "drizzle" | "prisma" | "supabase" | undefined;
47
- databaseProvider?: "unknown" | "pg" | "sqlite" | "mysql" | "mongodb" | undefined;
48
+ databaseProvider?: "unknown" | "pg" | "mysql" | "sqlite" | "mongodb" | undefined;
48
49
  linting?: "eslint" | "unknown" | undefined;
49
50
  formatting?: "biome" | "unknown" | undefined;
50
51
  payment?: "unknown" | "stripe" | undefined;
@@ -59,7 +60,6 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
59
60
  mail?: "unknown" | "resend" | undefined;
60
61
  cache?: "unknown" | "redis" | undefined;
61
62
  storage?: "unknown" | "cloudflare" | undefined;
62
- cdn?: "unknown" | "cloudflare" | undefined;
63
63
  cms?: "unknown" | "contentlayer" | undefined;
64
64
  seo?: "unknown" | "next-seo" | undefined;
65
65
  motion?: "unknown" | "framer" | undefined;
@@ -83,7 +83,7 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
83
83
  dontRemoveComments?: boolean | undefined;
84
84
  shouldAddComments?: boolean | undefined;
85
85
  typeOrInterface?: "type" | "interface" | "mixed" | undefined;
86
- importOrRequire?: "import" | "require" | "mixed" | undefined;
86
+ importOrRequire?: "import" | "mixed" | "require" | undefined;
87
87
  cjsToEsm?: boolean | undefined;
88
88
  modernize?: {
89
89
  replaceFs?: boolean | undefined;
@@ -111,9 +111,9 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
111
111
  customReposOnNewProject?: boolean | undefined;
112
112
  envComposerOpenBrowser?: boolean | undefined;
113
113
  repoBranch?: string | undefined;
114
- repoPrivacy?: "unknown" | "private" | "public" | undefined;
114
+ repoPrivacy?: "unknown" | "public" | "private" | undefined;
115
115
  projectArchitecture?: "unknown" | "fullstack" | "separated" | undefined;
116
- projectRuntime?: "bun" | "node" | "deno" | undefined;
116
+ projectRuntime?: "node" | "bun" | "deno" | undefined;
117
117
  skipPromptsUseAutoBehavior?: boolean | undefined;
118
118
  deployBehavior?: "prompt" | "autoYes" | "autoNo" | undefined;
119
119
  depsBehavior?: "prompt" | "autoYes" | "autoNo" | undefined;
@@ -1,5 +1,6 @@
1
1
  import { isAbsolute, normalize, relative, resolve } from "@reliverse/pathkit";
2
2
  import { relinka } from "@reliverse/relinka";
3
+ import { useSpinner } from "@reliverse/rempts";
3
4
  import { defu } from "defu";
4
5
  import { createHooks } from "hookable";
5
6
  import { createJiti } from "jiti";
@@ -10,7 +11,6 @@ import prettyMilliseconds from "pretty-ms";
10
11
  import { glob } from "tinyglobby";
11
12
  import { createPerfTimer, getElapsedPerfTime } from "../../../utils/utils-perf.js";
12
13
  import { copyBuild } from "./copy/copy-mod.js";
13
- import { useSpinner } from "./mkdist/mkdist-impl/utils/spinner.js";
14
14
  import { mkdistBuild } from "./mkdist/mkdist-mod.js";
15
15
  import { rollupBuild } from "./rollup/build.js";
16
16
  import { typesBuild } from "./untyped/untyped-mod.js";
@@ -1,11 +1,11 @@
1
1
  import { resolve, extname, join, basename, dirname } from "@reliverse/pathkit";
2
+ import { useSpinner } from "@reliverse/rempts";
2
3
  import defu from "defu";
3
4
  import fsp from "node:fs/promises";
4
5
  import { glob } from "tinyglobby";
5
6
  import { createLoader } from "./loader.js";
6
7
  import { getDeclarations, normalizeCompilerOptions } from "./utils/dts.js";
7
8
  import { copyFileWithStream } from "./utils/fs.js";
8
- import { useSpinner } from "./utils/spinner.js";
9
9
  import { getVueDeclarations } from "./utils/vue-dts.js";
10
10
  export async function mkdist(options = {}) {
11
11
  return await useSpinner.withTiming(
@@ -1,8 +1,8 @@
1
1
  import { relative, dirname as pathDirname } from "@reliverse/pathkit";
2
2
  import { relinka } from "@reliverse/relinka";
3
+ import { useSpinner } from "@reliverse/rempts";
3
4
  import { rmdir, symlink, warn } from "../utils.js";
4
5
  import { mkdist } from "./mkdist-impl/make.js";
5
- import { useSpinner } from "./mkdist-impl/utils/spinner.js";
6
6
  export async function mkdistBuild(ctx) {
7
7
  const entries = ctx.options.entries.filter((e) => e.builder === "mkdist");
8
8
  if (entries.length === 0) {
@@ -1,5 +1,5 @@
1
1
  import { endPrompt, startPrompt } from "@reliverse/rempts";
2
- const version = "1.7.53";
2
+ const version = "1.7.55";
3
3
  export async function showStartPrompt(isDev) {
4
4
  await startPrompt({
5
5
  titleColor: "inverse",
@@ -16,7 +16,6 @@ export { mkdist } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/mak
16
16
  export type { DeclarationOutput } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/dts.js";
17
17
  export { normalizeCompilerOptions, getDeclarations, extractDeclarations, augmentWithDiagnostics, } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/dts.js";
18
18
  export { copyFileWithStream } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/fs.js";
19
- export { useSpinner } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/spinner.js";
20
19
  export { getVueDeclarations } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/vue-dts.js";
21
20
  export { mkdistBuild } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-mod.js";
22
21
  export { rollupBuild } from "./sdk-impl/build/bundlers/unified/rollup/build.js";
@@ -24,7 +24,6 @@ export {
24
24
  augmentWithDiagnostics
25
25
  } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/dts.js";
26
26
  export { copyFileWithStream } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/fs.js";
27
- export { useSpinner } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/spinner.js";
28
27
  export { getVueDeclarations } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-impl/utils/vue-dts.js";
29
28
  export { mkdistBuild } from "./sdk-impl/build/bundlers/unified/mkdist/mkdist-mod.js";
30
29
  export { rollupBuild } from "./sdk-impl/build/bundlers/unified/rollup/build.js";
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "@reliverse/relico": "^1.1.2",
7
7
  "@reliverse/relifso": "^1.4.5",
8
8
  "@reliverse/relinka": "^1.4.7",
9
- "@reliverse/rempts": "^1.7.28",
9
+ "@reliverse/rempts": "^1.7.29",
10
10
  "@reliverse/runtime": "^1.0.3",
11
11
  "@rollup/plugin-alias": "^5.1.1",
12
12
  "@rollup/plugin-commonjs": "^28.0.6",
@@ -32,7 +32,6 @@
32
32
  "magic-string": "^0.30.17",
33
33
  "mlly": "^1.7.4",
34
34
  "nypm": "^0.6.0",
35
- "ora": "^8.2.0",
36
35
  "p-all": "^5.0.0",
37
36
  "p-map": "^7.0.3",
38
37
  "pkg-types": "^2.1.0",
@@ -54,7 +53,7 @@
54
53
  "license": "MIT",
55
54
  "name": "@reliverse/dler",
56
55
  "type": "module",
57
- "version": "1.7.53",
56
+ "version": "1.7.55",
58
57
  "keywords": [
59
58
  "reliverse",
60
59
  "cli",
@@ -1,99 +0,0 @@
1
- import { type Color, type Options as OraOptions } from "ora";
2
- interface SpinnerOptions {
3
- text: string;
4
- color?: Color;
5
- spinner?: OraOptions["spinner"];
6
- successText?: string;
7
- failText?: string;
8
- prefixText?: string;
9
- silent?: boolean;
10
- hideCursor?: boolean;
11
- }
12
- interface ProgressOptions {
13
- current: number;
14
- total: number;
15
- format?: "percentage" | "count" | "both";
16
- }
17
- interface SpinnerControls {
18
- start: (text?: string) => SpinnerControls;
19
- stop: () => void;
20
- setText: (text: string) => void;
21
- setProgress: (progress: ProgressOptions) => void;
22
- succeed: (text?: string) => void;
23
- fail: (text?: string) => void;
24
- warn: (text?: string) => void;
25
- info: (text?: string) => void;
26
- isSpinning: () => boolean;
27
- clear: () => void;
28
- getElapsedTime: () => number;
29
- pause: () => void;
30
- resume: () => void;
31
- dispose: () => void;
32
- }
33
- /**
34
- * Creates a terminal spinner with enhanced controls and styling options.
35
- *
36
- * @example
37
- * ```typescript
38
- * // Basic usage
39
- * const spinner = useSpinner({ text: "Loading..." }).start();
40
- * spinner.stop();
41
- *
42
- * // With progress tracking
43
- * const spinner = useSpinner({ text: "Processing files..." }).start();
44
- * for (let i = 0; i < files.length; i++) {
45
- * spinner.setProgress({ current: i + 1, total: files.length });
46
- * await processFile(files[i]);
47
- * }
48
- * spinner.succeed();
49
- *
50
- * // With custom color and spinner
51
- * const spinner = useSpinner({
52
- * text: "Processing...",
53
- * color: "cyan",
54
- * spinner: "dots"
55
- * }).start();
56
- *
57
- * // With success/failure states
58
- * const spinner = useSpinner({
59
- * text: "Uploading...",
60
- * successText: "Upload complete!",
61
- * failText: "Upload failed!"
62
- * }).start();
63
- * try {
64
- * await uploadFile();
65
- * spinner.succeed();
66
- * } catch (error) {
67
- * spinner.fail();
68
- * }
69
- *
70
- * // Using the wrapper for async operations
71
- * await useSpinner.promise(
72
- * async (spinner) => {
73
- * await longOperation();
74
- * spinner.setProgress({ current: 50, total: 100 });
75
- * },
76
- * {
77
- * text: "Working...",
78
- * successText: "Done!",
79
- * failText: "Failed!"
80
- * }
81
- * );
82
- * ```
83
- */
84
- export declare function useSpinner(options: SpinnerOptions): SpinnerControls;
85
- export declare namespace useSpinner {
86
- var promise: <T>(operation: (spinner: SpinnerControls) => Promise<T>, options: SpinnerOptions) => Promise<T>;
87
- var nested: (parentOptions: SpinnerOptions) => {
88
- start: () => {
89
- child: (childOptions: SpinnerOptions) => SpinnerControls;
90
- finish: (success: boolean, text?: string) => void;
91
- dispose: () => void;
92
- };
93
- };
94
- var withTiming: <T>(operation: (spinner: SpinnerControls) => Promise<T>, options: SpinnerOptions) => Promise<{
95
- result: T;
96
- duration: number;
97
- }>;
98
- }
99
- export {};
@@ -1,206 +0,0 @@
1
- import ora from "ora";
2
- function isInteractive() {
3
- return process.stdout.isTTY && !process.env.CI && !process.env.GITHUB_ACTIONS && !process.env.GITLAB_CI && !process.env.BUILDKITE && process.env.TERM !== "dumb";
4
- }
5
- function formatProgress(options) {
6
- const { current, total, format = "both" } = options;
7
- const percentage = Math.round(current / total * 100);
8
- switch (format) {
9
- case "percentage":
10
- return `${percentage}%`;
11
- case "count":
12
- return `${current}/${total}`;
13
- case "both":
14
- return `${current}/${total} (${percentage}%)`;
15
- default:
16
- return `${current}/${total}`;
17
- }
18
- }
19
- export function useSpinner(options) {
20
- let spinnerInstance = null;
21
- const interactive = isInteractive();
22
- const state = {
23
- isActive: false,
24
- isPaused: false,
25
- startTime: null,
26
- pausedTime: 0,
27
- text: options.text
28
- };
29
- const controls = {
30
- start: (text) => {
31
- if (text) {
32
- options.text = text;
33
- state.text = text;
34
- }
35
- if (options.silent || !interactive) {
36
- console.log(options.prefixText ? `${options.prefixText} ${options.text}` : options.text);
37
- state.isActive = true;
38
- state.startTime = Date.now();
39
- return controls;
40
- }
41
- if (!spinnerInstance) {
42
- spinnerInstance = ora({
43
- text: options.text,
44
- color: options.color,
45
- spinner: options.spinner,
46
- hideCursor: options.hideCursor,
47
- prefixText: options.prefixText
48
- });
49
- } else {
50
- spinnerInstance.text = options.text;
51
- }
52
- spinnerInstance.start();
53
- state.isActive = true;
54
- state.startTime = Date.now();
55
- return controls;
56
- },
57
- stop: () => {
58
- if (spinnerInstance) {
59
- spinnerInstance.stop();
60
- }
61
- state.isActive = false;
62
- },
63
- setText: (text) => {
64
- state.text = text;
65
- if (spinnerInstance && !state.isPaused) {
66
- spinnerInstance.text = text;
67
- } else if (options.silent || !interactive) {
68
- console.log(options.prefixText ? `${options.prefixText} ${text}` : text);
69
- }
70
- options.text = text;
71
- },
72
- setProgress: (progress) => {
73
- const progressText = formatProgress(progress);
74
- const newText = `${state.text} [${progressText}]`;
75
- if (spinnerInstance && !state.isPaused) {
76
- spinnerInstance.text = newText;
77
- } else if (options.silent || !interactive) {
78
- console.log(options.prefixText ? `${options.prefixText} ${newText}` : newText);
79
- }
80
- },
81
- succeed: (text) => {
82
- const successText = text ?? options.successText ?? state.text;
83
- if (spinnerInstance) {
84
- spinnerInstance.succeed(successText);
85
- } else {
86
- console.log(`\u2713 ${successText}`);
87
- }
88
- state.isActive = false;
89
- },
90
- fail: (text) => {
91
- const failText = text ?? options.failText ?? state.text;
92
- if (spinnerInstance) {
93
- spinnerInstance.fail(failText);
94
- } else {
95
- console.error(`\u2717 ${failText}`);
96
- }
97
- state.isActive = false;
98
- },
99
- warn: (text) => {
100
- const warnText = text ?? state.text;
101
- if (spinnerInstance) {
102
- spinnerInstance.warn(warnText);
103
- } else {
104
- console.warn(`\u26A0 ${warnText}`);
105
- }
106
- },
107
- info: (text) => {
108
- const infoText = text ?? state.text;
109
- if (spinnerInstance) {
110
- spinnerInstance.info(infoText);
111
- } else {
112
- console.info(`\u2139 ${infoText}`);
113
- }
114
- },
115
- isSpinning: () => {
116
- return state.isActive && !state.isPaused;
117
- },
118
- clear: () => {
119
- if (spinnerInstance) {
120
- spinnerInstance.clear();
121
- }
122
- },
123
- getElapsedTime: () => {
124
- if (!state.startTime) return 0;
125
- const currentTime = Date.now();
126
- return currentTime - state.startTime - state.pausedTime;
127
- },
128
- pause: () => {
129
- if (state.isActive && !state.isPaused) {
130
- if (spinnerInstance) {
131
- spinnerInstance.stop();
132
- }
133
- state.isPaused = true;
134
- }
135
- },
136
- resume: () => {
137
- if (state.isActive && state.isPaused) {
138
- if (spinnerInstance) {
139
- spinnerInstance.start();
140
- }
141
- state.isPaused = false;
142
- }
143
- },
144
- dispose: () => {
145
- if (spinnerInstance) {
146
- spinnerInstance.stop();
147
- spinnerInstance = null;
148
- }
149
- state.isActive = false;
150
- state.isPaused = false;
151
- }
152
- };
153
- return controls;
154
- }
155
- useSpinner.promise = async (operation, options) => {
156
- const spinner = useSpinner(options).start();
157
- try {
158
- const result = await operation(spinner);
159
- spinner.succeed();
160
- return result;
161
- } catch (error) {
162
- spinner.fail();
163
- throw error;
164
- } finally {
165
- spinner.dispose();
166
- }
167
- };
168
- useSpinner.nested = (parentOptions) => {
169
- const parentSpinner = useSpinner({
170
- ...parentOptions,
171
- silent: true
172
- // Parent is silent, children will show progress
173
- });
174
- return {
175
- start: () => {
176
- parentSpinner.start();
177
- return {
178
- child: (childOptions) => useSpinner(childOptions),
179
- finish: (success, text) => {
180
- if (success) {
181
- parentSpinner.succeed(text);
182
- } else {
183
- parentSpinner.fail(text);
184
- }
185
- },
186
- dispose: () => parentSpinner.dispose()
187
- };
188
- }
189
- };
190
- };
191
- useSpinner.withTiming = async (operation, options) => {
192
- const spinner = useSpinner(options).start();
193
- const startTime = Date.now();
194
- try {
195
- const result = await operation(spinner);
196
- const duration = Date.now() - startTime;
197
- spinner.succeed(`${options.successText || options.text} (${duration}ms)`);
198
- return { result, duration };
199
- } catch (error) {
200
- const duration = Date.now() - startTime;
201
- spinner.fail(`${options.failText || options.text} (failed after ${duration}ms)`);
202
- throw error;
203
- } finally {
204
- spinner.dispose();
205
- }
206
- };