typelizer 0.11.0 → 0.13.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.
data/README.md CHANGED
@@ -2,727 +2,79 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/typelizer.svg)](https://rubygems.org/gems/typelizer)
4
4
 
5
- Typelizer generates TypeScript types from your Ruby serializers. It supports multiple serializer libraries and a flexible, layered configuration model so you can keep your backend and frontend in sync without handmaintaining types.
6
-
7
- ## Table of Contents
8
-
9
- - [Features](#features)
10
- - [Installation](#installation)
11
- - [Usage](#usage)
12
- - [Basic Setup](#basic-setup)
13
- - [Manual Typing](#manual-typing)
14
- - [Alba Traits](#alba-traits)
15
- - [TypeScript Integration](#typescript-integration)
16
- - [Manual Generation](#manual-generation)
17
- - [Automatic Generation in Development](#automatic-generation-in-development)
18
- - [Disabling Typelizer](#disabling-typelizer)
19
- - [OpenAPI Schema Generation](#openapi-schema-generation)
20
- - [Configuration](#configuration)
21
- - [Global Configuration](#simple-configuration)
22
- - [Writers (multiple outputs)](#defining-multiple-writers)
23
- - [Per-Serializer Configuration](#per-serializer-configuration)
24
- - [Credits](#credits)
25
- - [License](#license)
26
-
27
- <a href="https://evilmartians.com/?utm_source=typelizer&utm_campaign=project_page">
28
- <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Built by Evil Martians" width="236" height="54">
29
- </a>
5
+ Typelizer generates TypeScript types, route helpers, and OpenAPI schemas from your Ruby on Rails application. It keeps your backend and frontend in sync without hand-maintaining types.
30
6
 
31
7
  ## Features
32
8
 
33
- - Automatic TypeScript interface generation
34
- - Infers types from database columns and associations, with support for the Attributes API
35
- - Supports multiple serializer libraries (`Alba`, `ActiveModel::Serializer`, `Oj::Serializer`, `Panko::Serializer`)
9
+ - Automatic TypeScript interface generation from serializers
10
+ - Type-safe route helpers from Rails routes
11
+ - Supports Alba, ActiveModel::Serializer, Oj::Serializer, Panko::Serializer
12
+ - OpenAPI 3.0/3.1 schema generation
13
+ - Multiple output writers with layered configuration
36
14
  - File watching with automatic regeneration in development
37
- - Multiple output writers: emit several variants (e.g., snake_case and camelCase) in parallel
38
15
 
39
- ## Installation
16
+ ## Quick Start
40
17
 
41
- To install Typelizer, add the following line to your `Gemfile` and run `bundle install`:
18
+ Add to your Gemfile:
42
19
 
43
20
  ```ruby
44
21
  gem "typelizer"
45
22
  ```
46
23
 
47
- ## Usage
48
-
49
- ### Basic Setup
50
-
51
- Include the Typelizer DSL in your serializers:
24
+ Include the DSL in your serializers:
52
25
 
53
26
  ```ruby
54
27
  class ApplicationResource
55
28
  include Alba::Resource
56
29
  include Typelizer::DSL
57
-
58
- # For Alba, we recommend using the `helper` method instead of `include`.
59
- # See the documentation: https://github.com/okuramasafumi/alba/blob/main/README.md#helper
60
- # helper Typelizer::DSL
61
30
  end
62
31
 
63
32
  class PostResource < ApplicationResource
64
33
  attributes :id, :title, :body
65
-
66
- has_one :author, serializer: AuthorResource
67
- end
68
-
69
- class AuthorResource < ApplicationResource
70
- # specify the model to infer types from (optional)
71
- typelize_from User
72
-
73
- attributes :id, :name
74
- end
75
- ```
76
-
77
- Typelizer will automatically generate TypeScript interfaces based on your serializer definitions using information from your models.
78
-
79
- ### Manual Typing
80
-
81
- You can manually specify TypeScript types in your serializers:
82
-
83
- ```ruby
84
- class PostResource < ApplicationResource
85
- attributes :id, :title, :body, :published_at
86
-
87
- typelize "string"
88
- attribute :author_name do |post|
89
- post.author.name
90
- end
91
-
92
- typelize :string, nullable: true, comment: "Author's avatar URL"
93
- attribute :avatar do
94
- "https://example.com/avatar.png" if active?
95
- end
96
- end
97
- ```
98
-
99
- `typelize` can be used with a Hash to specify multiple types at once.
100
-
101
- ```ruby
102
- class PostResource < ApplicationResource
103
- attributes :id, :title, :body, :published_at
104
-
105
- attribute :author_name do |post|
106
- post.author.name
107
- end
108
-
109
- typelize author_name: :string, published_at: :string
110
- end
111
- ```
112
-
113
- You can also use shortcut syntax for common type modifiers:
114
-
115
- ```ruby
116
- class PostResource < ApplicationResource
117
- typelize author_name: "string?" # optional string (name?: string)
118
- typelize tag_ids: "number[]" # array of numbers (tag_ids: Array<number>)
119
- typelize categories: "string?[]" # optional array of strings (categories?: Array<string>)
120
-
121
- # Shortcuts can be combined with explicit options
122
- typelize status: [:string?, nullable: true] # optional and nullable
123
-
124
- # Also works with keyless typelize
125
- typelize :string?
126
- attribute :nickname do |user|
127
- user.nickname
128
- end
129
- end
130
- ```
131
-
132
- You can reference other serializers directly by passing the class. Typelizer resolves the class to its generated type name automatically:
133
-
134
- ```ruby
135
- class PostResource < ApplicationResource
136
- attributes :id, :title
137
-
138
- # Reference another serializer — resolves to its generated TypeScript type
139
- typelize reviewer: [AuthorResource, {optional: true, nullable: true}]
140
- attribute :reviewer do |post|
141
- post.reviewer
142
- end
143
-
144
- # Self-reference works too
145
- typelize previous_post: PostResource
146
- attribute :previous_post do |post|
147
- post.previous_post
148
- end
149
- end
150
- ```
151
-
152
- Union types are supported for polymorphic associations. You can use serializer class references, which resolve to their generated type names:
153
-
154
- ```ruby
155
- class PostResource < ApplicationResource
156
- attributes :id, :title
157
-
158
- # Union of two serializers — resolves to generated type names
159
- typelize commentable: [UserResource, CommentResource]
160
- attribute :commentable
161
-
162
- # Nullable union — extracts null and marks as nullable
163
- typelize approver: "AuthorResource | null"
164
- attribute :approver
165
-
166
- # Pipe-delimited string with serializer names
167
- typelize target: "UserResource | CommentResource"
168
- attribute :target
169
-
170
- # Pipe-delimited string with namespaced serializer
171
- typelize item: "Namespace::UserResource | CommentResource"
172
- attribute :item
173
- end
174
- ```
175
-
176
- You can also use plain TypeScript type names for custom types that aren't backed by serializers:
177
-
178
- ```ruby
179
- class PostResource < ApplicationResource
180
- attributes :id, :title
181
-
182
- # Plain type names — passed through as-is to TypeScript
183
- typelize content: "TextBlock | ImageBlock"
184
- attribute :content
185
-
186
- # Works with arrays of symbols too
187
- typelize sections: [:TextBlock, :ImageBlock]
188
- attribute :sections
189
- end
190
- ```
191
-
192
- This generates:
193
-
194
- ```typescript
195
- type Post = {
196
- id: number;
197
- title: string;
198
- content: TextBlock | ImageBlock;
199
- sections: TextBlock | ImageBlock;
200
- }
201
- ```
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
-
232
- For more complex type definitions, use the full API:
233
-
234
- ```ruby
235
- typelize attribute_name: [:string, :Date, optional: true, nullable: true, multi: true, enum: %w[foo bar], comment: "Attribute description", deprecated: "Use `another_attribute` instead"]
236
- ```
237
-
238
- ### Alba Traits
239
-
240
- Typelizer supports [Alba traits](https://github.com/okuramasafumi/alba#traits), generating separate TypeScript types for each trait. When using `with_traits` in associations, Typelizer generates intersection types.
241
-
242
- ```ruby
243
- class UserResource < ApplicationResource
244
- attributes :id, :name
245
-
246
- trait :detailed do
247
- attributes :email, :created_at
248
- end
249
-
250
- trait :with_posts do
251
- has_many :posts, resource: PostResource, with_traits: [:summary]
252
- end
253
- end
254
- ```
255
-
256
- This generates:
257
-
258
- ```typescript
259
- // User.ts
260
- export type User = {
261
- id: number;
262
- name: string;
263
- }
264
-
265
- type UserDetailedTrait = {
266
- email: string;
267
- created_at: string;
268
- }
269
-
270
- type UserWithPostsTrait = {
271
- posts: Array<Post & PostSummaryTrait>;
272
- }
273
-
274
- export default User;
275
- ```
276
-
277
- When using `with_traits` in associations, Typelizer generates intersection types combining the base type with trait types:
278
-
279
- ```ruby
280
- class TeamResource < ApplicationResource
281
- attributes :id, :name
282
- has_one :lead, resource: UserResource, with_traits: [:detailed]
283
- has_many :members, resource: UserResource, with_traits: [:detailed, :with_posts]
284
- end
285
- ```
286
-
287
- This generates:
288
-
289
- ```typescript
290
- // Team.ts
291
- import type { User, UserDetailedTrait, UserWithPostsTrait } from "@/types";
292
-
293
- export type Team = {
294
- id: number;
295
- name: string;
296
- lead: User & UserDetailedTrait;
297
- members: Array<User & UserDetailedTrait & UserWithPostsTrait>;
298
- }
299
-
300
- export default Team;
301
- ```
302
-
303
- The `typelize` method works inside traits for manual type specification:
304
-
305
- ```ruby
306
- trait :with_stats do
307
- typelize :number
308
- attribute :posts_count do |user|
309
- user.posts.count
310
- end
311
-
312
- typelize score: :number
313
- attributes :score
314
- end
315
- ```
316
-
317
- ### TypeScript Integration
318
-
319
- Typelizer generates TypeScript interfaces in the specified output directory:
320
-
321
- ```typescript
322
- // app/javascript/types/serializers/Post.ts
323
- export interface Post {
324
- id: number;
325
- title: string;
326
- category?: "news" | "article" | "blog" | null;
327
- body: string;
328
- published_at: string | null;
329
- author_name: string;
330
- }
331
- ```
332
-
333
- All generated interfaces are automatically imported in a single file:
334
-
335
- ```typescript
336
- // app/javascript/types/serializers/index.ts
337
- export * from "./post";
338
- export * from "./author";
339
- ```
340
-
341
- We recommend importing this file in a central location:
342
-
343
- ```typescript
344
- // app/javascript/types/index.ts
345
- import "@/types/serializers";
346
- // Custom types can be added here
347
- // ...
348
- ```
349
-
350
- With such a setup, you can import all generated interfaces in your TypeScript files:
351
-
352
- ```typescript
353
- import { Post } from "@/types";
354
- ```
355
-
356
- This setup also allows you to use custom types in your serializers:
357
-
358
- ```ruby
359
- class PostWithMetaResource < ApplicationResource
360
- attributes :id, :title
361
- typelize "PostMeta"
362
- attribute :meta do |post|
363
- { likes: post.likes, comments: post.comments }
364
- end
365
34
  end
366
35
  ```
367
36
 
368
- ```typescript
369
- // app/javascript/types/serializers/PostWithMeta.ts
370
-
371
- import { PostMeta } from "@/types";
372
-
373
- export interface Post {
374
- id: number;
375
- title: string;
376
- meta: PostMeta;
377
- }
378
- ```
379
-
380
- The `"@/types"` import path is configurable:
381
-
382
- ```ruby
383
- Typelizer.configure do |config|
384
- config.types_import_path = "@/types";
385
- end
386
- ```
387
-
388
- See the [Configuration](#configuration) section for more options.
389
-
390
- ### Manual Generation
391
-
392
- To manually generate TypeScript interfaces use one of the following commands:
37
+ Generate TypeScript types:
393
38
 
394
39
  ```bash
395
- # Generate new interfaces
396
40
  rails typelizer:generate
397
-
398
- # Clean output directory and regenerate all interfaces
399
- rails typelizer:generate:refresh
400
- ````
401
-
402
- ### Automatic Generation in Development
403
-
404
- When [Listen](https://github.com/guard/listen) is installed, Typelizer automatically watches for changes and regenerates interfaces in development mode. You can disable this behavior:
405
-
406
- ```ruby
407
- Typelizer.listen = false
408
- ```
409
-
410
- ### Disabling Typelizer
411
-
412
- Sometimes we want to use Typelizer only with manual generation. To disable Typelizer during development, we can set `DISABLE_TYPELIZER` environment variable to `true`. This doesn't affect manual generation.
413
-
414
- ## OpenAPI Schema Generation
415
-
416
- Typelizer can generate [OpenAPI](https://swagger.io/specification/) component schemas from your serializers. This is useful for documenting your API or integrating with tools like [rswag](https://github.com/rswag/rswag).
417
-
418
- Get all schemas as a hash:
419
-
420
- ```ruby
421
- Typelizer.openapi_schemas
422
- # => {
423
- # "Post" => {
424
- # type: :object,
425
- # properties: {
426
- # id: { type: :integer },
427
- # title: { type: :string },
428
- # published_at: { type: :string, format: :"date-time", nullable: true }
429
- # },
430
- # required: [:id, :title]
431
- # },
432
- # "Author" => { ... }
433
- # }
434
- ```
435
-
436
- By default, schemas are generated for OpenAPI 3.0. Pass `openapi_version: "3.1"` for OpenAPI 3.1 output (e.g., `type: [:string, :null]` instead of `nullable: true`):
437
-
438
- ```ruby
439
- Typelizer.openapi_schemas(openapi_version: "3.1")
440
- ```
441
-
442
- Generate a schema for a single interface:
443
-
444
- ```ruby
445
- interfaces = Typelizer.interfaces
446
- post_interface = interfaces.find { |i| i.name == "Post" }
447
- Typelizer::OpenAPI.schema_for(post_interface)
448
- Typelizer::OpenAPI.schema_for(post_interface, openapi_version: "3.1")
449
- ```
450
-
451
- Column types are mapped to OpenAPI types automatically:
452
-
453
- | Column type | OpenAPI type | Format |
454
- |---|---|---|
455
- | `integer` | `integer` | |
456
- | `bigint` | `integer` | `int64` |
457
- | `float` | `number` | `float` |
458
- | `decimal` | `number` | `double` |
459
- | `boolean` | `boolean` | |
460
- | `string`, `text`, `citext` | `string` | |
461
- | `uuid` | `string` | `uuid` |
462
- | `date` | `string` | `date` |
463
- | `datetime` | `string` | `date-time` |
464
- | `time` | `string` | `time` |
465
-
466
- Enums, nullable fields, arrays, deprecated flags, and `$ref` associations are all handled automatically.
467
-
468
- ## Configuration
469
-
470
- Typelizer provides several global configuration options:
471
-
472
- ```ruby
473
- # Directories to search for serializers:
474
- Typelizer.dirs = [Rails.root.join("app", "resources"), Rails.root.join("app", "serializers")]
475
- # Reject specific classes from being typelized:
476
- Typelizer.reject_class = ->(serializer:) { false }
477
- # Logger for debugging:
478
- Typelizer.logger = Logger.new($stdout, level: :info)
479
- # Force enable or disable file watching with Listen:
480
- Typelizer.listen = nil
481
- ```
482
-
483
- ### Configuration Layers
484
-
485
- Typelizer uses a hierarchical system to resolve settings. Settings are applied in the following order of precedence, where higher numbers override lower ones:
486
-
487
- 1. **Per-Serializer Overrides**: Settings defined using `typelizer_config` directly within a serializer class. This layer has the highest priority.
488
- 2. **Writer-Specific Settings**: Settings defined within a `config.writer(:name) { ... }` block.
489
- 3. **Global Settings**: Application-wide settings defined by direct assignment (e.g., `config.comments = true`) within the `Typelizer.configure` block.
490
- 4. **Library Defaults**: The gem's built-in default values.
491
-
492
- ### Simple Configuration (Single Output)
493
-
494
- For most apps, a single output is enough. All settings in an initializer apply to the `:default` writer and also act as a global baseline.
495
-
496
- - Settings like `dirs` are considered **Global** and establish a baseline for all writers.
497
- - Settings like `output_dir` or `comments` configure the implicit **`:default` writer**.
498
-
499
- ```ruby
500
- # config/initializers/typelizer.rb
501
- Typelizer.configure do |config|
502
- # This is a GLOBAL SETTING. It applies to ALL writers.
503
- config.dirs = [Rails.root.join("app/serializers")]
504
-
505
- # This setting configures the :default writer and ALSO acts as a global setting.
506
- config.output_dir = "app/javascript/types/generated"
507
- config.comments = true
508
- end
509
- ```
510
-
511
- ### Defining Multiple Writers
512
-
513
- The multi-writer system allows for the generation of multiple, distinct TypeScript outputs. Each output is managed by a named writer with an isolated configuration.
514
-
515
-
516
- #### Writer Inheritance Rules
517
-
518
- - By default, a new writer inherits its base settings from the Global Settings.
519
- - To inherit from another existing writer, use the `from:` option.
520
-
521
-
522
- **A Note on the :default Writer and Inheritance**
523
- - You usually do not need to declare `writer(:default)`. The implicit default writer automatically uses your global settings.
524
- - Declare `writer(:default)` when you want to apply specific overrides to it that should not be inherited by other new writers. This provides a way to separate your application's global baseline from settings that are truly unique to the default output
525
-
526
- #### Example of the distinction:
527
- ```ruby
528
- Typelizer.configure do |config|
529
- # === Global Setting ===
530
- # `comments: true` applies to :default and will be inherited by :camel_case.
531
- config.comments = true
532
-
533
- # === Default-Writer-Only Setting ===
534
- # `prefer_double_quotes: true` applies ONLY to the :default writer.
535
- # It is NOT a global setting and will NOT be inherited by :camel_case.
536
- config.writer(:default) do |c|
537
- c.prefer_double_quotes = true
538
- end
539
-
540
- # === New Writer Definition ===
541
- config.writer(:camel_case) do |c|
542
- c.output_dir = "app/javascript/types/camel_case"
543
- # This writer inherits `comments: true` from globals.
544
- # It does NOT inherit `prefer_double_quotes: true` from the :default writer's block.
545
- # Its `prefer_double_quotes` will be `false` (the library default).
546
- end
547
- end
548
41
  ```
549
42
 
550
- #### Configuring Writers
551
- You can define writers either inside the configure block or directly on the Typelizer module.
552
-
553
- 1. **Inside the configure block**
554
-
555
- This is the approach for keeping all configuration centralized.
43
+ ## Documentation
556
44
 
557
- ```ruby
558
- # config/initializers/typelizer.rb
559
- Typelizer.configure do |config|
560
- # ... global settings ...
45
+ **Full documentation: https://typelizer.dev**
561
46
 
562
- config.writer(:camel_case) do |c|
563
- c.output_dir = "app/javascript/types/camel_case"
564
- c.properties_transformer = ->(properties) { # ... transform ... }
565
- end
47
+ - [Getting Started](https://typelizer.dev/getting-started)
48
+ - [Manual Typing](https://typelizer.dev/guides/manual-typing)
49
+ - [Route Helpers](https://typelizer.dev/guides/routes)
50
+ - [Configuration](https://typelizer.dev/reference/configuration)
51
+ - [Type Mapping](https://typelizer.dev/reference/type-mapping)
566
52
 
567
- config.writer(:admin, from: :camel_case) do |c|
568
- c.output_dir = "app/javascript/types/admin"
569
- c.null_strategy = :optional
570
- end
571
- end
572
- ```
53
+ ## Development
573
54
 
574
- 2. Top-Level Helper
55
+ You need PostgreSQL running locally. Then:
575
56
 
576
- ```ruby
577
- Typelizer.writer(:admin, from: :default) do |c|
578
- c.output_dir = Rails.root.join("app/javascript/types/admin")
579
- c.prefer_double_quotes = true
580
- end
581
- ```
582
-
583
- #### Comprehensive Example
584
- This example configures three distinct outputs, demonstrating all inheritance mechanisms.
585
-
586
- ```ruby
587
- # config/initializers/typelizer.rb
588
- Typelizer.configure do |config|
589
- # === 1. Global Settings (Baseline for ALL writers) ===
590
- config.comments = true
591
- config.dirs = [Rails.root.join("app/serializers")]
592
-
593
- # === 2. The :default writer (snake_case output) ===
594
- config.writer(:default) do |c|
595
- c.output_dir = "app/javascript/types/snake_case"
596
- end
597
-
598
- # === 3. A new :camel_case writer ===
599
- # Inherits `comments: true` and `dirs` from the Global Settings.
600
- config.writer(:camel_case) do |c|
601
- c.output_dir = "app/javascript/types/camel_case"
602
- c.properties_transformer = lambda do |properties|
603
- properties.map { |prop| prop.with_overrides(name: prop.name.to_s.camelize(:lower)) }
604
- end
605
- end
606
-
607
- # === 4. An "admin" writer that clones :camel_case ===
608
- # Use `from:` to explicitly inherit another writer's complete configuration.
609
- config.writer(:admin, from: :camel_case) do |c|
610
- c.output_dir = "app/javascript/types/admin"
611
- # This writer inherits the properties_transformer from :camel_case.
612
- c.null_strategy = :optional
613
- end
614
- end
615
- ```
616
-
617
- ### Per-serializer configuration
618
-
619
- Use `typelizer_config` within a serializer class to apply overrides with the highest possible priority.
620
- These settings will supersede any conflicting settings from the active writer, global settings, or library defaults.
621
-
622
- ```ruby
623
- class PostResource < ApplicationResource
624
- typelizer_config do |c|
625
- c.null_strategy = :nullable_and_optional
626
- c.plugin_configs = { alba: { ts_mapper: { "UUID" => { type: :string } } } }
627
- end
628
- end
57
+ ```bash
58
+ bundle install
59
+ cd spec/app && RAILS_ENV=test bundle exec rails db:create db:migrate && cd ../..
60
+ bundle exec rspec
629
61
  ```
630
62
 
631
- You can also override `output_dir` per serializer to place its generated file in a different directory:
63
+ The test suite uses a dummy Rails app in `spec/app/` with models, migrations, and serializers for all four supported frameworks (Alba, AMS, OjSerializers, Panko). Linting is done with StandardRB:
632
64
 
633
- ```ruby
634
- class Admin::UserResource < ApplicationResource
635
- typelizer_config do |c|
636
- c.output_dir = Rails.root.join("app/javascript/types/admin")
637
- end
638
- end
65
+ ```bash
66
+ bundle exec standardrb
639
67
  ```
640
68
 
641
- ### Option reference
642
-
643
- ```ruby
644
- Typelizer.configure do |config|
645
- # Name to type mapping for serializer classes
646
- config.serializer_name_mapper = ->(serializer) { ... }
647
-
648
- # Custom file path mapping (decouples filename from type name)
649
- # Receives the mapped name (output of serializer_name_mapper) and returns a file path.
650
- # When nil (default), filename is derived from the type name.
651
- # Example: ->(name) { name.gsub("::", "/") }
652
- # Alba::UserSerializer → types/Alba/User.ts (type name stays AlbaUser)
653
- config.filename_mapper = nil
654
-
655
- # Maps serializers to their corresponding model classes
656
- config.serializer_model_mapper = ->(serializer) { ... }
657
-
658
- # Custom transformation for generated properties
659
- config.properties_transformer = ->(properties) { ... }
660
-
661
- # Strategy for ordering properties in generated TypeScript interfaces
662
- # :none - preserve serializer definition order (default)
663
- # :alphabetical - sort properties A-Z (case-insensitive)
664
- # :id_first_alphabetical - place 'id' first, then sort remaining A-Z
665
- # Proc - custom sorting function receiving array of Property objects
666
- config.properties_sort_order = :none
667
-
668
- # Strategy for ordering imports in generated TypeScript interfaces
669
- # :none - preserve original order (default)
670
- # :alphabetical - sort imports A-Z (case-insensitive)
671
- # Proc - custom sorting function receiving array of import strings
672
- config.imports_sort_order = :none
673
-
674
- # Plugin for model type inference (default: ModelPlugins::Auto)
675
- config.model_plugin = Typelizer::ModelPlugins::Auto
676
-
677
- # Plugin for serializer parsing (default: SerializerPlugins::Auto)
678
- config.serializer_plugin = Typelizer::SerializerPlugins::Auto
679
-
680
- # Additional configurations for specific plugins
681
- config.plugin_configs = { alba: { ts_mapper: {...} } }
682
-
683
- # Custom DB to TypeScript type mapping
684
- config.type_mapping = config.type_mapping.merge(jsonb: "Record<string, undefined>", ... )
685
-
686
- # Strategy for handling null values (:nullable, :optional, or :nullable_and_optional)
687
- config.null_strategy = :nullable
688
-
689
- # Strategy for handling serializer inheritance (:none, :inheritance)
690
- # :none - lists all attributes of the serializer in the type
691
- # :inheritance - extends the type from the parent serializer
692
- config.inheritance_strategy = :none
693
-
694
- # Strategy for handling `has_one` and `belongs_to` associations nullability (:database, :active_record)
695
- # :database - uses the database column nullability
696
- # :active_record - uses the `required` / `optional` association options
697
- config.associations_strategy = :database
698
-
699
- # Directory where TypeScript interfaces will be generated
700
- config.output_dir = Rails.root.join("app/javascript/types/serializers")
701
-
702
- # Import path for generated types in TypeScript files
703
- # (e.g., `import { MyType } from "@/types"`)
704
- config.types_import_path = "@/types"
705
-
706
- # List of type names that should be considered global in TypeScript
707
- # (i.e. not prefixed with the import path)
708
- config.types_global = %w[Array Date Record File FileList]
709
-
710
- # Support TypeScript's Verbatim module syntax option (default: false)
711
- # Will change imports and exports of types from default to support this syntax option
712
- config.verbatim_module_syntax = false
713
-
714
- # Use double quotes in generated TypeScript interfaces (default: false)
715
- config.prefer_double_quotes = false
716
-
717
- # Support comments in generated TypeScript interfaces (default: false)
718
- # Will add comments to the generated interfaces
719
- config.comments = false
720
- end
721
- ```
69
+ `bundle exec rake` runs both the tests and the linter.
722
70
 
723
71
  ## Credits
724
72
 
725
- Typelizer is inspired by [types_from_serializers](https://github.com/ElMassimo/types_from_serializers).
73
+ Typelizer is inspired by [types_from_serializers](https://github.com/ElMassimo/types_from_serializers), [js-routes](https://github.com/railsware/js-routes), and [Wayfinder](https://github.com/nicholasvansanten/wayfinder).
74
+
75
+ <a href="https://evilmartians.com/?utm_source=typelizer&utm_campaign=project_page">
76
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Built by Evil Martians" width="236" height="54">
77
+ </a>
726
78
 
727
79
  ## License
728
80