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,23 +191,43 @@ 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 rl ?: InquirerReadline ;
201199
202- constructor ( prompts : PromptCollection , opt : StreamOptions = { } ) {
200+ constructor (
201+ prompts : PromptCollection ,
202+ { answers, ...opt } : StreamOptions & { answers ?: Partial < A > } = { } ,
203+ ) {
203204 this . opt = opt ;
204205 this . prompts = prompts ;
206+
207+ this . answers = isProxy ( answers )
208+ ? answers
209+ : new Proxy (
210+ { ...answers } ,
211+ {
212+ get : ( target , prop ) => {
213+ if ( typeof prop !== 'string' ) {
214+ return ;
215+ }
216+ return _ . get ( target , prop ) ;
217+ } ,
218+ set : ( target , prop : string , value ) => {
219+ _ . set ( target , prop , value ) ;
220+ return true ;
221+ } ,
222+ } ,
223+ ) ;
205224 }
206225
207- async run ( questions : PromptSession < A > , answers ?: Partial < A > ) : Promise < A > {
226+ async run < Session extends PromptSession < A > = PromptSession < A > > (
227+ questions : Session ,
228+ ) : Promise < A > {
208229 this . abortController = new AbortController ( ) ;
209230
210- // Keep global reference to the answers
211- this . answers = typeof answers === 'object' ? { ...answers } : { } ;
212-
213231 let obs : Observable < AnyQuestion < A > > ;
214232 if ( isQuestionArray ( questions ) ) {
215233 obs = from ( questions ) ;
@@ -224,34 +242,36 @@ export default class PromptsRunner<A extends Answers> {
224242 ) ;
225243 } else {
226244 // Case: Called with a single question config
227- obs = from ( [ questions ] ) ;
245+ obs = from ( [ questions as AnyQuestion < A > ] ) ;
228246 }
229247
230- this . process = obs . pipe (
231- concatMap ( ( question ) =>
232- of ( question ) . pipe (
248+ return lastValueFrom (
249+ obs
250+ . pipe (
233251 concatMap ( ( question ) =>
234- from (
235- this . shouldRun ( question ) . then ( ( shouldRun : boolean | void ) => {
236- if ( shouldRun ) {
237- return question ;
238- }
239- return ;
240- } ) ,
241- ) . pipe ( filter ( ( val ) => val != null ) ) ,
252+ of ( question )
253+ . pipe (
254+ concatMap ( ( question ) =>
255+ from (
256+ this . shouldRun ( question ) . then ( ( shouldRun : boolean | void ) => {
257+ if ( shouldRun ) {
258+ return question ;
259+ }
260+ return ;
261+ } ) ,
262+ ) . pipe ( filter ( ( val ) => val != null ) ) ,
263+ ) ,
264+ concatMap ( ( question ) => defer ( ( ) => from ( this . fetchAnswer ( question ) ) ) ) ,
265+ )
266+ . pipe ( tap ( ( answer ) => this . process . next ( answer ) ) ) ,
242267 ) ,
243- concatMap ( ( question ) => defer ( ( ) => from ( this . fetchAnswer ( question ) ) ) ) ,
268+ )
269+ . pipe (
270+ reduce ( ( answersObj : any , answer : { name : string ; answer : unknown } ) => {
271+ answersObj [ answer . name ] = answer . answer ;
272+ return answersObj ;
273+ } , this . answers ) ,
244274 ) ,
245- ) ,
246- ) ;
247-
248- return lastValueFrom (
249- this . process . pipe (
250- reduce ( ( answersObj , answer : { name : string ; answer : unknown } ) => {
251- _ . set ( answersObj , answer . name , answer . answer ) ;
252- return answersObj ;
253- } , this . answers ) ,
254- ) ,
255275 )
256276 . then ( ( ) => this . answers as A )
257277 . finally ( ( ) => this . close ( ) ) ;
@@ -389,10 +409,7 @@ export default class PromptsRunner<A extends Answers> {
389409 } ;
390410
391411 private shouldRun = async ( question : AnyQuestion < A > ) : Promise < boolean > => {
392- if (
393- question . askAnswered !== true &&
394- _ . get ( this . answers , question . name ) !== undefined
395- ) {
412+ if ( question . askAnswered !== true && this . answers [ question . name ] !== undefined ) {
396413 return false ;
397414 }
398415
0 commit comments