@@ -15,6 +15,10 @@ module Compilers
1515 # - Predicate: `def name?` - returns boolean
1616 # - Setter: `def name=` (private) - sets the value
1717 #
18+ # Additionally, typed inner classes are generated:
19+ # - `Arguments` - T::Struct representing all service arguments
20+ # - `Outputs` - T::Struct representing all service outputs
21+ #
1822 # @example Service definition
1923 # class CreateUser < Operandi::Base
2024 # arg :name, type: String
@@ -26,6 +30,22 @@ module Compilers
2630 #
2731 # @example Generated RBI
2832 # class CreateUser
33+ # class Arguments < T::Struct
34+ # prop :name, ::String
35+ # prop :email, T.nilable(::String), default: nil
36+ # prop :role, T.any(::Symbol, ::String)
37+ # end
38+ #
39+ # class Outputs < T::Struct
40+ # prop :user, ::User
41+ # end
42+ #
43+ # sig { returns(Arguments) }
44+ # def arguments; end
45+ #
46+ # sig { returns(Outputs) }
47+ # def outputs; end
48+ #
2949 # sig { returns(String) }
3050 # def name; end
3151 #
@@ -81,6 +101,10 @@ def decorate
81101 # Generate class methods (.run, .run!, .with)
82102 generate_class_methods ( klass )
83103
104+ # Generate typed inner classes for arguments and outputs
105+ generate_arguments_type ( klass )
106+ generate_outputs_type ( klass )
107+
84108 # Generate argument methods
85109 constant . arguments . each_value do |field |
86110 generate_field_methods ( klass , field )
@@ -102,6 +126,22 @@ def generate_class_methods(klass)
102126 generate_with_method ( klass )
103127 end
104128
129+ sig { params ( klass : RBI ::Scope ) . void }
130+ def generate_arguments_type ( klass )
131+ return if constant . arguments . empty?
132+
133+ generate_struct_class ( klass , "Arguments" , constant . arguments )
134+ klass . create_method ( "arguments" , return_type : "Arguments" )
135+ end
136+
137+ sig { params ( klass : RBI ::Scope ) . void }
138+ def generate_outputs_type ( klass )
139+ return if constant . outputs . empty?
140+
141+ generate_struct_class ( klass , "Outputs" , constant . outputs )
142+ klass . create_method ( "outputs" , return_type : "Outputs" )
143+ end
144+
105145 sig { params ( klass : RBI ::Scope ) . void }
106146 def generate_run_method ( klass )
107147 klass . create_method (
@@ -248,6 +288,33 @@ def as_nilable_type(type)
248288
249289 "T.nilable(#{ type } )"
250290 end
291+
292+ sig do
293+ params (
294+ klass : RBI ::Scope ,
295+ class_name : String ,
296+ fields : T ::Hash [ Symbol , ::Operandi ::Settings ::Field ] ,
297+ ) . void
298+ end
299+ def generate_struct_class ( klass , class_name , fields )
300+ return if fields . empty?
301+
302+ klass . create_class ( class_name , superclass_name : "T::Struct" ) do |struct_klass |
303+ fields . each_value do |field |
304+ generate_struct_prop ( struct_klass , field )
305+ end
306+ end
307+ end
308+
309+ sig { params ( struct_klass : RBI ::Scope , field : ::Operandi ::Settings ::Field ) . void }
310+ def generate_struct_prop ( struct_klass , field )
311+ name = field . name . to_s
312+ ruby_type = resolve_type ( field )
313+ prop_type = field . optional ? as_nilable_type ( ruby_type ) : ruby_type
314+ default_value = format_default_value ( field ) if field . optional || field . default_exists
315+
316+ struct_klass << RBI ::TStructProp . new ( name , prop_type , default : default_value )
317+ end
251318 end
252319 end
253320 end
0 commit comments