grimoire-wizard 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -1449
- package/dist/cli.js +134 -24
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +104 -1
- package/dist/index.js +125 -17
- package/dist/index.js.map +1 -1
- package/examples/handlers/setup-project.ts +9 -0
- package/examples/json/with-actions.json +61 -0
- package/examples/json/with-oncomplete.json +45 -0
- package/examples/yaml/with-actions.yaml +45 -0
- package/examples/yaml/with-oncomplete.yaml +35 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -164,6 +164,10 @@ interface ThemeConfig {
|
|
|
164
164
|
stepPending?: string;
|
|
165
165
|
pointer?: string;
|
|
166
166
|
};
|
|
167
|
+
spinner?: string | {
|
|
168
|
+
frames: string[];
|
|
169
|
+
interval?: number;
|
|
170
|
+
};
|
|
167
171
|
}
|
|
168
172
|
interface PreFlightCheck {
|
|
169
173
|
name: string;
|
|
@@ -175,12 +179,17 @@ interface ActionConfig {
|
|
|
175
179
|
run: string;
|
|
176
180
|
when?: Condition;
|
|
177
181
|
}
|
|
182
|
+
type OnCompleteHandler = (context: {
|
|
183
|
+
answers: Record<string, unknown>;
|
|
184
|
+
config: WizardConfig;
|
|
185
|
+
}) => Promise<void> | void;
|
|
178
186
|
interface WizardConfig {
|
|
179
187
|
meta: {
|
|
180
188
|
name: string;
|
|
181
189
|
version?: string;
|
|
182
190
|
description?: string;
|
|
183
191
|
review?: boolean;
|
|
192
|
+
icon?: string;
|
|
184
193
|
};
|
|
185
194
|
theme?: ThemeConfig;
|
|
186
195
|
steps: StepConfig[];
|
|
@@ -191,6 +200,7 @@ interface WizardConfig {
|
|
|
191
200
|
extends?: string;
|
|
192
201
|
checks?: PreFlightCheck[];
|
|
193
202
|
actions?: ActionConfig[];
|
|
203
|
+
onComplete?: string;
|
|
194
204
|
}
|
|
195
205
|
interface WizardState {
|
|
196
206
|
currentStepId: string;
|
|
@@ -268,6 +278,13 @@ type WizardEvent = {
|
|
|
268
278
|
} | {
|
|
269
279
|
type: 'action:fail';
|
|
270
280
|
name: string;
|
|
281
|
+
} | {
|
|
282
|
+
type: 'oncomplete:start';
|
|
283
|
+
} | {
|
|
284
|
+
type: 'oncomplete:pass';
|
|
285
|
+
} | {
|
|
286
|
+
type: 'oncomplete:fail';
|
|
287
|
+
error: string;
|
|
271
288
|
};
|
|
272
289
|
interface ResolvedTheme {
|
|
273
290
|
primary: (text: string) => string;
|
|
@@ -279,6 +296,10 @@ interface ResolvedTheme {
|
|
|
279
296
|
accent: (text: string) => string;
|
|
280
297
|
bold: (text: string) => string;
|
|
281
298
|
icons: Required<NonNullable<ThemeConfig['icons']>>;
|
|
299
|
+
spinner: {
|
|
300
|
+
frames: string[];
|
|
301
|
+
interval: number;
|
|
302
|
+
};
|
|
282
303
|
}
|
|
283
304
|
interface WizardRenderer {
|
|
284
305
|
renderText(step: TextStepConfig, state: WizardState, theme: ResolvedTheme): Promise<string>;
|
|
@@ -315,6 +336,79 @@ declare function wizardReducer(state: WizardState, transition: WizardTransition,
|
|
|
315
336
|
|
|
316
337
|
declare function resolveTheme(themeConfig?: ThemeConfig): ResolvedTheme;
|
|
317
338
|
|
|
339
|
+
interface SpinnerConfig {
|
|
340
|
+
frames: string[];
|
|
341
|
+
interval: number;
|
|
342
|
+
}
|
|
343
|
+
declare const spinners: {
|
|
344
|
+
readonly dots: {
|
|
345
|
+
readonly interval: 80;
|
|
346
|
+
readonly frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
347
|
+
};
|
|
348
|
+
readonly dots2: {
|
|
349
|
+
readonly interval: 80;
|
|
350
|
+
readonly frames: ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
|
|
351
|
+
};
|
|
352
|
+
readonly line: {
|
|
353
|
+
readonly interval: 130;
|
|
354
|
+
readonly frames: ["-", "\\", "|", "/"];
|
|
355
|
+
};
|
|
356
|
+
readonly arc: {
|
|
357
|
+
readonly interval: 100;
|
|
358
|
+
readonly frames: ["◜", "◠", "◝", "◞", "◡", "◟"];
|
|
359
|
+
};
|
|
360
|
+
readonly circle: {
|
|
361
|
+
readonly interval: 80;
|
|
362
|
+
readonly frames: ["◒", "◐", "◓", "◑"];
|
|
363
|
+
};
|
|
364
|
+
readonly circleHalves: {
|
|
365
|
+
readonly interval: 50;
|
|
366
|
+
readonly frames: ["◐", "◓", "◑", "◒"];
|
|
367
|
+
};
|
|
368
|
+
readonly triangle: {
|
|
369
|
+
readonly interval: 50;
|
|
370
|
+
readonly frames: ["◢", "◣", "◤", "◥"];
|
|
371
|
+
};
|
|
372
|
+
readonly pipe: {
|
|
373
|
+
readonly interval: 100;
|
|
374
|
+
readonly frames: ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"];
|
|
375
|
+
};
|
|
376
|
+
readonly arrow: {
|
|
377
|
+
readonly interval: 100;
|
|
378
|
+
readonly frames: ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"];
|
|
379
|
+
};
|
|
380
|
+
readonly arrow3: {
|
|
381
|
+
readonly interval: 120;
|
|
382
|
+
readonly frames: ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"];
|
|
383
|
+
};
|
|
384
|
+
readonly bouncingBar: {
|
|
385
|
+
readonly interval: 80;
|
|
386
|
+
readonly frames: ["[ ]", "[= ]", "[== ]", "[=== ]", "[====]", "[ ===]", "[ ==]", "[ =]", "[ ]", "[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]"];
|
|
387
|
+
};
|
|
388
|
+
readonly bouncingBall: {
|
|
389
|
+
readonly interval: 80;
|
|
390
|
+
readonly frames: ["( ● )", "( ● )", "( ● )", "( ● )", "( ●)", "( ● )", "( ● )", "( ● )", "( ● )", "(● )"];
|
|
391
|
+
};
|
|
392
|
+
readonly simpleDots: {
|
|
393
|
+
readonly interval: 400;
|
|
394
|
+
readonly frames: [". ", ".. ", "...", " "];
|
|
395
|
+
};
|
|
396
|
+
readonly aesthetic: {
|
|
397
|
+
readonly interval: 80;
|
|
398
|
+
readonly frames: ["▰▱▱▱▱▱▱", "▰▰▱▱▱▱▱", "▰▰▰▱▱▱▱", "▰▰▰▰▱▱▱", "▰▰▰▰▰▱▱", "▰▰▰▰▰▰▱", "▰▰▰▰▰▰▰", "▰▱▱▱▱▱▱"];
|
|
399
|
+
};
|
|
400
|
+
readonly star: {
|
|
401
|
+
readonly interval: 70;
|
|
402
|
+
readonly frames: ["✶", "✸", "✹", "✺", "✹", "✷"];
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
type SpinnerName = keyof typeof spinners;
|
|
406
|
+
declare const DEFAULT_SPINNER: SpinnerName;
|
|
407
|
+
declare function resolveSpinner(config?: string | {
|
|
408
|
+
frames: string[];
|
|
409
|
+
interval?: number;
|
|
410
|
+
}): SpinnerConfig;
|
|
411
|
+
|
|
318
412
|
declare function resolveEnvDefault(value: string | undefined): string | undefined;
|
|
319
413
|
|
|
320
414
|
interface StepPlugin {
|
|
@@ -346,6 +440,8 @@ interface RunWizardOptions {
|
|
|
346
440
|
};
|
|
347
441
|
mru?: boolean;
|
|
348
442
|
resume?: boolean;
|
|
443
|
+
configFilePath?: string;
|
|
444
|
+
optionsProvider?: (stepId: string, answers: Record<string, unknown>) => Promise<SelectOption[] | undefined>;
|
|
349
445
|
}
|
|
350
446
|
declare function runPreFlightChecks(checks: PreFlightCheck[], theme: ResolvedTheme, renderer?: WizardRenderer): void;
|
|
351
447
|
declare function runWizard(config: WizardConfig, options?: RunWizardOptions): Promise<Record<string, unknown>>;
|
|
@@ -375,6 +471,12 @@ declare class InquirerRenderer implements WizardRenderer {
|
|
|
375
471
|
* Array values are joined with ", ". Unresolved placeholders remain as-is.
|
|
376
472
|
*/
|
|
377
473
|
declare function resolveTemplate(template: string, answers: Record<string, unknown>): string;
|
|
474
|
+
/**
|
|
475
|
+
* Resolve {{stepId}} placeholders strictly — throws if any placeholder
|
|
476
|
+
* references a step-id not found in the answers map.
|
|
477
|
+
* Used by actions where missing answers indicate a config error.
|
|
478
|
+
*/
|
|
479
|
+
declare function resolveTemplateStrict(template: string, answers: Record<string, unknown>): string;
|
|
378
480
|
|
|
379
481
|
/**
|
|
380
482
|
* Render a figlet ASCII art banner for the wizard name.
|
|
@@ -382,6 +484,7 @@ declare function resolveTemplate(template: string, answers: Record<string, unkno
|
|
|
382
484
|
*/
|
|
383
485
|
declare function renderBanner(name: string, theme: ResolvedTheme, options?: {
|
|
384
486
|
plain?: boolean;
|
|
487
|
+
icon?: string;
|
|
385
488
|
}): string;
|
|
386
489
|
|
|
387
490
|
declare function slugify(name: string): string;
|
|
@@ -455,4 +558,4 @@ interface PipelineStep {
|
|
|
455
558
|
}
|
|
456
559
|
declare function runPipeline(steps: PipelineStep[], globalOptions?: Omit<RunWizardOptions, 'mockAnswers' | 'templateAnswers'>): Promise<Record<string, Record<string, unknown>>>;
|
|
457
560
|
|
|
458
|
-
export { type ActionConfig, ClackRenderer, type Condition, type ConfirmStepConfig, type EditorStepConfig, type GrimoirePlugin, InkRenderer, InquirerRenderer, type MessageStepConfig, type MultiSelectStepConfig, type NoteStepConfig, type NumberStepConfig, type PasswordStepConfig, type PathStepConfig, type PipelineStep, type PreFlightCheck, type ResolvedTheme, type RunWizardOptions, type SavedProgress, type SearchStepConfig, type SelectChoice, type SelectOption, type SelectStepConfig, type SeparatorOption, type StepConfig, type StepPlugin, type TextStepConfig, type ThemeConfig, type ToggleStepConfig, type ValidationRule, type WizardConfig, type WizardEvent, type WizardRenderer, type WizardState, type WizardTransition, clearCache, clearMruData, clearPlugins, clearProgress, createWizardState, defineWizard, deleteTemplate, evaluateCondition, getCacheDir, getOrderedOptions, getPluginStep, getVisibleSteps, isStepVisible, listTemplates, loadCachedAnswers, loadProgress, loadTemplate, loadWizardConfig, parseWizardConfig, parseWizardYAML, recordSelection, registerPlugin, renderBanner, resolveEnvDefault, resolveNextStep, resolveTemplate, resolveTheme, runPipeline, runPreFlightChecks, runWizard, saveCachedAnswers, saveProgress, saveTemplate, slugify, validateStepAnswer, wizardReducer };
|
|
561
|
+
export { type ActionConfig, ClackRenderer, type Condition, type ConfirmStepConfig, DEFAULT_SPINNER, type EditorStepConfig, type GrimoirePlugin, InkRenderer, InquirerRenderer, type MessageStepConfig, type MultiSelectStepConfig, type NoteStepConfig, type NumberStepConfig, type OnCompleteHandler, type PasswordStepConfig, type PathStepConfig, type PipelineStep, type PreFlightCheck, type ResolvedTheme, type RunWizardOptions, type SavedProgress, type SearchStepConfig, type SelectChoice, type SelectOption, type SelectStepConfig, type SeparatorOption, type SpinnerConfig, type SpinnerName, type StepConfig, type StepPlugin, type TextStepConfig, type ThemeConfig, type ToggleStepConfig, type ValidationRule, type WizardConfig, type WizardEvent, type WizardRenderer, type WizardState, type WizardTransition, clearCache, clearMruData, clearPlugins, clearProgress, createWizardState, defineWizard, deleteTemplate, evaluateCondition, getCacheDir, getOrderedOptions, getPluginStep, getVisibleSteps, isStepVisible, listTemplates, loadCachedAnswers, loadProgress, loadTemplate, loadWizardConfig, parseWizardConfig, parseWizardYAML, recordSelection, registerPlugin, renderBanner, resolveEnvDefault, resolveNextStep, resolveSpinner, resolveTemplate, resolveTemplateStrict, resolveTheme, runPipeline, runPreFlightChecks, runWizard, saveCachedAnswers, saveProgress, saveTemplate, slugify, spinners, validateStepAnswer, wizardReducer };
|
package/dist/index.js
CHANGED
|
@@ -218,7 +218,14 @@ var init_schema = __esm({
|
|
|
218
218
|
stepDone: z.string().optional(),
|
|
219
219
|
stepPending: z.string().optional(),
|
|
220
220
|
pointer: z.string().optional()
|
|
221
|
-
}).optional()
|
|
221
|
+
}).optional(),
|
|
222
|
+
spinner: z.union([
|
|
223
|
+
z.string(),
|
|
224
|
+
z.object({
|
|
225
|
+
frames: z.array(z.string()).min(1),
|
|
226
|
+
interval: z.number().positive().optional()
|
|
227
|
+
})
|
|
228
|
+
]).optional()
|
|
222
229
|
});
|
|
223
230
|
preFlightCheckSchema = z.object({
|
|
224
231
|
name: z.string(),
|
|
@@ -235,7 +242,8 @@ var init_schema = __esm({
|
|
|
235
242
|
name: z.string(),
|
|
236
243
|
version: z.string().optional(),
|
|
237
244
|
description: z.string().optional(),
|
|
238
|
-
review: z.boolean().optional()
|
|
245
|
+
review: z.boolean().optional(),
|
|
246
|
+
icon: z.string().optional()
|
|
239
247
|
}),
|
|
240
248
|
theme: themeConfigSchema.optional(),
|
|
241
249
|
steps: z.array(stepConfigSchema).min(1),
|
|
@@ -245,7 +253,8 @@ var init_schema = __esm({
|
|
|
245
253
|
}).optional(),
|
|
246
254
|
extends: z.string().optional(),
|
|
247
255
|
checks: z.array(preFlightCheckSchema).optional(),
|
|
248
|
-
actions: z.array(actionConfigSchema).optional()
|
|
256
|
+
actions: z.array(actionConfigSchema).optional(),
|
|
257
|
+
onComplete: z.string().optional()
|
|
249
258
|
}).superRefine((config, ctx) => {
|
|
250
259
|
const stepIds = /* @__PURE__ */ new Set();
|
|
251
260
|
for (const step of config.steps) {
|
|
@@ -869,6 +878,41 @@ var THEME_PRESETS = {
|
|
|
869
878
|
};
|
|
870
879
|
var PRESET_NAMES = Object.keys(THEME_PRESETS);
|
|
871
880
|
|
|
881
|
+
// src/spinners.ts
|
|
882
|
+
var spinners = {
|
|
883
|
+
dots: { interval: 80, frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"] },
|
|
884
|
+
dots2: { interval: 80, frames: ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"] },
|
|
885
|
+
line: { interval: 130, frames: ["-", "\\", "|", "/"] },
|
|
886
|
+
arc: { interval: 100, frames: ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"] },
|
|
887
|
+
circle: { interval: 80, frames: ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] },
|
|
888
|
+
circleHalves: { interval: 50, frames: ["\u25D0", "\u25D3", "\u25D1", "\u25D2"] },
|
|
889
|
+
triangle: { interval: 50, frames: ["\u25E2", "\u25E3", "\u25E4", "\u25E5"] },
|
|
890
|
+
pipe: { interval: 100, frames: ["\u2524", "\u2518", "\u2534", "\u2514", "\u251C", "\u250C", "\u252C", "\u2510"] },
|
|
891
|
+
arrow: { interval: 100, frames: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"] },
|
|
892
|
+
arrow3: { interval: 120, frames: ["\u25B9\u25B9\u25B9\u25B9\u25B9", "\u25B8\u25B9\u25B9\u25B9\u25B9", "\u25B9\u25B8\u25B9\u25B9\u25B9", "\u25B9\u25B9\u25B8\u25B9\u25B9", "\u25B9\u25B9\u25B9\u25B8\u25B9", "\u25B9\u25B9\u25B9\u25B9\u25B8"] },
|
|
893
|
+
bouncingBar: { interval: 80, frames: ["[ ]", "[= ]", "[== ]", "[=== ]", "[====]", "[ ===]", "[ ==]", "[ =]", "[ ]", "[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]"] },
|
|
894
|
+
bouncingBall: { interval: 80, frames: ["( \u25CF )", "( \u25CF )", "( \u25CF )", "( \u25CF )", "( \u25CF)", "( \u25CF )", "( \u25CF )", "( \u25CF )", "( \u25CF )", "(\u25CF )"] },
|
|
895
|
+
simpleDots: { interval: 400, frames: [". ", ".. ", "...", " "] },
|
|
896
|
+
aesthetic: { interval: 80, frames: ["\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0", "\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1\u25B1"] },
|
|
897
|
+
star: { interval: 70, frames: ["\u2736", "\u2738", "\u2739", "\u273A", "\u2739", "\u2737"] }
|
|
898
|
+
};
|
|
899
|
+
var DEFAULT_SPINNER = "circle";
|
|
900
|
+
function resolveSpinner(config) {
|
|
901
|
+
if (!config) {
|
|
902
|
+
return spinners[DEFAULT_SPINNER];
|
|
903
|
+
}
|
|
904
|
+
if (typeof config === "string") {
|
|
905
|
+
if (config in spinners) {
|
|
906
|
+
return spinners[config];
|
|
907
|
+
}
|
|
908
|
+
throw new Error(`Unknown spinner preset: "${config}". Available: ${Object.keys(spinners).join(", ")}`);
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
frames: config.frames,
|
|
912
|
+
interval: config.interval ?? 80
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
|
|
872
916
|
// src/theme.ts
|
|
873
917
|
var DEFAULT_TOKENS = {
|
|
874
918
|
primary: "#5B9BD5",
|
|
@@ -898,7 +942,8 @@ function resolveTheme(themeConfig) {
|
|
|
898
942
|
muted: chalk.hex(tokens.muted),
|
|
899
943
|
accent: chalk.hex(tokens.accent),
|
|
900
944
|
bold: chalk.bold,
|
|
901
|
-
icons
|
|
945
|
+
icons,
|
|
946
|
+
spinner: resolveSpinner(themeConfig?.spinner)
|
|
902
947
|
};
|
|
903
948
|
}
|
|
904
949
|
|
|
@@ -925,6 +970,8 @@ function resolveEnvDefaultBoolean(value) {
|
|
|
925
970
|
|
|
926
971
|
// src/runner.ts
|
|
927
972
|
import { execSync } from "child_process";
|
|
973
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
974
|
+
import { pathToFileURL } from "url";
|
|
928
975
|
|
|
929
976
|
// src/renderers/inquirer.ts
|
|
930
977
|
import {
|
|
@@ -1125,14 +1172,27 @@ function resolveTemplate(template, answers) {
|
|
|
1125
1172
|
return _match;
|
|
1126
1173
|
});
|
|
1127
1174
|
}
|
|
1175
|
+
function resolveTemplateStrict(template, answers) {
|
|
1176
|
+
return template.replace(/\{\{([^}]+)\}\}/g, (_match, key) => {
|
|
1177
|
+
const trimmedKey = key.trim();
|
|
1178
|
+
if (!(trimmedKey in answers)) {
|
|
1179
|
+
throw new Error(`Action references unknown step "${trimmedKey}"`);
|
|
1180
|
+
}
|
|
1181
|
+
const value = answers[trimmedKey];
|
|
1182
|
+
if (Array.isArray(value)) return value.join(", ");
|
|
1183
|
+
return String(value);
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1128
1186
|
|
|
1129
1187
|
// src/banner.ts
|
|
1130
1188
|
import figlet from "figlet";
|
|
1131
1189
|
import gradient from "gradient-string";
|
|
1132
1190
|
var GRIMOIRE_GRADIENT = gradient(["#C084FC", "#5B9BD5", "#6BCB77"]);
|
|
1133
1191
|
function renderBanner(name, theme, options) {
|
|
1192
|
+
const icon = options?.icon;
|
|
1193
|
+
const prefix = icon ? `${icon} ` : "";
|
|
1134
1194
|
if (options?.plain) {
|
|
1135
|
-
return ` ${theme.bold(name)}`;
|
|
1195
|
+
return ` ${prefix}${theme.bold(name)}`;
|
|
1136
1196
|
}
|
|
1137
1197
|
try {
|
|
1138
1198
|
const art = figlet.textSync(name, {
|
|
@@ -1140,9 +1200,11 @@ function renderBanner(name, theme, options) {
|
|
|
1140
1200
|
horizontalLayout: "default"
|
|
1141
1201
|
});
|
|
1142
1202
|
const lines = art.split("\n").map((line) => ` ${line}`).join("\n");
|
|
1143
|
-
|
|
1203
|
+
const banner = GRIMOIRE_GRADIENT(lines);
|
|
1204
|
+
return icon ? ` ${icon}
|
|
1205
|
+
${banner}` : banner;
|
|
1144
1206
|
} catch {
|
|
1145
|
-
return ` ${theme.bold(name)}`;
|
|
1207
|
+
return ` ${prefix}${theme.bold(name)}`;
|
|
1146
1208
|
}
|
|
1147
1209
|
}
|
|
1148
1210
|
|
|
@@ -1384,11 +1446,14 @@ function emitEvent(renderer, event, theme) {
|
|
|
1384
1446
|
function runPreFlightChecks(checks, theme, renderer) {
|
|
1385
1447
|
if (renderer) emitEvent(renderer, { type: "checks:start", checks }, theme);
|
|
1386
1448
|
for (const check of checks) {
|
|
1449
|
+
if (renderer) emitEvent(renderer, { type: "spinner:start", message: check.name }, theme);
|
|
1387
1450
|
try {
|
|
1388
1451
|
execSync(check.run, { stdio: "pipe" });
|
|
1452
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop", message: `${check.name}` }, theme);
|
|
1389
1453
|
console.log(` ${theme.success("\u2713")} ${check.name}`);
|
|
1390
1454
|
if (renderer) emitEvent(renderer, { type: "check:pass", name: check.name }, theme);
|
|
1391
1455
|
} catch {
|
|
1456
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
|
|
1392
1457
|
console.log(` ${theme.error("\u2717")} ${check.name}: ${check.message}`);
|
|
1393
1458
|
if (renderer) emitEvent(renderer, { type: "check:fail", name: check.name, message: check.message }, theme);
|
|
1394
1459
|
throw new Error(`Pre-flight check failed: ${check.name} \u2014 ${check.message}`);
|
|
@@ -1508,8 +1573,17 @@ async function runWizard(config, options) {
|
|
|
1508
1573
|
const withTemplate = options?.templateAnswers ? applyTemplateDefaults(resolvedStep, options.templateAnswers) : resolvedStep;
|
|
1509
1574
|
const templatedStep = resolveStepTemplates(withTemplate, state.answers);
|
|
1510
1575
|
const mruStep = mruEnabled ? applyMruOrdering(templatedStep, config.meta.name) : templatedStep;
|
|
1576
|
+
let finalStep = mruStep;
|
|
1577
|
+
if (!isMock && options?.optionsProvider && isSelectLikeStep(currentStep.type)) {
|
|
1578
|
+
if (renderer) emitEvent(renderer, { type: "spinner:start", message: resolvedMessage }, theme);
|
|
1579
|
+
const dynamicOptions = await options.optionsProvider(currentStep.id, state.answers);
|
|
1580
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop", message: resolvedMessage }, theme);
|
|
1581
|
+
if (dynamicOptions) {
|
|
1582
|
+
finalStep = { ...mruStep, options: dynamicOptions };
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1511
1585
|
try {
|
|
1512
|
-
const value = isMock ? getMockValue(
|
|
1586
|
+
const value = isMock ? getMockValue(finalStep, mockAnswers) : pluginStep ? await pluginStep.render(toStepRecord(finalStep), state, theme) : await renderStep(renderer, finalStep, state, theme);
|
|
1513
1587
|
if (pluginStep?.validate) {
|
|
1514
1588
|
const pluginError = pluginStep.validate(value, toStepRecord(templatedStep));
|
|
1515
1589
|
if (pluginError) {
|
|
@@ -1625,8 +1699,13 @@ async function runWizard(config, options) {
|
|
|
1625
1699
|
if (state.status === "done" && !quiet) {
|
|
1626
1700
|
renderer.renderSummary(state.answers, config.steps, theme);
|
|
1627
1701
|
}
|
|
1628
|
-
if (state.status === "done" &&
|
|
1629
|
-
|
|
1702
|
+
if (state.status === "done" && !isMock) {
|
|
1703
|
+
if (config.onComplete) {
|
|
1704
|
+
await executeOnComplete(config.onComplete, options?.configFilePath, state.answers, config, theme, renderer);
|
|
1705
|
+
}
|
|
1706
|
+
if (config.actions && config.actions.length > 0) {
|
|
1707
|
+
await executeActions(config.actions, state.answers, theme, renderer);
|
|
1708
|
+
}
|
|
1630
1709
|
}
|
|
1631
1710
|
emitEvent(renderer, { type: "session:end", answers: state.answers, cancelled: state.status === "cancelled" }, theme);
|
|
1632
1711
|
if (state.status === "done" && cacheEnabled) {
|
|
@@ -1841,6 +1920,28 @@ function resolveStepTemplates(step, answers) {
|
|
|
1841
1920
|
};
|
|
1842
1921
|
}
|
|
1843
1922
|
}
|
|
1923
|
+
async function executeOnComplete(handlerPath, configFilePath, answers, config, theme, renderer) {
|
|
1924
|
+
if (renderer) emitEvent(renderer, { type: "oncomplete:start" }, theme);
|
|
1925
|
+
if (renderer) emitEvent(renderer, { type: "spinner:start", message: `Running onComplete handler...` }, theme);
|
|
1926
|
+
const resolvedPath = configFilePath ? resolve2(dirname2(configFilePath), handlerPath) : resolve2(handlerPath);
|
|
1927
|
+
try {
|
|
1928
|
+
const mod = await import(pathToFileURL(resolvedPath).href);
|
|
1929
|
+
if (typeof mod.default !== "function") {
|
|
1930
|
+
throw new Error(`onComplete handler "${handlerPath}" must export a default function`);
|
|
1931
|
+
}
|
|
1932
|
+
await mod.default({ answers, config });
|
|
1933
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop", message: "Handler complete" }, theme);
|
|
1934
|
+
if (renderer) emitEvent(renderer, { type: "oncomplete:pass" }, theme);
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1937
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
|
|
1938
|
+
if (renderer) emitEvent(renderer, { type: "oncomplete:fail", error: message }, theme);
|
|
1939
|
+
console.log(`
|
|
1940
|
+
${theme.error("\u2717")} onComplete handler failed: ${message}
|
|
1941
|
+
`);
|
|
1942
|
+
throw error;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1844
1945
|
async function executeActions(actions, answers, theme, renderer) {
|
|
1845
1946
|
if (renderer) emitEvent(renderer, { type: "actions:start" }, theme);
|
|
1846
1947
|
console.log(`
|
|
@@ -1850,14 +1951,17 @@ async function executeActions(actions, answers, theme, renderer) {
|
|
|
1850
1951
|
if (action.when && !evaluateCondition(action.when, answers)) {
|
|
1851
1952
|
continue;
|
|
1852
1953
|
}
|
|
1853
|
-
const resolvedCommand =
|
|
1854
|
-
const resolvedName = action.name ?
|
|
1954
|
+
const resolvedCommand = resolveTemplateStrict(action.run, answers);
|
|
1955
|
+
const resolvedName = action.name ? resolveTemplateStrict(action.name, answers) : void 0;
|
|
1855
1956
|
const label = resolvedName ?? resolvedCommand;
|
|
1957
|
+
if (renderer) emitEvent(renderer, { type: "spinner:start", message: label }, theme);
|
|
1856
1958
|
try {
|
|
1857
1959
|
execSync(resolvedCommand, { stdio: "pipe" });
|
|
1960
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop", message: label }, theme);
|
|
1858
1961
|
console.log(` ${theme.success("\u2713")} ${label}`);
|
|
1859
1962
|
if (renderer) emitEvent(renderer, { type: "action:pass", name: label }, theme);
|
|
1860
1963
|
} catch {
|
|
1964
|
+
if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
|
|
1861
1965
|
console.log(` ${theme.error("\u2717")} ${label}`);
|
|
1862
1966
|
if (renderer) emitEvent(renderer, { type: "action:fail", name: label }, theme);
|
|
1863
1967
|
throw new Error(`Action failed: ${label}`);
|
|
@@ -1867,7 +1971,7 @@ async function executeActions(actions, answers, theme, renderer) {
|
|
|
1867
1971
|
}
|
|
1868
1972
|
function printWizardHeader(config, theme, plain) {
|
|
1869
1973
|
console.log();
|
|
1870
|
-
console.log(renderBanner(config.meta.name, theme, { plain }));
|
|
1974
|
+
console.log(renderBanner(config.meta.name, theme, { plain, icon: config.meta.icon }));
|
|
1871
1975
|
if (config.meta.description) {
|
|
1872
1976
|
console.log(` ${theme.muted(config.meta.description)}`);
|
|
1873
1977
|
}
|
|
@@ -2102,7 +2206,6 @@ var S_STEP_ERROR = u("\u25B2", "x");
|
|
|
2102
2206
|
var S_CORNER_TR = u("\u256E", "+");
|
|
2103
2207
|
var S_CORNER_BR = u("\u256F", "+");
|
|
2104
2208
|
var S_BAR_H = u("\u2500", "-");
|
|
2105
|
-
var S_SPINNER_FRAMES = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"];
|
|
2106
2209
|
|
|
2107
2210
|
// src/renderers/clack.ts
|
|
2108
2211
|
var ClackRenderer = class extends InquirerRenderer {
|
|
@@ -2241,13 +2344,14 @@ var ClackRenderer = class extends InquirerRenderer {
|
|
|
2241
2344
|
process.stdout.write(`${chalk2.gray(S_BAR)} ${chalk2.gray(`\u256E${bottomLine}`)}
|
|
2242
2345
|
`);
|
|
2243
2346
|
}
|
|
2244
|
-
startSpinner(message,
|
|
2347
|
+
startSpinner(message, theme) {
|
|
2245
2348
|
this.spinnerFrameIndex = 0;
|
|
2349
|
+
const { frames, interval } = theme.spinner;
|
|
2246
2350
|
this.spinnerInterval = setInterval(() => {
|
|
2247
|
-
const frame =
|
|
2351
|
+
const frame = frames[this.spinnerFrameIndex % frames.length];
|
|
2248
2352
|
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${chalk2.cyan(frame ?? "")} ${message}`);
|
|
2249
2353
|
this.spinnerFrameIndex++;
|
|
2250
|
-
},
|
|
2354
|
+
}, interval);
|
|
2251
2355
|
}
|
|
2252
2356
|
stopSpinner(message, theme) {
|
|
2253
2357
|
if (this.spinnerInterval) {
|
|
@@ -2345,6 +2449,7 @@ async function runPipeline(steps, globalOptions) {
|
|
|
2345
2449
|
}
|
|
2346
2450
|
export {
|
|
2347
2451
|
ClackRenderer,
|
|
2452
|
+
DEFAULT_SPINNER,
|
|
2348
2453
|
InkRenderer,
|
|
2349
2454
|
InquirerRenderer,
|
|
2350
2455
|
clearCache,
|
|
@@ -2372,7 +2477,9 @@ export {
|
|
|
2372
2477
|
renderBanner,
|
|
2373
2478
|
resolveEnvDefault,
|
|
2374
2479
|
resolveNextStep,
|
|
2480
|
+
resolveSpinner,
|
|
2375
2481
|
resolveTemplate,
|
|
2482
|
+
resolveTemplateStrict,
|
|
2376
2483
|
resolveTheme,
|
|
2377
2484
|
runPipeline,
|
|
2378
2485
|
runPreFlightChecks,
|
|
@@ -2381,6 +2488,7 @@ export {
|
|
|
2381
2488
|
saveProgress,
|
|
2382
2489
|
saveTemplate,
|
|
2383
2490
|
slugify,
|
|
2491
|
+
spinners,
|
|
2384
2492
|
validateStepAnswer,
|
|
2385
2493
|
wizardReducer
|
|
2386
2494
|
};
|