jazzy 0.13.2 → 0.13.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/Tests.yml +52 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +118 -0
  5. data/CONTRIBUTING.md +5 -5
  6. data/Gemfile.lock +68 -59
  7. data/README.md +65 -5
  8. data/Rakefile +30 -0
  9. data/bin/sourcekitten +0 -0
  10. data/js/package-lock.json +44 -0
  11. data/js/package.json +17 -0
  12. data/lib/jazzy/config.rb +29 -8
  13. data/lib/jazzy/doc_builder.rb +14 -2
  14. data/lib/jazzy/docset_builder.rb +2 -0
  15. data/lib/jazzy/docset_builder/info_plist.mustache +8 -0
  16. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_AMS-Regular.ttf +0 -0
  17. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_AMS-Regular.woff +0 -0
  18. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  19. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  20. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  21. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  22. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  23. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  24. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  25. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  26. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  27. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  28. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  29. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  30. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  31. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Bold.ttf +0 -0
  32. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Bold.woff +0 -0
  33. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Bold.woff2 +0 -0
  34. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  35. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  36. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  37. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Italic.ttf +0 -0
  38. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Italic.woff +0 -0
  39. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Italic.woff2 +0 -0
  40. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Regular.ttf +0 -0
  41. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Regular.woff +0 -0
  42. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Main-Regular.woff2 +0 -0
  43. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  44. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  45. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  46. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-Italic.ttf +0 -0
  47. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-Italic.woff +0 -0
  48. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Math-Italic.woff2 +0 -0
  49. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  50. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  51. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  52. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  53. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  54. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  55. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  56. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  57. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  58. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Script-Regular.ttf +0 -0
  59. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Script-Regular.woff +0 -0
  60. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Script-Regular.woff2 +0 -0
  61. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size1-Regular.ttf +0 -0
  62. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size1-Regular.woff +0 -0
  63. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  64. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size2-Regular.ttf +0 -0
  65. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size2-Regular.woff +0 -0
  66. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  67. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size3-Regular.ttf +0 -0
  68. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size3-Regular.woff +0 -0
  69. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  70. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size4-Regular.ttf +0 -0
  71. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size4-Regular.woff +0 -0
  72. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  73. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  74. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  75. data/lib/jazzy/extensions/katex/css/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  76. data/lib/jazzy/extensions/katex/css/katex.min.css +1 -1
  77. data/lib/jazzy/extensions/katex/js/katex.min.js +1 -1
  78. data/lib/jazzy/gem_version.rb +1 -1
  79. data/lib/jazzy/jazzy_markdown.rb +38 -0
  80. data/lib/jazzy/podspec_documenter.rb +15 -3
  81. data/lib/jazzy/source_declaration.rb +15 -2
  82. data/lib/jazzy/source_declaration/type.rb +30 -0
  83. data/lib/jazzy/source_module.rb +2 -1
  84. data/lib/jazzy/sourcekitten.rb +11 -11
  85. data/lib/jazzy/symbol_graph.rb +95 -0
  86. data/lib/jazzy/symbol_graph/constraint.rb +94 -0
  87. data/lib/jazzy/symbol_graph/ext_node.rb +114 -0
  88. data/lib/jazzy/symbol_graph/graph.rb +193 -0
  89. data/lib/jazzy/symbol_graph/relationship.rb +39 -0
  90. data/lib/jazzy/symbol_graph/sym_node.rb +158 -0
  91. data/lib/jazzy/symbol_graph/symbol.rb +219 -0
  92. data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +96 -3
  93. data/lib/jazzy/themes/apple/assets/img/spinner.gif +0 -0
  94. data/lib/jazzy/themes/apple/assets/js/jazzy.search.js +70 -0
  95. data/lib/jazzy/themes/apple/assets/js/jquery.min.js +2 -2
  96. data/lib/jazzy/themes/apple/assets/js/lunr.min.js +6 -0
  97. data/lib/jazzy/themes/apple/assets/js/typeahead.jquery.js +1694 -0
  98. data/lib/jazzy/themes/apple/templates/doc.mustache +35 -0
  99. data/lib/jazzy/themes/apple/templates/header.mustache +7 -0
  100. data/lib/jazzy/themes/apple/templates/task.mustache +1 -1
  101. data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +5 -0
  102. data/lib/jazzy/themes/fullwidth/assets/js/jquery.min.js +2 -2
  103. data/lib/jazzy/themes/fullwidth/assets/js/lunr.min.js +6 -1
  104. data/lib/jazzy/themes/fullwidth/assets/js/typeahead.jquery.js +34 -14
  105. data/lib/jazzy/themes/fullwidth/templates/doc.mustache +30 -0
  106. data/lib/jazzy/themes/fullwidth/templates/task.mustache +1 -1
  107. data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +29 -1
  108. data/lib/jazzy/themes/jony/assets/js/jquery.min.js +2 -2
  109. data/lib/jazzy/themes/jony/templates/doc.mustache +30 -0
  110. data/lib/jazzy/themes/jony/templates/task.mustache +1 -1
  111. data/spec/integration_spec.rb +17 -8
  112. metadata +20 -8
  113. data/.circleci/config.yml +0 -83
@@ -0,0 +1,95 @@
1
+ require 'set'
2
+ require 'jazzy/symbol_graph/graph'
3
+ require 'jazzy/symbol_graph/constraint'
4
+ require 'jazzy/symbol_graph/symbol'
5
+ require 'jazzy/symbol_graph/relationship'
6
+ require 'jazzy/symbol_graph/sym_node'
7
+ require 'jazzy/symbol_graph/ext_node'
8
+
9
+ # This is the top-level symbolgraph driver that deals with
10
+ # figuring out arguments, running the tool, and loading the
11
+ # results.
12
+
13
+ module Jazzy
14
+ module SymbolGraph
15
+ # Run `swift symbolgraph-extract` with configured args,
16
+ # parse the results, and return as JSON in SourceKit[ten]
17
+ # format.
18
+ def self.build(config)
19
+ Dir.mktmpdir do |tmp_dir|
20
+ args = arguments(config, tmp_dir)
21
+
22
+ Executable.execute_command('swift',
23
+ args.unshift('symbolgraph-extract'),
24
+ true) # raise on error
25
+
26
+ Dir[tmp_dir + '/*.symbols.json'].map do |filename|
27
+ # The @ part is for extensions in our module (before the @)
28
+ # of types in another module (after the @).
29
+ filename =~ /(.*?)(@(.*?))?\.symbols/
30
+ module_name = Regexp.last_match[3] || Regexp.last_match[1]
31
+ {
32
+ filename =>
33
+ Graph.new(File.read(filename), module_name).to_sourcekit,
34
+ }
35
+ end.to_json
36
+ end
37
+ end
38
+
39
+ # Figure out the args to pass to symbolgraph-extract
40
+ # rubocop:disable Metrics/CyclomaticComplexity
41
+ def self.arguments(config, output_path)
42
+ if config.module_name.empty?
43
+ raise 'error: `--swift-build-tool symbolgraph` requires `--module`.'
44
+ end
45
+
46
+ user_args = config.build_tool_arguments.join
47
+
48
+ if user_args =~ /--(?:module-name|minimum-access-level|output-dir)/
49
+ raise 'error: `--build-tool-arguments` for '\
50
+ "`--swift-build-tool symbolgraph` can't use `--module`, "\
51
+ '`--minimum-access-level`, or `--output-dir`.'
52
+ end
53
+
54
+ # Default set
55
+ args = [
56
+ "--module-name=#{config.module_name}",
57
+ '--minimum-access-level=private',
58
+ "--output-dir=#{output_path}",
59
+ '--skip-synthesized-members',
60
+ ]
61
+
62
+ # Things user can override
63
+ args.append("--sdk=#{sdk(config)}") unless user_args =~ /--sdk/
64
+ args.append("--target=#{target}") unless user_args =~ /--target/
65
+ args.append("-F=#{config.source_directory}") unless user_args =~ /-F(?!s)/
66
+ args.append("-I=#{config.source_directory}") unless user_args =~ /-I/
67
+
68
+ args + config.build_tool_arguments
69
+ end
70
+ # rubocop:enable Metrics/CyclomaticComplexity
71
+
72
+ # Get the SDK path. On !darwin this just isn't needed.
73
+ def self.sdk(config)
74
+ `xcrun --show-sdk-path --sdk #{config.sdk}`.chomp
75
+ end
76
+
77
+ # Guess a default LLVM target. Feels like the tool should figure this
78
+ # out from sdk + the binary somehow?
79
+ def self.target
80
+ `swift -version` =~ /Target: (.*?)$/
81
+ Regexp.last_match[1] || 'x86_64-apple-macosx10.15'
82
+ end
83
+
84
+ # This is a last-ditch fallback for when symbolgraph doesn't
85
+ # provide a name - at least conforming external types to local
86
+ # protocols.
87
+ def self.demangle(usr)
88
+ args = %w[demangle -simplified -compact].append(usr.sub(/^s:/, 's'))
89
+ output, = Executable.execute_command('swift', args, true)
90
+ return output.chomp
91
+ rescue
92
+ usr
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,94 @@
1
+ module Jazzy
2
+ module SymbolGraph
3
+ # Constraint is a tidied-up JSON object, used by both Symbol and
4
+ # Relationship, and key to reconstructing extensions.
5
+ class Constraint
6
+ attr_accessor :kind
7
+ attr_accessor :lhs
8
+ attr_accessor :rhs
9
+
10
+ private
11
+
12
+ def initialize(kind, lhs, rhs)
13
+ self.kind = kind # "==" or ":"
14
+ self.lhs = lhs
15
+ self.rhs = rhs
16
+ end
17
+
18
+ public
19
+
20
+ KIND_MAP = {
21
+ 'conformance' => ':',
22
+ 'superclass' => ':',
23
+ 'sameType' => '==',
24
+ }.freeze
25
+
26
+ # Init from a JSON hash
27
+ def self.new_hash(hash)
28
+ kind = KIND_MAP[hash[:kind]]
29
+ raise "Unknown constraint kind '#{kind}'" unless kind
30
+ lhs = hash[:lhs].sub(/^Self\./, '')
31
+ rhs = hash[:rhs].sub(/^Self\./, '')
32
+ new(kind, lhs, rhs)
33
+ end
34
+
35
+ # Init from a Swift declaration fragment eg. 'A : B'
36
+ def self.new_declaration(decl)
37
+ decl =~ /^(.*?)\s*([:<=]+)\s*(.*)$/
38
+ new(Regexp.last_match[2],
39
+ Regexp.last_match[1],
40
+ Regexp.last_match[3])
41
+ end
42
+
43
+ def to_swift
44
+ "#{lhs} #{kind} #{rhs}"
45
+ end
46
+
47
+ # The first component of types in the constraint
48
+ def type_names
49
+ Set.new([lhs, rhs].map { |n| n.sub(/\..*$/, '') })
50
+ end
51
+
52
+ def self.new_list(hash_list)
53
+ hash_list.map { |h| Constraint.new_hash(h) }.sort.uniq
54
+ end
55
+
56
+ # Swift protocols and reqs have an implementation/hidden conformance
57
+ # to their own protocol: we don't want to think about this in docs.
58
+ def self.new_list_for_symbol(hash_list, path_components)
59
+ hash_list.map do |hash|
60
+ if hash[:lhs] == 'Self' &&
61
+ hash[:kind] == 'conformance' &&
62
+ path_components.include?(hash[:rhs])
63
+ next nil
64
+ end
65
+ Constraint.new_hash(hash)
66
+ end.compact
67
+ end
68
+
69
+ # Workaround Swift 5.3 bug with missing constraint rels
70
+ def self.new_list_from_declaration(decl)
71
+ decl.split(/\s*,\s*/).map { |cons| Constraint.new_declaration(cons) }
72
+ end
73
+
74
+ # Sort order - by Swift text
75
+ include Comparable
76
+
77
+ def <=>(other)
78
+ to_swift <=> other.to_swift
79
+ end
80
+
81
+ alias eql? ==
82
+
83
+ def hash
84
+ to_swift.hash
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ class Array
91
+ def to_where_clause
92
+ empty? ? '' : ' where ' + map(&:to_swift).join(', ')
93
+ end
94
+ end
@@ -0,0 +1,114 @@
1
+ module Jazzy
2
+ module SymbolGraph
3
+ # For extensions we need to track constraints of the extended type
4
+ # and the constraints introduced by the extension.
5
+ class ExtConstraints
6
+ attr_accessor :type # array
7
+ attr_accessor :ext # array
8
+
9
+ # all constraints inherited by members of the extension
10
+ def merged
11
+ (type + ext).sort
12
+ end
13
+
14
+ def initialize(type_constraints, ext_constraints)
15
+ self.type = type_constraints || []
16
+ self.ext = ext_constraints || []
17
+ end
18
+ end
19
+
20
+ # An ExtNode is a node of the reconstructed syntax tree representing
21
+ # an extension that we fabricate to resolve certain relationships.
22
+ class ExtNode < BaseNode
23
+ attr_accessor :usr
24
+ attr_accessor :name
25
+ attr_accessor :all_constraints # ExtConstraints
26
+ attr_accessor :conformances # array, can be empty
27
+
28
+ # Deduce an extension from a member of an unknown type or
29
+ # of known type with additional constraints
30
+ def self.new_for_member(type_usr,
31
+ member,
32
+ constraints)
33
+ new(type_usr,
34
+ member.parent_qualified_name,
35
+ constraints).tap { |o| o.add_child(member) }
36
+ end
37
+
38
+ # Deduce an extension from a protocol conformance for some type
39
+ def self.new_for_conformance(type_usr,
40
+ type_name,
41
+ protocol,
42
+ constraints)
43
+ new(type_usr, type_name, constraints).tap do |o|
44
+ o.add_conformance(protocol)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def initialize(usr, name, constraints)
51
+ self.usr = usr
52
+ self.name = name
53
+ self.all_constraints = constraints
54
+ self.conformances = []
55
+ super()
56
+ end
57
+
58
+ public
59
+
60
+ def constraints
61
+ all_constraints.merged
62
+ end
63
+
64
+ def add_conformance(protocol)
65
+ conformances.append(protocol).sort!
66
+ end
67
+
68
+ def full_declaration
69
+ decl = "extension #{name}"
70
+ unless conformances.empty?
71
+ decl += ' : ' + conformances.join(', ')
72
+ end
73
+ decl + all_constraints.ext.to_where_clause
74
+ end
75
+
76
+ def to_sourcekit(module_name)
77
+ declaration = full_declaration
78
+ xml_declaration = "<swift>#{CGI.escapeHTML(declaration)}</swift>"
79
+
80
+ hash = {
81
+ 'key.kind' => 'source.lang.swift.decl.extension',
82
+ 'key.usr' => usr,
83
+ 'key.name' => name,
84
+ 'key.modulename' => module_name,
85
+ 'key.parsed_declaration' => declaration,
86
+ 'key.annotated_decl' => xml_declaration,
87
+ }
88
+
89
+ unless conformances.empty?
90
+ hash['key.inheritedtypes'] = conformances.map do |conformance|
91
+ { 'key.name' => conformance }
92
+ end
93
+ end
94
+
95
+ unless children.empty?
96
+ hash['key.substructure'] = children_to_sourcekit
97
+ end
98
+
99
+ hash
100
+ end
101
+
102
+ # Sort order - by type name then constraint
103
+ include Comparable
104
+
105
+ def sort_key
106
+ name + constraints.map(&:to_swift).join
107
+ end
108
+
109
+ def <=>(other)
110
+ sort_key <=> other.sort_key
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,193 @@
1
+ # rubocop:disable Metrics/ClassLength
2
+ module Jazzy
3
+ module SymbolGraph
4
+ # A Graph is the coordinator to import a symbolgraph json file.
5
+ # Deserialize it to Symbols and Relationships, then rebuild
6
+ # the AST shape using SymNodes and ExtNodes and extract SourceKit json.
7
+ class Graph
8
+ attr_accessor :module_name
9
+ attr_accessor :symbol_nodes # usr -> SymNode
10
+ attr_accessor :relationships # [Relationship]
11
+ attr_accessor :ext_nodes # (usr, constraints) -> ExtNode
12
+
13
+ # Parse the JSON into flat tables of data
14
+ def initialize(json, module_name)
15
+ self.module_name = module_name
16
+ graph = JSON.parse(json, symbolize_names: true)
17
+
18
+ self.symbol_nodes = {}
19
+ graph[:symbols].each do |hash|
20
+ symbol = Symbol.new(hash)
21
+ symbol_nodes[symbol.usr] = SymNode.new(symbol)
22
+ end
23
+
24
+ self.relationships =
25
+ graph[:relationships].map { |hash| Relationship.new(hash) }
26
+
27
+ self.ext_nodes = {}
28
+ end
29
+
30
+ # ExtNode index. (type USR, extension constraints) -> ExtNode.
31
+ # This minimizes the number of extensions
32
+
33
+ def ext_key(usr, constraints)
34
+ usr + constraints.map(&:to_swift).join
35
+ end
36
+
37
+ def add_ext_member(type_usr, member_node, constraints)
38
+ key = ext_key(type_usr, constraints.ext)
39
+ if ext_node = ext_nodes[key]
40
+ ext_node.add_child(member_node)
41
+ else
42
+ ext_nodes[key] =
43
+ ExtNode.new_for_member(type_usr, member_node, constraints)
44
+ end
45
+ end
46
+
47
+ def add_ext_conformance(type_usr,
48
+ type_name,
49
+ protocol,
50
+ constraints)
51
+ key = ext_key(type_usr, constraints.ext)
52
+ if ext_node = ext_nodes[key]
53
+ ext_node.add_conformance(protocol)
54
+ else
55
+ ext_nodes[key] =
56
+ ExtNode.new_for_conformance(type_usr,
57
+ type_name,
58
+ protocol,
59
+ constraints)
60
+ end
61
+ end
62
+
63
+ # Increasingly desparate ways to find the name of the symbol
64
+ # at the target end of a relationship
65
+ def rel_target_name(rel, target_node)
66
+ (target_node && target_node.symbol.name) ||
67
+ rel.target_fallback ||
68
+ Jazzy::SymbolGraph.demangle(rel.target_usr)
69
+ end
70
+
71
+ # Same for the source end. Less help from the tool here
72
+ def rel_source_name(rel, source_node)
73
+ (source_node && source_node.qualified_name) ||
74
+ Jazzy::SymbolGraph.demangle(rel.source_usr)
75
+ end
76
+
77
+ # Protocol conformance is redundant if it's unconditional
78
+ # and already expressed in the type's declaration.
79
+ def redundant_conformance?(rel, type, protocol)
80
+ type && rel.constraints.empty? && type.conformance?(protocol)
81
+ end
82
+
83
+ # source is a member/protocol requirement of target
84
+ def rebuild_member(rel, source, target)
85
+ return unless source
86
+
87
+ source.protocol_requirement = rel.protocol_requirement?
88
+ constraints =
89
+ ExtConstraints.new(target && target.constraints,
90
+ source.unique_context_constraints(target))
91
+
92
+ # Add to its parent or invent an extension
93
+ unless target && target.try_add_child(source, constraints.ext)
94
+ add_ext_member(rel.target_usr, source, constraints)
95
+ end
96
+ end
97
+
98
+ # "source : target" either from type decl or ext decl
99
+ def rebuild_conformance(rel, source, target)
100
+ protocol_name = rel_target_name(rel, target)
101
+
102
+ return if redundant_conformance?(rel, source, protocol_name)
103
+
104
+ type_constraints = (source && source.constraints) || []
105
+ constraints =
106
+ ExtConstraints.new(type_constraints,
107
+ rel.constraints - type_constraints)
108
+
109
+ # Create an extension or enhance an existing one
110
+ add_ext_conformance(rel.source_usr,
111
+ rel_source_name(rel, source),
112
+ protocol_name,
113
+ constraints)
114
+ end
115
+
116
+ # "source is a default implementation of protocol requirement target"
117
+ def rebuild_default_implementation(_rel, source, target)
118
+ return unless source
119
+
120
+ unless target &&
121
+ (target_parent = target.parent) &&
122
+ target_parent.is_a?(SymNode)
123
+ # Could probably figure this out with demangle, but...
124
+ warn "Can't resolve membership of default implementation "\
125
+ "#{source.symbol.usr}."
126
+ source.unlisted = true
127
+ return
128
+ end
129
+ constraints =
130
+ ExtConstraints.new(target_parent.constraints,
131
+ source.unique_context_constraints(target_parent))
132
+
133
+ add_ext_member(target_parent.symbol.usr,
134
+ source,
135
+ constraints)
136
+ end
137
+
138
+ # "source is a class that inherits from target"
139
+ def rebuild_inherits(_rel, source, target)
140
+ if source && target
141
+ source.superclass_name = target.symbol.name
142
+ end
143
+ end
144
+
145
+ # Process a structural relationship to link nodes
146
+ def rebuild_rel(rel)
147
+ source = symbol_nodes[rel.source_usr]
148
+ target = symbol_nodes[rel.target_usr]
149
+
150
+ case rel.kind
151
+ when :memberOf, :optionalRequirementOf, :requirementOf
152
+ rebuild_member(rel, source, target)
153
+
154
+ when :conformsTo
155
+ rebuild_conformance(rel, source, target)
156
+
157
+ when :defaultImplementationOf
158
+ rebuild_default_implementation(rel, source, target)
159
+
160
+ when :inheritsFrom
161
+ rebuild_inherits(rel, source, target)
162
+ end
163
+ # don't seem to care about:
164
+ # - overrides: not bothered, also unimplemented for protocols
165
+ end
166
+
167
+ # Rebuild the AST structure and convert to SourceKit
168
+ def to_sourcekit
169
+ # Do default impls after the others so we can find protocol
170
+ # type nodes from protocol requirements.
171
+ default_impls, other_rels =
172
+ relationships.partition(&:default_implementation?)
173
+ (other_rels + default_impls).each { |r| rebuild_rel(r) }
174
+
175
+ root_symbol_nodes =
176
+ symbol_nodes.values
177
+ .select(&:top_level_decl?)
178
+ .sort
179
+ .map(&:to_sourcekit)
180
+
181
+ root_ext_nodes =
182
+ ext_nodes.values
183
+ .sort
184
+ .map { |n| n.to_sourcekit(module_name) }
185
+ {
186
+ 'key.diagnostic_stage' => 'parse',
187
+ 'key.substructure' => root_symbol_nodes + root_ext_nodes,
188
+ }
189
+ end
190
+ end
191
+ end
192
+ end
193
+ # rubocop:enable Metrics/ClassLength