jazzy 0.13.7 → 0.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/Tests.yml +6 -6
  3. data/.rubocop.yml +155 -24
  4. data/CHANGELOG.md +91 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Dangerfile +11 -8
  7. data/Gemfile +3 -1
  8. data/Gemfile.lock +85 -64
  9. data/ObjectiveC.md +208 -0
  10. data/README.md +63 -33
  11. data/Rakefile +18 -15
  12. data/bin/jazzy +3 -2
  13. data/bin/sourcekitten +0 -0
  14. data/jazzy.gemspec +9 -6
  15. data/lib/jazzy/config.rb +135 -69
  16. data/lib/jazzy/doc.rb +3 -1
  17. data/lib/jazzy/doc_builder.rb +72 -83
  18. data/lib/jazzy/docset_builder.rb +3 -1
  19. data/lib/jazzy/documentation_generator.rb +6 -2
  20. data/lib/jazzy/executable.rb +3 -0
  21. data/lib/jazzy/extensions/bitbucket/img/bitbucket.svg +11 -0
  22. data/lib/jazzy/{themes/apple/assets → extensions/github}/img/gh.png +0 -0
  23. data/lib/jazzy/extensions/gitlab/img/gitlab.svg +23 -0
  24. data/lib/jazzy/gem_version.rb +3 -1
  25. data/lib/jazzy/highlighter.rb +5 -3
  26. data/lib/jazzy/jazzy_markdown.rb +75 -32
  27. data/lib/jazzy/podspec_documenter.rb +14 -16
  28. data/lib/jazzy/search_builder.rb +5 -6
  29. data/lib/jazzy/source_declaration/access_control_level.rb +7 -5
  30. data/lib/jazzy/source_declaration/type.rb +29 -3
  31. data/lib/jazzy/source_declaration.rb +22 -5
  32. data/lib/jazzy/source_document.rb +8 -5
  33. data/lib/jazzy/source_host.rb +111 -0
  34. data/lib/jazzy/source_mark.rb +8 -6
  35. data/lib/jazzy/source_module.rb +6 -6
  36. data/lib/jazzy/sourcekitten.rb +155 -81
  37. data/lib/jazzy/stats.rb +14 -3
  38. data/lib/jazzy/symbol_graph/constraint.rb +5 -1
  39. data/lib/jazzy/symbol_graph/ext_node.rb +3 -1
  40. data/lib/jazzy/symbol_graph/graph.rb +19 -12
  41. data/lib/jazzy/symbol_graph/relationship.rb +9 -0
  42. data/lib/jazzy/symbol_graph/sym_node.rb +25 -7
  43. data/lib/jazzy/symbol_graph/symbol.rb +54 -25
  44. data/lib/jazzy/symbol_graph.rb +43 -32
  45. data/lib/jazzy/themes/apple/assets/css/highlight.css.scss +63 -59
  46. data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +5 -1
  47. data/lib/jazzy/themes/apple/assets/js/jazzy.js +4 -0
  48. data/lib/jazzy/themes/apple/assets/js/jazzy.search.js +4 -0
  49. data/lib/jazzy/themes/apple/templates/doc.mustache +4 -5
  50. data/lib/jazzy/themes/apple/templates/footer.mustache +1 -1
  51. data/lib/jazzy/themes/apple/templates/header.mustache +6 -6
  52. data/lib/jazzy/themes/apple/templates/task.mustache +6 -11
  53. data/lib/jazzy/themes/fullwidth/assets/css/highlight.css.scss +63 -59
  54. data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +6 -2
  55. data/lib/jazzy/themes/fullwidth/assets/js/jazzy.js +4 -0
  56. data/lib/jazzy/themes/fullwidth/assets/js/jazzy.search.js +4 -0
  57. data/lib/jazzy/themes/fullwidth/templates/doc.mustache +4 -5
  58. data/lib/jazzy/themes/fullwidth/templates/footer.mustache +1 -1
  59. data/lib/jazzy/themes/fullwidth/templates/header.mustache +8 -8
  60. data/lib/jazzy/themes/fullwidth/templates/task.mustache +6 -11
  61. data/lib/jazzy/themes/jony/assets/css/highlight.css.scss +63 -59
  62. data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +5 -1
  63. data/lib/jazzy/themes/jony/assets/js/jazzy.js +4 -0
  64. data/lib/jazzy/themes/jony/templates/doc.mustache +4 -5
  65. data/lib/jazzy/themes/jony/templates/footer.mustache +1 -1
  66. data/lib/jazzy/themes/jony/templates/header.mustache +6 -6
  67. data/lib/jazzy/themes/jony/templates/task.mustache +6 -11
  68. data/lib/jazzy.rb +2 -0
  69. data/spec/integration_spec.rb +46 -42
  70. data/spec/spec_helper/pre_flight.rb +2 -0
  71. data/spec/spec_helper.rb +3 -1
  72. metadata +32 -16
  73. data/lib/jazzy/themes/fullwidth/assets/img/gh.png +0 -0
  74. data/lib/jazzy/themes/jony/assets/img/gh.png +0 -0
  75. data/spec/sourcekitten_spec.rb +0 -6
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'mustache'
3
5
  require 'pathname'
@@ -51,8 +53,8 @@ module Jazzy
51
53
 
52
54
  def self.children_for_doc(doc)
53
55
  doc.children
54
- .sort_by { |c| [c.nav_order, c.name, c.usr || ''] }
55
- .flat_map do |child|
56
+ .sort_by { |c| [c.nav_order, c.name, c.usr || ''] }
57
+ .flat_map do |child|
56
58
  # FIXME: include arbitrarily nested extensible types
57
59
  [{ name: child.name, url: child.url }] +
58
60
  Array(child.children.select do |sub_child|
@@ -68,8 +70,7 @@ module Jazzy
68
70
  # @return [SourceModule] the documented source module
69
71
  def self.build(options)
70
72
  if options.sourcekitten_sourcefile_configured
71
- stdout = '[' + options.sourcekitten_sourcefile.map(&:read)
72
- .join(',') + ']'
73
+ stdout = "[#{options.sourcekitten_sourcefile.map(&:read).join(',')}]"
73
74
  elsif options.podspec_configured
74
75
  pod_documenter = PodspecDocumenter.new(options.podspec)
75
76
  stdout = pod_documenter.sourcekitten_output(options)
@@ -104,6 +105,7 @@ module Jazzy
104
105
  def self.each_doc(output_dir, docs, &block)
105
106
  docs.each do |doc|
106
107
  next unless doc.render_as_page?
108
+
107
109
  # Filepath is relative to documentation root:
108
110
  path = output_dir + doc.filepath
109
111
  block.call(doc, path)
@@ -132,8 +134,8 @@ module Jazzy
132
134
  SearchBuilder.build(source_module, output_dir)
133
135
  end
134
136
 
135
- copy_assets(output_dir)
136
- copy_extensions(output_dir)
137
+ copy_extensions(source_module, output_dir)
138
+ copy_theme_assets(output_dir)
137
139
 
138
140
  DocsetBuilder.new(output_dir, source_module).build!
139
141
 
@@ -170,7 +172,7 @@ module Jazzy
170
172
 
171
173
  def self.relative_path_if_inside(path, base_path)
172
174
  relative = path.relative_path_from(base_path)
173
- if relative.to_path =~ %r{/^..(\/|$)/}
175
+ if relative.to_path =~ %r{/^..(/|$)/}
174
176
  path
175
177
  else
176
178
  relative
@@ -181,7 +183,7 @@ module Jazzy
181
183
  decls.map do |decl|
182
184
  {
183
185
  file: decl.file,
184
- line: decl.line || decl.start_line,
186
+ line: decl.start_line || decl.line,
185
187
  symbol: decl.fully_qualified_name,
186
188
  symbol_kind: decl.type.kind,
187
189
  warning: 'undocumented',
@@ -206,7 +208,7 @@ module Jazzy
206
208
  end
207
209
  end
208
210
 
209
- def self.copy_assets(destination)
211
+ def self.copy_theme_assets(destination)
210
212
  assets_directory = Config.instance.theme_directory + 'assets'
211
213
  FileUtils.cp_r(assets_directory.children, destination)
212
214
  Pathname.glob(destination + 'css/**/*.scss').each do |scss|
@@ -217,12 +219,15 @@ module Jazzy
217
219
  end
218
220
  end
219
221
 
220
- def self.copy_extensions(destination)
222
+ def self.copy_extensions(source_module, destination)
223
+ if source_host = source_module.host&.extension
224
+ copy_extension(source_host, destination)
225
+ end
221
226
  copy_extension('katex', destination) if Markdown.has_math
222
227
  end
223
228
 
224
229
  def self.copy_extension(name, destination)
225
- ext_directory = Pathname(__FILE__).parent + 'extensions/' + name
230
+ ext_directory = Pathname(__dir__) / 'extensions' / name
226
231
  FileUtils.cp_r(ext_directory.children, destination)
227
232
  end
228
233
 
@@ -231,26 +236,42 @@ module Jazzy
231
236
  SourceKitten.autolink_document(html, doc_model)
232
237
  end
233
238
 
239
+ def self.render_inline(doc_model, markdown)
240
+ html = Markdown.render_inline(markdown)
241
+ SourceKitten.autolink_document(html, doc_model)
242
+ end
243
+
244
+ # Build Mustache document - common fields between page types
245
+ def self.new_document(source_module, doc_model)
246
+ Doc.new.tap do |doc|
247
+ doc[:custom_head] = Config.instance.custom_head
248
+ doc[:disable_search] = Config.instance.disable_search
249
+ doc[:doc_coverage] = source_module.doc_coverage unless
250
+ Config.instance.hide_documentation_coverage
251
+ doc[:structure] = source_module.doc_structure
252
+ doc[:module_name] = source_module.name
253
+ doc[:author_name] = source_module.author_name
254
+ if source_host = source_module.host
255
+ doc[:source_host_name] = source_host.name
256
+ doc[:source_host_url] = source_host.url
257
+ doc[:source_host_image] = source_host.image
258
+ doc[:source_host_item_url] = source_host.item_url(doc_model)
259
+ doc[:github_url] = doc[:source_host_url]
260
+ doc[:github_token_url] = doc[:source_host_item_url]
261
+ end
262
+ doc[:dash_url] = source_module.dash_url
263
+ end
264
+ end
265
+
234
266
  # Build Mustache document from a markdown source file
235
- # @param [Config] options Build options
267
+ # @param [SourceModule] module-wide settings
236
268
  # @param [Hash] doc_model Parsed doc. @see SourceKitten.parse
237
269
  # @param [String] path_to_root
238
- # @param [Array] doc_structure doc structure comprised of section names and
239
- # child names and URLs. @see doc_structure_for_docs
240
270
  def self.document_markdown(source_module, doc_model, path_to_root)
241
- doc = Doc.new # Mustache model instance
271
+ doc = new_document(source_module, doc_model)
242
272
  name = doc_model.name == 'index' ? source_module.name : doc_model.name
243
273
  doc[:name] = name
244
274
  doc[:overview] = render(doc_model, doc_model.content(source_module))
245
- doc[:custom_head] = Config.instance.custom_head
246
- doc[:disable_search] = Config.instance.disable_search
247
- doc[:doc_coverage] = source_module.doc_coverage unless
248
- Config.instance.hide_documentation_coverage
249
- doc[:structure] = source_module.doc_structure
250
- doc[:module_name] = source_module.name
251
- doc[:author_name] = source_module.author_name
252
- doc[:github_url] = source_module.github_url
253
- doc[:dash_url] = source_module.dash_url
254
275
  doc[:path_to_root] = path_to_root
255
276
  doc[:hide_name] = true
256
277
  doc.render.gsub(ELIDED_AUTOLINK_TOKEN, path_to_root)
@@ -324,30 +345,6 @@ module Jazzy
324
345
  end
325
346
  # rubocop:enable Metrics/MethodLength
326
347
 
327
- def self.should_link_to_github(file)
328
- return unless file
329
- file = file.realpath.to_path
330
- source_directory = Config.instance.source_directory.to_path
331
- file.start_with?(source_directory)
332
- end
333
-
334
- # Construct Github token URL
335
- # @param [Hash] item Parsed doc child item
336
- # @param [Config] options Build options
337
- def self.gh_token_url(item, source_module)
338
- return unless github_prefix = source_module.github_file_prefix
339
- return unless should_link_to_github(item.file)
340
- gh_line = if item.start_line && (item.start_line != item.end_line)
341
- "#L#{item.start_line}-L#{item.end_line}"
342
- else
343
- "#L#{item.line}"
344
- end
345
- relative_file_path = item.file.realpath.relative_path_from(
346
- source_module.root_path,
347
- )
348
- "#{github_prefix}/#{relative_file_path}#{gh_line}"
349
- end
350
-
351
348
  # Build mustache item for a top-level doc
352
349
  # @param [Hash] item Parsed doc child item
353
350
  # @param [Config] options Build options
@@ -355,27 +352,31 @@ module Jazzy
355
352
  def self.render_item(item, source_module)
356
353
  # Combine abstract and discussion into abstract
357
354
  abstract = (item.abstract || '') + (item.discussion || '')
355
+ source_host_item_url = source_module.host&.item_url(item)
358
356
  {
359
- name: item.name,
360
- name_html: item.name.gsub(':', ':<wbr>'),
361
- abstract: abstract,
362
- declaration: item.display_declaration,
363
- language: item.display_language,
357
+ name: item.name,
358
+ name_html: item.name.gsub(':', ':<wbr>'),
359
+ abstract: abstract,
360
+ declaration: item.display_declaration,
361
+ language: item.display_language,
364
362
  other_language_declaration: item.display_other_language_declaration,
365
- usr: item.usr,
366
- dash_type: item.type.dash_type,
367
- github_token_url: gh_token_url(item, source_module),
368
- default_impl_abstract: item.default_impl_abstract,
369
- from_protocol_extension: item.from_protocol_extension,
370
- return: item.return,
371
- parameters: (item.parameters if item.parameters.any?),
372
- url: (item.url if item.render_as_page?),
373
- start_line: item.start_line,
374
- end_line: item.end_line,
375
- direct_link: item.omit_content_from_parent?,
376
- deprecation_message: item.deprecation_message,
377
- unavailable_message: item.unavailable_message,
378
- usage_discouraged: item.usage_discouraged?,
363
+ usr: item.usr,
364
+ dash_type: item.type.dash_type,
365
+ source_host_item_url: source_host_item_url,
366
+ github_token_url: source_host_item_url,
367
+ default_impl_abstract: item.default_impl_abstract,
368
+ from_protocol_extension: item.from_protocol_extension,
369
+ return: item.return,
370
+ parameters: (item.parameters if item.parameters.any?),
371
+ url: (item.url if item.render_as_page?),
372
+ start_line: item.start_line,
373
+ end_line: item.end_line,
374
+ direct_link: item.omit_content_from_parent?,
375
+ deprecation_message: item.deprecation_message,
376
+ unavailable_message: item.unavailable_message,
377
+ usage_discouraged: item.usage_discouraged?,
378
+ async: item.async,
379
+ declaration_note: item.declaration_note,
379
380
  }
380
381
  end
381
382
  # rubocop:enable Metrics/MethodLength
@@ -383,7 +384,7 @@ module Jazzy
383
384
  def self.make_task(mark, uid, items, doc_model)
384
385
  {
385
386
  name: mark.name,
386
- name_html: (render(doc_model, mark.name) if mark.name),
387
+ name_html: (render_inline(doc_model, mark.name) if mark.name),
387
388
  uid: ERB::Util.url_encode(uid),
388
389
  items: items,
389
390
  pre_separator: mark.has_start_dash,
@@ -412,12 +413,10 @@ module Jazzy
412
413
  end
413
414
 
414
415
  # rubocop:disable Metrics/MethodLength
415
- # Build Mustache document from single parsed doc
416
- # @param [Config] options Build options
416
+ # Build Mustache document from single parsed decl
417
+ # @param [SourceModule] module-wide settings
417
418
  # @param [Hash] doc_model Parsed doc. @see SourceKitten.parse
418
419
  # @param [String] path_to_root
419
- # @param [Array] doc_structure doc structure comprised of section names and
420
- # child names and URLs. @see doc_structure_for_docs
421
420
  def self.document(source_module, doc_model, path_to_root)
422
421
  if doc_model.type.markdown?
423
422
  return document_markdown(source_module, doc_model, path_to_root)
@@ -429,11 +428,7 @@ module Jazzy
429
428
  overview = render(doc_model, alternative_abstract) + overview
430
429
  end
431
430
 
432
- doc = Doc.new # Mustache model instance
433
- doc[:custom_head] = Config.instance.custom_head
434
- doc[:disable_search] = Config.instance.disable_search
435
- doc[:doc_coverage] = source_module.doc_coverage unless
436
- Config.instance.hide_documentation_coverage
431
+ doc = new_document(source_module, doc_model)
437
432
  doc[:name] = doc_model.name
438
433
  doc[:kind] = doc_model.type.name
439
434
  doc[:dash_type] = doc_model.type.dash_type
@@ -444,13 +439,7 @@ module Jazzy
444
439
  doc[:overview] = overview
445
440
  doc[:parameters] = doc_model.parameters
446
441
  doc[:return] = doc_model.return
447
- doc[:structure] = source_module.doc_structure
448
442
  doc[:tasks] = render_tasks(source_module, doc_model.children)
449
- doc[:module_name] = source_module.name
450
- doc[:author_name] = source_module.author_name
451
- doc[:github_url] = source_module.github_url
452
- doc[:github_token_url] = gh_token_url(doc_model, source_module)
453
- doc[:dash_url] = source_module.dash_url
454
443
  doc[:path_to_root] = path_to_root
455
444
  doc[:deprecation_message] = doc_model.deprecation_message
456
445
  doc[:unavailable_message] = doc_model.unavailable_message
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mustache'
2
4
  require 'sqlite3'
3
5
 
@@ -89,7 +91,7 @@ module Jazzy
89
91
  (output_dir + "#{source_module.name}.xml").open('w') do |xml|
90
92
  url = URI.join(config.root_url, "docsets/#{source_module.name}.tgz")
91
93
  xml << "<entry><version>#{config.version}</version><url>#{url}" \
92
- "</url></entry>\n"
94
+ "</url></entry>\n"
93
95
  end
94
96
  end
95
97
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
 
3
5
  require 'jazzy/jazzy_markdown'
@@ -12,19 +14,21 @@ module Jazzy
12
14
  SourceDocument.new.tap do |sd|
13
15
  sd.name = File.basename(file_path, '.md')
14
16
  sd.overview = overview Pathname(file_path)
15
- sd.usr = 'documentation.' + sd.name
17
+ sd.usr = "documentation.#{sd.name}"
16
18
  end
17
19
  end
18
20
  end
19
21
 
20
22
  def self.overview(file_path)
21
- return '' unless file_path && file_path.exist?
23
+ return '' unless file_path&.exist?
24
+
22
25
  file_path.read
23
26
  end
24
27
 
25
28
  def self.documentation_entries
26
29
  return [] unless
27
30
  config.documentation_glob_configured && config.documentation_glob
31
+
28
32
  config.documentation_glob.select { |e| File.file? e }
29
33
  end
30
34
  end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Jazzy
2
4
  module Executable
3
5
  class IO < Array
4
6
  def initialize(io = nil)
7
+ super()
5
8
  @io = io
6
9
  end
7
10
 
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg fill="none" version="1.1" viewBox="0 0 24 21.58" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="m22.95 7.2332h-7.1932l-1.1989 7.0734h-4.9953l-5.8745 6.9934s0.27972 0.2398 0.67935 0.2398h15.665c0.3597 0 0.6794-0.2797 0.7593-0.6394z" fill="url(#paint0_linear)"/>
4
+ <path d="m0.77041 0c-0.47956 0-0.83918 0.43959-0.75926 0.87918l3.237 19.822c0.03996 0.2398 0.15986 0.4796 0.35968 0.6394 0 0 0.27972 0.2398 0.67935 0.2398l6.0743-7.2732h-0.8392l-1.3188-7.0734h14.746l1.039-6.3541c0.08-0.47955-0.2797-0.87918-0.7593-0.87918z" fill="#fff"/>
5
+ <defs>
6
+ <linearGradient id="paint0_linear" x1="27.898" x2="16.618" y1="15.387" y2="23.023" gradientTransform="translate(-4 -5)" gradientUnits="userSpaceOnUse">
7
+ <stop stop-color="#fff" stop-opacity=".4" offset=".071833"/>
8
+ <stop stop-color="#fff" offset="1"/>
9
+ </linearGradient>
10
+ </defs>
11
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ height="313.44601"
4
+ width="338.96616"
5
+ xml:space="preserve"
6
+ viewBox="0 0 338.96616 313.44601"
7
+ y="0px"
8
+ x="0px"
9
+ version="1.1">
10
+ <style
11
+ id="style10"
12
+ type="text/css">
13
+ .st2{fill:#FFFFFF;}
14
+ </style>
15
+ <g
16
+ transform="translate(-123.54995,-122.776)"
17
+ id="logo_art">
18
+ <path
19
+ id="path12"
20
+ d="m 461.514,298.355 -18.049,-55.587 c 0.008,0.025 0.011,0.051 0.019,0.076 -0.009,-0.029 -0.014,-0.058 -0.022,-0.087 -10e-4,-0.002 -10e-4,-0.003 -10e-4,-0.005 0,-0.001 0,-0.002 0,-0.002 l -35.83,-110.31 c -1.96,-5.811 -7.353,-9.711 -13.536,-9.663 -6.201,0.032 -11.446,3.857 -13.364,9.748 L 346.721,237.23 H 239.408 L 205.334,132.518 c -1.916,-5.886 -7.162,-9.71 -13.362,-9.742 -0.025,0 -0.049,0 -0.075,0 -6.105,0 -11.509,3.876 -13.49,9.752 l -35.732,110.211 -0.005,0.014 c 0,0.001 0,0.002 0,0.003 -0.009,0.028 -0.013,0.056 -0.022,0.084 0.008,-0.025 0.011,-0.051 0.019,-0.076 l -18.115,55.591 c -2.725,8.392 0.232,17.512 7.36,22.697 L 288.328,434.7 c 0.023,0.017 0.049,0.027 0.072,0.044 0.067,0.048 0.132,0.097 0.2,0.142 -0.064,-0.043 -0.124,-0.09 -0.187,-0.134 0,0 0,-0.001 -0.001,-0.001 0.01,0.008 0.022,0.013 0.033,0.02 0.009,0.006 0.018,0.01 0.027,0.016 0.001,0.001 0.002,0.002 0.004,0.003 0.242,0.168 0.493,0.322 0.753,0.463 0.036,0.02 0.068,0.045 0.104,0.064 10e-4,0 10e-4,10e-4 0.002,10e-4 0.022,0.011 0.042,0.025 0.064,0.036 0.017,0.008 0.035,0.013 0.051,0.021 0.012,0.006 0.025,0.01 0.037,0.015 0.029,0.014 0.061,0.023 0.09,0.038 0.136,0.065 0.279,0.118 0.419,0.175 0.131,0.054 0.258,0.117 0.392,0.164 0.006,0.002 0.011,0.005 0.017,0.007 0.022,0.008 0.042,0.019 0.065,0.027 0.028,0.01 0.055,0.021 0.083,0.03 0.011,0.003 0.022,0.005 0.033,0.008 0.035,0.011 0.073,0.016 0.108,0.026 0.013,0.004 0.028,0.006 0.042,0.01 0.188,0.057 0.383,0.098 0.577,0.141 0.076,0.017 0.149,0.041 0.226,0.055 0.011,0.002 0.021,0.006 0.033,0.008 0.025,0.005 0.048,0.014 0.074,0.018 0.041,0.007 0.081,0.02 0.123,0.026 0.033,0.005 0.067,0.003 0.1,0.008 0.006,0.001 0.011,0 0.017,0.001 0.002,0 0.003,0 0.005,0 0.369,0.053 0.743,0.09 1.124,0.09 0.002,0 0.004,0 0.007,0 v 0 c 0.001,0 0.002,0 0.002,0 0,0 10e-4,0 10e-4,0 0.001,0 0.002,0 0.003,0 0.382,0 0.756,-0.037 1.126,-0.09 10e-4,0 0.003,0 0.004,0 0.006,-0.001 0.012,0 0.018,-0.001 0.033,-0.005 0.068,-0.003 0.101,-0.008 0.042,-0.007 0.082,-0.019 0.124,-0.026 0.025,-0.004 0.048,-0.013 0.073,-0.018 0.011,-0.002 0.021,-0.006 0.032,-0.008 0.078,-0.015 0.153,-0.039 0.231,-0.056 0.191,-0.042 0.383,-0.083 0.57,-0.139 0.013,-0.004 0.026,-0.005 0.039,-0.009 0.037,-0.011 0.075,-0.016 0.112,-0.027 0.011,-0.004 0.023,-0.005 0.034,-0.008 0.029,-0.009 0.057,-0.021 0.085,-0.031 0.022,-0.008 0.042,-0.019 0.064,-0.027 0.006,-0.002 0.011,-0.005 0.017,-0.007 0.142,-0.05 0.276,-0.116 0.415,-0.173 0.129,-0.054 0.261,-0.102 0.387,-0.162 0.031,-0.015 0.064,-0.024 0.094,-0.039 0.012,-0.006 0.026,-0.01 0.038,-0.016 0.017,-0.008 0.035,-0.013 0.052,-0.022 0.023,-0.012 0.045,-0.026 0.067,-0.037 0,0 10e-4,0 10e-4,-10e-4 0.037,-0.019 0.07,-0.046 0.107,-0.066 0.258,-0.14 0.508,-0.293 0.749,-0.46 0.019,-0.013 0.041,-0.023 0.061,-0.037 0.005,-0.004 0.011,-0.006 0.016,-0.01 0.023,-0.017 0.05,-0.028 0.073,-0.045 l 156.44,-113.65 c 7.124,-5.182 10.081,-14.302 7.356,-22.694 z m -67.32,-155.581 30.68,94.456 h -61.36 z m 25.307,110.428 -12.519,16.041 -92.334,118.307 43.677,-134.348 z M 285.428,430.707 c 0,0 0,0 0,0 0.008,0.024 0.021,0.046 0.029,0.071 -0.008,-0.025 -0.021,-0.047 -0.029,-0.071 z M 271.42,387.558 166.624,253.202 v 0 h 61.18 z m -79.545,-244.785 30.737,94.457 h -61.36 z m -50.571,165.36 c -1.516,-1.103 -2.144,-3.05 -1.563,-4.838 l 13.466,-41.325 98.67,126.502 z m 146.749,126.356 c -0.031,-0.025 -0.061,-0.052 -0.091,-0.078 -0.006,-0.005 -0.012,-0.012 -0.019,-0.017 -0.06,-0.05 -0.119,-0.101 -0.177,-0.153 -0.114,-0.099 -0.226,-0.2 -0.333,-0.306 0.009,0.008 0.019,0.015 0.028,0.023 0.012,0.011 0.025,0.02 0.037,0.031 0.229,0.219 0.47,0.425 0.722,0.615 0.003,0.002 0.005,0.005 0.008,0.007 0.012,0.009 0.022,0.02 0.034,0.03 -0.069,-0.05 -0.141,-0.098 -0.209,-0.152 z m 4.975,-32.097 -25.665,-79.059 -22.766,-70.131 h 96.933 z m 5.253,31.849 c -0.06,0.052 -0.118,0.104 -0.179,0.154 -0.007,0.006 -0.014,0.013 -0.021,0.019 -0.031,0.025 -0.06,0.052 -0.09,0.077 -0.066,0.053 -0.138,0.101 -0.207,0.152 0.012,-0.009 0.022,-0.021 0.035,-0.029 0.002,-0.002 0.004,-0.004 0.006,-0.006 0.252,-0.19 0.492,-0.394 0.719,-0.613 0.009,-0.009 0.02,-0.016 0.029,-0.024 0.012,-0.011 0.025,-0.02 0.036,-0.031 -0.106,0.103 -0.217,0.203 -0.328,0.301 z M 444.766,308.13 334.209,388.447 432.912,261.98 l 13.412,41.307 c 0.582,1.796 -0.045,3.743 -1.558,4.843 z"
21
+ class="st2" />
22
+ </g>
23
+ </svg>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Jazzy
2
- VERSION = '0.13.7'.freeze unless defined? Jazzy::VERSION
4
+ VERSION = '0.14.2' unless defined? Jazzy::VERSION
3
5
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rouge'
2
4
 
3
5
  module Jazzy
4
6
  # This module helps highlight code
5
7
  module Highlighter
6
- SWIFT = 'swift'.freeze
7
- OBJC = 'objective_c'.freeze
8
+ SWIFT = 'swift'
9
+ OBJC = 'objective_c'
8
10
 
9
11
  class Formatter < Rouge::Formatters::HTML
10
12
  def initialize(language)
@@ -12,7 +14,7 @@ module Jazzy
12
14
  super()
13
15
  end
14
16
 
15
- def stream(tokens, &b)
17
+ def stream(tokens, &block)
16
18
  yield "<pre class=\"highlight #{@language}\"><code>"
17
19
  super
18
20
  yield "</code></pre>\n"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'redcarpet'
2
4
  require 'rouge'
3
5
  require 'rouge/plugins/redcarpet'
@@ -38,10 +40,12 @@ module Jazzy
38
40
  mapped = map_footnote(num)
39
41
  "\n<li><div class='footnote-def' id=\"fn#{mapped}\">" +
40
42
  text.sub(%r{(?=</p>)},
41
- "&nbsp;<a href=\"#fnref#{mapped}\">&#8617;</a></div></li>")
43
+ "&nbsp;<a href=\"#fnref#{mapped}\">&#8617;</a>") +
44
+ '</div></li>'
42
45
  end
43
46
  end
44
47
 
48
+ # rubocop:disable Metrics/ClassLength
45
49
  class JazzyHTML < Redcarpet::Render::HTML
46
50
  include Redcarpet::Render::SmartyPants
47
51
  include Rouge::Plugins::Redcarpet
@@ -51,24 +55,27 @@ module Jazzy
51
55
 
52
56
  def header(text, header_level)
53
57
  text_slug = text.gsub(/[^[[:word:]]]+/, '-')
54
- .downcase
55
- .sub(/^-/, '')
56
- .sub(/-$/, '')
58
+ .downcase
59
+ .sub(/^-/, '')
60
+ .sub(/-$/, '')
57
61
 
58
62
  "<h#{header_level} id='#{text_slug}' class='heading'>" \
59
63
  "#{text}" \
60
- "</h#{header_level}>\n"
64
+ "</h#{header_level}>\n"
61
65
  end
62
66
 
63
67
  def codespan(text)
64
- if /^\$\$(.*)\$\$$/m =~ text
65
- o = ["<div class='math m-block'>", Regexp.last_match[1], '</div>']
68
+ case text
69
+ when /^\$\$(.*)\$\$$/m
70
+ o = ["</p><div class='math m-block'>",
71
+ Regexp.last_match[1],
72
+ '</div><p>']
66
73
  Markdown.has_math = true
67
- elsif /^\$(.*)\$$/m =~ text
74
+ when /^\$(.*)\$$/m
68
75
  o = ["<span class='math m-inline'>", Regexp.last_match[1], '</span>']
69
76
  Markdown.has_math = true
70
77
  else
71
- o = ['<code>', text, '</code>']
78
+ o = ['<code>', text.to_s, '</code>']
72
79
  end
73
80
 
74
81
  o[0] + CGI.escapeHTML(o[1]) + o[2]
@@ -115,10 +122,10 @@ module Jazzy
115
122
  # any one of our special list types
116
123
  (#{SPECIAL_LIST_TYPES.map(&Regexp.method(:escape)).join('|')})
117
124
  [\s:] # followed by either a space or a colon
118
- }ix
125
+ }ix.freeze
119
126
 
120
127
  ELIDED_LI_TOKEN =
121
- '7wNVzLB0OYPL2eGlPKu8q4vITltqh0Y6DPZf659TPMAeYh49o'.freeze
128
+ '7wNVzLB0OYPL2eGlPKu8q4vITltqh0Y6DPZf659TPMAeYh49o'
122
129
 
123
130
  def list_item(text, _list_type)
124
131
  if text =~ SPECIAL_LIST_TYPE_REGEX
@@ -126,30 +133,58 @@ module Jazzy
126
133
  if UNIQUELY_HANDLED_CALLOUTS.include? type.downcase
127
134
  return ELIDED_LI_TOKEN
128
135
  end
129
- return render_aside(type, text.sub(/#{Regexp.escape(type)}:\s+/, ''))
136
+
137
+ return render_list_aside(type,
138
+ text.sub(/#{Regexp.escape(type)}:\s+/, ''))
130
139
  end
131
- str = '<li>'
132
- str << text.strip
133
- str << "</li>\n"
140
+ "<li>#{text.strip}</li>\n"
141
+ end
142
+
143
+ def render_list_aside(type, text)
144
+ "</ul>#{render_aside(type, text).chomp}<ul>\n"
134
145
  end
135
146
 
136
147
  def render_aside(type, text)
137
148
  <<-HTML
138
- </ul><div class="aside aside-#{type.underscore.tr('_', '-')}">
149
+ <div class="aside aside-#{type.underscore.tr('_', '-')}">
139
150
  <p class="aside-title">#{type.underscore.humanize}</p>
140
151
  #{text}
141
- </div><ul>
152
+ </div>
142
153
  HTML
143
154
  end
144
155
 
145
156
  def list(text, list_type)
146
157
  elided = text.gsub!(ELIDED_LI_TOKEN, '')
147
158
  return if text =~ /\A\s*\Z/ && elided
148
- str = "\n"
149
- str << (list_type == :ordered ? "<ol>\n" : "<ul>\n")
150
- str << text
151
- str << (list_type == :ordered ? "</ol>\n" : "</ul>\n")
152
- str.gsub(%r{\n?<ul>\n<\/ul>}, '')
159
+
160
+ tag = list_type == :ordered ? 'ol' : 'ul'
161
+ "\n<#{tag}>\n#{text}</#{tag}>\n"
162
+ .gsub(%r{\n?<ul>\n?</ul>}, '')
163
+ end
164
+
165
+ # List from
166
+ # https://developer.apple.com/documentation/xcode/formatting-your-documentation-content#Add-Notes-and-Other-Asides
167
+ DOCC_CALLOUTS = %w[note
168
+ important
169
+ warning
170
+ tip
171
+ experiment].freeze
172
+
173
+ DOCC_CALLOUT_REGEX = %r{
174
+ \A\s* # optional leading spaces
175
+ (?:<p>\s*)? # optional opening p tag
176
+ # any one of the callout names
177
+ (#{DOCC_CALLOUTS.map(&Regexp.method(:escape)).join('|')})
178
+ : # followed directly by a colon
179
+ }ix.freeze
180
+
181
+ def block_quote(html)
182
+ if html =~ DOCC_CALLOUT_REGEX
183
+ type = Regexp.last_match[1]
184
+ render_aside(type, html.sub(/#{Regexp.escape(type)}:\s*/, ''))
185
+ else
186
+ "\n<blockquote>\n#{html}</blockquote>\n"
187
+ end
153
188
  end
154
189
 
155
190
  def block_code(code, language)
@@ -160,6 +195,7 @@ module Jazzy
160
195
  Highlighter::Formatter.new(lexer.tag)
161
196
  end
162
197
  end
198
+ # rubocop:enable Metrics/ClassLength
163
199
 
164
200
  REDCARPET_OPTIONS = {
165
201
  autolink: true,
@@ -182,22 +218,22 @@ module Jazzy
182
218
  super
183
219
  end
184
220
 
185
- INTRO_PAT = '\A(?<intro>\s*(<p>\s*)?)'.freeze
186
- OUTRO_PAT = '(?<outro>.*)\z'.freeze
221
+ INTRO_PAT = '\A(?<intro>\s*(<p>\s*)?)'
222
+ OUTRO_PAT = '(?<outro>.*)\z'
187
223
 
188
- RETURNS_REGEX = /#{INTRO_PAT}returns:#{OUTRO_PAT}/im
224
+ RETURNS_REGEX = /#{INTRO_PAT}returns:#{OUTRO_PAT}/im.freeze
189
225
 
190
- IDENT_PAT = '(?<param>\S+)'.freeze
226
+ IDENT_PAT = '(?<param>\S+)'
191
227
 
192
228
  # Param formats: normal swift, objc via sourcekitten, and
193
229
  # possibly inside 'Parameters:'
194
- PARAM_PAT1 = "(parameter +#{IDENT_PAT}\\s*:)".freeze
195
- PARAM_PAT2 = "(parameter:\\s*#{IDENT_PAT}\\s+)".freeze
196
- PARAM_PAT3 = "(#{IDENT_PAT}\\s*:)".freeze
230
+ PARAM_PAT1 = "(parameter +#{IDENT_PAT}\\s*:)"
231
+ PARAM_PAT2 = "(parameter:\\s*#{IDENT_PAT}\\s+)"
232
+ PARAM_PAT3 = "(#{IDENT_PAT}\\s*:)"
197
233
 
198
- PARAM_PAT = "(?:#{PARAM_PAT1}|#{PARAM_PAT2}|#{PARAM_PAT3})".freeze
234
+ PARAM_PAT = "(?:#{PARAM_PAT1}|#{PARAM_PAT2}|#{PARAM_PAT3})"
199
235
 
200
- PARAM_REGEX = /#{INTRO_PAT}#{PARAM_PAT}#{OUTRO_PAT}/im
236
+ PARAM_REGEX = /#{INTRO_PAT}#{PARAM_PAT}#{OUTRO_PAT}/im.freeze
201
237
 
202
238
  def list_item(text, _list_type)
203
239
  if text =~ RETURNS_REGEX
@@ -225,12 +261,19 @@ module Jazzy
225
261
  @markdown ||= Redcarpet::Markdown.new(renderer, REDCARPET_OPTIONS)
226
262
  end
227
263
 
264
+ # Produces <p>-delimited block content
228
265
  def self.render(markdown_text, default_language = nil)
229
266
  renderer.reset
230
267
  renderer.default_language = default_language
231
268
  markdown.render(markdown_text)
232
269
  end
233
270
 
271
+ # Produces <span>-delimited inline content
272
+ def self.render_inline(markdown_text, default_language = nil)
273
+ render(markdown_text, default_language)
274
+ .sub(%r{^<p>(.*)</p>$}, '<span>\1</span>')
275
+ end
276
+
234
277
  def self.rendered_returns
235
278
  renderer.returns
236
279
  end
@@ -242,7 +285,7 @@ module Jazzy
242
285
  class JazzyCopyright < Redcarpet::Render::HTML
243
286
  def link(link, _title, content)
244
287
  %(<a class="link" href="#{link}" target="_blank" \
245
- rel="external">#{content}</a>)
288
+ rel="external noopener">#{content}</a>)
246
289
  end
247
290
  end
248
291