typelizer 0.2.0 → 0.3.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: d00f7bda8328c5148fe2bb6053d27066dd128fd834432c92d39417c3bbdc9405
4
- data.tar.gz: 8b7fc9baa4b646cd91965b1316d9c9dcb22867a5bc8b65407c3fa36bbff9d85c
3
+ metadata.gz: 391ff3345874135d72e3875c60aff109ebfd8ce98b0766e51dd1d2a8909e2af9
4
+ data.tar.gz: 1a3c12dad42402fc5485f3124660e2376db4f8dec7b36d016a8d48a33d568fa0
5
5
  SHA512:
6
- metadata.gz: 9174cd537b757ea89f7a886c1443e12a78f16b269bc16ccb2e49866128c47471df83e55c32cc60ef7148ea4e8cd15d5cc1552f907dad903931c043af97ab6bc2
7
- data.tar.gz: f4d59939214975e140d1a9db3cdc8c5bd9a3278baf6f59d686af7434499917ae30581fcb2a2681c1e106372fcda819250a47f5ba61a4844819dac660f8dea93a
6
+ metadata.gz: 6111652d2f134f20fa6450c1eccaf592a1bade20e0325b49b43a55628e9ac4f7eab1dfbfad09df0aa28893ae898571ccb486d92aa79f23cce682ab3d0c61b8d4
7
+ data.tar.gz: 1b73e070ce4dc50cc87d1a589a286afffcca8f42f596a6172e9b236e9911c72b45ea391d8e7b20ac8321eb83bb488f871c48d67e2a5ece6672530e0e897a6689
data/CHANGELOG.md CHANGED
@@ -7,21 +7,57 @@ and this project adheres to [Semantic Versioning].
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2025-02-28
11
+
12
+ ### Added
13
+
14
+ - Support transform keys. ([@patvice], [@skryukov])
15
+
16
+ Typelizer now respects `transform_keys`/`key_transform` configurations for all plugins.
17
+
18
+ - Support typing method def in Alba. ([@patvice])
19
+
20
+ The `typelize` helper now can be used before a method definition:
21
+
22
+ ```ruby
23
+ class UserResource < ApplicationResource
24
+ attributes :id, :name, :email, :chars_in_name
25
+
26
+ typelize :number
27
+ def chars_in_name(obj)
28
+ obj.name.chars.count
29
+ end
30
+ end
31
+ ```
32
+
33
+ - Support for deprecated attributes. ([@Envek])
34
+
35
+ They will be marked as deprecated using JSDoc [`@deprecated` tag](https://jsdoc.app/tags-deprecated) in TypeScript interface comments.
36
+
37
+ In ActiveModel::Serializer attributes `deprecated` option is recognized.
38
+
39
+ For other serializers, you can use `deprecated` option of `typelize` method.
40
+
41
+ ### Fixed
42
+
43
+ - Ignore `nil` values on fingerprint calculation. ([@Envek])
44
+
10
45
  ## [0.2.0] - 2024-11-26
11
46
 
12
47
  ## Added
13
48
 
14
- - Add support for enum attributes declared using `ActiveRecord::Enum` or explicitly in serializers ([@envek])
15
- - Add support for comments in generated TypeScript interfaces ([@envek])
49
+ - Add support for enum attributes declared using `ActiveRecord::Enum` or explicitly in serializers ([@Envek])
50
+ - Add support for comments in generated TypeScript interfaces ([@Envek])
16
51
  - Add TypeScript verbatim module syntax support through `verbatim_module_syntax` config option ([@patvice])
17
52
  - Add `typelizer:generate:refresh` command to clean output directory and regenerate all interfaces ([@patvice])
18
53
  - Allow disabling Typelizer in Rails development with `DISABLE_TYPELIZER` environment variable to `true` ([@okuramasafumi])
54
+ - Allow to get interfaces without generating TypeScript files ([@Envek])
19
55
 
20
- ## Fixes
56
+ ## Fixed
21
57
 
22
58
  - Do not override `Typelizer.dirs` in the railtie initializer ([@patvice])
23
59
  - Do not raise on empty nested serializers ([@skryukov])
24
- - Attribute options merging in inherited serializers ([@envek])
60
+ - Attribute options merging in inherited serializers ([@Envek])
25
61
  - Allow recursive type definition ([@okuramasafumi])
26
62
 
27
63
  ## [0.1.5] - 2024-10-07
@@ -75,12 +111,13 @@ and this project adheres to [Semantic Versioning].
75
111
  - Initial release ([@skryukov])
76
112
 
77
113
  [@davidrunger]: https://github.com/davidrunger
78
- [@envek]: https://github.com/envek
114
+ [@Envek]: https://github.com/Envek
79
115
  [@okuramasafumi]: https://github.com/okuramasafumi
80
116
  [@patvice]: https://github.com/patvice
81
117
  [@skryukov]: https://github.com/skryukov
82
118
 
83
- [Unreleased]: https://github.com/skryukov/typelizer/compare/v0.2.0...HEAD
119
+ [Unreleased]: https://github.com/skryukov/typelizer/compare/v0.3.0...HEAD
120
+ [0.3.0]: https://github.com/skryukov/typelizer/compare/v0.2.0...v0.3.0
84
121
  [0.2.0]: https://github.com/skryukov/typelizer/compare/v0.1.5...v0.2.0
85
122
  [0.1.5]: https://github.com/skryukov/typelizer/compare/v0.1.4...v0.1.5
86
123
  [0.1.4]: https://github.com/skryukov/typelizer/compare/v0.1.3...v0.1.4
data/README.md CHANGED
@@ -105,7 +105,7 @@ end
105
105
  You can also specify more complex type definitions using a lower-level API:
106
106
 
107
107
  ```ruby
108
- typelize attribute_name: ["string", "Date", optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description"]
108
+ typelize attribute_name: ["string", "Date", optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description", deprecated: "Use `another_attribute` instead"]
109
109
  ```
110
110
 
111
111
  ### TypeScript Integration
@@ -73,6 +73,10 @@ module Typelizer
73
73
  "<#{self.class.name} #{name} properties=#{properties.inspect}>"
74
74
  end
75
75
 
76
+ def fingerprint
77
+ "<#{self.class.name} #{name} properties=[#{properties.map(&:fingerprint).join(", ")}]>"
78
+ end
79
+
76
80
  private
77
81
 
78
82
  def self_type_name
@@ -90,7 +94,7 @@ module Typelizer
90
94
  def infer_types(props, hash_name = :_typelizer_attributes)
91
95
  props.map do |prop|
92
96
  if serializer.respond_to?(hash_name)
93
- dsl_type = serializer.public_send(hash_name)[prop.name.to_sym]
97
+ dsl_type = serializer.public_send(hash_name)[prop.column_name.to_sym]
94
98
  if dsl_type&.any?
95
99
  next Property.new(prop.to_h.merge(dsl_type)).tap do |property|
96
100
  property.comment ||= model_plugin.comment_for(property) if config.comments && property.comment != false
@@ -1,7 +1,7 @@
1
1
  module Typelizer
2
2
  Property = Struct.new(
3
3
  :name, :type, :optional, :nullable,
4
- :multi, :column_name, :comment, :enum,
4
+ :multi, :column_name, :comment, :enum, :deprecated,
5
5
  keyword_init: true
6
6
  ) do
7
7
  def inspect
@@ -17,6 +17,11 @@ module Typelizer
17
17
  "#{name}#{"?" if optional}: #{type_str}"
18
18
  end
19
19
 
20
+ def fingerprint
21
+ props = to_h.merge(type: type_name).reject { |_, v| v.nil? }.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")
22
+ "<#{self.class.name} #{props}>"
23
+ end
24
+
20
25
  private
21
26
 
22
27
  def type_name
@@ -22,19 +22,31 @@ module Typelizer
22
22
  :association, :one, :has_one,
23
23
  :many, :has_many,
24
24
  :attributes, :attribute,
25
+ :method_added,
25
26
  :nested_attribute, :nested,
26
27
  :meta
27
28
  ]
28
29
  end
29
30
 
30
31
  def typelize_method_transform(method:, name:, binding:, type:, attrs:)
31
- return {name => [type, attrs.merge(multi: true)]} if [:many, :has_many].include?(method)
32
+ if method == :method_added && binding.local_variable_defined?(:method_name)
33
+ name = binding.local_variable_get(:method_name)
34
+ end
35
+
36
+ if [:many, :has_many].include?(method)
37
+ return {name => [type, attrs.merge(multi: true)]}
38
+ end
32
39
 
33
40
  super
34
41
  end
35
42
 
36
43
  def root_key
37
- serializer.new({}).send(:_key)
44
+ root = serializer.new({}).send(:_key)
45
+ if !root.nil? && has_transform_key?(serializer) && should_transform_root_key?(serializer)
46
+ fetch_key(serializer, root)
47
+ else
48
+ root
49
+ end
38
50
  end
39
51
 
40
52
  def meta_fields
@@ -51,6 +63,12 @@ module Typelizer
51
63
  private
52
64
 
53
65
  def build_property(name, attr, **options)
66
+ column_name = name
67
+
68
+ if has_transform_key?(serializer)
69
+ name = fetch_key(serializer, name)
70
+ end
71
+
54
72
  case attr
55
73
  when Symbol
56
74
  Property.new(
@@ -59,7 +77,7 @@ module Typelizer
59
77
  optional: false,
60
78
  nullable: false,
61
79
  multi: false,
62
- column_name: name,
80
+ column_name: column_name,
63
81
  **options
64
82
  )
65
83
  when Proc
@@ -69,7 +87,7 @@ module Typelizer
69
87
  optional: false,
70
88
  nullable: false,
71
89
  multi: false,
72
- column_name: nil,
90
+ column_name: column_name,
73
91
  **options
74
92
  )
75
93
  when ::Alba::Association
@@ -80,7 +98,7 @@ module Typelizer
80
98
  optional: false,
81
99
  nullable: false,
82
100
  multi: false, # we override this in typelize_method_transform
83
- column_name: name,
101
+ column_name: column_name,
84
102
  **options
85
103
  )
86
104
  when ::Alba::TypedAttribute
@@ -91,7 +109,7 @@ module Typelizer
91
109
  # not sure if that's a good default tbh
92
110
  nullable: !alba_type.instance_variable_get(:@auto_convert),
93
111
  multi: false,
94
- column_name: name,
112
+ column_name: column_name,
95
113
  **ts_mapper[alba_type.name.to_s],
96
114
  **options
97
115
  )
@@ -102,7 +120,7 @@ module Typelizer
102
120
  optional: false,
103
121
  nullable: false,
104
122
  multi: false,
105
- column_name: nil,
123
+ column_name: column_name,
106
124
  **options
107
125
  )
108
126
  when ::Alba::ConditionalAttribute
@@ -112,6 +130,18 @@ module Typelizer
112
130
  end
113
131
  end
114
132
 
133
+ def has_transform_key?(serializer)
134
+ serializer._transform_type != :none
135
+ end
136
+
137
+ def should_transform_root_key?(serializer)
138
+ serializer._transforming_root_key
139
+ end
140
+
141
+ def fetch_key(serializer, key)
142
+ ::Alba.transform_key(key, transform_type: serializer._transform_type)
143
+ end
144
+
115
145
  private
116
146
 
117
147
  def ts_mapper
@@ -19,11 +19,13 @@ module Typelizer
19
19
  def properties
20
20
  serializer._attributes_data.merge(serializer._reflections).flat_map do |key, association|
21
21
  type = association.options[:serializer] ? Interface.new(serializer: association.options[:serializer]) : nil
22
+ adapter = ActiveModelSerializers::Adapter.configured_adapter
22
23
  Property.new(
23
- name: key.to_s,
24
+ name: adapter.transform_key_casing!(key.to_s, association.options),
24
25
  type: type,
25
26
  optional: association.options.key?(:if) || association.options.key?(:unless),
26
27
  multi: association.respond_to?(:collection?) && association.collection?,
28
+ deprecated: (association.options[:deprecated] if association.options.key?(:deprecated)),
27
29
  column_name: association.name.to_s
28
30
  )
29
31
  end
@@ -11,7 +11,11 @@ module Typelizer
11
11
  end
12
12
 
13
13
  def properties
14
- serializer._attributes
14
+ transform_keys = serializer.try(:_transform_keys)
15
+ attributes = serializer._attributes
16
+ attributes = attributes.transform_keys(&transform_keys) if transform_keys
17
+
18
+ attributes
15
19
  .flat_map do |key, options|
16
20
  if options[:association] == :flat
17
21
  Interface.new(serializer: options.fetch(:serializer)).properties
@@ -18,7 +18,10 @@ type <%= interface.name %> = {
18
18
  <%- else -%>
19
19
  type <%= interface.name %> = {
20
20
  <%- interface.properties.each do |property| -%>
21
- <%= indent("/** #{property.comment.split("\n").map(&:strip).join("\n * ")} */\n") if interface.config.comments && property.comment -%>
21
+ <%- comment = "" -%>
22
+ <%- comment += property.comment.to_s if interface.config.comments -%>
23
+ <%- comment += "\n@deprecated #{property.deprecated.is_a?(String) ? property.deprecated : ''}" if property.deprecated -%>
24
+ <%= indent("/** #{comment.strip.split("\n").map(&:strip).join("\n * ")} */\n") unless comment.empty? -%>
22
25
  <%= indent(property) %>;
23
26
  <%- end -%>
24
27
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typelizer
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -32,7 +32,7 @@ module Typelizer
32
32
  end
33
33
 
34
34
  def write_interface(interface)
35
- write_file("#{interface.filename}.ts", interface.inspect) do
35
+ write_file("#{interface.filename}.ts", interface.fingerprint) do
36
36
  render_template("interface.ts.erb", interface: interface)
37
37
  end
38
38
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typelizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svyatoslav Kryukov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-26 00:00:00.000000000 Z
10
+ date: 2025-02-28 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: railties
@@ -67,7 +66,6 @@ metadata:
67
66
  homepage_uri: https://github.com/skryukov/typelizer
68
67
  source_code_uri: https://github.com/skryukov/typelizer
69
68
  rubygems_mfa_required: 'true'
70
- post_install_message:
71
69
  rdoc_options: []
72
70
  require_paths:
73
71
  - lib
@@ -82,8 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
80
  - !ruby/object:Gem::Version
83
81
  version: '0'
84
82
  requirements: []
85
- rubygems_version: 3.5.23
86
- signing_key:
83
+ rubygems_version: 3.6.2
87
84
  specification_version: 4
88
85
  summary: A TypeScript type generator for Ruby serializers.
89
86
  test_files: []