Skip to content

Commit

Permalink
fix(inquirer): adjust parameters (#1556)
Browse files Browse the repository at this point in the history
* don't expose `rl`
  • Loading branch information
mshima authored Sep 17, 2024
1 parent 9e29035 commit a6ac2fa
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 40 deletions.
9 changes: 6 additions & 3 deletions packages/inquirer/inquirer.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ class StubEventualyFailingPrompt {
timeout?: NodeJS.Timeout;

run() {
this.timeout = setTimeout(() => {}, 1000);
return Promise.reject(new Error('This test prompt always reject'));
return new Promise((_, reject) => {
this.timeout = setTimeout(() => {
reject(new Error('This test prompt always reject'));
}, 1000);
});
}

close() {
Expand Down Expand Up @@ -802,7 +805,7 @@ describe('AbortSignal support', () => {
localPrompt.registerPrompt('stub', StubEventualyFailingPrompt);

const promise = localPrompt({ type: 'stub', name: 'q1', message: 'message' });
abortController.abort();
setTimeout(() => abortController.abort(), 0);
await expect(promise).rejects.toThrow(AbortPromptError);
});

Expand Down
73 changes: 36 additions & 37 deletions packages/inquirer/src/ui/prompt.mts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export interface LegacyPromptConstructor {

export type PromptFn<Value = any, Config = any> = (
config: Config,
context?: StreamOptions,
context: StreamOptions & { signal: AbortSignal },
) => Promise<Value>;

/**
Expand Down Expand Up @@ -197,7 +197,6 @@ export default class PromptsRunner<A extends Answers> {
process: Observable<any> = EMPTY;
private abortController: AbortController = new AbortController();
private opt: StreamOptions;
rl?: InquirerReadline;

constructor(prompts: PromptCollection, opt: StreamOptions = {}) {
this.opt = opt;
Expand Down Expand Up @@ -300,62 +299,70 @@ export default class PromptsRunner<A extends Answers> {
let cleanupSignal: (() => void) | undefined;

const promptFn: PromptFn<A> = isPromptConstructor(prompt)
? (q, { signal } = {}) =>
? (q, opt) =>
new Promise<A>((resolve, reject) => {
const { signal } = opt;
if (signal.aborted) {
reject(new AbortPromptError({ cause: signal.reason }));
return;
}

const rl = readline.createInterface(
setupReadlineOptions(this.opt),
setupReadlineOptions(opt),
) as InquirerReadline;
rl.resume();

/**
* Handle the ^C exit
*/
const onForceClose = () => {
this.close();
process.kill(process.pid, 'SIGINT');
console.log('');
};

const onClose = () => {
process.removeListener('exit', this.onForceClose);
rl.removeListener('SIGINT', this.onForceClose);
process.removeListener('exit', onForceClose);
rl.removeListener('SIGINT', onForceClose);
rl.setPrompt('');
rl.output.unmute();
rl.output.write(ansiEscapes.cursorShow);
rl.output.end();
rl.close();
};
this.rl = rl;

// Make sure new prompt start on a newline when closing
process.on('exit', this.onForceClose);
rl.on('SIGINT', this.onForceClose);
process.on('exit', onForceClose);
rl.on('SIGINT', onForceClose);

const activePrompt = new prompt(q, rl, this.answers);

const cleanup = () => {
onClose();
this.rl = undefined;
cleanupSignal?.();
};

if (signal) {
const abort = () => {
reject(new AbortPromptError({ cause: signal.reason }));
cleanup();
};
if (signal.aborted) {
abort();
return;
}
signal.addEventListener('abort', abort);
cleanupSignal = () => {
signal.removeEventListener('abort', abort);
cleanupSignal = undefined;
};
}
const abort = () => {
reject(new AbortPromptError({ cause: signal.reason }));
cleanup();
};
signal.addEventListener('abort', abort);
cleanupSignal = () => {
signal.removeEventListener('abort', abort);
cleanupSignal = undefined;
};

activePrompt.run().then(resolve, reject).finally(cleanup);
})
: prompt;

let cleanupModuleSignal: (() => void) | undefined;
const { signal: moduleSignal } = this.opt;
if (moduleSignal?.aborted) {
this.abortController.abort(moduleSignal.reason);
} else if (moduleSignal) {
const abort = (reason: unknown) => this.abortController?.abort(reason);
const abort = () => this.abortController?.abort(moduleSignal.reason);
moduleSignal.addEventListener('abort', abort);
cleanupSignal = () => {
cleanupModuleSignal = () => {
moduleSignal.removeEventListener('abort', abort);
};
}
Expand All @@ -369,18 +376,10 @@ export default class PromptsRunner<A extends Answers> {
}))
.finally(() => {
cleanupSignal?.();
cleanupModuleSignal?.();
});
};

/**
* Handle the ^C exit
*/
private onForceClose = () => {
this.close();
process.kill(process.pid, 'SIGINT');
console.log('');
};

/**
* Close the interface and cleanup listeners
*/
Expand Down

0 comments on commit a6ac2fa

Please sign in to comment.