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_nodes ⇒ Object
(usr, constraints) -> ExtNode.
-
#module_name ⇒ Object
Returns the value of attribute module_name.
-
#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
-
#ext_key(usr, constraints) ⇒ Object
ExtNode index.
-
#initialize(json, 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.
Constructor Details
#initialize(json, module_name) ⇒ Graph
Parse the JSON into flat tables of data
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 16 def initialize(json, module_name) self.module_name = module_name graph = JSON.parse(json, symbolize_names: true) self.symbol_nodes = {} graph[:symbols].each do |hash| symbol = Symbol.new(hash) symbol_nodes[symbol.usr] = SymNode.new(symbol) end self.relationships = graph[:relationships].map { |hash| Relationship.new(hash) } self.ext_nodes = {} end |
Instance Attribute Details
#ext_nodes ⇒ Object
(usr, constraints) -> ExtNode
13 14 15 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 13 def ext_nodes @ext_nodes end |
#module_name ⇒ Object
Returns the value of attribute module_name.
10 11 12 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 10 def module_name @module_name end |
#relationships ⇒ Object
- Relationship
12 13 14 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 12 def relationships @relationships end |
#symbol_nodes ⇒ Object
usr -> SymNode
11 12 13 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 11 def symbol_nodes @symbol_nodes end |
Instance Method Details
#add_ext_conformance(type_usr, type_name, protocol, constraints) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 49 def add_ext_conformance(type_usr, type_name, protocol, constraints) key = ext_key(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
39 40 41 42 43 44 45 46 47 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 39 def add_ext_member(type_usr, member_node, constraints) key = ext_key(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 |
#ext_key(usr, constraints) ⇒ Object
ExtNode index. (type USR, extension constraints) -> ExtNode. This minimizes the number of extensions
35 36 37 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 35 def ext_key(usr, constraints) usr + constraints.map(&:to_swift).join end |
#rebuild_conformance(rel, source, target) ⇒ Object
“source : target” either from type decl or ext decl
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 106 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”
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 124 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”
146 147 148 149 150 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 146 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
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 91 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
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 153 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) 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.
83 84 85 86 87 88 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 83 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
74 75 76 77 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 74 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
67 68 69 70 71 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 67 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
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/jazzy/symbol_graph/graph.rb', line 175 def to_sourcekit # Do default impls after the others so we can find protocol # type nodes from protocol requirements. default_impls, other_rels = relationships.partition(&:default_implementation?) (other_rels + default_impls).each { |r| rebuild_rel(r) } root_symbol_nodes = symbol_nodes.values .select(&:top_level_decl?) .sort .map(&:to_sourcekit) root_ext_nodes = ext_nodes.values .sort .map { |n| n.to_sourcekit(module_name) } { 'key.diagnostic_stage' => 'parse', 'key.substructure' => root_symbol_nodes + root_ext_nodes, } end |