types_from_serializers 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ab46cb83091bc01087646a3e9c1eee590d4148ea16f86fcca2c83ad91b24d2a5
4
+ data.tar.gz: 95e62afbb4b49ab897434fe33926322964439af03726c570bec6296eb4c51ca1
5
+ SHA512:
6
+ metadata.gz: 8280b0616181a1b13b4192bc6cd9ceb6b43498d31bd83b871d3da0bba924c63b52d67598df83df8d8ccac535999f81a99e42b530cbc0ab6afeddbfa9366928e2
7
+ data.tar.gz: ee8d6f445603ef26932c631a2064f337186c6f27451771b2f31577df37c587f318b1abe22e9277e7db48f2d65d47ca7c62f1177a67cbc35df615e5277931bce1
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # 0.1.0 (2022-07-12)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * handle non-ActiveRecord models and extract types from unions ([ea9b2a7](https://github.com/ElMassimo/types_from_serializers/commit/ea9b2a71cb85503ff691e5ef115ab73f89b005af))
7
+
8
+
9
+ ### Features
10
+
11
+ * make the DSL is available without manually requiring ([04a4f3a](https://github.com/ElMassimo/types_from_serializers/commit/04a4f3ad3c96658639cbe75de07f19cc7f79f4c6))
12
+ * support specifying base serializers and additional dirs to scan ([164cfe1](https://github.com/ElMassimo/types_from_serializers/commit/164cfe17bb0527c59cf95441381aef7bf797a568))
13
+
14
+
15
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 Máximo Mussini
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ <h1 align="center">
2
+ Types From Serializers
3
+ <p align="center">
4
+ <a href="https://travis-ci.org/ElMassimo/types_from_serializers"><img alt="Build Status" src="https://travis-ci.org/ElMassimo/types_from_serializers.svg"/></a>
5
+ <a href="http://inch-ci.org/github/ElMassimo/types_from_serializers"><img alt="Inline docs" src="http://inch-ci.org/github/ElMassimo/types_from_serializers.svg"/></a>
6
+ <a href="https://codeclimate.com/github/ElMassimo/types_from_serializers"><img alt="Maintainability" src="https://codeclimate.com/github/ElMassimo/types_from_serializers/badges/gpa.svg"/></a>
7
+ <a href="https://codeclimate.com/github/ElMassimo/types_from_serializers"><img alt="Test Coverage" src="https://codeclimate.com/github/ElMassimo/types_from_serializers/badges/coverage.svg"/></a>
8
+ <a href="https://rubygems.org/gems/types_from_serializers"><img alt="Gem Version" src="https://img.shields.io/gem/v/types_from_serializers.svg?colorB=e9573f"/></a>
9
+ <a href="https://github.com/ElMassimo/types_from_serializers/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/badge/license-MIT-428F7E.svg"/></a>
10
+ </p>
11
+ </h1>
12
+
13
+ [aliases]: https://vite-ruby.netlify.app/guide/development.html#import-aliases-%F0%9F%91%89
14
+ [config options]: https://github.com/ElMassimo/types_from_serializers/blob/main/lib/types_from_serializers/generator.rb#L82-L85
15
+ [readme]: https://github.com/ElMassimo/types_from_serializers
16
+
17
+ For more information, check the main [README].
18
+
19
+ ### Installation 💿
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'types_from_serializers'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install types_from_serializers
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ # Internal: A DSL to specify types for serializer attributes.
6
+ module TypesFromSerializer
7
+ module DSL
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ # Override: Capture the name of the model related to the serializer.
12
+ #
13
+ # name - An alias for the internal object in the serializer.
14
+ # model - The name of an ActiveRecord model to infer types from the schema.
15
+ # types_from - The name of a TypeScript interface to infer types from.
16
+ def object_as(name, model: nil, types_from: nil)
17
+ # NOTE: Avoid taking memory for type information that won't be used.
18
+ if Rails.env.development?
19
+ model ||= name.is_a?(Symbol) ? name : try(:_serializer_model_name)
20
+ @_serializer_model_name = model || name
21
+ @_serializer_types_from = types_from if types_from
22
+ end
23
+
24
+ super(name)
25
+ end
26
+
27
+ # Public: Like `attributes`, but providing type information for each field.
28
+ def typed_attributes(attrs)
29
+ attributes(*attrs.keys)
30
+
31
+ # NOTE: Avoid taking memory for type information that won't be used.
32
+ if Rails.env.development?
33
+ _typed_attributes.update(attrs.map { |key, type|
34
+ [key.to_s, type.is_a?(Hash) ? type : {type: type}]
35
+ }.to_h)
36
+ end
37
+ end
38
+
39
+ # Public: Allows to specify the type for a serializer method that will
40
+ # be defined immediately after calling this method.
41
+ def type(type = :unknown, optional: false)
42
+ @_current_attribute_type = {type: type, optional: optional}
43
+ end
44
+
45
+ # Internal: Intercept a method definition, tying a type that was
46
+ # previously specified to the name of the attribute.
47
+ def method_added(name)
48
+ super(name)
49
+ if @_current_attribute_type
50
+ serializer_attributes name
51
+
52
+ # NOTE: Avoid taking memory for type information that won't be used.
53
+ if Rails.env.development?
54
+ _typed_attributes[name.to_s] = @_current_attribute_type
55
+ end
56
+
57
+ @_current_attribute_type = nil
58
+ end
59
+ end
60
+
61
+ # NOTE: Avoid taking memory for type information that won't be used.
62
+ if Rails.env.development?
63
+ # Internal: Contains type information for serializer attributes.
64
+ def _typed_attributes
65
+ unless defined?(@_typed_attributes)
66
+ @_typed_attributes = superclass.try(:_typed_attributes)&.dup || {}
67
+ end
68
+ @_typed_attributes
69
+ end
70
+
71
+ # Internal: The name of the model that will be serialized by this
72
+ # serializer, used to infer field types from the SQL columns.
73
+ def _serializer_model_name
74
+ unless defined?(@_serializer_model_name)
75
+ @_serializer_model_name = superclass.try(:_serializer_model_name)
76
+ end
77
+ @_serializer_model_name
78
+ end
79
+
80
+ # Internal: The TypeScript interface that will be used by default to
81
+ # infer the serializer field types when not explicitly provided.
82
+ def _serializer_types_from
83
+ unless defined?(@_serializer_types_from)
84
+ @_serializer_types_from = superclass.try(:_serializer_types_from)
85
+ end
86
+ @_serializer_types_from
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,343 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "fileutils"
5
+ require "pathname"
6
+
7
+ # Public: Automatically generates TypeScript interfaces for Ruby serializers.
8
+ module TypesFromSerializers
9
+ # Internal: The configuration for TypeScript generation.
10
+ Config = Struct.new(
11
+ :base_serializers,
12
+ :serializers_dirs,
13
+ :output_dir,
14
+ :name_from_serializer,
15
+ :native_types,
16
+ :sql_to_typescript_type_mapping,
17
+ keyword_init: true,
18
+ )
19
+
20
+ # Internal: The type metadata for a serializer.
21
+ SerializerMetadata = Struct.new(
22
+ :attributes,
23
+ :associations,
24
+ :model_name,
25
+ :types_from,
26
+ keyword_init: true,
27
+ )
28
+
29
+ # Internal: The type metadata for a serializer field.
30
+ FieldMetadata = Struct.new(:name, :type, :optional, :many, keyword_init: true) do
31
+ def typescript_name
32
+ name.to_s.camelize(:lower)
33
+ end
34
+ end
35
+
36
+ # Internal: Extensions that simplify the implementation of the generator.
37
+ module SerializerRefinements
38
+ refine String do
39
+ # Internal: Converts a name such as :user to the User constant.
40
+ def to_model
41
+ classify.safe_constantize
42
+ end
43
+ end
44
+
45
+ refine Symbol do
46
+ def safe_constantize
47
+ to_s.classify.safe_constantize
48
+ end
49
+
50
+ delegate :to_model, to: :to_s
51
+ end
52
+ # rubocop:enable Rails/Delegate
53
+
54
+ refine Class do
55
+ # Internal: Name of the TypeScript interface.
56
+ def typescript_interface_name
57
+ TypesFromSerializers.config.name_from_serializer.call(name).tr_s(":", "")
58
+ end
59
+
60
+ # Internal: The base name of the TypeScript file to be written.
61
+ def typescript_interface_basename
62
+ TypesFromSerializers.config.name_from_serializer.call(name).gsub("::", "/")
63
+ end
64
+
65
+ # Internal: A first pass of gathering types for the serializer fields.
66
+ def typescript_metadata
67
+ SerializerMetadata.new(
68
+ model_name: _serializer_model_name,
69
+ types_from: _serializer_types_from,
70
+ attributes: _attributes.map { |key, options|
71
+ typed_attrs = _typed_attributes.fetch(key, {})
72
+ FieldMetadata.new(
73
+ **typed_attrs,
74
+ name: key,
75
+ optional: typed_attrs[:optional] || options.key?(:if),
76
+ )
77
+ },
78
+ associations: _associations.map { |key, options|
79
+ FieldMetadata.new(
80
+ name: options.fetch(:root, key),
81
+ type: options.fetch(:serializer),
82
+ optional: options.key?(:if),
83
+ many: options.fetch(:write_method) == :write_many,
84
+ )
85
+ },
86
+ )
87
+ end
88
+
89
+ # Internal: Infers field types by checking the SQL columns for the model
90
+ # serialized, or from a TypeScript interface if provided.
91
+ def typescript_infer_types(metadata)
92
+ model = metadata.model_name&.to_model
93
+ interface = metadata.types_from
94
+
95
+ metadata.attributes.reject(&:type).each do |meta|
96
+ if model&.respond_to?(:columns_hash) && (column = model.columns_hash[meta.name.to_s])
97
+ meta[:type] = TypesFromSerializers.config.sql_to_typescript_type_mapping[column.type]
98
+ meta[:optional] ||= column.null
99
+ elsif interface
100
+ meta[:type] = "#{interface}['#{meta.typescript_name}']"
101
+ end
102
+ end
103
+ end
104
+
105
+ def typescript_imports(metadata)
106
+ assoc_imports = metadata.associations.map { |meta|
107
+ [meta.type.typescript_interface_name, "~/types/serializers/#{meta.type.typescript_interface_basename}"]
108
+ }
109
+
110
+ attr_imports = metadata.attributes
111
+ .flat_map { |meta| extract_typescript_types(meta.type.to_s) }
112
+ .uniq
113
+ .reject { |type| typescript_native_type?(type) }
114
+ .map { |type|
115
+ [type, "~/types/#{type}"]
116
+ }
117
+
118
+ (assoc_imports + attr_imports).uniq.map { |interface, filename|
119
+ "import type #{interface} from '#{filename}'\n"
120
+ }.uniq
121
+ end
122
+
123
+ # Internal: Extracts any types inside generics or array types.
124
+ def extract_typescript_types(type)
125
+ type.split(/[<>\[\],\s|]+/)
126
+ end
127
+
128
+ # NOTE: Treat uppercase names as custom types.
129
+ # Lowercase names would be native types, such as :string and :boolean.
130
+ def typescript_native_type?(type)
131
+ type[0] == type[0].downcase || TypesFromSerializers.config.native_types.include?(type)
132
+ end
133
+
134
+ def typescript_fields(metadata)
135
+ (metadata.attributes + metadata.associations).map { |meta|
136
+ type = meta.type.is_a?(Class) ? meta.type.typescript_interface_name : meta.type || :unknown
137
+ type = meta.many ? "#{type}[]" : type
138
+ " #{meta.typescript_name}#{"?" if meta.optional}: #{type}"
139
+ }
140
+ end
141
+ end
142
+ end
143
+
144
+ # Internal: Structure to keep track of changed files.
145
+ class Changes
146
+ def initialize(dirs)
147
+ @added = Set.new
148
+ @removed = Set.new
149
+ @modified = Set.new
150
+ track_changes(dirs)
151
+ end
152
+
153
+ def updated?
154
+ @modified.any? || @added.any? || @removed.any?
155
+ end
156
+
157
+ def any_removed?
158
+ @removed.any?
159
+ end
160
+
161
+ def modified_files
162
+ @modified
163
+ end
164
+
165
+ def only_modified?
166
+ @added.empty? && @removed.empty?
167
+ end
168
+
169
+ def clear
170
+ @added.clear
171
+ @removed.clear
172
+ @modified.clear
173
+ end
174
+
175
+ private
176
+
177
+ def track_changes(dirs)
178
+ Listen.to(*dirs, only: %r{.rb$}) do |modified, added, removed|
179
+ modified.each { |file| @modified.add(file) }
180
+ added.each { |file| @added.add(file) }
181
+ removed.each { |file| @removed.add(file) }
182
+ end.start
183
+ end
184
+ end
185
+
186
+ class << self
187
+ using SerializerRefinements
188
+
189
+ attr_reader :force_generation
190
+
191
+ # Public: Configuration of the code generator.
192
+ def config
193
+ (@config ||= default_config(root)).tap do |config|
194
+ yield(config) if block_given?
195
+ end
196
+ end
197
+
198
+ # Public: Generates code for all serializers in the app.
199
+ def generate(force: ENV["SERIALIZER_TYPES_FORCE"])
200
+ @force_generation = force
201
+ generate_index_file
202
+
203
+ loaded_serializers.each do |serializer|
204
+ generate_interface_for(serializer)
205
+ end
206
+ end
207
+
208
+ def generate_changed
209
+ if changes.updated?
210
+ config.output_dir.rmtree if changes.any_removed?
211
+ load_serializers(changes.modified_files)
212
+ generate
213
+ changes.clear
214
+ end
215
+ end
216
+
217
+ # Internal: Defines a TypeScript interface for the serializer.
218
+ def generate_interface_for(serializer)
219
+ metadata = serializer.typescript_metadata
220
+ filename = serializer.typescript_interface_basename
221
+
222
+ write_if_changed(filename: filename, cache_key: metadata.inspect) {
223
+ serializer.typescript_infer_types(metadata)
224
+ <<~TS
225
+ //
226
+ // DO NOT MODIFY: This file was automatically generated by TypesFromSerializers.
227
+ #{serializer.typescript_imports(metadata).join}
228
+ export default interface #{serializer.typescript_interface_name} {
229
+ #{serializer.typescript_fields(metadata).join("\n")}
230
+ }
231
+ TS
232
+ }
233
+ end
234
+
235
+ # Internal: Allows to import all serializer types from a single file.
236
+ def generate_index_file
237
+ write_if_changed(filename: "index", cache_key: all_serializer_files.join) {
238
+ load_serializers(all_serializer_files)
239
+ <<~TS
240
+ //
241
+ // DO NOT MODIFY: This file was automatically generated by TypesFromSerializers.
242
+ #{loaded_serializers.map { |s| "export type { default as #{s.typescript_interface_name} } from './#{s.typescript_interface_basename}'" }.join("\n")}
243
+ TS
244
+ }
245
+ end
246
+
247
+ # Internal: Checks if it should avoid generating an interface.
248
+ def skip_serializer?(name)
249
+ name.include?("BaseSerializer") || name.in?(config.base_serializers)
250
+ end
251
+
252
+ # Internal: Returns an object compatible with FileUpdateChecker.
253
+ def track_changes
254
+ changes
255
+ end
256
+
257
+ private
258
+
259
+ def root
260
+ defined?(Rails) ? Rails.root : Pathname.new(Dir.pwd)
261
+ end
262
+
263
+ def changes
264
+ @changes ||= Changes.new(config.serializers_dirs)
265
+ end
266
+
267
+ def all_serializer_files
268
+ config.serializers_dirs.flat_map { |dir| Dir["#{dir}/**/*.rb"] }
269
+ end
270
+
271
+ def load_serializers(files)
272
+ files.each { |file| require file }
273
+ end
274
+
275
+ def loaded_serializers
276
+ config.base_serializers.map(&:constantize)
277
+ .flat_map(&:descendants)
278
+ .uniq
279
+ .sort_by(&:name)
280
+ .reject { |s| skip_serializer?(s.name) }
281
+ rescue NameError
282
+ raise ArgumentError, "Please ensure all your serializers extend BaseSerializer, or configure `config.base_serializers`."
283
+ end
284
+
285
+ def default_config(root)
286
+ Config.new(
287
+ # The base serializers that all other serializers extend.
288
+ base_serializers: ["BaseSerializer"],
289
+
290
+ # The dirs where the serializer files are located.
291
+ serializers_dirs: [root.join("app/serializers").to_s],
292
+
293
+ # The dir where interface files are placed.
294
+ output_dir: root.join(defined?(ViteRuby) ? ViteRuby.config.source_code_dir : "app/frontend").join("types/serializers"),
295
+
296
+ # Remove the serializer suffix from the class name.
297
+ name_from_serializer: ->(name) { name.delete_suffix("Serializer") },
298
+
299
+ # Types that don't need to be imported in TypeScript.
300
+ native_types: [
301
+ "Array",
302
+ "Record",
303
+ "Date",
304
+ ].to_set,
305
+
306
+ # Maps SQL column types to TypeScript native and custom types.
307
+ sql_to_typescript_type_mapping: {
308
+ boolean: :boolean,
309
+ date: "string | Date",
310
+ datetime: "string | Date",
311
+ decimal: :number,
312
+ integer: :number,
313
+ string: :string,
314
+ text: :string,
315
+ }.tap do |types|
316
+ types.default = :unknown
317
+ end,
318
+ )
319
+ end
320
+
321
+ # Internal: Writes if the file does not exist or the cache key has changed.
322
+ # The cache strategy consists of a comment on the first line of the file.
323
+ #
324
+ # Yields to receive the rendered file content when it needs to.
325
+ def write_if_changed(filename:, cache_key:)
326
+ filename = config.output_dir.join("#{filename}.ts")
327
+ FileUtils.mkdir_p(filename.dirname)
328
+ cache_key_comment = "// TypesFromSerializers CacheKey #{Digest::MD5.hexdigest(cache_key)}\n"
329
+ File.open(filename, "a+") { |file|
330
+ if stale?(file, cache_key_comment)
331
+ file.truncate(0)
332
+ file.write(cache_key_comment)
333
+ file.write(yield)
334
+ end
335
+ }
336
+ end
337
+
338
+ # Internal: Returns true if the cache key has changed since the last codegen.
339
+ def stale?(file, cache_key_comment)
340
+ @force_generation || file.gets != cache_key_comment
341
+ end
342
+ end
343
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ class TypesFromSerializers::Railtie < Rails::Railtie
6
+ railtie_name :types_from_serializers
7
+
8
+ # Automatically generates code whenever a serializer is loaded.
9
+ if defined?(Rails.env) && Rails.env.development?
10
+ require_relative "generator"
11
+
12
+ initializer "types_from_serializers.reloader" do |app|
13
+ if Gem.loaded_specs["listen"]
14
+ require "listen"
15
+
16
+ app.config.after_initialize do
17
+ app.reloaders << TypesFromSerializers.track_changes
18
+ end
19
+
20
+ app.config.to_prepare do
21
+ TypesFromSerializers.generate_changed
22
+ end
23
+ else
24
+ app.config.to_prepare do
25
+ TypesFromSerializers.generate
26
+ end
27
+
28
+ Rails.logger.warn "Add 'listen' to your Gemfile to automatically generate code on serializer changes."
29
+ end
30
+ end
31
+ end
32
+
33
+ # Suitable when triggering code generation manually.
34
+ rake_tasks do |app|
35
+ namespace :types_from_serializers do
36
+ desc "Generates TypeScript interfaces for each serializer in the app."
37
+ task generate: :environment do
38
+ require_relative "generator"
39
+ serializers = TypesFromSerializers.generate(force: true)
40
+ puts "Generated TypeScript interfaces for #{serializers.size} serializers:"
41
+ puts serializers.map { |s| "\t#{s.name}" }.join("\n")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TypesFromSerializers
4
+ # Public: This library adheres to semantic versioning.
5
+ VERSION = "0.1.0"
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "types_from_serializers/version"
4
+ require_relative "types_from_serializers/dsl"
5
+ require_relative "types_from_serializers/railtie"
metadata ADDED
@@ -0,0 +1,228 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: types_from_serializers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Máximo Mussini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-07-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
33
+ - !ruby/object:Gem::Dependency
34
+ name: oj_serializers
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: listen
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.2'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2'
75
+ - !ruby/object:Gem::Dependency
76
+ name: pry-byebug
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.9'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.9'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '13'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '13'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec-given
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.8'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.8'
117
+ - !ruby/object:Gem::Dependency
118
+ name: simplecov
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "<"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.18'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "<"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.18'
131
+ - !ruby/object:Gem::Dependency
132
+ name: standard
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop-rails
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: rubocop-rspec
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: rubocop-performance
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ description: types_from_serializers helps you by automatically generating TypeScript
188
+ interfaces for your JSON serializers, allowing you typecheck your frontend code
189
+ to ship fast and with confidence.
190
+ email:
191
+ - maximomussini@gmail.com
192
+ executables: []
193
+ extensions: []
194
+ extra_rdoc_files:
195
+ - README.md
196
+ files:
197
+ - CHANGELOG.md
198
+ - LICENSE.txt
199
+ - README.md
200
+ - lib/types_from_serializers.rb
201
+ - lib/types_from_serializers/dsl.rb
202
+ - lib/types_from_serializers/generator.rb
203
+ - lib/types_from_serializers/railtie.rb
204
+ - lib/types_from_serializers/version.rb
205
+ homepage: https://github.com/ElMassimo/types_from_serializers
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubygems_version: 3.3.7
225
+ signing_key:
226
+ specification_version: 4
227
+ summary: Generate TypeScript interfaces from your JSON serializers.
228
+ test_files: []