jazzy 0.14.4 → 0.15.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/Tests.yml +6 -5
  3. data/.rubocop.yml +13 -0
  4. data/CHANGELOG.md +40 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile.lock +62 -47
  7. data/README.md +115 -5
  8. data/bin/sourcekitten +0 -0
  9. data/js/package-lock.json +6 -6
  10. data/lib/jazzy/config.rb +156 -24
  11. data/lib/jazzy/doc.rb +2 -2
  12. data/lib/jazzy/doc_builder.rb +55 -29
  13. data/lib/jazzy/doc_index.rb +185 -0
  14. data/lib/jazzy/docset_builder/info_plist.mustache +1 -1
  15. data/lib/jazzy/docset_builder.rb +44 -13
  16. data/lib/jazzy/extensions/katex/css/katex.min.css +1 -1
  17. data/lib/jazzy/extensions/katex/js/katex.min.js +1 -1
  18. data/lib/jazzy/gem_version.rb +1 -1
  19. data/lib/jazzy/grouper.rb +130 -0
  20. data/lib/jazzy/podspec_documenter.rb +1 -1
  21. data/lib/jazzy/source_declaration/type.rb +10 -2
  22. data/lib/jazzy/source_declaration.rb +69 -8
  23. data/lib/jazzy/source_document.rb +5 -1
  24. data/lib/jazzy/source_module.rb +13 -11
  25. data/lib/jazzy/sourcekitten.rb +231 -237
  26. data/lib/jazzy/symbol_graph/ext_key.rb +37 -0
  27. data/lib/jazzy/symbol_graph/ext_node.rb +23 -6
  28. data/lib/jazzy/symbol_graph/graph.rb +31 -19
  29. data/lib/jazzy/symbol_graph/relationship.rb +21 -3
  30. data/lib/jazzy/symbol_graph/sym_node.rb +10 -22
  31. data/lib/jazzy/symbol_graph/symbol.rb +28 -0
  32. data/lib/jazzy/symbol_graph.rb +19 -16
  33. data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +10 -7
  34. data/lib/jazzy/themes/apple/assets/js/typeahead.jquery.js +3 -2
  35. data/lib/jazzy/themes/apple/templates/doc.mustache +8 -1
  36. data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +5 -5
  37. data/lib/jazzy/themes/fullwidth/assets/js/typeahead.jquery.js +3 -2
  38. data/lib/jazzy/themes/fullwidth/templates/doc.mustache +8 -1
  39. data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +6 -5
  40. data/lib/jazzy/themes/jony/templates/doc.mustache +9 -2
  41. data/spec/integration_spec.rb +8 -1
  42. metadata +5 -2
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jazzy
4
+ module SymbolGraph
5
+ # An ExtKey identifies an extension of a type, made up of the USR of
6
+ # the type and the constraints of the extension. With Swift 5.9 extension
7
+ # symbols, the USR is the 'fake' USR invented by symbolgraph to solve the
8
+ # same problem as this type, which means less merging takes place.
9
+ class ExtKey
10
+ attr_accessor :usr
11
+ attr_accessor :constraints_text
12
+
13
+ def initialize(usr, constraints)
14
+ self.usr = usr
15
+ self.constraints_text = constraints.map(&:to_swift).join
16
+ end
17
+
18
+ def hash_key
19
+ usr + constraints_text
20
+ end
21
+
22
+ def eql?(other)
23
+ hash_key == other.hash_key
24
+ end
25
+
26
+ def hash
27
+ hash_key.hash
28
+ end
29
+ end
30
+
31
+ class ExtSymNode
32
+ def ext_key
33
+ ExtKey.new(usr, all_constraints.ext)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -23,6 +23,7 @@ module Jazzy
23
23
  # an extension that we fabricate to resolve certain relationships.
24
24
  class ExtNode < BaseNode
25
25
  attr_accessor :usr
26
+ attr_accessor :real_usr
26
27
  attr_accessor :name
27
28
  attr_accessor :all_constraints # ExtConstraints
28
29
  attr_accessor :conformances # array, can be empty
@@ -75,15 +76,15 @@ module Jazzy
75
76
  decl + all_constraints.ext.to_where_clause
76
77
  end
77
78
 
78
- def to_sourcekit(module_name)
79
+ def to_sourcekit(module_name, ext_module_name)
79
80
  declaration = full_declaration
80
81
  xml_declaration = "<swift>#{CGI.escapeHTML(declaration)}</swift>"
81
82
 
82
83
  hash = {
83
84
  'key.kind' => 'source.lang.swift.decl.extension',
84
- 'key.usr' => usr,
85
+ 'key.usr' => real_usr || usr,
85
86
  'key.name' => name,
86
- 'key.modulename' => module_name,
87
+ 'key.modulename' => ext_module_name,
87
88
  'key.parsed_declaration' => declaration,
88
89
  'key.annotated_decl' => xml_declaration,
89
90
  }
@@ -94,9 +95,7 @@ module Jazzy
94
95
  end
95
96
  end
96
97
 
97
- unless children.empty?
98
- hash['key.substructure'] = children_to_sourcekit
99
- end
98
+ add_children_to_sourcekit(hash, module_name)
100
99
 
101
100
  hash
102
101
  end
@@ -112,5 +111,23 @@ module Jazzy
112
111
  sort_key <=> other.sort_key
113
112
  end
114
113
  end
114
+
115
+ # An ExtSymNode is an extension generated from a Swift 5.9 extension
116
+ # symbol, for extensions of types from other modules only.
117
+ class ExtSymNode < ExtNode
118
+ attr_accessor :symbol
119
+
120
+ def initialize(symbol)
121
+ self.symbol = symbol
122
+ super(symbol.usr, symbol.full_name,
123
+ # sadly can't tell what constraints are inherited vs added
124
+ ExtConstraints.new([], symbol.constraints))
125
+ end
126
+
127
+ def to_sourcekit(module_name, ext_module_name)
128
+ hash = super
129
+ symbol.add_to_sourcekit(hash)
130
+ end
131
+ end
115
132
  end
116
133
  end
@@ -7,37 +7,40 @@ module Jazzy
7
7
  # Deserialize it to Symbols and Relationships, then rebuild
8
8
  # the AST shape using SymNodes and ExtNodes and extract SourceKit json.
9
9
  class Graph
10
- attr_accessor :module_name
10
+ attr_accessor :module_name # Our module
11
+ attr_accessor :ext_module_name # Module being extended
11
12
  attr_accessor :symbol_nodes # usr -> SymNode
12
13
  attr_accessor :relationships # [Relationship]
13
14
  attr_accessor :ext_nodes # (usr, constraints) -> ExtNode
14
15
 
15
16
  # Parse the JSON into flat tables of data
16
- def initialize(json, module_name)
17
+ def initialize(json, module_name, ext_module_name)
17
18
  self.module_name = module_name
19
+ self.ext_module_name = ext_module_name
18
20
  graph = JSON.parse(json, symbolize_names: true)
19
21
 
20
22
  self.symbol_nodes = {}
23
+ self.ext_nodes = {}
24
+
21
25
  graph[:symbols].each do |hash|
22
26
  symbol = Symbol.new(hash)
23
- symbol_nodes[symbol.usr] = SymNode.new(symbol)
27
+ if symbol.extension?
28
+ node = ExtSymNode.new(symbol)
29
+ ext_nodes[node.ext_key] = node
30
+ else
31
+ symbol_nodes[symbol.usr] = SymNode.new(symbol)
32
+ end
24
33
  end
25
34
 
26
35
  self.relationships =
27
36
  graph[:relationships].map { |hash| Relationship.new(hash) }
28
-
29
- self.ext_nodes = {}
30
37
  end
31
38
 
32
- # ExtNode index. (type USR, extension constraints) -> ExtNode.
39
+ # ExtNode index. ExtKey (type USR, extension constraints) -> ExtNode.
33
40
  # This minimizes the number of extensions
34
41
 
35
- def ext_key(usr, constraints)
36
- usr + constraints.map(&:to_swift).join
37
- end
38
-
39
42
  def add_ext_member(type_usr, member_node, constraints)
40
- key = ext_key(type_usr, constraints.ext)
43
+ key = ExtKey.new(type_usr, constraints.ext)
41
44
  if ext_node = ext_nodes[key]
42
45
  ext_node.add_child(member_node)
43
46
  else
@@ -50,7 +53,7 @@ module Jazzy
50
53
  type_name,
51
54
  protocol,
52
55
  constraints)
53
- key = ext_key(type_usr, constraints.ext)
56
+ key = ExtKey.new(type_usr, constraints.ext)
54
57
  if ext_node = ext_nodes[key]
55
58
  ext_node.add_conformance(protocol)
56
59
  else
@@ -149,6 +152,15 @@ module Jazzy
149
152
  end
150
153
  end
151
154
 
155
+ # "References to fake_usr should be real_usr"
156
+ def unalias_extensions(fake_usr, real_usr)
157
+ ext_nodes.each_pair do |key, ext|
158
+ if key.usr == fake_usr
159
+ ext.real_usr = real_usr
160
+ end
161
+ end
162
+ end
163
+
152
164
  # Process a structural relationship to link nodes
153
165
  def rebuild_rel(rel)
154
166
  source = symbol_nodes[rel.source_usr]
@@ -166,29 +178,29 @@ module Jazzy
166
178
 
167
179
  when :inheritsFrom
168
180
  rebuild_inherits(rel, source, target)
181
+
182
+ when :extensionTo
183
+ unalias_extensions(rel.source_usr, rel.target_usr)
169
184
  end
185
+
170
186
  # don't seem to care about:
171
187
  # - overrides: not bothered, also unimplemented for protocols
172
188
  end
173
189
 
174
190
  # Rebuild the AST structure and convert to SourceKit
175
191
  def to_sourcekit
176
- # Do default impls after the others so we can find protocol
177
- # type nodes from protocol requirements.
178
- default_impls, other_rels =
179
- relationships.partition(&:default_implementation?)
180
- (other_rels + default_impls).each { |r| rebuild_rel(r) }
192
+ relationships.sort.each { |r| rebuild_rel(r) }
181
193
 
182
194
  root_symbol_nodes =
183
195
  symbol_nodes.values
184
196
  .select(&:top_level_decl?)
185
197
  .sort
186
- .map(&:to_sourcekit)
198
+ .map { |n| n.to_sourcekit(module_name) }
187
199
 
188
200
  root_ext_nodes =
189
201
  ext_nodes.values
190
202
  .sort
191
- .map { |n| n.to_sourcekit(module_name) }
203
+ .map { |n| n.to_sourcekit(module_name, ext_module_name) }
192
204
  {
193
205
  'key.diagnostic_stage' => 'parse',
194
206
  'key.substructure' => root_symbol_nodes + root_ext_nodes,
@@ -10,9 +10,14 @@ module Jazzy
10
10
  attr_accessor :target_fallback # can be nil
11
11
  attr_accessor :constraints # array, can be empty
12
12
 
13
- KINDS = %w[memberOf conformsTo defaultImplementationOf
14
- overrides inheritsFrom requirementOf
15
- optionalRequirementOf].freeze
13
+ # Order matters: defaultImplementationOf after the protocols
14
+ # have been defined; extensionTo after all the extensions have
15
+ # been discovered.
16
+ KINDS = %w[memberOf conformsTo overrides inheritsFrom
17
+ requirementOf optionalRequirementOf
18
+ defaultImplementationOf extensionTo].freeze
19
+
20
+ KINDS_INDEX = KINDS.to_h { |i| [i.to_sym, KINDS.index(i)] }.freeze
16
21
 
17
22
  def protocol_requirement?
18
23
  %i[requirementOf optionalRequirementOf].include? kind
@@ -22,6 +27,10 @@ module Jazzy
22
27
  kind == :defaultImplementationOf
23
28
  end
24
29
 
30
+ def extension_to?
31
+ kind == :extensionTo
32
+ end
33
+
25
34
  # Protocol conformances added by compiler to actor decls that
26
35
  # users aren't interested in.
27
36
  def actor_protocol?
@@ -43,6 +52,15 @@ module Jazzy
43
52
  end
44
53
  self.constraints = Constraint.new_list(hash[:swiftConstraints] || [])
45
54
  end
55
+
56
+ # Sort order
57
+ include Comparable
58
+
59
+ def <=>(other)
60
+ return 0 if kind == other.kind
61
+
62
+ KINDS_INDEX[kind] <=> KINDS_INDEX[other.kind]
63
+ end
46
64
  end
47
65
  end
48
66
  end
@@ -18,14 +18,16 @@ module Jazzy
18
18
  children.append(child)
19
19
  end
20
20
 
21
- def children_to_sourcekit
22
- children.sort.map(&:to_sourcekit)
21
+ def add_children_to_sourcekit(hash, module_name)
22
+ unless children.empty?
23
+ hash['key.substructure'] =
24
+ children.sort.map { |c| c.to_sourcekit(module_name) }
25
+ end
23
26
  end
24
27
  end
25
28
 
26
29
  # A SymNode is a node of the reconstructed syntax tree holding a symbol.
27
30
  # It can turn itself into SourceKit and helps decode extensions.
28
- # rubocop:disable Metrics/ClassLength
29
31
  class SymNode < BaseNode
30
32
  attr_accessor :symbol
31
33
  attr_writer :override
@@ -128,8 +130,7 @@ module Jazzy
128
130
  .join("\n")
129
131
  end
130
132
 
131
- # rubocop:disable Metrics/MethodLength
132
- def to_sourcekit
133
+ def to_sourcekit(module_name)
133
134
  declaration = full_declaration
134
135
  xml_declaration = "<swift>#{CGI.escapeHTML(declaration)}</swift>"
135
136
 
@@ -137,32 +138,20 @@ module Jazzy
137
138
  'key.kind' => symbol.kind,
138
139
  'key.usr' => symbol.usr,
139
140
  'key.name' => symbol.name,
140
- 'key.accessibility' => symbol.acl,
141
- 'key.parsed_decl' => declaration,
141
+ 'key.modulename' => module_name,
142
+ 'key.parsed_declaration' => declaration,
142
143
  'key.annotated_decl' => xml_declaration,
143
144
  'key.symgraph_async' => async?,
144
145
  }
145
- if docs = symbol.doc_comments
146
- hash['key.doc.comment'] = docs
147
- hash['key.doc.full_as_xml'] = ''
148
- end
149
146
  if params = symbol.parameter_names
150
147
  hash['key.doc.parameters'] =
151
148
  params.map { |name| { 'name' => name } }
152
149
  end
153
- if location = symbol.location
154
- hash['key.filepath'] = location[:filename]
155
- hash['key.doc.line'] = location[:line] + 1
156
- hash['key.doc.column'] = location[:character] + 1
157
- end
158
- unless children.empty?
159
- hash['key.substructure'] = children_to_sourcekit
160
- end
161
150
  hash['key.symgraph_spi'] = true if symbol.spi
162
151
 
163
- hash
152
+ add_children_to_sourcekit(hash, module_name)
153
+ symbol.add_to_sourcekit(hash)
164
154
  end
165
- # rubocop:enable Metrics/MethodLength
166
155
 
167
156
  # Sort order - by symbol
168
157
  include Comparable
@@ -171,6 +160,5 @@ module Jazzy
171
160
  symbol <=> other.symbol
172
161
  end
173
162
  end
174
- # rubocop:enable Metrics/ClassLength
175
163
  end
176
164
  end
@@ -22,6 +22,10 @@ module Jazzy
22
22
  path_components[-1] || '??'
23
23
  end
24
24
 
25
+ def full_name
26
+ path_components.join('.')
27
+ end
28
+
25
29
  def initialize(hash)
26
30
  self.usr = hash[:identifier][:precise]
27
31
  self.path_components = hash[:pathComponents]
@@ -101,6 +105,7 @@ module Jazzy
101
105
  'associatedtype' => 'associatedtype',
102
106
  'actor' => 'actor',
103
107
  'macro' => 'macro',
108
+ 'extension' => 'extension',
104
109
  }.freeze
105
110
 
106
111
  # We treat 'static var' differently to 'class var'
@@ -122,6 +127,10 @@ module Jazzy
122
127
  self.kind = "source.lang.swift.decl.#{sourcekit_kind}"
123
128
  end
124
129
 
130
+ def extension?
131
+ kind.end_with?('extension')
132
+ end
133
+
125
134
  # Mapping SymbolGraph's ACL to SourceKit
126
135
 
127
136
  def init_acl(acl)
@@ -217,6 +226,25 @@ module Jazzy
217
226
  availability_attributes(avail_hash_list) + spi_attributes
218
227
  end
219
228
 
229
+ # SourceKit common fields, shared by extension and regular symbols.
230
+ # Things we do not know for fabricated extensions.
231
+ def add_to_sourcekit(hash)
232
+ unless doc_comments.nil?
233
+ hash['key.doc.comment'] = doc_comments
234
+ hash['key.doc.full_as_xml'] = ''
235
+ end
236
+
237
+ hash['key.accessibility'] = acl
238
+
239
+ unless location.nil?
240
+ hash['key.filepath'] = location[:filename]
241
+ hash['key.doc.line'] = location[:line] + 1
242
+ hash['key.doc.column'] = location[:character] + 1
243
+ end
244
+
245
+ hash
246
+ end
247
+
220
248
  # Sort order
221
249
  include Comparable
222
250
 
@@ -7,6 +7,7 @@ require 'jazzy/symbol_graph/symbol'
7
7
  require 'jazzy/symbol_graph/relationship'
8
8
  require 'jazzy/symbol_graph/sym_node'
9
9
  require 'jazzy/symbol_graph/ext_node'
10
+ require 'jazzy/symbol_graph/ext_key'
10
11
 
11
12
  # This is the top-level symbolgraph driver that deals with
12
13
  # figuring out arguments, running the tool, and loading the
@@ -19,10 +20,10 @@ module Jazzy
19
20
  # with configured args.
20
21
  # Then parse the results, and return as JSON in SourceKit[ten]
21
22
  # format.
22
- def self.build(config)
23
- if config.symbolgraph_directory.nil?
23
+ def self.build(module_config)
24
+ if module_config.symbolgraph_directory.nil?
24
25
  Dir.mktmpdir do |tmp_dir|
25
- args = arguments(config, tmp_dir)
26
+ args = arguments(module_config, tmp_dir)
26
27
 
27
28
  Executable.execute_command('swift',
28
29
  args.unshift('symbolgraph-extract'),
@@ -31,17 +32,17 @@ module Jazzy
31
32
  parse_symbols(tmp_dir)
32
33
  end
33
34
  else
34
- parse_symbols(config.symbolgraph_directory.to_s)
35
+ parse_symbols(module_config.symbolgraph_directory.to_s)
35
36
  end
36
37
  end
37
38
 
38
39
  # Figure out the args to pass to symbolgraph-extract
39
- def self.arguments(config, output_path)
40
- if config.module_name.empty?
40
+ def self.arguments(module_config, output_path)
41
+ if module_config.module_name.empty?
41
42
  raise 'error: `--swift-build-tool symbolgraph` requires `--module`.'
42
43
  end
43
44
 
44
- user_args = config.build_tool_arguments.join
45
+ user_args = module_config.build_tool_arguments.join
45
46
 
46
47
  if user_args =~ /-(?:module-name|minimum-access-level|output-dir)/
47
48
  raise 'error: `--build-tool-arguments` for ' \
@@ -51,19 +52,19 @@ module Jazzy
51
52
 
52
53
  # Default set
53
54
  args = [
54
- '-module-name', config.module_name,
55
+ '-module-name', module_config.module_name,
55
56
  '-minimum-access-level', 'private',
56
57
  '-output-dir', output_path,
57
58
  '-skip-synthesized-members'
58
59
  ]
59
60
 
60
61
  # Things user can override
61
- args += ['-sdk', sdk(config)] unless user_args =~ /-sdk/
62
+ args += ['-sdk', sdk(module_config)] unless user_args =~ /-sdk/
62
63
  args += ['-target', target] unless user_args =~ /-target/
63
- args += ['-F', config.source_directory.to_s] unless user_args =~ /-F(?!s)/
64
- args += ['-I', config.source_directory.to_s] unless user_args =~ /-I/
64
+ args += ['-F', module_config.source_directory.to_s] unless user_args =~ /-F(?!s)/
65
+ args += ['-I', module_config.source_directory.to_s] unless user_args =~ /-I/
65
66
 
66
- args + config.build_tool_arguments
67
+ args + module_config.build_tool_arguments
67
68
  end
68
69
 
69
70
  # Parse the symbol files in the given directory
@@ -72,17 +73,19 @@ module Jazzy
72
73
  # The @ part is for extensions in our module (before the @)
73
74
  # of types in another module (after the @).
74
75
  File.basename(filename) =~ /(.*?)(@(.*?))?\.symbols/
75
- module_name = Regexp.last_match[3] || Regexp.last_match[1]
76
+ module_name = Regexp.last_match[1]
77
+ ext_module_name = Regexp.last_match[3] || module_name
78
+ json = File.read(filename)
76
79
  {
77
80
  filename =>
78
- Graph.new(File.read(filename), module_name).to_sourcekit,
81
+ Graph.new(json, module_name, ext_module_name).to_sourcekit,
79
82
  }
80
83
  end.to_json
81
84
  end
82
85
 
83
86
  # Get the SDK path. On !darwin this just isn't needed.
84
- def self.sdk(config)
85
- `xcrun --show-sdk-path --sdk #{config.sdk}`.chomp
87
+ def self.sdk(module_config)
88
+ `xcrun --show-sdk-path --sdk #{module_config.sdk}`.chomp
86
89
  end
87
90
 
88
91
  # Guess a default LLVM target. Feels like the tool should figure this
@@ -23,7 +23,7 @@ $content_top_offset: 70px;
23
23
  $content_body_margin: 16px;
24
24
  $content_body_left_offset: $sidebar_width + $content_body_margin;
25
25
  $header_height: 32px;
26
- $breadcrumb_padding_top: 17px;
26
+ $breadcrumb_padding_top: 12px;
27
27
 
28
28
  $code_font: 0.95em Menlo, monospace;
29
29
 
@@ -206,9 +206,11 @@ header {
206
206
  height: $content_top_offset - $header_height - $breadcrumb_padding_top;
207
207
  padding-top: $breadcrumb_padding_top;
208
208
  position: fixed;
209
- width: 100%;
209
+ width: inherit;
210
210
  z-index: 2;
211
211
  margin-top: $header_height;
212
+ white-space: nowrap;
213
+ overflow-x: scroll;
212
214
  #carat {
213
215
  height: 10px;
214
216
  margin: 0 5px;
@@ -412,11 +414,12 @@ header {
412
414
  .discouraged {
413
415
  text-decoration: line-through;
414
416
  }
415
- .declaration-note {
416
- font-size: .85em;
417
- color: rgba(128,128,128,1);
418
- font-style: italic;
419
- }
417
+ }
418
+
419
+ .declaration-note {
420
+ font-size: .85em;
421
+ color: rgba(128,128,128,1);
422
+ font-style: italic;
420
423
  }
421
424
 
422
425
  .pointer-container {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * typeahead.js 1.3.1
2
+ * typeahead.js 1.3.3
3
3
  * https://github.com/corejavascript/typeahead.js
4
- * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT
4
+ * Copyright 2013-2024 Twitter, Inc. and other contributors; Licensed MIT
5
5
  */
6
6
 
7
7
 
@@ -499,6 +499,7 @@
499
499
  });
500
500
  this.$input.attr({
501
501
  "aria-owns": id + "_listbox",
502
+ "aria-controls": id + "_listbox",
502
503
  role: "combobox",
503
504
  "aria-autocomplete": "list",
504
505
  "aria-expanded": false
@@ -28,9 +28,16 @@
28
28
  {{> header}}
29
29
  <div class="content-wrapper">
30
30
  <p id="breadcrumbs">
31
- <a href="{{path_to_root}}index.html">{{module_name}} Reference</a>
31
+ <a href="{{path_to_root}}index.html">{{readme_title}}</a>
32
+ {{#breadcrumbs}}
32
33
  <img id="carat" src="{{path_to_root}}img/carat.png" alt=""/>
34
+ {{#last}}
33
35
  {{name}} {{kind}} Reference
36
+ {{/last}}
37
+ {{^last}}
38
+ <a href="{{path_to_root}}{{url}}">{{name}}</a>
39
+ {{/last}}
40
+ {{/breadcrumbs}}
34
41
  </p>
35
42
  </div>
36
43
  <div class="content-wrapper">
@@ -454,12 +454,12 @@ pre code {
454
454
  margin-left: 20px;
455
455
  font-size: 1rem;
456
456
  }
457
+ }
457
458
 
458
- .declaration-note {
459
- font-size: .85em;
460
- color: #808080;
461
- font-style: italic;
462
- }
459
+ .declaration-note {
460
+ font-size: .85em;
461
+ color: #808080;
462
+ font-style: italic;
463
463
  }
464
464
 
465
465
  .pointer-container {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * typeahead.js 1.3.1
2
+ * typeahead.js 1.3.3
3
3
  * https://github.com/corejavascript/typeahead.js
4
- * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT
4
+ * Copyright 2013-2024 Twitter, Inc. and other contributors; Licensed MIT
5
5
  */
6
6
 
7
7
 
@@ -499,6 +499,7 @@
499
499
  });
500
500
  this.$input.attr({
501
501
  "aria-owns": id + "_listbox",
502
+ "aria-controls": id + "_listbox",
502
503
  role: "combobox",
503
504
  "aria-autocomplete": "list",
504
505
  "aria-expanded": false
@@ -31,9 +31,16 @@
31
31
  {{> header}}
32
32
 
33
33
  <p class="breadcrumbs">
34
- <a class="breadcrumb" href="{{path_to_root}}index.html">{{module_name}} Reference</a>
34
+ <a class="breadcrumb" href="{{path_to_root}}index.html">{{readme_title}}</a>
35
+ {{#breadcrumbs}}
35
36
  <img class="carat" src="{{path_to_root}}img/carat.png" alt=""/>
37
+ {{#last}}
36
38
  {{name}} {{kind}} Reference
39
+ {{/last}}
40
+ {{^last}}
41
+ <a class="breadcrumb" href="{{path_to_root}}{{url}}">{{name}}</a>
42
+ {{/last}}
43
+ {{/breadcrumbs}}
37
44
  </p>
38
45
 
39
46
  <div class="content-wrapper">
@@ -450,11 +450,12 @@ header {
450
450
  .token-open {
451
451
  margin-left: 45px;
452
452
  }
453
- .declaration-note {
454
- font-size: .85em;
455
- color: rgba(128,128,128,1);
456
- font-style: italic;
457
- }
453
+ }
454
+
455
+ .declaration-note {
456
+ font-size: .85em;
457
+ color: rgba(128,128,128,1);
458
+ font-style: italic;
458
459
  }
459
460
 
460
461
  .pointer-container {
@@ -26,10 +26,17 @@
26
26
  <div class="content-wrapper">
27
27
  <p id="breadcrumbs">
28
28
  <span class="no-mobile">
29
- <a href="{{path_to_root}}index.html">{{module_name}} Reference</a>
29
+ <a href="{{path_to_root}}index.html">{{readme_title}}</a>
30
+ {{#breadcrumbs}}
30
31
  <img id="carat" src="{{path_to_root}}img/carat.png" alt=""/>
32
+ {{#last}}
33
+ {{name}} {{kind}} Reference
34
+ {{/last}}
35
+ {{^last}}
36
+ <a href="{{path_to_root}}{{url}}">{{name}}</a>
37
+ {{/last}}
38
+ {{/breadcrumbs}}
31
39
  </span>
32
- {{name}} {{kind}} Reference
33
40
  </p>
34
41
  </div>
35
42
  </div>
@@ -121,6 +121,8 @@ describe_cli 'jazzy' do
121
121
  s.replace_pattern(%r{/transformed/}, '/')
122
122
  # Xcode 15 workaround
123
123
  s.replace_pattern(/objc\[.....\]: Class _?DTX\w+ is implemented in both.*?\n/, '')
124
+ # arm vs. intel workaround
125
+ s.replace_pattern(%r{(?<=build/)(arm64|x86_64)(?=-apple)}, '')
124
126
  end
125
127
 
126
128
  require 'shellwords'
@@ -246,7 +248,12 @@ describe_cli 'jazzy' do
246
248
  module_path = `swift build --scratch-path #{build_path} --show-bin-path`
247
249
  behaves_like cli_spec 'misc_jazzy_symgraph_features',
248
250
  '--swift-build-tool symbolgraph ' \
249
- "--build-tool-arguments -I,#{module_path} "
251
+ '--build-tool-arguments ' \
252
+ "-emit-extension-block-symbols,-I,#{module_path}"
253
+ end
254
+
255
+ describe 'Creates docs for a multiple-module project' do
256
+ behaves_like cli_spec 'jazzy_multi_modules'
250
257
  end
251
258
  end if !spec_subset || spec_subset == 'swift'
252
259