tapioca 0.11.15 → 0.11.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tapioca/dsl/compilers/action_text.rb +100 -0
- data/lib/tapioca/dsl/compilers/active_job.rb +1 -0
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +4 -1
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +1 -1
- data/lib/tapioca/dsl/compilers/identity_cache.rb +6 -9
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +3 -0
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +37 -10
- data/lib/tapioca/gem/pipeline.rb +1 -0
- data/lib/tapioca/runtime/reflection.rb +17 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a74fea1cf7f8de26296fa1fb617362cceac2f800740cfaac4e95b8b0106dfc9
|
4
|
+
data.tar.gz: 911ce69b722d3b30d07f2806ae155e0c390d015eea45ba85bf69c0796e6b5bf5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fa1c5dcd97eee61f4385ba685c8f0b7e9290bc9a79822bdf46dcbe681b7b40bcef256cf8a293911b4bcbcb39ea325b1280da1eabbfde069d6d21161d1a6a6b0
|
7
|
+
data.tar.gz: b7d3e1b1e0341bd8b835daa3f4a405271a97376eca922ea46a5680b7d388560426819d77ea9b64623f91deb68d76548372b78488d626386f5cfb35ca6531934b
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "action_text"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module Tapioca
|
11
|
+
module Dsl
|
12
|
+
module Compilers
|
13
|
+
# `Tapioca::Dsl::Compilers::ActionText` decorates RBI files for subclasses of
|
14
|
+
# `ActiveRecord::Base` that declare [has_rich_text](https://edgeguides.rubyonrails.org/action_text_overview.html#creating-rich-text-content)
|
15
|
+
#
|
16
|
+
# For example, with the following `ActiveRecord::Base` subclass:
|
17
|
+
#
|
18
|
+
# ~~~rb
|
19
|
+
# class Post < ApplicationRecord
|
20
|
+
# has_rich_text :body
|
21
|
+
# has_rich_text :title, encrypted: true
|
22
|
+
# end
|
23
|
+
# ~~~
|
24
|
+
#
|
25
|
+
# this compiler will produce the RBI file `post.rbi` with the following content:
|
26
|
+
#
|
27
|
+
# ~~~rbi
|
28
|
+
# # typed: strong
|
29
|
+
#
|
30
|
+
# class Post
|
31
|
+
# sig { returns(ActionText::RichText) }
|
32
|
+
# def body; end
|
33
|
+
#
|
34
|
+
# sig { params(value: T.nilable(T.any(ActionText::RichText, String))).returns(T.untyped) }
|
35
|
+
# def body=(value); end
|
36
|
+
#
|
37
|
+
# sig { returns(T::Boolean) }
|
38
|
+
# def body?; end
|
39
|
+
#
|
40
|
+
# sig { returns(ActionText::EncryptedRichText) }
|
41
|
+
# def title; end
|
42
|
+
#
|
43
|
+
# sig { params(value: T.nilable(T.any(ActionText::EncryptedRichText, String))).returns(T.untyped) }
|
44
|
+
# def title=(value); end
|
45
|
+
#
|
46
|
+
# sig { returns(T::Boolean) }
|
47
|
+
# def title?; end
|
48
|
+
# end
|
49
|
+
# ~~~
|
50
|
+
class ActionText < Compiler
|
51
|
+
extend T::Sig
|
52
|
+
|
53
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
54
|
+
|
55
|
+
sig { override.void }
|
56
|
+
def decorate
|
57
|
+
root.create_path(constant) do |scope|
|
58
|
+
self.class.action_text_associations(constant).each do |name|
|
59
|
+
reflection = constant.reflections.fetch(name)
|
60
|
+
type = reflection.options.fetch(:class_name)
|
61
|
+
name = reflection.name.to_s.sub("rich_text_", "")
|
62
|
+
scope.create_method(
|
63
|
+
name,
|
64
|
+
return_type: type,
|
65
|
+
)
|
66
|
+
scope.create_method(
|
67
|
+
"#{name}?",
|
68
|
+
return_type: "T::Boolean",
|
69
|
+
)
|
70
|
+
scope.create_method(
|
71
|
+
"#{name}=",
|
72
|
+
parameters: [create_param("value", type: "T.nilable(T.any(#{type}, String))")],
|
73
|
+
return_type: "T.untyped",
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
extend T::Sig
|
81
|
+
|
82
|
+
sig { params(constant: T.class_of(::ActiveRecord::Base)).returns(T::Array[String]) }
|
83
|
+
def action_text_associations(constant)
|
84
|
+
# Implementation copied from https://github.com/rails/rails/blob/31052d0e518b9da103eea2f79d250242ed1e3705/actiontext/lib/action_text/attribute.rb#L66
|
85
|
+
constant.reflect_on_all_associations(:has_one)
|
86
|
+
.map(&:name).map(&:to_s)
|
87
|
+
.select { |n| n.start_with?("rich_text_") }
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { override.returns(T::Enumerable[Module]) }
|
91
|
+
def gather_constants
|
92
|
+
descendants_of(::ActiveRecord::Base)
|
93
|
+
.reject(&:abstract_class?)
|
94
|
+
.select { |c| action_text_associations(c).any? }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -83,6 +83,7 @@ module Tapioca
|
|
83
83
|
end
|
84
84
|
def perform_later_parameters(parameters, constant_name)
|
85
85
|
if ::Gem::Requirement.new(">= 7.0").satisfied_by?(::ActiveJob.gem_version)
|
86
|
+
parameters.reject! { |typed_param| RBI::BlockParam === typed_param.param }
|
86
87
|
parameters + [create_block_param(
|
87
88
|
"block",
|
88
89
|
type: "T.nilable(T.proc.params(job: #{constant_name}).void)",
|
@@ -55,7 +55,10 @@ module Tapioca
|
|
55
55
|
root.create_path(constant) do |input_object|
|
56
56
|
arguments.each do |argument|
|
57
57
|
name = argument.keyword.to_s
|
58
|
-
input_object.create_method(
|
58
|
+
input_object.create_method(
|
59
|
+
name,
|
60
|
+
return_type: Helpers::GraphqlTypeHelper.type_for_argument(argument, constant),
|
61
|
+
)
|
59
62
|
end
|
60
63
|
end
|
61
64
|
end
|
@@ -224,7 +224,6 @@ module Tapioca
|
|
224
224
|
def create_aliased_fetch_by_methods(field, klass)
|
225
225
|
type, _ = Helpers::ActiveRecordColumnTypeHelper.new(constant).type_for(field.alias_name.to_s)
|
226
226
|
multi_type = type.delete_prefix("T.nilable(").delete_suffix(")").delete_prefix("::")
|
227
|
-
length = field.key_fields.length
|
228
227
|
suffix = field.send(:fetch_method_suffix)
|
229
228
|
|
230
229
|
parameters = field.key_fields.map do |arg|
|
@@ -238,14 +237,12 @@ module Tapioca
|
|
238
237
|
return_type: type,
|
239
238
|
)
|
240
239
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
)
|
248
|
-
end
|
240
|
+
klass.create_method(
|
241
|
+
"fetch_multi_#{suffix}",
|
242
|
+
class_method: true,
|
243
|
+
parameters: [create_param("keys", type: "T::Enumerable[T.untyped]")],
|
244
|
+
return_type: COLLECTION_TYPE.call(multi_type),
|
245
|
+
)
|
249
246
|
end
|
250
247
|
end
|
251
248
|
end
|
@@ -85,6 +85,9 @@ module Tapioca
|
|
85
85
|
"::String"
|
86
86
|
when ActiveRecord::Type::Serialized
|
87
87
|
serialized_column_type(column_type)
|
88
|
+
when defined?(ActiveRecord::Normalization::NormalizedValueType) &&
|
89
|
+
ActiveRecord::Normalization::NormalizedValueType
|
90
|
+
type_for_activerecord_value(column_type.cast_type)
|
88
91
|
when defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid) &&
|
89
92
|
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid
|
90
93
|
"::String"
|
@@ -15,7 +15,7 @@ module Tapioca
|
|
15
15
|
constant: T.any(T.class_of(GraphQL::Schema::Mutation), T.class_of(GraphQL::Schema::InputObject)),
|
16
16
|
).returns(String)
|
17
17
|
end
|
18
|
-
def
|
18
|
+
def type_for_argument(argument, constant)
|
19
19
|
type = if argument.loads
|
20
20
|
loads_type = ::GraphQL::Schema::Wrapper.new(argument.loads)
|
21
21
|
loads_type = loads_type.to_list_type if argument.type.list?
|
@@ -25,6 +25,36 @@ module Tapioca
|
|
25
25
|
argument.type
|
26
26
|
end
|
27
27
|
|
28
|
+
prepare = argument.prepare
|
29
|
+
prepare_method = if prepare.is_a?(Symbol) || prepare.is_a?(String)
|
30
|
+
if constant.respond_to?(prepare)
|
31
|
+
constant.method(prepare.to_sym)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
type_for(
|
36
|
+
type,
|
37
|
+
ignore_nilable_wrapper: has_replaceable_default?(argument),
|
38
|
+
prepare_method: prepare_method,
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
sig do
|
43
|
+
params(
|
44
|
+
type: T.any(
|
45
|
+
GraphQL::Schema::Wrapper,
|
46
|
+
T.class_of(GraphQL::Schema::Scalar),
|
47
|
+
T.class_of(GraphQL::Schema::Enum),
|
48
|
+
T.class_of(GraphQL::Schema::Union),
|
49
|
+
T.class_of(GraphQL::Schema::Object),
|
50
|
+
T.class_of(GraphQL::Schema::Interface),
|
51
|
+
T.class_of(GraphQL::Schema::InputObject),
|
52
|
+
),
|
53
|
+
ignore_nilable_wrapper: T::Boolean,
|
54
|
+
prepare_method: T.nilable(Method),
|
55
|
+
).returns(String)
|
56
|
+
end
|
57
|
+
def type_for(type, ignore_nilable_wrapper: false, prepare_method: nil)
|
28
58
|
unwrapped_type = type.unwrap
|
29
59
|
|
30
60
|
parsed_type = case unwrapped_type
|
@@ -65,14 +95,11 @@ module Tapioca
|
|
65
95
|
"T.untyped"
|
66
96
|
end
|
67
97
|
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if valid_return_type?(prepare_signature&.return_type)
|
74
|
-
parsed_type = prepare_signature.return_type&.to_s
|
75
|
-
end
|
98
|
+
if prepare_method
|
99
|
+
prepare_signature = Runtime::Reflection.signature_of(prepare_method)
|
100
|
+
prepare_return_type = prepare_signature&.return_type
|
101
|
+
if valid_return_type?(prepare_return_type)
|
102
|
+
parsed_type = prepare_return_type&.to_s
|
76
103
|
end
|
77
104
|
end
|
78
105
|
|
@@ -80,7 +107,7 @@ module Tapioca
|
|
80
107
|
parsed_type = "T::Array[#{parsed_type}]"
|
81
108
|
end
|
82
109
|
|
83
|
-
unless type.non_null? ||
|
110
|
+
unless type.non_null? || ignore_nilable_wrapper
|
84
111
|
parsed_type = RBIHelper.as_nilable_type(parsed_type)
|
85
112
|
end
|
86
113
|
|
data/lib/tapioca/gem/pipeline.rb
CHANGED
@@ -255,6 +255,23 @@ module Tapioca
|
|
255
255
|
def method_defined_by_forwardable_module?(method)
|
256
256
|
method.source_location&.first == Object.const_source_location(:Forwardable)&.first
|
257
257
|
end
|
258
|
+
|
259
|
+
sig { params(name: String).returns(T::Boolean) }
|
260
|
+
def has_aliased_namespace?(name)
|
261
|
+
name_parts = name.split("::")
|
262
|
+
name_parts.pop # drop the constant name, leaving just the namespace
|
263
|
+
|
264
|
+
name_parts.each_with_object([]) do |name_part, namespaces|
|
265
|
+
namespaces << "#{namespaces.last}::#{name_part}".delete_prefix("::")
|
266
|
+
end.any? do |namespace|
|
267
|
+
constant = constantize(namespace)
|
268
|
+
next unless Module === constant
|
269
|
+
|
270
|
+
# If the constant name doesn't match the namespace,
|
271
|
+
# the namespace must contain an alias
|
272
|
+
name_of(constant) != namespace
|
273
|
+
end
|
274
|
+
end
|
258
275
|
end
|
259
276
|
end
|
260
277
|
end
|
data/lib/tapioca/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapioca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2024-01-
|
14
|
+
date: 2024-01-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -173,6 +173,7 @@ files:
|
|
173
173
|
- lib/tapioca/dsl/compilers/aasm.rb
|
174
174
|
- lib/tapioca/dsl/compilers/action_controller_helpers.rb
|
175
175
|
- lib/tapioca/dsl/compilers/action_mailer.rb
|
176
|
+
- lib/tapioca/dsl/compilers/action_text.rb
|
176
177
|
- lib/tapioca/dsl/compilers/active_job.rb
|
177
178
|
- lib/tapioca/dsl/compilers/active_model_attributes.rb
|
178
179
|
- lib/tapioca/dsl/compilers/active_model_secure_password.rb
|