jazzy 0.13.7 → 0.14.2
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.
- checksums.yaml +4 -4
- data/.github/workflows/Tests.yml +6 -6
- data/.rubocop.yml +155 -24
- data/CHANGELOG.md +91 -0
- data/CONTRIBUTING.md +1 -1
- data/Dangerfile +11 -8
- data/Gemfile +3 -1
- data/Gemfile.lock +85 -64
- data/ObjectiveC.md +208 -0
- data/README.md +63 -33
- data/Rakefile +18 -15
- data/bin/jazzy +3 -2
- data/bin/sourcekitten +0 -0
- data/jazzy.gemspec +9 -6
- data/lib/jazzy/config.rb +135 -69
- data/lib/jazzy/doc.rb +3 -1
- data/lib/jazzy/doc_builder.rb +72 -83
- data/lib/jazzy/docset_builder.rb +3 -1
- data/lib/jazzy/documentation_generator.rb +6 -2
- data/lib/jazzy/executable.rb +3 -0
- data/lib/jazzy/extensions/bitbucket/img/bitbucket.svg +11 -0
- data/lib/jazzy/{themes/apple/assets → extensions/github}/img/gh.png +0 -0
- data/lib/jazzy/extensions/gitlab/img/gitlab.svg +23 -0
- data/lib/jazzy/gem_version.rb +3 -1
- data/lib/jazzy/highlighter.rb +5 -3
- data/lib/jazzy/jazzy_markdown.rb +75 -32
- data/lib/jazzy/podspec_documenter.rb +14 -16
- data/lib/jazzy/search_builder.rb +5 -6
- data/lib/jazzy/source_declaration/access_control_level.rb +7 -5
- data/lib/jazzy/source_declaration/type.rb +29 -3
- data/lib/jazzy/source_declaration.rb +22 -5
- data/lib/jazzy/source_document.rb +8 -5
- data/lib/jazzy/source_host.rb +111 -0
- data/lib/jazzy/source_mark.rb +8 -6
- data/lib/jazzy/source_module.rb +6 -6
- data/lib/jazzy/sourcekitten.rb +155 -81
- data/lib/jazzy/stats.rb +14 -3
- data/lib/jazzy/symbol_graph/constraint.rb +5 -1
- data/lib/jazzy/symbol_graph/ext_node.rb +3 -1
- data/lib/jazzy/symbol_graph/graph.rb +19 -12
- data/lib/jazzy/symbol_graph/relationship.rb +9 -0
- data/lib/jazzy/symbol_graph/sym_node.rb +25 -7
- data/lib/jazzy/symbol_graph/symbol.rb +54 -25
- data/lib/jazzy/symbol_graph.rb +43 -32
- data/lib/jazzy/themes/apple/assets/css/highlight.css.scss +63 -59
- data/lib/jazzy/themes/apple/assets/css/jazzy.css.scss +5 -1
- data/lib/jazzy/themes/apple/assets/js/jazzy.js +4 -0
- data/lib/jazzy/themes/apple/assets/js/jazzy.search.js +4 -0
- data/lib/jazzy/themes/apple/templates/doc.mustache +4 -5
- data/lib/jazzy/themes/apple/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/apple/templates/header.mustache +6 -6
- data/lib/jazzy/themes/apple/templates/task.mustache +6 -11
- data/lib/jazzy/themes/fullwidth/assets/css/highlight.css.scss +63 -59
- data/lib/jazzy/themes/fullwidth/assets/css/jazzy.css.scss +6 -2
- data/lib/jazzy/themes/fullwidth/assets/js/jazzy.js +4 -0
- data/lib/jazzy/themes/fullwidth/assets/js/jazzy.search.js +4 -0
- data/lib/jazzy/themes/fullwidth/templates/doc.mustache +4 -5
- data/lib/jazzy/themes/fullwidth/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/fullwidth/templates/header.mustache +8 -8
- data/lib/jazzy/themes/fullwidth/templates/task.mustache +6 -11
- data/lib/jazzy/themes/jony/assets/css/highlight.css.scss +63 -59
- data/lib/jazzy/themes/jony/assets/css/jazzy.css.scss +5 -1
- data/lib/jazzy/themes/jony/assets/js/jazzy.js +4 -0
- data/lib/jazzy/themes/jony/templates/doc.mustache +4 -5
- data/lib/jazzy/themes/jony/templates/footer.mustache +1 -1
- data/lib/jazzy/themes/jony/templates/header.mustache +6 -6
- data/lib/jazzy/themes/jony/templates/task.mustache +6 -11
- data/lib/jazzy.rb +2 -0
- data/spec/integration_spec.rb +46 -42
- data/spec/spec_helper/pre_flight.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- metadata +32 -16
- data/lib/jazzy/themes/fullwidth/assets/img/gh.png +0 -0
- data/lib/jazzy/themes/jony/assets/img/gh.png +0 -0
- data/spec/sourcekitten_spec.rb +0 -6
data/lib/jazzy/sourcekitten.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'pathname'
|
3
5
|
require 'shellwords'
|
@@ -12,7 +14,7 @@ require 'jazzy/source_declaration'
|
|
12
14
|
require 'jazzy/source_mark'
|
13
15
|
require 'jazzy/stats'
|
14
16
|
|
15
|
-
ELIDED_AUTOLINK_TOKEN = '36f8f5912051ae747ef441d6511ca4cb'
|
17
|
+
ELIDED_AUTOLINK_TOKEN = '36f8f5912051ae747ef441d6511ca4cb'
|
16
18
|
|
17
19
|
def autolink_regex(middle_regex, after_highlight)
|
18
20
|
start_tag_re, end_tag_re =
|
@@ -29,16 +31,15 @@ class String
|
|
29
31
|
gsub(autolink_regex(middle_regex, after_highlight)) do
|
30
32
|
original = Regexp.last_match(0)
|
31
33
|
start_tag, raw_name, end_tag = Regexp.last_match.captures
|
32
|
-
link_target = yield(CGI.unescape_html(raw_name))
|
34
|
+
link_target, display_name = yield(CGI.unescape_html(raw_name))
|
33
35
|
|
34
36
|
if link_target &&
|
35
37
|
!link_target.type.extension? &&
|
36
38
|
link_target.url &&
|
37
39
|
link_target.url != doc_url.split('#').first && # Don't link to parent
|
38
40
|
link_target.url != doc_url # Don't link to self
|
39
|
-
start_tag
|
40
|
-
"
|
41
|
-
raw_name + '</a>' + end_tag
|
41
|
+
"#{start_tag}<a href=\"#{ELIDED_AUTOLINK_TOKEN}#{link_target.url}\">" \
|
42
|
+
"#{CGI.escape_html(display_name)}</a>#{end_tag}"
|
42
43
|
else
|
43
44
|
original
|
44
45
|
end
|
@@ -74,8 +75,8 @@ module Jazzy
|
|
74
75
|
children = category['children'].flat_map do |name|
|
75
76
|
docs_with_name, docs = docs.partition { |doc| doc.name == name }
|
76
77
|
if docs_with_name.empty?
|
77
|
-
|
78
|
-
|
78
|
+
warn 'WARNING: No documented top-level declarations match ' \
|
79
|
+
"name \"#{name}\" specified in categories file"
|
79
80
|
end
|
80
81
|
docs_with_name
|
81
82
|
end
|
@@ -129,7 +130,7 @@ module Jazzy
|
|
129
130
|
def self.merge_consecutive_marks(docs)
|
130
131
|
prev_mark = nil
|
131
132
|
docs.each do |doc|
|
132
|
-
if prev_mark
|
133
|
+
if prev_mark&.can_merge?(doc.mark)
|
133
134
|
doc.mark = prev_mark
|
134
135
|
end
|
135
136
|
prev_mark = doc.mark
|
@@ -141,9 +142,9 @@ module Jazzy
|
|
141
142
|
unsafe_filename = doc.docs_filename
|
142
143
|
sanitzation_enabled = Config.instance.use_safe_filenames
|
143
144
|
if sanitzation_enabled && !doc.type.name_controlled_manually?
|
144
|
-
|
145
|
+
CGI.escape(unsafe_filename).gsub('_', '%5F').tr('%', '_')
|
145
146
|
else
|
146
|
-
|
147
|
+
unsafe_filename
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
@@ -162,11 +163,11 @@ module Jazzy
|
|
162
163
|
# Don't create HTML page for this doc if it doesn't have children
|
163
164
|
# Instead, make its link a hash-link on its parent's page
|
164
165
|
if doc.typename == '<<error type>>'
|
165
|
-
warn
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
166
|
+
warn "A compile error prevented #{doc.fully_qualified_name} " \
|
167
|
+
'from receiving a unique USR. Documentation may be ' \
|
168
|
+
'incomplete. Please check for compile errors by running ' \
|
169
|
+
'`xcodebuild` or `swift build` with arguments ' \
|
170
|
+
"`#{Config.instance.build_tool_arguments.shelljoin}`."
|
170
171
|
end
|
171
172
|
id = doc.usr
|
172
173
|
unless id
|
@@ -174,11 +175,11 @@ module Jazzy
|
|
174
175
|
warn "`#{id}` has no USR. First make sure all modules used in " \
|
175
176
|
'your project have been imported. If all used modules are ' \
|
176
177
|
'imported, please report this problem by filing an issue at ' \
|
177
|
-
'https://github.com/realm/jazzy/issues along with your
|
178
|
-
'project. If this token is declared in an `#if` block,
|
179
|
-
'ignore this message.'
|
178
|
+
'https://github.com/realm/jazzy/issues along with your ' \
|
179
|
+
'Xcode project. If this token is declared in an `#if` block, ' \
|
180
|
+
'please ignore this message.'
|
180
181
|
end
|
181
|
-
doc.url = doc.parent_in_docs.url
|
182
|
+
doc.url = "#{doc.parent_in_docs.url}#/#{id}"
|
182
183
|
end
|
183
184
|
end
|
184
185
|
end
|
@@ -189,6 +190,7 @@ module Jazzy
|
|
189
190
|
# Declarations under outer namespace type (Structures, Classes, etc.)
|
190
191
|
def self.subdir_for_doc(doc)
|
191
192
|
return [] if doc.type.markdown?
|
193
|
+
|
192
194
|
top_level_decl = doc.namespace_path.first
|
193
195
|
if top_level_decl.type.name
|
194
196
|
[top_level_decl.type.plural_url_name] +
|
@@ -258,6 +260,7 @@ module Jazzy
|
|
258
260
|
unless xcode = XCInvoke::Xcode.find_swift_version(swift_version)
|
259
261
|
raise "Unable to find an Xcode with swift version #{swift_version}."
|
260
262
|
end
|
263
|
+
|
261
264
|
env = xcode.as_env
|
262
265
|
else
|
263
266
|
env = ENV
|
@@ -269,22 +272,25 @@ module Jazzy
|
|
269
272
|
|
270
273
|
def self.make_default_doc_info(declaration)
|
271
274
|
# @todo: Fix these
|
272
|
-
declaration.line = nil
|
273
|
-
declaration.column = nil
|
274
275
|
declaration.abstract = ''
|
275
276
|
declaration.parameters = []
|
276
277
|
declaration.children = []
|
277
278
|
end
|
278
279
|
|
280
|
+
def self.attribute?(doc, attr_name)
|
281
|
+
doc['key.attributes']&.find do |attribute|
|
282
|
+
attribute['key.attribute'] == "source.decl.attribute.#{attr_name}"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
279
286
|
def self.availability_attribute?(doc)
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
287
|
+
attribute?(doc, 'available')
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.spi_attribute?(doc)
|
291
|
+
attribute?(doc, '_spi')
|
284
292
|
end
|
285
293
|
|
286
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
287
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
288
294
|
def self.should_document?(doc)
|
289
295
|
return false if doc['key.doc.comment'].to_s.include?(':nodoc:')
|
290
296
|
|
@@ -302,10 +308,31 @@ module Jazzy
|
|
302
308
|
return false
|
303
309
|
end
|
304
310
|
|
305
|
-
#
|
311
|
+
# Only document @_spi declarations in some scenarios
|
312
|
+
return false unless should_document_spi?(doc)
|
313
|
+
|
314
|
+
# Don't document declarations excluded by the min_acl setting
|
315
|
+
if type.swift_extension?
|
316
|
+
should_document_swift_extension?(doc)
|
317
|
+
else
|
318
|
+
should_document_acl?(type, doc)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Check visibility: SPI
|
323
|
+
def self.should_document_spi?(doc)
|
324
|
+
spi_ok = @min_acl < SourceDeclaration::AccessControlLevel.public ||
|
325
|
+
Config.instance.include_spi_declarations ||
|
326
|
+
(!spi_attribute?(doc) && !doc['key.symgraph_spi'])
|
327
|
+
|
328
|
+
@stats.add_spi_skipped unless spi_ok
|
329
|
+
spi_ok
|
330
|
+
end
|
331
|
+
|
332
|
+
# Check visibility: access control
|
333
|
+
def self.should_document_acl?(type, doc)
|
334
|
+
# Include all enum elements for now, can't tell their ACL.
|
306
335
|
return true if type.swift_enum_element?
|
307
|
-
# Document extensions if they might have parts covered by the ACL.
|
308
|
-
return should_document_swift_extension?(doc) if type.swift_extension?
|
309
336
|
|
310
337
|
acl_ok = SourceDeclaration::AccessControlLevel.from_doc(doc) >= @min_acl
|
311
338
|
unless acl_ok
|
@@ -314,9 +341,9 @@ module Jazzy
|
|
314
341
|
end
|
315
342
|
acl_ok
|
316
343
|
end
|
317
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
318
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
319
344
|
|
345
|
+
# Document extensions if they add protocol conformances, or have any
|
346
|
+
# member that needs to be documented.
|
320
347
|
def self.should_document_swift_extension?(doc)
|
321
348
|
doc['key.inheritedtypes'] ||
|
322
349
|
Array(doc['key.substructure']).any? do |subdoc|
|
@@ -328,7 +355,9 @@ module Jazzy
|
|
328
355
|
# Call things undocumented if they were compiled properly
|
329
356
|
# and came from our module.
|
330
357
|
def self.should_mark_undocumented(declaration)
|
331
|
-
declaration.usr &&
|
358
|
+
declaration.usr &&
|
359
|
+
(declaration.modulename.nil? ||
|
360
|
+
declaration.modulename == Config.instance.module_name)
|
332
361
|
end
|
333
362
|
|
334
363
|
def self.process_undocumented_token(doc, declaration)
|
@@ -337,6 +366,7 @@ module Jazzy
|
|
337
366
|
if !declaration.swift? || should_mark_undocumented(declaration)
|
338
367
|
@stats.add_undocumented(declaration)
|
339
368
|
return nil if @skip_undocumented
|
369
|
+
|
340
370
|
declaration.abstract = undocumented_abstract
|
341
371
|
else
|
342
372
|
declaration.abstract = Markdown.render(doc['key.doc.comment'] || '',
|
@@ -404,7 +434,7 @@ module Jazzy
|
|
404
434
|
def self.xml_to_text(xml)
|
405
435
|
document = REXML::Document.new(xml)
|
406
436
|
REXML::XPath.match(document.root, '//text()').map(&:value).join
|
407
|
-
rescue
|
437
|
+
rescue StandardError
|
408
438
|
''
|
409
439
|
end
|
410
440
|
|
@@ -490,11 +520,18 @@ module Jazzy
|
|
490
520
|
end
|
491
521
|
|
492
522
|
# @available attrs only in compiler 'interface' style
|
493
|
-
|
523
|
+
extract_availability(doc['key.doc.declaration'] || '')
|
524
|
+
.concat(extract_attributes(annotated_decl_attrs))
|
525
|
+
.push(decl)
|
526
|
+
.join("\n")
|
527
|
+
end
|
494
528
|
|
495
|
-
|
496
|
-
|
497
|
-
|
529
|
+
# Exclude non-async routines that accept async closures
|
530
|
+
def self.swift_async?(fully_annotated_decl)
|
531
|
+
document = REXML::Document.new(fully_annotated_decl)
|
532
|
+
!document.elements['/*/syntaxtype.keyword[text()="async"]'].nil?
|
533
|
+
rescue StandardError
|
534
|
+
nil
|
498
535
|
end
|
499
536
|
|
500
537
|
# Strip default property attributes because libclang
|
@@ -510,12 +547,14 @@ module Jazzy
|
|
510
547
|
attrs = Regexp.last_match[1].split(',').map(&:strip) - DEFAULT_ATTRIBUTES
|
511
548
|
attrs_text = attrs.empty? ? '' : " (#{attrs.join(', ')})"
|
512
549
|
|
513
|
-
declaration
|
514
|
-
|
550
|
+
declaration
|
551
|
+
.sub(/(?<=@property)\s+\(.*?\)/, attrs_text)
|
552
|
+
.gsub(/\s+/, ' ')
|
515
553
|
end
|
516
554
|
|
517
555
|
def self.make_substructure(doc, declaration)
|
518
556
|
return [] unless subdocs = doc['key.substructure']
|
557
|
+
|
519
558
|
make_source_declarations(subdocs,
|
520
559
|
declaration,
|
521
560
|
declaration.mark_for_children)
|
@@ -536,7 +575,9 @@ module Jazzy
|
|
536
575
|
end
|
537
576
|
declaration = SourceDeclaration.new
|
538
577
|
declaration.parent_in_code = parent
|
539
|
-
declaration.type =
|
578
|
+
declaration.type =
|
579
|
+
SourceDeclaration::Type.new(doc['key.kind'],
|
580
|
+
doc['key.fully_annotated_decl'])
|
540
581
|
declaration.typename = doc['key.typename']
|
541
582
|
declaration.objc_name = doc['key.name']
|
542
583
|
documented_name = if Config.instance.hide_objc? && doc['key.swift_name']
|
@@ -558,8 +599,8 @@ module Jazzy
|
|
558
599
|
|
559
600
|
unless declaration.type.name
|
560
601
|
raise 'Please file an issue at ' \
|
561
|
-
|
562
|
-
|
602
|
+
'https://github.com/realm/jazzy/issues about adding support ' \
|
603
|
+
"for `#{declaration.type.kind}`."
|
563
604
|
end
|
564
605
|
|
565
606
|
declaration.file = Pathname(doc['key.filepath']) if doc['key.filepath']
|
@@ -570,8 +611,8 @@ module Jazzy
|
|
570
611
|
declaration.mark = current_mark
|
571
612
|
declaration.access_control_level =
|
572
613
|
SourceDeclaration::AccessControlLevel.from_doc(doc)
|
573
|
-
declaration.line = doc['key.doc.line']
|
574
|
-
declaration.column = doc['key.doc.column']
|
614
|
+
declaration.line = doc['key.doc.line'] || doc['key.line']
|
615
|
+
declaration.column = doc['key.doc.column'] || doc['key.column']
|
575
616
|
declaration.start_line = doc['key.parsed_scope.start']
|
576
617
|
declaration.end_line = doc['key.parsed_scope.end']
|
577
618
|
declaration.deprecated = doc['key.always_deprecated']
|
@@ -581,12 +622,19 @@ module Jazzy
|
|
581
622
|
inherited_types = doc['key.inheritedtypes'] || []
|
582
623
|
declaration.inherited_types =
|
583
624
|
inherited_types.map { |type| type['key.name'] }.compact
|
625
|
+
declaration.async =
|
626
|
+
doc['key.symgraph_async'] ||
|
627
|
+
if xml_declaration = doc['key.fully_annotated_decl']
|
628
|
+
swift_async?(xml_declaration)
|
629
|
+
end
|
584
630
|
|
585
631
|
next unless make_doc_info(doc, declaration)
|
632
|
+
|
586
633
|
declaration.children = make_substructure(doc, declaration)
|
587
634
|
next if declaration.type.extension? &&
|
588
635
|
declaration.children.empty? &&
|
589
636
|
!declaration.inherited_types?
|
637
|
+
|
590
638
|
declarations << declaration
|
591
639
|
end
|
592
640
|
declarations
|
@@ -598,6 +646,7 @@ module Jazzy
|
|
598
646
|
def self.find_generic_requirements(parsed_declaration)
|
599
647
|
parsed_declaration =~ /\bwhere\s+(.*)$/m
|
600
648
|
return nil unless Regexp.last_match
|
649
|
+
|
601
650
|
Regexp.last_match[1].gsub(/\s+/, ' ')
|
602
651
|
end
|
603
652
|
|
@@ -619,6 +668,7 @@ module Jazzy
|
|
619
668
|
|
620
669
|
def self.expand_extension(extension, name_parts, decls)
|
621
670
|
return extension if name_parts.empty?
|
671
|
+
|
622
672
|
name = name_parts.shift
|
623
673
|
candidates = decls.select { |decl| decl.name == name }
|
624
674
|
SourceDeclaration.new.tap do |decl|
|
@@ -644,8 +694,8 @@ module Jazzy
|
|
644
694
|
# Merges redundant declarations when documenting podspecs.
|
645
695
|
def self.deduplicate_declarations(declarations)
|
646
696
|
duplicate_groups = declarations
|
647
|
-
|
648
|
-
|
697
|
+
.group_by { |d| deduplication_key(d, declarations) }
|
698
|
+
.values
|
649
699
|
|
650
700
|
duplicate_groups.flat_map do |group|
|
651
701
|
# Put extended type (if present) before extensions
|
@@ -688,15 +738,17 @@ module Jazzy
|
|
688
738
|
end
|
689
739
|
|
690
740
|
# rubocop:disable Metrics/MethodLength
|
741
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
691
742
|
# Merges all of the given types and extensions into a single document.
|
692
743
|
def self.merge_declarations(decls)
|
693
744
|
extensions, typedecls = decls.partition { |d| d.type.extension? }
|
694
745
|
|
695
746
|
if typedecls.size > 1
|
747
|
+
info = typedecls
|
748
|
+
.map { |t| "#{t.type.name.downcase} #{t.name}" }
|
749
|
+
.join(', ')
|
696
750
|
warn 'Found conflicting type declarations with the same name, which ' \
|
697
|
-
|
698
|
-
typedecls.map { |t| "#{t.type.name.downcase} #{t.name}" }
|
699
|
-
.join(', ')
|
751
|
+
"may indicate a build issue or a bug in Jazzy: #{info}"
|
700
752
|
end
|
701
753
|
typedecl = typedecls.first
|
702
754
|
|
@@ -712,13 +764,14 @@ module Jazzy
|
|
712
764
|
end
|
713
765
|
|
714
766
|
# Keep type-aliases separate from any extensions
|
715
|
-
if typedecl
|
767
|
+
if typedecl&.type&.swift_typealias?
|
716
768
|
[merge_type_and_extensions(typedecls, []),
|
717
769
|
merge_type_and_extensions([], extensions)]
|
718
770
|
else
|
719
771
|
merge_type_and_extensions(typedecls, extensions)
|
720
772
|
end
|
721
773
|
end
|
774
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
722
775
|
# rubocop:enable Metrics/MethodLength
|
723
776
|
|
724
777
|
def self.merge_type_and_extensions(typedecls, extensions)
|
@@ -783,7 +836,9 @@ module Jazzy
|
|
783
836
|
extensions.each do |ext|
|
784
837
|
ext.children = ext.children.select do |ext_member|
|
785
838
|
proto_member = protocol.children.find do |p|
|
786
|
-
p.name == ext_member.name &&
|
839
|
+
p.name == ext_member.name &&
|
840
|
+
p.type == ext_member.type &&
|
841
|
+
p.async == ext_member.async
|
787
842
|
end
|
788
843
|
|
789
844
|
# Extension-only method, keep.
|
@@ -810,6 +865,7 @@ module Jazzy
|
|
810
865
|
# (unless they already have a mark)
|
811
866
|
def self.merge_objc_declaration_marks(typedecl, extensions)
|
812
867
|
return unless typedecl.type.objc_class?
|
868
|
+
|
813
869
|
extensions.each do |ext|
|
814
870
|
_, category_name = ext.objc_category_name
|
815
871
|
ext.children.each { |c| c.mark.name ||= category_name }
|
@@ -819,7 +875,8 @@ module Jazzy
|
|
819
875
|
# For each extension to be merged, move any MARK from the extension
|
820
876
|
# declaration down to the extension contents so it still shows up.
|
821
877
|
def self.move_merged_extension_marks(decls)
|
822
|
-
return unless to_be_merged = decls[1
|
878
|
+
return unless to_be_merged = decls[1..]
|
879
|
+
|
823
880
|
to_be_merged.each do |ext|
|
824
881
|
child = ext.children.first
|
825
882
|
if child && child.mark.empty?
|
@@ -834,7 +891,7 @@ module Jazzy
|
|
834
891
|
def self.merge_code_declaration(decls)
|
835
892
|
first = decls.first
|
836
893
|
|
837
|
-
declarations = decls[1
|
894
|
+
declarations = decls[1..].select do |decl|
|
838
895
|
decl.type.swift_extension? &&
|
839
896
|
(decl.other_inherited_types?(@inaccessible_protocols) ||
|
840
897
|
(first.type.swift_extension? && decl.constrained_extension?))
|
@@ -879,9 +936,11 @@ module Jazzy
|
|
879
936
|
|
880
937
|
def self.name_match(name_part, docs)
|
881
938
|
return nil unless name_part
|
939
|
+
|
882
940
|
wildcard_expansion = Regexp.escape(name_part)
|
883
|
-
|
884
|
-
|
941
|
+
.gsub('\.\.\.', '[^)]*')
|
942
|
+
.gsub(/<.*>/, '')
|
943
|
+
|
885
944
|
whole_name_pat = /\A#{wildcard_expansion}\Z/
|
886
945
|
docs.find do |doc|
|
887
946
|
whole_name_pat =~ doc.name
|
@@ -911,19 +970,26 @@ module Jazzy
|
|
911
970
|
# - method signatures after they've been processed by the highlighter
|
912
971
|
#
|
913
972
|
# The `after_highlight` flag is used to differentiate between the two modes.
|
914
|
-
|
973
|
+
#
|
974
|
+
# DocC link format - follow Xcode and don't display slash-separated parts.
|
975
|
+
# rubocop:disable Metrics/MethodLength
|
976
|
+
def self.autolink_text(text, doc, root_decls, after_highlight: false)
|
915
977
|
text.autolink_block(doc.url, '[^\s]+', after_highlight) do |raw_name|
|
916
|
-
|
917
|
-
|
918
|
-
|
978
|
+
sym_name =
|
979
|
+
(raw_name[/^<doc:(.*)>$/, 1] || raw_name).sub(/(?<!^)-.+$/, '')
|
980
|
+
|
981
|
+
parts = sym_name
|
982
|
+
.sub(/^@/, '') # ignore for custom attribute ref
|
983
|
+
.split(%r{(?<!\.)[/.](?!\.)}) # dot or slash, but not '...'
|
984
|
+
.reject(&:empty?)
|
919
985
|
|
920
986
|
# First dot-separated component can match any ancestor or top-level doc
|
921
987
|
first_part = parts.shift
|
922
988
|
name_root = ancestor_name_match(first_part, doc) ||
|
923
989
|
name_match(first_part, root_decls)
|
924
990
|
|
925
|
-
# Traverse children via
|
926
|
-
name_traversal(parts, name_root)
|
991
|
+
# Traverse children via subsequent components, if any
|
992
|
+
[name_traversal(parts, name_root), sym_name.sub(%r{^.*/}, '')]
|
927
993
|
end.autolink_block(doc.url, '[+-]\[\w+(?: ?\(\w+\))? [\w:]+\]',
|
928
994
|
after_highlight) do |raw_name|
|
929
995
|
match = raw_name.match(/([+-])\[(\w+(?: ?\(\w+\))?) ([\w:]+)\]/)
|
@@ -935,42 +1001,50 @@ module Jazzy
|
|
935
1001
|
|
936
1002
|
if name_root
|
937
1003
|
# Look up the verb in the subject’s children
|
938
|
-
name_match(match[1] + match[3], name_root.children)
|
1004
|
+
[name_match(match[1] + match[3], name_root.children), raw_name]
|
939
1005
|
end
|
940
1006
|
end.autolink_block(doc.url, '[+-]\w[\w:]*', after_highlight) do |raw_name|
|
941
|
-
name_match(raw_name, doc.children)
|
1007
|
+
[name_match(raw_name, doc.children), raw_name]
|
942
1008
|
end
|
943
1009
|
end
|
1010
|
+
# rubocop:enable Metrics/MethodLength
|
944
1011
|
|
945
1012
|
AUTOLINK_TEXT_FIELDS = %w[return
|
946
1013
|
abstract
|
947
1014
|
unavailable_message
|
948
1015
|
deprecation_message].freeze
|
949
1016
|
|
1017
|
+
def self.autolink_text_fields(doc, root_decls)
|
1018
|
+
AUTOLINK_TEXT_FIELDS.each do |field|
|
1019
|
+
if text = doc.send(field)
|
1020
|
+
doc.send(field + '=', autolink_text(text, doc, root_decls))
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
(doc.parameters || []).each do |param|
|
1025
|
+
param[:discussion] =
|
1026
|
+
autolink_text(param[:discussion], doc, root_decls)
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
950
1030
|
AUTOLINK_HIGHLIGHT_FIELDS = %w[declaration
|
951
1031
|
other_language_declaration].freeze
|
952
1032
|
|
1033
|
+
def self.autolink_highlight_fields(doc, root_decls)
|
1034
|
+
AUTOLINK_HIGHLIGHT_FIELDS.each do |field|
|
1035
|
+
if text = doc.send(field)
|
1036
|
+
doc.send(field + '=',
|
1037
|
+
autolink_text(text, doc, root_decls, after_highlight: true))
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
953
1042
|
def self.autolink(docs, root_decls)
|
954
1043
|
@autolink_root_decls = root_decls
|
955
1044
|
docs.each do |doc|
|
956
1045
|
doc.children = autolink(doc.children, root_decls)
|
957
|
-
|
958
|
-
|
959
|
-
if text = doc.send(field)
|
960
|
-
doc.send(field + '=', autolink_text(text, doc, root_decls))
|
961
|
-
end
|
962
|
-
end
|
963
|
-
|
964
|
-
AUTOLINK_HIGHLIGHT_FIELDS.each do |field|
|
965
|
-
if text = doc.send(field)
|
966
|
-
doc.send(field + '=', autolink_text(text, doc, root_decls, true))
|
967
|
-
end
|
968
|
-
end
|
969
|
-
|
970
|
-
(doc.parameters || []).each do |param|
|
971
|
-
param[:discussion] =
|
972
|
-
autolink_text(param[:discussion], doc, root_decls)
|
973
|
-
end
|
1046
|
+
autolink_text_fields(doc, root_decls)
|
1047
|
+
autolink_highlight_fields(doc, root_decls)
|
974
1048
|
end
|
975
1049
|
end
|
976
1050
|
|
data/lib/jazzy/stats.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
# Collect + report metadata about a processed module
|
3
5
|
class Stats
|
4
6
|
include Config::Mixin
|
5
7
|
|
6
|
-
attr_reader :documented, :acl_skipped
|
7
|
-
attr_reader :undocumented_decls
|
8
|
+
attr_reader :documented, :acl_skipped, :spi_skipped, :undocumented_decls
|
8
9
|
|
9
10
|
def add_documented
|
10
11
|
@documented += 1
|
@@ -14,6 +15,10 @@ module Jazzy
|
|
14
15
|
@acl_skipped += 1
|
15
16
|
end
|
16
17
|
|
18
|
+
def add_spi_skipped
|
19
|
+
@spi_skipped += 1
|
20
|
+
end
|
21
|
+
|
17
22
|
def add_undocumented(decl)
|
18
23
|
@undocumented_decls << decl
|
19
24
|
end
|
@@ -31,7 +36,7 @@ module Jazzy
|
|
31
36
|
end
|
32
37
|
|
33
38
|
def initialize
|
34
|
-
@documented = @acl_skipped = 0
|
39
|
+
@documented = @acl_skipped = @spi_skipped = 0
|
35
40
|
@undocumented_decls = []
|
36
41
|
end
|
37
42
|
|
@@ -53,10 +58,16 @@ module Jazzy
|
|
53
58
|
"#{symbol_or_symbols(acl_skipped)} " \
|
54
59
|
'(use `--min-acl` to specify a different minimum ACL)'
|
55
60
|
end
|
61
|
+
|
62
|
+
if spi_skipped > 0
|
63
|
+
puts "skipped #{spi_skipped} SPI #{symbol_or_symbols(spi_skipped)} " \
|
64
|
+
'(use `--include-spi-declarations` to include these)'
|
65
|
+
end
|
56
66
|
end
|
57
67
|
|
58
68
|
def doc_coverage
|
59
69
|
return 0 if acl_included == 0
|
70
|
+
|
60
71
|
(100 * documented) / acl_included
|
61
72
|
end
|
62
73
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
module SymbolGraph
|
3
5
|
# Constraint is a tidied-up JSON object, used by both Symbol and
|
@@ -27,6 +29,7 @@ module Jazzy
|
|
27
29
|
def self.new_hash(hash)
|
28
30
|
kind = KIND_MAP[hash[:kind]]
|
29
31
|
raise "Unknown constraint kind '#{kind}'" unless kind
|
32
|
+
|
30
33
|
lhs = hash[:lhs].sub(/^Self\./, '')
|
31
34
|
rhs = hash[:rhs].sub(/^Self\./, '')
|
32
35
|
new(kind, lhs, rhs)
|
@@ -62,6 +65,7 @@ module Jazzy
|
|
62
65
|
path_components.include?(hash[:rhs])
|
63
66
|
next nil
|
64
67
|
end
|
68
|
+
|
65
69
|
Constraint.new_hash(hash)
|
66
70
|
end.compact
|
67
71
|
end
|
@@ -89,6 +93,6 @@ end
|
|
89
93
|
|
90
94
|
class Array
|
91
95
|
def to_where_clause
|
92
|
-
empty? ? '' :
|
96
|
+
empty? ? '' : " where #{map(&:to_swift).join(', ')}"
|
93
97
|
end
|
94
98
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jazzy
|
2
4
|
module SymbolGraph
|
3
5
|
# For extensions we need to track constraints of the extended type
|
@@ -68,7 +70,7 @@ module Jazzy
|
|
68
70
|
def full_declaration
|
69
71
|
decl = "extension #{name}"
|
70
72
|
unless conformances.empty?
|
71
|
-
decl +=
|
73
|
+
decl += " : #{conformances.join(', ')}"
|
72
74
|
end
|
73
75
|
decl + all_constraints.ext.to_where_clause
|
74
76
|
end
|