typespec_from_serializers 0.5.2 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46bcf5deebdc474b0f22abee212194c394fc811492bf55c9a3eaae01ed3976a0
4
- data.tar.gz: 8dc54c4ffb68a326c94c99f6ac778ebf9ee777e925e2bbe456c9256ed25abae6
3
+ metadata.gz: 1bc90948b5d93848663bab0d1162a1f26d49d832a05ef4c57eb5cb1e90f74ff3
4
+ data.tar.gz: '008ddb8319166e72e2e75a30d840ad387a082df6e4d0846698e87f9b15ac1c05'
5
5
  SHA512:
6
- metadata.gz: 0bccf7a80481a2c8b20157c9889ef18a89390854692017c559d16feb52c464ba9cf95d9a280078b203d626b4f46c0f720d3b8b46b72d8d8543a550b76e1d7e67
7
- data.tar.gz: 42c5a6028324542ecfaf6a79a5fea5fc635677688b960507cb8f4dc805ca7b7be164e3a5f39288dfbeea74f1e3af9b44f462f1d070eaed9cc947f4bee21c8ab0
6
+ metadata.gz: 950c7c34c0d3766854fd6eb4b3aa958b7ed8a20040ad8a43c5573d52741b156441b43e0fbded753536624d368ce353959f5f9e13d311eddea05ba75b8a4e85df
7
+ data.tar.gz: 6695700e9a0f73b03e97107d1844e2ef878dcf50217b45826418488827643923260f9b2465bd20fc4d03ef298ea2028f87132fa496abbb67f43ad635fda47562
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # TypeSpec From Serializers Changelog
2
2
 
3
+ ## [0.5.3] - 2025-12-23
4
+
5
+ ### Fixed
6
+ - Body params now scoped per action by analyzing which `*_params` methods are called
7
+
3
8
  ## [0.5.2] - 2025-12-22
4
9
 
5
10
  ### Fixed
@@ -980,56 +980,19 @@ module TypeSpecFromSerializers
980
980
 
981
981
  # Internal: Extracts serializer class from controller method source using Prism AST
982
982
  def extract_serializer_from_controller_method(controller_class, action)
983
- return nil unless controller_class.method_defined?(action)
984
-
985
- method = controller_class.instance_method(action)
986
- source_location = method.source_location
987
- return nil unless source_location
988
-
989
- file_path, line_number = source_location
990
- return nil unless File.exist?(file_path)
991
-
992
- # Parse the file with Prism
993
- result = Prism.parse_file(file_path)
994
- return nil unless result.success?
995
-
996
- # Find the specific method definition node
997
- method_finder = MethodFinder.new(action.to_s, line_number)
998
- method_finder.visit(result.value)
999
- return nil unless method_finder.method_node
983
+ method_node = find_action_node(controller_class, action)
984
+ return unless method_node
1000
985
 
1001
986
  # Find serializer references only within this method
1002
987
  visitor = SerializerVisitor.new
1003
- visitor.visit(method_finder.method_node)
988
+ visitor.visit(method_node)
1004
989
 
1005
990
  # Try to constantize any found serializers and return the first valid one
1006
991
  visitor.serializer_names.filter_map(&:safe_constantize).first
1007
992
  rescue
1008
- # File read or parsing error - return nil
1009
993
  nil
1010
994
  end
1011
995
 
1012
- # Internal: Prism visitor to find a specific method definition by name and line
1013
- class MethodFinder < Prism::Visitor
1014
- attr_reader :method_node
1015
-
1016
- def initialize(method_name, line_number)
1017
- super()
1018
- @method_name = method_name
1019
- @line_number = line_number
1020
- @method_node = nil
1021
- end
1022
-
1023
- def visit_def_node(node)
1024
- # Match by method name and line number proximity
1025
- if node.name.to_s == @method_name &&
1026
- node.location.start_line <= @line_number &&
1027
- node.location.end_line >= @line_number
1028
- @method_node = node
1029
- end
1030
- super
1031
- end
1032
- end
1033
996
 
1034
997
  # Internal: Prism visitor to extract serializer class names from AST
1035
998
  class SerializerVisitor < Prism::Visitor
@@ -1124,10 +1087,8 @@ module TypeSpecFromSerializers
1124
1087
  def extract_param_types_from_controller(controller_class, action)
1125
1088
  param_types = {}
1126
1089
 
1127
- # Extract from *_params methods with type DSL declarations
1128
- # Include private methods since *_params methods are typically private
1129
- param_methods = (controller_class.instance_methods(false) | controller_class.private_instance_methods(false))
1130
- .select { |m| m.to_s.end_with?(config.param_method_suffix) }
1090
+ # Find which *_params methods are called by this action
1091
+ param_methods = find_params_methods_called_by_action(controller_class, action)
1131
1092
 
1132
1093
  param_methods.each do |method_name|
1133
1094
  type_found = false
@@ -1172,6 +1133,63 @@ module TypeSpecFromSerializers
1172
1133
  {}
1173
1134
  end
1174
1135
 
1136
+ # Internal: Finds *_params methods that are called by a specific action method
1137
+ def find_params_methods_called_by_action(controller_class, action)
1138
+ method_node = find_action_node(controller_class, action)
1139
+ return [] unless method_node
1140
+
1141
+ suffix = config.param_method_suffix
1142
+ find_method_calls(method_node)
1143
+ .select { |name| name.end_with?(suffix) }
1144
+ .map(&:to_sym)
1145
+ rescue
1146
+ []
1147
+ end
1148
+
1149
+ # Internal: Finds the AST node for a controller action method.
1150
+ def find_action_node(controller_class, action)
1151
+ return unless controller_class.method_defined?(action)
1152
+
1153
+ method = controller_class.instance_method(action)
1154
+ file_path, line_number = method.source_location
1155
+ return unless file_path && File.exist?(file_path)
1156
+
1157
+ find_method_at_line(file_path, line_number)
1158
+ end
1159
+
1160
+ # Internal: Parses a Ruby file and caches the result.
1161
+ def parse_file_cached(file_path)
1162
+ @parsed_files ||= {}
1163
+ @parsed_files[file_path] ||= begin
1164
+ result = Prism.parse_file(file_path)
1165
+ result.success? ? result.value : nil
1166
+ end
1167
+ end
1168
+
1169
+ # Internal: Finds a DefNode at the exact line number.
1170
+ def find_method_at_line(file_path, line_number)
1171
+ ast = parse_file_cached(file_path)
1172
+ return unless ast
1173
+
1174
+ queue = [ast]
1175
+ while (node = queue.shift)
1176
+ return node if node.is_a?(Prism::DefNode) && node.location.start_line == line_number
1177
+ queue.concat(node.compact_child_nodes)
1178
+ end
1179
+ nil
1180
+ end
1181
+
1182
+ # Internal: Finds all unqualified method call names in an AST node.
1183
+ def find_method_calls(node)
1184
+ calls = []
1185
+ queue = [node]
1186
+ while (current = queue.shift)
1187
+ calls << current.name.to_s if current.is_a?(Prism::CallNode) && current.receiver.nil?
1188
+ queue.concat(current.compact_child_nodes)
1189
+ end
1190
+ calls.uniq
1191
+ end
1192
+
1175
1193
  # Internal: Extracts key-value types from Sorbet hash type
1176
1194
  def extract_hash_types_from_sorbet(sorbet_type)
1177
1195
  param_types = {}
@@ -2,5 +2,5 @@
2
2
 
3
3
  module TypeSpecFromSerializers
4
4
  # Public: This library adheres to semantic versioning.
5
- VERSION = "0.5.2"
5
+ VERSION = "0.5.3"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typespec_from_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danila Poyarkov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-12-22 00:00:00.000000000 Z
12
+ date: 2025-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties