typelizer 0.9.0 → 0.9.2
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 +16 -1
- data/lib/typelizer/interface.rb +1 -1
- data/lib/typelizer/model_plugins/active_record.rb +18 -6
- data/lib/typelizer/openapi.rb +20 -4
- data/lib/typelizer/type_parser.rb +5 -1
- data/lib/typelizer/union_type_sorter.rb +15 -3
- data/lib/typelizer/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 505210c62639d70e95336cfb02bb0ab952089ac8433d5816774977853af264a1
|
|
4
|
+
data.tar.gz: 2878868d86acf4da05caaf5e139e3ccacf58025b8bf5fc2bc56c04b0a91049b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1522f196e8372d77e253bba7f9515043f925aa0f4d8ac6c3b1a11b837424743bba3225774b9dbd65232e46befdabbcb440ef6cf3370edc61e9dece9bf204e2e
|
|
7
|
+
data.tar.gz: 6e8acdb494ec3f5167bbfe9f53422ebd26d4e9d8dab89ec832518b1acda47aae821a002dd954daa7605f273f323092e3622699dffad88805120dbf3d3ad2fa4e
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning].
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.2] - 2026-02-26
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Fix string literal unions in OpenAPI and bracket-aware union type splitting. ([@skryukov])
|
|
15
|
+
|
|
16
|
+
## [0.9.1] - 2026-02-26
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Fix crash when using tuple types in serializers. ([@skryukov])
|
|
21
|
+
- Handle abstract ActiveRecord classes gracefully during type inference. ([@skryukov])
|
|
22
|
+
|
|
10
23
|
## [0.9.0] - 2026-02-26
|
|
11
24
|
|
|
12
25
|
### Added
|
|
@@ -413,7 +426,9 @@ and this project adheres to [Semantic Versioning].
|
|
|
413
426
|
[@skryukov]: https://github.com/skryukov
|
|
414
427
|
[@ventsislaf]: https://github.com/ventsislaf
|
|
415
428
|
|
|
416
|
-
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.9.
|
|
429
|
+
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.9.2...HEAD
|
|
430
|
+
[0.9.2]: https://github.com/skryukov/typelizer/compare/v0.9.1...v0.9.2
|
|
431
|
+
[0.9.1]: https://github.com/skryukov/typelizer/compare/v0.9.0...v0.9.1
|
|
417
432
|
[0.9.0]: https://github.com/skryukov/typelizer/compare/v0.8.0...v0.9.0
|
|
418
433
|
[0.8.0]: https://github.com/skryukov/typelizer/compare/v0.7.0...v0.8.0
|
|
419
434
|
[0.7.0]: https://github.com/skryukov/typelizer/compare/v0.6.0...v0.7.0
|
data/lib/typelizer/interface.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Typelizer
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def comment_for(prop)
|
|
22
|
-
column =
|
|
22
|
+
column = columns_hash&.dig(prop.column_name.to_s)
|
|
23
23
|
return nil unless column
|
|
24
24
|
|
|
25
25
|
prop.comment = column.comment
|
|
@@ -35,6 +35,20 @@ module Typelizer
|
|
|
35
35
|
|
|
36
36
|
private
|
|
37
37
|
|
|
38
|
+
def columns_hash
|
|
39
|
+
return nil unless model_class
|
|
40
|
+
return nil if model_class.abstract_class?
|
|
41
|
+
|
|
42
|
+
model_class.columns_hash
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def attribute_types
|
|
46
|
+
return nil unless model_class&.respond_to?(:attribute_types)
|
|
47
|
+
return nil if model_class.abstract_class?
|
|
48
|
+
|
|
49
|
+
model_class.attribute_types
|
|
50
|
+
end
|
|
51
|
+
|
|
38
52
|
def infer_types_for_association(prop)
|
|
39
53
|
association = model_class&.reflect_on_association(prop.column_name.to_sym)
|
|
40
54
|
return nil unless association
|
|
@@ -42,7 +56,7 @@ module Typelizer
|
|
|
42
56
|
case association.macro
|
|
43
57
|
when :belongs_to
|
|
44
58
|
foreign_key = association.foreign_key
|
|
45
|
-
column =
|
|
59
|
+
column = columns_hash&.dig(foreign_key.to_s)
|
|
46
60
|
if config.associations_strategy == :database
|
|
47
61
|
prop.nullable = column.null if column
|
|
48
62
|
elsif config.associations_strategy == :active_record
|
|
@@ -64,7 +78,7 @@ module Typelizer
|
|
|
64
78
|
end
|
|
65
79
|
|
|
66
80
|
def infer_types_for_column(prop)
|
|
67
|
-
column =
|
|
81
|
+
column = columns_hash&.dig(prop.column_name.to_s)
|
|
68
82
|
return nil unless column
|
|
69
83
|
|
|
70
84
|
prop.column_type = column.type
|
|
@@ -122,9 +136,7 @@ module Typelizer
|
|
|
122
136
|
end
|
|
123
137
|
|
|
124
138
|
def infer_types_for_attribute(prop)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
attribute_type_obj = model_class.attribute_types.fetch(prop.column_name.to_s, nil)
|
|
139
|
+
attribute_type_obj = attribute_types&.fetch(prop.column_name.to_s, nil)
|
|
128
140
|
return nil unless attribute_type_obj
|
|
129
141
|
|
|
130
142
|
if attribute_type_obj.instance_of?(::ActiveRecord::Type::Serialized)
|
data/lib/typelizer/openapi.rb
CHANGED
|
@@ -89,9 +89,11 @@ module Typelizer
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def union_schema(property, openapi_version:)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
definition = if property.type.all? { |part| string_literal?(part) }
|
|
93
|
+
{type: :string, enum: property.type.map { |part| unquote_string_literal(part) }}
|
|
94
|
+
else
|
|
95
|
+
{anyOf: property.type.map { |part| union_member_schema(part) }}
|
|
96
|
+
end
|
|
95
97
|
|
|
96
98
|
unless property.multi
|
|
97
99
|
apply_nullable(definition, property, openapi_version: openapi_version)
|
|
@@ -154,6 +156,8 @@ module Typelizer
|
|
|
154
156
|
elsif definition[:type]
|
|
155
157
|
v31?(openapi_version) ? definition[:type] = [definition[:type], :null] : definition[:nullable] = true
|
|
156
158
|
end
|
|
159
|
+
|
|
160
|
+
definition[:enum] << nil if definition[:enum].is_a?(Array) && !definition[:enum].include?(nil)
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
def wrap_multi(definition, property, openapi_version:)
|
|
@@ -180,6 +184,8 @@ module Typelizer
|
|
|
180
184
|
result = COLUMN_TYPE_MAP[property.column_type].dup
|
|
181
185
|
result[:type] = :string if property.enum
|
|
182
186
|
result
|
|
187
|
+
elsif string_literal?(property.type)
|
|
188
|
+
{type: :string, enum: [unquote_string_literal(property.type)]}
|
|
183
189
|
elsif (property.type.is_a?(String) || property.type.is_a?(Symbol)) && !OPENAPI_TYPES.include?(property.type.to_sym) && !ts_only_type?(property.type.to_s)
|
|
184
190
|
{"$ref" => "#/components/schemas/#{property.type}"}
|
|
185
191
|
else
|
|
@@ -203,7 +209,17 @@ module Typelizer
|
|
|
203
209
|
end
|
|
204
210
|
|
|
205
211
|
def ts_only_type?(type_str)
|
|
206
|
-
type_str.start_with?("{") || type_str.include?("<") || TS_OBJECT_TYPES.include?(type_str)
|
|
212
|
+
type_str.start_with?("{", "[") || type_str.include?("<") || TS_OBJECT_TYPES.include?(type_str)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def string_literal?(type)
|
|
216
|
+
str = type.to_s
|
|
217
|
+
str.length > 2 &&
|
|
218
|
+
((str.start_with?("'") && str.end_with?("'")) || (str.start_with?('"') && str.end_with?('"')))
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def unquote_string_literal(type)
|
|
222
|
+
type.to_s[1..-2]
|
|
207
223
|
end
|
|
208
224
|
|
|
209
225
|
def validate_version!(openapi_version)
|
|
@@ -40,7 +40,11 @@ module Typelizer
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
42
|
def parse_union(type_str, **options)
|
|
43
|
-
parts =
|
|
43
|
+
parts = UnionTypeSorter.split_union_members(type_str)
|
|
44
|
+
|
|
45
|
+
# No top-level | found — the | is nested inside brackets
|
|
46
|
+
return {type: type_str.to_sym}.merge(options) if parts.size <= 1
|
|
47
|
+
|
|
44
48
|
options[:nullable] = true if parts.delete("null")
|
|
45
49
|
if parts.size == 1
|
|
46
50
|
parse(parts.first, **options)
|
|
@@ -98,10 +98,10 @@ module Typelizer
|
|
|
98
98
|
|
|
99
99
|
str.each_char do |char|
|
|
100
100
|
case char
|
|
101
|
-
when "<", "("
|
|
101
|
+
when "<", "(", "{", "["
|
|
102
102
|
depth += 1
|
|
103
103
|
current << char
|
|
104
|
-
when ">", ")"
|
|
104
|
+
when ">", ")", "}", "]"
|
|
105
105
|
depth -= 1
|
|
106
106
|
current << char
|
|
107
107
|
when "|"
|
|
@@ -126,6 +126,8 @@ module Typelizer
|
|
|
126
126
|
def self.balanced_brackets?(str)
|
|
127
127
|
angle_depth = 0
|
|
128
128
|
paren_depth = 0
|
|
129
|
+
brace_depth = 0
|
|
130
|
+
bracket_depth = 0
|
|
129
131
|
|
|
130
132
|
str.each_char do |char|
|
|
131
133
|
case char
|
|
@@ -139,10 +141,20 @@ module Typelizer
|
|
|
139
141
|
when ")"
|
|
140
142
|
paren_depth -= 1
|
|
141
143
|
return false if paren_depth < 0
|
|
144
|
+
when "{"
|
|
145
|
+
brace_depth += 1
|
|
146
|
+
when "}"
|
|
147
|
+
brace_depth -= 1
|
|
148
|
+
return false if brace_depth < 0
|
|
149
|
+
when "["
|
|
150
|
+
bracket_depth += 1
|
|
151
|
+
when "]"
|
|
152
|
+
bracket_depth -= 1
|
|
153
|
+
return false if bracket_depth < 0
|
|
142
154
|
end
|
|
143
155
|
end
|
|
144
156
|
|
|
145
|
-
angle_depth == 0 && paren_depth == 0
|
|
157
|
+
angle_depth == 0 && paren_depth == 0 && brace_depth == 0 && bracket_depth == 0
|
|
146
158
|
end
|
|
147
159
|
end
|
|
148
160
|
end
|
data/lib/typelizer/version.rb
CHANGED