grimoire-wizard 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -58,6 +58,7 @@ interface SelectOption {
58
58
  label: string;
59
59
  hint?: string;
60
60
  disabled?: boolean | string;
61
+ checked?: boolean;
61
62
  }
62
63
  interface SeparatorOption {
63
64
  separator: string;
@@ -189,6 +190,7 @@ interface WizardConfig {
189
190
  version?: string;
190
191
  description?: string;
191
192
  review?: boolean;
193
+ icon?: string;
192
194
  };
193
195
  theme?: ThemeConfig;
194
196
  steps: StepConfig[];
@@ -440,6 +442,7 @@ interface RunWizardOptions {
440
442
  mru?: boolean;
441
443
  resume?: boolean;
442
444
  configFilePath?: string;
445
+ optionsProvider?: (stepId: string, answers: Record<string, unknown>) => Promise<SelectOption[] | undefined>;
443
446
  }
444
447
  declare function runPreFlightChecks(checks: PreFlightCheck[], theme: ResolvedTheme, renderer?: WizardRenderer): void;
445
448
  declare function runWizard(config: WizardConfig, options?: RunWizardOptions): Promise<Record<string, unknown>>;
@@ -482,6 +485,7 @@ declare function resolveTemplateStrict(template: string, answers: Record<string,
482
485
  */
483
486
  declare function renderBanner(name: string, theme: ResolvedTheme, options?: {
484
487
  plain?: boolean;
488
+ icon?: string;
485
489
  }): string;
486
490
 
487
491
  declare function slugify(name: string): string;
package/dist/index.js CHANGED
@@ -242,7 +242,8 @@ var init_schema = __esm({
242
242
  name: z.string(),
243
243
  version: z.string().optional(),
244
244
  description: z.string().optional(),
245
- review: z.boolean().optional()
245
+ review: z.boolean().optional(),
246
+ icon: z.string().optional()
246
247
  }),
247
248
  theme: themeConfigSchema.optional(),
248
249
  steps: z.array(stepConfigSchema).min(1),
@@ -1188,18 +1189,26 @@ import figlet from "figlet";
1188
1189
  import gradient from "gradient-string";
1189
1190
  var GRIMOIRE_GRADIENT = gradient(["#C084FC", "#5B9BD5", "#6BCB77"]);
1190
1191
  function renderBanner(name, theme, options) {
1192
+ const icon = options?.icon;
1193
+ const prefix = icon ? `${icon} ` : "";
1191
1194
  if (options?.plain) {
1192
- return ` ${theme.bold(name)}`;
1195
+ return ` ${prefix}${theme.bold(name)}`;
1193
1196
  }
1194
1197
  try {
1195
1198
  const art = figlet.textSync(name, {
1196
1199
  font: "Small",
1197
1200
  horizontalLayout: "default"
1198
1201
  });
1199
- const lines = art.split("\n").map((line) => ` ${line}`).join("\n");
1202
+ const artLines = art.split("\n");
1203
+ const lines = artLines.map((line, i) => {
1204
+ if (icon && i === Math.floor(artLines.length / 2)) {
1205
+ return ` ${icon} ${line}`;
1206
+ }
1207
+ return icon ? ` ${line}` : ` ${line}`;
1208
+ }).join("\n");
1200
1209
  return GRIMOIRE_GRADIENT(lines);
1201
1210
  } catch {
1202
- return ` ${theme.bold(name)}`;
1211
+ return ` ${prefix}${theme.bold(name)}`;
1203
1212
  }
1204
1213
  }
1205
1214
 
@@ -1441,11 +1450,14 @@ function emitEvent(renderer, event, theme) {
1441
1450
  function runPreFlightChecks(checks, theme, renderer) {
1442
1451
  if (renderer) emitEvent(renderer, { type: "checks:start", checks }, theme);
1443
1452
  for (const check of checks) {
1453
+ if (renderer) emitEvent(renderer, { type: "spinner:start", message: check.name }, theme);
1444
1454
  try {
1445
1455
  execSync(check.run, { stdio: "pipe" });
1456
+ if (renderer) emitEvent(renderer, { type: "spinner:stop", message: `${check.name}` }, theme);
1446
1457
  console.log(` ${theme.success("\u2713")} ${check.name}`);
1447
1458
  if (renderer) emitEvent(renderer, { type: "check:pass", name: check.name }, theme);
1448
1459
  } catch {
1460
+ if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
1449
1461
  console.log(` ${theme.error("\u2717")} ${check.name}: ${check.message}`);
1450
1462
  if (renderer) emitEvent(renderer, { type: "check:fail", name: check.name, message: check.message }, theme);
1451
1463
  throw new Error(`Pre-flight check failed: ${check.name} \u2014 ${check.message}`);
@@ -1565,8 +1577,17 @@ async function runWizard(config, options) {
1565
1577
  const withTemplate = options?.templateAnswers ? applyTemplateDefaults(resolvedStep, options.templateAnswers) : resolvedStep;
1566
1578
  const templatedStep = resolveStepTemplates(withTemplate, state.answers);
1567
1579
  const mruStep = mruEnabled ? applyMruOrdering(templatedStep, config.meta.name) : templatedStep;
1580
+ let finalStep = mruStep;
1581
+ if (!isMock && options?.optionsProvider && isSelectLikeStep(currentStep.type)) {
1582
+ if (renderer) emitEvent(renderer, { type: "spinner:start", message: resolvedMessage }, theme);
1583
+ const dynamicOptions = await options.optionsProvider(currentStep.id, state.answers);
1584
+ if (renderer) emitEvent(renderer, { type: "spinner:stop", message: resolvedMessage }, theme);
1585
+ if (dynamicOptions) {
1586
+ finalStep = { ...mruStep, options: dynamicOptions };
1587
+ }
1588
+ }
1568
1589
  try {
1569
- const value = isMock ? getMockValue(mruStep, mockAnswers) : pluginStep ? await pluginStep.render(toStepRecord(mruStep), state, theme) : await renderStep(renderer, mruStep, state, theme);
1590
+ const value = isMock ? getMockValue(finalStep, mockAnswers) : pluginStep ? await pluginStep.render(toStepRecord(finalStep), state, theme) : await renderStep(renderer, finalStep, state, theme);
1570
1591
  if (pluginStep?.validate) {
1571
1592
  const pluginError = pluginStep.validate(value, toStepRecord(templatedStep));
1572
1593
  if (pluginError) {
@@ -1905,6 +1926,7 @@ function resolveStepTemplates(step, answers) {
1905
1926
  }
1906
1927
  async function executeOnComplete(handlerPath, configFilePath, answers, config, theme, renderer) {
1907
1928
  if (renderer) emitEvent(renderer, { type: "oncomplete:start" }, theme);
1929
+ if (renderer) emitEvent(renderer, { type: "spinner:start", message: `Running onComplete handler...` }, theme);
1908
1930
  const resolvedPath = configFilePath ? resolve2(dirname2(configFilePath), handlerPath) : resolve2(handlerPath);
1909
1931
  try {
1910
1932
  const mod = await import(pathToFileURL(resolvedPath).href);
@@ -1912,9 +1934,11 @@ async function executeOnComplete(handlerPath, configFilePath, answers, config, t
1912
1934
  throw new Error(`onComplete handler "${handlerPath}" must export a default function`);
1913
1935
  }
1914
1936
  await mod.default({ answers, config });
1937
+ if (renderer) emitEvent(renderer, { type: "spinner:stop", message: "Handler complete" }, theme);
1915
1938
  if (renderer) emitEvent(renderer, { type: "oncomplete:pass" }, theme);
1916
1939
  } catch (error) {
1917
1940
  const message = error instanceof Error ? error.message : String(error);
1941
+ if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
1918
1942
  if (renderer) emitEvent(renderer, { type: "oncomplete:fail", error: message }, theme);
1919
1943
  console.log(`
1920
1944
  ${theme.error("\u2717")} onComplete handler failed: ${message}
@@ -1934,11 +1958,14 @@ async function executeActions(actions, answers, theme, renderer) {
1934
1958
  const resolvedCommand = resolveTemplateStrict(action.run, answers);
1935
1959
  const resolvedName = action.name ? resolveTemplateStrict(action.name, answers) : void 0;
1936
1960
  const label = resolvedName ?? resolvedCommand;
1961
+ if (renderer) emitEvent(renderer, { type: "spinner:start", message: label }, theme);
1937
1962
  try {
1938
1963
  execSync(resolvedCommand, { stdio: "pipe" });
1964
+ if (renderer) emitEvent(renderer, { type: "spinner:stop", message: label }, theme);
1939
1965
  console.log(` ${theme.success("\u2713")} ${label}`);
1940
1966
  if (renderer) emitEvent(renderer, { type: "action:pass", name: label }, theme);
1941
1967
  } catch {
1968
+ if (renderer) emitEvent(renderer, { type: "spinner:stop" }, theme);
1942
1969
  console.log(` ${theme.error("\u2717")} ${label}`);
1943
1970
  if (renderer) emitEvent(renderer, { type: "action:fail", name: label }, theme);
1944
1971
  throw new Error(`Action failed: ${label}`);
@@ -1948,7 +1975,7 @@ async function executeActions(actions, answers, theme, renderer) {
1948
1975
  }
1949
1976
  function printWizardHeader(config, theme, plain) {
1950
1977
  console.log();
1951
- console.log(renderBanner(config.meta.name, theme, { plain }));
1978
+ console.log(renderBanner(config.meta.name, theme, { plain, icon: config.meta.icon }));
1952
1979
  if (config.meta.description) {
1953
1980
  console.log(` ${theme.muted(config.meta.description)}`);
1954
1981
  }