jazzy 0.9.4 → 0.11.1

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 (49) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +3 -3
  3. data/CHANGELOG.md +162 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/Gemfile.lock +67 -70
  6. data/README.md +92 -13
  7. data/Rakefile +7 -6
  8. data/bin/sourcekitten +0 -0
  9. data/jazzy.gemspec +4 -4
  10. data/lib/jazzy/config.rb +38 -5
  11. data/lib/jazzy/doc.rb +19 -2
  12. data/lib/jazzy/doc_builder.rb +22 -24
  13. data/lib/jazzy/docset_builder.rb +1 -1
  14. data/lib/jazzy/documentation_generator.rb +0 -7
  15. data/lib/jazzy/gem_version.rb +1 -1
  16. data/lib/jazzy/jazzy_markdown.rb +1 -1
  17. data/lib/jazzy/podspec_documenter.rb +36 -9
  18. data/lib/jazzy/source_declaration.rb +19 -4
  19. data/lib/jazzy/source_declaration/access_control_level.rb +10 -3
  20. data/lib/jazzy/source_declaration/type.rb +11 -1
  21. data/lib/jazzy/source_document.rb +21 -4
  22. data/lib/jazzy/sourcekitten.rb +69 -35
  23. data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +13 -5
  24. data/lib/jazzy/themes/apple/assets/js/jazzy.js +33 -20
  25. data/lib/jazzy/themes/apple/assets/js/jquery.min.js +2 -4
  26. data/lib/jazzy/themes/apple/templates/deprecation.mustache +12 -0
  27. data/lib/jazzy/themes/apple/templates/doc.mustache +1 -0
  28. data/lib/jazzy/themes/apple/templates/header.mustache +1 -1
  29. data/lib/jazzy/themes/apple/templates/task.mustache +12 -0
  30. data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +10 -4
  31. data/lib/jazzy/themes/fullwidth/assets/js/jazzy.js +33 -17
  32. data/lib/jazzy/themes/fullwidth/assets/js/jazzy.search.js +17 -9
  33. data/lib/jazzy/themes/fullwidth/assets/js/jquery.min.js +2 -4
  34. data/lib/jazzy/themes/fullwidth/assets/js/lunr.min.js +1 -6
  35. data/lib/jazzy/themes/fullwidth/assets/js/typeahead.jquery.js +182 -46
  36. data/lib/jazzy/themes/fullwidth/templates/deprecation.mustache +12 -0
  37. data/lib/jazzy/themes/fullwidth/templates/doc.mustache +1 -0
  38. data/lib/jazzy/themes/fullwidth/templates/header.mustache +1 -1
  39. data/lib/jazzy/themes/fullwidth/templates/task.mustache +12 -0
  40. data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +9 -2
  41. data/lib/jazzy/themes/jony/assets/js/jazzy.js +33 -21
  42. data/lib/jazzy/themes/jony/assets/js/jquery.min.js +2 -4
  43. data/lib/jazzy/themes/jony/templates/deprecation.mustache +12 -0
  44. data/lib/jazzy/themes/jony/templates/doc.mustache +1 -0
  45. data/lib/jazzy/themes/jony/templates/header.mustache +1 -1
  46. data/lib/jazzy/themes/jony/templates/task.mustache +12 -0
  47. data/spec/integration_spec.rb +7 -12
  48. metadata +15 -13
  49. data/lib/jazzy/readme_generator.rb +0 -61
@@ -78,7 +78,7 @@ module Jazzy
78
78
  'searchIndex (name, type, path);')
79
79
  source_module.all_declarations.select(&:type).each do |doc|
80
80
  db.execute('INSERT OR IGNORE INTO searchIndex(name, type, path) ' \
81
- 'VALUES (?, ?, ?);', [doc.name, doc.type.dash_type, doc.url])
81
+ 'VALUES (?, ?, ?);', [doc.name, doc.type.dash_type, doc.filepath])
82
82
  end
83
83
  end
84
84
  end
@@ -11,15 +11,8 @@ module Jazzy
11
11
  documentation_entries.map do |file_path|
12
12
  SourceDocument.new.tap do |sd|
13
13
  sd.name = File.basename(file_path, '.md')
14
- sd.url = sd.name.downcase.strip
15
- .tr(' ', '-').gsub(/[^\w-]/, '') + '.html'
16
- sd.type = SourceDeclaration::Type.new 'document.markdown'
17
- sd.children = []
18
14
  sd.overview = overview Pathname(file_path)
19
15
  sd.usr = 'documentation.' + sd.name
20
- sd.abstract = ''
21
- sd.return = ''
22
- sd.parameters = []
23
16
  end
24
17
  end
25
18
  end
@@ -1,3 +1,3 @@
1
1
  module Jazzy
2
- VERSION = '0.9.4'.freeze unless defined? Jazzy::VERSION
2
+ VERSION = '0.11.1'.freeze unless defined? Jazzy::VERSION
3
3
  end
@@ -11,7 +11,7 @@ module Jazzy
11
11
  attr_accessor :default_language
12
12
 
13
13
  def header(text, header_level)
14
- text_slug = text.gsub(/[^\w]+/, '-')
14
+ text_slug = text.gsub(/[^[[:word:]]]+/, '-')
15
15
  .downcase
16
16
  .sub(/^-/, '')
17
17
  .sub(/-$/, '')
@@ -18,7 +18,8 @@ module Jazzy
18
18
  Pod::Config.instance.with_changes(installation_root: installation_root,
19
19
  verbose: false) do
20
20
  sandbox = Pod::Sandbox.new(Pod::Config.instance.sandbox_root)
21
- installer = Pod::Installer.new(sandbox, podfile)
21
+ swift_version = compiler_swift_version(config.swift_version)
22
+ installer = Pod::Installer.new(sandbox, podfile(swift_version))
22
23
  installer.install!
23
24
  stdout = Dir.chdir(sandbox.root) do
24
25
  targets = installer.pod_targets
@@ -27,8 +28,6 @@ module Jazzy
27
28
 
28
29
  targets.map do |t|
29
30
  args = %W[doc --module-name #{podspec.module_name} -- -target #{t}]
30
- swift_version = (config.swift_version || '4')[0] + '.0'
31
- args << "SWIFT_VERSION=#{swift_version}"
32
31
  SourceKitten.run_sourcekitten(args)
33
32
  end
34
33
  end
@@ -97,6 +96,34 @@ module Jazzy
97
96
 
98
97
  private_class_method :github_file_prefix
99
98
 
99
+ # Latest valid value for SWIFT_VERSION.
100
+ LATEST_SWIFT_VERSION = '5'.freeze
101
+
102
+ # All valid values for SWIFT_VERSION that are longer
103
+ # than a major version number. Ordered ascending.
104
+ LONG_SWIFT_VERSIONS = ['4.2'].freeze
105
+
106
+ # Go from a full Swift version like 4.2.1 to
107
+ # something valid for SWIFT_VERSION.
108
+ def compiler_swift_version(user_version)
109
+ unless user_version
110
+ return podspec_swift_version || LATEST_SWIFT_VERSION
111
+ end
112
+
113
+ LONG_SWIFT_VERSIONS.select do |version|
114
+ user_version.start_with?(version)
115
+ end.last || "#{user_version[0]}.0"
116
+ end
117
+
118
+ def podspec_swift_version
119
+ # `swift_versions` exists from CocoaPods 1.7
120
+ if podspec.respond_to?('swift_versions')
121
+ podspec.swift_versions.max
122
+ else
123
+ podspec.swift_version
124
+ end
125
+ end
126
+
100
127
  # @!group SourceKitten output helper methods
101
128
 
102
129
  def pod_path
@@ -107,7 +134,8 @@ module Jazzy
107
134
  end
108
135
  end
109
136
 
110
- def podfile
137
+ # rubocop:disable Metrics/MethodLength
138
+ def podfile(swift_version)
111
139
  podspec = @podspec
112
140
  path = pod_path
113
141
  @podfile ||= Pod::Podfile.new do
@@ -116,26 +144,25 @@ module Jazzy
116
144
  deterministic_uuids: false
117
145
 
118
146
  [podspec, *podspec.recursive_subspecs].each do |ss|
119
- # test_specification exists from CocoaPods 1.3.0
120
- next if ss.respond_to?('test_specification') && ss.test_specification
147
+ next if ss.test_specification
121
148
 
122
149
  ss.available_platforms.each do |p|
123
150
  # Travis builds take too long when building docs for all available
124
151
  # platforms for the Moya integration spec, so we just document OSX.
125
- # Also Moya's RxSwift subspec doesn't yet support Swift 4, so skip
126
- # that too while we're at it.
127
152
  # TODO: remove once jazzy is fast enough.
128
153
  if ENV['JAZZY_INTEGRATION_SPECS']
129
- next if (p.name != :osx) || (ss.name == 'Moya/RxSwift')
154
+ next if p.name != :osx
130
155
  end
131
156
  target("Jazzy-#{ss.name.gsub('/', '__')}-#{p.name}") do
132
157
  use_frameworks!
133
158
  platform p.name, p.deployment_target
134
159
  pod ss.name, path: path.realpath.to_s
160
+ current_target_definition.swift_version = swift_version
135
161
  end
136
162
  end
137
163
  end
138
164
  end
139
165
  end
166
+ # rubocop:enable Metrics/MethodLength
140
167
  end
141
168
  end
@@ -8,12 +8,15 @@ module Jazzy
8
8
  # static type of declared element (e.g. String.Type -> ())
9
9
  attr_accessor :typename
10
10
 
11
- def type?(type_kind)
12
- respond_to?(:type) && type.kind == type_kind
11
+ # Give the item its own page or just inline into parent?
12
+ def render_as_page?
13
+ children.any?
13
14
  end
14
15
 
15
- def render?
16
- type?('document.markdown') || children.count != 0
16
+ # When referencing this item from its parent category,
17
+ # include the content or just link to it directly?
18
+ def omit_content_from_parent?
19
+ false
17
20
  end
18
21
 
19
22
  # Element containing this declaration in the code
@@ -99,6 +102,18 @@ module Jazzy
99
102
  attr_accessor :end_line
100
103
  attr_accessor :nav_order
101
104
  attr_accessor :url_name
105
+ attr_accessor :deprecated
106
+ attr_accessor :deprecation_message
107
+ attr_accessor :unavailable
108
+ attr_accessor :unavailable_message
109
+
110
+ def usage_discouraged?
111
+ unavailable || deprecated
112
+ end
113
+
114
+ def filepath
115
+ CGI.unescape(url)
116
+ end
102
117
 
103
118
  def alternative_abstract
104
119
  if file = alternative_abstract_file
@@ -26,6 +26,8 @@ module Jazzy
26
26
  end
27
27
 
28
28
  def self.from_doc(doc)
29
+ return AccessControlLevel.internal if implicit_deinit?(doc)
30
+
29
31
  accessibility = doc['key.accessibility']
30
32
  if accessibility
31
33
  acl = new(accessibility)
@@ -33,12 +35,17 @@ module Jazzy
33
35
  return acl
34
36
  end
35
37
  end
36
- acl = from_explicit_declaration(doc['key.parsed_declaration'])
38
+ acl = from_doc_explicit_declaration(doc)
37
39
  acl || AccessControlLevel.public # fallback on public ACL
38
40
  end
39
41
 
40
- def self.from_explicit_declaration(declaration_string)
41
- case declaration_string
42
+ def self.implicit_deinit?(doc)
43
+ doc['key.name'] == 'deinit' &&
44
+ from_doc_explicit_declaration(doc).nil?
45
+ end
46
+
47
+ def self.from_doc_explicit_declaration(doc)
48
+ case doc['key.parsed_declaration']
42
49
  when /private\ / then private
43
50
  when /fileprivate\ / then fileprivate
44
51
  when /public\ / then public
@@ -129,6 +129,16 @@ module Jazzy
129
129
  Type.new('Overview')
130
130
  end
131
131
 
132
+ MARKDOWN_KIND = 'document.markdown'.freeze
133
+
134
+ def self.markdown
135
+ Type.new(MARKDOWN_KIND)
136
+ end
137
+
138
+ def markdown?
139
+ kind == MARKDOWN_KIND
140
+ end
141
+
132
142
  def hash
133
143
  kind.hash
134
144
  end
@@ -140,7 +150,7 @@ module Jazzy
140
150
 
141
151
  TYPES = {
142
152
  # Markdown
143
- 'document.markdown' => {
153
+ MARKDOWN_KIND => {
144
154
  jazzy: 'Guide',
145
155
  dash: 'Guide',
146
156
  }.freeze,
@@ -3,25 +3,42 @@ require 'pathname'
3
3
  require 'jazzy/jazzy_markdown'
4
4
 
5
5
  module Jazzy
6
+ # Standalone markdown docs including index.html
6
7
  class SourceDocument < SourceDeclaration
7
8
  attr_accessor :overview
8
9
  attr_accessor :readme_path
9
10
 
11
+ def initialize
12
+ super
13
+ self.children = []
14
+ self.parameters = []
15
+ self.abstract = ''
16
+ self.type = SourceDeclaration::Type.markdown
17
+ self.mark = SourceMark.new
18
+ end
19
+
10
20
  def self.make_index(readme_path)
11
21
  SourceDocument.new.tap do |sd|
12
22
  sd.name = 'index'
13
- sd.children = []
14
- sd.type = SourceDeclaration::Type.new 'document.markdown'
23
+ sd.url = sd.name + '.html'
15
24
  sd.readme_path = readme_path
16
25
  end
17
26
  end
18
27
 
28
+ def render_as_page?
29
+ true
30
+ end
31
+
32
+ def omit_content_from_parent?
33
+ true
34
+ end
35
+
19
36
  def config
20
37
  Config.instance
21
38
  end
22
39
 
23
- def url
24
- name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '') + '.html'
40
+ def url_name
41
+ name.downcase.strip.tr(' ', '-').gsub(/[^[[:word:]]-]/, '')
25
42
  end
26
43
 
27
44
  def content(source_module)
@@ -126,12 +126,11 @@ module Jazzy
126
126
  # @return [Hash] input docs with URLs
127
127
  def self.make_doc_urls(docs)
128
128
  docs.each do |doc|
129
- if !doc.parent_in_docs || doc.children.count > 0
130
- # Create HTML page for this doc if it has children or is root-level
129
+ if doc.render_as_page?
131
130
  doc.url = (
132
131
  subdir_for_doc(doc) +
133
132
  [sanitize_filename(doc) + '.html']
134
- ).join('/')
133
+ ).map { |path| ERB::Util.url_encode(path) }.join('/')
135
134
  doc.children = make_doc_urls(doc.children)
136
135
  else
137
136
  # Don't create HTML page for this doc if it doesn't have children
@@ -140,8 +139,8 @@ module Jazzy
140
139
  warn 'A compile error prevented ' + doc.fully_qualified_name +
141
140
  ' from receiving a unique USR. Documentation may be ' \
142
141
  'incomplete. Please check for compile errors by running ' \
143
- '`xcodebuild ' \
144
- "#{Config.instance.xcodebuild_arguments.shelljoin}`."
142
+ '`xcodebuild` or `swift build` with arguments ' \
143
+ "`#{Config.instance.build_tool_arguments.shelljoin}`."
145
144
  end
146
145
  id = doc.usr
147
146
  unless id
@@ -159,17 +158,17 @@ module Jazzy
159
158
  end
160
159
  # rubocop:enable Metrics/MethodLength
161
160
 
162
- # Determine the subdirectory in which a doc should be placed
161
+ # Determine the subdirectory in which a doc should be placed.
162
+ # Guides in the root for back-compatibility.
163
+ # Declarations under outer namespace type (Structures, Classes, etc.)
163
164
  def self.subdir_for_doc(doc)
164
- # We always want to create top-level subdirs according to type (Struct,
165
- # Class, etc).
165
+ return [] if doc.type.markdown?
166
166
  top_level_decl = doc.namespace_path.first
167
- if top_level_decl && top_level_decl.type && top_level_decl.type.name
168
- # File program elements under top ancestor’s type (Struct, Class, etc.)
167
+ if top_level_decl.type.name
169
168
  [top_level_decl.type.plural_url_name] +
170
169
  doc.namespace_ancestors.map(&:name)
171
170
  else
172
- # Categories live in their own directory
171
+ # Category - in the root
173
172
  []
174
173
  end
175
174
  end
@@ -183,22 +182,33 @@ module Jazzy
183
182
  end.select { |x| x }.flatten(1)
184
183
  end
185
184
 
185
+ def self.use_spm?(options)
186
+ options.swift_build_tool == :spm ||
187
+ (!options.swift_build_tool_configured &&
188
+ Dir['*.xcodeproj', '*.xcworkspace'].empty? &&
189
+ !options.build_tool_arguments.include?('-project') &&
190
+ !options.build_tool_arguments.include?('-workspace'))
191
+ end
192
+
186
193
  # Builds SourceKitten arguments based on Jazzy options
187
194
  def self.arguments_from_options(options)
188
195
  arguments = ['doc']
189
- arguments += if options.objc_mode
190
- objc_arguments_from_options(options)
191
- elsif !options.module_name.empty?
192
- ['--module-name', options.module_name, '--']
193
- else
194
- ['--']
195
- end
196
- arguments + options.xcodebuild_arguments
196
+ if options.objc_mode
197
+ arguments += objc_arguments_from_options(options)
198
+ else
199
+ arguments += ['--spm'] if use_spm?(options)
200
+ if options.module_name_configured
201
+ arguments += ['--module-name', options.module_name]
202
+ end
203
+ arguments += ['--']
204
+ end
205
+
206
+ arguments + options.build_tool_arguments
197
207
  end
198
208
 
199
209
  def self.objc_arguments_from_options(options)
200
210
  arguments = []
201
- if options.xcodebuild_arguments.empty?
211
+ if options.build_tool_arguments.empty?
202
212
  arguments += ['--objc', options.umbrella_header.to_s, '--', '-x',
203
213
  'objective-c', '-isysroot',
204
214
  `xcrun --show-sdk-path --sdk #{options.sdk}`.chomp,
@@ -322,6 +332,8 @@ module Jazzy
322
332
  Highlighter.highlight(make_swift_declaration(doc, declaration))
323
333
  end
324
334
 
335
+ make_deprecation_info(doc, declaration)
336
+
325
337
  unless doc['key.doc.full_as_xml']
326
338
  return process_undocumented_token(doc, declaration)
327
339
  end
@@ -335,6 +347,17 @@ module Jazzy
335
347
  @stats.add_documented
336
348
  end
337
349
 
350
+ def self.make_deprecation_info(doc, declaration)
351
+ if declaration.deprecated
352
+ declaration.deprecation_message =
353
+ Markdown.render(doc['key.deprecation_message'] || '')
354
+ end
355
+ if declaration.unavailable
356
+ declaration.unavailable_message =
357
+ Markdown.render(doc['key.unavailable_message'] || '')
358
+ end
359
+ end
360
+
338
361
  # Strip tags and convert entities
339
362
  def self.xml_to_text(xml)
340
363
  document = REXML::Document.new(xml)
@@ -378,7 +401,8 @@ module Jazzy
378
401
  parsed &&
379
402
  (annotated.include?(' = default') || # SR-2608
380
403
  parsed.match('@autoclosure|@escaping') || # SR-6321
381
- parsed.include?("\n"))
404
+ parsed.include?("\n") ||
405
+ parsed.include?('extension '))
382
406
  end
383
407
 
384
408
  # Replace the fully qualified name of a type with its base name
@@ -407,7 +431,9 @@ module Jazzy
407
431
  parsed_decl_body.unindent(inline_attrs.length)
408
432
  else
409
433
  # Strip ugly references to decl type name
410
- unqualify_name(annotated_decl_body, declaration)
434
+ unqualified = unqualify_name(annotated_decl_body, declaration)
435
+ # Workaround for SR-9816
436
+ unqualified.gsub(" {\n get\n }", '')
411
437
  end
412
438
 
413
439
  # @available attrs only in compiler 'interface' style
@@ -482,6 +508,8 @@ module Jazzy
482
508
  declaration.column = doc['key.doc.column']
483
509
  declaration.start_line = doc['key.parsed_scope.start']
484
510
  declaration.end_line = doc['key.parsed_scope.end']
511
+ declaration.deprecated = doc['key.always_deprecated']
512
+ declaration.unavailable = doc['key.always_unavailable']
485
513
 
486
514
  next unless make_doc_info(doc, declaration)
487
515
  make_substructure(doc, declaration)
@@ -742,28 +770,34 @@ module Jazzy
742
770
  end
743
771
  end
744
772
 
773
+ AUTOLINK_TEXT_FIELDS = %w[return
774
+ abstract
775
+ unavailable_message
776
+ deprecation_message].freeze
777
+
778
+ AUTOLINK_HIGHLIGHT_FIELDS = %w[declaration
779
+ other_language_declaration].freeze
780
+
745
781
  def self.autolink(docs, root_decls)
746
782
  @autolink_root_decls = root_decls
747
783
  docs.each do |doc|
748
784
  doc.children = autolink(doc.children, root_decls)
749
785
 
750
- doc.return = autolink_text(doc.return, doc, root_decls) if doc.return
751
- doc.abstract = autolink_text(doc.abstract, doc, root_decls)
752
- (doc.parameters || []).each do |param|
753
- param[:discussion] =
754
- autolink_text(param[:discussion], doc, root_decls)
786
+ AUTOLINK_TEXT_FIELDS.each do |field|
787
+ if text = doc.send(field)
788
+ doc.send(field + '=', autolink_text(text, doc, root_decls))
789
+ end
755
790
  end
756
791
 
757
- if doc.declaration
758
- doc.declaration = autolink_text(
759
- doc.declaration, doc, root_decls, true
760
- )
792
+ AUTOLINK_HIGHLIGHT_FIELDS.each do |field|
793
+ if text = doc.send(field)
794
+ doc.send(field + '=', autolink_text(text, doc, root_decls, true))
795
+ end
761
796
  end
762
797
 
763
- if doc.other_language_declaration
764
- doc.other_language_declaration = autolink_text(
765
- doc.other_language_declaration, doc, root_decls, true
766
- )
798
+ (doc.parameters || []).each do |param|
799
+ param[:discussion] =
800
+ autolink_text(param[:discussion], doc, root_decls)
767
801
  end
768
802
  end
769
803
  end