rails-openapi-gen 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/CLAUDE.md +17 -5
- data/README.md +25 -0
- data/lib/rails-openapi-gen/ast_nodes/array_node.rb +101 -0
- data/lib/rails-openapi-gen/ast_nodes/base_node.rb +139 -0
- data/lib/rails-openapi-gen/ast_nodes/comment_data.rb +180 -0
- data/lib/rails-openapi-gen/ast_nodes/node_factory.rb +206 -0
- data/lib/rails-openapi-gen/ast_nodes/object_node.rb +129 -0
- data/lib/rails-openapi-gen/ast_nodes/partial_node.rb +111 -0
- data/lib/rails-openapi-gen/ast_nodes/property_node.rb +74 -0
- data/lib/rails-openapi-gen/ast_nodes.rb +129 -0
- data/lib/rails-openapi-gen/configuration.rb +154 -22
- data/lib/rails-openapi-gen/debug_helpers.rb +185 -0
- data/lib/rails-openapi-gen/engine.rb +1 -1
- data/lib/rails-openapi-gen/generators/yaml_generator.rb +242 -27
- data/lib/rails-openapi-gen/generators.rb +5 -0
- data/lib/rails-openapi-gen/importer.rb +164 -145
- data/lib/rails-openapi-gen/parsers/comment_parser.rb +1 -1
- data/lib/rails-openapi-gen/parsers/comment_parsers/attribute_parser.rb +7 -7
- data/lib/rails-openapi-gen/parsers/comment_parsers/base_attribute_parser.rb +5 -9
- data/lib/rails-openapi-gen/parsers/comment_parsers/body_parser.rb +6 -6
- data/lib/rails-openapi-gen/parsers/comment_parsers/conditional_parser.rb +1 -1
- data/lib/rails-openapi-gen/parsers/comment_parsers/operation_parser.rb +5 -5
- data/lib/rails-openapi-gen/parsers/comment_parsers/param_parser.rb +6 -6
- data/lib/rails-openapi-gen/parsers/comment_parsers/query_parser.rb +6 -6
- data/lib/rails-openapi-gen/parsers/controller_parser.rb +64 -20
- data/lib/rails-openapi-gen/parsers/jbuilder/ast_parser.rb +914 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/array_call_detector.rb +103 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/base_detector.rb +107 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/cache_call_detector.rb +112 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/json_call_detector.rb +91 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/key_format_detector.rb +27 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/null_handling_detector.rb +27 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/object_manipulation_detector.rb +27 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors/partial_call_detector.rb +125 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/call_detectors.rb +95 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/jbuilder_parser.rb +39 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/operation_comment_parser.rb +26 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/array_processor.rb +266 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/base_processor.rb +235 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/composite_processor.rb +97 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/object_processor.rb +176 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/partial_processor.rb +69 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors/property_processor.rb +68 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/processors.rb +10 -0
- data/lib/rails-openapi-gen/parsers/jbuilder/property_comment_parser.rb +26 -0
- data/lib/rails-openapi-gen/parsers/jbuilder.rb +10 -0
- data/lib/rails-openapi-gen/parsers/routes_parser.rb +83 -9
- data/lib/rails-openapi-gen/parsers/template_processors/jbuilder_template_processor.rb +125 -131
- data/lib/rails-openapi-gen/parsers/template_processors/response_template_processor.rb +8 -12
- data/lib/rails-openapi-gen/parsers/template_processors.rb +6 -0
- data/lib/rails-openapi-gen/parsers.rb +9 -0
- data/lib/rails-openapi-gen/processors/ast_to_schema_processor.rb +226 -0
- data/lib/rails-openapi-gen/processors/base_processor.rb +124 -0
- data/lib/rails-openapi-gen/processors/component_schema_processor.rb +35 -0
- data/lib/rails-openapi-gen/processors/openapi_schema_processor.rb +218 -0
- data/lib/rails-openapi-gen/processors.rb +7 -0
- data/lib/rails-openapi-gen/railtie.rb +1 -1
- data/lib/rails-openapi-gen/tasks/openapi.rake +4 -4
- data/lib/rails-openapi-gen/version.rb +1 -1
- data/lib/rails-openapi-gen.rb +169 -196
- data/lib/tasks/openapi_import.rake +35 -36
- data/rails-openapi-gen.gemspec +6 -5
- metadata +62 -23
- data/lib/rails-openapi-gen/parsers/jbuilder_parser.rb +0 -529
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsOpenapiGen::AstNodes
|
4
|
+
# Factory class for creating AST nodes
|
5
|
+
# Provides convenient methods for creating different types of nodes
|
6
|
+
class NodeFactory
|
7
|
+
class << self
|
8
|
+
# Create a property node
|
9
|
+
# @param property_name [String] Name of the property
|
10
|
+
# @param comment_data [CommentData, Hash, nil] Comment data
|
11
|
+
# @param is_conditional [Boolean] Whether property is conditional
|
12
|
+
# @param is_component_ref [Boolean] Whether this is a component reference
|
13
|
+
# @param component_name [String, nil] Name of the referenced component
|
14
|
+
# @param parent [BaseNode, nil] Parent node
|
15
|
+
# @return [PropertyNode] Created property node
|
16
|
+
def create_property(property_name:, comment_data: nil, is_conditional: false, is_component_ref: false, component_name: nil, parent: nil)
|
17
|
+
PropertyNode.new(
|
18
|
+
property_name: property_name,
|
19
|
+
comment_data: normalize_comment_data(comment_data),
|
20
|
+
is_conditional: is_conditional,
|
21
|
+
is_component_ref: is_component_ref,
|
22
|
+
component_name: component_name,
|
23
|
+
parent: parent
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create an array node
|
28
|
+
# @param property_name [String, nil] Name of the array property
|
29
|
+
# @param comment_data [CommentData, Hash, nil] Comment data
|
30
|
+
# @param is_conditional [Boolean] Whether array is conditional
|
31
|
+
# @param is_root_array [Boolean] Whether this is a root array (json.array!)
|
32
|
+
# @param parent [BaseNode, nil] Parent node
|
33
|
+
# @return [ArrayNode] Created array node
|
34
|
+
def create_array(property_name: nil, comment_data: nil, is_conditional: false, is_root_array: false, parent: nil)
|
35
|
+
ArrayNode.new(
|
36
|
+
property_name: property_name,
|
37
|
+
comment_data: normalize_comment_data(comment_data, default_type: 'array'),
|
38
|
+
is_conditional: is_conditional,
|
39
|
+
is_root_array: is_root_array,
|
40
|
+
parent: parent
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create an object node
|
45
|
+
# @param property_name [String] Name of the object property
|
46
|
+
# @param comment_data [CommentData, Hash, nil] Comment data
|
47
|
+
# @param is_conditional [Boolean] Whether object is conditional
|
48
|
+
# @param parent [BaseNode, nil] Parent node
|
49
|
+
# @return [ObjectNode] Created object node
|
50
|
+
def create_object(property_name:, comment_data: nil, is_conditional: false, parent: nil)
|
51
|
+
ObjectNode.new(
|
52
|
+
property_name: property_name,
|
53
|
+
comment_data: normalize_comment_data(comment_data, default_type: 'object'),
|
54
|
+
is_conditional: is_conditional,
|
55
|
+
parent: parent
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Create a partial node
|
60
|
+
# @param partial_path [String] Path to the partial
|
61
|
+
# @param property_name [String, nil] Name of the property (for nested partials)
|
62
|
+
# @param comment_data [CommentData, Hash, nil] Comment data
|
63
|
+
# @param is_conditional [Boolean] Whether partial is conditional
|
64
|
+
# @param local_variables [Hash] Local variables passed to partial
|
65
|
+
# @param parent [BaseNode, nil] Parent node
|
66
|
+
# @return [PartialNode] Created partial node
|
67
|
+
def create_partial(partial_path:, property_name: nil, comment_data: nil, is_conditional: false, local_variables: {}, parent: nil)
|
68
|
+
PartialNode.new(
|
69
|
+
partial_path: partial_path,
|
70
|
+
property_name: property_name,
|
71
|
+
comment_data: normalize_comment_data(comment_data),
|
72
|
+
is_conditional: is_conditional,
|
73
|
+
local_variables: local_variables,
|
74
|
+
parent: parent
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Create a node from hash data (backward compatibility)
|
79
|
+
# @param hash_data [Hash] Hash containing node data
|
80
|
+
# @return [BaseNode] Created node
|
81
|
+
def from_hash(hash_data)
|
82
|
+
return hash_data unless hash_data.is_a?(Hash)
|
83
|
+
|
84
|
+
case hash_data[:node_type]&.to_sym
|
85
|
+
when :array
|
86
|
+
create_array(
|
87
|
+
property_name: hash_data[:property_name] || hash_data[:property],
|
88
|
+
comment_data: hash_data[:comment_data],
|
89
|
+
is_conditional: hash_data[:is_conditional] || false,
|
90
|
+
is_root_array: hash_data[:is_root_array] || hash_data[:is_array_root] || false
|
91
|
+
)
|
92
|
+
when :object
|
93
|
+
create_object(
|
94
|
+
property_name: hash_data[:property_name] || hash_data[:property],
|
95
|
+
comment_data: hash_data[:comment_data],
|
96
|
+
is_conditional: hash_data[:is_conditional] || false
|
97
|
+
)
|
98
|
+
when :partial
|
99
|
+
create_partial(
|
100
|
+
partial_path: hash_data[:partial_path],
|
101
|
+
property_name: hash_data[:property_name] || hash_data[:property],
|
102
|
+
comment_data: hash_data[:comment_data],
|
103
|
+
is_conditional: hash_data[:is_conditional] || false,
|
104
|
+
local_variables: hash_data[:local_variables] || {}
|
105
|
+
)
|
106
|
+
else
|
107
|
+
# Check if this is an array property that should be preserved as hash
|
108
|
+
if hash_data[:is_array] && hash_data[:array_item_properties]
|
109
|
+
# Return hash data directly to preserve array information
|
110
|
+
hash_data
|
111
|
+
else
|
112
|
+
create_property(
|
113
|
+
property_name: hash_data[:property_name] || hash_data[:property],
|
114
|
+
comment_data: hash_data[:comment_data],
|
115
|
+
is_conditional: hash_data[:is_conditional] || false
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Create nodes from an array of hash data
|
122
|
+
# @param hash_array [Array<Hash>] Array of hash data
|
123
|
+
# @return [Array<BaseNode>] Array of created nodes
|
124
|
+
def from_hash_array(hash_array)
|
125
|
+
return [] unless hash_array.is_a?(Array)
|
126
|
+
|
127
|
+
hash_array.map { |hash_data| from_hash(hash_data) }
|
128
|
+
end
|
129
|
+
|
130
|
+
# Create a tree structure from nested hash data
|
131
|
+
# @param hash_data [Hash] Root hash data
|
132
|
+
# @return [BaseNode] Root node with children
|
133
|
+
def create_tree(hash_data)
|
134
|
+
root_node = from_hash(hash_data)
|
135
|
+
|
136
|
+
# Add children if present
|
137
|
+
if hash_data[:children]
|
138
|
+
hash_data[:children].each do |child_data|
|
139
|
+
child_node = create_tree(child_data)
|
140
|
+
root_node.add_child(child_node)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Add specific child types
|
145
|
+
add_specific_children(root_node, hash_data)
|
146
|
+
|
147
|
+
root_node
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
# Normalize comment data to CommentData instance
|
153
|
+
# @param data [CommentData, Hash, nil] Comment data input
|
154
|
+
# @param default_type [String, nil] Default type if not specified
|
155
|
+
# @return [CommentData] Normalized comment data
|
156
|
+
def normalize_comment_data(data, default_type: nil)
|
157
|
+
return CommentData.new(type: default_type) if data.nil?
|
158
|
+
return data if data.is_a?(CommentData)
|
159
|
+
|
160
|
+
# Convert hash to CommentData
|
161
|
+
CommentData.new(
|
162
|
+
type: data[:type] || default_type,
|
163
|
+
description: data[:description],
|
164
|
+
required: data[:required],
|
165
|
+
enum: data[:enum],
|
166
|
+
field_name: data[:field_name],
|
167
|
+
items: data[:items],
|
168
|
+
conditional: data[:conditional],
|
169
|
+
format: data[:format],
|
170
|
+
example: data[:example]
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Add specific children based on node type
|
175
|
+
# @param node [BaseNode] Parent node
|
176
|
+
# @param hash_data [Hash] Hash data containing children
|
177
|
+
# @return [void]
|
178
|
+
def add_specific_children(node, hash_data)
|
179
|
+
case node
|
180
|
+
when ArrayNode
|
181
|
+
# Add array items
|
182
|
+
if hash_data[:items]
|
183
|
+
hash_data[:items].each do |item_data|
|
184
|
+
item_node = from_hash(item_data)
|
185
|
+
node.add_item(item_node)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
when ObjectNode
|
189
|
+
# Add object properties
|
190
|
+
if hash_data[:properties]
|
191
|
+
hash_data[:properties].each do |prop_data|
|
192
|
+
prop_node = from_hash(prop_data)
|
193
|
+
node.add_property(prop_node)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
when PartialNode
|
197
|
+
# Add parsed properties
|
198
|
+
if hash_data[:properties]
|
199
|
+
properties = from_hash_array(hash_data[:properties])
|
200
|
+
node.add_parsed_properties(properties)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsOpenapiGen::AstNodes
|
4
|
+
# Represents an object node in Jbuilder template (json.object do...end)
|
5
|
+
class ObjectNode < BaseNode
|
6
|
+
attr_reader :property_name, :comment_data, :is_conditional # json.xxx # @openapi comments # if/else
|
7
|
+
|
8
|
+
def initialize(property_name:, comment_data: nil, is_conditional: false, parent: nil, metadata: {})
|
9
|
+
super(parent: parent, metadata: metadata)
|
10
|
+
@property_name = property_name
|
11
|
+
@comment_data = comment_data || CommentData.new(type: 'object')
|
12
|
+
@is_conditional = is_conditional
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add a property to this object
|
16
|
+
# @param property_node [BaseNode] Property node to add
|
17
|
+
# @return [BaseNode] The added property node
|
18
|
+
def add_property(property_node)
|
19
|
+
add_child(property_node)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get all properties in this object
|
23
|
+
# @return [Array<BaseNode>] Property nodes
|
24
|
+
def properties
|
25
|
+
@children
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get required properties for OpenAPI schema
|
29
|
+
# @return [Array<String>] Names of required properties
|
30
|
+
def required_properties
|
31
|
+
properties.select do |property|
|
32
|
+
if property.respond_to?(:required?)
|
33
|
+
property.required?
|
34
|
+
else
|
35
|
+
# Handle legacy Hash objects
|
36
|
+
property.is_a?(Hash) && property[:required] == true
|
37
|
+
end
|
38
|
+
end.map do |property|
|
39
|
+
if property.respond_to?(:property_name)
|
40
|
+
property.property_name
|
41
|
+
else
|
42
|
+
# Handle legacy Hash objects
|
43
|
+
property[:property_name] || property[:property]
|
44
|
+
end
|
45
|
+
end.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get optional properties for OpenAPI schema
|
49
|
+
# @return [Array<String>] Names of optional properties
|
50
|
+
def optional_properties
|
51
|
+
properties.select do |property|
|
52
|
+
if property.respond_to?(:optional?)
|
53
|
+
property.optional?
|
54
|
+
else
|
55
|
+
# Handle legacy Hash objects
|
56
|
+
property.is_a?(Hash) && property[:required] != true
|
57
|
+
end
|
58
|
+
end.map do |property|
|
59
|
+
if property.respond_to?(:property_name)
|
60
|
+
property.property_name
|
61
|
+
else
|
62
|
+
# Handle legacy Hash objects
|
63
|
+
property[:property_name] || property[:property]
|
64
|
+
end
|
65
|
+
end.compact
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check if this object is required in OpenAPI schema
|
69
|
+
# @return [Boolean] True if object is required
|
70
|
+
def required?
|
71
|
+
@comment_data.required? && !@is_conditional
|
72
|
+
end
|
73
|
+
|
74
|
+
# Check if this object is optional in OpenAPI schema
|
75
|
+
# @return [Boolean] True if object is optional
|
76
|
+
def optional?
|
77
|
+
!required?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the description for this object
|
81
|
+
# @return [String, nil] Object description
|
82
|
+
def description
|
83
|
+
@comment_data.description
|
84
|
+
end
|
85
|
+
|
86
|
+
# Find a property by name
|
87
|
+
# @param name [String] Property name to find
|
88
|
+
# @return [BaseNode, nil] Property node or nil if not found
|
89
|
+
def find_property(name)
|
90
|
+
properties.find do |prop|
|
91
|
+
if prop.respond_to?(:property_name)
|
92
|
+
prop.property_name == name
|
93
|
+
else
|
94
|
+
# Handle legacy Hash objects
|
95
|
+
(prop[:property_name] || prop[:property]) == name
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Check if object has any properties
|
101
|
+
# @return [Boolean] True if object has properties
|
102
|
+
def has_properties?
|
103
|
+
!properties.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
# Convert to hash representation
|
107
|
+
# @return [Hash] Hash representation
|
108
|
+
def to_h
|
109
|
+
super.merge(
|
110
|
+
property_name: @property_name,
|
111
|
+
comment_data: @comment_data&.to_h,
|
112
|
+
is_conditional: @is_conditional,
|
113
|
+
required: required?,
|
114
|
+
openapi_type: 'object',
|
115
|
+
description: description,
|
116
|
+
properties: properties.map { |prop| prop.respond_to?(:to_h) ? prop.to_h : prop },
|
117
|
+
required_properties: required_properties,
|
118
|
+
optional_properties: optional_properties
|
119
|
+
).compact
|
120
|
+
end
|
121
|
+
|
122
|
+
# Accept visitor for visitor pattern
|
123
|
+
# @param visitor [Object] Visitor object
|
124
|
+
# @return [Object] Result from visitor
|
125
|
+
def accept(visitor)
|
126
|
+
visitor.visit_object(self)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsOpenapiGen::AstNodes
|
4
|
+
# Represents a partial node in Jbuilder template (json.partial!)
|
5
|
+
class PartialNode < BaseNode
|
6
|
+
attr_reader :partial_path, :property_name, :comment_data, :is_conditional, :local_variables
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
partial_path:,
|
10
|
+
property_name: nil,
|
11
|
+
comment_data: nil,
|
12
|
+
is_conditional: false,
|
13
|
+
local_variables: {},
|
14
|
+
parent: nil,
|
15
|
+
metadata: {}
|
16
|
+
)
|
17
|
+
super(parent: parent, metadata: metadata)
|
18
|
+
@partial_path = partial_path
|
19
|
+
@property_name = property_name
|
20
|
+
@comment_data = comment_data || CommentData.new
|
21
|
+
@is_conditional = is_conditional
|
22
|
+
@local_variables = local_variables
|
23
|
+
end
|
24
|
+
|
25
|
+
# Resolve the absolute path of the partial
|
26
|
+
# @param base_path [String] Base path for resolution
|
27
|
+
# @return [String] Resolved partial path
|
28
|
+
def resolve_path(base_path = nil)
|
29
|
+
return @partial_path if @partial_path.start_with?('/')
|
30
|
+
|
31
|
+
if base_path
|
32
|
+
File.join(File.dirname(base_path), "#{@partial_path}.json.jbuilder")
|
33
|
+
else
|
34
|
+
"#{@partial_path}.json.jbuilder"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check if this partial is required in OpenAPI schema
|
39
|
+
# @return [Boolean] True if partial is required
|
40
|
+
def required?
|
41
|
+
@comment_data.required? && !@is_conditional
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check if this partial is optional in OpenAPI schema
|
45
|
+
# @return [Boolean] True if partial is optional
|
46
|
+
def optional?
|
47
|
+
!required?
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get the description for this partial
|
51
|
+
# @return [String, nil] Partial description
|
52
|
+
def description
|
53
|
+
@comment_data.description
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check if partial has local variables
|
57
|
+
# @return [Boolean] True if partial has local variables
|
58
|
+
def has_locals?
|
59
|
+
!@local_variables.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get local variable names
|
63
|
+
# @return [Array<String>] Local variable names
|
64
|
+
def local_names
|
65
|
+
@local_variables.keys
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get value for a local variable
|
69
|
+
# @param name [String] Local variable name
|
70
|
+
# @return [Object] Local variable value
|
71
|
+
def local_value(name)
|
72
|
+
@local_variables[name]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add parsed properties from the partial
|
76
|
+
# @param properties [Array<BaseNode>] Properties from parsed partial
|
77
|
+
# @return [Array<BaseNode>] Added properties
|
78
|
+
def add_parsed_properties(properties)
|
79
|
+
properties.each { |prop| add_child(prop) }
|
80
|
+
properties
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get all properties from the parsed partial
|
84
|
+
# @return [Array<BaseNode>] Properties from partial
|
85
|
+
def properties
|
86
|
+
@children
|
87
|
+
end
|
88
|
+
|
89
|
+
# Convert to hash representation
|
90
|
+
# @return [Hash] Hash representation
|
91
|
+
def to_h
|
92
|
+
super.merge(
|
93
|
+
partial_path: @partial_path,
|
94
|
+
property_name: @property_name,
|
95
|
+
comment_data: @comment_data&.to_h,
|
96
|
+
is_conditional: @is_conditional,
|
97
|
+
required: required?,
|
98
|
+
description: description,
|
99
|
+
local_variables: @local_variables,
|
100
|
+
properties: properties.map { |prop| prop.respond_to?(:to_h) ? prop.to_h : prop }
|
101
|
+
).compact
|
102
|
+
end
|
103
|
+
|
104
|
+
# Accept visitor for visitor pattern
|
105
|
+
# @param visitor [Object] Visitor object
|
106
|
+
# @return [Object] Result from visitor
|
107
|
+
def accept(visitor)
|
108
|
+
visitor.visit_partial(self)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsOpenapiGen
|
4
|
+
module AstNodes
|
5
|
+
# Represents a property node in Jbuilder template (json.property_name)
|
6
|
+
class PropertyNode < BaseNode
|
7
|
+
attr_reader :property_name, :comment_data, :is_conditional, :is_component_ref, :component_name # json.xxx # @openapi comments # if/else # whether this is a component reference # name of referenced component
|
8
|
+
|
9
|
+
def initialize(property_name:, comment_data: nil, is_conditional: false, is_component_ref: false, component_name: nil, parent: nil, metadata: {})
|
10
|
+
super(parent: parent, metadata: metadata)
|
11
|
+
@property_name = property_name
|
12
|
+
@comment_data = comment_data || CommentData.new
|
13
|
+
@is_conditional = is_conditional
|
14
|
+
@is_component_ref = is_component_ref
|
15
|
+
@component_name = component_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# Check if this property is required in OpenAPI schema
|
19
|
+
# @return [Boolean] True if property is required
|
20
|
+
def required?
|
21
|
+
@comment_data.required? && !@is_conditional
|
22
|
+
end
|
23
|
+
|
24
|
+
# Check if this property is optional in OpenAPI schema
|
25
|
+
# @return [Boolean] True if property is optional
|
26
|
+
def optional?
|
27
|
+
!required?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the OpenAPI type for this property
|
31
|
+
# @return [String] OpenAPI type
|
32
|
+
def openapi_type
|
33
|
+
@comment_data.type || 'string'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get the description for this property
|
37
|
+
# @return [String, nil] Property description
|
38
|
+
def description
|
39
|
+
@comment_data.description
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get enum values if specified
|
43
|
+
# @return [Array, nil] Enum values
|
44
|
+
def enum_values
|
45
|
+
@comment_data.enum
|
46
|
+
end
|
47
|
+
|
48
|
+
# Convert to hash representation
|
49
|
+
# @return [Hash] Hash representation
|
50
|
+
def to_h
|
51
|
+
super.merge(
|
52
|
+
property_name: @property_name,
|
53
|
+
comment_data: @comment_data&.to_h,
|
54
|
+
is_conditional: @is_conditional,
|
55
|
+
is_component_ref: @is_component_ref,
|
56
|
+
component_name: @component_name,
|
57
|
+
required: required?,
|
58
|
+
openapi_type: openapi_type,
|
59
|
+
description: description,
|
60
|
+
enum: enum_values,
|
61
|
+
# Backward compatibility - also provide property for Generator
|
62
|
+
property: @property_name
|
63
|
+
).compact
|
64
|
+
end
|
65
|
+
|
66
|
+
# Accept visitor for visitor pattern
|
67
|
+
# @param visitor [Object] Visitor object
|
68
|
+
# @return [Object] Result from visitor
|
69
|
+
def accept(visitor)
|
70
|
+
visitor.visit_property(self)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsOpenapiGen
|
4
|
+
module AstNodes
|
5
|
+
autoload :BaseNode, "rails-openapi-gen/ast_nodes/base_node"
|
6
|
+
autoload :PropertyNode, "rails-openapi-gen/ast_nodes/property_node"
|
7
|
+
autoload :ArrayNode, "rails-openapi-gen/ast_nodes/array_node"
|
8
|
+
autoload :PartialNode, "rails-openapi-gen/ast_nodes/partial_node"
|
9
|
+
autoload :ObjectNode, "rails-openapi-gen/ast_nodes/object_node"
|
10
|
+
autoload :CommentData, "rails-openapi-gen/ast_nodes/comment_data"
|
11
|
+
autoload :NodeFactory, "rails-openapi-gen/ast_nodes/node_factory"
|
12
|
+
|
13
|
+
# Legacy compatibility classes - will be deprecated
|
14
|
+
# These maintain backward compatibility with existing code
|
15
|
+
class PropertyNodeFactory < NodeFactory
|
16
|
+
# Delegate to NodeFactory for backward compatibility
|
17
|
+
class << self
|
18
|
+
def from_hash(hash_data)
|
19
|
+
NodeFactory.from_hash(hash_data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_simple(property:, comment_data: nil, is_conditional: false)
|
23
|
+
NodeFactory.create_property(
|
24
|
+
property_name: property,
|
25
|
+
comment_data: comment_data,
|
26
|
+
is_conditional: is_conditional
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_array(property:, comment_data: nil, is_conditional: false, array_item_properties: [])
|
31
|
+
node = NodeFactory.create_array(
|
32
|
+
property_name: property,
|
33
|
+
comment_data: comment_data,
|
34
|
+
is_conditional: is_conditional
|
35
|
+
)
|
36
|
+
array_item_properties.each { |item| node.add_item(item) }
|
37
|
+
node
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_object(property:, comment_data: nil, is_conditional: false, nested_properties: [])
|
41
|
+
node = NodeFactory.create_object(
|
42
|
+
property_name: property,
|
43
|
+
comment_data: comment_data,
|
44
|
+
is_conditional: is_conditional
|
45
|
+
)
|
46
|
+
nested_properties.each { |prop| node.add_property(prop) }
|
47
|
+
node
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_array_root(comment_data: nil, array_item_properties: [])
|
51
|
+
node = NodeFactory.create_array(
|
52
|
+
comment_data: comment_data,
|
53
|
+
is_root_array: true
|
54
|
+
)
|
55
|
+
array_item_properties.each { |item| node.add_item(item) }
|
56
|
+
node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Legacy property node classes for backward compatibility
|
62
|
+
class SimplePropertyNode < PropertyNode
|
63
|
+
def initialize(property:, comment_data: nil, is_conditional: false)
|
64
|
+
super(property_name: property, comment_data: comment_data, is_conditional: is_conditional)
|
65
|
+
end
|
66
|
+
|
67
|
+
def property
|
68
|
+
property_name
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class ArrayPropertyNode < ArrayNode
|
73
|
+
def initialize(property:, comment_data: nil, is_conditional: false, array_item_properties: [])
|
74
|
+
super(property_name: property, comment_data: comment_data, is_conditional: is_conditional)
|
75
|
+
array_item_properties.each { |item| add_item(item) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def property
|
79
|
+
property_name
|
80
|
+
end
|
81
|
+
|
82
|
+
def array_item_properties
|
83
|
+
items
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_item_property(property_node)
|
87
|
+
add_item(property_node)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class ObjectPropertyNode < ObjectNode
|
92
|
+
def initialize(property:, comment_data: nil, is_conditional: false, nested_properties: [])
|
93
|
+
super(property_name: property, comment_data: comment_data, is_conditional: is_conditional)
|
94
|
+
nested_properties.each { |prop| add_property(prop) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def property
|
98
|
+
property_name
|
99
|
+
end
|
100
|
+
|
101
|
+
def nested_properties
|
102
|
+
properties
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_nested_property(property_node)
|
106
|
+
add_property(property_node)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class ArrayRootNode < ArrayNode
|
111
|
+
def initialize(comment_data: nil, array_item_properties: [])
|
112
|
+
super(property_name: 'items', comment_data: comment_data, is_root_array: true)
|
113
|
+
array_item_properties.each { |item| add_item(item) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def property
|
117
|
+
property_name
|
118
|
+
end
|
119
|
+
|
120
|
+
def array_item_properties
|
121
|
+
items
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_item_property(property_node)
|
125
|
+
add_item(property_node)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|