tapioca 0.11.15 → 0.11.17
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 +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
|