@@ -395,6 +395,122 @@ func (e *Executor) describeMicroflow(name ast.QualifiedName) error {
395395 return nil
396396}
397397
398+ // describeNanoflow generates re-executable CREATE OR REPLACE NANOFLOW MDL output
399+ // with activities and control flows listed as comments.
400+ func (e * Executor ) describeNanoflow (name ast.QualifiedName ) error {
401+ h , err := e .getHierarchy ()
402+ if err != nil {
403+ return fmt .Errorf ("failed to build hierarchy: %w" , err )
404+ }
405+
406+ // Build entity name lookup
407+ entityNames := make (map [model.ID ]string )
408+ domainModels , _ := e .reader .ListDomainModels ()
409+ for _ , dm := range domainModels {
410+ modName := h .GetModuleName (dm .ContainerID )
411+ for _ , entity := range dm .Entities {
412+ entityNames [entity .ID ] = modName + "." + entity .Name
413+ }
414+ }
415+
416+ // Build microflow/nanoflow name lookup (used for call actions)
417+ microflowNames := make (map [model.ID ]string )
418+ allMicroflows , _ := e .reader .ListMicroflows ()
419+ for _ , mf := range allMicroflows {
420+ microflowNames [mf .ID ] = h .GetQualifiedName (mf .ContainerID , mf .Name )
421+ }
422+
423+ // Find the nanoflow
424+ allNanoflows , err := e .reader .ListNanoflows ()
425+ if err != nil {
426+ return fmt .Errorf ("failed to list nanoflows: %w" , err )
427+ }
428+
429+ for _ , nf := range allNanoflows {
430+ microflowNames [nf .ID ] = h .GetQualifiedName (nf .ContainerID , nf .Name )
431+ }
432+
433+ var targetNf * microflows.Nanoflow
434+ for _ , nf := range allNanoflows {
435+ modID := h .FindModuleID (nf .ContainerID )
436+ modName := h .GetModuleName (modID )
437+ if modName == name .Module && nf .Name == name .Name {
438+ targetNf = nf
439+ break
440+ }
441+ }
442+
443+ if targetNf == nil {
444+ return fmt .Errorf ("nanoflow not found: %s" , name )
445+ }
446+
447+ var lines []string
448+
449+ // Documentation
450+ if targetNf .Documentation != "" {
451+ lines = append (lines , "/**" )
452+ for docLine := range strings .SplitSeq (targetNf .Documentation , "\n " ) {
453+ lines = append (lines , " * " + docLine )
454+ }
455+ lines = append (lines , " */" )
456+ }
457+
458+ // CREATE NANOFLOW header
459+ qualifiedName := name .Module + "." + name .Name
460+ if len (targetNf .Parameters ) > 0 {
461+ lines = append (lines , fmt .Sprintf ("CREATE OR REPLACE NANOFLOW %s (" , qualifiedName ))
462+ for i , param := range targetNf .Parameters {
463+ paramType := "Object"
464+ if param .Type != nil {
465+ paramType = e .formatMicroflowDataType (param .Type , entityNames )
466+ }
467+ comma := ","
468+ if i == len (targetNf .Parameters )- 1 {
469+ comma = ""
470+ }
471+ lines = append (lines , fmt .Sprintf (" $%s: %s%s" , param .Name , paramType , comma ))
472+ }
473+ lines = append (lines , ")" )
474+ } else {
475+ lines = append (lines , fmt .Sprintf ("CREATE OR REPLACE NANOFLOW %s ()" , qualifiedName ))
476+ }
477+
478+ // Return type
479+ if targetNf .ReturnType != nil {
480+ returnType := e .formatMicroflowDataType (targetNf .ReturnType , entityNames )
481+ if returnType != "Void" && returnType != "" {
482+ lines = append (lines , fmt .Sprintf ("RETURNS %s" , returnType ))
483+ }
484+ }
485+
486+ // Folder
487+ if folderPath := h .BuildFolderPath (targetNf .ContainerID ); folderPath != "" {
488+ lines = append (lines , fmt .Sprintf ("FOLDER '%s'" , folderPath ))
489+ }
490+
491+ // BEGIN block with activities
492+ lines = append (lines , "BEGIN" )
493+
494+ // Wrap nanoflow in a Microflow to reuse formatMicroflowActivities
495+ if targetNf .ObjectCollection != nil && len (targetNf .ObjectCollection .Objects ) > 0 {
496+ wrapperMf := & microflows.Microflow {
497+ ObjectCollection : targetNf .ObjectCollection ,
498+ }
499+ activityLines := e .formatMicroflowActivities (wrapperMf , entityNames , microflowNames )
500+ for _ , line := range activityLines {
501+ lines = append (lines , " " + line )
502+ }
503+ } else {
504+ lines = append (lines , " -- No activities" )
505+ }
506+
507+ lines = append (lines , "END;" )
508+ lines = append (lines , "/" )
509+
510+ fmt .Fprintln (e .output , strings .Join (lines , "\n " ))
511+ return nil
512+ }
513+
398514// describeMicroflowToString generates MDL source for a microflow and returns it as a string
399515// along with a source map mapping node IDs to line ranges.
400516func (e * Executor ) describeMicroflowToString (name ast.QualifiedName ) (string , map [string ]elkSourceRange , error ) {
0 commit comments