11import { Either , Match } from "effect"
2- import { type CreateCommand , type ParseError , deriveRepoPathParts , resolveRepoInput } from "./frontend-lib/core/domain.js"
2+ import {
3+ type CreateCommand ,
4+ deriveRepoPathParts ,
5+ type ParseError ,
6+ resolveRepoInput
7+ } from "./frontend-lib/core/domain.js"
38import { defaultProjectsRoot } from "./frontend-lib/usecases/menu-helpers.js"
49
510import { buildCreateCommand } from "./cli/parser-create.js"
@@ -25,6 +30,12 @@ type AdvanceCreateFlowResult =
2530 | { readonly _tag : "Error" ; readonly error : ParseError }
2631 | { readonly _tag : "Complete" ; readonly inputs : CreateInputs }
2732
33+ type AdvanceCreateFlowHandlers = {
34+ readonly onComplete : ( inputs : CreateInputs ) => void
35+ readonly onContinue : ( view : CreateFlowView ) => void
36+ readonly onError : ( error : ParseError ) => void
37+ }
38+
2839type AdvanceCreateFlowOptions = {
2940 readonly quickCreate ?: boolean
3041}
@@ -134,59 +145,67 @@ const createParseError = (reason: string): ParseError => ({
134145 reason
135146} )
136147
148+ type CreateTokenizeState = {
149+ current : string
150+ escaping : boolean
151+ quote : "'" | "\"" | null
152+ readonly tokens : Array < string >
153+ }
154+
155+ const pushCreateToken = ( state : CreateTokenizeState ) : void => {
156+ if ( state . current . length > 0 ) {
157+ state . tokens . push ( state . current )
158+ state . current = ""
159+ }
160+ }
161+
162+ const consumeCreateTokenChar = ( state : CreateTokenizeState , char : string ) : void => {
163+ if ( state . escaping ) {
164+ state . current += char
165+ state . escaping = false
166+ return
167+ }
168+ if ( char === "\\" ) {
169+ state . escaping = true
170+ return
171+ }
172+ if ( state . quote !== null ) {
173+ if ( char === state . quote ) {
174+ state . quote = null
175+ return
176+ }
177+ state . current += char
178+ return
179+ }
180+ if ( char === "'" || char === "\"" ) {
181+ state . quote = char
182+ return
183+ }
184+ if ( / \s / u. test ( char ) ) {
185+ pushCreateToken ( state )
186+ return
187+ }
188+ state . current += char
189+ }
190+
137191const tokenizeCreateCommandLine = (
138192 input : string
139193) : Either . Either < ReadonlyArray < string > , ParseError > => {
140- const tokens : Array < string > = [ ]
141- let current = ""
142- let quote : "'" | "\"" | null = null
143- let escaping = false
144-
145- const pushCurrent = ( ) => {
146- if ( current . length > 0 ) {
147- tokens . push ( current )
148- current = ""
149- }
150- }
194+ const state : CreateTokenizeState = { current : "" , escaping : false , quote : null , tokens : [ ] }
151195
152196 for ( const char of input . trim ( ) ) {
153- if ( escaping ) {
154- current += char
155- escaping = false
156- continue
157- }
158- if ( char === "\\" ) {
159- escaping = true
160- continue
161- }
162- if ( quote !== null ) {
163- if ( char === quote ) {
164- quote = null
165- } else {
166- current += char
167- }
168- continue
169- }
170- if ( char === "'" || char === "\"" ) {
171- quote = char
172- continue
173- }
174- if ( / \s / u. test ( char ) ) {
175- pushCurrent ( )
176- continue
177- }
178- current += char
197+ consumeCreateTokenChar ( state , char )
179198 }
180199
181- if ( escaping ) {
200+ if ( state . escaping ) {
182201 return Either . left ( createParseError ( "unterminated escape sequence" ) )
183202 }
184- if ( quote !== null ) {
203+ if ( state . quote !== null ) {
185204 return Either . left ( createParseError ( "unterminated quoted value" ) )
186205 }
187206
188- pushCurrent ( )
189- return Either . right ( tokens )
207+ pushCreateToken ( state )
208+ return Either . right ( state . tokens )
190209}
191210
192211const unsupportedCreatePrefixes = new Set ( [
@@ -234,22 +253,40 @@ const normalizeCreateTokens = (
234253 return Either . right ( withoutBinary )
235254}
236255
256+ type RawCreateOptions = Parameters < typeof buildCreateCommand > [ 0 ]
257+
258+ const cpuLimitCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
259+ raw . cpuLimit === undefined ? { } : { cpuLimit : command . config . cpuLimit ?? "" }
260+
261+ const ramLimitCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
262+ raw . ramLimit === undefined ? { } : { ramLimit : command . config . ramLimit ?? "" }
263+
264+ const runUpCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
265+ raw . up === undefined ? { } : { runUp : command . runUp }
266+
267+ const playwrightCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
268+ raw . enableMcpPlaywright === undefined ? { } : { enableMcpPlaywright : command . config . enableMcpPlaywright }
269+
270+ const forceCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
271+ raw . force === undefined ? { } : { force : command . force }
272+
273+ const forceEnvCreateInput = ( raw : RawCreateOptions , command : CreateCommand ) : Partial < CreateInputs > =>
274+ raw . forceEnv === undefined ? { } : { forceEnv : command . forceEnv }
275+
237276const createInputsFromCommand = (
238277 repoUrl : string ,
239- raw : Parameters < typeof buildCreateCommand > [ 0 ] ,
278+ raw : RawCreateOptions ,
240279 command : CreateCommand
241280) : Partial < CreateInputs > => ( {
242281 repoUrl,
243282 repoRef : command . config . repoRef ,
244283 outDir : command . outDir ,
245- ...( raw . cpuLimit !== undefined ? { cpuLimit : command . config . cpuLimit ?? "" } : { } ) ,
246- ...( raw . ramLimit !== undefined ? { ramLimit : command . config . ramLimit ?? "" } : { } ) ,
247- ...( raw . up !== undefined ? { runUp : command . runUp } : { } ) ,
248- ...( raw . enableMcpPlaywright !== undefined
249- ? { enableMcpPlaywright : command . config . enableMcpPlaywright }
250- : { } ) ,
251- ...( raw . force !== undefined ? { force : command . force } : { } ) ,
252- ...( raw . forceEnv !== undefined ? { forceEnv : command . forceEnv } : { } )
284+ ...cpuLimitCreateInput ( raw , command ) ,
285+ ...ramLimitCreateInput ( raw , command ) ,
286+ ...runUpCreateInput ( raw , command ) ,
287+ ...playwrightCreateInput ( raw , command ) ,
288+ ...forceCreateInput ( raw , command ) ,
289+ ...forceEnvCreateInput ( raw , command )
253290} )
254291
255292const parseRepoStepInput = (
@@ -279,9 +316,12 @@ const parseRepoStepInput = (
279316 } )
280317}
281318
282- const createStepApplied = ( ) : Either . Either < true , ParseError > => Either . right ( true as const )
319+ const createStepApplied = ( ) : Either . Either < true , ParseError > => {
320+ const applied = true
321+ return Either . right ( applied )
322+ }
283323
284- const hasOwn = < K extends keyof CreateInputs > ( values : Partial < CreateInputs > , key : K ) : boolean =>
324+ const hasOwn = ( values : Partial < CreateInputs > , key : keyof CreateInputs ) : boolean =>
285325 Object . prototype . hasOwnProperty . call ( values , key )
286326
287327const isCreateStepSatisfied = (
@@ -432,6 +472,24 @@ export const advanceCreateFlow = (
432472 }
433473}
434474
475+ export const handleAdvanceCreateFlowResult = (
476+ next : AdvanceCreateFlowResult | null ,
477+ handlers : AdvanceCreateFlowHandlers
478+ ) : void => {
479+ if ( next === null ) {
480+ return
481+ }
482+ if ( next . _tag === "Error" ) {
483+ handlers . onError ( next . error )
484+ return
485+ }
486+ if ( next . _tag === "Continue" ) {
487+ handlers . onContinue ( next . view )
488+ return
489+ }
490+ handlers . onComplete ( next . inputs )
491+ }
492+
435493export const createProjectDraftFromInputs = (
436494 input : CreateInputs
437495) : {
0 commit comments