sorbet-baml 0.1.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +94 -0
  3. data/README.md +315 -122
  4. data/Rakefile +2 -2
  5. data/docs-site/.gitignore +48 -0
  6. data/docs-site/Gemfile +5 -0
  7. data/docs-site/Gemfile.lock +140 -0
  8. data/docs-site/Rakefile +3 -0
  9. data/docs-site/bridgetown.config.yml +15 -0
  10. data/docs-site/config/initializers.rb +9 -0
  11. data/docs-site/config/puma.rb +9 -0
  12. data/docs-site/config.ru +5 -0
  13. data/docs-site/esbuild.config.js +11 -0
  14. data/docs-site/frontend/javascript/index.js +22 -0
  15. data/docs-site/frontend/styles/index.css +61 -0
  16. data/docs-site/package.json +18 -0
  17. data/docs-site/postcss.config.js +6 -0
  18. data/docs-site/server/roda_app.rb +9 -0
  19. data/docs-site/src/_components/head.liquid +26 -0
  20. data/docs-site/src/_components/nav.liquid +68 -0
  21. data/docs-site/src/_layouts/default.liquid +27 -0
  22. data/docs-site/src/_layouts/doc.liquid +39 -0
  23. data/docs-site/src/advanced-usage.md +598 -0
  24. data/docs-site/src/getting-started.md +170 -0
  25. data/docs-site/src/index.md +183 -0
  26. data/docs-site/src/troubleshooting.md +317 -0
  27. data/docs-site/src/type-mapping.md +236 -0
  28. data/docs-site/tailwind.config.js +85 -0
  29. data/examples/description_parameters.rb +49 -0
  30. data/lib/sorbet_baml/comment_extractor.rb +51 -54
  31. data/lib/sorbet_baml/converter.rb +69 -35
  32. data/lib/sorbet_baml/dependency_resolver.rb +11 -11
  33. data/lib/sorbet_baml/description_extension.rb +34 -0
  34. data/lib/sorbet_baml/description_extractor.rb +34 -0
  35. data/lib/sorbet_baml/dspy_tool_converter.rb +97 -0
  36. data/lib/sorbet_baml/dspy_tool_extensions.rb +23 -0
  37. data/lib/sorbet_baml/enum_extensions.rb +2 -2
  38. data/lib/sorbet_baml/struct_extensions.rb +2 -2
  39. data/lib/sorbet_baml/tool_extensions.rb +23 -0
  40. data/lib/sorbet_baml/type_mapper.rb +35 -37
  41. data/lib/sorbet_baml/version.rb +1 -1
  42. data/lib/sorbet_baml.rb +41 -10
  43. data/sorbet/config +2 -0
  44. data/sorbet/rbi/gems/anthropic@1.5.0.rbi +21252 -0
  45. data/sorbet/rbi/gems/async@2.27.3.rbi +9 -0
  46. data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +9 -0
  47. data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +424 -0
  48. data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
  49. data/sorbet/rbi/gems/console@1.33.0.rbi +9 -0
  50. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
  51. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1729 -0
  52. data/sorbet/rbi/gems/dry-logger@1.1.0.rbi +1317 -0
  53. data/sorbet/rbi/gems/dspy@0.19.1.rbi +6677 -0
  54. data/sorbet/rbi/gems/ffi@1.17.2.rbi +2174 -0
  55. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +9 -0
  56. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +9 -0
  57. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +9 -0
  58. data/sorbet/rbi/gems/google-protobuf@4.32.0.rbi +9 -0
  59. data/sorbet/rbi/gems/googleapis-common-protos-types@1.20.0.rbi +9 -0
  60. data/sorbet/rbi/gems/informers@1.2.1.rbi +1875 -0
  61. data/sorbet/rbi/gems/io-event@1.12.1.rbi +9 -0
  62. data/sorbet/rbi/gems/metrics@0.13.0.rbi +9 -0
  63. data/sorbet/rbi/gems/onnxruntime@0.10.0.rbi +304 -0
  64. data/sorbet/rbi/gems/openai@0.16.0.rbi +68055 -0
  65. data/sorbet/rbi/gems/opentelemetry-api@1.6.0.rbi +9 -0
  66. data/sorbet/rbi/gems/opentelemetry-common@0.22.0.rbi +9 -0
  67. data/sorbet/rbi/gems/opentelemetry-exporter-otlp@0.30.0.rbi +9 -0
  68. data/sorbet/rbi/gems/opentelemetry-registry@0.4.0.rbi +9 -0
  69. data/sorbet/rbi/gems/opentelemetry-sdk@1.8.1.rbi +9 -0
  70. data/sorbet/rbi/gems/opentelemetry-semantic_conventions@1.11.0.rbi +9 -0
  71. data/sorbet/rbi/gems/polars-df@0.20.0.rbi +9 -0
  72. data/sorbet/rbi/gems/sorbet-result@1.4.0.rbi +242 -0
  73. data/sorbet/rbi/gems/sorbet-schema@0.9.2.rbi +743 -0
  74. data/sorbet/rbi/gems/sorbet-struct-comparable@1.3.0.rbi +48 -0
  75. data/sorbet/rbi/gems/tokenizers@0.5.5.rbi +754 -0
  76. data/sorbet/rbi/gems/traces@0.17.0.rbi +9 -0
  77. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
  78. metadata +67 -7
  79. data/docs/README.md +0 -117
  80. data/docs/advanced-usage.md +0 -427
  81. data/docs/getting-started.md +0 -91
  82. data/docs/troubleshooting.md +0 -291
  83. data/docs/type-mapping.md +0 -192
@@ -1,91 +0,0 @@
1
- # Getting Started
2
-
3
- ## Prerequisites
4
-
5
- - Ruby 3.2+
6
- - Sorbet installed in your project
7
- - Basic familiarity with T::Struct
8
-
9
- ## Quick Start
10
-
11
- ### 1. Define your Sorbet types
12
-
13
- ```ruby
14
- class User < T::Struct
15
- const :id, Integer
16
- const :name, String
17
- const :email, T.nilable(String)
18
- end
19
- ```
20
-
21
- ### 2. Convert to BAML
22
-
23
- ```ruby
24
- require 'sorbet-baml'
25
-
26
- # Ruby-idiomatic API (recommended)
27
- User.to_baml
28
-
29
- # Legacy API (still supported)
30
- baml = SorbetBaml.from_struct(User)
31
- puts baml
32
- ```
33
-
34
- **Generated BAML:**
35
- ```baml
36
- class User {
37
- id int
38
- name string
39
- email string?
40
- }
41
- ```
42
-
43
- ### 3. Add field descriptions (optional)
44
-
45
- Document your fields with comments for better LLM understanding:
46
-
47
- ```ruby
48
- class User < T::Struct
49
- # Unique identifier for the user account
50
- const :id, Integer
51
-
52
- # User's display name, visible to other users
53
- const :name, String
54
-
55
- # Optional email for notifications and login
56
- const :email, T.nilable(String)
57
- end
58
-
59
- # Generate BAML (descriptions included by default!)
60
- User.to_baml
61
- ```
62
-
63
- **Generated BAML with descriptions:**
64
- ```baml
65
- class User {
66
- id int @description("Unique identifier for the user account")
67
- name string @description("User's display name, visible to other users")
68
- email string? @description("Optional email for notifications and login")
69
- }
70
- ```
71
-
72
- ### 4. Use with your LLM
73
-
74
- Include the BAML definition in your prompt:
75
-
76
- ```ruby
77
- baml = User.to_baml
78
- prompt = <<~PROMPT
79
- Generate sample data matching this schema:
80
-
81
- #{baml}
82
-
83
- Return 3 realistic examples.
84
- PROMPT
85
- ```
86
-
87
- ## Next Steps
88
-
89
- - [Type Mapping Reference](./type-mapping.md)
90
- - [Advanced Usage](./advanced-usage.md)
91
- - [Troubleshooting](./troubleshooting.md)
@@ -1,291 +0,0 @@
1
- # Troubleshooting
2
-
3
- ## Common Issues
4
-
5
- ### "undefined method `props' for Class"
6
-
7
- **Problem**: The class you're trying to convert is not a T::Struct.
8
-
9
- **Solution**: Ensure your class inherits from `T::Struct`:
10
-
11
- ```ruby
12
- # ❌ Wrong
13
- class User
14
- attr_reader :name
15
- end
16
-
17
- # ✅ Correct
18
- class User < T::Struct
19
- const :name, String
20
- end
21
-
22
- # Generate BAML
23
- User.to_baml
24
- ```
25
-
26
- **Generated BAML:**
27
- ```baml
28
- class User {
29
- name string
30
- }
31
- ```
32
-
33
- ### Empty output
34
-
35
- **Problem**: The struct has no properties defined.
36
-
37
- **Solution**: Define at least one property using `const` or `prop`:
38
-
39
- ```ruby
40
- class User < T::Struct
41
- const :name, String # Add properties
42
- const :age, Integer
43
- end
44
-
45
- User.to_baml
46
- ```
47
-
48
- **Generated BAML:**
49
- ```baml
50
- class User {
51
- name string
52
- age int
53
- }
54
- ```
55
-
56
- ### Self-referential types work fine
57
-
58
- **Problem**: You think self-referential types aren't supported.
59
-
60
- **Solution**: They actually work perfectly! Self-referential types are fully supported:
61
-
62
- ```ruby
63
- class Category < T::Struct
64
- const :name, String
65
- const :parent, T.nilable(Category)
66
- const :children, T::Array[Category]
67
- end
68
-
69
- Category.to_baml
70
- ```
71
-
72
- **Generated BAML:**
73
- ```baml
74
- class Category {
75
- name string
76
- parent Category?
77
- children Category[]
78
- }
79
- ```
80
-
81
- ## Type-Specific Issues
82
-
83
- ### Arrays not converting correctly
84
-
85
- Ensure you're using the Sorbet array syntax:
86
-
87
- ```ruby
88
- # ❌ Wrong
89
- class User < T::Struct
90
- const :items, Array # Generic Array won't work
91
- end
92
-
93
- # ✅ Correct
94
- class User < T::Struct
95
- const :items, T::Array[String]
96
- end
97
-
98
- User.to_baml
99
- ```
100
-
101
- **Generated BAML:**
102
- ```baml
103
- class User {
104
- items string[]
105
- }
106
- ```
107
-
108
- ### Optional fields showing as required
109
-
110
- Make sure to use `T.nilable`:
111
-
112
- ```ruby
113
- # ❌ Wrong - will be required
114
- class User < T::Struct
115
- const :email, String
116
- end
117
-
118
- # ✅ Correct - will be optional
119
- class User < T::Struct
120
- const :email, T.nilable(String)
121
- end
122
-
123
- User.to_baml
124
- ```
125
-
126
- **Generated BAML:**
127
- ```baml
128
- class User {
129
- email string?
130
- }
131
- ```
132
-
133
- ### Union types not working
134
-
135
- Ensure you're using `T.any` for union types:
136
-
137
- ```ruby
138
- # ❌ Wrong
139
- class Config < T::Struct
140
- const :value, String || Integer # Ruby OR, not Sorbet union
141
- end
142
-
143
- # ✅ Correct
144
- class Config < T::Struct
145
- const :value, T.any(String, Integer)
146
- end
147
-
148
- Config.to_baml
149
- ```
150
-
151
- **Generated BAML:**
152
- ```baml
153
- class Config {
154
- value string | int
155
- }
156
- ```
157
-
158
- ### Hash types not mapping correctly
159
-
160
- Use the full `T::Hash[K, V]` syntax:
161
-
162
- ```ruby
163
- # ❌ Wrong
164
- class User < T::Struct
165
- const :metadata, Hash # Generic Hash won't work
166
- end
167
-
168
- # ✅ Correct
169
- class User < T::Struct
170
- const :metadata, T::Hash[String, T.any(String, Integer)]
171
- end
172
-
173
- User.to_baml
174
- ```
175
-
176
- **Generated BAML:**
177
- ```baml
178
- class User {
179
- metadata map<string, string | int>
180
- }
181
- ```
182
-
183
- ## Dependency Issues
184
-
185
- ### Missing dependencies in output
186
-
187
- Use `include_dependencies: true` to automatically include all referenced types:
188
-
189
- ```ruby
190
- class Address < T::Struct
191
- const :street, String
192
- const :city, String
193
- end
194
-
195
- class User < T::Struct
196
- const :name, String
197
- const :address, Address
198
- end
199
-
200
- # ❌ Only outputs User class
201
- User.to_baml
202
-
203
- # ✅ Outputs both Address and User in correct order
204
- User.to_baml(include_dependencies: true)
205
- ```
206
-
207
- **Generated BAML (with dependencies):**
208
- ```baml
209
- class Address {
210
- street string
211
- city string
212
- }
213
-
214
- class User {
215
- name string
216
- address Address
217
- }
218
- ```
219
-
220
- ### Wrong dependency order
221
-
222
- The gem automatically handles dependency ordering using topological sorting. Dependencies always come before the types that reference them.
223
-
224
- ## Enum Issues
225
-
226
- ### Enums not converting
227
-
228
- Ensure you're using the correct T::Enum syntax:
229
-
230
- ```ruby
231
- # ❌ Wrong
232
- class Status
233
- ACTIVE = 'active'
234
- INACTIVE = 'inactive'
235
- end
236
-
237
- # ✅ Correct
238
- class Status < T::Enum
239
- enums do
240
- Active = new('active')
241
- Inactive = new('inactive')
242
- end
243
- end
244
-
245
- Status.to_baml
246
- ```
247
-
248
- **Generated BAML:**
249
- ```baml
250
- enum Status {
251
- "active"
252
- "inactive"
253
- }
254
- ```
255
-
256
- ## Getting Help
257
-
258
- 1. Check the [Type Mapping Reference](./type-mapping.md) for complete type support
259
- 2. Review examples in [Getting Started](./getting-started.md) and [Advanced Usage](./advanced-usage.md)
260
- 3. File an issue at https://github.com/vicentereig/sorbet-baml/issues
261
-
262
- ## Advanced Debugging
263
-
264
- ### Inspect Sorbet type information
265
-
266
- ```ruby
267
- # See what Sorbet sees for your struct
268
- MyStruct.props
269
- # => {name: String, age: Integer, ...}
270
-
271
- # Check if a class is a T::Struct
272
- MyStruct < T::Struct
273
- # => true
274
-
275
- # See enum values
276
- MyEnum.values
277
- # => [#<MyEnum:0x... @serialize="value1">, ...]
278
- ```
279
-
280
- ### Testing your BAML output
281
-
282
- ```ruby
283
- # Verify the output looks correct
284
- baml = User.to_baml(include_dependencies: true)
285
- puts baml
286
-
287
- # Check that all expected types are included
288
- expected_types = ['class User', 'class Address', 'enum Status']
289
- expected_types.all? { |type| baml.include?(type) }
290
- # => true
291
- ```
data/docs/type-mapping.md DELETED
@@ -1,192 +0,0 @@
1
- # Type Mapping Reference
2
-
3
- Complete mapping between Sorbet types and BAML output. All listed types are **fully supported**.
4
-
5
- ## Basic Types
6
-
7
- | Sorbet Type | BAML Output | Example |
8
- |-------------|-------------|---------|
9
- | `String` | `string` | `name string` |
10
- | `Integer` | `int` | `age int` |
11
- | `Float` | `float` | `price float` |
12
- | `T::Boolean` | `bool` | `active bool` |
13
- | `NilClass` | `null` | `null` |
14
- | `Symbol` | `string` | `status string` |
15
- | `Date/DateTime/Time` | `string` | `created_at string` |
16
-
17
- ## Optional Types (T.nilable)
18
-
19
- | Sorbet Type | BAML Output | Example |
20
- |-------------|-------------|---------|
21
- | `T.nilable(String)` | `string?` | `email string?` |
22
- | `T.nilable(Integer)` | `int?` | `age int?` |
23
- | `T.nilable(MyStruct)` | `MyStruct?` | `address Address?` |
24
-
25
- ## Collection Types
26
-
27
- | Sorbet Type | BAML Output | Example |
28
- |-------------|-------------|---------|
29
- | `T::Array[String]` | `string[]` | `tags string[]` |
30
- | `T::Array[Integer]` | `int[]` | `scores int[]` |
31
- | `T::Array[MyStruct]` | `MyStruct[]` | `addresses Address[]` |
32
-
33
- ## Hash/Map Types
34
-
35
- | Sorbet Type | BAML Output | Example |
36
- |-------------|-------------|---------|
37
- | `T::Hash[String, String]` | `map<string, string>` | `metadata map<string, string>` |
38
- | `T::Hash[String, Integer]` | `map<string, int>` | `counts map<string, int>` |
39
- | `T::Hash[Symbol, String]` | `map<string, string>` | `config map<string, string>` |
40
-
41
- ## Union Types (T.any)
42
-
43
- | Sorbet Type | BAML Output | Example |
44
- |-------------|-------------|---------|
45
- | `T.any(String, Integer)` | `string \| int` | `value string \| int` |
46
- | `T.any(String, Integer, Float)` | `string \| int \| float` | `mixed string \| int \| float` |
47
- | `T.nilable(T.any(String, Integer))` | `(string \| int)?` | `optional (string \| int)?` |
48
-
49
- ## Complex Collection Types
50
-
51
- | Sorbet Type | BAML Output | Example |
52
- |-------------|-------------|---------|
53
- | `T::Array[T.any(String, Integer)]` | `(string \| int)[]` | `mixed_array (string \| int)[]` |
54
- | `T::Hash[String, T.any(String, Integer)]` | `map<string, string \| int>` | `settings map<string, string \| int>` |
55
- | `T::Hash[String, T::Array[String]]` | `map<string, string[]>` | `labels map<string, string[]>` |
56
-
57
- ## Structured Types
58
-
59
- ### T::Struct to BAML Classes
60
-
61
- ```ruby
62
- class Address < T::Struct
63
- const :street, String
64
- const :city, String
65
- const :postal_code, T.nilable(String)
66
- end
67
-
68
- class User < T::Struct
69
- const :name, String
70
- const :age, Integer
71
- const :address, Address
72
- const :tags, T::Array[String]
73
- end
74
- ```
75
-
76
- ```ruby
77
- User.to_baml
78
- ```
79
-
80
- **Generated BAML:**
81
- ```baml
82
- class User {
83
- name string
84
- age int
85
- address Address
86
- tags string[]
87
- }
88
- ```
89
-
90
- ### T::Enum to BAML Enums
91
-
92
- ```ruby
93
- class Status < T::Enum
94
- enums do
95
- Active = new('active')
96
- Inactive = new('inactive')
97
- Pending = new('pending')
98
- end
99
- end
100
-
101
- class User < T::Struct
102
- const :name, String
103
- const :status, Status
104
- end
105
- ```
106
-
107
- ```ruby
108
- [Status, User].map(&:to_baml).join("\n\n")
109
- ```
110
-
111
- **Generated BAML:**
112
- ```baml
113
- enum Status {
114
- "active"
115
- "inactive"
116
- "pending"
117
- }
118
-
119
- class User {
120
- name string
121
- status Status
122
- }
123
- ```
124
-
125
- ### Complex Real-World Example
126
-
127
- ```ruby
128
- class Priority < T::Enum
129
- enums do
130
- Low = new('low')
131
- Medium = new('medium')
132
- High = new('high')
133
- end
134
- end
135
-
136
- class Task < T::Struct
137
- const :title, String
138
- const :description, T.nilable(String)
139
- const :priority, Priority
140
- const :tags, T::Array[String]
141
- const :metadata, T::Hash[String, T.any(String, Integer)]
142
- const :subtasks, T::Array[Task]
143
- end
144
- ```
145
-
146
- ```ruby
147
- [Priority, Task].map(&:to_baml).join("\n\n")
148
- ```
149
-
150
- **Generated BAML:**
151
- ```baml
152
- enum Priority {
153
- "low"
154
- "medium"
155
- "high"
156
- }
157
-
158
- class Task {
159
- title string
160
- description string?
161
- priority Priority
162
- tags string[]
163
- metadata map<string, string | int>
164
- subtasks Task[]
165
- }
166
- ```
167
-
168
- ## Advanced Features
169
-
170
- ### Dependency Management
171
-
172
- ```ruby
173
- # Dependencies automatically included with smart defaults
174
- User.to_baml
175
- # Outputs Address, then User in correct order
176
- ```
177
-
178
- ### Custom Formatting
179
-
180
- ```ruby
181
- # Smart defaults include dependencies automatically
182
- User.to_baml(indent_size: 4)
183
- ```
184
-
185
- ## Future Enhancements (Optional)
186
-
187
- These are nice-to-have features for future versions:
188
-
189
- - `T.type_alias` → `type Name = ...`
190
- - Field descriptions from comments
191
- - Custom naming strategies (snake_case ↔ camelCase)
192
- - Self-referential type handling