typelizer 0.5.5 → 0.6.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 +4 -4
- data/CHANGELOG.md +40 -1
- data/README.md +6 -0
- data/lib/typelizer/config.rb +2 -0
- data/lib/typelizer/import_sorter.rb +22 -0
- data/lib/typelizer/interface.rb +14 -1
- data/lib/typelizer/model_plugins/active_record.rb +23 -0
- data/lib/typelizer/property.rb +8 -2
- data/lib/typelizer/serializer_plugins/alba/trait_attribute_collector.rb +9 -5
- data/lib/typelizer/templates/enums.ts.erb +3 -0
- data/lib/typelizer/templates/index.ts.erb +3 -0
- data/lib/typelizer/version.rb +1 -1
- data/lib/typelizer/writer.rb +21 -4
- data/lib/typelizer.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 57cc88a8063ebe9f00e0558f3dbd59aca579b5e191bdce38d3f8ca9b0451acee
|
|
4
|
+
data.tar.gz: 32cb1941e3ece707061fd7f2b1e6287710a0f9e2e8f8fc4d56b7f39fe444a7f6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a9fb264406d6ea58bc1b7cc7e875bef11e08cf8f758786f0f63e4d110db5b0e39832615167068baea973a5cf5236f76cac537ce1cfd3f21abd3def162a33edd2
|
|
7
|
+
data.tar.gz: 74a8a3552d25fff6c5dee5837d42dc6f257d097944874ade9aee247d432ff7d85303ebb9a6e60ae000bb8634c2a47e4be2e52dc5f4b08d49bd06963473a19b43
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning].
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-01-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- New `imports_sort_order` configuration option for consistent import ordering in generated TypeScript interfaces. ([@jonmarkgo])
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
Typelizer.configure do |config|
|
|
18
|
+
# Sort imports alphabetically
|
|
19
|
+
config.imports_sort_order = :alphabetical
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Available options:
|
|
24
|
+
- `:none` (default) - preserve original order
|
|
25
|
+
- `:alphabetical` - sort imports A-Z (case-insensitive)
|
|
26
|
+
- `Proc` - custom sorting logic
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Rails enum attributes now generate named types (e.g., `PostCategory`) in a separate `Enums.ts` file instead of inline unions. ([@skryukov])
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Fix `index.ts` not being regenerated when traits are added or removed. ([@skryukov])
|
|
35
|
+
|
|
36
|
+
## [0.5.6] - 2026-01-12
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- Type inference for serialized fields. `serialize :skills, type: Array` generates `Array<unknown>`, `serialize :settings, type: Hash` generates `Record<string, unknown>`. ([@skryukov])
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- Alba: respect `key:` option for associations defined in traits. ([@skryukov])
|
|
45
|
+
|
|
10
46
|
## [0.5.5] - 2025-12-24
|
|
11
47
|
|
|
12
48
|
### Added
|
|
@@ -299,6 +335,7 @@ and this project adheres to [Semantic Versioning].
|
|
|
299
335
|
|
|
300
336
|
[@davidrunger]: https://github.com/davidrunger
|
|
301
337
|
[@Envek]: https://github.com/Envek
|
|
338
|
+
[@jonmarkgo]: https://github.com/jonmarkgo
|
|
302
339
|
[@hkamberovic]: https://github.com/hkamberovic
|
|
303
340
|
[@kristinemcbride]: https://github.com/kristinemcbride
|
|
304
341
|
[@nkriege]: https://github.com/nkriege
|
|
@@ -310,7 +347,9 @@ and this project adheres to [Semantic Versioning].
|
|
|
310
347
|
[@prog-supdex]: https://github.com/prog-supdex
|
|
311
348
|
[@ventsislaf]: https://github.com/ventsislaf
|
|
312
349
|
|
|
313
|
-
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.
|
|
350
|
+
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.6.0...HEAD
|
|
351
|
+
[0.6.0]: https://github.com/skryukov/typelizer/compare/v0.5.6...v0.6.0
|
|
352
|
+
[0.5.6]: https://github.com/skryukov/typelizer/compare/v0.5.5...v0.5.6
|
|
314
353
|
[0.5.5]: https://github.com/skryukov/typelizer/compare/v0.5.4...v0.5.5
|
|
315
354
|
[0.5.4]: https://github.com/skryukov/typelizer/compare/v0.5.3...v0.5.4
|
|
316
355
|
[0.5.3]: https://github.com/skryukov/typelizer/compare/v0.5.2...v0.5.3
|
data/README.md
CHANGED
|
@@ -493,6 +493,12 @@ Typelizer.configure do |config|
|
|
|
493
493
|
# Proc - custom sorting function receiving array of Property objects
|
|
494
494
|
config.properties_sort_order = :none
|
|
495
495
|
|
|
496
|
+
# Strategy for ordering imports in generated TypeScript interfaces
|
|
497
|
+
# :none - preserve original order (default)
|
|
498
|
+
# :alphabetical - sort imports A-Z (case-insensitive)
|
|
499
|
+
# Proc - custom sorting function receiving array of import strings
|
|
500
|
+
config.imports_sort_order = :none
|
|
501
|
+
|
|
496
502
|
# Plugin for model type inference (default: ModelPlugins::Auto)
|
|
497
503
|
config.model_plugin = Typelizer::ModelPlugins::Auto
|
|
498
504
|
|
data/lib/typelizer/config.rb
CHANGED
|
@@ -24,6 +24,7 @@ module Typelizer
|
|
|
24
24
|
:serializer_model_mapper,
|
|
25
25
|
:properties_transformer,
|
|
26
26
|
:properties_sort_order,
|
|
27
|
+
:imports_sort_order,
|
|
27
28
|
:model_plugin,
|
|
28
29
|
:serializer_plugin,
|
|
29
30
|
:plugin_configs,
|
|
@@ -79,6 +80,7 @@ module Typelizer
|
|
|
79
80
|
types_global: DEFAULT_TYPES_GLOBAL,
|
|
80
81
|
properties_transformer: nil,
|
|
81
82
|
properties_sort_order: :none,
|
|
83
|
+
imports_sort_order: :none,
|
|
82
84
|
verbatim_module_syntax: false
|
|
83
85
|
}
|
|
84
86
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Typelizer
|
|
4
|
+
module ImportSorter
|
|
5
|
+
def self.sort(imports, sort_order)
|
|
6
|
+
case sort_order
|
|
7
|
+
when :none, nil
|
|
8
|
+
imports
|
|
9
|
+
when :alphabetical
|
|
10
|
+
imports.sort_by { |i| i.to_s.downcase }
|
|
11
|
+
when Proc
|
|
12
|
+
result = sort_order.call(imports)
|
|
13
|
+
result.is_a?(Array) ? result : imports
|
|
14
|
+
else
|
|
15
|
+
imports
|
|
16
|
+
end
|
|
17
|
+
rescue => e
|
|
18
|
+
Typelizer.logger.warn("ImportSorter error: #{e.message}, preserving original order")
|
|
19
|
+
imports
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/typelizer/interface.rb
CHANGED
|
@@ -58,6 +58,15 @@ module Typelizer
|
|
|
58
58
|
@trait_interfaces ||= serializer_plugin.trait_interfaces
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def enum_types
|
|
62
|
+
@enum_types ||= begin
|
|
63
|
+
all_properties = properties + trait_interfaces.flat_map(&:properties)
|
|
64
|
+
all_properties
|
|
65
|
+
.select(&:enum_definition)
|
|
66
|
+
.uniq(&:enum_type_name)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
61
70
|
def properties
|
|
62
71
|
@properties ||= begin
|
|
63
72
|
props = serializer_plugin.properties
|
|
@@ -119,7 +128,11 @@ module Typelizer
|
|
|
119
128
|
prop.with_traits.map { |t| "#{prop.type.name}#{t.to_s.camelize}Trait" }
|
|
120
129
|
end
|
|
121
130
|
|
|
122
|
-
|
|
131
|
+
# Collect enum type names from properties
|
|
132
|
+
enum_imports = all_properties.filter_map(&:enum_type_name)
|
|
133
|
+
|
|
134
|
+
result = (custom_type_imports + serializer_types + trait_imports + enum_imports + Array(parent_interface&.name)).uniq - [self_type_name, name]
|
|
135
|
+
ImportSorter.sort(result, config.imports_sort_order)
|
|
123
136
|
end
|
|
124
137
|
end
|
|
125
138
|
|
|
@@ -28,6 +28,8 @@ module Typelizer
|
|
|
28
28
|
return unless model_class&.defined_enums&.key?(prop.column_name.to_s)
|
|
29
29
|
|
|
30
30
|
prop.enum = model_class.defined_enums[prop.column_name.to_s].keys
|
|
31
|
+
prop.enum_type_name = "#{model_class.name.demodulize}#{prop.column_name.to_s.camelize}"
|
|
32
|
+
prop.enum
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
private
|
|
@@ -104,6 +106,10 @@ module Typelizer
|
|
|
104
106
|
attribute_type_obj = model_class.attribute_types.fetch(prop.column_name.to_s, nil)
|
|
105
107
|
return nil unless attribute_type_obj
|
|
106
108
|
|
|
109
|
+
if attribute_type_obj.instance_of?(::ActiveRecord::Type::Serialized)
|
|
110
|
+
return infer_types_for_serialized(prop, attribute_type_obj)
|
|
111
|
+
end
|
|
112
|
+
|
|
107
113
|
if attribute_type_obj.respond_to?(:subtype)
|
|
108
114
|
prop.type = @config.type_mapping[attribute_type_obj.subtype.type]
|
|
109
115
|
prop.multi = true
|
|
@@ -113,6 +119,23 @@ module Typelizer
|
|
|
113
119
|
|
|
114
120
|
prop
|
|
115
121
|
end
|
|
122
|
+
|
|
123
|
+
def infer_types_for_serialized(prop, type_obj)
|
|
124
|
+
object_class = type_obj.coder.try(:object_class) ||
|
|
125
|
+
type_obj.try(:object_class)
|
|
126
|
+
|
|
127
|
+
case object_class&.to_s
|
|
128
|
+
when "Array"
|
|
129
|
+
prop.type = :unknown
|
|
130
|
+
prop.multi = true
|
|
131
|
+
when "Hash"
|
|
132
|
+
prop.type = "Record<string, unknown>"
|
|
133
|
+
else
|
|
134
|
+
prop.type = :unknown
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
prop
|
|
138
|
+
end
|
|
116
139
|
end
|
|
117
140
|
end
|
|
118
141
|
end
|
data/lib/typelizer/property.rb
CHANGED
|
@@ -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, :deprecated,
|
|
4
|
+
:multi, :column_name, :comment, :enum, :enum_type_name, :deprecated,
|
|
5
5
|
:with_traits,
|
|
6
6
|
keyword_init: true
|
|
7
7
|
) do
|
|
@@ -39,10 +39,16 @@ module Typelizer
|
|
|
39
39
|
end << ">"
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
def enum_definition
|
|
43
|
+
return unless enum && enum_type_name
|
|
44
|
+
|
|
45
|
+
"type #{enum_type_name} = #{enum.map { |v| v.to_s.inspect }.join(" | ")}"
|
|
46
|
+
end
|
|
47
|
+
|
|
42
48
|
private
|
|
43
49
|
|
|
44
50
|
def type_name
|
|
45
|
-
return
|
|
51
|
+
return enum_type_name if enum_type_name
|
|
46
52
|
|
|
47
53
|
type.respond_to?(:name) ? type.name : type || "unknown"
|
|
48
54
|
end
|
|
@@ -54,17 +54,19 @@ module Typelizer
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# Simple struct to hold association info from traits
|
|
57
|
-
TraitAssociation = Struct.new(:name, :resource, :with_traits, :multi, keyword_init: true)
|
|
57
|
+
TraitAssociation = Struct.new(:name, :resource, :with_traits, :multi, :key, keyword_init: true)
|
|
58
58
|
|
|
59
59
|
# Support association methods that might be used in traits
|
|
60
60
|
def one(name, **options, &block)
|
|
61
61
|
resource = options[:resource] || options[:serializer]
|
|
62
62
|
with_traits = options[:with_traits]
|
|
63
|
-
|
|
63
|
+
key = options[:key] || name
|
|
64
|
+
@collected_attributes[key] = TraitAssociation.new(
|
|
64
65
|
name: name,
|
|
65
66
|
resource: resource,
|
|
66
67
|
with_traits: with_traits,
|
|
67
|
-
multi: false
|
|
68
|
+
multi: false,
|
|
69
|
+
key: key
|
|
68
70
|
)
|
|
69
71
|
end
|
|
70
72
|
|
|
@@ -74,11 +76,13 @@ module Typelizer
|
|
|
74
76
|
def many(name, **options, &block)
|
|
75
77
|
resource = options[:resource] || options[:serializer]
|
|
76
78
|
with_traits = options[:with_traits]
|
|
77
|
-
|
|
79
|
+
key = options[:key] || name
|
|
80
|
+
@collected_attributes[key] = TraitAssociation.new(
|
|
78
81
|
name: name,
|
|
79
82
|
resource: resource,
|
|
80
83
|
with_traits: with_traits,
|
|
81
|
-
multi: true
|
|
84
|
+
multi: true,
|
|
85
|
+
key: key
|
|
82
86
|
)
|
|
83
87
|
end
|
|
84
88
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
<%- if enums.any? -%>
|
|
2
|
+
export type { <%= enums.map(&:enum_type_name).join(", ") %> } from './Enums'
|
|
3
|
+
<%- end -%>
|
|
1
4
|
<%- interfaces.each do |interface| -%>
|
|
2
5
|
<%- if interface.config.verbatim_module_syntax -%>
|
|
3
6
|
export type { <%= interface.name %><%= ", " + interface.trait_interfaces.map(&:name).join(", ") if interface.trait_interfaces.any? %> } from <%= interface.quote('./' + interface.filename) %>
|
data/lib/typelizer/version.rb
CHANGED
data/lib/typelizer/writer.rb
CHANGED
|
@@ -22,7 +22,10 @@ module Typelizer
|
|
|
22
22
|
begin
|
|
23
23
|
written_files.concat(valid_interfaces.map { |interface| write_interface(interface) })
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
enums = collect_enums(valid_interfaces)
|
|
26
|
+
written_files << write_enums(enums) if enums.any?
|
|
27
|
+
|
|
28
|
+
written_files << write_index(valid_interfaces, enums: enums)
|
|
26
29
|
|
|
27
30
|
cleanup_stale_files(written_files) unless force
|
|
28
31
|
|
|
@@ -49,9 +52,23 @@ module Typelizer
|
|
|
49
52
|
File.delete(*stale_files) unless stale_files.empty?
|
|
50
53
|
end
|
|
51
54
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
def collect_enums(interfaces)
|
|
56
|
+
interfaces
|
|
57
|
+
.flat_map(&:enum_types)
|
|
58
|
+
.uniq(&:enum_type_name)
|
|
59
|
+
.sort_by(&:enum_type_name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def write_enums(enums)
|
|
63
|
+
write_file("Enums.ts", enums.map(&:fingerprint).join) do
|
|
64
|
+
render_template("enums.ts.erb", enums: enums)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def write_index(interfaces, enums: [])
|
|
69
|
+
fingerprint = interfaces.map(&:fingerprint).join + enums.map(&:fingerprint).join
|
|
70
|
+
write_file("index.ts", fingerprint) do
|
|
71
|
+
render_template("index.ts.erb", interfaces: interfaces, enums: enums)
|
|
55
72
|
end
|
|
56
73
|
end
|
|
57
74
|
|
data/lib/typelizer.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "typelizer/serializer_config_layer"
|
|
|
12
12
|
require_relative "typelizer/contexts/writer_context"
|
|
13
13
|
require_relative "typelizer/contexts/scan_context"
|
|
14
14
|
require_relative "typelizer/property_sorter"
|
|
15
|
+
require_relative "typelizer/import_sorter"
|
|
15
16
|
require_relative "typelizer/interface"
|
|
16
17
|
require_relative "typelizer/renderer"
|
|
17
18
|
require_relative "typelizer/writer"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typelizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Svyatoslav Kryukov
|
|
@@ -54,6 +54,7 @@ files:
|
|
|
54
54
|
- lib/typelizer/contexts/writer_context.rb
|
|
55
55
|
- lib/typelizer/dsl.rb
|
|
56
56
|
- lib/typelizer/generator.rb
|
|
57
|
+
- lib/typelizer/import_sorter.rb
|
|
57
58
|
- lib/typelizer/interface.rb
|
|
58
59
|
- lib/typelizer/listen.rb
|
|
59
60
|
- lib/typelizer/model_plugins/active_record.rb
|
|
@@ -73,6 +74,7 @@ files:
|
|
|
73
74
|
- lib/typelizer/serializer_plugins/oj_serializers.rb
|
|
74
75
|
- lib/typelizer/serializer_plugins/panko.rb
|
|
75
76
|
- lib/typelizer/templates/comment.ts.erb
|
|
77
|
+
- lib/typelizer/templates/enums.ts.erb
|
|
76
78
|
- lib/typelizer/templates/fingerprint.ts.erb
|
|
77
79
|
- lib/typelizer/templates/index.ts.erb
|
|
78
80
|
- lib/typelizer/templates/inheritance.ts.erb
|