11use rquickjs:: module:: { Declarations , Exports , ModuleDef } ;
22use rquickjs:: { prelude:: Func , Ctx , Exception , Object , Result } ;
3- pub mod types;
3+ use std:: collections:: HashMap ;
4+ use std:: env;
5+ use std:: sync:: { Arc , Condvar , LazyLock , Mutex } ;
46
5- # [ cfg ( feature = "native" ) ]
6- pub mod native ;
7+ static STEP_OUTPUTS_STORE : LazyLock < Mutex < HashMap < String , HashMap < String , String > > > > =
8+ LazyLock :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
79
8- #[ cfg( feature ="wasm" ) ]
9- pub mod wasm;
10+ static STEP_OUTPUT_NOTIFIER : LazyLock < Arc < Condvar > > =LazyLock :: new ( ||Arc :: new ( Condvar :: new ( ) ) ) ;
11+
12+ pub fn set_step_output (
13+ output_name : & str ,
14+ value : & str ,
15+ ) -> std:: result:: Result < ( ) , Box < dyn std:: error:: Error > > {
16+ let step_id = env:: var ( "CODEMOD_STEP_ID" ) . unwrap_or_default ( ) ;
17+
18+ {
19+ let mut store =STEP_OUTPUTS_STORE . lock ( ) . unwrap ( ) ;
20+ store
21+ . entry ( step_id)
22+ . or_default ( )
23+ . insert ( output_name. to_string ( ) , value. to_string ( ) ) ;
24+ }
25+
26+ STEP_OUTPUT_NOTIFIER . notify_all ( ) ;
27+
28+ Ok ( ( ) )
29+ }
30+
31+ pub fn get_step_output (
32+ step_id : & str ,
33+ output_name : & str ,
34+ ) -> std:: result:: Result < Option < String > , Box < dyn std:: error:: Error > > {
35+ let store =STEP_OUTPUTS_STORE . lock ( ) . unwrap ( ) ;
36+
37+ if let Some ( outputs) = store. get ( step_id) {
38+ if let Some ( value) = outputs. get ( output_name) {
39+ return Ok ( Some ( value. clone ( ) ) ) ;
40+ }
41+ }
42+
43+ Ok ( None )
44+ }
45+
46+ pub fn get_step_outputs (
47+ step_id : & str ,
48+ ) -> std:: result:: Result < HashMap < String , String > , Box < dyn std:: error:: Error > > {
49+ let store =STEP_OUTPUTS_STORE . lock ( ) . unwrap ( ) ;
50+
51+ if let Some ( outputs) = store. get ( step_id) {
52+ Ok ( outputs. clone ( ) )
53+ } else {
54+ Ok ( HashMap :: new ( ) )
55+ }
56+ }
57+
58+ /// Get or set step output atomically
59+ /// If the output exists, returns it. If not, sets it to the provided value and returns it.
60+ pub fn get_or_set_step_output (
61+ step_id : & str ,
62+ output_name : & str ,
63+ default_value : & str ,
64+ ) -> std:: result:: Result < String , Box < dyn std:: error:: Error > > {
65+ let mut store =STEP_OUTPUTS_STORE . lock ( ) . unwrap ( ) ;
66+
67+ let outputs = store. entry ( step_id. to_string ( ) ) . or_default ( ) ;
68+
69+ if let Some ( value) = outputs. get ( output_name) {
70+ // Output already exists, return it
71+ Ok ( value. clone ( ) )
72+ } else {
73+ // Output doesn't exist, set it and return the new value
74+ outputs. insert ( output_name. to_string ( ) , default_value. to_string ( ) ) ;
75+ drop ( store) ; // Release lock before notifying
76+ STEP_OUTPUT_NOTIFIER . notify_all ( ) ;
77+ Ok ( default_value. to_string ( ) )
78+ }
79+ }
1080
1181#[ allow( dead_code) ]
1282pub ( crate ) struct WorkflowGlobalModule ;
@@ -15,6 +85,8 @@ impl ModuleDef for WorkflowGlobalModule {
1585fn declare ( declare : & Declarations ) ->Result < ( ) > {
1686 declare. declare ( "setStepOutput" ) ?;
1787 declare. declare ( "getStepOutput" ) ?;
88+ declare. declare ( "waitForStepOutput" ) ?;
89+ declare. declare ( "getOrSetStepOutput" ) ?;
1890 declare. declare ( "default" ) ?;
1991Ok ( ( ) )
2092}
@@ -24,21 +96,19 @@ impl ModuleDef for WorkflowGlobalModule {
2496
2597 default. set ( "setStepOutput" , Func :: from ( set_step_output_rjs) ) ?;
2698 default. set ( "getStepOutput" , Func :: from ( get_step_output_rjs) ) ?;
99+ default. set ( "getOrSetStepOutput" , Func :: from ( get_or_set_step_output_rjs) ) ?;
27100
28101 exports. export ( "setStepOutput" , Func :: from ( set_step_output_rjs) ) ?;
29102 exports. export ( "getStepOutput" , Func :: from ( get_step_output_rjs) ) ?;
103+ exports. export ( "getOrSetStepOutput" , Func :: from ( get_or_set_step_output_rjs) ) ?;
30104
31105 exports. export ( "default" , default) ?;
32106Ok ( ( ) )
33107}
34108}
35109
36110fn set_step_output_rjs ( ctx : Ctx < ' _ > , output_name : String , value : String ) ->Result < ( ) > {
37- #[ cfg( feature ="native" ) ]
38- let result = native:: set_step_output ( & output_name, & value) ;
39- #[ cfg( feature ="wasm" ) ]
40- let result = wasm:: set_step_output ( & output_name, & value) ;
41-
111+ let result =set_step_output ( & output_name, & value) ;
42112 result. map_err ( |e|Exception :: throw_message ( & ctx, & format ! ( "Failed to set step output: {e}" ) ) )
43113}
44114
@@ -47,10 +117,18 @@ fn get_step_output_rjs(
47117step_id : String ,
48118output_name : String ,
49119) ->Result < Option < String > > {
50- #[ cfg( feature ="native" ) ]
51- let result = native:: get_step_output ( & step_id, & output_name) ;
52- #[ cfg( feature ="wasm" ) ]
53- let result = wasm:: get_step_output ( & step_id, & output_name) ;
54-
120+ let result =get_step_output ( & step_id, & output_name) ;
55121 result. map_err ( |e|Exception :: throw_message ( & ctx, & format ! ( "Failed to get step output: {e}" ) ) )
56122}
123+
124+ fn get_or_set_step_output_rjs (
125+ ctx : Ctx < ' _ > ,
126+ step_id : String ,
127+ output_name : String ,
128+ default_value : String ,
129+ ) ->Result < String > {
130+ let result =get_or_set_step_output ( & step_id, & output_name, & default_value) ;
131+ result. map_err ( |e|{
132+ Exception :: throw_message ( & ctx, & format ! ( "Failed to get or set step output: {e}" ) )
133+ } )
134+ }