11/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment */
22import readline from 'node:readline' ;
3+ import { isProxy } from 'node:util/types' ;
34import {
45 defer ,
5- EMPTY ,
66 from ,
77 of ,
88 concatMap ,
99 filter ,
1010 reduce ,
1111 isObservable ,
1212 Observable ,
13+ Subject ,
1314 lastValueFrom ,
15+ tap ,
1416} from 'rxjs' ;
1517import runAsync from 'run-async' ;
1618import MuteStream from 'mute-stream' ;
@@ -40,11 +42,7 @@ export const _ = {
4042 pointer = pointer [ key ] as Record < string , unknown > ;
4143 } ) ;
4244 } ,
43- get : (
44- obj : object ,
45- path : string | number | symbol = '' ,
46- defaultValue ?: unknown ,
47- ) : any => {
45+ get : ( obj : object , path : string = '' , defaultValue ?: unknown ) : any => {
4846 const travel = ( regexp : RegExp ) =>
4947 String . prototype . split
5048 . call ( path , regexp )
@@ -193,22 +191,42 @@ function isPromptConstructor(
193191 */
194192export default class PromptsRunner < A extends Answers > {
195193 private prompts : PromptCollection ;
196- answers : Partial < A > = { } ;
197- process : Observable < any > = EMPTY ;
194+ answers : Partial < A > ;
195+ process : Subject < { name : string ; answer : any } > = new Subject ( ) ;
198196 private abortController : AbortController = new AbortController ( ) ;
199197 private opt : StreamOptions ;
200198
201- constructor ( prompts : PromptCollection , opt : StreamOptions = { } ) {
199+ constructor (
200+ prompts : PromptCollection ,
201+ { answers = { } , ...opt } : StreamOptions & { answers ?: Partial < A > } = { } ,
202+ ) {
202203 this . opt = opt ;
203204 this . prompts = prompts ;
205+
206+ this . answers = isProxy ( answers )
207+ ? answers
208+ : new Proxy (
209+ { ...answers } ,
210+ {
211+ get : ( target , prop ) => {
212+ if ( typeof prop !== 'string' ) {
213+ return ;
214+ }
215+ return _ . get ( target , prop ) ;
216+ } ,
217+ set : ( target , prop : string , value ) => {
218+ _ . set ( target , prop , value ) ;
219+ return true ;
220+ } ,
221+ } ,
222+ ) ;
204223 }
205224
206- async run ( questions : PromptSession < A > , answers ?: Partial < A > ) : Promise < A > {
225+ async run < Session extends PromptSession < A > = PromptSession < A > > (
226+ questions : Session ,
227+ ) : Promise < A > {
207228 this . abortController = new AbortController ( ) ;
208229
209- // Keep global reference to the answers
210- this . answers = typeof answers === 'object' ? { ...answers } : { } ;
211-
212230 let obs : Observable < AnyQuestion < A > > ;
213231 if ( isQuestionArray ( questions ) ) {
214232 obs = from ( questions ) ;
@@ -223,34 +241,36 @@ export default class PromptsRunner<A extends Answers> {
223241 ) ;
224242 } else {
225243 // Case: Called with a single question config
226- obs = from ( [ questions ] ) ;
244+ obs = from ( [ questions as AnyQuestion < A > ] ) ;
227245 }
228246
229- this . process = obs . pipe (
230- concatMap ( ( question ) =>
231- of ( question ) . pipe (
247+ return lastValueFrom (
248+ obs
249+ . pipe (
232250 concatMap ( ( question ) =>
233- from (
234- this . shouldRun ( question ) . then ( ( shouldRun : boolean | void ) => {
235- if ( shouldRun ) {
236- return question ;
237- }
238- return ;
239- } ) ,
240- ) . pipe ( filter ( ( val ) => val != null ) ) ,
251+ of ( question )
252+ . pipe (
253+ concatMap ( ( question ) =>
254+ from (
255+ this . shouldRun ( question ) . then ( ( shouldRun : boolean | void ) => {
256+ if ( shouldRun ) {
257+ return question ;
258+ }
259+ return ;
260+ } ) ,
261+ ) . pipe ( filter ( ( val ) => val != null ) ) ,
262+ ) ,
263+ concatMap ( ( question ) => defer ( ( ) => from ( this . fetchAnswer ( question ) ) ) ) ,
264+ )
265+ . pipe ( tap ( ( answer ) => this . process . next ( answer ) ) ) ,
241266 ) ,
242- concatMap ( ( question ) => defer ( ( ) => from ( this . fetchAnswer ( question ) ) ) ) ,
267+ )
268+ . pipe (
269+ reduce ( ( answersObj : Record < string , any > , answer : { name : string ; answer : unknown } ) => {
270+ answersObj [ answer . name ] = answer . answer ;
271+ return answersObj ;
272+ } , this . answers ) ,
243273 ) ,
244- ) ,
245- ) ;
246-
247- return lastValueFrom (
248- this . process . pipe (
249- reduce ( ( answersObj , answer : { name : string ; answer : unknown } ) => {
250- _ . set ( answersObj , answer . name , answer . answer ) ;
251- return answersObj ;
252- } , this . answers ) ,
253- ) ,
254274 )
255275 . then ( ( ) => this . answers as A )
256276 . finally ( ( ) => this . close ( ) ) ;
@@ -388,10 +408,7 @@ export default class PromptsRunner<A extends Answers> {
388408 } ;
389409
390410 private shouldRun = async ( question : AnyQuestion < A > ) : Promise < boolean > => {
391- if (
392- question . askAnswered !== true &&
393- _ . get ( this . answers , question . name ) !== undefined
394- ) {
411+ if ( question . askAnswered !== true && this . answers [ question . name ] !== undefined ) {
395412 return false ;
396413 }
397414
0 commit comments