@@ -3,7 +3,7 @@ use crate::prelude::*;
33use crate :: base:: schema:: { FieldSchema , ValueType } ;
44use crate :: base:: spec:: VectorSimilarityMetric ;
55use crate :: base:: spec:: { NamedSpec , ReactiveOpSpec } ;
6- use crate :: base:: spec:: { OutputMode , SpecFormatter } ;
6+ use crate :: base:: spec:: { OutputMode , RenderedSpec , RenderedSpecLine , SpecFormatter } ;
77use crate :: execution:: query;
88use crate :: lib_context:: { clear_lib_context, get_auth_registry, init_lib_context} ;
99use crate :: ops:: interface:: { QueryResult , QueryResults } ;
@@ -198,76 +198,94 @@ impl Flow {
198198 } )
199199 }
200200
201- #[ pyo3( signature = ( output_mode="concise" ) ) ]
202- pub fn get_spec ( & self , output_mode : & str ) -> PyResult < Vec < ( String , String , u32 ) > > {
203- let mode = OutputMode :: from_str ( output_mode ) ;
201+ #[ pyo3( signature = ( output_mode=None ) ) ]
202+ pub fn get_spec ( & self , output_mode : Option < Pythonized < OutputMode > > ) -> PyResult < RenderedSpec > {
203+ let mode = output_mode . map_or ( OutputMode :: Concise , |m| m . into_inner ( ) ) ;
204204 let spec = & self . 0 . flow . flow_instance ;
205- let mut result = Vec :: with_capacity (
206- 1 + spec. import_ops . len ( )
207- + spec. reactive_ops . len ( )
208- + spec. export_ops . len ( )
209- + spec. declarations . len ( ) ,
205+ let mut sections: IndexMap < String , Vec < RenderedSpecLine > > = IndexMap :: new ( ) ;
206+
207+ // Initialize sections
208+ sections. insert (
209+ "Header" . to_string ( ) ,
210+ vec ! [ RenderedSpecLine {
211+ content: format!( "Flow: {}" , spec. name) ,
212+ scope: None ,
213+ children: vec![ ] ,
214+ } ] ,
210215 ) ;
211-
212- fn extend_with < T , I , F > (
213- out : & mut Vec < ( String , String , u32 ) > ,
214- label : & ' static str ,
215- items : I ,
216- f : F ,
217- ) where
218- I : IntoIterator < Item = T > ,
219- F : Fn ( & T ) -> String ,
220- {
221- out. extend ( items. into_iter ( ) . map ( |item| ( label. into ( ) , f ( & item) , 0 ) ) ) ;
216+ for key in [ "Sources" , "Processing" , "Targets" , "Declarations" ] {
217+ sections. insert ( key. to_string ( ) , Vec :: new ( ) ) ;
222218 }
223219
224- // Header
225- result. push ( ( "Header" . into ( ) , format ! ( "Flow: {}" , spec. name) , 0 ) ) ;
226-
227220 // Sources
228- extend_with ( & mut result, "Sources" , spec. import_ops . iter ( ) , |op| {
229- format ! ( "Import: name={}, {}" , op. name, op. spec. format( mode) )
230- } ) ;
221+ for op in & spec. import_ops {
222+ sections
223+ . entry ( "Sources" . to_string ( ) )
224+ . or_default ( )
225+ . push ( RenderedSpecLine {
226+ content : format ! ( "Import: name={}, {}" , op. name, op. spec. format( mode) ) ,
227+ scope : None ,
228+ children : vec ! [ ] ,
229+ } ) ;
230+ }
231231
232232 // Processing
233233 fn walk (
234234 op : & NamedSpec < ReactiveOpSpec > ,
235- indent : u32 ,
236235 mode : OutputMode ,
237- out : & mut Vec < ( String , String , u32 ) > ,
238- ) {
239- out. push ( (
240- "Processing" . into ( ) ,
241- format ! ( "{}: {}" , op. name, op. spec. format( mode) ) ,
242- indent,
243- ) ) ;
236+ scope : Option < String > ,
237+ ) -> RenderedSpecLine {
238+ let content = format ! ( "{}: {}" , op. name, op. spec. format( mode) ) ;
239+ let mut line = RenderedSpecLine {
240+ content,
241+ scope,
242+ children : vec ! [ ] ,
243+ } ;
244244
245245 if let ReactiveOpSpec :: ForEach ( fe) = & op. spec {
246- out. push ( ( "Processing" . into ( ) , fe. op_scope . to_string ( ) , indent + 1 ) ) ;
247246 for nested in & fe. op_scope . ops {
248- walk ( nested, indent + 2 , mode, out) ;
247+ line. children
248+ . push ( walk ( nested, mode, Some ( fe. op_scope . name . clone ( ) ) ) ) ;
249249 }
250250 }
251+
252+ line
251253 }
252254
253255 for op in & spec. reactive_ops {
254- walk ( op, 0 , mode, & mut result) ;
256+ sections
257+ . entry ( "Processing" . to_string ( ) )
258+ . or_default ( )
259+ . push ( walk ( op, mode, None ) ) ;
255260 }
256261
257262 // Targets
258- extend_with ( & mut result, "Targets" , spec. export_ops . iter ( ) , |op| {
259- format ! ( "Export: name={}, {}" , op. name, op. spec. format( mode) )
260- } ) ;
263+ for op in & spec. export_ops {
264+ sections
265+ . entry ( "Targets" . to_string ( ) )
266+ . or_default ( )
267+ . push ( RenderedSpecLine {
268+ content : format ! ( "Export: name={}, {}" , op. name, op. spec. format( mode) ) ,
269+ scope : None ,
270+ children : vec ! [ ] ,
271+ } ) ;
272+ }
261273
262274 // Declarations
263- extend_with (
264- & mut result,
265- "Declarations" ,
266- spec. declarations . iter ( ) ,
267- |decl| format ! ( "Declaration: {}" , decl. format( mode) ) ,
268- ) ;
275+ for decl in & spec. declarations {
276+ sections
277+ . entry ( "Declarations" . to_string ( ) )
278+ . or_default ( )
279+ . push ( RenderedSpecLine {
280+ content : format ! ( "Declaration: {}" , decl. format( mode) ) ,
281+ scope : None ,
282+ children : vec ! [ ] ,
283+ } ) ;
284+ }
269285
270- Ok ( result)
286+ Ok ( RenderedSpec {
287+ sections : sections. into_iter ( ) . collect ( ) ,
288+ } )
271289 }
272290
273291 pub fn get_schema ( & self ) -> Vec < ( String , String , String ) > {
@@ -518,6 +536,8 @@ fn cocoindex_engine(m: &Bound<'_, PyModule>) -> PyResult<()> {
518536 m. add_class :: < SimpleSemanticsQueryHandler > ( ) ?;
519537 m. add_class :: < SetupStatusCheck > ( ) ?;
520538 m. add_class :: < PyOpArgSchema > ( ) ?;
539+ m. add_class :: < RenderedSpec > ( ) ?;
540+ m. add_class :: < RenderedSpecLine > ( ) ?;
521541
522542 Ok ( ( ) )
523543}
0 commit comments