jazzy 0.9.6 → 0.12.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.
@@ -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 = compiler_swift_version(config.swift_version)
31
- args << "SWIFT_VERSION=#{swift_version}"
32
31
  SourceKitten.run_sourcekitten(args)
33
32
  end
34
33
  end
@@ -107,13 +106,24 @@ module Jazzy
107
106
  # Go from a full Swift version like 4.2.1 to
108
107
  # something valid for SWIFT_VERSION.
109
108
  def compiler_swift_version(user_version)
110
- return LATEST_SWIFT_VERSION unless user_version
109
+ unless user_version
110
+ return podspec_swift_version || LATEST_SWIFT_VERSION
111
+ end
111
112
 
112
113
  LONG_SWIFT_VERSIONS.select do |version|
113
114
  user_version.start_with?(version)
114
115
  end.last || "#{user_version[0]}.0"
115
116
  end
116
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
+
117
127
  # @!group SourceKitten output helper methods
118
128
 
119
129
  def pod_path
@@ -124,7 +134,8 @@ module Jazzy
124
134
  end
125
135
  end
126
136
 
127
- def podfile
137
+ # rubocop:disable Metrics/MethodLength
138
+ def podfile(swift_version)
128
139
  podspec = @podspec
129
140
  path = pod_path
130
141
  @podfile ||= Pod::Podfile.new do
@@ -133,8 +144,7 @@ module Jazzy
133
144
  deterministic_uuids: false
134
145
 
135
146
  [podspec, *podspec.recursive_subspecs].each do |ss|
136
- # test_specification exists from CocoaPods 1.3.0
137
- next if ss.respond_to?('test_specification') && ss.test_specification
147
+ next if ss.test_specification
138
148
 
139
149
  ss.available_platforms.each do |p|
140
150
  # Travis builds take too long when building docs for all available
@@ -147,10 +157,12 @@ module Jazzy
147
157
  use_frameworks!
148
158
  platform p.name, p.deployment_target
149
159
  pod ss.name, path: path.realpath.to_s
160
+ current_target_definition.swift_version = swift_version
150
161
  end
151
162
  end
152
163
  end
153
164
  end
154
165
  end
166
+ # rubocop:enable Metrics/MethodLength
155
167
  end
156
168
  end
@@ -1,6 +1,7 @@
1
1
  require 'jazzy/source_declaration/access_control_level'
2
2
  require 'jazzy/source_declaration/type'
3
3
 
4
+ # rubocop:disable Metrics/ClassLength
4
5
  module Jazzy
5
6
  class SourceDeclaration
6
7
  # kind of declaration (e.g. class, variable, function)
@@ -13,6 +14,14 @@ module Jazzy
13
14
  children.any?
14
15
  end
15
16
 
17
+ def swift?
18
+ type.swift_type?
19
+ end
20
+
21
+ def highlight_language
22
+ swift? ? Highlighter::SWIFT : Highlighter::OBJC
23
+ end
24
+
16
25
  # When referencing this item from its parent category,
17
26
  # include the content or just link to it directly?
18
27
  def omit_content_from_parent?
@@ -67,17 +76,32 @@ module Jazzy
67
76
  name.split(/[\(\)]/) if type.objc_category?
68
77
  end
69
78
 
79
+ def swift_objc_extension?
80
+ type.swift_extension? && usr && usr.start_with?('c:objc')
81
+ end
82
+
83
+ def swift_extension_objc_name
84
+ return unless type.swift_extension? && usr
85
+
86
+ usr.split('(cs)').last
87
+ end
88
+
89
+ # The language in the templates for display
90
+ def display_language
91
+ return 'Swift' if swift?
92
+
93
+ Config.instance.hide_objc? ? 'Swift' : 'Objective-C'
94
+ end
95
+
70
96
  def display_declaration
71
- if Config.instance.hide_declarations == 'objc'
72
- other_language_declaration
73
- else
74
- declaration
75
- end
97
+ return declaration if swift?
98
+
99
+ Config.instance.hide_objc? ? other_language_declaration : declaration
76
100
  end
77
101
 
78
102
  def display_other_language_declaration
79
103
  other_language_declaration unless
80
- %w[swift objc].include? Config.instance.hide_declarations
104
+ Config.instance.hide_objc? || Config.instance.hide_swift?
81
105
  end
82
106
 
83
107
  attr_accessor :file
@@ -111,6 +135,10 @@ module Jazzy
111
135
  unavailable || deprecated
112
136
  end
113
137
 
138
+ def filepath
139
+ CGI.unescape(url)
140
+ end
141
+
114
142
  def alternative_abstract
115
143
  if file = alternative_abstract_file
116
144
  Pathname(file).read
@@ -77,6 +77,10 @@ module Jazzy
77
77
  kind == 'sourcekitten.source.lang.objc.decl.class'
78
78
  end
79
79
 
80
+ def swift_type?
81
+ kind.include? 'swift'
82
+ end
83
+
80
84
  def swift_enum_case?
81
85
  kind == 'source.lang.swift.decl.enumcase'
82
86
  end
@@ -20,6 +20,7 @@ module Jazzy
20
20
  def self.make_index(readme_path)
21
21
  SourceDocument.new.tap do |sd|
22
22
  sd.name = 'index'
23
+ sd.url = sd.name + '.html'
23
24
  sd.readme_path = readme_path
24
25
  end
25
26
  end
@@ -36,8 +37,8 @@ module Jazzy
36
37
  Config.instance
37
38
  end
38
39
 
39
- def url
40
- name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '') + '.html'
40
+ def url_name
41
+ name.downcase.strip.tr(' ', '-').gsub(/[^[[:word:]]-]/, '')
41
42
  end
42
43
 
43
44
  def content(source_module)
@@ -65,7 +65,7 @@ module Jazzy
65
65
  type_categories, uncategorized = group_type_categories(
66
66
  docs, custom_categories.any? ? 'Other ' : ''
67
67
  )
68
- custom_categories + type_categories + uncategorized
68
+ custom_categories + merge_categories(type_categories) + uncategorized
69
69
  end
70
70
 
71
71
  def self.group_custom_categories(docs)
@@ -98,6 +98,19 @@ module Jazzy
98
98
  [group.compact, docs]
99
99
  end
100
100
 
101
+ # Join categories with the same name (eg. ObjC and Swift classes)
102
+ def self.merge_categories(categories)
103
+ merged = []
104
+ categories.each do |new_category|
105
+ if existing = merged.find { |c| c.name == new_category.name }
106
+ existing.children += new_category.children
107
+ else
108
+ merged.append(new_category)
109
+ end
110
+ end
111
+ merged
112
+ end
113
+
101
114
  def self.make_group(group, name, abstract, url_name = nil)
102
115
  group.reject! { |doc| doc.name.empty? }
103
116
  unless group.empty?
@@ -126,12 +139,11 @@ module Jazzy
126
139
  # @return [Hash] input docs with URLs
127
140
  def self.make_doc_urls(docs)
128
141
  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
142
+ if doc.render_as_page?
131
143
  doc.url = (
132
144
  subdir_for_doc(doc) +
133
145
  [sanitize_filename(doc) + '.html']
134
- ).join('/')
146
+ ).map { |path| ERB::Util.url_encode(path) }.join('/')
135
147
  doc.children = make_doc_urls(doc.children)
136
148
  else
137
149
  # Don't create HTML page for this doc if it doesn't have children
@@ -140,8 +152,8 @@ module Jazzy
140
152
  warn 'A compile error prevented ' + doc.fully_qualified_name +
141
153
  ' from receiving a unique USR. Documentation may be ' \
142
154
  'incomplete. Please check for compile errors by running ' \
143
- '`xcodebuild ' \
144
- "#{Config.instance.xcodebuild_arguments.shelljoin}`."
155
+ '`xcodebuild` or `swift build` with arguments ' \
156
+ "`#{Config.instance.build_tool_arguments.shelljoin}`."
145
157
  end
146
158
  id = doc.usr
147
159
  unless id
@@ -159,17 +171,17 @@ module Jazzy
159
171
  end
160
172
  # rubocop:enable Metrics/MethodLength
161
173
 
162
- # Determine the subdirectory in which a doc should be placed
174
+ # Determine the subdirectory in which a doc should be placed.
175
+ # Guides in the root for back-compatibility.
176
+ # Declarations under outer namespace type (Structures, Classes, etc.)
163
177
  def self.subdir_for_doc(doc)
164
- # We always want to create top-level subdirs according to type (Struct,
165
- # Class, etc).
178
+ return [] if doc.type.markdown?
166
179
  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.)
180
+ if top_level_decl.type.name
169
181
  [top_level_decl.type.plural_url_name] +
170
182
  doc.namespace_ancestors.map(&:name)
171
183
  else
172
- # Categories live in their own directory
184
+ # Category - in the root
173
185
  []
174
186
  end
175
187
  end
@@ -183,22 +195,33 @@ module Jazzy
183
195
  end.select { |x| x }.flatten(1)
184
196
  end
185
197
 
198
+ def self.use_spm?(options)
199
+ options.swift_build_tool == :spm ||
200
+ (!options.swift_build_tool_configured &&
201
+ Dir['*.xcodeproj', '*.xcworkspace'].empty? &&
202
+ !options.build_tool_arguments.include?('-project') &&
203
+ !options.build_tool_arguments.include?('-workspace'))
204
+ end
205
+
186
206
  # Builds SourceKitten arguments based on Jazzy options
187
207
  def self.arguments_from_options(options)
188
208
  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
209
+ if options.objc_mode
210
+ arguments += objc_arguments_from_options(options)
211
+ else
212
+ arguments += ['--spm'] if use_spm?(options)
213
+ unless options.module_name.empty?
214
+ arguments += ['--module-name', options.module_name]
215
+ end
216
+ arguments += ['--']
217
+ end
218
+
219
+ arguments + options.build_tool_arguments
197
220
  end
198
221
 
199
222
  def self.objc_arguments_from_options(options)
200
223
  arguments = []
201
- if options.xcodebuild_arguments.empty?
224
+ if options.build_tool_arguments.empty?
202
225
  arguments += ['--objc', options.umbrella_header.to_s, '--', '-x',
203
226
  'objective-c', '-isysroot',
204
227
  `xcrun --show-sdk-path --sdk #{options.sdk}`.chomp,
@@ -252,8 +275,13 @@ module Jazzy
252
275
  def self.should_document?(doc)
253
276
  return false if doc['key.doc.comment'].to_s.include?(':nodoc:')
254
277
 
278
+ type = SourceDeclaration::Type.new(doc['key.kind'])
279
+
255
280
  # Always document Objective-C declarations.
256
- return true if Config.instance.objc_mode
281
+ return true unless type.swift_type?
282
+
283
+ # Don't document Swift types if we are hiding Swift
284
+ return false if Config.instance.hide_swift?
257
285
 
258
286
  # Don't document @available declarations with no USR, since it means
259
287
  # they're unavailable.
@@ -262,7 +290,6 @@ module Jazzy
262
290
  end
263
291
 
264
292
  # Document extensions & enum elements, since we can't tell their ACL.
265
- type = SourceDeclaration::Type.new(doc['key.kind'])
266
293
  return true if type.swift_enum_element?
267
294
  if type.swift_extension?
268
295
  return Array(doc['key.substructure']).any? do |subdoc|
@@ -286,14 +313,14 @@ module Jazzy
286
313
  make_default_doc_info(declaration)
287
314
 
288
315
  filepath = doc['key.filepath']
289
- objc = Config.instance.objc_mode
290
- if objc || should_mark_undocumented(filepath)
316
+
317
+ if !declaration.swift? || should_mark_undocumented(filepath)
291
318
  @stats.add_undocumented(declaration)
292
319
  return nil if @skip_undocumented
293
320
  declaration.abstract = undocumented_abstract
294
321
  else
295
322
  declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',
296
- Highlighter.default_language)
323
+ declaration.highlight_language)
297
324
  end
298
325
 
299
326
  declaration
@@ -312,16 +339,7 @@ module Jazzy
312
339
  def self.make_doc_info(doc, declaration)
313
340
  return unless should_document?(doc)
314
341
 
315
- if Config.instance.objc_mode
316
- declaration.declaration =
317
- Highlighter.highlight(doc['key.parsed_declaration'])
318
- declaration.other_language_declaration =
319
- Highlighter.highlight(doc['key.swift_declaration'], 'swift')
320
- else
321
- declaration.declaration =
322
- Highlighter.highlight(make_swift_declaration(doc, declaration))
323
- end
324
-
342
+ highlight_declaration(doc, declaration)
325
343
  make_deprecation_info(doc, declaration)
326
344
 
327
345
  unless doc['key.doc.full_as_xml']
@@ -329,7 +347,7 @@ module Jazzy
329
347
  end
330
348
 
331
349
  declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',
332
- Highlighter.default_language)
350
+ declaration.highlight_language)
333
351
  declaration.discussion = ''
334
352
  declaration.return = Markdown.rendered_returns
335
353
  declaration.parameters = parameters(doc, Markdown.rendered_parameters)
@@ -337,6 +355,18 @@ module Jazzy
337
355
  @stats.add_documented
338
356
  end
339
357
 
358
+ def self.highlight_declaration(doc, declaration)
359
+ if declaration.swift?
360
+ declaration.declaration =
361
+ Highlighter.highlight_swift(make_swift_declaration(doc, declaration))
362
+ else
363
+ declaration.declaration =
364
+ Highlighter.highlight_objc(doc['key.parsed_declaration'])
365
+ declaration.other_language_declaration =
366
+ Highlighter.highlight_swift(doc['key.swift_declaration'])
367
+ end
368
+ end
369
+
340
370
  def self.make_deprecation_info(doc, declaration)
341
371
  if declaration.deprecated
342
372
  declaration.deprecation_message =
@@ -413,6 +443,9 @@ module Jazzy
413
443
  # From source code
414
444
  parsed_decl = doc['key.parsed_declaration']
415
445
 
446
+ # Don't present type attributes on extensions
447
+ return parsed_decl if declaration.type.extension?
448
+
416
449
  decl =
417
450
  if prefer_parsed_decl?(parsed_decl, annotated_decl_body)
418
451
  # Strip any attrs captured by parsed version
@@ -462,8 +495,7 @@ module Jazzy
462
495
  declaration.type = SourceDeclaration::Type.new(doc['key.kind'])
463
496
  declaration.typename = doc['key.typename']
464
497
  declaration.objc_name = doc['key.name']
465
- documented_name = if Config.instance.hide_declarations == 'objc' &&
466
- doc['key.swift_name']
498
+ documented_name = if Config.instance.hide_objc? && doc['key.swift_name']
467
499
  doc['key.swift_name']
468
500
  else
469
501
  declaration.objc_name
@@ -517,6 +549,10 @@ module Jazzy
517
549
  decls.map do |decl|
518
550
  next decl unless decl.type.extension? && decl.name.include?('.')
519
551
 
552
+ # Don't expand the Swift namespace if we're in ObjC mode.
553
+ # ex: NS_SWIFT_NAME(Foo.Bar) should not create top-level Foo
554
+ next decl if decl.swift_objc_extension? && !Config.instance.hide_objc?
555
+
520
556
  name_parts = decl.name.split('.')
521
557
  decl.name = name_parts.pop
522
558
  expand_extension(decl, name_parts, decls)
@@ -567,11 +603,18 @@ module Jazzy
567
603
 
568
604
  # Two declarations get merged if they have the same deduplication key.
569
605
  def self.deduplication_key(decl, root_decls)
570
- if decl.type.swift_extensible? || decl.type.swift_extension?
606
+ # Swift extension of objc class
607
+ if decl.swift_objc_extension?
608
+ [decl.swift_extension_objc_name, :objc_class_and_categories]
609
+ # Swift type or Swift extension of Swift type
610
+ elsif decl.type.swift_extensible? || decl.type.swift_extension?
571
611
  [decl.usr, decl.name]
612
+ # Objc categories and classes
572
613
  elsif mergeable_objc?(decl, root_decls)
573
- name, _ = decl.objc_category_name || decl.name
614
+ # Using the ObjC name to match swift_objc_extension.
615
+ name, _ = decl.objc_category_name || decl.objc_name
574
616
  [name, :objc_class_and_categories]
617
+ # Non-mergable declarations (funcs, typedefs etc...)
575
618
  else
576
619
  [decl.usr, decl.name, decl.type.kind]
577
620
  end
@@ -817,17 +860,14 @@ module Jazzy
817
860
  @min_acl = min_acl
818
861
  @skip_undocumented = skip_undocumented
819
862
  @stats = Stats.new
820
- sourcekitten_json = filter_files(JSON.parse(sourcekitten_output))
863
+ sourcekitten_json = filter_files(JSON.parse(sourcekitten_output).flatten)
821
864
  docs = make_source_declarations(sourcekitten_json).concat inject_docs
822
865
  docs = expand_extensions(docs)
823
866
  docs = deduplicate_declarations(docs)
824
- if Config.instance.objc_mode
825
- docs = reject_objc_types(docs)
826
- else
827
- # Remove top-level enum cases because it means they have an ACL lower
828
- # than min_acl
829
- docs = docs.reject { |doc| doc.type.swift_enum_element? }
830
- end
867
+ docs = reject_objc_types(docs)
868
+ # Remove top-level enum cases because it means they have an ACL lower
869
+ # than min_acl
870
+ docs = docs.reject { |doc| doc.type.swift_enum_element? }
831
871
  ungrouped_docs = docs
832
872
  docs = group_docs(docs)
833
873
  make_doc_urls(docs)