Class: Jazzy::SymbolGraph::Graph
- Inherits:
-
Object
- Object
- Jazzy::SymbolGraph::Graph
- Defined in:
- lib/jazzy/symbol_graph/graph.rb
Overview
A Graph is the coordinator to import a symbolgraph json file. Deserialize it to Symbols and Relationships, then rebuild the AST shape using SymNodes and ExtNodes and extract SourceKit json.
Instance Attribute Summary collapse
-
#ext_module_name ⇒ Object
Module being extended.
-
#ext_nodes ⇒ Object
(usr, constraints) -> ExtNode.
-
#module_name ⇒ Object
Our module.
-
#relationships ⇒ Object
[Relationship].
-
#symbol_nodes ⇒ Object
usr -> SymNode.
Instance Method Summary collapse
- #add_ext_conformance(type_usr, type_name, protocol, constraints) ⇒ Object
-
#add_ext_member(type_usr, member_node, constraints) ⇒ Object
ExtNode index.
-
#initialize(json, module_name, ext_module_name) ⇒ Graph
constructor
Parse the JSON into flat tables of data.
-
#rebuild_conformance(rel, source, target) ⇒ Object
“source : target” either from type decl or ext decl.
-
#rebuild_default_implementation(_rel, source, target) ⇒ Object
“source is a default implementation of protocol requirement target”.
-
#rebuild_inherits(_rel, source, target) ⇒ Object
“source is a class that inherits from target”.
-
#rebuild_member(rel, source, target) ⇒ Object
source is a member/protocol requirement of target.
-
#rebuild_rel(rel) ⇒ Object
Process a structural relationship to link nodes.
-
#redundant_conformance?(rel, type, protocol) ⇒ Boolean
Protocol conformance is redundant if it’s unconditional and already expressed in the type’s declaration.
-
#rel_source_name(rel, source_node) ⇒ Object
Same for the source end.
-
#rel_target_name(rel, target_node) ⇒ Object
Increasingly desparate ways to find the name of the symbol at the target end of a relationship.
-
#to_sourcekit ⇒ Object
Rebuild the AST structure and convert to SourceKit.
-
#unalias_extensions(fake_usr, real_usr) ⇒ Object
“References to fake_usr should be real_usr”.
Constructor Details
#initialize(json, module_name, ext_module_name) ⇒ Graph
Parse the JSON into flat tables of data
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 17 def initialize(json, module_name, ext_module_name) self.module_name = module_name self.ext_module_name = ext_module_name graph = JSON.parse(json, symbolize_names: true) self.symbol_nodes = {} self.ext_nodes = {} graph[:symbols].each do |hash| symbol = Symbol.new(hash) if symbol.extension? node = ExtSymNode.new(symbol) ext_nodes[node.ext_key] = node else symbol_nodes[symbol.usr] = SymNode.new(symbol) end end self.relationships = graph[:relationships].map { |hash| Relationship.new(hash) } end |
Instance Attribute Details
#ext_module_name ⇒ Object
Module being extended
11 12 13 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 11 def ext_module_name @ext_module_name end |
#ext_nodes ⇒ Object
(usr, constraints) -> ExtNode
14 15 16 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 14 def ext_nodes @ext_nodes end |
#module_name ⇒ Object
Our module
10 11 12 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 10 def module_name @module_name end |
#relationships ⇒ Object
- Relationship
13 14 15 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 13 def relationships @relationships end |
#symbol_nodes ⇒ Object
usr -> SymNode
12 13 14 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 12 def symbol_nodes @symbol_nodes end |
Instance Method Details
#add_ext_conformance(type_usr, type_name, protocol, constraints) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 52 def add_ext_conformance(type_usr, type_name, protocol, constraints) key = ExtKey.new(type_usr, constraints.ext) if ext_node = ext_nodes[key] ext_node.add_conformance(protocol) else ext_nodes[key] = ExtNode.new_for_conformance(type_usr, type_name, protocol, constraints) end end |
#add_ext_member(type_usr, member_node, constraints) ⇒ Object
ExtNode index. ExtKey (type USR, extension constraints) -> ExtNode. This minimizes the number of extensions
42 43 44 45 46 47 48 49 50 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 42 def add_ext_member(type_usr, member_node, constraints) key = ExtKey.new(type_usr, constraints.ext) if ext_node = ext_nodes[key] ext_node.add_child(member_node) else ext_nodes[key] = ExtNode.new_for_member(type_usr, member_node, constraints) end end |
#rebuild_conformance(rel, source, target) ⇒ Object
“source : target” either from type decl or ext decl
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 109 def rebuild_conformance(rel, source, target) protocol_name = rel_target_name(rel, target) return if redundant_conformance?(rel, source, protocol_name) type_constraints = source&.constraints || [] constraints = ExtConstraints.new(type_constraints, rel.constraints - type_constraints) # Create an extension or enhance an existing one add_ext_conformance(rel.source_usr, rel_source_name(rel, source), protocol_name, constraints) end |
#rebuild_default_implementation(_rel, source, target) ⇒ Object
“source is a default implementation of protocol requirement target”
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 127 def rebuild_default_implementation(_rel, source, target) return unless source unless target && (target_parent = target.parent) && target_parent.is_a?(SymNode) # Could probably figure this out with demangle, but... warn "Can't resolve membership of default implementation " \ "#{source.symbol.usr}." source.unlisted = true return end constraints = ExtConstraints.new(target_parent.constraints, source.unique_context_constraints(target_parent)) add_ext_member(target_parent.symbol.usr, source, constraints) end |
#rebuild_inherits(_rel, source, target) ⇒ Object
“source is a class that inherits from target”
149 150 151 152 153 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 149 def rebuild_inherits(_rel, source, target) if source && target source.superclass_name = target.symbol.name end end |
#rebuild_member(rel, source, target) ⇒ Object
source is a member/protocol requirement of target
94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 94 def rebuild_member(rel, source, target) return unless source source.protocol_requirement = rel.protocol_requirement? constraints = ExtConstraints.new(target&.constraints, source.unique_context_constraints(target)) # Add to its parent or invent an extension unless target&.try_add_child(source, constraints.ext) add_ext_member(rel.target_usr, source, constraints) end end |
#rebuild_rel(rel) ⇒ Object
Process a structural relationship to link nodes
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 165 def rebuild_rel(rel) source = symbol_nodes[rel.source_usr] target = symbol_nodes[rel.target_usr] case rel.kind when :memberOf, :optionalRequirementOf, :requirementOf rebuild_member(rel, source, target) when :conformsTo rebuild_conformance(rel, source, target) when :defaultImplementationOf rebuild_default_implementation(rel, source, target) when :inheritsFrom rebuild_inherits(rel, source, target) when :extensionTo unalias_extensions(rel.source_usr, rel.target_usr) end # don't seem to care about: # - overrides: not bothered, also unimplemented for protocols end |
#redundant_conformance?(rel, type, protocol) ⇒ Boolean
Protocol conformance is redundant if it’s unconditional and already expressed in the type’s declaration.
Skip implementation-detail conformances.
86 87 88 89 90 91 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 86 def redundant_conformance?(rel, type, protocol) return false unless type (rel.constraints.empty? && type.conformance?(protocol)) || (type.actor? && rel.actor_protocol?) end |
#rel_source_name(rel, source_node) ⇒ Object
Same for the source end. Less help from the tool here
77 78 79 80 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 77 def rel_source_name(rel, source_node) source_node&.qualified_name || Jazzy::SymbolGraph.demangle(rel.source_usr) end |
#rel_target_name(rel, target_node) ⇒ Object
Increasingly desparate ways to find the name of the symbol at the target end of a relationship
70 71 72 73 74 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 70 def rel_target_name(rel, target_node) target_node&.symbol&.name || rel.target_fallback || Jazzy::SymbolGraph.demangle(rel.target_usr) end |
#to_sourcekit ⇒ Object
Rebuild the AST structure and convert to SourceKit
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 191 def to_sourcekit relationships.sort.each { |r| rebuild_rel(r) } root_symbol_nodes = symbol_nodes.values .select(&:top_level_decl?) .sort .map { |n| n.to_sourcekit(module_name) } root_ext_nodes = ext_nodes.values .sort .map { |n| n.to_sourcekit(module_name, ext_module_name) } { 'key.diagnostic_stage' => 'parse', 'key.substructure' => root_symbol_nodes + root_ext_nodes, } end |
#unalias_extensions(fake_usr, real_usr) ⇒ Object
“References to fake_usr should be real_usr”
156 157 158 159 160 161 162 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 156 def unalias_extensions(fake_usr, real_usr) ext_nodes.each_pair do |key, ext| if key.usr == fake_usr ext.real_usr = real_usr end end end |