typelizer 0.2.0 → 0.4.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: ed3e7b6339e4a79168c10afd541bba9ea8c509b00f689465df037501327ac6e2
4
+ data.tar.gz: a7f079a7ad377d1f2754cc1efcb98a7bc0e8af11c3910e8f56b648090ddb7f46
5
5
  SHA512:
6
- metadata.gz: 9174cd537b757ea89f7a886c1443e12a78f16b269bc16ccb2e49866128c47471df83e55c32cc60ef7148ea4e8cd15d5cc1552f907dad903931c043af97ab6bc2
7
- data.tar.gz: f4d59939214975e140d1a9db3cdc8c5bd9a3278baf6f59d686af7434499917ae30581fcb2a2681c1e106372fcda819250a47f5ba61a4844819dac660f8dea93a
6
+ metadata.gz: 7687ff8e061c46e11f56421684a5629a823debc4d76ac3018e3ab7ac960416a05088662372b38bb4029a650ba6d81c74fbccb49d9821d7864f86023fdddd819e
7
+ data.tar.gz: 860d8dc24a04302c2e70d30a4ef6811f595ee4e55788ab47d6966c10a405370dc756419b06e15b343b00fc38d495897e706d5be5a5fb1816b9a0da3315c009ce
data/CHANGELOG.md CHANGED
@@ -5,23 +5,93 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog],
6
6
  and this project adheres to [Semantic Versioning].
7
7
 
8
- ## [Unreleased]
8
+ ## [0.4.0] - 2025-05-03
9
+
10
+ ### Added
11
+
12
+ - Support for `panko_serializer` gem ([@PedroAugustoRamalhoDuarte], [@skryukov])
13
+ - Mark `has_one` and `belongs_to` association as nullable. ([@skryukov])
14
+
15
+ By default, `has_one` associations are marked as nullable in TypeScript interfaces.
16
+ `belongs_to` associations are marked as nullable if the database column is nullable.
17
+ Use the new `config.associations_strategy = :active_record` configuration option to mark associations as nullable based on the `required`/`optional` options.
18
+ You can also use the type hint `typelize latest_post: {nullable: false}` in the serializer to override the defaults.
19
+
20
+ - Support inherited typelization. ([@skryukov])
21
+
22
+ Set `config.inheritance_strategy = :inheritance` to make Typelizer respect the inheritance hierarchy of serializers:
23
+
24
+ ```ruby
25
+ class AdminSerializer < UserSerializer
26
+ attributes :admin_level
27
+ end
28
+ ```
29
+
30
+ ```typescript
31
+ // app/javascript/types/serializers/Admin.ts
32
+ import { User } from "@/types";
33
+
34
+ export type Admin = User & {
35
+ admin_level: number;
36
+ }
37
+ ```
38
+
39
+ ### Fixed
40
+
41
+ - Alba: always use strings for keys in properties. ([@skryukov])
42
+ This change will fire update of all hashes for Alba serializers, but it's necessary to support inheritance strategy.
43
+
44
+ ## [0.3.0] - 2025-02-28
45
+
46
+ ### Added
47
+
48
+ - Support transform keys. ([@patvice], [@skryukov])
49
+
50
+ Typelizer now respects `transform_keys`/`key_transform` configurations for all plugins.
51
+
52
+ - Support typing method def in Alba. ([@patvice])
53
+
54
+ The `typelize` helper now can be used before a method definition:
55
+
56
+ ```ruby
57
+ class UserResource < ApplicationResource
58
+ attributes :id, :name, :email, :chars_in_name
59
+
60
+ typelize :number
61
+ def chars_in_name(obj)
62
+ obj.name.chars.count
63
+ end
64
+ end
65
+ ```
66
+
67
+ - Support for deprecated attributes. ([@Envek])
68
+
69
+ They will be marked as deprecated using JSDoc [`@deprecated` tag](https://jsdoc.app/tags-deprecated) in TypeScript interface comments.
70
+
71
+ In ActiveModel::Serializer attributes `deprecated` option is recognized.
72
+
73
+ For other serializers, you can use `deprecated` option of `typelize` method.
74
+
75
+ ### Fixed
76
+
77
+ - Ignore `nil` values on fingerprint calculation. ([@Envek])
9
78
 
10
79
  ## [0.2.0] - 2024-11-26
11
80
 
12
81
  ## Added
13
82
 
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])
83
+ - Add support for enum attributes declared using `ActiveRecord::Enum` or explicitly in serializers ([@Envek])
84
+ - Add support for comments in generated TypeScript interfaces ([@Envek])
16
85
  - Add TypeScript verbatim module syntax support through `verbatim_module_syntax` config option ([@patvice])
17
86
  - Add `typelizer:generate:refresh` command to clean output directory and regenerate all interfaces ([@patvice])
18
87
  - Allow disabling Typelizer in Rails development with `DISABLE_TYPELIZER` environment variable to `true` ([@okuramasafumi])
88
+ - Allow to get interfaces without generating TypeScript files ([@Envek])
19
89
 
20
- ## Fixes
90
+ ## Fixed
21
91
 
22
92
  - Do not override `Typelizer.dirs` in the railtie initializer ([@patvice])
23
93
  - Do not raise on empty nested serializers ([@skryukov])
24
- - Attribute options merging in inherited serializers ([@envek])
94
+ - Attribute options merging in inherited serializers ([@Envek])
25
95
  - Allow recursive type definition ([@okuramasafumi])
26
96
 
27
97
  ## [0.1.5] - 2024-10-07
@@ -75,12 +145,14 @@ and this project adheres to [Semantic Versioning].
75
145
  - Initial release ([@skryukov])
76
146
 
77
147
  [@davidrunger]: https://github.com/davidrunger
78
- [@envek]: https://github.com/envek
148
+ [@Envek]: https://github.com/Envek
79
149
  [@okuramasafumi]: https://github.com/okuramasafumi
80
150
  [@patvice]: https://github.com/patvice
81
151
  [@skryukov]: https://github.com/skryukov
82
152
 
83
- [Unreleased]: https://github.com/skryukov/typelizer/compare/v0.2.0...HEAD
153
+ [Unreleased]: https://github.com/skryukov/typelizer/compare/v0.4.0...HEAD
154
+ [0.4.0]: https://github.com/skryukov/typelizer/compare/v0.3.0...v0.4.0
155
+ [0.3.0]: https://github.com/skryukov/typelizer/compare/v0.2.0...v0.3.0
84
156
  [0.2.0]: https://github.com/skryukov/typelizer/compare/v0.1.5...v0.2.0
85
157
  [0.1.5]: https://github.com/skryukov/typelizer/compare/v0.1.4...v0.1.5
86
158
  [0.1.4]: https://github.com/skryukov/typelizer/compare/v0.1.3...v0.1.4
data/README.md CHANGED
@@ -29,7 +29,7 @@ Typelizer is a Ruby gem that automatically generates TypeScript interfaces from
29
29
  ## Features
30
30
 
31
31
  - Automatic TypeScript interface generation
32
- - Support for multiple serializer libraries (`Alba`, `ActiveModel::Serializer`, `Oj::Serializer`)
32
+ - Support for multiple serializer libraries (`Alba`, `ActiveModel::Serializer`, `Oj::Serializer`, `Panko::Serializer`)
33
33
  - File watching and automatic regeneration in development
34
34
 
35
35
  ## Installation
@@ -50,6 +50,10 @@ Include the Typelizer DSL in your serializers:
50
50
  class ApplicationResource
51
51
  include Alba::Resource
52
52
  include Typelizer::DSL
53
+
54
+ # For Alba, we recommend using the `helper` method instead of `include`.
55
+ # See the documentation: https://github.com/okuramasafumi/alba/blob/main/README.md#helper
56
+ # helper Typelizer::DSL
53
57
  end
54
58
 
55
59
  class PostResource < ApplicationResource
@@ -105,7 +109,7 @@ end
105
109
  You can also specify more complex type definitions using a lower-level API:
106
110
 
107
111
  ```ruby
108
- typelize attribute_name: ["string", "Date", optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description"]
112
+ typelize attribute_name: ["string", "Date", optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description", deprecated: "Use `another_attribute` instead"]
109
113
  ```
110
114
 
111
115
  ### TypeScript Integration
@@ -252,6 +256,16 @@ Typelizer.configure do |config|
252
256
  # Strategy for handling null values (:nullable, :optional, or :nullable_and_optional)
253
257
  config.null_strategy = :nullable
254
258
 
259
+ # Strategy for handling serializer inheritance (:none, :inheritance)
260
+ # :none - lists all attributes of the serializer in the type
261
+ # :inheritance - extends the type from the parent serializer
262
+ config.inheritance_strategy = :none
263
+
264
+ # Strategy for handling `has_one` and `belongs_to` associations nullability (:database, :active_record)
265
+ # :database - uses the database column nullability
266
+ # :active_record - uses the `required` / `optional` association options
267
+ config.associations_strategy = :database
268
+
255
269
  # Directory where TypeScript interfaces will be generated
256
270
  config.output_dir = Rails.root.join("app/javascript/types/serializers")
257
271
 
@@ -25,6 +25,8 @@ module Typelizer
25
25
  :types_import_path,
26
26
  :types_global,
27
27
  :verbatim_module_syntax,
28
+ :inheritance_strategy,
29
+ :associations_strategy,
28
30
  :comments,
29
31
  keyword_init: true
30
32
  ) do
@@ -47,6 +49,8 @@ module Typelizer
47
49
 
48
50
  type_mapping: TYPE_MAPPING,
49
51
  null_strategy: :nullable,
52
+ inheritance_strategy: :none,
53
+ associations_strategy: :database,
50
54
  comments: false,
51
55
 
52
56
  output_dir: js_root.join("types/serializers"),
@@ -17,7 +17,7 @@ module Typelizer
17
17
 
18
18
  def name
19
19
  if inline?
20
- Renderer.new("inline_type.ts.erb").call(properties: properties).strip
20
+ Renderer.call("inline_type.ts.erb", properties: properties).strip
21
21
  else
22
22
  config.serializer_name_mapper.call(serializer).tr_s(":", "")
23
23
  end
@@ -53,26 +53,56 @@ module Typelizer
53
53
  end
54
54
  end
55
55
 
56
+ def overwritten_properties
57
+ return [] unless parent_interface
58
+
59
+ @overwritten_properties ||= parent_interface.properties - properties
60
+ end
61
+
62
+ def own_properties
63
+ @own_properties ||= properties - (parent_interface&.properties || [])
64
+ end
65
+
66
+ def properties_to_print
67
+ parent_interface ? own_properties : properties
68
+ end
69
+
70
+ def parent_interface
71
+ return if config.inheritance_strategy == :none
72
+ return unless serializer.superclass.respond_to?(:typelizer_interface)
73
+
74
+ interface = serializer.superclass.typelizer_interface
75
+ return if interface.empty?
76
+
77
+ interface
78
+ end
79
+
56
80
  def imports
57
- association_serializers, attribute_types = properties.filter_map(&:type)
58
- .uniq
59
- .partition { |type| type.is_a?(Interface) }
81
+ @imports ||= begin
82
+ association_serializers, attribute_types = properties_to_print.filter_map(&:type)
83
+ .uniq
84
+ .partition { |type| type.is_a?(Interface) }
60
85
 
61
- serializer_types = association_serializers
62
- .filter_map { |interface| interface.name if interface.name != name && !interface.inline? }
86
+ serializer_types = association_serializers
87
+ .filter_map { |interface| interface.name if interface.name != name && !interface.inline? }
63
88
 
64
- custom_type_imports = attribute_types
65
- .flat_map { |type| extract_typescript_types(type.to_s) }
66
- .uniq
67
- .reject { |type| global_type?(type) }
89
+ custom_type_imports = attribute_types
90
+ .flat_map { |type| extract_typescript_types(type.to_s) }
91
+ .uniq
92
+ .reject { |type| global_type?(type) }
68
93
 
69
- (custom_type_imports + serializer_types).uniq - Array(self_type_name)
94
+ (custom_type_imports + serializer_types + Array(parent_interface&.name)).uniq - Array(self_type_name)
95
+ end
70
96
  end
71
97
 
72
98
  def inspect
73
99
  "<#{self.class.name} #{name} properties=#{properties.inspect}>"
74
100
  end
75
101
 
102
+ def fingerprint
103
+ "<#{self.class.name} #{name} properties=[#{properties_to_print.map(&:fingerprint).join(", ")}]>"
104
+ end
105
+
76
106
  private
77
107
 
78
108
  def self_type_name
@@ -90,7 +120,7 @@ module Typelizer
90
120
  def infer_types(props, hash_name = :_typelizer_attributes)
91
121
  props.map do |prop|
92
122
  if serializer.respond_to?(hash_name)
93
- dsl_type = serializer.public_send(hash_name)[prop.name.to_sym]
123
+ dsl_type = serializer.public_send(hash_name)[prop.column_name.to_sym]
94
124
  if dsl_type&.any?
95
125
  next Property.new(prop.to_h.merge(dsl_type)).tap do |property|
96
126
  property.comment ||= model_plugin.comment_for(property) if config.comments && property.comment != false
@@ -9,6 +9,30 @@ module Typelizer
9
9
  attr_reader :model_class, :config
10
10
 
11
11
  def infer_types(prop)
12
+ if (association = model_class&.reflect_on_association(prop.column_name.to_sym))
13
+ case association.macro
14
+ when :belongs_to
15
+ foreign_key = association.foreign_key
16
+ column = model_class&.columns_hash&.dig(foreign_key.to_s)
17
+ if config.associations_strategy == :database
18
+ prop.nullable = column.null if column
19
+ elsif config.associations_strategy == :active_record
20
+ prop.nullable = !association.options[:required] || association.options[:optional]
21
+ else
22
+ raise "Unknown associations strategy: #{config.associations_strategy}"
23
+ end
24
+ when :has_one
25
+ if config.associations_strategy == :database
26
+ prop.nullable = true
27
+ elsif config.associations_strategy == :active_record
28
+ prop.nullable = !association.options[:required]
29
+ else
30
+ raise "Unknown associations strategy: #{config.associations_strategy}"
31
+ end
32
+ end
33
+ return prop
34
+ end
35
+
12
36
  column = model_class&.columns_hash&.dig(prop.column_name.to_s)
13
37
  return prop unless column
14
38
 
@@ -1,7 +1,7 @@
1
1
  module Typelizer
2
2
  module ModelPlugins
3
3
  class Poro
4
- # We don't care about intialization
4
+ # We don't care about initialization
5
5
  def initialize(...)
6
6
  end
7
7
 
@@ -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
@@ -9,6 +9,12 @@ module Typelizer
9
9
  "<#{self.class.name} #{props}>"
10
10
  end
11
11
 
12
+ def eql?(other)
13
+ return false unless other.is_a?(self.class)
14
+
15
+ fingerprint == other.fingerprint
16
+ end
17
+
12
18
  def to_s
13
19
  type_str = type_name
14
20
  type_str = "Array<#{type_str}>" if multi
@@ -17,6 +23,11 @@ module Typelizer
17
23
  "#{name}#{"?" if optional}: #{type_str}"
18
24
  end
19
25
 
26
+ def fingerprint
27
+ props = to_h.merge(type: type_name).reject { |_, v| v.nil? }.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")
28
+ "<#{self.class.name} #{props}>"
29
+ end
30
+
20
31
  private
21
32
 
22
33
  def type_name
@@ -4,6 +4,10 @@ require "erb"
4
4
 
5
5
  module Typelizer
6
6
  class Renderer
7
+ def self.call(template, **context)
8
+ new(template).call(**context)
9
+ end
10
+
7
11
  def initialize(template)
8
12
  @erb = ERB.new(File.read(File.join(File.dirname(__FILE__), "templates/#{template}")), trim_mode: "-")
9
13
  end
@@ -24,5 +28,9 @@ module Typelizer
24
28
  spaces = " " * multiplier
25
29
  content.to_s.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join
26
30
  end
31
+
32
+ def render(template, **context)
33
+ Renderer.call(template, **context)
34
+ end
27
35
  end
28
36
  end
@@ -13,7 +13,7 @@ module Typelizer
13
13
 
14
14
  def properties
15
15
  serializer._attributes.map do |name, attr|
16
- build_property(name, attr)
16
+ build_property(name.is_a?(Symbol) ? name.name : name, attr)
17
17
  end
18
18
  end
19
19
 
@@ -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
@@ -13,6 +13,8 @@ module Typelizer
13
13
  Alba
14
14
  elsif defined?(ActiveModel::Serializer) && serializer.ancestors.include?(ActiveModel::Serializer)
15
15
  AMS
16
+ elsif defined?(::Panko::Serializer) && serializer.ancestors.include?(::Panko::Serializer)
17
+ Panko
16
18
  else
17
19
  raise "Can't guess serializer plugin for #{serializer}. " \
18
20
  "Please specify it with `config.serializer_plugin`."
@@ -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
@@ -0,0 +1,63 @@
1
+ require_relative "base"
2
+
3
+ module Typelizer
4
+ module SerializerPlugins
5
+ class Panko < Base
6
+ def methods_to_typelize
7
+ [:has_many, :has_one, :attributes, :method_added]
8
+ end
9
+
10
+ def properties
11
+ descriptor = serializer.new.instance_variable_get(:@descriptor)
12
+ attributes = descriptor.attributes
13
+ methods_attributes = descriptor.method_fields
14
+ has_many_associations = descriptor.has_many_associations
15
+ has_one_associations = descriptor.has_one_associations
16
+
17
+ attributes.map do |att|
18
+ attribute_property(att)
19
+ end + methods_attributes.map do |att|
20
+ attribute_property(att)
21
+ end + has_many_associations.map do |assoc|
22
+ association_property(assoc, multi: true)
23
+ end + has_one_associations.map do |assoc|
24
+ association_property(assoc, multi: false)
25
+ end
26
+ end
27
+
28
+ def typelize_method_transform(method:, name:, binding:, type:, attrs:)
29
+ if method == :method_added && binding.local_variable_defined?(:method)
30
+ name = binding.local_variable_get(:method)
31
+ end
32
+
33
+ super
34
+ end
35
+
36
+ private
37
+
38
+ def attribute_property(att)
39
+ Property.new(
40
+ name: att.alias_name || att.name,
41
+ optional: false,
42
+ nullable: false,
43
+ multi: false,
44
+ column_name: att.name
45
+ )
46
+ end
47
+
48
+ def association_property(assoc, multi: false)
49
+ key = assoc.name_str
50
+ serializer = assoc.descriptor.type
51
+ type = serializer ? Interface.new(serializer: serializer) : nil
52
+ Property.new(
53
+ name: key,
54
+ type: type,
55
+ optional: false,
56
+ nullable: false,
57
+ multi: multi,
58
+ column_name: key
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ <%
2
+ comment = ""
3
+ comment += property.comment.to_s if interface.config.comments
4
+ if property.deprecated
5
+ comment += "\n@deprecated #{property.deprecated.is_a?(String) ? property.deprecated : ''}"
6
+ end
7
+ -%>
8
+ <%= indent("/** #{comment.strip.split("\n").map(&:strip).join("\n * ")} */\n") unless comment.empty? -%>
@@ -0,0 +1 @@
1
+ <%= interface.overwritten_properties.any? ? "Omit<" : "" %><%= interface.parent_interface.name %><%= "['#{interface.parent_interface.root_key}']" if interface.parent_interface.root_key %><%= interface.overwritten_properties.any? ? ", " + interface.overwritten_properties.map { |pr| "'#{pr.name}'" }.join(' | ') + ">" : ""%>
@@ -1,31 +1,28 @@
1
- <%- if interface.imports.any? -%>
1
+ <% if interface.imports.any? -%>
2
2
  import type {<%= interface.imports.join(", ") %>} from '<%= interface.config.types_import_path %>'
3
- <%- end -%>
3
+ <% end -%>
4
4
 
5
- <%- if interface.root_key -%>
6
- type <%= interface.name %>Data = {
7
- <%- interface.properties.each do |property| -%>
5
+ type <%= interface.name %><%= "Data" if interface.root_key %> = <%=
6
+ render("inheritance.ts.erb", interface: interface).strip if interface.parent_interface
7
+ -%>
8
+ <% unless interface.parent_interface && interface.properties_to_print.empty? -%>
9
+ <%= " & " if interface.parent_interface %>{
10
+ <% interface.properties_to_print.each do |property| -%>
11
+ <%= render("comment.ts.erb", interface: interface, property: property) -%>
8
12
  <%= indent(property) %>;
9
- <%- end -%>
13
+ <% end -%>
10
14
  }
11
-
12
- type <%= interface.name %> = {
13
- <%= interface.root_key %>: <%= interface.name %>Data;
14
- <%- interface.meta_fields&.each do |property| -%>
15
- <%= indent(property) %>;
16
- <%- end -%>
17
- }
18
- <%- else -%>
15
+ <% end %><% if interface.root_key %>
19
16
  type <%= interface.name %> = {
20
- <%- interface.properties.each do |property| -%>
21
- <%= indent("/** #{property.comment.split("\n").map(&:strip).join("\n * ")} */\n") if interface.config.comments && property.comment -%>
17
+ <%= indent(interface.root_key) %>: <%= interface.name %>Data;
18
+ <% interface.meta_fields&.each do |property| -%>
22
19
  <%= indent(property) %>;
23
- <%- end -%>
20
+ <% end -%>
24
21
  }
25
- <%- end -%>
22
+ <% end -%>
26
23
 
27
- <%-if interface.config.verbatim_module_syntax -%>
24
+ <% if interface.config.verbatim_module_syntax -%>
28
25
  export type { <%= interface.name %> };
29
- <%- else -%>
26
+ <% else -%>
30
27
  export default <%= interface.name %>;
31
- <%- end -%>
28
+ <% end -%>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typelizer
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.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
data/lib/typelizer.rb CHANGED
@@ -14,6 +14,7 @@ require_relative "typelizer/serializer_plugins/auto"
14
14
  require_relative "typelizer/serializer_plugins/oj_serializers"
15
15
  require_relative "typelizer/serializer_plugins/alba"
16
16
  require_relative "typelizer/serializer_plugins/ams"
17
+ require_relative "typelizer/serializer_plugins/panko"
17
18
 
18
19
  require_relative "typelizer/model_plugins/active_record"
19
20
  require_relative "typelizer/model_plugins/poro"
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.4.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-05-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: railties
@@ -51,8 +50,11 @@ files:
51
50
  - lib/typelizer/serializer_plugins/auto.rb
52
51
  - lib/typelizer/serializer_plugins/base.rb
53
52
  - lib/typelizer/serializer_plugins/oj_serializers.rb
53
+ - lib/typelizer/serializer_plugins/panko.rb
54
+ - lib/typelizer/templates/comment.ts.erb
54
55
  - lib/typelizer/templates/fingerprint.ts.erb
55
56
  - lib/typelizer/templates/index.ts.erb
57
+ - lib/typelizer/templates/inheritance.ts.erb
56
58
  - lib/typelizer/templates/inline_type.ts.erb
57
59
  - lib/typelizer/templates/interface.ts.erb
58
60
  - lib/typelizer/version.rb
@@ -67,7 +69,6 @@ metadata:
67
69
  homepage_uri: https://github.com/skryukov/typelizer
68
70
  source_code_uri: https://github.com/skryukov/typelizer
69
71
  rubygems_mfa_required: 'true'
70
- post_install_message:
71
72
  rdoc_options: []
72
73
  require_paths:
73
74
  - lib
@@ -82,8 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
83
  - !ruby/object:Gem::Version
83
84
  version: '0'
84
85
  requirements: []
85
- rubygems_version: 3.5.23
86
- signing_key:
86
+ rubygems_version: 3.6.2
87
87
  specification_version: 4
88
88
  summary: A TypeScript type generator for Ruby serializers.
89
89
  test_files: []