sord 0.7.1 → 0.8.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.
@@ -0,0 +1,82 @@
1
+ require 'stringio'
2
+
3
+ module Sord
4
+ module Resolver
5
+ # @return [void]
6
+ def self.prepare
7
+ # Construct a hash of class names to full paths
8
+ @@names_to_paths ||= YARD::Registry.all(:class)
9
+ .group_by(&:name)
10
+ .map { |k, v| [k.to_s, v.map(&:path)] }
11
+ .to_h
12
+ .merge(builtin_classes.map { |x| [x, [x]] }.to_h) do |k, a, b|
13
+ a | b
14
+ end
15
+ end
16
+
17
+ # @return [void]
18
+ def self.clear
19
+ @@names_to_paths = nil
20
+ end
21
+
22
+ # @param [String] name
23
+ # @return [Array<String>]
24
+ def self.paths_for(name)
25
+ prepare
26
+ (@@names_to_paths[name.split('::').last] || [])
27
+ .select { |x| x.end_with?(name) }
28
+ end
29
+
30
+ # @param [String] name
31
+ # @return [String, nil]
32
+ def self.path_for(name)
33
+ paths_for(name).one? ? paths_for(name).first : nil
34
+ end
35
+
36
+ # @return [Array<String>]
37
+ def self.builtin_classes
38
+ # This prints some deprecation warnings, so suppress them
39
+ prev_stderr = $stderr
40
+ $stderr = StringIO.new
41
+
42
+ Object.constants
43
+ .select { |x| Object.const_get(x).is_a?(Class) }
44
+ .map(&:to_s)
45
+ ensure
46
+ $stderr = prev_stderr
47
+ end
48
+
49
+ # @param [String] name
50
+ # @param [Object] item
51
+ # @return [Boolean]
52
+ def self.resolvable?(name, item)
53
+ name_parts = name.split('::')
54
+
55
+ current_context = item
56
+ current_context = current_context.parent \
57
+ until current_context.is_a?(YARD::CodeObjects::NamespaceObject)
58
+
59
+ matching_paths = []
60
+
61
+ loop do
62
+ # Try to find that class in this context
63
+ path_followed_context = current_context
64
+ name_parts.each do |name_part|
65
+ path_followed_context = path_followed_context&.child(
66
+ name: name_part, type: [:class, :method, :module]
67
+ )
68
+ end
69
+
70
+ # Return true if we found the constant we're looking for here
71
+ matching_paths |= [path_followed_context.path] if path_followed_context
72
+
73
+ # Move up one context
74
+ break if current_context.root?
75
+ current_context = current_context.parent
76
+ end
77
+
78
+ return (builtin_classes.include?(name) && matching_paths.empty?) ||
79
+ (matching_paths.one? && !builtin_classes.include?(name))
80
+ end
81
+ end
82
+ end
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'sord/logging'
3
+ require 'sord/resolver'
3
4
 
4
5
  module Sord
5
6
  # Contains methods to convert YARD types to Sorbet types.
@@ -21,14 +22,22 @@ module Sord
21
22
  # Match duck types which require the object implement one or more methods,
22
23
  # like '#foo', '#foo & #bar', '#foo&#bar&#baz', and '#foo&#bar&#baz&#foo_bar'.
23
24
  DUCK_TYPE_REGEX =
24
- /^\##{SIMPLE_TYPE_REGEX}(?:( ?\& ?\#)*[a-zA-Z_][a-zA-Z_0-9]*)*$/
25
+ /^\#[a-zA-Z_][\w]*(?:[a-zA-Z_][\w=]*)*(?:( ?\& ?\#)*[a-zA-Z_][\w=]*)*$/
25
26
 
26
27
  # A regular expression which matches ordered lists in the format of
27
28
  # either "Array(String, Symbol)" or "(String, Symbol)".
28
29
  ORDERED_LIST_REGEX = /^(?:Array|)\((.*)\s*\)$/
29
30
 
31
+ # A regular expression which matches the shorthand Hash syntax,
32
+ # "{String => Symbol}".
33
+ SHORTHAND_HASH_SYNTAX = /^{\s*(.*)\s*}$/
34
+
35
+ # A regular expression which matches the shorthand Array syntax,
36
+ # "<String>".
37
+ SHORTHAND_ARRAY_SYNTAX = /^<\s*(.*)\s*>$/
38
+
30
39
  # An array of built-in generic types supported by Sorbet.
31
- SORBET_SUPPORTED_GENERIC_TYPES = %w{Array Set Enumerable Enumerator Range Hash}
40
+ SORBET_SUPPORTED_GENERIC_TYPES = %w{Array Set Enumerable Enumerator Range Hash Class}
32
41
  SORBET_SINGLE_ARG_GENERIC_TYPES = %w{Array Set Enumerable Enumerator Range}
33
42
 
34
43
  # Given a string of YARD type parameters (without angle brackets), splits
@@ -85,7 +94,11 @@ module Sord
85
94
  # @param [YARD::CodeObjects::Base] item The CodeObject which the YARD type
86
95
  # is associated with. This is used for logging and can be nil, but this
87
96
  # will lead to less informative log messages.
88
- def self.yard_to_sorbet(yard, item=nil)
97
+ # @param [Integer] indent_level
98
+ # @param [Boolean] replace_errors_with_untyped If true, T.untyped is used
99
+ # instead of SORD_ERROR_ constants for unknown types.
100
+ # @return [String]
101
+ def self.yard_to_sorbet(yard, item = nil, indent_level = 0, replace_errors_with_untyped = false)
89
102
  case yard
90
103
  when nil # Type not specified
91
104
  "T.untyped"
@@ -98,7 +111,7 @@ module Sord
98
111
  # selection of any of the types
99
112
  types = yard
100
113
  .reject { |x| x == 'nil' }
101
- .map { |x| yard_to_sorbet(x, item) }
114
+ .map { |x| yard_to_sorbet(x, item, indent_level, replace_errors_with_untyped) }
102
115
  .uniq
103
116
  result = types.length == 1 ? types.first : "T.any(#{types.join(', ')})"
104
117
  result = "T.nilable(#{result})" if yard.include?('nil')
@@ -106,11 +119,26 @@ module Sord
106
119
  when /^#{SIMPLE_TYPE_REGEX}$/
107
120
  # If this doesn't begin with an uppercase letter, warn
108
121
  if /^[_a-z]/ === yard
109
- Logging.warn("#{yard} is probably not a type, but using anyway", item)
122
+ Logging.warn("#{yard} is probably not a type, but using anyway", item, indent_level)
123
+ end
124
+
125
+ # Check if whatever has been specified is actually resolvable; if not,
126
+ # do some inference to replace it
127
+ if item && !Resolver.resolvable?(yard, item)
128
+ if Resolver.path_for(yard)
129
+ new_path = Resolver.path_for(yard)
130
+ Logging.infer("#{yard} was resolved to #{new_path}", item, indent_level) \
131
+ unless yard == new_path
132
+ new_path
133
+ else
134
+ Logging.warn("#{yard} wasn't able to be resolved to a constant in this project", item, indent_level)
135
+ yard
136
+ end
137
+ else
138
+ yard
110
139
  end
111
- yard
112
140
  when DUCK_TYPE_REGEX
113
- Logging.duck("#{yard} looks like a duck type, replacing with T.untyped", item)
141
+ Logging.duck("#{yard} looks like a duck type, replacing with T.untyped", item, indent_level)
114
142
  'T.untyped'
115
143
  when /^#{GENERIC_TYPE_REGEX}$/
116
144
  generic_type = $1
@@ -118,31 +146,45 @@ module Sord
118
146
 
119
147
  if SORBET_SUPPORTED_GENERIC_TYPES.include?(generic_type)
120
148
  parameters = split_type_parameters(type_parameters)
121
- .map { |x| yard_to_sorbet(x, item) }
149
+ .map { |x| yard_to_sorbet(x, item, indent_level, replace_errors_with_untyped) }
122
150
  if SORBET_SINGLE_ARG_GENERIC_TYPES.include?(generic_type) && parameters.length > 1
123
151
  "T::#{generic_type}[T.any(#{parameters.join(', ')})]"
152
+ elsif generic_type == 'Class' && parameters.length == 1
153
+ "T.class_of(#{parameters.first})"
124
154
  else
125
155
  "T::#{generic_type}[#{parameters.join(', ')}]"
126
156
  end
127
157
  else
128
- Logging.warn("unsupported generic type #{generic_type.inspect} in #{yard.inspect}", item)
129
- "SORD_ERROR_#{generic_type.gsub(/[^0-9A-Za-z_]/i, '')}"
158
+ Logging.warn("unsupported generic type #{generic_type.inspect} in #{yard.inspect}", item, indent_level)
159
+ replace_errors_with_untyped ? "T.untyped" : "SORD_ERROR_#{generic_type.gsub(/[^0-9A-Za-z_]/i, '')}"
130
160
  end
131
161
  # Converts ordered lists like Array(Symbol, String) or (Symbol, String)
132
162
  # into Sorbet Tuples like [Symbol, String].
133
163
  when ORDERED_LIST_REGEX
134
164
  type_parameters = $1
135
165
  parameters = split_type_parameters(type_parameters)
136
- .map { |x| yard_to_sorbet(x, item) }
166
+ .map { |x| yard_to_sorbet(x, item, indent_level, replace_errors_with_untyped) }
137
167
  "[#{parameters.join(', ')}]"
168
+ when SHORTHAND_HASH_SYNTAX
169
+ type_parameters = $1
170
+ parameters = split_type_parameters(type_parameters)
171
+ .map { |x| yard_to_sorbet(x, item, indent_level, replace_errors_with_untyped) }
172
+ "T::Hash<#{parameters.join(', ')}>"
173
+ when SHORTHAND_ARRAY_SYNTAX
174
+ type_parameters = $1
175
+ parameters = split_type_parameters(type_parameters)
176
+ .map { |x| yard_to_sorbet(x, item, indent_level, replace_errors_with_untyped) }
177
+ parameters.one? \
178
+ ? "T::Array<#{parameters.first}>"
179
+ : "T::Array<T.any(#{parameters.join(', ')})>"
138
180
  else
139
181
  # Check for literals
140
182
  from_yaml = YAML.load(yard) rescue nil
141
183
  return from_yaml.class.to_s \
142
184
  if [Symbol, Float, Integer].include?(from_yaml.class)
143
185
 
144
- Logging.warn("#{yard.inspect} does not appear to be a type", item)
145
- "SORD_ERROR_#{yard.gsub(/[^0-9A-Za-z_]/i, '')}"
186
+ Logging.warn("#{yard.inspect} does not appear to be a type", item, indent_level)
187
+ replace_errors_with_untyped ? "T.untyped" : "SORD_ERROR_#{yard.gsub(/[^0-9A-Za-z_]/i, '')}"
146
188
  end
147
189
  end
148
190
  end
@@ -1,4 +1,4 @@
1
1
  # typed: strong
2
2
  module Sord
3
- VERSION = '0.7.1'
3
+ VERSION = '0.8.0'
4
4
  end
@@ -0,0 +1,165 @@
1
+ # typed: strong
2
+ module Sord
3
+ module Logging
4
+ sig { returns(T::Array[Proc]) }
5
+ def self.hooks(); end
6
+
7
+ sig { returns(T::Boolean) }
8
+ def self.silent?(); end
9
+
10
+ sig { params(value: T::Boolean).void }
11
+ def self.silent=(value); end
12
+
13
+ sig { params(value: T::Array[Symbol]).void }
14
+ def self.enabled_types=(value); end
15
+
16
+ sig { returns(T::Array[Symbol]) }
17
+ def self.enabled_types(); end
18
+
19
+ sig { params(value: T::Array[Symbol]).void }
20
+ def self.valid_types?(value); end
21
+
22
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
23
+ sig do
24
+ params(
25
+ kind: Symbol,
26
+ header: String,
27
+ msg: String,
28
+ item: YARD::CodeObjects::Base,
29
+ indent_level: Integer
30
+ ).void
31
+ end
32
+ def self.generic(kind, header, msg, item, indent_level = 0); end
33
+
34
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
35
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
36
+ def self.warn(msg, item = nil, indent_level = 0); end
37
+
38
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
39
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
40
+ def self.info(msg, item = nil, indent_level = 0); end
41
+
42
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
43
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
44
+ def self.duck(msg, item = nil, indent_level = 0); end
45
+
46
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
47
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
48
+ def self.error(msg, item = nil, indent_level = 0); end
49
+
50
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
51
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
52
+ def self.infer(msg, item = nil, indent_level = 0); end
53
+
54
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
55
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
56
+ def self.omit(msg, item = nil, indent_level = 0); end
57
+
58
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
59
+ sig { params(msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void }
60
+ def self.done(msg, item = nil, indent_level = 0); end
61
+
62
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
63
+ sig do
64
+ params(
65
+ kind: Symbol,
66
+ msg: String,
67
+ item: YARD::CodeObjects::Base,
68
+ indent_level: Integer
69
+ ).void
70
+ end
71
+ def self.invoke_hooks(kind, msg, item, indent_level = 0); end
72
+
73
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
74
+ sig { params(blk: T.proc.params(kind: Symbol, msg: String, item: YARD::CodeObjects::Base, indent_level: Integer).void).void }
75
+ def self.add_hook(&blk); end
76
+ end
77
+
78
+ module Resolver
79
+ sig { void }
80
+ def self.prepare(); end
81
+
82
+ sig { void }
83
+ def self.clear(); end
84
+
85
+ sig { params(name: String).returns(T::Array[String]) }
86
+ def self.paths_for(name); end
87
+
88
+ sig { params(name: String).returns(T.nilable(String)) }
89
+ def self.path_for(name); end
90
+
91
+ sig { returns(T::Array[String]) }
92
+ def self.builtin_classes(); end
93
+
94
+ sig { params(name: String, item: Object).returns(T::Boolean) }
95
+ def self.resolvable?(name, item); end
96
+ end
97
+
98
+ class RbiGenerator
99
+ sig { returns(T::Array[String]) }
100
+ def rbi_contents(); end
101
+
102
+ sig { returns(Integer) }
103
+ def object_count(); end
104
+
105
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
106
+ sig { returns(T::Array[[String, YARD::CodeObjects::Base, Integer]]) }
107
+ def warnings(); end
108
+
109
+ sig { returns(T::Boolean) }
110
+ def next_item_is_first_in_namespace(); end
111
+
112
+ # sord infer - inferred type of parameter "value" as T::Boolean using getter's return type
113
+ sig { params(value: T::Boolean).returns(T::Boolean) }
114
+ def next_item_is_first_in_namespace=(value); end
115
+
116
+ sig { params(options: Hash).void }
117
+ def initialize(options); end
118
+
119
+ sig { void }
120
+ def count_namespace(); end
121
+
122
+ sig { void }
123
+ def count_method(); end
124
+
125
+ sig { void }
126
+ def add_blank(); end
127
+
128
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
129
+ sig { params(item: YARD::CodeObjects::Base, indent_level: Integer).returns(Integer) }
130
+ def add_mixins(item, indent_level); end
131
+
132
+ sig { params(params: T::Array[String], returns: String, indent_level: Integer).void }
133
+ def add_signature(params, returns, indent_level); end
134
+
135
+ # sord warn - YARD::CodeObjects::NamespaceObject wasn't able to be resolved to a constant in this project
136
+ sig { params(item: YARD::CodeObjects::NamespaceObject, indent_level: Integer).void }
137
+ def add_methods(item, indent_level); end
138
+
139
+ # sord warn - YARD::CodeObjects::NamespaceObject wasn't able to be resolved to a constant in this project
140
+ sig { params(item: YARD::CodeObjects::NamespaceObject, indent_level: Integer).void }
141
+ def add_namespace(item, indent_level = 0); end
142
+
143
+ sig { returns(String) }
144
+ def generate(); end
145
+
146
+ sig { params(filename: T.nilable(String)).void }
147
+ def run(filename); end
148
+ end
149
+
150
+ module TypeConverter
151
+ sig { params(params: String).returns(T::Array[String]) }
152
+ def self.split_type_parameters(params); end
153
+
154
+ # sord warn - YARD::CodeObjects::Base wasn't able to be resolved to a constant in this project
155
+ sig do
156
+ params(
157
+ yard: T.any(T::Boolean, Array, String),
158
+ item: YARD::CodeObjects::Base,
159
+ indent_level: Integer,
160
+ replace_errors_with_untyped: T::Boolean
161
+ ).returns(String)
162
+ end
163
+ def self.yard_to_sorbet(yard, item = nil, indent_level = 0, replace_errors_with_untyped = false); end
164
+ end
165
+ end
@@ -1,2 +0,0 @@
1
- --dir
2
- .
@@ -0,0 +1,81 @@
1
+ # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2
+ # srb rbi gems
3
+
4
+ # typed: true
5
+ #
6
+ # If you would like to make changes to this file, great! Please create the gem's shim here:
7
+ #
8
+ # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/colorize/all/colorize.rbi
9
+ #
10
+ # colorize-0.8.1
11
+ module Colorize
12
+ end
13
+ module Colorize::ClassMethods
14
+ def color_codes; end
15
+ def color_matrix(_ = nil); end
16
+ def color_methods; end
17
+ def color_samples; end
18
+ def colors; end
19
+ def disable_colorization(value = nil); end
20
+ def disable_colorization=(value); end
21
+ def mode_codes; end
22
+ def modes; end
23
+ def modes_methods; end
24
+ end
25
+ module Colorize::InstanceMethods
26
+ def background_color(color); end
27
+ def color(color); end
28
+ def color_from_symbol(match, symbol); end
29
+ def colorize(params); end
30
+ def colorized?; end
31
+ def colors_from_hash(match, hash); end
32
+ def colors_from_params(match, params); end
33
+ def defaults_colors(match); end
34
+ def mode(mode); end
35
+ def require_windows_libs; end
36
+ def scan_for_colors; end
37
+ def split_colors(match); end
38
+ def uncolorize; end
39
+ end
40
+ class String
41
+ def black; end
42
+ def blink; end
43
+ def blue; end
44
+ def bold; end
45
+ def cyan; end
46
+ def green; end
47
+ def hide; end
48
+ def italic; end
49
+ def light_black; end
50
+ def light_blue; end
51
+ def light_cyan; end
52
+ def light_green; end
53
+ def light_magenta; end
54
+ def light_red; end
55
+ def light_white; end
56
+ def light_yellow; end
57
+ def magenta; end
58
+ def on_black; end
59
+ def on_blue; end
60
+ def on_cyan; end
61
+ def on_green; end
62
+ def on_light_black; end
63
+ def on_light_blue; end
64
+ def on_light_cyan; end
65
+ def on_light_green; end
66
+ def on_light_magenta; end
67
+ def on_light_red; end
68
+ def on_light_white; end
69
+ def on_light_yellow; end
70
+ def on_magenta; end
71
+ def on_red; end
72
+ def on_white; end
73
+ def on_yellow; end
74
+ def red; end
75
+ def swap; end
76
+ def underline; end
77
+ def white; end
78
+ def yellow; end
79
+ extend Colorize::ClassMethods
80
+ include Colorize::InstanceMethods
81
+ end