Class: Steep::Services::TypeNameCompletion

Inherits:
Object
  • Object
show all
Defined in:
lib/steep/services/type_name_completion.rb

Defined Under Namespace

Modules: Prefix

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env:, context:, dirs:) ⇒ TypeNameCompletion

Returns a new instance of TypeNameCompletion.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/steep/services/type_name_completion.rb', line 54

def initialize(env:, context:, dirs:)
  @env = env
  @context = context

  table = RBS::Environment::UseMap::Table.new()
  table.known_types.merge(env.class_decls.keys)
  table.known_types.merge(env.class_alias_decls.keys)
  table.known_types.merge(env.type_alias_decls.keys)
  table.known_types.merge(env.interface_decls.keys)
  table.compute_children

  @map = RBS::Environment::UseMap.new(table: table)
  dirs.each do |dir|
    dir.clauses.each do |clause|
      @map.build_map(clause)
    end
  end

  @type_name_resolver = RBS::Resolver::TypeNameResolver.new(env)
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



52
53
54
# File 'lib/steep/services/type_name_completion.rb', line 52

def context
  @context
end

#envObject (readonly)

Returns the value of attribute env.



52
53
54
# File 'lib/steep/services/type_name_completion.rb', line 52

def env
  @env
end

#mapObject (readonly)

Returns the value of attribute map.



52
53
54
# File 'lib/steep/services/type_name_completion.rb', line 52

def map
  @map
end

#type_name_resolverObject (readonly)

Returns the value of attribute type_name_resolver.



52
53
54
# File 'lib/steep/services/type_name_completion.rb', line 52

def type_name_resolver
  @type_name_resolver
end

Instance Method Details

#each_outer_module(context = self.context, &block) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/steep/services/type_name_completion.rb', line 75

def each_outer_module(context = self.context, &block)
  if block
    if (parent, con = context)
      namespace = each_outer_module(parent, &block)
      case con
      when false
        namespace
      when RBS::TypeName
        ns = con.with_prefix(namespace).to_namespace
        yield(ns)
        ns
      end
    else
      yield(RBS::Namespace.root)
      RBS::Namespace.root
    end
  else
    enum_for :each_outer_module
  end
end

#each_type_name(&block) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/steep/services/type_name_completion.rb', line 96

def each_type_name(&block)
  if block
    env = self.env

    table = {} #: Hash[RBS::Namespace, Array[RBS::TypeName]]
    env.class_decls.each_key do |type_name|
      yield(type_name)
      (table[type_name.namespace] ||= []) << type_name
    end
    env.type_alias_decls.each_key do |type_name|
      yield(type_name)
      (table[type_name.namespace] ||= []) << type_name
    end
    env.interface_decls.each_key do |type_name|
      yield(type_name)
      (table[type_name.namespace] ||= []) << type_name
    end
    env.class_alias_decls.each_key do |type_name|
      yield(type_name)
      (table[type_name.namespace] ||= []) << type_name
    end

    env.class_alias_decls.each_key do |alias_name|
      normalized_name = env.normalize_module_name?(alias_name) or next
      each_type_name_under(alias_name, normalized_name, table: table, &block)
    end

    resolve_pairs = [] #: Array[[RBS::TypeName, RBS::TypeName]]

    map.instance_eval do
      @map.each_key do |name|
        relative_name = RBS::TypeName.new(name: name, namespace: RBS::Namespace.empty)
        if absolute_name = resolve?(relative_name)
          if env.type_name?(absolute_name)
            # Yields only if the relative type name resolves to existing absolute type name
            resolve_pairs << [relative_name, absolute_name]
          end
        end
      end
    end

    resolve_pairs.each do |use_name, absolute_name|
      yield use_name
      each_type_name_under(use_name, absolute_name, table: table, &block)
    end
  else
    enum_for :each_type_name
  end
end

#each_type_name_under(module_name, normalized_name, table:, &block) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/steep/services/type_name_completion.rb', line 146

def each_type_name_under(module_name, normalized_name, table:, &block)
  if children = table.fetch(normalized_name.to_namespace, nil)
    module_namespace = module_name.to_namespace

    children.each do |normalized_child_name|
      child_name = RBS::TypeName.new(namespace: module_namespace, name: normalized_child_name.name)

      yield child_name

      if normalized_child_name.class?
        each_type_name_under(child_name, env.normalize_module_name(normalized_child_name), table: table, &block)
      end
    end
  end
end

#find_type_names(prefix) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/steep/services/type_name_completion.rb', line 206

def find_type_names(prefix)
  case prefix
  when Prefix::RawIdentPrefix
    each_type_name.filter do |type_name|
      type_name.split.any? {|sym| sym.to_s.downcase.include?(prefix.ident.downcase) }
    end
  when Prefix::NamespacedIdentPrefix
    absolute_namespace =
      if prefix.namespace.empty?
        RBS::Namespace.root
      else
        type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
      end

    each_type_name.filter do|name|
      name.namespace == absolute_namespace &&
        name.name.to_s.downcase.include?(prefix.ident.downcase)
    end
  when Prefix::NamespacePrefix
    absolute_namespace = type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
    each_type_name.filter {|name| name.namespace == absolute_namespace }
  else
    # Returns all of the accessible type names from the context
    namespaces = each_outer_module.to_set
    # Relative type name means a *use*d type name
    each_type_name.filter {|name| namespaces.include?(name.namespace) || !name.absolute? }
  end
end

#resolve_name_in_context(name) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/steep/services/type_name_completion.rb', line 180

def resolve_name_in_context(name)
  if resolved_name = resolve_used_name(name)
    return [resolved_name, name]
  end

  name.absolute? or raise
  normalized_name = env.normalize_type_name?(name) or raise "Cannot normalize given type name `#{name}`"

  name.namespace.path.reverse_each.inject(RBS::TypeName.new(namespace: RBS::Namespace.empty, name: name.name)) do |relative_name, component|
    if type_name_resolver.resolve(relative_name, context: context) == name
      return [normalized_name, relative_name]
    end

    RBS::TypeName.new(
      namespace: RBS::Namespace.new(path: [component, *relative_name.namespace.path], absolute: false),
      name: name.name
    )
  end

  if type_name_resolver.resolve(name.relative!, context: context) == name && !resolve_used_name(name.relative!)
    [normalized_name, name.relative!]
  else
    [normalized_name, name]
  end
end

#resolve_used_name(name) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/steep/services/type_name_completion.rb', line 162

def resolve_used_name(name)
  return nil if name.absolute?

  case
  when resolved = map.resolve?(name)
    resolved
  when name.namespace.empty?
    nil
  else
    if resolved_parent = resolve_used_name(name.namespace.to_type_name)
      resolved_name = RBS::TypeName.new(namespace: resolved_parent.to_namespace, name: name.name)
      if env.normalize_type_name?(resolved_name)
        resolved_name
      end
    end
  end
end