typespec_from_serializers 0.4.0 → 0.5.0

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: 5a1d95c0934cefa4c37d29af028dbd3677a3d07b5a6f8af804c206400091472d
4
- data.tar.gz: 8ea38365134c4d22d0e60fb19886d6803e6ee9ad82b97a52c8e21decb4ee916c
3
+ metadata.gz: 58c9803235729fabc83ae742e83822906d3ed88746e2c40f7d04d7368409a5cb
4
+ data.tar.gz: de245ba8d20d6b695af332f886c8b0b83a491cd563364a2c06f000c90726739e
5
5
  SHA512:
6
- metadata.gz: 2cfdedc3b5e45b9b9fac2e6abbfd215495787f9eb150d639091f3e5df9eaa4b4d7f84b5ba5fab3ede09876df871a08b11a3165eb358cc2788bac3be8ebbe41ea
7
- data.tar.gz: 745708a0339c1cb4f7f45773eff7a2751826d734a9f6a252a6f275c050ad194b4b9c9464cd6f81e885575befda88345681db27389a980b9ae36ab64eadd51b27
6
+ metadata.gz: efc632aa512a2fec97c35bde59de42c1516ec23d4231be04cbc3238ca5a1bc7756c495cb9b7efcbb5a0209aade99bd6096b04229b0b6bbc4b1afae58a5b4b62b
7
+ data.tar.gz: 2a2fb5ca8cf367d6a22649538af11e2ee690256522caca1b63de0639d8e5b64fb8d6d5af1453ac7604a2632c439b3132652a4b906d16b0cac76c0ac4c87150f3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # TypeSpec From Serializers Changelog
2
2
 
3
+ ## [0.5.0] - 2025-12-22
4
+
5
+ ### Fixed
6
+ - Route parameter typing with `type:` now works correctly without interfering with Rails routing
7
+
3
8
  ## [0.4.0] - 2025-12-22
4
9
 
5
10
  ### Added
@@ -30,6 +30,21 @@ module TypeSpecFromSerializers
30
30
  module Linting
31
31
  extend self
32
32
 
33
+ @warning_count = 0
34
+
35
+ def reset_count
36
+ @warning_count = 0
37
+ end
38
+
39
+ def warning_count
40
+ @warning_count
41
+ end
42
+
43
+ def print_summary
44
+ return if @warning_count == 0
45
+ puts "\nTypeSpec generation completed with #{@warning_count} lint warning#{'s' unless @warning_count == 1}"
46
+ end
47
+
33
48
  # Internal: Lints for missing parameter types
34
49
  def missing_param_types(controller, route, path_param_names, param_types, config)
35
50
  return unless enabled?(config.linting, :missing_param_types)
@@ -37,6 +52,7 @@ module TypeSpecFromSerializers
37
52
  missing_path_params = path_param_names.select { |name| !param_types.key?(name) }
38
53
 
39
54
  unless missing_path_params.empty?
55
+ @warning_count += 1
40
56
  location = "#{controller.camelize}#{config.controller_suffix}##{route[:action]}"
41
57
  warn "TypeSpec Lint: Missing type for path parameter(s) #{missing_path_params.join(', ')} in #{location} (#{route[:method]} #{route[:path]}). Defaulting to 'string'."
42
58
  end
@@ -47,6 +63,7 @@ module TypeSpecFromSerializers
47
63
  return unless enabled?(config.linting, :unknown_response_types)
48
64
 
49
65
  if response_type == "unknown"
66
+ @warning_count += 1
50
67
  location = "#{controller.camelize}#{config.controller_suffix}##{route[:action]}"
51
68
  warn "TypeSpec Lint: Unknown response type for #{location} (#{route[:method]} #{route[:path]}). Consider adding a serializer or explicit type annotation."
52
69
  end
@@ -57,6 +74,7 @@ module TypeSpecFromSerializers
57
74
  return unless enabled?(config.linting, :missing_documentation) && config.extract_docs
58
75
 
59
76
  if doc.nil?
77
+ @warning_count += 1
60
78
  location = "#{controller.camelize}#{config.controller_suffix}##{route[:action]}"
61
79
  warn "TypeSpec Lint: Missing documentation for #{location} (#{route[:method]} #{route[:path]}). Consider adding an RDoc comment."
62
80
  end
@@ -68,6 +86,7 @@ module TypeSpecFromSerializers
68
86
 
69
87
  duplicates = name_counts.select { |_, count| count > 1 }
70
88
  duplicates.each do |action, count|
89
+ @warning_count += 1
71
90
  ops = operations.select { |op| op.action == action }
72
91
  methods = ops.map { |op| op.method }.join(', ')
73
92
  warn "TypeSpec Lint: Action '#{action}' used for multiple routes (#{methods}). Using method suffix to differentiate."
@@ -79,6 +98,7 @@ module TypeSpecFromSerializers
79
98
  return unless enabled?(config.linting, :type_inference_failures)
80
99
 
81
100
  if property.type.nil? && explicit_type.nil?
101
+ @warning_count += 1
82
102
  warn "TypeSpec Lint: Could not infer type for '#{property.name}' in #{serializer_name}. Consider adding explicit type annotation."
83
103
  end
84
104
  end
@@ -598,6 +618,8 @@ module TypeSpecFromSerializers
598
618
 
599
619
  # Public: Generates code for all serializers in the app.
600
620
  def generate(force: ENV["SERIALIZER_TYPESPEC_FORCE"])
621
+ Linting.reset_count
622
+
601
623
  @force_generation = force
602
624
  clean_output_dir if force && config.output_dir.exist?
603
625
 
@@ -614,6 +636,8 @@ module TypeSpecFromSerializers
614
636
  generate_model_for(serializer)
615
637
  end
616
638
 
639
+ Linting.print_summary
640
+
617
641
  {serializers: serializers, controllers: controllers}
618
642
  end
619
643
 
@@ -763,7 +787,7 @@ module TypeSpecFromSerializers
763
787
  path: path,
764
788
  response_type: response_type,
765
789
  route_name: route_name,
766
- param_types: route.defaults[:type] || {},
790
+ param_types: route.defaults[:__typespec_types] || {},
767
791
  }
768
792
  end
769
793
 
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/routing/mapper"
4
+ require "action_dispatch/journey/route"
5
+
6
+ # Internal: Minimal surgical patches to ActionDispatch routing for TypeSpec metadata support.
7
+ #
8
+ # This module patches Rails routing to support the `type:` parameter for specifying
9
+ # path parameter types without interfering with Rails' route matching or URL generation.
10
+ #
11
+ # The type metadata is stored in route defaults under the :__typespec_types key and
12
+ # explicitly excluded from route requirements to prevent it from affecting routing behavior.
13
+ #
14
+ # Examples
15
+ #
16
+ # # In routes.rb
17
+ # resources :users, type: { id: Integer }
18
+ # get '/posts/:id', to: 'posts#show', type: { id: Integer }
19
+ #
20
+ # The patches work at three interception points:
21
+ # 1. Mapper::Base#match - for GET/POST/PATCH/etc methods
22
+ # 2. Mapper::Resources#resources - for resources/resource methods
23
+ # 3. Journey::Route#requirements - filters metadata from route requirements
24
+ module TypeSpecFromSerializers
25
+ # Internal: Shared logic for moving type metadata from options to defaults.
26
+ module RoutingPatchHelpers
27
+ module_function
28
+
29
+ # Internal: Moves type: parameter from route options to defaults[:__typespec_types].
30
+ #
31
+ # This ensures type metadata is stored but doesn't interfere with routing.
32
+ #
33
+ # options - Hash of route options (will be modified in place)
34
+ #
35
+ # Returns the modified options Hash
36
+ def move_type_to_defaults!(options)
37
+ return options unless options.key?(:type)
38
+
39
+ types = options.delete(:type)
40
+ options[:defaults] = (options[:defaults] || {}).merge(__typespec_types: types)
41
+ options
42
+ end
43
+ end
44
+
45
+ # Internal: Patches ActionDispatch::Routing::Mapper::Base to intercept match method.
46
+ #
47
+ # Intercepts the low-level match method used by get, post, patch, delete, etc.
48
+ module MapperPatch
49
+ def match(path, *rest, &block)
50
+ options = rest.last.is_a?(Hash) ? rest.pop.dup : {}
51
+ RoutingPatchHelpers.move_type_to_defaults!(options)
52
+
53
+ rest.push(options) unless options.empty?
54
+ super(path, *rest, &block)
55
+ end
56
+ end
57
+
58
+ # Internal: Patches ActionDispatch::Routing::Mapper::Resources to intercept resources method.
59
+ #
60
+ # Intercepts the resources/resource DSL methods to support type: parameter.
61
+ module ResourcesPatch
62
+ def resources(*resources, &block)
63
+ options = resources.extract_options!
64
+ RoutingPatchHelpers.move_type_to_defaults!(options)
65
+
66
+ resources.push(options) unless options.empty?
67
+ super(*resources, &block)
68
+ end
69
+ end
70
+
71
+ # Internal: Patches ActionDispatch::Journey::Route to filter type metadata from requirements.
72
+ #
73
+ # The requirements method is used for route matching and URL generation.
74
+ # We exclude :__typespec_types to ensure it doesn't affect routing behavior.
75
+ module RoutePatch
76
+ def requirements
77
+ super.except(:__typespec_types)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Apply patches to ActionDispatch
83
+ ActionDispatch::Routing::Mapper::Base.prepend(TypeSpecFromSerializers::MapperPatch)
84
+ ActionDispatch::Routing::Mapper::Resources.prepend(TypeSpecFromSerializers::ResourcesPatch)
85
+ ActionDispatch::Journey::Route.prepend(TypeSpecFromSerializers::RoutePatch)
@@ -2,5 +2,5 @@
2
2
 
3
3
  module TypeSpecFromSerializers
4
4
  # Public: This library adheres to semantic versioning.
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end
@@ -5,3 +5,4 @@ require_relative "typespec_from_serializers/dsl"
5
5
  require_relative "typespec_from_serializers/sorbet"
6
6
  require_relative "typespec_from_serializers/rbi"
7
7
  require_relative "typespec_from_serializers/railtie"
8
+ require_relative "typespec_from_serializers/routing_patch"
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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danila Poyarkov
@@ -320,6 +320,7 @@ files:
320
320
  - lib/typespec_from_serializers/railtie.rb
321
321
  - lib/typespec_from_serializers/rbi.rb
322
322
  - lib/typespec_from_serializers/rdoc.rb
323
+ - lib/typespec_from_serializers/routing_patch.rb
323
324
  - lib/typespec_from_serializers/runner.rb
324
325
  - lib/typespec_from_serializers/sorbet.rb
325
326
  - lib/typespec_from_serializers/version.rb