From e831b83c5acf500a54d40400ffb531205b3e7e32 Mon Sep 17 00:00:00 2001 From: Luis Rodriguez Date: Wed, 24 Jun 2026 20:20:53 +0000 Subject: [PATCH 1/4] feat(core,prompts): export CANCEL_SYMBOL and CancelSymbol type isCancel() identifies cancellation values but the underlying symbol was not exported, making a few things unnecessarily difficult: - Tests cannot create a synthetic cancel value that behaves like clack's own cancel result without re-implementing the internals - Return types of prompts use the broad `symbol` type rather than a precise branded type - isCancel() narrowed to `symbol` instead of a specific cancel type Fixes #554 Changes: - Added `CancelSymbol` type alias (`typeof CANCEL_SYMBOL`) in core utils - Updated `isCancel` guard to narrow to `CancelSymbol` instead of `symbol` - Exported `CANCEL_SYMBOL` and `CancelSymbol` from `@clack/core` - Re-exported both from `@clack/prompts` Usage after this change: ```ts import { CANCEL_SYMBOL, isCancel } from '@clack/prompts' import type { CancelSymbol } from '@clack/prompts' const result = await text({ message: 'Name?' }) if (isCancel(result)) { // result is now narrowed to CancelSymbol, not the broad symbol type } // Tests can now create a synthetic cancel without internal knowledge: const cancelled: CancelSymbol = CANCEL_SYMBOL ``` --- packages/core/src/index.ts | 3 ++- packages/core/src/utils/index.ts | 5 ++++- packages/prompts/src/index.ts | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 4383a3df..c6a0b95f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -21,7 +21,8 @@ export { default as SelectKeyPrompt } from './prompts/select-key.js'; export type { TextOptions } from './prompts/text.js'; export { default as TextPrompt } from './prompts/text.js'; export type { ClackState as State } from './types.js'; -export { block, getColumns, getRows, isCancel, wrapTextWithPrefix } from './utils/index.js'; +export { block, getColumns, getRows, isCancel, CANCEL_SYMBOL, wrapTextWithPrefix } from './utils/index.js'; +export type { CancelSymbol } from './utils/index.js'; export type { ClackSettings } from './utils/settings.js'; export { settings, updateSettings } from './utils/settings.js'; export type { Validate } from './utils/validation.js'; diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 84ddd611..1405fb59 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -14,7 +14,10 @@ const isWindows = globalThis.process.platform.startsWith('win'); export const CANCEL_SYMBOL = Symbol('clack:cancel'); -export function isCancel(value: unknown): value is symbol { +/** The type of the cancel symbol returned by prompts when the user cancels. */ +export type CancelSymbol = typeof CANCEL_SYMBOL; + +export function isCancel(value: unknown): value is CancelSymbol { return value === CANCEL_SYMBOL; } diff --git a/packages/prompts/src/index.ts b/packages/prompts/src/index.ts index d12551b7..8f033211 100644 --- a/packages/prompts/src/index.ts +++ b/packages/prompts/src/index.ts @@ -1,5 +1,5 @@ -export type { ClackSettings } from '@clack/core'; -export { isCancel, settings, updateSettings } from '@clack/core'; +export type { ClackSettings, CancelSymbol } from '@clack/core'; +export { isCancel, CANCEL_SYMBOL, settings, updateSettings } from '@clack/core'; export * from './autocomplete.js'; export * from './box.js'; From f44c43934fd2857b0672ba0203901c781a1f074d Mon Sep 17 00:00:00 2001 From: Luis Rodriguez Date: Wed, 24 Jun 2026 20:25:09 +0000 Subject: [PATCH 2/4] chore: add changeset for CANCEL_SYMBOL export --- .changeset/bright-wolves-export-cancel.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/bright-wolves-export-cancel.md diff --git a/.changeset/bright-wolves-export-cancel.md b/.changeset/bright-wolves-export-cancel.md new file mode 100644 index 00000000..0cd29724 --- /dev/null +++ b/.changeset/bright-wolves-export-cancel.md @@ -0,0 +1,9 @@ +--- +"@clack/core": minor +"@clack/prompts": minor +--- + +Export `CANCEL_SYMBOL` constant and `CancelSymbol` type from both packages. + +This allows consumers to create synthetic cancel values in tests and write +precise TypeScript types without reimplementing internals. From 4b172598b048d6ebdbc4f0390759aa1f499debd0 Mon Sep 17 00:00:00 2001 From: Luis Rodriguez Date: Wed, 24 Jun 2026 20:26:56 +0000 Subject: [PATCH 3/4] chore: add changeset for CANCEL_SYMBOL export --- .changeset/shaggy-boxes-crash.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/shaggy-boxes-crash.md diff --git a/.changeset/shaggy-boxes-crash.md b/.changeset/shaggy-boxes-crash.md new file mode 100644 index 00000000..f017edcd --- /dev/null +++ b/.changeset/shaggy-boxes-crash.md @@ -0,0 +1,6 @@ +--- +"@clack/core": minor +"@clack/prompts": minor +--- + +Export `CANCEL_SYMBOL` constant and `CancelSymbol` type from `@clack/core` and `@clack/prompts`. Update `isCancel` type guard to narrow to `CancelSymbol` instead of the broad `symbol` type. From 0d078738c21404400f8fb67e175f1c6c413ffa27 Mon Sep 17 00:00:00 2001 From: luisangelrod Date: Thu, 25 Jun 2026 06:49:37 -0400 Subject: [PATCH 4/4] simplify: remove CancelSymbol type export, just export CANCEL_SYMBOL --- packages/core/src/index.ts | 1 - packages/core/src/utils/index.ts | 5 +---- packages/prompts/src/index.ts | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c6a0b95f..a98c0a3e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -22,7 +22,6 @@ export type { TextOptions } from './prompts/text.js'; export { default as TextPrompt } from './prompts/text.js'; export type { ClackState as State } from './types.js'; export { block, getColumns, getRows, isCancel, CANCEL_SYMBOL, wrapTextWithPrefix } from './utils/index.js'; -export type { CancelSymbol } from './utils/index.js'; export type { ClackSettings } from './utils/settings.js'; export { settings, updateSettings } from './utils/settings.js'; export type { Validate } from './utils/validation.js'; diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 1405fb59..96199a8b 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -14,10 +14,7 @@ const isWindows = globalThis.process.platform.startsWith('win'); export const CANCEL_SYMBOL = Symbol('clack:cancel'); -/** The type of the cancel symbol returned by prompts when the user cancels. */ -export type CancelSymbol = typeof CANCEL_SYMBOL; - -export function isCancel(value: unknown): value is CancelSymbol { +export function isCancel(value: unknown): value is typeof CANCEL_SYMBOL { return value === CANCEL_SYMBOL; } diff --git a/packages/prompts/src/index.ts b/packages/prompts/src/index.ts index 8f033211..61b10917 100644 --- a/packages/prompts/src/index.ts +++ b/packages/prompts/src/index.ts @@ -1,4 +1,4 @@ -export type { ClackSettings, CancelSymbol } from '@clack/core'; +export type { ClackSettings } from '@clack/core'; export { isCancel, CANCEL_SYMBOL, settings, updateSettings } from '@clack/core'; export * from './autocomplete.js';