-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5cf1cdd
Showing
109 changed files
with
2,952 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
name: Ruby | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
pull_request: | ||
|
||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
name: Linter | ||
env: | ||
BUNDLE_JOBS: 4 | ||
BUNDLE_RETRY: 3 | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: "3.3" | ||
bundler-cache: true | ||
- name: Run StandardRB | ||
run: bundle exec standardrb | ||
|
||
build: | ||
runs-on: ubuntu-latest | ||
name: Ruby ${{ matrix.ruby }} | ||
env: | ||
BUNDLE_JOBS: 4 | ||
BUNDLE_RETRY: 3 | ||
strategy: | ||
matrix: | ||
ruby: | ||
- "3.3" | ||
- "3.2" | ||
- "3.1" | ||
- "3.0" | ||
- "2.7" | ||
- "jruby" | ||
- "truffleruby" | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: ${{ matrix.ruby }} | ||
bundler-cache: true | ||
- name: Run tests | ||
run: bundle exec rspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/.bundle/ | ||
/.yardoc | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
|
||
# rspec failure tracking | ||
.rspec_status | ||
|
||
Gemfile.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--format documentation | ||
--color | ||
--require spec_helper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# For available configuration options, see: | ||
# https://github.com/standardrb/standard | ||
ruby_version: 2.7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Changelog | ||
|
||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog], | ||
and this project adheres to [Semantic Versioning]. | ||
|
||
## [Unreleased] | ||
|
||
## [0.1.0] - 2024-08-02 | ||
|
||
- Initial release ([@skryukov]) | ||
|
||
[@skryukov]: https://github.com/skryukov | ||
|
||
[Unreleased]: https://github.com/skryukov/typelizer/compare/v0.1.0...HEAD | ||
[0.1.0]: https://github.com/skryukov/typelizer/commits/v0.1.0 | ||
|
||
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ | ||
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# frozen_string_literal: true | ||
|
||
source "https://rubygems.org" | ||
|
||
gemspec | ||
|
||
gem "rake", "~> 13.0" | ||
|
||
gem "rspec", "~> 3.0" | ||
|
||
gem "rspec-snapshot", "~> 2.0" | ||
|
||
gem "standard", "~> 1.3" | ||
|
||
gem "oj_serializers" | ||
|
||
gem "active_model_serializers" | ||
|
||
gem "alba" | ||
|
||
# Rails app | ||
gem "rails", "~> 7.1.3" | ||
gem "sqlite3", "~> 1.4" | ||
gem "puma", ">= 5.0" | ||
gem "tzinfo-data", platforms: %i[windows jruby] | ||
gem "rspec-rails" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
# Typelizer | ||
|
||
[![Gem Version](https://badge.fury.io/rb/typelizer.svg)](https://rubygems.org/gems/typelizer) | ||
|
||
Typelizer is a Ruby gem that automatically generates TypeScript interfaces from your Ruby serializers, bridging the gap between your Ruby backend and TypeScript frontend. It supports multiple serializer libraries and provides a flexible configuration system, making it easier to maintain type consistency across your full-stack application. | ||
|
||
## Table of Contents | ||
|
||
- [Features](#features) | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Basic Setup](#basic-setup) | ||
- [Manual Typing](#manual-typing) | ||
- [TypeScript Integration](#typescript-integration) | ||
- [Manual Generation](#manual-generation) | ||
- [Automatic Generation in Development](#automatic-generation-in-development) | ||
- [Configuration](#configuration) | ||
- [Global Configuration](#global-configuration) | ||
- [Config Options](#config-options) | ||
- [Per-Serializer Configuration](#per-serializer-configuration) | ||
- [Credits](#credits) | ||
- [License](#license) | ||
|
||
<a href="https://evilmartians.com/?utm_source=typelizer&utm_campaign=project_page"> | ||
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Built by Evil Martians" width="236" height="54"> | ||
</a> | ||
|
||
## Features | ||
|
||
- Automatic TypeScript interface generation | ||
- Support for multiple serializer libraries (`Alba`, `ActiveModel::Serializer`, `Oj::Serializer`) | ||
- File watching and automatic regeneration in development | ||
|
||
## Installation | ||
|
||
To install Typelizer, add the following line to your `Gemfile` and run `bundle install`: | ||
|
||
```ruby | ||
gem "typelizer" | ||
``` | ||
|
||
## Usage | ||
|
||
### Basic Setup | ||
|
||
Include the Typelizer DSL in your serializers: | ||
|
||
```ruby | ||
class ApplicationResource | ||
include Alba::Resource | ||
include Typelizer::DSL | ||
end | ||
|
||
class PostResource < ApplicationResource | ||
attributes :id, :title, :body | ||
|
||
has_one :author, serializer: AuthorResource | ||
end | ||
|
||
class AuthorResource < ApplicationResource | ||
# specify the model to infer types from (optional) | ||
typelize_from User | ||
|
||
attributes :id, :name | ||
end | ||
``` | ||
|
||
Typelizer will automatically generate TypeScript interfaces based on your serializer definitions using information from your models. | ||
|
||
### Manual Typing | ||
|
||
You can manually specify TypeScript types in your serializers: | ||
|
||
```ruby | ||
class PostResource < ApplicationResource | ||
attributes :id, :title, :body, :published_at | ||
|
||
typelize "string" | ||
attribute :author_name do |post| | ||
post.author.name | ||
end | ||
end | ||
``` | ||
|
||
### TypeScript Integration | ||
|
||
Typelizer generates TypeScript interfaces in the specified output directory: | ||
|
||
```typescript | ||
// app/javascript/types/serializers/Post.ts | ||
export interface Post { | ||
id: number; | ||
title: string; | ||
body: string; | ||
published_at: string | null; | ||
author_name: string; | ||
} | ||
``` | ||
|
||
All generated interfaces are automatically imported in a single file: | ||
|
||
```typescript | ||
// app/javascript/types/serializers/index.ts | ||
export * from "./post"; | ||
export * from "./author"; | ||
``` | ||
|
||
We recommend importing this file in a central location: | ||
|
||
```typescript | ||
// app/javascript/types/index.ts | ||
import "@/types/serializers"; | ||
// Custom types can be added here | ||
// ... | ||
``` | ||
|
||
With such a setup, you can import all generated interfaces in your TypeScript files: | ||
|
||
```typescript | ||
import { Post } from "@/types"; | ||
``` | ||
|
||
This setup also allows you to use custom types in your serializers: | ||
|
||
```ruby | ||
class PostWithMetaResource < ApplicationResource | ||
attributes :id, :title | ||
typelize "PostMeta" | ||
attribute :meta do |post| | ||
{ likes: post.likes, comments: post.comments } | ||
end | ||
end | ||
``` | ||
|
||
```typescript | ||
// app/javascript/types/serializers/PostWithMeta.ts | ||
|
||
import { PostMeta } from "@/types"; | ||
|
||
export interface Post { | ||
id: number; | ||
title: string; | ||
meta: PostMeta; | ||
} | ||
``` | ||
|
||
The `"@/types"` import path is configurable: | ||
|
||
```ruby | ||
Typelizer.configure do |config| | ||
config.types_import_path = "@/types"; | ||
end | ||
``` | ||
|
||
See the [Configuration](#configuration) section for more options. | ||
|
||
### Manual Generation | ||
|
||
To manually generate TypeScript interfaces: | ||
|
||
``` | ||
$ rails typelizer:generate | ||
``` | ||
|
||
### Automatic Generation in Development | ||
|
||
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: | ||
|
||
```ruby | ||
Typelizer.listen = false | ||
``` | ||
|
||
## Configuration | ||
|
||
### Global Configuration | ||
|
||
Typelizer provides several global configuration options: | ||
|
||
```ruby | ||
# Directories to search for serializers: | ||
Typelizer.dirs = [Rails.root.join("app", "resources"), Rails.root.join("app", "serializers")] | ||
# Reject specific classes from being typelized: | ||
Typelizer.reject_class = ->(serializer:) { false } | ||
# Logger for debugging: | ||
Typelizer.logger = Logger.new($stdout, level: :info) | ||
# Force enable or disable file watching with Listen: | ||
Typelizer.listen = nil | ||
``` | ||
|
||
### Config Options | ||
|
||
`Typelizer::Config` offers fine-grained control over the gem's behavior. Here's a list of available options: | ||
|
||
```ruby | ||
Typelizer.configure do |config| | ||
# Determines how serializer names are mapped to TypeScript interface names | ||
config.serializer_name_mapper = ->(serializer) { ... } | ||
|
||
# Maps serializers to their corresponding model classes | ||
config.serializer_model_mapper = ->(serializer) { ... } | ||
|
||
# Custom transformation for generated properties | ||
config.properties_transformer = ->(properties) { ... } | ||
|
||
# Plugin for model type inference (default: ModelPlugins::ActiveRecord) | ||
config.model_plugin = Typelizer::ModelPlugins::ActiveRecord | ||
|
||
# Plugin for serializer parsing (default: SerializerPlugins::Auto) | ||
config.serializer_plugin = Typelizer::SerializerPlugins::Auto | ||
|
||
# Additional configurations for specific plugins | ||
config.plugin_configs = { alba: { ts_mapper: {...} } } | ||
|
||
# Custom DB to TypeScript type mapping | ||
config.type_mapping = config.type_mapping.merge(jsonb: "Record<string, undefined>", ... ) | ||
|
||
# Strategy for handling null values (:nullable, :optional, or :nullable_and_optional) | ||
config.null_strategy = :nullable | ||
|
||
# Directory where TypeScript interfaces will be generated | ||
config.output_dir = Rails.root.join("app/javascript/types/serializers") | ||
|
||
# Import path for generated types in TypeScript files | ||
# (e.g., `import { MyType } from "@/types"`) | ||
config.types_import_path = "@/types" | ||
|
||
# List of type names that should be considered global in TypeScript | ||
# (i.e. not prefixed with the import path) | ||
config.types_global << %w[Array Date Record File FileList] | ||
end | ||
``` | ||
|
||
### Per-Serializer Configuration | ||
|
||
You can also configure Typelizer on a per-serializer basis: | ||
|
||
```ruby | ||
class PostResource < ApplicationResource | ||
typelizer_config do |config| | ||
config.type_mapping = config.type_mapping.merge(jsonb: "Record<string, undefined>", ... ) | ||
config.null_strategy = :nullable | ||
# ... | ||
end | ||
end | ||
``` | ||
|
||
## Credits | ||
|
||
Typelizer is inspired by [types_from_serializers](https://github.com/ElMassimo/types_from_serializers). | ||
|
||
## License | ||
|
||
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# frozen_string_literal: true | ||
|
||
require "bundler/gem_tasks" | ||
require "rspec/core/rake_task" | ||
|
||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
require "standard/rake" | ||
|
||
task default: %i[spec standard] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
require "bundler/setup" | ||
require "typelizer" | ||
|
||
# You can add fixtures and/or initialization code here to make experimenting | ||
# with your gem easier. You can also use a different console, if you like. | ||
|
||
require "irb" | ||
IRB.start(__FILE__) |
Oops, something went wrong.