@@ -271,18 +271,16 @@ var devCommand = cli.Command{
271271 Value : false ,
272272 Usage : "Only check for diagnostic errors without running a full build." ,
273273 },
274- & cli.BoolFlag {
275- Name : "lint-first" ,
276- Value : false ,
277- Usage : "Run linting before starting the build process." ,
278- },
279274 },
280275 Action : runPreview ,
281276}
282277
283278func runPreview (ctx context.Context , cmd * cli.Command ) error {
284279 cc := getAPICommandContext (cmd )
285280
281+ openapiSpecPath := cmd .String ("openapi-spec" )
282+ stainlessConfigPath := cmd .String ("stainless-config" )
283+
286284 // If only linting is requested, run in lint-only mode
287285 if cmd .Bool ("lint" ) {
288286 return runLintLoop (ctx , cmd )
@@ -366,18 +364,29 @@ func runPreview(ctx context.Context, cmd *cli.Command) error {
366364
367365 // Phase 3: Start build and monitor progress in a loop
368366 for {
369- // Check if we should run linting before building
370- if cmd . Bool ( "lint-first" ) {
371- diagnostics , err := getPreviewDiagnosticsJSON (ctx , cmd )
367+ // Keep checking diagnostics until they're all fixed
368+ for {
369+ diagnostics , err := getPreviewDiagnostics (ctx , cmd )
372370 if err != nil {
373371 if errors .Is (err , ErrUserCancelled ) {
374372 return nil
375373 }
376374 return err
377375 }
378- jsonObj := gjson .Parse (diagnostics .Raw )
379- transform := cmd .String ("transform" )
380- ShowJSON ("Linting Results" , jsonObj , cmd .String ("format" ), transform )
376+
377+ if len (diagnostics ) > 0 {
378+ fmt .Println (ViewDiagnosticsPrint (diagnostics , 10 ))
379+ }
380+
381+ if hasBlockingDiagnostic (diagnostics ) {
382+ fmt .Println ("\n Diagnostic checks will re-run once you edit your configuration files..." )
383+ if err := waitTillAnyFileChanged (ctx , []string {openapiSpecPath , stainlessConfigPath }); err != nil {
384+ return err
385+ }
386+ continue
387+ } else {
388+ break
389+ }
381390 }
382391
383392 // Start the build process
@@ -401,16 +410,6 @@ func runLintLoop(ctx context.Context, cmd *cli.Command) error {
401410 openapiSpecPath := cmd .String ("openapi-spec" )
402411 stainlessConfigPath := cmd .String ("stainless-config" )
403412
404- var openapiSpecLastModified , stainlessConfigLastModified time.Time
405-
406- if openapiSpecStat , err := os .Stat (openapiSpecPath ); err == nil {
407- openapiSpecLastModified = openapiSpecStat .ModTime ()
408- }
409-
410- if stainlessConfigStat , err := os .Stat (stainlessConfigPath ); err == nil {
411- stainlessConfigLastModified = stainlessConfigStat .ModTime ()
412- }
413-
414413 for {
415414 diagnostics , err := getPreviewDiagnosticsJSON (ctx , cmd )
416415 if err != nil {
@@ -426,31 +425,37 @@ func runLintLoop(ctx context.Context, cmd *cli.Command) error {
426425 break
427426 }
428427
429- for {
430- time .Sleep (500 * time .Millisecond )
428+ if err := waitTillAnyFileChanged (ctx , []string {openapiSpecPath , stainlessConfigPath }); err != nil {
429+ return err
430+ }
431+ }
432+ return nil
433+ }
431434
432- if openapiSpecStat , err := os .Stat (openapiSpecPath ); err == nil {
433- if openapiSpecStat .ModTime ().After (openapiSpecLastModified ) {
434- openapiSpecLastModified = openapiSpecStat .ModTime ()
435- break // File changed, run linting again
436- }
437- }
435+ func waitTillAnyFileChanged (ctx context.Context , files []string ) error {
436+ lastModified := make (map [string ]time.Time )
437+ for _ , file := range files {
438+ if stat , err := os .Stat (file ); err == nil {
439+ lastModified [file ] = stat .ModTime ()
440+ }
441+ }
438442
439- // Check Stainless config file
440- if stainlessConfigStat , err := os .Stat (stainlessConfigPath ); err == nil {
441- if stainlessConfigStat .ModTime ().After (stainlessConfigLastModified ) {
442- stainlessConfigLastModified = stainlessConfigStat .ModTime ()
443- break // File changed, run linting again
444- }
445- }
443+ for {
444+ time .Sleep (500 * time .Millisecond )
446445
447- // Check for cancellation
448- select {
449- case <- ctx . Done ():
450- return ctx . Err ()
451- default :
446+ for _ , file := range files {
447+ if stat , err := os . Stat ( file ); err == nil {
448+ if stat . ModTime (). After ( lastModified [ file ]) {
449+ return nil
450+ }
452451 }
453452 }
453+ // Check for cancellation
454+ select {
455+ case <- ctx .Done ():
456+ return ctx .Err ()
457+ default :
458+ }
454459 }
455460 return nil
456461}
@@ -547,7 +552,7 @@ func getPreviewDiagnosticsJSON(ctx context.Context, cmd *cli.Command) (*gjson.Re
547552 return nil , err
548553 }
549554 json := gjson .ParseBytes (result )
550- diagnostics := json .Get ("spec.diagnostics.@values.@flatten.#.{code,level,ignored,endpoint,message,more,language,location,stainlessPath,oasRef,configRef} " )
555+ diagnostics := json .Get ("spec.diagnostics.@values.@flatten" )
551556 return & diagnostics , nil
552557}
553558
@@ -562,3 +567,19 @@ func getPreviewDiagnostics(ctx context.Context, cmd *cli.Command) ([]stainless.B
562567 }
563568 return diagnostics , err
564569}
570+
571+ func hasBlockingDiagnostic (diagnostics []stainless.BuildDiagnostic ) bool {
572+ for _ , d := range diagnostics {
573+ if ! d .Ignored {
574+ switch d .Level {
575+ case stainless .BuildDiagnosticLevelFatal :
576+ case stainless .BuildDiagnosticLevelError :
577+ case stainless .BuildDiagnosticLevelWarning :
578+ return true
579+ case stainless .BuildDiagnosticLevelNote :
580+ continue
581+ }
582+ }
583+ }
584+ return false
585+ }
0 commit comments