typelizer 0.9.3 → 0.10.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 +8 -1
- data/README.md +36 -7
- data/lib/typelizer/dsl.rb +1 -22
- data/lib/typelizer/serializer_plugins/alba/block_attribute_collector.rb +1 -11
- data/lib/typelizer/type_parser.rb +29 -12
- 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: bc23d62a95119b1ff871bcde1eeb0c3180cc0fe1e38fa1252edad30a454661bc
|
|
4
|
+
data.tar.gz: 2658b01eebb6f9317ff4905f6c482cbdfa55afcadd4ba6508e1cd9b5469072da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 237f41ebfc6999a73c30e97a89dab3435638c49bac38ff8072493b62833fd7a6c7d5cd7655868bf07c958b879c906c4c38bd809331cad1827b37529183c1aae3
|
|
7
|
+
data.tar.gz: b882bab4aea8a599b69e39c296a8794cf1fa357ec20f092649d5fa7e7d80bf2fb05ffff69b4362f7e0aa0be9b669724933a4167bfe403f9ce094e37254dfc9e8
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning].
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.10.0] - 2026-03-02
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Breaking:** Arrays of strings in `typelize` now produce string literal unions (`'active' | 'inactive'`) instead of type reference unions. Use symbols for type references: `typelize status: [:string, :number]`. ([@skryukov])
|
|
15
|
+
|
|
10
16
|
## [0.9.3] - 2026-02-27
|
|
11
17
|
|
|
12
18
|
### Fixed
|
|
@@ -433,7 +439,8 @@ and this project adheres to [Semantic Versioning].
|
|
|
433
439
|
[@skryukov]: https://github.com/skryukov
|
|
434
440
|
[@ventsislaf]: https://github.com/ventsislaf
|
|
435
441
|
|
|
436
|
-
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.
|
|
442
|
+
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.10.0...HEAD
|
|
443
|
+
[0.10.0]: https://github.com/skryukov/typelizer/compare/v0.9.3...v0.10.0
|
|
437
444
|
[0.9.3]: https://github.com/skryukov/typelizer/compare/v0.9.2...v0.9.3
|
|
438
445
|
[0.9.2]: https://github.com/skryukov/typelizer/compare/v0.9.1...v0.9.2
|
|
439
446
|
[0.9.1]: https://github.com/skryukov/typelizer/compare/v0.9.0...v0.9.1
|
data/README.md
CHANGED
|
@@ -119,10 +119,10 @@ class PostResource < ApplicationResource
|
|
|
119
119
|
typelize categories: "string?[]" # optional array of strings (categories?: Array<string>)
|
|
120
120
|
|
|
121
121
|
# Shortcuts can be combined with explicit options
|
|
122
|
-
typelize status: [
|
|
122
|
+
typelize status: [:string?, nullable: true] # optional and nullable
|
|
123
123
|
|
|
124
124
|
# Also works with keyless typelize
|
|
125
|
-
typelize
|
|
125
|
+
typelize :string?
|
|
126
126
|
attribute :nickname do |user|
|
|
127
127
|
user.nickname
|
|
128
128
|
end
|
|
@@ -167,8 +167,8 @@ class PostResource < ApplicationResource
|
|
|
167
167
|
typelize target: "UserResource | CommentResource"
|
|
168
168
|
attribute :target
|
|
169
169
|
|
|
170
|
-
#
|
|
171
|
-
typelize item:
|
|
170
|
+
# Pipe-delimited string with namespaced serializer
|
|
171
|
+
typelize item: "Namespace::UserResource | CommentResource"
|
|
172
172
|
attribute :item
|
|
173
173
|
end
|
|
174
174
|
```
|
|
@@ -183,8 +183,8 @@ class PostResource < ApplicationResource
|
|
|
183
183
|
typelize content: "TextBlock | ImageBlock"
|
|
184
184
|
attribute :content
|
|
185
185
|
|
|
186
|
-
# Works with arrays too
|
|
187
|
-
typelize sections: [
|
|
186
|
+
# Works with arrays of symbols too
|
|
187
|
+
typelize sections: [:TextBlock, :ImageBlock]
|
|
188
188
|
attribute :sections
|
|
189
189
|
end
|
|
190
190
|
```
|
|
@@ -200,10 +200,39 @@ type Post = {
|
|
|
200
200
|
}
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
+
String arrays are treated as string literal unions — useful for enums and state machines:
|
|
204
|
+
|
|
205
|
+
```ruby
|
|
206
|
+
class PostResource < ApplicationResource
|
|
207
|
+
attributes :id, :title
|
|
208
|
+
|
|
209
|
+
# Array of strings — generates string literal union type
|
|
210
|
+
typelize status: ["draft", "published", "archived"]
|
|
211
|
+
attribute :status
|
|
212
|
+
|
|
213
|
+
# Works with Rails enums and state machines
|
|
214
|
+
typelize review_state: ReviewStateMachine.states.keys
|
|
215
|
+
attribute :review_state
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This generates:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
type Post = {
|
|
223
|
+
id: number;
|
|
224
|
+
title: string;
|
|
225
|
+
status: 'draft' | 'published' | 'archived';
|
|
226
|
+
review_state: 'pending' | 'approved' | 'rejected';
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
> **Note:** In arrays, **strings** become string literal types (`'a'`), while **symbols** and **class constants** become type references (`A`). You can mix them: `[:number, "auto"]` produces `number | 'auto'`.
|
|
231
|
+
|
|
203
232
|
For more complex type definitions, use the full API:
|
|
204
233
|
|
|
205
234
|
```ruby
|
|
206
|
-
typelize attribute_name: [
|
|
235
|
+
typelize attribute_name: [:string, :Date, optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description", deprecated: "Use `another_attribute` instead"]
|
|
207
236
|
```
|
|
208
237
|
|
|
209
238
|
### Alba Traits
|
data/lib/typelizer/dsl.rb
CHANGED
|
@@ -87,8 +87,7 @@ module Typelizer
|
|
|
87
87
|
attributes.each do |name, attrs|
|
|
88
88
|
next unless name
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
store_type(attribute_name, name, options)
|
|
90
|
+
store_type(attribute_name, name, TypeParser.parse_declaration(attrs))
|
|
92
91
|
end
|
|
93
92
|
end
|
|
94
93
|
|
|
@@ -112,26 +111,6 @@ module Typelizer
|
|
|
112
111
|
end
|
|
113
112
|
end
|
|
114
113
|
end
|
|
115
|
-
|
|
116
|
-
def parse_type_declaration(attrs)
|
|
117
|
-
attrs = [attrs] if attrs && !attrs.is_a?(Array)
|
|
118
|
-
options = attrs.last.is_a?(Hash) ? attrs.pop : {}
|
|
119
|
-
|
|
120
|
-
if attrs.any?
|
|
121
|
-
parsed_types = attrs.map { |t| TypeParser.parse(t) }
|
|
122
|
-
all_types = parsed_types.flat_map { |p| Array(p[:type]) }
|
|
123
|
-
parsed_types.each do |parsed|
|
|
124
|
-
options[:optional] = true if parsed[:optional]
|
|
125
|
-
options[:multi] = true if parsed[:multi]
|
|
126
|
-
options[:nullable] = true if parsed[:nullable]
|
|
127
|
-
end
|
|
128
|
-
options[:nullable] = true if all_types.delete(:null)
|
|
129
|
-
# Unwrap single-element arrays: typelize field: ["string"] behaves like typelize field: "string"
|
|
130
|
-
options[:type] = (all_types.size == 1) ? all_types.first : all_types
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
options
|
|
134
|
-
end
|
|
135
114
|
end
|
|
136
115
|
end
|
|
137
116
|
end
|
|
@@ -111,17 +111,7 @@ module Typelizer
|
|
|
111
111
|
private
|
|
112
112
|
|
|
113
113
|
def normalize_typelize(type_def, **options)
|
|
114
|
-
|
|
115
|
-
when Array
|
|
116
|
-
# [:string, nullable: true] or ['string?', nullable: true]
|
|
117
|
-
type, *rest = type_def
|
|
118
|
-
opts = rest.first || {}
|
|
119
|
-
TypeParser.parse(type, **opts)
|
|
120
|
-
when Symbol, String
|
|
121
|
-
TypeParser.parse(type_def, **options)
|
|
122
|
-
else
|
|
123
|
-
options
|
|
124
|
-
end
|
|
114
|
+
TypeParser.parse_declaration(type_def, **options)
|
|
125
115
|
end
|
|
126
116
|
end
|
|
127
117
|
end
|
|
@@ -10,6 +10,17 @@ module Typelizer
|
|
|
10
10
|
TYPE_PATTERN = /\A(.+?)(\?)?(\[\])?(\?)?\z/
|
|
11
11
|
|
|
12
12
|
class << self
|
|
13
|
+
def parse_declaration(attrs, **options)
|
|
14
|
+
return options.merge(attrs) if attrs.is_a?(Hash)
|
|
15
|
+
return parse(attrs, **options) unless attrs.is_a?(Array)
|
|
16
|
+
|
|
17
|
+
options = attrs.last.merge(options) if attrs.last.is_a?(Hash)
|
|
18
|
+
types = attrs.reject { |t| t.is_a?(Hash) }
|
|
19
|
+
return options if types.empty?
|
|
20
|
+
|
|
21
|
+
parse((types.size == 1) ? types.first : types, **options)
|
|
22
|
+
end
|
|
23
|
+
|
|
13
24
|
def parse(type_def, **options)
|
|
14
25
|
return options if type_def.nil?
|
|
15
26
|
return parse_array(type_def, **options) if type_def.is_a?(Array)
|
|
@@ -41,22 +52,28 @@ module Typelizer
|
|
|
41
52
|
private
|
|
42
53
|
|
|
43
54
|
def parse_array(type_defs, **options)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
raise ArgumentError, "Empty array passed to typelize" if type_defs.empty?
|
|
56
|
+
|
|
57
|
+
types = []
|
|
58
|
+
type_defs.each do |t|
|
|
59
|
+
if t.is_a?(String)
|
|
60
|
+
types << :"'#{t}'"
|
|
61
|
+
else
|
|
62
|
+
parsed = parse(t)
|
|
63
|
+
types.concat(Array(parsed[:type]))
|
|
64
|
+
options[:optional] = true if parsed[:optional]
|
|
65
|
+
options[:multi] = true if parsed[:multi]
|
|
66
|
+
options[:nullable] = true if parsed[:nullable]
|
|
67
|
+
end
|
|
51
68
|
end
|
|
52
69
|
|
|
53
70
|
options[:nullable] = true if types.delete(:null)
|
|
71
|
+
wrap_type(types, **options)
|
|
72
|
+
end
|
|
54
73
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{type: types}.merge(options)
|
|
59
|
-
end
|
|
74
|
+
def wrap_type(types, **options)
|
|
75
|
+
type = (types.size == 1) ? types.first : types
|
|
76
|
+
{type: type}.merge(options)
|
|
60
77
|
end
|
|
61
78
|
|
|
62
79
|
def parse_union(type_str, **options)
|
data/lib/typelizer/version.rb
CHANGED