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
@@ -12,7 +12,7 @@ module RailsOpenapiGen
|
|
12
12
|
def parse(comment_text)
|
13
13
|
# Skip conditional pattern which is handled by ConditionalParser
|
14
14
|
return nil if comment_text.match?(/@openapi\s+conditional:true\s*$/)
|
15
|
-
|
15
|
+
|
16
16
|
match = comment_text.match(REGEX)
|
17
17
|
return nil unless match
|
18
18
|
|
@@ -24,20 +24,20 @@ module RailsOpenapiGen
|
|
24
24
|
|
25
25
|
def parse_attributes(content)
|
26
26
|
attributes = {}
|
27
|
-
|
27
|
+
|
28
28
|
parts = parse_key_value_pairs(content)
|
29
|
-
|
29
|
+
|
30
30
|
# First part should be field_name:type
|
31
31
|
if parts.any?
|
32
32
|
first_key, first_value = parts.first
|
33
33
|
attributes[:field_name] = first_key
|
34
34
|
attributes[:type] = clean_value(first_value)
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
# Remaining parts are attributes
|
38
38
|
parts[1..-1]&.each do |key, value|
|
39
39
|
cleaned_value = clean_value(value)
|
40
|
-
|
40
|
+
|
41
41
|
case key
|
42
42
|
when "required"
|
43
43
|
attributes[:required] = cleaned_value
|
@@ -49,9 +49,9 @@ module RailsOpenapiGen
|
|
49
49
|
attributes[key.to_sym] = cleaned_value
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
attributes
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
|
-
end
|
57
|
+
end
|
@@ -7,11 +7,9 @@ module RailsOpenapiGen
|
|
7
7
|
|
8
8
|
def clean_value(value)
|
9
9
|
value = value.strip
|
10
|
-
|
10
|
+
|
11
11
|
if value.start_with?('"') && value.end_with?('"')
|
12
12
|
value[1..-2]
|
13
|
-
elsif value.start_with?('[') && value.end_with?(']')
|
14
|
-
value
|
15
13
|
else
|
16
14
|
value
|
17
15
|
end
|
@@ -19,10 +17,10 @@ module RailsOpenapiGen
|
|
19
17
|
|
20
18
|
def parse_enum(value)
|
21
19
|
return value unless value.is_a?(String) && value.start_with?('[') && value.end_with?(']')
|
22
|
-
|
20
|
+
|
23
21
|
inner = value[1..-2]
|
24
|
-
|
25
|
-
|
22
|
+
|
23
|
+
inner.split(',').map do |item|
|
26
24
|
item = item.strip
|
27
25
|
if item.start_with?('"') && item.end_with?('"')
|
28
26
|
item[1..-2]
|
@@ -30,8 +28,6 @@ module RailsOpenapiGen
|
|
30
28
|
item
|
31
29
|
end
|
32
30
|
end
|
33
|
-
|
34
|
-
items
|
35
31
|
end
|
36
32
|
|
37
33
|
def parse_key_value_pairs(content)
|
@@ -39,4 +35,4 @@ module RailsOpenapiGen
|
|
39
35
|
end
|
40
36
|
end
|
41
37
|
end
|
42
|
-
end
|
38
|
+
end
|
@@ -21,20 +21,20 @@ module RailsOpenapiGen
|
|
21
21
|
|
22
22
|
def parse_parameter_attributes(content)
|
23
23
|
attributes = {}
|
24
|
-
|
24
|
+
|
25
25
|
parts = parse_key_value_pairs(content)
|
26
|
-
|
26
|
+
|
27
27
|
# First part should be parameter_name:type
|
28
28
|
if parts.any?
|
29
29
|
first_key, first_value = parts.first
|
30
30
|
attributes[:name] = first_key
|
31
31
|
attributes[:type] = clean_value(first_value)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Remaining parts are attributes
|
35
35
|
parts[1..-1]&.each do |key, value|
|
36
36
|
cleaned_value = clean_value(value)
|
37
|
-
|
37
|
+
|
38
38
|
case key
|
39
39
|
when "required"
|
40
40
|
attributes[:required] = cleaned_value
|
@@ -54,9 +54,9 @@ module RailsOpenapiGen
|
|
54
54
|
attributes[key.to_sym] = cleaned_value
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
attributes
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
|
-
end
|
62
|
+
end
|
@@ -21,12 +21,12 @@ module RailsOpenapiGen
|
|
21
21
|
|
22
22
|
def parse_operation_attributes(content)
|
23
23
|
attributes = {}
|
24
|
-
|
24
|
+
|
25
25
|
parts = parse_key_value_pairs(content)
|
26
|
-
|
26
|
+
|
27
27
|
parts.each do |key, value|
|
28
28
|
cleaned_value = clean_value(value)
|
29
|
-
|
29
|
+
|
30
30
|
case key
|
31
31
|
when "summary"
|
32
32
|
attributes[:summary] = cleaned_value
|
@@ -42,9 +42,9 @@ module RailsOpenapiGen
|
|
42
42
|
attributes[key.to_sym] = cleaned_value
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
attributes
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
-
end
|
50
|
+
end
|
@@ -21,20 +21,20 @@ module RailsOpenapiGen
|
|
21
21
|
|
22
22
|
def parse_parameter_attributes(content)
|
23
23
|
attributes = {}
|
24
|
-
|
24
|
+
|
25
25
|
parts = parse_key_value_pairs(content)
|
26
|
-
|
26
|
+
|
27
27
|
# First part should be parameter_name:type
|
28
28
|
if parts.any?
|
29
29
|
first_key, first_value = parts.first
|
30
30
|
attributes[:name] = first_key
|
31
31
|
attributes[:type] = clean_value(first_value)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Remaining parts are attributes
|
35
35
|
parts[1..-1]&.each do |key, value|
|
36
36
|
cleaned_value = clean_value(value)
|
37
|
-
|
37
|
+
|
38
38
|
case key
|
39
39
|
when "required"
|
40
40
|
attributes[:required] = cleaned_value
|
@@ -54,9 +54,9 @@ module RailsOpenapiGen
|
|
54
54
|
attributes[key.to_sym] = cleaned_value
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
attributes
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
|
-
end
|
62
|
+
end
|
@@ -21,20 +21,20 @@ module RailsOpenapiGen
|
|
21
21
|
|
22
22
|
def parse_parameter_attributes(content)
|
23
23
|
attributes = {}
|
24
|
-
|
24
|
+
|
25
25
|
parts = parse_key_value_pairs(content)
|
26
|
-
|
26
|
+
|
27
27
|
# First part should be parameter_name:type
|
28
28
|
if parts.any?
|
29
29
|
first_key, first_value = parts.first
|
30
30
|
attributes[:name] = first_key
|
31
31
|
attributes[:type] = clean_value(first_value)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Remaining parts are attributes
|
35
35
|
parts[1..-1]&.each do |key, value|
|
36
36
|
cleaned_value = clean_value(value)
|
37
|
-
|
37
|
+
|
38
38
|
case key
|
39
39
|
when "required"
|
40
40
|
attributes[:required] = cleaned_value
|
@@ -54,9 +54,9 @@ module RailsOpenapiGen
|
|
54
54
|
attributes[key.to_sym] = cleaned_value
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
attributes
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
|
-
end
|
62
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "parser/current"
|
4
|
-
require_relative "template_processors
|
4
|
+
require_relative "template_processors"
|
5
5
|
|
6
6
|
module RailsOpenapiGen
|
7
7
|
module Parsers
|
@@ -13,7 +13,9 @@ module RailsOpenapiGen
|
|
13
13
|
# @param template_processor [ResponseTemplateProcessor] Template processor for extracting template paths
|
14
14
|
def initialize(route, template_processor: nil)
|
15
15
|
@route = route
|
16
|
-
@template_processor = template_processor || TemplateProcessors::JbuilderTemplateProcessor.new(
|
16
|
+
@template_processor = template_processor || RailsOpenapiGen::Parsers::TemplateProcessors::JbuilderTemplateProcessor.new(
|
17
|
+
route[:controller], route[:action]
|
18
|
+
)
|
17
19
|
end
|
18
20
|
|
19
21
|
# Parses controller to find action method and response template
|
@@ -24,13 +26,13 @@ module RailsOpenapiGen
|
|
24
26
|
|
25
27
|
content = File.read(controller_path)
|
26
28
|
ast = Parser::CurrentRuby.parse(content)
|
27
|
-
|
29
|
+
|
28
30
|
action_node = find_action_method(ast)
|
29
31
|
return {} unless action_node
|
30
32
|
|
31
33
|
template_path = extract_template_path(action_node)
|
32
34
|
parameters = extract_parameters_from_comments(content, action_node)
|
33
|
-
|
35
|
+
|
34
36
|
{
|
35
37
|
controller_path: controller_path,
|
36
38
|
jbuilder_path: template_path, # Keep existing key name for backward compatibility
|
@@ -48,15 +50,16 @@ module RailsOpenapiGen
|
|
48
50
|
possible_paths = [
|
49
51
|
Rails.root.join("app", "controllers", "#{controller_name}.rb")
|
50
52
|
]
|
51
|
-
|
53
|
+
|
52
54
|
# Handle nested controllers
|
53
55
|
if route[:controller].include?("/")
|
54
56
|
parts = route[:controller].split("/")
|
55
57
|
nested_path = Rails.root.join("app", "controllers", *parts[0..-2], "#{parts.last}_controller.rb")
|
56
58
|
possible_paths << nested_path
|
57
59
|
end
|
58
|
-
|
59
|
-
possible_paths.find { |path| File.exist?(path) }
|
60
|
+
|
61
|
+
found_path = possible_paths.find { |path| File.exist?(path.to_s) }
|
62
|
+
found_path&.to_s
|
60
63
|
end
|
61
64
|
|
62
65
|
# Finds action method node in the AST
|
@@ -78,10 +81,10 @@ module RailsOpenapiGen
|
|
78
81
|
|
79
82
|
# Try to extract explicit template path from action
|
80
83
|
template_path = template_processor.extract_template_path(action_node, route)
|
81
|
-
|
84
|
+
|
82
85
|
# If no explicit template found, check for default template
|
83
86
|
template_path ||= template_processor.find_default_template(route)
|
84
|
-
|
87
|
+
|
85
88
|
template_path
|
86
89
|
end
|
87
90
|
|
@@ -94,29 +97,70 @@ module RailsOpenapiGen
|
|
94
97
|
|
95
98
|
lines = content.lines
|
96
99
|
action_line = action_node.location.line - 1 # Convert to 0-based index
|
97
|
-
|
100
|
+
|
98
101
|
# Look for comments before the action method
|
99
102
|
parameters = {
|
100
103
|
path_parameters: [],
|
101
104
|
query_parameters: [],
|
102
105
|
body_parameters: []
|
103
106
|
}
|
104
|
-
|
107
|
+
|
105
108
|
comment_parser = RailsOpenapiGen::Parsers::CommentParser.new
|
106
|
-
|
109
|
+
|
107
110
|
# Scan backwards from the action line to find comments
|
108
111
|
(action_line - 1).downto(0) do |line_index|
|
109
112
|
line = lines[line_index].strip
|
110
|
-
|
113
|
+
|
111
114
|
# Stop if we encounter a non-comment line that's not empty
|
112
115
|
break if !line.empty? && !line.start_with?('#')
|
113
|
-
|
116
|
+
|
114
117
|
next if line.empty? || !line.include?('@openapi')
|
115
|
-
|
118
|
+
|
116
119
|
parsed = comment_parser.parse(line)
|
117
120
|
next unless parsed
|
118
|
-
|
119
|
-
|
121
|
+
|
122
|
+
# Handle different comment formats
|
123
|
+
if line.include?('path_parameter')
|
124
|
+
# Extract the parameter info from parsed attributes
|
125
|
+
param_info = {
|
126
|
+
name: parsed[:field_name],
|
127
|
+
type: parsed[:type],
|
128
|
+
description: parsed[:description],
|
129
|
+
required: parsed[:required] || 'true',
|
130
|
+
enum: parsed[:enum],
|
131
|
+
format: parsed[:format],
|
132
|
+
minimum: parsed[:minimum],
|
133
|
+
maximum: parsed[:maximum],
|
134
|
+
example: parsed[:example]
|
135
|
+
}.compact
|
136
|
+
parameters[:path_parameters] << param_info
|
137
|
+
elsif line.include?('query_parameter')
|
138
|
+
param_info = {
|
139
|
+
name: parsed[:field_name],
|
140
|
+
type: parsed[:type],
|
141
|
+
description: parsed[:description],
|
142
|
+
required: parsed[:required] || 'false',
|
143
|
+
enum: parsed[:enum],
|
144
|
+
format: parsed[:format],
|
145
|
+
minimum: parsed[:minimum],
|
146
|
+
maximum: parsed[:maximum],
|
147
|
+
example: parsed[:example]
|
148
|
+
}.compact
|
149
|
+
parameters[:query_parameters] << param_info
|
150
|
+
elsif line.include?('body_parameter')
|
151
|
+
param_info = {
|
152
|
+
name: parsed[:field_name],
|
153
|
+
type: parsed[:type],
|
154
|
+
description: parsed[:description],
|
155
|
+
required: parsed[:required] || 'true',
|
156
|
+
enum: parsed[:enum],
|
157
|
+
format: parsed[:format],
|
158
|
+
minimum: parsed[:minimum],
|
159
|
+
maximum: parsed[:maximum],
|
160
|
+
example: parsed[:example]
|
161
|
+
}.compact
|
162
|
+
parameters[:body_parameters] << param_info
|
163
|
+
elsif parsed[:parameter]
|
120
164
|
parameters[:path_parameters] << parsed[:parameter]
|
121
165
|
elsif parsed[:query_parameter]
|
122
166
|
parameters[:query_parameters] << parsed[:query_parameter]
|
@@ -124,7 +168,7 @@ module RailsOpenapiGen
|
|
124
168
|
parameters[:body_parameters] << parsed[:body_parameter]
|
125
169
|
end
|
126
170
|
end
|
127
|
-
|
171
|
+
|
128
172
|
parameters
|
129
173
|
end
|
130
174
|
|
@@ -134,6 +178,7 @@ module RailsOpenapiGen
|
|
134
178
|
# Initializes processor to find specific action method
|
135
179
|
# @param action_name [String, Symbol] Name of action to find
|
136
180
|
def initialize(action_name)
|
181
|
+
super()
|
137
182
|
@action_name = action_name.to_sym
|
138
183
|
@action_node = nil
|
139
184
|
end
|
@@ -147,7 +192,6 @@ module RailsOpenapiGen
|
|
147
192
|
super
|
148
193
|
end
|
149
194
|
end
|
150
|
-
|
151
195
|
end
|
152
196
|
end
|
153
|
-
end
|
197
|
+
end
|