sorbet-runtime 0.6.12449 → 0.6.12652
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/types/configuration.rb +0 -10
- data/lib/types/private/abstract/data.rb +1 -1
- data/lib/types/private/methods/_methods.rb +32 -33
- data/lib/types/private/methods/signature_validation.rb +9 -3
- data/lib/types/private/sealed.rb +1 -1
- data/lib/types/props/_props.rb +5 -8
- data/lib/types/props/decorator.rb +14 -37
- data/lib/types/props/has_lazily_specialized_methods.rb +1 -1
- data/lib/types/props/pretty_printable.rb +5 -5
- data/lib/types/props/private/deserializer_generator.rb +10 -6
- data/lib/types/props/private/serializer_generator.rb +9 -5
- data/lib/types/props/serializable.rb +4 -9
- data/lib/types/types/t_enum.rb +2 -0
- data/lib/types/types/typed_array.rb +2 -2
- data/lib/types/types/typed_enumerator.rb +2 -2
- data/lib/types/types/typed_enumerator_chain.rb +2 -2
- data/lib/types/types/typed_enumerator_lazy.rb +2 -2
- data/lib/types/types/typed_hash.rb +2 -2
- data/lib/types/types/typed_range.rb +2 -2
- data/lib/types/types/typed_set.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b5ae526c822c1b9eac7f55430c678b64b807489cf4326c51c3a31f48ca4a8c0
|
|
4
|
+
data.tar.gz: 901ac0445af6e20b17df21d2366ed09da7abaf54cbefe728ffd005fd553c1daf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 79f837c6cf32a3737045ad77d12945f8b8c79a46431c211b5014b2e425980249f2b118362e78e89239706e1456ad3a045910611fb152f48ed714a5626f6a458b
|
|
7
|
+
data.tar.gz: b9cd8500296a6aad4250d6df216fa32e4007cf282a6273ac2247b8102b44f0f71bb7908e0c0a2e0aeccd0643b881fac95dd540c5ac6e3d61420ade1483972966
|
data/lib/types/configuration.rb
CHANGED
|
@@ -546,16 +546,6 @@ module T::Configuration
|
|
|
546
546
|
@legacy_t_enum_migration_mode || false
|
|
547
547
|
end
|
|
548
548
|
|
|
549
|
-
@prop_freeze_handler = ->(instance, prop_name) {}
|
|
550
|
-
|
|
551
|
-
def self.prop_freeze_handler=(handler)
|
|
552
|
-
@prop_freeze_handler = handler
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def self.prop_freeze_handler
|
|
556
|
-
@prop_freeze_handler
|
|
557
|
-
end
|
|
558
|
-
|
|
559
549
|
@sealed_violation_whitelist = nil
|
|
560
550
|
# @param [Array] sealed_violation_whitelist An array of Regexp to validate
|
|
561
551
|
# whether inheriting /including a sealed module outside the defining module
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# modules that override the `hash` method with something completely broken.
|
|
13
13
|
module T::Private::Abstract::Data
|
|
14
14
|
def self.get(mod, key)
|
|
15
|
-
mod.instance_variable_get("@opus_abstract__#{key}")
|
|
15
|
+
mod.instance_variable_get("@opus_abstract__#{key}")
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.set(mod, key, value)
|
|
@@ -104,24 +104,6 @@ module T::Private::Methods
|
|
|
104
104
|
T::Types::Proc.new(decl.params, decl.returns)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
# Returns the signature for a method whose definition was preceded by `sig`.
|
|
108
|
-
#
|
|
109
|
-
# @param method [UnboundMethod]
|
|
110
|
-
# @return [T::Private::Methods::Signature]
|
|
111
|
-
def self.signature_for_method(method)
|
|
112
|
-
signature_for_key(method_to_key(method))
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
private_class_method def self.signature_for_key(key)
|
|
116
|
-
maybe_run_sig_block_for_key(key)
|
|
117
|
-
|
|
118
|
-
# If a subclass Sub inherits a method `foo` from Base, then
|
|
119
|
-
# Sub.instance_method(:foo) != Base.instance_method(:foo) even though they resolve to the
|
|
120
|
-
# same method. Similarly, Foo.method(:bar) != Foo.singleton_class.instance_method(:bar).
|
|
121
|
-
# So, we always do the look up by the method on the owner (Base in this example).
|
|
122
|
-
@signatures_by_method[key]
|
|
123
|
-
end
|
|
124
|
-
|
|
125
107
|
# Fetch the directory name of the file that defines the `T::Private` constant and
|
|
126
108
|
# add a trailing slash to allow us to match it as a directory prefix.
|
|
127
109
|
SORBET_RUNTIME_LIB_PATH = File.dirname(T.const_source_location(:Private).first) + File::SEPARATOR
|
|
@@ -407,6 +389,19 @@ module T::Private::Methods
|
|
|
407
389
|
end
|
|
408
390
|
end
|
|
409
391
|
|
|
392
|
+
# Returns the signature for a method whose definition was preceded by `sig`.
|
|
393
|
+
#
|
|
394
|
+
# @param method [UnboundMethod]
|
|
395
|
+
# @return [T::Private::Methods::Signature]
|
|
396
|
+
def self.signature_for_method(method)
|
|
397
|
+
signature_for_key(method_to_key(method))
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
private_class_method def self.signature_for_key(key)
|
|
401
|
+
maybe_run_sig_block_for_key(key)
|
|
402
|
+
@signatures_by_method[key]
|
|
403
|
+
end
|
|
404
|
+
|
|
410
405
|
def self.unwrap_method(mod, signature, original_method)
|
|
411
406
|
maybe_wrapped_method = CallValidation.wrap_method_if_needed(mod, signature, original_method)
|
|
412
407
|
@signatures_by_method[method_to_key(maybe_wrapped_method)] = signature
|
|
@@ -433,6 +428,25 @@ module T::Private::Methods
|
|
|
433
428
|
run_sig_block_for_key(method_to_key(method))
|
|
434
429
|
end
|
|
435
430
|
|
|
431
|
+
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
|
|
432
|
+
private_class_method def self.method_owner_and_name_to_key(owner, name)
|
|
433
|
+
"#{owner.object_id}##{name}"
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
private_class_method def self.method_to_key(method)
|
|
437
|
+
# If a subclass Sub inherits a method `foo` from Base, then
|
|
438
|
+
# Sub.instance_method(:foo) != Base.instance_method(:foo) even though they resolve to the
|
|
439
|
+
# same method. Similarly, Foo.method(:bar) != Foo.singleton_class.instance_method(:bar).
|
|
440
|
+
# So, we always do the look up by the method on the owner (Base in this example).
|
|
441
|
+
method_owner_and_name_to_key(method.owner, method.name)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
private_class_method def self.key_to_method(key)
|
|
445
|
+
id, name = key.split("#")
|
|
446
|
+
obj = ObjectSpace._id2ref(id.to_i)
|
|
447
|
+
obj.instance_method(name)
|
|
448
|
+
end
|
|
449
|
+
|
|
436
450
|
private_class_method def self.run_sig_block_for_key(key, force_type_init: false)
|
|
437
451
|
blk = @sig_wrappers[key]
|
|
438
452
|
if !blk
|
|
@@ -604,21 +618,6 @@ module T::Private::Methods
|
|
|
604
618
|
mod.method(name)
|
|
605
619
|
end
|
|
606
620
|
end
|
|
607
|
-
|
|
608
|
-
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
|
|
609
|
-
private_class_method def self.method_owner_and_name_to_key(owner, name)
|
|
610
|
-
"#{owner.object_id}##{name}"
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
private_class_method def self.method_to_key(method)
|
|
614
|
-
method_owner_and_name_to_key(method.owner, method.name)
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
private_class_method def self.key_to_method(key)
|
|
618
|
-
id, name = key.split("#")
|
|
619
|
-
obj = ObjectSpace._id2ref(id.to_i)
|
|
620
|
-
obj.instance_method(name)
|
|
621
|
-
end
|
|
622
621
|
end
|
|
623
622
|
|
|
624
623
|
# This has to be here, and can't be nested inside `T::Private::Methods`,
|
|
@@ -277,6 +277,9 @@ module T::Private::Methods::SignatureValidation
|
|
|
277
277
|
end
|
|
278
278
|
end
|
|
279
279
|
|
|
280
|
+
ALLOW_INCOMPATIBLE_VISIBILITY = [:visibility, true].freeze
|
|
281
|
+
private_constant :ALLOW_INCOMPATIBLE_VISIBILITY
|
|
282
|
+
|
|
280
283
|
def self.validate_override_visibility(signature, super_signature)
|
|
281
284
|
return if super_signature.mode == Modes.untyped
|
|
282
285
|
# This departs from the behavior of other `validate_override_whatever` functions in that it
|
|
@@ -284,8 +287,8 @@ module T::Private::Methods::SignatureValidation
|
|
|
284
287
|
# done because the primary method for silencing these errors (`allow_incompatible: :visibility`)
|
|
285
288
|
# requires an `override` node to attach to. Once we have static override checking for implicitly
|
|
286
289
|
# overridden methods, we can remove this.
|
|
287
|
-
return unless
|
|
288
|
-
return if
|
|
290
|
+
return unless Modes::OVERRIDE_MODES.include?(signature.mode)
|
|
291
|
+
return if ALLOW_INCOMPATIBLE_VISIBILITY.include?(signature.override_allow_incompatible)
|
|
289
292
|
method = signature.method
|
|
290
293
|
super_method = super_signature.method
|
|
291
294
|
mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
|
|
@@ -305,8 +308,11 @@ module T::Private::Methods::SignatureValidation
|
|
|
305
308
|
end
|
|
306
309
|
|
|
307
310
|
# Higher = more restrictive.
|
|
311
|
+
METHOD_VISIBILITIES = %i[public protected private].freeze
|
|
312
|
+
private_constant :METHOD_VISIBILITIES
|
|
313
|
+
|
|
308
314
|
private_class_method def self.visibility_strength(vis)
|
|
309
|
-
|
|
315
|
+
METHOD_VISIBILITIES.find_index(vis)
|
|
310
316
|
end
|
|
311
317
|
|
|
312
318
|
private_class_method def self.base_override_loc_str(signature, super_signature)
|
data/lib/types/private/sealed.rb
CHANGED
|
@@ -70,7 +70,7 @@ module T::Private::Sealed
|
|
|
70
70
|
|
|
71
71
|
def self.validate_inheritance(caller_loc, parent, child, verb)
|
|
72
72
|
this_file = caller_loc&.path
|
|
73
|
-
decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file)
|
|
73
|
+
decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file)
|
|
74
74
|
|
|
75
75
|
if !this_file
|
|
76
76
|
raise "Could not use backtrace to determine file for #{verb} child #{child}"
|
data/lib/types/props/_props.rb
CHANGED
|
@@ -132,17 +132,14 @@ module T::Props
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
# Shorthand helper to define a `prop` with `immutable => true`
|
|
135
|
-
sig { params(name: Symbol,
|
|
136
|
-
def const(name,
|
|
137
|
-
if
|
|
135
|
+
sig { params(name: Symbol, cls: T.untyped, rules: T.untyped).void }
|
|
136
|
+
def const(name, cls, **rules)
|
|
137
|
+
if rules.key?(:immutable)
|
|
138
138
|
Kernel.raise ArgumentError.new("Cannot pass 'immutable' argument when using 'const' keyword to define a prop")
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
else
|
|
144
|
-
self.prop(name, cls_or_args, **args.merge(immutable: true))
|
|
145
|
-
end
|
|
141
|
+
rules[:immutable] = true
|
|
142
|
+
self.prop(name, cls, **rules)
|
|
146
143
|
end
|
|
147
144
|
|
|
148
145
|
def included(child)
|
|
@@ -174,7 +174,9 @@ class T::Props::Decorator
|
|
|
174
174
|
.checked(:never)
|
|
175
175
|
end
|
|
176
176
|
def prop_get(instance, prop, rules=prop_rules(prop))
|
|
177
|
-
|
|
177
|
+
# `instance_variable_get` will return nil if the variable doesn't exist
|
|
178
|
+
# which is what we want to have happen for the logic below.
|
|
179
|
+
val = instance.instance_variable_get(rules[:accessor_key])
|
|
178
180
|
if !val.nil?
|
|
179
181
|
val
|
|
180
182
|
elsif (d = rules[:ifunset])
|
|
@@ -194,7 +196,9 @@ class T::Props::Decorator
|
|
|
194
196
|
.checked(:never)
|
|
195
197
|
end
|
|
196
198
|
def prop_get_if_set(instance, prop, rules=prop_rules(prop))
|
|
197
|
-
|
|
199
|
+
# `instance_variable_get` will return nil if the variable doesn't exist
|
|
200
|
+
# which is what we want to have happen for the return value here.
|
|
201
|
+
instance.instance_variable_get(rules[:accessor_key])
|
|
198
202
|
end
|
|
199
203
|
alias_method :get, :prop_get_if_set # Alias for backwards compatibility
|
|
200
204
|
|
|
@@ -238,7 +242,9 @@ class T::Props::Decorator
|
|
|
238
242
|
end
|
|
239
243
|
|
|
240
244
|
if rules.keys.any? { |k| !valid_rule_key?(k) }
|
|
241
|
-
|
|
245
|
+
invalid_keys = rules.keys.reject { |k| valid_rule_key?(k) }
|
|
246
|
+
suffix = invalid_keys.size == 1 ? "" : "s"
|
|
247
|
+
raise ArgumentError.new("Invalid prop arg#{suffix} supplied in #{self}: #{invalid_keys.inspect}")
|
|
242
248
|
end
|
|
243
249
|
|
|
244
250
|
if !rules[:clobber_existing_method!] && !rules[:without_accessors] && BANNED_METHOD_NAMES.include?(name.to_sym)
|
|
@@ -259,6 +265,8 @@ class T::Props::Decorator
|
|
|
259
265
|
end
|
|
260
266
|
|
|
261
267
|
SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z/.freeze, Regexp, checked: false)
|
|
268
|
+
# Should be exactly the same as `SAFE_NAME`, but with a leading `@`.
|
|
269
|
+
SAFE_ACCESSOR_KEY_NAME = T.let(/\A@[A-Za-z_][A-Za-z0-9_-]*\z/.freeze, Regexp, checked: false)
|
|
262
270
|
|
|
263
271
|
# Used to validate both prop names and serialized forms
|
|
264
272
|
sig { params(name: T.any(Symbol, String)).void.checked(:never) }
|
|
@@ -319,9 +327,9 @@ class T::Props::Decorator
|
|
|
319
327
|
sig(:final) { params(name: Symbol).returns(T::Boolean).checked(:never) }
|
|
320
328
|
private def method_defined_on_ancestor?(name)
|
|
321
329
|
(@class.method_defined?(name) || @class.private_method_defined?(name)) &&
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
330
|
+
# Unfortunately, older versions of ruby don't allow the second parameter on
|
|
331
|
+
# `private_method_defined?`.
|
|
332
|
+
(!@class.method_defined?(name, false) && !@class.private_method_defined?(name, false))
|
|
325
333
|
end
|
|
326
334
|
|
|
327
335
|
sig(:final) { params(name: Symbol, rules: Rules).void.checked(:never) }
|
|
@@ -402,8 +410,6 @@ class T::Props::Decorator
|
|
|
402
410
|
|
|
403
411
|
# extra arbitrary metadata attached by the code defining this property
|
|
404
412
|
|
|
405
|
-
validate_not_missing_sensitivity(name, rules)
|
|
406
|
-
|
|
407
413
|
# for backcompat (the `:array` key is deprecated but because the name is
|
|
408
414
|
# so generic it's really hard to be sure it's not being relied on anymore)
|
|
409
415
|
if type.is_a?(T::Types::TypedArray)
|
|
@@ -479,35 +485,6 @@ class T::Props::Decorator
|
|
|
479
485
|
end
|
|
480
486
|
end
|
|
481
487
|
|
|
482
|
-
# checked(:never) - Rules hash is expensive to check
|
|
483
|
-
sig { params(prop_name: Symbol, rules: Rules).void.checked(:never) }
|
|
484
|
-
private def validate_not_missing_sensitivity(prop_name, rules)
|
|
485
|
-
if rules[:sensitivity].nil?
|
|
486
|
-
if rules[:redaction]
|
|
487
|
-
T::Configuration.hard_assert_handler(
|
|
488
|
-
"#{@class}##{prop_name} has a 'redaction:' annotation but no " \
|
|
489
|
-
"'sensitivity:' annotation. This is probably wrong, because if a " \
|
|
490
|
-
"prop needs redaction then it is probably sensitive. Add a " \
|
|
491
|
-
"sensitivity annotation like 'sensitivity: Opus::Sensitivity::PII." \
|
|
492
|
-
"whatever', or explicitly override this check with 'sensitivity: []'."
|
|
493
|
-
)
|
|
494
|
-
end
|
|
495
|
-
# TODO(PRIVACYENG-982) Ideally we'd also check for 'password' and possibly
|
|
496
|
-
# other terms, but this interacts badly with ProtoDefinedDocument because
|
|
497
|
-
# the proto syntax currently can't declare "sensitivity: []"
|
|
498
|
-
if /\bsecret\b/.match?(prop_name)
|
|
499
|
-
T::Configuration.hard_assert_handler(
|
|
500
|
-
"#{@class}##{prop_name} has the word 'secret' in its name, but no " \
|
|
501
|
-
"'sensitivity:' annotation. This is probably wrong, because if a " \
|
|
502
|
-
"prop is named 'secret' then it is probably sensitive. Add a " \
|
|
503
|
-
"sensitivity annotation like 'sensitivity: Opus::Sensitivity::NonPII." \
|
|
504
|
-
"security_token', or explicitly override this check with " \
|
|
505
|
-
"'sensitivity: []'."
|
|
506
|
-
)
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
|
|
511
488
|
# Create `#{prop_name}_redacted` method
|
|
512
489
|
sig do
|
|
513
490
|
params(
|
|
@@ -12,8 +12,8 @@ module T::Props::PrettyPrintable
|
|
|
12
12
|
pp.group(1, "<#{klass.inspect_class_with_decoration(self)}", ">") do
|
|
13
13
|
klass.all_props.sort.each do |prop|
|
|
14
14
|
pp.breakable
|
|
15
|
-
val = klass.get(self, prop)
|
|
16
15
|
rules = klass.prop_rules(prop)
|
|
16
|
+
val = klass.get(self, prop, rules)
|
|
17
17
|
pp.text("#{prop}=")
|
|
18
18
|
if (custom_inspect = rules[:inspect])
|
|
19
19
|
inspected = if T::Utils.arity(custom_inspect) == 1
|
|
@@ -22,8 +22,8 @@ module T::Props::PrettyPrintable
|
|
|
22
22
|
custom_inspect.call(val, {multiline: multiline})
|
|
23
23
|
end
|
|
24
24
|
pp.text(inspected.nil? ? "nil" : inspected)
|
|
25
|
-
elsif rules[:sensitivity] && !
|
|
26
|
-
pp.text("<REDACTED #{
|
|
25
|
+
elsif (sensitivity = rules[:sensitivity]) && !sensitivity.empty? && !val.nil?
|
|
26
|
+
pp.text("<REDACTED #{sensitivity.join(', ')}>")
|
|
27
27
|
else
|
|
28
28
|
val.pretty_print(pp)
|
|
29
29
|
end
|
|
@@ -56,14 +56,14 @@ module T::Props::PrettyPrintable
|
|
|
56
56
|
|
|
57
57
|
# Overridable method to specify how the first part of a `pretty_print`d object's class should look like
|
|
58
58
|
# NOTE: This is just to support Stripe's `PrettyPrintableModel` case, and not recommended to be overridden
|
|
59
|
-
sig { params(instance: T::Props::PrettyPrintable).returns(String) }
|
|
59
|
+
sig { params(instance: T::Props::PrettyPrintable).returns(String).checked(:never) }
|
|
60
60
|
def inspect_class_with_decoration(instance)
|
|
61
61
|
T.unsafe(instance).class.to_s
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Overridable method to add anything that is not a prop
|
|
65
65
|
# NOTE: This is to support cases like Serializable's `@_extra_props`, and Stripe's `PrettyPrintableModel#@_deleted`
|
|
66
|
-
sig { params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void }
|
|
66
|
+
sig { params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void.checked(:never) }
|
|
67
67
|
def pretty_print_extra(instance, pp); end
|
|
68
68
|
end
|
|
69
69
|
end
|
|
@@ -16,6 +16,8 @@ module T::Props
|
|
|
16
16
|
module DeserializerGenerator
|
|
17
17
|
extend T::Sig
|
|
18
18
|
|
|
19
|
+
CAN_USE_SYMBOL_NAME = T.let(RUBY_VERSION >= "3.3.0", T::Boolean)
|
|
20
|
+
|
|
19
21
|
# Generate a method that takes a T::Hash[String, T.untyped] representing
|
|
20
22
|
# serialized props, sets instance variables for each prop found in the
|
|
21
23
|
# input, and returns the count of we props set (which we can use to check
|
|
@@ -29,19 +31,21 @@ module T::Props
|
|
|
29
31
|
.checked(:never)
|
|
30
32
|
end
|
|
31
33
|
def self.generate(props, defaults)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
parts = props.filter_map do |prop, rules|
|
|
35
|
+
next if rules[:dont_store]
|
|
36
|
+
|
|
34
37
|
# All of these strings should already be validated (directly or
|
|
35
38
|
# indirectly) in `validate_prop_name`, so we don't bother with a nice
|
|
36
39
|
# error message, but we double check here to prevent a refactoring
|
|
37
40
|
# from introducing a security vulnerability.
|
|
38
|
-
raise unless T::Props::Decorator::SAFE_NAME.match?(prop.to_s)
|
|
41
|
+
raise unless T::Props::Decorator::SAFE_NAME.match?(CAN_USE_SYMBOL_NAME ? prop.name : prop.to_s)
|
|
39
42
|
|
|
40
43
|
hash_key = rules.fetch(:serialized_form)
|
|
41
44
|
raise unless T::Props::Decorator::SAFE_NAME.match?(hash_key)
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
key = rules.fetch(:accessor_key)
|
|
47
|
+
ivar_name = CAN_USE_SYMBOL_NAME ? key.name : key.to_s
|
|
48
|
+
raise unless ivar_name.start_with?('@') && T::Props::Decorator::SAFE_ACCESSOR_KEY_NAME.match?(ivar_name)
|
|
45
49
|
|
|
46
50
|
transformation = SerdeTransform.generate(
|
|
47
51
|
T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)),
|
|
@@ -90,7 +94,7 @@ module T::Props
|
|
|
90
94
|
|
|
91
95
|
<<~RUBY
|
|
92
96
|
def __t_props_generated_deserialize(hash)
|
|
93
|
-
found = #{
|
|
97
|
+
found = #{parts.size}
|
|
94
98
|
#{parts.join("\n\n")}
|
|
95
99
|
found
|
|
96
100
|
end
|
|
@@ -16,6 +16,8 @@ module T::Props
|
|
|
16
16
|
module SerializerGenerator
|
|
17
17
|
extend T::Sig
|
|
18
18
|
|
|
19
|
+
CAN_USE_SYMBOL_NAME = T.let(RUBY_VERSION >= "3.3.0", T::Boolean)
|
|
20
|
+
|
|
19
21
|
sig do
|
|
20
22
|
params(
|
|
21
23
|
props: T::Hash[Symbol, T::Hash[Symbol, T.untyped]],
|
|
@@ -24,19 +26,21 @@ module T::Props
|
|
|
24
26
|
.checked(:never)
|
|
25
27
|
end
|
|
26
28
|
def self.generate(props)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
parts = props.filter_map do |prop, rules|
|
|
30
|
+
next if rules[:dont_store]
|
|
31
|
+
|
|
29
32
|
# All of these strings should already be validated (directly or
|
|
30
33
|
# indirectly) in `validate_prop_name`, so we don't bother with a nice
|
|
31
34
|
# error message, but we double check here to prevent a refactoring
|
|
32
35
|
# from introducing a security vulnerability.
|
|
33
|
-
raise unless T::Props::Decorator::SAFE_NAME.match?(prop.to_s)
|
|
36
|
+
raise unless T::Props::Decorator::SAFE_NAME.match?(CAN_USE_SYMBOL_NAME ? prop.name : prop.to_s)
|
|
34
37
|
|
|
35
38
|
hash_key = rules.fetch(:serialized_form)
|
|
36
39
|
raise unless T::Props::Decorator::SAFE_NAME.match?(hash_key)
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
key = rules.fetch(:accessor_key)
|
|
42
|
+
ivar_name = CAN_USE_SYMBOL_NAME ? key.name : key.to_s
|
|
43
|
+
raise unless ivar_name.start_with?('@') && T::Props::Decorator::SAFE_ACCESSOR_KEY_NAME.match?(ivar_name)
|
|
40
44
|
|
|
41
45
|
transformed_val = SerdeTransform.generate(
|
|
42
46
|
T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)),
|
|
@@ -121,8 +121,8 @@ module T::Props::Serializable
|
|
|
121
121
|
private def with_existing_hash(changed_props, existing_hash:)
|
|
122
122
|
serialized = existing_hash
|
|
123
123
|
new_val = self.class.from_hash(serialized.merge(recursive_stringify_keys(changed_props)))
|
|
124
|
-
old_extra = self.instance_variable_get(:@_extra_props)
|
|
125
|
-
new_extra = new_val.instance_variable_get(:@_extra_props)
|
|
124
|
+
old_extra = self.instance_variable_get(:@_extra_props)
|
|
125
|
+
new_extra = new_val.instance_variable_get(:@_extra_props)
|
|
126
126
|
if old_extra != new_extra
|
|
127
127
|
difference =
|
|
128
128
|
if old_extra
|
|
@@ -137,8 +137,7 @@ module T::Props::Serializable
|
|
|
137
137
|
|
|
138
138
|
# Asserts if this property is missing during strict serialize
|
|
139
139
|
private def required_prop_missing_from_serialize(prop)
|
|
140
|
-
if
|
|
141
|
-
@_required_props_missing_from_deserialize&.include?(prop)
|
|
140
|
+
if @_required_props_missing_from_deserialize&.include?(prop)
|
|
142
141
|
# If the prop was already missing during deserialization, that means the application
|
|
143
142
|
# code already had to deal with a nil value, which means we wouldn't be accomplishing
|
|
144
143
|
# much by raising here (other than causing an unnecessary breakage).
|
|
@@ -353,11 +352,7 @@ module T::Props::Serializable::DecoratorMethods
|
|
|
353
352
|
private_constant :EMPTY_EXTRA_PROPS
|
|
354
353
|
|
|
355
354
|
def extra_props(instance)
|
|
356
|
-
|
|
357
|
-
instance.instance_variable_get(:@_extra_props) || EMPTY_EXTRA_PROPS
|
|
358
|
-
else
|
|
359
|
-
EMPTY_EXTRA_PROPS
|
|
360
|
-
end
|
|
355
|
+
instance.instance_variable_get(:@_extra_props) || EMPTY_EXTRA_PROPS
|
|
361
356
|
end
|
|
362
357
|
|
|
363
358
|
# adds to the default result of T::Props::PrettyPrintable
|
data/lib/types/types/t_enum.rb
CHANGED
|
@@ -28,11 +28,11 @@ module T::Types
|
|
|
28
28
|
obj.is_a?(Set)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def new(
|
|
31
|
+
def new(...)
|
|
32
32
|
# Fine for this to blow up, because hopefully if they're trying to make a
|
|
33
33
|
# Set, they don't mind putting (or already have put) a `require 'set'` in
|
|
34
34
|
# their program directly.
|
|
35
|
-
Set.new(
|
|
35
|
+
Set.new(...)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
class Untyped < TypedSet
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sorbet-runtime
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.12652
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stripe
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|